From 45576494e547ae3ebb3d289d83367840a22398ec Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Sat, 3 May 2014 21:01:38 +0200 Subject: [PATCH] raspi: fix audio decoding with newer libavcodec Current libavcodec does no longer always return S16 sample format, but the conversion needs to be done explicitly. Use libswscale for that. Not tested on raspbian, only on yocto/ffmpeg. --- configure.ac | 2 +- raspi/Makefile.am | 1 + raspi/avdec.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index d490a48..697556d 100644 --- a/configure.ac +++ b/configure.ac @@ -30,7 +30,6 @@ if test x$BOXTYPE = xgeneric; then PKG_CHECK_MODULES([AVCODEC], [libavcodec >= 54.28.0]) # don't know which version is exactly needed here... PKG_CHECK_MODULES([SWSCALE], [libswscale]) - PKG_CHECK_MODULES([SWRESAMPLE], [libswresample]) else # openmaxil are the broadcom userspace libs # my yocto (openembedded) layer has an openmaxil package built from userland git. @@ -46,6 +45,7 @@ if test x$BOXTYPE = xgeneric; then PKG_CHECK_MODULES([AVFORMAT], [libavformat]) PKG_CHECK_MODULES([AVCODEC], [libavcodec]) fi + PKG_CHECK_MODULES([SWRESAMPLE], [libswresample]) # don't know which version is exactly needed here... PKG_CHECK_MODULES([AVUTIL], [libavutil]) fi diff --git a/raspi/Makefile.am b/raspi/Makefile.am index cf9d148..3cab3e5 100644 --- a/raspi/Makefile.am +++ b/raspi/Makefile.am @@ -13,6 +13,7 @@ AM_LDFLAGS = \ @AVFORMAT_LIBS@ \ @AVUTIL_LIBS@ \ @AVCODEC_LIBS@ \ + @SWRESAMPLE_LIBS@ \ @OMX_LIBS@ \ -lOpenThreads diff --git a/raspi/avdec.cpp b/raspi/avdec.cpp index 0090966..85fc599 100644 --- a/raspi/avdec.cpp +++ b/raspi/avdec.cpp @@ -33,6 +33,7 @@ extern "C" { #include #include #include +#include //#include #include "codec.h" #include "avcodec_omx.h" @@ -329,6 +330,13 @@ void aDec::run() AVCodecContext *c = NULL; AVInputFormat *inp; AVFrame *frame; + /* resample / sample format conversion */ + SwrContext *swr = NULL; + uint8_t *obuf = NULL; + int obuf_sz = 0; /* in samples */ + int obuf_sz_max = 0; + int o_ch = 2, o_sr = 48000; /* output channels and sample rate */ + uint8_t *inbuf; AVPacket avpkt; char tmp[128] = "unknown"; @@ -375,6 +383,10 @@ void aDec::run() lt_info("aDec: Codec for codec_id 0x%08x not found\n", c->codec_id); goto out; } + /* now using libswresample anyway + if (c->sample_fmt == AV_SAMPLE_FMT_S16P) + c->request_sample_fmt = AV_SAMPLE_FMT_S16; + */ if (avcodec_open2(c, codec, NULL) < 0) { lt_info("aDec: avcodec_open2() failed\n"); goto out; @@ -387,6 +399,15 @@ void aDec::run() /* output sample rate, channels, layout could be set here if necessary */ avcodec_string(tmp, sizeof(tmp), c, 0); lt_info("aDec: decoding %s\n", tmp); + swr = swr_alloc_set_opts(swr, + AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, o_sr, /* output */ + c->channel_layout, c->sample_fmt, c->sample_rate, /* input */ + 0, NULL); + if (!swr) { + lt_info("could not alloc resample context\n"); + goto out3; + } + swr_init(swr); while (dec_running) { int gotframe = 0; if (av_read_frame(avfc, &avpkt) < 0) { @@ -398,19 +419,36 @@ void aDec::run() av_free_packet(&avpkt); continue; } + int len = avcodec_decode_audio4(c, frame, &gotframe, &avpkt); if (gotframe && dec_running) { - curr_pts = (avpkt.pts); + int out_linesize; + obuf_sz = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + + frame->nb_samples, o_sr, c->sample_rate, AV_ROUND_UP); + if (obuf_sz > obuf_sz_max) { + lt_info("obuf_sz: %d old: %d\n", obuf_sz, obuf_sz_max); + av_free(obuf); + if (av_samples_alloc(&obuf, &out_linesize, o_ch, + frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0) { + lt_info("av_samples_alloc failed\n"); + av_free_packet(&avpkt); + break; /* while (thread_started) */ + } + obuf_sz_max = obuf_sz; + } + obuf_sz = swr_convert(swr, &obuf, obuf_sz, + (const uint8_t **)frame->extended_data, frame->nb_samples); + curr_pts = av_frame_get_best_effort_timestamp(frame); apts = curr_pts; lt_debug("aDec: pts 0x%" PRIx64 " %3f\n", curr_pts, curr_pts/90000.0); - int data_size = av_samples_get_buffer_size(NULL, c->channels, - frame->nb_samples, c->sample_fmt, 1); + int data_size = av_samples_get_buffer_size(&out_linesize, o_ch, + obuf_sz, AV_SAMPLE_FMT_S16, 1); packet = (packet_t *)malloc(sizeof(*packet)); packet->PTS = av_rescale_q(avpkt.pts, avfc->streams[0]->time_base, omx_timebase); packet->DTS = -1; packet->packetlength = data_size; packet->packet = (uint8_t *)malloc(data_size); - memcpy(packet->packet, frame->data[0], data_size); + memcpy(packet->packet, obuf, data_size); packet->buf = packet->packet; /* This is what is free()ed */ codec_queue_add_item(&codecs.acodec, packet, MSG_PACKET); } @@ -419,6 +457,8 @@ void aDec::run() av_free_packet(&avpkt); } lt_info("aDec: decoder loop exited\n"); + swr_free(&swr); + out3: #if LIBAVCODEC_VERSION_INT >= (54 << 16 | 28 << 8) avcodec_free_frame(&frame); #else