00001 #include "fileyuv.h"
00002 #include "asset.h"
00003 #include "bchash.h"
00004 #include "edit.h"
00005 #include "file.h"
00006 #include "guicast.h"
00007 #include "guicast.h"
00008 #include "interlacemodes.h"
00009 #include "quicktime.h"
00010 #include "mainerror.h"
00011 #include "mwindow.h"
00012 #include "vframe.h"
00013
00014 #include <ctype.h>
00015 #include <errno.h>
00016 #include <fcntl.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019
00020 FileYUV::FileYUV(Asset *asset, File *file)
00021 : FileBase(asset, file)
00022 {
00023 if (asset->format == FILE_UNKNOWN) asset->format = FILE_YUV;
00024 asset->byte_order = 0;
00025 temp = 0;
00026 ffmpeg = 0;
00027 stream = new YUVStream();
00028 pipe_latency = 0;
00029 }
00030
00031 FileYUV::~FileYUV()
00032 {
00033
00034 delete stream;
00035 }
00036
00037 int FileYUV::open_file(int should_read, int should_write)
00038 {
00039 int result;
00040
00041 if (should_read)
00042 {
00043 result = stream->open_read(asset->path);
00044 if (result) return result;
00045
00046
00047 asset->video_length = stream->frame_count;
00048
00049 asset->width = stream->get_width();
00050 asset->height = stream->get_height();
00051 if (asset->width * asset->height <= 0)
00052 {
00053 eprintf("illegal frame size '%d x %d'\n", asset->width, asset->height);
00054 return 1;
00055 }
00056
00057 asset->layers = 1;
00058 asset->video_data = 1;
00059 asset->audio_data = 0;
00060
00061 asset->frame_rate = stream->get_frame_rate();
00062 asset->aspect_ratio = stream->get_aspect_ratio();
00063 asset->interlace_mode = stream->get_interlace();
00064
00065 return 0;
00066 }
00067
00068 if (should_write) {
00069 if (asset->use_pipe) {
00070 result = stream->open_write(asset->path, asset->pipe);
00071 } else {
00072 result = stream->open_write(asset->path, NULL);
00073 }
00074 if (result) return result;
00075
00076
00077 stream->set_interlace(asset->interlace_mode);
00078 stream->set_width(asset->width);
00079 stream->set_height(asset->height);
00080 stream->set_frame_rate(asset->frame_rate);
00081 stream->set_aspect_ratio(asset->aspect_ratio);
00082
00083 result = stream->write_header();
00084 if (result) return result;
00085
00086 return 0;
00087 }
00088
00089
00090 return 1;
00091 }
00092
00093 int FileYUV::close_file() {
00094 if (pipe_latency && ffmpeg && stream) {
00095
00096 ensure_temp(incoming_asset->width, incoming_asset->height);
00097 if (ffmpeg->decode(NULL, 0, temp) == 0)
00098 {
00099 uint8_t *yuv[3];
00100 yuv[0] = temp->get_y();
00101 yuv[1] = temp->get_u();
00102 yuv[2] = temp->get_v();
00103 stream->write_frame(yuv);
00104 }
00105 pipe_latency = 0;
00106 }
00107 stream->close_fd();
00108 if (ffmpeg) delete ffmpeg;
00109 ffmpeg = 0;
00110 return 0;
00111 }
00112
00113
00114 int FileYUV::set_video_position(int64_t frame_number) {
00115 return stream->seek_frame(frame_number);
00116 }
00117
00118 int FileYUV::read_frame(VFrame *frame)
00119 {
00120 int result;
00121 VFrame *input = frame;
00122
00123
00124 if (frame->get_color_model() == BC_COMPRESSED) {
00125 long frame_size = (long)
00126 (stream->get_height() * stream->get_width() * 1.5);
00127 frame->allocate_compressed_data(frame_size);
00128 frame->set_compressed_size(frame_size);
00129 return stream->read_frame_raw(frame->get_data(), frame_size);
00130 }
00131
00132
00133
00134 if (! cmodel_is_planar(frame->get_color_model()) ||
00135 (frame->get_w() != stream->get_width()) ||
00136 (frame->get_h() != stream->get_height()))
00137 {
00138 ensure_temp(stream->get_width(), stream->get_height());
00139 input = temp;
00140 }
00141
00142 uint8_t *yuv[3];
00143 yuv[0] = input->get_y();
00144 yuv[1] = input->get_u();
00145 yuv[2] = input->get_v();
00146 result = stream->read_frame(yuv);
00147 if (result) return result;
00148
00149
00150 if (input != frame)
00151 {
00152 FFMPEG::convert_cmodel(input, frame);
00153 }
00154
00155 return 0;
00156 }
00157
00158 int FileYUV::write_frames(VFrame ***layers, int len)
00159 {
00160 int result;
00161
00162
00163 VFrame **frames = layers[0];
00164 VFrame *frame;
00165
00166 for (int n = 0; n < len; n++)
00167 {
00168 frame = frames[n];
00169
00170
00171 if (frame->get_color_model() == BC_COMPRESSED)
00172 {
00173 long frame_size = frame->get_compressed_size();
00174 if (incoming_asset->format == FILE_YUV)
00175 return stream->write_frame_raw(frame->get_data(), frame_size);
00176
00177
00178 if (FFMPEG::codec_id(incoming_asset->vcodec) != CODEC_ID_NONE)
00179 {
00180 if (! ffmpeg)
00181 {
00182 ffmpeg = new FFMPEG(incoming_asset);
00183 ffmpeg->init(incoming_asset->vcodec);
00184 }
00185
00186 ensure_temp(incoming_asset->width, incoming_asset->height);
00187 int result = ffmpeg->decode(frame->get_data(), frame_size, temp);
00188
00189
00190 if (result == FFMPEG_LATENCY)
00191 {
00192
00193 pipe_latency++;
00194 return 0;
00195 }
00196
00197 if (result)
00198 {
00199 delete ffmpeg;
00200 ffmpeg = 0;
00201 return 1;
00202 }
00203
00204
00205 uint8_t *yuv[3];
00206 yuv[0] = temp->get_y();
00207 yuv[1] = temp->get_u();
00208 yuv[2] = temp->get_v();
00209 return stream->write_frame(yuv);
00210 }
00211 }
00212
00213
00214 if (! cmodel_is_planar(frame->get_color_model()) ||
00215 (frame->get_w() != stream->get_width()) ||
00216 (frame->get_h() != stream->get_height()))
00217 {
00218 ensure_temp(asset->width, asset->height);
00219 FFMPEG::convert_cmodel(frame, temp);
00220 frame = temp;
00221 }
00222
00223 uint8_t *yuv[3];
00224 yuv[0] = frame->get_y();
00225 yuv[1] = frame->get_u();
00226 yuv[2] = frame->get_v();
00227 result = stream->write_frame(yuv);
00228 if (result) return result;
00229 }
00230
00231 return 0;
00232 }
00233
00234
00235 void FileYUV::get_parameters(BC_WindowBase *parent_window,
00236 Asset *asset,
00237 BC_WindowBase* &format_window,
00238 int video_options,
00239 FormatTools *format)
00240 {
00241 if (! video_options) return;
00242
00243 YUVConfigVideo *config = new YUVConfigVideo(parent_window, asset, format);
00244 format_window = config;
00245 config->create_objects();
00246 if (config->run_window() == 0)
00247 {
00248
00249 strcpy(asset->path, config->path_textbox->get_text());
00250 strcpy(asset->pipe, config->pipe_textbox->get_text());
00251
00252 asset->use_pipe = config->pipe_checkbox->get_value();
00253
00254 format->path_textbox->update(asset->path);
00255
00256 const char *prefix = FILE_FORMAT_PREFIX(asset->format);
00257 config->path_recent->add_item(prefix, asset->path);
00258 config->pipe_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
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
00277
00278 int FileYUV::can_copy_from(Edit *edit, int64_t position)
00279 {
00280
00281
00282
00283 incoming_asset = edit->asset;
00284
00285 if (edit->asset->format == FILE_YUV) return 1;
00286
00287
00288 if (FFMPEG::codec_id(edit->asset->vcodec) != CODEC_ID_NONE) return 1;
00289
00290 incoming_asset = 0;
00291
00292 return 0;
00293 }
00294
00295 int FileYUV::get_best_colormodel(Asset *asset, int driver)
00296 {
00297
00298 return BC_YUV420P;
00299 }
00300
00301
00302 int FileYUV::colormodel_supported(int color_model)
00303 {
00304
00305 return color_model;
00306
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 void FileYUV::ensure_temp(int width, int height)
00325 {
00326
00327 if (temp && (temp->get_w() != width ||
00328 temp->get_h() != height ||
00329 temp->get_color_model() != BC_YUV420P))
00330 {
00331 delete temp;
00332 temp = 0;
00333 }
00334
00335
00336 if (temp == 0)
00337 {
00338 temp = new VFrame(0, width, height, BC_YUV420P);
00339 }
00340 }
00341
00342
00343 YUVConfigVideo::YUVConfigVideo(BC_WindowBase *parent_window, Asset *asset, 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_checkbox;
00361 delete pipe_textbox;
00362 delete pipe_recent;
00363 delete mpeg2enc;
00364 delete ffmpeg;
00365 }
00366
00367 int YUVConfigVideo::create_objects()
00368 {
00369 BC_Title *bt;
00370 int init_x = 10;
00371 int init_y = 10;
00372
00373 int x = init_x;
00374 int y = init_y;
00375
00376 add_subwindow(new BC_Title(init_x, y, _("Output Path:")));
00377 add_subwindow(path_textbox = new BC_TextBox(init_x + 100, y, 350, 1, asset->path));
00378 add_subwindow(path_recent = new BC_RecentList("PATH", defaults, path_textbox, 10, init_x + 450, y, path_textbox->get_w(), 100));
00379 path_recent->load_items(FILE_FORMAT_PREFIX(asset->format));
00380
00381 x = init_x;
00382 y += 30;
00383
00384 add_subwindow(bt = new BC_Title(init_x, y, _("Use Pipe:")));
00385 add_subwindow(pipe_checkbox = new PipeCheckBox(init_x + bt->get_w(), y, asset->use_pipe));
00386 add_subwindow(pipe_textbox = new BC_TextBox(init_x + 100, y, 350, 1, asset->pipe));
00387 add_subwindow(pipe_recent = new BC_RecentList("PIPE", defaults, pipe_textbox, 10, init_x + 450, y, pipe_textbox->get_w(), 100));
00388 pipe_recent->load_items(FILE_FORMAT_PREFIX(asset->format));
00389
00390 pipe_checkbox->textbox = pipe_textbox;
00391 if (!asset->use_pipe) pipe_textbox->disable();
00392
00393 x = init_x;
00394 y += 30;
00395 add_subwindow(new BC_Title(x, y, _("Stream Header:"), MEDIUMFONT, RED));
00396
00397 x = init_x + 20;
00398 y += 30;
00399 add_subwindow(bt = new BC_Title(x, y, _("Interlacing:")));
00400 char string[BCTEXTLEN];
00401 ilacemode_to_text(string,asset->interlace_mode);
00402 add_subwindow(new BC_Title(x + bt->get_w() + 5, y, string, MEDIUMFONT, YELLOW));
00403
00404 x = init_x;
00405 y += 30;
00406 add_subwindow(new BC_Title(x, y, _("Pipe Presets:")));
00407
00408 x += 130;
00409 add_subwindow(mpeg2enc = new PipePreset(x, y, "mpeg2enc", pipe_textbox, pipe_checkbox));
00410
00411
00412
00413 mpeg2enc->add_item(new BC_MenuItem ("(DVD) | mpeg2enc -f 8 -o %"));
00414 mpeg2enc->add_item(new BC_MenuItem ("(VCD) | mpeg2enc -f 2 -o %"));
00415
00416 x += 180;
00417 add_subwindow(ffmpeg = new PipePreset(x, y, "ffmpeg", pipe_textbox, pipe_checkbox));
00418 ffmpeg->add_item(new BC_MenuItem("(DVD) | ffmpeg -f yuv4mpegpipe -i - -y -target dvd -ilme -ildct -hq -f mpeg2video %"));
00419 ffmpeg->add_item(new BC_MenuItem("(VCD) | ffmpeg -f yuv4mpegpipe -i - -y -target vcd -hq -f mpeg2video %"));
00420
00421 add_subwindow(new BC_OKButton(this));
00422 add_subwindow(new BC_CancelButton(this));
00423 show_window();
00424 return 0;
00425 }
00426
00427 int YUVConfigVideo::close_event()
00428 {
00429 set_done(0);
00430 return 1;
00431 }
00432
00433
00434 PipeCheckBox::PipeCheckBox(int x, int y, int value)
00435 : BC_CheckBox(x, y, value)
00436 {
00437 this->textbox = 0;
00438 }
00439
00440 int PipeCheckBox::handle_event()
00441 {
00442 if (textbox)
00443 if (get_value())
00444 textbox->enable();
00445 else
00446 textbox->disable();
00447 }
00448
00449
00450 PipePreset::PipePreset(int x, int y, char *title, BC_TextBox *textbox, BC_CheckBox *checkbox)
00451 : BC_PopupMenu(x, y, 150, title)
00452 {
00453 this->pipe_textbox = textbox;
00454 this->pipe_checkbox =checkbox;
00455 this->title = title;
00456 }
00457
00458 int PipePreset::handle_event()
00459 {
00460 char *text = get_text();
00461
00462 char *pipe = strchr(text, '|');
00463
00464 if (pipe) pipe_textbox->update(pipe + 1);
00465
00466 pipe_textbox->enable();
00467 pipe_checkbox->set_value(1, 1);
00468
00469
00470 set_text(title);
00471 }