]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv.cpp
Fix breakage in transcode file selection
[vlc] / modules / demux / mkv.cpp
index 8c259740f262bef4da641b2e0115862d504ef9c0..1477151cea8805b8f5c097e7800f53ad0b2d666e 100644 (file)
 #include "matroska/KaxTrackAudio.h"
 #include "matroska/KaxTrackVideo.h"
 #include "matroska/KaxTrackEntryData.h"
+#include "matroska/KaxContentEncoding.h"
 
 #include "ebml/StdIOCallback.h"
 
+extern "C" {
+   #include "mp4/libmp4.h"
+}
+#ifdef HAVE_ZLIB_H
+#   include <zlib.h>
+#endif
+
+#define MATROSKA_COMPRESSION_NONE 0
+#define MATROSKA_COMPRESSION_ZLIB 1
+
 using namespace LIBMATROSKA_NAMESPACE;
 using namespace std;
 
@@ -84,9 +95,12 @@ static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
 vlc_module_begin();
+    set_shortname( _("Matroska") );
     set_description( _("Matroska stream demuxer" ) );
     set_capability( "demux2", 50 );
     set_callbacks( Open, Close );
+    set_category( CAT_INPUT );
+    set_subcategory( SUBCAT_INPUT_DEMUX );
 
     add_bool( "mkv-seek-percent", 1, NULL,
             N_("Seek based on percent not time"),
@@ -103,7 +117,79 @@ static int  Demux  ( demux_t * );
 static int  Control( demux_t *, int, va_list );
 static void Seek   ( demux_t *, mtime_t i_date, int i_percent );
 
+#ifdef HAVE_ZLIB_H
+block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
+    int result, dstsize, n;
+    unsigned char *dst;
+    block_t *p_block;
+    z_stream d_stream;
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+    result = inflateInit(&d_stream);
+    if( result != Z_OK )
+    {
+        msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
+        return NULL;
+    }
+
+    d_stream.next_in = (Bytef *)p_in_block->p_buffer;
+    d_stream.avail_in = p_in_block->i_buffer;
+    n = 0;
+    p_block = block_New( p_this, 0 );
+    dst = NULL;
+    do
+    {
+        n++;
+        p_block = block_Realloc( p_block, 0, n * 1000 );
+        dst = (unsigned char *)p_block->p_buffer;
+        d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
+        d_stream.avail_out = 1000;
+        result = inflate(&d_stream, Z_NO_FLUSH);
+        if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
+        {
+            msg_Dbg( p_this, "Zlib decompression failed. Result: %d", result );
+            return NULL;
+        }
+    }
+    while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
+           ( result != Z_STREAM_END ) );
+
+    dstsize = d_stream.total_out;
+    inflateEnd( &d_stream );
+
+    p_block = block_Realloc( p_block, 0, dstsize );
+    p_block->i_buffer = dstsize;
+    block_Release( p_in_block );
 
+    return p_block;
+}
+#endif
+
+/**
+ * Helper function to print the mkv parse tree
+ */
+static void MkvTree( demux_t *p_this, int i_level, char *psz_format, ... )
+{
+    va_list args;
+    if( i_level > 9 )
+    {
+        msg_Err( p_this, "too deep tree" );
+        return;
+    }
+    va_start( args, psz_format );
+    static char *psz_foo = "|   |   |   |   |   |   |   |   |   |";
+    char *psz_foo2 = (char*)malloc( ( i_level * 4 + 3 + strlen( psz_format ) ) * sizeof(char) );
+    strncpy( psz_foo2, psz_foo, 4 * i_level );
+    psz_foo2[ 4 * i_level ] = '+';
+    psz_foo2[ 4 * i_level + 1 ] = ' ';
+    strcpy( &psz_foo2[ 4 * i_level + 2 ], psz_format );
+    __msg_GenericVa( VLC_OBJECT(p_this), VLC_MSG_DBG, "mkv", psz_foo2, args );
+    free( psz_foo2 );
+    va_end( args );
+}
+    
 /*****************************************************************************
  * Stream managment
  *****************************************************************************/
@@ -195,6 +281,9 @@ typedef struct
     char         *psz_codec_settings;
     char         *psz_codec_info_url;
     char         *psz_codec_download_url;
+    
+    /* encryption/compression */
+    int           i_compression_type;
 
 } mkv_track_t;
 
@@ -354,7 +443,7 @@ static int Open( vlc_object_t * p_this )
         msg_Err( p_demux, "cannot find KaxSegment" );
         goto error;
     }
-    msg_Dbg( p_demux, "+ Segment" );
+    MkvTree( p_demux, 0, "Segment" );
     p_sys->segment = (KaxSegment*)el;
     p_sys->cluster = NULL;
 
@@ -485,6 +574,23 @@ static int Open( vlc_object_t * p_this )
                 tk.fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
             }
         }
+        else if( !strcmp( tk.psz_codec, "V_QUICKTIME" ) )
+        {
+            MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
+            stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(p_demux),
+                                                       tk.p_extra_data,
+                                                       tk.i_extra_data );
+            MP4_ReadBoxCommon( p_mp4_stream, p_box );
+            MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
+            tk.fmt.i_codec = p_box->i_type;
+            tk.fmt.video.i_width = p_box->data.p_sample_vide->i_width;
+            tk.fmt.video.i_height = p_box->data.p_sample_vide->i_height;
+            tk.fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
+            tk.fmt.p_extra = malloc( tk.fmt.i_extra );
+            memcpy( tk.fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, tk.fmt.i_extra );
+            MP4_FreeBox_sample_vide( p_box );
+            stream_MemoryDelete( p_mp4_stream, VLC_TRUE );
+        }
         else if( !strcmp( tk.psz_codec, "A_MS/ACM" ) )
         {
             if( tk.i_extra_data < (int)sizeof( WAVEFORMATEX ) )
@@ -645,12 +751,35 @@ static int Open( vlc_object_t * p_this )
         else if( !strcmp( tk.psz_codec, "S_VOBSUB" ) )
         {
             tk.fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
+            if( tk.i_extra_data )
+            {
+                char *p_start;
+                char *p_buf = (char *)malloc( tk.i_extra_data + 1);
+                memcpy( p_buf, tk.p_extra_data , tk.i_extra_data );
+                p_buf[tk.i_extra_data] = '\0';
+                
+                p_start = strstr( p_buf, "size:" );
+                if( sscanf( p_start, "size: %dx%d",
+                        &tk.fmt.subs.spu.i_original_frame_width, &tk.fmt.subs.spu.i_original_frame_height ) == 2 )
+                {
+                    msg_Dbg( p_demux, "original frame size vobsubs: %dx%d", tk.fmt.subs.spu.i_original_frame_width, tk.fmt.subs.spu.i_original_frame_height );
+                }
+                else
+                {
+                    msg_Warn( p_demux, "reading original frame size for vobsub failed" );
+                }
+                free( p_buf );
+            }
         }
         else
         {
             msg_Err( p_demux, "unknow codec id=`%s'", tk.psz_codec );
             tk.fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
         }
+        if( tk.b_default )
+        {
+            tk.fmt.i_priority = 1000;
+        }
 
         tk.p_es = es_out_Add( p_demux->out, &tk.fmt );
 #undef tk
@@ -991,11 +1120,19 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
         DataBuffer &data = block->GetBuffer(i);
 
         p_block = MemToBlock( p_demux, data.Buffer(), data.Size() );
+
         if( p_block == NULL )
         {
             break;
         }
 
+#if defined(HAVE_ZLIB_H)
+        if( tk.i_compression_type )
+        {
+            p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
+        }
+#endif
+
         if( tk.fmt.i_cat != VIDEO_ES )
             p_block->i_dts = p_block->i_pts = i_pts;
         else
@@ -1750,6 +1887,8 @@ static void ParseTrackEntry( demux_t *p_demux, EbmlMaster *m )
     tk->psz_codec_settings = NULL;
     tk->psz_codec_info_url = NULL;
     tk->psz_codec_download_url = NULL;
+    
+    tk->i_compression_type = MATROSKA_COMPRESSION_NONE;
 
     for( i = 0; i < m->ListSize(); i++ )
     {
@@ -1883,6 +2022,72 @@ static void ParseTrackEntry( demux_t *p_demux, EbmlMaster *m )
             tk->psz_codec_name = UTF8ToStr( UTFstring( cname ) );
             msg_Dbg( p_demux, "|   |   |   + Track Codec Name=%s", tk->psz_codec_name );
         }
+        else if( MKV_IS_ID( l, KaxContentEncodings ) )
+        {
+            EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
+            MkvTree( p_demux, 3, "Content Encodings" );
+            for( unsigned int i = 0; i < cencs->ListSize(); i++ )
+            {
+                EbmlElement *l2 = (*cencs)[i];
+                if( MKV_IS_ID( l2, KaxContentEncoding ) )
+                {
+                    MkvTree( p_demux, 4, "Content Encoding" );
+                    EbmlMaster *cenc = static_cast<EbmlMaster*>(l2);
+                    for( unsigned int i = 0; i < cenc->ListSize(); i++ )
+                    {
+                        EbmlElement *l3 = (*cenc)[i];
+                        if( MKV_IS_ID( l3, KaxContentEncodingOrder ) )
+                        {
+                            KaxContentEncodingOrder &encord = *(KaxContentEncodingOrder*)l3;
+                            MkvTree( p_demux, 5, "Order: %i", uint32( encord ) );
+                        }
+                        else if( MKV_IS_ID( l3, KaxContentEncodingScope ) )
+                        {
+                            KaxContentEncodingScope &encscope = *(KaxContentEncodingScope*)l3;
+                            MkvTree( p_demux, 5, "Scope: %i", uint32( encscope ) );
+                        }
+                        else if( MKV_IS_ID( l3, KaxContentEncodingType ) )
+                        {
+                            KaxContentEncodingType &enctype = *(KaxContentEncodingType*)l3;
+                            MkvTree( p_demux, 5, "Type: %i", uint32( enctype ) );
+                        }
+                        else if( MKV_IS_ID( l3, KaxContentCompression ) )
+                        {
+                            EbmlMaster *compr = static_cast<EbmlMaster*>(l3);
+                            MkvTree( p_demux, 5, "Content Compression" );
+                            for( unsigned int i = 0; i < compr->ListSize(); i++ )
+                            {
+                                EbmlElement *l4 = (*compr)[i];
+                                if( MKV_IS_ID( l4, KaxContentCompAlgo ) )
+                                {
+                                    KaxContentCompAlgo &compalg = *(KaxContentCompAlgo*)l4;
+                                    MkvTree( p_demux, 6, "Compression Algorithm: %i", uint32(compalg) );
+                                    if( uint32( compalg ) == 0 )
+                                    {
+                                        tk->i_compression_type = MATROSKA_COMPRESSION_ZLIB;
+                                    }
+                                }
+                                else
+                                {
+                                    MkvTree( p_demux, 6, "Unknown (%s)", typeid(*l4).name() );
+                                }
+                            }
+                        }
+
+                        else
+                        {
+                            MkvTree( p_demux, 5, "Unknown (%s)", typeid(*l3).name() );
+                        }
+                    }
+                    
+                }
+                else
+                {
+                    MkvTree( p_demux, 4, "Unknown (%s)", typeid(*l2).name() );
+                }
+            }
+                
+        }
 //        else if( EbmlId( *l ) == KaxCodecSettings::ClassInfos.GlobalId )
 //        {
 //            KaxCodecSettings &cset = *(KaxCodecSettings*)l;