diff options
Diffstat (limited to 'src/decoder/libav_decoder_plugin.c')
-rw-r--r-- | src/decoder/libav_decoder_plugin.c | 93 |
1 files changed, 22 insertions, 71 deletions
diff --git a/src/decoder/libav_decoder_plugin.c b/src/decoder/libav_decoder_plugin.c index 88dd4a8f..05b9b2fb 100644 --- a/src/decoder/libav_decoder_plugin.c +++ b/src/decoder/libav_decoder_plugin.c @@ -41,6 +41,7 @@ #include <libavutil/log.h> #include <libavutil/mathematics.h> #include <libavutil/dict.h> +#include <libavutil/opt.h> #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "libav" @@ -159,40 +160,6 @@ static int64_t time_to_libav(double t, const AVRational time_base) return av_rescale_q((int64_t)(t * 1024), (AVRational){1, 1024}, time_base); } -/** - * 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) -{ - 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); - uint16_t *dst = (uint16_t*)buffer; - - 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) { - for (int i = 0; i < frame->nb_samples; i++) { - for (int j = 0; j < codec_context->channels; j++) - dst[i * codec_context->channels + j] = ((uint16_t*)frame->extended_data[j])[i]; - } - } else { - memcpy(buffer, frame->extended_data[0], data_size); - } - - return data_size; -} - -#define AVCODEC_MAX_AUDIO_FRAME_SIZE 50000 - static enum decoder_command libav_send_packet(struct decoder *decoder, struct input_stream *is, const AVPacket *packet, @@ -200,9 +167,6 @@ static enum decoder_command libav_send_packet(struct decoder *decoder, const AVRational *time_base) { AVPacket packet2 = *packet; - uint8_t aligned_buffer[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16]; - const size_t buffer_size = sizeof(aligned_buffer); - enum decoder_command cmd = DECODE_COMMAND_NONE; if (packet->pts != (int64_t)AV_NOPTS_VALUE) @@ -210,37 +174,31 @@ static enum decoder_command libav_send_packet(struct decoder *decoder, while (packet2.size > 0 && cmd == DECODE_COMMAND_NONE) { - int audio_size = buffer_size; - AVFrame frame; + AVFrame *frame = av_frame_alloc(); int got_frame = 0; - int len = avcodec_decode_audio4(codec_context, - &frame, &got_frame, - &packet2); - if (len >= 0 && got_frame) { - audio_size = copy_interleave_frame(codec_context, - &frame, - aligned_buffer, - buffer_size); - if (audio_size < 0) - len = audio_size; - } else if (len >= 0) - len = -1; - - if (len < 0) { - /* if error, we skip the frame */ + int ret; + + if (!frame) { + g_warning("Error allocating a frame for decoding.\n"); + break; + } + + ret = avcodec_decode_audio4(codec_context, frame, &got_frame, &packet2); + if (ret < 0) { g_message("decoding failed, frame skipped\n"); break; } - packet2.data += len; - packet2.size -= len; + packet2.data += ret; + packet2.size -= ret; - if (audio_size <= 0) + if (!got_frame) { + if (!ret) + break; continue; + } - cmd = decoder_data(decoder, is, - aligned_buffer, audio_size, - codec_context->bit_rate / 1000); + cmd = decoder_data(decoder, is, frame, codec_context->bit_rate / 1000); } return cmd; } @@ -248,17 +206,9 @@ static enum decoder_command libav_send_packet(struct decoder *decoder, static enum sample_format libav_sample_format(const AVCodecContext *codec_context) { switch (codec_context->sample_fmt) { - case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S16P: - return SAMPLE_FORMAT_S16; - - case AV_SAMPLE_FMT_S32: - return SAMPLE_FORMAT_S32; - - default: - g_warning("Unsupported libavcodec SampleFormat value: %d", - codec_context->sample_fmt); - return SAMPLE_FORMAT_UNDEFINED; + case AV_SAMPLE_FMT_S16: return SAMPLE_FORMAT_S16; + case AV_SAMPLE_FMT_S32: return SAMPLE_FORMAT_S32; + default: return SAMPLE_FORMAT_UNDEFINED; } } @@ -298,6 +248,7 @@ static void libav_decode(struct decoder *decoder, struct input_stream *input) values into AVCodecContext.channels - a change that will be reverted later by avcodec_decode_audio3() */ + av_opt_set_int(dec, "refcounted_frames", 1, 0); ret = avcodec_open2(dec, codec, NULL); if (ret < 0) { g_warning("Could not open codec\n"); |