#include "ebml/StdIOCallback.h"
+extern "C" {
+ #include "mp4/libmp4.h"
+}
#ifdef HAVE_ZLIB_H
# include <zlib.h>
#endif
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"),
static void Seek ( demux_t *, mtime_t i_date, int i_percent );
#ifdef HAVE_ZLIB_H
-int do_zlib_decompress( unsigned char *src, unsigned char **_dst, int slen ) {
+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;
result = inflateInit(&d_stream);
if( result != Z_OK )
{
- printf( "inflateInit() failed. Result: %d\n", result );
- return( -1 );
+ msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
+ return NULL;
}
- d_stream.next_in = (Bytef *)src;
- d_stream.avail_in = slen;
+ 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++;
- dst = (unsigned char *)realloc(dst, n * 1000);
+ 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 ) )
{
- printf( "Zlib decompression failed. Result: %d\n", result );
- return( -1 );
+ msg_Dbg( p_this, "Zlib decompression failed. Result: %d", result );
+ return NULL;
}
}
while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
dstsize = d_stream.total_out;
inflateEnd( &d_stream );
- *_dst = (unsigned char *)realloc( dst, dstsize );
+ p_block = block_Realloc( p_block, 0, dstsize );
+ p_block->i_buffer = dstsize;
+ block_Release( p_in_block );
- return dstsize;
+ 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
*****************************************************************************/
char *psz_codec_download_url;
/* encryption/compression */
- vlc_bool_t b_compression_zlib;
+ int i_compression_type;
} mkv_track_t;
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;
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 ) )
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
tk->psz_codec_info_url = NULL;
tk->psz_codec_download_url = NULL;
- tk->b_compression_zlib = MATROSKA_COMPRESSION_NONE;
+ tk->i_compression_type = MATROSKA_COMPRESSION_NONE;
for( i = 0; i < m->ListSize(); i++ )
{
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, KaxContentEncoding ) )
+ else if( MKV_IS_ID( l, KaxContentEncodings ) )
{
- KaxContentEncoding &cenc = *(KaxContentEncoding*)l;
- msg_Dbg( p_demux, "| | | + Track Content Compression: ZLIB" );
+ 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 )
// {