mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Audio improvement.
Made audio thread cancelable. Calculate audio PTS. Disable alsa message to stderr. Better buffer flush with threaded play. Prepared audio resample, for unsupported number of audio channels.
This commit is contained in:
parent
fc2580dc2a
commit
3f8ff57e30
159
audio.c
159
audio.c
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
#define _(str) gettext(str) ///< gettext shortcut
|
#define _(str) gettext(str) ///< gettext shortcut
|
||||||
@ -63,7 +64,7 @@ static volatile char AudioRunning; ///< thread running / stopped
|
|||||||
static int AudioPaused; ///< audio paused
|
static int AudioPaused; ///< audio paused
|
||||||
static unsigned AudioSampleRate; ///< audio sample rate in hz
|
static unsigned AudioSampleRate; ///< audio sample rate in hz
|
||||||
static unsigned AudioChannels; ///< number of audio channels
|
static unsigned AudioChannels; ///< number of audio channels
|
||||||
static uint64_t AudioPTS; ///< audio pts clock
|
static int64_t AudioPTS; ///< audio pts clock
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Alsa variables
|
// Alsa variables
|
||||||
@ -75,6 +76,7 @@ static int AlsaUseMmap; ///< use mmap
|
|||||||
|
|
||||||
static RingBuffer *AlsaRingBuffer; ///< audio ring buffer
|
static RingBuffer *AlsaRingBuffer; ///< audio ring buffer
|
||||||
static unsigned AlsaStartThreshold; ///< start play, if filled
|
static unsigned AlsaStartThreshold; ///< start play, if filled
|
||||||
|
static int AlsaFlushBuffer; ///< flag empty buffer
|
||||||
|
|
||||||
static snd_mixer_t *AlsaMixer; ///< alsa mixer handle
|
static snd_mixer_t *AlsaMixer; ///< alsa mixer handle
|
||||||
static snd_mixer_elem_t *AlsaMixerElem; ///< alsa pcm mixer element
|
static snd_mixer_elem_t *AlsaMixerElem; ///< alsa pcm mixer element
|
||||||
@ -102,7 +104,8 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
|
|||||||
// too many bytes are lost
|
// too many bytes are lost
|
||||||
}
|
}
|
||||||
// Update audio clock
|
// Update audio clock
|
||||||
AudioPTS += (count * 90000) / (AudioSampleRate * AudioChannels * 2);
|
AudioPTS +=
|
||||||
|
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels * 2);
|
||||||
|
|
||||||
if (!AudioRunning) {
|
if (!AudioRunning) {
|
||||||
if (AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) {
|
if (AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) {
|
||||||
@ -149,7 +152,7 @@ static int AlsaPlayRingbuffer(void)
|
|||||||
// happens with broken alsa drivers
|
// happens with broken alsa drivers
|
||||||
Error(_("audio/alsa: broken driver %d\n"), avail);
|
Error(_("audio/alsa: broken driver %d\n"), avail);
|
||||||
}
|
}
|
||||||
break;
|
//break;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = RingBufferGetReadPointer(AlsaRingBuffer, &p);
|
n = RingBufferGetReadPointer(AlsaRingBuffer, &p);
|
||||||
@ -373,6 +376,18 @@ static void *AudioPlayHandlerThread(void *dummy)
|
|||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (AlsaFlushBuffer) {
|
||||||
|
// we can flush too many, but wo cares
|
||||||
|
Debug(3, "audio/alsa: flushing buffers\n");
|
||||||
|
RingBufferReadAdvance(AlsaRingBuffer,
|
||||||
|
RingBufferUsedBytes(AlsaRingBuffer));
|
||||||
|
if ((err = snd_pcm_drain(AlsaPCMHandle))) {
|
||||||
|
Error(_("audio: snd_pcm_drain(): %s\n"),
|
||||||
|
snd_strerror(err));
|
||||||
|
}
|
||||||
|
AlsaFlushBuffer = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ((err = AlsaPlayRingbuffer())) { // empty / error
|
if ((err = AlsaPlayRingbuffer())) { // empty / error
|
||||||
snd_pcm_state_t state;
|
snd_pcm_state_t state;
|
||||||
|
|
||||||
@ -400,6 +415,10 @@ static void *AudioPlayHandlerThread(void *dummy)
|
|||||||
*/
|
*/
|
||||||
void AudioEnqueue(const void *samples, int count)
|
void AudioEnqueue(const void *samples, int count)
|
||||||
{
|
{
|
||||||
|
if (!AlsaRingBuffer || !AlsaPCMHandle) {
|
||||||
|
Debug(3, "audio/alsa: alsa not ready\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (AlsaAddToRingbuffer(samples, count)) {
|
if (AlsaAddToRingbuffer(samples, count)) {
|
||||||
snd_pcm_state_t state;
|
snd_pcm_state_t state;
|
||||||
|
|
||||||
@ -508,7 +527,7 @@ static void AlsaInitPCM(void)
|
|||||||
pthread_mutex_init(&AudioMutex, NULL);
|
pthread_mutex_init(&AudioMutex, NULL);
|
||||||
pthread_cond_init(&AudioStartCond, NULL);
|
pthread_cond_init(&AudioStartCond, NULL);
|
||||||
pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL);
|
pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL);
|
||||||
pthread_detach(AudioThread);
|
//pthread_detach(AudioThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -583,6 +602,21 @@ static void AlsaInitMixer(void)
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Set audio clock base.
|
||||||
|
**
|
||||||
|
** @param pts audio presentation timestamp
|
||||||
|
*/
|
||||||
|
void AudioSetClock(int64_t pts)
|
||||||
|
{
|
||||||
|
if (AudioPTS != pts) {
|
||||||
|
Debug(3, "audio: set clock to %#012" PRIx64 " %#012" PRIx64 " pts\n",
|
||||||
|
AudioPTS, pts);
|
||||||
|
|
||||||
|
AudioPTS = pts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get audio delay in time stamps.
|
** Get audio delay in time stamps.
|
||||||
*/
|
*/
|
||||||
@ -590,21 +624,21 @@ uint64_t AudioGetDelay(void)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_sframes_t delay;
|
snd_pcm_sframes_t delay;
|
||||||
|
uint64_t pts;
|
||||||
|
|
||||||
if ((err = snd_pcm_delay(AlsaPCMHandle, &delay)) < 0) {
|
if ((err = snd_pcm_delay(AlsaPCMHandle, &delay)) < 0) {
|
||||||
//Debug(3, "audio/alsa: no hw delay\n");
|
//Debug(3, "audio/alsa: no hw delay\n");
|
||||||
delay = 0UL;
|
delay = 0UL;
|
||||||
} else if (snd_pcm_state(AlsaPCMHandle) != SND_PCM_STATE_RUNNING) {
|
} else if (snd_pcm_state(AlsaPCMHandle) != SND_PCM_STATE_RUNNING) {
|
||||||
//Debug(3, "audio/alsa: %lu delay ok, but not running\n", delay);
|
//Debug(3, "audio/alsa: %ld delay ok, but not running\n", delay);
|
||||||
}
|
}
|
||||||
delay = (delay * 90000) / AudioSampleRate;
|
|
||||||
//Debug(3, "audio/alsa: hw delay %lu\n", delay);
|
|
||||||
delay +=
|
|
||||||
(RingBufferUsedBytes(AlsaRingBuffer) * 90000) / (AudioSampleRate *
|
|
||||||
AudioChannels);
|
|
||||||
//Debug(3, "audio/alsa: hw+sw delay %lu ms\n", delay / 90);
|
|
||||||
|
|
||||||
return delay;
|
pts = ((uint64_t) delay * 90000) / AudioSampleRate;
|
||||||
|
pts += ((uint64_t) RingBufferUsedBytes(AlsaRingBuffer) * 90000)
|
||||||
|
/ (AudioSampleRate * AudioChannels);
|
||||||
|
//Debug(3, "audio/alsa: hw+sw delay %"PRId64" ms\n", pts / 90);
|
||||||
|
|
||||||
|
return pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -613,40 +647,70 @@ uint64_t AudioGetDelay(void)
|
|||||||
** @param freq sample frequency
|
** @param freq sample frequency
|
||||||
** @param channels number of channels
|
** @param channels number of channels
|
||||||
**
|
**
|
||||||
|
** @retval 0 everything ok
|
||||||
|
** @retval 1 didn't support frequency/channels combination
|
||||||
|
** @retval -1 something gone wrong
|
||||||
|
**
|
||||||
** @todo audio changes must be queued and done when the buffer is empty
|
** @todo audio changes must be queued and done when the buffer is empty
|
||||||
*/
|
*/
|
||||||
void AudioSetup(int freq, int channels)
|
int AudioSetup(int *freq, int *channels)
|
||||||
{
|
{
|
||||||
snd_pcm_uframes_t buffer_size;
|
snd_pcm_uframes_t buffer_size;
|
||||||
snd_pcm_uframes_t period_size;
|
snd_pcm_uframes_t period_size;
|
||||||
int err;
|
int err;
|
||||||
|
int ret;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
Debug(3, "audio/alsa: channels %d frequency %d hz\n", channels, freq);
|
Debug(3, "audio/alsa: channels %d frequency %d hz\n", *channels, *freq);
|
||||||
|
|
||||||
if (!freq || !channels) { // invalid parameter
|
// invalid parameter
|
||||||
|
if (!freq || !channels || !*freq || !*channels) {
|
||||||
|
Debug(3, "audio: bad channels or frequency parameters\n");
|
||||||
// FIXME: set flag invalid setup
|
// FIXME: set flag invalid setup
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioChannels = channels;
|
AudioChannels = *channels;
|
||||||
AudioSampleRate = freq;
|
AudioSampleRate = *freq;
|
||||||
// FIXME: thread!!
|
|
||||||
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
|
|
||||||
|
|
||||||
|
// flush any buffered data
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
if (AudioRunning) {
|
||||||
|
AlsaFlushBuffer = 1;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
RingBufferReadAdvance(AlsaRingBuffer,
|
||||||
|
RingBufferUsedBytes(AlsaRingBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
try_again:
|
||||||
if ((err =
|
if ((err =
|
||||||
snd_pcm_set_params(AlsaPCMHandle, SND_PCM_FORMAT_S16,
|
snd_pcm_set_params(AlsaPCMHandle, SND_PCM_FORMAT_S16,
|
||||||
AlsaUseMmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED :
|
AlsaUseMmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED :
|
||||||
SND_PCM_ACCESS_RW_INTERLEAVED, channels, freq, 1,
|
SND_PCM_ACCESS_RW_INTERLEAVED, *channels, *freq, 1,
|
||||||
125 * 1000))) {
|
125 * 1000))) {
|
||||||
Error(_("audio/alsa: set params error: %s\n"), snd_strerror(err));
|
Error(_("audio/alsa: set params error: %s\n"), snd_strerror(err));
|
||||||
if (channels == 2) {
|
switch (*channels) {
|
||||||
// FIXME: must stop sound
|
case 1:
|
||||||
return;
|
// FIXME: enable channel upmix
|
||||||
}
|
ret = 1;
|
||||||
|
*channels = 2;
|
||||||
|
goto try_again;
|
||||||
|
case 2:
|
||||||
|
return -1;
|
||||||
|
case 4:
|
||||||
|
case 6:
|
||||||
// FIXME: enable channel downmix
|
// FIXME: enable channel downmix
|
||||||
// AudioChannels = downmix_channels;
|
*channels = 2;
|
||||||
return;
|
goto try_again;
|
||||||
|
default:
|
||||||
|
Error(_("audio/alsa: unsupported number of channels\n"));
|
||||||
|
// FIXME: must stop sound
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
snd_pcm_hw_params_t *hw_params;
|
snd_pcm_hw_params_t *hw_params;
|
||||||
@ -731,14 +795,15 @@ void AudioSetup(int freq, int channels)
|
|||||||
Debug(3, "audio/alsa: state %s\n",
|
Debug(3, "audio/alsa: state %s\n",
|
||||||
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
||||||
|
|
||||||
AlsaStartThreshold =
|
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, buffer_size);
|
||||||
snd_pcm_frames_to_bytes(AlsaPCMHandle, buffer_size + period_size);
|
|
||||||
// min 500ms
|
// min 500ms
|
||||||
if (AlsaStartThreshold < (freq * channels * 2U) / 2) {
|
if (AlsaStartThreshold < (*freq * *channels * 2U) / 2) {
|
||||||
AlsaStartThreshold = (freq * channels * 2U) / 2;
|
AlsaStartThreshold = (*freq * *channels * 2U) / 2;
|
||||||
}
|
}
|
||||||
Debug(3, "audio/alsa: delay %u ms\n", (AlsaStartThreshold * 1000)
|
Debug(3, "audio/alsa: delay %u ms\n", (AlsaStartThreshold * 1000)
|
||||||
/ (AudioSampleRate * AudioChannels * 2));
|
/ (AudioSampleRate * AudioChannels * 2));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -751,17 +816,40 @@ void AudioSetDevice(const char *device)
|
|||||||
AudioPCMDevice = device;
|
AudioPCMDevice = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Empty log callback
|
||||||
|
*/
|
||||||
|
static void AlsaNoopCallback( __attribute__ ((unused))
|
||||||
|
const char *file, __attribute__ ((unused))
|
||||||
|
int line, __attribute__ ((unused))
|
||||||
|
const char *function, __attribute__ ((unused))
|
||||||
|
int err, __attribute__ ((unused))
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize audio output module.
|
** Initialize audio output module.
|
||||||
*/
|
*/
|
||||||
void AudioInit(void)
|
void AudioInit(void)
|
||||||
{
|
{
|
||||||
|
int freq;
|
||||||
|
int chan;
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
// display alsa error messages
|
||||||
|
snd_lib_error_set_handler(AlsaNoopCallback);
|
||||||
|
#endif
|
||||||
AlsaRingBuffer = RingBufferNew(48000 * 8 * 2); // ~1s 8ch 16bit
|
AlsaRingBuffer = RingBufferNew(48000 * 8 * 2); // ~1s 8ch 16bit
|
||||||
|
|
||||||
AlsaInitPCM();
|
AlsaInitPCM();
|
||||||
AlsaInitMixer();
|
AlsaInitMixer();
|
||||||
|
|
||||||
AudioSetup(48000, 2); // set default parameters
|
freq = 48000;
|
||||||
|
chan = 2;
|
||||||
|
if (AudioSetup(&freq, &chan)) { // set default parameters
|
||||||
|
Error(_("audio: can't do initial setup\n"));
|
||||||
|
}
|
||||||
|
|
||||||
AudioPaused = 1;
|
AudioPaused = 1;
|
||||||
}
|
}
|
||||||
@ -773,9 +861,10 @@ void AudioExit(void)
|
|||||||
{
|
{
|
||||||
void *retval;
|
void *retval;
|
||||||
|
|
||||||
pthread_cancel(AudioThread);
|
if (pthread_cancel(AudioThread)) {
|
||||||
pthread_join(AudioThread, &retval);
|
Error(_("audio: can't queue cancel alsa play thread\n"));
|
||||||
if (retval != PTHREAD_CANCELED) {
|
}
|
||||||
|
if (pthread_join(AudioThread, &retval) || retval != PTHREAD_CANCELED) {
|
||||||
Error(_("audio: can't cancel alsa play thread\n"));
|
Error(_("audio: can't cancel alsa play thread\n"));
|
||||||
}
|
}
|
||||||
pthread_cond_destroy(&AudioStartCond);
|
pthread_cond_destroy(&AudioStartCond);
|
||||||
|
92
codec.c
92
codec.c
@ -346,7 +346,7 @@ void CodecVideoClose(VideoDecoder * video_decoder)
|
|||||||
{
|
{
|
||||||
// FIXME: play buffered data
|
// FIXME: play buffered data
|
||||||
av_freep(&video_decoder->Frame);
|
av_freep(&video_decoder->Frame);
|
||||||
if ( video_decoder->VideoCtx ) {
|
if (video_decoder->VideoCtx) {
|
||||||
avcodec_close(video_decoder->VideoCtx);
|
avcodec_close(video_decoder->VideoCtx);
|
||||||
av_freep(&video_decoder->VideoCtx);
|
av_freep(&video_decoder->VideoCtx);
|
||||||
}
|
}
|
||||||
@ -455,8 +455,13 @@ struct _audio_decoder_
|
|||||||
|
|
||||||
/// audio parser to support wired dvb streaks
|
/// audio parser to support wired dvb streaks
|
||||||
AVCodecParserContext *AudioParser;
|
AVCodecParserContext *AudioParser;
|
||||||
int SampleRate; ///< old sample rate
|
int SampleRate; ///< current sample rate
|
||||||
int Channels; ///< old channels
|
int Channels; ///< current channels
|
||||||
|
|
||||||
|
int HwSampleRate; ///< hw sample rate
|
||||||
|
int HwChannels; ///< hw channels
|
||||||
|
|
||||||
|
ReSampleContext *ReSample; ///< audio resampling context
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -525,6 +530,10 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
|
|||||||
void CodecAudioClose(AudioDecoder * audio_decoder)
|
void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||||
{
|
{
|
||||||
// FIXME: output any buffered data
|
// FIXME: output any buffered data
|
||||||
|
if (audio_decoder->ReSample) {
|
||||||
|
audio_resample_close(audio_decoder->ReSample);
|
||||||
|
audio_decoder->ReSample = NULL;
|
||||||
|
}
|
||||||
if (audio_decoder->AudioParser) {
|
if (audio_decoder->AudioParser) {
|
||||||
av_parser_close(audio_decoder->AudioParser);
|
av_parser_close(audio_decoder->AudioParser);
|
||||||
audio_decoder->AudioParser = NULL;
|
audio_decoder->AudioParser = NULL;
|
||||||
@ -549,11 +558,13 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
|||||||
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
|
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
|
||||||
AVCodecContext *audio_ctx;
|
AVCodecContext *audio_ctx;
|
||||||
int index;
|
int index;
|
||||||
AVPacket spkt[1];
|
|
||||||
|
|
||||||
if (!audio_decoder->AudioParser) {
|
if (!audio_decoder->AudioParser) {
|
||||||
Fatal(_("codec: internal error parser freeded while running\n"));
|
Fatal(_("codec: internal error parser freeded while running\n"));
|
||||||
}
|
}
|
||||||
|
#define spkt avpkt
|
||||||
|
#if 0
|
||||||
|
AVPacket spkt[1];
|
||||||
|
|
||||||
if (av_new_packet(spkt, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE)) {
|
if (av_new_packet(spkt, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE)) {
|
||||||
Error(_("codec: out of memory\n"));
|
Error(_("codec: out of memory\n"));
|
||||||
@ -561,6 +572,9 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
|||||||
}
|
}
|
||||||
memcpy(spkt->data, avpkt->data, avpkt->size);
|
memcpy(spkt->data, avpkt->data, avpkt->size);
|
||||||
memset(spkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
memset(spkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
spkt->pts = avpkt->pts;
|
||||||
|
#endif
|
||||||
|
|
||||||
audio_ctx = audio_decoder->AudioCtx;
|
audio_ctx = audio_decoder->AudioCtx;
|
||||||
index = 0;
|
index = 0;
|
||||||
while (avpkt->size > index) {
|
while (avpkt->size > index) {
|
||||||
@ -571,11 +585,13 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
|||||||
av_init_packet(dpkt);
|
av_init_packet(dpkt);
|
||||||
n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx,
|
n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx,
|
||||||
&dpkt->data, &dpkt->size, spkt->data + index, avpkt->size - index,
|
&dpkt->data, &dpkt->size, spkt->data + index, avpkt->size - index,
|
||||||
AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
|
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE, AV_NOPTS_VALUE,
|
||||||
|
-1);
|
||||||
|
|
||||||
if (dpkt->size) {
|
if (dpkt->size) {
|
||||||
int buf_sz;
|
int buf_sz;
|
||||||
|
|
||||||
|
dpkt->pts = audio_decoder->AudioParser->pts;
|
||||||
buf_sz = sizeof(buf);
|
buf_sz = sizeof(buf);
|
||||||
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
|
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
|
||||||
if (l < 0) { // no audio frame could be decompressed
|
if (l < 0) { // no audio frame could be decompressed
|
||||||
@ -589,17 +605,62 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
|||||||
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
|
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
// Update audio clock
|
||||||
|
if ((uint64_t) dpkt->pts != AV_NOPTS_VALUE) {
|
||||||
|
AudioSetClock(dpkt->pts);
|
||||||
|
}
|
||||||
// FIXME: must first play remainings bytes, than change and play new.
|
// FIXME: must first play remainings bytes, than change and play new.
|
||||||
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||||
|| audio_decoder->Channels != audio_ctx->channels) {
|
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||||
|
int err;
|
||||||
|
|
||||||
// FIXME: channels not support?
|
if (audio_decoder->ReSample) {
|
||||||
AudioSetup(audio_ctx->sample_rate, audio_ctx->channels);
|
audio_resample_close(audio_decoder->ReSample);
|
||||||
|
audio_decoder->ReSample = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
audio_decoder->SampleRate = audio_ctx->sample_rate;
|
audio_decoder->SampleRate = audio_ctx->sample_rate;
|
||||||
|
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
|
||||||
audio_decoder->Channels = audio_ctx->channels;
|
audio_decoder->Channels = audio_ctx->channels;
|
||||||
|
audio_decoder->HwChannels = audio_ctx->channels;
|
||||||
|
|
||||||
|
// channels not support?
|
||||||
|
if ((err =
|
||||||
|
AudioSetup(&audio_decoder->HwSampleRate,
|
||||||
|
&audio_decoder->HwChannels))) {
|
||||||
|
Debug(3, "codec/audio: resample %d -> %d\n",
|
||||||
|
audio_ctx->channels, audio_decoder->HwChannels);
|
||||||
|
|
||||||
|
if (err == 1) {
|
||||||
|
audio_decoder->ReSample =
|
||||||
|
av_audio_resample_init(audio_decoder->HwChannels,
|
||||||
|
audio_ctx->channels, audio_decoder->HwSampleRate,
|
||||||
|
audio_ctx->sample_rate, audio_ctx->sample_fmt,
|
||||||
|
audio_ctx->sample_fmt, 16, 10, 0, 0.8);
|
||||||
|
} else {
|
||||||
|
// FIXME: handle errors
|
||||||
|
audio_decoder->HwChannels = 0;
|
||||||
|
audio_decoder->HwSampleRate = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_decoder->HwSampleRate && audio_decoder->HwChannels) {
|
||||||
|
// need to resample audio
|
||||||
|
if (audio_decoder->ReSample) {
|
||||||
|
int16_t outbuf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
|
||||||
|
FF_INPUT_BUFFER_PADDING_SIZE]
|
||||||
|
__attribute__ ((aligned(16)));
|
||||||
|
int outlen;
|
||||||
|
|
||||||
|
outlen =
|
||||||
|
audio_resample(audio_decoder->ReSample, outbuf, buf,
|
||||||
|
buf_sz);
|
||||||
|
AudioEnqueue(outbuf, outlen);
|
||||||
|
} else {
|
||||||
AudioEnqueue(buf, buf_sz);
|
AudioEnqueue(buf, buf_sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dpkt->size > l) {
|
if (dpkt->size > l) {
|
||||||
Error(_("codec: error more than one frame data\n"));
|
Error(_("codec: error more than one frame data\n"));
|
||||||
@ -608,18 +669,35 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
|||||||
|
|
||||||
index += n;
|
index += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
av_destruct_packet(spkt);
|
av_destruct_packet(spkt);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Codec
|
// Codec
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Empty log callback
|
||||||
|
*/
|
||||||
|
static void CodecNoopCallback( __attribute__ ((unused))
|
||||||
|
void *ptr, __attribute__ ((unused))
|
||||||
|
int level, __attribute__ ((unused))
|
||||||
|
const char *fmt, __attribute__ ((unused)) va_list vl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Codec init
|
** Codec init
|
||||||
*/
|
*/
|
||||||
void CodecInit(void)
|
void CodecInit(void)
|
||||||
{
|
{
|
||||||
|
#ifndef DEBUG
|
||||||
|
// display ffmpeg error messages
|
||||||
|
av_log_set_callback(CodecNoopCallback);
|
||||||
|
#endif
|
||||||
avcodec_register_all(); // register all formats and codecs
|
avcodec_register_all(); // register all formats and codecs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user