Index: libs/libmyth/libmyth.pro
===================================================================
--- libs/libmyth/libmyth.pro	(revision 9048)
+++ libs/libmyth/libmyth.pro	(working copy)
@@ -34,11 +34,14 @@
 SOURCES += virtualkeyboard.cpp mythobservable.cpp
 
 INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../..
+INCLUDEPATH += ../libavutil ..
 DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch
+DEPENDPATH += ../libavutil ../libavcodec
 
 
 LIBS += -L../libmythsamplerate -lmythsamplerate-$${LIBVERSION}
 LIBS += -L../libmythsoundtouch -lmythsoundtouch-$${LIBVERSION}
+LIBS += -L../libavcodec -lmythavcodec-$${LIBVERSION}
 
 isEmpty(QMAKE_EXTENSION_SHLIB) {
   QMAKE_EXTENSION_SHLIB=so
Index: libs/libmyth/audiooutput.h
===================================================================
--- libs/libmyth/audiooutput.h	(revision 9048)
+++ libs/libmyth/audiooutput.h	(working copy)
@@ -30,8 +30,12 @@
     virtual ~AudioOutput() { };
 
     // reconfigure sound out for new params
-    virtual void Reconfigure(int audio_bits, int audio_channels,
-                             int audio_samplerate, bool audio_passthru) = 0;
+    virtual void Reconfigure(int audio_bits, 
+                             int audio_channels, 
+                             int audio_samplerate,
+                             bool audio_passthru,
+                             void* audio_codec = NULL
+                             ) = 0;
     
     virtual void SetStretchFactor(float factor);
 
@@ -73,6 +77,8 @@
         lastError = msg;
         VERBOSE(VB_IMPORTANT, "AudioOutput Error: " + lastError);
     }
+    void ClearError()
+     { lastError = QString::null; };
 
     void Warn(QString msg)
     {
Index: libs/libmyth/audiooutputdx.h
===================================================================
--- libs/libmyth/audiooutputdx.h	(revision 9048)
+++ libs/libmyth/audiooutputdx.h	(working copy)
@@ -22,7 +22,10 @@
 
     virtual void Reset(void);
     virtual void Reconfigure(int audio_bits, 
-                         int audio_channels, int audio_samplerate);
+                         int audio_channels, 
+                         int audio_samplerate,
+                         bool audio_passthru,
+                         AudioCodecMode aom = AUDIOCODECMODE_NORMAL);
     virtual void SetBlocking(bool blocking);
 
     virtual bool AddSamples(char *buffer, int samples, long long timecode);
Index: libs/libmyth/audiooutputdx.cpp
===================================================================
--- libs/libmyth/audiooutputdx.cpp	(revision 9048)
+++ libs/libmyth/audiooutputdx.cpp	(working copy)
@@ -119,8 +119,12 @@
     // FIXME: kedl: not sure what else could be required here?
 }
 
-void AudioOutputDX::Reconfigure(int audio_bits, int audio_channels,
-                                int audio_samplerate, int audio_passthru)
+void AudioOutputDX::Reconfigure(int audio_bits, 
+                                int audio_channels, 
+                                int audio_samplerate,
+                                int audio_passthru,
+                                AudioCodecMode laom
+                                )
 {
     if (dsbuffer)
         DestroyDSBuffer();
Index: libs/libmyth/audiooutputbase.h
===================================================================
--- libs/libmyth/audiooutputbase.h	(revision 9048)
+++ libs/libmyth/audiooutputbase.h	(working copy)
@@ -12,8 +12,14 @@
 #include "samplerate.h"
 #include "SoundTouch.h"
 
-#define AUDBUFSIZE 768000
+struct AVCodecContext;
+class DigitalEncoder;
 
+//#define AUDBUFSIZE 768000
+//divisible by 12,10,8,6,4,2 and around 1024000
+//#define AUDBUFSIZE 1024080
+#define AUDBUFSIZE 1536000
+
 class AudioOutputBase : public AudioOutput
 {
  public:
@@ -24,8 +30,11 @@
     virtual ~AudioOutputBase();
 
     // reconfigure sound out for new params
-    virtual void Reconfigure(int audio_bits, int audio_channels,
-                             int audio_samplerate, bool audio_passthru);
+    virtual void Reconfigure(int audio_bits, 
+                             int audio_channels, 
+                             int audio_samplerate,
+                             bool audio_passthru,
+                             void* audio_codec = NULL);
     
     // do AddSamples calls block?
     virtual void SetBlocking(bool blocking);
@@ -109,6 +118,7 @@
 
     float audio_stretchfactor;
     AudioOutputSource source;
+    AVCodecContext *audio_codec;
 
     bool killaudio;
 
@@ -116,6 +126,8 @@
     bool set_initial_vol;
     bool buffer_output_data_for_use; //  used by AudioOutputNULL
     
+    int configured_audio_channels;
+
  private:
     // resampler
     bool need_resampler;
@@ -126,6 +138,7 @@
 
     // timestretch
     soundtouch::SoundTouch * pSoundStretch;
+    DigitalEncoder * encoder;
 
     bool blocking; // do AddSamples calls block?
 
@@ -141,14 +154,14 @@
 
     pthread_mutex_t avsync_lock; /* must hold avsync_lock to read or write
                                     'audiotime' and 'audiotime_updated' */
-    int audiotime; // timecode of audio leaving the soundcard (same units as
+    long long audiotime; // timecode of audio leaving the soundcard (same units as
                    //                                          timecodes) ...
     struct timeval audiotime_updated; // ... which was last updated at this time
 
     /* Audio circular buffer */
     unsigned char audiobuffer[AUDBUFSIZE];  /* buffer */
     int raud, waud;     /* read and write positions */
-    int audbuf_timecode;    /* timecode of audio most recently placed into
+    long long audbuf_timecode;    /* timecode of audio most recently placed into
                    buffer */
 
     int numlowbuffer;
Index: libs/libmyth/audiooutputbase.cpp
===================================================================
--- libs/libmyth/audiooutputbase.cpp	(revision 9048)
+++ libs/libmyth/audiooutputbase.cpp	(working copy)
@@ -12,7 +12,344 @@
 #include <sys/time.h>
 #include <unistd.h>
 
+extern "C" {
+#include "libavcodec/avcodec.h"
+#include "libavcodec/liba52/a52.h"
+}
 
+#if QT_VERSION < 0x030200
+#define LONGLONGCONVERT (long)
+#else
+#define LONGLONGCONVERT
+#endif
+
+#define LOC QString("DEnc: ");
+#define MAX_AC3_FRAME_SIZE 6144
+class DigitalEncoder
+{
+public:
+    DigitalEncoder();
+    ~DigitalEncoder();
+    void Dispose();
+    bool DigitalEncoder::Init(CodecID codec_id, int bitrate, int samplerate, int channels);
+    size_t Encode(short * buff);
+
+    // if needed
+    char * GetFrameBuffer() 
+    { 
+        if (!frame_buffer && av_context)
+        {
+            frame_buffer = new char [one_frame_bytes];
+        }
+        return frame_buffer; 
+    }    
+    size_t FrameSize() const { return one_frame_bytes; }
+    char * GetOutBuff() const { return outbuf; }
+
+    size_t audio_bytes_per_sample;
+private:
+    AVCodecContext *av_context;
+    char * outbuf;
+    char * frame_buffer;
+    int outbuf_size;
+    size_t one_frame_bytes;
+};
+
+DigitalEncoder::DigitalEncoder()
+{
+    av_context = NULL;
+    outbuf = NULL;
+    outbuf_size = 0;
+    one_frame_bytes = 0;
+    frame_buffer = NULL;
+}
+
+DigitalEncoder::~DigitalEncoder()
+{
+    Dispose();
+}
+
+void DigitalEncoder::Dispose()
+{
+    if (av_context)
+    {
+        avcodec_close(av_context);
+        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 DigitalEncoder::Init(CodecID codec_id, int bitrate, int samplerate, int channels)
+{
+    AVCodec * codec;
+    int ret;
+
+    VERBOSE(VB_AUDIO, QString("DigitalEncoder::Init codecid=%1, br=%2, sr=%3, ch=%4")
+            .arg(codec_id_string(codec_id))
+            .arg(bitrate)
+            .arg(samplerate)
+            .arg(channels));
+    //codec = avcodec_find_encoder(codec_id);
+    // always AC3 as there is no DTS encoder at the moment 2005/1/9
+    codec = avcodec_find_encoder(CODEC_ID_AC3);
+    if (!codec)
+    {
+        VERBOSE(VB_IMPORTANT,"Error: could not find codec");
+        return false;
+    }
+    av_context = avcodec_alloc_context();
+    av_context->bit_rate = bitrate;
+    av_context->sample_rate = samplerate;
+    av_context->channels = channels;
+    // open it */
+    if ((ret = avcodec_open(av_context, codec)) < 0) 
+    {
+        VERBOSE(VB_IMPORTANT,"Error: could not open codec, invalid bitrate or samplerate");
+        Dispose();
+        return false;
+    }
+
+    size_t bytes_per_frame = av_context->channels * sizeof(short);
+    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)
+            .arg(one_frame_bytes)
+           );
+
+    return true;
+}
+
+static int DTS_SAMPLEFREQS[16] =
+{
+    0,      8000,   16000,  32000,  64000,  128000, 11025,  22050,
+    44100,  88200,  176400, 12000,  24000,  48000,  96000,  192000
+};
+
+static int DTS_BITRATES[30] =
+{
+    32000,    56000,    64000,    96000,    112000,   128000,
+    192000,   224000,   256000,   320000,   384000,   448000,
+    512000,   576000,   640000,   768000,   896000,   1024000,
+    1152000,  1280000,  1344000,  1408000,  1411200,  1472000,
+    1536000,  1920000,  2048000,  3072000,  3840000,  4096000
+};
+
+static int dts_decode_header(uint8_t *indata_ptr, int *rate,
+                             int *nblks, int *sfreq)
+{
+    uint id = ((indata_ptr[0] << 24) | (indata_ptr[1] << 16) |
+               (indata_ptr[2] << 8)  | (indata_ptr[3]));
+
+    if (id != 0x7ffe8001)
+        return -1;
+
+    int ftype = indata_ptr[4] >> 7;
+
+    int surp = (indata_ptr[4] >> 2) & 0x1f;
+    surp = (surp + 1) % 32;
+
+    *nblks = (indata_ptr[4] & 0x01) << 6 | (indata_ptr[5] >> 2);
+    ++*nblks;
+
+    int fsize = (indata_ptr[5] & 0x03) << 12 |
+                (indata_ptr[6]         << 4) | (indata_ptr[7] >> 4);
+    ++fsize;
+
+    *sfreq = (indata_ptr[8] >> 2) & 0x0f;
+    *rate = (indata_ptr[8] & 0x03) << 3 | ((indata_ptr[9] >> 5) & 0x07);
+
+    if (ftype != 1)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: Termination frames not handled (ftype %1)")
+                .arg(ftype));
+        return -1;
+    }
+
+    if (*sfreq != 13)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: Only 48kHz supported (sfreq %1)").arg(*sfreq));
+        return -1;
+    }
+
+    if ((fsize > 8192) || (fsize < 96))
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: fsize: %1 invalid").arg(fsize));
+        return -1;
+    }
+
+    if (*nblks != 8 && *nblks != 16 && *nblks != 32 &&
+        *nblks != 64 && *nblks != 128 && ftype == 1)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: nblks %1 not valid for normal frame")
+                .arg(*nblks));
+        return -1;
+    }
+
+    return fsize;
+}
+
+static int dts_syncinfo(uint8_t *indata_ptr, int * /*flags*/,
+                        int *sample_rate, int *bit_rate)
+{
+    int nblks;
+    int rate;
+    int sfreq;
+
+    int fsize = dts_decode_header(indata_ptr, &rate, &nblks, &sfreq);
+    if (fsize >= 0)
+    {
+        if (rate >= 0 && rate <= 29)
+            *bit_rate = DTS_BITRATES[rate];
+        else
+            *bit_rate = 0;
+        if (sfreq >= 1 && sfreq <= 15)
+            *sample_rate = DTS_SAMPLEFREQS[sfreq];
+        else
+            *sample_rate = 0;
+    }
+    return fsize;
+}
+
+static int encode_frame(
+        bool dts, 
+        unsigned char *data,
+        size_t &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
+    // the receiver will have enough sense to do that.  if someone has a
+    // receiver that doesn't, here would be a good place to put in a call
+    // to a52_crc16_block(samples+2, data_size-2) - but what do we do if the
+    // packet is bad?  we'd need to send something that the receiver would
+    // ignore, and if so, may as well just assume that it will ignore
+    // anything with a bad CRC...
+
+    uint nr_samples = 0, block_len;
+    if (dts)
+    {
+        enc_len = dts_syncinfo(data+8, &flags, &sample_rate, &bit_rate);
+        int rate, sfreq, nblks;
+        dts_decode_header(data+8, &rate, &nblks, &sfreq);
+        nr_samples = nblks * 32;
+        block_len = nr_samples * 2 * 2;
+    }
+    else
+    {
+        enc_len = a52_syncinfo(data+8, &flags, &sample_rate, &bit_rate);
+        block_len = MAX_AC3_FRAME_SIZE;
+    }
+
+    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(data+8, data+8, enc_len);
+    //VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+    //        QString("DigitalEncoder::Encode swab test %1 %2")
+    //        .arg(x,0,16).arg(*(uint32_t*)(data+8),0,16));
+
+    // the following values come from libmpcodecs/ad_hwac3.c in mplayer.
+    // they form a valid IEC958 AC3 header.
+    data[0] = 0x72;
+    data[1] = 0xF8;
+    data[2] = 0x1F;
+    data[3] = 0x4E;
+    data[4] = 0x01;
+    if (dts)
+    {
+        switch(nr_samples)
+        {
+            case 512:
+                data[4] = 0x0B;      /* DTS-1 (512-sample bursts) */
+                break;
+
+            case 1024:
+                data[4] = 0x0C;      /* DTS-2 (1024-sample bursts) */
+                break;
+
+            case 2048:
+                data[4] = 0x0D;      /* DTS-3 (2048-sample bursts) */
+                break;
+
+            default:
+                VERBOSE(VB_IMPORTANT, LOC +
+                        QString("DTS: %1-sample bursts not supported")
+                        .arg(nr_samples));
+                data[4] = 0x00;
+                break;
+        }
+    }
+    data[5] = 0x00;
+    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 DigitalEncoder::Encode(short * buff)
+{
+    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)
+           );
+
+    return outsize;
+}
+#undef LOC
+#define LOC QString("AO: ")
+
 AudioOutputBase::AudioOutputBase(QString audiodevice, int, 
                                  int, int,
                                  AudioOutputSource source,
@@ -31,14 +368,16 @@
     current_seconds = -1;
     source_bitrate = -1;
     audio_stretchfactor = 1.0;
+    audio_codec = NULL;
     pSoundStretch = NULL;
+    encoder = NULL;
     blocking = false;
     this->source = source;
     this->set_initial_vol = set_initial_vol;
     soundcard_buffer_size = 0;
     buffer_output_data_for_use = false; // used by AudioOutputNULL
+    configured_audio_channels = gContext->GetNumSetting("MaxChannels", 2);
 
-
     src_ctx = NULL;
 
     // You need to call the next line from your concrete class.
@@ -80,8 +419,35 @@
             VERBOSE(VB_GENERAL, QString("Using time stretch %1")
                                         .arg(audio_stretchfactor));
             pSoundStretch = new soundtouch::SoundTouch();
-            pSoundStretch->setSampleRate(audio_samplerate);
-            pSoundStretch->setChannels(audio_channels);
+            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 DigitalEncoder();
+                    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 (encoder)
+            {
+                pSoundStretch->setSampleRate(audio_codec->sample_rate);
+                pSoundStretch->setChannels(audio_codec->channels);
+            }
+            else
+            {
+                pSoundStretch->setSampleRate(audio_samplerate);
+                pSoundStretch->setChannels(audio_channels);
+            }
 
             pSoundStretch->setTempo(audio_stretchfactor);
             pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 35);
@@ -104,11 +470,31 @@
 }
 
 void AudioOutputBase::Reconfigure(int laudio_bits, int laudio_channels, 
-                                 int laudio_samplerate, bool laudio_passthru)
+                                 int laudio_samplerate, bool laudio_passthru,
+                                 void* laudio_codec)
 {
+    int codec_id = CODEC_ID_NONE;
+    int lcodec_id = CODEC_ID_NONE;
+    int lcchannels = 0;
+    int cchannels = 0;
+    if (laudio_codec)
+    {
+        lcodec_id = ((AVCodecContext*)laudio_codec)->codec_id;
+        laudio_bits = 16;
+        laudio_channels = 2;
+        laudio_samplerate = 48000;
+        lcchannels = ((AVCodecContext*)laudio_codec)->channels;
+    }
+    if (audio_codec)
+    {
+        codec_id = audio_codec->codec_id;
+        cchannels = ((AVCodecContext*)audio_codec)->channels;
+    }
+    ClearError();
     if (laudio_bits == audio_bits && laudio_channels == audio_channels &&
-        laudio_samplerate == audio_samplerate &&
-        laudio_passthru == audio_passthru && !need_resampler)
+        laudio_samplerate == audio_samplerate && !need_resampler &&
+        laudio_passthru == audio_passthru &&
+        lcodec_id == codec_id && lcchannels == cchannels)
         return;
 
     KillAudio();
@@ -120,9 +506,11 @@
     waud = raud = 0;
     audio_actually_paused = false;
     
+    bool redo_stretch = (pSoundStretch && audio_channels != laudio_channels);
     audio_channels = laudio_channels;
     audio_bits = laudio_bits;
     audio_samplerate = laudio_samplerate;
+    audio_codec = (AVCodecContext*)laudio_codec;
     audio_passthru = laudio_passthru;
     if (audio_bits != 8 && audio_bits != 16)
     {
@@ -141,15 +529,17 @@
     
     numlowbuffer = 0;
 
-    VERBOSE(VB_GENERAL, QString("Opening audio device '%1'.")
-            .arg(audiodevice));
+    VERBOSE(VB_GENERAL, QString("Opening audio device '%1'. ch %2 sr %3")
+            .arg(audiodevice).arg(audio_channels).arg(audio_samplerate));
     
     // Actually do the device specific open call
     if (!OpenDevice())
     {
-        VERBOSE(VB_AUDIO, "Aborting reconfigure");
         pthread_mutex_unlock(&avsync_lock);
         pthread_mutex_unlock(&audio_buflock);
+        if (GetError().isEmpty())
+            Error("Aborting reconfigure");
+        VERBOSE(VB_AUDIO, "Aborting reconfigure");
         return;
     }
 
@@ -171,6 +561,7 @@
     current_seconds = -1;
     source_bitrate = -1;
 
+    // NOTE: this wont do anything as above samplerate vars are set equal
     // Check if we need the resampler
     if (audio_samplerate != laudio_samplerate)
     {
@@ -194,13 +585,54 @@
     }
 
     VERBOSE(VB_AUDIO, 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"));
 
-    SetStretchFactorLocked(audio_stretchfactor);
-    if (pSoundStretch)
+    if (redo_stretch)
     {
-        pSoundStretch->setSampleRate(audio_samplerate);
-        pSoundStretch->setChannels(audio_channels);
+        float laudio_stretchfactor = audio_stretchfactor;
+        delete pSoundStretch;
+        pSoundStretch = NULL;
+        audio_stretchfactor = 0.0;
+        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 DigitalEncoder();
+                    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 (encoder)
+            {
+                pSoundStretch->setSampleRate(audio_codec->sample_rate);
+                pSoundStretch->setChannels(audio_codec->channels);
+            }
+            else
+            {
+                pSoundStretch->setSampleRate(audio_samplerate);
+                pSoundStretch->setChannels(audio_channels);
+            }
+        }
+    }
 
     // Setup visualisations, zero the visualisations buffers
     prepareVisuals();
@@ -246,6 +678,12 @@
         pSoundStretch = NULL;
     }
 
+    if (encoder)
+    {
+        delete encoder;
+        encoder = NULL;
+    }
+
     CloseDevice();
 
     killAudioLock.unlock();
@@ -259,6 +697,7 @@
 
 void AudioOutputBase::Pause(bool paused)
 {
+    VERBOSE(VB_AUDIO, LOC+ QString("Pause %0").arg(paused));
     pauseaudio = paused;
     audio_actually_paused = false;
 }
@@ -339,7 +778,7 @@
        The reason is that computing 'audiotime' requires acquiring the audio 
        lock, which the video thread should not do. So, we call 'SetAudioTime()'
        from the audio thread, and then call this from the video thread. */
-    int ret;
+    long long ret;
     struct timeval now;
 
     if (audiotime == 0)
@@ -351,12 +790,23 @@
 
     ret = (now.tv_sec - audiotime_updated.tv_sec) * 1000;
     ret += (now.tv_usec - audiotime_updated.tv_usec) / 1000;
-    ret = (int)(ret * audio_stretchfactor);
+    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)
+            .arg(audiotime_updated.tv_sec).arg(audiotime_updated.tv_usec)
+            .arg(ret)
+            .arg(audiotime)
+            .arg(audio_stretchfactor)
+           );
+#endif
+
     ret += audiotime;
 
     pthread_mutex_unlock(&avsync_lock);
-    return ret;
+    return (int)ret;
 }
 
 void AudioOutputBase::SetAudiotime(void)
@@ -393,15 +843,33 @@
     // include algorithmic latencies
     if (pSoundStretch)
     {
+        // if encoder is active, then use its idea of audiobytes
+        //size_t abps = encoder?encoder->audio_bytes_per_sample:audio_bytes_per_sample;
+
+        // 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);
     }
-               
+
     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")
+            .arg(audiotime_updated.tv_sec).arg(audiotime_updated.tv_usec)
+            .arg(audiotime)
+            .arg(audbuf_timecode)
+            .arg(totalbuffer)
+            .arg(soundcard_buffer)
+            .arg(effdspstretched)
+            .arg(audio_bytes_per_sample)
+            .arg(audio_stretchfactor)
+           );
+#endif
 
     pthread_mutex_unlock(&avsync_lock);
     pthread_mutex_unlock(&audio_buflock);
@@ -461,13 +929,18 @@
     // NOTE: This function is not threadsafe
 
     int afree = audiofree(true);
-    int len = samples * audio_bytes_per_sample;
+    int len = samples * (encoder?encoder->audio_bytes_per_sample:audio_bytes_per_sample);
 
     // Check we have enough space to write the data
     if (need_resampler && src_ctx)
         len = (int)ceilf(float(len) * src_data.src_ratio);
     if ((len > afree) && !blocking)
+    {
+        VERBOSE(VB_AUDIO|VB_TIMESTAMP, QString("AddSamples FAILED bytes=%1, used=%2, free=%3, timecode=%4")
+            .arg(len)
+            .arg(AUDBUFSIZE-afree).arg(afree).arg(LONGLONGCONVERT timecode));
         return false; // would overflow
+    }
 
     // resample input if necessary
     if (need_resampler && src_ctx) 
@@ -501,23 +974,26 @@
 
 int AudioOutputBase::WaitForFreeSpace(int samples)
 {
-    int len = samples * audio_bytes_per_sample;
+    int abps = encoder?encoder->audio_bytes_per_sample:audio_bytes_per_sample;
+    int len = samples * abps;
     int afree = audiofree(false);
 
     while (len > afree)
     {
         if (blocking)
         {
-            VERBOSE(VB_AUDIO, "Waiting for free space");
+            VERBOSE(VB_AUDIO|VB_TIMESTAMP, "Waiting for free space");
             // wait for more space
             pthread_cond_wait(&audio_bufsig, &audio_buflock);
             afree = audiofree(false);
         }
         else
         {
-            VERBOSE(VB_IMPORTANT, "Audio buffer overflow, audio data lost!");
-            samples = afree / audio_bytes_per_sample;
-            len = samples * audio_bytes_per_sample;
+            VERBOSE(VB_IMPORTANT, 
+                    QString("Audio buffer overflow, %1 audio samples lost!")
+                        .arg(samples-afree / abps));
+            samples = afree / abps;
+            len = samples * abps;
             if (src_ctx) 
             {
                 int error = src_reset(src_ctx);
@@ -542,9 +1018,11 @@
     
     int afree = audiofree(false);
 
-    VERBOSE(VB_AUDIO, QString("_AddSamples bytes=%1, used=%2, free=%3, timecode=%4")
-            .arg(samples * audio_bytes_per_sample)
-            .arg(AUDBUFSIZE-afree).arg(afree).arg((long)timecode));
+    int abps = encoder?encoder->audio_bytes_per_sample:audio_bytes_per_sample;
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP, QString("_AddSamples samples=%1 bytes=%2, used=%3, free=%4, timecode=%5")
+            .arg(samples)
+            .arg(samples * abps)
+            .arg(AUDBUFSIZE-afree).arg(afree).arg(LONGLONGCONVERT timecode));
     
     len = WaitForFreeSpace(samples);
 
@@ -581,52 +1059,98 @@
 
     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/audio_bytes_per_sample;
+        int nSamplesToEnd = bdiff/abps;
         if (bdiff < len)
         {
             pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)(audiobuffer + 
                                       org_waud), nSamplesToEnd);
             pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer,
-                                      (len - bdiff) / audio_bytes_per_sample);
+                                      (len - bdiff) / abps);
         }
         else
         {
             pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)(audiobuffer + 
-                                      org_waud), len / audio_bytes_per_sample);
+                                      org_waud), len / abps);
         }
 
-        int newLen = 0;
-        int nSamples;
-        len = WaitForFreeSpace(pSoundStretch->numSamples() * 
-                               audio_bytes_per_sample);
-        do 
+        if (encoder)
         {
-            int samplesToGet = len/audio_bytes_per_sample;
-            if (samplesToGet > nSamplesToEnd)
+            // pull out a packet's worth and reencode it until we dont 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)
             {
-                samplesToGet = nSamplesToEnd;    
+                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 == 0)
+                    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);
+                bdiff = AUDBUFSIZE - amount;
+                org_waud += amount;
             }
-
-            nSamples = pSoundStretch->receiveSamples((soundtouch::SAMPLETYPE*)
-                                      (audiobuffer + org_waud), samplesToGet);
-            if (nSamples == nSamplesToEnd)
+        }
+        else
+        {
+            int newLen = 0;
+            int nSamples;
+            len = WaitForFreeSpace(pSoundStretch->numSamples() * 
+                                   audio_bytes_per_sample);
+            do 
             {
-                org_waud = 0;
-                nSamplesToEnd = AUDBUFSIZE/audio_bytes_per_sample;
-            }
-            else
-            {
-                org_waud += nSamples * audio_bytes_per_sample;
-                nSamplesToEnd -= nSamples;
-            }
+                int samplesToGet = len/audio_bytes_per_sample;
+                if (samplesToGet > nSamplesToEnd)
+                {
+                    samplesToGet = nSamplesToEnd;    
+                }
 
-            newLen += nSamples * audio_bytes_per_sample;
-            len -= nSamples * audio_bytes_per_sample;
-        } while (nSamples > 0);
+                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);
+        }
     }
 
     waud = org_waud;
@@ -696,7 +1220,7 @@
             space_on_soundcard = getSpaceOnSoundcard();
 
             if (space_on_soundcard != last_space_on_soundcard) {
-                VERBOSE(VB_AUDIO, QString("%1 bytes free on soundcard")
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP, QString("%1 bytes free on soundcard")
                         .arg(space_on_soundcard));
                 last_space_on_soundcard = space_on_soundcard;
             }
@@ -709,7 +1233,7 @@
                     WriteAudio(zeros, fragment_size);
                 } else {
                     // this should never happen now -dag
-                    VERBOSE(VB_AUDIO,
+                    VERBOSE(VB_AUDIO|VB_TIMESTAMP,
                             QString("waiting for space on soundcard "
                                     "to write zeros: have %1 need %2")
                             .arg(space_on_soundcard).arg(fragment_size));
@@ -745,12 +1269,12 @@
         if (fragment_size > audiolen(true))
         {
             if (audiolen(true) > 0)  // only log if we're sending some audio
-                VERBOSE(VB_AUDIO,
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP,
                         QString("audio waiting for buffer to fill: "
                                 "have %1 want %2")
                         .arg(audiolen(true)).arg(fragment_size));
 
-            VERBOSE(VB_AUDIO, "Broadcasting free space avail");
+            //VERBOSE(VB_AUDIO|VB_TIMESTAMP, "Broadcasting free space avail");
             pthread_mutex_lock(&audio_buflock);
             pthread_cond_broadcast(&audio_bufsig);
             pthread_mutex_unlock(&audio_buflock);
@@ -764,7 +1288,7 @@
         if (fragment_size > space_on_soundcard)
         {
             if (space_on_soundcard != last_space_on_soundcard) {
-                VERBOSE(VB_AUDIO,
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP,
                         QString("audio waiting for space on soundcard: "
                                 "have %1 need %2")
                         .arg(space_on_soundcard).arg(fragment_size));
@@ -826,7 +1350,7 @@
 
         /* update raud */
         raud = (raud + fragment_size) % AUDBUFSIZE;
-        VERBOSE(VB_AUDIO, "Broadcasting free space avail");
+        //VERBOSE(VB_AUDIO|VB_TIMESTAMP, "Broadcasting free space avail");
         pthread_cond_broadcast(&audio_bufsig);
 
         written_size = fragment_size;
Index: libs/libmyth/audiooutputalsa.cpp
===================================================================
--- libs/libmyth/audiooutputalsa.cpp	(revision 9048)
+++ libs/libmyth/audiooutputalsa.cpp	(working copy)
@@ -82,8 +82,10 @@
     }
     else
     {
-        fragment_size = 6144; // nicely divisible by 2,4,6,8 channels @ 16-bits
-        buffer_time = 500000;  // .5 seconds
+        //fragment_size = 6144; // nicely divisible by 2,4,6,8 channels @ 16-bits
+        //fragment_size = 3072*audio_channels; // nicely divisible by 2,4,6,8 channels @ 16-bits
+        fragment_size = (audio_bits * audio_channels * audio_samplerate) / (8*30);
+        buffer_time = 100000;  // .5 seconds
         period_time = buffer_time / 4;  // 4 interrupts per buffer
     }
 
@@ -155,7 +157,7 @@
     
     tmpbuf = aubuf;
 
-    VERBOSE(VB_AUDIO, QString("WriteAudio: Preparing %1 bytes (%2 frames)")
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP, QString("WriteAudio: Preparing %1 bytes (%2 frames)")
             .arg(size).arg(frames));
     
     while (frames > 0) 
Index: libs/libmythsoundtouch/TDStretch.cpp
===================================================================
--- libs/libmythsoundtouch/TDStretch.cpp	(revision 9048)
+++ libs/libmythsoundtouch/TDStretch.cpp	(working copy)
@@ -96,6 +96,7 @@
 
     pMidBuffer = NULL;
     pRefMidBufferUnaligned = NULL;
+    midBufferLength = 0;
     overlapLength = 0;
 
     setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
@@ -108,8 +109,12 @@
 
 TDStretch::~TDStretch()
 {
-    delete[] pMidBuffer;
-    delete[] pRefMidBufferUnaligned;
+    if (midBufferLength)
+    {
+        delete[] pMidBuffer;
+        delete[] pRefMidBufferUnaligned;
+        midBufferLength = 0;
+    }
 }
 
 
@@ -196,9 +201,9 @@
 
 void TDStretch::clearMidBuffer()
 {
-    if (bMidBufferDirty) 
+    if (bMidBufferDirty && midBufferLength) 
     {
-        memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength);
+        memset(pMidBuffer, 0, channels * sizeof(SAMPLETYPE) * overlapLength);
         bMidBufferDirty = FALSE;
     }
 }
@@ -239,6 +244,21 @@
 // Seeks for the optimal overlap-mixing position.
 uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
 {
+#ifdef MULTICHANNEL
+    if (channels > 2) 
+    {
+        // stereo sound
+        if (bQuickseek) 
+        {
+            return seekBestOverlapPositionMultiQuick(refPos);
+        } 
+        else 
+        {
+            return seekBestOverlapPositionMulti(refPos);
+        }
+    } 
+    else 
+#endif
     if (channels == 2) 
     {
         // stereo sound
@@ -272,6 +292,13 @@
 // of 'ovlPos'.
 inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const
 {
+#ifdef MULTICHANNEL
+    if (channels > 2) 
+    {
+        overlapMulti(output, input + channels * ovlPos);
+    }
+    else 
+#endif
     if (channels == 2) 
     {
         // stereo sound
@@ -285,12 +312,109 @@
 
 
 
+#ifdef MULTICHANNEL
 // Seeks for the optimal overlap-mixing position. The 'stereo' version of the
 // routine
 //
 // The best position is determined as the position where the two overlapped
 // sample sequences are 'most alike', in terms of the highest cross-correlation
 // value over the overlapping period
+uint TDStretch::seekBestOverlapPositionMulti(const SAMPLETYPE *refPos) 
+{
+    uint bestOffs;
+    LONG_SAMPLETYPE bestCorr, corr;
+    uint i;
+
+    // Slopes the amplitudes of the 'midBuffer' samples
+    precalcCorrReference();
+
+    bestCorr = INT_MIN;
+    bestOffs = 0;
+
+    // Scans for the best correlation value by testing each possible position
+    // over the permitted range.
+    for (i = 0; i < seekLength; i ++) 
+    {
+        // Calculates correlation value for the mixing position corresponding
+        // to 'i'
+        corr = calcCrossCorrMulti(refPos + channels * i, pRefMidBuffer);
+
+        // Checks for the highest correlation value
+        if (corr > bestCorr) 
+        {
+            bestCorr = corr;
+            bestOffs = i;
+        }
+    }
+    // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+    clearCrossCorrState();
+
+    return bestOffs;
+}
+
+
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+uint TDStretch::seekBestOverlapPositionMultiQuick(const SAMPLETYPE *refPos) 
+{
+    uint j;
+    uint bestOffs;
+    LONG_SAMPLETYPE bestCorr, corr;
+    uint scanCount, corrOffset, tempOffset;
+
+    // Slopes the amplitude of the 'midBuffer' samples
+    precalcCorrReference();
+
+    bestCorr = INT_MIN;
+    bestOffs = 0;
+    corrOffset = 0;
+    tempOffset = 0;
+
+    // Scans for the best correlation value using four-pass hierarchical search.
+    //
+    // The look-up table 'scans' has hierarchical position adjusting steps.
+    // In first pass the routine searhes for the highest correlation with 
+    // relatively coarse steps, then rescans the neighbourhood of the highest
+    // correlation with better resolution and so on.
+    for (scanCount = 0;scanCount < 4; scanCount ++) 
+    {
+        j = 0;
+        while (scanOffsets[scanCount][j]) 
+        {
+            tempOffset = corrOffset + scanOffsets[scanCount][j];
+            if (tempOffset >= seekLength) break;
+
+            // Calculates correlation value for the mixing position corresponding
+            // to 'tempOffset'
+            corr = calcCrossCorrMulti(refPos + channels * tempOffset, pRefMidBuffer);
+
+            // Checks for the highest correlation value
+            if (corr > bestCorr) 
+            {
+                bestCorr = corr;
+                bestOffs = tempOffset;
+            }
+            j ++;
+        }
+        corrOffset = bestOffs;
+    }
+    // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+    clearCrossCorrState();
+
+    return bestOffs;
+}
+#endif
+
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
 uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) 
 {
     uint bestOffs;
@@ -512,7 +636,11 @@
 void TDStretch::setChannels(uint numChannels)
 {
     if (channels == numChannels) return;
+#ifdef MULTICHANNEL
+    assert(numChannels >= 1 && numChannels <= MULTICHANNEL);
+#else
     assert(numChannels == 1 || numChannels == 2);
+#endif
 
     channels = numChannels;
     inputBuffer.setChannels(channels);
@@ -635,21 +763,23 @@
 /// Set new overlap length parameter & reallocate RefMidBuffer if necessary.
 void TDStretch::acceptNewOverlapLength(uint newOverlapLength)
 {
-    uint prevOvl;
-
-    prevOvl = overlapLength;
     overlapLength = newOverlapLength;
 
-    if (overlapLength > prevOvl)
+    if (overlapLength*channels > midBufferLength)
     {
-        delete[] pMidBuffer;
-        delete[] pRefMidBufferUnaligned;
+        if (midBufferLength)
+        {
+            delete[] pMidBuffer;
+            delete[] pRefMidBufferUnaligned;
+            midBufferLength = 0;
+        }
 
-        pMidBuffer = new SAMPLETYPE[overlapLength * 2];
+        midBufferLength = overlapLength * channels;
+        pMidBuffer = new SAMPLETYPE[midBufferLength];
         bMidBufferDirty = TRUE;
         clearMidBuffer();
 
-        pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)];
+        pRefMidBufferUnaligned = new SAMPLETYPE[midBufferLength + 16 / sizeof(SAMPLETYPE)];
         // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency
         pRefMidBuffer = (SAMPLETYPE *)((((ulong)pRefMidBufferUnaligned) + 15) & -16);
     }
@@ -718,8 +848,31 @@
 
 #ifdef INTEGER_SAMPLES
 
+#ifdef MULTICHANNEL
 // Slopes the amplitude of the 'midBuffer' samples so that cross correlation
 // is faster to calculate
+void TDStretch::precalcCorrReference()
+{
+    int i,j;
+    int temp, temp2;
+    short *src = pMidBuffer;
+    short *dest = pRefMidBuffer;
+
+    for (i=0 ; i < (int)overlapLength ;i ++) 
+    {
+        temp = i * (overlapLength - i);
+
+        for(j=0;j<channels;j++)
+        {
+            temp2 = (*src++ * temp) / slopingDivider;
+            *dest++ = (short)(temp2);
+        }
+    }
+}
+#endif
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
 void TDStretch::precalcCorrReferenceStereo()
 {
     int i, cnt2;
@@ -772,7 +925,28 @@
     }
 }
 
+#ifdef MULTICHANNEL
+// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' 
+// version of the routine.
+void TDStretch::overlapMulti(short *output, const short *input) const
+{
+    int i,j;
+    short temp;
+    //uint cnt2;
+    const short *ip = input;
+    short *op = output;
+    const short *md = pMidBuffer;
 
+    for (i = 0; i < (int)overlapLength ; i ++) 
+    {
+        temp = (short)(overlapLength - i);
+        for(j=0;j<channels;j++)
+            *op++ = (*ip++ * i + *md++ * temp )  / overlapLength;
+    }
+}
+#endif
+
+
 /// Calculates overlap period length in samples.
 /// Integer version rounds overlap length to closest power of 2
 /// for a divide scaling operation.
@@ -824,6 +998,22 @@
     return corr;
 }
 
+#ifdef MULTICHANNEL
+long TDStretch::calcCrossCorrMulti(const short *mixingPos, const short *compare) const
+{
+    long corr;
+    uint i;
+
+    corr = 0;
+    for (i = channels; i < channels * overlapLength; i++) 
+    {
+        corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
+    }
+
+    return corr;
+}
+#endif
+
 #endif // INTEGER_SAMPLES
 
 //////////////////////////////////////////////////////////////////////////////
@@ -931,4 +1121,4 @@
     return corr;
 }
 
-#endif // FLOAT_SAMPLES
\ No newline at end of file
+#endif // FLOAT_SAMPLES
Index: libs/libmythsoundtouch/TDStretch.h
===================================================================
--- libs/libmythsoundtouch/TDStretch.h	(revision 9048)
+++ libs/libmythsoundtouch/TDStretch.h	(working copy)
@@ -48,6 +48,10 @@
 #include "RateTransposer.h"
 #include "FIFOSamplePipe.h"
 
+#ifdef MULTICHANNEL
+#define USE_MULTI_MMX
+#endif
+
 namespace soundtouch
 {
 
@@ -100,6 +104,7 @@
     SAMPLETYPE *pMidBuffer;
     SAMPLETYPE *pRefMidBuffer;
     SAMPLETYPE *pRefMidBufferUnaligned;
+    uint midBufferLength;
     uint overlapLength;
     uint overlapDividerBits;
     uint slopingDivider;
@@ -123,21 +128,34 @@
     virtual void clearCrossCorrState();
     void calculateOverlapLength(uint overlapMs);
 
+#ifdef MULTICHANNEL
+    virtual LONG_SAMPLETYPE calcCrossCorrMulti(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
+#endif
     virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
     virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
 
+#ifdef MULTICHANNEL
+    virtual uint seekBestOverlapPositionMulti(const SAMPLETYPE *refPos);
+    virtual uint seekBestOverlapPositionMultiQuick(const SAMPLETYPE *refPos);
+#endif
     virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos);
     virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos);
     virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos);
     virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos);
     uint seekBestOverlapPosition(const SAMPLETYPE *refPos);
 
+#ifdef MULTICHANNEL
+    virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const;
+#endif
     virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
     virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
 
     void clearMidBuffer();
     void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
 
+#ifdef MULTICHANNEL
+    void precalcCorrReference();
+#endif
     void precalcCorrReferenceMono();
     void precalcCorrReferenceStereo();
 
@@ -225,6 +243,11 @@
     class TDStretchMMX : public TDStretch
     {
     protected:
+#ifdef USE_MULTI_MMX
+#ifdef MULTICHANNEL
+        long calcCrossCorrMulti(const short *mixingPos, const short *compare) const;
+#endif
+#endif
         long calcCrossCorrStereo(const short *mixingPos, const short *compare) const;
         virtual void overlapStereo(short *output, const short *input) const;
         virtual void clearCrossCorrState();
@@ -237,6 +260,9 @@
     class TDStretch3DNow : public TDStretch
     {
     protected:
+#ifdef MULTICHANNEL
+        //double calcCrossCorrMulti(const float *mixingPos, const float *compare) const;
+#endif
         double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
     };
 #endif /// ALLOW_3DNOW
@@ -247,6 +273,9 @@
     class TDStretchSSE : public TDStretch
     {
     protected:
+#ifdef MULTICHANNEL
+        //double calcCrossCorrMulti(const float *mixingPos, const float *compare) const;
+#endif
         double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
     };
 
Index: libs/libmythsoundtouch/RateTransposer.cpp
===================================================================
--- libs/libmythsoundtouch/RateTransposer.cpp	(revision 9048)
+++ libs/libmythsoundtouch/RateTransposer.cpp	(working copy)
@@ -330,7 +330,11 @@
 {
     if (uChannels == numchannels) return;
 
+#ifdef MULTICHANNEL
+    assert(numchannels >= 1 && numchannels <= MULTICHANNEL);
+#else
     assert(numchannels == 1 || numchannels == 2);
+#endif
     uChannels = numchannels;
 
     storeBuffer.setChannels(uChannels);
Index: libs/libmythsoundtouch/mmx_gcc.cpp
===================================================================
--- libs/libmythsoundtouch/mmx_gcc.cpp	(revision 9048)
+++ libs/libmythsoundtouch/mmx_gcc.cpp	(working copy)
@@ -141,6 +141,124 @@
     return tmp;
 }
 
+#ifdef USE_MULTI_MMX
+// Calculates cross correlation of two buffers
+long TDStretchMMX::calcCrossCorrMulti(const short *pV1, const short *pV2) const
+{
+    //static const unsigned long long int mm_half __attribute__ ((aligned(8))) = 0xffffffffULL;
+    static const __m64 mm_mask[4][8] __attribute__ ((aligned(8))) = {
+        {
+            // even bit
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0,
+            0,
+            0,
+            0
+        },
+        {
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0x0000ffffffffffffULL,
+            0,
+            0,
+            0,
+            0
+        },
+        {
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0x00000000ffffffffULL,
+            0,
+            0,
+            0,
+            0
+        },
+        {
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0xffffffffffffffffULL,
+            0x000000000000ffffULL,
+            0,
+            0,
+            0,
+            0
+        }
+    };
+    uint tmp; 
+    uint adjustedOverlapLength = overlapLength*channels;
+    uint counter = ((adjustedOverlapLength+15)>>4)-1;    // load counter to counter = overlapLength / 8 - 1
+    uint remainder = (16-adjustedOverlapLength)&0xf;     // since there are 1/3 sample per 1/2 quadword
+
+    __m64 *ph = (__m64*)&mm_mask[remainder&3][remainder>>2];
+    __m64 *pv1=(__m64*)pV1, *pv2=(__m64*)pV2;
+    GI(__m64 m0, m1, m2, m3, m4, m5, m6); // temporaries
+    uint shift = overlapDividerBits;
+
+    // prepare to the first round by loading 
+    SI(m1 = pv1[0],             movq_a2r(0, pv1, mm1)); // load m1 = pv1[0]
+    SI(m2 = pv1[1],             movq_a2r(8, pv1, mm2)); // load m2 = pv1[1]
+    SI(m0 = _mm_setzero_si64(), pxor_r2r(mm0, mm0));    // clear m0
+    SI(m5 = _mm_cvtsi32_si64(shift),movd_v2r(shift, mm5));   // shift in 64bit reg
+
+    do {
+        // Calculate cross-correlation between the tempOffset and tmpbid_buffer.
+        // Process 4 parallel batches of 2 * stereo samples each during one
+        // round to improve CPU-level parallellization.
+        SI(m1 = _mm_madd_pi16(m1, pv2[0]),pmaddwd_a2r(0, pv2, mm1)); // multiply-add m1 = m1 * pv2[0]
+        SI(m3 = pv1[2],                   movq_a2r(16, pv1, mm3));   // load mm3 = pv1[2]
+        SI(m2 = _mm_madd_pi16(m2, pv2[1]),pmaddwd_a2r(8, pv2, mm2)); // multiply-add m2 = m2 * pv2[1]
+        SI(m4 = pv1[3],                   movq_a2r(24, pv1, mm4));   // load mm4 = pv1[3]
+        SI(m3 = _mm_madd_pi16(m3, pv2[2]),pmaddwd_a2r(16, pv2, mm3));// multiply-add m3 = m3 * pv2[2]
+        SI(m2 = _mm_add_pi32(m2, m1),     paddd_r2r(mm1, mm2));      // add m2 += m1
+        SI(m4 = _mm_madd_pi16(m4, pv2[3]),pmaddwd_a2r(24, pv2, mm4));// multiply-add m4 = m4 * pv2[3]
+        SI(m1 = pv1[4],                   movq_a2r(32, pv1, mm1));   // mm1 = pv1[0] for next round
+        SI(m2 = _mm_srai_pi32(m2, m5),    psrad_r2r(mm5, mm2));      // m2 >>= shift (mm5)
+        pv1 += 4;                                                    // increment first pointer
+        SI(m3 = _mm_add_pi32(m3, m4),     paddd_r2r(mm4, mm3));      // m3 += m4
+        SI(m0 = _mm_add_pi32(m0, m2),     paddd_r2r(mm2, mm0));      // m0 += m2
+        SI(m2 = pv1[1],                   movq_a2r(8, pv1, mm2));    // mm2 = pv1[1] for next round
+        SI(m3 = _mm_srai_pi32(m3, m5),    psrad_r2r(mm5, mm3));    // m3 >>= shift (mm5)
+        pv2 += 4;                                                    // increment second pointer
+        SI(m0 = _mm_add_pi32(m0, m3),     paddd_r2r(mm3, mm0));      // add m0 += m3
+    } while ((--counter)!=0);
+
+    SI(m6 = ph[0], movq_a2r(0, ph, mm6));
+    // Finalize the last partial loop:
+    SI(m1 = _mm_madd_pi16(m1, pv2[0]), pmaddwd_a2r(0, pv2, mm1));
+    SI(m1 = _mm_and_si64(m1, m6),      pand_r2r(mm6, mm1));
+    SI(m3 = pv1[2],                    movq_a2r(16, pv1, mm3));
+    SI(m6 = ph[1], movq_a2r(8, ph, mm6));
+    SI(m2 = _mm_madd_pi16(m2, pv2[1]), pmaddwd_a2r(8, pv2, mm2));
+    SI(m2 = _mm_and_si64(m2, m6),      pand_r2r(mm6, mm2));
+    SI(m4 = pv1[3],                    movq_a2r(24, pv1, mm4));
+    SI(m6 = ph[2], movq_a2r(16, ph, mm6));
+    SI(m3 = _mm_madd_pi16(m3, pv2[2]), pmaddwd_a2r(16, pv2, mm3));
+    SI(m3 = _mm_and_si64(m3, m6),      pand_r2r(mm6, mm3));
+    SI(m2 = _mm_add_pi32(m2, m1),      paddd_r2r(mm1, mm2));
+    SI(m6 = ph[3], movq_a2r(24, ph, mm6));
+    SI(m4 = _mm_madd_pi16(m4, pv2[3]), pmaddwd_a2r(24, pv2, mm4));
+    SI(m4 = _mm_and_si64(m4, m6),      pand_r2r(mm6, mm4));
+    SI(m2 = _mm_srai_pi32(m2, m5),     psrad_r2r(mm5, mm2));
+    SI(m3 = _mm_add_pi32(m3, m4),      paddd_r2r(mm4, mm3));
+    SI(m0 = _mm_add_pi32(m0, m2),      paddd_r2r(mm2, mm0));
+    SI(m3 = _mm_srai_pi32(m3, m5),     psrad_r2r(mm5, mm3));
+    SI(m0 = _mm_add_pi32(m0, m3),      paddd_r2r(mm3, mm0));
+
+    // copy hi-dword of mm0 to lo-dword of mm1, then sum mm0+mm1
+    // and finally return the result
+    SI(m1 = m0,                        movq_r2r(mm0, mm1));
+    SI(m1 = _mm_srli_si64(m1, 32),     psrld_i2r(32, mm1));
+    SI(m0 = _mm_add_pi32(m0, m1),      paddd_r2r(mm1, mm0));
+    SI(tmp = _mm_cvtsi64_si32(m0),     movd_r2m(mm0, tmp));
+    return tmp;
+}
+#endif
+
 void TDStretchMMX::clearCrossCorrState()
 {
     _mm_empty();
@@ -224,6 +342,86 @@
     _mm_empty();
 }
 
+#if 0
+// MMX-optimized version of the function overlapMulti
+void TDStretchMMX::overlapMulti(short *output, const short *input) const
+{
+    _mm_empty();
+    uint shift = overlapDividerBits;
+    uint counter = overlapLength>>2;                 // counter = overlapLength / 4
+    __m64 *inPtr = (__m64*) input;                   // load address of inputBuffer
+    __m64 *midPtr = (__m64*) pMidBuffer;             // load address of midBuffer
+    __m64 *outPtr = ((__m64*) output)-2;             // load address of outputBuffer
+    GI(__m64 m0, m1, m2, m3, m4, m5, m6, m7);        // temporaries
+
+    // load mixing value adder to mm5
+    uint tmp0 = 0x0002fffe;                                      // tmp0 = 0x0002 fffe
+    SI(m5 = _mm_cvtsi32_si64(tmp0),    movd_v2r(tmp0, mm5));     // mm5 = 0x0000 0000 0002 fffe
+    SI(m5 = _mm_unpacklo_pi32(m5,m5),  punpckldq_r2r(mm5, mm5)); // mm5 = 0x0002 fffe 0002 fffe
+    // load sliding mixing value counter to mm6
+    SI(m6 = _mm_cvtsi32_si64(overlapLength), movd_v2r(overlapLength, mm6));
+    SI(m6 = _mm_unpacklo_pi32(m6, m6), punpckldq_r2r(mm6, mm6)); // mm6 = 0x0000 OVL_ 0000 OVL_
+    // load sliding mixing value counter to mm7
+    uint tmp1 = (overlapLength-1)|0x00010000;                    // tmp1 = 0x0001 overlapLength-1
+    SI(m7 = _mm_cvtsi32_si64(tmp1),    movd_v2r(tmp1, mm7));     // mm7 = 0x0000 0000 0001 01ff
+    SI(m7 = _mm_unpacklo_pi32(m7, m7), punpckldq_r2r(mm7, mm7)); // mm7 = 0x0001 01ff 0001 01ff
+
+    do {
+        // Process two parallel batches of 2+2 stereo samples during each round 
+        // to improve CPU-level parallellization.
+        //
+        // Load [midPtr] into m0 and m1
+        // Load [inPtr] into m3
+        // unpack words of m0, m1 and m3 into m0 and m1
+        // multiply-add m0*m6 and m1*m7, store results into m0 and m1
+        // divide m0 and m1 by 512 (=right-shift by overlapDividerBits)
+        // pack the result into m0 and store into [edx]
+        //
+        // Load [midPtr+8] into m2 and m3
+        // Load [inPtr+8] into m4
+        // unpack words of m2, m3 and m4 into m2 and m3
+        // multiply-add m2*m6 and m3*m7, store results into m2 and m3
+        // divide m2 and m3 by 512 (=right-shift by overlapDividerBits)
+        // pack the result into m2 and store into [edx+8]
+        SI(m0 = midPtr[0],                movq_a2r(0, midPtr, mm0));// mm0 = m1l m1r m0l m0r
+        outPtr += 2;
+        SI(m3 = inPtr[0],                 movq_a2r(0, inPtr, mm3)); // mm3 = i1l i1r i0l i0r
+        SI(m1 = m0,                       movq_r2r(mm0, mm1));      // mm1 = m1l m1r m0l m0r
+        SI(m2 = midPtr[1],                movq_a2r(8, midPtr, mm2));// mm2 = m3l m3r m2l m2r
+        SI(m0 = _mm_unpacklo_pi16(m0, m3),punpcklwd_r2r(mm3, mm0)); // mm0 = i0l m0l i0r m0r
+        midPtr += 2;
+        SI(m4 = inPtr[1],                 movq_a2r(8, inPtr, mm4)); // mm4 = i3l i3r i2l i2r
+        SI(m1 = _mm_unpackhi_pi16(m1, m3),punpckhwd_r2r(mm3, mm1)); // mm1 = i1l m1l i1r m1r
+        inPtr+=2;
+        SI(m3 = m2,                       movq_r2r(mm2, mm3));      // mm3 = m3l m3r m2l m2r
+        SI(m2 = _mm_unpacklo_pi16(m2, m4),punpcklwd_r2r(mm4, mm2)); // mm2 = i2l m2l i2r m2r
+        // mm0 = i0l*m63+m0l*m62 i0r*m61+m0r*m60
+        SI(m0 = _mm_madd_pi16(m0, m6),    pmaddwd_r2r(mm6, mm0));
+        SI(m3 = _mm_unpackhi_pi16(m3, m4),punpckhwd_r2r(mm4, mm3)); // mm3 = i3l m3l i3r m3r
+        SI(m4 = _mm_cvtsi32_si64(shift),  movd_v2r(shift, mm4));    // mm4 = shift
+        // mm1 = i1l*m73+m1l*m72 i1r*m71+m1r*m70
+        SI(m1 = _mm_madd_pi16(m1, m7),    pmaddwd_r2r(mm7, mm1));
+        SI(m6 = _mm_add_pi16(m6, m5),     paddw_r2r(mm5, mm6));
+        SI(m7 = _mm_add_pi16(m7, m5),     paddw_r2r(mm5, mm7));
+        SI(m0 = _mm_srai_pi32(m0, m4),    psrad_r2r(mm4, mm0));    // mm0 >>= shift
+        // mm2 = i2l*m63+m2l*m62 i2r*m61+m2r*m60
+        SI(m2 = _mm_madd_pi16(m2, m6),    pmaddwd_r2r(mm6, mm2));
+        SI(m1 = _mm_srai_pi32(m1, m4),    psrad_r2r(mm4, mm1));    // mm1 >>= shift
+        // mm3 = i3l*m73+m3l*m72 i3r*m71+m3r*m70
+        SI(m3 = _mm_madd_pi16(m3, m7),    pmaddwd_r2r(mm7, mm3));
+        SI(m2 = _mm_srai_pi32(m2, m4),    psrad_r2r(mm4, mm2));    // mm2 >>= shift
+        SI(m0 = _mm_packs_pi32(m0, m1),   packssdw_r2r(mm1, mm0)); // mm0 = mm1h mm1l mm0h mm0l
+        SI(m3 = _mm_srai_pi32(m3, m4),    psrad_r2r(mm4, mm3));    // mm3 >>= shift
+        SI(m6 = _mm_add_pi16(m6, m5),     paddw_r2r(mm5, mm6));
+        SI(m2 = _mm_packs_pi32(m2, m3),   packssdw_r2r(mm3, mm2)); // mm2 = mm2h mm2l mm3h mm3l
+        SI(m7 = _mm_add_pi16(m7, m5),     paddw_r2r(mm5, mm7));
+        SI(outPtr[0] = m0,                movq_r2a(mm0, 0, outPtr));
+        SI(outPtr[1] = m2,                movq_r2a(mm2, 8, outPtr));
+    } while ((--counter)!=0);
+    _mm_empty();
+}
+#endif
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // implementation of MMX optimized functions of class 'FIRFilter'
Index: libs/libmythsoundtouch/STTypes.h
===================================================================
--- libs/libmythsoundtouch/STTypes.h	(revision 9048)
+++ libs/libmythsoundtouch/STTypes.h	(working copy)
@@ -61,6 +61,7 @@
     #define INTEGER_SAMPLES       //< 16bit integer samples
     //#define FLOAT_SAMPLES       //< 32bit float samples
 
+    #define MULTICHANNEL 6
 
     /// Define this to allow CPU-specific assembler optimizations. Notice that 
     /// having this enabled on non-x86 platforms doesn't matter; the compiler can 
Index: libs/libmythsoundtouch/SoundTouch.cpp
===================================================================
--- libs/libmythsoundtouch/SoundTouch.cpp	(revision 9048)
+++ libs/libmythsoundtouch/SoundTouch.cpp	(working copy)
@@ -140,7 +140,11 @@
 // Sets the number of channels, 1 = mono, 2 = stereo
 void SoundTouch::setChannels(uint numChannels)
 {
+#ifdef MULTICHANNEL
+    if (numChannels < 1 || numChannels > MULTICHANNEL)
+#else
     if (numChannels != 1 && numChannels != 2) 
+#endif
     {
         throw std::runtime_error("Illegal number of channels");
     }
Index: programs/mythfrontend/globalsettings.cpp
===================================================================
--- programs/mythfrontend/globalsettings.cpp	(revision 9048)
+++ programs/mythfrontend/globalsettings.cpp	(working copy)
@@ -36,10 +36,42 @@
         dev.setNameFilter("adsp*");
         gc->fillSelectionsFromDir(dev);
     }
+#ifdef USE_ALSA
+    gc->addSelection("ALSA:default", "ALSA:default");
+    gc->addSelection("ALSA:analog", "ALSA:analog");
+    gc->addSelection("ALSA:digital", "ALSA:digital");
+    gc->addSelection("ALSA:mixed-analog", "ALSA:mixed-analog");
+    gc->addSelection("ALSA:mixed-digital", "ALSA:mixed-digital");
+#endif
+#ifdef USE_ARTS
+    gc->addSelection("ARTS:", "ARTS:");
+#endif
+#ifdef USE_JACK
+    gc->addSelection("JACK:output", "JACK:output");
+#endif
+    gc->addSelection("NULL", "NULL");
 
     return gc;
 }
 
+static HostComboBox *MaxAudioChannels()
+{
+    HostComboBox *gc = new HostComboBox("MaxChannels",false);
+    gc->setLabel(QObject::tr("Max Audio Channels"));
+    //gc->addSelection(QObject::tr("Mono"), "1");
+    //gc->addSelection(QObject::tr("Stereo L+R"), "2", true); // default
+    //gc->addSelection(QObject::tr("3 Channel: L C R"), "3");
+    //gc->addSelection(QObject::tr("4 Channel: L R LS RS"), "4");
+    //gc->addSelection(QObject::tr("5 Channel: L C R LS RS"), "5");
+    //gc->addSelection(QObject::tr("6 Channel: L C R LS RS LFE"), "6");
+    gc->addSelection(QObject::tr("Stereo"), "2", true); // default
+    gc->addSelection(QObject::tr("6 Channel"), "6");
+    gc->setHelpText(
+            QObject::tr("Set the maximum number of audio channels to be decoded. "
+                "This is for multi-channel/surround audio playback."));
+    return gc;
+}
+
 static HostCheckBox *MythControlsVolume()
 {
     HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
@@ -2125,11 +2157,29 @@
          setUseLabel(false);
 
          addChild(AudioOutputDevice());
+#if 0
+         ConfigurationGroup *hg = new HorizontalConfigurationGroup(false, false);
+         ConfigurationGroup* settingsLeft = new VerticalConfigurationGroup(false,false);
+         settingsLeft->addChild(AC3PassThrough());
+#ifdef CONFIG_DTS
+         settingsLeft->addChild(DTSPassThrough());
+#endif
+         settingsLeft->addChild(AggressiveBuffer());
+         hg->addChild(settingsLeft);
+
+         ConfigurationGroup* settingsRight = new VerticalConfigurationGroup(false,false);
+         settingsRight->addChild(MaxAudioChannels());
+         hg->addChild(settingsRight);
+
+         addChild(hg);
+#else
          addChild(AC3PassThrough());
 #ifdef CONFIG_DTS
          addChild(DTSPassThrough());
 #endif
          addChild(AggressiveBuffer());
+         addChild(MaxAudioChannels());
+#endif
 
          Setting* volumeControl = MythControlsVolume();
          addChild(volumeControl);
Index: programs/mythtranscode/transcode.cpp
===================================================================
--- programs/mythtranscode/transcode.cpp	(revision 9048)
+++ programs/mythtranscode/transcode.cpp	(working copy)
@@ -46,12 +46,16 @@
 
     // reconfigure sound out for new params
     virtual void Reconfigure(int audio_bits, int audio_channels,
-                             int audio_samplerate, bool audio_passthru)
+                             int audio_samplerate, bool audio_passthru,
+                             void * = NULL)
     {
+        ClearError();
         (void)audio_samplerate;
         bits = audio_bits;
         channels = audio_channels;
         bytes_per_sample = bits * channels / 8;
+        if (channels>2)
+            Error("Invalid channel count");
     }
 
     // dsprate is in 100 * samples/second
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 9048)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -243,6 +243,7 @@
     bool              allow_ac3_passthru;
     bool              allow_dts_passthru;
     bool              disable_passthru;
+    int               max_channels;
 
     AudioInfo         audioIn;
     AudioInfo         audioOut;
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 9048)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -39,7 +39,12 @@
 #define MAX_AC3_FRAME_SIZE 6144
 
 /** Set to zero to allow any number of AC3 channels. */
+#define MAXCHANNELSELECT 1
+#if MAXCHANNELSELECT
+#define MAX_OUTPUT_CHANNELS compiler error
+#else
 #define MAX_OUTPUT_CHANNELS 2
+#endif
 
 static int dts_syncinfo(uint8_t *indata_ptr, int *flags,
                         int *sample_rate, int *bit_rate);
@@ -290,6 +295,7 @@
 #ifdef CONFIG_DTS
     allow_dts_passthru = gContext->GetNumSetting("DTSPassThru", false);
 #endif
+    max_channels = gContext->GetNumSetting("MaxChannels", 2);
 
     audioIn.sample_size = -32; // force SetupAudioStream to run once
     ttd = GetNVP()->GetTeletextDecoder();
@@ -411,8 +417,25 @@
     framesPlayed = lastKey;
     framesRead = lastKey;
 
+    VERBOSE(VB_PLAYBACK, QString("AvFormatDecoder::DoFastForward newframe %5 frame %1 fps %2 ts %3 disc %4 cur_dts %6 adj %7 newts %8 fsa %9")
+        .arg(desiredFrame)
+        .arg(fps)
+        .arg(ts)
+        .arg(discardFrames)
+        .arg(framesPlayed)
+        .arg(st->cur_dts)
+        .arg(adj_cur_dts)
+        .arg(newts)
+        .arg(frameseekadjust)
+        );
+
     int normalframes = desiredFrame - framesPlayed;
 
+#if 0
+    if (!exactseeks)
+        normalframes = 0;
+#endif
+
     SeekReset(lastKey, normalframes, discardFrames, discardFrames);
 
     if (discardFrames)
@@ -781,6 +804,17 @@
 
     fmt->flags &= ~AVFMT_NOFILE;
 
+#if 1
+    if ((m_playbackinfo) || livetv || watchingrecording)
+    {
+        const char *name = ic->av_class->item_name(ic);
+        VERBOSE(VB_GENERAL, QString("libavformat type %1").arg(name));
+    }
+#endif
+ 
+    //struct timeval one, two, res;
+    //gettimeofday(&one, NULL);
+
     if (!ringBuffer->isDVD())
         av_estimate_timings(ic);
 
@@ -791,6 +825,11 @@
     if (-1 == ret)
         return ret;
 
+    // make sure its at the real start due to av_find_stream_info reading
+    ret = av_seek_frame(ic, -1, 0, AVSEEK_FLAG_BACKWARD);
+    if (ret < 0)
+        av_seek_frame(ic, -1, 0, AVSEEK_FLAG_BYTE);     // reposition to start of stream
+
     // Select some starting audio and subtitle tracks.
     // TODO do we need this? They will be called by GetFrame() anyway...
     autoSelectAudioTrack();
@@ -813,8 +852,9 @@
     // If we don't have a position map, set up ffmpeg for seeking
     if (!recordingHasPositionMap)
     {
+        const char *name = ic->av_class->item_name(ic);
         VERBOSE(VB_PLAYBACK, LOC +
-                "Recording has no position -- using libavformat seeking.");
+                QString("Recording has no position -- using libavformat seeking. %1").arg(name));
         int64_t dur = ic->duration / (int64_t)AV_TIME_BASE;
 
         if (dur > 0)
@@ -859,6 +899,9 @@
             QString("Successfully opened decoder for file: "
                     "\"%1\". novideo(%2)").arg(filename).arg(novideo));
 
+    // set initial position correctly
+    //DoFastForward(0, true);
+
     // Return true if recording has position map
     return recordingHasPositionMap;
 }
@@ -1096,7 +1139,13 @@
                             <<") already open, leaving it alone.");
                 }
                 //assert(enc->codec_id);
+                VERBOSE(VB_GENERAL, QString("AVFD: codec %1 has %2 channels").arg(codec_id_string(enc->codec_id)).arg(enc->channels));
+#if 0
+                if (enc->channels > 2)
+                    enc->channels = 2;
+#endif
 
+#if 0
                 // HACK BEGIN REALLY UGLY HACK FOR DTS PASSTHRU
                 if (enc->codec_id == CODEC_ID_DTS)
                 {
@@ -1105,6 +1154,7 @@
                     // enc->bit_rate = what??;
                 }
                 // HACK END REALLY UGLY HACK FOR DTS PASSTHRU
+#endif
 
                 bitrate += enc->bit_rate;
                 break;
@@ -1605,7 +1655,7 @@
         {
             long long startpos = pkt->pos;
 
-            VERBOSE(VB_PLAYBACK, LOC + 
+            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + 
                     QString("positionMap[ %1 ] == %2.")
                     .arg(prevgoppos / keyframedist)
                     .arg((int)startpos));
@@ -2364,6 +2414,14 @@
 
         AVStream *curstream = ic->streams[pkt->stream_index];
 
+#if 0
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("timecode pts:%1 dts:%2 codec:%3")
+                .arg(pkt->pts)
+                .arg(pkt->dts)
+                .arg((curstream && curstream->codec)?curstream->codec->codec_type:-1)
+               );
+#endif
+
         if (pkt->dts != (int64_t)AV_NOPTS_VALUE)
             pts = (long long)(av_q2d(curstream->time_base) * pkt->dts * 1000);
 
@@ -2484,7 +2542,13 @@
                     if (!curstream->codec->channels)
                     {
                         QMutexLocker locker(&avcodeclock);
+#if MAXCHANNELSELECT
+                        VERBOSE(VB_IMPORTANT, LOC + QString("Setting channels to %1").arg(audioOut.channels));
+                        curstream->codec->cqp = max_channels;
+                        curstream->codec->channels = audioOut.channels;
+#else
                         curstream->codec->channels = MAX_OUTPUT_CHANNELS;
+#endif
                         ret = avcodec_decode_audio(
                             curstream->codec, audioSamples,
                             &data_size, ptr, len);
@@ -2535,9 +2599,15 @@
                     {
                         AVCodecContext *ctx = curstream->codec;
 
+#if MAXCHANNELSELECT
                         if ((ctx->channels == 0) ||
+                            (ctx->channels > audioOut.channels))
+                            ctx->channels = audioOut.channels;
+#else
+                        if ((ctx->channels == 0) ||
                             (ctx->channels > MAX_OUTPUT_CHANNELS))
                             ctx->channels = MAX_OUTPUT_CHANNELS;
+#endif
 
                         ret = avcodec_decode_audio(
                             ctx, audioSamples, &data_size, ptr, len);
@@ -2573,6 +2643,10 @@
                                 (curstream->codec->channels * 2) / 
                                 curstream->codec->sample_rate);
 
+                    VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("audio timecode %1 %2 %3 %4")
+                            .arg(pkt->pts)
+                            .arg(pkt->dts)
+                            .arg(temppts).arg(lastapts));
                     GetNVP()->AddAudioData((char *)audioSamples, data_size,
                                            temppts);
 
@@ -2673,6 +2747,10 @@
                     else
                         temppts = lastvpts;
 
+                    VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("video timecode %1 %2 %3 %4")
+                            .arg(pkt->pts)
+                            .arg(pkt->dts)
+                            .arg(temppts).arg(lastvpts));
 /* XXX: Broken.
                     if (mpa_pic.qscale_table != NULL && mpa_pic.qstride > 0 &&
                         context->height == picframe->height)
@@ -2769,12 +2847,17 @@
 
 void AvFormatDecoder::SetDisablePassThrough(bool disable)
 {
+#if MAXCHANNELSELECT
+    // can only disable never reenable as once tiemstretch is on its on for the session
+    if (disable_passthru)
+        return;
+#endif
     if (selectedAudioStream.av_stream_index < 0)
     {
         disable_passthru = disable;
         return;
     }
-
+ 
     if (disable != disable_passthru)
     {
         disable_passthru = disable;
@@ -2801,6 +2884,7 @@
     AVCodecContext *codec_ctx = NULL;
     AudioInfo old_in  = audioIn;
     AudioInfo old_out = audioOut;
+    bool using_passthru = false;
 
     if ((currentAudioTrack >= 0) &&
         (selectedAudioStream.av_stream_index <= ic->nb_streams) &&
@@ -2808,34 +2892,89 @@
     {
         assert(curstream);
         assert(curstream->codec);
-        codec_ctx = curstream->codec;        
+        codec_ctx = curstream->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));
+        using_passthru = do_ac3_passthru || do_dts_passthru;
         info = AudioInfo(codec_ctx->codec_id,
                          codec_ctx->sample_rate, codec_ctx->channels,
-                         do_ac3_passthru || do_dts_passthru);
+                         using_passthru && !disable_passthru);
     }
 
     if (info == audioIn)
         return false; // no change
 
+    QString ptmsg = "";
+    if (using_passthru)
+    {
+        ptmsg = QString(" using passthru");
+    }
     VERBOSE(VB_AUDIO, LOC + "Initializing audio parms from " +
-            QString("audio track #%1").arg(currentAudioTrack+1));
+            QString("audio track #%1")
+                .arg(currentAudioTrack+1)
+            + ptmsg );
 
     audioOut = audioIn = info;
+#if MAXCHANNELSELECT
+    if (using_passthru)
+#else
     if (audioIn.do_passthru)
+#endif
     {
         // A passthru stream looks like a 48KHz 2ch (@ 16bit) to the sound card
-        audioOut.channels    = 2;
-        audioOut.sample_rate = 48000;
-        audioOut.sample_size = 4;
+        AudioInfo digInfo = audioOut;
+        if (!disable_passthru)
+        {
+            digInfo.channels    = 2;
+            digInfo.sample_rate = 48000;
+            digInfo.sample_size = 4;
+        }
+        if (audioOut.channels > max_channels)
+        {
+            audioOut.channels = max_channels;
+            audioOut.sample_size = audioOut.channels * 2;
+            codec_ctx->channels = audioOut.channels;
+        }
+#if MAXCHANNELSELECT
+        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(audioOut.bps(), audioOut.channels,
+        //                         audioOut.sample_rate);
+        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;
+#endif
     }
+#if MAXCHANNELSELECT
     else
     {
+        if (audioOut.channels > max_channels)
+        {
+            audioOut.channels = max_channels;
+            audioOut.sample_size = audioOut.channels * 2;
+            codec_ctx->channels = audioOut.channels;
+        }
+    }
+    bool audiook;
+#if 0
+    do 
+    {
+#endif
+#else
+    else
+    {
         if (audioOut.channels > MAX_OUTPUT_CHANNELS)
         {
             audioOut.channels = MAX_OUTPUT_CHANNELS;
@@ -2843,6 +2982,7 @@
             codec_ctx->channels = MAX_OUTPUT_CHANNELS;
         }
     }
+#endif
 
     VERBOSE(VB_AUDIO, LOC + "Audio format changed " +
             QString("\n\t\t\tfrom %1 ; %2\n\t\t\tto   %3 ; %4")
@@ -2855,7 +2995,52 @@
     GetNVP()->SetAudioParams(audioOut.bps(), audioOut.channels,
                              audioOut.sample_rate,
                              audioIn.do_passthru);
-    GetNVP()->ReinitAudio();
+    // allow the audio stuff to reencode
+    GetNVP()->SetAudioCodec(using_passthru?codec_ctx:NULL);
+    QString errMsg = GetNVP()->ReinitAudio();
+#if MAXCHANNELSELECT
+        audiook = errMsg.isEmpty();
+#if 0
+        if (!audiook)
+        {
+            switch (audioOut.channels)
+            {
+#if 0
+                case 8:
+                    audioOut.channels = 6;
+                    break;
+#endif
+                case 6:
+#if 0
+                    audioOut.channels = 5;
+                    break;
+                case 5:
+                    audioOut.channels = 4;
+                    break;
+                case 4:
+                    audioOut.channels = 3;
+                    break;
+                case 3:
+#endif
+                    audioOut.channels = 2;
+                    break;
+#if 0
+                case 2:
+                    audioOut.channels = 1;
+                    break;
+#endif
+                default:
+                    // failed to reconfigure under any circumstances
+                    audiook = true;
+                    audioOut.channels = 0;
+                    break;
+            }
+            audioOut.sample_size = audioOut.channels * 2;
+            codec_ctx->channels = audioOut.channels;
+        }
+    } while (!audiook);
+#endif
+#endif
 
     return true;
 }
Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 9048)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -112,6 +112,7 @@
     void SetVideoParams(int w, int h, double fps, int keydist,
                         float a = 1.33333, FrameScanType scan = kScan_Ignore);
     void SetAudioParams(int bits, int channels, int samplerate, bool passthru);
+    void SetAudioCodec(void *ac);
     void SetEffDsp(int dsprate);
     void SetFileLength(int total, int frames);
     void Zoom(int direction);
@@ -149,6 +150,7 @@
     bool    IsDecoderThreadAlive(void) const  { return decoder_thread_alive; }
     bool    IsReallyNearEnd(void) const;
     bool    IsNearEnd(long long framesRemaining = -1) const;
+    float   GetAudioStretchFactor() { return audio_stretchfactor; }
     bool    PlayingSlowForPrebuffer(void) const { return m_playing_slower; }
     bool    HasAudioIn(void) const            { return !no_audio_in; }
     bool    HasAudioOut(void) const           { return !no_audio_out; }
@@ -178,6 +180,7 @@
     bool Play(float speed = 1.0, bool normal = true,
               bool unpauseaudio = true);
     bool GetPause(void) const;
+    float GetNextPlaySpeed() { return next_play_speed; }
 
     // Seek stuff
     bool FastForward(float seconds);
@@ -509,6 +512,7 @@
     int      audio_bits;
     int      audio_samplerate;
     float    audio_stretchfactor;
+    void     *audio_codec;
     bool     audio_passthru;
 
     // Picture-in-Picture
Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 9048)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -126,6 +126,7 @@
       audioOutput(NULL),            audiodevice("/dev/dsp"),
       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
@@ -565,7 +566,8 @@
     if (audioOutput)
     {
         audioOutput->Reconfigure(audio_bits, audio_channels,
-                                 audio_samplerate, audio_passthru);
+                                 audio_samplerate, audio_passthru,
+                                 audio_codec);
         errMsg = audioOutput->GetError();
         if (!errMsg.isEmpty())
             audioOutput->SetStretchFactor(audio_stretchfactor);
@@ -698,6 +700,8 @@
         {
             VERBOSE(VB_IMPORTANT, "Video sync method can't support double "
                     "framerate (refresh rate too low for bob deint)");
+            //m_scan = kScan_Ignore;
+            //m_can_double = false;
             FallbackDeint();
         }
     }
@@ -1567,9 +1571,18 @@
     warpfactor_avg = (warpfactor + (warpfactor_avg * (WARPAVLEN - 1))) /
                       WARPAVLEN;
 
-    //cerr << "Divergence: " << divergence << "  Rate: " << rate
-    //<< "  Warpfactor: " << warpfactor << "  warpfactor_avg: "
-    //<< warpfactor_avg << endl;
+#if 1
+    VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("A/V "
+        "Divergence: %1 "
+        "  Rate: %2" 
+        "  Warpfactor: %3" 
+        "  warpfactor_avg: %4")
+        .arg(divergence)
+        .arg(rate)
+        .arg(warpfactor)
+        .arg(warpfactor_avg)
+        );
+#endif
     return divergence;
 }
 
@@ -1650,7 +1663,7 @@
     if (diverge < -MAXDIVERGE)
     {
         // If video is way ahead of audio, adjust for it...
-        QString dbg = QString("Video is %1 frames ahead of audio, ")
+        QString dbg = QString("Audio is %1 frames ahead of video, ")
             .arg(-diverge);
 
         // Reset A/V Sync
@@ -1665,12 +1678,12 @@
             // decoding; display the frame, but don't wait for A/V Sync.
             videoOutput->PrepareFrame(buffer, ps);
             videoOutput->Show(m_scan);
-            VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait.");
+            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + dbg + "skipping A/V wait.");
         }
         else
         {
             // If we are using software decoding, skip this frame altogether.
-            VERBOSE(VB_PLAYBACK, LOC + dbg + "dropping frame.");
+            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + dbg + "dropping frame.");
         }
     }
     else if (!using_null_videoout)
@@ -1679,7 +1692,9 @@
         if (buffer)
             videoOutput->PrepareFrame(buffer, ps);
 
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2").arg(avsync_adjustment).arg(m_double_framerate));
         videosync->WaitForFrame(avsync_adjustment);
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
         if (!resetvideo)
             videoOutput->Show(m_scan);
 
@@ -1699,7 +1714,7 @@
 
             // Display the second field
             videosync->AdvanceTrigger();
-            videosync->WaitForFrame(0);
+            videosync->WaitForFrame(avsync_adjustment);
             if (!resetvideo)
                 videoOutput->Show(kScan_Intr2ndField);
         }
@@ -1711,10 +1726,17 @@
 
     if (output_jmeter && output_jmeter->RecordCycleTime())
     {
-        //cerr << "avsync_delay: " << avsync_delay / 1000
-        //     << ", avsync_avg: " << avsync_avg / 1000
-        //     << ", warpfactor: " << warpfactor
-        //     << ", warpfactor_avg: " << warpfactor_avg << endl;
+#if 1
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("A/V "
+            "avsync_delay: %1" 
+            ", avsync_avg: %2" 
+            ", warpfactor: %3" 
+            ", warpfactor_avg: %4")
+                .arg(avsync_delay / 1000)
+                .arg(avsync_avg / 1000)
+                .arg(warpfactor)
+                .arg(warpfactor_avg));
+#endif
     }
 
     videosync->AdvanceTrigger();
@@ -1725,18 +1747,19 @@
         // If audio is way ahead of video, adjust for it...
         // by cutting the frame rate in half for the length of this frame
 
-        avsync_adjustment = frame_interval;
+        //avsync_adjustment = frame_interval;
+        avsync_adjustment = refreshrate;
         lastsync = true;
-        VERBOSE(VB_PLAYBACK, LOC + 
-                QString("Audio is %1 frames ahead of video,\n"
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + 
+                QString("Video is %1 frames ahead of audio,\n"
                         "\t\t\tdoubling video frame interval.").arg(diverge));
     }
 
     if (audioOutput && normal_speed)
     {
         long long currentaudiotime = audioOutput->GetAudiotime();
-#if 0
-        VERBOSE(VB_PLAYBACK, QString(
+#if 1
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString(
                     "A/V timecodes audio %1 video %2 frameinterval %3 "
                     "avdel %4 avg %5 tcoffset %6")
                 .arg(currentaudiotime)
@@ -2002,7 +2025,7 @@
 
     usevideotimebase = gContext->GetNumSetting("UseVideoTimebase", 0);
 
-    if ((print_verbose_messages & VB_PLAYBACK) != 0)
+    if ((print_verbose_messages & VB_PLAYBACK|VB_TIMESTAMP) == (VB_PLAYBACK|VB_TIMESTAMP))
         output_jmeter = new Jitterometer("video_output", 100);
     else
         output_jmeter = NULL;
@@ -2042,6 +2065,8 @@
             {
                 VERBOSE(VB_IMPORTANT, "Video sync method can't support double "
                         "framerate (refresh rate too low for bob deint)");
+                //m_scan = kScan_Ignore;
+                //m_can_double = false;
                 FallbackDeint();
             }
         }
@@ -2806,6 +2831,11 @@
     audio_passthru = passthru;
 }
 
+void NuppelVideoPlayer::SetAudioCodec(void* ac)
+{
+    audio_codec = ac;
+}
+
 void NuppelVideoPlayer::SetEffDsp(int dsprate)
 {
     if (audioOutput)
@@ -2850,7 +2880,7 @@
         tc_avcheck_framecounter++;
         if (tc_avcheck_framecounter == 30)
         {
-#define AUTO_RESYNC 1
+#define AUTO_RESYNC 0
 #if AUTO_RESYNC
             // something's terribly, terribly wrong.
             if (tc_lastval[TC_AUDIO] < tc_lastval[TC_VIDEO] - 10000000 ||
Index: libs/libavcodec/a52dec.c
===================================================================
--- libs/libavcodec/a52dec.c	(revision 9048)
+++ libs/libavcodec/a52dec.c	(working copy)
@@ -142,6 +142,147 @@
     }
 }
 
+static inline int16_t convert (int32_t i)
+{
+    if (i > 0x43c07fff)
+	return 32767;
+    else if (i < 0x43bf8000)
+	return -32768;
+    else
+	return i - 0x43c00000;
+}
+
+void float2s16_2 (float * _f, int16_t * s16)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    for (i = 0; i < 256; i++) {
+	s16[2*i] = convert (f[i]);
+	s16[2*i+1] = convert (f[i+256]);
+    }
+}
+
+void float2s16_4 (float * _f, int16_t * s16)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    for (i = 0; i < 256; i++) {
+	s16[4*i] = convert (f[i]);
+	s16[4*i+1] = convert (f[i+256]);
+	s16[4*i+2] = convert (f[i+512]);
+	s16[4*i+3] = convert (f[i+768]);
+    }
+}
+
+void float2s16_5 (float * _f, int16_t * s16)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    for (i = 0; i < 256; i++) {
+	s16[5*i] = convert (f[i]);
+	s16[5*i+1] = convert (f[i+256]);
+	s16[5*i+2] = convert (f[i+512]);
+	s16[5*i+3] = convert (f[i+768]);
+	s16[5*i+4] = convert (f[i+1024]);
+    }
+}
+
+int channels_multi (int flags)
+{
+    if (flags & A52_LFE)
+	return 6;
+    else if (flags & 1)	/* center channel */
+	return 5;
+    else if ((flags & A52_CHANNEL_MASK) == A52_2F2R)
+	return 4;
+    else
+	return 2;
+}
+
+void float2s16_multi (float * _f, int16_t * s16, int flags)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    switch (flags) {
+    case A52_MONO:
+	for (i = 0; i < 256; i++) {
+	    s16[5*i] = s16[5*i+1] = s16[5*i+2] = s16[5*i+3] = 0;
+	    s16[5*i+4] = convert (f[i]);
+	}
+	break;
+    case A52_CHANNEL:
+    case A52_STEREO:
+    case A52_DOLBY:
+	float2s16_2 (_f, s16);
+	break;
+    case A52_3F:
+	for (i = 0; i < 256; i++) {
+	    s16[5*i] = convert (f[i]);
+	    s16[5*i+1] = convert (f[i+512]);
+	    s16[5*i+2] = s16[5*i+3] = 0;
+	    s16[5*i+4] = convert (f[i+256]);
+	}
+	break;
+    case A52_2F2R:
+	float2s16_4 (_f, s16);
+	break;
+    case A52_3F2R:
+	float2s16_5 (_f, s16);
+	break;
+    case A52_MONO | A52_LFE:
+	for (i = 0; i < 256; i++) {
+	    s16[6*i] = s16[6*i+1] = s16[6*i+2] = s16[6*i+3] = 0;
+	    s16[6*i+4] = convert (f[i+256]);
+	    s16[6*i+5] = convert (f[i]);
+	}
+	break;
+    case A52_CHANNEL | A52_LFE:
+    case A52_STEREO | A52_LFE:
+    case A52_DOLBY | A52_LFE:
+	for (i = 0; i < 256; i++) {
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+512]);
+	    s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0;
+	    s16[6*i+5] = convert (f[i]);
+	}
+	break;
+    case A52_3F | A52_LFE:
+	for (i = 0; i < 256; i++) {
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+768]);
+	    s16[6*i+2] = s16[6*i+3] = 0;
+	    s16[6*i+4] = convert (f[i+512]);
+	    s16[6*i+5] = convert (f[i]);
+	}
+	break;
+    case A52_2F2R | A52_LFE:
+	for (i = 0; i < 256; i++) {
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+512]);
+	    s16[6*i+2] = convert (f[i+768]);
+	    s16[6*i+3] = convert (f[i+1024]);
+	    s16[6*i+4] = 0;
+	    s16[6*i+5] = convert (f[i]);
+	}
+	break;
+    case A52_3F2R | A52_LFE:
+	for (i = 0; i < 256; i++) {
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+768]);
+	    s16[6*i+2] = convert (f[i+1024]);
+	    s16[6*i+3] = convert (f[i+1280]);
+	    s16[6*i+4] = convert (f[i+512]);
+	    s16[6*i+5] = convert (f[i]);
+	}
+	break;
+    }
+}
+
+
 /**** end */
 
 #define HEADER_SIZE 7
@@ -183,6 +324,8 @@
                     /* update codec info */
                     avctx->sample_rate = sample_rate;
                     s->channels = ac3_channels[s->flags & 7];
+                    if (avctx->cqp >= 0)
+                        avctx->channels = avctx->cqp;
                     if (s->flags & A52_LFE)
                         s->channels++;
                     if (avctx->channels == 0)
@@ -205,14 +348,20 @@
             s->inbuf_ptr += len;
             buf_size -= len;
         } else {
+            int chans;
             flags = s->flags;
             if (avctx->channels == 1)
                 flags = A52_MONO;
-            else if (avctx->channels == 2)
-                flags = A52_STEREO;
+            else if (avctx->channels == 2) {
+                if (s->channels>2)
+                    flags = A52_DOLBY;
+                else
+                    flags = A52_STEREO;
+            }
             else
                 flags |= A52_ADJUST_LEVEL;
             level = 1;
+            chans = channels_multi(flags);
             if (s->a52_frame(s->state, s->inbuf, &flags, &level, 384)) {
             fail:
                 s->inbuf_ptr = s->inbuf;
@@ -222,11 +371,13 @@
             for (i = 0; i < 6; i++) {
                 if (s->a52_block(s->state))
                     goto fail;
-                float_to_int(s->samples, out_samples + i * 256 * avctx->channels, avctx->channels);
+                //float_to_int(s->samples, out_samples + i * 256 * avctx->channels, avctx->channels);
+                float2s16_multi(s->samples, out_samples + i * 256 * chans, flags);
             }
             s->inbuf_ptr = s->inbuf;
             s->frame_size = 0;
-            *data_size = 6 * avctx->channels * 256 * sizeof(int16_t);
+            //*data_size = 6 * avctx->channels * 256 * sizeof(int16_t);
+            *data_size = 6 * chans * 256 * sizeof(int16_t);
             break;
         }
     }
Index: libs/libavcodec/ac3enc.c
===================================================================
--- libs/libavcodec/ac3enc.c	(revision 9048)
+++ libs/libavcodec/ac3enc.c	(working copy)
@@ -1362,6 +1362,18 @@
 {
     AC3EncodeContext *s = avctx->priv_data;
     int16_t *samples = data;
+    // expects L C R LS RS LFE
+    // audio format is L R LS RS C LFE
+    static int channel_index[6] = { 0, 4, 1, 2, 3, 5 };
+    /*
+     * A52->Analog->AC3Enc
+     * 1->0->0
+     * 3->1->2
+     * 4->2->3
+     * 5->3->4
+     * 2->4->1
+     * 0->5->5
+     */
     int i, j, k, v, ch;
     int16_t input_samples[N];
     int32_t mdct_coef[NB_BLOCKS][AC3_MAX_CHANNELS][N/2];
@@ -1382,7 +1394,7 @@
             /* compute input samples */
             memcpy(input_samples, s->last_samples[ch], N/2 * sizeof(int16_t));
             sinc = s->nb_all_channels;
-            sptr = samples + (sinc * (N/2) * i) + ch;
+            sptr = samples + (sinc * (N/2) * i) + channel_index[ch];
             for(j=0;j<N/2;j++) {
                 v = *sptr;
                 input_samples[j + N/2] = v;
@@ -1403,7 +1415,7 @@
             v = 14 - log2_tab(input_samples, N);
             if (v < 0)
                 v = 0;
-            exp_samples[i][ch] = v - 8;
+            exp_samples[i][ch] = v - 9;
             lshift_tab(input_samples, N, v);
 
             /* do the MDCT */
