audio: cleanup spdif format definitions

Before this commit, there was AF_FORMAT_AC3 (the original spdif format,
used for AC3 and DTS core), and AF_FORMAT_IEC61937 (used for AC3, DTS
and DTS-HD), which was handled as some sort of superset for
AF_FORMAT_AC3. There also was AF_FORMAT_MPEG2, which used
IEC61937-framing, but still was handled as something "separate".

Technically, all of them are pretty similar, but may use different
bitrates. Since digital passthrough pretends to be PCM (just with
special headers that wrap digital packets), this is easily detectable by
the higher samplerate or higher number of channels, so I don't know why
you'd need a separate "class" of sample formats (AF_FORMAT_AC3 vs.
AF_FORMAT_IEC61937) to distinguish them. Actually, this whole thing is
just a mess.

Simplify this by handling all these formats the same way.
AF_FORMAT_IS_IEC61937() now returns 1 for all spdif formats (even MP3).
All AOs just accept all spdif formats now - whether that works or not is
not really clear (seems inconsistent due to earlier attempts to make
DTS-HD work). But on the other hand, enabling spdif requires manual user
interaction, so it doesn't matter much if initialization fails in
slightly less graceful ways if it can't work at all.

At a later point, we will support passthrough with ao_pulse. It seems
the PulseAudio API wants to know the codec type (or maybe not - feeding
it DTS while telling it it's AC3 works), add separate formats for each
codecs. While this reminds of the earlier chaos, it's stricter, and most
code just uses AF_FORMAT_IS_IEC61937().

Also, modify AF_FORMAT_TYPE_MASK (renamed from AF_FORMAT_POINT_MASK) to
include special formats, so that it always describes the fundamental
sample format type. This also ensures valid AF formats are never 0 (this
was probably broken in one of the earlier commits from today).
This commit is contained in:
wm4 2014-09-23 22:44:54 +02:00
parent 308d72a02e
commit 81bf9a1963
14 changed files with 94 additions and 93 deletions

View File

@ -117,13 +117,13 @@ static int init(struct dec_audio *da, const char *decoder)
switch (stream->codec->codec_id) {
case AV_CODEC_ID_AAC:
spdif_ctx->iec61937_packet_size = 16384;
sample_format = AF_FORMAT_IEC61937;
sample_format = AF_FORMAT_S_AAC;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_AC3:
spdif_ctx->iec61937_packet_size = 6144;
sample_format = AF_FORMAT_AC3;
sample_format = AF_FORMAT_S_AC3;
samplerate = 48000;
num_channels = 2;
break;
@ -131,31 +131,31 @@ static int init(struct dec_audio *da, const char *decoder)
if (da->opts->dtshd) {
av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_IEC61937;
sample_format = AF_FORMAT_S_DTSHD;
samplerate = 192000;
num_channels = 2*4;
} else {
spdif_ctx->iec61937_packet_size = 32768;
sample_format = AF_FORMAT_AC3;
sample_format = AF_FORMAT_S_DTS;
samplerate = 48000;
num_channels = 2;
}
break;
case AV_CODEC_ID_EAC3:
spdif_ctx->iec61937_packet_size = 24576;
sample_format = AF_FORMAT_IEC61937;
sample_format = AF_FORMAT_S_EAC3;
samplerate = 192000;
num_channels = 2;
break;
case AV_CODEC_ID_MP3:
spdif_ctx->iec61937_packet_size = 4608;
sample_format = AF_FORMAT_MPEG2;
sample_format = AF_FORMAT_S_MP3;
samplerate = 48000;
num_channels = 2;
break;
case AV_CODEC_ID_TRUEHD:
spdif_ctx->iec61937_packet_size = 61440;
sample_format = AF_FORMAT_IEC61937;
sample_format = AF_FORMAT_S_TRUEHD;
samplerate = 192000;
num_channels = 8;
break;

View File

@ -29,7 +29,7 @@ static bool test_conversion(int src_format, int dst_format)
return false;
if (((src_format & ~AF_FORMAT_SIGN_MASK) ==
(dst_format & ~AF_FORMAT_SIGN_MASK)) &&
((src_format & AF_FORMAT_POINT_MASK) == AF_FORMAT_I))
((src_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_I))
return true;
return false;
}

View File

@ -88,7 +88,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (in->nch > AC3_MAX_CHANNELS)
mp_audio_set_num_channels(in, AC3_MAX_CHANNELS);
mp_audio_set_format(af->data, AF_FORMAT_AC3);
mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
mp_audio_set_num_channels(af->data, 2);
if (!mp_audio_config_equals(in, &orig_in))

View File

@ -30,9 +30,6 @@
int af_fmt2bps(int format)
{
if (AF_FORMAT_IS_AC3(format)) return 2;
if (format == AF_FORMAT_UNKNOWN)
return 0;
switch (format & AF_FORMAT_BITS_MASK) {
case AF_FORMAT_8BIT: return 1;
case AF_FORMAT_16BIT: return 2;
@ -62,7 +59,7 @@ static int bits_to_mask(int bits)
int af_fmt_change_bits(int format, int bits)
{
if (!af_fmt_is_valid(format) || (format & AF_FORMAT_SPECIAL_MASK))
if (!af_fmt_is_valid(format))
return 0;
int mask = bits_to_mask(bits);
format = (format & ~AF_FORMAT_BITS_MASK) | mask;
@ -110,10 +107,6 @@ bool af_fmt_is_planar(int format)
}
const struct af_fmt_entry af_fmtstr_table[] = {
{"mpeg2", AF_FORMAT_MPEG2},
{"ac3", AF_FORMAT_AC3},
{"iec61937", AF_FORMAT_IEC61937},
{"u8", AF_FORMAT_U8},
{"s8", AF_FORMAT_S8},
{"u16", AF_FORMAT_U16},
@ -131,6 +124,14 @@ const struct af_fmt_entry af_fmtstr_table[] = {
{"floatp", AF_FORMAT_FLOATP},
{"doublep", AF_FORMAT_DOUBLEP},
{"spdif-aac", AF_FORMAT_S_AAC},
{"spdif-ac3", AF_FORMAT_S_AC3},
{"spdif-dts", AF_FORMAT_S_DTS},
{"spdif-dtshd", AF_FORMAT_S_DTSHD},
{"spdif-eac3", AF_FORMAT_S_EAC3},
{"spdif-mp3", AF_FORMAT_S_MP3},
{"spdif-truehd",AF_FORMAT_S_TRUEHD},
{0}
};
@ -199,9 +200,9 @@ int af_format_conversion_score(int dst_format, int src_format)
score -= 1; // has to (de-)planarize
if (FMT_DIFF(AF_FORMAT_SIGN_MASK, dst_format, src_format))
score -= 4; // has to swap sign
if (FMT_DIFF(AF_FORMAT_POINT_MASK, dst_format, src_format)) {
if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) {
int dst_bits = dst_format & AF_FORMAT_BITS_MASK;
if ((dst_format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F) {
if ((dst_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F) {
// For int->float, always prefer 32 bit float.
score -= dst_bits == AF_FORMAT_32BIT ? 8 : 0;
} else {
@ -217,7 +218,7 @@ int af_format_conversion_score(int dst_format, int src_format)
}
}
// Consider this the worst case.
if (FMT_DIFF(AF_FORMAT_POINT_MASK, dst_format, src_format))
if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format))
score -= 2048; // has to convert float<->int
return score;
}

View File

@ -28,39 +28,38 @@
#include "misc/bstr.h"
// Signed/unsigned
#define AF_FORMAT_SI (0<<1) // Signed
#define AF_FORMAT_US (1<<1) // Unsigned
#define AF_FORMAT_SIGN_MASK (1<<1)
#define AF_FORMAT_SI (0<<0) // Signed
#define AF_FORMAT_US (1<<0) // Unsigned
#define AF_FORMAT_SIGN_MASK (1<<0)
// Bits used
// Some code assumes they're sorted by size.
#define AF_FORMAT_8BIT (0<<3)
#define AF_FORMAT_16BIT (1<<3)
#define AF_FORMAT_24BIT (2<<3)
#define AF_FORMAT_32BIT (3<<3)
#define AF_FORMAT_64BIT (4<<3)
#define AF_FORMAT_BITS_MASK (7<<3)
#define AF_FORMAT_8BIT (0<<1)
#define AF_FORMAT_16BIT (1<<1)
#define AF_FORMAT_24BIT (2<<1)
#define AF_FORMAT_32BIT (3<<1)
#define AF_FORMAT_64BIT (4<<1)
#define AF_FORMAT_BITS_MASK (7<<1)
// Special flags refering to non pcm data (note: 1<<6, 2<<6, 5<<6 unused)
#define AF_FORMAT_S_MPEG2 (3<<6) // MPEG(2) audio
#define AF_FORMAT_S_AC3 (4<<6) // Dolby Digital AC3
#define AF_FORMAT_S_IEC61937 (6<<6)
#define AF_FORMAT_SPECIAL_MASK (7<<6)
// Fixed or floating point
#define AF_FORMAT_I (1<<9) // Int
#define AF_FORMAT_F (2<<9) // Foating point
#define AF_FORMAT_POINT_MASK (3<<9)
// Fixed/floating point/special
#define AF_FORMAT_I (1<<4) // Int
#define AF_FORMAT_F (2<<4) // Foating point
#define AF_FORMAT_S (4<<4) // special (IEC61937)
#define AF_FORMAT_TYPE_MASK (7<<4)
// Interleaving (planar formats have data for each channel in separate planes)
#define AF_FORMAT_INTERLEAVED (0<<11) // must be 0
#define AF_FORMAT_PLANAR (1<<11)
#define AF_FORMAT_INTERLEAVING_MASK (1<<11)
#define AF_FORMAT_INTERLEAVED (0<<7) // must be 0
#define AF_FORMAT_PLANAR (1<<7)
#define AF_FORMAT_INTERLEAVING_MASK (1<<7)
#define AF_FORMAT_S_CODEC(n) ((n)<<8)
#define AF_FORMAT_S_CODEC_MASK (15 <<8) // 16 codecs max.
#define AF_FORMAT_MASK ((1<<12)-1)
#define AF_INTP (AF_FORMAT_I|AF_FORMAT_PLANAR)
#define AF_FLTP (AF_FORMAT_F|AF_FORMAT_PLANAR)
#define AF_FORMAT_S_(n) (AF_FORMAT_S_CODEC(n)|AF_FORMAT_S|AF_FORMAT_16BIT)
// actual sample formats
enum af_format {
@ -78,27 +77,25 @@ enum af_format {
AF_FORMAT_FLOAT = (AF_FORMAT_F|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLE = (AF_FORMAT_F|AF_FORMAT_64BIT),
AF_FORMAT_AC3 = (AF_FORMAT_S_AC3|AF_FORMAT_16BIT),
AF_FORMAT_IEC61937 = (AF_FORMAT_S_IEC61937|AF_FORMAT_16BIT),
AF_FORMAT_MPEG2 = (AF_FORMAT_S_MPEG2),
// Planar variants
AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT),
AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT),
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_32BIT),
AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT),
AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_64BIT),
// All of these use IEC61937 framing, and otherwise pretend to be like PCM.
AF_FORMAT_S_AAC = AF_FORMAT_S_(0),
AF_FORMAT_S_AC3 = AF_FORMAT_S_(1),
AF_FORMAT_S_DTS = AF_FORMAT_S_(2),
AF_FORMAT_S_DTSHD = AF_FORMAT_S_(3),
AF_FORMAT_S_EAC3 = AF_FORMAT_S_(4),
AF_FORMAT_S_MP3 = AF_FORMAT_S_(5),
AF_FORMAT_S_TRUEHD = AF_FORMAT_S_(6),
};
#define AF_FORMAT_IS_AC3(fmt) \
((fmt) == AF_FORMAT_AC3)
#define AF_FORMAT_IS_IEC61937(fmt) \
(AF_FORMAT_IS_AC3(fmt) || \
((fmt) & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_S_IEC61937)
#define AF_FORMAT_IS_SPECIAL(fmt) \
((fmt & AF_FORMAT_SPECIAL_MASK) != 0)
#define AF_FORMAT_IS_IEC61937(f) (((f) & AF_FORMAT_TYPE_MASK) == AF_FORMAT_S)
#define AF_FORMAT_IS_SPECIAL(f) AF_FORMAT_IS_IEC61937(f)
struct af_fmt_entry {
const char *name;

View File

@ -100,7 +100,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
long get_vol, set_vol;
float f_multi;
if (AF_FORMAT_IS_IEC61937(ao->format))
if (AF_FORMAT_IS_SPECIAL(ao->format))
return CONTROL_FALSE;
//allocate simple id
@ -218,9 +218,6 @@ static const int mp_to_alsa_format[][2] = {
{AF_FORMAT_S24,
MP_SELECT_LE_BE(SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3BE)},
{AF_FORMAT_FLOAT, SND_PCM_FORMAT_FLOAT},
{AF_FORMAT_AC3, SND_PCM_FORMAT_S16},
{AF_FORMAT_IEC61937, SND_PCM_FORMAT_S16},
{AF_FORMAT_MPEG2, SND_PCM_FORMAT_MPEG},
{AF_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN},
};
@ -403,7 +400,15 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to get initial parameters");
p->alsa_fmt = find_alsa_format(ao->format);
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (ao->format == AF_FORMAT_S_MP3) {
p->alsa_fmt = SND_PCM_FORMAT_MPEG;
} else {
p->alsa_fmt = SND_PCM_FORMAT_S16;
}
} else {
p->alsa_fmt = find_alsa_format(ao->format);
}
if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) {
p->alsa_fmt = SND_PCM_FORMAT_S16;
ao->format = AF_FORMAT_S16;
@ -411,15 +416,12 @@ static int init(struct ao *ao)
err = snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt);
if (err < 0) {
if (AF_FORMAT_IS_IEC61937(ao->format))
CHECK_ALSA_ERROR("Unable to set IEC61937 format");
MP_INFO(ao, "Format %s is not supported by hardware, trying default.\n",
af_fmt_to_str(ao->format));
p->alsa_fmt = SND_PCM_FORMAT_S16;
if (AF_FORMAT_IS_AC3(ao->format))
ao->format = AF_FORMAT_AC3;
else if (AF_FORMAT_IS_IEC61937(ao->format))
ao->format = AF_FORMAT_IEC61937;
else
ao->format = AF_FORMAT_S16;
ao->format = AF_FORMAT_S16;
}
err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt);

View File

@ -410,8 +410,9 @@ static int init(struct ao *ao)
ao->format = af_fmt_from_planar(ao->format);
bool supports_digital = false;
/* Probe whether device support S/PDIF stream output if input is AC3 stream. */
if (AF_FORMAT_IS_AC3(ao->format)) {
/* Probe whether device support S/PDIF stream output if input is AC3 stream,
* or anything else IEC61937-framed. */
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (ca_device_supports_digital(ao, p->device))
supports_digital = true;
}

View File

@ -130,14 +130,15 @@ bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message)
void ca_fill_asbd(struct ao *ao, AudioStreamBasicDescription *asbd)
{
asbd->mSampleRate = ao->samplerate;
asbd->mFormatID = AF_FORMAT_IS_AC3(ao->format) ?
// Set "AC3" for other spdif formats too - unknown if that works.
asbd->mFormatID = AF_FORMAT_IS_IEC61937(ao->format) ?
kAudioFormat60958AC3 :
kAudioFormatLinearPCM;
asbd->mChannelsPerFrame = ao->channels.num;
asbd->mBitsPerChannel = af_fmt2bits(ao->format);
asbd->mFormatFlags = kAudioFormatFlagIsPacked;
if ((ao->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F)
if ((ao->format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F)
asbd->mFormatFlags |= kAudioFormatFlagIsFloat;
if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI)

View File

@ -382,21 +382,20 @@ static int init(struct ao *ao)
int format = af_fmt_from_planar(ao->format);
int rate = ao->samplerate;
if (AF_FORMAT_IS_AC3(format))
format = AF_FORMAT_AC3;
else {
if (!AF_FORMAT_IS_IEC61937(format)) {
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
}
switch (format) {
case AF_FORMAT_AC3:
case AF_FORMAT_S24:
case AF_FORMAT_S16:
case AF_FORMAT_U8:
break;
default:
if (AF_FORMAT_IS_IEC61937(format))
break;
MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n",
af_fmt_to_str(format));
format = AF_FORMAT_S16;
@ -417,7 +416,8 @@ static int init(struct ao *ao)
? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = ao->channels.num;
wformat.Format.nSamplesPerSec = rate;
if (AF_FORMAT_IS_AC3(format)) {
if (AF_FORMAT_IS_IEC61937(format)) {
// Whether it also works with e.g. DTS is unknown, but probably does.
wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
wformat.Format.wBitsPerSample = 16;
wformat.Format.nBlockAlign = 4;

View File

@ -133,17 +133,14 @@ static const int format_table[][2] = {
#endif
#ifdef AFMT_FLOAT
{AFMT_FLOAT, AF_FORMAT_FLOAT},
#endif
// SPECIALS
#ifdef AFMT_MPEG
{AFMT_MPEG, AF_FORMAT_MPEG2},
#endif
#ifdef AFMT_AC3
{AFMT_AC3, AF_FORMAT_AC3},
#endif
{-1, -1}
};
#ifndef AFMT_AC3
#define AFMT_AC3 -1
#endif
static int format2oss(int format)
{
for (int n = 0; format_table[n][0] != -1; n++) {
@ -204,7 +201,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
return CONTROL_OK;
#endif
if (AF_FORMAT_IS_AC3(ao->format))
if (AF_FORMAT_IS_SPECIAL(ao->format))
return CONTROL_TRUE;
if ((fd = open(p->oss_mixer_device, O_RDONLY)) != -1) {
@ -293,14 +290,16 @@ static int reopen_device(struct ao *ao, bool allow_format_changes)
fcntl(p->audio_fd, F_SETFD, FD_CLOEXEC);
#endif
if (AF_FORMAT_IS_AC3(format)) {
if (AF_FORMAT_IS_IEC61937(format)) {
ioctl(p->audio_fd, SNDCTL_DSP_SPEED, &samplerate);
}
ac3_retry:
if (AF_FORMAT_IS_AC3(format))
format = AF_FORMAT_AC3;
oss_format = format2oss(format);
if (AF_FORMAT_IS_IEC61937(format)) {
oss_format = format2oss(format);
} else {
oss_format = AFMT_AC3;
}
if (oss_format == -1) {
MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n",
af_fmt_to_str(format));
@ -345,7 +344,7 @@ ac3_retry:
MP_VERBOSE(ao, "sample format: %s\n", af_fmt_to_str(format));
if (!AF_FORMAT_IS_AC3(format)) {
if (!AF_FORMAT_IS_IEC61937(format)) {
struct mp_chmap_sel sel = {0};
for (int n = 0; n < MP_NUM_CHANNELS + 1; n++)
mp_chmap_sel_add_map(&sel, &oss_layouts[n]);

View File

@ -137,10 +137,10 @@ static int init(struct ao *ao)
case AF_FORMAT_S24:
case AF_FORMAT_S32:
case AF_FORMAT_FLOAT:
case AF_FORMAT_AC3:
break;
default:
ao->format = AF_FORMAT_S16;
if (!AF_FORMAT_IS_IEC61937(ao->format))
ao->format = AF_FORMAT_S16;
break;
}
}

View File

@ -300,7 +300,7 @@ static int find_formats(struct ao *const ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
if (AF_FORMAT_IS_IEC61937(ao->format) || ao->format == AF_FORMAT_MPEG2) {
if (AF_FORMAT_IS_IEC61937(ao->format)) {
if (try_passthrough(state, ao))
return 0;

View File

@ -110,7 +110,7 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
return -1;
if ((opts->aformat & AF_FORMAT_SPECIAL_MASK) != 0)
if (AF_FORMAT_IS_SPECIAL(opts->aformat))
return -1;
sh = new_sh_stream(demuxer, STREAM_AUDIO);

View File

@ -315,7 +315,7 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
ao_get_format(mpctx->ao, &out_format);
double play_samplerate = out_format.rate / opts->playback_speed;
bool is_pcm = !(out_format.format & AF_FORMAT_SPECIAL_MASK); // no spdif
bool is_pcm = !AF_FORMAT_IS_SPECIAL(out_format.format); // no spdif
if (!opts->initial_audio_sync || !is_pcm) {
mpctx->audio_status = STATUS_FILLING;
return true;