[FFmpeg-devel] Fix FFM-based audio streaming from FFmpeg to FFserver

Ronald S. Bultje rsbultje
Thu Mar 25 23:28:09 CET 2010


Hi,

On Tue, Mar 16, 2010 at 6:02 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
> a clone function is usefull, yet another local hack for a special case
> is unmaintainable. It will break in no time, especially without regression
> tests. And with reg tests i know i will curse the continous need to
> fix it after every second addition to AVCodecContext.
> Sorry but i think any design for which a addition to AVCodecContext in
> avcodec.h requires one to go over the source and to update all the local
> hacks that copy it (for rt*p, for ffserver, ...) is not practical

OK, so attached adds a primitive copying function that appears to work
and I think is correct for most pointer-related resources in
AVCodecContext.

Ronald
-------------- next part --------------
Index: ffserver.c
===================================================================
--- ffserver.c	(revision 22655)
+++ ffserver.c	(working copy)
@@ -4039,7 +4039,6 @@
                         filename, line_num);
             } else {
                 FFStream *s;
-                const AVClass *class;
                 stream = av_mallocz(sizeof(FFStream));
                 get_arg(stream->filename, sizeof(stream->filename), &p);
                 q = strrchr(stream->filename, '>');
@@ -4055,15 +4054,8 @@
                 }
 
                 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
-                /* fetch avclass so AVOption works
-                 * FIXME try to use avcodec_get_context_defaults2
-                 * without changing defaults too much */
-                avcodec_get_context_defaults(&video_enc);
-                class = video_enc.av_class;
-                memset(&audio_enc, 0, sizeof(AVCodecContext));
-                memset(&video_enc, 0, sizeof(AVCodecContext));
-                audio_enc.av_class = class;
-                video_enc.av_class = class;
+                avcodec_get_context_defaults2(&video_enc, CODEC_TYPE_VIDEO);
+                avcodec_get_context_defaults2(&audio_enc, CODEC_TYPE_AUDIO);
                 audio_id = CODEC_ID_NONE;
                 video_id = CODEC_ID_NONE;
                 if (stream->fmt) {
Index: ffmpeg.c
===================================================================
--- ffmpeg.c	(revision 22655)
+++ ffmpeg.c	(working copy)
@@ -472,6 +472,36 @@
     return ret;
 }
 
+static void choose_sample_fmt(AVStream *st, AVCodec *codec)
+{
+    if(codec && codec->sample_fmts){
+        const enum SampleFormat *p= codec->sample_fmts;
+        for(; *p!=-1; p++){
+            if(*p == st->codec->sample_fmt)
+                break;
+        }
+        if(*p == -1)
+            st->codec->sample_fmt = codec->sample_fmts[0];
+    }
+}
+
+static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
+{
+    if(codec && codec->pix_fmts){
+        const enum PixelFormat *p= codec->pix_fmts;
+        for(; *p!=-1; p++){
+            if(*p == st->codec->pix_fmt)
+                break;
+        }
+        if(*p == -1
+           && !(   st->codec->codec_id==CODEC_ID_MJPEG
+                && st->codec->strict_std_compliance <= FF_COMPLIANCE_INOFFICIAL
+                && (   st->codec->pix_fmt == PIX_FMT_YUV420P
+                    || st->codec->pix_fmt == PIX_FMT_YUV422P)))
+            st->codec->pix_fmt = codec->pix_fmts[0];
+    }
+}
+
 static int read_ffserver_streams(AVFormatContext *s, const char *filename)
 {
     int i, err;
@@ -485,6 +515,7 @@
     s->nb_streams = ic->nb_streams;
     for(i=0;i<ic->nb_streams;i++) {
         AVStream *st;
+        AVCodec *codec;
 
         // FIXME: a more elegant solution is needed
         st = av_mallocz(sizeof(AVStream));
@@ -494,14 +525,21 @@
             print_error(filename, AVERROR(ENOMEM));
             av_exit(1);
         }
-        memcpy(st->codec, ic->streams[i]->codec, sizeof(AVCodecContext));
+        avcodec_copy_context(st->codec, ic->streams[i]->codec);
         s->streams[i] = st;
 
-        if (st->codec->codec_type == CODEC_TYPE_AUDIO && audio_stream_copy)
-            st->stream_copy = 1;
-        else if (st->codec->codec_type == CODEC_TYPE_VIDEO && video_stream_copy)
-            st->stream_copy = 1;
-
+        codec = avcodec_find_encoder(st->codec->codec_id);
+        if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
+            if (audio_stream_copy) {
+                st->stream_copy = 1;
+            } else
+                choose_sample_fmt(st, codec);
+        } else if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
+            if (video_stream_copy) {
+                st->stream_copy = 1;
+            } else
+                choose_pixel_fmt(st, codec);
+        }
         if(!st->codec->thread_count)
             st->codec->thread_count = 1;
         if(st->codec->thread_count>1)
@@ -3189,19 +3227,7 @@
         video_enc->pix_fmt = frame_pix_fmt;
         st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
 
-        if(codec && codec->pix_fmts){
-            const enum PixelFormat *p= codec->pix_fmts;
-            for(; *p!=-1; p++){
-                if(*p == video_enc->pix_fmt)
-                    break;
-            }
-            if(*p == -1
-               && !(   video_enc->codec_id==CODEC_ID_MJPEG
-                    && video_enc->strict_std_compliance <= FF_COMPLIANCE_INOFFICIAL
-                    && (   video_enc->pix_fmt == PIX_FMT_YUV420P
-                        || video_enc->pix_fmt == PIX_FMT_YUV422P)))
-                video_enc->pix_fmt = codec->pix_fmts[0];
-        }
+        choose_pixel_fmt(st, codec);
 
         if (intra_only)
             video_enc->gop_size = 0;
@@ -3326,16 +3352,7 @@
         audio_enc->channel_layout = channel_layout;
         if (avcodec_channel_layout_num_channels(channel_layout) != audio_channels)
             audio_enc->channel_layout = 0;
-
-        if(codec && codec->sample_fmts){
-            const enum SampleFormat *p= codec->sample_fmts;
-            for(; *p!=-1; p++){
-                if(*p == audio_enc->sample_fmt)
-                    break;
-            }
-            if(*p == -1)
-                audio_enc->sample_fmt = codec->sample_fmts[0];
-        }
+        choose_sample_fmt(st, codec);
     }
     nb_ocodecs++;
     audio_enc->sample_rate = audio_sample_rate;
Index: libavcodec/avcodec.h
===================================================================
--- libavcodec/avcodec.h	(revision 22655)
+++ libavcodec/avcodec.h	(working copy)
@@ -3211,6 +3211,15 @@
 AVCodecContext *avcodec_alloc_context2(enum CodecType);
 
 /**
+ * Copy the settings of the source AVCodecContext into the destination
+ * AVCodecContext. The resulting destination codec context will be
+ * unopened, i.e. you are required to call avcodec_open() before you
+ * can use this AVCodecContext to decode/encode video/audio data.
+ * @returns AVERROR() on error (e.g. memory allocation error), 0 on success.
+ */
+int avcodec_copy_context(AVCodecContext *dest, AVCodecContext *src);
+
+/**
  * Sets the fields of the given AVFrame to default values.
  *
  * @param pic The AVFrame of which the fields should be set to default values.
Index: libavcodec/options.c
===================================================================
--- libavcodec/options.c	(revision 22655)
+++ libavcodec/options.c	(working copy)
@@ -464,3 +464,55 @@
     return avcodec_alloc_context2(CODEC_TYPE_UNKNOWN);
 }
 
+int avcodec_copy_context(AVCodecContext *dest, AVCodecContext *src)
+{
+    memcpy(dest, src, sizeof(*dest));
+
+    /* set values specific to opened codecs back to their default state */
+    dest->priv_data       = NULL;
+    dest->codec           = NULL;
+    dest->palctrl         = NULL;
+    dest->slice_offset    = NULL;
+    dest->internal_buffer = NULL;
+    dest->hwaccel         = NULL;
+    dest->execute         = NULL;
+    dest->execute2        = NULL;
+    dest->reget_buffer    = NULL;
+    dest->thread_opaque   = NULL;
+
+    /* reallocate values that should be allocated separately */
+    if (dest->rc_eq) {
+        dest->rc_eq = av_strdup(src->rc_eq);
+        if (!dest->rc_eq)
+            return AVERROR(ENOMEM);
+    }
+    if (src->extradata && src->extradata_size > 0) {
+        dest->extradata = av_malloc(src->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+        if (!dest->extradata)
+            return AVERROR(ENOMEM);
+        memcpy(dest->extradata, src->extradata, src->extradata_size);
+        memset(dest->extradata + dest->extradata_size, 0,
+               FF_INPUT_BUFFER_PADDING_SIZE);
+    }
+    if (src->intra_matrix) {
+        dest->intra_matrix = av_malloc(64 * sizeof(int16_t));
+        if (!dest->intra_matrix)
+            return AVERROR(ENOMEM);
+        memcpy(dest->intra_matrix, src->intra_matrix, 64 * sizeof(int16_t));
+    }
+    if (src->inter_matrix) {
+        dest->inter_matrix = av_malloc(64 * sizeof(int16_t));
+        if (!dest->inter_matrix)
+            return AVERROR(ENOMEM);
+        memcpy(dest->inter_matrix, src->inter_matrix, 64 * sizeof(int16_t));
+    }
+    if (src->rc_override_count > 0 && src->rc_override) {
+        dest->rc_override = av_malloc(sizeof(*src->rc_override) * src->rc_override_count);
+        if (!dest->rc_override)
+            return AVERROR(ENOMEM);
+        memcpy(dest->rc_override, src->rc_override,
+               dest->rc_override_count * sizeof(*src->rc_override));
+    }
+
+    return 0;
+}



More information about the ffmpeg-devel mailing list