Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 21008)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -182,6 +182,225 @@
 typedef MythDeque<AVFrame*> avframe_q;
 
 /**
+ * Queues for AVPackets
+ */
+
+struct CountedPacket
+{
+        uint64_t    count;
+        AVPacket   *packet;
+};
+
+class AVPacketQueues
+{
+    public:
+        AVPacketQueues()
+            : m_count(0) { ; }
+        ~AVPacketQueues();
+
+        void Flush(void);
+        bool IsFilled(void);
+        void PrintQueueStatus(void);
+        CountedPacket *TakeFirstPacket(enum CodecType type);
+        AVPacket *NextPacket(void);
+        void PushBack(AVPacket *pkt, enum CodecType);
+
+    private:
+        QList<CountedPacket*> m_videoPacketQueue;
+        QList<CountedPacket*> m_audioPacketQueue;
+        QList<CountedPacket*> m_subtitlePacketQueue;
+        QList<CountedPacket*> m_dataPacketQueue;
+        uint64_t              m_count;
+};
+
+AVPacketQueues::~AVPacketQueues()
+{
+    Flush();
+}
+
+static void flush_packet_queue(QList<CountedPacket*> pq)
+{
+    while (!pq.isEmpty())
+    {
+        CountedPacket *pkt = pq.takeFirst();
+        av_free_packet(pkt->packet);
+        av_free(pkt->packet);
+        delete pkt;
+    }
+}
+
+void AVPacketQueues::Flush(void)
+{
+    flush_packet_queue(m_videoPacketQueue);
+    flush_packet_queue(m_audioPacketQueue);
+    flush_packet_queue(m_subtitlePacketQueue);
+    flush_packet_queue(m_dataPacketQueue);
+}
+
+bool AVPacketQueues::IsFilled(void)
+{
+    bool filled =
+         m_videoPacketQueue.count()    &&
+         m_audioPacketQueue.count()    &&
+         m_subtitlePacketQueue.count() &&
+         m_dataPacketQueue.count();
+
+    filled |= m_videoPacketQueue.count() > 100;
+    filled |= m_audioPacketQueue.count() > 250;
+
+    return filled;
+}
+
+void AVPacketQueues::PrintQueueStatus(void)
+{
+    VERBOSE(VB_IMPORTANT, QString("packet queue status %1, v:%2, a:%3, s:%4, d:%5")
+            .arg(IsFilled())
+            .arg(m_videoPacketQueue.count())
+            .arg(m_audioPacketQueue.count())
+            .arg(m_subtitlePacketQueue.count())
+            .arg(m_dataPacketQueue.count()));
+}
+
+CountedPacket *AVPacketQueues::TakeFirstPacket(enum CodecType type)
+{
+    CountedPacket *pkt = NULL;
+
+    switch (type)
+    {
+        case CODEC_TYPE_VIDEO:
+            if (!m_videoPacketQueue.isEmpty())
+                pkt = m_videoPacketQueue.takeFirst();
+            break;
+        case CODEC_TYPE_AUDIO:
+            if (!m_audioPacketQueue.isEmpty())
+                pkt = m_audioPacketQueue.takeFirst();
+            break;
+        case CODEC_TYPE_SUBTITLE:
+            if (!m_subtitlePacketQueue.isEmpty())
+                pkt = m_subtitlePacketQueue.takeFirst();
+            break;
+        case CODEC_TYPE_DATA:
+            if (!m_dataPacketQueue.isEmpty())
+                pkt = m_dataPacketQueue.takeFirst();
+            break;
+        default:
+            return NULL;
+    }
+
+    return pkt;
+}
+
+static void find_min_packet(CountedPacket* pkt, int64_t &min_pts, uint64_t &min_pts_count,
+                            enum CodecType &nextq_pts,
+                            uint64_t &min_count, enum CodecType &nextq_count,
+                            enum CodecType type)
+{
+    int64_t pts = pkt->packet->dts;
+
+    if (pts != (int64_t)AV_NOPTS_VALUE && (min_pts == (int64_t)AV_NOPTS_VALUE || pts < min_pts))
+    {
+        min_pts       = pts;
+        min_pts_count = pkt->count;
+        nextq_pts     = type;
+    }
+    if (pts == (int64_t)AV_NOPTS_VALUE && pkt->count < min_count)
+    {
+        min_count   = pkt->count;
+        nextq_count = type;
+    }
+}
+
+AVPacket *AVPacketQueues::NextPacket(void)
+{
+    CountedPacket *pkt       = NULL;
+    int64_t        min_pts   = (int64_t)AV_NOPTS_VALUE;
+    uint64_t       min_count = ~0ULL;
+
+    uint64_t       min_pts_count;
+    enum CodecType nextq_pts, nextq_count;
+
+    if (!m_videoPacketQueue.isEmpty())
+    {
+        pkt = m_videoPacketQueue.first();
+        find_min_packet(pkt, min_pts, min_pts_count, nextq_pts, min_count,
+                        nextq_count, CODEC_TYPE_VIDEO);
+    }
+    if (!m_audioPacketQueue.isEmpty())
+    {
+        pkt = m_audioPacketQueue.first();
+        find_min_packet(pkt, min_pts, min_pts_count, nextq_pts, min_count,
+                        nextq_count, CODEC_TYPE_AUDIO);
+    }
+    if (!m_subtitlePacketQueue.isEmpty())
+    {
+        pkt = m_subtitlePacketQueue.first();
+        find_min_packet(pkt, min_pts, min_pts_count, nextq_pts, min_count,
+                        nextq_count, CODEC_TYPE_SUBTITLE);
+    }
+    if (!m_dataPacketQueue.isEmpty())
+    {
+        pkt = m_dataPacketQueue.first();
+        find_min_packet(pkt, min_pts, min_pts_count, nextq_pts, min_count,
+                        nextq_count, CODEC_TYPE_DATA);
+    }
+
+    if (min_pts != (int64_t)AV_NOPTS_VALUE && min_pts_count <= min_count)
+    {
+//         VERBOSE(VB_IMPORTANT, QString("Taking one %1 packet count %2 pts %3 - other_cnt %4")
+//                 .arg(nextq_pts).arg(min_pts_count).arg(min_pts).arg(min_count));
+        pkt = TakeFirstPacket(nextq_pts);
+    }
+    else if (min_count < ~0ULL)
+    {
+//         VERBOSE(VB_IMPORTANT, QString("Taking one %1 packet count %2 - pts %3 other_cnt %4")
+//                 .arg(nextq_count).arg(min_count).arg(min_pts).arg(min_pts_count));
+        pkt = TakeFirstPacket(nextq_count);
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, "no packet found");
+        return NULL;
+    }
+
+    AVPacket *packet = pkt->packet;
+    delete pkt;
+
+    return packet;
+}
+
+void AVPacketQueues::PushBack(AVPacket *pkt, enum CodecType type)
+{
+    av_dup_packet(pkt);
+
+//     VERBOSE(VB_IMPORTANT, QString("Adding packet %1 with type %2")
+//             .arg(m_count).arg((int)type));
+
+    CountedPacket *cpkt = new CountedPacket();
+    cpkt->count  = m_count++;
+    cpkt->packet = pkt;
+
+    switch (type)
+    {
+        case CODEC_TYPE_VIDEO:
+            m_videoPacketQueue.push_back(cpkt);
+            break;
+        case CODEC_TYPE_AUDIO:
+            m_audioPacketQueue.push_back(cpkt);
+            break;
+        case CODEC_TYPE_SUBTITLE:
+            m_subtitlePacketQueue.push_back(cpkt);
+            break;
+        case CODEC_TYPE_DATA:
+            m_dataPacketQueue.push_back(cpkt);
+            break;
+        default:
+            av_free_packet(pkt);
+            av_free(pkt);
+            return;
+    }
+}
+
+/**
  * Management of libmpeg2 decoding
  */
 class AvFormatDecoderPrivate
@@ -439,7 +658,7 @@
       m_h264_parser(new H264Parser()),
       ic(NULL),
       frame_decoded(0),             decoded_video_frame(NULL),
-      avfRingBuffer(NULL),
+      avfRingBuffer(NULL),          m_packet_queue(new AVPacketQueues()),
       directrendering(false),       drawband(false),
       gopset(false),                seen_gop(false),
       seq_count(0),                 firstgoppos(0),
@@ -494,12 +713,7 @@
 
 AvFormatDecoder::~AvFormatDecoder()
 {
-    while (!storedPackets.isEmpty())
-    {
-        AVPacket *pkt = storedPackets.takeFirst();
-        av_free_packet(pkt);
-        delete pkt;
-    }
+    delete m_packet_queue;
 
     CloseContext();
     delete ccd608;
@@ -727,12 +941,7 @@
     if (doflush)
     {
         // Free up the stored up packets
-        while (!storedPackets.isEmpty())
-        {
-            AVPacket *pkt = storedPackets.takeFirst();
-            av_free_packet(pkt);
-            delete pkt;
-        }
+        m_packet_queue->Flush();
 
         prevgoppos = 0;
         gopset = false;
@@ -3193,6 +3402,63 @@
     }
 }
 
+
+AVPacket *AvFormatDecoder::GetNextPacket()
+{
+    if (!ic)
+        return NULL;
+
+//     m_packet_queue->PrintQueueStatus();
+
+    while (!m_packet_queue->IsFilled())
+    {
+        AVPacket *pkt = (AVPacket*)av_mallocz(sizeof(AVPacket));
+        av_init_packet(pkt);
+
+        if (av_read_frame(ic, pkt) < 0)
+        {
+                av_free_packet(pkt);
+                av_freep(&pkt);
+                break;
+        }
+        
+        if (pkt->stream_index > (int) ic->nb_streams)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "Bad stream");
+            av_free_packet(pkt);
+            av_freep(&pkt);
+            continue;
+        }
+
+        AVStream *curstream = ic->streams[pkt->stream_index];
+
+        switch (curstream->codec->codec_type)
+        {
+            case CODEC_TYPE_VIDEO:
+            case CODEC_TYPE_AUDIO:
+            case CODEC_TYPE_SUBTITLE:
+                    m_packet_queue->PushBack(pkt, curstream->codec->codec_type);
+                    break;
+            case CODEC_TYPE_DATA:
+                if (curstream->codec->codec_id == CODEC_ID_MPEG2VBI ||
+                    curstream->codec->codec_id == CODEC_ID_DVB_VBI  ||
+                    curstream->codec->codec_id == CODEC_ID_DSMCC_B)
+                {
+                    m_packet_queue->PushBack(pkt, CODEC_TYPE_DATA);
+                    break;
+                }
+            default:
+                av_free_packet(pkt);
+                av_freep(&pkt);
+        }
+    }
+
+//     m_packet_queue->PrintQueueStatus();
+
+    return m_packet_queue->NextPacket();
+}
+
+
 // documented in decoderbase.h
 bool AvFormatDecoder::GetFrame(int onlyvideo)
 {
@@ -3209,7 +3475,6 @@
     decoded_video_frame = NULL;
 
     bool allowedquit = false;
-    bool storevideoframes = false;
 
     avcodeclock.lock();
     AutoSelectTracks();
@@ -3233,7 +3498,7 @@
         allowedquit = (onlyvideo < 0) && (ofill > othresh);
     }
 
-    while (!allowedquit)
+    while (!allowedquit && !frame_decoded)
     {
         if ((onlyvideo == 0) &&
             ((currentTrack[kTrackTypeAudio] < 0) ||
@@ -3258,31 +3523,16 @@
             selectedVideoIndex = 0;
             if (dvdTitleChanged)
             {
-                if ((storedPackets.count() > 10 && !decodeStillFrame) ||
-                    decodeStillFrame)
+                if (decodeStillFrame)
                 {
-                    storevideoframes = false;
                     dvdTitleChanged = false;
                     ScanStreams(true);
                 }
-                else
-                    storevideoframes = true;
             }
             else
             {
-                storevideoframes = false;
-
-                if (storedPackets.count() < 2 && !decodeStillFrame)
-                    storevideoframes = true;
-
-                VERBOSE(VB_PLAYBACK+VB_EXTRA, QString("DVD Playback Debugging "
-                    "inDVDMenu %1 storedPacketcount %2 dvdstill %3")
-                    .arg(inDVDMenu).arg(storedPackets.count()).arg(inDVDStill));
-
-                if (inDVDMenu && storedPackets.count() > 0)
+                if (inDVDMenu)
                     ringBuffer->DVD()->SetRunSeekCellStart(false);
-                else if (storedPackets.count() == 0)
-                    ringBuffer->DVD()->RunSeekCellStart();
             }
             if (GetNVP()->AtNormalSpeed() &&
                 ((cellChanged) || (lastdvdtitle != dvdtitle)))
@@ -3319,47 +3569,11 @@
             }
         }
 
-        if (gotvideo)
-        {
-            if (lowbuffers && onlyvideo == 0 &&
-                storedPackets.count() < max_video_queue_size &&
-                lastapts < lastvpts + 100 &&
-                !ringBuffer->InDVDMenuOrStillFrame())
-            {
-                storevideoframes = true;
-            }
-            else if (onlyvideo >= 0)
-            {
-                if (storedPackets.count() >= max_video_queue_size)
-                    VERBOSE(VB_IMPORTANT,
-                            QString("Audio %1 ms behind video but already %2 "
-                               "video frames queued. AV-Sync might be broken.")
-                            .arg(lastvpts-lastapts).arg(storedPackets.count()));
-                allowedquit = true;
-                continue;
-            }
-        }
+        pkt = GetNextPacket();
 
-        if (!storevideoframes && storedPackets.count() > 0)
+        if (!pkt)
         {
-            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))
-            {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "no packet, stream ended?");
                 ateof = true;
                 GetNVP()->SetEof();
                 delete pkt;
@@ -3379,7 +3593,6 @@
 
             if (pkt->pos > readAdjust)
                 pkt->pos -= readAdjust;
-        }
 
         if (pkt->stream_index > (int) ic->nb_streams)
         {
@@ -3459,15 +3672,6 @@
             }
         }
 
-        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)
         {
@@ -4042,6 +4246,8 @@
 
                     if (gotSubtitles)
                     {
+                        VERBOSE(VB_PLAYBACK|VB_EXTRA, QString("Got Subtitle. pts = %1, start %2 - end = %3")
+                                .arg(pts).arg(subtitle.start_display_time).arg(subtitle.end_display_time));
                         subtitle.start_display_time += pts;
                         subtitle.end_display_time += pts;
                         GetNVP()->AddAVSubtitle(subtitle);
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 21008)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -25,6 +25,7 @@
 class InteractiveTV;
 class ProgramInfo;
 class MythSqlDatabase;
+class AVPacketQueues;
 
 extern "C" void HandleStreamChange(void*);
 
@@ -170,6 +171,8 @@
     friend int64_t seek_avf(URLContext *h, int64_t offset, int whence);
     friend int close_avf(URLContext *h);
 
+    AVPacket *GetNextPacket();
+
     void DecodeDTVCC(const uint8_t *buf);
     void InitByteContext(void);
     void InitVideoCodec(AVStream *stream, AVCodecContext *enc,
@@ -215,6 +218,8 @@
     VideoFrame *decoded_video_frame;
     AVFRingBuffer *avfRingBuffer;
 
+    AVPacketQueues  *m_packet_queue;
+
     bool directrendering;
     bool drawband;
 
@@ -225,8 +230,6 @@
     bool seen_gop;
     int seq_count; ///< A counter used to determine if we need to force a call to HandleGopStart
 
-    QList<AVPacket*> storedPackets;
-
     int firstgoppos;
     int prevgoppos;
 

