summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-11-13 19:19:57 +0100
committerwm4 <wm4@nowhere>2013-11-13 20:10:17 +0100
commit933fbf733362eee9db15dd2671c263781abd5635 (patch)
treec204671f5da9fecb369d1ac3f1d21726b029118b /audio
parent95ed81c32902899168709e0f12d55936ee3cae5f (diff)
downloadmpv-933fbf733362eee9db15dd2671c263781abd5635.tar.bz2
mpv-933fbf733362eee9db15dd2671c263781abd5635.tar.xz
ao_lavc: support non-interleaved audio
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_lavc.c235
-rw-r--r--audio/reorder_ch.c36
-rw-r--r--audio/reorder_ch.h3
3 files changed, 42 insertions, 232 deletions
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index c1fce6a715..117b6c6832 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
#include <libavutil/common.h>
#include <libavutil/audioconvert.h>
@@ -31,22 +32,17 @@
#include "mpvcore/options.h"
#include "mpvcore/mp_common.h"
#include "audio/format.h"
-#include "audio/reorder_ch.h"
+#include "audio/fmt-conversion.h"
#include "talloc.h"
#include "ao.h"
#include "mpvcore/mp_msg.h"
#include "mpvcore/encode_lavc.h"
-static const char *sample_padding_signed = "\x00\x00\x00\x00";
-static const char *sample_padding_u8 = "\x80";
-static const char *sample_padding_float = "\x00\x00\x00\x00";
-
struct priv {
uint8_t *buffer;
size_t buffer_size;
AVStream *stream;
- bool planarize;
int pcmhack;
int aframesize;
int aframecount;
@@ -103,143 +99,34 @@ static int init(struct ao *ao)
ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels);
ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
- ao->format = af_fmt_from_planar(ao->format);
- {
- // first check if the selected format is somewhere in the list of
- // supported formats by the codec
- for (sampleformat = codec->sample_fmts;
- sampleformat && *sampleformat != AV_SAMPLE_FMT_NONE;
- ++sampleformat) {
- switch (*sampleformat) {
- case AV_SAMPLE_FMT_U8:
- case AV_SAMPLE_FMT_U8P:
- if (ao->format == AF_FORMAT_U8)
- goto out_search;
- break;
- case AV_SAMPLE_FMT_S16:
- case AV_SAMPLE_FMT_S16P:
- if (ao->format == AF_FORMAT_S16_BE)
- goto out_search;
- if (ao->format == AF_FORMAT_S16_LE)
- goto out_search;
- break;
- case AV_SAMPLE_FMT_S32:
- case AV_SAMPLE_FMT_S32P:
- if (ao->format == AF_FORMAT_S32_BE)
- goto out_search;
- if (ao->format == AF_FORMAT_S32_LE)
- goto out_search;
- break;
- case AV_SAMPLE_FMT_FLT:
- case AV_SAMPLE_FMT_FLTP:
- if (ao->format == AF_FORMAT_FLOAT_BE)
- goto out_search;
- if (ao->format == AF_FORMAT_FLOAT_LE)
- goto out_search;
- break;
- // FIXME do we need support for AV_SAMPLE_FORMAT_DBL/DBLP?
- default:
- break;
- }
- }
-out_search:
- ;
+ // first check if the selected format is somewhere in the list of
+ // supported formats by the codec
+ for (sampleformat = codec->sample_fmts;
+ sampleformat && *sampleformat != AV_SAMPLE_FMT_NONE;
+ ++sampleformat) {
+ if (ao->format == af_from_avformat(*sampleformat))
+ break;
}
if (!sampleformat || *sampleformat == AV_SAMPLE_FMT_NONE) {
// if the selected format is not supported, we have to pick the first
// one we CAN support
- // note: not needing to select endianness here, as the switch() below
- // does that anyway for us
for (sampleformat = codec->sample_fmts;
sampleformat && *sampleformat != AV_SAMPLE_FMT_NONE;
++sampleformat) {
- switch (*sampleformat) {
- case AV_SAMPLE_FMT_U8:
- case AV_SAMPLE_FMT_U8P:
- ao->format = AF_FORMAT_U8;
- goto out_takefirst;
- case AV_SAMPLE_FMT_S16:
- case AV_SAMPLE_FMT_S16P:
- ao->format = AF_FORMAT_S16_NE;
- goto out_takefirst;
- case AV_SAMPLE_FMT_S32:
- case AV_SAMPLE_FMT_S32P:
- ao->format = AF_FORMAT_S32_NE;
- goto out_takefirst;
- case AV_SAMPLE_FMT_FLT:
- case AV_SAMPLE_FMT_FLTP:
- ao->format = AF_FORMAT_FLOAT_NE;
- goto out_takefirst;
- // FIXME do we need support for AV_SAMPLE_FORMAT_DBL/DBLP?
- default:
+ int format = af_from_avformat(*sampleformat);
+ if (format) {
+ ao->format = format;
break;
}
}
-out_takefirst:
- ;
- }
-
- switch (ao->format) {
- // now that we have chosen a format, set up the fields for it, boldly
- // switching endianness if needed (mplayer code will convert for us
- // anyway, but ffmpeg always expects native endianness)
- case AF_FORMAT_U8:
- ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_U8;
- ac->sample_size = 1;
- ac->sample_padding = sample_padding_u8;
- ao->format = AF_FORMAT_U8;
- break;
- default:
- case AF_FORMAT_S16_BE:
- case AF_FORMAT_S16_LE:
- ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_S16;
- ac->sample_size = 2;
- ac->sample_padding = sample_padding_signed;
- ao->format = AF_FORMAT_S16_NE;
- break;
- case AF_FORMAT_S32_BE:
- case AF_FORMAT_S32_LE:
- ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_S32;
- ac->sample_size = 4;
- ac->sample_padding = sample_padding_signed;
- ao->format = AF_FORMAT_S32_NE;
- break;
- case AF_FORMAT_FLOAT_BE:
- case AF_FORMAT_FLOAT_LE:
- ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
- ac->sample_size = 4;
- ac->sample_padding = sample_padding_float;
- ao->format = AF_FORMAT_FLOAT_NE;
- break;
- }
-
- // detect if we have to planarize
- ac->planarize = false;
- {
- bool found_format = false;
- bool found_planar_format = false;
- for (sampleformat = codec->sample_fmts;
- sampleformat && *sampleformat != AV_SAMPLE_FMT_NONE;
- ++sampleformat) {
- if (*sampleformat == ac->stream->codec->sample_fmt)
- found_format = true;
- if (*sampleformat ==
- av_get_planar_sample_fmt(ac->stream->codec->sample_fmt))
- found_planar_format = true;
- }
- if (!found_format && found_planar_format) {
- ac->stream->codec->sample_fmt =
- av_get_planar_sample_fmt(ac->stream->codec->sample_fmt);
- ac->planarize = true;
- }
- if (!found_format && !found_planar_format) {
- // shouldn't happen
- MP_ERR(ao, "sample format not found\n");
- }
+ if (!sampleformat)
+ MP_ERR(ao, "sample format not found\n"); // shouldn't happen
}
+ ac->sample_size = af_fmt2bits(ao->format) / 8;
+ ac->stream->codec->sample_fmt = af_to_avformat(ao->format);
ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8;
if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0)
@@ -273,23 +160,9 @@ out_takefirst:
ao->untimed = true;
ao->priv = ac;
- if (ac->planarize)
- MP_WARN(ao, "need to planarize audio data\n");
-
return 0;
}
-static void fill_with_padding(void *buf, int cnt, int sz, const void *padding)
-{
- int i;
- if (sz == 1) {
- memset(buf, cnt, *(char *)padding);
- return;
- }
- for (i = 0; i < cnt; ++i)
- memcpy((char *) buf + i * sz, padding, sz);
-}
-
// close audio device
static void uninit(struct ao *ao, bool cut_audio)
{
@@ -312,7 +185,7 @@ static int get_space(struct ao *ao)
}
// must get exactly ac->aframesize amount of data
-static int encode(struct ao *ao, double apts, void *data)
+static int encode(struct ao *ao, double apts, void **data)
{
AVFrame *frame;
AVPacket packet;
@@ -335,22 +208,11 @@ static int encode(struct ao *ao, double apts, void *data)
frame = avcodec_alloc_frame();
frame->nb_samples = ac->aframesize;
- if (ac->planarize) {
- void *data2 = talloc_size(ao, ac->aframesize * ao->channels.num *
- ac->sample_size);
- reorder_to_planar(data2, data, ac->sample_size, ao->channels.num,
- ac->aframesize);
- data = data2;
- }
+ assert(ao->channels.num <= AV_NUM_DATA_POINTERS);
+ for (int n = 0; n < ao->channels.num; n++)
+ frame->extended_data[n] = data[n];
- size_t audiolen = ac->aframesize * ao->channels.num * ac->sample_size;
- if (avcodec_fill_audio_frame(frame, ao->channels.num,
- ac->stream->codec->sample_fmt, data,
- audiolen, 1))
- {
- MP_ERR(ao, "error filling\n");
- return -1;
- }
+ frame->linesize[0] = frame->nb_samples * ao->sstride;
if (ectx->options->rawts || ectx->options->copyts) {
// real audio pts
@@ -380,11 +242,6 @@ static int encode(struct ao *ao, double apts, void *data)
}
avcodec_free_frame(&frame);
-
- if (ac->planarize) {
- talloc_free(data);
- data = NULL;
- }
}
else
{
@@ -437,23 +294,16 @@ static int encode(struct ao *ao, double apts, void *data)
return packet.size;
}
-// plays 'samples' samples of 'ni_data[0]'
-// it should round it down to frame sizes
+// this should round samples down to frame sizes
// return: number of samples played
-static int play(struct ao *ao, void **ni_data, int samples, int flags)
+static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
int bufpos = 0;
- void *paddingbuf = NULL;
double nextpts;
double pts = ao->pts;
double outpts;
- void *data = ni_data[0];
- int len = samples * ao->sstride;
- int bytelen = len;
-
- len /= ac->sample_size * ao->channels.num;
if (!encode_lavc_start(ectx)) {
MP_WARN(ao, "not ready yet for encoding audio\n");
@@ -462,22 +312,22 @@ static int play(struct ao *ao, void **ni_data, int samples, int flags)
if (flags & AOPLAY_FINAL_CHUNK) {
int written = 0;
- if (len > 0) {
- size_t extralen =
- (ac->aframesize - 1) * ao->channels.num * ac->sample_size;
- paddingbuf = talloc_size(NULL, bytelen + extralen);
- memcpy(paddingbuf, data, bytelen);
- fill_with_padding((char *) paddingbuf + bytelen,
- extralen / ac->sample_size,
- ac->sample_size, ac->sample_padding);
+ if (samples > 0) {
+ void *tmp = talloc_new(NULL);
+ size_t bytelen = samples * ao->sstride;
+ size_t extralen = (ac->aframesize - 1) * ao->sstride;
+ void *padded[MP_NUM_CHANNELS];
+ for (int n = 0; n < ao->channels.num; n++) {
+ padded[n] = talloc_size(tmp, bytelen + extralen);
+ memcpy(padded[n], data[n], bytelen);
+ af_fill_silence((char *)padded[n] + bytelen, extralen, ao->format);
+ }
// No danger of recursion, because AOPLAY_FINAL_CHUNK not set
- written =
- play(ao, &paddingbuf, (bytelen + extralen) / ao->sstride, 0);
- if (written * ao->sstride < bytelen) {
+ written = play(ao, padded, (bytelen + extralen) / ao->sstride, 0);
+ if (written < samples) {
MP_ERR(ao, "did not write enough data at the end\n");
}
- talloc_free(paddingbuf);
- paddingbuf = NULL;
+ talloc_free(tmp);
}
outpts = ac->expected_next_pts;
@@ -487,7 +337,7 @@ static int play(struct ao *ao, void **ni_data, int samples, int flags)
while (encode(ao, outpts, NULL) > 0) ;
- return (FFMIN(written, bytelen)) / ao->sstride;
+ return FFMIN(written, samples);
}
if (pts == MP_NOPTS_VALUE) {
@@ -559,15 +409,14 @@ static int play(struct ao *ao, void **ni_data, int samples, int flags)
// Shift pts by the pts offset first.
outpts += encode_lavc_getoffset(ectx, ac->stream);
- while (len - bufpos >= ac->aframesize) {
- encode(ao,
- outpts + bufpos / (double) ao->samplerate,
- (char *) data + ac->sample_size * bufpos * ao->channels.num);
+ while (samples - bufpos >= ac->aframesize) {
+ void *start[MP_NUM_CHANNELS];
+ for (int n = 0; n < ao->channels.num; n++)
+ start[n] = (char *)data[n] + bufpos * ao->sstride;
+ encode(ao, outpts + bufpos / (double) ao->samplerate, start);
bufpos += ac->aframesize;
}
- talloc_free(paddingbuf);
-
// Calculate expected pts of next audio frame (input side).
ac->expected_next_pts = pts + bufpos / (double) ao->samplerate;
diff --git a/audio/reorder_ch.c b/audio/reorder_ch.c
index b99731e6bf..e7bdaaccff 100644
--- a/audio/reorder_ch.c
+++ b/audio/reorder_ch.c
@@ -27,42 +27,6 @@
#include "chmap.h"
#include "reorder_ch.h"
-static inline void reorder_to_planar_(void *restrict out, const void *restrict in,
- size_t size, size_t nchan, size_t nmemb)
-{
- size_t i, c;
- char *outptr = (char *) out;
- size_t instep = nchan * size;
-
- for (c = 0; c < nchan; ++c) {
- const char *inptr = ((const char *) in) + c * size;
- for (i = 0; i < nmemb; ++i, inptr += instep, outptr += size) {
- memcpy(outptr, inptr, size);
- }
- }
-}
-
-void reorder_to_planar(void *restrict out, const void *restrict in,
- size_t size, size_t nchan, size_t nmemb)
-{
- // special case for mono (nothing to do...)
- if (nchan == 1)
- memcpy(out, in, size * nchan * nmemb);
- // these calls exist to insert an inline copy of to_planar_ here with known
- // value of size to help the compiler replace the memcpy calls by mov
- // instructions
- else if (size == 1)
- reorder_to_planar_(out, in, 1, nchan, nmemb);
- else if (size == 2)
- reorder_to_planar_(out, in, 2, nchan, nmemb);
- else if (size == 4)
- reorder_to_planar_(out, in, 4, nchan, nmemb);
- // general case (calls memcpy a lot, should actually never happen, but
- // stays here for correctness purposes)
- else
- reorder_to_planar_(out, in, size, nchan, nmemb);
-}
-
#define MAX_SAMPLESIZE 8
static void reorder_channels_(uint8_t *restrict data, int *restrict ch_order,
diff --git a/audio/reorder_ch.h b/audio/reorder_ch.h
index d81aab7dfa..1ad50bbb00 100644
--- a/audio/reorder_ch.h
+++ b/audio/reorder_ch.h
@@ -25,9 +25,6 @@
#include <inttypes.h>
-void reorder_to_planar(void *restrict out, const void *restrict in,
- size_t size, size_t nchan, size_t nmemb);
-
void reorder_channels(void *restrict data, int *restrict ch_order,
size_t sample_size, size_t num_ch, size_t num_frames);