diff options
author | Anton Khirnov <anton@khirnov.net> | 2012-05-07 13:55:03 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2012-05-09 17:46:54 +0200 |
commit | a5117a2444f3e636ff824ea467bc828d482c68fc (patch) | |
tree | 5987200061f5c74ce5b35af47cbcf81a88f8583f /libavcodec | |
parent | 6d7f61770094cc80ca2d93c4784c0091411d8242 (diff) | |
download | ffmpeg-a5117a2444f3e636ff824ea467bc828d482c68fc.tar.gz |
lavc: pad last audio frame with silence when needed.
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/avcodec.h | 10 | ||||
-rw-r--r-- | libavcodec/internal.h | 6 | ||||
-rw-r--r-- | libavcodec/utils.c | 64 | ||||
-rw-r--r-- | libavcodec/version.h | 2 |
4 files changed, 74 insertions, 8 deletions
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index bec13e7c1a..102df3a7a0 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3860,15 +3860,11 @@ int attribute_deprecated avcodec_encode_audio(AVCodecContext *avctx, * @param[in] frame AVFrame containing the raw audio data to be encoded. * May be NULL when flushing an encoder that has the * CODEC_CAP_DELAY capability set. - * There are 2 codec capabilities that affect the allowed - * values of frame->nb_samples. - * If CODEC_CAP_SMALL_LAST_FRAME is set, then only the final - * frame may be smaller than avctx->frame_size, and all other - * frames must be equal to avctx->frame_size. * If CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame * can have any number of samples. - * If neither is set, frame->nb_samples must be equal to - * avctx->frame_size for all frames. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the * output packet is non-empty, and to 0 if it is * empty. If the function returns an error, the diff --git a/libavcodec/internal.h b/libavcodec/internal.h index bedb2ed85d..57d551d850 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -70,6 +70,12 @@ typedef struct AVCodecInternal { */ int sample_count; #endif + + /** + * An audio frame with less than required samples has been submitted and + * padded with silence. Reject all subsequent frames. + */ + int last_audio_frame; } AVCodecInternal; struct AVCodecDefault { diff --git a/libavcodec/utils.c b/libavcodec/utils.c index ca386646c3..9631c99899 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -857,11 +857,58 @@ int ff_alloc_packet(AVPacket *avpkt, int size) } } +/** + * Pad last frame with silence. + */ +static int pad_last_frame(AVCodecContext *s, AVFrame **dst, const AVFrame *src) +{ + AVFrame *frame = NULL; + uint8_t *buf = NULL; + int ret; + + if (!(frame = avcodec_alloc_frame())) + return AVERROR(ENOMEM); + *frame = *src; + + if ((ret = av_samples_get_buffer_size(&frame->linesize[0], s->channels, + s->frame_size, s->sample_fmt, 0)) < 0) + goto fail; + + if (!(buf = av_malloc(ret))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + frame->nb_samples = s->frame_size; + if ((ret = avcodec_fill_audio_frame(frame, s->channels, s->sample_fmt, + buf, ret, 0)) < 0) + goto fail; + if ((ret = av_samples_copy(frame->extended_data, src->extended_data, 0, 0, + src->nb_samples, s->channels, s->sample_fmt)) < 0) + goto fail; + if ((ret = av_samples_set_silence(frame->extended_data, src->nb_samples, + frame->nb_samples - src->nb_samples, + s->channels, s->sample_fmt)) < 0) + goto fail; + + *dst = frame; + + return 0; + +fail: + if (frame->extended_data != frame->data) + av_freep(&frame->extended_data); + av_freep(&buf); + av_freep(&frame); + return ret; +} + int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { + AVFrame *padded_frame = NULL; int ret; int user_packet = !!avpkt->data; @@ -879,6 +926,16 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, if (frame->nb_samples > avctx->frame_size) return AVERROR(EINVAL); } else if (!(avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) { + if (frame->nb_samples < avctx->frame_size && + !avctx->internal->last_audio_frame) { + ret = pad_last_frame(avctx, &padded_frame, frame); + if (ret < 0) + return ret; + + frame = padded_frame; + avctx->internal->last_audio_frame = 1; + } + if (frame->nb_samples != avctx->frame_size) return AVERROR(EINVAL); } @@ -919,6 +976,13 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, here to simplify things */ avpkt->flags |= AV_PKT_FLAG_KEY; + if (padded_frame) { + av_freep(&padded_frame->data[0]); + if (padded_frame->extended_data != padded_frame->data) + av_freep(&padded_frame->extended_data); + av_freep(&padded_frame); + } + return ret; } diff --git a/libavcodec/version.h b/libavcodec/version.h index be39f4ffca..da7796abb0 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #define LIBAVCODEC_VERSION_MAJOR 54 #define LIBAVCODEC_VERSION_MINOR 13 -#define LIBAVCODEC_VERSION_MICRO 0 +#define LIBAVCODEC_VERSION_MICRO 1 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ |