diff --git a/mythtv/libs/libmyth/audio/audiooutput.cpp b/mythtv/libs/libmyth/audio/audiooutput.cpp index 052e933b610..d08d1e2376d 100644 --- a/mythtv/libs/libmyth/audio/audiooutput.cpp +++ b/mythtv/libs/libmyth/audio/audiooutput.cpp @@ -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; } diff --git a/mythtv/libs/libmyth/audio/audiooutput.h b/mythtv/libs/libmyth/audio/audiooutput.h index 750087fbced..8206b395912 100644 --- a/mythtv/libs/libmyth/audio/audiooutput.h +++ b/mythtv/libs/libmyth/audio/audiooutput.h @@ -66,7 +66,8 @@ 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; @@ -74,8 +75,35 @@ class MPUBLIC AudioOutput : public VolumeBase, public OutputListeners 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; diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.cpp b/mythtv/libs/libmyth/audio/audiooutputbase.cpp index b0dac837f60..56cc49ab87f 100644 --- a/mythtv/libs/libmyth/audio/audiooutputbase.cpp +++ b/mythtv/libs/libmyth/audio/audiooutputbase.cpp @@ -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(); diff --git a/mythtv/libs/libmyth/audio/audiooutputbase.h b/mythtv/libs/libmyth/audio/audiooutputbase.h index 94c71ea11fd..39102e4079f 100644 --- a/mythtv/libs/libmyth/audio/audiooutputbase.h +++ b/mythtv/libs/libmyth/audio/audiooutputbase.h @@ -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; } diff --git a/mythtv/libs/libmyth/audio/audiooutputsettings.h b/mythtv/libs/libmyth/audio/audiooutputsettings.h index efce2742119..16ebb316cf2 100644 --- a/mythtv/libs/libmyth/audio/audiooutputsettings.h +++ b/mythtv/libs/libmyth/audio/audiooutputsettings.h @@ -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; }; /** diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h index beebac2727c..cc261e5981f 100644 --- a/mythtv/libs/libmythbase/mythversion.h +++ b/mythtv/libs/libmythbase/mythversion.h @@ -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. * diff --git a/mythtv/libs/libmythtv/audioplayer.cpp b/mythtv/libs/libmythtv/audioplayer.cpp index 3c725269859..f8b9d7d181c 100644 --- a/mythtv/libs/libmythtv/audioplayer.cpp +++ b/mythtv/libs/libmythtv/audioplayer.cpp @@ -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) diff --git a/mythtv/libs/libmythtv/audioplayer.h b/mythtv/libs/libmythtv/audioplayer.h index 8ff42f0933d..8580c73857a 100644 --- a/mythtv/libs/libmythtv/audioplayer.h +++ b/mythtv/libs/libmythtv/audioplayer.h @@ -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); diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp index 26907710ec4..bedd20de953 100644 --- a/mythtv/libs/libmythtv/avformatdecoder.cpp +++ b/mythtv/libs/libmythtv/avformatdecoder.cpp @@ -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; } diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h index 4821fd9fe1d..1401f5df26f 100644 --- a/mythtv/libs/libmythtv/avformatdecoder.h +++ b/mythtv/libs/libmythtv/avformatdecoder.h @@ -337,7 +337,6 @@ class AvFormatDecoder : public DecoderBase // Audio short int *audioSamples; - bool internal_vol; bool disable_passthru; VideoFrame *dummy_frame; diff --git a/mythtv/libs/libmythtv/nuppeldecoder.cpp b/mythtv/libs/libmythtv/nuppeldecoder.cpp index 10de281a1db..4aa7603dc36 100644 --- a/mythtv/libs/libmythtv/nuppeldecoder.cpp +++ b/mythtv/libs/libmythtv/nuppeldecoder.cpp @@ -1258,7 +1258,7 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype) if (data_size) m_audio->AddAudioData((char *)audioSamples, data_size, - frameheader.timecode); + frameheader.timecode, 0); pkt.size -= ret; pkt.data += ret; @@ -1283,7 +1283,7 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype) VERBOSE(VB_PLAYBACK+VB_EXTRA, QString("A audio timecode %1") .arg(frameheader.timecode)); m_audio->AddAudioData((char *)strm, frameheader.packetlength, - frameheader.timecode); + frameheader.timecode, 0); } } diff --git a/mythtv/programs/mythtranscode/transcode.cpp b/mythtv/programs/mythtranscode/transcode.cpp index 23afd5c96ef..2528ee69a67 100644 --- a/mythtv/programs/mythtranscode/transcode.cpp +++ b/mythtv/programs/mythtranscode/transcode.cpp @@ -9,7 +9,6 @@ #include "transcode.h" #include "audiooutput.h" -#include "spdifencoder.h" #include "recordingprofile.h" #include "mythcorecontext.h" #include "jobqueue.h" @@ -51,7 +50,6 @@ class AudioReencodeBuffer : public AudioOutput memset(ab_offset, 0, sizeof(ab_offset)); memset(ab_time, 0, sizeof(ab_time)); m_initpassthru = passthru; - m_spdifenc = NULL; } ~AudioReencodeBuffer() @@ -68,50 +66,7 @@ class AudioReencodeBuffer : public AudioOutput channels = settings.channels; bytes_per_frame = channels * 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; + eff_audiorate = settings.samplerate; } // dsprate is in 100 * frames/second @@ -126,40 +81,18 @@ 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) { - return AddData(buffer, frames * bytes_per_frame, timecode); + return AddData(buffer, frames * bytes_per_frame, timecode, frames); } // timecode is in milliseconds. - virtual bool AddData(void *buffer, int len, int64_t timecode) + virtual bool AddData(void *buffer, int len, int64_t timecode, int frames) { 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) { bufsize += len - freebuf; @@ -177,7 +110,7 @@ class AudioReencodeBuffer : public AudioOutput audiobuffer_len += len; // last_audiotime is at the end of the frame - last_audiotime = timecode + (newlen / bytes_per_frame) * 1000 / + last_audiotime = timecode + frames * 1000 / eff_audiorate; ab_time[ab_count] = last_audiotime; @@ -295,11 +228,7 @@ class AudioReencodeBuffer : public AudioOutput 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) :