]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/ffmenc.c
Merge commit 'd639dcdae022130078c9c84b7b691c5e9694786c'
[ffmpeg] / libavformat / ffmenc.c
index 221f0a2cfdc5f3daefd122a792f09559e3dade7c..ef7dc3a03113a3c5fe17245b62613a1b00d32f62 100644 (file)
@@ -95,11 +95,12 @@ static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id)
     av_free(dyn_buf);
 }
 
-static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, int type)
+static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecParameters *ctxpar, unsigned tag, int type)
 {
     AVIOContext *tmp;
     char *buf = NULL;
     int ret, need_coma = 0;
+    AVCodecContext *ctx = NULL;
 
 #define SKIP_DEFAULTS   AV_OPT_SERIALIZE_SKIP_DEFAULTS
 #define OPT_FLAGS_EXACT AV_OPT_SERIALIZE_OPT_FLAGS_EXACT
@@ -107,6 +108,16 @@ static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsi
 
     if (avio_open_dyn_buf(&tmp) < 0)
         return AVERROR(ENOMEM);
+
+    // AVCodecParameters does not suport AVOptions, we thus must copy it over to a context that does
+    // otherwise it could be used directly and this would be much simpler
+    ctx = avcodec_alloc_context3(NULL);
+    if (!ctx) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+    avcodec_parameters_to_context(ctx, ctxpar);
+
     if ((ret = av_opt_serialize(ctx, ENC | type, SKIP_DEFAULTS, &buf, '=', ',')) < 0)
         goto fail;
     if (buf && strlen(buf)) {
@@ -124,10 +135,12 @@ static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsi
     av_freep(&buf);
     avio_w8(tmp, 0);
     write_header_chunk(pb, tmp, tag);
+    avcodec_free_context(&ctx);
     return 0;
   fail:
     av_free(buf);
     ffio_free_dyn_buf(&tmp);
+    avcodec_free_context(&ctx);
     return ret;
 
 #undef SKIP_DEFAULTS
@@ -135,11 +148,11 @@ static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsi
 #undef ENC
 }
 
-static int ffm_write_recommended_config(AVIOContext *pb, AVCodecContext *ctx, unsigned tag,
+static int ffm_write_recommended_config(AVIOContext *pb, AVCodecParameters *codecpar, unsigned tag,
                                         const char *configuration)
 {
     int ret;
-    const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id);
+    const AVCodec *enc = avcodec_find_encoder(codecpar->codec_id);
     AVIOContext *tmp;
     AVDictionaryEntry *t = NULL;
     AVDictionary *all = NULL, *comm = NULL, *prv = NULL;
@@ -194,7 +207,6 @@ static int ffm_write_header(AVFormatContext *s)
     FFMContext *ffm = s->priv_data;
     AVStream *st;
     AVIOContext *pb = s->pb;
-    AVCodecContext *codec;
     AVCodecParameters *codecpar;
     int bit_rate, i, ret;
 
@@ -223,18 +235,27 @@ static int ffm_write_header(AVFormatContext *s)
 
     /* list of streams */
     for(i=0;i<s->nb_streams;i++) {
+        int flags = 0;
         st = s->streams[i];
         avpriv_set_pts_info(st, 64, 1, 1000000);
         if(avio_open_dyn_buf(&pb) < 0)
             return AVERROR(ENOMEM);
 
-        codec = st->codec;
         codecpar = st->codecpar;
         /* generic info */
         avio_wb32(pb, codecpar->codec_id);
         avio_w8(pb, codecpar->codec_type);
         avio_wb32(pb, codecpar->bit_rate);
-        avio_wb32(pb, codecpar->extradata_size ? AV_CODEC_FLAG_GLOBAL_HEADER : 0);
+        if (codecpar->extradata_size)
+            flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+        // If the user is not providing us with a configuration we have to fill it in as we cannot access the encoder
+        if (!st->recommended_encoder_configuration) {
+            if (s->flags & AVFMT_FLAG_BITEXACT)
+                flags |= AV_CODEC_FLAG_BITEXACT;
+        }
+
+        avio_wb32(pb, flags);
         avio_wb32(pb, 0); // flags2
         avio_wb32(pb, 0); // debug
         if (codecpar->extradata_size) {
@@ -248,20 +269,20 @@ static int ffm_write_header(AVFormatContext *s)
             if (st->recommended_encoder_configuration) {
                 av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n",
                        st->recommended_encoder_configuration);
-                if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'V', 'I'),
+                if ((ret = ffm_write_recommended_config(s->pb, codecpar, MKBETAG('S', '2', 'V', 'I'),
                                                         st->recommended_encoder_configuration)) < 0)
                 return ret;
-            } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0)
+            } else if ((ret = ffm_write_header_codec_ctx(s->pb, codecpar, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0)
                 return ret;
             break;
         case AVMEDIA_TYPE_AUDIO:
             if (st->recommended_encoder_configuration) {
                 av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n",
                        st->recommended_encoder_configuration);
-                if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'A', 'U'),
+                if ((ret = ffm_write_recommended_config(s->pb, codecpar, MKBETAG('S', '2', 'A', 'U'),
                                                         st->recommended_encoder_configuration)) < 0)
                 return ret;
-            } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0)
+            } else if ((ret = ffm_write_header_codec_ctx(s->pb, codecpar, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0)
                 return ret;
             break;
         default: