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;
00022 temp = 0;
00023 ffmpeg = 0;
00024 stream = new YUVStream();
00025 pipe_latency = 0;
00026 }
00027
00028 FileYUV::~FileYUV()
00029 {
00030
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
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
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
00088 return 1;
00089 }
00090
00091 int FileYUV::close_file() {
00092 if (pipe_latency && ffmpeg && stream) {
00093
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
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
00122 if (frame->get_color_model() == BC_COMPRESSED) {
00123 long frame_size = (long)
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
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
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
00160 VFrame **frames = layers[0];
00161 VFrame *frame;
00162
00163 for (int n = 0; n < len; n++) {
00164
00165 frame = frames[n];
00166
00167
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
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
00188 if (result == FFMPEG_LATENCY) {
00189
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
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
00247 strcpy(asset->path, config->path_textbox->get_text());
00248 strcpy(asset->pipe, config->pipe_config->textbox->get_text());
00249
00250 asset->use_pipe = config->pipe_config->checkbox->get_value();
00251
00252 format->path_textbox->update(asset->path);
00253
00254 format->pipe_status->set_status(asset);
00255
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
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 incoming_asset = edit->asset;
00283
00284 if (edit->asset->format == FILE_YUV) return 1;
00285
00286
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
00299 return BC_YUV420P;
00300 }
00301
00302
00303 int FileYUV::colormodel_supported(int color_model)
00304 {
00305
00306 return color_model;
00307
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 void FileYUV::ensure_temp(int width, int height) {
00326
00327
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
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
00399
00400
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