diff options
-rw-r--r-- | src/decoder/FfmpegDecoderPlugin.cxx | 103 |
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); } |