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.
This commit is contained in:
Stefan Seyfried
2014-05-03 21:01:38 +02:00
parent d71950c4a2
commit 45576494e5
3 changed files with 46 additions and 5 deletions

View File

@@ -30,7 +30,6 @@ if test x$BOXTYPE = xgeneric; then
PKG_CHECK_MODULES([AVCODEC], [libavcodec >= 54.28.0]) PKG_CHECK_MODULES([AVCODEC], [libavcodec >= 54.28.0])
# don't know which version is exactly needed here... # don't know which version is exactly needed here...
PKG_CHECK_MODULES([SWSCALE], [libswscale]) PKG_CHECK_MODULES([SWSCALE], [libswscale])
PKG_CHECK_MODULES([SWRESAMPLE], [libswresample])
else else
# openmaxil are the broadcom userspace libs # openmaxil are the broadcom userspace libs
# my yocto (openembedded) layer has an openmaxil package built from userland git. # 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([AVFORMAT], [libavformat])
PKG_CHECK_MODULES([AVCODEC], [libavcodec]) PKG_CHECK_MODULES([AVCODEC], [libavcodec])
fi fi
PKG_CHECK_MODULES([SWRESAMPLE], [libswresample])
# don't know which version is exactly needed here... # don't know which version is exactly needed here...
PKG_CHECK_MODULES([AVUTIL], [libavutil]) PKG_CHECK_MODULES([AVUTIL], [libavutil])
fi fi

View File

@@ -13,6 +13,7 @@ AM_LDFLAGS = \
@AVFORMAT_LIBS@ \ @AVFORMAT_LIBS@ \
@AVUTIL_LIBS@ \ @AVUTIL_LIBS@ \
@AVCODEC_LIBS@ \ @AVCODEC_LIBS@ \
@SWRESAMPLE_LIBS@ \
@OMX_LIBS@ \ @OMX_LIBS@ \
-lOpenThreads -lOpenThreads

View File

@@ -33,6 +33,7 @@ extern "C" {
#include <libavutil/opt.h> #include <libavutil/opt.h>
#include <libavutil/samplefmt.h> #include <libavutil/samplefmt.h>
#include <libavutil/mathematics.h> #include <libavutil/mathematics.h>
#include <libswresample/swresample.h>
//#include <ao/ao.h> //#include <ao/ao.h>
#include "codec.h" #include "codec.h"
#include "avcodec_omx.h" #include "avcodec_omx.h"
@@ -329,6 +330,13 @@ void aDec::run()
AVCodecContext *c = NULL; AVCodecContext *c = NULL;
AVInputFormat *inp; AVInputFormat *inp;
AVFrame *frame; 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; uint8_t *inbuf;
AVPacket avpkt; AVPacket avpkt;
char tmp[128] = "unknown"; 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); lt_info("aDec: Codec for codec_id 0x%08x not found\n", c->codec_id);
goto out; 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) { if (avcodec_open2(c, codec, NULL) < 0) {
lt_info("aDec: avcodec_open2() failed\n"); lt_info("aDec: avcodec_open2() failed\n");
goto out; goto out;
@@ -387,6 +399,15 @@ void aDec::run()
/* output sample rate, channels, layout could be set here if necessary */ /* output sample rate, channels, layout could be set here if necessary */
avcodec_string(tmp, sizeof(tmp), c, 0); avcodec_string(tmp, sizeof(tmp), c, 0);
lt_info("aDec: decoding %s\n", tmp); 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) { while (dec_running) {
int gotframe = 0; int gotframe = 0;
if (av_read_frame(avfc, &avpkt) < 0) { if (av_read_frame(avfc, &avpkt) < 0) {
@@ -398,19 +419,36 @@ void aDec::run()
av_free_packet(&avpkt); av_free_packet(&avpkt);
continue; continue;
} }
int len = avcodec_decode_audio4(c, frame, &gotframe, &avpkt); int len = avcodec_decode_audio4(c, frame, &gotframe, &avpkt);
if (gotframe && dec_running) { 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; apts = curr_pts;
lt_debug("aDec: pts 0x%" PRIx64 " %3f\n", curr_pts, curr_pts/90000.0); 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, int data_size = av_samples_get_buffer_size(&out_linesize, o_ch,
frame->nb_samples, c->sample_fmt, 1); obuf_sz, AV_SAMPLE_FMT_S16, 1);
packet = (packet_t *)malloc(sizeof(*packet)); packet = (packet_t *)malloc(sizeof(*packet));
packet->PTS = av_rescale_q(avpkt.pts, avfc->streams[0]->time_base, omx_timebase); packet->PTS = av_rescale_q(avpkt.pts, avfc->streams[0]->time_base, omx_timebase);
packet->DTS = -1; packet->DTS = -1;
packet->packetlength = data_size; packet->packetlength = data_size;
packet->packet = (uint8_t *)malloc(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 */ packet->buf = packet->packet; /* This is what is free()ed */
codec_queue_add_item(&codecs.acodec, packet, MSG_PACKET); codec_queue_add_item(&codecs.acodec, packet, MSG_PACKET);
} }
@@ -419,6 +457,8 @@ void aDec::run()
av_free_packet(&avpkt); av_free_packet(&avpkt);
} }
lt_info("aDec: decoder loop exited\n"); lt_info("aDec: decoder loop exited\n");
swr_free(&swr);
out3:
#if LIBAVCODEC_VERSION_INT >= (54 << 16 | 28 << 8) #if LIBAVCODEC_VERSION_INT >= (54 << 16 | 28 << 8)
avcodec_free_frame(&frame); avcodec_free_frame(&frame);
#else #else