10 #include "mainerror.h"
18 FileYUV::FileYUV(Asset *asset, File *file)
19 : FileBase(asset, file)
21 if (asset->format == FILE_UNKNOWN) asset->format = FILE_YUV;
22 asset->byte_order = 0; // FUTURE: is this always correct?
25 stream = new YUVStream();
31 // NOTE: close_file() is already called
35 int FileYUV::open_file(int should_read, int should_write)
41 result = stream->open_read(asset->path);
42 if (result) return result;
44 // NOTE: no easy way to defer setting video_length
45 asset->video_length = stream->frame_count;
47 asset->width = stream->get_width();
48 asset->height = stream->get_height();
49 if (asset->width * asset->height <= 0) {
50 eprintf("illegal frame size '%d x %d'\n",
51 asset->width, asset->height);
56 asset->video_data = 1;
57 asset->audio_data = 0;
59 asset->frame_rate = stream->get_frame_rate();
60 asset->aspect_ratio = stream->get_aspect_ratio();
61 asset->interlace_mode = stream->get_interlace();
67 if (asset->use_pipe) {
68 result = stream->open_write(asset->path, asset->pipe);
71 result = stream->open_write(asset->path, NULL);
73 if (result) return result;
75 // not sure if we're supposed to send interlace info with each set of frames, (wouldn't know howto!)??
76 stream->set_interlace(asset->interlace_mode);
77 stream->set_width(asset->width);
78 stream->set_height(asset->height);
79 stream->set_frame_rate(asset->frame_rate);
80 stream->set_aspect_ratio(asset->aspect_ratio);
82 result = stream->write_header();
83 if (result) return result;
92 int FileYUV::close_file() {
93 if (pipe_latency && ffmpeg && stream) {
94 // deal with last frame still in the pipe
95 ensure_temp(incoming_asset->width,
96 incoming_asset->height);
97 if (ffmpeg->decode(NULL, 0, temp) == 0) {
99 yuv[0] = temp->get_y();
100 yuv[1] = temp->get_u();
101 yuv[2] = temp->get_v();
102 stream->write_frame(yuv);
107 if (ffmpeg) delete ffmpeg;
112 // NOTE: set_video_position() called every time a frame is read
113 int FileYUV::set_video_position(int64_t frame_number) {
114 return stream->seek_frame(frame_number);
117 int FileYUV::read_frame(VFrame *frame)
120 VFrame *input = frame;
122 // short cut for direct copy routines
123 if (frame->get_color_model() == BC_COMPRESSED) {
124 long frame_size = (long) // w*h + w*h/4 + w*h/4
125 (stream->get_height() * stream->get_width() * 1.5);
126 frame->allocate_compressed_data(frame_size);
127 frame->set_compressed_size(frame_size);
128 return stream->read_frame_raw(frame->get_data(), frame_size);
132 // process through a temp frame if necessary
133 if (! cmodel_is_planar(frame->get_color_model()) ||
134 (frame->get_w() != stream->get_width()) ||
135 (frame->get_h() != stream->get_height())) {
136 ensure_temp(stream->get_width(),
137 stream->get_height());
142 yuv[0] = input->get_y();
143 yuv[1] = input->get_u();
144 yuv[2] = input->get_v();
145 result = stream->read_frame(yuv);
146 if (result) return result;
148 // transfer from the temp frame to the real one
149 if (input != frame) {
150 FFMPEG::convert_cmodel(input, frame);
156 int FileYUV::write_frames(VFrame ***layers, int len)
160 // only one layer supported
161 VFrame **frames = layers[0];
164 for (int n = 0; n < len; n++) {
168 // short cut for direct copy routines
169 if (frame->get_color_model() == BC_COMPRESSED) {
170 long frame_size = frame->get_compressed_size();
171 if (incoming_asset->format == FILE_YUV) {
172 return stream->write_frame_raw
173 (frame->get_data(), frame_size);
176 // decode and write an encoded frame
177 if (FFMPEG::codec_id(incoming_asset->vcodec) != CODEC_ID_NONE) {
179 ffmpeg = new FFMPEG(incoming_asset);
180 ffmpeg->init(incoming_asset->vcodec);
183 ensure_temp(incoming_asset->width,
184 incoming_asset->height);
185 int result = ffmpeg->decode(frame->get_data(),
188 // some formats are decoded one frame later
189 if (result == FFMPEG_LATENCY) {
190 // remember to write the last frame
203 yuv[0] = temp->get_y();
204 yuv[1] = temp->get_u();
205 yuv[2] = temp->get_v();
206 return stream->write_frame(yuv);
211 // process through a temp frame only if necessary
212 if (! cmodel_is_planar(frame->get_color_model()) ||
213 (frame->get_w() != stream->get_width()) ||
214 (frame->get_h() != stream->get_height())) {
215 ensure_temp(asset->width, asset->height);
216 FFMPEG::convert_cmodel(frame, temp);
221 yuv[0] = frame->get_y();
222 yuv[1] = frame->get_u();
223 yuv[2] = frame->get_v();
224 result = stream->write_frame(yuv);
225 if (result) return result;
234 void FileYUV::get_parameters(BC_WindowBase *parent_window,
236 BC_WindowBase* &format_window,
240 if (! video_options) return;
242 YUVConfigVideo *config =
243 new YUVConfigVideo(parent_window, asset, format);
244 format_window = config;
245 config->create_objects();
246 if (config->run_window() == 0) {
247 // save the new path and pipe to the asset
248 strcpy(asset->path, config->path_textbox->get_text());
249 strcpy(asset->pipe, config->pipe_config->textbox->get_text());
250 // are we using the pipe (if there is one)
251 asset->use_pipe = config->pipe_config->checkbox->get_value();
252 // update the path textbox in the render window
253 format->path_textbox->update(asset->path);
254 // set the pipe status in the render window
255 format->pipe_status->set_status(asset);
256 // and add the new path and pipe to the defaults list
257 const char *prefix = FILE_FORMAT_PREFIX(asset->format);
258 config->path_recent->add_item(prefix, asset->path);
259 config->pipe_config->recent->add_item(prefix, asset->pipe);
264 int FileYUV::check_sig(Asset *asset)
267 FILE *f = fopen(asset->path, "rb");
269 // check for starting with "YUV4MPEG2"
270 fread(&temp, 9, 1, f);
272 if (strncmp(temp, "YUV4MPEG2", 9) == 0) return 1;
277 // NOTE: this is called on the write stream, not the read stream!
278 // as such, I have no idea what one is supposed to do with position.
279 int FileYUV::can_copy_from(Edit *edit, int64_t position)
280 { // NOTE: width and height already checked in file.C
282 // FUTURE: is the incoming asset already available somewhere?
283 incoming_asset = edit->asset;
285 if (edit->asset->format == FILE_YUV) return 1;
287 // if FFMPEG can decode it, we'll accept it
288 if (FFMPEG::codec_id(edit->asset->vcodec) != CODEC_ID_NONE) {
297 int FileYUV::get_best_colormodel(Asset *asset, int driver)
299 // FUTURE: is there a reason to try to accept anything else?
304 int FileYUV::colormodel_supported(int color_model)
306 // we convert internally to any color model proposed
308 // NOTE: file.C does not convert from YUV, so we have to do it.
313 Other member functions used in other file* modules:
315 write_compressed_frame(): used for record, so probably not needed
316 read_compressed_frame(): perhaps never used?
317 get_video_position: used by record only
318 reset_parameters(): not sure when used or needed
319 reset_parameters_derived(): not sure when used or needed
320 *_audio_*: yuv4mpeg doesn't handle audio
326 void FileYUV::ensure_temp(int width, int height) {
328 // make sure the temp is correct size and type
329 if (temp && (temp->get_w() != width ||
330 temp->get_h() != height ||
331 temp->get_color_model() != BC_YUV420P)) {
336 // create a correct temp frame if we don't have one
338 temp = new VFrame(0, width, height, BC_YUV420P);
343 YUVConfigVideo::YUVConfigVideo(BC_WindowBase *parent_window, Asset *asset,
345 : BC_Window(PROGRAM_NAME ": YUV4MPEG Stream",
346 parent_window->get_abs_cursor_x(1),
347 parent_window->get_abs_cursor_y(1),
351 this->parent_window = parent_window;
353 this->format = format;
354 this->defaults = format->mwindow->defaults;
357 YUVConfigVideo::~YUVConfigVideo()
366 int YUVConfigVideo::create_objects()
374 add_subwindow(new BC_Title(x, y, _("Output Path:")));
376 path_textbox = new BC_TextBox(x, y, 350, 1, asset->path);
377 add_subwindow(path_textbox);
380 path_recent = new BC_RecentList("PATH", defaults, path_textbox,
382 add_subwindow(path_recent);
383 path_recent->load_items(FILE_FORMAT_PREFIX(asset->format));
388 pipe_config = new PipeConfig(this, defaults, asset);
389 pipe_config->create_objects(x, y, 350, asset->format);
395 add_subwindow(new BC_Title(x, y, _("Pipe Presets:")));
397 mpeg2enc = new PipePreset(x, y, "mpeg2enc", pipe_config);
398 add_subwindow(mpeg2enc);
399 // NOTE: the '%' character will be replaced by the current path
400 // NOTE: to insert a real '%' double it up: '%%' -> '%'
401 // NOTE: preset items must have a '|' before the actual command
402 mpeg2enc->add_item(new BC_MenuItem ("(DVD) | mpeg2enc -f 8 -o %"));
403 mpeg2enc->add_item(new BC_MenuItem ("(VCD) | mpeg2enc -f 2 -o %"));
406 ffmpeg = new PipePreset(x, y, "ffmpeg", pipe_config);
407 add_subwindow(ffmpeg);
408 ffmpeg->add_item(new BC_MenuItem("(DVD) | ffmpeg -f yuv4mpegpipe -i - -y -target dvd -ilme -ildct -hq -f mpeg2video %"));
409 ffmpeg->add_item(new BC_MenuItem("(VCD) | ffmpeg -f yuv4mpegpipe -i - -y -target vcd -hq -f mpeg2video %"));
411 add_subwindow(new BC_OKButton(this));
412 add_subwindow(new BC_CancelButton(this));
417 int YUVConfigVideo::close_event()