Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / fileffmpeg.C
index 0db64205be373bff1a33959de608a51b5da4438c..2fbf6c86f80327055b703295b5d66017895aaf0e 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2010 Monty Montgomery
+ * Copyright (C) 2012-2014 Paolo Rampino
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
 
 #include <stdio.h>
 #include <stdint.h>
@@ -159,7 +180,7 @@ void FFMpegPixelFormat::update_formats()
        pixfmts.remove_all_objects();
        char video_codec[BCSTRLEN]; video_codec[0] = 0;
        const char *vcodec = vid_config->asset->vcodec;
-       AVCodec *av_codec = !FFMPEG::get_codec(video_codec, "video", vcodec) ?
+       const AVCodec *av_codec = !FFMPEG::get_codec(video_codec, "video", vcodec) ?
                avcodec_find_encoder_by_name(video_codec) : 0;
        const AVPixelFormat *pix_fmts = av_codec ? av_codec->pix_fmts : 0;
        if( pix_fmts ) {
@@ -190,7 +211,7 @@ void FFMpegSampleFormat::update_formats()
        samplefmts.remove_all_objects();
        char audio_codec[BCSTRLEN]; audio_codec[0] = 0;
        const char *acodec = aud_config->asset->acodec;
-       AVCodec *av_codec = !FFMPEG::get_codec(audio_codec, "audio", acodec) ?
+       const AVCodec *av_codec = !FFMPEG::get_codec(audio_codec, "audio", acodec) ?
                avcodec_find_encoder_by_name(audio_codec) : 0;
        const AVSampleFormat *sample_fmts = av_codec ? av_codec->sample_fmts : 0;
        if( sample_fmts ) {
@@ -326,7 +347,7 @@ int FileFFMPEG::open_file(int rd, int wr)
        int result = 0;
        if( ff ) return 1;
        ff = new FFMPEG(this);
-
+       
        if( rd ) {
                result = ff->init_decoder(asset->path);
                if( !result ) result = ff->open_decoder();
@@ -342,6 +363,12 @@ int FileFFMPEG::open_file(int rd, int wr)
                        int video_layers = ff->ff_total_video_layers();
                        if( video_layers > 0 ) {
                                asset->video_data = 1;
+                               asset->aspect_ratio = ff->ff_aspect_ratio(0);
+                               if (!asset->interlace_mode) asset->interlace_mode = ff->ff_interlace(0);
+                               if ( ff->ff_video_frames(0) > 1 ) {
+//                             ff->video_probe(1);
+                                if (!asset->interlace_mode && (ff->interlace_from_codec) ) asset->interlace_mode = ff->video_probe(1); 
+                               }
                                if( !asset->layers ) asset->layers = video_layers;
                                asset->actual_width = ff->ff_video_width(0);
                                asset->actual_height = ff->ff_video_height(0);
@@ -355,7 +382,7 @@ int FileFFMPEG::open_file(int rd, int wr)
                                        asset->ff_color_range = ff->ff_color_range(0);
                                if( asset->ff_color_space < 0 )
                                        asset->ff_color_space = ff->ff_color_space(0);
-                               strcpy(asset->vcodec, ff->ff_video_format(0));
+                               strcpy(asset->vcodec, ff->ff_video_codec(0));
                        }
                        IndexState *index_state = asset->index_state;
                        index_state->read_markers(file->preferences->index_directory, asset->path);
@@ -474,8 +501,9 @@ FFMPEGConfigWindow::FFMPEGConfigWindow(const char *title,
        this->parent_window = parent_window;
        this->asset = asset;
        this->edl = edl;
+       avctx = 0;
+       fmt_ctx = 0;
        ff_options_dialog = 0;
-       obj = 0;
        format_name = 0;
        codec_name = 0;
 }
@@ -485,9 +513,15 @@ FFMPEGConfigWindow::~FFMPEGConfigWindow()
        delete ff_options_dialog;
 }
 
-void FFMPEGConfigWindow::start(const void *obj)
+void FFMPEGConfigWindow::start(AVCodecContext *avctx)
 {
-       this->obj = obj;
+       this->avctx = avctx;
+       ff_options_dialog->start();
+}
+
+void FFMPEGConfigWindow::start(AVFormatContext *fmt_ctx)
+{
+       this->fmt_ctx = fmt_ctx;
        ff_options_dialog->start();
 }
 
@@ -503,6 +537,8 @@ FFMPEGConfigAudio::FFMPEGConfigAudio(BC_WindowBase *parent_window,
        audio_options = 0;
        format_name = asset->fformat;
        codec_name = asset->acodec;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Options for Render with FFmpeg");
 }
 
 FFMPEGConfigAudio::~FFMPEGConfigAudio()
@@ -514,11 +550,17 @@ FFMPEGConfigAudio::~FFMPEGConfigAudio()
        unlock_window();
 }
 
-char *FFMPEGConfigAudio::get_options() {
-       return asset->ff_audio_options;
+void FFMPEGConfigAudio::read_options()
+{
+       const char *options = audio_options->get_text();
+       int options_len = strlen(options);
+       ff_options_dialog->load_options(options, options_len);
 }
-int FFMPEGConfigAudio::get_options_len() {
-       return sizeof(asset->ff_audio_options)-1;
+void FFMPEGConfigAudio::save_options()
+{
+       char options[BCTEXTLEN];
+       ff_options_dialog->store_options(options, sizeof(options)-1);
+       audio_options->update(options);
 }
 
 void FFMPEGConfigAudio::load_options()
@@ -662,6 +704,8 @@ FFMPEGConfigVideo::FFMPEGConfigVideo(BC_WindowBase *parent_window,
        bitrate = 0;
        quality = 0;
        video_options = 0;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Options for Render with FFmpeg");
 }
 
 FFMPEGConfigVideo::~FFMPEGConfigVideo()
@@ -674,11 +718,17 @@ FFMPEGConfigVideo::~FFMPEGConfigVideo()
        unlock_window();
 }
 
-char *FFMPEGConfigVideo::get_options() {
-       return asset->ff_video_options;
+void FFMPEGConfigVideo::read_options()
+{
+       const char *options = video_options->get_text();
+       int options_len = strlen(options);
+       ff_options_dialog->load_options(options, options_len);
 }
-int FFMPEGConfigVideo::get_options_len() {
-       return sizeof(asset->ff_video_options)-1;
+void FFMPEGConfigVideo::save_options()
+{
+       char options[BCTEXTLEN];
+       ff_options_dialog->store_options(options, sizeof(options)-1);
+       video_options->update(options);
 }
 
 void FFMPEGConfigVideo::load_options()
@@ -822,6 +872,8 @@ FFMPEGConfigFormat::FFMPEGConfigFormat(FFOptionsFormatViewDialog *view_dialog,
        format_options = 0;
        format_name = asset->fformat;
        codec_name = 0;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Modifying FFmpeg Format Options");
 }
 
 FFMPEGConfigFormat::~FFMPEGConfigFormat()
@@ -831,11 +883,24 @@ FFMPEGConfigFormat::~FFMPEGConfigFormat()
        unlock_window();
 }
 
-char *FFMPEGConfigFormat::get_options() {
-       return asset->ff_format_options;
+void FFMPEGConfigFormat::read_options()
+{
+       const char *options = format_options->get_text();
+       int options_len = strlen(options);
+       ff_options_dialog->load_options(options, options_len);
 }
-int FFMPEGConfigFormat::get_options_len() {
-       return sizeof(asset->ff_format_options)-1;
+void FFMPEGConfigFormat::save_options()
+{
+       char options[BCTEXTLEN];
+       ff_options_dialog->store_options(options, sizeof(options)-1);
+       format_options->update(options);
+}
+void FFMPEGConfigFormat::save_changes()
+{
+       read_options();
+       char *options = asset->ff_format_options;
+       int options_len = sizeof(asset->ff_format_options)-1;
+       ff_options_dialog->store_options(options, options_len);
 }
 
 void FFMPEGConfigFormat::load_options()
@@ -1064,7 +1129,7 @@ char *FFOptions_Opt::get(char *vp, int sz)
        void *obj = (void *)options->obj;
        uint8_t *bp = 0;
        if( av_opt_get(obj, opt->name, 0, &bp) >= 0 && bp != 0 ) {
-       const char *val = (const char *)bp;
+               const char *val = (const char *)bp;
                if( opt->unit && *val ) {
                        int id = atoi(val);
                        const char *uid = unit_name(id);
@@ -1102,6 +1167,7 @@ int FFOptionsKindItem::handle_event()
        FFOptionsWindow *fwin = kind->fwin;
        FFOptions &options = fwin->options;
        options.initialize(fwin, idx);
+       kind->set_text(get_text());
        fwin->draw();
        return 1;
 }
@@ -1212,14 +1278,12 @@ int FFOptionsApply::handle_event()
 
 FFOptions::FFOptions()
 {
-       avctx = 0;
        obj = 0;
 }
 
 FFOptions::~FFOptions()
 {
        remove_all_objects();
-       avcodec_free_context(&avctx);
 }
 
 int FFOptions::cmpr(const void *a, const void *b)
@@ -1234,9 +1298,21 @@ int FFOptions::cmpr(const void *a, const void *b)
 void FFOptions::initialize(FFOptionsWindow *win, int kind)
 {
        remove_all_objects();
-       this->win = win;
        win->selected = 0;
-       obj = win->dialog->cfg_window->obj;
+       const void *obj = 0;
+       switch( kind ) {
+       case FF_KIND_CODEC:
+               obj = (const void *)win->dialog->cfg_window->avctx->priv_data;
+               break;
+       case FF_KIND_FFMPEG:
+               obj = (const void *)win->dialog->cfg_window->avctx;
+               break;
+       case FF_KIND_FORMAT:
+               obj = (const void *)win->dialog->cfg_window->fmt_ctx->priv_data;
+               break;
+       }
+       this->win = win;
+       this->obj = obj;
        if( obj ) {
                FFOptions &conf = *this;
                const AVOption *opt = 0;
@@ -1263,8 +1339,6 @@ void FFOptions::initialize(FFOptionsWindow *win, int kind)
                }
                qsort(&values[0],size(),sizeof(values[0]),cmpr);
        }
-       if( win->kind )
-               win->kind->set(kind);
        win->panel->update();
        win->panel->set_yposition(0);
 }
@@ -1546,6 +1620,8 @@ FFOptionsWindow::FFOptionsWindow(FFOptionsDialog *dialog, int x, int y)
        this->dialog = dialog;
        this->selected = 0;
        this->kind = 0;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("Modifying FFmpeg Format Options");
 }
 
 FFOptionsWindow::~FFOptionsWindow()
@@ -1603,7 +1679,10 @@ void FFOptionsWindow::create_objects()
        add_subwindow(new BC_OKButton(this));
        add_subwindow(new BC_CancelButton(this));
        panel->create_objects();
-       options.initialize(this, codec_name ? FF_KIND_CODEC : FF_KIND_FORMAT);
+       int k = codec_name ? FF_KIND_CODEC : FF_KIND_FORMAT;
+       options.initialize(this, k);
+       if( kind )
+               kind->set(k);
        draw();
        show_window(1);
        unlock_window();
@@ -1653,6 +1732,7 @@ FFOptionsDialog::~FFOptionsDialog()
 
 void FFOptionsDialog::load_options(const char *bp, int len)
 {
+       av_dict_free(&ff_opts);
        char line[BCTEXTLEN];
        char key[BCSTRLEN], val[BCTEXTLEN];
        const char *dp = bp + len-1;
@@ -1687,6 +1767,7 @@ void FFOptionsDialog::store_options(char *cp, int len)
        *cp = 0;
 }
 
+
 void FFOptionsDialog::start()
 {
        if( options_window ) {
@@ -1696,9 +1777,7 @@ void FFOptionsDialog::start()
                return;
        }
        cfg_window->get_pop_cursor(wx, wy);
-       char *options = cfg_window->get_options();
-       int options_len = cfg_window->get_options_len();
-       load_options(options, options_len);
+       cfg_window->read_options();
        BC_DialogThread::start();
 }
 
@@ -1712,10 +1791,9 @@ BC_Window* FFOptionsDialog::new_gui()
 void FFOptionsDialog::handle_done_event(int result)
 {
        if( !result ) {
-               char *options = cfg_window->get_options();
-               int options_len = cfg_window->get_options_len();
-               store_options(options, options_len);
-               update_options(options);
+               cfg_window->lock_window("FFMPEGConfigFormat::save_options");
+               cfg_window->save_options();
+               cfg_window->unlock_window();
        }
        options_window = 0;
 }
@@ -1793,9 +1871,9 @@ int FFOptionsViewAudio::handle_event()
        int ret = 0;
        Asset *asset = aud_config->asset;
        const char *name = asset->acodec;
-       char *audio_format = aud_config->format_name;
-       char *audio_codec = aud_config->codec_name;
-       AVCodec *codec = !ret &&
+       char audio_format[BCSTRLEN];  audio_format[0] = 0;
+       char audio_codec[BCSTRLEN];   audio_codec[0] = 0;
+       const AVCodec *codec = !ret &&
            !FFMPEG::get_format(audio_format, "audio", name) &&
            !FFMPEG::get_codec(audio_codec, "audio", name) ?
                avcodec_find_encoder_by_name(audio_codec) : 0;
@@ -1808,10 +1886,8 @@ int FFOptionsViewAudio::handle_event()
                eprintf(_("no codec context: %s: %s"), name, audio_codec);
                ret = 1;
        }
-       if( !ret ) {
-               const void *obj = avctx->priv_data;
-               aud_config->start(obj);
-       }
+       if( !ret )
+               aud_config->start(avctx);
        return 1;
 }
 
@@ -1833,9 +1909,9 @@ int FFOptionsViewVideo::handle_event()
        int ret = 0;
        Asset *asset = vid_config->asset;
        const char *name = asset->vcodec;
-       char *video_format = vid_config->format_name;
-       char *video_codec = vid_config->codec_name;
-       AVCodec *codec = !ret &&
+       char video_format[BCSTRLEN];  video_format[0] = 0;
+       char video_codec[BCSTRLEN];   video_codec[0] = 0;
+       const AVCodec *codec = !ret &&
            !FFMPEG::get_format(video_format, "video", name) &&
            !FFMPEG::get_codec(video_codec, "video", name) ?
                avcodec_find_encoder_by_name(video_codec) : 0;
@@ -1849,18 +1925,16 @@ int FFOptionsViewVideo::handle_event()
                ret = 1;
        }
 
-       if( !ret ) {
-               const void *obj = (const void *)avctx->priv_data;
-               vid_config->start(obj);
-       }
+       if( !ret )
+               vid_config->start(avctx);
        return 1;
 }
 
-FFOptionsViewFormat::FFOptionsViewFormat(BC_WindowBase *parent_window,
+FFOptionsViewFormat::FFOptionsViewFormat(FFMPEGConfigWindow *cfg_window,
                EDL *edl, Asset *asset, int x, int y, const char *text)
  : BC_GenericButton(x, y, text)
 {
-       this->parent_window = parent_window;
+       this->cfg_window = cfg_window;
        this->edl = edl;
        this->asset = asset;
        format_dialog = 0;
@@ -1899,16 +1973,23 @@ int FFOptionsFormatView::handle_event()
 {
        Asset *asset = fmt_config->asset;
        char *format_name = asset->fformat;
+       char replace_name0[] = "mov";
+       char replace_name1[] = "mpegts";
+       char replace_name2[] = "matroska";
+       if (!strcmp(format_name, "qt"))
+               format_name = replace_name0; // fixup
+       if (!strcmp(format_name, "m2ts"))
+               format_name = replace_name1; // fixup
+       if (!strcmp(format_name, "mkv"))
+               format_name = replace_name2; // fixup
        avformat_free_context(fmt_ctx);  fmt_ctx = 0;
        int ret = avformat_alloc_output_context2(&fmt_ctx, 0, format_name, 0);
        if( ret || !fmt_ctx ) {
                eprintf(_("no format named: %s"), format_name);
                ret = 1;
        }
-       if( !ret ) {
-               const void *obj = fmt_ctx->priv_data;
-               fmt_config->start(obj);
-       }
+       if( !ret )
+               fmt_config->start(fmt_ctx);
        return 1;
 }
 
@@ -1931,17 +2012,14 @@ BC_Window *FFOptionsFormatViewDialog::new_gui()
        cfg_window = new FFMPEGConfigFormat(this, wx, wy,
                view_format->asset, view_format->edl);
        cfg_window->create_objects();
+       cfg_window->read_options();
        return cfg_window;
 }
 
 void FFOptionsFormatViewDialog::handle_done_event(int result)
 {
-       if( !result ) {
-               char *options = cfg_window->get_options();
-               int options_len = cfg_window->get_options_len();
-               cfg_window->ff_options_dialog->store_options(options, options_len);
-               cfg_window->ff_options_dialog->update_options(options);
-       }
+       if( !result )
+               cfg_window->save_changes();
        cfg_window = 0;
 }