]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv/demux.cpp
demux: mkv: enforce valid frame rate
[vlc] / modules / demux / mkv / demux.cpp
index 87ae9684a37f9abc284d781bec7934fb58e5bd51..a0e8e89b5979ef349a5524fcf1789a18ea95ac03 100644 (file)
@@ -2,31 +2,33 @@
 /*****************************************************************************
  * mkv.cpp : matroska demuxer
  *****************************************************************************
- * Copyright (C) 2003-2004 the VideoLAN team
+ * Copyright (C) 2003-2004 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Steve Lhomme <steve.lhomme@free.fr>
  *
- * 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 "demux.hpp"
 #include "stream_io_callback.hpp"
 #include "Ebml_parser.hpp"
 
+#include <vlc_keys.h>
+
 event_thread_t::event_thread_t(demux_t *p_demux) : p_demux(p_demux)
 {
     vlc_mutex_init( &lock );
@@ -462,16 +464,24 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlS
     EbmlElement *p_l0, *p_l1, *p_l2;
     bool b_keep_stream = false, b_keep_segment = false;
 
-    // verify the EBML Header
-    p_l0 = p_estream->FindNextID(EBML_INFO(EbmlHead), UINT64_MAX);
+    /* verify the EBML Header... it shouldn't be bigger than 1kB */
+    p_l0 = p_estream->FindNextID(EBML_INFO(EbmlHead), 1024);
     if (p_l0 == NULL)
     {
         msg_Err( p_demux, "No EBML header found" );
         return NULL;
     }
 
-    // verify we can read this Segment, we only support Matroska version 1 for now
-    p_l0->Read(*p_estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
+    /* verify we can read this Segment */
+    try
+    {
+        p_l0->Read(*p_estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
+    }
+    catch(...)
+    {
+        msg_Err(p_demux, "EBML Header Read failed");
+        return NULL;
+    }
 
     EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
     if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" )
@@ -517,8 +527,20 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlS
                     // find the families of this segment
                     KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
                     b_keep_segment = b_initial;
-
-                    p_info->Read(*p_estream, EBML_CLASS_CONTEXT(KaxInfo), i_upper_lvl, p_l2, true);
+                    if( unlikely( p_info->GetSize() >= SIZE_MAX ) )
+                    {
+                        msg_Err( p_demux, "KaxInfo too big aborting" );
+                        break;
+                    }
+                    try
+                    {
+                        p_info->Read(*p_estream, EBML_CLASS_CONTEXT(KaxInfo), i_upper_lvl, p_l2, true);
+                    }
+                    catch (...)
+                    {
+                        msg_Err( p_demux, "KaxInfo found but corrupted");
+                        break;
+                    }
                     for( size_t i = 0; i < p_info->ListSize(); i++ )
                     {
                         EbmlElement *l = (*p_info)[i];
@@ -653,36 +675,58 @@ bool demux_sys_t::PreloadLinked()
         p_seg = used_segments[i];
         if ( p_seg->Editions() != NULL )
         {
-            input_title_t *p_title = vlc_input_title_New();
-            p_seg->i_sys_title = i;
-            int i_chapters;
-
-            // TODO use a name for each edition, let the TITLE deal with a codec name
             for ( j=0; j<p_seg->Editions()->size(); j++ )
             {
+                virtual_edition_c * p_ved = (*p_seg->Editions())[j];
+                input_title_t *p_title = vlc_input_title_New();
+                int i_chapters;
+
+                // TODO use a name for each edition, let the TITLE deal with a codec name
                 if ( p_title->psz_name == NULL )
                 {
-                    const char* psz_tmp = (*p_seg->Editions())[j]->GetMainName().c_str();
-                    if( *psz_tmp != '\0' )
-                        p_title->psz_name = strdup( psz_tmp );
+                    if( p_ved->GetMainName().length() )
+                        p_title->psz_name = strdup( p_ved->GetMainName().c_str() );
+                    else
+                    {
+                        /* Check in tags if the edition has a name */
+
+                        /* We use only the tags of the first segment as it contains the edition */
+                        std::vector<Tag*> &tags = opened_segments[0]->tags;
+                        uint64_t i_ed_uid = 0;
+                        if( p_ved->p_edition )
+                            i_ed_uid = (uint64_t) p_ved->p_edition->i_uid;
+
+                        for( size_t k = 0; k < tags.size(); k++ )
+                        {
+                            if( tags[k]->i_tag_type == EDITION_UID && tags[k]->i_uid == i_ed_uid )
+                                for( size_t l = 0; l < tags[k]->simple_tags.size(); l++ )
+                                {
+                                    SimpleTag * p_st = tags[k]->simple_tags[l];
+                                    if( !strcmp(p_st->psz_tag_name,"TITLE") )
+                                    {
+                                        msg_Dbg( &demuxer, "Using title \"%s\" from tag for edition %"PRIu64, p_st->p_value, i_ed_uid );
+                                        p_title->psz_name = strdup( p_st->p_value );
+                                        break;
+                                    }
+                                }
+                        }
+
+                        if( !p_title->psz_name &&
+                            asprintf(&(p_title->psz_name), "%s %d", N_("Segment"), (int)i) == -1 )
+                            p_title->psz_name = NULL;
+                    }
                 }
 
                 i_chapters = 0;
-                ( *p_seg->Editions() )[j]->PublishChapters( *p_title, i_chapters, 0 );
+                p_ved->PublishChapters( *p_title, i_chapters, 0 );
 
                 // Input duration into i_length
-                p_title->i_length = ( *p_seg->Editions() )[j]->i_duration;
-            }
+                p_title->i_length = p_ved->i_duration;
 
-            // create a name if there is none
-            if ( p_title->psz_name == NULL )
-            {
-                if( asprintf(&(p_title->psz_name), "%s %d", N_("Segment"), (int)i) == -1 )
-                    p_title->psz_name = NULL;
+                titles.push_back( p_title );
             }
-
-            titles.push_back( p_title );
         }
+        p_seg->i_sys_title = p_seg->i_current_edition;
     }
 
     // TODO decide which segment should be first used (VMG for DVD)
@@ -690,6 +734,37 @@ bool demux_sys_t::PreloadLinked()
     return true;
 }
 
+void demux_sys_t::FreeUnused()
+{
+    size_t i;
+    for( i = 0; i < streams.size(); i++ )
+    {
+        bool used = false;
+        struct matroska_stream_c *p_s = streams[i];
+        for( size_t j = 0; j < p_s->segments.size(); j++ )
+        {
+            if( p_s->segments[j]->b_preloaded )
+            {
+                used = true;
+                break;
+            }
+        }
+        if( !used )
+        {
+            streams[i] = NULL;
+            delete p_s;
+        }
+    }
+    for( i = 0; i < opened_segments.size(); i++)
+    {
+        if( !opened_segments[i]->b_preloaded )
+        {
+            delete opened_segments[i];
+            opened_segments[i] = NULL;
+        }
+    }
+}
+
 virtual_segment_c *demux_sys_t::VirtualFromSegments( std::vector<matroska_segment_c*> *p_segments ) const
 {
     if ( p_segments->empty() )
@@ -719,6 +794,10 @@ bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
     p_current_segment->CurrentSegment()->InformationCreate( );
     p_current_segment->CurrentSegment()->Select( 0 );
 
+    /* Seek to the beginning */
+    p_current_segment->Seek(p_current_segment->CurrentSegment()->sys.demuxer,
+                            0, 0, NULL, -1);
+
     return true;
 }