Skip to content
Permalink
Browse files

Add ability to passthru any audio type to mythtranscode.

This is done by allowing avformatdecoder to output completely unprocessed raw audio data too AudioOutput::AddData. The check for passthrough capabilities is now entirely done by the base audio class and AVFD doesn't need to know anything about the codecs who can be bitstreamed. This will allow bitstream to be easily extended, in particular AAC bitstream.

For exploiting the new capabilities of mythtranscode, the appropriate script will have to be written using mythtranscode FIFO mode.

Closes #9536
  • Loading branch information
jyavenard committed Mar 22, 2011
1 parent c3bc396 commit 77e60c37e4d3ade66e96f001c368edd559b65d35
@@ -225,7 +225,8 @@ AudioOutputSettings* AudioOutput::GetOutputSettingsUsers(bool /*digital*/)

bool AudioOutput::CanPassthrough(int /*samplerate*/,
int /*channels*/,
int /*codec*/) const
int /*codec*/,
int /*profile*/) const
{
return false;
}
@@ -66,16 +66,44 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners

virtual AudioOutputSettings* GetOutputSettingsCleaned(bool digital = true);
virtual AudioOutputSettings* GetOutputSettingsUsers(bool digital = true);
virtual bool CanPassthrough(int samplerate, int channels, int codec) const;
virtual bool CanPassthrough(int samplerate, int channels,
int codec, int profile) const;

// dsprate is in 100 * samples/second
virtual void SetEffDsp(int dsprate) = 0;

virtual void Reset(void) = 0;

virtual bool AddFrames(void *buffer, int frames, int64_t timecode) = 0;
virtual bool AddData(void *buffer, int len, int64_t timecode) = 0;
virtual int64_t LengthLastData(void) = 0;
/**
* AddData:
* Add data to the audiobuffer for playback
*
* in:
* buffer : pointer to audio data
* len : length of audio data added
* timecode: timecode of the first sample added
* frames : number of frames added.
* out:
* return false if there wasn't enough space in audio buffer to
* process all the data
*/
virtual bool AddData(void *buffer, int len,
int64_t timecode, int frames) = 0;
/**
* NeedDecodingBeforePassthrough:
* returns true if AudioOutput class can determine the length in
* millisecond of native audio frames bitstreamed passed to AddData.
* If false, LengthLastData method must be implemented
*/
virtual bool NeedDecodingBeforePassthrough(void) const { return true; };
/**
* LengthLastData:
* returns the length of the last data added in millisecond.
* This function must be implemented if NeedDecodingBeforePassthrough
* returned false
*/
virtual int64_t LengthLastData(void) const { return -1; };

virtual void SetTimecode(int64_t timecode) = 0;
virtual bool IsPaused(void) const = 0;
@@ -241,19 +241,52 @@ AudioOutputSettings* AudioOutputBase::GetOutputSettingsUsers(bool digital)
* Test if we can output digital audio and if sample rate is supported
*/
bool AudioOutputBase::CanPassthrough(int samplerate, int channels,
int codec) const
int codec, int profile) const
{
bool ret = false;
ret = output_settingsdigital->IsSupportedFormat(FORMAT_S16);
bool ret = !internal_vol;;
DigitalFeature arg = FEATURE_NONE;

switch(codec)
{
case CODEC_ID_AC3:
arg = FEATURE_AC3;
break;
case CODEC_ID_DTS:
switch(profile)
{
case FF_PROFILE_DTS:
case FF_PROFILE_DTS_ES:
case FF_PROFILE_DTS_96_24:
arg = FEATURE_DTS;
break;
case FF_PROFILE_DTS_HD_HRA:
case FF_PROFILE_DTS_HD_MA:
arg = FEATURE_DTSHD;
default:
break;
}
break;
case CODEC_ID_EAC3:
arg = FEATURE_EAC3;
break;
case CODEC_ID_TRUEHD:
arg = FEATURE_TRUEHD;
break;
}
// we can't passthrough any other codecs than those defined above
ret &= output_settingsdigital->canFeature(arg);
ret &= output_settingsdigital->IsSupportedFormat(FORMAT_S16);
ret &= output_settingsdigital->IsSupportedRate(samplerate);
// Don't know any cards that support spdif clocked at < 44100
// Some US cable transmissions have 2ch 32k AC-3 streams
ret &= samplerate >= 44100;
if (!ret)
return false;
// Will passthrough if surround audio was defined. Amplifier will
// do the downmix if required
ret &= max_channels >= 6 && channels > 2;
// Stereo content will always be decoded so it can later be upmixed
// unless audio is configured for stereoo
// unless audio is configured for stereoo. We can passthrough otherwise
ret |= max_channels == 2;

return ret;
@@ -1172,7 +1205,8 @@ int AudioOutputBase::CopyWithUpmix(char *buffer, int frames, int &org_waud)
bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
int64_t timecode)
{
return AddData(in_buffer, in_frames * source_bytes_per_frame, timecode);
return AddData(in_buffer, in_frames * source_bytes_per_frame, timecode,
in_frames);
}

/**
@@ -1181,7 +1215,7 @@ bool AudioOutputBase::AddFrames(void *in_buffer, int in_frames,
* Returns false if there's not enough space right now
*/
bool AudioOutputBase::AddData(void *in_buffer, int in_len,
int64_t timecode)
int64_t timecode, int /*in_frames*/)
{
int org_waud = waud;
int afree = audiofree();
@@ -68,7 +68,8 @@ class AudioOutputBase : public AudioOutput, public QThread
virtual AudioFormat GetFormat(void) const { return format; };
virtual int GetBytesPerFrame(void) const { return source_bytes_per_frame; };

virtual bool CanPassthrough(int samplerate, int channels, int codec) const;
virtual bool CanPassthrough(int samplerate, int channels,
int codec, int profile) const;
virtual bool ToggleUpmix(void);

virtual void Reset(void);
@@ -78,8 +79,9 @@ class AudioOutputBase : public AudioOutput, public QThread

// timecode is in milliseconds.
virtual bool AddFrames(void *buffer, int frames, int64_t timecode);
virtual bool AddData(void *buffer, int len, int64_t timecode);
virtual int64_t LengthLastData(void) { return m_length_last_data; }
virtual bool AddData(void *buffer, int len, int64_t timecode, int frames);
virtual bool NeedDecodingBeforePassthrough() const { return false; };
virtual int64_t LengthLastData(void) const { return m_length_last_data; }

virtual void SetTimecode(int64_t timecode);
virtual bool IsPaused(void) const { return actually_paused; }
@@ -84,9 +84,9 @@ class MPUBLIC AudioOutputSettings
* - FEATURE_TRUEHD
* - FEATURE_DTSHD
*/
unsigned int canFeature(DigitalFeature arg)
bool canFeature(DigitalFeature arg)
{ return m_features & arg; };
unsigned int canFeature(unsigned int arg)
bool canFeature(unsigned int arg)
{ return m_features & arg; };

/**
@@ -12,7 +12,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
#define MYTH_BINARY_VERSION "0.25.20110321-1"
#define MYTH_BINARY_VERSION "0.25.20110322-1"

/** \brief Increment this whenever the MythTV network protocol changes.
*
@@ -398,14 +398,20 @@ int AudioPlayer::GetMaxHDRate()
return m_audioOutput->GetOutputSettingsUsers(true)->GetMaxHDRate();
}

bool AudioPlayer::CanPassthrough(int samplerate, int channels, int codec)
bool AudioPlayer::CanPassthrough(int samplerate, int channels,
int codec, int profile)
{
if (!m_audioOutput)
return false;
return m_audioOutput->CanPassthrough(samplerate, channels, codec);
return m_audioOutput->CanPassthrough(samplerate, channels, codec, profile);
}

void AudioPlayer::AddAudioData(char *buffer, int len, int64_t timecode)
/*
* if frames = -1 : let AudioOuput calculate value
* if frames = 0 && len > 0: will calculate according to len
*/
void AudioPlayer::AddAudioData(char *buffer, int len,
int64_t timecode, int frames)
{
if (!m_audioOutput || m_no_audio_out)
return;
@@ -417,11 +423,22 @@ void AudioPlayer::AddAudioData(char *buffer, int len, int64_t timecode)
if (samplesize <= 0)
return;

if (!m_audioOutput->AddData(buffer, len, timecode))
if (frames == 0 && len > 0)
frames = len / samplesize;

if (!m_audioOutput->AddData(buffer, len, timecode, frames))
VERBOSE(VB_PLAYBACK, LOC + "AddAudioData(): "
"Audio buffer overflow, audio data lost!");
}

bool AudioPlayer::NeedDecodingBeforePassthrough(void)
{
if (!m_audioOutput)
return true;
else
return m_audioOutput->NeedDecodingBeforePassthrough();
}

int64_t AudioPlayer::LengthLastData(void)
{
if (!m_audioOutput)
@@ -49,7 +49,7 @@ class MTV_PUBLIC AudioPlayer
float GetStretchFactor(void) { return m_stretchfactor; }
void SetStretchFactor(float factor);
bool ToggleUpmix(void);
bool CanPassthrough(int samplerate, int channels, int codec = 0);
bool CanPassthrough(int samplerate, int channels, int codec, int profile);
bool CanAC3(void);
bool CanDTS(void);
bool CanEAC3(void);
@@ -65,7 +65,8 @@ class MTV_PUBLIC AudioPlayer
MuteState SetMuteState(MuteState);
MuteState IncrMuteState(void);

void AddAudioData(char *buffer, int len, int64_t timecode);
void AddAudioData(char *buffer, int len, int64_t timecode, int frames);
bool NeedDecodingBeforePassthrough(void);
int64_t LengthLastData(void);
bool GetBufferStatus(uint &fill, uint &total);
bool IsBufferAlmostFull(void);
@@ -279,7 +279,6 @@ AvFormatDecoder::AvFormatDecoder(MythPlayer *parent,
itv(NULL),
// Audio
audioSamples(NULL),
internal_vol(false),
disable_passthru(false),
dummy_frame(NULL),
m_fps(0.0f),
@@ -297,8 +296,6 @@ AvFormatDecoder::AvFormatDecoder(MythPlayer *parent,
av_log_set_level((debug) ? AV_LOG_DEBUG : AV_LOG_ERROR);
av_log_set_callback(myth_av_log);

internal_vol = gCoreContext->GetNumSetting("MythControlsVolume", 0);

audioIn.sample_size = -32; // force SetupAudioStream to run once
itv = m_parent->GetInteractiveTV();

@@ -3660,7 +3657,7 @@ int AvFormatDecoder::AutoSelectAudioTrack(void)
if (selTrack < 0)
selTrack = filter_max_ch(ic, atracks, flang, CODEC_ID_EAC3);

if (!transcoding && selTrack < 0)
if (selTrack < 0)
selTrack = filter_max_ch(ic, atracks, flang, CODEC_ID_DTS);

if (selTrack < 0)
@@ -3730,6 +3727,7 @@ bool AvFormatDecoder::ProcessAudioPacket(AVStream *curstream, AVPacket *pkt,
int ret = 0;
int data_size = 0;
bool firstloop = true;
int frames = -1;

avcodeclock->lock();
int audIdx = selectedTrack[kTrackTypeAudio].av_stream_index;
@@ -3791,6 +3789,9 @@ bool AvFormatDecoder::ProcessAudioPacket(AVStream *curstream, AVPacket *pkt,
data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
ret = avcodec_decode_audio3(ctx, audioSamples,
&data_size, &tmp_pkt);
frames = data_size /
(ctx->channels *
av_get_bits_per_sample_format(ctx->sample_fmt)>>3);
already_decoded = true;
reselectAudioTrack |= ctx->channels;
}
@@ -3836,6 +3837,20 @@ bool AvFormatDecoder::ProcessAudioPacket(AVStream *curstream, AVPacket *pkt,

if (audioOut.do_passthru)
{
if (!already_decoded)
{
if (m_audio->NeedDecodingBeforePassthrough())
{
data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
ret = avcodec_decode_audio3(ctx, audioSamples, &data_size,
&tmp_pkt);
frames = data_size /
(ctx->channels *
av_get_bits_per_sample_format(ctx->sample_fmt)>>3);
}
else
frames = -1;
}
memcpy(audioSamples, tmp_pkt.data, tmp_pkt.size);
data_size = tmp_pkt.size;
// We have processed all the data, there can't be any left
@@ -3857,6 +3872,9 @@ bool AvFormatDecoder::ProcessAudioPacket(AVStream *curstream, AVPacket *pkt,
data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
ret = avcodec_decode_audio3(ctx, audioSamples, &data_size,
&tmp_pkt);
frames = data_size /
(ctx->channels *
av_get_bits_per_sample_format(ctx->sample_fmt)>>3);
}

// When decoding some audio streams the number of
@@ -3893,8 +3911,16 @@ bool AvFormatDecoder::ProcessAudioPacket(AVStream *curstream, AVPacket *pkt,
extract_mono_channel(audSubIdx, &audioOut,
(char *)audioSamples, data_size);

m_audio->AddAudioData((char *)audioSamples, data_size, temppts);
lastapts += m_audio->LengthLastData();
m_audio->AddAudioData((char *)audioSamples, data_size, temppts, frames);
if (audioOut.do_passthru && !m_audio->NeedDecodingBeforePassthrough())
{
lastapts += m_audio->LengthLastData();
}
else
{
lastapts += (long long)
((double)(frames * 1000) / ctx->sample_rate);
}

VERBOSE(VB_TIMESTAMP,
LOC + QString("audio timecode %1 %2 %3 %4")
@@ -4325,38 +4351,11 @@ inline bool AvFormatDecoder::DecoderWillDownmix(const AVCodecContext *ctx)

bool AvFormatDecoder::DoPassThrough(const AVCodecContext *ctx)
{
bool passthru = false;
bool passthru;

switch(ctx->codec_id)
{
case CODEC_ID_AC3:
passthru = m_audio->CanAC3();
break;
case CODEC_ID_DTS:
switch(ctx->profile)
{
case FF_PROFILE_DTS:
case FF_PROFILE_DTS_ES:
case FF_PROFILE_DTS_96_24:
passthru = m_audio->CanDTS();
break;
case FF_PROFILE_DTS_HD_HRA:
case FF_PROFILE_DTS_HD_MA:
passthru = m_audio->CanDTSHD();
default:
break;
}
break;
case CODEC_ID_EAC3:
passthru = m_audio->CanEAC3();
break;
case CODEC_ID_TRUEHD:
passthru = m_audio->CanTrueHD();
break;
}
passthru &= m_audio->CanPassthrough(ctx->sample_rate, ctx->channels);
passthru &= !internal_vol;
passthru &= !transcoding && !disable_passthru;
passthru = m_audio->CanPassthrough(ctx->sample_rate, ctx->channels,
ctx->codec_id, ctx->profile);
passthru &= !disable_passthru;

return passthru;
}
@@ -337,7 +337,6 @@ class AvFormatDecoder : public DecoderBase

// Audio
short int *audioSamples;
bool internal_vol;
bool disable_passthru;

VideoFrame *dummy_frame;

0 comments on commit 77e60c3

Please sign in to comment.
You can’t perform that action at this time.