X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fmkv.cpp;h=1477151cea8805b8f5c097e7800f53ad0b2d666e;hb=e9694509281cd3378759235433f576f2bfdb72ba;hp=8c259740f262bef4da641b2e0115862d504ef9c0;hpb=381fcdb7866f29786566f5dbf7cfbf112c9868b4;p=vlc diff --git a/modules/demux/mkv.cpp b/modules/demux/mkv.cpp index 8c259740f2..1477151cea 100644 --- a/modules/demux/mkv.cpp +++ b/modules/demux/mkv.cpp @@ -71,9 +71,20 @@ #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 +#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(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(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(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;