Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

filemov.C

Go to the documentation of this file.
00001 #include "asset.h"
00002 #include "bcsignals.h"
00003 #include "bitspopup.h"
00004 #include "byteorder.h"
00005 #include "condition.h"
00006 #include "edit.h"
00007 #include "file.h"
00008 #include "filemov.h"
00009 #include "guicast.h"
00010 #include "language.h"
00011 #include "mwindow.inc"
00012 #include "vframe.h"
00013 #include "videodevice.inc"
00014 
00015 #include <unistd.h>
00016 #include <libdv/dv.h>
00017 
00018 #if 0
00019 N_("MPEG-4")
00020 N_("Dual H.264")
00021 N_("Dual MPEG-4")
00022 N_("H.264")
00023 N_("H.263")
00024 N_("Microsoft MPEG-4")
00025 N_("DV")
00026 N_("PNG")
00027 N_("PNG with Alpha")
00028 N_("Uncompressed RGB")
00029 N_("Uncompressed RGBA")
00030 N_("YUV 4:2:0 Planar")
00031 N_("Component Video")
00032 N_("YUV 4:1:1 Packed")
00033 N_("Component Y'CbCr 8-bit 4:4:4")
00034 N_("Component Y'CbCrA 8-bit 4:4:4:4")
00035 N_("Component Y'CbCr 10-bit 4:4:4")
00036 N_("JPEG Photo")
00037 N_("Motion JPEG A")
00038 
00039 
00040 N_("Twos complement")
00041 N_("Unsigned")
00042 N_("IMA-4")
00043 N_("U-Law")
00044 N_("Vorbis")
00045 N_("MP3")
00046 N_("MPEG-4 Audio")
00047 #endif
00048 
00049 #define DIVX_NAME "MPEG-4"
00050 #define HV64_NAME "Dual H.264"
00051 #define MP4V_NAME "MPEG-4 Video"
00052 #define H264_NAME "H.264"
00053 #define H263_NAME "H.263"
00054 #define HV60_NAME "Dual MPEG-4"
00055 #define DIV3_NAME "Microsoft MPEG-4"
00056 #define DV_NAME "DV"
00057 #define PNG_NAME "PNG"
00058 #define PNGA_NAME "PNG with Alpha"
00059 #define RGB_NAME "Uncompressed RGB"
00060 #define RGBA_NAME "Uncompressed RGBA"
00061 #define YUV420_NAME "YUV 4:2:0 Planar"
00062 #define YUV422_NAME "Component Video"
00063 #define YUV411_NAME "YUV 4:1:1 Packed"
00064 #define YUV444_NAME "Component Y'CbCr 8-bit 4:4:4"
00065 #define YUVA4444_NAME "Component Y'CbCrA 8-bit 4:4:4:4"
00066 #define YUV444_10BIT_NAME "Component Y'CbCr 10-bit 4:4:4"
00067 #define QTJPEG_NAME "JPEG Photo"
00068 #define MJPA_NAME "Motion JPEG A"
00069 
00070 #define TWOS_NAME "Twos complement"
00071 #define RAW_NAME "Unsigned"
00072 #define IMA4_NAME "IMA-4"
00073 #define ULAW_NAME "U-Law"
00074 //#define VORBIS_NAME "Vorbis"
00075 #define MP3_NAME "MP3"
00076 #define MP4A_NAME "MPEG-4 Audio"
00077 #define VORBIS_NAME "OGG Vorbis"
00078 
00079 
00080 
00081 
00082 
00083 FileMOV::FileMOV(Asset *asset, File *file)
00084  : FileBase(asset, file)
00085 {
00086         reset_parameters();
00087         if(asset->format == FILE_UNKNOWN)
00088                 asset->format = FILE_MOV;
00089         asset->byte_order = 0;
00090         suffix_number = 0;
00091         threadframe_lock = new Mutex("FileMOV::threadframe_lock");
00092 }
00093 
00094 FileMOV::~FileMOV()
00095 {
00096         close_file();
00097         delete threadframe_lock;
00098 }
00099 
00100 void FileMOV::get_parameters(BC_WindowBase *parent_window, 
00101         Asset *asset, 
00102         BC_WindowBase* &format_window,
00103         int audio_options,
00104         int video_options,
00105         int lock_compressor)
00106 {
00107         fix_codecs(asset);
00108         if(audio_options)
00109         {
00110                 MOVConfigAudio *window = new MOVConfigAudio(parent_window, asset);
00111                 format_window = window;
00112                 window->create_objects();
00113                 window->run_window();
00114                 delete window;
00115         }
00116         else
00117         if(video_options)
00118         {
00119                 MOVConfigVideo *window = new MOVConfigVideo(parent_window, 
00120                         asset, 
00121                         lock_compressor);
00122                 format_window = window;
00123                 window->create_objects();
00124                 window->run_window();
00125                 delete window;
00126         }
00127 }
00128 
00129 void FileMOV::fix_codecs(Asset *asset)
00130 {
00131 //      if(asset->format == FILE_MOV)
00132 //      {
00133 //              if(!strcasecmp(asset->acodec, QUICKTIME_MP3))
00134 //                      strcpy(asset->acodec, QUICKTIME_TWOS);
00135 //      }
00136 //      else
00137 //      {
00138 //              if(strcasecmp(asset->vcodec, QUICKTIME_DIV3))
00139 //              {
00140 //                      strcpy(asset->vcodec, QUICKTIME_DIV3);
00141 //              }
00142 //              strcpy(asset->acodec, QUICKTIME_MP3);
00143 //      }
00144 }
00145 
00146 int FileMOV::check_sig(Asset *asset)
00147 {
00148         return quicktime_check_sig(asset->path);
00149 }
00150 
00151 
00152 int FileMOV::reset_parameters_derived()
00153 {
00154         fd = 0;
00155         prev_track = 0;
00156         quicktime_atracks = 0;
00157         quicktime_vtracks = 0;
00158         depth = 24;
00159         threads = 0;
00160         frames_correction = 0;
00161         samples_correction = 0;
00162         temp_float = 0;
00163         temp_allocated = 0;
00164 }
00165 
00166 
00167 // Just create the Quicktime objects since this routine is also called
00168 // for reopening.
00169 int FileMOV::open_file(int rd, int wr)
00170 {
00171 
00172         this->rd = rd;
00173         this->wr = wr;
00174 
00175         if(suffix_number == 0) strcpy(prefix_path, asset->path);
00176 
00177         if(!(fd = quicktime_open(asset->path, rd, wr)))
00178         {
00179                 printf(_("FileMOV::open_file %s: No such file or directory\n"), asset->path);
00180                 return 1;
00181         }
00182 
00183         quicktime_set_cpus(fd, file->cpus);
00184 
00185         if(rd)
00186         {
00187                 format_to_asset();
00188                 
00189                 // If DV stream, get the timecode
00190                 if(match4(asset->vcodec, QUICKTIME_DV))
00191                 {
00192                         char tc[12];
00193                         dv_decoder_t *tmp_decoder = dv_decoder_new(0,0,0);
00194                         VFrame *frame = new VFrame(0, 0, 0, BC_COMPRESSED);
00195                         
00196                         read_frame(frame);
00197                         set_video_position(0);
00198                         
00199                         if(dv_parse_header(tmp_decoder, frame->get_data()) > -1)
00200                         {
00201                                 dv_parse_packs(tmp_decoder, frame->get_data());
00202                                 dv_get_timestamp(tmp_decoder, tc);
00203                                 printf("Timestamp %s\n", tc);
00204                         
00205                                 float seconds = Units::text_to_seconds(tc,
00206                                                                                 1, // Use 1 as sample rate, doesn't matter
00207                                                                                 TIME_HMSF,
00208                                                                                 tmp_decoder->height == 576 ? 25 : 30, // FIXME
00209                                                                                 0);
00210                                 // Get frame number
00211                                 asset->tcstart = int64_t(seconds * (tmp_decoder->height == 576 ? 25 : 30));
00212                         }
00213                         
00214                 }
00215         }
00216 
00217         if(wr) asset_to_format();
00218 
00219 // Set decoding parameter
00220         quicktime_set_parameter(fd, "divx_use_deblocking", &asset->divx_use_deblocking);
00221 
00222 // Set timecode offset
00223         quicktime_set_frame_start(fd, asset->tcstart);
00224 
00225         return 0;
00226 }
00227 
00228 int FileMOV::close_file()
00229 {
00230 //printf("FileMOV::close_file 1 %s\n", asset->path);
00231         if(fd)
00232         {
00233                 if(wr) quicktime_set_framerate(fd, asset->frame_rate);
00234                 quicktime_close(fd);
00235         }
00236 
00237 //printf("FileMOV::close_file 1\n");
00238         if(threads)
00239         {
00240                 for(int i = 0; i < file->cpus; i++)
00241                 {
00242                         threads[i]->stop_encoding();
00243                         delete threads[i];
00244                 }
00245                 delete [] threads;
00246                 threads = 0;
00247         }
00248 
00249 //printf("FileMOV::close_file 1\n");
00250         threadframes.remove_all_objects();
00251 
00252 
00253         if(temp_float) 
00254         {
00255                 for(int i = 0; i < asset->channels; i++)
00256                         delete [] temp_float[i];
00257                 delete [] temp_float;
00258         }
00259 
00260 //printf("FileMOV::close_file 1\n");
00261         reset_parameters();
00262         FileBase::close_file();
00263 //printf("FileMOV::close_file 2\n");
00264         return 0;
00265 }
00266 
00267 void FileMOV::set_frame_start(int64_t offset)
00268 {
00269         quicktime_set_frame_start(fd, offset);
00270 }
00271 
00272 void FileMOV::asset_to_format()
00273 {
00274         if(!fd) return;
00275         char audio_codec[5];
00276 
00277         fix_codecs(asset);
00278 
00279 // Fix up the Quicktime file.
00280         quicktime_set_copyright(fd, _("Made with Cinelerra for Linux"));
00281         quicktime_set_info(fd, "Quicktime for Linux");
00282 
00283         if(asset->audio_data)
00284         {
00285                 quicktime_atracks = quicktime_set_audio(fd, 
00286                                 asset->channels, 
00287                                 asset->sample_rate, 
00288                                 asset->bits, 
00289                                 asset->acodec);
00290                 quicktime_set_parameter(fd, "vorbis_vbr", &asset->vorbis_vbr);
00291                 quicktime_set_parameter(fd, "vorbis_min_bitrate", &asset->vorbis_min_bitrate);
00292                 quicktime_set_parameter(fd, "vorbis_bitrate", &asset->vorbis_bitrate);
00293                 quicktime_set_parameter(fd, "vorbis_max_bitrate", &asset->vorbis_max_bitrate);
00294                 quicktime_set_parameter(fd, "mp3_bitrate", &asset->mp3_bitrate);
00295                 quicktime_set_parameter(fd, "mp4a_bitrate", &asset->mp4a_bitrate);
00296         }
00297 
00298         if(asset->video_data)
00299         {
00300                 char string[16];
00301 // Set up the alpha channel compressors
00302                 if(!strcmp(asset->vcodec, MOV_RGBA))
00303                 {
00304                         strcpy(string, QUICKTIME_RAW);
00305                         depth = 32;
00306                 }
00307                 else
00308                 if(!strcmp(asset->vcodec, MOV_PNGA))
00309                 {
00310                         strcpy(string, QUICKTIME_PNG);
00311                         depth = 32;
00312                 }
00313                 else
00314                 if(!strcmp(asset->vcodec, QUICKTIME_YUVA4444))
00315                 {
00316                         strcpy(string, asset->vcodec);
00317                         depth = 32;
00318                 }
00319                 else
00320                 {
00321                         strcpy(string, asset->vcodec);
00322                         depth = 24;
00323                 }
00324 
00325                 quicktime_vtracks = quicktime_set_video(fd, 
00326                                         asset->layers, 
00327                                         asset->width, 
00328                                         asset->height,
00329                                         asset->frame_rate,
00330                                         string);
00331 
00332 
00333 
00334                 for(int i = 0; i < asset->layers; i++)
00335                         quicktime_set_depth(fd, depth, i);
00336 
00337                 quicktime_set_parameter(fd, "jpeg_quality", &asset->jpeg_quality);
00338 
00339 // set the compression parameters if there are any
00340                 quicktime_set_parameter(fd, "divx_bitrate", &asset->divx_bitrate);
00341                 quicktime_set_parameter(fd, "divx_rc_period", &asset->divx_rc_period);
00342                 quicktime_set_parameter(fd, "divx_rc_reaction_ratio", &asset->divx_rc_reaction_ratio);
00343                 quicktime_set_parameter(fd, "divx_rc_reaction_period", &asset->divx_rc_reaction_period);
00344                 quicktime_set_parameter(fd, "divx_max_key_interval", &asset->divx_max_key_interval);
00345                 quicktime_set_parameter(fd, "divx_max_quantizer", &asset->divx_max_quantizer);
00346                 quicktime_set_parameter(fd, "divx_min_quantizer", &asset->divx_min_quantizer);
00347                 quicktime_set_parameter(fd, "divx_quantizer", &asset->divx_quantizer);
00348                 quicktime_set_parameter(fd, "divx_quality", &asset->divx_quality);
00349                 quicktime_set_parameter(fd, "divx_fix_bitrate", &asset->divx_fix_bitrate);
00350 
00351                 quicktime_set_parameter(fd, "ffmpeg_bitrate", &asset->ms_bitrate);
00352                 quicktime_set_parameter(fd, "ffmpeg_bitrate_tolerance", &asset->ms_bitrate_tolerance);
00353                 quicktime_set_parameter(fd, "ffmpeg_interlaced", &asset->ms_interlaced);
00354                 quicktime_set_parameter(fd, "ffmpeg_quantizer", &asset->ms_quantization);
00355                 quicktime_set_parameter(fd, "ffmpeg_gop_size", &asset->ms_gop_size);
00356                 quicktime_set_parameter(fd, "ffmpeg_fix_bitrate", &asset->ms_fix_bitrate);
00357 
00358                 quicktime_set_parameter(fd, "h264_bitrate", &asset->h264_bitrate);
00359                 quicktime_set_parameter(fd, "h264_quantizer", &asset->h264_quantizer);
00360                 quicktime_set_parameter(fd, "h264_fix_bitrate", &asset->h264_fix_bitrate);
00361 
00362 
00363         }
00364 //printf("FileMOV::asset_to_format 3.4\n");
00365 
00366 //printf("FileMOV::asset_to_format 4 %d %d\n", wr, 
00367 //                              asset->format);
00368 
00369         if(wr && asset->format == FILE_AVI)
00370         {
00371                 quicktime_set_avi(fd, 1);
00372         }
00373 }
00374 
00375 
00376 void FileMOV::format_to_asset()
00377 {
00378         if(!fd) return;
00379 
00380         if(quicktime_is_avi(fd)) asset->format = FILE_AVI;
00381         asset->audio_data = quicktime_has_audio(fd);
00382         if(asset->audio_data)
00383         {
00384                 asset->channels = 0;
00385                 int qt_tracks = quicktime_audio_tracks(fd);
00386                 for(int i = 0; i < qt_tracks; i++)
00387                         asset->channels += quicktime_track_channels(fd, i);
00388         
00389                 if(!asset->sample_rate)
00390                         asset->sample_rate = quicktime_sample_rate(fd, 0);
00391                 asset->bits = quicktime_audio_bits(fd, 0);
00392                 asset->audio_length = quicktime_audio_length(fd, 0);
00393                 strncpy(asset->acodec, quicktime_audio_compressor(fd, 0), 4);
00394         }
00395 
00396 // determine if the video can be read before declaring video data
00397         if(quicktime_has_video(fd) && quicktime_supported_video(fd, 0))
00398                         asset->video_data = 1;
00399 
00400         if(asset->video_data)
00401         {
00402                 depth = quicktime_video_depth(fd, 0);
00403                 asset->layers = quicktime_video_tracks(fd);
00404                 asset->width = quicktime_video_width(fd, 0);
00405                 asset->height = quicktime_video_height(fd, 0);
00406                 asset->video_length = quicktime_video_length(fd, 0);
00407 // Don't want a user configured frame rate to get destroyed
00408                 if(!asset->frame_rate)
00409                         asset->frame_rate = quicktime_frame_rate(fd, 0);
00410                 if(!asset->interlace_mode)
00411                         asset->interlace_mode = quicktime_video_interlacemode(fd, 0);
00412 
00413                 strncpy(asset->vcodec, quicktime_video_compressor(fd, 0), 4);
00414         }
00415 }
00416 
00417 int FileMOV::colormodel_supported(int colormodel)
00418 {
00419         return colormodel;
00420 }
00421 
00422 int FileMOV::get_best_colormodel(Asset *asset, int driver)
00423 {
00424         switch(driver)
00425         {
00426                 case PLAYBACK_X11:
00427                         return BC_RGB888;
00428                         break;
00429                 case PLAYBACK_X11_XV:
00430                         if(match4(asset->vcodec, QUICKTIME_YUV420)) return BC_YUV420P;
00431                         if(match4(asset->vcodec, QUICKTIME_YUV422)) return BC_YUV422P;
00432                         if(match4(asset->vcodec, QUICKTIME_JPEG)) return BC_YUV420P;
00433                         if(match4(asset->vcodec, QUICKTIME_MJPA)) return BC_YUV422P;
00434                         if(match4(asset->vcodec, QUICKTIME_DV)) return BC_YUV422;
00435                         if(match4(asset->vcodec, QUICKTIME_DVSD)) return BC_YUV422;
00436                         if(match4(asset->vcodec, QUICKTIME_HV60)) return BC_YUV420P;
00437                         if(match4(asset->vcodec, QUICKTIME_DIVX)) return BC_YUV420P;
00438                         if(match4(asset->vcodec, QUICKTIME_DVSD)) return BC_YUV422;
00439                         if(match4(asset->vcodec, QUICKTIME_MP4V)) return BC_YUV420P;
00440                         if(match4(asset->vcodec, QUICKTIME_H263)) return BC_YUV420P;
00441                         if(match4(asset->vcodec, QUICKTIME_H264)) return BC_YUV420P;
00442                         if(match4(asset->vcodec, QUICKTIME_HV64)) return BC_YUV420P;
00443                         if(match4(asset->vcodec, QUICKTIME_DIV3)) return BC_YUV420P;
00444                         break;
00445                 case PLAYBACK_DV1394:
00446                 case PLAYBACK_FIREWIRE:
00447                         if(match4(asset->vcodec, QUICKTIME_DV) || 
00448                                 match4(asset->vcodec, QUICKTIME_DVSD)) return BC_COMPRESSED;
00449                         return BC_YUV422P;
00450                         break;
00451                 case PLAYBACK_LML:
00452                 case PLAYBACK_BUZ:
00453                         if(match4(asset->vcodec, QUICKTIME_MJPA)) 
00454                                 return BC_COMPRESSED;
00455                         else
00456                                 return BC_YUV422P;
00457                         break;
00458                 case VIDEO4LINUX:
00459                 case VIDEO4LINUX2:
00460                         if(!strncasecmp(asset->vcodec, QUICKTIME_YUV420, 4)) return BC_YUV422;
00461                         else
00462                         if(!strncasecmp(asset->vcodec, QUICKTIME_YUV422, 4)) return BC_YUV422;
00463                         else
00464                         if(!strncasecmp(asset->vcodec, QUICKTIME_YUV411, 4)) return BC_YUV411P;
00465                         else
00466                         if(!strncasecmp(asset->vcodec, QUICKTIME_JPEG, 4)) return BC_YUV420P;
00467                         else
00468                         if(!strncasecmp(asset->vcodec, QUICKTIME_MJPA, 4)) return BC_YUV422P;
00469                         else
00470                         if(!strncasecmp(asset->vcodec, QUICKTIME_HV60, 4)) return BC_YUV420P;
00471                         else
00472                         if(!strncasecmp(asset->vcodec, QUICKTIME_DIVX, 4)) return BC_YUV420P;
00473                         else
00474                         if(!strncasecmp(asset->vcodec, QUICKTIME_H263, 4)) return BC_YUV420P;
00475                         else
00476                         if(!strncasecmp(asset->vcodec, QUICKTIME_DIV3, 4)) return BC_YUV420P;
00477                         break;
00478                 case CAPTURE_BUZ:
00479                 case CAPTURE_LML:
00480                 case VIDEO4LINUX2JPEG:
00481                         if(!strncasecmp(asset->vcodec, QUICKTIME_MJPA, 4)) 
00482                                 return BC_COMPRESSED;
00483                         else
00484                                 return BC_YUV422;
00485                         break;
00486                 case CAPTURE_FIREWIRE:
00487                 case CAPTURE_IEC61883:
00488                         if(!strncasecmp(asset->vcodec, QUICKTIME_DV, 4) ||
00489                                 !strncasecmp(asset->vcodec, QUICKTIME_DVSD, 4)) 
00490                                 return BC_COMPRESSED;
00491                         else
00492                                 return BC_YUV422;
00493                         break;
00494         }
00495         return BC_RGB888;
00496 }
00497 
00498 int FileMOV::can_copy_from(Edit *edit, int64_t position)
00499 {
00500         if(!fd) return 0;
00501 
00502 //printf("FileMOV::can_copy_from 1 %d %s %s\n", edit->asset->format, edit->asset->vcodec, this->asset->vcodec);
00503         if(edit->asset->format == FILE_JPEG_LIST && 
00504                 match4(this->asset->vcodec, QUICKTIME_JPEG))
00505                 return 1;
00506         else
00507         if((edit->asset->format == FILE_MOV || 
00508                 edit->asset->format == FILE_AVI))
00509         {
00510                 if(match4(edit->asset->vcodec, this->asset->vcodec))
00511                         return 1;
00512 // there are combinations where the same codec has multiple fourcc codes
00513 // check for DV...
00514                 int is_edit_dv = 0;
00515                 int is_this_dv = 0;
00516                 if (match4(edit->asset->vcodec, QUICKTIME_DV) || 
00517                         match4(edit->asset->vcodec, QUICKTIME_DVSD))
00518                         is_edit_dv = 1;
00519                 if (match4(this->asset->vcodec, QUICKTIME_DV) || 
00520                         match4(this->asset->vcodec, QUICKTIME_DVSD))
00521                         is_this_dv = 1;
00522                 if (is_this_dv && is_edit_dv)
00523                         return 1;
00524         }
00525         else
00526         if(edit->asset->format == FILE_RAWDV)
00527         {
00528                 if(match4(this->asset->vcodec, QUICKTIME_DV) || match4(this->asset->vcodec, QUICKTIME_DVSD))
00529                         return 1;
00530         }
00531 
00532 
00533         return 0;
00534 }
00535 
00536 
00537 int64_t FileMOV::get_audio_length()
00538 {
00539         if(!fd) return 0;
00540         int64_t result = quicktime_audio_length(fd, 0) + samples_correction;
00541 
00542         return result;
00543 }
00544 
00545 int FileMOV::set_audio_position(int64_t x)
00546 {
00547         if(!fd) return 1;
00548 // quicktime sets positions for each track seperately so store position in audio_position
00549         if(x >= 0 && x < asset->audio_length)
00550                 return quicktime_set_audio_position(fd, x, 0);
00551         else
00552                 return 1;
00553 }
00554 
00555 int FileMOV::set_video_position(int64_t x)
00556 {
00557         if(!fd) return 1;
00558         if(x >= 0 && x < asset->video_length)
00559         {
00560                 int result = quicktime_set_video_position(fd, x, file->current_layer);
00561                 return result;
00562         }else
00563                 return 1;
00564 }
00565 
00566 
00567 void FileMOV::new_audio_temp(int64_t len)
00568 {
00569         if(temp_allocated && temp_allocated < len)
00570         {
00571                 for(int i = 0; i < asset->channels; i++)
00572                         delete [] temp_float[i];
00573                 delete [] temp_float;
00574                 temp_allocated = 0;
00575         }
00576 
00577         if(!temp_allocated)
00578         {
00579                 temp_allocated = len;
00580                 temp_float = new float*[asset->channels];
00581                 for(int i = 0; i < asset->channels; i++)
00582                         temp_float[i] = new float[len];
00583         }
00584 }
00585 
00586 
00587 
00588 int FileMOV::write_samples(double **buffer, int64_t len)
00589 {
00590         int i, j;
00591         int64_t bytes;
00592         int result = 0, track_channels = 0;
00593         int chunk_size;
00594 
00595         if(!fd) return 0;
00596 
00597         if(quicktime_supported_audio(fd, 0))
00598         {
00599 // Use Quicktime's compressor. (Always used)
00600 // Allocate temp buffer
00601                 new_audio_temp(len);
00602 
00603 // Copy to float buffer
00604                 for(i = 0; i < asset->channels; i++)
00605                 {
00606                         for(j = 0; j < len; j++)
00607                         {
00608                                 temp_float[i][j] = buffer[i][j];
00609                         }
00610                 }
00611 
00612 // Because of the way Quicktime's compressors work we want to limit the chunk
00613 // size to speed up decompression.
00614                 float **channel_ptr;
00615                 channel_ptr = new float*[asset->channels];
00616 
00617                 for(j = 0; j < len && !result; )
00618                 {
00619                         chunk_size = asset->sample_rate;
00620                         if(j + chunk_size > len) chunk_size = len - j;
00621 
00622                         for(i = 0; i < asset->channels; i++)
00623                         {
00624                                 channel_ptr[i] = &temp_float[i][j];
00625                         }
00626 
00627                         result = quicktime_encode_audio(fd, 0, channel_ptr, chunk_size);
00628                         j += asset->sample_rate;
00629                 }
00630 
00631                 delete [] channel_ptr;
00632         }
00633         return result;
00634 }
00635 
00636 int FileMOV::write_frames(VFrame ***frames, int len)
00637 {
00638 //printf("FileMOV::write_frames 1\n");
00639         int i, j, k, result = 0;
00640         int default_compressor = 1;
00641         if(!fd) return 0;
00642 
00643         for(i = 0; i < asset->layers && !result; i++)
00644         {
00645 
00646 
00647 
00648 
00649 
00650 // Fix direct copy cases for format conversions.
00651                 if(frames[i][0]->get_color_model() == BC_COMPRESSED)
00652                 {
00653                         default_compressor = 0;
00654                         for(j = 0; j < len && !result; j++)
00655                         {
00656                                 VFrame *frame = frames[i][j];
00657 
00658 
00659 
00660 // Special handling for DIVX
00661 // Determine keyframe status.
00662 // Write VOL header in the first frame if none exists
00663                                 if(!strcmp(asset->vcodec, QUICKTIME_DIVX) ||
00664                                         !strcmp(asset->vcodec, QUICKTIME_H263) ||
00665                                         !strcmp(asset->vcodec, QUICKTIME_HV60))
00666                                 {
00667                                         if(quicktime_mpeg4_is_key(frame->get_data(), 
00668                                                 frame->get_compressed_size(),
00669                                                 asset->vcodec))
00670                                                 quicktime_insert_keyframe(fd, file->current_frame + j, i);
00671 
00672 
00673 // Write header
00674                                         if(!(file->current_frame + j) && 
00675                                                 !quicktime_mpeg4_has_vol(frame->get_data()))
00676                                         {
00677                                                 VFrame *temp_frame = new VFrame;
00678 
00679                                                 temp_frame->allocate_compressed_data(frame->get_compressed_size() + 
00680                                                         0xff);
00681                                                 int bytes = quicktime_mpeg4_write_vol(temp_frame->get_data(),
00682                                                         asset->width, 
00683                                                         asset->height, 
00684                                                         60000, 
00685                                                         asset->frame_rate);
00686                                                 memcpy(temp_frame->get_data() + bytes, 
00687                                                         frame->get_data(), 
00688                                                         frame->get_compressed_size());
00689                                                 temp_frame->set_compressed_size(frame->get_compressed_size() + bytes);
00690 
00691                                                 result = quicktime_write_frame(fd,
00692                                                         temp_frame->get_data(),
00693                                                         temp_frame->get_compressed_size(),
00694                                                         i);
00695 
00696                                                 delete temp_frame;
00697 
00698 
00699                                         }
00700                                         else
00701                                         {
00702                                                 result = quicktime_write_frame(fd,
00703                                                         frame->get_data(),
00704                                                         frame->get_compressed_size(),
00705                                                         i);
00706                                         }
00707                                 }
00708                                 else
00709 // Determine keyframe status
00710                                 if(!strcmp(asset->vcodec, QUICKTIME_H264) ||
00711                                         !strcmp(asset->vcodec, QUICKTIME_HV64) ||
00712                                         !strcmp(asset->vcodec, QUICKTIME_MP4V))
00713                                 {
00714                                         if(frame->get_keyframe() || file->current_frame + j == 0)
00715                                                 quicktime_insert_keyframe(fd, file->current_frame + j, i);
00716 
00717 // Write frame
00718                                                 result = quicktime_write_frame(fd,
00719                                                         frame->get_data(),
00720                                                         frame->get_compressed_size(),
00721                                                         i);
00722                                 }
00723                                 else
00724                                 if(!strcmp(asset->vcodec, QUICKTIME_DIV3))
00725                                 {
00726                                         if(quicktime_mpeg4_is_key(frame->get_data(), 
00727                                                 frame->get_compressed_size(),
00728                                                 asset->vcodec))
00729                                                 quicktime_insert_keyframe(fd, file->current_frame + j, i);
00730                                         result = quicktime_write_frame(fd,
00731                                                 frame->get_data(),
00732                                                 frame->get_compressed_size(),
00733                                                 i);
00734                                 }
00735                                 else
00736                                 if(!strcmp(asset->vcodec, QUICKTIME_MJPA))
00737                                 {
00738                                         long field2_offset;
00739 
00740 // Create extra space for markers
00741                                         if(frame->get_compressed_allocated() - frame->get_compressed_size() < 0x100)
00742                                                 frame->allocate_compressed_data(frame->get_compressed_size() + 0x100);
00743 
00744                                         unsigned char *data = frame->get_data();
00745                                         long data_size = frame->get_compressed_size();
00746                                         long data_allocated = frame->get_compressed_allocated();
00747 
00748 // Sometimes get 0 length frames
00749                                         if(data_size)
00750                                         {
00751                                                 if(asset->format == FILE_MOV)
00752                                                 {
00753                                                         mjpeg_insert_quicktime_markers(&data,
00754                                                                 &data_size,
00755                                                                 &data_allocated,
00756                                                                 2,
00757                                                                 &field2_offset);
00758                                                 }
00759                                                 else
00760                                                 {
00761                                                         mjpeg_insert_avi_markers(&data,
00762                                                                 &data_size,
00763                                                                 &data_allocated,
00764                                                                 2,
00765                                                                 &field2_offset);
00766                                                 }
00767                                                 frame->set_compressed_size(data_size);
00768                                                 result = quicktime_write_frame(fd,
00769                                                         frame->get_data(),
00770                                                         frame->get_compressed_size(),
00771                                                         i);
00772                                         }
00773                                         else
00774                                                 printf("FileMOV::write_frames data_size=%d\n", data_size);
00775                                 }
00776                                 else
00777                                         result = quicktime_write_frame(fd,
00778                                                 frame->get_data(),
00779                                                 frame->get_compressed_size(),
00780                                                 i);
00781                                 
00782                                 
00783                         }
00784                 }
00785                 else
00786                 if(match4(asset->vcodec, QUICKTIME_YUV420) ||
00787                         match4(asset->vcodec, QUICKTIME_YUV422) ||
00788                         match4(asset->vcodec, QUICKTIME_RAW))
00789                 {
00790 // Direct copy planes where possible
00791                         default_compressor = 0;
00792                         for(j = 0; j < len && !result; j++)
00793                         {
00794                                 VFrame *frame = frames[i][j];
00795 //printf("FileMOV::write_frames 1 %d\n", frame->get_color_model());
00796                                 quicktime_set_cmodel(fd, frame->get_color_model());
00797                                 if(cmodel_is_planar(frame->get_color_model()))
00798                                 {
00799                                         unsigned char *planes[3];
00800                                         planes[0] = frame->get_y();
00801                                         planes[1] = frame->get_u();
00802                                         planes[2] = frame->get_v();
00803                                         result = quicktime_encode_video(fd, planes, i);
00804                                 }
00805                                 else
00806                                 {
00807                                         result = quicktime_encode_video(fd, frame->get_rows(), i);
00808 //printf("FileMOV::write_frames 2 %d\n", result);
00809                                 }
00810 //printf("FileMOV::write_frames 2\n");
00811                         }
00812                 }
00813                 else
00814                 if(file->cpus > 1 && 
00815                         (match4(asset->vcodec, QUICKTIME_JPEG) || 
00816                         match4(asset->vcodec, QUICKTIME_MJPA)))
00817                 {
00818                         default_compressor = 0;
00819 // Compress symmetrically on an SMP system.
00820                         ThreadStruct *threadframe;
00821                         int fields = match4(asset->vcodec, QUICKTIME_MJPA) ? 2 : 1;
00822 
00823 // Set up threads for symmetric compression.
00824                         if(!threads)
00825                         {
00826                                 threads = new FileMOVThread*[file->cpus];
00827                                 for(j = 0; j < file->cpus; j++)
00828                                 {
00829                                         threads[j] = new FileMOVThread(this, fields);
00830                                         threads[j]->start_encoding();
00831                                 }
00832                         }
00833 
00834 // Set up the frame structures for asynchronous compression.
00835 // The mjpeg object must exist in each threadframe because it is where the output
00836 // is stored.
00837                         while(threadframes.total < len)
00838                         {
00839                                 threadframes.append(threadframe = new ThreadStruct);
00840                         }
00841 
00842 // Load thread frame structures with new frames.
00843                         for(j = 0; j < len; j++)
00844                         {
00845                                 VFrame *frame = frames[i][j];
00846                                 threadframes.values[j]->input = frame;
00847                                 threadframes.values[j]->completion_lock->lock("FileMOV::write_frames 1");
00848                         }
00849                         total_threadframes = len;
00850                         current_threadframe = 0;
00851 
00852 // Start the threads compressing
00853                         for(j = 0; j < file->cpus; j++)
00854                         {
00855                                 threads[j]->encode_buffer();
00856                         }
00857 
00858 
00859 // Write the frames as they're finished
00860                         for(j = 0; j < len; j++)
00861                         {
00862                                 threadframes.values[j]->completion_lock->lock("FileMOV::write_frames 1");
00863                                 threadframes.values[j]->completion_lock->unlock();
00864                                 if(!result)
00865                                 {
00866                                         result = quicktime_write_frame(fd, 
00867                                                 threadframes.values[j]->output,
00868                                                 threadframes.values[j]->output_size,
00869                                                 i);
00870                                 }
00871                         }
00872                 }
00873 
00874                 if(default_compressor)
00875                 {
00876 //printf("FileMOV::write_frames 3\n");
00877 // Use the library's built in compressor.
00878                         for(j = 0; j < len && !result; j++)
00879                         {
00880 //printf("FileMOV::write_frames 4\n");
00881                                 VFrame *frame = frames[i][j];
00882                                 quicktime_set_cmodel(fd, frame->get_color_model());
00883 //printf("FileMOV::write_frames 5\n");
00884                                 if(cmodel_is_planar(frame->get_color_model()))
00885                                 {
00886                                         unsigned char *planes[3];
00887                                         planes[0] = frame->get_y();
00888                                         planes[1] = frame->get_u();
00889                                         planes[2] = frame->get_v();
00890                                         result = quicktime_encode_video(fd, planes, i);
00891                                 }
00892                                 else
00893                                 {
00894                                         result = quicktime_encode_video(fd, frame->get_rows(), i);
00895                                 }
00896                         }
00897                 }
00898 //printf("FileMOV::write_frames 4\n");
00899         }
00900 
00901 
00902 //printf("FileMOV::write_frames 100\n");
00903         return result;
00904 }
00905 
00906 
00907 
00908 int FileMOV::read_frame(VFrame *frame)
00909 {
00910         if(!fd) return 1;
00911         int result = 0;
00912 
00913         switch(frame->get_color_model())
00914         {
00915                 case BC_COMPRESSED:
00916                         frame->allocate_compressed_data(quicktime_frame_size(fd, file->current_frame, file->current_layer));
00917                         frame->set_compressed_size(quicktime_frame_size(fd, file->current_frame, file->current_layer));
00918                         frame->set_keyframe((quicktime_get_keyframe_before(fd, 
00919                                 file->current_frame, 
00920                                 file->current_layer) == file->current_frame));
00921 //printf("FileMOV::read_frame 1 %lld %d\n", file->current_frame, frame->get_keyframe());
00922                         result = quicktime_read_frame(fd, 
00923                                 frame->get_data(), 
00924                                 file->current_layer);
00925                         break;
00926 
00927 // Progressive
00928                 case BC_YUV420P:
00929                 case BC_YUV422P:
00930                 {
00931                         unsigned char *row_pointers[3];
00932                         row_pointers[0] = frame->get_y();
00933                         row_pointers[1] = frame->get_u();
00934                         row_pointers[2] = frame->get_v();
00935 
00936                         quicktime_set_cmodel(fd, frame->get_color_model());
00937                         quicktime_decode_video(fd, 
00938                                 row_pointers,
00939                                 file->current_layer);
00940                 }
00941                         break;
00942 
00943 // Packed
00944                 default:
00945                         quicktime_set_cmodel(fd, frame->get_color_model());
00946                         result = quicktime_decode_video(fd, 
00947                                 frame->get_rows(),
00948                                 file->current_layer);
00949 //for(int i = 0; i < 10000; i++) frame->get_rows()[0][i] = 0xff;
00950                         break;
00951         }
00952 
00953 
00954 
00955         return result;
00956 }
00957 
00958 
00959 
00960 int64_t FileMOV::compressed_frame_size()
00961 {
00962         if(!fd) return 0;
00963         return quicktime_frame_size(fd, file->current_frame, file->current_layer);
00964 }
00965 
00966 int FileMOV::read_compressed_frame(VFrame *buffer)
00967 {
00968         int64_t result;
00969         if(!fd) return 0;
00970 
00971         result = quicktime_read_frame(fd, buffer->get_data(), file->current_layer);
00972         buffer->set_compressed_size(result);
00973         buffer->set_keyframe((quicktime_get_keyframe_before(fd, 
00974                 file->current_frame, 
00975                 file->current_layer) == file->current_frame));
00976         result = !result;
00977         return result;
00978 }
00979 
00980 int FileMOV::write_compressed_frame(VFrame *buffer)
00981 {
00982         int result = 0;
00983         if(!fd) return 0;
00984 
00985         result = quicktime_write_frame(fd, 
00986                 buffer->get_data(), 
00987                 buffer->get_compressed_size(), 
00988                 file->current_layer);
00989         return result;
00990 }
00991 
00992 
00993 
00994 int FileMOV::read_raw(VFrame *frame, 
00995                 float in_x1, float in_y1, float in_x2, float in_y2,
00996                 float out_x1, float out_y1, float out_x2, float out_y2, 
00997                 int use_float, int interpolate)
00998 {
00999         int64_t i, color_channels, result = 0;
01000         if(!fd) return 0;
01001 
01002         quicktime_set_video_position(fd, file->current_frame, file->current_layer);
01003 // Develop importing strategy
01004         switch(frame->get_color_model())
01005         {
01006                 case BC_RGB888:
01007                         result = quicktime_decode_video(fd, frame->get_rows(), file->current_layer);
01008                         break;
01009                 case BC_RGBA8888:
01010                         break;
01011                 case BC_RGB161616:
01012                         break;
01013                 case BC_RGBA16161616:
01014                         break;
01015                 case BC_YUV888:
01016                         break;
01017                 case BC_YUVA8888:
01018                         break;
01019                 case BC_YUV161616:
01020                         break;
01021                 case BC_YUVA16161616:
01022                         break;
01023                 case BC_YUV420P:
01024                         break;
01025         }
01026         return result;
01027 }
01028 
01029 // Overlay samples
01030 int FileMOV::read_samples(double *buffer, int64_t len)
01031 {
01032         int qt_track, qt_channel;
01033 
01034         if(!fd) return 0;
01035 
01036         if(quicktime_track_channels(fd, 0) > file->current_channel &&
01037                 quicktime_supported_audio(fd, 0))
01038         {
01039 
01040 //printf("FileMOV::read_samples 2 %ld %ld\n", file->current_sample, quicktime_audio_position(fd, 0));
01041                 new_audio_temp(len);
01042 
01043 //printf("FileMOV::read_samples 3 %ld %ld\n", file->current_sample, quicktime_audio_position(fd, 0));
01044                 if(quicktime_decode_audio(fd, 0, temp_float[0], len, file->current_channel))
01045                 {
01046                         printf("FileMOV::read_samples: quicktime_decode_audio failed\n");
01047                         return 1;
01048                 }
01049                 else
01050                 {
01051                         for(int i = 0; i < len; i++) buffer[i] = temp_float[0][i];
01052                 }
01053 
01054 // if(file->current_channel == 0)
01055 // for(int i = 0; i < len; i++)
01056 // {
01057 //      int16_t value;
01058 //      value = (int16_t)(temp_float[0][i] * 32767);
01059 //      fwrite(&value, 2, 1, stdout);
01060 // }
01061 //printf("FileMOV::read_samples 4 %ld %ld\n", file->current_sample, quicktime_audio_position(fd, 0));
01062         }
01063 
01064         return 0;
01065 }
01066 
01067 
01068 char* FileMOV::strtocompression(char *string)
01069 {
01070         if(!strcasecmp(string, _(DIVX_NAME))) return QUICKTIME_DIVX;
01071         if(!strcasecmp(string, _(H264_NAME))) return QUICKTIME_H264;
01072         if(!strcasecmp(string, _(HV64_NAME))) return QUICKTIME_HV64;
01073         if(!strcasecmp(string, _(MP4V_NAME))) return QUICKTIME_MP4V;
01074         if(!strcasecmp(string, _(H263_NAME))) return QUICKTIME_H263;
01075         if(!strcasecmp(string, _(HV60_NAME))) return QUICKTIME_HV60;
01076         if(!strcasecmp(string, _(DIV3_NAME))) return QUICKTIME_DIV3;
01077         if(!strcasecmp(string, _(DV_NAME))) return QUICKTIME_DVSD;
01078 //      if(!strcasecmp(string, _(DV_NAME))) return QUICKTIME_DV;
01079         if(!strcasecmp(string, _(PNG_NAME))) return QUICKTIME_PNG;
01080         if(!strcasecmp(string, _(PNGA_NAME))) return MOV_PNGA;
01081         if(!strcasecmp(string, _(RGB_NAME))) return QUICKTIME_RAW;
01082         if(!strcasecmp(string, _(RGBA_NAME))) return MOV_RGBA;
01083         if(!strcasecmp(string, _(QTJPEG_NAME))) return QUICKTIME_JPEG;
01084         if(!strcasecmp(string, _(MJPA_NAME))) return QUICKTIME_MJPA;
01085         if(!strcasecmp(string, _(YUV420_NAME))) return QUICKTIME_YUV420;
01086         if(!strcasecmp(string, _(YUV411_NAME))) return QUICKTIME_YUV411;
01087         if(!strcasecmp(string, _(YUV422_NAME))) return QUICKTIME_YUV422;
01088         if(!strcasecmp(string, _(YUV444_NAME))) return QUICKTIME_YUV444;
01089         if(!strcasecmp(string, _(YUVA4444_NAME))) return QUICKTIME_YUVA4444;
01090         if(!strcasecmp(string, _(YUV444_10BIT_NAME))) return QUICKTIME_YUV444_10bit;
01091 
01092         if(!strcasecmp(string, _(TWOS_NAME))) return QUICKTIME_TWOS;
01093         if(!strcasecmp(string, _(RAW_NAME))) return QUICKTIME_RAW;
01094         if(!strcasecmp(string, _(IMA4_NAME))) return QUICKTIME_IMA4;
01095         if(!strcasecmp(string, _(ULAW_NAME))) return QUICKTIME_ULAW;
01096         if(!strcasecmp(string, _(MP3_NAME))) return QUICKTIME_MP3;
01097         if(!strcasecmp(string, _(MP4A_NAME))) return QUICKTIME_MP4A;
01098         if(!strcasecmp(string, _(VORBIS_NAME))) return QUICKTIME_VORBIS;
01099 
01100 
01101 
01102         return QUICKTIME_RAW;
01103 }
01104 
01105 char* FileMOV::compressiontostr(char *string)
01106 {
01107         if(match4(string, QUICKTIME_H263)) return _(H263_NAME);
01108         if(match4(string, QUICKTIME_H264)) return