diff -r 2081edfa7267 mythtv/libs/libmythtv/avformatdecoder.cpp
--- a/mythtv/libs/libmythtv/avformatdecoder.cpp	Wed Apr 14 10:26:13 2010 +0000
+++ b/mythtv/libs/libmythtv/avformatdecoder.cpp	Wed Apr 14 21:00:57 2010 +1000
@@ -472,12 +472,14 @@
       is_db_ignored(gContext->IsDatabaseIgnored()),
       m_h264_parser(new H264Parser()),
       ic(NULL),
-      frame_decoded(0),             decoded_video_frame(NULL),
+      decoded_video_frame(NULL),
       avfRingBuffer(NULL),          sws_ctx(NULL),
       directrendering(false),
       gopset(false),                seen_gop(false),
-      seq_count(0),
-      prevgoppos(0),                gotvideo(false),
+      seq_count(0),                 prevgoppos(0),
+      wantaudio(false),             wantvideo(false),
+      gotvideo(false),              skipaudio(false),
+      allowedquit(false),
       start_code_state(0xffffffff),
       lastvpts(0),                  lastapts(0),
       lastccptsu(0),
@@ -496,10 +498,9 @@
       audioSamples(NULL),           audioSamplesResampled(NULL),
       reformat_ctx(NULL),           audio_src_fmt(SAMPLE_FMT_NONE),
       allow_ac3_passthru(false),    allow_dts_passthru(false),
-      internal_vol(false),
-      disable_passthru(false),      max_channels(2),
-      last_ac3_channels(0),         last_framesRead(0),
-      dummy_frame(NULL),
+      internal_vol(false),          disable_passthru(false),
+      max_channels(2),              last_ac3_channels(0),
+      last_framesRead(0),           dummy_frame(NULL),
       // DVD
       lastdvdtitle(-1),
       decodeStillFrame(false),
@@ -3118,6 +3119,447 @@
     return on_frame;
 }
 
+bool AvFormatDecoder::PreProcessVideoPacket(AVPacket *pkt, AVStream *stream)
+{
+
+    AVCodecContext *ctx = stream->codec;
+    bool on_frame = true;
+
+    if (CODEC_IS_FFMPEG_MPEG(ctx->codec_id))
+    {
+        if (!ringBuffer->isDVD())
+            MpegPreProcessPkt(stream, pkt);
+    }
+    else if (CODEC_IS_H264(ctx->codec_id))
+        on_frame = H264PreProcessPkt(stream, pkt);
+    else
+    {
+        if (pkt->flags & PKT_FLAG_KEY)
+        {
+            HandleGopStart(pkt, false);
+            seen_gop = true;
+        }
+        else
+        {
+            seq_count++;
+            if (!seen_gop && seq_count > 1)
+                HandleGopStart(pkt, false);
+        }
+    }
+
+    if (framesRead == 0 && !justAfterChange && !(pkt->flags & PKT_FLAG_KEY))
+    {
+        av_free_packet(pkt);
+        return false;
+    }
+
+    if (on_frame)
+        framesRead++;
+    justAfterChange = false;
+
+    if (exitafterdecoded)
+        gotvideo = 1;
+
+    return true;
+}
+
+int AvFormatDecoder::ProcessVideoPacket(const AVPacket *pkt,
+                                        const AVStream *stream,
+                                        long long pts,  bool firstloop)
+{
+    AVCodecContext *ctx = stream->codec;
+    uchar *ptr          = pkt->data;
+    int len             = pkt->size;
+    int ret             = 0;
+
+    if (pkt->stream_index != selectedVideoIndex)
+        return len;
+
+    if (firstloop && pts != (int64_t) AV_NOPTS_VALUE)
+        lastccptsu = (long long)
+            (av_q2d(stream->time_base) * pkt->pts * 1000000);
+
+    if (!wantvideo)
+    {
+        framesPlayed++;
+        gotvideo = 1;
+        return len;
+    }
+
+    AVFrame mpa_pic;
+    bzero(&mpa_pic, sizeof(AVFrame));
+
+    int gotpicture = 0;
+
+    avcodeclock->lock();
+    if (d->HasDecoder())
+    {
+        if (decodeStillFrame)
+        {
+            int count = 0;
+            // HACK
+            while (!gotpicture && count < 5)
+            {
+                ret = d->DecodeMPEG2Video(ctx, &mpa_pic, &gotpicture, ptr, len);
+                count++;
+            }
+        }
+        else
+            ret = d->DecodeMPEG2Video(ctx, &mpa_pic, &gotpicture, ptr, len);
+    }
+    else
+    {
+        ret = avcodec_decode_video(ctx, &mpa_pic, &gotpicture, ptr, len);
+        // Reparse it to not drop the DVD still frame
+        if (decodeStillFrame)
+            ret = avcodec_decode_video(ctx, &mpa_pic, &gotpicture, ptr, len);
+    }
+    avcodeclock->unlock();
+
+    if (ret < 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unknown decoding error");
+        return len;
+    }
+
+    if (!gotpicture)
+        return len;
+
+    // Decode CEA-608 and CEA-708 captions
+    for (uint i = 0; i < (uint)mpa_pic.atsc_cc_len;
+         i += ((mpa_pic.atsc_cc_buf[i] & 0x1f) * 3) + 2)
+        DecodeDTVCC(mpa_pic.atsc_cc_buf + i, mpa_pic.atsc_cc_len - i);
+
+    VideoFrame *picframe = (VideoFrame *)(mpa_pic.opaque);
+
+    if (!directrendering)
+    {
+        AVPicture tmppicture;
+
+        VideoFrame *xf = picframe;
+        picframe = GetNVP()->GetNextVideoFrame(false);
+
+        unsigned char *buf     = picframe->buf;
+        avpicture_fill(&tmppicture, buf, PIX_FMT_YUV420P,
+ 	                   ctx->width, ctx->height);
+        tmppicture.data[0]     = buf + picframe->offsets[0];
+        tmppicture.data[1]     = buf + picframe->offsets[1];
+        tmppicture.data[2]     = buf + picframe->offsets[2];
+        tmppicture.linesize[0] = picframe->pitches[0];
+        tmppicture.linesize[1] = picframe->pitches[1];
+        tmppicture.linesize[2] = picframe->pitches[2];
+
+        sws_ctx = sws_getCachedContext(sws_ctx, ctx->width,
+                      ctx->height, ctx->pix_fmt,
+                      ctx->width, ctx->height,
+                      PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
+                      NULL, NULL, NULL);
+        if (!sws_ctx)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR +
+                    "Failed to allocate sws context");
+            return -1;
+        }
+        sws_scale(sws_ctx, mpa_pic.data, mpa_pic.linesize,
+                  0, ctx->height, tmppicture.data,
+                  tmppicture.linesize);
+
+        if (xf)
+        {
+            // Set the frame flags, but then discard it
+            // since we are not using it for display.
+            xf->interlaced_frame = mpa_pic.interlaced_frame;
+            xf->top_field_first = mpa_pic.top_field_first;
+            xf->frameNumber = framesPlayed;
+            GetNVP()->DiscardVideoFrame(xf);
+        }
+    }
+
+    long long temppts = pts;
+
+    // Validate the video pts against the last pts. If it's
+    // a little bit smaller, equal or not available, compute
+    // it from the last. Otherwise assume a wraparound.
+    if (!ringBuffer->isDVD() && temppts <= lastvpts &&
+        (temppts + 10000 > lastvpts || temppts <= 0))
+    {
+        temppts = lastvpts;
+        temppts += (long long)(1000 / fps);
+        // MPEG2/H264 frames can be repeated, update pts accordingly
+        temppts += (long long)(mpa_pic.repeat_pict * 500 / fps);
+    }
+
+    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)
+    {
+        int tblsize = mpa_pic.qstride *
+                      ((picframe->height + 15) / 16);
+
+        if (picframe->qstride != mpa_pic.qstride ||
+            picframe->qscale_table == NULL)
+        {
+            picframe->qstride = mpa_pic.qstride;
+            if (picframe->qscale_table)
+                delete [] picframe->qscale_table;
+            picframe->qscale_table = new unsigned char[tblsize];
+        }
+
+        memcpy(picframe->qscale_table, mpa_pic.qscale_table,
+               tblsize);
+    }
+*/
+
+    picframe->interlaced_frame = mpa_pic.interlaced_frame;
+    picframe->top_field_first  = mpa_pic.top_field_first;
+    picframe->repeat_pict      = mpa_pic.repeat_pict;
+    picframe->frameNumber      = framesPlayed;
+
+    GetNVP()->ReleaseNextVideoFrame(picframe, temppts);
+    if (d->HasMPEG2Dec() && mpa_pic.data[3])
+        ctx->release_buffer(ctx, &mpa_pic);
+
+    decoded_video_frame = picframe;
+    gotvideo            = true;
+    lastvpts            = temppts;
+    framesPlayed++;
+
+    return ret;
+
+}
+
+static void extract_mono_channel(uint channel, AudioInfo *audioInfo,
+                                 char *buffer, int bufsize)
+{
+    // Only stereo -> mono (left or right) is supported
+    if (audioInfo->channels != 2)
+        return;
+
+    if (channel >= (uint)audioInfo->channels)
+        return;
+
+    const uint samplesize = audioInfo->sample_size;
+    const uint samples    = bufsize / samplesize;
+    const uint halfsample = samplesize >> 1;
+
+    const char *from = (channel == 1) ? buffer + halfsample : buffer;
+    char *to         = (channel == 0) ? buffer + halfsample : buffer;
+
+    for (uint sample = 0; sample < samples;
+         (sample++), (from += samplesize), (to += samplesize))
+    {
+        memmove(to, from, halfsample);
+    }
+}
+
+int AvFormatDecoder::ProcessAudioPacket(const AVPacket *pkt,
+                                        const AVStream *stream,
+                                        uchar *ptr, int len, int &decoded,
+                                        bool firstloop)
+{
+    AVCodecContext *ctx     = stream->codec;
+    int ret                 = 0;
+    bool reselectAudioTrack = false, dts = false;
+    AC3HeaderInfo hdr;
+    char *s;
+
+    avcodeclock->lock();
+    int audIdx = selectedTrack[kTrackTypeAudio].av_stream_index;
+    int audSubIdx = selectedTrack[kTrackTypeAudio].av_substream_index;
+    avcodeclock->unlock();
+    /// HACK HACK HACK -- begin See #3731
+    if (!GetNVP()->HasAudioIn())
+    {
+        VERBOSE(VB_AUDIO, LOC + "Audio is disabled - trying to restart it");
+        reselectAudioTrack = true;
+    }
+    /// HACK HACK HACK -- end
+
+    // detect switches between stereo and dual languages
+    bool wasDual = audSubIdx != -1;
+    bool isDual  = ctx->avcodec_dual_language;
+    if ((wasDual && !isDual) || (!wasDual &&  isDual))
+    {
+        SetupAudioStreamSubIndexes(audIdx);
+        reselectAudioTrack = true;
+    }
+
+    // detect channels on streams that need
+    // to be decoded before we can know this
+    bool already_decoded = false;
+    if (!ctx->channels)
+    {
+        QMutexLocker locker(avcodeclock);
+        VERBOSE(VB_IMPORTANT,
+            LOC + QString("Setting channels to %1")
+                    .arg(audioOut.channels));
+
+        if (DoPassThrough(ctx))
+            ctx->channels = ctx->request_channels = 0;
+        else
+            ctx->channels = ctx->request_channels = audioOut.channels;
+
+        decoded = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+        ret = avcodec_decode_audio2(ctx, audioSamples, &decoded, ptr, len);
+        already_decoded = true;
+        reselectAudioTrack |= ctx->channels;
+    }
+
+    if (ctx->codec_id == CODEC_ID_AC3)
+    {
+        GetBitContext gbc;
+        init_get_bits(&gbc, ptr, len << 3);
+        if (!ff_ac3_parse_header(&gbc, &hdr)   &&
+            hdr.channels != last_ac3_channels)
+        {
+            VERBOSE(VB_AUDIO, LOC +
+                QString("AC3 changed from %1 to %2 channels (frame %3)")
+                    .arg(last_ac3_channels).arg(hdr.channels).arg(framesRead));
+
+            if ((framesRead - last_framesRead) > AUDIOMAXFRAMES ||
+                hdr.channels < last_ac3_channels)
+            {
+                ctx->channels = hdr.channels;
+            }
+
+            last_ac3_channels = hdr.channels;
+            last_framesRead = framesRead;
+            SetupAudioStream();
+        }
+    }
+
+    if (reselectAudioTrack)
+    {
+        QMutexLocker locker(avcodeclock);
+        currentTrack[kTrackTypeAudio]                  = -1;
+        selectedTrack[kTrackTypeAudio].av_stream_index = -1;
+        audIdx = audSubIdx = -1;
+        AutoSelectAudioTrack();
+        audIdx    = selectedTrack[kTrackTypeAudio].av_stream_index;
+        audSubIdx = selectedTrack[kTrackTypeAudio].av_substream_index;
+    }
+
+    if (!wantaudio || pkt->stream_index != audIdx)
+    {
+        decoded = 0;
+        return len;
+    }
+
+    if (firstloop && pkt->pts != (int64_t)AV_NOPTS_VALUE)
+        lastapts = (long long)(av_q2d(stream->time_base) * pkt->pts * 1000);
+
+    if (skipaudio)
+    {
+        if ((lastapts < lastvpts - (10.0 / fps)) || lastvpts == 0)
+        {
+            decoded = 0;
+            return len;
+        }
+        else
+            skipaudio = false;
+    }
+
+    avcodeclock->lock();
+    decoded = 0;
+
+    if (audioOut.do_passthru)
+    {
+        decoded = pkt->size;
+        dts = CODEC_ID_DTS == ctx->codec_id;
+        ret = encode_frame(dts, ptr, len, audioSamples, decoded);
+        s = (char *)audioSamples;
+    }
+    else
+    {
+        if (!ctx->channels || ctx->channels > audioOut.channels)
+            ctx->channels = audioOut.channels;
+
+        if (!already_decoded)
+        {
+            ctx->request_channels = audioOut.channels;
+            decoded = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+            ret = avcodec_decode_audio2(ctx, audioSamples, &decoded, ptr, len);
+        }
+
+        // Convert sample format if required (Myth only handles 8 and 16 bits audio)
+        if (ctx->sample_fmt == SAMPLE_FMT_S16 ||
+            ctx->sample_fmt == SAMPLE_FMT_U8  ||
+            (s = ConvertSampleFormat(ctx, decoded)) == NULL)
+        {
+            s = (char *)audioSamples;
+        }
+        // When decoding some audio streams the number of
+        // channels, etc isn't known until we try decoding it.
+        if ((ctx->sample_rate != audioOut.sample_rate) ||
+            (ctx->channels    != audioOut.channels))
+        {
+            VERBOSE(VB_IMPORTANT, LOC + "Audio stream changed");
+            currentTrack[kTrackTypeAudio]                  = -1;
+            selectedTrack[kTrackTypeAudio].av_stream_index = -1;
+            audIdx  = -1;
+            decoded =  0;
+            AutoSelectAudioTrack();
+        }
+    }
+    avcodeclock->unlock();
+
+    if (ret < 0)
+    {
+        if (!dts)
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "Unknown audio decoding error");
+        decoded = 0;
+        return len;
+    }
+
+    if (decoded <= 0)
+        return ret;
+
+    long long temppts = lastapts;
+
+    // calc for next frame
+    lastapts += (long long)((double)(decoded * 1000) /
+                (ctx->sample_rate * ctx->channels *
+                 av_get_bits_per_sample_format(ctx->sample_fmt)>>3));
+
+    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP,
+            LOC + QString("audio timecode %1 %2 %3 %4")
+                    .arg(pkt->pts).arg(pkt->dts).arg(temppts).arg(lastapts));
+
+    if (audSubIdx != -1)
+        extract_mono_channel(audSubIdx, &audioOut, s, decoded);
+
+    GetNVP()->AddAudioData(s, decoded, temppts);
+
+    return ret;
+
+}
+
+bool AvFormatDecoder::TopUpAudioBuffer(int decoded, uint total_decoded,
+                                       uint ofill,  uint othresh)
+{
+    uint fill, total;
+
+    if (ofill + total_decoded > othresh)
+        return true;
+
+    if (!GetNVP()->GetAudioBufferStatus(fill, total))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "GetFrame() : Failed to top off "
+                                        "buffers in audio only mode");
+        return false;
+    }
+
+    total /= 6; // HACK needed for some audio files
+    return (fill == 0) || (fill > (total>>1))    ||
+           ((total - fill) < (uint)decoded)      ||
+           (ofill + total_decoded > (total>>2))  ||
+           ((total - fill) < (uint)decoded * 2);
+}
+
 /** \fn AvFormatDecoder::ProcessVBIDataPacket(const AVStream*, const AVPacket*)
  *  \brief Process ivtv proprietary embedded vertical blanking
  *         interval captions.
@@ -3276,6 +3718,103 @@
 #endif // USING_MHEG
 }
 
+int AvFormatDecoder::ProcessSubtitlePacket(const AVPacket *pkt,
+                                           const AVStream *stream,
+                                           long long pts)
+{
+    uchar *ptr       = pkt->data;
+    int len          = pkt->size;
+    int gotSubtitles = 0;
+    AVSubtitle subtitle;
+    memset(&subtitle, 0, sizeof(AVSubtitle));
+    avcodeclock->lock();
+    int subIdx = selectedTrack[kTrackTypeSubtitle].av_stream_index;
+    avcodeclock->unlock();
+
+    if (ringBuffer->isDVD())
+    {
+        if (ringBuffer->DVD()->NumMenuButtons() > 0)
+            ringBuffer->DVD()->GetMenuSPUPkt(ptr, len, stream->id);
+        else
+        {
+            if (pkt->stream_index == subIdx)
+            {
+                QMutexLocker locker(avcodeclock);
+                ringBuffer->DVD()->DecodeSubtitles(&subtitle, &gotSubtitles,
+                                                   ptr, len);
+            }
+        }
+    }
+    else if (pkt->stream_index == subIdx)
+    {
+        QMutexLocker locker(avcodeclock);
+        avcodec_decode_subtitle(stream->codec, &subtitle, &gotSubtitles,
+                                ptr, len);
+    }
+
+    if (gotSubtitles)
+    {
+        subtitle.start_display_time += pts;
+        subtitle.end_display_time   += pts;
+        GetNVP()->AddAVSubtitle(subtitle);
+
+        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC +
+                QString("subtl timecode %1 %2 %3 %4")
+                    .arg(pkt->pts).arg(pkt->dts)
+                    .arg(subtitle.start_display_time)
+                    .arg(subtitle.end_display_time));
+    }
+
+    return len;
+}
+
+bool AvFormatDecoder::ProcessDataPacket(AVPacket *pkt, const AVStream *stream)
+{
+    AVCodecContext *ctx = stream->codec;
+
+    if (ctx->codec_id == CODEC_ID_MPEG2VBI)
+    {
+        ProcessVBIDataPacket(stream, pkt);
+        av_free_packet(pkt);
+        return true;
+    }
+
+    if (ctx->codec_id == CODEC_ID_DVB_VBI ||
+        ctx->codec_id == CODEC_ID_DVB_TELETEXT)
+    {
+        ProcessDVBDataPacket(stream, pkt);
+        av_free_packet(pkt);
+        return true;
+    }
+
+#ifdef USING_MHEG
+    if (ctx->codec_id == CODEC_ID_DSMCC_B)
+    {
+        ProcessDSMCCPacket(stream, pkt);
+        av_free_packet(pkt);
+        // Have to return regularly to ensure that the OSD is updated.
+        // This applies both to MHEG and also channel browsing.
+        if (!wantvideo)
+        {
+            allowedquit |= (itv && itv->ImageHasChanged());
+            OSD *osd = NULL;
+            if (!allowedquit && GetNVP() && (osd = GetNVP()->GetOSD()))
+                allowedquit |= osd->HasChanged();
+        }
+        return true;
+    }
+#endif // USING_MHEG
+
+    // we don't care about other data streams
+    if (ctx->codec_type == CODEC_TYPE_DATA)
+    {
+        av_free_packet(pkt);
+        return true;
+    }
+
+    return false;
+}
+
 int AvFormatDecoder::SetTrack(uint type, int trackNo)
 {
     bool ret = DecoderBase::SetTrack(type, trackNo);
@@ -3645,176 +4184,122 @@
     return selTrack;
 }
 
-static void extract_mono_channel(uint channel, AudioInfo *audioInfo,
-                                 char *buffer, int bufsize)
-{
-    // Only stereo -> mono (left or right) is supported
-    if (audioInfo->channels != 2)
-        return;
-
-    if (channel >= (uint)audioInfo->channels)
-        return;
-
-    const uint samplesize = audioInfo->sample_size;
-    const uint samples    = bufsize / samplesize;
-    const uint halfsample = samplesize >> 1;
-
-    const char *from = (channel == 1) ? buffer + halfsample : buffer;
-    char *to         = (channel == 0) ? buffer + halfsample : buffer;
-
-    for (uint sample = 0; sample < samples;
-         (sample++), (from += samplesize), (to += samplesize))
-    {
-        memmove(to, from, halfsample);
-    }
+AVPacket* AvFormatDecoder::GetPacket(AVPacket *pkt, bool storevideoframes)
+{
+    if (!storevideoframes && storedPackets.count() > 0)
+    {
+        if (pkt)
+        {
+            av_free_packet(pkt);
+            delete pkt;
+        }
+        pkt = storedPackets.takeFirst();
+        return pkt;
+    }
+
+    if (!pkt)
+    {
+        pkt = new AVPacket;
+        bzero(pkt, sizeof(AVPacket));
+        av_init_packet(pkt);
+    }
+
+    if (!ic || (av_read_frame(ic, pkt) < 0))
+    {
+        ateof = true;
+        GetNVP()->SetEof();
+        delete pkt;
+        return NULL;
+    }
+
+    if (ringBuffer->isDVD() && ringBuffer->DVD()->InStillFrame())
+    {
+        AVStream *curstream = ic->streams[pkt->stream_index];
+        if (curstream && curstream->codec->codec_type == CODEC_TYPE_VIDEO)
+        {
+            mpeg_seq_end_seen = decodeStillFrame = false;
+            ringBuffer->DVD()->InStillFrame(false);
+        }
+    }
+
+    if (waitingForChange && pkt->pos >= readAdjust)
+        FileChanged();
+
+    if (pkt->pos > readAdjust)
+        pkt->pos -= readAdjust;
+
+    return pkt;
 }
 
 // documented in decoderbase.h
 bool AvFormatDecoder::GetFrame(DecodeType decodetype)
 {
     AVPacket *pkt = NULL;
-    AC3HeaderInfo hdr;
-    int len;
+    int len, ret;
+    long long pts;
     unsigned char *ptr;
-    int data_size = 0;
-    long long pts;
-    bool firstloop = false, have_err = false;
-
+    bool firstloop = false;
+    bool storevideoframes = false;
+    bool has_video = HasVideo(ic);
+
+    wantvideo           = decodetype & kDecodeVideo;
+    wantaudio           = decodetype & kDecodeAudio;
     gotvideo = false;
-
-    frame_decoded = 0;
+    skipaudio           = (lastvpts == 0);
     decoded_video_frame = NULL;
-
-    bool allowedquit = false;
-    bool storevideoframes = false;
+    allowedquit         = false;
 
     avcodeclock->lock();
     AutoSelectTracks();
     avcodeclock->unlock();
 
-    bool skipaudio = (lastvpts == 0);
-
-    bool has_video = HasVideo(ic);
-
-    if (!has_video && (decodetype & kDecodeVideo))
+    if (wantvideo && !has_video)
     {
         gotvideo = GenerateDummyVideoFrame();
-        decodetype = (DecodeType)((int)decodetype & ~kDecodeVideo);
-        skipaudio = false;
+        wantvideo  = skipaudio = false;
     }
 
     uint ofill = 0, ototal = 0, othresh = 0, total_decoded_audio = 0;
     if (GetNVP()->GetAudioBufferStatus(ofill, ototal))
     {
         othresh =  ((ototal>>1) + (ototal>>2));
-        allowedquit = (!(decodetype & kDecodeAudio)) && (ofill > othresh);
+        allowedquit = !wantaudio && (ofill > othresh);
     }
 
     while (!allowedquit)
     {
-        if ((decodetype & kDecodeAudio) &&
+        if (wantaudio &&
             ((currentTrack[kTrackTypeAudio] < 0) ||
              (selectedTrack[kTrackTypeAudio].av_stream_index < 0)))
         {
             // disable audio request if there are no audio streams anymore
             // and we have video, otherwise allow decoding to stop
             if (has_video)
-                decodetype = (DecodeType)((int)decodetype & ~kDecodeAudio);
+                wantaudio = false;
             else
                 allowedquit = true;
         }
 
         if (ringBuffer->isDVD())
-        {
-            int dvdtitle  = 0;
-            int dvdpart = 0;
-            ringBuffer->DVD()->GetPartAndTitle(dvdpart, dvdtitle);
-            bool cellChanged = ringBuffer->DVD()->CellChanged();
-            bool inDVDStill = ringBuffer->DVD()->InStillFrame();
-            bool inDVDMenu  = ringBuffer->DVD()->IsInMenu();
-            int storedPktCount = storedPackets.count();
-            selectedVideoIndex = 0;
-            if (dvdTitleChanged)
-            {
-                if ((storedPktCount > 10 && !decodeStillFrame) ||
-                    decodeStillFrame)
-                {
-                    storevideoframes = false;
-                    dvdTitleChanged = false;
-                    ScanStreams(true);
-                }
-                else
-                    storevideoframes = true;
-            }
-            else
-            {
-                storevideoframes = false;
-
-                if (storedPktCount < 2 && !decodeStillFrame)
-                    storevideoframes = true;
-
-                VERBOSE(VB_PLAYBACK+VB_EXTRA, QString("DVD Playback Debugging "
-                    "inDVDMenu %1 storedPacketcount %2 dvdstill %3")
-                    .arg(inDVDMenu).arg(storedPktCount).arg(inDVDStill));
-
-                if (inDVDStill && (storedPktCount == 0) &&
-                    (GetNVP()->getVideoOutput()->ValidVideoFrames() == 0))
-                {
-                    ringBuffer->DVD()->RunSeekCellStart();
-                }
-            }
-            if (GetNVP()->AtNormalSpeed() &&
-                ((cellChanged) || (lastdvdtitle != dvdtitle)))
-            {
-                if (dvdtitle != lastdvdtitle)
-                {
-                    VERBOSE(VB_PLAYBACK, LOC + "DVD Title Changed");
-                    lastdvdtitle = dvdtitle;
-                    if (lastdvdtitle != -1 )
-                        dvdTitleChanged = true;
-                    if (GetNVP() && GetNVP()->getVideoOutput())
-                    {
-                        if (ringBuffer->DVD()->InStillFrame())
-                            GetNVP()->getVideoOutput()->SetPrebuffering(false);
-                        else
-                            GetNVP()->getVideoOutput()->SetPrebuffering(true);
-                    }
-                }
-
-                if (ringBuffer->DVD()->PGCLengthChanged())
-                {
-                    {
-                        QMutexLocker locker(&m_positionMapLock);
-                        posmapStarted = false;
-                        m_positionMap.clear();
-                    }
-                    SyncPositionMap();
-                }
-
-                UpdateDVDFramesPlayed();
-                VERBOSE(VB_PLAYBACK, QString(LOC + "DVD Cell Changed. "
-                                             "Update framesPlayed: %1 ")
-                                             .arg(framesPlayed));
-            }
-        }
+            storevideoframes = UpdateDVDStatus();
 
         if (gotvideo)
         {
-            if (decodetype == kDecodeNothing)
+            if (!wantvideo && !wantaudio)
             {
                 // no need to buffer audio or video if we
                 // only care about building a keyframe map.
                 allowedquit = true;
                 continue;
             }
-            else if (lowbuffers && ((decodetype & kDecodeAV) == kDecodeAV) &&
+            else if (lowbuffers && wantaudio && wantvideo &&
                      storedPackets.count() < max_video_queue_size &&
                      lastapts < lastvpts + 100 &&
                      !ringBuffer->InDVDMenuOrStillFrame())
             {
                 storevideoframes = true;
             }
-            else if (decodetype & kDecodeVideo)
+            else if (wantvideo)
             {
                 if (storedPackets.count() >= max_video_queue_size)
                     VERBOSE(VB_IMPORTANT,
@@ -3826,55 +4311,12 @@
             }
         }
 
-        if (!storevideoframes && storedPackets.count() > 0)
-        {
-            if (pkt)
-            {
-                av_free_packet(pkt);
-                delete pkt;
-            }
-            pkt = storedPackets.takeFirst();
-        }
-        else
-        {
-            if (!pkt)
-            {
-                pkt = new AVPacket;
-                bzero(pkt, sizeof(AVPacket));
-                av_init_packet(pkt);
-            }
-
-            if (!ic || (av_read_frame(ic, pkt) < 0))
-            {
-                ateof = true;
-                GetNVP()->SetEof();
-                delete pkt;
+        if ((pkt = GetPacket(pkt, storevideoframes)) == NULL)
                 return false;
-            }
-
-            if (ringBuffer->isDVD() &&
-                ringBuffer->DVD()->InStillFrame())
-            {
-                AVStream *curstream = ic->streams[pkt->stream_index];
-                if (curstream &&
-                    curstream->codec->codec_type == CODEC_TYPE_VIDEO)
-                {
-                    mpeg_seq_end_seen = false;
-                    decodeStillFrame = false;
-                    ringBuffer->DVD()->InStillFrame(false);
-                }
-            }
-
-            if (waitingForChange && pkt->pos >= readAdjust)
-                FileChanged();
-
-            if (pkt->pos > readAdjust)
-                pkt->pos -= readAdjust;
-        }
 
         if (pkt->stream_index > (int) ic->nb_streams)
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "Bad stream");
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "Packet stream index out of bounds");
             av_free_packet(pkt);
             continue;
         }
@@ -3883,9 +4325,10 @@
         ptr = pkt->data;
         pts = 0;
 
-        AVStream *curstream = ic->streams[pkt->stream_index];
-
-        if (!curstream)
+        AVStream *stream = ic->streams[pkt->stream_index];
+        AVCodecContext *ctx = stream->codec;
+
+        if (!stream)
         {
             VERBOSE(VB_IMPORTANT, LOC_ERR + "Bad stream (NULL)");;
             av_free_packet(pkt);
@@ -3893,12 +4336,194 @@
         }
 
         if (pkt->dts != (int64_t)AV_NOPTS_VALUE)
-            pts = (long long)(av_q2d(curstream->time_base) * pkt->dts * 1000);
-
-        if (ringBuffer->isDVD() &&
-            curstream->codec->codec_type == CODEC_TYPE_VIDEO)
-        {
-            MpegPreProcessPkt(curstream, pkt);
+            pts = (long long)(av_q2d(stream->time_base) * pkt->dts * 1000);
+
+        if (len <= 0)
+        {
+            av_free_packet(pkt);
+            continue;
+        }
+
+        if (ctx->codec_type == CODEC_TYPE_VIDEO)
+        {
+            if (ringBuffer->isDVD() && !PreProcessDVDVideoPacket(pkt, stream))
+                continue;
+
+            if (storevideoframes)
+            {
+                av_dup_packet(pkt);
+                storedPackets.append(pkt);
+                pkt = NULL;
+                continue;
+            }
+
+            if (pkt->stream_index == selectedVideoIndex)
+            {
+                if (!PreProcessVideoPacket(pkt, stream))
+                    continue;
+                // If the resolution changed in XXXPreProcessPkt, we may
+                // have a fatal error, so check for this before continuing.
+                if (GetNVP()->IsErrored())
+                {
+                    av_free_packet(pkt);
+                    delete pkt;
+                    return false;
+                }
+            }
+        }
+        else if ((ctx->codec_type == CODEC_TYPE_DATA      ||
+                  ctx->codec_type == CODEC_TYPE_SUBTITLE) &&
+                 ProcessDataPacket(pkt, stream))
+            continue;
+
+        if (!ctx->codec)
+        {
+            VERBOSE(VB_PLAYBACK, LOC +
+                    QString("No codec for stream index %1, type(%2) id(%3:%4)")
+                    .arg(pkt->stream_index)
+                    .arg(codec_type_string(ctx->codec_type))
+                    .arg(codec_id_string(ctx->codec_id))
+                    .arg(ctx->codec_id));
+            av_free_packet(pkt);
+            continue;
+        }
+
+        int ctype = ctx->codec_type;
+        firstloop = true;
+
+        while (len > 0)
+        {
+            switch (ctype)
+            {
+                case CODEC_TYPE_AUDIO:
+                    int decoded;
+                    ret = ProcessAudioPacket(pkt, stream, ptr, len,
+                                             decoded, firstloop);
+                    if (decoded <= 0)
+                        break;
+
+                    total_decoded_audio += decoded;
+                    allowedquit |= ringBuffer->InDVDMenuOrStillFrame();
+                    // top off audio buffers initially in audio only mode
+                    if (!allowedquit && !wantvideo)
+                        allowedquit = TopUpAudioBuffer(decoded,
+                                                       total_decoded_audio,
+                                                       ofill, othresh);
+                    break;
+                case CODEC_TYPE_VIDEO:
+                {
+                    ret = ProcessVideoPacket(pkt, stream, pts, firstloop);
+                    break;
+                }
+                case CODEC_TYPE_SUBTITLE:
+                {
+                    ret = ProcessSubtitlePacket(pkt, stream, pts);
+                    break;
+                }
+                default:
+                {
+                    VERBOSE(VB_IMPORTANT, LOC_ERR +
+                            QString("Decoding - id(%1) type(%2)")
+                                .arg(codec_id_string(ctx->codec_id))
+                                .arg(codec_type_string(ctx->codec_type)));
+                    ret = len;
+                    break;
+                }
+            }
+            ptr += ret;
+            len -= ret;
+            firstloop = false;
+        }
+        av_free_packet(pkt);
+    }
+
+    if (pkt)
+        delete pkt;
+
+    return true;
+}
+
+bool AvFormatDecoder::UpdateDVDStatus()
+{
+    int dvdtitle          = 0;
+    int dvdpart           = 0;
+    bool cellChanged      = ringBuffer->DVD()->CellChanged();
+    bool inDVDStill       = ringBuffer->DVD()->InStillFrame();
+    bool inDVDMenu        = ringBuffer->DVD()->IsInMenu();
+    int storedPktCount    = storedPackets.count();
+    bool storevideoframes = false;
+    selectedVideoIndex    = 0;
+
+    ringBuffer->DVD()->GetPartAndTitle(dvdpart, dvdtitle);
+
+    if (dvdTitleChanged)
+    {
+        if ((storedPktCount > 10 && !decodeStillFrame) || decodeStillFrame)
+        {
+            storevideoframes = dvdTitleChanged = false;
+            ScanStreams(true);
+        }
+        else
+            storevideoframes = true;
+    }
+    else
+    {
+        storevideoframes = false;
+
+        if (storedPktCount < 2 && !decodeStillFrame)
+            storevideoframes = true;
+
+        VERBOSE(VB_PLAYBACK+VB_EXTRA, QString("DVD Playback Debugging "
+            "inDVDMenu %1 storedPacketcount %2 dvdstill %3")
+            .arg(inDVDMenu).arg(storedPktCount).arg(inDVDStill));
+
+        if (inDVDStill && storedPktCount == 0 &&
+            GetNVP()->getVideoOutput()->ValidVideoFrames() == 0)
+        {
+            ringBuffer->DVD()->RunSeekCellStart();
+        }
+    }
+
+    if (GetNVP()->AtNormalSpeed() && (cellChanged || lastdvdtitle != dvdtitle))
+    {
+        if (dvdtitle != lastdvdtitle)
+        {
+            VERBOSE(VB_PLAYBACK, LOC + "DVD Title Changed");
+            lastdvdtitle = dvdtitle;
+            if (lastdvdtitle != -1)
+                dvdTitleChanged = true;
+            if (GetNVP() && GetNVP()->getVideoOutput())
+            {
+                if (ringBuffer->DVD()->InStillFrame())
+                    GetNVP()->getVideoOutput()->SetPrebuffering(false);
+                else
+                    GetNVP()->getVideoOutput()->SetPrebuffering(true);
+            }
+        }
+
+        if (ringBuffer->DVD()->PGCLengthChanged())
+        {
+            {
+                QMutexLocker locker(&m_positionMapLock);
+                posmapStarted = false;
+                m_positionMap.clear();
+            }
+            SyncPositionMap();
+        }
+
+        UpdateDVDFramesPlayed();
+        VERBOSE(VB_PLAYBACK, QString(LOC + "DVD Cell Changed. "
+                                     "Update framesPlayed: %1")
+                                     .arg(framesPlayed));
+    }
+
+    return storevideoframes;
+}
+
+bool AvFormatDecoder::PreProcessDVDVideoPacket(AVPacket *pkt, AVStream *stream)
+{
+
+    MpegPreProcessPkt(stream, pkt);
 
             if (mpeg_seq_end_seen)
                 ringBuffer->DVD()->InStillFrame(true);
@@ -3906,8 +4531,8 @@
             bool inDVDStill = ringBuffer->DVD()->InStillFrame();
 
             VERBOSE(VB_PLAYBACK+VB_EXTRA,
-                QString("DVD Playback Debugging: mpeg seq end %1 "
-                " inDVDStill %2 decodeStillFrame %3")
+            QString("DVD Playback Debugging: mpeg seq end %1 inDVDStill %2 "
+                    "decodeStillFrame %3")
                 .arg(mpeg_seq_end_seen).arg(inDVDStill).arg(decodeStillFrame));
 
             if (!decodeStillFrame && inDVDStill)
@@ -3918,34 +4543,31 @@
 
             if (!d->HasMPEG2Dec())
             {
-                int current_width = curstream->codec->width;
+        int current_width = stream->codec->width;
                 int video_width = GetNVP()->GetVideoSize().width();
                 if (dvd_xvmc_enabled && GetNVP() && GetNVP()->getVideoOutput())
                 {
-                    bool dvd_xvmc_active = false;
-                    if (codec_is_xvmc(video_codec_id))
-                    {
-                        dvd_xvmc_active = true;
-                    }
-
+            bool dvd_xvmc_active = codec_is_xvmc(video_codec_id);
                     bool indvdmenu   = ringBuffer->InDVDMenuOrStillFrame();
                     if ((indvdmenu && dvd_xvmc_active) ||
                         ((!indvdmenu && !dvd_xvmc_active)))
                     {
-                        VERBOSE(VB_PLAYBACK, LOC + QString("DVD Codec Change "
-                                    "indvdmenu %1 dvd_xvmc_active %2")
+                VERBOSE(VB_PLAYBACK, LOC +
+                        QString("DVD Codec Change indvdmenu %1 "
+                                "dvd_xvmc_active %2")
                                 .arg(indvdmenu).arg(dvd_xvmc_active));
                         dvd_video_codec_changed = true;
                     }
                 }
 
-                if ((video_width > 0) && dvd_video_codec_changed)
-                {
-                    VERBOSE(VB_PLAYBACK, LOC + QString("DVD Stream/Codec Change "
-                                "video_width %1 current_width %2 "
-                                "dvd_video_codec_changed %3")
+        if (video_width > 0 && dvd_video_codec_changed)
+        {
+            VERBOSE(VB_PLAYBACK, LOC +
+                    QString("DVD Stream/Codec Change video_width %1 "
+                            "current_width %2 dvd_video_codec_changed %3")
                             .arg(video_width).arg(current_width)
                             .arg(dvd_video_codec_changed));
+
                     av_free_packet(pkt);
                     if (current_width > 0) {
                         CloseCodecs();
@@ -3953,699 +4575,10 @@
                         allowedquit = true;
                         dvd_video_codec_changed = false;
                     }
-                    continue;
-                }
-            }
-        }
-
-        if (storevideoframes &&
-            curstream->codec->codec_type == CODEC_TYPE_VIDEO)
-        {
-            av_dup_packet(pkt);
-            storedPackets.append(pkt);
-            pkt = NULL;
-            continue;
-        }
-
-        if (len > 0 && curstream->codec->codec_type == CODEC_TYPE_VIDEO &&
-            pkt->stream_index == selectedVideoIndex)
-        {
-            AVCodecContext *context = curstream->codec;
-            bool on_frame = true;
-
-            if (CODEC_IS_FFMPEG_MPEG(context->codec_id))
-            {
-                if (!ringBuffer->isDVD())
-                    MpegPreProcessPkt(curstream, pkt);
-            }
-            else if (CODEC_IS_H264(context->codec_id))
-            {
-                on_frame = H264PreProcessPkt(curstream, pkt);
-            }
-            else
-            {
-                if (pkt->flags & PKT_FLAG_KEY)
-                {
-                    HandleGopStart(pkt, false);
-                    seen_gop = true;
-                }
-                else
-                {
-                    seq_count++;
-                    if (!seen_gop && seq_count > 1)
-                    {
-                        HandleGopStart(pkt, false);
-                    }
-                }
-            }
-
-            if (framesRead == 0 && !justAfterChange &&
-                !(pkt->flags & PKT_FLAG_KEY))
-            {
-                av_free_packet(pkt);
-                continue;
-            }
-
-            if (on_frame)
-                framesRead++;
-            justAfterChange = false;
-
-            if (exitafterdecoded)
-                gotvideo = 1;
-
-            // If the resolution changed in XXXPreProcessPkt, we may
-            // have a fatal error, so check for this before continuing.
-            if (GetNVP()->IsErrored())
-            {
-                av_free_packet(pkt);
-                delete pkt;
                 return false;
             }
         }
 
-        if (len > 0 &&
-            curstream->codec->codec_type == CODEC_TYPE_DATA &&
-            curstream->codec->codec_id   == CODEC_ID_MPEG2VBI)
-        {
-            ProcessVBIDataPacket(curstream, pkt);
-
-            av_free_packet(pkt);
-            continue;
-        }
-
-        if (len > 0 &&
-            ((curstream->codec->codec_type == CODEC_TYPE_DATA &&
-              curstream->codec->codec_id   == CODEC_ID_DVB_VBI) ||
-             (curstream->codec->codec_type == CODEC_TYPE_SUBTITLE &&
-              curstream->codec->codec_id   == CODEC_ID_DVB_TELETEXT)))
-        {
-            ProcessDVBDataPacket(curstream, pkt);
-
-            av_free_packet(pkt);
-            continue;
-        }
-
-#ifdef USING_MHEG
-        if (len > 0 &&
-            curstream->codec->codec_type == CODEC_TYPE_DATA &&
-            curstream->codec->codec_id   == CODEC_ID_DSMCC_B)
-        {
-            ProcessDSMCCPacket(curstream, pkt);
-
-            av_free_packet(pkt);
-
-            // Have to return regularly to ensure that the OSD is updated.
-            // This applies both to MHEG and also channel browsing.
-            if (!(decodetype & kDecodeVideo))
-            {
-                allowedquit |= (itv && itv->ImageHasChanged());
-                OSD *osd = NULL;
-                if (!allowedquit && GetNVP() && (osd = GetNVP()->GetOSD()))
-                    allowedquit |=  osd->HasChanged();
-            }
-
-            continue;
-        }
-#endif // USING_MHEG
-
-        // we don't care about other data streams
-        if (curstream->codec->codec_type == CODEC_TYPE_DATA)
-        {
-            av_free_packet(pkt);
-            continue;
-        }
-
-        if (!curstream->codec->codec)
-        {
-            VERBOSE(VB_PLAYBACK, LOC +
-                    QString("No codec for stream index %1, type(%2) id(%3:%4)")
-                    .arg(pkt->stream_index)
-                    .arg(codec_type_string(curstream->codec->codec_type))
-                    .arg(codec_id_string(curstream->codec->codec_id))
-                    .arg(curstream->codec->codec_id));
-            av_free_packet(pkt);
-            continue;
-        }
-
-        firstloop = true;
-        have_err = false;
-
-        avcodeclock->lock();
-        int ctype  = curstream->codec->codec_type;
-        int audIdx = selectedTrack[kTrackTypeAudio].av_stream_index;
-        int audSubIdx = selectedTrack[kTrackTypeAudio].av_substream_index;
-        int subIdx = selectedTrack[kTrackTypeSubtitle].av_stream_index;
-        avcodeclock->unlock();
-
-        while (!have_err && len > 0)
-        {
-            int ret = 0;
-            bool dts = false;
-            switch (ctype)
-            {
-                case CODEC_TYPE_AUDIO:
-                {
-                    bool reselectAudioTrack = false;
-                    char *s;
-
-                    /// HACK HACK HACK -- begin See #3731
-                    if (!GetNVP()->HasAudioIn())
-                    {
-                        VERBOSE(VB_AUDIO, LOC + "Audio is disabled - trying to restart it");
-                        reselectAudioTrack = true;
-                    }
-                    /// HACK HACK HACK -- end
-
-                    // detect switches between stereo and dual languages
-                    bool wasDual = audSubIdx != -1;
-                    bool isDual = curstream->codec->avcodec_dual_language;
-                    if ((wasDual && !isDual) || (!wasDual &&  isDual))
-                    {
-                        SetupAudioStreamSubIndexes(audIdx);
-                        reselectAudioTrack = true;
-                    }
-
-                    // detect channels on streams that need
-                    // to be decoded before we can know this
-                    bool already_decoded = false;
-                    if (!curstream->codec->channels)
-                    {
-                        QMutexLocker locker(avcodeclock);
-                        VERBOSE(VB_IMPORTANT, LOC +
-                                QString("Setting channels to %1")
-                                .arg(audioOut.channels));
-
-                        if (DoPassThrough(curstream->codec))
-                        {
-                            // for passthru let it select the max number
-                            // of channels
-                            curstream->codec->channels = 0;
-                            curstream->codec->request_channels = 0;
-                        }
-                        else
-                        {
-                            curstream->codec->channels = audioOut.channels;
-                            curstream->codec->request_channels =
-                                audioOut.channels;
-                        }
-                        data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
-                        ret = avcodec_decode_audio2(curstream->codec,
-                                                    audioSamples, &data_size,
-                                                    ptr, len);
-                        already_decoded = true;
-
-                        reselectAudioTrack |= curstream->codec->channels;
-                    }
-
-                    if (curstream->codec->codec_id == CODEC_ID_AC3)
-                    {
-                        GetBitContext gbc;
-                        init_get_bits(&gbc, ptr, len * 8);
-                        if (!ff_ac3_parse_header(&gbc, &hdr))
-                        {
-                            if (hdr.channels != last_ac3_channels)
-                            {
-                                VERBOSE(VB_AUDIO, LOC + QString("AC3 changed from %1 to %2 channels (frame %3)")
-                                        .arg(last_ac3_channels).arg(hdr.channels).arg(framesRead));
-                                if ((framesRead - last_framesRead) > AUDIOMAXFRAMES ||
-                                    hdr.channels < last_ac3_channels)
-                                    curstream->codec->channels = hdr.channels;
-                                last_ac3_channels = hdr.channels;
-                                last_framesRead = framesRead;
-                                SetupAudioStream();
-                            }
-                        }
-                    }
-
-                    if (reselectAudioTrack)
-                    {
-                        QMutexLocker locker(avcodeclock);
-                        currentTrack[kTrackTypeAudio] = -1;
-                        selectedTrack[kTrackTypeAudio]
-                            .av_stream_index = -1;
-                        audIdx = -1;
-                        audSubIdx = -1;
-                        AutoSelectAudioTrack();
-                        audIdx = selectedTrack[kTrackTypeAudio]
-                            .av_stream_index;
-                        audSubIdx = selectedTrack[kTrackTypeAudio]
-                            .av_substream_index;
-                    }
-
-                    if (!(decodetype & kDecodeAudio) ||
-                        (pkt->stream_index != audIdx))
-                    {
-                        ptr += len;
-                        len = 0;
-                        continue;
-                    }
-
-                    if (firstloop && pkt->pts != (int64_t)AV_NOPTS_VALUE)
-                        lastapts = (long long)(av_q2d(curstream->time_base) *
-                                               pkt->pts * 1000);
-
-                    if (skipaudio)
-                    {
-                        if ((lastapts < lastvpts - (10.0 / fps)) ||
-                            lastvpts == 0)
-                        {
-                            ptr += len;
-                            len = 0;
-                            continue;
-                        }
-                        else
-                            skipaudio = false;
-                    }
-
-                    avcodeclock->lock();
-                    data_size = 0;
-
-                    if (audioOut.do_passthru)
-                    {
-                        data_size = pkt->size;
-                        dts = CODEC_ID_DTS == curstream->codec->codec_id;
-                        ret = encode_frame(dts, ptr, len,
-                                           audioSamples, data_size);
-                        s = (char *)audioSamples;
-                    }
-                    else
-                    {
-                        AVCodecContext *ctx = curstream->codec;
-
-                        if ((ctx->channels == 0) ||
-                            (ctx->channels > audioOut.channels))
-                        {
-                            ctx->channels = audioOut.channels;
-                        }
-
-                        if (!already_decoded)
-                        {
-                            curstream->codec->request_channels =
-                                audioOut.channels;
-                            data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
-                            ret = avcodec_decode_audio2(ctx, audioSamples,
-                                                        &data_size, ptr, len);
-                        }
-
-                            // Convert sample format if required (Myth only handles 8 and 16 bits audio)
-                        if (ctx->sample_fmt != SAMPLE_FMT_S16 && ctx->sample_fmt != SAMPLE_FMT_U8)
-                        {
-                            if (audio_src_fmt != ctx->sample_fmt)
-                            {
-                                if (reformat_ctx)
-                                    av_audio_convert_free(reformat_ctx);
-                                reformat_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, 1,
-                                                                      ctx->sample_fmt, 1,
-                                                                      NULL, 0);
-                                if (!reformat_ctx ||
-                                    (!audioSamplesResampled &&
-                                    !(audioSamplesResampled = (short int *)av_mallocz(AVCODEC_MAX_AUDIO_FRAME_SIZE *
-                                                                                      sizeof(*audioSamplesResampled)))))
-                                {
-                                    VERBOSE(VB_PLAYBACK, QString("Cannot convert %1 sample format to %2 sample format")
-                                            .arg(avcodec_get_sample_fmt_name(ctx->sample_fmt))
-                                            .arg(avcodec_get_sample_fmt_name(SAMPLE_FMT_S16)));
-
-                                    avcodeclock->unlock();
-                                    have_err = true;
-                                    continue;
-                                }
-                                audio_src_fmt = ctx->sample_fmt;
-                            }
-                        }
-
-                        if (reformat_ctx)
-                        {
-                            const void *ibuf[6] = {audioSamples};
-                            void *obuf[6] = {audioSamplesResampled};
-                            int istride[6] = {av_get_bits_per_sample_format(ctx->sample_fmt)/8};
-                            int ostride[6] = {2};
-                            int len = data_size/istride[0];
-                            if (av_audio_convert(reformat_ctx, obuf, ostride,
-                                                 ibuf, istride, len) < 0)
-                            {
-                                VERBOSE(VB_PLAYBACK, "av_audio_convert() failed");
-
-                                avcodeclock->unlock();
-                                have_err = true;
-                                continue;
-                            }
-
-                            data_size = len * 2;
-                            s = (char *)audioSamplesResampled;
-                        }
-                        else
-                            s = (char *)audioSamples;
-
-                        // When decoding some audio streams the number of
-                        // channels, etc isn't known until we try decoding it.
-                        if ((ctx->sample_rate != audioOut.sample_rate) ||
-                            (ctx->channels    != audioOut.channels))
-                        {
-                            VERBOSE(VB_IMPORTANT, "audio stream changed");
-                            currentTrack[kTrackTypeAudio] = -1;
-                            selectedTrack[kTrackTypeAudio]
-                                .av_stream_index = -1;
-                            audIdx = -1;
-                            AutoSelectAudioTrack();
-                            data_size = 0;
-                        }
-                    }
-                    avcodeclock->unlock();
-
-                    if (ret < 0)
-                    {
-                        if (!dts)
-                        {
-                            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                                    "Unknown audio decoding error");
-                        }
-                        have_err = true;
-                        continue;
-                    }
-
-                    if (data_size <= 0)
-                    {
-                        ptr += ret;
-                        len -= ret;
-                        continue;
-                    }
-
-                    long long temppts = lastapts;
-
-                    // calc for next frame
-                    lastapts += (long long)((double)(data_size * 1000) /
-                                (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));
-
-                    if (audSubIdx != -1)
-                    {
-                        extract_mono_channel(audSubIdx, &audioOut,
-                                             s, data_size);
-                    }
-
-                    GetNVP()->AddAudioData(s, data_size, temppts);
-
-                    total_decoded_audio += data_size;
-
-                    allowedquit |= ringBuffer->InDVDMenuOrStillFrame();
-                    allowedquit |= !(decodetype & kDecodeVideo) &&
-                        (ofill + total_decoded_audio > othresh);
-
-                    // top off audio buffers initially in audio only mode
-                    if (!allowedquit && !(decodetype & kDecodeVideo))
-                    {
-                        uint fill, total;
-                        if (GetNVP()->GetAudioBufferStatus(fill, total))
-                        {
-                            total /= 6; // HACK needed for some audio files
-                            allowedquit =
-                                (fill == 0) || (fill > (total>>1)) ||
-                                ((total - fill) < (uint) data_size) ||
-                                (ofill + total_decoded_audio > (total>>2)) ||
-                                ((total - fill) < (uint) data_size * 2);
-                        }
-                        else
-                        {
-                            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                                    "GetFrame() : Failed to top off "
-                                    "buffers in audio only mode");
-                        }
-                    }
-
-                    break;
-                }
-                case CODEC_TYPE_VIDEO:
-                {
-                    if (pkt->stream_index != selectedVideoIndex)
-                    {
-                        ptr += pkt->size;
-                        len -= pkt->size;
-                        continue;
-                    }
-
-                    if (firstloop && pts != (int64_t) AV_NOPTS_VALUE)
-                    {
-                        lastccptsu = (long long)
-                            (av_q2d(curstream->time_base)*pkt->pts*1000000);
-                    }
-
-                    if (!(decodetype & kDecodeVideo))
-                    {
-                        framesPlayed++;
-                        gotvideo = 1;
-                        ptr += pkt->size;
-                        len -= pkt->size;
-                        continue;
-                    }
-
-                    AVCodecContext *context = curstream->codec;
-                    AVFrame mpa_pic;
-                    bzero(&mpa_pic, sizeof(AVFrame));
-
-                    int gotpicture = 0;
-
-                    avcodeclock->lock();
-                    if (d->HasDecoder())
-                    {
-                        if (decodeStillFrame)
-                        {
-                            int count = 0;
-                            // HACK
-                            while (!gotpicture && count < 5)
-                            {
-                                ret = d->DecodeMPEG2Video(context, &mpa_pic,
-                                                  &gotpicture, ptr, len);
-                                count++;
-                            }
-                        }
-                        else
-                        {
-                            ret = d->DecodeMPEG2Video(context, &mpa_pic,
-                                                &gotpicture, ptr, len);
-                        }
-                    }
-                    else
-                    {
-                        ret = avcodec_decode_video(context, &mpa_pic,
-                                                   &gotpicture, ptr, len);
-                        // Reparse it to not drop the DVD still frame
-                        if (decodeStillFrame)
-                            ret = avcodec_decode_video(context, &mpa_pic,
-                                                        &gotpicture, ptr, len);
-                    }
-                    avcodeclock->unlock();
-
-                    if (ret < 0)
-                    {
-                        VERBOSE(VB_IMPORTANT, LOC_ERR +
-                                "Unknown decoding error");
-                        have_err = true;
-                        continue;
-                    }
-
-                    if (!gotpicture)
-                    {
-                        ptr += ret;
-                        len -= ret;
-                        continue;
-                    }
-
-                    // Decode CEA-608 and CEA-708 captions
-                    for (uint i = 0; i < (uint)mpa_pic.atsc_cc_len;
-                         i += ((mpa_pic.atsc_cc_buf[i] & 0x1f) * 3) + 2)
-                    {
-                        DecodeDTVCC(mpa_pic.atsc_cc_buf + i,
-                                    mpa_pic.atsc_cc_len - i);
-                    }
-
-                    VideoFrame *picframe = (VideoFrame *)(mpa_pic.opaque);
-
-                    if (!directrendering)
-                    {
-                        AVPicture tmppicture;
-
-                        VideoFrame *xf = picframe;
-                        picframe = GetNVP()->GetNextVideoFrame(false);
-
-                        unsigned char *buf = picframe->buf;
-                        avpicture_fill(&tmppicture, buf, PIX_FMT_YUV420P,
-                                       context->width, context->height);
-                        tmppicture.data[0] = buf + picframe->offsets[0];
-                        tmppicture.data[1] = buf + picframe->offsets[1];
-                        tmppicture.data[2] = buf + picframe->offsets[2];
-                        tmppicture.linesize[0] = picframe->pitches[0];
-                        tmppicture.linesize[1] = picframe->pitches[1];
-                        tmppicture.linesize[2] = picframe->pitches[2];
-
-                        sws_ctx = sws_getCachedContext(sws_ctx, context->width,
-                                      context->height, context->pix_fmt,
-                                      context->width, context->height,
-                                      PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
-                                      NULL, NULL, NULL);
-                        if (!sws_ctx)
-                        {
-                            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                                    "Failed to allocate sws context");
-                            have_err = true;
-                            continue;
-                        }
-                        sws_scale(sws_ctx, mpa_pic.data, mpa_pic.linesize,
-                                  0, context->height, tmppicture.data,
-                                  tmppicture.linesize);
-
-
-                        if (xf)
-                        {
-                            // Set the frame flags, but then discard it
-                            // since we are not using it for display.
-                            xf->interlaced_frame = mpa_pic.interlaced_frame;
-                            xf->top_field_first = mpa_pic.top_field_first;
-                            xf->frameNumber = framesPlayed;
-                            GetNVP()->DiscardVideoFrame(xf);
-                        }
-                    }
-
-                    long long temppts = pts;
-
-                    // Validate the video pts against the last pts. If it's
-                    // a little bit smaller, equal or not available, compute
-                    // it from the last. Otherwise assume a wraparound.
-                    if (!ringBuffer->isDVD() &&
-                        temppts <= lastvpts &&
-                        (temppts + 10000 > lastvpts || temppts <= 0))
-                    {
-                        temppts = lastvpts;
-                        temppts += (long long)(1000 / fps);
-                        // MPEG2/H264 frames can be repeated, update pts accordingly
-                        temppts += (long long)(mpa_pic.repeat_pict * 500 / fps);
-                    }
-
-                    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)
-                    {
-                        int tblsize = mpa_pic.qstride *
-                                      ((picframe->height + 15) / 16);
-
-                        if (picframe->qstride != mpa_pic.qstride ||
-                            picframe->qscale_table == NULL)
-                        {
-                            picframe->qstride = mpa_pic.qstride;
-                            if (picframe->qscale_table)
-                                delete [] picframe->qscale_table;
-                            picframe->qscale_table = new unsigned char[tblsize];
-                        }
-
-                        memcpy(picframe->qscale_table, mpa_pic.qscale_table,
-                               tblsize);
-                    }
-*/
-
-                    picframe->interlaced_frame = mpa_pic.interlaced_frame;
-                    picframe->top_field_first = mpa_pic.top_field_first;
-                    picframe->repeat_pict = mpa_pic.repeat_pict;
-
-                    picframe->frameNumber = framesPlayed;
-                    GetNVP()->ReleaseNextVideoFrame(picframe, temppts);
-                    if (d->HasMPEG2Dec() && mpa_pic.data[3])
-                        context->release_buffer(context, &mpa_pic);
-
-                    decoded_video_frame = picframe;
-                    gotvideo = 1;
-                    framesPlayed++;
-
-                    lastvpts = temppts;
-                    break;
-                }
-                case CODEC_TYPE_SUBTITLE:
-                {
-                    int gotSubtitles = 0;
-                    AVSubtitle subtitle;
-                    memset(&subtitle, 0, sizeof(AVSubtitle));
-
-                    if (ringBuffer->isDVD())
-                    {
-                        if (ringBuffer->DVD()->NumMenuButtons() > 0)
-                        {
-                            ringBuffer->DVD()->GetMenuSPUPkt(ptr, len,
-                                                             curstream->id);
-                        }
-                        else
-                        {
-                            if (pkt->stream_index == subIdx)
-                            {
-                                QMutexLocker locker(avcodeclock);
-                                ringBuffer->DVD()->DecodeSubtitles(&subtitle,
-                                                                   &gotSubtitles,
-                                                                   ptr, len);
-                            }
-                        }
-                    }
-                    else if (pkt->stream_index == subIdx)
-                    {
-                        QMutexLocker locker(avcodeclock);
-                        avcodec_decode_subtitle(curstream->codec,
-                                                &subtitle, &gotSubtitles,
-                                                ptr, len);
-                    }
-
-                    // the subtitle decoder always consumes the whole packet
-                    ptr += len;
-                    len = 0;
-
-                    if (gotSubtitles)
-                    {
-                        subtitle.start_display_time += pts;
-                        subtitle.end_display_time += pts;
-                        GetNVP()->AddAVSubtitle(subtitle);
-
-                        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC +
-                                QString("subtl timecode %1 %2 %3 %4")
-                                .arg(pkt->pts).arg(pkt->dts)
-                                .arg(subtitle.start_display_time)
-                                .arg(subtitle.end_display_time));
-                    }
-
-                    break;
-                }
-                default:
-                {
-                    AVCodecContext *enc = curstream->codec;
-                    VERBOSE(VB_IMPORTANT, LOC_ERR +
-                            QString("Decoding - id(%1) type(%2)")
-                            .arg(codec_id_string(enc->codec_id))
-                            .arg(codec_type_string(enc->codec_type)));
-                    have_err = true;
-                    break;
-                }
-            }
-
-            if (!have_err)
-            {
-                ptr += ret;
-                len -= ret;
-                frame_decoded = 1;
-                firstloop = false;
-            }
-        }
-
-        av_free_packet(pkt);
-    }
-
-    if (pkt)
-        delete pkt;
-
     return true;
 }
 
@@ -4905,6 +4838,53 @@
     return true;
 }
 
+char* AvFormatDecoder::ConvertSampleFormat(const AVCodecContext *ctx,
+                                           int &decoded)
+{
+    if (audio_src_fmt != ctx->sample_fmt)
+    {
+        if (reformat_ctx)
+            av_audio_convert_free(reformat_ctx);
+        reformat_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, 1,
+                                              ctx->sample_fmt, 1, NULL, 0);
+
+        if (!reformat_ctx ||
+            (!audioSamplesResampled &&
+             !(audioSamplesResampled =
+                (short int *)av_mallocz(AVCODEC_MAX_AUDIO_FRAME_SIZE *
+                                        sizeof(*audioSamplesResampled)))))
+        {
+            VERBOSE(VB_PLAYBACK,
+                QString("Cannot convert %1 sample format to %2 sample format")
+                    .arg(avcodec_get_sample_fmt_name(ctx->sample_fmt))
+                    .arg(avcodec_get_sample_fmt_name(SAMPLE_FMT_S16)));
+            return NULL;
+        }
+
+        audio_src_fmt = ctx->sample_fmt;
+    }
+
+    if (reformat_ctx)
+    {
+        const void *ibuf[6] = {audioSamples};
+        void *obuf[6]       = {audioSamplesResampled};
+        int is[6]         = {av_get_bits_per_sample_format(ctx->sample_fmt)>>3};
+        int os[6]           = {2};
+        int samples         = decoded / is[0];
+
+        if (av_audio_convert(reformat_ctx, obuf, os, ibuf, is, samples) < 0)
+        {
+            VERBOSE(VB_PLAYBACK, "av_audio_convert() failed");
+            return NULL;
+        }
+
+        decoded = samples << 1;
+        return (char *)audioSamplesResampled;
+    }
+
+    return NULL;
+}
+
 static int encode_frame(bool dts, unsigned char *data, int len,
                         short *samples, int &samples_size)
 {
