]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/utils.c
lavc: limit realloc() on encoding to the libav compatibility API.
[ffmpeg] / libavcodec / utils.c
index 74206720ca607ac0d8317e20d45b04de908ac2e4..e918024ca5626796d1dc690488b0f88781ac05cf 100644 (file)
@@ -115,15 +115,15 @@ static void avcodec_init(void)
         return;
     initialized = 1;
 
-    dsputil_static_init();
+    ff_dsputil_static_init();
 }
 
-static av_always_inline int codec_is_encoder(AVCodec *codec)
+int av_codec_is_encoder(AVCodec *codec)
 {
     return codec && (codec->encode || codec->encode2);
 }
 
-static av_always_inline int codec_is_decoder(AVCodec *codec)
+int av_codec_is_decoder(AVCodec *codec)
 {
     return codec && codec->decode;
 }
@@ -178,6 +178,7 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
     case PIX_FMT_YUVJ440P:
     case PIX_FMT_YUVJ444P:
     case PIX_FMT_YUVA420P:
+    case PIX_FMT_YUVA444P:
     case PIX_FMT_YUV420P9LE:
     case PIX_FMT_YUV420P9BE:
     case PIX_FMT_YUV420P10LE:
@@ -244,18 +245,6 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
 
     for (i = 0; i < 4; i++)
         linesize_align[i] = STRIDE_ALIGN;
-//STRIDE_ALIGN is 8 for SSE* but this does not work for SVQ1 chroma planes
-//we could change STRIDE_ALIGN to 16 for x86/sse but it would increase the
-//picture size unneccessarily in some cases. The solution here is not
-//pretty and better ideas are welcome!
-#if HAVE_MMX
-    if(s->codec_id == CODEC_ID_SVQ1 || s->codec_id == CODEC_ID_VP5 ||
-       s->codec_id == CODEC_ID_VP6 || s->codec_id == CODEC_ID_VP6F ||
-       s->codec_id == CODEC_ID_VP6A || s->codec_id == CODEC_ID_DIRAC) {
-        for (i = 0; i < 4; i++)
-            linesize_align[i] = 16;
-    }
-#endif
 }
 
 void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height){
@@ -308,7 +297,7 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
     }
 
     if ((ret = av_samples_fill_arrays(frame->extended_data, &frame->linesize[0],
-                                      buf, nb_channels, frame->nb_samples,
+                                      (uint8_t *)(intptr_t)buf, nb_channels, frame->nb_samples,
                                       sample_fmt, align)) < 0) {
         if (frame->extended_data != frame->data)
             av_freep(&frame->extended_data);
@@ -425,7 +414,7 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
         return -1;
     }
 
-    if(av_image_check_size(w, h, 0, s))
+    if(av_image_check_size(w, h, 0, s) || s->pix_fmt<0)
         return -1;
 
     if (!avci->buffer) {
@@ -614,6 +603,8 @@ int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic){
         return s->get_buffer(s, pic);
     }
 
+    assert(s->pix_fmt == pic->format);
+
     /* If internal buffer type return the same buffer */
     if(pic->type == FF_BUFFER_TYPE_INTERNAL) {
         return 0;
@@ -688,6 +679,29 @@ static void avcodec_get_subtitle_defaults(AVSubtitle *sub)
     sub->pts = AV_NOPTS_VALUE;
 }
 
+static int get_bit_rate(AVCodecContext *ctx)
+{
+    int bit_rate;
+    int bits_per_sample;
+
+    switch(ctx->codec_type) {
+    case AVMEDIA_TYPE_VIDEO:
+    case AVMEDIA_TYPE_DATA:
+    case AVMEDIA_TYPE_SUBTITLE:
+    case AVMEDIA_TYPE_ATTACHMENT:
+        bit_rate = ctx->bit_rate;
+        break;
+    case AVMEDIA_TYPE_AUDIO:
+        bits_per_sample = av_get_bits_per_sample(ctx->codec_id);
+        bit_rate = bits_per_sample ? ctx->sample_rate * ctx->channels * bits_per_sample : ctx->bit_rate;
+        break;
+    default:
+        bit_rate = 0;
+        break;
+    }
+    return bit_rate;
+}
+
 #if FF_API_AVCODEC_OPEN
 int attribute_align_arg avcodec_open(AVCodecContext *avctx, AVCodec *codec)
 {
@@ -748,7 +762,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
             goto end;
         }
         if (codec->priv_class) {
-            *(AVClass**)avctx->priv_data= codec->priv_class;
+            *(const AVClass**)avctx->priv_data= codec->priv_class;
             av_opt_set_defaults(avctx->priv_data);
         }
       }
@@ -784,7 +798,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
 
     /* if the decoder init function was already called previously,
        free the already allocated subtitle_header before overwriting it */
-    if (codec_is_decoder(codec))
+    if (av_codec_is_decoder(codec))
         av_freep(&avctx->subtitle_header);
 
 #define SANE_NB_CHANNELS 128U
@@ -831,7 +845,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
         ret = AVERROR(EINVAL);
         goto free_and_end;
     }
-    if (codec_is_encoder(avctx->codec)) {
+    if (av_codec_is_encoder(avctx->codec)) {
         int i;
         if (avctx->codec->sample_fmts) {
             for (i = 0; avctx->codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++)
@@ -843,6 +857,16 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
                 goto free_and_end;
             }
         }
+        if (avctx->codec->pix_fmts) {
+            for (i = 0; avctx->codec->pix_fmts[i] != PIX_FMT_NONE; i++)
+                if (avctx->pix_fmt == avctx->codec->pix_fmts[i])
+                    break;
+            if (avctx->codec->pix_fmts[i] == PIX_FMT_NONE) {
+                av_log(avctx, AV_LOG_ERROR, "Specified pix_fmt is not supported\n");
+                ret = AVERROR(EINVAL);
+                goto free_and_end;
+            }
+        }
         if (avctx->codec->supported_samplerates) {
             for (i = 0; avctx->codec->supported_samplerates[i] != 0; i++)
                 if (avctx->sample_rate == avctx->codec->supported_samplerates[i])
@@ -890,6 +914,9 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
         }
     }
 
+    if (av_codec_is_decoder(avctx->codec) && !avctx->bit_rate)
+        avctx->bit_rate = get_bit_rate(avctx);
+
     ret=0;
 end:
     entangled_thread_counter--;
@@ -912,37 +939,60 @@ free_and_end:
     goto end;
 }
 
-int ff_alloc_packet(AVPacket *avpkt, int size)
+int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int size)
 {
-    if (size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
+    if (size < 0 || avpkt->size < 0 || size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+        av_log(avctx, AV_LOG_ERROR, "Size %d invalid\n", size);
         return AVERROR(EINVAL);
+    }
+
+    av_assert0(!avpkt->data || avpkt->data != avctx->internal->byte_buffer);
+    if (!avpkt->data || avpkt->size < size) {
+        av_fast_padded_malloc(&avctx->internal->byte_buffer, &avctx->internal->byte_buffer_size, size);
+        avpkt->data = avctx->internal->byte_buffer;
+        avpkt->size = avctx->internal->byte_buffer_size;
+        avpkt->destruct = NULL;
+    }
 
     if (avpkt->data) {
-        uint8_t *pkt_data;
+        void *destruct = avpkt->destruct;
 
-        if (avpkt->size < size)
+        if (avpkt->size < size) {
+            av_log(avctx, AV_LOG_ERROR, "User packet is too small (%d < %d)\n", avpkt->size, size);
             return AVERROR(EINVAL);
+        }
 
-        pkt_data = avpkt->data;
         av_init_packet(avpkt);
-        avpkt->data = pkt_data;
+        avpkt->destruct = destruct;
         avpkt->size = size;
         return 0;
     } else {
-        return av_new_packet(avpkt, size);
+        int ret = av_new_packet(avpkt, size);
+        if (ret < 0)
+            av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet of size %d\n", size);
+        return ret;
     }
 }
 
+int ff_alloc_packet(AVPacket *avpkt, int size)
+{
+    return ff_alloc_packet2(NULL, avpkt, size);
+}
+
 int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
                                               AVPacket *avpkt,
                                               const AVFrame *frame,
                                               int *got_packet_ptr)
 {
     int ret;
-    int user_packet = !!avpkt->data;
+    AVPacket user_pkt = *avpkt;
     int nb_samples;
+    int needs_realloc = !user_pkt.data;
+
+    *got_packet_ptr = 0;
 
     if (!(avctx->codec->capabilities & CODEC_CAP_DELAY) && !frame) {
+        av_free_packet(avpkt);
         av_init_packet(avpkt);
         avpkt->size = 0;
         return 0;
@@ -963,14 +1013,18 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
     }
 
     if (avctx->codec->encode2) {
-        *got_packet_ptr = 0;
         ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr);
-        if (!ret && *got_packet_ptr &&
-            !(avctx->codec->capabilities & CODEC_CAP_DELAY)) {
-            avpkt->pts = frame->pts;
-            avpkt->duration = av_rescale_q(frame->nb_samples,
-                                           (AVRational){ 1, avctx->sample_rate },
-                                           avctx->time_base);
+        if (!ret && *got_packet_ptr) {
+            if (!(avctx->codec->capabilities & CODEC_CAP_DELAY)) {
+                if (avpkt->pts == AV_NOPTS_VALUE)
+                    avpkt->pts = frame->pts;
+                if (!avpkt->duration)
+                    avpkt->duration = ff_samples_to_time_base(avctx,
+                                                              frame->nb_samples);
+            }
+            avpkt->dts = avpkt->pts;
+        } else {
+            avpkt->size = 0;
         }
     } else {
         /* for compatibility with encoders not supporting encode2(), we need to
@@ -978,7 +1032,7 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
            the size otherwise */
         int fs_tmp   = 0;
         int buf_size = avpkt->size;
-        if (!user_packet) {
+        if (!user_pkt.data) {
             if (avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) {
                 av_assert0(av_get_bits_per_sample(avctx->codec_id) != 0);
                 if (!frame)
@@ -991,10 +1045,10 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
                    implement encode2() */
                 buf_size = 2 * avctx->frame_size * avctx->channels *
                            av_get_bytes_per_sample(avctx->sample_fmt);
-                buf_size += FF_MIN_BUFFER_SIZE;
+                buf_size += 2*FF_MIN_BUFFER_SIZE;
             }
         }
-        if ((ret = ff_alloc_packet(avpkt, buf_size)))
+        if ((ret = ff_alloc_packet2(avctx, avpkt, buf_size)))
             return ret;
 
         /* Encoders using AVCodec.encode() that support
@@ -1015,18 +1069,17 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
             if (!ret) {
                 /* no output. if the packet data was allocated by libavcodec,
                    free it */
-                if (!user_packet)
+                if (!user_pkt.data && avpkt->data != avctx->internal->byte_buffer)
                     av_freep(&avpkt->data);
             } else {
                 if (avctx->coded_frame)
-                    avpkt->pts = avctx->coded_frame->pts;
+                    avpkt->pts = avpkt->dts = avctx->coded_frame->pts;
                 /* Set duration for final small packet. This can be removed
                    once all encoders supporting CODEC_CAP_SMALL_LAST_FRAME use
                    encode2() */
                 if (fs_tmp) {
-                    avpkt->duration = av_rescale_q(avctx->frame_size,
-                                                   (AVRational){ 1, avctx->sample_rate },
-                                                   avctx->time_base);
+                    avpkt->duration = ff_samples_to_time_base(avctx,
+                                                              avctx->frame_size);
                 }
             }
             avpkt->size = ret;
@@ -1037,8 +1090,37 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
         if (fs_tmp)
             avctx->frame_size = fs_tmp;
     }
-    if (!ret)
+    if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) {
+        needs_realloc = 0;
+        if (user_pkt.data) {
+            if (user_pkt.size >= avpkt->size) {
+                memcpy(user_pkt.data, avpkt->data, avpkt->size);
+            } else {
+                av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size);
+                avpkt->size = user_pkt.size;
+                ret = -1;
+            }
+            avpkt->data     = user_pkt.data;
+            avpkt->destruct = user_pkt.destruct;
+        } else {
+            if (av_dup_packet(avpkt) < 0) {
+                ret = AVERROR(ENOMEM);
+            }
+        }
+    }
+
+    if (!ret) {
+        if (needs_realloc && avpkt->data) {
+            uint8_t *new_data = av_realloc(avpkt->data, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
+            if (new_data)
+                avpkt->data = new_data;
+        }
+
         avctx->frame_number++;
+    }
+
+    if (ret < 0 || !*got_packet_ptr)
+        av_free_packet(avpkt);
 
     /* NOTE: if we add any audio encoders which output non-keyframe packets,
              this needs to be moved to the encoders, but for now we can do it
@@ -1092,16 +1174,15 @@ int attribute_align_arg avcodec_encode_audio(AVCodecContext *avctx,
                                                   avctx->sample_fmt, 1);
         if ((ret = avcodec_fill_audio_frame(frame, avctx->channels,
                                             avctx->sample_fmt,
-                                            samples, samples_size, 1)))
+                                            (const uint8_t *)samples, samples_size, 1)))
             return ret;
 
         /* fabricate frame pts from sample count.
            this is needed because the avcodec_encode_audio() API does not have
            a way for the user to provide pts */
         if(avctx->sample_rate && avctx->time_base.num)
-            frame->pts = av_rescale_q(avctx->internal->sample_count,
-                                  (AVRational){ 1, avctx->sample_rate },
-                                  avctx->time_base);
+            frame->pts = ff_samples_to_time_base(avctx,
+                                                avctx->internal->sample_count);
         else
             frame->pts = AV_NOPTS_VALUE;
         avctx->internal->sample_count += frame->nb_samples;
@@ -1125,23 +1206,107 @@ int attribute_align_arg avcodec_encode_audio(AVCodecContext *avctx,
 }
 #endif
 
+#if FF_API_OLD_ENCODE_VIDEO
 int attribute_align_arg avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
                          const AVFrame *pict)
 {
+    AVPacket pkt;
+    int ret, got_packet = 0;
+
     if(buf_size < FF_MIN_BUFFER_SIZE){
         av_log(avctx, AV_LOG_ERROR, "buffer smaller than minimum size\n");
         return -1;
     }
-    if(av_image_check_size(avctx->width, avctx->height, 0, avctx))
-        return -1;
-    if((avctx->codec->capabilities & CODEC_CAP_DELAY) || pict){
-        int ret = avctx->codec->encode(avctx, buf, buf_size, pict);
-        avctx->frame_number++;
-        emms_c(); //needed to avoid an emms_c() call before every return;
 
-        return ret;
-    }else
+    av_init_packet(&pkt);
+    pkt.data = buf;
+    pkt.size = buf_size;
+
+    ret = avcodec_encode_video2(avctx, &pkt, pict, &got_packet);
+    if (!ret && got_packet && avctx->coded_frame) {
+        avctx->coded_frame->pts       = pkt.pts;
+        avctx->coded_frame->key_frame = !!(pkt.flags & AV_PKT_FLAG_KEY);
+    }
+
+    /* free any side data since we cannot return it */
+    if (pkt.side_data_elems > 0) {
+        int i;
+        for (i = 0; i < pkt.side_data_elems; i++)
+            av_free(pkt.side_data[i].data);
+        av_freep(&pkt.side_data);
+        pkt.side_data_elems = 0;
+    }
+
+    return ret ? ret : pkt.size;
+}
+#endif
+
+int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,
+                                              AVPacket *avpkt,
+                                              const AVFrame *frame,
+                                              int *got_packet_ptr)
+{
+    int ret;
+    AVPacket user_pkt = *avpkt;
+    int needs_realloc = !user_pkt.data;
+
+    *got_packet_ptr = 0;
+
+    if (!(avctx->codec->capabilities & CODEC_CAP_DELAY) && !frame) {
+        av_free_packet(avpkt);
+        av_init_packet(avpkt);
+        avpkt->size     = 0;
         return 0;
+    }
+
+    if (av_image_check_size(avctx->width, avctx->height, 0, avctx))
+        return AVERROR(EINVAL);
+
+    av_assert0(avctx->codec->encode2);
+
+    ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr);
+    av_assert0(ret <= 0);
+
+    if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) {
+        needs_realloc = 0;
+        if (user_pkt.data) {
+            if (user_pkt.size >= avpkt->size) {
+                memcpy(user_pkt.data, avpkt->data, avpkt->size);
+            } else {
+                av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size);
+                avpkt->size = user_pkt.size;
+                ret = -1;
+            }
+            avpkt->data     = user_pkt.data;
+            avpkt->destruct = user_pkt.destruct;
+        } else {
+            if (av_dup_packet(avpkt) < 0) {
+                ret = AVERROR(ENOMEM);
+            }
+        }
+    }
+
+    if (!ret) {
+        if (!*got_packet_ptr)
+            avpkt->size = 0;
+        else if (!(avctx->codec->capabilities & CODEC_CAP_DELAY))
+            avpkt->pts = avpkt->dts = frame->pts;
+
+        if (needs_realloc && avpkt->data &&
+            avpkt->destruct == av_destruct_packet) {
+            uint8_t *new_data = av_realloc(avpkt->data, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
+            if (new_data)
+                avpkt->data = new_data;
+        }
+
+        avctx->frame_number++;
+    }
+
+    if (ret < 0 || !*got_packet_ptr)
+        av_free_packet(avpkt);
+
+    emms_c();
+    return ret;
 }
 
 int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
@@ -1153,7 +1318,7 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
         return -1;
     }
 
-    ret = avctx->codec->encode(avctx, buf, buf_size, sub);
+    ret = avctx->codec->encode(avctx, buf, buf_size, (void *)(intptr_t)sub);
     avctx->frame_number++;
     return ret;
 }
@@ -1423,6 +1588,8 @@ av_cold int avcodec_close(AVCodecContext *avctx)
             avctx->codec->close(avctx);
         avcodec_default_free_buffers(avctx);
         avctx->coded_frame = NULL;
+        avctx->internal->byte_buffer_size = 0;
+        av_freep(&avctx->internal->byte_buffer);
         av_freep(&avctx->internal);
     }
 
@@ -1430,7 +1597,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
         av_opt_free(avctx->priv_data);
     av_opt_free(avctx);
     av_freep(&avctx->priv_data);
-    if (codec_is_encoder(avctx->codec))
+    if (av_codec_is_encoder(avctx->codec))
         av_freep(&avctx->extradata);
     avctx->codec = NULL;
     avctx->active_thread_type = 0;
@@ -1459,7 +1626,7 @@ AVCodec *avcodec_find_encoder(enum CodecID id)
     p = first_avcodec;
     id= remap_deprecated_codec_id(id);
     while (p) {
-        if (codec_is_encoder(p) && p->id == id) {
+        if (av_codec_is_encoder(p) && p->id == id) {
             if (p->capabilities & CODEC_CAP_EXPERIMENTAL && !experimental) {
                 experimental = p;
             } else
@@ -1477,7 +1644,7 @@ AVCodec *avcodec_find_encoder_by_name(const char *name)
         return NULL;
     p = first_avcodec;
     while (p) {
-        if (codec_is_encoder(p) && strcmp(name,p->name) == 0)
+        if (av_codec_is_encoder(p) && strcmp(name,p->name) == 0)
             return p;
         p = p->next;
     }
@@ -1490,7 +1657,7 @@ AVCodec *avcodec_find_decoder(enum CodecID id)
     p = first_avcodec;
     id= remap_deprecated_codec_id(id);
     while (p) {
-        if (codec_is_decoder(p) && p->id == id) {
+        if (av_codec_is_decoder(p) && p->id == id) {
             if (p->capabilities & CODEC_CAP_EXPERIMENTAL && !experimental) {
                 experimental = p;
             } else
@@ -1508,36 +1675,13 @@ AVCodec *avcodec_find_decoder_by_name(const char *name)
         return NULL;
     p = first_avcodec;
     while (p) {
-        if (codec_is_decoder(p) && strcmp(name,p->name) == 0)
+        if (av_codec_is_decoder(p) && strcmp(name,p->name) == 0)
             return p;
         p = p->next;
     }
     return NULL;
 }
 
-static int get_bit_rate(AVCodecContext *ctx)
-{
-    int bit_rate;
-    int bits_per_sample;
-
-    switch(ctx->codec_type) {
-    case AVMEDIA_TYPE_VIDEO:
-    case AVMEDIA_TYPE_DATA:
-    case AVMEDIA_TYPE_SUBTITLE:
-    case AVMEDIA_TYPE_ATTACHMENT:
-        bit_rate = ctx->bit_rate;
-        break;
-    case AVMEDIA_TYPE_AUDIO:
-        bits_per_sample = av_get_bits_per_sample(ctx->codec_id);
-        bit_rate = bits_per_sample ? ctx->sample_rate * ctx->channels * bits_per_sample : ctx->bit_rate;
-        break;
-    default:
-        bit_rate = 0;
-        break;
-    }
-    return bit_rate;
-}
-
 const char *avcodec_get_name(enum CodecID id)
 {
     AVCodec *codec;
@@ -1764,21 +1908,15 @@ void avcodec_default_free_buffers(AVCodecContext *avctx)
     }
 }
 
-int av_get_bits_per_sample(enum CodecID codec_id){
+int av_get_exact_bits_per_sample(enum CodecID codec_id)
+{
     switch(codec_id){
-    case CODEC_ID_ADPCM_SBPRO_2:
-        return 2;
-    case CODEC_ID_ADPCM_SBPRO_3:
-        return 3;
-    case CODEC_ID_ADPCM_SBPRO_4:
     case CODEC_ID_ADPCM_CT:
     case CODEC_ID_ADPCM_IMA_APC:
-    case CODEC_ID_ADPCM_IMA_WAV:
-    case CODEC_ID_ADPCM_IMA_QT:
-    case CODEC_ID_ADPCM_SWF:
-    case CODEC_ID_ADPCM_MS:
-    case CODEC_ID_ADPCM_YAMAHA:
+    case CODEC_ID_ADPCM_IMA_EA_SEAD:
+    case CODEC_ID_ADPCM_IMA_WS:
     case CODEC_ID_ADPCM_G722:
+    case CODEC_ID_ADPCM_YAMAHA:
         return 4;
     case CODEC_ID_PCM_ALAW:
     case CODEC_ID_PCM_MULAW:
@@ -1813,6 +1951,187 @@ int av_get_bits_per_sample(enum CodecID codec_id){
     }
 }
 
+enum CodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be)
+{
+    static const enum CodecID map[AV_SAMPLE_FMT_NB][2] = {
+        [AV_SAMPLE_FMT_U8  ] = { CODEC_ID_PCM_U8,    CODEC_ID_PCM_U8    },
+        [AV_SAMPLE_FMT_S16 ] = { CODEC_ID_PCM_S16LE, CODEC_ID_PCM_S16BE },
+        [AV_SAMPLE_FMT_S32 ] = { CODEC_ID_PCM_S32LE, CODEC_ID_PCM_S32BE },
+        [AV_SAMPLE_FMT_FLT ] = { CODEC_ID_PCM_F32LE, CODEC_ID_PCM_F32BE },
+        [AV_SAMPLE_FMT_DBL ] = { CODEC_ID_PCM_F64LE, CODEC_ID_PCM_F64BE },
+        [AV_SAMPLE_FMT_U8P ] = { CODEC_ID_PCM_U8,    CODEC_ID_PCM_U8    },
+        [AV_SAMPLE_FMT_S16P] = { CODEC_ID_PCM_S16LE, CODEC_ID_PCM_S16BE },
+        [AV_SAMPLE_FMT_S32P] = { CODEC_ID_PCM_S32LE, CODEC_ID_PCM_S32BE },
+        [AV_SAMPLE_FMT_FLTP] = { CODEC_ID_PCM_F32LE, CODEC_ID_PCM_F32BE },
+        [AV_SAMPLE_FMT_DBLP] = { CODEC_ID_PCM_F64LE, CODEC_ID_PCM_F64BE },
+    };
+    if (fmt < 0 || fmt >= AV_SAMPLE_FMT_NB)
+        return CODEC_ID_NONE;
+    if (be < 0 || be > 1)
+        be = AV_NE(1, 0);
+    return map[fmt][be];
+}
+
+int av_get_bits_per_sample(enum CodecID codec_id)
+{
+    switch (codec_id) {
+    case CODEC_ID_ADPCM_SBPRO_2:
+        return 2;
+    case CODEC_ID_ADPCM_SBPRO_3:
+        return 3;
+    case CODEC_ID_ADPCM_SBPRO_4:
+    case CODEC_ID_ADPCM_IMA_WAV:
+    case CODEC_ID_ADPCM_IMA_QT:
+    case CODEC_ID_ADPCM_SWF:
+    case CODEC_ID_ADPCM_MS:
+        return 4;
+    default:
+        return av_get_exact_bits_per_sample(codec_id);
+    }
+}
+
+int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
+{
+    int id, sr, ch, ba, tag, bps;
+
+    id  = avctx->codec_id;
+    sr  = avctx->sample_rate;
+    ch  = avctx->channels;
+    ba  = avctx->block_align;
+    tag = avctx->codec_tag;
+    bps = av_get_exact_bits_per_sample(avctx->codec_id);
+
+    /* codecs with an exact constant bits per sample */
+    if (bps > 0 && ch > 0 && frame_bytes > 0)
+        return (frame_bytes * 8) / (bps * ch);
+    bps = avctx->bits_per_coded_sample;
+
+    /* codecs with a fixed packet duration */
+    switch (id) {
+    case CODEC_ID_ADPCM_ADX:    return   32;
+    case CODEC_ID_ADPCM_IMA_QT: return   64;
+    case CODEC_ID_ADPCM_EA_XAS: return  128;
+    case CODEC_ID_AMR_NB:
+    case CODEC_ID_GSM:
+    case CODEC_ID_QCELP:
+    case CODEC_ID_RA_144:
+    case CODEC_ID_RA_288:       return  160;
+    case CODEC_ID_IMC:          return  256;
+    case CODEC_ID_AMR_WB:
+    case CODEC_ID_GSM_MS:       return  320;
+    case CODEC_ID_MP1:          return  384;
+    case CODEC_ID_ATRAC1:       return  512;
+    case CODEC_ID_ATRAC3:       return 1024;
+    case CODEC_ID_MP2:
+    case CODEC_ID_MUSEPACK7:    return 1152;
+    case CODEC_ID_AC3:          return 1536;
+    }
+
+    if (sr > 0) {
+        /* calc from sample rate */
+        if (id == CODEC_ID_TTA)
+            return 256 * sr / 245;
+
+        if (ch > 0) {
+            /* calc from sample rate and channels */
+            if (id == CODEC_ID_BINKAUDIO_DCT)
+                return (480 << (sr / 22050)) / ch;
+        }
+    }
+
+    if (ba > 0) {
+        /* calc from block_align */
+        if (id == CODEC_ID_SIPR) {
+            switch (ba) {
+            case 20: return 160;
+            case 19: return 144;
+            case 29: return 288;
+            case 37: return 480;
+            }
+        }
+    }
+
+    if (frame_bytes > 0) {
+        /* calc from frame_bytes only */
+        if (id == CODEC_ID_TRUESPEECH)
+            return 240 * (frame_bytes / 32);
+        if (id == CODEC_ID_NELLYMOSER)
+            return 256 * (frame_bytes / 64);
+
+        if (bps > 0) {
+            /* calc from frame_bytes and bits_per_coded_sample */
+            if (id == CODEC_ID_ADPCM_G726)
+                return frame_bytes * 8 / bps;
+        }
+
+        if (ch > 0) {
+            /* calc from frame_bytes and channels */
+            switch (id) {
+            case CODEC_ID_ADPCM_4XM:
+            case CODEC_ID_ADPCM_IMA_ISS:
+                return (frame_bytes - 4 * ch) * 2 / ch;
+            case CODEC_ID_ADPCM_IMA_SMJPEG:
+                return (frame_bytes - 4) * 2 / ch;
+            case CODEC_ID_ADPCM_IMA_AMV:
+                return (frame_bytes - 8) * 2 / ch;
+            case CODEC_ID_ADPCM_XA:
+                return (frame_bytes / 128) * 224 / ch;
+            case CODEC_ID_INTERPLAY_DPCM:
+                return (frame_bytes - 6 - ch) / ch;
+            case CODEC_ID_ROQ_DPCM:
+                return (frame_bytes - 8) / ch;
+            case CODEC_ID_XAN_DPCM:
+                return (frame_bytes - 2 * ch) / ch;
+            case CODEC_ID_MACE3:
+                return 3 * frame_bytes / ch;
+            case CODEC_ID_MACE6:
+                return 6 * frame_bytes / ch;
+            case CODEC_ID_PCM_LXF:
+                return 2 * (frame_bytes / (5 * ch));
+            }
+
+            if (tag) {
+                /* calc from frame_bytes, channels, and codec_tag */
+                if (id == CODEC_ID_SOL_DPCM) {
+                    if (tag == 3)
+                        return frame_bytes / ch;
+                    else
+                        return frame_bytes * 2 / ch;
+                }
+            }
+
+            if (ba > 0) {
+                /* calc from frame_bytes, channels, and block_align */
+                int blocks = frame_bytes / ba;
+                switch (avctx->codec_id) {
+                case CODEC_ID_ADPCM_IMA_WAV:
+                    return blocks * (1 + (ba - 4 * ch) / (4 * ch) * 8);
+                case CODEC_ID_ADPCM_IMA_DK3:
+                    return blocks * (((ba - 16) * 2 / 3 * 4) / ch);
+                case CODEC_ID_ADPCM_IMA_DK4:
+                    return blocks * (1 + (ba - 4 * ch) * 2 / ch);
+                case CODEC_ID_ADPCM_MS:
+                    return blocks * (2 + (ba - 7 * ch) * 2 / ch);
+                }
+            }
+
+            if (bps > 0) {
+                /* calc from frame_bytes, channels, and bits_per_coded_sample */
+                switch (avctx->codec_id) {
+                case CODEC_ID_PCM_DVD:
+                    return 2 * (frame_bytes / ((bps * 2 / 8) * ch));
+                case CODEC_ID_PCM_BLURAY:
+                    return frame_bytes / ((FFALIGN(ch, 2) * bps) / 8);
+                case CODEC_ID_S302M:
+                    return 2 * (frame_bytes / ((bps + 4) / 4)) / ch;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
 #if !HAVE_THREADS
 int ff_thread_init(AVCodecContext *s){
     return -1;