Skip to content

Commit

Permalink
Add digital bitstream support to mythtranscode.
Browse files Browse the repository at this point in the history
This is untested, but this change contains several fixes to mythtranscode. When using mythtranscode with --passthrough, if AC3, DTS or other digital audio stream, the raw, unprocessed audio data it will be passed directly to fifo buffer
  • Loading branch information
jyavenard committed Mar 21, 2011
1 parent 4afa839 commit 3c82ead
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 72 deletions.
2 changes: 1 addition & 1 deletion mythtv/libs/libmyth/audiooutput.h
Expand Up @@ -75,7 +75,7 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners

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) { return 0; }
virtual int64_t LengthLastData(void) = 0;

virtual void SetTimecode(int64_t timecode) = 0;
virtual bool IsPaused(void) const = 0;
Expand Down
67 changes: 5 additions & 62 deletions mythtv/libs/libmyth/audiooutputbase.cpp
Expand Up @@ -350,69 +350,11 @@ bool AudioOutputBase::ToggleUpmix(void)
bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
int &samplerate_tmp, int &channels_tmp)
{
channels_tmp = 2;
QString log;
QString log = AudioOutputSettings::GetPassthroughParams(
codec, codec_profile,
samplerate_tmp, channels_tmp,
output_settingsdigital->GetMaxHDRate() == 768000);

switch (codec)
{
case CODEC_ID_AC3:
log = "AC3";
break;
case CODEC_ID_EAC3:
samplerate_tmp = samplerate_tmp * 4;
log = "Dolby Digital Plus (E-AC3)";
break;
case CODEC_ID_DTS:
switch(codec_profile)
{
case FF_PROFILE_DTS_ES:
log = "DTS-ES";
break;
case FF_PROFILE_DTS_96_24:
log = "DTS 96/24";
break;
case FF_PROFILE_DTS_HD_HRA:
case FF_PROFILE_DTS_HD_MA:
samplerate_tmp = 192000;
if (output_settingsdigital->GetMaxHDRate() == 768000)
{
log = "DTS-HD MA";
channels_tmp = 8;
}
else
{
log = "DTS-HD High-Res";
}
break;
case FF_PROFILE_DTS:
default:
log = "DTS Core";
break;
}
break;
case CODEC_ID_TRUEHD:
channels_tmp = 8;
log = "TrueHD";
switch(samplerate_tmp)
{
case 48000:
case 96000:
case 192000:
samplerate_tmp = 192000;
break;
case 44100:
case 88200:
case 176400:
samplerate_tmp = 176400;
break;
default:
VBAUDIO("TrueHD: Unsupported samplerate");
break;
}
break;
default:
break;
}
VBAUDIO("Setting " + log + " passthrough");

if (m_spdifenc)
Expand All @@ -437,6 +379,7 @@ bool AudioOutputBase::SetupPassthrough(int codec, int codec_profile,
break;
case FF_PROFILE_DTS_HD_MA:
m_spdifenc->SetMaxHDRate(OutputSettings(true)->GetMaxHDRate());
break;
}
}

Expand Down
73 changes: 73 additions & 0 deletions mythtv/libs/libmyth/audiooutputsettings.cpp
Expand Up @@ -417,3 +417,76 @@ QString AudioOutputSettings::FeaturesToString(DigitalFeature arg)
}
return tmp;
}

QString AudioOutputSettings::GetPassthroughParams(int codec, int codec_profile,
int &samplerate,
int &channels,
bool canDTSHDMA)
{
QString log;

channels = 2;

switch (codec)
{
case CODEC_ID_AC3:
log = "AC3";
break;
case CODEC_ID_EAC3:
samplerate = samplerate * 4;
log = "Dolby Digital Plus (E-AC3)";
break;
case CODEC_ID_DTS:
switch(codec_profile)
{
case FF_PROFILE_DTS_ES:
log = "DTS-ES";
break;
case FF_PROFILE_DTS_96_24:
log = "DTS 96/24";
break;
case FF_PROFILE_DTS_HD_HRA:
case FF_PROFILE_DTS_HD_MA:
samplerate = 192000;
if (canDTSHDMA)
{
log = "DTS-HD MA";
channels = 8;
}
else
{
log = "DTS-HD High-Res";
}
break;
case FF_PROFILE_DTS:
default:
log = "DTS Core";
break;
}
break;
case CODEC_ID_TRUEHD:
channels = 8;
log = "TrueHD";
switch(samplerate)
{
case 48000:
case 96000:
case 192000:
samplerate = 192000;
break;
case 44100:
case 88200:
case 176400:
samplerate = 176400;
break;
default:
log = "TrueHD: Unsupported samplerate";
break;
}
break;
default:
break;
}
return log;
}

7 changes: 7 additions & 0 deletions mythtv/libs/libmyth/audiooutputsettings.h
Expand Up @@ -149,6 +149,13 @@ class MPUBLIC AudioOutputSettings
QString FeaturesToString(void)
{ return FeaturesToString((DigitalFeature)m_features); };

/**
* Setup samplerate and number of channels for passthrough
*/
static QString GetPassthroughParams(int codec, int codec_profile,
int &samplerate, int &channels,
bool canDTSHDMA);

private:
void SortSupportedChannels();

Expand Down
8 changes: 7 additions & 1 deletion mythtv/programs/mythtranscode/main.cpp
Expand Up @@ -163,6 +163,7 @@ int main(int argc, char *argv[])
int found_infile = 0;
int update_index = 1;
int isVideo = 0;
bool passthru = false;

for (int argpos = 1; argpos < a.argc(); ++argpos)
{
Expand Down Expand Up @@ -480,6 +481,10 @@ int main(int argc, char *argv[])
usage(a.argv()[0]);
return TRANSCODE_EXIT_OK;
}
else if (!strcmp(a.argv()[argpos],"--passthrough"))
{
passthru = true;
}
else
{
cerr << "Unknown option: " << a.argv()[argpos] << endl;
Expand Down Expand Up @@ -639,7 +644,8 @@ int main(int argc, char *argv[])
result = transcode->TranscodeFile(infile, outfile,
profilename, useCutlist,
(fifosync || keyframesonly), jobID,
fifodir, deleteMap);
fifodir, deleteMap,
passthru);
if ((result == REENCODE_OK) && (jobID >= 0))
JobQueue::ChangeJobArgs(jobID, "RENAME_TO_NUV");
}
Expand Down
99 changes: 92 additions & 7 deletions mythtv/programs/mythtranscode/transcode.cpp
Expand Up @@ -9,6 +9,7 @@

#include "transcode.h"
#include "audiooutput.h"
#include "spdifencoder.h"
#include "recordingprofile.h"
#include "mythcorecontext.h"
#include "jobqueue.h"
Expand Down Expand Up @@ -36,7 +37,8 @@ using namespace std;
class AudioReencodeBuffer : public AudioOutput
{
public:
AudioReencodeBuffer(AudioFormat audio_format, int audio_channels)
AudioReencodeBuffer(AudioFormat audio_format, int audio_channels,
bool passthru)
{
Reset();
const AudioSettings settings(audio_format, audio_channels, 0, 0, false);
Expand All @@ -48,9 +50,11 @@ class AudioReencodeBuffer : public AudioOutput
memset(ab_len, 0, sizeof(ab_len));
memset(ab_offset, 0, sizeof(ab_offset));
memset(ab_time, 0, sizeof(ab_time));
m_initpassthru = passthru;
m_spdifenc = NULL;
}

~AudioReencodeBuffer()
~AudioReencodeBuffer()
{
delete [] audiobuffer;
}
Expand All @@ -60,9 +64,54 @@ class AudioReencodeBuffer : public AudioOutput
{
ClearError();

channels = settings.channels;
m_passthru = settings.use_passthru;
channels = settings.channels;
bytes_per_frame = channels *
AudioOutputSettings::SampleSize(settings.format);
AudioOutputSettings::SampleSize(settings.format);
m_samplerate = settings.samplerate;

if (m_passthru)
{
QString log = AudioOutputSettings::GetPassthroughParams(
settings.codec,
settings.codec_profile,
m_samplerate, channels,
true);
VERBOSE(VB_AUDIO, "Setting " + log + " passthrough");

bytes_per_frame = channels *
AudioOutputSettings::SampleSize(FORMAT_S16);

if (m_spdifenc)
{
delete m_spdifenc;
}

m_spdifenc = new SPDIFEncoder("spdif", settings.codec);
if (m_spdifenc->Succeeded() && settings.codec == CODEC_ID_DTS)
{
switch(settings.codec_profile)
{
case FF_PROFILE_DTS:
case FF_PROFILE_DTS_ES:
case FF_PROFILE_DTS_96_24:
m_spdifenc->SetMaxHDRate(0);
break;
case FF_PROFILE_DTS_HD_HRA:
m_spdifenc->SetMaxHDRate(192000);
break;
case FF_PROFILE_DTS_HD_MA:
m_spdifenc->SetMaxHDRate(768000);
break;
}
}
if (!m_spdifenc->Succeeded())
{
delete m_spdifenc;
m_spdifenc = NULL;
}
}
eff_audiorate = m_samplerate * 100;
}

// dsprate is in 100 * frames/second
Expand All @@ -77,6 +126,8 @@ class AudioReencodeBuffer : public AudioOutput
ab_count = 0;
}

virtual int64_t LengthLastData(void) { return m_length_last_data; }

// timecode is in milliseconds.
virtual bool AddFrames(void *buffer, int frames, int64_t timecode)
{
Expand All @@ -87,6 +138,27 @@ class AudioReencodeBuffer : public AudioOutput
virtual bool AddData(void *buffer, int len, int64_t timecode)
{
int freebuf = bufsize - audiobuffer_len;
int newlen;

if (m_passthru && m_spdifenc)
{
/*
* mux into an IEC958 packet. The resulting data will be dumped.
* We do so to estimate timestamps
*/
m_spdifenc->WriteFrame((unsigned char *)buffer, len);
newlen = m_spdifenc->GetProcessedSize();
if (newlen > 0)
{
m_spdifenc->Reset();
}
}
else
{
newlen = len;
}
m_length_last_data = (int64_t)
((double)(newlen * 1000) / (m_samplerate * bytes_per_frame));

if (len > freebuf)
{
Expand All @@ -105,7 +177,7 @@ class AudioReencodeBuffer : public AudioOutput
audiobuffer_len += len;

// last_audiotime is at the end of the frame
last_audiotime = timecode + (len / bytes_per_frame) * 1000 /
last_audiotime = timecode + (newlen / bytes_per_frame) * 1000 /
eff_audiorate;

ab_time[ab_count] = last_audiotime;
Expand Down Expand Up @@ -209,6 +281,11 @@ class AudioReencodeBuffer : public AudioOutput
virtual void bufferOutputData(bool){ return; }
virtual int readOutputData(unsigned char*, int ){ return 0; }

/**
* Test if we can output digital audio
*/
virtual bool CanPassthrough(int, int, int) const { return m_initpassthru; }

int bufsize;
int ab_count;
int ab_len[128];
Expand All @@ -217,6 +294,12 @@ class AudioReencodeBuffer : public AudioOutput
unsigned char *audiobuffer;
int audiobuffer_len, channels, bits, bytes_per_frame, eff_audiorate;
long long last_audiotime;
private:
int m_samplerate;
bool m_passthru, m_initpassthru;
// SPDIF Encoder for digital passthrough
SPDIFEncoder *m_spdifenc;
int64_t m_length_last_data;
};

Transcode::Transcode(ProgramInfo *pginfo) :
Expand Down Expand Up @@ -367,7 +450,8 @@ int Transcode::TranscodeFile(
const QString &profileName,
bool honorCutList, bool framecontrol,
int jobID, QString fifodir,
frm_dir_map_t &deleteMap)
frm_dir_map_t &deleteMap,
bool passthru)
{
QDateTime curtime = QDateTime::currentDateTime();
QDateTime statustime = curtime;
Expand Down Expand Up @@ -395,7 +479,8 @@ int Transcode::TranscodeFile(
statustime = statustime.addSecs(5);
}

AudioOutput *audioOutput = new AudioReencodeBuffer(FORMAT_NONE, 0);
AudioOutput *audioOutput = new AudioReencodeBuffer(FORMAT_NONE, 0,
passthru);
AudioReencodeBuffer *arb = ((AudioReencodeBuffer*)audioOutput);
player->GetAudio()->SetAudioOutput(audioOutput);
player->SetTranscoding(true);
Expand Down
3 changes: 2 additions & 1 deletion mythtv/programs/mythtranscode/transcode.h
Expand Up @@ -20,7 +20,8 @@ class Transcode : public QObject
const QString &outputname,
const QString &profileName,
bool honorCutList, bool framecontrol, int jobID,
QString fifodir, frm_dir_map_t &deleteMap);
QString fifodir, frm_dir_map_t &deleteMap,
bool passthru = false);
void ShowProgress(bool val) { showprogress = val; }
void SetRecorderOptions(QString options) { recorderOptions = options; }

Expand Down

0 comments on commit 3c82ead

Please sign in to comment.