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

fileyuv.C

Go to the documentation of this file.
00001 #include "fileyuv.h"
00002 #include "asset.h"
00003 #include "file.h"
00004 #include "guicast.h"
00005 #include "mwindow.h"
00006 #include "defaults.h"
00007 #include "vframe.h"
00008 #include "edit.h"
00009 #include "quicktime.h"
00010 
00011 #include <ctype.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <fcntl.h>
00015 #include <errno.h>
00016 
00017 FileYUV::FileYUV(Asset *asset, File *file)
00018         : FileBase(asset, file)
00019 {
00020         if (asset->format == FILE_UNKNOWN) asset->format = FILE_YUV;
00021         asset->byte_order = 0; // FUTURE: is this always correct?
00022         temp = 0;
00023         ffmpeg = 0;
00024         stream = new YUVStream();
00025         pipe_latency = 0;
00026 }
00027 
00028 FileYUV::~FileYUV()
00029 {
00030         // NOTE: close_file() is already called
00031         delete stream;
00032 }
00033         
00034 int FileYUV::open_file(int should_read, int should_write)
00035 {
00036         int result;
00037 
00038         if (should_read) {
00039 
00040                 result = stream->open_read(asset->path);
00041                 if (result) return result;
00042 
00043                 // NOTE: no easy way to defer setting video_length
00044                 asset->video_length = stream->frame_count;
00045                 
00046                 asset->width = stream->get_width();
00047                 asset->height = stream->get_height();
00048                 if (asset->width * asset->height <= 0) {
00049                         printf("illegal frame size '%d x %d'\n", 
00050                                asset->width, asset->height);
00051                         return 1;
00052                 }
00053                 
00054                 asset->layers = 1;
00055                 asset->video_data = 1;
00056                 asset->audio_data = 0;
00057                 
00058                 asset->frame_rate = stream->get_frame_rate();
00059                 asset->aspect_ratio = stream->get_aspect_ratio();
00060                 asset->interlace_mode = stream->get_interlace();
00061                 
00062                 return 0;
00063         }
00064 
00065         if (should_write) {
00066                 if (asset->use_pipe) {
00067                         result = stream->open_write(asset->path, asset->pipe);
00068                 }
00069                 else {
00070                         result = stream->open_write(asset->path, NULL);
00071                 }
00072                 if (result) return result;
00073 
00074                 // not sure if we're supposed to send interlace info with each set of frames, (wouldn't know howto!)??
00075                 stream->set_interlace(asset->interlace_mode);
00076                 stream->set_width(asset->width);
00077                 stream->set_height(asset->height);
00078                 stream->set_frame_rate(asset->frame_rate);
00079                 stream->set_aspect_ratio(asset->aspect_ratio);
00080 
00081                 result = stream->write_header();
00082                 if (result) return result;
00083                 
00084                 return 0;
00085         }
00086         
00087         // no action given
00088         return 1;
00089 }
00090 
00091 int FileYUV::close_file() {
00092         if (pipe_latency && ffmpeg && stream) {
00093                 // deal with last frame still in the pipe
00094                 ensure_temp(incoming_asset->width,
00095                             incoming_asset->height); 
00096                 if (ffmpeg->decode(NULL, 0, temp) == 0) {
00097                         uint8_t *yuv[3];
00098                         yuv[0] = temp->get_y();
00099                         yuv[1] = temp->get_u();
00100                         yuv[2] = temp->get_v();
00101                         stream->write_frame(yuv);
00102                 }
00103                 pipe_latency = 0;
00104         }
00105         stream->close_fd();
00106         if (ffmpeg) delete ffmpeg;
00107         ffmpeg = 0;
00108         return 0;
00109 }
00110 
00111 // NOTE: set_video_position() called every time a frame is read
00112 int FileYUV::set_video_position(int64_t frame_number) {
00113         return stream->seek_frame(frame_number);
00114 }
00115 
00116 int FileYUV::read_frame(VFrame *frame)
00117 {
00118         int result;
00119         VFrame *input = frame;
00120 
00121         // short cut for direct copy routines
00122         if (frame->get_color_model() == BC_COMPRESSED) {
00123                 long frame_size = (long) // w*h + w*h/4 + w*h/4
00124                         (stream->get_height() * stream->get_width() * 1.5); 
00125                 frame->allocate_compressed_data(frame_size);
00126                 frame->set_compressed_size(frame_size);
00127                 return stream->read_frame_raw(frame->get_data(), frame_size);
00128         }
00129         
00130 
00131         // process through a temp frame if necessary
00132         if (! cmodel_is_planar(frame->get_color_model()) ||
00133             (frame->get_w() != stream->get_width()) ||
00134             (frame->get_h() != stream->get_height())) {
00135                 ensure_temp(stream->get_width(),
00136                             stream->get_height());
00137                 input = temp;
00138         }
00139 
00140         uint8_t *yuv[3];
00141         yuv[0] = input->get_y();
00142         yuv[1] = input->get_u();
00143         yuv[2] = input->get_v();
00144         result = stream->read_frame(yuv);
00145         if (result) return result;
00146 
00147         // transfer from the temp frame to the real one
00148         if (input != frame) {
00149                 FFMPEG::convert_cmodel(input, frame);
00150         }
00151         
00152         return 0;
00153 }
00154 
00155 int FileYUV::write_frames(VFrame ***layers, int len)
00156 {
00157         int result;
00158 
00159         // only one layer supported
00160         VFrame **frames = layers[0];
00161         VFrame *frame;
00162 
00163         for (int n = 0; n < len; n++) {
00164 
00165                 frame = frames[n];
00166 
00167                 // short cut for direct copy routines
00168                 if (frame->get_color_model() == BC_COMPRESSED) {
00169                         long frame_size = frame->get_compressed_size();
00170                         if (incoming_asset->format == FILE_YUV) {
00171                                 return stream->write_frame_raw
00172                                         (frame->get_data(), frame_size);
00173                         }
00174 
00175                         // decode and write an encoded frame
00176                         if (FFMPEG::codec_id(incoming_asset->vcodec) != CODEC_ID_NONE) {
00177                                 if (! ffmpeg) {
00178                                         ffmpeg = new FFMPEG(incoming_asset);
00179                                         ffmpeg->init(incoming_asset->vcodec);
00180                                 }
00181                                 
00182                                 ensure_temp(incoming_asset->width,
00183                                             incoming_asset->height); 
00184                                 int result = ffmpeg->decode(frame->get_data(),
00185                                                             frame_size, temp);
00186 
00187                                 // some formats are decoded one frame later
00188                                 if (result == FFMPEG_LATENCY) {
00189                                         // remember to write the last frame
00190                                         pipe_latency++;
00191                                         return 0;
00192                                 }
00193 
00194                                 if (result) {
00195                                         delete ffmpeg;
00196                                         ffmpeg = 0;
00197                                         return 1;
00198                                 }
00199 
00200 
00201                                 uint8_t *yuv[3];
00202                                 yuv[0] = temp->get_y();
00203                                 yuv[1] = temp->get_u();
00204                                 yuv[2] = temp->get_v();
00205                                 return stream->write_frame(yuv);
00206                         }
00207 
00208                 }
00209 
00210                 // process through a temp frame only if necessary
00211                 if (! cmodel_is_planar(frame->get_color_model()) ||
00212                     (frame->get_w() != stream->get_width()) ||
00213                     (frame->get_h() != stream->get_height())) {
00214                         ensure_temp(asset->width, asset->height);
00215                         FFMPEG::convert_cmodel(frame, temp);
00216                         frame = temp;
00217                 }
00218 
00219                 uint8_t *yuv[3];
00220                 yuv[0] = frame->get_y();
00221                 yuv[1] = frame->get_u();
00222                 yuv[2] = frame->get_v();
00223                 result = stream->write_frame(yuv);
00224                 if (result) return result;
00225 
00226 
00227         }
00228 
00229         return 0;
00230 }
00231 
00232 
00233 void FileYUV::get_parameters(BC_WindowBase *parent_window, 
00234                              Asset *asset, 
00235                              BC_WindowBase* &format_window,
00236                              int video_options,
00237                              FormatTools *format)
00238 {
00239         if (! video_options) return;
00240 
00241         YUVConfigVideo *config =  
00242                 new YUVConfigVideo(parent_window, asset, format);
00243         format_window = config;
00244         config->create_objects();
00245         if (config->run_window() == 0) {
00246                 // save the new path and pipe to the asset
00247                 strcpy(asset->path, config->path_textbox->get_text());
00248                 strcpy(asset->pipe, config->pipe_config->textbox->get_text());
00249                 // are we using the pipe (if there is one)
00250                 asset->use_pipe = config->pipe_config->checkbox->get_value();
00251                 // update the path textbox in the render window
00252                 format->path_textbox->update(asset->path);
00253                 // set the pipe status in the render window
00254                 format->pipe_status->set_status(asset);
00255                 // and add the new path and pipe to the defaults list
00256                 const char *prefix = FILE_FORMAT_PREFIX(asset->format);
00257                 config->path_recent->add_item(prefix, asset->path);
00258                 config->pipe_config->recent->add_item(prefix, asset->pipe);
00259         }
00260         delete config;
00261 }
00262 
00263 int FileYUV::check_sig(Asset *asset)
00264 {
00265         char temp[9];
00266         FILE *f = fopen(asset->path, "rb");
00267 
00268         // check for starting with "YUV4MPEG2"
00269         fread(&temp, 9, 1, f);
00270         fclose(f);
00271         if (strncmp(temp, "YUV4MPEG2", 9) == 0) return 1;
00272 
00273         return 0;
00274 }
00275 
00276 // NOTE: this is called on the write stream, not the read stream!
00277 //       as such, I have no idea what one is supposed to do with position.
00278 int FileYUV::can_copy_from(Edit *edit, int64_t position)
00279 {       // NOTE: width and height already checked in file.C
00280 
00281         // FUTURE: is the incoming asset already available somewhere?
00282         incoming_asset = edit->asset;
00283 
00284         if (edit->asset->format == FILE_YUV) return 1;
00285 
00286         // if FFMPEG can decode it, we'll accept it
00287         if (FFMPEG::codec_id(edit->asset->vcodec) != CODEC_ID_NONE) {
00288                 return 1;
00289         }
00290 
00291         incoming_asset = 0;
00292 
00293         return 0;
00294 }
00295 
00296 int FileYUV::get_best_colormodel(Asset *asset, int driver) 
00297 {
00298         // FUTURE: is there a reason to try to accept anything else?  
00299         return BC_YUV420P;
00300 }
00301 
00302 
00303 int FileYUV::colormodel_supported(int color_model) 
00304 {
00305         // we convert internally to any color model proposed
00306         return color_model;
00307         // NOTE: file.C does not convert from YUV, so we have to do it.  
00308 }
00309 
00310 
00311 /*  
00312     Other member functions used in other file* modules:
00313 
00314     write_compressed_frame(): used for record, so probably not needed
00315     read_compressed_frame(): perhaps never used?
00316     get_video_position: used by record only
00317     reset_parameters(): not sure when used or needed
00318     reset_parameters_derived(): not sure when used or needed
00319     *_audio_*: yuv4mpeg doesn't handle audio
00320     
00321 */
00322         
00323 
00324 
00325 void FileYUV::ensure_temp(int width, int height) {
00326         
00327         // make sure the temp is correct size and type
00328         if (temp && (temp->get_w() != width ||
00329                      temp->get_h() != height ||
00330                      temp->get_color_model() != BC_YUV420P)) {
00331                 delete temp;
00332                 temp = 0;
00333         }
00334         
00335         // create a correct temp frame if we don't have one
00336         if (temp == 0) {
00337                 temp = new VFrame(0, width, height, BC_YUV420P);
00338         }
00339 }
00340 
00341 
00342 YUVConfigVideo::YUVConfigVideo(BC_WindowBase *parent_window, Asset *asset, 
00343                                FormatTools *format)
00344         : BC_Window(PROGRAM_NAME ": YUV4MPEG Stream",
00345                     parent_window->get_abs_cursor_x(1),
00346                     parent_window->get_abs_cursor_y(1),
00347                     500,
00348                     240)
00349 {
00350         this->parent_window = parent_window;
00351         this->asset = asset;
00352         this->format = format;
00353         this->defaults = format->mwindow->defaults;
00354 }
00355 
00356 YUVConfigVideo::~YUVConfigVideo()
00357 {
00358         delete path_textbox;
00359         delete path_recent;
00360         delete pipe_config;
00361         delete mpeg2enc;
00362         delete ffmpeg;
00363 }
00364 
00365 int YUVConfigVideo::create_objects()
00366 {
00367         int init_x = 10;
00368         int init_y = 10;
00369         
00370         int x = init_x;
00371         int y = init_y;
00372 
00373         add_subwindow(new BC_Title(x, y, _("Output Path:")));
00374         x += 120;
00375         path_textbox = new BC_TextBox(x, y, 350, 1, asset->path);
00376         add_subwindow(path_textbox);
00377 
00378         x += 350;
00379         path_recent = new BC_RecentList("PATH", defaults, path_textbox, 
00380                                         10, x, y, 350, 100);
00381         add_subwindow(path_recent);
00382         path_recent->load_items(FILE_FORMAT_PREFIX(asset->format));
00383 
00384         x = init_x;
00385         y += 30;
00386 
00387         pipe_config = new PipeConfig(this, defaults, asset);
00388         pipe_config->create_objects(x, y, 350, asset->format);
00389         
00390 
00391         x = init_x;
00392         y += 120;
00393 
00394         add_subwindow(new BC_Title(x, y, _("Pipe Presets:")));
00395         x += 130;
00396         mpeg2enc = new PipePreset(x, y, "mpeg2enc", pipe_config);
00397         add_subwindow(mpeg2enc);
00398         // NOTE: the '%' character will be replaced by the current path
00399         // NOTE: to insert a real '%' double it up: '%%' -> '%'
00400         // NOTE: preset items must have a '|' before the actual command
00401         mpeg2enc->add_item(new BC_MenuItem ("(DVD) | mpeg2enc -f 8 -o %"));
00402         mpeg2enc->add_item(new BC_MenuItem ("(VCD) | mpeg2enc -f 2 -o %"));
00403 
00404         x += 160;
00405         ffmpeg = new PipePreset(x, y, "ffmpeg", pipe_config);
00406         add_subwindow(ffmpeg);
00407         ffmpeg->add_item(new BC_MenuItem("(DVD) | ffmpeg -f yuv4mpegpipe -i - -y -target dvd -ilme -ildct -hq -f mpeg2video %"));
00408         ffmpeg->add_item(new BC_MenuItem("(VCD) | ffmpeg -f yuv4mpegpipe -i - -y -target vcd -hq -f mpeg2video %"));
00409 
00410         add_subwindow(new BC_OKButton(this));
00411         add_subwindow(new BC_CancelButton(this));
00412         show_window();
00413         return 0;
00414 }
00415 
00416 int YUVConfigVideo::close_event()
00417 {
00418         set_done(0);
00419         return 1;
00420 }
00421 
00422 
00423 

Generated on Sun Jan 8 13:38:55 2006 for Cinelerra-svn by  doxygen 1.4.4