3 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
4 * Copyright (C) 2010 Monty Montgomery
5 * Copyright (C) 2012-2014 Paolo Rampino
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 // work around for __STDC_CONSTANT_MACROS
32 #include "bcwindowbase.h"
33 #include "bitspopup.h"
39 #include "fileffmpeg.h"
40 #include "filesystem.h"
41 #include "indexfile.h"
42 #include "interlacemodes.h"
44 #include "mainerror.h"
45 #include "mainprogress.h"
47 #include "preferences.h"
48 #include "videodevice.inc"
54 FileFFMPEG::FileFFMPEG(Asset *asset, File *file)
55 : FileBase(asset, file)
58 if(asset->format == FILE_UNKNOWN)
59 asset->format = FILE_FFMPEG;
62 FileFFMPEG::~FileFFMPEG()
68 FFMpegConfigNum::FFMpegConfigNum(BC_Window *window,
69 int x, int y, char *title_text, int *output)
70 : BC_TumbleTextBox(window, *output, -1, INT_MAX, xS(100), y, xS(100))
72 this->window = window;
73 this->x = x; this->y = y;
74 this->title_text = title_text;
75 this->output = output;
78 FFMpegConfigNum::~FFMpegConfigNum()
82 void FFMpegConfigNum::create_objects()
84 window->add_subwindow(title = new BC_Title(x, y, title_text));
85 BC_TumbleTextBox::create_objects();
88 int FFMpegConfigNum::update_param(const char *param, const char *opts)
91 if( !FFMPEG::get_ff_option(param, opts, value) ) {
92 if( (*output = atoi(value)) < 0 ) {
97 BC_TumbleTextBox::update((int64_t)*output);
102 int FFMpegConfigNum::handle_event()
104 *output = atoi(get_text());
108 FFMpegAudioNum::FFMpegAudioNum(BC_Window *window,
109 int x, int y, char *title_text, int *output)
110 : FFMpegConfigNum(window, x, y, title_text, output)
114 int FFMpegAudioBitrate::handle_event()
116 int ret = FFMpegAudioNum::handle_event();
117 Asset *asset = window()->asset;
118 if( asset->ff_audio_bitrate > 0 )
119 window()->quality->disable();
120 else if( !window()->quality->get_textbox()->is_hidden() )
121 window()->quality->enable();
125 int FFMpegAudioQuality::handle_event()
127 int ret = FFMpegAudioNum::handle_event();
128 Asset *asset = window()->asset;
129 if( asset->ff_audio_quality >= 0 )
130 window()->bitrate->disable();
131 else if( !window()->bitrate->get_textbox()->is_hidden() )
132 window()->bitrate->enable();
136 FFMpegVideoNum::FFMpegVideoNum(BC_Window *window,
137 int x, int y, char *title_text, int *output)
138 : FFMpegConfigNum(window, x, y, title_text, output)
142 int FFMpegVideoBitrate::handle_event()
144 int ret = FFMpegVideoNum::handle_event();
145 Asset *asset = window()->asset;
146 if( asset->ff_video_bitrate > 0 )
147 window()->quality->disable();
148 else if( !window()->quality->get_textbox()->is_hidden() )
149 window()->quality->enable();
153 int FFMpegVideoQuality::handle_event()
155 int ret = FFMpegVideoNum::handle_event();
156 Asset *asset = window()->asset;
157 if( asset->ff_video_quality >= 0 )
158 window()->bitrate->disable();
159 else if( !window()->bitrate->get_textbox()->is_hidden() )
160 window()->bitrate->enable();
164 FFMpegPixelFormat::FFMpegPixelFormat(FFMPEGConfigVideo *vid_config,
165 int x, int y, int w, int list_h)
166 : BC_PopupTextBox(vid_config, 0, 0, x, y, w, list_h)
168 this->vid_config = vid_config;
171 int FFMpegPixelFormat::handle_event()
173 strncpy(vid_config->asset->ff_pixel_format, get_text(),
174 sizeof(vid_config->asset->ff_pixel_format));
178 void FFMpegPixelFormat::update_formats()
180 pixfmts.remove_all_objects();
181 char video_codec[BCSTRLEN]; video_codec[0] = 0;
182 const char *vcodec = vid_config->asset->vcodec;
183 const AVCodec *av_codec = !FFMPEG::get_codec(video_codec, "video", vcodec) ?
184 avcodec_find_encoder_by_name(video_codec) : 0;
185 const AVPixelFormat *pix_fmts = av_codec ? av_codec->pix_fmts : 0;
187 for( int i=0; pix_fmts[i]>=0; ++i ) {
188 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmts[i]);
189 if( desc ) pixfmts.append(new BC_ListBoxItem(desc->name));
192 update_list(&pixfmts);
195 FFMpegSampleFormat::FFMpegSampleFormat(FFMPEGConfigAudio *aud_config,
196 int x, int y, int w, int list_h)
197 : BC_PopupTextBox(aud_config, 0, 0, x, y, w, list_h)
199 this->aud_config = aud_config;
202 int FFMpegSampleFormat::handle_event()
204 strncpy(aud_config->asset->ff_sample_format, get_text(),
205 sizeof(aud_config->asset->ff_sample_format));
209 void FFMpegSampleFormat::update_formats()
211 samplefmts.remove_all_objects();
212 char audio_codec[BCSTRLEN]; audio_codec[0] = 0;
213 const char *acodec = aud_config->asset->acodec;
214 const AVCodec *av_codec = !FFMPEG::get_codec(audio_codec, "audio", acodec) ?
215 avcodec_find_encoder_by_name(audio_codec) : 0;
216 const AVSampleFormat *sample_fmts = av_codec ? av_codec->sample_fmts : 0;
218 for( int i=0; sample_fmts[i]>=0; ++i ) {
219 const char *name = av_get_sample_fmt_name(sample_fmts[i]);
220 if( name ) samplefmts.append(new BC_ListBoxItem(name));
223 update_list(&samplefmts);
226 void FileFFMPEG::set_options(char *cp, int len, const char *bp)
228 char *ep = cp + len-2, ch = 0;
229 while( cp < ep && *bp != 0 ) { ch = *bp++; *cp++ = ch; }
230 if( ch != '\n' ) *cp++ = '\n';
234 void FileFFMPEG::get_parameters(BC_WindowBase *parent_window,
235 Asset *asset, BC_WindowBase *&format_window,
236 int audio_options, int video_options, EDL *edl)
238 Asset *ff_asset = new Asset();
239 ff_asset->copy_from(asset, 0);
241 parent_window->get_pop_cursor(wx, wy);
242 if( audio_options ) {
243 FFMPEGConfigAudio *window = new FFMPEGConfigAudio(parent_window,
244 wx, wy, ff_asset, edl);
245 format_window = window;
246 window->create_objects();
247 if( !window->run_window() ) {
248 asset->copy_from(ff_asset,0);
249 set_options(asset->ff_audio_options,
250 sizeof(asset->ff_audio_options),
251 window->audio_options->get_text());
255 else if( video_options ) {
256 FFMPEGConfigVideo *window = new FFMPEGConfigVideo(parent_window,
257 wx, wy, ff_asset, edl);
258 format_window = window;
259 window->create_objects();
260 if( !window->run_window() ) {
261 asset->copy_from(ff_asset,0);
262 set_options(asset->ff_video_options,
263 sizeof(asset->ff_video_options),
264 window->video_options->get_text());
268 ff_asset->remove_user();
271 int FileFFMPEG::check_sig(Asset *asset)
273 char *ptr = strstr(asset->path, ".pcm");
275 ptr = strstr(asset->path, ".raw");
279 int ret = !ffmpeg.init_decoder(asset->path) &&
280 !ffmpeg.open_decoder() ? 1 : 0;
284 void FileFFMPEG::get_info(char *path, char *text, int len)
288 cp += sprintf(cp, _("file path: %s\n"), path);
291 if( stat(path, &st) < 0 ) {
292 cp += sprintf(cp, _(" err: %s\n"), strerror(errno));
296 cp += sprintf(cp, _(" %jd bytes\n"), st.st_size);
298 if( !ret ) ret = ffmpeg.init_decoder(path);
299 if( !ret ) ret = ffmpeg.open_decoder();
301 cp += sprintf(cp, _("info:\n"));
302 ffmpeg.info(cp, len-(cp-text));
305 sprintf(cp, _("== open failed\n"));
308 int FileFFMPEG::get_video_info(int track, int &pid, double &framerate,
309 int &width, int &height, char *title)
312 pid = ff->ff_video_pid(track);
313 framerate = ff->ff_frame_rate(track);
314 width = ff->ff_video_width(track);
315 height = ff->ff_video_height(track);
316 if( title ) *title = 0;
320 int FileFFMPEG::get_audio_for_video(int vstream, int astream, int64_t &channel_mask)
323 return ff->ff_audio_for_video(vstream, astream, channel_mask);
326 int FileFFMPEG::select_video_stream(Asset *asset, int vstream)
328 if( !ff || !asset->video_data ) return 1;
329 asset->width = ff->ff_video_width(vstream);
330 asset->height = ff->ff_video_height(vstream);
331 if( (asset->video_length = ff->ff_video_frames(vstream)) < 2 )
332 asset->video_length = asset->video_length < 0 ? 0 : -1;
333 asset->frame_rate = ff->ff_frame_rate(vstream);
337 int FileFFMPEG::select_audio_stream(Asset *asset, int astream)
339 if( !ff || !asset->audio_data ) return 1;
340 asset->sample_rate = ff->ff_sample_rate(astream);
341 asset->audio_length = ff->ff_audio_samples(astream);
345 int FileFFMPEG::open_file(int rd, int wr)
349 ff = new FFMPEG(this);
352 result = ff->init_decoder(asset->path);
353 if( !result ) result = ff->open_decoder();
355 int audio_channels = ff->ff_total_audio_channels();
356 if( audio_channels > 0 ) {
357 asset->audio_data = 1;
358 asset->channels = audio_channels;
359 asset->sample_rate = ff->ff_sample_rate(0);
360 asset->audio_length = ff->ff_audio_samples(0);
361 strcpy(asset->acodec, ff->ff_audio_format(0));
363 int video_layers = ff->ff_total_video_layers();
364 if( video_layers > 0 ) {
365 asset->video_data = 1;
366 asset->aspect_ratio = ff->ff_aspect_ratio(0);
367 if (!asset->interlace_mode) asset->interlace_mode = ff->ff_interlace(0);
368 if ( ff->ff_video_frames(0) > 1 ) {
369 // ff->video_probe(1);
370 if (!asset->interlace_mode && (ff->interlace_from_codec) ) asset->interlace_mode = ff->video_probe(1);
372 if( !asset->layers ) asset->layers = video_layers;
373 asset->actual_width = ff->ff_video_width(0);
374 asset->actual_height = ff->ff_video_height(0);
375 if( !asset->width ) asset->width = asset->actual_width;
376 if( !asset->height ) asset->height = asset->actual_height;
377 if( !asset->video_length &&
378 (asset->video_length = ff->ff_video_frames(0)) < 2 )
379 asset->video_length = asset->video_length < 0 ? 0 : -1;
380 if( !asset->frame_rate ) asset->frame_rate = ff->ff_frame_rate(0);
381 if( asset->ff_color_range < 0 )
382 asset->ff_color_range = ff->ff_color_range(0);
383 if( asset->ff_color_space < 0 )
384 asset->ff_color_space = ff->ff_color_space(0);
385 strcpy(asset->vcodec, ff->ff_video_codec(0));
387 IndexState *index_state = asset->index_state;
388 index_state->read_markers(file->preferences->index_directory, asset->path);
392 result = ff->init_encoder(asset->path);
393 // must be in this order or dvdauthor will fail
394 if( !result && asset->video_data )
395 result = ff->open_encoder("video", asset->vcodec);
396 if( !result && asset->audio_data )
397 result = ff->open_encoder("audio", asset->acodec);
402 int FileFFMPEG::close_file()
410 int FileFFMPEG::write_samples(double **buffer, int64_t len)
412 if( !ff || len < 0 ) return -1;
414 int ret = ff->encode(stream, buffer, len);
418 int FileFFMPEG::write_frames(VFrame ***frames, int len)
421 int ret = 0, layer = 0;
422 for(int i = 0; i < 1; i++) {
423 for(int j = 0; j < len && !ret; j++) {
424 VFrame *frame = frames[i][j];
425 ret = ff->encode(layer, frame);
432 int FileFFMPEG::read_samples(double *buffer, int64_t len)
434 if( !ff || len < 0 ) return -1;
435 int ch = file->current_channel;
436 int64_t pos = file->current_sample;
437 int ret = ff->decode(ch, pos, buffer, len);
438 if( ret > 0 ) return 0;
439 memset(buffer,0,len*sizeof(*buffer));
443 int FileFFMPEG::read_frame(VFrame *frame)
446 int layer = file->current_layer;
447 int64_t pos = asset->video_length >= 0 ? file->current_frame : 0;
448 int ret = ff->decode(layer, pos, frame);
449 frame->set_status(ret);
450 if( ret >= 0 ) return 0;
451 frame->clear_frame();
456 int64_t FileFFMPEG::get_memory_usage()
461 int FileFFMPEG::colormodel_supported(int colormodel)
467 int FileFFMPEG::get_best_colormodel(int driver, int vstream)
469 if( vstream < 0 ) vstream = 0;
470 int is_mpeg = !ff ? 0 : ff->ff_video_mpeg_color_range(vstream);
474 case PLAYBACK_X11_GL: return is_mpeg ? BC_YUV888 : BC_RGB888;
475 case PLAYBACK_X11_XV: return BC_YUV420P;
481 int FileFFMPEG::get_best_colormodel(Asset *asset, int driver)
484 // the direct X11 color model requires scaling in the codec
487 case PLAYBACK_X11_GL: return BC_RGB888;
488 case PLAYBACK_X11_XV: return BC_YUV420P;
495 FFMPEGConfigWindow::FFMPEGConfigWindow(const char *title,
496 BC_WindowBase *parent_window,
497 int x, int y, int w, int h,
498 Asset *asset, EDL *edl)
499 : BC_Window(title, x, y, w, h)
501 this->parent_window = parent_window;
506 ff_options_dialog = 0;
511 FFMPEGConfigWindow::~FFMPEGConfigWindow()
513 delete ff_options_dialog;
516 void FFMPEGConfigWindow::start(AVCodecContext *avctx)
519 ff_options_dialog->start();
522 void FFMPEGConfigWindow::start(AVFormatContext *fmt_ctx)
524 this->fmt_ctx = fmt_ctx;
525 ff_options_dialog->start();
530 FFMPEGConfigAudio::FFMPEGConfigAudio(BC_WindowBase *parent_window,
531 int x, int y, Asset *asset, EDL *edl)
532 : FFMPEGConfigWindow(_(PROGRAM_NAME ": Audio Preset"), parent_window, x, y,
533 xS(420), yS(420), asset, edl)
538 format_name = asset->fformat;
539 codec_name = asset->acodec;
540 // *** CONTEXT_HELP ***
541 context_help_set_keyword("Options for Render with FFmpeg");
544 FFMPEGConfigAudio::~FFMPEGConfigAudio()
546 lock_window("FFMPEGConfigAudio::~FFMPEGConfigAudio");
548 presets.remove_all_objects();
549 delete audio_options;
553 void FFMPEGConfigAudio::read_options()
555 const char *options = audio_options->get_text();
556 int options_len = strlen(options);
557 ff_options_dialog->load_options(options, options_len);
559 void FFMPEGConfigAudio::save_options()
561 char options[BCTEXTLEN];
562 ff_options_dialog->store_options(options, sizeof(options)-1);
563 audio_options->update(options);
566 void FFMPEGConfigAudio::load_options()
568 FFMPEG::load_audio_options(asset, edl);
571 void FFMPEGConfigAudio::create_objects()
573 int x = xS(10), y = yS(10);
574 lock_window("FFMPEGConfigAudio::create_objects");
577 char option_path[BCTEXTLEN];
578 FFMPEG::set_option_path(option_path, "audio");
579 fs.update(option_path);
580 int total_files = fs.total_files();
581 for(int i = 0; i < total_files; i++) {
582 const char *name = fs.get_entry(i)->get_name();
583 if( asset->fformat[0] != 0 ) {
584 const char *ext = strrchr(name,'.');
586 if( strcmp(asset->fformat, ++ext) ) continue;
588 presets.append(new BC_ListBoxItem(name));
591 if( asset->acodec[0] ) {
592 int k = presets.size();
593 while( --k >= 0 && strcmp(asset->acodec, presets[k]->get_text()) );
594 if( k < 0 ) asset->acodec[0] = 0;
597 if( !asset->acodec[0] && presets.size() > 0 )
598 strcpy(asset->acodec, presets[0]->get_text());
600 add_tool(new BC_Title(x, y, _("Preset:")));
602 preset_popup = new FFMPEGConfigAudioPopup(this, x, y);
603 preset_popup->create_objects();
606 bitrate = new FFMpegAudioBitrate(this, x, y, _("Bitrate:"), &asset->ff_audio_bitrate);
607 bitrate->create_objects();
608 bitrate->set_increment(1000);
609 bitrate->set_boundaries((int64_t)0, (int64_t)INT_MAX);
610 y += bitrate->get_h() + 5;
611 quality = new FFMpegAudioQuality(this, x, y, _("Quality:"), &asset->ff_audio_quality);
612 quality->create_objects();
613 quality->set_increment(1);
614 quality->set_boundaries((int64_t)-1, (int64_t)51);
615 y += quality->get_h() + yS(10);
617 add_subwindow(new BC_Title(x, y, _("Samples:")));
618 sample_format = new FFMpegSampleFormat(this, x+xS(90), y, xS(100), yS(120));
619 sample_format->create_objects();
620 if( asset->acodec[0] ) {
621 sample_format->update_formats();
622 if( !asset->ff_audio_options[0] )
625 if( !asset->ff_sample_format[0] ) strcpy(asset->ff_sample_format, _("None"));
626 sample_format->update(asset->ff_sample_format);
627 y += sample_format->get_h() + yS(10);
629 BC_Title *title = new BC_Title(x, y, _("Audio Options:"));
630 add_subwindow(title);
632 ff_options_dialog = new FFOptionsAudioDialog(this);
633 int x1 = x + title->get_w() + xS(8);
634 add_subwindow(view_audio = new FFOptionsViewAudio(this, x1, y, _("view")));
635 x1 += x + view_audio->get_w() + xS(20);
636 view_format = new FFOptionsViewFormat(this, edl, asset, x1, y, _("format"));
637 add_subwindow(view_format);
640 audio_options = new FFAudioOptions(this, x, y, get_w()-x-xS(20), 8,
641 sizeof(asset->ff_audio_options)-1, asset->ff_audio_options);
642 audio_options->create_objects();
643 add_subwindow(new BC_OKButton(this));
644 add_subwindow(new BC_CancelButton(this));
647 bitrate->update_param("cin_bitrate", asset->ff_audio_options);
648 quality->update_param("cin_quality", asset->ff_audio_options);
650 if( asset->ff_audio_bitrate > 0 ) quality->disable();
651 else if( asset->ff_audio_quality >= 0 ) bitrate->disable();
656 int FFMPEGConfigAudio::close_event()
662 FFAudioOptions::FFAudioOptions(FFMPEGConfigAudio *audio_popup,
663 int x, int y, int w, int rows, int size, char *text)
664 : BC_ScrollTextBox(audio_popup, x, y, w, rows, text, size)
666 this->audio_popup = audio_popup;
670 FFMPEGConfigAudioPopup::FFMPEGConfigAudioPopup(FFMPEGConfigAudio *popup, int x, int y)
671 : BC_PopupTextBox(popup, &popup->presets, popup->asset->acodec, x, y, xS(300), yS(300))
676 int FFMPEGConfigAudioPopup::handle_event()
678 strcpy(popup->asset->acodec, get_text());
679 popup->sample_format->update_formats();
680 Asset *asset = popup->asset;
681 asset->ff_audio_bitrate = 0; asset->ff_audio_quality = -1;
682 popup->load_options();
683 popup->audio_options->update(asset->ff_audio_options);
684 popup->audio_options->set_text_row(0);
686 popup->bitrate->update_param("cin_bitrate", asset->ff_audio_options);
687 popup->quality->update_param("cin_quality", asset->ff_audio_options);
688 popup->sample_format->update(asset->ff_sample_format);
694 FFMPEGConfigVideo::FFMPEGConfigVideo(BC_WindowBase *parent_window,
695 int x, int y, Asset *asset, EDL *edl)
696 : FFMPEGConfigWindow(_(PROGRAM_NAME ": Video Preset"), parent_window, x, y,
697 xS(420), yS(420), asset, edl)
701 format_name = asset->fformat;
702 codec_name = asset->vcodec;
707 // *** CONTEXT_HELP ***
708 context_help_set_keyword("Options for Render with FFmpeg");
711 FFMPEGConfigVideo::~FFMPEGConfigVideo()
713 lock_window("FFMPEGConfigVideo::~FFMPEGConfigVideo");
716 delete video_options;
717 presets.remove_all_objects();
721 void FFMPEGConfigVideo::read_options()
723 const char *options = video_options->get_text();
724 int options_len = strlen(options);
725 ff_options_dialog->load_options(options, options_len);
727 void FFMPEGConfigVideo::save_options()
729 char options[BCTEXTLEN];
730 ff_options_dialog->store_options(options, sizeof(options)-1);
731 video_options->update(options);
734 void FFMPEGConfigVideo::load_options()
736 FFMPEG::load_video_options(asset, edl);
739 void FFMPEGConfigVideo::create_objects()
741 int x = xS(10), y = yS(10);
742 lock_window("FFMPEGConfigVideo::create_objects");
744 add_subwindow(new BC_Title(x, y, _("Compression:")));
748 char option_path[BCTEXTLEN];
749 FFMPEG::set_option_path(option_path, "video");
750 fs.update(option_path);
751 int total_files = fs.total_files();
752 for(int i = 0; i < total_files; i++) {
753 const char *name = fs.get_entry(i)->get_name();
754 if( asset->fformat[0] != 0 ) {
755 const char *ext = strrchr(name,'.');
757 if( strcmp(asset->fformat, ++ext) ) continue;
759 presets.append(new BC_ListBoxItem(name));
762 if( asset->vcodec[0] ) {
763 int k = presets.size();
764 while( --k >= 0 && strcmp(asset->vcodec, presets[k]->get_text()) );
765 if( k < 0 ) asset->vcodec[0] = 0;
768 if( !asset->vcodec[0] && presets.size() > 0 )
769 strcpy(asset->vcodec, presets[0]->get_text());
771 preset_popup = new FFMPEGConfigVideoPopup(this, x, y);
772 preset_popup->create_objects();
774 if( asset->ff_video_bitrate > 0 && asset->ff_video_quality >= 0 ) {
775 asset->ff_video_bitrate = 0; asset->ff_video_quality = -1;
779 bitrate = new FFMpegVideoBitrate(this, x, y, _("Bitrate:"), &asset->ff_video_bitrate);
780 bitrate->create_objects();
781 bitrate->set_increment(100000);
782 bitrate->set_boundaries((int64_t)0, (int64_t)INT_MAX);
783 y += bitrate->get_h() + 5;
784 quality = new FFMpegVideoQuality(this, x, y, _("Quality:"), &asset->ff_video_quality);
785 quality->create_objects();
786 quality->set_increment(1);
787 quality->set_boundaries((int64_t)-1, (int64_t)51);
788 y += quality->get_h() + yS(10);
790 add_subwindow(new BC_Title(x, y, _("Pixels:")));
791 pixel_format = new FFMpegPixelFormat(this, x+xS(90), y, xS(100), yS(120));
792 pixel_format->create_objects();
793 if( asset->vcodec[0] ) {
794 pixel_format->update_formats();
795 if( !asset->ff_video_options[0] )
798 if( !asset->ff_pixel_format[0] ) strcpy(asset->ff_pixel_format, _("None"));
799 pixel_format->update(asset->ff_pixel_format);
800 y += pixel_format->get_h() + yS(10);
802 BC_Title *title = new BC_Title(x, y, _("Video Options:"));
803 add_subwindow(title);
805 ff_options_dialog = new FFOptionsVideoDialog(this);
806 int x1 = x + title->get_w() + 8;
807 add_subwindow(view_video = new FFOptionsViewVideo(this, x1, y, _("view")));
808 x1 += x + view_video->get_w() + xS(20);
809 view_format = new FFOptionsViewFormat(this, edl, asset, x1, y, _("format"));
810 add_subwindow(view_format);
813 video_options = new FFVideoOptions(this, x, y, get_w()-x-xS(20), 8,
814 sizeof(asset->ff_video_options)-1, asset->ff_video_options);
815 video_options->create_objects();
816 add_subwindow(new BC_OKButton(this));
817 add_subwindow(new BC_CancelButton(this));
820 bitrate->update_param("cin_bitrate", asset->ff_video_options);
821 quality->update_param("cin_quality", asset->ff_video_options);
823 if( asset->ff_video_bitrate > 0 ) quality->disable();
824 else if( asset->ff_video_quality >= 0 ) bitrate->disable();
828 int FFMPEGConfigVideo::close_event()
834 FFVideoOptions::FFVideoOptions(FFMPEGConfigVideo *video_popup,
835 int x, int y, int w, int rows, int size, char *text)
836 : BC_ScrollTextBox(video_popup, x, y, w, rows, text, size)
838 this->video_popup = video_popup;
842 FFMPEGConfigVideoPopup::FFMPEGConfigVideoPopup(FFMPEGConfigVideo *popup, int x, int y)
843 : BC_PopupTextBox(popup, &popup->presets, popup->asset->vcodec, x, y, xS(300), yS(300))
848 int FFMPEGConfigVideoPopup::handle_event()
850 strcpy(popup->asset->vcodec, get_text());
851 popup->pixel_format->update_formats();
852 Asset *asset = popup->asset;
853 asset->ff_video_bitrate = 0; asset->ff_video_quality = -1;
854 popup->load_options();
855 popup->video_options->update(asset->ff_video_options);
856 popup->video_options->set_text_row(0);
858 popup->bitrate->update_param("cin_bitrate", asset->ff_video_options);
859 popup->quality->update_param("cin_quality", asset->ff_video_options);
860 popup->pixel_format->update(asset->ff_pixel_format);
866 FFMPEGConfigFormat::FFMPEGConfigFormat(FFOptionsFormatViewDialog *view_dialog,
867 int x, int y, Asset *asset, EDL *edl)
868 : FFMPEGConfigWindow(_(PROGRAM_NAME ": Format Preset"),
869 view_dialog->view_format, x, y, xS(420), yS(300), asset, edl)
871 this->view_dialog = view_dialog;
873 format_name = asset->fformat;
875 // *** CONTEXT_HELP ***
876 context_help_set_keyword("Modifying FFmpeg Format Options");
879 FFMPEGConfigFormat::~FFMPEGConfigFormat()
881 lock_window("FFMPEGConfigFormat::~FFMPEGConfigFormat");
882 delete format_options;
886 void FFMPEGConfigFormat::read_options()
888 const char *options = format_options->get_text();
889 int options_len = strlen(options);
890 ff_options_dialog->load_options(options, options_len);
892 void FFMPEGConfigFormat::save_options()
894 char options[BCTEXTLEN];
895 ff_options_dialog->store_options(options, sizeof(options)-1);
896 format_options->update(options);
898 void FFMPEGConfigFormat::save_changes()
901 char *options = asset->ff_format_options;
902 int options_len = sizeof(asset->ff_format_options)-1;
903 ff_options_dialog->store_options(options, options_len);
906 void FFMPEGConfigFormat::load_options()
908 Asset *asset = view_dialog->view_format->asset;
909 EDL *edl = view_dialog->view_format->edl;
910 FFMPEG::load_format_options(asset, edl);
913 void FFMPEGConfigFormat::create_objects()
915 int x = xS(10), y = yS(10);
916 lock_window("FFMPEGConfigFormat::create_objects");
917 Asset *asset = view_dialog->view_format->asset;
919 add_subwindow(title = new BC_Title(x, y, _("Format:")));
920 int x1 = x + title->get_w() + 8;
921 add_subwindow(new BC_Title(x1, y, asset->fformat));
924 add_subwindow(title = new BC_Title(x, y, _("Format Options:")));
926 ff_options_dialog = new FFOptionsFormatDialog(this);
927 x1 = x + title->get_w() + 8;
928 add_subwindow(new FFOptionsFormatView(this, x1, y, _("view")));
931 format_options = new FFFormatOptions(this, x, y, get_w()-x-xS(20), 8,
932 sizeof(asset->ff_format_options)-1, asset->ff_format_options);
933 format_options->create_objects();
934 add_subwindow(new BC_OKButton(this));
935 add_subwindow(new BC_CancelButton(this));
940 int FFMPEGConfigFormat::close_event()
946 FFFormatOptions::FFFormatOptions(FFMPEGConfigFormat *format_popup,
947 int x, int y, int w, int rows, int size, char *text)
948 : BC_ScrollTextBox(format_popup, x, y, w, rows, text, size)
950 this->format_popup = format_popup;
955 FFMPEGScanProgress::FFMPEGScanProgress(IndexFile *index_file, MainProgressBar *progress_bar,
956 const char *title, int64_t length, int64_t *position, int *canceled)
959 this->index_file = index_file;
960 this->progress_bar = progress_bar;
961 strcpy(this->progress_title, title);
962 this->length = length;
963 this->position = position;
964 this->canceled = canceled;
969 FFMPEGScanProgress::~FFMPEGScanProgress()
976 void FFMPEGScanProgress::run()
979 if( progress_bar->update(*position) ) {
980 *canceled = done = 1;
983 index_file->redraw_edits(0);
988 int FileFFMPEG::get_index(IndexFile *index_file, MainProgressBar *progress_bar)
991 if( !file->preferences->ffmpeg_marker_indexes ) return 1;
993 IndexState *index_state = index_file->get_state();
994 if( index_state->index_status != INDEX_NOTTESTED ) return 0;
995 index_state->reset_index();
996 index_state->reset_markers();
997 index_state->index_status = INDEX_BUILDING;
999 for( int aidx=0; aidx<ff->ffaudio.size(); ++aidx ) {
1000 FFAudioStream *aud = ff->ffaudio[aidx];
1001 index_state->add_audio_stream(aud->channels, aud->length);
1005 int64_t file_bytes = fs.get_size(ff->fmt_ctx->url);
1006 char *index_path = index_file->index_filename;
1009 int64_t scan_position = 0;
1010 FFMPEGScanProgress *scan_progress = 0;
1011 if( progress_bar ) {
1012 char progress_title[BCTEXTLEN];
1013 sprintf(progress_title, _("Creating %s\n"), index_path);
1014 progress_bar->update_title(progress_title, 1);
1015 progress_bar->update_length(file_bytes);
1016 scan_progress = new FFMPEGScanProgress(index_file,
1017 progress_bar, progress_title, file_bytes,
1018 &scan_position, &canceled);
1021 index_state->index_bytes = file_bytes;
1022 index_state->init_scan(file->preferences->index_size);
1024 if( ff->scan(index_state, &scan_position, &canceled) || canceled ) {
1025 index_state->reset_index();
1026 index_state->reset_markers();
1030 delete scan_progress;
1031 if( canceled ) return 1;
1033 index_state->marker_status = MARKERS_READY;
1034 return index_state->create_index(index_path, asset);
1038 FFOptions_OptPanel::
1039 FFOptions_OptPanel(FFOptionsWindow *fwin, int x, int y, int w, int h)
1040 : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1])
1043 update(); // init col/wid/columns
1046 FFOptions_OptPanel::
1047 ~FFOptions_OptPanel()
1051 void FFOptions_OptPanel::create_objects()
1053 const char *cols[] = { _("option"), _("value"), };
1054 const int col1_w = xS(150);
1055 int wids[] = { col1_w, get_w()-col1_w };
1056 BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0]));
1059 int FFOptions_OptPanel::update()
1063 FFOptions &options = fwin->options;
1064 for( int i=0; i<options.size(); ++i ) {
1065 FFOptions_Opt *opt = options[i];
1066 opts.append(opt->item_name);
1067 vals.append(opt->item_value);
1073 int FFOptions_OptPanel::cursor_leave_event()
1080 FFOptions_OptName::FFOptions_OptName(FFOptions_Opt *opt, const char *nm)
1086 FFOptions_OptName::~FFOptions_OptName()
1090 FFOptions_OptValue::FFOptions_OptValue(FFOptions_Opt *opt)
1096 void FFOptions_OptValue::update()
1099 char val[BCTEXTLEN]; val[0] = 0;
1100 opt->get(val, sizeof(val));
1104 void FFOptions_OptValue::update(const char *v)
1109 FFOptions_Opt::FFOptions_Opt(FFOptions *options, const AVOption *opt, const char *nm)
1111 this->options = options;
1113 item_name = new FFOptions_OptName(this, nm);
1114 item_value = new FFOptions_OptValue(this);
1117 FFOptions_Opt::~FFOptions_Opt()
1123 char *FFOptions_Opt::get(char *vp, int sz)
1127 if( !opt ) return cp;
1129 void *obj = (void *)options->obj;
1131 if( av_opt_get(obj, opt->name, 0, &bp) >= 0 && bp != 0 ) {
1132 const char *val = (const char *)bp;
1133 if( opt->unit && *val ) {
1135 const char *uid = unit_name(id);
1136 if( uid ) val = uid;
1138 cp = sz >= 0 ? strncpy(vp,val,sz) : strcpy(vp, val);
1139 if( sz > 0 ) vp[sz-1] = 0;
1146 void FFOptions_Opt::set(const char *val)
1148 void *obj = (void *)options->obj;
1149 if( !obj || !opt ) return;
1150 av_opt_set(obj, opt->name, val, 0);
1154 FFOptionsKindItem::FFOptionsKindItem(FFOptionsKind *kind, const char *text, int idx)
1161 FFOptionsKindItem::~FFOptionsKindItem()
1165 int FFOptionsKindItem::handle_event()
1167 FFOptionsWindow *fwin = kind->fwin;
1168 FFOptions &options = fwin->options;
1169 options.initialize(fwin, idx);
1170 kind->set_text(get_text());
1175 const char *FFOptionsKind::kinds[] = {
1176 N_("codec"), // FF_KIND_CODEC
1177 N_("format"), // FF_KIND_FORMAT
1178 N_("ffmpeg"), // FF_KIND_FFMPEG
1182 FFOptionsKind(FFOptionsWindow *fwin, int x, int y, int w)
1183 : BC_PopupMenu(x, y, w, "")
1193 void FFOptionsKind::create_objects()
1195 add_item(new FFOptionsKindItem(this, _(kinds[FF_KIND_CODEC]), FF_KIND_CODEC));
1196 add_item(new FFOptionsKindItem(this, _(kinds[FF_KIND_FFMPEG]), FF_KIND_FFMPEG));
1199 int FFOptionsKind::handle_event()
1204 void FFOptionsKind::set(int k)
1207 set_text(_(kinds[k]));
1211 FFOptionsText(FFOptionsWindow *fwin, int x, int y, int w)
1212 : BC_TextBox(x, y, w, 1, (char *)"")
1222 int FFOptionsText::handle_event()
1228 FFOptionsUnits(FFOptionsWindow *fwin, int x, int y, int w)
1229 : BC_PopupMenu(x, y, w, "")
1239 int FFOptionsUnits::handle_event()
1241 const char *text = get_text();
1242 if( text && fwin->selected ) {
1243 fwin->selected->set(text);
1244 fwin->selected->item_value->update();
1245 av_dict_set(&fwin->dialog->ff_opts,
1246 fwin->selected->item_name->get_text(),
1247 fwin->selected->item_value->get_text(), 0);
1254 FFOptionsApply(FFOptionsWindow *fwin, int x, int y)
1255 : BC_GenericButton(x, y, _("Apply"))
1265 int FFOptionsApply::handle_event()
1267 const char *text = fwin->text->get_text();
1268 if( text && fwin->selected ) {
1269 fwin->selected->set(text);
1270 fwin->selected->item_value->update();
1271 av_dict_set(&fwin->dialog->ff_opts,
1272 fwin->selected->item_name->get_text(),
1273 fwin->selected->item_value->get_text(), 0);
1279 FFOptions::FFOptions()
1284 FFOptions::~FFOptions()
1286 remove_all_objects();
1289 int FFOptions::cmpr(const void *a, const void *b)
1291 FFOptions_Opt *ap = *(FFOptions_Opt **)a;
1292 FFOptions_Opt *bp = *(FFOptions_Opt **)b;
1293 const char *vap = ap->item_name->get_text();
1294 const char *vbp = bp->item_name->get_text();
1295 return strcmp(vap, vbp);
1298 void FFOptions::initialize(FFOptionsWindow *win, int kind)
1300 remove_all_objects();
1302 const void *obj = 0;
1305 obj = (const void *)win->dialog->cfg_window->avctx->priv_data;
1307 case FF_KIND_FFMPEG:
1308 obj = (const void *)win->dialog->cfg_window->avctx;
1310 case FF_KIND_FORMAT:
1311 obj = (const void *)win->dialog->cfg_window->fmt_ctx->priv_data;
1317 FFOptions &conf = *this;
1318 const AVOption *opt = 0;
1319 while( (opt=av_opt_next(obj, opt)) != 0 ) {
1320 if( opt->type == AV_OPT_TYPE_CONST ) continue;
1322 for( int i=0; !dupl && i<size(); ++i ) {
1323 FFOptions_Opt *fopt = conf[i];
1324 const AVOption *op = fopt->opt;
1325 if( op->offset != opt->offset ) continue;
1326 if( op->type != opt->type ) continue;
1328 if( strlen(op->name) < strlen(opt->name) )
1331 if( dupl ) continue;
1332 FFOptions_Opt *fopt = new FFOptions_Opt(this, opt, opt->name);
1334 AVDictionaryEntry *elem = av_dict_get(win->dialog->ff_opts,
1335 opt->name, 0, AV_DICT_IGNORE_SUFFIX);
1336 if( elem && elem->value ) fopt->set(elem->value);
1337 char val[BCTEXTLEN], *vp = fopt->get(val, sizeof(val));
1338 fopt->item_value->update(vp);
1340 qsort(&values[0],size(),sizeof(values[0]),cmpr);
1342 win->panel->update();
1343 win->panel->set_yposition(0);
1346 int FFOptions::update()
1349 FFOptions &conf = *this;
1351 for( int i=0; i<size(); ++i ) {
1352 FFOptions_Opt *fopt = conf[i];
1353 char val[BCTEXTLEN], *vp = fopt->get(val, sizeof(val));
1354 if( !vp || !strcmp(val, fopt->item_value->get_text()) ) continue;
1355 fopt->item_value->update(val);
1361 void FFOptions::dump(FILE *fp)
1364 const AVOption *opt = 0;
1365 FFOptions &conf = *this;
1367 while( (opt=av_opt_next(obj, opt)) != 0 ) {
1368 if( opt->type == AV_OPT_TYPE_CONST ) continue;
1370 while( --k >= 0 && strcmp(opt->name, conf[k]->opt->name) );
1371 if( k < 0 ) continue;
1372 FFOptions_Opt *fopt = conf[k];
1373 char val[BCTEXTLEN], *vp = fopt->get(val,sizeof(val));
1374 fprintf(fp, " %s:=%s", opt->name, vp);
1376 char unt[BCTEXTLEN], *up = unt;
1378 fprintf(fp, "%s", unt);
1385 void FFOptionsWindow::update(FFOptions_Opt *opt)
1387 if( selected != opt ) {
1388 if( selected ) selected->item_name->set_selected(0);
1390 if( selected ) selected->item_name->set_selected(1);
1392 clear_box(0,0, 0,panel->get_y());
1393 char str[BCTEXTLEN], *sp;
1395 if( opt ) opt->types(sp);
1398 if( opt ) opt->ranges(sp);
1400 while( units->total_items() ) units->del_item(0);
1401 char unit[BCSTRLEN]; strcpy(unit, "()");
1402 if( opt && opt->opt ) {
1403 ArrayList<const char *> names;
1405 if( opt->opt->unit ) {
1406 n = opt->units(names);
1407 if( n > 0 ) strcpy(unit,opt->opt->unit);
1409 for( int i=0; i<n; ++i )
1410 units->add_item(new BC_MenuItem(names[i], 0));
1412 units->set_text(unit);
1413 char val[BCTEXTLEN]; val[0] = 0;
1414 if( opt ) opt->get(val, sizeof(val));
1420 void FFOptions_OptPanel::show_tip(const char *tip)
1423 int len = strlen(tip);
1424 if( len > (int)sizeof(tip_text)-1 ) len = sizeof(tip_text)-1;
1425 strncpy(tip_text,tip,len);
1427 int line_limit = 60;
1428 int limit2 = line_limit/2;
1429 int limit4 = line_limit/4-2;
1430 char *cp = tip_text, *dp = cp+len;
1431 int n; char *bp, *ep, *pp, *sp;
1433 for( ep=cp; ep<dp && *ep!='\n'; ++ep );
1434 // target about half remaining line, constrain line_limit
1435 if( (n=(ep-1-cp)/2) < limit2 || n > line_limit )
1437 // search for last punct, last space before line_limit
1438 for( bp=cp, pp=sp=0; --n>=0 && cp<ep; ++cp ) {
1439 if( ispunct(*cp) && isspace(*(cp+1)) ) pp = cp;
1440 else if( isspace(*cp) ) sp = cp;
1444 // first, after punctuation
1445 if( pp && pp-bp >= limit4 )
1451 // last, on next space
1453 while( cp<dp && !isspace(*cp) ) ++cp;
1460 fwin->panel->set_tooltip(tip_text);
1461 fwin->panel->show_tooltip();
1464 int FFOptions_OptPanel::selection_changed()
1466 FFOptions_Opt *opt = 0;
1467 BC_ListBoxItem *item = get_selection(0, 0);
1469 FFOptions_OptName *opt_name = (FFOptions_OptName *)item;
1470 opt = opt_name->opt;
1473 if( opt ) show_tip(opt->tip());
1478 int FFOptions_Opt::types(char *rp)
1480 const char *cp = "";
1481 if( opt ) switch (opt->type) {
1482 case AV_OPT_TYPE_FLAGS: cp = N_("<flags>"); break;
1483 case AV_OPT_TYPE_INT: cp = N_("<int>"); break;
1484 case AV_OPT_TYPE_INT64: cp = N_("<int64>"); break;
1485 case AV_OPT_TYPE_DOUBLE: cp = N_("<double>"); break;
1486 case AV_OPT_TYPE_FLOAT: cp = N_("<float>"); break;
1487 case AV_OPT_TYPE_STRING: cp = N_("<string>"); break;
1488 case AV_OPT_TYPE_RATIONAL: cp = N_("<rational>"); break;
1489 case AV_OPT_TYPE_BINARY: cp = N_("<binary>"); break;
1490 case AV_OPT_TYPE_IMAGE_SIZE: cp = N_("<image_size>"); break;
1491 case AV_OPT_TYPE_VIDEO_RATE: cp = N_("<video_rate>"); break;
1492 case AV_OPT_TYPE_PIXEL_FMT: cp = N_("<pix_fmt>"); break;
1493 case AV_OPT_TYPE_SAMPLE_FMT: cp = N_("<sample_fmt>"); break;
1494 case AV_OPT_TYPE_DURATION: cp = N_("<duration>"); break;
1495 case AV_OPT_TYPE_COLOR: cp = N_("<color>"); break;
1496 case AV_OPT_TYPE_CHLAYOUT: cp = N_("<channel_layout>"); break;
1497 case AV_OPT_TYPE_BOOL: cp = N_("<bool>"); break;
1498 default: cp = N_("<undef>"); break;
1500 return sprintf(rp, "%s", _(cp));
1502 int FFOptions_Opt::scalar(double d, char *rp)
1505 if( d == INT_MAX ) cp = "INT_MAX";
1506 else if( d == INT_MIN ) cp = "INT_MIN";
1507 else if( d == UINT32_MAX ) cp = "UINT32_MAX";
1508 else if( d == (double)INT64_MAX ) cp = "I64_MAX";
1509 else if( d == INT64_MIN ) cp = "I64_MIN";
1510 else if( d == FLT_MAX ) cp = "FLT_MAX";
1511 else if( d == FLT_MIN ) cp = "FLT_MIN";
1512 else if( d == -FLT_MAX ) cp = "-FLT_MAX";
1513 else if( d == -FLT_MIN ) cp = "-FLT_MIN";
1514 else if( d == DBL_MAX ) cp = "DBL_MAX";
1515 else if( d == DBL_MIN ) cp = "DBL_MIN";
1516 else if( d == -DBL_MAX ) cp = "-DBL_MAX";
1517 else if( d == -DBL_MIN ) cp = "-DBL_MIN";
1518 else if( d == 0 ) cp = signbit(d) ? "-0" : "0";
1519 else if( isnan(d) ) cp = signbit(d) ? "-NAN" : "NAN";
1520 else if( isinf(d) ) cp = signbit(d) ? "-INF" : "INF";
1521 else return sprintf(rp, "%g", d);
1522 return sprintf(rp, "%s", cp);
1525 int FFOptions_Opt::ranges(char *rp)
1527 if( !opt ) return 0;
1528 void *obj = (void *)options->obj;
1529 if( !obj ) return 0;
1531 switch (opt->type) {
1532 case AV_OPT_TYPE_INT:
1533 case AV_OPT_TYPE_INT64:
1534 case AV_OPT_TYPE_DOUBLE:
1535 case AV_OPT_TYPE_FLOAT: break;
1538 AVOptionRanges *r = 0;
1540 if( av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) < 0 ) return 0;
1541 for( int i=0; i<r->nb_ranges; ++i ) {
1542 cp += sprintf(cp, " ("); cp += scalar(r->range[i]->value_min, cp);
1543 cp += sprintf(cp, ".."); cp += scalar(r->range[i]->value_max, cp);
1544 cp += sprintf(cp, ")");
1546 av_opt_freep_ranges(&r);
1550 int FFOptions_Opt::units(ArrayList<const char *> &names)
1552 if( !opt || !opt->unit ) return 0;
1553 const void *obj = options->obj;
1554 if( !obj ) return 0;
1556 ArrayList<const AVOption *> opts;
1557 const AVOption *opt = NULL;
1558 while( (opt=av_opt_next(obj, opt)) != 0 ) {
1559 if( !opt->unit ) continue;
1560 if( opt->type != AV_OPT_TYPE_CONST ) continue;
1561 if( strcmp(this->opt->unit, opt->unit) ) continue;
1562 int i = opts.size();
1564 if( opts[i]->default_val.i64 != opt->default_val.i64 ) continue;
1565 if( strlen(opts[i]->name) < strlen(opt->name) ) opts[i] = opt;
1568 if( i >= 0 ) continue;
1572 for( int i=0; i<opts.size(); ++i )
1573 names.append(opts[i]->name);
1575 return names.size();
1578 int FFOptions_Opt::units(char *rp)
1580 ArrayList<const char *> names;
1581 int n = units(names);
1584 cp += sprintf(cp, " [%s:", this->opt->unit);
1585 for( int i=0; i<n; ++i )
1586 cp += sprintf(cp, " %s", names[i]);
1587 cp += sprintf(cp, "]:");
1591 const char *FFOptions_Opt::unit_name(int id)
1593 if( !opt || !opt->unit ) return 0;
1594 const void *obj = options->obj;
1595 if( !obj ) return 0;
1597 const char *ret = 0;
1598 const AVOption *opt = NULL;
1599 while( (opt=av_opt_next(obj, opt)) != 0 ) {
1600 if( !opt->unit ) continue;
1601 if( opt->type != AV_OPT_TYPE_CONST ) continue;
1602 if( strcmp(this->opt->unit, opt->unit) ) continue;
1603 if( opt->default_val.i64 != id ) continue;
1604 if( !ret ) { ret = opt->name; continue; }
1605 if( strlen(ret) < strlen(opt->name) ) ret = opt->name;
1611 const char *FFOptions_Opt::tip()
1613 return !opt ? 0 : opt->help;
1617 FFOptionsWindow::FFOptionsWindow(FFOptionsDialog *dialog, int x, int y)
1618 : BC_Window(_(PROGRAM_NAME ": Options"), x, y, xS(640), yS(400))
1620 this->dialog = dialog;
1623 // *** CONTEXT_HELP ***
1624 context_help_set_keyword("Modifying FFmpeg Format Options");
1627 FFOptionsWindow::~FFOptionsWindow()
1631 void FFOptionsWindow::create_objects()
1633 int xs8 = xS(8), xs10 = xS(10);
1635 lock_window("FFOptionsWindow::create_objects");
1637 const char *format_name = dialog->cfg_window->format_name;
1638 const char *codec_name = dialog->cfg_window->codec_name;
1639 int x0 = xs10, y0 = ys10;
1641 add_subwindow(title = new BC_Title(x, y, _("Format: ")));
1642 x += title->get_w();
1643 add_subwindow(new BC_Title(x, y, format_name));
1646 add_subwindow(title = new BC_Title(x, y, _("Codec: ")));
1647 x += title->get_w();
1648 add_subwindow(new BC_Title(x, y, codec_name));
1650 x = x0; y += title->get_h() + ys10; y0 = y;
1651 add_subwindow(title = new BC_Title(x, y, _("Type: ")));
1652 x += title->get_w() + xs8;
1653 add_subwindow(type = new BC_Title(x, y, (char *)""));
1655 add_subwindow(title = new BC_Title(x, y, _("Range: ")));
1656 x += title->get_w() + xs8;
1657 add_subwindow(range = new BC_Title(x, y, (char *)""));
1659 x = x0; y += title->get_h() + ys10;
1660 add_subwindow(units = new FFOptionsUnits(this, x, y, xS(120)));
1661 x += units->get_w() + xs8;
1662 int x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - xs8;
1663 add_subwindow(text = new FFOptionsText(this, x, y, x1-x - xs8));
1664 add_subwindow(apply = new FFOptionsApply(this, x1, y));
1665 y += units->get_h() + ys10;
1667 add_subwindow(kind = new FFOptionsKind(this, x1, y0, apply->get_w()));
1668 kind->create_objects();
1669 const char *kind_text = _("Kind:");
1670 x1 -= BC_Title::calculate_w(this, kind_text) + xs8;
1671 add_subwindow(kind_title = new BC_Title(x1, y0, kind_text));
1674 panel_x = x0; panel_y = y0;
1675 panel_w = get_w()-xs10 - panel_x;
1676 panel_h = get_h()-ys10 - panel_y - BC_OKButton::calculate_h();
1677 panel = new FFOptions_OptPanel(this, panel_x, panel_y, panel_w, panel_h);
1678 add_subwindow(panel);
1679 add_subwindow(new BC_OKButton(this));
1680 add_subwindow(new BC_CancelButton(this));
1681 panel->create_objects();
1682 int k = codec_name ? FF_KIND_CODEC : FF_KIND_FORMAT;
1683 options.initialize(this, k);
1691 void FFOptionsWindow::draw()
1696 int FFOptionsWindow::resize_event(int w, int h)
1698 int xs8 = xS(8), xs10 = xS(10);
1701 int x0 = w - xs8 - kind->get_w();
1702 int y0 = kind->get_y();
1703 kind->reposition_window(x0, y0);
1704 x0 -= kind_title->get_w() + xs8;
1705 kind_title->reposition_window(x0, y0);
1707 int x1 = get_w() - apply->get_w() - xs8;
1708 int y1 = units->get_y();
1709 apply->reposition_window(x1, y1);
1710 int x0 = units->get_x() + units->get_w() + xs8;
1711 int y0 = units->get_y();
1712 text->reposition_window(x0,y0, x1-x0-xs8);
1713 panel_w = get_w()-xs10 - panel_x;
1714 panel_h = get_h()-ys10 - panel_y - BC_OKButton::calculate_h();
1715 panel->reposition_window(panel_x,panel_y, panel_w, panel_h);
1719 FFOptionsDialog::FFOptionsDialog(FFMPEGConfigWindow *cfg_window)
1722 this->cfg_window = cfg_window;
1727 FFOptionsDialog::~FFOptionsDialog()
1730 av_dict_free(&ff_opts);
1733 void FFOptionsDialog::load_options(const char *bp, int len)
1735 av_dict_free(&ff_opts);
1736 char line[BCTEXTLEN];
1737 char key[BCSTRLEN], val[BCTEXTLEN];
1738 const char *dp = bp + len-1;
1740 while( bp < dp && *bp != 0 ) {
1742 char *cp = line, *ep = cp+sizeof(line)-1;
1743 while( *bp && cp<ep && (*cp=*bp++)!='\n' ) ++cp;
1745 if( line[0] == '#' ) {
1746 sprintf(key,"#%d", no);
1747 av_dict_set(&ff_opts, key, line, 0);
1750 if( line[0] == '\n' ) continue;
1751 if( FFMPEG::scan_option_line(line, key, val) ) continue;
1752 av_dict_set(&ff_opts, key, val, 0);
1756 void FFOptionsDialog::store_options(char *cp, int len)
1758 char *ep = cp + len-1;
1759 AVDictionaryEntry *elem = 0;
1760 while( (elem=av_dict_get(ff_opts, "", elem, AV_DICT_IGNORE_SUFFIX)) != 0 ) {
1761 if( elem->key[0] == '#' ) {
1762 cp += snprintf(cp,ep-cp, "%s\n", elem->value);
1765 cp += snprintf(cp,ep-cp, "%s=%s\n", elem->key, elem->value);
1771 void FFOptionsDialog::start()
1773 if( options_window ) {
1774 options_window->lock_window("FFOptionsDialog::start");
1775 options_window->raise_window();
1776 options_window->unlock_window();
1779 cfg_window->get_pop_cursor(wx, wy);
1780 cfg_window->read_options();
1781 BC_DialogThread::start();
1784 BC_Window* FFOptionsDialog::new_gui()
1786 options_window = new FFOptionsWindow(this, wx, wy);
1787 options_window->create_objects();
1788 return options_window;
1791 void FFOptionsDialog::handle_done_event(int result)
1794 cfg_window->lock_window("FFMPEGConfigFormat::save_options");
1795 cfg_window->save_options();
1796 cfg_window->unlock_window();
1801 FFOptionsAudioDialog::FFOptionsAudioDialog(FFMPEGConfigAudio *aud_config)
1802 : FFOptionsDialog(aud_config)
1804 this->aud_config = aud_config;
1807 FFOptionsAudioDialog::~FFOptionsAudioDialog()
1812 void FFOptionsAudioDialog::update_options(const char *options)
1814 aud_config->lock_window("FFOptionsAudioDialog::update_options");
1815 aud_config->audio_options->update(options);
1816 aud_config->unlock_window();
1819 FFOptionsVideoDialog::FFOptionsVideoDialog(FFMPEGConfigVideo *vid_config)
1820 : FFOptionsDialog(vid_config)
1822 this->vid_config = vid_config;
1825 FFOptionsVideoDialog::~FFOptionsVideoDialog()
1830 void FFOptionsVideoDialog::update_options(const char *options)
1832 vid_config->lock_window("FFOptionsVideoDialog::update_options");
1833 vid_config->video_options->update(options);
1834 vid_config->unlock_window();
1837 FFOptionsFormatDialog::FFOptionsFormatDialog(FFMPEGConfigFormat *fmt_config)
1838 : FFOptionsDialog(fmt_config)
1840 this->fmt_config = fmt_config;
1843 FFOptionsFormatDialog::~FFOptionsFormatDialog()
1848 void FFOptionsFormatDialog::update_options(const char *options)
1850 fmt_config->lock_window("FFOptionsFormatDialog::update_options");
1851 fmt_config->format_options->update(options);
1852 fmt_config->unlock_window();
1856 FFOptionsViewAudio::FFOptionsViewAudio(FFMPEGConfigAudio *aud_config,
1857 int x, int y, const char *text)
1858 : BC_GenericButton(x, y, text)
1860 this->aud_config = aud_config;
1864 FFOptionsViewAudio::~FFOptionsViewAudio()
1866 avcodec_free_context(&avctx);
1869 int FFOptionsViewAudio::handle_event()
1872 Asset *asset = aud_config->asset;
1873 const char *name = asset->acodec;
1874 char audio_format[BCSTRLEN]; audio_format[0] = 0;
1875 char audio_codec[BCSTRLEN]; audio_codec[0] = 0;
1876 const AVCodec *codec = !ret &&
1877 !FFMPEG::get_format(audio_format, "audio", name) &&
1878 !FFMPEG::get_codec(audio_codec, "audio", name) ?
1879 avcodec_find_encoder_by_name(audio_codec) : 0;
1880 if( !ret && !codec ) {
1881 eprintf(_("no codec named: %s: %s"), name, audio_codec);
1884 avcodec_free_context(&avctx);
1885 if( !ret && !(avctx = avcodec_alloc_context3(codec)) ) {
1886 eprintf(_("no codec context: %s: %s"), name, audio_codec);
1890 aud_config->start(avctx);
1894 FFOptionsViewVideo::FFOptionsViewVideo(FFMPEGConfigVideo *vid_config,
1895 int x, int y, const char *text)
1896 : BC_GenericButton(x, y, text)
1898 this->vid_config = vid_config;
1902 FFOptionsViewVideo::~FFOptionsViewVideo()
1904 avcodec_free_context(&avctx);
1907 int FFOptionsViewVideo::handle_event()
1910 Asset *asset = vid_config->asset;
1911 const char *name = asset->vcodec;
1912 char video_format[BCSTRLEN]; video_format[0] = 0;
1913 char video_codec[BCSTRLEN]; video_codec[0] = 0;
1914 const AVCodec *codec = !ret &&
1915 !FFMPEG::get_format(video_format, "video", name) &&
1916 !FFMPEG::get_codec(video_codec, "video", name) ?
1917 avcodec_find_encoder_by_name(video_codec) : 0;
1918 if( !ret && !codec ) {
1919 eprintf(_("no codec named: %s: %s"), name, video_codec);
1922 avcodec_free_context(&avctx);
1923 if( !ret && !(avctx = avcodec_alloc_context3(codec)) ) {
1924 eprintf(_("no codec context: %s: %s"), name, video_codec);
1929 vid_config->start(avctx);
1933 FFOptionsViewFormat::FFOptionsViewFormat(FFMPEGConfigWindow *cfg_window,
1934 EDL *edl, Asset *asset, int x, int y, const char *text)
1935 : BC_GenericButton(x, y, text)
1937 this->cfg_window = cfg_window;
1939 this->asset = asset;
1943 FFOptionsViewFormat::~FFOptionsViewFormat()
1945 delete format_dialog;
1948 int FFOptionsViewFormat::handle_event()
1950 delete format_dialog;
1952 get_pop_cursor(wx, wy);
1953 format_dialog = new FFOptionsFormatViewDialog(this, wx, wy);
1954 format_dialog->start();
1959 FFOptionsFormatView::FFOptionsFormatView(FFMPEGConfigFormat *fmt_config,
1960 int x, int y, const char *text)
1961 : BC_GenericButton(x, y, text)
1963 this->fmt_config = fmt_config;
1967 FFOptionsFormatView::~FFOptionsFormatView()
1969 avformat_free_context(fmt_ctx);
1972 int FFOptionsFormatView::handle_event()
1974 Asset *asset = fmt_config->asset;
1975 char *format_name = asset->fformat;
1976 char replace_name0[] = "mov";
1977 char replace_name1[] = "mpegts";
1978 char replace_name2[] = "matroska";
1979 if (!strcmp(format_name, "qt"))
1980 format_name = replace_name0; // fixup
1981 if (!strcmp(format_name, "m2ts"))
1982 format_name = replace_name1; // fixup
1983 if (!strcmp(format_name, "mkv"))
1984 format_name = replace_name2; // fixup
1985 avformat_free_context(fmt_ctx); fmt_ctx = 0;
1986 int ret = avformat_alloc_output_context2(&fmt_ctx, 0, format_name, 0);
1987 if( ret || !fmt_ctx ) {
1988 eprintf(_("no format named: %s"), format_name);
1992 fmt_config->start(fmt_ctx);
1996 FFOptionsFormatViewDialog::FFOptionsFormatViewDialog(FFOptionsViewFormat *view_format,
1999 this->view_format = view_format;
2005 FFOptionsFormatViewDialog::~FFOptionsFormatViewDialog()
2010 BC_Window *FFOptionsFormatViewDialog::new_gui()
2012 cfg_window = new FFMPEGConfigFormat(this, wx, wy,
2013 view_format->asset, view_format->edl);
2014 cfg_window->create_objects();
2015 cfg_window->read_options();
2019 void FFOptionsFormatViewDialog::handle_done_event(int result)
2022 cfg_window->save_changes();