]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv/virtual_segment.cpp
demux: mkv: fix previous type fix
[vlc] / modules / demux / mkv / virtual_segment.cpp
index 3388f0c54bac411b84f29ff8243a1e6ab9a2802d..922b686390a0d0fb16d342b1fd26ad2540c95aec 100644 (file)
@@ -8,19 +8,19 @@
  *          Steve Lhomme <steve.lhomme@free.fr>
  *          Denis Charmet <typx@dinauz.org>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 #include <vector>
 
@@ -31,7 +31,8 @@ matroska_segment_c * getSegmentbyUID( KaxSegmentUID * p_uid, std::vector<matrosk
 {
     for( size_t i = 0; i < (*segments).size(); i++ )
     {
-        if( *p_uid == *((*segments)[i]->p_segment_uid) )
+        if( (*segments)[i]->p_segment_uid &&
+            *p_uid == *((*segments)[i]->p_segment_uid) )
             return (*segments)[i];
     }
     return NULL;
@@ -53,7 +54,7 @@ virtual_chapter_c * virtual_chapter_c::CreateVirtualChapter( chapter_item_c * p_
     int64_t start = ( b_ordered )? *usertime_offset : p_chap->i_start_time;
     int64_t stop = ( b_ordered )? ( *usertime_offset + p_chap->i_end_time - p_chap->i_start_time ) : p_chap->i_end_time;
 
-    if( p_chap->p_segment_uid && 
+    if( p_chap->p_segment_uid &&
        ( !( p_segment = getSegmentbyUID( (KaxSegmentUID*) p_chap->p_segment_uid,segments ) ) || !b_ordered ) )
     {
         msg_Warn( &p_main_segment->sys.demuxer,
@@ -87,7 +88,7 @@ virtual_chapter_c * virtual_chapter_c::CreateVirtualChapter( chapter_item_c * p_
         *usertime_offset = tmp;
 
     msg_Dbg( &p_main_segment->sys.demuxer,
-             "Virtual chapter %s from %"PRId64" to %"PRId64" - " ,
+             "Virtual chapter %s from %" PRId64 " to %" PRId64 " - " ,
              p_chap->psz_name.c_str(), p_vchap->i_virtual_start_time, p_vchap->i_virtual_stop_time );
 
     return p_vchap;
@@ -102,8 +103,10 @@ virtual_chapter_c::~virtual_chapter_c()
 
 virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<matroska_segment_c*> *opened_segments)
 {
+    bool b_fake_ordered = false;
     matroska_segment_c *p_main_segment = (*opened_segments)[0];
     p_edition = p_edit;
+    b_ordered = false;
 
     int64_t usertime_offset = 0;
 
@@ -119,18 +122,20 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
             if( p_vchap )
                 chapters.push_back( p_vchap );
         }
-        i_duration = chapters[ chapters.size() - 1 ]->i_virtual_stop_time;
+        if( chapters.size() )
+            i_duration = chapters[ chapters.size() - 1 ]->i_virtual_stop_time;
+        else
+            i_duration = 0; /* Empty ordered editions will be ignored */
     }
     else /* Not ordered or no edition at all */
     {
-        b_ordered = false;
         matroska_segment_c * p_cur = p_main_segment;
         virtual_chapter_c * p_vchap = NULL;
         int64_t tmp = 0;
 
         /* check for prev linked segments */
-        /* FIXME to avoid infinite recursion we limit to 5 prev sould be better as parameter */
-        for( int limit = 0; limit < 5 && p_cur->p_prev_segment_uid ; limit++ )
+        /* FIXME to avoid infinite recursion we limit to 10 prev should be better as parameter */
+        for( int limit = 0; limit < 10 && p_cur->p_prev_segment_uid ; limit++ )
         {
             matroska_segment_c * p_prev = NULL;
             if( ( p_prev = getSegmentbyUID( p_cur->p_prev_segment_uid, opened_segments ) ) )
@@ -139,6 +144,10 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
                 msg_Dbg( &p_main_segment->sys.demuxer, "Prev segment 0x%x found\n",
                          *(int32_t*)p_cur->p_prev_segment_uid->GetBuffer() );
 
+                /* Preload segment */
+                if ( !p_prev->b_preloaded )
+                    p_prev->Preload();
+
                 /* Create virtual_chapter from the first edition if any */
                 chapter_item_c * p_chap = ( p_prev->stored_editions.size() > 0 )? ((chapter_item_c *)p_prev->stored_editions[0]) : NULL;
 
@@ -148,6 +157,7 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
                     chapters.insert( chapters.begin(), p_vchap );
 
                 p_cur = p_prev;
+                b_fake_ordered = true;
             }
             else /* segment not found */
                 break;
@@ -162,7 +172,7 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
             chapters.push_back( p_vchap );
 
         /* Append next linked segments */
-        for( int limit = 0; limit < 5 && p_cur->p_next_segment_uid; limit++ )
+        for( int limit = 0; limit < 10 && p_cur->p_next_segment_uid; limit++ )
         {
             matroska_segment_c * p_next = NULL;
             if( ( p_next = getSegmentbyUID( p_cur->p_next_segment_uid, opened_segments ) ) )
@@ -171,6 +181,10 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
                 msg_Dbg( &p_main_segment->sys.demuxer, "Next segment 0x%x found\n",
                          *(int32_t*) p_cur->p_next_segment_uid->GetBuffer() );
 
+                /* Preload segment */
+                if ( !p_next->b_preloaded )
+                    p_next->Preload();
+
                 /* Create virtual_chapter from the first edition if any */
                 chapter_item_c * p_chap = ( p_next->stored_editions.size() > 0 )?( (chapter_item_c *)p_next->stored_editions[0] ) : NULL;
 
@@ -181,6 +195,7 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
 
 
                 p_cur = p_next;
+                b_fake_ordered = true;
             }
             else /* segment not found */
                 break;
@@ -188,6 +203,8 @@ virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<ma
 
         /* Retime chapters */
         retimeChapters();
+        if(b_fake_ordered)
+            b_ordered = true;
     }
 
 #if MKV_DEBUG
@@ -228,10 +245,6 @@ void virtual_edition_c::retimeChapters()
 
     i_duration = 0;
 
-    /* Sort by start time */
-    if( chapters.size() > 1 )
-        std::sort( chapters.begin(), chapters.end(), virtual_chapter_c::CompareTimecode );
-
     /* On non ordered editions we have one top chapter == one segment */
     for( size_t i = 0; i < chapters.size(); i++ )
     {
@@ -248,23 +261,37 @@ void virtual_edition_c::retimeChapters()
 virtual_segment_c::virtual_segment_c( std::vector<matroska_segment_c*> * p_opened_segments )
 {
     /* Main segment */
+    std::vector<chapter_edition_c*>::size_type i;
     matroska_segment_c *p_segment = (*p_opened_segments)[0];
     i_current_edition = 0;
     i_sys_title = 0;
     p_current_chapter = NULL;
 
-    for( size_t i = 0; i < p_segment->stored_editions.size(); i++ )
-    {
-        /* Get the default edition, if non use the first one */
-        if( p_segment->stored_editions[i]->b_default )
-            i_current_edition = i;
+    i_current_edition = p_segment->i_default_edition;
 
+    for( i = 0; i < p_segment->stored_editions.size(); i++ )
+    {
         /* Create a virtual edition from opened */
         virtual_edition_c * p_vedition = new virtual_edition_c( p_segment->stored_editions[i], p_opened_segments );
 
-        /*FIXME if p_vedition failed...*/
+        /* Ordered empty edition can happen when all chapters are
+         * on an other segment which couldn't be found... ignore it */
+        if(p_vedition->b_ordered && p_vedition->i_duration == 0)
+        {
 
-        editions.push_back( p_vedition );
+            msg_Warn( &p_segment->sys.demuxer,
+                      "Edition %s (%zu) links to other segments not found and is empty... ignoring it",
+                       p_vedition->GetMainName().c_str(), i );
+            if(i_current_edition == i)
+            {
+                msg_Warn( &p_segment->sys.demuxer,
+                          "Empty edition was the default... defaulting to 0");
+                i_current_edition = 0;
+            }
+            delete p_vedition;
+        }
+        else
+            editions.push_back( p_vedition );
     }
     /*if we don't have edition create a dummy one*/
     if( !p_segment->stored_editions.size() )
@@ -273,6 +300,15 @@ virtual_segment_c::virtual_segment_c( std::vector<matroska_segment_c*> * p_opene
         editions.push_back( p_vedition );
     }
 
+    /* Get the default edition, if there is none, use the first one */
+    for( i = 0; i < editions.size(); i++)
+    {
+        if( editions[i]->p_edition && editions[i]->p_edition->b_default )
+        {
+            i_current_edition = i;
+            break;
+        }
+    }
     /* Set current chapter */
     p_current_chapter = editions[i_current_edition]->getChapterbyTimecode(0);
 
@@ -373,7 +409,7 @@ bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
     /* we have moved to a new chapter */
     if ( p_cur_chapter != NULL && p_current_chapter != p_cur_chapter )
         {
-            msg_Dbg( &demux, "NEW CHAPTER %"PRId64, sys.i_pts );
+            msg_Dbg( &demux, "NEW CHAPTER %" PRId64, sys.i_pts );
             if ( p_cur_edition->b_ordered )
             {
                 /* FIXME EnterAndLeave has probably been broken for a long time */
@@ -383,14 +419,14 @@ bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
                 {
                     // only physically seek if necessary
                     if ( p_current_chapter == NULL ||
-                        ( p_current_chapter->p_chapter->i_end_time != p_cur_chapter->p_chapter->i_start_time ) ||
-                        ( p_current_chapter && p_current_chapter->p_segment != p_cur_chapter->p_segment ) )
+                        ( p_current_chapter && p_current_chapter->p_segment != p_cur_chapter->p_segment ) ||
+                        ( p_current_chapter->p_chapter->i_end_time != p_cur_chapter->p_chapter->i_start_time ))
                     {
-                        /* hack : we have to use input to seek in order to clean buffers */
-                        var_SetTime( demux.p_sys->p_input, "time", p_cur_chapter->i_virtual_start_time );
+                        Seek( demux, p_cur_chapter->i_virtual_start_time, 0, p_cur_chapter, -1 );
                         return true;
                     }
                 }
+                sys.i_start_pts = p_cur_chapter->i_virtual_start_time;;
             }
 
             p_current_chapter = p_cur_chapter;
@@ -426,7 +462,7 @@ bool virtual_chapter_c::EnterAndLeave( virtual_chapter_c *p_item, bool b_enter )
     return p_chapter->EnterAndLeave( p_item->p_chapter, b_enter );
 }
 
-void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, 
+void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset,
                               virtual_chapter_c *p_chapter, int64_t i_global_position )
 {
     demux_sys_t *p_sys = demuxer.p_sys;
@@ -439,8 +475,8 @@ void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_
 
     if ( p_chapter != NULL )
     {
-        p_sys->i_chapter_time =
-            i_time_offset = p_chapter->i_virtual_start_time - ( ( p_chapter->p_chapter )? p_chapter->p_chapter->i_start_time : 0 );
+        i_time_offset = p_chapter->i_virtual_start_time - ( ( p_chapter->p_chapter )? p_chapter->p_chapter->i_start_time : 0 );
+        p_sys->i_chapter_time = i_time_offset - p_chapter->p_segment->i_start_time;
         if ( p_chapter->p_chapter && p_chapter->i_seekpoint_num > 0 )
         {
             demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
@@ -449,11 +485,7 @@ void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_
         }
 
         if( p_current_chapter->p_segment != p_chapter->p_segment )
-        {
-            p_current_chapter->p_segment->UnSelect();
-            es_out_Control( demuxer.out, ES_OUT_RESET_PCR );
-            p_chapter->p_segment->Select( i_date );
-        }
+            ChangeSegment( p_current_chapter->p_segment, p_chapter->p_segment, i_date );
         p_current_chapter = p_chapter;
 
         p_chapter->p_segment->Seek( i_date, i_time_offset, i_global_position );
@@ -531,15 +563,13 @@ int virtual_edition_c::PublishChapters( input_title_t & title, int & i_user_chap
 {
 
     /* HACK for now don't expose edition as a seekpoint if its start time is the same than it's first chapter */
-    if( chapters.size() > 0 && chapters[0]->i_virtual_start_time )
+    if( chapters.size() > 0 &&
+        chapters[0]->i_virtual_start_time && p_edition )
     {
         seekpoint_t *sk = vlc_seekpoint_New();
 
         sk->i_time_offset = 0;
-        if( p_edition )
-            sk->psz_name = strdup( p_edition->psz_name.c_str() );
-        else
-            sk->psz_name = strdup( "Dummy edition" );
+        sk->psz_name = strdup( p_edition->psz_name.c_str() );
 
         title.i_seekpoint++;
         title.seekpoint = (seekpoint_t**)xrealloc( title.seekpoint,
@@ -551,8 +581,9 @@ int virtual_edition_c::PublishChapters( input_title_t & title, int & i_user_chap
         i_seekpoint_num = i_user_chapters;
     }
 
-    for( size_t i = 0; i < chapters.size(); i++ )
-        chapters[i]->PublishChapters( title, i_user_chapters, i_level );
+//    if( chapters.size() > 1 )
+        for( size_t i = 0; i < chapters.size(); i++ )
+            chapters[i]->PublishChapters( title, i_user_chapters, i_level );
 
     return i_user_chapters;
 }
@@ -580,7 +611,7 @@ bool virtual_chapter_c::Leave( bool b_do_subs )
 }
 
 #if MKV_DEBUG
-void virtual_chapter_c::print() 
+void virtual_chapter_c::print()
 {
     msg_Dbg( &p_segment->sys.demuxer, "*** chapter %"PRId64" - %"PRId64" (%u)",
              i_virtual_start_time, i_virtual_stop_time, sub_chapters.size() );
@@ -588,3 +619,76 @@ void virtual_chapter_c::print()
         sub_chapters[i]->print();
 }
 #endif
+
+void virtual_segment_c::ChangeSegment( matroska_segment_c * p_old, matroska_segment_c * p_new, mtime_t i_start_time )
+{
+    size_t i, j;
+    char *sub_lang = NULL, *aud_lang = NULL;
+    for( i = 0; i < p_old->tracks.size(); i++)
+    {
+        mkv_track_t *p_tk = p_old->tracks[i];
+        es_format_t *p_ofmt = &p_tk->fmt;
+        if( p_tk->p_es )
+        {
+            bool state = false;
+            es_out_Control( p_old->sys.demuxer.out, ES_OUT_GET_ES_STATE, p_tk->p_es, &state );
+            if( state )
+            {
+                if( p_ofmt->i_cat == AUDIO_ES )
+                    aud_lang = p_tk->fmt.psz_language;
+                else if( p_ofmt->i_cat == SPU_ES )
+                    sub_lang = p_tk->fmt.psz_language;
+            }
+        }
+    }
+    for( i = 0; i < p_new->tracks.size(); i++)
+    {
+        mkv_track_t *p_tk = p_new->tracks[i];
+        es_format_t *p_nfmt = &p_tk->fmt;
+
+        /* Let's only do that for audio and video for now */
+        if( p_nfmt->i_cat == AUDIO_ES || p_nfmt->i_cat == VIDEO_ES )
+        {
+
+            /* check for a similar elementary stream */
+            for( j = 0; j < p_old->tracks.size(); j++)
+            {
+                es_format_t * p_ofmt = &p_old->tracks[j]->fmt;
+
+                if( !p_old->tracks[j]->p_es )
+                    continue;
+
+                if( ( p_nfmt->i_cat == p_ofmt->i_cat ) &&
+                    ( p_nfmt->i_codec == p_ofmt->i_codec ) &&
+                    ( p_nfmt->i_priority == p_ofmt->i_priority ) &&
+                    ( p_nfmt->i_bitrate == p_ofmt->i_bitrate ) &&
+                    ( p_nfmt->i_extra == p_ofmt->i_extra ) &&
+                    ( p_nfmt->i_extra == 0 ||
+                      !memcmp( p_nfmt->p_extra, p_ofmt->p_extra, p_nfmt->i_extra ) ) &&
+                    !strcasecmp( p_nfmt->psz_language, p_ofmt->psz_language ) &&
+                    ( ( p_nfmt->i_cat == AUDIO_ES &&
+                        !memcmp( &p_nfmt->audio, &p_ofmt->audio, sizeof(audio_format_t) ) ) ||
+                      ( p_nfmt->i_cat == VIDEO_ES &&
+                        !memcmp( &p_nfmt->video, &p_ofmt->video, sizeof(video_format_t) ) ) ) )
+                {
+                    /* FIXME handle video palettes... */
+                    msg_Warn( &p_old->sys.demuxer, "Reusing decoder of old track %zu for track %zu", j, i);
+                    p_tk->p_es = p_old->tracks[j]->p_es;
+                    p_old->tracks[j]->p_es = NULL;
+                    break;
+                }
+            }
+        }
+        p_tk->fmt.i_priority &= ~(0x10);
+        if( ( sub_lang && p_nfmt->i_cat == SPU_ES && !strcasecmp(sub_lang, p_nfmt->psz_language) ) ||
+            ( aud_lang && p_nfmt->i_cat == AUDIO_ES && !strcasecmp(aud_lang, p_nfmt->psz_language) ) )
+        {
+            msg_Warn( &p_old->sys.demuxer, "Since previous segment used lang %s forcing track %zu",
+                      p_nfmt->psz_language, i);
+            p_tk->fmt.i_priority |= 0x10;
+            p_tk->b_forced = true;
+        }
+    }
+    p_new->Select( i_start_time );
+    p_old->UnSelect();
+}