Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 8096)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -167,7 +167,10 @@
       audio_sample_size(-1), audio_sampling_rate(-1), audio_channels(-1),
       do_ac3_passthru(false), wantedAudioStream(-1),
       audio_check_1st(2), audio_sampling_rate_2nd(0), audio_channels_2nd(0),
-      wantedSubtitleStream(-1)
+      // Subtitles
+      languagePreference(iso639_get_language_key_list()),
+      wantedSubtitleStream(),
+      selectedSubtitleStream()
 {
     bzero(&params, sizeof(AVFormatParameters));
     bzero(prvpkt, 3 * sizeof(char));
@@ -835,6 +838,8 @@
     audio_sampling_rate_2nd = -1;
     audio_channels_2nd = -1;
 
+    map<int,uint> lang_cnt;
+
     for (int i = 0; i < ic->nb_streams; i++)
     {
         AVCodecContext *enc = ic->streams[i]->codec;
@@ -989,7 +994,15 @@
 
         if (enc->codec_type == CODEC_TYPE_SUBTITLE)
         {
-            subtitleStreams.push_back( i );
+            int lang = -1, lang_indx = 0;
+            if (ic->streams[i]->language)
+            {
+                lang = iso639_str3_to_key(ic->streams[i]->language);
+                lang = iso639_key_to_canonical_key(lang);
+                lang_indx = lang_cnt[lang];
+                lang_cnt[lang]++;
+            }
+            subtitleStreams.push_back(SubtitleInfo(i, lang, lang_indx));
         }
 
         if (enc->codec_type == CODEC_TYPE_AUDIO)
@@ -1869,128 +1882,121 @@
 }
 
 
-void AvFormatDecoder::incCurrentSubtitleTrack()
+void AvFormatDecoder::incCurrentSubtitleTrack(void)
 {
-    if (subtitleStreams.size())
-    {
-        int tempTrackNo = currentSubtitleTrack;
-        ++tempTrackNo;
-        if (tempTrackNo > (int)(subtitleStreams.size() - 1))
-            tempTrackNo = 0;
-
-        currentSubtitleTrack = tempTrackNo;
-        wantedSubtitleStream = subtitleStreams[currentSubtitleTrack];
-    }
+    int numStreams = (int)subtitleStreams.size();
+    int next       = (currentSubtitleTrack+1) % numStreams;
+    setCurrentSubtitleTrack((!numStreams) ? -1 : next);
 }
 
-void AvFormatDecoder::decCurrentSubtitleTrack()
+void AvFormatDecoder::decCurrentSubtitleTrack(void)
 {
-    if (subtitleStreams.size())
-    {
-        int tempTrackNo = currentSubtitleTrack;
-        --tempTrackNo;
-        if (tempTrackNo < 0)
-            tempTrackNo = subtitleStreams.size() - 1;
-
-        currentSubtitleTrack = tempTrackNo;
-        wantedSubtitleStream = subtitleStreams[currentSubtitleTrack];
-    }
+    int numStreams = (int)subtitleStreams.size();
+    int next       = (currentSubtitleTrack < 0) ? 0 : currentSubtitleTrack;
+    next           = (next+numStreams-1) % numStreams;
+    setCurrentSubtitleTrack((!numStreams) ? -1 : next);
 }
 
 bool AvFormatDecoder::setCurrentSubtitleTrack(int trackNo)
 {
-    if (trackNo < 0)
-        trackNo = -1;
-    else if (trackNo >= (int)subtitleStreams.size())
+    if (trackNo >= (int)subtitleStreams.size())
         return false;
 
-    currentSubtitleTrack = trackNo;
-    if (currentSubtitleTrack < 0)
-        return false;
-
-    wantedSubtitleStream = subtitleStreams[currentSubtitleTrack];
-
-    return true;
+    currentSubtitleTrack = max(-1, trackNo);
+    if (currentSubtitleTrack > 0)
+    {
+        wantedSubtitleStream   = subtitleStreams[currentSubtitleTrack];
+        selectedSubtitleStream = subtitleStreams[currentSubtitleTrack];
+        return true;
+    }
+    return false;
 }
 
-QStringList AvFormatDecoder::listSubtitleTracks() const
+QStringList AvFormatDecoder::listSubtitleTracks(void) const
 {
     QStringList list;
-    int num_tracks = subtitleStreams.size();
-    int track;
-    
-    for (track = 0; track < num_tracks; track++)
+
+    for (uint i = 0; i < subtitleStreams.size(); i++)
     {
-        AVStream *s = ic->streams[subtitleStreams[track]];
-        
-        if (!s)
-            continue;
-        
-        QString t = QString("%1: ").arg(track + 1);
-        
-        if (strlen(s->language) > 0)
-        {
-            t += iso639_str_toName((unsigned char *)(s->language));
-            t += " ";
-        }
-         
-        list += t;
+        QString msg  = iso639_key_toName(subtitleStreams[i].language);
+        msg          = msg.isEmpty() ? "?" : msg;
+        list        += QString("%1: %2 ").arg(i+1).arg(msg);
     }
-    
+
     return list;
 }
 
-// in case there's only one subtitle language available, always choose it
-//
-// if more than one subtitle languages are found, the best one is
-// picked according to the ISO639Language[0..] settings
-//
-// in case there are no ISOLanguage[0..] settings, or no preferred language
-// is found, the first found subtitle stream is chosen
-bool AvFormatDecoder::autoSelectSubtitleTrack()
+/** \fn AvFormatDecoder::autoSelectSubtitleTrack(void)
+ *  \brief Select best subtitle track.
+ *
+ *   If case there's only one subtitle available, always choose it.
+ *
+ *   If there is a user selected subtitle we try to find it.
+ *
+ *   If we can't find the user selected subtitle we try to
+ *   picked according to the ISO639Language[0..] settings.
+ *
+ *   In case there are no ISOLanguage[0..] settings, or no preferred language
+ *   is found, the first found subtitle stream is chosen
+ */
+bool AvFormatDecoder::autoSelectSubtitleTrack(void)
 {
-    if (!subtitleStreams.size())
+    uint numStreams = subtitleStreams.size();
+
+    if ((currentSubtitleTrack > 0) && (currentSubtitleTrack < (int)numStreams))
+        return true; // subtitle already selected
+
+    if (!numStreams)
     {
         currentSubtitleTrack = -1;
-        wantedSubtitleStream = -1;
-        return false;
+        selectedSubtitleStream.av_stream_index = -1;
+        return false; // no subtitles available
     }
 
-    int maxTracks = (subtitleStreams.size() - 1);
+    int selectedTrack = (1 == numStreams) ? 0 : -1;
 
-    int selectedTrack = -1;
-    
-    // go through all preferred languages and pick the best found
-    QStringList langPref = iso639_get_language_list();
-    QStringList::iterator l = langPref.begin();
-    for (; l != langPref.end() && selectedTrack == -1; ++l)
+    if ((selectedTrack < 0) && wantedSubtitleStream.language)
     {
-        for (int track = 0; track < maxTracks; track++)
+        // Try to reselect user selected subtitle stream.
+        // This should find the stream after a commercial
+        // break and in some cases after a channel change.
+        int  wlang = wantedSubtitleStream.language;
+        uint windx = wantedSubtitleStream.language_index;
+        for (uint i = 0; i < numStreams; i++)
         {
-            int tempStream = subtitleStreams[track];
-            AVStream* st = ic->streams[tempStream];
+            if (wlang == subtitleStreams[i].language)
+                selectedTrack = i;
+            if (windx == subtitleStreams[i].language_index)
+                break;
+        }
+    }
 
-            if (st->language == *l)
+    if (selectedTrack < 0)
+    {
+        // Find first subtitle stream that matches a language in
+        // order of most preferred to least preferred language.
+        vector<int>::iterator it = languagePreference.begin();
+        for (; (it != languagePreference.end()) && (selectedTrack < 0); ++it)
+        {
+            for (uint i = 0; i < numStreams; i++)
             {
-                selectedTrack = track;
-                break;
+                if (*it == subtitleStreams[i].language)
+                {
+                    selectedTrack = i;
+                    break;
+                }
             }
         }
     }
-    
-    if (selectedTrack == -1)
-    {
-        selectedTrack = 0;
-    }
 
-    currentSubtitleTrack = selectedTrack;
-    wantedSubtitleStream = subtitleStreams[currentSubtitleTrack];
+    currentSubtitleTrack = (selectedTrack < 0) ? 0 : -1;
+    selectedSubtitleStream = subtitleStreams[currentSubtitleTrack];
+    if (!wantedSubtitleStream.language)
+        wantedSubtitleStream = selectedSubtitleStream;
      
     return true;
 }
 
-
-
 bool AvFormatDecoder::GetFrame(int onlyvideo)
 {
     AVPacket *pkt = NULL;
@@ -2013,12 +2019,7 @@
         autoSelectAudioTrack();
     }
 
-    if ((currentSubtitleTrack == -1 || 
-        currentSubtitleTrack >= (int)subtitleStreams.size()) &&
-        subtitleStreams.size() > 0)
-    {
-        autoSelectSubtitleTrack();
-    }
+    autoSelectSubtitleTrack();
 
     bool skipaudio = (lastvpts == 0);
 
@@ -2336,7 +2337,8 @@
                     int gotSubtitles = 0;
                     AVSubtitle subtitle;
 
-                    if (pkt->stream_index == wantedSubtitleStream)
+                    if (pkt->stream_index == 
+                        selectedSubtitleStream.av_stream_index)
                     {
                         avcodec_decode_subtitle(context, &subtitle, 
                                                 &gotSubtitles, ptr, len);
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 8096)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -20,6 +20,19 @@
 
 extern "C" void HandleStreamChange(void*);
 
+class SubtitleInfo
+{
+  public:
+    SubtitleInfo() : av_stream_index(-1), language(0), language_index(0) {}
+    SubtitleInfo(int a, int b, uint c)
+        : av_stream_index(a), language(b), language_index(c) {}
+  public:
+    int  av_stream_index;
+    int  language; ///< ISO639 cannonical language key
+    uint language_index;
+};
+typedef vector<SubtitleInfo> sub_vec_t;
+
 /// A decoder for video files.
 
 /// The AvFormatDecoder is used to decode non-NuppleVideo files.
@@ -197,8 +210,10 @@
     int               audio_sampling_rate_2nd; ///< Used by CheckAudioParams
     int               audio_channels_2nd;      ///< Used by CheckAudioParams
 
-    QValueVector<int> subtitleStreams;
-    int wantedSubtitleStream;
+    sub_vec_t         subtitleStreams;
+    vector<int>       languagePreference;
+    SubtitleInfo      wantedSubtitleStream;
+    SubtitleInfo      selectedSubtitleStream;
 };
 
 #endif
