diff -Naur --exclude=.svn a/libs/libmyth/audiooutput.h b/libs/libmyth/audiooutput.h --- a/libs/libmyth/audiooutput.h 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutput.h 2009-01-28 15:49:56.000000000 +1100 @@ -34,11 +34,11 @@ virtual void Reconfigure(int audio_bits, int audio_channels, int audio_samplerate, - bool audio_passthru, - void* audio_codec = NULL) = 0; + bool audio_passthru) = 0; virtual void SetStretchFactor(float factor); virtual float GetStretchFactor(void) { return 1.0f; } + virtual bool ToggleUpmix(void) = 0; // do AddSamples calls block? virtual void SetBlocking(bool blocking) = 0; diff -Naur --exclude=.svn a/libs/libmyth/audiooutputalsa.cpp b/libs/libmyth/audiooutputalsa.cpp --- a/libs/libmyth/audiooutputalsa.cpp 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutputalsa.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -35,6 +35,55 @@ AudioOutputALSA::~AudioOutputALSA() { KillAudio(); + SetIECStatus(true); +} + +void AudioOutputALSA::SetIECStatus(bool audio) { + + snd_ctl_t *ctl; + const char *spdif_str = SND_CTL_NAME_IEC958("", PLAYBACK, DEFAULT); + int spdif_index = -1; + snd_ctl_elem_list_t *clist; + snd_ctl_elem_id_t *cid; + snd_ctl_elem_value_t *cval; + snd_aes_iec958_t iec958; + int cidx, controls; + + VERBOSE(VB_AUDIO, QString("Setting IEC958 status: %1") + .arg(audio ? "audio" : "non-audio")); + + snd_ctl_open(&ctl, "default", 0); + snd_ctl_elem_list_alloca(&clist); + snd_ctl_elem_list(ctl, clist); + snd_ctl_elem_list_alloc_space(clist, snd_ctl_elem_list_get_count(clist)); + snd_ctl_elem_list(ctl, clist); + controls = snd_ctl_elem_list_get_used(clist); + for (cidx = 0; cidx < controls; cidx++) + { + if (!strcmp(snd_ctl_elem_list_get_name(clist, cidx), spdif_str)) + if (spdif_index < 0 || + snd_ctl_elem_list_get_index(clist, cidx) == (uint)spdif_index) + break; + } + + if (cidx >= controls) + return; + + snd_ctl_elem_id_alloca(&cid); + snd_ctl_elem_list_get_id(clist, cidx, cid); + snd_ctl_elem_value_alloca(&cval); + snd_ctl_elem_value_set_id(cval, cid); + snd_ctl_elem_read(ctl,cval); + snd_ctl_elem_value_get_iec958(cval, &iec958); + + if (!audio) + iec958.status[0] |= IEC958_AES0_NONAUDIO; + else + iec958.status[0] &= ~IEC958_AES0_NONAUDIO; + + snd_ctl_elem_value_set_iec958(cval, &iec958); + snd_ctl_elem_write(ctl, cval); + } bool AudioOutputALSA::OpenDevice() @@ -42,15 +91,24 @@ snd_pcm_format_t format; unsigned int buffer_time, period_time; int err; + QString real_device; if (pcm_handle != NULL) CloseDevice(); pcm_handle = NULL; numbadioctls = 0; - - QString real_device = (audio_passthru) ? - audio_passthru_device : audio_main_device; + + if (audio_passthru || audio_enc) + { + real_device = audio_passthru_device; + SetIECStatus(false); + } + else + { + real_device = audio_main_device; + SetIECStatus(true); + } VERBOSE(VB_GENERAL, QString("Opening ALSA audio device '%1'.") .arg(real_device)); diff -Naur --exclude=.svn a/libs/libmyth/audiooutputalsa.h b/libs/libmyth/audiooutputalsa.h --- a/libs/libmyth/audiooutputalsa.h 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutputalsa.h 2009-01-28 15:49:56.000000000 +1100 @@ -37,6 +37,7 @@ virtual inline int getBufferedOnSoundcard(void); private: + void SetIECStatus(bool audio); inline int SetParameters(snd_pcm_t *handle, snd_pcm_format_t format, unsigned int channels, unsigned int rate, unsigned int buffer_time, diff -Naur --exclude=.svn a/libs/libmyth/audiooutputbase.cpp b/libs/libmyth/audiooutputbase.cpp --- a/libs/libmyth/audiooutputbase.cpp 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutputbase.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -37,9 +37,9 @@ audio_main_device(QDeepCopy(laudio_main_device)), audio_passthru_device(QDeepCopy(laudio_passthru_device)), - audio_passthru(false), audio_stretchfactor(1.0f), + audio_passthru(false), audio_enc(false), + audio_reenc(false), audio_stretchfactor(1.0f), - audio_codec(NULL), source(lsource), killaudio(false), pauseaudio(false), audio_actually_paused(false), @@ -54,10 +54,13 @@ pSoundStretch(NULL), encoder(NULL), upmixer(NULL), + source_audio_channels(-1), + source_audio_samplerate(0), source_audio_bytes_per_sample(0), needs_upmix(false), surround_mode(FreeSurround::SurroundModePassive), + old_audio_stretchfactor(1.0), blocking(false), @@ -84,6 +87,9 @@ memset(&audiotime_updated, 0, sizeof(audiotime_updated)); memset(audiobuffer, 0, sizeof(char) * AUDBUFSIZE); configured_audio_channels = gContext->GetNumSetting("MaxChannels", 2); + orig_config_channels = configured_audio_channels; + allow_ac3_passthru = gContext->GetNumSetting("AC3PassThru", false); + src_quality = gContext->GetNumSetting("SRCQuality", 2); // You need to call Reconfigure from your concrete class. // Reconfigure(laudio_bits, laudio_channels, @@ -124,40 +130,9 @@ VERBOSE(VB_GENERAL, LOC + QString("Using time stretch %1") .arg(audio_stretchfactor)); pSoundStretch = new soundtouch::SoundTouch(); - if (audio_codec) - { - if (!encoder) - { - VERBOSE(VB_AUDIO, LOC + - QString("Creating Encoder for codec %1 origfs %2") - .arg(audio_codec->codec_id) - .arg(audio_codec->frame_size)); - - encoder = new AudioOutputDigitalEncoder(); - if (!encoder->Init(audio_codec->codec_id, - audio_codec->bit_rate, - audio_codec->sample_rate, - audio_codec->channels - )) - { - // eeks - delete encoder; - encoder = NULL; - VERBOSE(VB_AUDIO, LOC + - QString("Failed to Create Encoder")); - } - } - } - if (audio_codec && encoder) - { - pSoundStretch->setSampleRate(audio_codec->sample_rate); - pSoundStretch->setChannels(audio_codec->channels); - } - else - { - pSoundStretch->setSampleRate(audio_samplerate); - pSoundStretch->setChannels(audio_channels); - } + pSoundStretch->setSampleRate(audio_samplerate); + pSoundStretch->setChannels(upmixer ? + configured_audio_channels : source_audio_channels); pSoundStretch->setTempo(audio_stretchfactor); pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 35); @@ -165,7 +140,6 @@ // dont need these with only tempo change //pSoundStretch->setPitch(1.0); //pSoundStretch->setRate(1.0); - //pSoundStretch->setSetting(SETTING_USE_QUICKSEEK, true); //pSoundStretch->setSetting(SETTING_USE_AA_FILTER, false); } @@ -184,35 +158,33 @@ return audio_stretchfactor; } +bool AudioOutputBase::ToggleUpmix(void) +{ + if (orig_config_channels == 2 || audio_passthru) + return false; + if (configured_audio_channels == 6) + configured_audio_channels = 2; + else + configured_audio_channels = 6; + + Reconfigure(audio_bits, source_audio_channels, + source_audio_samplerate, audio_passthru); + return (configured_audio_channels == 6); +} + void AudioOutputBase::Reconfigure(int laudio_bits, int laudio_channels, - int laudio_samplerate, bool laudio_passthru, - void *laudio_codec) + int laudio_samplerate, bool laudio_passthru) { - int codec_id = CODEC_ID_NONE; - int lcodec_id = CODEC_ID_NONE; - int lcchannels = 0; - int cchannels = 0; int lsource_audio_channels = laudio_channels; bool lneeds_upmix = false; - - if (laudio_codec) - { - lcodec_id = ((AVCodecContext*)laudio_codec)->codec_id; - laudio_bits = 16; - laudio_channels = 2; - lsource_audio_channels = laudio_channels; - laudio_samplerate = 48000; - lcchannels = ((AVCodecContext*)laudio_codec)->channels; - } - - if (audio_codec) - { - codec_id = audio_codec->codec_id; - cchannels = ((AVCodecContext*)audio_codec)->channels; - } - - if ((configured_audio_channels == 6) && - !(laudio_codec || audio_codec)) + bool laudio_reenc = false; + + // Are we perhaps reencoding a (previously) timestretched bitstream? + if (laudio_channels > 2 && !laudio_passthru) + laudio_reenc = true; + + // Enough channels? Upmix if not + if (laudio_channels < configured_audio_channels && !laudio_passthru) { laudio_channels = configured_audio_channels; lneeds_upmix = true; @@ -225,7 +197,7 @@ laudio_samplerate == audio_samplerate && !need_resampler && laudio_passthru == audio_passthru && lneeds_upmix == needs_upmix && - lcodec_id == codec_id && lcchannels == cchannels); + laudio_reenc == audio_reenc); bool upmix_deps = (lsource_audio_channels == source_audio_channels); if (general_deps && upmix_deps) @@ -252,12 +224,11 @@ waud = raud = 0; audio_actually_paused = false; - bool redo_stretch = (pSoundStretch && audio_channels != laudio_channels); audio_channels = laudio_channels; source_audio_channels = lsource_audio_channels; audio_bits = laudio_bits; - audio_samplerate = laudio_samplerate; - audio_codec = (AVCodecContext*)laudio_codec; + source_audio_samplerate = audio_samplerate = laudio_samplerate; + audio_reenc = laudio_reenc; audio_passthru = laudio_passthru; needs_upmix = lneeds_upmix; @@ -268,8 +239,6 @@ Error("AudioOutput only supports 8 or 16bit audio."); return; } - audio_bytes_per_sample = audio_channels * audio_bits / 8; - source_audio_bytes_per_sample = source_audio_channels * audio_bits / 8; need_resampler = false; killaudio = false; @@ -278,7 +247,58 @@ internal_vol = gContext->GetNumSetting("MythControlsVolume", 0); numlowbuffer = 0; + + // Encode to AC-3 if not passing thru, there's more than 2 channels + // and we're allowed to passthru AC-3 + // This won't reencode timestretched 2ch AC-3 but there's no point doing so + if (!audio_passthru && audio_channels > 2 && allow_ac3_passthru) + { + VERBOSE(VB_AUDIO, LOC + "Creating AC-3 Encoder"); + int srate = src_quality == 0 ? audio_samplerate : 48000; + encoder = new AudioOutputDigitalEncoder(); + if (!encoder->Init(CODEC_ID_AC3, 448000, srate, + audio_channels, audio_reenc)) + { + VERBOSE(VB_AUDIO, LOC + "Can't create AC-3 encoder"); + delete encoder; + encoder = NULL; + } + + audio_enc = true; + } + + if(audio_passthru || audio_enc) + // AC-3 output - soundcard expects a 2ch 48k stream + audio_channels = 2; + + audio_bytes_per_sample = audio_channels * audio_bits / 8; + source_audio_bytes_per_sample = source_audio_channels * audio_bits / 8; + // Always resample to 48k - many cards can't do anything else + // and ALSA will do it with linear interpolation (yuk) if we don't anyway + if (src_quality != 0 && audio_samplerate != 48000) + { + int error; + audio_samplerate = 48000; + VERBOSE(VB_GENERAL, LOC + QString("Using resampler. From: %1 to %2") + .arg(laudio_samplerate).arg(audio_samplerate)); + src_ctx = src_new(3-src_quality, audio_channels, &error); + if (error) + { + Error(QString("Error creating resampler, the error was: %1") + .arg(src_strerror(error)) ); + pthread_mutex_unlock(&avsync_lock); + pthread_mutex_unlock(&audio_buflock); + src_ctx = NULL; + return; + } + src_data.src_ratio = (double) audio_samplerate / laudio_samplerate; + src_data.data_in = src_in; + src_data.data_out = src_out; + src_data.output_frames = 16384*6; + need_resampler = true; + } + VERBOSE(VB_GENERAL, QString("Opening audio device '%1'. ch %2(%3) sr %4") .arg(audio_main_device).arg(audio_channels) .arg(source_audio_channels).arg(audio_samplerate)); @@ -314,32 +334,8 @@ current_seconds = -1; source_bitrate = -1; - // NOTE: this won't do anything as above samplerate vars are set equal - // Check if we need the resampler - if (audio_samplerate != laudio_samplerate) - { - int error; - VERBOSE(VB_GENERAL, LOC + QString("Using resampler. From: %1 to %2") - .arg(laudio_samplerate).arg(audio_samplerate)); - src_ctx = src_new (SRC_SINC_BEST_QUALITY, audio_channels, &error); - if (error) - { - Error(QString("Error creating resampler, the error was: %1") - .arg(src_strerror(error)) ); - pthread_mutex_unlock(&avsync_lock); - pthread_mutex_unlock(&audio_buflock); - return; - } - src_data.src_ratio = (double) audio_samplerate / laudio_samplerate; - src_data.data_in = src_in; - src_data.data_out = src_out; - src_data.output_frames = 16384*6; - need_resampler = true; - } - if (needs_upmix) { - VERBOSE(VB_AUDIO, LOC + QString("create upmixer")); if (configured_audio_channels == 6) { surround_mode = gContext->GetNumSetting("AudioUpmixType", 2); @@ -351,64 +347,14 @@ (FreeSurround::SurroundMode)surround_mode); VERBOSE(VB_AUDIO, LOC + - QString("create upmixer done with surround mode %1") + QString("Create upmixer done with surround mode %1") .arg(surround_mode)); } VERBOSE(VB_AUDIO, LOC + QString("Audio Stretch Factor: %1") .arg(audio_stretchfactor)); - VERBOSE(VB_AUDIO, QString("Audio Codec Used: %1") - .arg((audio_codec) ? - codec_id_string(audio_codec->codec_id) : "not set")); - if (redo_stretch) - { - float laudio_stretchfactor = audio_stretchfactor; - delete pSoundStretch; - pSoundStretch = NULL; - audio_stretchfactor = 0.0f; - SetStretchFactorLocked(laudio_stretchfactor); - } - else - { - SetStretchFactorLocked(audio_stretchfactor); - if (pSoundStretch) - { - // if its passthru then we need to reencode - if (audio_codec) - { - if (!encoder) - { - VERBOSE(VB_AUDIO, LOC + - QString("Creating Encoder for codec %1") - .arg(audio_codec->codec_id)); - - encoder = new AudioOutputDigitalEncoder(); - if (!encoder->Init(audio_codec->codec_id, - audio_codec->bit_rate, - audio_codec->sample_rate, - audio_codec->channels - )) - { - // eeks - delete encoder; - encoder = NULL; - VERBOSE(VB_AUDIO, LOC + "Failed to Create Encoder"); - } - } - } - if (audio_codec && encoder) - { - pSoundStretch->setSampleRate(audio_codec->sample_rate); - pSoundStretch->setChannels(audio_codec->channels); - } - else - { - pSoundStretch->setSampleRate(audio_samplerate); - pSoundStretch->setChannels(audio_channels); - } - } - } + SetStretchFactorLocked(old_audio_stretchfactor); // Setup visualisations, zero the visualisations buffers prepareVisuals(); @@ -455,10 +401,16 @@ VERBOSE(VB_AUDIO, LOC + "Killing AudioOutputDSP"); killaudio = true; StopOutputThread(); + + pthread_mutex_lock(&audio_buflock); // Close resampler? if (src_ctx) + { src_delete(src_ctx); + src_ctx = NULL; + } + need_resampler = false; // close sound stretcher @@ -466,6 +418,8 @@ { delete pSoundStretch; pSoundStretch = NULL; + old_audio_stretchfactor = audio_stretchfactor; + audio_stretchfactor = 1.0; } if (encoder) @@ -480,9 +434,11 @@ upmixer = NULL; } needs_upmix = false; + audio_enc = false; CloseDevice(); + pthread_mutex_unlock(&audio_buflock); killAudioLock.unlock(); } @@ -591,7 +547,6 @@ ret += (now.tv_usec - audiotime_updated.tv_usec) / 1000; ret = (long long)(ret * audio_stretchfactor); -#if 1 VERBOSE(VB_AUDIO|VB_TIMESTAMP, QString("GetAudiotime now=%1.%2, set=%3.%4, ret=%5, audt=%6 sf=%7") .arg(now.tv_sec).arg(now.tv_usec) @@ -600,7 +555,6 @@ .arg(audiotime) .arg(audio_stretchfactor) ); -#endif ret += audiotime; @@ -638,29 +592,23 @@ soundcard_buffer = getBufferedOnSoundcard(); // bytes totalbuffer = audiolen(false) + soundcard_buffer; - + // include algorithmic latencies if (pSoundStretch) - { - // add the effect of any unused but processed samples, - // AC3 reencode does this - totalbuffer += (int)(pSoundStretch->numSamples() * - audio_bytes_per_sample); - // add the effect of unprocessed samples in time stretch algo totalbuffer += (int)((pSoundStretch->numUnprocessedSamples() * audio_bytes_per_sample) / audio_stretchfactor); - } if (upmixer && needs_upmix) - { totalbuffer += upmixer->sampleLatency() * audio_bytes_per_sample; - } + + if (encoder) + totalbuffer += encoder->Buffered(); audiotime = audbuf_timecode - (int)(totalbuffer * 100000.0 / (audio_bytes_per_sample * effdspstretched)); gettimeofday(&audiotime_updated, NULL); -#if 1 + VERBOSE(VB_AUDIO|VB_TIMESTAMP, QString("SetAudiotime set=%1.%2, audt=%3 atc=%4 " "tb=%5 sb=%6 eds=%7 abps=%8 sf=%9") @@ -672,7 +620,6 @@ .arg(effdspstretched) .arg(audio_bytes_per_sample) .arg(audio_stretchfactor)); -#endif pthread_mutex_unlock(&avsync_lock); pthread_mutex_unlock(&audio_buflock); @@ -686,7 +633,7 @@ int abps = (encoder) ? encoder->audio_bytes_per_sample : audio_bytes_per_sample; int len = samples * abps; - + // Check we have enough space to write the data if (need_resampler && src_ctx) len = (int)ceilf(float(len) * src_data.src_ratio); @@ -708,6 +655,8 @@ return false; // would overflow } + + pthread_mutex_lock(&audio_buflock); // resample input if necessary if (need_resampler && src_ctx) @@ -741,6 +690,8 @@ // Call our function to do the work _AddSamples(buffers, false, samples, timecode); } + + pthread_mutex_unlock(&audio_buflock); return true; } @@ -753,6 +704,10 @@ int abps = (encoder) ? encoder->audio_bytes_per_sample : audio_bytes_per_sample; int len = samples * abps; + + // Give original samples to mythmusic visualisation + dispatchVisual((unsigned char *)buffer, len, timecode, + source_audio_channels, audio_bits); // Check we have enough space to write the data if (need_resampler && src_ctx) @@ -776,6 +731,8 @@ .arg(timecode)); return false; // would overflow } + + pthread_mutex_lock(&audio_buflock); // resample input if necessary if (need_resampler && src_ctx) @@ -804,6 +761,8 @@ // Call our function to do the work _AddSamples(buffer, true, samples, timecode); } + + pthread_mutex_unlock(&audio_buflock); return true; } @@ -836,10 +795,13 @@ if (src_ctx) { int error = src_reset(src_ctx); - if (error) + if (error) + { VERBOSE(VB_IMPORTANT, LOC_ERR + QString( "Error occured while resetting resampler: %1") .arg(src_strerror(error))); + src_ctx = NULL; + } } } } @@ -849,8 +811,6 @@ void AudioOutputBase::_AddSamples(void *buffer, bool interleaved, int samples, long long timecode) { - pthread_mutex_lock(&audio_buflock); - int len; // = samples * audio_bytes_per_sample; int audio_bytes = audio_bits / 8; int org_waud = waud; @@ -867,17 +827,17 @@ .arg(samples * abps) .arg(AUDBUFSIZE-afree).arg(afree).arg(timecode) .arg(needs_upmix)); + + len = WaitForFreeSpace(samples); if (upmixer && needs_upmix) { int out_samples = 0; + org_waud = waud; int step = (interleaved)?source_audio_channels:1; - len = WaitForFreeSpace(samples); // test + for (int itemp = 0; itemp < samples; ) { - // just in case it does a processing cycle, release the lock - // to allow the output loop to do output - pthread_mutex_unlock(&audio_buflock); if (audio_bytes == 2) { itemp += upmixer->putSamples( @@ -894,7 +854,6 @@ source_audio_channels, (interleaved) ? 0 : samples); } - pthread_mutex_lock(&audio_buflock); int copy_samples = upmixer->numSamples(); if (copy_samples) @@ -913,10 +872,9 @@ (short*)(audiobuffer), (copy_samples - bdiff_samples)); } else - { upmixer->receiveSamples( (short*)(audiobuffer + org_waud), copy_samples); - } + org_waud = (org_waud + copy_len) % AUDBUFSIZE; } } @@ -928,8 +886,6 @@ } else { - len = WaitForFreeSpace(samples); - if (interleaved) { char *mybuf = (char*)buffer; @@ -964,138 +920,105 @@ } } } - - if (samples > 0) + + if (samples <= 0) + return; + + if (pSoundStretch) { - if (pSoundStretch) - { - - // does not change the timecode, only the number of samples - // back to orig pos - org_waud = waud; - int bdiff = AUDBUFSIZE - org_waud; - int nSamplesToEnd = bdiff/abps; - if (bdiff < len) - { - pSoundStretch->putSamples((soundtouch::SAMPLETYPE*) - (audiobuffer + - org_waud), nSamplesToEnd); - pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer, - (len - bdiff) / abps); - } - else - { - pSoundStretch->putSamples((soundtouch::SAMPLETYPE*) - (audiobuffer + org_waud), - len / abps); - } - - if (encoder) - { - // pull out a packet's worth and reencode it until we - // don't have enough for any more packets - soundtouch::SAMPLETYPE *temp_buff = - (soundtouch::SAMPLETYPE*)encoder->GetFrameBuffer(); - size_t frameSize = encoder->FrameSize()/abps; - - VERBOSE(VB_AUDIO|VB_TIMESTAMP, - QString("_AddSamples Enc sfs=%1 bfs=%2 sss=%3") - .arg(frameSize) - .arg(encoder->FrameSize()) - .arg(pSoundStretch->numSamples())); - - // process the same number of samples as it creates - // a full encoded buffer just like before - while (pSoundStretch->numSamples() >= frameSize) - { - int got = pSoundStretch->receiveSamples( - temp_buff, frameSize); - int amount = encoder->Encode(temp_buff); - - VERBOSE(VB_AUDIO|VB_TIMESTAMP, - QString("_AddSamples Enc bytes=%1 got=%2 left=%3") - .arg(amount) - .arg(got) - .arg(pSoundStretch->numSamples())); - - if (!amount) - continue; - - //len = WaitForFreeSpace(amount); - char *ob = encoder->GetOutBuff(); - if (amount >= bdiff) - { - memcpy(audiobuffer + org_waud, ob, bdiff); - ob += bdiff; - amount -= bdiff; - org_waud = 0; - } - if (amount > 0) - memcpy(audiobuffer + org_waud, ob, amount); + // does not change the timecode, only the number of samples + // back to orig pos + org_waud = waud; + int bdiff = AUDBUFSIZE - org_waud; + int nSamplesToEnd = bdiff/abps; + if (bdiff < len) + { + pSoundStretch->putSamples((soundtouch::SAMPLETYPE*) + (audiobuffer + + org_waud), nSamplesToEnd); + pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer, + (len - bdiff) / abps); + } + else + pSoundStretch->putSamples((soundtouch::SAMPLETYPE*) + (audiobuffer + org_waud), + len / abps); - bdiff = AUDBUFSIZE - amount; - org_waud += amount; - } - } - else - { - int newLen = 0; - int nSamples; - len = WaitForFreeSpace(pSoundStretch->numSamples() * - audio_bytes_per_sample); - do - { - int samplesToGet = len/audio_bytes_per_sample; - if (samplesToGet > nSamplesToEnd) - { - samplesToGet = nSamplesToEnd; - } - - nSamples = pSoundStretch->receiveSamples( - (soundtouch::SAMPLETYPE*) - (audiobuffer + org_waud), samplesToGet); - if (nSamples == nSamplesToEnd) - { - org_waud = 0; - nSamplesToEnd = AUDBUFSIZE/audio_bytes_per_sample; - } - else - { - org_waud += nSamples * audio_bytes_per_sample; - nSamplesToEnd -= nSamples; - } - - newLen += nSamples * audio_bytes_per_sample; - len -= nSamples * audio_bytes_per_sample; - } while (nSamples > 0); + int nSamples = pSoundStretch->numSamples(); + len = WaitForFreeSpace(nSamples); + + while ((nSamples = pSoundStretch->numSamples())) + { + if (nSamples > nSamplesToEnd) + nSamples = nSamplesToEnd; + + nSamples = pSoundStretch->receiveSamples( + (soundtouch::SAMPLETYPE*) + (audiobuffer + org_waud), nSamples + ); + + if (nSamples == nSamplesToEnd) { + org_waud = 0; + nSamplesToEnd = AUDBUFSIZE/abps; + } + else { + org_waud += nSamples * abps; + nSamplesToEnd -= nSamples; } + } + + } - waud = org_waud; - lastaudiolen = audiolen(false); + // Encode to AC-3? + if (encoder) + { + + org_waud = waud; + int bdiff = AUDBUFSIZE - org_waud; + int to_get = 0; - if (timecode < 0) + if (bdiff < len) { - // mythmusic doesn't give timestamps.. - timecode = (int)((samples_buffered * 100000.0) / effdsp); + encoder->Encode(audiobuffer + org_waud, bdiff); + to_get = encoder->Encode(audiobuffer, len - bdiff); } + else + to_get = encoder->Encode(audiobuffer + org_waud, len); - samples_buffered += samples; - - /* we want the time at the end -- but the file format stores - time at the start of the chunk. */ - // even with timestretch, timecode is still calculated from original - // sample count - audbuf_timecode = timecode + (int)((samples * 100000.0) / effdsp); - - if (interleaved) + if (to_get > 0) { - dispatchVisual((unsigned char *)buffer, len, timecode, - source_audio_channels, audio_bits); + + if (to_get >= bdiff) + { + encoder->GetFrames(audiobuffer + org_waud, bdiff); + to_get -= bdiff; + org_waud = 0; + } + if (to_get > 0) + encoder->GetFrames(audiobuffer + org_waud, to_get); + + org_waud += to_get; + } + } - pthread_mutex_unlock(&audio_buflock); + waud = org_waud; + lastaudiolen = audiolen(false); + + if (timecode < 0) + // mythmusic doesn't give timestamps.. + timecode = (int)((samples_buffered * 100000.0) / effdsp); + + samples_buffered += samples; + + /* we want the time at the end -- but the file format stores + time at the start of the chunk. */ + // even with timestretch, timecode is still calculated from original + // sample count + audbuf_timecode = timecode + (int)((samples * 100000.0) / effdsp); + } void AudioOutputBase::Status() diff -Naur --exclude=.svn a/libs/libmyth/audiooutputbase.h b/libs/libmyth/audiooutputbase.h --- a/libs/libmyth/audiooutputbase.h 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutputbase.h 2009-01-28 15:49:56.000000000 +1100 @@ -48,8 +48,7 @@ virtual void Reconfigure(int audio_bits, int audio_channels, int audio_samplerate, - bool audio_passthru, - void *audio_codec = NULL); + bool audio_passthru); // do AddSamples calls block? virtual void SetBlocking(bool blocking); @@ -59,6 +58,7 @@ virtual void SetStretchFactor(float factor); virtual float GetStretchFactor(void); + virtual bool ToggleUpmix(void); virtual void Reset(void); @@ -139,9 +139,10 @@ QString audio_passthru_device; bool audio_passthru; + bool audio_enc; + bool audio_reenc; float audio_stretchfactor; - AVCodecContext *audio_codec; AudioOutputSource source; bool killaudio; @@ -151,6 +152,8 @@ bool buffer_output_data_for_use; // used by AudioOutputNULL int configured_audio_channels; + int orig_config_channels; + int src_quality; private: // resampler @@ -167,9 +170,12 @@ FreeSurround *upmixer; int source_audio_channels; + int source_audio_samplerate; int source_audio_bytes_per_sample; bool needs_upmix; int surround_mode; + bool allow_ac3_passthru; + float old_audio_stretchfactor; bool blocking; // do AddSamples calls block? diff -Naur --exclude=.svn a/libs/libmyth/audiooutputdigitalencoder.cpp b/libs/libmyth/audiooutputdigitalencoder.cpp --- a/libs/libmyth/audiooutputdigitalencoder.cpp 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutputdigitalencoder.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -27,10 +27,10 @@ AudioOutputDigitalEncoder::AudioOutputDigitalEncoder(void) : av_context(NULL), - outbuf(NULL), - outbuf_size(0), - frame_buffer(NULL), - one_frame_bytes(0) + outbuflen(0), + inbuflen(0), + one_frame_bytes(0), + reorder(true) { } @@ -47,36 +47,27 @@ av_free(av_context); av_context = NULL; } - - if (outbuf) - { - delete [] outbuf; - outbuf = NULL; - outbuf_size = 0; - } - - if (frame_buffer) - { - delete [] frame_buffer; - frame_buffer = NULL; - one_frame_bytes = 0; - } } //CODEC_ID_AC3 bool AudioOutputDigitalEncoder::Init( - CodecID codec_id, int bitrate, int samplerate, int channels) + CodecID codec_id, int bitrate, int samplerate, int channels, bool reencoding) { AVCodec *codec; int ret; - VERBOSE(VB_AUDIO, LOC + QString("Init codecid=%1, br=%2, sr=%3, ch=%4") + VERBOSE(VB_AUDIO, LOC + QString("Init codecid=%1, br=%2, sr=%3, ch=%4 re=%5") .arg(codec_id_string(codec_id)) .arg(bitrate) .arg(samplerate) - .arg(channels)); - - //codec = avcodec_find_encoder(codec_id); + .arg(channels) + .arg(reencoding)); + + reorder = !reencoding; + + // We need to do this when called from mythmusic + avcodec_init(); + avcodec_register_all(); // always AC3 as there is no DTS encoder at the moment 2005/1/9 codec = avcodec_find_encoder(CODEC_ID_AC3); if (!codec) @@ -105,8 +96,6 @@ audio_bytes_per_sample = bytes_per_frame; one_frame_bytes = bytes_per_frame * av_context->frame_size; - outbuf_size = 16384; // ok for AC3 but DTS? - outbuf = new char [outbuf_size]; VERBOSE(VB_AUDIO, QString("DigitalEncoder::Init fs=%1, bpf=%2 ofb=%3") .arg(av_context->frame_size) .arg(bytes_per_frame) @@ -256,12 +245,26 @@ } AESHeader; + +void reorder_6ch_ac3(void *buf, unsigned int len) { + unsigned short *src = (unsigned short *)buf; + unsigned short tmp; + unsigned int samples = len >> 1; + + for (uint i = 0; i < samples; i += 6) { + tmp = src[i+4]; + src[i+4] = src[i+3]; + src[i+3] = src[i+2]; + src[i+2] = src[i+1]; + src[i+1] = tmp; + } +} + static int encode_frame( bool dts, unsigned char *data, - size_t &len) + size_t enc_len) { - size_t enc_len; int flags, sample_rate, bit_rate; // we don't do any length/crc validation of the AC3 frame here; presumably @@ -273,6 +276,7 @@ // anything with a bad CRC... uint nr_samples = 0, block_len; + if (dts) { enc_len = dts_syncinfo(data+8, &flags, &sample_rate, &bit_rate); @@ -293,15 +297,8 @@ #endif } - if (enc_len == 0 || enc_len > len) - { - int l = len; - len = 0; - return l; - } - enc_len = min((uint)enc_len, block_len - 8); - + //uint32_t x = *(uint32_t*)(data+8); // in place swab swab((const char *)data + 8, (char *)data + 8, enc_len); @@ -348,35 +345,49 @@ break; } } - data[5] = 0x00; + data[5] = 0; data[6] = (enc_len << 3) & 0xFF; data[7] = (enc_len >> 5) & 0xFF; memset(data + 8 + enc_len, 0, block_len - 8 - enc_len); - len = block_len; return enc_len; } -// must have exactly 1 frames worth of data -size_t AudioOutputDigitalEncoder::Encode(short *buff) +size_t AudioOutputDigitalEncoder::Encode(void *buf, int len) { - int encsize = 0; size_t outsize = 0; - // put data in the correct spot for encode frame - outsize = avcodec_encode_audio( - av_context, ((uchar*)outbuf) + 8, outbuf_size - 8, buff); - - size_t tmpsize = outsize; - - outsize = MAX_AC3_FRAME_SIZE; - encsize = encode_frame( - /*av_context->codec_id==CODEC_ID_DTS*/ false, - (unsigned char*)outbuf, outsize); - - VERBOSE(VB_AUDIO|VB_TIMESTAMP, - QString("DigitalEncoder::Encode len1=%1 len2=%2 finallen=%3") - .arg(tmpsize).arg(encsize).arg(outsize)); + int fs = FrameSize(); + memcpy(inbuf+inbuflen, buf, len); + inbuflen += len; + int frames = inbuflen / fs; + + while (frames--) + { + if (reorder) + reorder_6ch_ac3(inbuf, fs); + + // put data in the correct spot for encode frame + outsize = avcodec_encode_audio( + av_context, ((uchar*)outbuf) + outbuflen + 8, OUTBUFSIZE - 8, (short int *)inbuf); + + encode_frame( + /*av_context->codec_id==CODEC_ID_DTS*/ false, + (unsigned char*)outbuf + outbuflen, outsize + ); + + outbuflen += MAX_AC3_FRAME_SIZE; + inbuflen -= fs; + memmove(inbuf, inbuf+fs, inbuflen); + } + + return outbuflen; +} - return outsize; +void AudioOutputDigitalEncoder::GetFrames(void *ptr, int maxlen) +{ + int len = (maxlen < outbuflen ? maxlen : outbuflen); + memcpy(ptr, outbuf, len); + outbuflen -= len; + memmove(outbuf, outbuf+len, outbuflen); } diff -Naur --exclude=.svn a/libs/libmyth/audiooutputdigitalencoder.h b/libs/libmyth/audiooutputdigitalencoder.h --- a/libs/libmyth/audiooutputdigitalencoder.h 2009-01-22 12:22:24.000000000 +1100 +++ b/libs/libmyth/audiooutputdigitalencoder.h 2009-01-28 15:49:56.000000000 +1100 @@ -5,37 +5,34 @@ #include "libavcodec/avcodec.h" }; +#define INBUFSIZE 131072 +#define OUTBUFSIZE 98304 + class AudioOutputDigitalEncoder { public: AudioOutputDigitalEncoder(void); ~AudioOutputDigitalEncoder(); - bool Init(CodecID codec_id, int bitrate, int samplerate, int channels); + bool Init(CodecID codec_id, int bitrate, int samplerate, + int channels, bool reencoding); void Dispose(void); - size_t Encode(short * buff); - - inline char *GetFrameBuffer(void); + size_t Encode(void *buf, int len); + void GetFrames(void *ptr, int maxlen); size_t FrameSize(void) const { return one_frame_bytes; } - char *GetOutBuff(void) const { return outbuf; } + int Buffered(void) const { return inbuflen; } public: size_t audio_bytes_per_sample; private: AVCodecContext *av_context; - char *outbuf; - int outbuf_size; - char *frame_buffer; + char outbuf[OUTBUFSIZE]; + char inbuf[INBUFSIZE]; + int outbuflen; + int inbuflen; size_t one_frame_bytes; + bool reorder; }; -inline char *AudioOutputDigitalEncoder::GetFrameBuffer(void) -{ - if (!frame_buffer && av_context) - frame_buffer = new char [one_frame_bytes]; - - return frame_buffer; -} - #endif diff -Naur --exclude=.svn a/libs/libmythfreesurround/el_processor.cpp b/libs/libmythfreesurround/el_processor.cpp --- a/libs/libmythfreesurround/el_processor.cpp 2009-01-22 12:22:25.000000000 +1100 +++ b/libs/libmythfreesurround/el_processor.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -40,17 +40,7 @@ const float PI = 3.141592654; const float epsilon = 0.000001; -//const float center_level = 0.5*sqrt(0.5); // gain of the center channel -//const float center_level = sqrt(0.5); // gain of the center channel -const float center_level = 1.0; // gain of the center channel -//const float center_level = 0.5; // gain of the center channel - -// should be .6-.7 -// but with centerlevel 2x what its supposed to be, we halve 0.68 -// to keep center from clipping -//const float window_gain = 0.34; -//const float window_gain = 0.68; -const float window_gain = 0.95; // to prive a bit of margin +const float center_level = 0.5*sqrt(0.5); // private implementation of the surround decoder class decoder_impl { @@ -98,19 +88,11 @@ outbuf[c].resize(N); filter[c].resize(N); } - // DC component of filters is always 0 - for (unsigned c=0;c<5;c++) - { - filter[c][0] = 0.0; - filter[c][1] = 0.0; - filter[c][halfN] = 0.0; - } sample_rate(48000); // generate the window function (square root of hann, b/c it is applied before and after the transform) wnd.resize(N); - // dft normalization included in the window for zero cost scaling - // also add a gain factor of *2 due to processing gain in algo (see center_level) - surround_gain(1.0); + for (unsigned k=0;k=2) && (f= -1 && x1.real() <= 1) - x = x1.real(); - else if (x2.real() >= -1 && x2.real() <= 1) - x = x2.real();*/ - - //cfloat yp = (rt - (x*E+H))/(F+x*G); - //cfloat xp = (lt - (y*B+D))/(A+y*C); - - /*xfs[f] = x; - yfs[f] = y.real();*/ - // --- this is the fancy new linear mode --- // get sound field x/y position @@ -597,7 +538,6 @@ float surround_high,surround_low; // high and low surround mixing coefficient (e.g. 0.8165/0.5774) float surround_balance; // the xfs balance that follows from the coeffs float surround_level; // gain for the surround channels (follows from the coeffs - float master_gain; // gain for all channels float phase_offsetL, phase_offsetR;// phase shifts to be applied to the rear channels float front_separation; // front stereo separation float rear_separation; // rear stereo separation @@ -625,8 +565,6 @@ void fsurround_decoder::surround_coefficients(float a, float b) { impl->surround_coefficients(a,b); } -void fsurround_decoder::gain(float gain) { impl->surround_gain(gain); } - void fsurround_decoder::phase_mode(unsigned mode) { impl->phase_mode(mode); } void fsurround_decoder::steering_mode(bool mode) { impl->steering_mode(mode); } diff -Naur --exclude=.svn a/libs/libmythfreesurround/el_processor.h b/libs/libmythfreesurround/el_processor.h --- a/libs/libmythfreesurround/el_processor.h 2009-01-22 12:22:25.000000000 +1100 +++ b/libs/libmythfreesurround/el_processor.h 2009-01-28 15:49:56.000000000 +1100 @@ -47,9 +47,6 @@ // a is the coefficient of left rear in left total, b is the coefficient of left rear in right total; the same is true for right. void surround_coefficients(float a, float b); - // override for master surround gain - void gain(float gain); - // set the phase shifting mode for decoding // 0 = (+0°,+0°) - music mode // 1 = (+0°,+180°) - PowerDVD compatibility diff -Naur --exclude=.svn a/libs/libmythfreesurround/freesurround.cpp b/libs/libmythfreesurround/freesurround.cpp --- a/libs/libmythfreesurround/freesurround.cpp 2009-01-22 12:22:25.000000000 +1100 +++ b/libs/libmythfreesurround/freesurround.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -63,10 +63,9 @@ const unsigned default_block_size = 8192; // there will be a slider for this in the future //const float master_gain = 1.0; -//#define MASTER_GAIN * master_gain +//#define MASTER_GAIN * master_gain #define MASTER_GAIN -//const float master_gain = 1.0/(1<<15); -//const float inv_master_gain = (1<<15); +//const float inv_master_gain = 1.0; //#define INV_MASTER_GAIN * inv_master_gain #define INV_MASTER_GAIN @@ -191,15 +190,13 @@ if (moviemode) { params.phasemode = 1; - params.center_width = 0; - params.gain = 1.0; + params.center_width = 25; + params.dimension = 0.5; } else { - params.center_width = 70; - // for 50, gain should be about 1.9, c/lr about 2.7 - // for 70, gain should be about 3.1, c/lr about 1.5 - params.gain = 3.1; + params.center_width = 65; + params.dimension = 0.3; } switch (surround_mode) { @@ -235,7 +232,6 @@ decoder->phase_mode(params.phasemode); decoder->surround_coefficients(params.coeff_a, params.coeff_b); decoder->separation(params.front_sep/100.0,params.rear_sep/100.0); - decoder->gain(params.gain); } } @@ -249,8 +245,7 @@ phasemode(0), steering(1), front_sep(100), - rear_sep(100), - gain(1.0) + rear_sep(100) { } @@ -654,16 +649,6 @@ { if (decoder) { - // actually these params need only be set when they change... but it doesn't hurt -#if 0 - decoder->steering_mode(params.steering); - decoder->phase_mode(params.phasemode); - decoder->surround_coefficients(params.coeff_a, params.coeff_b); - decoder->separation(params.front_sep/100.0,params.rear_sep/100.0); -#endif - // decode the bufs->block - //decoder->decode(input,output,params.center_width/100.0,params.dimension/100.0); - //decoder->decode(output,params.center_width/100.0,params.dimension/100.0); decoder->decode(params.center_width/100.0,params.dimension/100.0); } } diff -Naur --exclude=.svn a/libs/libmythsamplerate/samplerate.c b/libs/libmythsamplerate/samplerate.c --- a/libs/libmythsamplerate/samplerate.c 2009-01-22 12:22:07.000000000 +1100 +++ b/libs/libmythsamplerate/samplerate.c 2009-01-28 15:49:56.000000000 +1100 @@ -452,11 +452,11 @@ { len -- ; scaled_value = in [len] * (8.0 * 0x10000000) ; - if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) + if (scaled_value >= (1.0 * 0x7FFFFFFF)) { out [len] = 32767 ; continue ; } ; - if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) + if (scaled_value <= (-8.0 * 0x10000000)) { out [len] = -32768 ; continue ; } ; diff -Naur --exclude=.svn a/libs/libmythtv/NuppelVideoPlayer.cpp b/libs/libmythtv/NuppelVideoPlayer.cpp --- a/libs/libmythtv/NuppelVideoPlayer.cpp 2009-01-28 16:29:46.000000000 +1100 +++ b/libs/libmythtv/NuppelVideoPlayer.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -209,7 +209,6 @@ audio_passthru_device(QString::null), audio_channels(2), audio_bits(-1), audio_samplerate(44100), audio_stretchfactor(1.0f), - audio_codec(NULL), // Picture-in-Picture pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false), // Preview window support @@ -804,8 +803,9 @@ if (audioOutput) { audioOutput->Reconfigure(audio_bits, audio_channels, - audio_samplerate, audio_passthru, - audio_codec); + audio_samplerate, audio_passthru); + if (audio_passthru) + audio_channels = 2; errMsg = audioOutput->GetError(); if (!errMsg.isEmpty()) audioOutput->SetStretchFactor(audio_stretchfactor); @@ -3718,11 +3718,6 @@ audio_passthru = passthru; } -void NuppelVideoPlayer::SetAudioCodec(void *ac) -{ - audio_codec = ac; -} - void NuppelVideoPlayer::SetEffDsp(int dsprate) { if (audioOutput) diff -Naur --exclude=.svn a/libs/libmythtv/NuppelVideoPlayer.h b/libs/libmythtv/NuppelVideoPlayer.h --- a/libs/libmythtv/NuppelVideoPlayer.h 2009-01-22 12:22:02.000000000 +1100 +++ b/libs/libmythtv/NuppelVideoPlayer.h 2009-01-28 15:49:56.000000000 +1100 @@ -685,7 +685,6 @@ int audio_bits; int audio_samplerate; float audio_stretchfactor; - void *audio_codec; bool audio_passthru; // Picture-in-Picture diff -Naur --exclude=.svn a/libs/libmythtv/avformatdecoder.cpp b/libs/libmythtv/avformatdecoder.cpp --- a/libs/libmythtv/avformatdecoder.cpp 2009-01-28 16:29:46.000000000 +1100 +++ b/libs/libmythtv/avformatdecoder.cpp 2009-01-28 16:22:52.000000000 +1100 @@ -425,7 +425,7 @@ audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]), allow_ac3_passthru(false), allow_dts_passthru(false), disable_passthru(false), max_channels(2), - dummy_frame(NULL), + last_ac3_channels(0), dummy_frame(NULL), // DVD lastdvdtitle(-1), decodeStillFrame(false), @@ -2944,15 +2944,9 @@ { int idx = atracks[i].av_stream_index; AVCodecContext *codec_ctx = ic->streams[idx]->codec; - bool do_ac3_passthru = (allow_ac3_passthru && !transcoding && - !disable_passthru && - (codec_ctx->codec_id == CODEC_ID_AC3)); - bool do_dts_passthru = (allow_dts_passthru && !transcoding && - !disable_passthru && - (codec_ctx->codec_id == CODEC_ID_DTS)); AudioInfo item(codec_ctx->codec_id, codec_ctx->sample_rate, codec_ctx->channels, - do_ac3_passthru || do_dts_passthru); + DoPassThrough(codec_ctx)); VERBOSE(VB_AUDIO, LOC + " * " + item.toString()); } #endif @@ -3086,6 +3080,7 @@ bool AvFormatDecoder::GetFrame(int onlyvideo) { AVPacket *pkt = NULL; + AC3HeaderInfo hdr; int len; unsigned char *ptr; int data_size = 0; @@ -3272,12 +3267,13 @@ pts = 0; AVStream *curstream = ic->streams[pkt->stream_index]; + AVCodecContext *ctx = curstream->codec; if (pkt->dts != (int64_t)AV_NOPTS_VALUE) pts = (long long)(av_q2d(curstream->time_base) * pkt->dts * 1000); if (ringBuffer->isDVD() && - curstream->codec->codec_type == CODEC_TYPE_VIDEO) + ctx->codec_type == CODEC_TYPE_VIDEO) { MpegPreProcessPkt(curstream, pkt); @@ -3305,7 +3301,7 @@ if (!d->HasMPEG2Dec()) { - int current_width = curstream->codec->width; + int current_width = ctx->width; int video_width = GetNVP()->GetVideoSize().width(); if (dvd_xvmc_enabled && GetNVP() && GetNVP()->getVideoOutput()) { @@ -3346,7 +3342,7 @@ } if (storevideoframes && - curstream->codec->codec_type == CODEC_TYPE_VIDEO) + ctx->codec_type == CODEC_TYPE_VIDEO) { av_dup_packet(pkt); storedPackets.append(pkt); @@ -3354,22 +3350,21 @@ continue; } - if (len > 0 && curstream->codec->codec_type == CODEC_TYPE_VIDEO && + if (len > 0 && ctx->codec_type == CODEC_TYPE_VIDEO && pkt->stream_index == selectedVideoIndex) { - AVCodecContext *context = curstream->codec; - if (context->codec_id == CODEC_ID_MPEG1VIDEO || - context->codec_id == CODEC_ID_MPEG2VIDEO || - context->codec_id == CODEC_ID_MPEG2VIDEO_XVMC || - context->codec_id == CODEC_ID_MPEG2VIDEO_XVMC_VLD || - context->codec_id == CODEC_ID_MPEGVIDEO_VDPAU) + if (ctx->codec_id == CODEC_ID_MPEG1VIDEO || + ctx->codec_id == CODEC_ID_MPEG2VIDEO || + ctx->codec_id == CODEC_ID_MPEG2VIDEO_XVMC || + ctx->codec_id == CODEC_ID_MPEG2VIDEO_XVMC_VLD || + ctx->codec_id == CODEC_ID_MPEGVIDEO_VDPAU) { if (!ringBuffer->isDVD()) MpegPreProcessPkt(curstream, pkt); } - else if (context->codec_id == CODEC_ID_H264 || - context->codec_id == CODEC_ID_H264_VDPAU) + else if (ctx->codec_id == CODEC_ID_H264 || + ctx->codec_id == CODEC_ID_H264_VDPAU) { H264PreProcessPkt(curstream, pkt); } @@ -3415,8 +3410,8 @@ } if (len > 0 && - curstream->codec->codec_type == CODEC_TYPE_DATA && - curstream->codec->codec_id == CODEC_ID_MPEG2VBI) + ctx->codec_type == CODEC_TYPE_DATA && + ctx->codec_id == CODEC_ID_MPEG2VBI) { ProcessVBIDataPacket(curstream, pkt); @@ -3425,8 +3420,8 @@ } if (len > 0 && - curstream->codec->codec_type == CODEC_TYPE_DATA && - curstream->codec->codec_id == CODEC_ID_DVB_VBI) + ctx->codec_type == CODEC_TYPE_DATA && + ctx->codec_id == CODEC_ID_DVB_VBI) { ProcessDVBDataPacket(curstream, pkt); @@ -3435,8 +3430,8 @@ } if (len > 0 && - curstream->codec->codec_type == CODEC_TYPE_DATA && - curstream->codec->codec_id == CODEC_ID_DSMCC_B) + ctx->codec_type == CODEC_TYPE_DATA && + ctx->codec_id == CODEC_ID_DSMCC_B) { ProcessDSMCCPacket(curstream, pkt); @@ -3456,20 +3451,20 @@ } // we don't care about other data streams - if (curstream->codec->codec_type == CODEC_TYPE_DATA) + if (ctx->codec_type == CODEC_TYPE_DATA) { av_free_packet(pkt); continue; } - if (!curstream->codec->codec) + if (!ctx->codec) { VERBOSE(VB_PLAYBACK, LOC + QString("No codec for stream index %1, type(%2) id(%3:%4)") .arg(pkt->stream_index) - .arg(codec_type_string(curstream->codec->codec_type)) - .arg(codec_id_string(curstream->codec->codec_id)) - .arg(curstream->codec->codec_id)); + .arg(codec_type_string(ctx->codec_type)) + .arg(codec_id_string(ctx->codec_id)) + .arg(ctx->codec_id)); av_free_packet(pkt); continue; } @@ -3478,7 +3473,7 @@ have_err = false; avcodeclock.lock(); - int ctype = curstream->codec->codec_type; + int ctype = ctx->codec_type; int audIdx = selectedTrack[kTrackTypeAudio].av_stream_index; int audSubIdx = selectedTrack[kTrackTypeAudio].av_substream_index; int subIdx = selectedTrack[kTrackTypeSubtitle].av_stream_index; @@ -3503,50 +3498,52 @@ // detect switches between stereo and dual languages bool wasDual = audSubIdx != -1; - bool isDual = curstream->codec->avcodec_dual_language; + bool isDual = ctx->avcodec_dual_language; if ((wasDual && !isDual) || (!wasDual && isDual)) { SetupAudioStreamSubIndexes(audIdx); reselectAudioTrack = true; } - bool do_ac3_passthru = - (allow_ac3_passthru && !transcoding && - (curstream->codec->codec_id == CODEC_ID_AC3)); - bool do_dts_passthru = - (allow_dts_passthru && !transcoding && - (curstream->codec->codec_id == CODEC_ID_DTS)); - bool using_passthru = do_ac3_passthru || do_dts_passthru; - // detect channels on streams that need // to be decoded before we can know this bool already_decoded = false; - if (!curstream->codec->channels) + if (!ctx->channels) { QMutexLocker locker(&avcodeclock); VERBOSE(VB_IMPORTANT, LOC + QString("Setting channels to %1") .arg(audioOut.channels)); - if (using_passthru) + if (DoPassThrough(ctx)) { // for passthru let it select the max number // of channels - curstream->codec->channels = 0; - curstream->codec->request_channels = 0; + ctx->channels = 0; + ctx->request_channels = 0; } else { - curstream->codec->channels = audioOut.channels; - curstream->codec->request_channels = + ctx->channels = audioOut.channels; + ctx->request_channels = audioOut.channels; } ret = avcodec_decode_audio( - curstream->codec, audioSamples, + ctx, audioSamples, &data_size, ptr, len); already_decoded = true; - reselectAudioTrack |= curstream->codec->channels; + reselectAudioTrack |= ctx->channels; + } + + if (ctx->codec_id == CODEC_ID_AC3 && + !ff_ac3_parse_header(ptr, &hdr)) + { + if (hdr.channels != last_ac3_channels) + { + last_ac3_channels = ctx->channels = hdr.channels; + SetupAudioStream(); + } } if (reselectAudioTrack) @@ -3562,6 +3559,7 @@ .av_stream_index; audSubIdx = selectedTrack[kTrackTypeAudio] .av_substream_index; + ctx = curstream->codec; } if ((onlyvideo > 0) || (pkt->stream_index != audIdx)) @@ -3593,14 +3591,12 @@ if (audioOut.do_passthru) { data_size = pkt->size; - bool dts = CODEC_ID_DTS == curstream->codec->codec_id; + bool dts = CODEC_ID_DTS == ctx->codec_id; ret = encode_frame(dts, ptr, len, audioSamples, data_size); } else { - AVCodecContext *ctx = curstream->codec; - if ((ctx->channels == 0) || (ctx->channels > audioOut.channels)) { @@ -3609,8 +3605,7 @@ if (!already_decoded) { - curstream->codec->request_channels = - audioOut.channels; + ctx->request_channels = audioOut.channels; ret = avcodec_decode_audio( ctx, audioSamples, &data_size, ptr, len); } @@ -3627,6 +3622,7 @@ audIdx = -1; AutoSelectAudioTrack(); data_size = 0; + ctx = curstream->codec; } } avcodeclock.unlock(); @@ -3644,8 +3640,7 @@ // calc for next frame lastapts += (long long)((double)(data_size * 1000) / - (curstream->codec->channels * 2) / - curstream->codec->sample_rate); + (ctx->channels * 2) / ctx->sample_rate); VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("audio timecode %1 %2 %3 %4") @@ -3705,7 +3700,6 @@ continue; } - AVCodecContext *context = curstream->codec; AVFrame mpa_pic; bzero(&mpa_pic, sizeof(AVFrame)); @@ -3720,24 +3714,24 @@ // HACK while (!gotpicture && count < 5) { - ret = d->DecodeMPEG2Video(context, &mpa_pic, + ret = d->DecodeMPEG2Video(ctx, &mpa_pic, &gotpicture, ptr, len); count++; } } else { - ret = d->DecodeMPEG2Video(context, &mpa_pic, + ret = d->DecodeMPEG2Video(ctx, &mpa_pic, &gotpicture, ptr, len); } } else { - ret = avcodec_decode_video(context, &mpa_pic, + ret = avcodec_decode_video(ctx, &mpa_pic, &gotpicture, ptr, len); // Reparse it to not drop the DVD still frame if (decodeStillFrame) - ret = avcodec_decode_video(context, &mpa_pic, + ret = avcodec_decode_video(ctx, &mpa_pic, &gotpicture, ptr, len); } avcodeclock.unlock(); @@ -3804,9 +3798,9 @@ img_convert(&tmppicture, PIX_FMT_YUV420P, (AVPicture *)&mpa_pic, - context->pix_fmt, - context->width, - context->height); + ctx->pix_fmt, + ctx->width, + ctx->height); if (xf) { @@ -3829,10 +3823,10 @@ (temppts + 10000 > lastvpts || temppts < 0)) { temppts = lastvpts; - temppts += (long long)(1000 * av_q2d(context->time_base)); + temppts += (long long)(1000 * av_q2d(ctx->time_base)); // MPEG2 frames can be repeated, update pts accordingly temppts += (long long)(mpa_pic.repeat_pict * 500 - * av_q2d(curstream->codec->time_base)); + * av_q2d(ctx->time_base)); } VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + @@ -3868,7 +3862,7 @@ picframe->frameNumber = framesPlayed; GetNVP()->ReleaseNextVideoFrame(picframe, temppts); if (d->HasMPEG2Dec() && mpa_pic.data[3]) - context->release_buffer(context, &mpa_pic); + ctx->release_buffer(ctx, &mpa_pic); decoded_video_frame = picframe; gotvideo = 1; @@ -3927,11 +3921,10 @@ } default: { - AVCodecContext *enc = curstream->codec; VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Decoding - id(%1) type(%2)") - .arg(codec_id_string(enc->codec_id)) - .arg(codec_type_string(enc->codec_type))); + .arg(codec_id_string(ctx->codec_id)) + .arg(codec_type_string(ctx->codec_type))); have_err = true; break; } @@ -4080,6 +4073,25 @@ } } +bool AvFormatDecoder::DoPassThrough(const AVCodecContext *ctx) +{ + bool passthru = false; + + if (ctx->codec_id == CODEC_ID_AC3) + passthru = allow_ac3_passthru && + ctx->channels >= (int)max_channels; + else if (ctx->codec_id == CODEC_ID_DTS) + passthru = allow_dts_passthru; + + passthru &= !transcoding && !disable_passthru; + // Don't know any cards that support spdif clocked at < 44100 + // Some US cable transmissions have 2ch 32k AC-3 streams + passthru &= ctx->sample_rate >= 44100; + + return passthru; +} + + /** \fn AvFormatDecoder::SetupAudioStream(void) * \brief Reinitializes audio if it needs to be reinitialized. * @@ -4093,7 +4105,6 @@ AVStream *curstream = NULL; AVCodecContext *codec_ctx = NULL; AudioInfo old_in = audioIn; - AudioInfo old_out = audioOut; bool using_passthru = false; if ((currentTrack[kTrackTypeAudio] >= 0) && @@ -4105,14 +4116,9 @@ assert(curstream); assert(curstream->codec); codec_ctx = curstream->codec; - bool do_ac3_passthru = (allow_ac3_passthru && !transcoding && - (codec_ctx->codec_id == CODEC_ID_AC3)); - bool do_dts_passthru = (allow_dts_passthru && !transcoding && - (codec_ctx->codec_id == CODEC_ID_DTS)); - using_passthru = do_ac3_passthru || do_dts_passthru; - info = AudioInfo(codec_ctx->codec_id, - codec_ctx->sample_rate, codec_ctx->channels, - using_passthru && !disable_passthru); + using_passthru = DoPassThrough(codec_ctx); + info = AudioInfo(codec_ctx->codec_id, codec_ctx->sample_rate, + codec_ctx->channels, using_passthru); } if (info == audioIn) @@ -4123,64 +4129,26 @@ QString("audio track #%1").arg(currentTrack[kTrackTypeAudio]+1)); audioOut = audioIn = info; - if (using_passthru) - { - // A passthru stream looks like a 48KHz 2ch (@ 16bit) to the sound card - AudioInfo digInfo = audioOut; - if (!disable_passthru) - { - digInfo.channels = 2; - digInfo.sample_rate = 48000; - digInfo.sample_size = 4; - } - if (audioOut.channels > (int) max_channels) - { - audioOut.channels = (int) max_channels; - audioOut.sample_size = audioOut.channels * 2; - codec_ctx->channels = audioOut.channels; - } - VERBOSE(VB_AUDIO, LOC + "Audio format changed digital passthrough " + - QString("%1\n\t\t\tfrom %2 ; %3\n\t\t\tto %4 ; %5") - .arg(digInfo.toString()) - .arg(old_in.toString()).arg(old_out.toString()) - .arg(audioIn.toString()).arg(audioOut.toString())); - - if (digInfo.sample_rate > 0) - GetNVP()->SetEffDsp(digInfo.sample_rate * 100); - - GetNVP()->SetAudioParams(digInfo.bps(), digInfo.channels, - digInfo.sample_rate, audioIn.do_passthru); - // allow the audio stuff to reencode - GetNVP()->SetAudioCodec(codec_ctx); - GetNVP()->ReinitAudio(); - return true; - } - else + + if (!using_passthru && audioOut.channels > (int)max_channels) { - if (audioOut.channels > (int) max_channels) - { - audioOut.channels = (int) max_channels; - audioOut.sample_size = audioOut.channels * 2; - codec_ctx->channels = audioOut.channels; - } + audioOut.channels = (int)max_channels; + audioOut.sample_size = audioOut.channels * 2; + codec_ctx->channels = audioOut.channels; } - + VERBOSE(VB_AUDIO, LOC + "Audio format changed " + - QString("\n\t\t\tfrom %1 ; %2\n\t\t\tto %3 ; %4") - .arg(old_in.toString()).arg(old_out.toString()) - .arg(audioIn.toString()).arg(audioOut.toString())); + QString("\n\t\t\tfrom %1 to %2") + .arg(old_in.toString()).arg(audioOut.toString())); if (audioOut.sample_rate > 0) GetNVP()->SetEffDsp(audioOut.sample_rate * 100); GetNVP()->SetAudioParams(audioOut.bps(), audioOut.channels, audioOut.sample_rate, - audioIn.do_passthru); + audioOut.do_passthru); - // allow the audio stuff to reencode - GetNVP()->SetAudioCodec(using_passthru?codec_ctx:NULL); QString errMsg = GetNVP()->ReinitAudio(); - bool audiook = errMsg.isEmpty(); return true; } diff -Naur --exclude=.svn a/libs/libmythtv/avformatdecoder.h b/libs/libmythtv/avformatdecoder.h --- a/libs/libmythtv/avformatdecoder.h 2009-01-28 16:29:46.000000000 +1100 +++ b/libs/libmythtv/avformatdecoder.h 2009-01-28 15:49:56.000000000 +1100 @@ -198,6 +198,7 @@ void SeekReset(long long, uint skipFrames, bool doFlush, bool discardFrames); + bool DoPassThrough(const AVCodecContext *ctx); bool SetupAudioStream(void); void SetupAudioStreamSubIndexes(int streamIndex); void RemoveAudioStreams(); @@ -266,6 +267,7 @@ bool allow_dts_passthru; bool disable_passthru; uint max_channels; + uint last_ac3_channels; VideoFrame *dummy_frame; diff -Naur --exclude=.svn a/libs/libmythtv/tv_play.cpp b/libs/libmythtv/tv_play.cpp --- a/libs/libmythtv/tv_play.cpp 2009-01-22 12:22:03.000000000 +1100 +++ b/libs/libmythtv/tv_play.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -348,6 +348,7 @@ REG_KEY("TV Playback", "VOLUMEDOWN", "Volume down", "[,{,F10,Volume Down"); REG_KEY("TV Playback", "VOLUMEUP", "Volume up", "],},F11,Volume Up"); REG_KEY("TV Playback", "MUTE", "Mute", "|,\\,F9,Volume Mute"); + REG_KEY("TV Playback", "TOGGLEUPMIX", "Toggle upmixer", "Ctrl+U"); REG_KEY("TV Playback", "TOGGLEPIPMODE", "Toggle Picture-in-Picture mode", "V"); REG_KEY("TV Playback", "TOGGLEPIPWINDOW", "Toggle active PiP window", "B"); @@ -480,7 +481,7 @@ Teletext F2,F3,F4,F5,F6,F7,F8 ITV F2,F3,F4,F5,F6,F7,F12 - Playback: Ctrl-B,Ctrl-G,Ctrl-Y + Playback: Ctrl-B,Ctrl-G,Ctrl-Y,Ctrl-U */ } @@ -2710,7 +2711,7 @@ else if (action == "VOLUMEDOWN" || action == "VOLUMEUP" || action == "STRETCHINC" || action == "STRETCHDEC" || action == "MUTE" || action == "TOGGLEASPECT" || - action == "TOGGLEFILL" ) + action == "TOGGLEFILL" || action == "TOGGLEUPMIX") { passThru = 1; handled = false; @@ -2725,11 +2726,11 @@ else handled = false; } - + if (!passThru) return; } - + if (zoomMode) { int passThru = 0; @@ -2765,7 +2766,7 @@ else if (action == "VOLUMEDOWN" || action == "VOLUMEUP" || action == "STRETCHINC" || action == "STRETCHDEC" || action == "MUTE" || action == "PAUSE" || - action == "CLEAROSD") + action == "CLEAROSD" || action == "TOGGLEUPMIX") { passThru = 1; handled = false; @@ -2777,7 +2778,7 @@ if (!passThru) return; } - + if (dialogname != "" && GetOSD() && GetOSD()->DialogShowing(dialogname)) { for (unsigned int i = 0; i < actions.size() && !handled; i++) @@ -3036,7 +3037,7 @@ return; } } - + for (unsigned int i = 0; i < actions.size() && !handled; i++) { QString action = actions[i]; @@ -3070,6 +3071,8 @@ ChangeTimeStretch(0); // just display else if (action == "TOGGLESTRETCH") ToggleTimeStretch(); + else if (action == "TOGGLEUPMIX") + ToggleUpmix(); else if (action == "CYCLECOMMSKIPMODE") { SetAutoCommercialSkip((enum commSkipMode) ((autoCommercialSkip + 1) % CommSkipModes)); @@ -6054,6 +6057,22 @@ } } +void TV::ToggleUpmix() +{ + AudioOutput *aud = nvp->getAudioOutput(); + if (!aud) + return; + QString text; + if (aud->ToggleUpmix()) + text = tr("Upmixer On"); + else + text = tr("Upmixer Off"); + + if (GetOSD() && !browsemode) + GetOSD()->SetSettingsText(text, 5); +} + + // dir in 10ms jumps void TV::ChangeAudioSync(int dir, bool allowEdit) { @@ -7300,6 +7319,8 @@ ChangeTimeStretch(0, !floatRead); // just display } + else if (action == "TOGGLEUPMIX") + ToggleUpmix(); else if (action.left(11) == "SELECTSCAN_") activenvp->SetScanType((FrameScanType) action.right(1).toInt()); else if (action.left(15) == "TOGGLEAUDIOSYNC") @@ -7547,6 +7568,8 @@ subitem = new OSDGenericTree(item, tr("1.5X"), "ADJUSTSTRETCH1.5", (speedX100 == 150) ? 1 : 0, NULL, "STRETCHGROUP"); + + item = new OSDGenericTree(treeMenu, tr("Toggle Upmixer"), "TOGGLEUPMIX"); // add scan mode override settings to menu FrameScanType scan_type = kScan_Ignore; diff -Naur --exclude=.svn a/libs/libmythtv/tv_play.h b/libs/libmythtv/tv_play.h --- a/libs/libmythtv/tv_play.h 2009-01-22 12:22:02.000000000 +1100 +++ b/libs/libmythtv/tv_play.h 2009-01-28 15:49:56.000000000 +1100 @@ -314,6 +314,7 @@ void ChangeSpeed(int direction); void ToggleTimeStretch(void); void ChangeTimeStretch(int dir, bool allowEdit = true); + void ToggleUpmix(void); void ChangeAudioSync(int dir, bool allowEdit = true); float StopFFRew(void); void ChangeFFRew(int direction); diff -Naur --exclude=.svn a/programs/mythfrontend/globalsettings.cpp b/programs/mythfrontend/globalsettings.cpp --- a/programs/mythfrontend/globalsettings.cpp 2009-01-22 12:22:26.000000000 +1100 +++ b/programs/mythfrontend/globalsettings.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -116,6 +116,26 @@ return gc; } +static HostComboBox *SRCQuality() +{ + HostComboBox *gc = new HostComboBox("SRCQuality", false); + gc->setLabel(QObject::tr("Sample Rate Conversion")); + gc->addSelection(QObject::tr("Best"), "3", true); // default + gc->addSelection(QObject::tr("Medium"), "2"); + gc->addSelection(QObject::tr("Fastest"), "1"); + gc->addSelection(QObject::tr("Disabled"), "0"); + gc->setHelpText( + QObject::tr( + "Set the quality of audio sample rate conversion. " + "This only affects non 48000Hz PCM audio. " + "All three options offer a worst-case SNR of 97dB. " + "'Best' at a bandwidth of 97%. " + "'Medium' at a bandwidth of 90%. " + "'Fastest' at a bandwidth of 80%. " + "Set 'Disabled' only if you know what you are doing . ")); + return gc; +} + static HostComboBox *PassThroughOutputDevice() { HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true); @@ -3307,6 +3327,11 @@ agrp->addChild(MaxAudioChannels()); agrp->addChild(AudioUpmixType()); addChild(agrp); + + HorizontalConfigurationGroup *agrp1 = + new HorizontalConfigurationGroup(false, false, true, true); + agrp1->addChild(SRCQuality()); + addChild(agrp1); VerticalConfigurationGroup *vgrp1 = new VerticalConfigurationGroup(false, false, true, true); diff -Naur --exclude=.svn a/programs/mythtranscode/transcode.cpp b/programs/mythtranscode/transcode.cpp --- a/programs/mythtranscode/transcode.cpp 2009-01-22 12:22:26.000000000 +1100 +++ b/programs/mythtranscode/transcode.cpp 2009-01-28 15:49:56.000000000 +1100 @@ -55,12 +55,10 @@ // reconfigure sound out for new params virtual void Reconfigure(int audio_bits, int audio_channels, - int audio_samplerate, bool audio_passthru, - void *audio_codec = NULL) + int audio_samplerate, bool audio_passthru) { (void)audio_samplerate; (void)audio_passthru; - (void)audio_codec; ClearError(); bits = audio_bits; @@ -218,6 +216,11 @@ // Do nothing return MUTE_OFF; } + virtual bool ToggleUpmix(void) + { + // Do nothing + return false; + } // These are pure virtual in AudioOutput, but we don't need them here virtual void bufferOutputData(bool){ return; }