Skip to content

Commit

Permalink
Add ability to passthru any audio type to mythtranscode.
Browse files Browse the repository at this point in the history
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 77e60c3
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 137 deletions.
3 changes: 2 additions & 1 deletion mythtv/libs/libmyth/audio/audiooutput.cpp
Expand Up @@ -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;
}
Expand Down
34 changes: 31 additions & 3 deletions mythtv/libs/libmyth/audio/audiooutput.h
Expand Up @@ -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;
Expand Down
46 changes: 40 additions & 6 deletions mythtv/libs/libmyth/audio/audiooutputbase.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -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();
Expand Down
8 changes: 5 additions & 3 deletions mythtv/libs/libmyth/audio/audiooutputbase.h
Expand Up @@ -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);
Expand All @@ -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; }
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmyth/audio/audiooutputsettings.h
Expand Up @@ -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; };

/**
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbase/mythversion.h
Expand Up @@ -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.
*
Expand Down
25 changes: 21 additions & 4 deletions mythtv/libs/libmythtv/audioplayer.cpp
Expand Up @@ -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;
Expand All @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions mythtv/libs/libmythtv/audioplayer.h
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
73 changes: 36 additions & 37 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -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),
Expand All @@ -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();

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 0 additions & 1 deletion mythtv/libs/libmythtv/avformatdecoder.h
Expand Up @@ -337,7 +337,6 @@ class AvFormatDecoder : public DecoderBase

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

VideoFrame *dummy_frame;
Expand Down

0 comments on commit 77e60c3

Please sign in to comment.