17 FileYUV::FileYUV(Asset *asset, File *file)
18 : FileBase(asset, file)
20 if (asset->format == FILE_UNKNOWN) asset->format = FILE_YUV;
21 asset->byte_order = 0; // FUTURE: is this always correct?
24 stream = new YUVStream();
30 // NOTE: close_file() is already called
34 int FileYUV::open_file(int should_read, int should_write)
40 result = stream->open_read(asset->path);
41 if (result) return result;
43 // NOTE: no easy way to defer setting video_length
44 asset->video_length = stream->frame_count;
46 asset->width = stream->get_width();
47 asset->height = stream->get_height();
48 if (asset->width * asset->height <= 0) {
49 printf("illegal frame size '%d x %d'\n",
50 asset->width, asset->height);
55 asset->video_data = 1;
56 asset->audio_data = 0;
58 asset->frame_rate = stream->get_frame_rate();
59 asset->aspect_ratio = stream->get_aspect_ratio();
60 asset->interlace_mode = stream->get_interlace();
66 if (asset->use_pipe) {
67 result = stream->open_write(asset->path, asset->pipe);
70 result = stream->open_write(asset->path, NULL);
72 if (result) return result;
74 // not sure if we're supposed to send interlace info with each set of frames, (wouldn't know howto!)??
75 stream->set_interlace(asset->interlace_mode);
76 stream->set_width(asset->width);
77 stream->set_height(asset->height);
78 stream->set_frame_rate(asset->frame_rate);
79 stream->set_aspect_ratio(asset->aspect_ratio);
81 result = stream->write_header();
82 if (result) return result;
91 int FileYUV::close_file() {
92 if (pipe_latency && ffmpeg && stream) {
93 // deal with last frame still in the pipe
94 ensure_temp(incoming_asset->width,
95 incoming_asset->height);
96 if (ffmpeg->decode(NULL, 0, temp) == 0) {
98 yuv[0] = temp->get_y();
99 yuv[1] = temp->get_u();
100 yuv[2] = temp->get_v();
101 stream->write_frame(yuv);
106 if (ffmpeg) delete ffmpeg;
111 // NOTE: set_video_position() called every time a frame is read
112 int FileYUV::set_video_position(int64_t frame_number) {
113 return stream->seek_frame(frame_number);
116 int FileYUV::read_frame(VFrame *frame)
119 VFrame *input = frame;
121 // short cut for direct copy routines
122 if (frame->get_color_model() == BC_COMPRESSED) {
123 long frame_size = (long) // w*h + w*h/4 + w*h/4
124 (stream->get_height() * stream->get_width() * 1.5);
125 frame->allocate_compressed_data(frame_size);
126 frame->set_compressed_size(frame_size);
127 return stream->read_frame_raw(frame->get_data(), frame_size);
131 // process through a temp frame if necessary
132 if (! cmodel_is_planar(frame->get_color_model()) ||
133 (frame->get_w() != stream->get_width()) ||
134 (frame->get_h() != stream->get_height())) {
135 ensure_temp(stream->get_width(),
136 stream->get_height());
141 yuv[0] = input->get_y();
142 yuv[1] = input->get_u();
143 yuv[2] = input->get_v();
144 result = stream->read_frame(yuv);
145 if (result) return result;
147 // transfer from the temp frame to the real one
148 if (input != frame) {
149 FFMPEG::convert_cmodel(input, frame);
155 int FileYUV::write_frames(VFrame ***layers, int len)
159 // only one layer supported
160 VFrame **frames = layers[0];
163 for (int n = 0; n < len; n++) {
167 // short cut for direct copy routines
168 if (frame->get_color_model() == BC_COMPRESSED) {
169 long frame_size = frame->get_compressed_size();
170 if (incoming_asset->format == FILE_YUV) {
171 return stream->write_frame_raw
172 (frame->get_data(), frame_size);
175 // decode and write an encoded frame
176 if (FFMPEG::codec_id(incoming_asset->vcodec) != CODEC_ID_NONE) {
178 ffmpeg = new FFMPEG(incoming_asset);
179 ffmpeg->init(incoming_asset->vcodec);
182 ensure_temp(incoming_asset->width,
183 incoming_asset->height);
184 int result = ffmpeg->decode(frame->get_data(),
187 // some formats are decoded one frame later
188 if (result == FFMPEG_LATENCY) {
189 // remember to write the last frame
202 yuv[0] = temp->get_y();
203 yuv[1] = temp->get_u();
204 yuv[2] = temp->get_v();
205 return stream->write_frame(yuv);
210 // process through a temp frame only if necessary
211 if (! cmodel_is_planar(frame->get_color_model()) ||
212 (frame->get_w() != stream->get_width()) ||
213 (frame->get_h() != stream->get_height())) {
214 ensure_temp(asset->width, asset->height);
215 FFMPEG::convert_cmodel(frame, temp);
220 yuv[0] = frame->get_y();
221 yuv[1] = frame->get_u();
222 yuv[2] = frame->get_v();
223 result = stream->write_frame(yuv);
224 if (result) return result;
233 void FileYUV::get_parameters(BC_WindowBase *parent_window,
235 BC_WindowBase* &format_window,
239 if (! video_options) return;
241 YUVConfigVideo *config =
242 new YUVConfigVideo(parent_window, asset, format);
243 format_window = config;
244 config->create_objects();
245 if (config->run_window() == 0) {
246 // save the new path and pipe to the asset
247 strcpy(asset->path, config->path_textbox->get_text());
248 strcpy(asset->pipe, config->pipe_config->textbox->get_text());
249 // are we using the pipe (if there is one)
250 asset->use_pipe = config->pipe_config->checkbox->get_value();
251 // update the path textbox in the render window
252 format->path_textbox->update(asset->path);
253 // set the pipe status in the render window
254 format->pipe_status->set_status(asset);
255 // and add the new path and pipe to the defaults list
256 const char *prefix = FILE_FORMAT_PREFIX(asset->format);
257 config->path_recent->add_item(prefix, asset->path);
258 config->pipe_config->recent->add_item(prefix, asset->pipe);
263 int FileYUV::check_sig(Asset *asset)
266 FILE *f = fopen(asset->path, "rb");
268 // check for starting with "YUV4MPEG2"
269 fread(&temp, 9, 1, f);
271 if (strncmp(temp, "YUV4MPEG2", 9) == 0) return 1;
276 // NOTE: this is called on the write stream, not the read stream!
277 // as such, I have no idea what one is supposed to do with position.
278 int FileYUV::can_copy_from(Edit *edit, int64_t position)
279 { // NOTE: width and height already checked in file.C
281 // FUTURE: is the incoming asset already available somewhere?
282 incoming_asset = edit->asset;
284 if (edit->asset->format == FILE_YUV) return 1;
286 // if FFMPEG can decode it, we'll accept it
287 if (FFMPEG::codec_id(edit->asset->vcodec) != CODEC_ID_NONE) {
296 int FileYUV::get_best_colormodel(Asset *asset, int driver)
298 // FUTURE: is there a reason to try to accept anything else?
303 int FileYUV::colormodel_supported(int color_model)
305 // we convert internally to any color model proposed
307 // NOTE: file.C does not convert from YUV, so we have to do it.
312 Other member functions used in other file* modules:
314 write_compressed_frame(): used for record, so probably not needed
315 read_compressed_frame(): perhaps never used?
316 get_video_position: used by record only
317 reset_parameters(): not sure when used or needed
318 reset_parameters_derived(): not sure when used or needed
319 *_audio_*: yuv4mpeg doesn't handle audio
325 void FileYUV::ensure_temp(int width, int height) {
327 // make sure the temp is correct size and type
328 if (temp && (temp->get_w() != width ||
329 temp->get_h() != height ||
330 temp->get_color_model() != BC_YUV420P)) {
335 // create a correct temp frame if we don't have one
337 temp = new VFrame(0, width, height, BC_YUV420P);
342 YUVConfigVideo::YUVConfigVideo(BC_WindowBase *parent_window, Asset *asset,
344 : BC_Window(PROGRAM_NAME ": YUV4MPEG Stream",
345 parent_window->get_abs_cursor_x(1),
346 parent_window->get_abs_cursor_y(1),
350 this->parent_window = parent_window;
352 this->format = format;
353 this->defaults = format->mwindow->defaults;
356 YUVConfigVideo::~YUVConfigVideo()
365 int YUVConfigVideo::create_objects()
373 add_subwindow(new BC_Title(x, y, _("Output Path:")));
375 path_textbox = new BC_TextBox(x, y, 350, 1, asset->path);
376 add_subwindow(path_textbox);
379 path_recent = new BC_RecentList("PATH", defaults, path_textbox,
381 add_subwindow(path_recent);
382 path_recent->load_items(FILE_FORMAT_PREFIX(asset->format));
387 pipe_config = new PipeConfig(this, defaults, asset);
388 pipe_config->create_objects(x, y, 350, asset->format);
394 add_subwindow(new BC_Title(x, y, _("Pipe Presets:")));
396 mpeg2enc = new PipePreset(x, y, "mpeg2enc", pipe_config);
397 add_subwindow(mpeg2enc);
398 // NOTE: the '%' character will be replaced by the current path
399 // NOTE: to insert a real '%' double it up: '%%' -> '%'
400 // NOTE: preset items must have a '|' before the actual command
401 mpeg2enc->add_item(new BC_MenuItem ("(DVD) | mpeg2enc -f 8 -o %"));
402 mpeg2enc->add_item(new BC_MenuItem ("(VCD) | mpeg2enc -f 2 -o %"));
405 ffmpeg = new PipePreset(x, y, "ffmpeg", pipe_config);
406 add_subwindow(ffmpeg);
407 ffmpeg->add_item(new BC_MenuItem("(DVD) | ffmpeg -f yuv4mpegpipe -i - -y -target dvd -ilme -ildct -hq -f mpeg2video %"));
408 ffmpeg->add_item(new BC_MenuItem("(VCD) | ffmpeg -f yuv4mpegpipe -i - -y -target vcd -hq -f mpeg2video %"));
410 add_subwindow(new BC_OKButton(this));
411 add_subwindow(new BC_CancelButton(this));
416 int YUVConfigVideo::close_event()