commit 7cef0613cac0cac57ec6bf36ba99cc8bc247a49f
Author: Mark Spieth <mspieth@digivation.com.au>
Date:   Wed Jan 5 10:49:43 2011 +1100

    audio addon for comm detector

diff --git a/mythtv/programs/mythcommflag/AudioBuffer.cpp b/mythtv/programs/mythcommflag/AudioBuffer.cpp
new file mode 100644
index 0000000..4f789fc
--- /dev/null
+++ b/mythtv/programs/mythcommflag/AudioBuffer.cpp
@@ -0,0 +1,347 @@
+
+#include "AudioBuffer.h"
+
+AudioSample::AudioSample()
+{
+    time = 0;
+    duration = 0;
+    power = 0;
+    channels = 0;
+    changed = false;
+}
+
+QString AudioSample::toString() const
+{
+    return QString("%1 %2 %3 %4 %5")
+        .arg(time)
+        .arg(duration)
+        .arg(power)
+        .arg(channels)
+        .arg(changed);
+}
+
+
+AudioBuffer::AudioBuffer(const AudioSettings &settings) :
+    configured_channels(CHANNELS_MAX),
+    last_audiotime(0),
+    output_settings(0),
+    changed(false),
+    info_valid(false),
+    m_lock(),
+    verboseDebugging(false),
+    enabled(false)
+{
+    if (getenv("DEBUGCOMMFLAG"))
+        verboseDebugging = true;
+
+    Reset();
+    //AudioSettings orig_settings("", "", AudioFormat::,);
+    //Reconfigure(audio_bits, audio_channels, 0);
+    Reconfigure(settings);
+}
+
+AudioBuffer::~AudioBuffer()
+{
+    //delete [] audiobuffer;
+    if (output_settings)
+    {
+        delete output_settings;
+        output_settings = NULL;
+    }
+}
+
+AudioOutputSettings* AudioBuffer::GetOutputSettings(bool /*digital*/)
+{
+    AudioOutputSettings *settings = new AudioOutputSettings();
+
+    for (uint channels = CHANNELS_MIN; channels <= CHANNELS_MAX; channels++)
+    {
+        settings->AddSupportedChannels(channels);
+    }
+
+    LOG(VB_COMMFLAG, LOG_INFO,
+        QString("GetOutputSettings"));
+    return settings;
+}
+
+AudioOutputSettings* AudioBuffer::GetOutputSettingsUsers(bool digital)
+{
+    if (!output_settings)
+        output_settings = GetOutputSettings(digital);
+    return output_settings;
+}
+
+AudioOutputSettings* AudioBuffer::GetOutputSettingsCleaned(bool digital)
+{
+    if (!output_settings)
+        output_settings = GetOutputSettings(digital);
+    return output_settings;
+}
+
+void AudioBuffer::Enable()
+{
+    enabled = true;
+}
+
+// reconfigure sound out for new params
+void AudioBuffer::Reconfigure(const AudioSettings &orig_settings)
+{
+    ClearError();
+    changed = (orig_settings.format != settings.format)
+        | (orig_settings.channels != settings.channels)
+        | (orig_settings.samplerate != settings.samplerate);
+    settings = orig_settings;
+
+    source_bytes_per_frame = source_channels * AudioOutputSettings::SampleSize(settings.format);
+    LOG(VB_COMMFLAG, LOG_INFO,
+        QString("Audio Reconfigure changed %1.").arg(changed));
+
+    QMutexLocker locker(&m_lock);
+    audioSamples.clear();
+    last_audiotime = 0;
+}
+
+// dsprate is in 100 * samples/second
+void AudioBuffer::SetEffDsp(int /* dsprate */)
+{
+    //eff_audiorate = (dsprate / 100);
+}
+
+void AudioBuffer::SetBlocking(bool block) 
+{
+    (void)block; 
+}
+
+void AudioBuffer::Reset(void)
+{
+    if (!enabled)
+        return;
+    if (verboseDebugging)
+    {
+        LOG(VB_COMMFLAG, LOG_DEBUG,
+            QString("audio reset"));
+    }
+    QMutexLocker locker(&m_lock);
+    audioSamples.clear();
+    last_audiotime = 0;
+}
+
+bool AudioBuffer::AddFrames(void *in_buffer, int in_frames,
+                                        int64_t timecode)
+{
+    if (!enabled)
+    {
+        last_audiotime = timecode;
+        return true;
+    }
+    return AddData(in_buffer, in_frames * source_bytes_per_frame, timecode,
+                                   in_frames);
+}
+
+bool AudioBuffer::AddData(void *in_buffer, int in_len,
+                     int64_t timecode, int in_frames)
+{
+    if (!enabled)
+    {
+        last_audiotime = timecode;
+        return true;
+    }
+    int i;
+    int f;
+    PAudioSample aSample(new AudioSample);
+    aSample->power = 0;
+    aSample->time = timecode;    // in ms
+    aSample->duration = (in_frames * 1000) / settings.samplerate; // in ms
+    aSample->channels = settings.channels;
+    if (changed)
+    {
+        aSample->changed = changed;
+        changed = false;
+    }
+    if (timecode < last_audiotime)
+    {
+        LOG(VB_COMMFLAG, LOG_DEBUG,
+            QString("audio time reset %1").arg(timecode));
+        QMutexLocker locker(&m_lock);
+        audioSamples.clear();
+        last_audiotime = 0;
+    }
+    if (last_audiotime != 0)
+    {
+        int64_t nextAudiotime = last_audiotime + aSample->duration;
+        while (aSample->time < nextAudiotime)
+        {
+            PAudioSample nullSample(new AudioSample);
+            nullSample->power = -1;
+            nullSample->time = nextAudiotime;
+            nullSample->duration = aSample->duration;
+            {
+                QMutexLocker locker(&m_lock);
+                audioSamples.push_back(nullSample);
+            }
+#ifdef AUDIODEBUGGING
+            LOG(VB_COMMFLAG, LOG_DEBUG,
+                QString("Audio AddData invalid time %1").arg(nullSample->time));
+#endif
+        }
+    }
+    switch (settings.format)
+    {
+        case FORMAT_S16:
+            {
+                int64_t power = 0;
+                int16_t *p = (int16_t*)in_buffer;
+                for(f=in_frames;f>0;--f)
+                {
+                    // power as mono
+                    int64_t sum = 0;
+                    for(i=settings.channels; i>0; --i)
+                    {
+                        sum += *p++;
+                        p++;
+                    }
+                    power += sum * sum;
+                }
+                aSample->power += ((double)power)/(INT16_MAX * INT16_MAX)/in_frames;
+                info_valid = true;
+                QMutexLocker locker(&m_lock);
+                audioSamples.push_back(aSample);
+            } break;
+        case FORMAT_FLT:
+            {
+                double power = 0;
+                float *p = (float*)in_buffer;
+                for(f=in_frames;f>0;--f)
+                {
+                    // power as mono
+                    int64_t sum = 0;
+                    for(i=settings.channels; i>0; --i)
+                    {
+                        sum += *p++;
+                        p++;
+                    }
+                    power += sum * sum;
+                }
+                aSample->power += power/in_frames;
+                info_valid = true;
+                QMutexLocker locker(&m_lock);
+                audioSamples.push_back(aSample);
+            } break;
+        default:
+            break;
+    }
+#ifdef AUDIODEBUGGING
+    if (info_valid)
+    {
+        LOG(VB_COMMFLAG, LOG_DEBUG,
+            QString("Audio AddData time %1 frames %2 power %3 changed %4").arg(timecode).arg(in_frames).arg(aSample->power).arg(aSample->changed));
+    }
+    else
+    {
+        LOG(VB_COMMFLAG, LOG_DEBUG,
+            QString("Audio AddData time %1 frames %2").arg(timecode).arg(in_frames));
+    }
+#endif
+    last_audiotime = timecode;
+    return true;
+}
+
+const PAudioSample AudioBuffer::GetSample(int64_t time) const
+{
+    if (audioSamples.size() > 0)
+    {
+        QMutexLocker locker(&m_lock);
+        int64_t index = (time - audioSamples[0]->time)/audioSamples[0]->duration;
+        //LOG(VB_COMMFLAG, LOG_DEBUG, QString("Audio GetSample time %1 tine0 %2 duration %3 index %4 size %5").arg(time).arg(audioSamples[0].time).arg(audioSamples[0].duration).arg(index).arg(audioSamples.size()));
+        if (index >= 0 && index < audioSamples.size())
+            return audioSamples[index];
+    }
+    return PAudioSample();
+}
+
+void AudioBuffer::SetTimecode(int64_t timecode)
+{
+    last_audiotime = timecode;
+}
+bool AudioBuffer::GetPause(void)
+{
+    return false;
+}
+void AudioBuffer::Pause(bool paused)
+{
+    (void)paused;
+}
+void AudioBuffer::Drain(void)
+{
+    // Do nothing
+    return;
+}
+bool AudioBuffer::IsPaused() const { return false; }
+void AudioBuffer::PauseUntilBuffered() { }
+bool AudioBuffer::IsUpmixing() { return false; }
+bool AudioBuffer::ToggleUpmix() { return false; }
+bool AudioBuffer::CanUpmix() { return false; }
+
+
+int64_t AudioBuffer::GetAudiotime(void)
+{
+    return last_audiotime;
+}
+
+int AudioBuffer::GetVolumeChannel(int) const
+{ 
+    // Do nothing
+    return 100;
+}
+void AudioBuffer::SetVolumeChannel(int, int) 
+{
+    // Do nothing
+}
+void AudioBuffer::SetVolumeAll(int)
+{
+    // Do nothing
+}
+int AudioBuffer::GetSWVolume(void)
+{
+    return 100;
+}
+void AudioBuffer::SetSWVolume(int, bool) {}
+
+
+int AudioBuffer::GetCurrentVolume(void)
+{ 
+    // Do nothing
+    return 100;
+}
+void AudioBuffer::SetCurrentVolume(int) 
+{
+    // Do nothing
+}
+void AudioBuffer::AdjustCurrentVolume(int) 
+{
+    // Do nothing
+}
+void AudioBuffer::SetMute(bool) 
+{
+    // Do nothing
+}
+void AudioBuffer::ToggleMute(void) 
+{
+    // Do nothing
+}
+MuteState AudioBuffer::GetMute(void) 
+{
+    // Do nothing
+    return kMuteOff;
+}
+MuteState AudioBuffer::IterateMutedChannels(void) 
+{
+    // Do nothing
+    return kMuteOff;
+}
+
+//  These are pure virtual in AudioOutput, but we don't need them here
+void AudioBuffer::bufferOutputData(bool){ return; }
+int AudioBuffer::readOutputData(unsigned char*, int ){ return 0; }
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/programs/mythcommflag/AudioBuffer.h b/mythtv/programs/mythcommflag/AudioBuffer.h
new file mode 100644
index 0000000..3c48f20
--- /dev/null
+++ b/mythtv/programs/mythcommflag/AudioBuffer.h
@@ -0,0 +1,125 @@
+#ifndef _AUDIOBUFFER_H_
+#define _AUDIOBUFFER_H_
+
+// POSIX headers
+#include <stdint.h>
+
+// Qt headers
+#include <QObject>
+#include <QSharedPointer>
+
+// MythTV headers
+#include "mythcontext.h"
+
+#include "audiooutput.h"
+
+#define COMM_DETECT_AUDIO 0x08
+#define COMM_DETECT_2_AUDIO (COMM_DETECT_2 | COMM_DETECT_AUDIO)
+
+//#define AUDIODEBUGGING
+
+class AudioSample : public QSharedData
+{
+public:
+    int64_t time;
+    int64_t duration;
+    double  power;
+    int     channels;
+    bool    changed;
+    AudioSample();
+    QString toString() const;
+};
+
+typedef QSharedDataPointer< AudioSample > PAudioSample;
+
+
+#define CHANNELS_MIN 1
+#define CHANNELS_MAX 8
+class AudioBuffer : public AudioOutput
+{
+ public:
+    AudioBuffer(const AudioSettings &settings);
+   ~AudioBuffer();
+
+    AudioOutputSettings* GetOutputSettings(bool /*digital*/);
+    AudioOutputSettings* GetOutputSettingsUsers(bool digital);
+    AudioOutputSettings* GetOutputSettingsCleaned(bool digital);
+
+    // reconfigure sound out for new params
+    virtual void Reconfigure(const AudioSettings &orig_settings);
+
+    void Enable();
+
+    virtual void SetEffDsp(int /* dsprate */);
+    virtual void SetBlocking(bool block);
+    virtual void Reset(void);
+    virtual bool AddFrames(void *in_buffer, int in_frames, int64_t timecode);
+    virtual bool AddData(void *in_buffer, int in_len,
+                         int64_t timecode, int in_frames);
+    const PAudioSample GetSample(int64_t time) const;
+    virtual void SetTimecode(int64_t timecode);
+    virtual bool GetPause(void);
+    virtual void Pause(bool paused);
+    virtual void Drain(void);
+    virtual bool IsPaused() const;
+    virtual void PauseUntilBuffered();
+    virtual bool IsUpmixing();
+    virtual bool ToggleUpmix();
+    virtual bool CanUpmix();
+
+    virtual int64_t GetAudiotime(void);
+    virtual int GetVolumeChannel(int) const;
+    virtual void SetVolumeChannel(int, int);
+    virtual void SetVolumeAll(int);
+    virtual int GetSWVolume(void);
+    virtual void SetSWVolume(int, bool);
+    virtual int GetCurrentVolume(void);
+    virtual void SetCurrentVolume(int);
+    virtual void AdjustCurrentVolume(int);
+    virtual void SetMute(bool);
+    virtual void ToggleMute(void);
+    virtual MuteState GetMute(void);
+    virtual MuteState IterateMutedChannels(void);
+
+    //  These are pure virtual in AudioOutput, but we don't need them here
+    virtual void bufferOutputData(bool);
+    virtual int readOutputData(unsigned char*, int );
+
+    // Basic details about the audio stream
+    int channels;
+    int codec;
+    int bytes_per_frame;
+    int output_bytes_per_frame;
+    AudioFormat format; 
+    AudioFormat output_format;
+    int samplerate;
+    int source_channels;
+    int source_samplerate;
+    int source_bytes_per_frame;
+
+    int bufsize;
+    //unsigned char *audiobuffer;
+    //int audiobuffer_len;
+    //int channels, bits, bytes_per_sample, eff_audiorate;
+    int configured_channels;
+    AudioSettings settings;
+    int64_t last_audiotime;
+
+    AudioOutputSettings* output_settings;
+
+    bool changed;
+    bool info_valid;
+
+    int64_t first_audiotime;
+
+    vector< PAudioSample > audioSamples;
+
+ private:
+    mutable QMutex m_lock;
+    bool verboseDebugging;
+    bool enabled;
+};
+
+#endif
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/programs/mythcommflag/AudioChangeDetector.cpp b/mythtv/programs/mythcommflag/AudioChangeDetector.cpp
new file mode 100644
index 0000000..63c8901
--- /dev/null
+++ b/mythtv/programs/mythcommflag/AudioChangeDetector.cpp
@@ -0,0 +1,13 @@
+using namespace std;
+
+#include "AudioChangeDetector.h"
+
+AudioChangeDetector::AudioChangeDetector()
+{
+}
+
+void AudioChangeDetector::processFrame(unsigned char *frame)
+{
+}
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/programs/mythcommflag/AudioChangeDetector.h b/mythtv/programs/mythcommflag/AudioChangeDetector.h
new file mode 100644
index 0000000..4d24215
--- /dev/null
+++ b/mythtv/programs/mythcommflag/AudioChangeDetector.h
@@ -0,0 +1,24 @@
+/*
+ * AudioChangeDetector
+ *
+ * Detect audi changes
+ */
+
+#ifndef __AUDIOCHANGEDETECTOR_H__
+#define __AUDIOCHANGEDETECTOR_H__
+
+#include "AudioChangeDetectorBase.h"
+
+class AudioChangeDetector : public AudioChangeDetectorBase
+{
+public:
+    AudioChangeDetector();
+    virtual ~AudioChangeDetector() {}
+
+    void processFrame(unsigned char *frame);
+
+};
+
+#endif  /* !__AUDIOCHANGEDETECTOR_H__ */
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/programs/mythcommflag/AudioChangeDetectorBase.cpp b/mythtv/programs/mythcommflag/AudioChangeDetectorBase.cpp
new file mode 100644
index 0000000..a4dd42d
--- /dev/null
+++ b/mythtv/programs/mythcommflag/AudioChangeDetectorBase.cpp
@@ -0,0 +1,8 @@
+
+#include "AudioChangeDetectorBase.h"
+
+AudioChangeDetectorBase::AudioChangeDetectorBase()
+{
+}
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/programs/mythcommflag/AudioChangeDetectorBase.h b/mythtv/programs/mythcommflag/AudioChangeDetectorBase.h
new file mode 100644
index 0000000..7966869
--- /dev/null
+++ b/mythtv/programs/mythcommflag/AudioChangeDetectorBase.h
@@ -0,0 +1,27 @@
+#ifndef _AUDIOCHANGEDETECTORBASE_H_
+#define _AUDIOCHANGEDETECTORBASE_H_
+
+#include <QObject>
+
+class AudioChangeDetectorBase : public QObject
+{
+    Q_OBJECT
+
+  public:
+    AudioChangeDetectorBase();
+
+    virtual void processFrame(unsigned char *frame) = 0;
+
+  signals:
+    void haveNewInformation(unsigned int framenum, bool audiochange,
+                            float amplitude,
+                            float debugValue = 0.0);
+
+  protected:
+    virtual ~AudioChangeDetectorBase() {}
+
+};
+
+#endif
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/programs/mythcommflag/ClassicCommDetector.cpp b/mythtv/programs/mythcommflag/ClassicCommDetector.cpp
index c5c40fc..061bc23 100644
--- a/mythtv/programs/mythcommflag/ClassicCommDetector.cpp
+++ b/mythtv/programs/mythcommflag/ClassicCommDetector.cpp
@@ -20,8 +20,12 @@ using namespace std;
 
 // Commercial Flagging headers
 #include "ClassicCommDetector.h"
+#ifdef USEAUDIO
+#include "AudioChangeDetector.h"
+#endif
 #include "ClassicLogoDetector.h"
 #include "ClassicSceneChangeDetector.h"
+#include "AudioBuffer.h"
 
 enum frameAspects {
     COMM_ASPECT_NORMAL = 0,
@@ -53,6 +57,14 @@ static QString toStringFrameMaskValues(int mask, bool verbose)
             msg += "aspect,";
         if (COMM_FRAME_RATING_SYMBOL & mask)
             msg += "rating,";
+#ifdef USEAUDIO
+        if (COMM_FRAME_NO_AUDIO & mask)
+            msg += "silent,";
+        if (COMM_FRAME_AUDIO_CHANGE & mask)
+            msg += "audchg,";
+        if (COMM_FRAME_INVALID_AUDIO & mask)
+            msg += "noaud,";
+#endif
 
         if (msg.length())
             msg = msg.left(msg.length() - 1);
@@ -67,6 +79,11 @@ static QString toStringFrameMaskValues(int mask, bool verbose)
         msg += (COMM_FRAME_LOGO_PRESENT  & mask) ? "L" : " ";
         msg += (COMM_FRAME_ASPECT_CHANGE & mask) ? "A" : " ";
         msg += (COMM_FRAME_RATING_SYMBOL & mask) ? "R" : " ";
+#ifdef USEAUDIO
+        msg += (COMM_FRAME_NO_AUDIO      & mask) ? "Q" : " ";
+        msg += (COMM_FRAME_AUDIO_CHANGE  & mask) ? "C" : " ";
+        msg += (COMM_FRAME_INVALID_AUDIO & mask) ? "I" : " ";
+#endif
     }
 
     return msg;
@@ -99,13 +116,17 @@ static QString toStringFrameFormats(int format, bool verbose)
 
 QString FrameInfoEntry::GetHeader(void)
 {
-    return QString("  frame     min/max/avg scene aspect format flags");
+    return QString("  frame     min/max/avg scene aspect format  apwr  achan flags");
 }
 
 QString FrameInfoEntry::toString(uint64_t frame, bool verbose) const
 {
     return QString(
+#ifdef USEAUDIO
+        "%1: %2/%3/%4 %5%  %6 %7 %8 %9 %10")
+#else
         "%1: %2/%3/%4 %5%  %6 %7 %8")
+#endif
         .arg(frame,10)
         .arg(minBrightness,3)
         .arg(maxBrightness,3)
@@ -113,6 +134,10 @@ QString FrameInfoEntry::toString(uint64_t frame, bool verbose) const
         .arg(sceneChangePercent,3)
         .arg(toStringFrameAspects(aspect, verbose))
         .arg(toStringFrameFormats(format, verbose))
+#ifdef USEAUDIO
+        .arg(audioPower,8)
+        .arg(audioMode,6)
+#endif
         .arg(toStringFrameMaskValues(flagMask, verbose));
 }
 
@@ -134,13 +159,18 @@ ClassicCommDetector::ClassicCommDetector(SkipType commDetectMethod_in,
     horizSpacing(0),                           vertSpacing(0),
     fpm(0.0),                                  blankFramesOnly(false),
     blankFrameCount(0),                        currentAspect(0),
+    silentFrameCount(0),
     totalMinBrightness(0),                     detectBlankFrames(false),
     detectSceneChanges(false),                 detectStationLogo(false),
+    detectSilentFrames(false),
     logoInfoAvailable(false),                  logoDetector(0),
     framePtr(0),                               frameIsBlank(false),
     sceneHasChanged(false),                    stationLogoPresent(false),
     lastFrameWasBlank(false),                  lastFrameWasSceneChange(false),
     decoderFoundAspectChanges(false),          sceneChangeDetector(0),
+#if USEAUDIO
+    audioChangeDetector(0),
+#endif
     player(player_in),
     startedAt(startedAt_in),                   stopsAt(stopsAt_in),
     recordingStartedAt(recordingStartedAt_in),
@@ -170,9 +200,22 @@ ClassicCommDetector::ClassicCommDetector(SkipType commDetectMethod_in,
         gCoreContext->GetNumSetting("CommDetectMinShowLength", 65);
     commDetectMaxCommLength =
         gCoreContext->GetNumSetting("CommDetectMaxCommLength", 125);
+    commDetectLargeSceneChangeThreshold =
+        gCoreContext->GetNumSetting("CommDetectLargeSceneChangeThreshold", 50);
+    QStringList commDetectCommLengthsString =
+        gCoreContext->GetSetting("CommDetectCommLengths", "15,20,30,40,60").split(',', QString::SkipEmptyParts);
+    for (QStringList::iterator it = commDetectCommLengthsString.begin(); it != commDetectCommLengthsString.end(); ++it)
+        commDetectCommLengths.append((*it).toFloat());
 
     commDetectBlankCanHaveLogo =
         !!gCoreContext->GetNumSetting("CommDetectBlankCanHaveLogo", 1);
+#ifdef USEAUDIO
+    AudioSettings settings("", "");
+    AudioOutput *audioOutput = new AudioBuffer(settings);
+    audioBuffer = ((AudioBuffer*)audioOutput);
+    player->GetAudio()->SetAudioOutput(audioOutput);
+#endif
+
 }
 
 void ClassicCommDetector::Init()
@@ -257,6 +300,16 @@ void ClassicCommDetector::Init()
          this,
          SLOT(sceneChangeDetectorHasNewInformation(unsigned int,bool,float))
     );
+#ifdef USEAUDIO
+    silentFrameCount = 0;
+    audioChangeDetector = new AudioChangeDetector();
+    connect(
+         audioChangeDetector,
+         SIGNAL(haveNewInformation(unsigned int,bool,float,float)),
+         this,
+         SLOT(audioDetectorHasNewInformation(unsigned int,bool,float,float))
+    );
+#endif
 
     frameIsBlank = false;
     stationLogoPresent = false;
@@ -278,6 +331,15 @@ void ClassicCommDetector::Init()
 
 void ClassicCommDetector::deleteLater(void)
 {
+#ifdef USEAUDIO
+    if (audioBuffer)
+    {
+        if (player && player->GetAudio())
+            player->GetAudio()->SetAudioOutput(NULL);
+        delete audioBuffer;
+        audioBuffer = NULL;
+    }
+#endif
     if (sceneChangeDetector)
         sceneChangeDetector->deleteLater();
 
@@ -289,6 +351,9 @@ void ClassicCommDetector::deleteLater(void)
 
 bool ClassicCommDetector::go()
 {
+#ifdef USEAUDIO
+    player->GetAudio()->ReinitAudio();
+#endif
     int secsSince = 0;
     int requiredBuffer = 30;
     int requiredHeadStart = requiredBuffer;
@@ -401,6 +466,14 @@ bool ClassicCommDetector::go()
 
     emit breathe();
 
+    audioBuffer->Enable();
+
+    // make sure we get a key frame before us otherwise reset doesnt happen correctly.
+    player->DiscardVideoFrame(player->GetRawVideoFrame(60));
+
+    emit breathe();
+
+    player->DiscardVideoFrame(player->GetRawVideoFrame(0));
     player->ResetTotalDuration();
 
     while (!player->GetEof())
@@ -606,8 +679,25 @@ void ClassicCommDetector::sceneChangeDetectorHasNewInformation(
     }
 
     frameInfo[framenum].sceneChangePercent = (int) (debugValue*100);
+    
+    if (verboseDebugging)
+    {
+        //LOG(VB_COMMFLAG, LOG_DEBUG, QString("Scene Change @%1 : %2 %3").arg(framenum).arg(isSceneChange).arg((int)(debugValue*100)));
+    }
 }
 
+#ifdef USEAUDIO
+void ClassicCommDetector::audioDetectorHasNewInformation(
+    unsigned int framenum, bool hasChanged, float amplitude, float debugValue)
+{
+    if (hasChanged)
+        frameInfo[framenum].flagMask |= COMM_FRAME_AUDIO_CHANGE;
+    else
+        frameInfo[framenum].flagMask &= ~COMM_FRAME_AUDIO_CHANGE;
+    frameInfo[framenum].audioMode = (int) (debugValue);
+}
+#endif
+
 void ClassicCommDetector::GetCommercialBreakList(frm_dir_map_t &marks)
 {
 
@@ -620,11 +710,12 @@ void ClassicCommDetector::GetCommercialBreakList(frm_dir_map_t &marks)
     bool blank = COMM_DETECT_BLANK & commDetectMethod;
     bool scene = COMM_DETECT_SCENE & commDetectMethod;
     bool logo  = COMM_DETECT_LOGO  & commDetectMethod;
+    bool audio = COMM_DETECT_AUDIO & commDetectMethod;
 
     if (COMM_DETECT_OFF == commDetectMethod)
         return;
 
-    if (!blank && !scene && !logo)
+    if (!blank && !scene && !logo && !audio)
     {
         LOG(VB_COMMFLAG, LOG_ERR, QString("Unexpected commDetectMethod: 0x%1")
                 .arg(commDetectMethod,0,16));
@@ -657,24 +748,33 @@ void ClassicCommDetector::GetCommercialBreakList(frm_dir_map_t &marks)
         marks = logoCommBreakMap;
     }
 
-    int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0);
-    if (cnt == 2)
+    if (audio)
+    {
+        BuildAudioFrameCommList();
+        marks = audioCommBreakMap;
+    }
+
+    int cnt = ((blank) ? 1 : 0) + ((scene) ? 1 : 0) + ((logo) ? 1 : 0) + ((audio) ? 1 : 0);
+    if (cnt >= 2)
     {
-        if (blank && scene)
+        marks.clear();
+        if (blank)
+        {
+            marks = Combine2Maps(blankCommBreakMap, marks);
+        }
+        if (scene)
         {
-            marks = commBreakMap = Combine2Maps(
-                blankCommBreakMap, sceneCommBreakMap);
+            marks = Combine2Maps(sceneCommBreakMap, marks);
         }
-        else if (blank && logo)
+        if (logo)
         {
-            marks = commBreakMap = Combine2Maps(
-                blankCommBreakMap, logoCommBreakMap);
+            marks = Combine2Maps(logoCommBreakMap, marks);
         }
-        else if (scene && logo)
+        if (audio)
         {
-            marks = commBreakMap = Combine2Maps(
-                sceneCommBreakMap, logoCommBreakMap);
+            marks = Combine2Maps(audioCommBreakMap, marks);
         }
+        commBreakMap = marks;
     }
 
     LOG(VB_COMMFLAG, LOG_INFO, "Final Commercial Break Map");
@@ -807,7 +907,7 @@ void ClassicCommDetector::ProcessFrame(VideoFrame *frame,
 
     if (commDetectMethod & COMM_DETECT_SCENE)
     {
-        sceneChangeDetector->processFrame(framePtr);
+        sceneChangeDetector->processFrame(framePtr, curFrameNumber);
     }
 
     stationLogoPresent = false;
@@ -958,6 +1058,60 @@ void ClassicCommDetector::ProcessFrame(VideoFrame *frame,
     if (stationLogoPresent)
         flagMask |= COMM_FRAME_LOGO_PRESENT;
 
+#ifdef USEAUDIO
+    if (commDetectMethod & COMM_DETECT_AUDIO)
+    {
+        if (audioBuffer)
+        {
+            // process a number of frames worth of audio
+            const AudioSample* audSample = audioBuffer->GetSample(frame->timecode);
+            int loops = 1000;
+            do
+            {
+                usleep(1000);
+                emit breathe();
+                audSample = audioBuffer->GetSample(frame->timecode);
+                if (--loops == 0)
+                    break;
+            }
+            while (audSample == NULL);
+
+            if (audSample && (audSample->power >= 0))
+            {
+                frameInfo[curFrameNumber].audioPower = audSample->power;
+                frameInfo[curFrameNumber].audioMode = audSample->channels;
+                if (audSample->changed)
+                    flagMask |= COMM_FRAME_AUDIO_CHANGE;
+                if (audSample->power < 1e-6)
+                {
+                    flagMask |= COMM_FRAME_NO_AUDIO;
+                    silentFrameCount++;
+                }
+#ifdef AUDIODEBUGGING
+                if (verboseDebugging)
+                {
+                    LOG(VB_COMMFLAG, LOG_DEBUG, QString(" video %1 audio %3")
+                        .arg(frame->timecode)
+                        .arg(audSample->toString()));
+                }
+#endif
+            }
+            else
+            {
+#ifdef AUDIODEBUGGING
+                if (verboseDebugging)
+                {
+                    LOG(VB_COMMFLAG, LOG_DEBUG, QString(" video %1")
+                        .arg(frame->timecode));
+                }
+#endif
+                frameInfo[curFrameNumber].audioPower = 0;
+                flagMask |= COMM_FRAME_INVALID_AUDIO;
+            }
+        }
+    }
+#endif
+
     //TODO: move this debugging code out of the perframe loop, and do it after
     // we've processed all frames. this is because a scenechangedetector can
     // now use a few frames to determine whether the frame a few frames ago was
@@ -968,7 +1122,11 @@ void ClassicCommDetector::ProcessFrame(VideoFrame *frame,
 
     if (verboseDebugging)
         LOG(VB_COMMFLAG, LOG_DEBUG,
+#ifdef USEAUDIO
+            QString().sprintf("Frame: %6ld -> %3d %3d %3d %3d %1d %1d %9.6f %1d %04x",
+#else
             QString().sprintf("Frame: %6ld -> %3d %3d %3d %3d %1d %1d %04x",
+#endif
                 (long)curFrameNumber,
                 frameInfo[curFrameNumber].minBrightness,
                 frameInfo[curFrameNumber].maxBrightness,
@@ -976,6 +1134,10 @@ void ClassicCommDetector::ProcessFrame(VideoFrame *frame,
                 frameInfo[curFrameNumber].sceneChangePercent,
                 frameInfo[curFrameNumber].format,
                 frameInfo[curFrameNumber].aspect,
+#ifdef USEAUDIO
+                frameInfo[curFrameNumber].audioPower,
+                frameInfo[curFrameNumber].audioMode,
+#endif
                 frameInfo[curFrameNumber].flagMask ));
 
 #ifdef SHOW_DEBUG_WIN
@@ -998,6 +1160,7 @@ void ClassicCommDetector::ClearAllMaps(void)
     blankCommBreakMap.clear();
     sceneMap.clear();
     sceneCommBreakMap.clear();
+    audioCommBreakMap.clear();
     commBreakMap.clear();
 }
 
@@ -1021,6 +1184,16 @@ void ClassicCommDetector::GetBlankCommBreakMap(frm_dir_map_t &comms)
     comms = blankCommBreakMap;
 }
 
+void ClassicCommDetector::GetAudioCommBreakMap(frm_dir_map_t &comms)
+{
+    LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::GetAudioCommBreakMap()");
+
+    if (audioCommBreakMap.isEmpty())
+        BuildAudioFrameCommList();
+
+    comms = audioCommBreakMap;
+}
+
 void ClassicCommDetector::GetSceneChangeMap(frm_dir_map_t &scenes,
                                             int64_t start_frame)
 {
@@ -1143,6 +1316,9 @@ void ClassicCommDetector::UpdateFrameBlock(FrameBlock *fbp,
 
     value = finfo.flagMask;
 
+    if (value & COMM_FRAME_BLANK)
+        fbp->bfCount++;
+
     if (value & COMM_FRAME_LOGO_PRESENT)
         fbp->logoCount++;
 
@@ -1152,6 +1328,20 @@ void ClassicCommDetector::UpdateFrameBlock(FrameBlock *fbp,
     if (value & COMM_FRAME_SCENE_CHANGE)
         fbp->scCount++;
 
+#ifdef USEAUDIO
+    if (value & COMM_FRAME_NO_AUDIO)
+        fbp->saCount++;
+
+    if (value & COMM_FRAME_AUDIO_CHANGE)
+        fbp->acCount++;
+
+    fbp->aPowerAvg += finfo.audioPower;
+    if (fbp->aPowerMin > finfo.audioPower)
+        fbp->aPowerMin = finfo.audioPower;
+    if (fbp->aPowerMax < finfo.audioPower)
+        fbp->aPowerMax = finfo.audioPower;
+#endif
+
     if (finfo.format == format)
         fbp->formatMatch++;
 
@@ -1177,8 +1367,8 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     uint64_t lastStart = 0;
     uint64_t lastEnd = 0;
     int64_t firstLogoFrame = -1;
-    bool nextFrameIsBlank = false;
     bool lastFrameWasBlank = false;
+    bool lastFrameWasSilent = false;
     uint64_t formatFrames = 0;
     int format = COMM_FORMAT_NORMAL;
     uint64_t aspectFrames = 0;
@@ -1188,9 +1378,11 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     frm_dir_map_t tmpCommMap;
     frm_dir_map_t::iterator it;
 
+    //bool preferAudioBreaks = (commDetectMethod & COMM_DETECT_AUDIO);
+
     commBreakMap.clear();
 
-    fblock = new FrameBlock[blankFrameCount + 2];
+    fblock = new FrameBlock[blankFrameCount + 2 + silentFrameCount + 2];
 
     curBlock = 0;
     curFrame = 1;
@@ -1198,6 +1390,11 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     fbp = &fblock[curBlock];
     fbp->start = 0;
     fbp->bfCount = 0;
+    fbp->saCount = 0;
+    fbp->aPowerAvg = 0;
+    fbp->aPowerMin = 1e40;
+    fbp->aPowerMax = 0;
+    fbp->acCount = 0;
     fbp->logoCount = 0;
     fbp->ratingCount = 0;
     fbp->scCount = 0;
@@ -1207,6 +1404,7 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     fbp->score = 0;
 
     lastFrameWasBlank = true;
+    lastFrameWasSilent = true;
 
     if (decoderFoundAspectChanges)
     {
@@ -1245,52 +1443,59 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
         }
     }
 
+#define SPLIT_MODE 2
     while (curFrame <= framesProcessed)
     {
         value = frameInfo[curFrame].flagMask;
 
-        if (((curFrame + 1) <= framesProcessed) &&
-            (frameInfo[curFrame + 1].flagMask & COMM_FRAME_BLANK))
-            nextFrameIsBlank = true;
-        else
-            nextFrameIsBlank = false;
+        bool newBlockMask = false;
+        bool lastSilentFrameState = lastFrameWasSilent;
+        lastFrameWasSilent = value & COMM_FRAME_NO_AUDIO;
+        newBlockMask |= (lastSilentFrameState != lastFrameWasSilent);
 
-        if (value & COMM_FRAME_BLANK)
-        {
-            fbp->bfCount++;
-
-            if (!nextFrameIsBlank || !lastFrameWasBlank)
-            {
-                UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
-
-                fbp->end = curFrame;
-                fbp->frames = fbp->end - fbp->start + 1;
-                fbp->length = fbp->frames / fps;
-
-                if ((fbp->scCount) && (fbp->length > 1.05))
-                    fbp->scRate = fbp->scCount / fbp->length;
-
-                curBlock++;
-
-                fbp = &fblock[curBlock];
-                fbp->bfCount = 1;
-                fbp->logoCount = 0;
-                fbp->ratingCount = 0;
-                fbp->scCount = 0;
-                fbp->scRate = 0.0;
-                fbp->score = 0;
-                fbp->formatMatch = 0;
-                fbp->aspectMatch = 0;
-                fbp->start = curFrame;
-            }
+        bool lastBlankFrameState = lastFrameWasBlank;
+        lastFrameWasBlank = value & COMM_FRAME_BLANK;
+#if SPLIT_MODE == 1
+        newBlockMask |= (lastBlankFrameState != lastFrameWasBlank);
+#elif SPLIT_MODE == 2
+        // transition only when both are set
+        newBlockMask = (lastSilentFrameState & lastBlankFrameState) != (lastFrameWasSilent & lastFrameWasBlank);
 
-            lastFrameWasBlank = true;
-        }
-        else
+        if ((frameInfo[curFrame].sceneChangePercent < 50) && lastFrameWasSilent && !lastFrameWasBlank)
         {
-            lastFrameWasBlank = false;
+            newBlockMask |= true;
         }
+#endif
 
+        if (newBlockMask)
+        {
+            fbp->end = curFrame - 1;
+            fbp->frames = fbp->end - fbp->start + 1;
+            fbp->length = fbp->frames / fps;
+
+            fbp->aPowerAvg /= fbp->frames;
+
+            if ((fbp->scCount) && (fbp->length > 1.05))
+                fbp->scRate = fbp->scCount / fbp->length;
+
+            curBlock++;
+
+            fbp = &fblock[curBlock];
+            fbp->bfCount = 0;
+            fbp->saCount = 0;
+            fbp->acCount = 0;
+            fbp->aPowerAvg = 0;
+            fbp->aPowerMin = 1e40;
+            fbp->aPowerMax = 0;
+            fbp->logoCount = 0;
+            fbp->ratingCount = 0;
+            fbp->scCount = 0;
+            fbp->scRate = 0.0;
+            fbp->score = 0;
+            fbp->formatMatch = 0;
+            fbp->aspectMatch = 0;
+            fbp->start = curFrame;
+        }
         UpdateFrameBlock(fbp, frameInfo[curFrame], format, aspect);
 
         if ((value & COMM_FRAME_LOGO_PRESENT) &&
@@ -1300,10 +1505,12 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
         curFrame++;
     }
 
-    fbp->end = curFrame;
+    fbp->end = curFrame - 1;
     fbp->frames = fbp->end - fbp->start + 1;
     fbp->length = fbp->frames / fps;
 
+    fbp->aPowerAvg /= fbp->frames;
+
     if ((fbp->scCount) && (fbp->length > 1.05))
         fbp->scRate = fbp->scCount / fbp->length;
 
@@ -1314,24 +1521,55 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     LOG(VB_COMMFLAG, LOG_INFO, "Initial Block pass");
     LOG(VB_COMMFLAG, LOG_DEBUG,
         "Block StTime StFrm  EndFrm Frames Secs    "
-        "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
+        "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch SA Cnt AC Cnt AudPower Score");
     LOG(VB_COMMFLAG, LOG_INFO,
         "----- ------ ------ ------ ------ ------- "
-        "--- ------ ------ ------ ----- ------ ------ -----");
+        "--- ------ ------ ------ ----- ------ ------ ------ -------- -----");
     while (curBlock <= maxBlock)
     {
         fbp = &fblock[curBlock];
 
         msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
-                    "%5.2f %6d %6d %5d",
+                    "%5.2f %6d %6d %6d %6d %8f %8f %8f %5d",
                     curBlock, (int)(fbp->start / fps) / 60,
                     (int)((fbp->start / fps )) % 60,
                     fbp->start, fbp->end, fbp->frames, fbp->length,
                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
                     fbp->scCount, fbp->scRate, fbp->formatMatch,
-                    fbp->aspectMatch, fbp->score);
+                    fbp->aspectMatch, fbp->saCount, fbp->acCount, fbp->aPowerAvg, fbp->aPowerMin, fbp->aPowerMax, fbp->score);
         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
 
+#if SPLIT_MODE == 1 
+        if ((fbp->saCount >= 2) && (fbp->bfCount >= 2))
+        {
+            for(int i=0; i<5; i++)
+            {
+                if (curBlock+1 > maxBlock)
+                    break;
+                FrameBlock *fbp2 = &fblock[curBlock + i];
+                if ((fbp2->saCount > 0) || (fbp2->bfCount > 0))
+                    continue;
+                if (fbp2->frames < fps)
+                    continue;
+                if (fbp2->frames > commDetectMaxCommLength)
+                {
+                    if (verboseDebugging)
+                        LOG(VB_COMMFLAG, LOG_DEBUG,
+                            QString("      blank+silent length @+%1 > max comm length, +10").arg(i));
+                    fbp2->score += 10;
+                }
+                if (fbp2->frames > commDetectMaxCommBreakLength)
+                {
+                    if (verboseDebugging)
+                        LOG(VB_COMMFLAG, LOG_DEBUG,
+                            QString("      blank+silent length @+%1 > max comm break length, +20").arg(i));
+                    fbp2->score += 20;
+                }
+                break;
+            }
+        }
+#endif
+
         if (fbp->frames > fps)
         {
             if (verboseDebugging)
@@ -1379,11 +1617,12 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
             }
 
             if ((logoInfoAvailable) &&
-                (fbp->logoCount < (fbp->frames * 0.50)))
+                (fbp->logoCount < (fbp->frames * 0.50)) &&
+                (fbp->bfCount < (fbp->frames * 0.10)))
             {
                 if (verboseDebugging)
                     LOG(VB_COMMFLAG, LOG_DEBUG,
-                        "      logoInfoAvailable && logoCount < frames * .50, "
+                        "      logoInfoAvailable && logoCount < frames * .50 && blanks < frames * 0.1, "
                         "-10");
                 fbp->score -= 10;
             }
@@ -1397,6 +1636,7 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
             }
 
             if ((fbp->scRate > 1.0) &&
+                (fbp->bfCount < (fbp->frames * 0.50)) &&
                 (fbp->logoCount < (fbp->frames * .90)))
             {
                 if (verboseDebugging)
@@ -1421,14 +1661,17 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
                 fbp->score -= 20;
             }
 
-            if ((abs((int)(fbp->frames - (15 * fps))) < 5 ) ||
-                (abs((int)(fbp->frames - (30 * fps))) < 6 ) ||
-                (abs((int)(fbp->frames - (60 * fps))) < 8 ))
+            // check for common comm break lengths
+            for(QList<float>::iterator lit = commDetectCommLengths.begin(); lit != commDetectCommLengths.end(); ++lit)
             {
-                if (verboseDebugging)
-                    LOG(VB_COMMFLAG, LOG_DEBUG,
-                        "      block appears to be standard comm length, -10");
-                fbp->score -= 10;
+                if (abs(fbp->frames - (*lit * fps) + fps/2) < (fps/2))
+                {
+                    if (verboseDebugging)
+                        LOG(VB_COMMFLAG, LOG_DEBUG,
+                            "      block appears to be standard comm length, -10");
+                    fbp->score -= 10;
+                    break;
+                }
             }
         }
         else
@@ -1476,13 +1719,13 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
         }
 
         msg.sprintf("  NOW %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
-                    "%5.2f %6d %6d %5d",
+                    "%5.2f %6d %6d %6d %6d %8f %8f %8f %5d",
                     (int)(fbp->start / fps) / 60,
                     (int)((fbp->start / fps )) % 60,
                     fbp->start, fbp->end, fbp->frames, fbp->length,
                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
                     fbp->scCount, fbp->scRate, fbp->formatMatch,
-                    fbp->aspectMatch, fbp->score);
+                    fbp->aspectMatch, fbp->saCount, fbp->acCount, fbp->aPowerAvg, fbp->aPowerMin, fbp->aPowerMax, fbp->score);
         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
 
         lastScore = fbp->score;
@@ -1496,22 +1739,22 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     LOG(VB_COMMFLAG, LOG_INFO, "Second Block pass");
     LOG(VB_COMMFLAG, LOG_DEBUG,
         "Block StTime StFrm  EndFrm Frames Secs    "
-        "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
+        "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch SA Cnt AC Cnt AudPower Score");
     LOG(VB_COMMFLAG, LOG_DEBUG,
         "----- ------ ------ ------ ------ ------- "
-        "--- ------ ------ ------ ----- ------ ------ -----");
+        "--- ------ ------ ------ ----- ------ ------ ------ ------ -------- -----");
     while (curBlock <= maxBlock)
     {
         fbp = &fblock[curBlock];
 
         msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
-                    "%5.2f %6d %6d %5d",
+                    "%5.2f %6d %6d %6d %6d %8f %8f %8f %5d",
                     curBlock, (int)(fbp->start / fps) / 60,
                     (int)((fbp->start / fps )) % 60,
                     fbp->start, fbp->end, fbp->frames, fbp->length,
                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
                     fbp->scCount, fbp->scRate, fbp->formatMatch,
-                    fbp->aspectMatch, fbp->score);
+                    fbp->aspectMatch, fbp->saCount, fbp->acCount, fbp->aPowerAvg, fbp->aPowerMin, fbp->aPowerMax, fbp->score);
         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
 
         if ((curBlock > 0) && (curBlock < maxBlock))
@@ -1537,6 +1780,16 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
                         "lastScore < 0 && nextScore < 0, setting -10");
                 fbp->score -= 10;
             }
+            if ((fbp->saCount > (fbp->frames * 0.95)) &&
+                (fbp->frames < (2*fps)) &&
+                (lastScore < 0 && nextScore < 0))
+            {
+                if (verboseDebugging)
+                    LOG(VB_COMMFLAG, LOG_DEBUG,
+                        "      silent > frames * 0.95 && frames < 2*fps && "
+                        "lastScore < 0 && nextScore < 0, setting -10");
+                fbp->score -= 10;
+            }
 
             if ((fbp->frames < (120*fps)) &&
                 (lastScore < 0) &&
@@ -1602,13 +1855,13 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
         }
 
         msg.sprintf("  NOW %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
-                    "%5.2f %6d %6d %5d",
+                    "%5.2f %6d %6d %6d %6d %8f %8f %8f %5d",
                     (int)(fbp->start / fps) / 60,
                     (int)((fbp->start / fps )) % 60,
                     fbp->start, fbp->end, fbp->frames, fbp->length,
                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
                     fbp->scCount, fbp->scRate, fbp->formatMatch,
-                    fbp->aspectMatch, fbp->score);
+                    fbp->aspectMatch, fbp->saCount, fbp->acCount, fbp->aPowerAvg, fbp->aPowerMin, fbp->aPowerMax, fbp->score);
         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
 
         lastScore = fbp->score;
@@ -1619,10 +1872,10 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
     LOG(VB_COMMFLAG, LOG_INFO, "FINAL Block stats");
     LOG(VB_COMMFLAG, LOG_DEBUG,
         "Block StTime StFrm  EndFrm Frames Secs    "
-        "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch Score");
+        "Bf  Lg Cnt RT Cnt SC Cnt SC Rt FmtMch AspMch SA Cnt AC Cnt AudPower Score");
     LOG(VB_COMMFLAG, LOG_DEBUG,
         "----- ------ ------ ------ ------ ------- "
-        "--- ------ ------ ------ ----- ------ ------ -----");
+        "--- ------ ------ ------ ----- ------ ------ ------ ------ -------- -----");
     curBlock = 0;
     lastScore = 0;
     breakStart = -1;
@@ -1780,13 +2033,13 @@ void ClassicCommDetector::BuildAllMethodsCommList(void)
         }
 
         msg.sprintf("%5d %3d:%02d %6ld %6ld %6ld %7.2f %3d %6d %6d %6d "
-                    "%5.2f %6d %6d %5d",
+                    "%5.2f %6d %6d %6d %6d %8f %8f %8f %5d",
                     curBlock, (int)(fbp->start / fps) / 60,
                     (int)((fbp->start / fps )) % 60,
                     fbp->start, fbp->end, fbp->frames, fbp->length,
                     fbp->bfCount, fbp->logoCount, fbp->ratingCount,
                     fbp->scCount, fbp->scRate, fbp->formatMatch,
-                    fbp->aspectMatch, thisScore);
+                    fbp->aspectMatch, fbp->saCount, fbp->acCount, fbp->aPowerAvg, fbp->aPowerMin, fbp->aPowerMax, thisScore);
         LOG(VB_COMMFLAG, LOG_DEBUG, msg);
 
         lastScore = thisScore;
@@ -2033,6 +2286,13 @@ void ClassicCommDetector::BuildBlankFrameCommList(void)
                 .arg(it.key()).arg(*it));
 }
 
+void ClassicCommDetector::BuildAudioFrameCommList(void)
+{
+    LOG(VB_COMMFLAG, LOG_INFO, "CommDetect::BuildBlankFrameCommList()");
+
+    audioCommBreakMap.clear();
+    // TODO
+}
 
 void ClassicCommDetector::BuildSceneChangeCommList(void)
 {
diff --git a/mythtv/programs/mythcommflag/ClassicCommDetector.h b/mythtv/programs/mythcommflag/ClassicCommDetector.h
index f9e5c4c..adcfd32 100644
--- a/mythtv/programs/mythcommflag/ClassicCommDetector.h
+++ b/mythtv/programs/mythcommflag/ClassicCommDetector.h
@@ -20,6 +20,11 @@ class MythPlayer;
 class LogoDetectorBase;
 class SceneChangeDetectorBase;
 
+#ifdef USEAUDIO
+class AudioChangeDetectorBase;
+class AudioBuffer;
+#endif
+
 enum frameMaskValues {
     COMM_FRAME_SKIPPED       = 0x0001,
     COMM_FRAME_BLANK         = 0x0002,
@@ -27,6 +32,11 @@ enum frameMaskValues {
     COMM_FRAME_LOGO_PRESENT  = 0x0008,
     COMM_FRAME_ASPECT_CHANGE = 0x0010,
     COMM_FRAME_RATING_SYMBOL = 0x0020
+#ifdef USEAUDIO
+    ,COMM_FRAME_NO_AUDIO     = 0x0100
+    ,COMM_FRAME_AUDIO_CHANGE = 0x0200
+    ,COMM_FRAME_INVALID_AUDIO = 0x0400
+#endif
 };
 
 class FrameInfoEntry
@@ -38,6 +48,10 @@ class FrameInfoEntry
     int sceneChangePercent;
     int aspect;
     int format;
+#ifdef USEAUDIO
+    double audioPower;
+    int audioMode;
+#endif
     int flagMask;
     static QString GetHeader(void);
     QString toString(uint64_t frame, bool verbose) const;
@@ -80,6 +94,11 @@ class ClassicCommDetector : public CommDetectorBase
             long frames;
             double length;
             int bfCount;
+            int saCount;
+            int acCount;
+            double aPowerAvg;
+            double aPowerMin;
+            double aPowerMax;
             int logoCount;
             int ratingCount;
             int scCount;
@@ -93,6 +112,8 @@ class ClassicCommDetector : public CommDetectorBase
         void ClearAllMaps(void);
         void GetBlankCommMap(frm_dir_map_t &comms);
         void GetBlankCommBreakMap(frm_dir_map_t &comms);
+        void GetSilentCommMap(frm_dir_map_t &comms);
+        void GetAudioCommBreakMap(frm_dir_map_t &comms);
         void GetSceneChangeMap(frm_dir_map_t &scenes,
                                int64_t start_frame);
         frm_dir_map_t Combine2Maps(
@@ -101,6 +122,7 @@ class ClassicCommDetector : public CommDetectorBase
                               int format, int aspect);
         void BuildAllMethodsCommList(void);
         void BuildBlankFrameCommList(void);
+        void BuildAudioFrameCommList(void);
         void BuildSceneChangeCommList(void);
         void BuildLogoCommList();
         void MergeBlankCommList(void);
@@ -128,6 +150,8 @@ class ClassicCommDetector : public CommDetectorBase
         int commDetectMinShowLength;
         int commDetectMaxCommLength;
         bool commDetectBlankCanHaveLogo;
+        int commDetectLargeSceneChangeThreshold;
+        QList<float> commDetectCommLengths;
 
         bool verboseDebugging;
 
@@ -142,6 +166,7 @@ class ClassicCommDetector : public CommDetectorBase
         bool blankFramesOnly;
         int blankFrameCount;
         int currentAspect;
+        int silentFrameCount;
 
 
         int totalMinBrightness;
@@ -149,6 +174,7 @@ class ClassicCommDetector : public CommDetectorBase
         bool detectBlankFrames;
         bool detectSceneChanges;
         bool detectStationLogo;
+        bool detectSilentFrames;
 
         bool logoInfoAvailable;
         LogoDetectorBase* logoDetector;
@@ -158,6 +184,8 @@ class ClassicCommDetector : public CommDetectorBase
         frm_dir_map_t blankFrameMap;
         frm_dir_map_t blankCommMap;
         frm_dir_map_t blankCommBreakMap;
+        frm_dir_map_t silentFrameMap;
+        frm_dir_map_t audioCommBreakMap;
         frm_dir_map_t sceneMap;
         frm_dir_map_t sceneCommBreakMap;
         frm_dir_map_t commBreakMap;
@@ -172,6 +200,9 @@ class ClassicCommDetector : public CommDetectorBase
         bool decoderFoundAspectChanges;
 
         SceneChangeDetectorBase* sceneChangeDetector;
+#if USEAUDIO
+        AudioChangeDetectorBase* audioChangeDetector;
+#endif
 
 protected:
         MythPlayer *player;
@@ -191,9 +222,16 @@ protected:
         void SetVideoParams(float aspect);
         void ProcessFrame(VideoFrame *frame, long long frame_number);
         QMap<long long, FrameInfoEntry> frameInfo;
+#ifdef USEAUDIO
+        AudioBuffer *audioBuffer;
+        int64_t audioFrame;
+#endif
 
 public slots:
         void sceneChangeDetectorHasNewInformation(unsigned int framenum, bool isSceneChange,float debugValue);
+#ifdef USEAUDIO
+        void audioDetectorHasNewInformation(unsigned int framenum, bool hasChanged, float amplitude, float debugValue);
+#endif
 };
 
 #endif
diff --git a/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp b/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp
index c449353..a626061 100644
--- a/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp
+++ b/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.cpp
@@ -1,6 +1,9 @@
 #include <algorithm>
 using namespace std;
 
+// MythTV headers
+#include "mythcontext.h"
+
 #include "ClassicSceneChangeDetector.h"
 #include "Histogram.h"
 
@@ -16,6 +19,8 @@ ClassicSceneChangeDetector::ClassicSceneChangeDetector(unsigned int width,
 {
     histogram = new Histogram;
     previousHistogram = new Histogram;
+    commDetectSceneChangeThreshold =
+        gCoreContext->GetNumSetting("CommDetectSceneChangeThreshold", 60)/100.0;
 }
 
 void ClassicSceneChangeDetector::deleteLater(void)
@@ -25,14 +30,14 @@ void ClassicSceneChangeDetector::deleteLater(void)
     SceneChangeDetectorBase::deleteLater();
 }
 
-void ClassicSceneChangeDetector::processFrame(unsigned char* frame)
+void ClassicSceneChangeDetector::processFrame(unsigned char* frame, long long frameNumber)
 {
     histogram->generateFromImage(frame, width, height, commdetectborder,
                                  width-commdetectborder, commdetectborder,
                                  height-commdetectborder, xspacing, yspacing);
     float similar = histogram->calculateSimilarityWith(*previousHistogram);
 
-    bool isSceneChange = (similar < .85 && !previousFrameWasSceneChange);
+    bool isSceneChange = (similar < commDetectSceneChangeThreshold && !previousFrameWasSceneChange);
 
     emit(haveNewInformation(frameNumber,isSceneChange,similar));
     previousFrameWasSceneChange = isSceneChange;
diff --git a/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h b/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h
index f4d2200..81b0127 100644
--- a/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h
+++ b/mythtv/programs/mythcommflag/ClassicSceneChangeDetector.h
@@ -13,7 +13,7 @@ class ClassicSceneChangeDetector : public SceneChangeDetectorBase
         unsigned int yspacing);
     virtual void deleteLater(void);
 
-    void processFrame(unsigned char* frame);
+    void processFrame(unsigned char* frame, long long frameNumber);
 
   private:
     ~ClassicSceneChangeDetector() {}
@@ -25,6 +25,7 @@ class ClassicSceneChangeDetector : public SceneChangeDetectorBase
     bool previousFrameWasSceneChange;
     unsigned int xspacing, yspacing;
     unsigned int commdetectborder;
+    double commDetectSceneChangeThreshold;
 };
 
 #endif
diff --git a/mythtv/programs/mythcommflag/SceneChangeDetectorBase.h b/mythtv/programs/mythcommflag/SceneChangeDetectorBase.h
index 67296d5..f901407 100644
--- a/mythtv/programs/mythcommflag/SceneChangeDetectorBase.h
+++ b/mythtv/programs/mythcommflag/SceneChangeDetectorBase.h
@@ -11,7 +11,7 @@ class SceneChangeDetectorBase : public QObject
     SceneChangeDetectorBase(unsigned int w, unsigned int h) :
         width(w), height(h) {}
 
-    virtual void processFrame(unsigned char *frame) = 0;
+    virtual void processFrame(unsigned char *frame, long long frameNumber) = 0;
 
   signals:
     void haveNewInformation(unsigned int framenum, bool scenechange,
diff --git a/mythtv/programs/mythcommflag/main.cpp b/mythtv/programs/mythcommflag/main.cpp
index bbba950..479b8d7 100644
--- a/mythtv/programs/mythcommflag/main.cpp
+++ b/mythtv/programs/mythcommflag/main.cpp
@@ -44,6 +44,7 @@ using namespace std;
 #include "CommDetectorFactory.h"
 #include "SlotRelayer.h"
 #include "CustomEventRelayer.h"
+#include "AudioBuffer.h"
 
 #define LOC      QString("MythCommFlag: ")
 #define LOC_WARN QString("MythCommFlag, Warning: ")
@@ -107,11 +108,13 @@ static QMap<QString,SkipTypes> *init_skip_types(void)
     (*tmp)["blankscene"]  = COMM_DETECT_BLANK_SCENE;
     (*tmp)["blank_scene"] = COMM_DETECT_BLANK_SCENE;
     (*tmp)["logo"]        = COMM_DETECT_LOGO;
-    (*tmp)["all"]         = COMM_DETECT_ALL;
+    (*tmp)["audio"]       = (SkipTypes)COMM_DETECT_AUDIO;
+    (*tmp)["all"]         = (SkipTypes)(COMM_DETECT_ALL | COMM_DETECT_AUDIO);
     (*tmp)["d2"]          = COMM_DETECT_2;
     (*tmp)["d2_logo"]     = COMM_DETECT_2_LOGO;
     (*tmp)["d2_blank"]    = COMM_DETECT_2_BLANK;
     (*tmp)["d2_scene"]    = COMM_DETECT_2_SCENE;
+    (*tmp)["d2_audio"]    = (SkipTypes)COMM_DETECT_2_AUDIO;
     (*tmp)["d2_all"]      = COMM_DETECT_2_ALL;
     return tmp;
 }
diff --git a/mythtv/programs/mythcommflag/mythcommflag.pro b/mythtv/programs/mythcommflag/mythcommflag.pro
index b7242cf..d66bbe1 100644
--- a/mythtv/programs/mythcommflag/mythcommflag.pro
+++ b/mythtv/programs/mythcommflag/mythcommflag.pro
@@ -8,6 +8,7 @@ target.path = $${PREFIX}/bin
 INSTALLS = target
 
 QMAKE_CLEAN += $(TARGET)
+DEFINES += USEAUDIO
 
 # Input
 HEADERS += CommDetectorFactory.h CommDetectorBase.h
@@ -31,6 +32,9 @@ HEADERS += LogoDetectorBase.h SceneChangeDetectorBase.h
 HEADERS += SlotRelayer.h CustomEventRelayer.h
 HEADERS += commandlineparser.h
 
+HEADERS += AudioChangeDetectorBase.h AudioChangeDetector.h
+HEADERS += AudioBuffer.h
+
 SOURCES += CommDetectorFactory.cpp CommDetectorBase.cpp
 SOURCES += ClassicLogoDetector.cpp
 SOURCES += ClassicSceneChangeDetector.cpp
@@ -47,6 +51,8 @@ SOURCES += HistogramAnalyzer.cpp
 SOURCES += BlankFrameDetector.cpp
 SOURCES += SceneChangeDetector.cpp
 SOURCES += PrePostRollFlagger.cpp
+SOURCES += AudioChangeDetectorBase.cpp AudioChangeDetector.cpp
+SOURCES += AudioBuffer.cpp
 
 SOURCES += main.cpp commandlineparser.cpp
 
