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();
65 if (asset->use_pipe) {
66 result = stream->open_write(asset->path, asset->pipe);
69 result = stream->open_write(asset->path, NULL);
71 if (result) return result;
73 stream->set_width(asset->width);
74 stream->set_height(asset->height);
75 stream->set_frame_rate(asset->frame_rate);
76 stream->set_aspect_ratio(asset->aspect_ratio);
78 result = stream->write_header();
79 if (result) return result;
88 int FileYUV::close_file() {
89 if (pipe_latency && ffmpeg && stream) {
90 // deal with last frame still in the pipe
91 ensure_temp(incoming_asset->width,
92 incoming_asset->height);
93 if (ffmpeg->decode(NULL, 0, temp) == 0) {
95 yuv[0] = temp->get_y();
96 yuv[1] = temp->get_u();
97 yuv[2] = temp->get_v();
98 stream->write_frame(yuv);
103 if (ffmpeg) delete ffmpeg;
108 // NOTE: set_video_position() called every time a frame is read
109 int FileYUV::set_video_position(int64_t frame_number) {
110 return stream->seek_frame(frame_number);
113 int FileYUV::read_frame(VFrame *frame)
116 VFrame *input = frame;
118 // short cut for direct copy routines
119 if (frame->get_color_model() == BC_COMPRESSED) {
120 long frame_size = (long) // w*h + w*h/4 + w*h/4
121 (stream->get_height() * stream->get_width() * 1.5);
122 frame->allocate_compressed_data(frame_size);
123 frame->set_compressed_size(frame_size);
124 return stream->read_frame_raw(frame->get_data(), frame_size);
128 // process through a temp frame if necessary
129 if (! cmodel_is_planar(frame->get_color_model()) ||
130 (frame->get_w() != stream->get_width()) ||
131 (frame->get_h() != stream->get_height())) {
132 ensure_temp(stream->get_width(),
133 stream->get_height());
138 yuv[0] = input->get_y();
139 yuv[1] = input->get_u();
140 yuv[2] = input->get_v();
141 result = stream->read_frame(yuv);
142 if (result) return result;
144 // transfer from the temp frame to the real one
145 if (input != frame) {
146 FFMPEG::convert_cmodel(input, frame);
152 int FileYUV::write_frames(VFrame ***layers, int len)
156 // only one layer supported
157 VFrame **frames = layers[0];
160 for (int n = 0; n < len; n++) {
164 // short cut for direct copy routines
165 if (frame->get_color_model() == BC_COMPRESSED) {
166 long frame_size = frame->get_compressed_size();
167 if (incoming_asset->format == FILE_YUV) {
168 return stream->write_frame_raw
169 (frame->get_data(), frame_size);
172 // decode and write an encoded frame
173 if (FFMPEG::codec_id(incoming_asset->vcodec) != CODEC_ID_NONE) {
175 ffmpeg = new FFMPEG(incoming_asset);
176 ffmpeg->init(incoming_asset->vcodec);
179 ensure_temp(incoming_asset->width,
180 incoming_asset->height);
181 int result = ffmpeg->decode(frame->get_data(),
184 // some formats are decoded one frame later
185 if (result == FFMPEG_LATENCY) {
186 // remember to write the last frame
199 yuv[0] = temp->get_y();
200 yuv[1] = temp->get_u();
201 yuv[2] = temp->get_v();
202 return stream->write_frame(yuv);
207 // process through a temp frame only if necessary
208 if (! cmodel_is_planar(frame->get_color_model()) ||
209 (frame->get_w() != stream->get_width()) ||
210 (frame->get_h() != stream->get_height())) {
211 ensure_temp(asset->width, asset->height);
212 FFMPEG::convert_cmodel(frame, temp);
217 yuv[0] = frame->get_y();
218 yuv[1] = frame->get_u();
219 yuv[2] = frame->get_v();
220 result = stream->write_frame(yuv);
221 if (result) return result;
230 void FileYUV::get_parameters(BC_WindowBase *parent_window,
232 BC_WindowBase* &format_window,
236 if (! video_options) return;
238 YUVConfigVideo *config =
239 new YUVConfigVideo(parent_window, asset, format);
240 format_window = config;
241 config->create_objects();
242 if (config->run_window() == 0) {
243 // save the new path and pipe to the asset
244 strcpy(asset->path, config->path_textbox->get_text());
245 strcpy(asset->pipe, config->pipe_config->textbox->get_text());
246 // are we using the pipe (if there is one)
247 asset->use_pipe = config->pipe_config->checkbox->get_value();
248 // update the path textbox in the render window
249 format->path_textbox->update(asset->path);
250 // set the pipe status in the render window
251 format->pipe_status->set_status(asset);
252 // and add the new path and pipe to the defaults list
253 const char *prefix = FILE_FORMAT_PREFIX(asset->format);
254 config->path_recent->add_item(prefix, asset->path);
255 config->pipe_config->recent->add_item(prefix, asset->pipe);
260 int FileYUV::check_sig(Asset *asset)
263 FILE *f = fopen(asset->path, "rb");
265 // check for starting with "YUV4MPEG2"
266 fread(&temp, 9, 1, f);
268 if (strncmp(temp, "YUV4MPEG2", 9) == 0) return 1;
273 // NOTE: this is called on the write stream, not the read stream!
274 // as such, I have no idea what one is supposed to do with position.
275 int FileYUV::can_copy_from(Edit *edit, int64_t position)
276 { // NOTE: width and height already checked in file.C
278 // FUTURE: is the incoming asset already available somewhere?
279 incoming_asset = edit->asset;
281 if (edit->asset->format == FILE_YUV) return 1;
283 // if FFMPEG can decode it, we'll accept it
284 if (FFMPEG::codec_id(edit->asset->vcodec) != CODEC_ID_NONE) {
293 int FileYUV::get_best_colormodel(Asset *asset, int driver)
295 // FUTURE: is there a reason to try to accept anything else?
300 int FileYUV::colormodel_supported(int color_model)
302 // we convert internally to any color model proposed
304 // NOTE: file.C does not convert from YUV, so we have to do it.
309 Other member functions used in other file* modules:
311 write_compressed_frame(): used for record, so probably not needed
312 read_compressed_frame(): perhaps never used?
313 get_video_position: used by record only
314 reset_parameters(): not sure when used or needed
315 reset_parameters_derived(): not sure when used or needed
316 *_audio_*: yuv4mpeg doesn't handle audio
322 void FileYUV::ensure_temp(int width, int height) {
324 // make sure the temp is correct size and type
325 if (temp && (temp->get_w() != width ||
326 temp->get_h() != height ||
327 temp->get_color_model() != BC_YUV420P)) {
332 // create a correct temp frame if we don't have one
334 temp = new VFrame(0, width, height, BC_YUV420P);
339 YUVConfigVideo::YUVConfigVideo(BC_WindowBase *parent_window, Asset *asset,
341 : BC_Window(PROGRAM_NAME ": YUV4MPEG Stream",
342 parent_window->get_abs_cursor_x(1),
343 parent_window->get_abs_cursor_y(1),
347 this->parent_window = parent_window;
349 this->format = format;
350 this->defaults = format->mwindow->defaults;
353 YUVConfigVideo::~YUVConfigVideo()
362 int YUVConfigVideo::create_objects()
370 add_subwindow(new BC_Title(x, y, _("Output Path:")));
372 path_textbox = new BC_TextBox(x, y, 350, 1, asset->path);
373 add_subwindow(path_textbox);
376 path_recent = new BC_RecentList("PATH", defaults, path_textbox,
378 add_subwindow(path_recent);
379 path_recent->load_items(FILE_FORMAT_PREFIX(asset->format));
384 pipe_config = new PipeConfig(this, defaults, asset);
385 pipe_config->create_objects(x, y, 350, asset->format);
391 add_subwindow(new BC_Title(x, y, _("Presets:")));
393 mpeg2enc = new PipePreset(x, y, "mpeg2enc", pipe_config);
394 add_subwindow(mpeg2enc);
395 // NOTE: the '%' character will be replaced by the current path
396 // NOTE: to insert a real '%' double it up: '%%' -> '%'
397 // NOTE: preset items must have a '|' before the actual command
398 mpeg2enc->add_item(new BC_MenuItem ("(DVD) | mpeg2enc -f 8 -o %"));
399 mpeg2enc->add_item(new BC_MenuItem ("(VCD) | mpeg2enc -f 2 -o %"));
402 ffmpeg = new PipePreset(x, y, "ffmpeg", pipe_config);
403 add_subwindow(ffmpeg);
404 ffmpeg->add_item(new BC_MenuItem("(DVD) | ffmpeg -f yuv4mpegpipe -i - -y -target dvd %"));
405 ffmpeg->add_item(new BC_MenuItem("(VCD) | ffmpeg -f yuv4mpegpipe -i - -y -target vcd %"));
407 add_subwindow(new BC_OKButton(this));
408 add_subwindow(new BC_CancelButton(this));
413 int YUVConfigVideo::close_event()