@ -212,6 +212,11 @@ typedef struct {
uint64_t length ;
} MatroskaLevel ;
typedef struct {
uint64_t timecode ;
EbmlList blocks ;
} MatroskaCluster ;
typedef struct {
AVFormatContext * ctx ;
@ -247,6 +252,13 @@ typedef struct {
/* File has a CUES element, but we defer parsing until it is needed. */
int cues_parsing_deferred ;
int current_cluster_num_blocks ;
int64_t current_cluster_pos ;
MatroskaCluster current_cluster ;
/* File has SSA subtitles which prevent incremental cluster parsing. */
int contains_ssa ;
} MatroskaDemuxContext ;
typedef struct {
@ -256,11 +268,6 @@ typedef struct {
EbmlBin bin ;
} MatroskaBlock ;
typedef struct {
uint64_t timecode ;
EbmlList blocks ;
} MatroskaCluster ;
static EbmlSyntax ebml_header [ ] = {
{ EBML_ID_EBMLREADVERSION , EBML_UINT , 0 , offsetof ( Ebml , version ) , { . u = EBML_VERSION } } ,
{ EBML_ID_EBMLMAXSIZELENGTH , EBML_UINT , 0 , offsetof ( Ebml , max_size ) , { . u = 8 } } ,
@ -514,6 +521,38 @@ static EbmlSyntax matroska_clusters[] = {
{ 0 }
} ;
static EbmlSyntax matroska_cluster_incremental_parsing [ ] = {
{ MATROSKA_ID_CLUSTERTIMECODE , EBML_UINT , 0 , offsetof ( MatroskaCluster , timecode ) } ,
{ MATROSKA_ID_BLOCKGROUP , EBML_NEST , sizeof ( MatroskaBlock ) , offsetof ( MatroskaCluster , blocks ) , { . n = matroska_blockgroup } } ,
{ MATROSKA_ID_SIMPLEBLOCK , EBML_PASS , sizeof ( MatroskaBlock ) , offsetof ( MatroskaCluster , blocks ) , { . n = matroska_blockgroup } } ,
{ MATROSKA_ID_CLUSTERPOSITION , EBML_NONE } ,
{ MATROSKA_ID_CLUSTERPREVSIZE , EBML_NONE } ,
{ MATROSKA_ID_INFO , EBML_NONE } ,
{ MATROSKA_ID_CUES , EBML_NONE } ,
{ MATROSKA_ID_TAGS , EBML_NONE } ,
{ MATROSKA_ID_SEEKHEAD , EBML_NONE } ,
{ MATROSKA_ID_CLUSTER , EBML_STOP } ,
{ 0 }
} ;
static EbmlSyntax matroska_cluster_incremental [ ] = {
{ MATROSKA_ID_CLUSTERTIMECODE , EBML_UINT , 0 , offsetof ( MatroskaCluster , timecode ) } ,
{ MATROSKA_ID_BLOCKGROUP , EBML_STOP } ,
{ MATROSKA_ID_SIMPLEBLOCK , EBML_STOP } ,
{ MATROSKA_ID_CLUSTERPOSITION , EBML_NONE } ,
{ MATROSKA_ID_CLUSTERPREVSIZE , EBML_NONE } ,
{ 0 }
} ;
static EbmlSyntax matroska_clusters_incremental [ ] = {
{ MATROSKA_ID_CLUSTER , EBML_NEST , 0 , 0 , { . n = matroska_cluster_incremental } } ,
{ MATROSKA_ID_INFO , EBML_NONE } ,
{ MATROSKA_ID_CUES , EBML_NONE } ,
{ MATROSKA_ID_TAGS , EBML_NONE } ,
{ MATROSKA_ID_SEEKHEAD , EBML_NONE } ,
{ 0 }
} ;
static const char * const matroska_doctypes [ ] = { " matroska " , " webm " } ;
/*
@ -1563,6 +1602,8 @@ static int matroska_read_header(AVFormatContext *s)
st - > need_parsing = AVSTREAM_PARSE_HEADERS ;
} else if ( track - > type = = MATROSKA_TRACK_TYPE_SUBTITLE ) {
st - > codec - > codec_type = AVMEDIA_TYPE_SUBTITLE ;
if ( st - > codec - > codec_id = = CODEC_ID_SSA )
matroska - > contains_ssa = 1 ;
}
}
@ -1634,6 +1675,7 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
matroska - > packets = newpackets ;
} else {
av_freep ( & matroska - > packets ) ;
matroska - > prev_pkt = NULL ;
}
matroska - > num_packets - - ;
return 0 ;
@ -1929,13 +1971,71 @@ end:
return res ;
}
static int matroska_parse_cluster_incremental ( MatroskaDemuxContext * matroska )
{
EbmlList * blocks_list ;
MatroskaBlock * blocks ;
int i , res ;
res = ebml_parse ( matroska ,
matroska_cluster_incremental_parsing ,
& matroska - > current_cluster ) ;
if ( res = = 1 ) {
/* New Cluster */
if ( matroska - > current_cluster_pos )
ebml_level_end ( matroska ) ;
ebml_free ( matroska_cluster , & matroska - > current_cluster ) ;
memset ( & matroska - > current_cluster , 0 , sizeof ( MatroskaCluster ) ) ;
matroska - > current_cluster_num_blocks = 0 ;
matroska - > current_cluster_pos = avio_tell ( matroska - > ctx - > pb ) ;
matroska - > prev_pkt = NULL ;
/* sizeof the ID which was already read */
if ( matroska - > current_id )
matroska - > current_cluster_pos - = 4 ;
res = ebml_parse ( matroska ,
matroska_clusters_incremental ,
& matroska - > current_cluster ) ;
/* Try parsing the block again. */
if ( res = = 1 )
res = ebml_parse ( matroska ,
matroska_cluster_incremental_parsing ,
& matroska - > current_cluster ) ;
}
if ( ! res & &
matroska - > current_cluster_num_blocks <
matroska - > current_cluster . blocks . nb_elem ) {
blocks_list = & matroska - > current_cluster . blocks ;
blocks = blocks_list - > elem ;
matroska - > current_cluster_num_blocks = blocks_list - > nb_elem ;
i = blocks_list - > nb_elem - 1 ;
if ( blocks [ i ] . bin . size > 0 & & blocks [ i ] . bin . data ) {
int is_keyframe = blocks [ i ] . non_simple ? ! blocks [ i ] . reference : - 1 ;
if ( ! blocks [ i ] . non_simple )
blocks [ i ] . duration = AV_NOPTS_VALUE ;
res = matroska_parse_block ( matroska ,
blocks [ i ] . bin . data , blocks [ i ] . bin . size ,
blocks [ i ] . bin . pos ,
matroska - > current_cluster . timecode ,
blocks [ i ] . duration , is_keyframe ,
matroska - > current_cluster_pos ) ;
}
}
if ( res < 0 ) matroska - > done = 1 ;
return res ;
}
static int matroska_parse_cluster ( MatroskaDemuxContext * matroska )
{
MatroskaCluster cluster = { 0 } ;
EbmlList * blocks_list ;
MatroskaBlock * blocks ;
int i , res ;
int64_t pos = avio_tell ( matroska - > ctx - > pb ) ;
int64_t pos ;
if ( ! matroska - > contains_ssa )
return matroska_parse_cluster_incremental ( matroska ) ;
pos = avio_tell ( matroska - > ctx - > pb ) ;
matroska - > prev_pkt = NULL ;
if ( matroska - > current_id )
pos - = 4 ; /* sizeof the ID which was already read */
@ -2040,6 +2140,7 @@ static int matroska_read_close(AVFormatContext *s)
for ( n = 0 ; n < matroska - > tracks . nb_elem ; n + + )
if ( tracks [ n ] . type = = MATROSKA_TRACK_TYPE_AUDIO )
av_free ( tracks [ n ] . audio . buf ) ;
ebml_free ( matroska_cluster , & matroska - > current_cluster ) ;
ebml_free ( matroska_segment , matroska ) ;
return 0 ;