summaryrefslogtreecommitdiffstats
path: root/libmpcodecs/ad_ffmpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmpcodecs/ad_ffmpeg.c')
-rw-r--r--libmpcodecs/ad_ffmpeg.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/libmpcodecs/ad_ffmpeg.c b/libmpcodecs/ad_ffmpeg.c
index c4d7c13941..cca7725490 100644
--- a/libmpcodecs/ad_ffmpeg.c
+++ b/libmpcodecs/ad_ffmpeg.c
@@ -52,6 +52,7 @@ struct priv {
AVCodecContext *avctx;
AVFrame *avframe;
char *output;
+ char *output_packed; // used by deplanarize to store packed audio samples
int output_left;
int unitsize;
int previous_data_left; // input demuxer packet data
@@ -71,7 +72,7 @@ static int setup_format(sh_audio_t *sh_audio,
const AVCodecContext *lavc_context)
{
int sample_format = sh_audio->sample_format;
- switch (lavc_context->sample_fmt) {
+ switch (av_get_packed_sample_fmt(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;
@@ -218,7 +219,7 @@ 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) {
+ switch (av_get_packed_sample_fmt(lavc_context->sample_fmt)) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S32:
@@ -264,6 +265,34 @@ static int control(sh_audio_t *sh, int cmd, void *arg, ...)
return CONTROL_UNKNOWN;
}
+static av_always_inline void deplanarize(struct sh_audio *sh)
+{
+ struct priv *priv = sh->context;
+
+ size_t bps = av_get_bytes_per_sample(priv->avctx->sample_fmt);
+ size_t nb_samples = priv->avframe->nb_samples;
+ size_t channels = priv->avctx->channels;
+ size_t size = bps * nb_samples * channels;
+
+ if (talloc_get_size(priv->output_packed) != size)
+ priv->output_packed =
+ talloc_realloc_size(priv, priv->output_packed, size);
+
+ size_t offset = 0;
+ unsigned char *output_ptr = priv->output_packed;
+ unsigned char **src = priv->avframe->data;
+
+ for (size_t s = 0; s < nb_samples; s++) {
+ for (size_t c = 0; c < channels; c++) {
+ memcpy(output_ptr, src[c] + offset, bps);
+ output_ptr += bps;
+ }
+ offset += bps;
+ }
+
+ priv->output = priv->output_packed;
+}
+
static int decode_new_packet(struct sh_audio *sh)
{
struct priv *priv = sh->context;
@@ -320,10 +349,6 @@ static int decode_new_packet(struct sh_audio *sh)
priv->previous_data_left = insize - ret;
if (!got_frame)
return 0;
- /* 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)
@@ -333,7 +358,11 @@ static int decode_new_packet(struct sh_audio *sh)
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) {
+ deplanarize(sh);
+ } else {
+ priv->output = priv->avframe->data[0];
+ }
mp_dbg(MSGT_DECAUDIO, MSGL_DBG2, "Decoded %d -> %d \n", insize,
priv->output_left);
return 0;