From 91a18f3998323b6d9b0ef67b4c1865d40fabfaf8 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 23 Oct 2012 19:43:26 +0200 Subject: [PATCH] audio, libav: support planar Libav audio formats Latest Libav versions have changed some decoders to support only planar audio sample formats, which are not natively supported by mplayer2 code. Add code (using libavresample) to convert libavcodec decoder output to a supported format if needed. Add similar conversion in the other direction to af_lavcac3enc (the ac3 encoder requires planar input in latest Libav). Libavresample support is optional and tested separately from the other Libav libraries in configure. Libavresample is only included with the latest Libav git versions. Older Libav versions do not include it, but work fine without it, as older libavcodec does not use planar formats and so does not require the conversion functionality. --- configure | 19 +++++ libaf/af_lavcac3enc.c | 159 +++++++++++++++++++++++++++++++++++++----- libmpcodecs/ad_ffmpeg.c | 181 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 304 insertions(+), 55 deletions(-) diff --git a/configure b/configure index 234c6639df..0672fbb74e 100755 --- a/configure +++ b/configure @@ -353,6 +353,7 @@ Optional features: --disable-libass disable subtitle rendering with libass [autodetect] --enable-rpath enable runtime linker path for extra libs [disabled] --disable-libpostproc disable postprocess filter (vf_pp) [autodetect] + --disable-libavresample disable libavresample (sample format conversion) [autodetect] Codecs: --enable-gif enable GIF support [autodetect] @@ -645,6 +646,7 @@ _w32threads=auto _ass=auto _rpath=no libpostproc=auto +libavresample=auto _asmalign_pot=auto _stream_cache=yes _priority=no @@ -974,6 +976,8 @@ for ac_option do --disable-rpath) _rpath=no ;; --enable-libpostproc) libpostproc=yes ;; --disable-libpostproc) libpostproc=no ;; + --enable-libavresample) libavresample=yes ;; + --disable-libavresample) libavresample=no ;; --enable-enca) _enca=yes ;; --disable-enca) _enca=no ;; @@ -5034,6 +5038,19 @@ else fi echores "$libpostproc" +echocheck "libavresample >= 1.0.0" +if test "$libavresample" = auto ; then + libavresample=no + if pkg_config_add "libavresample >= 1.0.0" ; then + libavresample=yes + fi +fi +if test "$libavresample" = yes ; then + def_libavresample='#define CONFIG_LIBAVRESAMPLE 1' +else + def_libavresample='#undef CONFIG_LIBAVRESAMPLE' +fi +echores "$libavresample" echocheck "libdv-0.9.5+" if test "$_libdv" = auto ; then @@ -5667,6 +5684,7 @@ LIBMAD = $_mad LCMS2 = $_lcms2 LIBNUT = $_libnut LIBPOSTPROC = $libpostproc +LIBAVRESAMPLE = $libavresample LIBSMBCLIENT = $_smb LIBQUVI = $_libquvi LIBTHEORA = $_theora @@ -5906,6 +5924,7 @@ $def_xvid $def_zlib $def_libpostproc +$def_libavresample $def_libnut diff --git a/libaf/af_lavcac3enc.c b/libaf/af_lavcac3enc.c index 9a5a3ada83..2aa69e6b36 100644 --- a/libaf/af_lavcac3enc.c +++ b/libaf/af_lavcac3enc.c @@ -27,13 +27,20 @@ #include #include +#include +#include #include #include +#include +#include #include "config.h" #include "af.h" #include "reorder_ch.h" +#ifdef CONFIG_LIBAVRESAMPLE +#include +#endif #define AC3_MAX_CHANNELS 6 #define AC3_MAX_CODED_FRAME_SIZE 3840 @@ -45,6 +52,12 @@ const uint16_t ac3_bitrate_tab[19] = { // Data for specific instances of this filter typedef struct af_ac3enc_s { +#ifdef CONFIG_LIBAVRESAMPLE + AVAudioResampleContext *avr; + uint8_t *resample_buf[AC3_MAX_CHANNELS]; + int linesize; +#endif + AVFrame *frame; struct AVCodec *lavc_acodec; struct AVCodecContext *lavc_actx; int add_iec61937_header; @@ -102,6 +115,47 @@ static int control(struct af_instance_s *af, int cmd, void *arg) avcodec_close(s->lavc_actx); +#ifdef CONFIG_LIBAVRESAMPLE + if (s->avr) { + uint64_t ch_layout = + av_get_default_channel_layout(af->data->nch); + enum AVSampleFormat in_sample_fmt = + av_get_packed_sample_fmt(s->lavc_actx->sample_fmt); + int ret; + + avresample_close(s->avr); + + if (af->data->nch != s->lavc_actx->channels) { + av_freep(&s->resample_buf[0]); + ret = av_samples_alloc(s->resample_buf, &s->linesize, + af->data->nch, AC3_FRAME_SIZE, + s->lavc_actx->sample_fmt, 0); + if (ret < 0) { + uint8_t error[128]; + av_strerror(ret, error, sizeof(error)); + mp_msg(MSGT_AFILTER, MSGL_ERR, "Error allocating " + "resample buffer: %s\n", error); + return AF_ERROR; + } + } + + av_opt_set_int(s->avr, "in_channel_layout", ch_layout, 0); + av_opt_set_int(s->avr, "out_channel_layout", ch_layout, 0); + av_opt_set_int(s->avr, "in_sample_rate", af->data->rate, 0); + av_opt_set_int(s->avr, "out_sample_rate", af->data->rate, 0); + av_opt_set_int(s->avr, "in_sample_fmt", in_sample_fmt, 0); + av_opt_set_int(s->avr, "out_sample_fmt", s->lavc_actx->sample_fmt, 0); + + if ((ret = avresample_open(s->avr)) < 0) { + uint8_t error[128]; + av_strerror(ret, error, sizeof(error)); + mp_msg(MSGT_AFILTER, MSGL_ERR, "Error configuring " + "libavresample: %s\n", error); + return AF_ERROR; + } + } +#endif + // Put sample parameters s->lavc_actx->channels = af->data->nch; s->lavc_actx->sample_rate = af->data->rate; @@ -164,11 +218,71 @@ static void uninit(struct af_instance_s* af) avcodec_close(s->lavc_actx); av_free(s->lavc_actx); } +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0) + avcodec_free_frame(&s->frame); +#else + av_freep(&s->frame); +#endif +#ifdef CONFIG_LIBAVRESAMPLE + avresample_free(&s->avr); + av_freep(&s->resample_buf[0]); +#endif free(s->pending_data); free(s); } } +static int encode_data(af_ac3enc_t *s, uint8_t *src, uint8_t *dst, int dst_len) +{ + AVPacket pkt; + uint8_t error[128]; + int total_samples = AC3_FRAME_SIZE * s->lavc_actx->channels; + int bps = av_get_bytes_per_sample(s->lavc_actx->sample_fmt); + int ret, got_frame; + + if (s->lavc_actx->channels >= 5) + reorder_channel_nch(src, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, + AF_CHANNEL_LAYOUT_LAVC_DEFAULT, + s->lavc_actx->channels, + total_samples, bps); + + s->frame->nb_samples = AC3_FRAME_SIZE; + s->frame->data[0] = src; + s->frame->linesize[0] = total_samples * bps; + +#ifdef CONFIG_LIBAVRESAMPLE + if (s->avr) { + ret = avresample_convert(s->avr, s->resample_buf, s->linesize, + AC3_FRAME_SIZE, &src, total_samples * bps, + AC3_FRAME_SIZE); + if (ret < 0) { + av_strerror(ret, error, sizeof(error)); + mp_msg(MSGT_AFILTER, MSGL_ERR, "Error converting audio sample " + "format: %s\n", error); + return AF_ERROR; + } else if (ret != AC3_FRAME_SIZE) { + mp_msg(MSGT_AFILTER, MSGL_ERR, "Not enough converted data.\n"); + return -1; + } + + memcpy(s->frame->data, s->resample_buf, sizeof(s->resample_buf)); + s->frame->linesize[0] = s->linesize; + } +#endif + + av_init_packet(&pkt); + pkt.data = dst; + pkt.size = dst_len; + + ret = avcodec_encode_audio2(s->lavc_actx, &pkt, s->frame, &got_frame); + if (ret < 0) { + av_strerror(ret, error, sizeof(error)); + mp_msg(MSGT_AFILTER, MSGL_ERR, "Error encoding audio: %s\n", error); + return ret; + } + return got_frame ? pkt.size : 0; +} + // Filter data through filter static af_data_t* play(struct af_instance_s* af, af_data_t* data) { @@ -179,7 +293,6 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data) char *buf, *src, *dest; int max_output_len; int frame_num = (data->len + s->pending_len) / s->expect_len; - int samplesize = af_fmt2bits(s->in_sampleformat) / 8; if (s->add_iec61937_header) max_output_len = AC3_FRAME_SIZE * 2 * 2 * frame_num; @@ -225,28 +338,17 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data) left -= needs; } - if (c->nch >= 5) - reorder_channel_nch(s->pending_data, - AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - AF_CHANNEL_LAYOUT_LAVC_DEFAULT, - c->nch, - s->expect_len / samplesize, samplesize); - - len = avcodec_encode_audio(s->lavc_actx, dest, destsize, - (void *)s->pending_data); + len = encode_data(s, s->pending_data, dest, destsize); s->pending_len = 0; } else { - if (c->nch >= 5) - reorder_channel_nch(src, - AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, - AF_CHANNEL_LAYOUT_LAVC_DEFAULT, - c->nch, - s->expect_len / samplesize, samplesize); - len = avcodec_encode_audio(s->lavc_actx,dest,destsize,(void *)src); + len = encode_data(s, src, dest, destsize); src += s->expect_len; left -= s->expect_len; } + if (len <= 0) + return NULL; + mp_msg(MSGT_AFILTER, MSGL_DBG2, "avcodec_encode_audio got %d, pending %d.\n", len, s->pending_len); @@ -296,22 +398,41 @@ static int af_open(af_instance_t* af){ mp_tmsg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, couldn't allocate context!\n"); return AF_ERROR; } + s->frame = avcodec_alloc_frame(); + if (!s->frame) + return AF_ERROR; const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts; for (int i = 0; ; i++) { if (fmts[i] == AV_SAMPLE_FMT_NONE) { mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't " "support expected sample formats!\n"); return AF_ERROR; - } else if (fmts[i] == AV_SAMPLE_FMT_S16) { + } + enum AVSampleFormat fmt_packed = fmts[i]; +#ifdef CONFIG_LIBAVRESAMPLE + fmt_packed = av_get_packed_sample_fmt(fmt_packed); +#endif + if (fmt_packed == AV_SAMPLE_FMT_S16) { s->in_sampleformat = AF_FORMAT_S16_NE; s->lavc_actx->sample_fmt = fmts[i]; break; - } else if (fmts[i] == AV_SAMPLE_FMT_FLT) { + } else if (fmt_packed == AV_SAMPLE_FMT_FLT) { s->in_sampleformat = AF_FORMAT_FLOAT_NE; s->lavc_actx->sample_fmt = fmts[i]; break; } } + if (av_sample_fmt_is_planar(s->lavc_actx->sample_fmt)) { +#ifdef CONFIG_LIBAVRESAMPLE + s->avr = avresample_alloc_context(); + if (!s->avr) + abort(); +#else + mp_msg(MSGT_AFILTER, MSGL_ERR, "Libavresample is required for this " + "filter to work with this libavcodec version.\n"); + return AF_ERROR; +#endif + } char buf[100]; mp_msg(MSGT_AFILTER, MSGL_V, "[af_lavcac3enc]: in sample format: %s\n", af_fmt2str(s->in_sampleformat, buf, 100)); diff --git a/libmpcodecs/ad_ffmpeg.c b/libmpcodecs/ad_ffmpeg.c index 807a703378..fb9ff43a55 100644 --- a/libmpcodecs/ad_ffmpeg.c +++ b/libmpcodecs/ad_ffmpeg.c @@ -23,7 +23,9 @@ #include #include +#include #include +#include #include "talloc.h" @@ -36,6 +38,10 @@ #include "mpbswap.h" +#ifdef CONFIG_LIBAVRESAMPLE +#include +#endif + static const ad_info_t info = { "libavcodec audio decoders", @@ -55,6 +61,15 @@ struct priv { int output_left; int unitsize; int previous_data_left; // input demuxer packet data + +#ifdef CONFIG_LIBAVRESAMPLE + AVAudioResampleContext *avr; + enum AVSampleFormat resample_fmt; + enum AVSampleFormat out_fmt; + int resample_channels; + uint8_t *resample_buf; + uint64_t resample_buf_size; +#endif }; static int preinit(sh_audio_t *sh) @@ -62,40 +77,107 @@ static int preinit(sh_audio_t *sh) return 1; } +static const int sample_fmt_map[][2] = { + { AV_SAMPLE_FMT_U8, AF_FORMAT_U8 }, + { AV_SAMPLE_FMT_S16, AF_FORMAT_S16_NE }, + { AV_SAMPLE_FMT_S32, AF_FORMAT_S32_NE }, + { AV_SAMPLE_FMT_FLT, AF_FORMAT_FLOAT_NE }, +}; + +static int sample_fmt_lavc2native(enum AVSampleFormat sample_fmt) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(sample_fmt_map); i++) + if (sample_fmt_map[i][0] == sample_fmt) + return sample_fmt_map[i][1]; + return AF_FORMAT_UNKNOWN; +} + /* Prefer playing audio with the samplerate given in container data * if available, but take number the number of channels and sample format * from the codec, since if the codec isn't using the correct values for * those everything breaks anyway. */ -static int setup_format(sh_audio_t *sh_audio, - const AVCodecContext *lavc_context) +static int setup_format(sh_audio_t *sh_audio) { + struct priv *priv = sh_audio->context; + AVCodecContext *codec = priv->avctx; int sample_format = sh_audio->sample_format; - switch (lavc_context->sample_fmt) { - case AV_SAMPLE_FMT_U8: sample_format = AF_FORMAT_U8; break; - case AV_SAMPLE_FMT_S16: sample_format = AF_FORMAT_S16_NE; break; - case AV_SAMPLE_FMT_S32: sample_format = AF_FORMAT_S32_NE; break; - case AV_SAMPLE_FMT_FLT: sample_format = AF_FORMAT_FLOAT_NE; break; - default: + + sample_format = sample_fmt_lavc2native(codec->sample_fmt); + if (sample_format == AF_FORMAT_UNKNOWN) { +#ifndef CONFIG_LIBAVRESAMPLE mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Unsupported sample format\n"); sample_format = AF_FORMAT_UNKNOWN; +#else + if (priv->avr && (priv->resample_fmt != codec->sample_fmt || + priv->resample_channels != codec->channels)) + avresample_free(&priv->avr); + + if (!priv->avr) { + int ret; + uint8_t error[128]; + enum AVSampleFormat out_fmt = + av_get_packed_sample_fmt(codec->sample_fmt); + uint64_t ch_layout = codec->channel_layout; + + mp_msg(MSGT_DECAUDIO, MSGL_V, + "(Re)initializing libavresample format conversion...\n"); + + if (!ch_layout) + ch_layout = av_get_default_channel_layout(codec->channels); + + /* if lavc format is planar, try just getting packed equivalent */ + sample_format = sample_fmt_lavc2native(out_fmt); + if (sample_format == AF_FORMAT_UNKNOWN) { + /* fallback to s16 */ + out_fmt = AV_SAMPLE_FMT_S16; + sample_format = AF_FORMAT_S16_NE; + } + + priv->avr = avresample_alloc_context(); + if (!priv->avr) { + mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Out of memory.\n"); + abort(); + } + av_opt_set_int(priv->avr, "in_channel_layout", ch_layout, 0); + av_opt_set_int(priv->avr, "out_channel_layout", ch_layout, 0); + av_opt_set_int(priv->avr, "in_sample_rate", codec->sample_rate, 0); + av_opt_set_int(priv->avr, "out_sample_rate", codec->sample_rate, 0); + av_opt_set_int(priv->avr, "in_sample_fmt", codec->sample_fmt, 0); + av_opt_set_int(priv->avr, "out_sample_fmt", out_fmt, 0); + + if ((ret = avresample_open(priv->avr)) < 0) { + av_strerror(ret, error, sizeof(error)); + mp_msg(MSGT_DECAUDIO, MSGL_ERR, + "Error opening libavresample: %s.\n", error); + } + priv->resample_fmt = codec->sample_fmt; + priv->resample_channels = codec->channels; + priv->out_fmt = out_fmt; + priv->unitsize = av_get_bytes_per_sample(out_fmt) * + codec->channels; + } else + sample_format = sh_audio->sample_format; + } else if (priv->avr) { + avresample_free(&priv->avr); +#endif } bool broken_srate = false; - int samplerate = lavc_context->sample_rate; + int samplerate = codec->sample_rate; int container_samplerate = sh_audio->container_out_samplerate; if (!container_samplerate && sh_audio->wf) container_samplerate = sh_audio->wf->nSamplesPerSec; - if (lavc_context->codec_id == CODEC_ID_AAC + if (codec->codec_id == CODEC_ID_AAC && samplerate == 2 * container_samplerate) broken_srate = true; else if (container_samplerate) samplerate = container_samplerate; - if (lavc_context->channels != sh_audio->channels || + if (codec->channels != sh_audio->channels || samplerate != sh_audio->samplerate || sample_format != sh_audio->sample_format) { - sh_audio->channels = lavc_context->channels; + sh_audio->channels = codec->channels; sh_audio->samplerate = samplerate; sh_audio->sample_format = sample_format; sh_audio->samplesize = af_fmt2bits(sh_audio->sample_format) / 8; @@ -157,6 +239,7 @@ static int init(sh_audio_t *sh_audio) lavc_context->bits_per_coded_sample = sh_audio->wf->wBitsPerSample; } lavc_context->request_channels = opts->audio_output_channels; + lavc_context->request_sample_fmt = AV_SAMPLE_FMT_S16P; lavc_context->codec_tag = sh_audio->format; //FOURCC lavc_context->codec_type = AVMEDIA_TYPE_AUDIO; lavc_context->codec_id = lavc_codec->id; // not sure if required, imho not --A'rpi @@ -218,16 +301,6 @@ static int init(sh_audio_t *sh_audio) if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec) sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec; - switch (lavc_context->sample_fmt) { - case AV_SAMPLE_FMT_U8: - case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S32: - case AV_SAMPLE_FMT_FLT: - break; - default: - uninit(sh_audio); - return 0; - } return 1; } @@ -245,6 +318,9 @@ static void uninit(sh_audio_t *sh) av_freep(&lavc_context->extradata); av_freep(&lavc_context); } +#ifdef CONFIG_LIBAVRESAMPLE + avresample_free(&ctx->avr); +#endif #if LIBAVCODEC_VERSION_INT >= (54 << 16 | 28 << 8) avcodec_free_frame(&ctx->avframe); #else @@ -324,20 +400,55 @@ static int decode_new_packet(struct sh_audio *sh) priv->previous_data_left = insize - ret; if (!got_frame) return 0; + + setup_format(sh); + +#ifdef CONFIG_LIBAVRESAMPLE + if (priv->avr) { + int ret; + uint64_t needed_size = av_samples_get_buffer_size(NULL, priv->resample_channels, + priv->avframe->nb_samples, + priv->resample_fmt, 0); + if (needed_size > priv->resample_buf_size) { + priv->resample_buf = talloc_realloc(priv, priv->resample_buf, + uint8_t, needed_size); + priv->resample_buf_size = needed_size; + } + + ret = avresample_convert(priv->avr, &priv->resample_buf, + priv->resample_buf_size, priv->avframe->nb_samples, + priv->avframe->extended_data, priv->avframe->linesize[0], + priv->avframe->nb_samples); + if (ret < 0) { + uint8_t error[128]; + av_strerror(ret, error, sizeof(error)); + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Error during sample format conversion: %s.\n", + error); + return -1; + } + + assert(ret == priv->avframe->nb_samples); + + priv->output = priv->resample_buf; + priv->output_left = priv->unitsize * ret; + } else { +#else /* An error is reported later from output format checking, but make * sure we don't crash by overreading first plane. */ - if (av_sample_fmt_is_planar(avctx->sample_fmt) && avctx->channels > 1) - return 0; - uint64_t unitsize = (uint64_t)av_get_bytes_per_sample(avctx->sample_fmt) * - avctx->channels; - if (unitsize > 100000) - abort(); - priv->unitsize = unitsize; - uint64_t output_left = unitsize * priv->avframe->nb_samples; - if (output_left > 500000000) - abort(); - priv->output_left = output_left; - priv->output = priv->avframe->data[0]; + if (!av_sample_fmt_is_planar(avctx->sample_fmt) || avctx->channels == 1) { +#endif + uint64_t unitsize = (uint64_t)av_get_bytes_per_sample(avctx->sample_fmt) * + avctx->channels; + if (unitsize > 100000) + abort(); + priv->unitsize = unitsize; + uint64_t output_left = unitsize * priv->avframe->nb_samples; + if (output_left > 500000000) + abort(); + priv->output_left = output_left; + priv->output = priv->avframe->data[0]; + } + mp_dbg(MSGT_DECAUDIO, MSGL_DBG2, "Decoded %d -> %d \n", insize, priv->output_left); return 0; @@ -357,8 +468,6 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen, break; continue; } - if (setup_format(sh_audio, avctx)) - return len; int size = (minlen - len + priv->unitsize - 1); size -= size % priv->unitsize; size = FFMIN(size, priv->output_left); -- 2.11.4.GIT