aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2012-05-07 13:55:03 +0200
committerAnton Khirnov <anton@khirnov.net>2012-05-09 17:46:54 +0200
commita5117a2444f3e636ff824ea467bc828d482c68fc (patch)
tree5987200061f5c74ce5b35af47cbcf81a88f8583f /libavcodec
parent6d7f61770094cc80ca2d93c4784c0091411d8242 (diff)
downloadffmpeg-a5117a2444f3e636ff824ea467bc828d482c68fc.tar.gz
lavc: pad last audio frame with silence when needed.
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/avcodec.h10
-rw-r--r--libavcodec/internal.h6
-rw-r--r--libavcodec/utils.c64
-rw-r--r--libavcodec/version.h2
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, \