mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Add audio compatibility with >=ffmpeg 1.1.
This commit is contained in:
parent
04286fb2ad
commit
f9998e7664
@ -1,6 +1,7 @@
|
|||||||
User johns
|
User johns
|
||||||
Date:
|
Date:
|
||||||
|
|
||||||
|
Add compatibility with >=ffmpeg 1.1.
|
||||||
Adds PIP (Picture-in-Picture) support.
|
Adds PIP (Picture-in-Picture) support.
|
||||||
Split mpeg packets in receiver thread.
|
Split mpeg packets in receiver thread.
|
||||||
|
|
||||||
|
20
Makefile
20
Makefile
@ -24,6 +24,8 @@ CONFIG += -DUSE_PIP # too experimental PIP support
|
|||||||
#CONFIG += -DHAVE_PTHREAD_NAME # supports new pthread_setname_np
|
#CONFIG += -DHAVE_PTHREAD_NAME # supports new pthread_setname_np
|
||||||
#CONFIG += -DNO_TS_AUDIO # disable ts audio parser
|
#CONFIG += -DNO_TS_AUDIO # disable ts audio parser
|
||||||
#CONFIG += -DUSE_TS_VIDEO # build new ts video parser
|
#CONFIG += -DUSE_TS_VIDEO # build new ts video parser
|
||||||
|
# use ffmpeg libswresample
|
||||||
|
CONFIG += $(shell pkg-config --exists libswresample && echo "-DUSE_SWRESAMPLE")
|
||||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||||
@ -73,12 +75,12 @@ _CFLAGS = $(DEFINES) $(INCLUDES) \
|
|||||||
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||||
`pkg-config --cflags gl glu` \
|
`pkg-config --cflags gl glu` \
|
||||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
$(if $(findstring USE_SWRESAMPLE,$(CONFIG)), \
|
||||||
`pkg-config --cflags vdpau`) \
|
$(shell pkg-config --cflags libswresample)) \
|
||||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||||
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
||||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||||
`pkg-config --cflags alsa`)
|
`pkg-config --cflags alsa`)
|
||||||
|
|
||||||
#override _CFLAGS += -Werror
|
#override _CFLAGS += -Werror
|
||||||
override CXXFLAGS += $(_CFLAGS)
|
override CXXFLAGS += $(_CFLAGS)
|
||||||
@ -89,12 +91,14 @@ LIBS += -lrt \
|
|||||||
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||||
`pkg-config --libs gl glu` \
|
`pkg-config --libs gl glu` \
|
||||||
|
$(if $(findstring USE_SWRESAMPLE,$(CONFIG)), \
|
||||||
|
$(shell pkg-config --libs libswresample)) \
|
||||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||||
`pkg-config --libs vdpau`) \
|
`pkg-config --libs vdpau`) \
|
||||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||||
`pkg-config --libs libva-x11 libva-glx libva`) \
|
`pkg-config --libs libva-x11 libva-glx libva`) \
|
||||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||||
`pkg-config --libs alsa`)
|
`pkg-config --libs alsa`)
|
||||||
|
|
||||||
### The object files (add further files here):
|
### The object files (add further files here):
|
||||||
|
|
||||||
@ -132,7 +136,7 @@ I18Npot = $(PODIR)/$(PLUGIN).pot
|
|||||||
%.mo: %.po
|
%.mo: %.po
|
||||||
msgfmt -c -o $@ $<
|
msgfmt -c -o $@ $<
|
||||||
|
|
||||||
$(I18Npot): $(wildcard *.cpp) $(wildcard *.c)
|
$(I18Npot): $(wildcard *.cpp) $(wildcard *.c)
|
||||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP \
|
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP \
|
||||||
-k_ -k_N --package-name=VDR --package-version=$(VDRVERSION) \
|
-k_ -k_N --package-name=VDR --package-version=$(VDRVERSION) \
|
||||||
--msgid-bugs-address='<see README>' -o $@ $^
|
--msgid-bugs-address='<see README>' -o $@ $^
|
||||||
|
2
Todo
2
Todo
@ -117,6 +117,8 @@ setup:
|
|||||||
unsorted:
|
unsorted:
|
||||||
stoping vdr while plugin is suspended opens and closes a window.
|
stoping vdr while plugin is suspended opens and closes a window.
|
||||||
svdrp prim: support plugin names for device numbers.
|
svdrp prim: support plugin names for device numbers.
|
||||||
|
hangup PipVideoStream -> Vdpau_get_format -> xcb -> poll
|
||||||
|
+ lock DecoderLockMutex
|
||||||
|
|
||||||
future features (not planed for 1.0 - 1.5)
|
future features (not planed for 1.0 - 1.5)
|
||||||
|
|
||||||
|
337
codec.c
337
codec.c
@ -36,6 +36,8 @@
|
|||||||
#define USE_AUDIO_DRIFT_CORRECTION
|
#define USE_AUDIO_DRIFT_CORRECTION
|
||||||
/// compile AC3 audio drift correction support (experimental)
|
/// compile AC3 audio drift correction support (experimental)
|
||||||
#define USE_AC3_DRIFT_CORRECTION
|
#define USE_AC3_DRIFT_CORRECTION
|
||||||
|
/// use ffmpeg libswresample API
|
||||||
|
#define noUSE_SWRESAMPLE
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -58,6 +60,9 @@
|
|||||||
#ifdef USE_VDPAU
|
#ifdef USE_VDPAU
|
||||||
#include <libavcodec/vdpau.h>
|
#include <libavcodec/vdpau.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_SWRESAMPLE
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __USE_GNU
|
#ifndef __USE_GNU
|
||||||
#define __USE_GNU
|
#define __USE_GNU
|
||||||
@ -629,7 +634,16 @@ struct _audio_decoder_
|
|||||||
int HwSampleRate; ///< hw sample rate
|
int HwSampleRate; ///< hw sample rate
|
||||||
int HwChannels; ///< hw channels
|
int HwChannels; ///< hw channels
|
||||||
|
|
||||||
|
#ifndef USE_SWRESAMPLE
|
||||||
ReSampleContext *ReSample; ///< audio resampling context
|
ReSampleContext *ReSample; ///< audio resampling context
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SWRESAMPLE
|
||||||
|
#if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(0, 15, 100)
|
||||||
|
struct SwrContext *Resample; ///< audio software resample context
|
||||||
|
#else
|
||||||
|
SwrContext *Resample; ///< audio software resample context
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
int64_t LastDelay; ///< last delay
|
int64_t LastDelay; ///< last delay
|
||||||
struct timespec LastTime; ///< last time
|
struct timespec LastTime; ///< last time
|
||||||
@ -639,6 +653,7 @@ struct _audio_decoder_
|
|||||||
int DriftCorr; ///< audio drift correction value
|
int DriftCorr; ///< audio drift correction value
|
||||||
int DriftFrac; ///< audio drift fraction for ac3
|
int DriftFrac; ///< audio drift fraction for ac3
|
||||||
|
|
||||||
|
#ifndef USE_SWRESAMPLE
|
||||||
struct AVResampleContext *AvResample; ///< second audio resample context
|
struct AVResampleContext *AvResample; ///< second audio resample context
|
||||||
#define MAX_CHANNELS 8 ///< max number of channels supported
|
#define MAX_CHANNELS 8 ///< max number of channels supported
|
||||||
int16_t *Buffer[MAX_CHANNELS]; ///< deinterleave sample buffers
|
int16_t *Buffer[MAX_CHANNELS]; ///< deinterleave sample buffers
|
||||||
@ -646,9 +661,12 @@ struct _audio_decoder_
|
|||||||
int16_t *Remain[MAX_CHANNELS]; ///< filter remaining samples
|
int16_t *Remain[MAX_CHANNELS]; ///< filter remaining samples
|
||||||
int RemainSize; ///< size of remain buffer
|
int RemainSize; ///< size of remain buffer
|
||||||
int RemainCount; ///< number of remaining samples
|
int RemainCount; ///< number of remaining samples
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||||
|
#define CORRECT_PCM 1 ///< do PCM audio-drift correction
|
||||||
|
#define CORRECT_AC3 2 ///< do AC3§ audio-drift correction
|
||||||
static char CodecAudioDrift; ///< flag: enable audio-drift correction
|
static char CodecAudioDrift; ///< flag: enable audio-drift correction
|
||||||
#else
|
#else
|
||||||
static const int CodecAudioDrift = 0;
|
static const int CodecAudioDrift = 0;
|
||||||
@ -718,10 +736,16 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CodecDownmix) {
|
if (CodecDownmix) {
|
||||||
|
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53,61,100)
|
||||||
audio_decoder->AudioCtx->request_channels = 2;
|
audio_decoder->AudioCtx->request_channels = 2;
|
||||||
|
#endif
|
||||||
audio_decoder->AudioCtx->request_channel_layout =
|
audio_decoder->AudioCtx->request_channel_layout =
|
||||||
AV_CH_LAYOUT_STEREO_DOWNMIX;
|
AV_CH_LAYOUT_STEREO_DOWNMIX;
|
||||||
}
|
}
|
||||||
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,61,100)
|
||||||
|
// this has no effect
|
||||||
|
// audio_decoder->AudioCtx->request_sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
#endif
|
||||||
pthread_mutex_lock(&CodecLockMutex);
|
pthread_mutex_lock(&CodecLockMutex);
|
||||||
// open codec
|
// open codec
|
||||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
|
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
|
||||||
@ -768,6 +792,7 @@ 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
|
||||||
|
#ifndef USE_SWRESAMPLE
|
||||||
if (audio_decoder->AvResample) {
|
if (audio_decoder->AvResample) {
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
@ -787,6 +812,12 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
|
|||||||
audio_resample_close(audio_decoder->ReSample);
|
audio_resample_close(audio_decoder->ReSample);
|
||||||
audio_decoder->ReSample = NULL;
|
audio_decoder->ReSample = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SWRESAMPLE
|
||||||
|
if (audio_decoder->Resample) {
|
||||||
|
swr_free(&audio_decoder->Resample);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (audio_decoder->AudioCtx) {
|
if (audio_decoder->AudioCtx) {
|
||||||
pthread_mutex_lock(&CodecLockMutex);
|
pthread_mutex_lock(&CodecLockMutex);
|
||||||
avcodec_close(audio_decoder->AudioCtx);
|
avcodec_close(audio_decoder->AudioCtx);
|
||||||
@ -895,6 +926,8 @@ static void CodecReorderAudioFrame(int16_t * buf, int size, int channels)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_SWRESAMPLE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Set/update audio pts clock.
|
** Set/update audio pts clock.
|
||||||
**
|
**
|
||||||
@ -916,14 +949,15 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
|||||||
if (!delay) {
|
if (!delay) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clock_gettime(CLOCK_REALTIME, &nowtime);
|
clock_gettime(CLOCK_MONOTONIC, &nowtime);
|
||||||
if (!audio_decoder->LastDelay) {
|
if (!audio_decoder->LastDelay) {
|
||||||
audio_decoder->LastTime = nowtime;
|
audio_decoder->LastTime = nowtime;
|
||||||
audio_decoder->LastPTS = pts;
|
audio_decoder->LastPTS = pts;
|
||||||
audio_decoder->LastDelay = delay;
|
audio_decoder->LastDelay = delay;
|
||||||
audio_decoder->Drift = 0;
|
audio_decoder->Drift = 0;
|
||||||
audio_decoder->DriftFrac = 0;
|
audio_decoder->DriftFrac = 0;
|
||||||
Debug(3, "codec/audio: inital delay %" PRId64 "ms\n", delay / 90);
|
Debug(3, "codec/audio: inital drift delay %" PRId64 "ms\n",
|
||||||
|
delay / 90);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// collect over some time
|
// collect over some time
|
||||||
@ -1205,14 +1239,6 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
|||||||
}
|
}
|
||||||
Error(_("codec: error more than one frame data\n"));
|
Error(_("codec: error more than one frame data\n"));
|
||||||
}
|
}
|
||||||
#ifdef notyetFF_API_OLD_DECODE_AUDIO
|
|
||||||
// FIXME: ffmpeg git comeing
|
|
||||||
int got_frame;
|
|
||||||
|
|
||||||
avcodec_decode_audio4(audio_ctx, frame, &got_frame, avpkt);
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// update audio clock
|
// update audio clock
|
||||||
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
||||||
CodecAudioSetClock(audio_decoder, avpkt->pts);
|
CodecAudioSetClock(audio_decoder, avpkt->pts);
|
||||||
@ -1352,6 +1378,297 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SWRESAMPLE
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Set/update audio pts clock.
|
||||||
|
**
|
||||||
|
** @param audio_decoder audio decoder data
|
||||||
|
** @param pts presentation timestamp
|
||||||
|
*/
|
||||||
|
static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
||||||
|
{
|
||||||
|
struct timespec nowtime;
|
||||||
|
int64_t delay;
|
||||||
|
int64_t tim_diff;
|
||||||
|
int64_t pts_diff;
|
||||||
|
int drift;
|
||||||
|
int corr;
|
||||||
|
|
||||||
|
AudioSetClock(pts);
|
||||||
|
|
||||||
|
delay = AudioGetDelay();
|
||||||
|
if (!delay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &nowtime);
|
||||||
|
if (!audio_decoder->LastDelay) {
|
||||||
|
audio_decoder->LastTime = nowtime;
|
||||||
|
audio_decoder->LastPTS = pts;
|
||||||
|
audio_decoder->LastDelay = delay;
|
||||||
|
audio_decoder->Drift = 0;
|
||||||
|
audio_decoder->DriftFrac = 0;
|
||||||
|
Debug(3, "codec/audio: inital drift delay %" PRId64 "ms\n",
|
||||||
|
delay / 90);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// collect over some time
|
||||||
|
pts_diff = pts - audio_decoder->LastPTS;
|
||||||
|
if (pts_diff < 10 * 1000 * 90) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tim_diff = (nowtime.tv_sec - audio_decoder->LastTime.tv_sec)
|
||||||
|
* 1000 * 1000 * 1000 + (nowtime.tv_nsec -
|
||||||
|
audio_decoder->LastTime.tv_nsec);
|
||||||
|
|
||||||
|
drift =
|
||||||
|
(tim_diff * 90) / (1000 * 1000) - pts_diff + delay -
|
||||||
|
audio_decoder->LastDelay;
|
||||||
|
|
||||||
|
// adjust rounding error
|
||||||
|
nowtime.tv_nsec -= nowtime.tv_nsec % (1000 * 1000 / 90);
|
||||||
|
audio_decoder->LastTime = nowtime;
|
||||||
|
audio_decoder->LastPTS = pts;
|
||||||
|
audio_decoder->LastDelay = delay;
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
Debug(3,
|
||||||
|
"codec/audio: interval P:%5" PRId64 "ms T:%5" PRId64 "ms D:%4"
|
||||||
|
PRId64 "ms %f %d\n", pts_diff / 90, tim_diff / (1000 * 1000),
|
||||||
|
delay / 90, drift / 90.0, audio_decoder->DriftCorr);
|
||||||
|
}
|
||||||
|
// underruns and av_resample have the same time :(((
|
||||||
|
if (abs(drift) > 10 * 90) {
|
||||||
|
// drift too big, pts changed?
|
||||||
|
Debug(3, "codec/audio: drift(%6d) %3dms reset\n",
|
||||||
|
audio_decoder->DriftCorr, drift / 90);
|
||||||
|
audio_decoder->LastDelay = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
corr = 0; // keep gcc happy
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
|
||||||
|
drift += audio_decoder->Drift;
|
||||||
|
audio_decoder->Drift = drift;
|
||||||
|
corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000);
|
||||||
|
// SPDIF/HDMI passthrough
|
||||||
|
if ((CodecAudioDrift & 2) && (!CodecPassthroughAC3
|
||||||
|
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3)) {
|
||||||
|
audio_decoder->DriftCorr = -corr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_decoder->DriftCorr < -20000) { // limit correction
|
||||||
|
audio_decoder->DriftCorr = -20000;
|
||||||
|
} else if (audio_decoder->DriftCorr > 20000) {
|
||||||
|
audio_decoder->DriftCorr = 20000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_decoder->Resample && audio_decoder->DriftCorr) {
|
||||||
|
int distance;
|
||||||
|
|
||||||
|
// try workaround for buggy ffmpeg 0.10
|
||||||
|
if (abs(audio_decoder->DriftCorr) < 2000) {
|
||||||
|
distance = (pts_diff * audio_decoder->HwSampleRate) / (900 * 1000);
|
||||||
|
} else {
|
||||||
|
distance = (pts_diff * audio_decoder->HwSampleRate) / (90 * 1000);
|
||||||
|
}
|
||||||
|
if (swr_set_compensation(audio_decoder->Resample,
|
||||||
|
audio_decoder->DriftCorr / 10, distance)) {
|
||||||
|
Debug(3, "codec/audio: swr_set_compensation failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (1) {
|
||||||
|
static int c;
|
||||||
|
|
||||||
|
if (!(c++ % 10)) {
|
||||||
|
Debug(3, "codec/audio: drift(%6d) %8dus %5d\n",
|
||||||
|
audio_decoder->DriftCorr, drift * 1000 / 90, corr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Handle audio format changes.
|
||||||
|
**
|
||||||
|
** @param audio_decoder audio decoder data
|
||||||
|
*/
|
||||||
|
static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||||
|
{
|
||||||
|
const AVCodecContext *audio_ctx;
|
||||||
|
int err;
|
||||||
|
int isAC3;
|
||||||
|
|
||||||
|
audio_ctx = audio_decoder->AudioCtx;
|
||||||
|
Debug(3, "codec/audio: format change %s %dHz *%d channels %s\n",
|
||||||
|
av_get_sample_fmt_name(audio_ctx->sample_fmt), audio_ctx->sample_rate,
|
||||||
|
audio_ctx->channels, CodecPassthroughAC3 ? "pass-through" : "");
|
||||||
|
|
||||||
|
audio_decoder->SampleRate = audio_ctx->sample_rate;
|
||||||
|
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
|
||||||
|
audio_decoder->Channels = audio_ctx->channels;
|
||||||
|
audio_decoder->PassthroughAC3 = CodecPassthroughAC3;
|
||||||
|
|
||||||
|
// SPDIF/HDMI passthrough
|
||||||
|
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
||||||
|
audio_decoder->HwChannels = 2;
|
||||||
|
isAC3 = 1;
|
||||||
|
} else {
|
||||||
|
audio_decoder->HwChannels = audio_ctx->channels;
|
||||||
|
isAC3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// channels not support?
|
||||||
|
if ((err =
|
||||||
|
AudioSetup(&audio_decoder->HwSampleRate,
|
||||||
|
&audio_decoder->HwChannels, isAC3))) {
|
||||||
|
|
||||||
|
Debug(3, "codec/audio: audio setup error\n");
|
||||||
|
// FIXME: handle errors
|
||||||
|
audio_decoder->HwChannels = 0;
|
||||||
|
audio_decoder->HwSampleRate = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAC3) { // no AC3 conversion allowed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(3, "codec/audio: resample %s %dHz *%d -> %s %dHz *%d\n",
|
||||||
|
av_get_sample_fmt_name(audio_ctx->sample_fmt), audio_ctx->sample_rate,
|
||||||
|
audio_ctx->channels, av_get_sample_fmt_name(AV_SAMPLE_FMT_S16),
|
||||||
|
audio_decoder->HwSampleRate, audio_decoder->HwChannels);
|
||||||
|
|
||||||
|
audio_decoder->Resample =
|
||||||
|
swr_alloc_set_opts(audio_decoder->Resample, audio_ctx->channel_layout,
|
||||||
|
AV_SAMPLE_FMT_S16, audio_decoder->HwSampleRate,
|
||||||
|
audio_ctx->channel_layout, audio_ctx->sample_fmt,
|
||||||
|
audio_ctx->sample_rate, 0, NULL);
|
||||||
|
if (audio_decoder->Resample) {
|
||||||
|
swr_init(audio_decoder->Resample);
|
||||||
|
} else {
|
||||||
|
Error(_("codec/audio: can't setup resample\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Decode an audio packet.
|
||||||
|
**
|
||||||
|
** PTS must be handled self.
|
||||||
|
**
|
||||||
|
** @note the caller has not aligned avpkt and not cleared the end.
|
||||||
|
**
|
||||||
|
** @param audio_decoder audio decoder data
|
||||||
|
** @param avpkt audio packet
|
||||||
|
*/
|
||||||
|
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||||
|
{
|
||||||
|
AVCodecContext *audio_ctx;
|
||||||
|
AVFrame frame;
|
||||||
|
int got_frame;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
audio_ctx = audio_decoder->AudioCtx;
|
||||||
|
|
||||||
|
frame.data[0] = NULL;
|
||||||
|
n = avcodec_decode_audio4(audio_ctx, &frame, &got_frame,
|
||||||
|
(AVPacket *) avpkt);
|
||||||
|
if (n != avpkt->size) {
|
||||||
|
if (n == AVERROR(EAGAIN)) {
|
||||||
|
Error(_("codec/audio: latm\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (n < 0) { // no audio frame could be decompressed
|
||||||
|
Error(_("codec/audio: bad audio frame\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Error(_("codec/audio: error more than one frame data\n"));
|
||||||
|
}
|
||||||
|
if (!got_frame) {
|
||||||
|
Error(_("codec/audio: no frame\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// update audio clock
|
||||||
|
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
||||||
|
CodecAudioSetClock(audio_decoder, avpkt->pts);
|
||||||
|
}
|
||||||
|
// format change
|
||||||
|
if (audio_decoder->PassthroughAC3 != CodecPassthroughAC3
|
||||||
|
|| audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||||
|
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||||
|
CodecAudioUpdateFormat(audio_decoder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!audio_decoder->HwSampleRate || !audio_decoder->HwChannels) {
|
||||||
|
return; // unsupported sample format
|
||||||
|
}
|
||||||
|
#ifdef USE_PASSTHROUGH
|
||||||
|
// SPDIF/HDMI passthrough
|
||||||
|
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
||||||
|
int16_t spdif[6144 / 2];
|
||||||
|
int spdif_sz;
|
||||||
|
|
||||||
|
// build SPDIF header and append A52 audio to it
|
||||||
|
// avpkt is the original data
|
||||||
|
spdif_sz = 6144;
|
||||||
|
if (spdif_sz < avpkt->size + 8) {
|
||||||
|
Error(_("codec/audio: decoded data smaller than encoded\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// copy original data for output
|
||||||
|
spdif[0] = htole16(0xF872); // iec 61937 sync word
|
||||||
|
spdif[1] = htole16(0x4E1F);
|
||||||
|
spdif[2] = htole16(0x01 | (avpkt->data[5] & 0x07) << 8);
|
||||||
|
spdif[3] = htole16(avpkt->size * 8);
|
||||||
|
// FIXME: not 100% sure, if endian is correct on not intel hardware
|
||||||
|
swab(avpkt->data, spdif + 4, avpkt->size);
|
||||||
|
memset(spdif + 4 + avpkt->size / 2, 0, spdif_sz - 8 - avpkt->size);
|
||||||
|
// don't play with the ac-3 samples
|
||||||
|
AudioEnqueue(spdif, spdif_sz);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (0) {
|
||||||
|
char strbuf[32];
|
||||||
|
int data_sz;
|
||||||
|
int plane_sz;
|
||||||
|
|
||||||
|
data_sz =
|
||||||
|
av_samples_get_buffer_size(&plane_sz, audio_ctx->channels,
|
||||||
|
frame.nb_samples, audio_ctx->sample_fmt, 1);
|
||||||
|
fprintf(stderr, "codec/audio: sample_fmt %s\n",
|
||||||
|
av_get_sample_fmt_name(audio_ctx->sample_fmt));
|
||||||
|
av_get_channel_layout_string(strbuf, 32, audio_ctx->channels,
|
||||||
|
audio_ctx->channel_layout);
|
||||||
|
fprintf(stderr, "codec/audio: layout %s\n", strbuf);
|
||||||
|
fprintf(stderr,
|
||||||
|
"codec/audio: channels %d samples %d plane %d data %d\n",
|
||||||
|
audio_ctx->channels, frame.nb_samples, plane_sz, data_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_decoder->Resample) {
|
||||||
|
uint8_t outbuf[8192 * 2 * 8];
|
||||||
|
uint8_t *out[1];
|
||||||
|
|
||||||
|
out[0] = outbuf;
|
||||||
|
n = swr_convert(audio_decoder->Resample, out,
|
||||||
|
sizeof(outbuf) / (2 * audio_decoder->HwChannels),
|
||||||
|
(const uint8_t **)frame.extended_data, frame.nb_samples);
|
||||||
|
if (n > 0) {
|
||||||
|
CodecReorderAudioFrame((int16_t *) outbuf,
|
||||||
|
n * 2 * audio_decoder->HwChannels, audio_decoder->HwChannels);
|
||||||
|
AudioEnqueue(outbuf, n * 2 * audio_decoder->HwChannels);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Flush the audio decoder.
|
** Flush the audio decoder.
|
||||||
**
|
**
|
||||||
|
Loading…
Reference in New Issue
Block a user