aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2013-03-27 17:25:55 +0100
committerAnton Khirnov <anton@khirnov.net>2013-04-20 08:28:45 +0200
commitb81bee38a67e42fd54ae0825fd1e3caa5183dc09 (patch)
tree7a5414b9265e8ca8839b1c5669cc544ab35cc805
parenta205d8a399bc6532a9a63b6d5a47b871a8513123 (diff)
ffmpeg decoder plugin: do not abuse the AVCODEC_MAX_AUDIO_FRAME_SIZE macroHEADmaster
It is not meant to be used with the new audio decoding API, decoded audio frames can now be arbitrarily large depending on the decoder and the input packet size. Instead dynamically allocate the interleaving buffer to be as large as needed. Fixes build with libavcodec 55. With the old decoding API, use the av_fast_malloc() function to allocate the aligned decoding buffer instead of doing manual alignment.
-rw-r--r--src/decoder/FfmpegDecoderPlugin.cxx103
1 files changed, 43 insertions, 60 deletions
diff --git a/src/decoder/FfmpegDecoderPlugin.cxx b/src/decoder/FfmpegDecoderPlugin.cxx
index 50b39d21..78720ad8 100644
--- a/src/decoder/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/FfmpegDecoderPlugin.cxx
@@ -55,6 +55,19 @@ extern "C" {
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "ffmpeg"
+struct ffmpeg_decoder_context {
+ AVStream *st;
+ AVCodecContext *avctx;
+ AVFrame *frame;
+ AVRational time_base;
+ struct audio_format audio_format;
+
+ /* a decoding buffer for old decoding API or
+ * for interleaved data */
+ void *buf;
+ unsigned int buf_size;
+};
+
static GLogLevelFlags
level_ffmpeg_to_glib(int level)
{
@@ -183,23 +196,6 @@ ffmpeg_find_audio_stream(const AVFormatContext *format_context)
return -1;
}
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53,25,0)
-/**
- * On some platforms, libavcodec wants the output buffer aligned to 16
- * bytes (because it uses SSE/Altivec internally). This function
- * returns the aligned version of the specified buffer, and corrects
- * the buffer size.
- */
-static void *
-align16(void *p, size_t *length_p)
-{
- unsigned add = 16 - (size_t)p % 16;
-
- *length_p -= add;
- return (char *)p + add;
-}
-#endif
-
G_GNUC_CONST
static double
time_from_ffmpeg(int64_t t, const AVRational time_base)
@@ -238,42 +234,32 @@ copy_interleave_frame2(uint8_t *dest, uint8_t **src,
* Copy PCM data from a AVFrame to an interleaved buffer.
*/
static int
-copy_interleave_frame(const AVCodecContext *codec_context,
- const AVFrame *frame,
- uint8_t *buffer, size_t buffer_size)
+copy_interleave_frame(struct ffmpeg_decoder_context *dec)
{
int plane_size;
const int data_size =
av_samples_get_buffer_size(&plane_size,
- codec_context->channels,
- frame->nb_samples,
- codec_context->sample_fmt, 1);
- if (buffer_size < (size_t)data_size)
- /* buffer is too small - shouldn't happen */
- return AVERROR(EINVAL);
-
- if (av_sample_fmt_is_planar(codec_context->sample_fmt) &&
- codec_context->channels > 1) {
- copy_interleave_frame2(buffer, frame->extended_data,
- frame->nb_samples,
- codec_context->channels,
- av_get_bytes_per_sample(codec_context->sample_fmt));
+ dec->avctx->channels,
+ dec->frame->nb_samples,
+ dec->avctx->sample_fmt, 1);
+ av_fast_malloc(&dec->buf, &dec->buf_size, data_size);
+ if (!dec->buf)
+ return AVERROR(ENOMEM);
+
+ if (av_sample_fmt_is_planar(dec->avctx->sample_fmt) &&
+ dec->avctx->channels > 1) {
+ copy_interleave_frame2((uint8_t*)dec->buf, dec->frame->extended_data,
+ dec->frame->nb_samples,
+ dec->avctx->channels,
+ av_get_bytes_per_sample(dec->avctx->sample_fmt));
} else {
- memcpy(buffer, frame->extended_data[0], data_size);
+ memcpy(dec->buf, dec->frame->extended_data[0], data_size);
}
return data_size;
}
#endif
-struct ffmpeg_decoder_context {
- AVStream *st;
- AVCodecContext *avctx;
- AVFrame *frame;
- AVRational time_base;
- struct audio_format audio_format;
-};
-
static enum decoder_command
ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
struct ffmpeg_decoder_context *dec,
@@ -285,37 +271,24 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
AVPacket packet2 = *packet;
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,25,0)
- uint8_t aligned_buffer[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16];
- const size_t buffer_size = sizeof(aligned_buffer);
-#else
- /* libavcodec < 0.8 needs an aligned buffer */
- uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16];
- size_t buffer_size = sizeof(audio_buf);
- int16_t *aligned_buffer = (int16_t *)align16(audio_buf, &buffer_size);
-#endif
-
enum decoder_command cmd = DECODE_COMMAND_NONE;
while (packet2.size > 0 &&
cmd == DECODE_COMMAND_NONE) {
- int audio_size = buffer_size;
+ int audio_size = dec->buf_size;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,25,0)
int got_frame = 0;
int len = avcodec_decode_audio4(dec->avctx,
dec->frame, &got_frame,
&packet2);
if (len >= 0 && got_frame) {
- audio_size = copy_interleave_frame(dec->avctx,
- dec->frame,
- aligned_buffer,
- buffer_size);
+ audio_size = copy_interleave_frame(dec);
if (audio_size < 0)
len = audio_size;
} else if (len >= 0)
len = -1;
#else
int len = avcodec_decode_audio3(dec->avctx,
- aligned_buffer, &audio_size,
+ (int16_t*)dec->buf, &audio_size,
&packet2);
#endif
@@ -332,7 +305,7 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
continue;
cmd = decoder_data(decoder, is,
- aligned_buffer, audio_size,
+ dec->buf, audio_size,
dec->avctx->bit_rate / 1000);
}
return cmd;
@@ -418,7 +391,7 @@ static int init_decoder(struct ffmpeg_decoder_context *dec,
return -1;
}
- memset(dec, 0, sizeof(dec));
+ memset(dec, 0, sizeof(*dec));
dec->st = fmtctx->streams[audio_stream];
dec->time_base = dec->st->time_base;
@@ -453,6 +426,15 @@ static int init_decoder(struct ffmpeg_decoder_context *dec,
return -1;
}
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 25, 0)
+ av_fast_malloc(&dec->buf, &dec->buf_size,
+ (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2);
+ if (!dec->buf) {
+ g_warning("Could not allocate decoding buffer\n");
+ return -1;
+ }
+#endif
+
/* the audio format must be read from AVCodecContext by now,
because avcodec_open() has been demonstrated to fill bogus
values into AVCodecContext.channels - a change that will be
@@ -479,6 +461,7 @@ static void uninit_decoder(struct ffmpeg_decoder_context *dec)
av_freep(&dec->frame);
#endif
+ av_freep(&dec->buf);
avcodec_close(dec->avctx);
}