New audio filters next part.

This commit is contained in:
Johns 2012-04-19 00:47:34 +02:00
parent 79e78bf235
commit 8039e8ae04
2 changed files with 347 additions and 62 deletions

387
audio.c
View File

@ -41,7 +41,7 @@
//#define USE_ALSA ///< enable alsa support
//#define USE_OSS ///< enable OSS support
#define USE_AUDIO_THREAD ///< use thread for audio playback
#define noUSE_AUDIORING ///< new audio ring code (incomplete)
#define USE_AUDIORING ///< new audio ring code (incomplete)
#include <stdio.h>
#include <stdint.h>
@ -133,10 +133,11 @@ static const char *AudioModuleName; ///< which audio module to use
/// Selected audio module.
static const AudioModule *AudioUsedModule = &NoopModule;
static const char *AudioPCMDevice; ///< alsa/OSS PCM device name
static const char *AudioAC3Device; ///< alsa/OSS AC3 device name
static const char *AudioMixerDevice; ///< alsa/OSS mixer device name
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
static const char *AudioPCMDevice; ///< PCM device name
static const char *AudioAC3Device; ///< AC3 device name
static const char *AudioMixerDevice; ///< mixer device name
static const char *AudioMixerChannel; ///< mixer channel name
static char AudioDoingInit; ///> flag in init, reduce error
static volatile char AudioRunning; ///< thread running / stopped
static volatile char AudioPaused; ///< audio paused
static volatile char AudioVideoIsReady; ///< video ready start early
@ -173,7 +174,7 @@ extern int VideoAudioDelay; ///< import audio/video delay
/// default ring buffer size ~2s 8ch 16bit
static const unsigned AudioRingBufferSize = 2 * 48000 * 8 * 2;
static int AudioChannelsInHw[8]; ///< table which channels are supported
static int AudioChannelsInHw[9]; ///< table which channels are supported
enum _audio_rates
{ ///< sample rates enumeration
// HW: 32000 44100 48000 88200 96000 176400 192000
@ -186,7 +187,17 @@ enum _audio_rates
//Audio192000, ///< 192.0Khz
AudioRatesMax ///< max index
};
static int AudioRatesInHw[AudioRatesMax]; ///< table which rates are supported
/// table which rates are supported
static int AudioRatesInHw[AudioRatesMax];
/// input to hardware channel matrix
static int AudioChannelMatrix[AudioRatesMax][9];
/// rates tables
static const unsigned AudioRatesTable[AudioRatesMax] = {
44100, 48000,
};
#ifdef USE_AUDIORING
@ -337,14 +348,14 @@ static void AudioSoftAmplifier(int16_t * samples, int count)
** Upmix mono to stereo.
**
** @param in input sample buffer
** @param count number of bytes in sample buffer
** @param frames number of frames in sample buffer
** @param out output sample buffer
*/
static void AudioMono2Stereo(const int16_t * in, int count, int16_t * out)
static void AudioMono2Stereo(const int16_t * in, int frames, int16_t * out)
{
int i;
for (i = 0; i < count / AudioBytesProSample; ++i) {
for (i = 0; i < frames; ++i) {
int t;
t = in[i];
@ -357,15 +368,145 @@ static void AudioMono2Stereo(const int16_t * in, int count, int16_t * out)
** Downmix stereo to mono.
**
** @param in input sample buffer
** @param count number of bytes in sample buffer
** @param frames number of frames in sample buffer
** @param out output sample buffer
*/
static void AudioStereo2Mono(const int16_t * in, int count, int16_t * out)
static void AudioStereo2Mono(const int16_t * in, int frames, int16_t * out)
{
int i;
for (i = 0; i < count / (2 * AudioBytesProSample); ++i) {
out[i] = (in[i * 2 + 0] + in[i * 2 + 1]) / 2;
for (i = 0; i < frames; i += 2) {
out[i / 2] = (in[i + 0] + in[i + 1]) / 2;
}
}
/**
** Downmix surround to stereo.
**
** ffmpeg L R C Ls Rs -> alsa L R Ls Rs C
** ffmpeg L R C LFE Ls Rs -> alsa L R Ls Rs C LFE
** ffmpeg L R C LFE Ls Rs Rl Rr -> alsa L R Ls Rs C LFE Rl Rr
**
** @param in input sample buffer
** @param in_chan nr. of input channels
** @param frames number of frames in sample buffer
** @param out output sample buffer
*/
static void AudioSurround2Stereo(const int16_t * in, int in_chan, int frames,
int16_t * out)
{
while (frames--) {
int l;
int r;
switch (in_chan) {
case 3: // stereo or surround? =>stereo
l = in[0] * 600; // L
r = in[1] * 600; // R
l += in[2] * 400; // C
r += in[2] * 400;
break;
case 4: // quad or surround? =>quad
l = in[0] * 600; // L
r = in[1] * 600; // R
l += in[2] * 400; // Ls
r += in[3] * 400; // Rs
break;
case 5: // 5.0
l = in[0] * 500; // L
r = in[1] * 500; // R
l += in[2] * 200; // Ls
r += in[3] * 200; // Rs
l += in[4] * 300; // C
r += in[4] * 300;
break;
case 6: // 5.1
l = in[0] * 400; // L
r = in[1] * 400; // R
l += in[2] * 200; // Ls
r += in[3] * 200; // Rs
l += in[4] * 300; // C
r += in[4] * 300;
l += in[5] * 300; // LFE
r += in[5] * 100;
break;
case 7: // 7.0
l = in[0] * 400; // L
r = in[1] * 400; // R
l += in[2] * 200; // Ls
r += in[3] * 200; // Rs
l += in[4] * 300; // C
r += in[4] * 300;
l += in[5] * 100; // RL
r += in[6] * 100; // RR
break;
case 8: // 7.1
l = in[0] * 400; // L
r = in[1] * 400; // R
l += in[2] * 150; // Ls
r += in[3] * 150; // Rs
l += in[4] * 250; // C
r += in[4] * 250;
l += in[5] * 100; // LFE
r += in[5] * 100;
l += in[6] * 100; // RL
r += in[7] * 100; // RR
break;
default:
abort();
}
in += in_chan;
out[0] = l / 1000;
out[1] = r / 1000;
out += 2;
}
}
/**
** Resample ffmpeg sample format to hardware format.
**
** @param in input sample buffer
** @param in_chan nr. of input channels
** @param frames number of frames in sample buffer
** @param out output sample buffer
** @param out_chan nr. of output channels
*/
static void AudioResample(const int16_t * in, int in_chan, int frames,
int16_t * out, int out_chan)
{
switch (in_chan * 8 + out_chan) {
case 1 * 8 + 1:
case 2 * 8 + 2:
case 3 * 8 + 3:
case 4 * 8 + 4:
case 5 * 8 + 5:
case 6 * 8 + 6:
case 7 * 8 + 7:
case 8 * 8 + 8: // input = output channels
memcpy(out, in, frames * in_chan * AudioBytesProSample);
break;
case 2 * 8 + 1:
AudioStereo2Mono(in, frames, out);
break;
case 1 * 8 + 2:
AudioMono2Stereo(in, frames, out);
break;
case 3 * 8 + 2:
case 4 * 8 + 2:
case 5 * 8 + 2:
case 6 * 8 + 2:
case 7 * 8 + 2:
case 8 * 8 + 2:
AudioSurround2Stereo(in, in_chan, frames, out);
break;
default:
Error("audio: unsupported %d -> %d channels resample\n", in_chan,
out_chan);
// play silence
memset(out, 0, frames * out_chan * AudioBytesProSample);
break;
}
}
@ -401,17 +542,34 @@ static atomic_t AudioRingFilled; ///< how many of the ring is used
static unsigned AudioStartThreshold; ///< start play, if filled
/**
** Add sample rate, number of channel change to ring.
** Add sample-rate, number of channel change to ring.
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
** @param sample_rate sample-rate frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval -1 error
** @retval 0 okay
*/
static int AudioRingAdd(int freq, int channels, int use_ac3)
static int AudioRingAdd(unsigned sample_rate, int channels, int use_ac3)
{
unsigned u;
// search supported sample-rates
for (u = 0; u < AudioRatesMax; ++u) {
if (AudioRatesTable[u] == sample_rate) {
break;
}
}
if (u == AudioRatesMax) { // unsupported sample-rate
Error(_("audio: %dHz sample-rate unsupported\n"), sample_rate);
return -1;
}
if (!AudioChannelMatrix[u][channels]) {
Error(_("audio: %d channels unsupported\n"), channels);
return -1; // unsupported nr. of channels
}
if (atomic_read(&AudioRingFilled) == AUDIO_RING_MAX) { // no free slot
// FIXME: can wait for ring buffer empty
Error(_("audio: out of ring buffers\n"));
@ -422,18 +580,23 @@ static int AudioRingAdd(int freq, int channels, int use_ac3)
// FIXME: don't flush buffers here
AudioRing[AudioRingWrite].FlushBuffers = 1;
AudioRing[AudioRingWrite].UseAc3 = use_ac3;
AudioRing[AudioRingWrite].HwSampleRate = freq;
AudioRing[AudioRingWrite].HwChannels = channels;
AudioRing[AudioRingWrite].InSampleRate = sample_rate;
AudioRing[AudioRingWrite].InChannels = channels;
AudioRing[AudioRingWrite].HwSampleRate = sample_rate;
AudioRing[AudioRingWrite].HwChannels = AudioChannelMatrix[u][channels];
AudioRing[AudioRingWrite].PTS = INT64_C(0x8000000000000000);
// reset ring-buffer
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer,
RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer));
atomic_inc(&AudioRingFilled);
#ifdef USE_AUDIO_THREAD
// tell thread, that there is something todo
AudioRunning = 1;
pthread_cond_signal(&AudioStartCond);
if (AudioThread) {
// tell thread, that there is something todo
AudioRunning = 1;
pthread_cond_signal(&AudioStartCond);
}
#endif
return 0;
@ -466,6 +629,7 @@ static void AudioRingExit(void)
AudioRing[i].RingBuffer = NULL;
}
AudioRing[i].HwSampleRate = 0; // checked for valid setup
AudioRing[i].InSampleRate = 0;
}
AudioRingRead = 0;
AudioRingWrite = 0;
@ -586,7 +750,7 @@ static int AlsaPlayRingbuffer(void)
if (!avail) { // full or buffer empty
break;
}
if (AudioSoftVolume) {
if (AudioSoftVolume && !AudioRing[AudioRingRead].UseAc3) {
// FIXME: quick&dirty cast
AudioSoftAmplifier((int16_t *) p, avail);
}
@ -1257,9 +1421,10 @@ static snd_pcm_t *AlsaOpenPCM(int use_ac3)
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
device = "default";
}
Info(_("audio/alsa: using %sdevice '%s'\n"), use_ac3 ? "ac3 " : "",
device);
if (!AudioDoingInit) {
Info(_("audio/alsa: using %sdevice '%s'\n"), use_ac3 ? "ac3 " : "",
device);
}
// open none blocking; if device is already used, we don't want wait
if ((err =
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
@ -1396,19 +1561,22 @@ static int64_t AlsaGetDelay(void)
snd_pcm_sframes_t delay;
int64_t pts;
if (!AlsaPCMHandle) { // setup error
// setup error
if (!AlsaPCMHandle || !AudioRing[AudioRingRead].HwSampleRate) {
return 0L;
}
// delay in frames in alsa + kernel buffers
if ((err = snd_pcm_delay(AlsaPCMHandle, &delay)) < 0) {
//Debug(3, "audio/alsa: no hw delay\n");
delay = 0L;
#ifdef DEBUG
} else if (snd_pcm_state(AlsaPCMHandle) != SND_PCM_STATE_RUNNING) {
//Debug(3, "audio/alsa: %ld frames delay ok, but not running\n", delay);
#endif
}
//Debug(3, "audio/alsa: %ld frames hw delay\n", delay);
// delay can be negative when underrun occur
// delay can be negative, when underrun occur
if (delay < 0) {
delay = 0L;
}
@ -1440,6 +1608,7 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
int delay;
if (!AlsaPCMHandle) { // alsa not running yet
// FIXME: if open fails for ac3, we never recover
return -1;
}
if (1) { // close+open to fix HDMI no sound bug
@ -1470,7 +1639,10 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
}
*/
Error(_("audio/alsa: set params error: %s\n"), snd_strerror(err));
if (!AudioDoingInit) {
Error(_("audio/alsa: set params error: %s\n"),
snd_strerror(err));
}
// FIXME: must stop sound, AudioChannels ... invalid
return -1;
}
@ -1536,8 +1708,10 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
if (AudioStartThreshold > AudioRingBufferSize / 3) {
AudioStartThreshold = AudioRingBufferSize / 3;
}
Info(_("audio/alsa: start delay %ums\n"), (AudioStartThreshold * 1000)
/ (*freq * *channels * AudioBytesProSample));
if (!AudioDoingInit) {
Info(_("audio/alsa: start delay %ums\n"), (AudioStartThreshold * 1000)
/ (*freq * *channels * AudioBytesProSample));
}
return 0;
}
@ -2743,15 +2917,15 @@ static int AudioNextRing(void)
sample_rate);
// FIXME: handle error
AudioRing[AudioRingRead].HwSampleRate = 0;
AudioRing[AudioRingRead].InSampleRate = 0;
return -1;
}
AudioSetVolume(AudioVolume); // update channel delta
AudioResetCompressor();
AudioResetNormalizer();
AudioRing[AudioRingRead].HwSampleRate = sample_rate;
AudioRing[AudioRingRead].HwChannels = channels;
// stop if not enough in next buffer
// stop, if not enough in next buffer
if (AudioStartThreshold >=
RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer)) {
return 1;
@ -2951,6 +3125,8 @@ void AudioEnqueue(const void *samples, int count)
{
#ifdef USE_AUDIORING
size_t n;
int16_t *buffer;
int frames;
#ifdef DEBUG
static uint32_t last_tick;
@ -2967,17 +3143,31 @@ void AudioEnqueue(const void *samples, int count)
Debug(3, "audio: enqueue not ready\n");
return; // no setup yet
}
//
// Convert / resample input to hardware format
//
frames =
count / (AudioRing[AudioRingWrite].InChannels * AudioBytesProSample);
buffer =
alloca(frames * AudioRing[AudioRingWrite].InChannels *
AudioBytesProSample);
AudioResample(samples, AudioRing[AudioRingWrite].InChannels, frames,
buffer, AudioRing[AudioRingWrite].HwChannels);
if (AudioCompression) {
// FIXME: quick&dirty const cast
AudioCompressor((int16_t *) samples, count);
count =
frames * AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample;
// resample into ring-buffer is too complex in the case of a roundabout
// just use a temporary buffer
if (AudioCompression) { // in place operation
AudioCompressor(buffer, count);
}
if (AudioNormalize) {
// FIXME: quick&dirty const cast
AudioNormalizer((int16_t *) samples, count);
if (AudioNormalize) { // in place operation
AudioNormalizer(buffer, count);
}
n = RingBufferWrite(AudioRing[AudioRingWrite].RingBuffer, samples, count);
n = RingBufferWrite(AudioRing[AudioRingWrite].RingBuffer, buffer, count);
if (n != (size_t) count) {
Error(_("audio: can't place %d samples in ring buffer\n"), count);
// too many bytes are lost
@ -3106,6 +3296,8 @@ void AudioFlushBuffers(void)
AudioRing[AudioRingWrite].UseAc3 = AudioRing[old].UseAc3;
AudioRing[AudioRingWrite].HwSampleRate = AudioRing[old].HwSampleRate;
AudioRing[AudioRingWrite].HwChannels = AudioRing[old].HwChannels;
AudioRing[AudioRingWrite].InSampleRate = AudioRing[old].InSampleRate;
AudioRing[AudioRingWrite].InChannels = AudioRing[old].InChannels;
AudioRing[AudioRingWrite].PTS = INT64_C(0x8000000000000000);
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer,
RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer));
@ -3257,7 +3449,7 @@ void AudioSetVolume(int volume)
AudioVolume = volume;
#ifdef USE_AUDIORING
// reduce loudness for stereo output
if (AudioStereoDescent && AudioRing[AudioRingRead].HwChannels == 2
if (AudioStereoDescent && AudioRing[AudioRingRead].InChannels == 2
&& !AudioRing[AudioRingRead].UseAc3) {
volume -= AudioStereoDescent;
if (volume < 0) {
@ -3297,13 +3489,6 @@ int AudioSetup(int *freq, int *channels, int use_ac3)
return -1;
}
#ifdef USE_AUDIORING
// FIXME: need to store possible combination and report this
if (*freq != 44100 && *freq != 48000) {
return -1;
}
if (*channels < 1 || *channels > 8) {
return -1;
}
return AudioRingAdd(*freq, *channels, use_ac3);
#else
return AudioUsedModule->Setup(freq, channels, use_ac3);
@ -3477,11 +3662,8 @@ void AudioInit(void)
{
unsigned u;
const char *name;
#ifndef USE_AUDIORING
int freq;
int chan;
#endif
name = "noop";
#ifdef USE_OSS
@ -3508,9 +3690,105 @@ void AudioInit(void)
return;
found:
AudioDoingInit = 1;
#ifdef USE_AUDIORING
AudioRingInit();
AudioUsedModule->Init();
//
// Check which channels/rates/formats are supported
// FIXME: we force 44.1Khz and 48Khz must be supported equal
// FIXME: should use bitmap of channels supported in RatesInHw
freq = 44100;
AudioRatesInHw[Audio44100] = 0;
for (chan = 1; chan < 9; ++chan) {
if (AudioUsedModule->Setup(&freq, &chan, 0)) {
AudioChannelsInHw[chan] = 0;
} else {
AudioChannelsInHw[chan] = chan;
AudioRatesInHw[Audio44100] |= (1 << chan);
}
}
freq = 48000;
AudioRatesInHw[Audio48000] = 0;
for (chan = 1; chan < 9; ++chan) {
if (!AudioChannelsInHw[chan]) {
continue;
}
if (AudioUsedModule->Setup(&freq, &chan, 0)) {
AudioChannelsInHw[chan] = 0;
} else {
AudioChannelsInHw[chan] = chan;
AudioRatesInHw[Audio48000] |= (1 << chan);
}
}
// build channel support and conversion table
for (u = 0; u < AudioRatesMax; ++u) {
for (chan = 1; chan < 9; ++chan) {
AudioChannelMatrix[u][chan] = 0;
if (!AudioRatesInHw[u]) { // rate unsupported
continue;
}
if (AudioChannelsInHw[chan]) {
AudioChannelMatrix[u][chan] = chan;
} else {
switch (chan) {
case 1:
if (AudioChannelsInHw[2]) {
AudioChannelMatrix[u][chan] = 2;
}
break;
case 2:
case 3:
if (AudioChannelsInHw[4]) {
AudioChannelMatrix[u][chan] = 4;
break;
}
case 4:
if (AudioChannelsInHw[5]) {
AudioChannelMatrix[u][chan] = 5;
break;
}
case 5:
if (AudioChannelsInHw[6]) {
AudioChannelMatrix[u][chan] = 6;
break;
}
case 6:
if (AudioChannelsInHw[7]) {
AudioChannelMatrix[u][chan] = 7;
break;
}
case 7:
if (AudioChannelsInHw[8]) {
AudioChannelMatrix[u][chan] = 8;
break;
}
case 8:
if (AudioChannelsInHw[6]) {
AudioChannelMatrix[u][chan] = 6;
break;
}
if (AudioChannelsInHw[2]) {
AudioChannelMatrix[u][chan] = 2;
break;
}
if (AudioChannelsInHw[1]) {
AudioChannelMatrix[u][chan] = 1;
break;
}
break;
}
}
}
}
for (u = 0; u < AudioRatesMax; ++u) {
Info(_("audio: %6dHz supports %d %d %d %d %d %d %d %d channels\n"),
AudioRatesTable[u], AudioChannelMatrix[u][1],
AudioChannelMatrix[u][2], AudioChannelMatrix[u][3],
AudioChannelMatrix[u][4], AudioChannelMatrix[u][5],
AudioChannelMatrix[u][6], AudioChannelMatrix[u][7],
AudioChannelMatrix[u][8]);
}
#else
AudioUsedModule->Init();
freq = 48000;
@ -3524,6 +3802,7 @@ void AudioInit(void)
AudioInitThread();
}
#endif
AudioDoingInit = 0;
}
/**

22
video.c
View File

@ -4508,7 +4508,7 @@ static void VaapiSyncDecoder(VaapiDecoder * decoder)
_("video: decoder buffer empty, "
"duping frame (%d/%d) %d v-buf\n"), decoder->FramesDuped,
decoder->FrameCounter, VideoGetBuffers());
if (decoder->Closing == -1) {
if (decoder->Closing < -300) {
atomic_set(&decoder->SurfacesFilled, 0);
}
}
@ -4670,9 +4670,12 @@ static void VaapiDisplayHandlerThread(void)
if (err) {
// FIXME: sleep on wakeup
usleep(5 * 1000); // nothing buffered
if (err == -1 && decoder->Closing > 0) {
Debug(3, "video/vaapi: closing eof\n");
decoder->Closing = -1;
if (err == -1 && decoder->Closing) {
decoder->Closing--;
if (!decoder->Closing) {
Debug(3, "video/vaapi: closing eof\n");
decoder->Closing = -1;
}
}
}
@ -7726,7 +7729,7 @@ static void VdpauSyncDecoder(VdpauDecoder * decoder)
_("video: decoder buffer empty, "
"duping frame (%d/%d) %d v-buf\n"), decoder->FramesDuped,
decoder->FrameCounter, VideoGetBuffers());
if (decoder->Closing == -1) {
if (decoder->Closing < -300) {
atomic_set(&decoder->SurfacesFilled, 0);
}
}
@ -7966,9 +7969,12 @@ static void VdpauDisplayHandlerThread(void)
if (err) {
// FIXME: sleep on wakeup
usleep(5 * 1000); // nothing buffered
if (err == -1 && decoder->Closing > 0) {
Debug(3, "video/vdpau: closing eof\n");
decoder->Closing = -1;
if (err == -1 && decoder->Closing) {
decoder->Closing--;
if (!decoder->Closing) {
Debug(3, "video/vdpau: closing eof\n");
decoder->Closing = -1;
}
}
}