Implement audio support in avcodec_default_get_buffer().
Deprecate avcodec_decode_audio3().
Note: This patch does not work by itself. All audio decoders must be converted
to use the new interface.
---
doc/APIchanges | 7 ++
libavcodec/avcodec.h | 125 +++++++++++++++++++++++++--
libavcodec/internal.h | 3 +
libavcodec/utils.c | 227 ++++++++++++++++++++++++++++++++++++++++++++----
libavcodec/version.h | 5 +-
5 files changed, 337 insertions(+), 30 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index 75ba38e..0b0e847 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,13 @@ libavutil: 2011-04-18
API changes, most recent first:
+2011-xx-xx - xxxxxxx - lavc 53.25.0
+ Add nb_samples and extended_data fields to AVFrame.
+ Deprecate AVCODEC_MAX_AUDIO_FRAME_SIZE.
+ Deprecate avcodec_decode_audio3() in favor of avcodec_decode_audio4().
+ avcodec_decode_audio4() writes output samples to an AVFrame, which allows
+ audio decoders to use get_buffer().
+
2011-xx-xx - xxxxxxx - lavc 53.24.0
Change AVFrame.data[4]/base[4] to [8] at next major bump.
Add AV_NUM_DATA_POINTERS to simplify the bump transition.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 1ea96a6..8d7e8fa 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -480,8 +480,10 @@ enum CodecID {
#define CH_LAYOUT_STEREO_DOWNMIX AV_CH_LAYOUT_STEREO_DOWNMIX
#endif
+#if FF_API_OLD_DECODE_AUDIO
/* in bytes */
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
+#endif
/**
* Required number of additionally allocated bytes at the end of the input
bitstream for decoding.
@@ -933,10 +935,10 @@ typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
#endif
/**
- * pointer to the picture planes.
+ * pointer to the picture/channel planes.
* This might be different from the first allocated byte
- * - encoding:
- * - decoding:
+ * - encoding: Set by user
+ * - decoding: set by AVCodecContext.get_buffer()
*/
uint8_t *data[AV_NUM_DATA_POINTERS];
int linesize[4];
@@ -993,7 +995,7 @@ typedef struct AVFrame {
* buffer age (1->was last buffer and dint change, 2->..., ...).
* Set to INT_MAX if the buffer has not been used yet.
* - encoding: unused
- * - decoding: MUST be set by get_buffer().
+ * - decoding: MUST be set by get_buffer() for video.
*/
int age;
@@ -1190,6 +1192,33 @@ typedef struct AVFrame {
* - decoding: Set by libavcodec.
*/
void *thread_opaque;
+
+ /**
+ * number of audio samples (per channel) described by this frame
+ * - encoding: unused
+ * - decoding: Set by libavcodec
+ */
+ int nb_samples;
+
+ /**
+ * pointers to the data planes/channels.
+ *
+ * For video, this should simply point to data[].
+ *
+ * For planar audio, each channel has a separate data pointer, and
+ * linesize[0] contains the size of each channel buffer.
+ * For packed audio, there is just one data pointer, and linesize[0]
+ * contains the total size of the buffer for all channels.
+ *
+ * Note: Both data and extended_data will always be set by get_buffer(),
+ * but for planar audio with more channels that can fit in data,
+ * extended_data must be used by the decoder in order to access all
+ * channels.
+ *
+ * encoding: unused
+ * decoding: set by AVCodecContext.get_buffer()
+ */
+ uint8_t **extended_data;
} AVFrame;
struct AVCodecInternal;
@@ -1545,15 +1574,51 @@ typedef struct AVCodecContext {
/**
* Called at the beginning of each frame to get a buffer for it.
- * If pic.reference is set then the frame will be read later by libavcodec.
- * avcodec_align_dimensions2() should be used to find the required width
and
- * height, as they normally need to be rounded up to the next multiple of
16.
+ *
+ * The function will set AVFrame.data[], AVFrame.linesize[].
+ * AVFrame.extended_data[] must also be set, but it should be the same as
+ * AVFrame.data[] except for planar audio with more channels than can fit
+ * in AVFrame.data[]. In that case, AVFrame.data[] shall still contain as
+ * many data as it can hold.
+ *
* if CODEC_CAP_DR1 is not set then get_buffer() must call
* avcodec_default_get_buffer() instead of providing buffers allocated by
* some other means.
+ *
+ * AVFrame.data[] should be 32- or 16-byte-aligned unless the CPU doesn't
+ * need it. avcodec_default_get_buffer() aligns the output buffer properly,
+ * but get_buffer() is overridden then alignment considerations should be
+ * taken into account.
+ *
+ * @see avcodec_default_get_buffer()
+ *
+ * Video:
+ *
+ * If pic.reference is set then the frame will be read later by libavcodec.
+ * avcodec_align_dimensions2() should be used to find the required width
and
+ * height, as they normally need to be rounded up to the next multiple of
16.
+ *
* If frame multithreading is used and thread_safe_callbacks is set,
- * it may be called from a different thread, but not from more than one at
once.
- * Does not need to be reentrant.
+ * it may be called from a different thread, but not from more than one at
+ * once. Does not need to be reentrant.
+ *
+ * @see release_buffer(), reget_buffer()
+ * @see avcodec_align_dimensions2()
+ *
+ * Audio:
+ *
+ * Decoders cannot use the buffer after returning from
+ * avcodec_decode_audio4(), so they will not call release_buffer(), as it
+ * is assumed to be released immediately upon return.
+ *
+ * As a convenience, av_samples_get_buffer_size() and
+ * av_samples_fill_arrays() in libavutil may be used by custom get_buffer()
+ * functions to find the required data size and to fill data pointers and
+ * linesize. In AVFrame.linesize, only linesize[0] needs to be set for
+ * audio since all planes must be the same size.
+ *
+ * @see av_samples_get_buffer_size(), av_samples_fill_arrays()
+ *
* - encoding: unused
* - decoding: Set by libavcodec, user can override.
*/
@@ -3882,7 +3947,12 @@ int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
*/
int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary
**options);
+#if FF_API_OLD_DECODE_AUDIO
/**
+ * Wrapper function which calls avcodec_decode_audio4.
+ *
+ * @deprecated Use avcodec_decode_audio4 instead.
+ *
* Decode the audio frame of size avpkt->size from avpkt->data into samples.
* Some decoders may support multiple frames in a single AVPacket, such
* decoders would then just decode the first frame. In this case,
@@ -3917,6 +3987,8 @@ int avcodec_open2(AVCodecContext *avctx, AVCodec *codec,
AVDictionary **options)
*
* @param avctx the codec context
* @param[out] samples the output buffer, sample type in avctx->sample_fmt
+ * If the sample format is planar, each channel plane will
+ * be the same size, with no padding between channels.
* @param[in,out] frame_size_ptr the output buffer size in bytes
* @param[in] avpkt The input AVPacket containing the input buffer.
* You can create such packet with av_init_packet() and by then
setting
@@ -3925,9 +3997,42 @@ int avcodec_open2(AVCodecContext *avctx, AVCodec *codec,
AVDictionary **options)
* @return On error a negative value is returned, otherwise the number of bytes
* used or zero if no frame data was decompressed (used) from the input
AVPacket.
*/
-int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
+attribute_deprecated int avcodec_decode_audio3(AVCodecContext *avctx, int16_t
*samples,
int *frame_size_ptr,
AVPacket *avpkt);
+#endif
+
+/**
+ * Decode the audio frame of size avpkt->size from avpkt->data into frame.
+ *
+ * Some decoders may support multiple frames in a single AVPacket. Such
+ * decoders would then just decode the first frame. In this case,
+ * avcodec_decode_audio4 has to be called again with an AVPacket containing
+ * the remaining data in order to decode the second frame, etc...
+ * Even if no frames are returned, the packet needs to be fed to the decoder
+ * with remaining data until it is completely consumed or an error occurs.
+ *
+ * @warning The input buffer, avpkt->data must be FF_INPUT_BUFFER_PADDING_SIZE
+ * larger than the actual read bytes because some optimized bitstream
+ * readers read 32 or 64 bits at once and could read over the end.
+ *
+ * @note You might have to align the input buffer. The alignment requirements
+ * depend on the CPU and the decoder.
+ *
+ * @param avctx the codec context
+ * @param[out] frame The AVFrame in which to store decoded audio samples.
+ *
+ * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is
+ * non-zero.
+ * @param[in] avpkt The input AVPacket containing the input buffer.
+ * At least avpkt->data and avpkt->size should be set. Some
+ * decoders might also require additional fields to be set.
+ * @return A negative error code is returned if an error occurred during
+ * decoding, otherwise the number of bytes consumed from the input
+ * AVPacket is returned.
+ */
+int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
+ int *got_frame_ptr, AVPacket *avpkt);
/**
* Decode the video frame of size avpkt->size from avpkt->data into picture.
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 18e851c..e4f23ab 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -37,6 +37,9 @@ typedef struct InternalBuffer {
int width;
int height;
enum PixelFormat pix_fmt;
+ uint8_t **extended_data;
+ int audio_data_size;
+ int nb_channels;
} InternalBuffer;
typedef struct AVCodecInternal {
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 53440e0..477e661 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -240,7 +240,108 @@ void avcodec_align_dimensions(AVCodecContext *s, int
*width, int *height){
*width=FFALIGN(*width, align);
}
-int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){
+static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
+{
+ AVCodecInternal *avci = avctx->internal;
+ InternalBuffer *buf;
+ int buf_size, ret, i, needs_extended_data;
+
+ buf_size = av_samples_get_buffer_size(NULL, avctx->channels,
+ frame->nb_samples, avctx->sample_fmt,
+ 32);
+ if (buf_size < 0)
+ return AVERROR(EINVAL);
+
+ needs_extended_data = av_sample_fmt_is_planar(avctx->sample_fmt) &&
+ avctx->channels > AV_NUM_DATA_POINTERS;
+
+ /* allocate InternalBuffer if needed */
+ if (!avci->buffer) {
+ avci->buffer = av_mallocz(sizeof(InternalBuffer));
+ if (!avci->buffer)
+ return AVERROR(ENOMEM);
+ }
+ buf = avci->buffer;
+
+ /* if there is a previously-used internal buffer, check its size and
+ channel count to see if we can reuse it */
+ if (buf->extended_data) {
+ /* if current buffer is too small, free it */
+ if (buf->extended_data[0] && buf_size > buf->audio_data_size) {
+ av_free(buf->extended_data[0]);
+ if (buf->extended_data != buf->data)
+ av_free(&buf->extended_data);
+ buf->extended_data = NULL;
+ buf->data[0] = NULL;
+ }
+ /* if number of channels has changed, reset and/or free extended data
+ pointers but leave data buffer in buf->data[0] for reuse */
+ if (buf->nb_channels != avctx->channels) {
+ if (buf->extended_data != buf->data)
+ av_free(buf->extended_data);
+ buf->extended_data = NULL;
+ }
+ }
+
+ /* if there is no previous buffer or the previous buffer cannot be used
+ as-is, allocate a new buffer and/or rearrange the channel pointers */
+ if (!buf->extended_data) {
+ /* if the channel pointers will fit, just set extended_data to data,
+ otherwise allocate the extended_data channel pointers */
+ if (needs_extended_data) {
+ buf->extended_data = av_mallocz(avctx->channels *
+ sizeof(*buf->extended_data));
+ if (!buf->extended_data)
+ return AVERROR(ENOMEM);
+ } else {
+ buf->extended_data = buf->data;
+ }
+
+ /* if there is a previous buffer and it is large enough, reuse it and
+ just fill-in new channel pointers and linesize, otherwise allocate
+ a new buffer */
+ if (buf->extended_data[0]) {
+ ret = av_samples_fill_arrays(buf->extended_data, &buf->linesize[0],
+ buf->extended_data[0],
avctx->channels,
+ frame->nb_samples, avctx->sample_fmt,
+ 32);
+ } else {
+ ret = av_samples_alloc(buf->extended_data, &buf->linesize[0],
+ avctx->channels, frame->nb_samples,
+ avctx->sample_fmt, 32);
+ }
+ if (ret)
+ return ret;
+
+ /* if data was not used for extended_data, we need to copy as many of
+ the extended_data channel pointers as will fit */
+ if (needs_extended_data) {
+ for (i = 0; i < AV_NUM_DATA_POINTERS; i++)
+ buf->data[i] = buf->extended_data[i];
+ }
+ buf->audio_data_size = buf_size;
+ buf->nb_channels = avctx->channels;
+ }
+
+ /* copy InternalBuffer info to the AVFrame */
+ frame->type = FF_BUFFER_TYPE_INTERNAL;
+ frame->extended_data = buf->extended_data;
+ frame->linesize[0] = buf->linesize[0];
+ memcpy(frame->data, buf->data, sizeof(frame->data));
+
+ if (avctx->pkt) frame->pkt_pts = avctx->pkt->pts;
+ else frame->pkt_pts = AV_NOPTS_VALUE;
+ frame->reordered_opaque = avctx->reordered_opaque;
+
+ if (avctx->debug & FF_DEBUG_BUFFERS)
+ av_log(avctx, AV_LOG_DEBUG, "default_get_buffer called on frame %p, "
+ "internal audio buffer used\n", frame);
+
+ return 0;
+}
+
+static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
+{
int i;
int w= s->width;
int h= s->height;
@@ -357,6 +458,7 @@ int avcodec_default_get_buffer(AVCodecContext *s, AVFrame
*pic){
pic->data[i]= buf->data[i];
pic->linesize[i]= buf->linesize[i];
}
+ pic->extended_data = pic->data;
avci->buffer_count++;
if(s->pkt) pic->pkt_pts= s->pkt->pts;
@@ -370,11 +472,25 @@ int avcodec_default_get_buffer(AVCodecContext *s, AVFrame
*pic){
return 0;
}
+int avcodec_default_get_buffer(AVCodecContext *avctx, AVFrame *frame)
+{
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ return video_get_buffer(avctx, frame);
+ case AVMEDIA_TYPE_AUDIO:
+ return audio_get_buffer(avctx, frame);
+ default:
+ return -1;
+ }
+}
+
void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){
int i;
InternalBuffer *buf, *last;
AVCodecInternal *avci = s->internal;
+ assert(s->codec_type == AVMEDIA_TYPE_VIDEO);
+
assert(pic->type==FF_BUFFER_TYPE_INTERNAL);
assert(avci->buffer_count);
@@ -407,6 +523,8 @@ int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame
*pic){
AVFrame temp_pic;
int i;
+ assert(s->codec_type == AVMEDIA_TYPE_VIDEO);
+
/* If no picture return a new buffer */
if(pic->data[0] == NULL) {
/* We will copy from buffer, so must be readable */
@@ -756,11 +874,61 @@ int attribute_align_arg
avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
return ret;
}
+#if FF_API_OLD_DECODE_AUDIO
int attribute_align_arg avcodec_decode_audio3(AVCodecContext *avctx, int16_t
*samples,
int *frame_size_ptr,
AVPacket *avpkt)
{
- int ret;
+ AVFrame frame;
+ int ret, got_frame = 0;
+
+ if (avctx->get_buffer != avcodec_default_get_buffer) {
+ av_log(avctx, AV_LOG_ERROR, "A custom get_buffer() cannot be used with
"
+ "avcodec_decode_audio3()\n");
+ return AVERROR(EINVAL);
+ }
+
+ ret = avcodec_decode_audio4(avctx, &frame, &got_frame, avpkt);
+
+ if (ret >= 0 && got_frame) {
+ int ch;
+ int planar = av_sample_fmt_is_planar(avctx->sample_fmt);
+ int plane_size = frame.nb_samples *
+ av_get_bytes_per_sample(avctx->sample_fmt) *
+ (planar ? 1 : avctx->channels);
+ int data_size = plane_size * (planar ? avctx->channels : 1);
+
+ if (*frame_size_ptr < data_size) {
+ av_log(avctx, AV_LOG_ERROR, "output buffer size is too small for "
+ "the current frame (%d < %d)\n", *frame_size_ptr,
data_size);
+ return AVERROR(EINVAL);
+ }
+
+ memcpy(samples, frame.extended_data[0], plane_size);
+
+ if (planar && avctx->channels > 1) {
+ uint8_t *out = ((uint8_t *)samples) + plane_size;
+ for (ch = 1; ch < avctx->channels; ch++) {
+ memcpy(out, frame.extended_data[ch], plane_size);
+ out += plane_size;
+ }
+ }
+ *frame_size_ptr = data_size;
+ } else {
+ *frame_size_ptr = 0;
+ }
+ return ret;
+}
+#endif
+
+int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
+ AVFrame *frame,
+ int *got_frame_ptr,
+ AVPacket *avpkt)
+{
+ int ret = 0;
+
+ *got_frame_ptr = 0;
avctx->pkt = avpkt;
@@ -769,23 +937,12 @@ int attribute_align_arg
avcodec_decode_audio3(AVCodecContext *avctx, int16_t *sa
return AVERROR(EINVAL);
}
- if((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size){
- //FIXME remove the check below _after_ ensuring that all audio check
that the available space is enough
- if(*frame_size_ptr < AVCODEC_MAX_AUDIO_FRAME_SIZE){
- av_log(avctx, AV_LOG_ERROR, "buffer smaller than
AVCODEC_MAX_AUDIO_FRAME_SIZE\n");
- return -1;
- }
- if(*frame_size_ptr < FF_MIN_BUFFER_SIZE ||
- *frame_size_ptr < avctx->channels * avctx->frame_size *
sizeof(int16_t)){
- av_log(avctx, AV_LOG_ERROR, "buffer %d too small\n",
*frame_size_ptr);
- return -1;
+ if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size) {
+ ret = avctx->codec->decode(avctx, frame, got_frame_ptr, avpkt);
+ if (ret >= 0 && *got_frame_ptr) {
+ avctx->frame_number++;
+ frame->pkt_dts = avpkt->dts;
}
-
- ret = avctx->codec->decode(avctx, samples, frame_size_ptr, avpkt);
- avctx->frame_number++;
- }else{
- ret= 0;
- *frame_size_ptr=0;
}
return ret;
}
@@ -1110,7 +1267,8 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
avctx->codec->flush(avctx);
}
-void avcodec_default_free_buffers(AVCodecContext *s){
+static void video_free_buffers(AVCodecContext *s)
+{
AVCodecInternal *avci = s->internal;
int i, j;
@@ -1132,6 +1290,37 @@ void avcodec_default_free_buffers(AVCodecContext *s){
avci->buffer_count=0;
}
+static void audio_free_buffers(AVCodecContext *avctx)
+{
+ AVCodecInternal *avci = avctx->internal;
+ InternalBuffer *buf;
+
+ if (!avci->buffer)
+ return;
+ buf = avci->buffer;
+
+ if (buf->extended_data) {
+ av_free(buf->extended_data[0]);
+ if (buf->extended_data != buf->data)
+ av_free(buf->extended_data);
+ }
+ av_freep(&avci->buffer);
+}
+
+void avcodec_default_free_buffers(AVCodecContext *avctx)
+{
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ video_free_buffers(avctx);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ audio_free_buffers(avctx);
+ break;
+ default:
+ break;
+ }
+}
+
#if FF_API_OLD_FF_PICT_TYPES
char av_get_pict_type_char(int pict_type){
return av_get_picture_type_char(pict_type);
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 7262c81..6faf793 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -21,7 +21,7 @@
#define AVCODEC_VERSION_H
#define LIBAVCODEC_VERSION_MAJOR 53
-#define LIBAVCODEC_VERSION_MINOR 24
+#define LIBAVCODEC_VERSION_MINOR 25
#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
@@ -113,5 +113,8 @@
#ifndef FF_API_DATA_POINTERS
#define FF_API_DATA_POINTERS (LIBAVCODEC_VERSION_MAJOR < 54)
#endif
+#ifndef FF_API_OLD_DECODE_AUDIO
+#define FF_API_OLD_DECODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 54)
+#endif
#endif /* AVCODEC_VERSION_H */
--
1.7.1
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel