From f22dd3e134527d3290bad749489583b851e1c6a5 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 27 Mar 2013 16:49:29 +0100 Subject: ffmpeg decoder plugin: refactor the decoding functions Move some variables shared between multiple functions to a struct so the functions don't need too many parameters. Move initializing the decoder into a separate function to improve readability and reduce cleanup code duplication. --- src/decoder/FfmpegDecoderPlugin.cxx | 206 ++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/src/decoder/FfmpegDecoderPlugin.cxx b/src/decoder/FfmpegDecoderPlugin.cxx index 3f3e8a43..a3a98a22 100644 --- a/src/decoder/FfmpegDecoderPlugin.cxx +++ b/src/decoder/FfmpegDecoderPlugin.cxx @@ -266,16 +266,22 @@ copy_interleave_frame(const AVCodecContext *codec_context, } #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, - const AVPacket *packet, - AVCodecContext *codec_context, - const AVRational *time_base, - AVFrame *frame) + struct ffmpeg_decoder_context *dec, + const AVPacket *packet) { if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE) decoder_timestamp(decoder, - time_from_ffmpeg(packet->pts, *time_base)); + time_from_ffmpeg(packet->pts, dec->time_base)); AVPacket packet2 = *packet; @@ -295,12 +301,12 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is, int audio_size = buffer_size; #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,25,0) int got_frame = 0; - int len = avcodec_decode_audio4(codec_context, - frame, &got_frame, + int len = avcodec_decode_audio4(dec->avctx, + dec->frame, &got_frame, &packet2); if (len >= 0 && got_frame) { - audio_size = copy_interleave_frame(codec_context, - frame, + audio_size = copy_interleave_frame(dec->avctx, + dec->frame, aligned_buffer, buffer_size); if (audio_size < 0) @@ -308,7 +314,7 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is, } else if (len >= 0) len = -1; #else - int len = avcodec_decode_audio3(codec_context, + int len = avcodec_decode_audio3(dec->avctx, aligned_buffer, &audio_size, &packet2); #endif @@ -327,7 +333,7 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is, cmd = decoder_data(decoder, is, aligned_buffer, audio_size, - codec_context->bit_rate / 1000); + dec->avctx->bit_rate / 1000); } return cmd; } @@ -403,6 +409,80 @@ ffmpeg_probe(struct decoder *decoder, struct input_stream *is) return format; } +static int init_decoder(struct ffmpeg_decoder_context *dec, + AVFormatContext *fmtctx) +{ + int audio_stream = ffmpeg_find_audio_stream(fmtctx); + if (audio_stream == -1) { + g_warning("No audio stream inside\n"); + return -1; + } + + memset(dec, 0, sizeof(dec)); + dec->st = fmtctx->streams[audio_stream]; + + dec->time_base = dec->st->time_base; + dec->avctx = dec->st->codec; + if (dec->avctx->codec_name[0] != 0) + g_debug("codec '%s'", dec->avctx->codec_name); + + AVCodec *codec = avcodec_find_decoder(dec->avctx->codec_id); + + if (!codec) { + g_warning("Unsupported audio codec\n"); + return -1; + } + + const enum sample_format sample_format = + ffmpeg_sample_format(dec->avctx->sample_fmt); + if (sample_format == SAMPLE_FORMAT_UNDEFINED) + return -1; + + GError *error = NULL; + if (!audio_format_init_checked(&dec->audio_format, + dec->avctx->sample_rate, + sample_format, + dec->avctx->channels, &error)) { + g_warning("%s", error->message); + g_error_free(error); + return -1; + } + + dec->frame = avcodec_alloc_frame(); + if (!dec->frame) { + g_warning("Could not allocate frame\n"); + return -1; + } + + /* 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 + reverted later by avcodec_decode_audio3() */ + +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,6,0) + const int open_result = avcodec_open2(dec->avctx, codec, NULL); +#else + const int open_result = avcodec_open(dec->avctx, codec); +#endif + if (open_result < 0) { + g_warning("Could not open codec\n"); + return -1; + } + + return 0; +} + +static void uninit_decoder(struct ffmpeg_decoder_context *dec) +{ +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0) + avcodec_free_frame(&dec->frame); +#else + av_freep(&dec->frame); +#endif + + avcodec_close(dec->avctx); +} + static void ffmpeg_decode(struct decoder *decoder, struct input_stream *input) { @@ -447,71 +527,10 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) return; } - int audio_stream = ffmpeg_find_audio_stream(format_context); - if (audio_stream == -1) { - g_warning("No audio stream inside\n"); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,17,0) - avformat_close_input(&format_context); -#else - av_close_input_stream(format_context); -#endif - mpd_ffmpeg_stream_close(stream); - return; - } - - AVStream *av_stream = format_context->streams[audio_stream]; - - AVCodecContext *codec_context = av_stream->codec; - if (codec_context->codec_name[0] != 0) - g_debug("codec '%s'", codec_context->codec_name); - - AVCodec *codec = avcodec_find_decoder(codec_context->codec_id); - - if (!codec) { - g_warning("Unsupported audio codec\n"); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,17,0) - avformat_close_input(&format_context); -#else - av_close_input_stream(format_context); -#endif - mpd_ffmpeg_stream_close(stream); - return; - } - - const enum sample_format sample_format = - ffmpeg_sample_format(codec_context->sample_fmt); - if (sample_format == SAMPLE_FORMAT_UNDEFINED) - return; - - GError *error = NULL; - struct audio_format audio_format; - if (!audio_format_init_checked(&audio_format, - codec_context->sample_rate, - sample_format, - codec_context->channels, &error)) { - g_warning("%s", error->message); - g_error_free(error); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,17,0) - avformat_close_input(&format_context); -#else - av_close_input_stream(format_context); -#endif - mpd_ffmpeg_stream_close(stream); - return; - } - - /* 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 - reverted later by avcodec_decode_audio3() */ - -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,6,0) - const int open_result = avcodec_open2(codec_context, codec, NULL); -#else - const int open_result = avcodec_open(codec_context, codec); -#endif - if (open_result < 0) { - g_warning("Could not open codec\n"); + struct ffmpeg_decoder_context dec; + int res = init_decoder(&dec, format_context); + if (res < 0) { + uninit_decoder(&dec); #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,17,0) avformat_close_input(&format_context); #else @@ -525,21 +544,9 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) ? format_context->duration / AV_TIME_BASE : 0; - decoder_initialized(decoder, &audio_format, + decoder_initialized(decoder, &dec.audio_format, input->seekable, total_time); - AVFrame *frame = avcodec_alloc_frame(); - if (!frame) { - g_warning("Could not allocate frame\n"); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,17,0) - avformat_close_input(&format_context); -#else - av_close_input_stream(format_context); -#endif - mpd_ffmpeg_stream_close(stream); - return; - } - enum decoder_command cmd; do { AVPacket packet; @@ -547,11 +554,9 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) /* end of file */ break; - if (packet.stream_index == audio_stream) - cmd = ffmpeg_send_packet(decoder, input, - &packet, codec_context, - &av_stream->time_base, - frame); + if (packet.stream_index == dec.st->index) + cmd = ffmpeg_send_packet(decoder, input, &dec, + &packet); else cmd = decoder_get_command(decoder); @@ -560,25 +565,20 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input) if (cmd == DECODE_COMMAND_SEEK) { int64_t where = time_to_ffmpeg(decoder_seek_where(decoder), - av_stream->time_base); + dec.st->time_base); - if (av_seek_frame(format_context, audio_stream, where, + if (av_seek_frame(format_context, dec.st->index, where, AV_TIME_BASE) < 0) decoder_seek_error(decoder); else { - avcodec_flush_buffers(codec_context); + avcodec_flush_buffers(dec.avctx); decoder_command_finished(decoder); } } } while (cmd != DECODE_COMMAND_STOP); -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0) - avcodec_free_frame(&frame); -#else - av_freep(&frame); -#endif + uninit_decoder(&dec); - avcodec_close(codec_context); #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,17,0) avformat_close_input(&format_context); #else -- cgit v1.2.3