Commit 11d6a071 authored by Gildas Bazin's avatar Gildas Bazin

* modules/demux/mkv.cpp: fix for chapters seeking + support for more chapter...

* modules/demux/mkv.cpp: fix for chapters seeking + support for more chapter elements, like hidden chapters. Patch by Steve Lhomme (steve dot lhomme at free dot fr).
* include/vlc_input.h: added an i_level member to seekpoint_t for nested chapters (patch by Steve Lhomme).
parent 191b359e
...@@ -169,6 +169,7 @@ struct seekpoint_t ...@@ -169,6 +169,7 @@ struct seekpoint_t
int64_t i_byte_offset; int64_t i_byte_offset;
int64_t i_time_offset; int64_t i_time_offset;
char *psz_name; char *psz_name;
int i_level;
}; };
static inline seekpoint_t *vlc_seekpoint_New( void ) static inline seekpoint_t *vlc_seekpoint_New( void )
...@@ -176,6 +177,7 @@ static inline seekpoint_t *vlc_seekpoint_New( void ) ...@@ -176,6 +177,7 @@ static inline seekpoint_t *vlc_seekpoint_New( void )
seekpoint_t *point = (seekpoint_t*)malloc( sizeof( seekpoint_t ) ); seekpoint_t *point = (seekpoint_t*)malloc( sizeof( seekpoint_t ) );
point->i_byte_offset = point->i_byte_offset =
point->i_time_offset = 0; point->i_time_offset = 0;
point->i_level = 0;
point->psz_name = NULL; point->psz_name = NULL;
return point; return point;
} }
......
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
#include "ebml/EbmlSubHead.h" #include "ebml/EbmlSubHead.h"
#include "ebml/EbmlStream.h" #include "ebml/EbmlStream.h"
#include "ebml/EbmlContexts.h" #include "ebml/EbmlContexts.h"
#include "ebml/EbmlVersion.h"
#include "ebml/EbmlVoid.h" #include "ebml/EbmlVoid.h"
#include "ebml/StdIOCallback.h" #include "ebml/StdIOCallback.h"
...@@ -333,6 +332,7 @@ public: ...@@ -333,6 +332,7 @@ public:
,segment(NULL) ,segment(NULL)
,cluster(NULL) ,cluster(NULL)
,i_pts(0) ,i_pts(0)
,i_start_pts(0)
,b_cues(false) ,b_cues(false)
,i_index(0) ,i_index(0)
,i_index_max(0) ,i_index_max(0)
...@@ -371,6 +371,7 @@ public: ...@@ -371,6 +371,7 @@ public:
KaxSegmentUID segment_uid; KaxSegmentUID segment_uid;
mtime_t i_pts; mtime_t i_pts;
mtime_t i_start_pts;
vlc_bool_t b_cues; vlc_bool_t b_cues;
int i_index; int i_index;
...@@ -390,6 +391,9 @@ public: ...@@ -390,6 +391,9 @@ public:
std::vector<KaxSegmentFamily> families; std::vector<KaxSegmentFamily> families;
std::vector<KaxSegment*> family_members; std::vector<KaxSegment*> family_members;
int64_t edition_uid;
bool edition_ordered;
}; };
#define MKVD_TIMECODESCALE 1000000 #define MKVD_TIMECODESCALE 1000000
...@@ -757,6 +761,10 @@ static int Open( vlc_object_t * p_this ) ...@@ -757,6 +761,10 @@ static int Open( vlc_object_t * p_this )
else if( !strcmp( tk.psz_codec, "V_MPEG4/ISO/AVC" ) ) else if( !strcmp( tk.psz_codec, "V_MPEG4/ISO/AVC" ) )
{ {
tk.fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '4' ); tk.fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '4' );
tk.fmt.b_packetized = VLC_FALSE;
tk.fmt.i_extra = tk.i_extra_data;
tk.fmt.p_extra = malloc( tk.i_extra_data );
memcpy( tk.fmt.p_extra,tk.p_extra_data, tk.i_extra_data );
} }
else else
{ {
...@@ -1057,6 +1065,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -1057,6 +1065,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
int64_t *pi64; int64_t *pi64;
double *pf, f; double *pf, f;
int i_skp;
vlc_meta_t **pp_meta; vlc_meta_t **pp_meta;
...@@ -1125,11 +1134,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -1125,11 +1134,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case DEMUX_SET_SEEKPOINT: case DEMUX_SET_SEEKPOINT:
/* FIXME do a better implementation */ /* FIXME do a better implementation */
if( p_sys->title && p_sys->title->i_seekpoint > 0 ) i_skp = (int)va_arg( args, int );
{
int i_skp = (int)va_arg( args, int );
if( p_sys->title && i_skp < p_sys->title->i_seekpoint)
{
Seek( p_demux, (int64_t)p_sys->title->seekpoint[i_skp]->i_time_offset, -1); Seek( p_demux, (int64_t)p_sys->title->seekpoint[i_skp]->i_time_offset, -1);
p_demux->info.i_seekpoint |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i_skp;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -1344,8 +1355,16 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts, ...@@ -1344,8 +1355,16 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
} }
#endif #endif
if( tk.fmt.i_cat != VIDEO_ES ) if (i_pts < p_sys->i_start_pts)
{
p_block->i_pts = -1;
p_block->i_dts = -1;
/* p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;*/
}
else if( tk.fmt.i_cat != VIDEO_ES )
{
p_block->i_dts = p_block->i_pts = i_pts; p_block->i_dts = p_block->i_pts = i_pts;
}
else else
{ {
p_block->i_dts = i_pts; p_block->i_dts = i_pts;
...@@ -1390,7 +1409,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent) ...@@ -1390,7 +1409,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent)
p_sys->cluster = NULL; p_sys->cluster = NULL;
/* seek without index or without date */ /* seek without index or without date */
if( config_GetInt( p_demux, "mkv-seek-percent" ) || !p_sys->b_cues || i_date < 0 ) if( i_percent >= 0 && (config_GetInt( p_demux, "mkv-seek-percent" ) || !p_sys->b_cues || i_date < 0 ))
{ {
int64_t i_pos = i_percent * stream_Size( p_demux->s ) / 100; int64_t i_pos = i_percent * stream_Size( p_demux->s ) / 100;
...@@ -1472,6 +1491,8 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent) ...@@ -1472,6 +1491,8 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent)
} }
} }
p_sys->i_start_pts = i_date;
while( i_track_skipping > 0 ) while( i_track_skipping > 0 )
{ {
if( BlockGet( p_demux, &block, &i_block_ref1, &i_block_ref2, &i_block_duration ) ) if( BlockGet( p_demux, &block, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
...@@ -1481,7 +1502,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent) ...@@ -1481,7 +1502,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent)
return; return;
} }
p_sys->i_pts = block->GlobalTimecode() / (mtime_t) 1000 + 1; p_sys->i_pts = block->GlobalTimecode() / (mtime_t) 1000;
for( i_track = 0; i_track < p_sys->i_track; i_track++ ) for( i_track = 0; i_track < p_sys->i_track; i_track++ )
{ {
...@@ -1536,7 +1557,7 @@ static int Demux( demux_t *p_demux) ...@@ -1536,7 +1557,7 @@ static int Demux( demux_t *p_demux)
return 0; return 0;
} }
p_sys->i_pts = block->GlobalTimecode() / (mtime_t) 1000 + 1; p_sys->i_pts = block->GlobalTimecode() / (mtime_t) 1000;
if( p_sys->i_pts > 0 ) if( p_sys->i_pts > 0 )
{ {
...@@ -2616,6 +2637,7 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca ) ...@@ -2616,6 +2637,7 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
unsigned int i; unsigned int i;
seekpoint_t *sk; seekpoint_t *sk;
bool b_display_seekpoint = true;
if( p_sys->title == NULL ) if( p_sys->title == NULL )
{ {
...@@ -2623,6 +2645,8 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca ) ...@@ -2623,6 +2645,8 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
} }
sk = vlc_seekpoint_New(); sk = vlc_seekpoint_New();
sk->i_level = i_level;
msg_Dbg( p_demux, "| | | + ChapterAtom (level=%d)", i_level ); msg_Dbg( p_demux, "| | | + ChapterAtom (level=%d)", i_level );
for( i = 0; i < ca->ListSize(); i++ ) for( i = 0; i < ca->ListSize(); i++ )
{ {
...@@ -2634,6 +2658,13 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca ) ...@@ -2634,6 +2658,13 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
uint32_t i_uid = uint32( uid ); uint32_t i_uid = uint32( uid );
msg_Dbg( p_demux, "| | | | + ChapterUID: 0x%x", i_uid ); msg_Dbg( p_demux, "| | | | + ChapterUID: 0x%x", i_uid );
} }
else if( MKV_IS_ID( l, KaxChapterFlagHidden ) )
{
KaxChapterFlagHidden &flag =*(KaxChapterFlagHidden*)l;
b_display_seekpoint = uint8( flag ) == 0;
msg_Dbg( p_demux, "| | | | + ChapterFlagHidden: %s", b_display_seekpoint ? "no":"yes" );
}
else if( MKV_IS_ID( l, KaxChapterTimeStart ) ) else if( MKV_IS_ID( l, KaxChapterTimeStart ) )
{ {
KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l; KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
...@@ -2660,10 +2691,16 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca ) ...@@ -2660,10 +2691,16 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
if( MKV_IS_ID( l, KaxChapterString ) ) if( MKV_IS_ID( l, KaxChapterString ) )
{ {
std::string psz;
int k;
KaxChapterString &name =*(KaxChapterString*)l; KaxChapterString &name =*(KaxChapterString*)l;
char *psz = UTF8ToStr( UTFstring( name ) ); for (k = 0; k < i_level; k++)
sk->psz_name = strdup( psz ); psz += '+';
msg_Dbg( p_demux, "| | | | | + ChapterString '%s'", psz ); psz += ' ';
psz += UTF8ToStr( UTFstring( name ) );
sk->psz_name = strdup( psz.c_str() );
msg_Dbg( p_demux, "| | | | | + ChapterString '%s'", UTF8ToStr(UTFstring(name)) );
} }
else if( MKV_IS_ID( l, KaxChapterLanguage ) ) else if( MKV_IS_ID( l, KaxChapterLanguage ) )
{ {
...@@ -2686,10 +2723,18 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca ) ...@@ -2686,10 +2723,18 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
ParseChapterAtom( p_demux, i_level+1, static_cast<EbmlMaster *>(l) ); ParseChapterAtom( p_demux, i_level+1, static_cast<EbmlMaster *>(l) );
} }
} }
// A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
p_sys->title->i_seekpoint++; if (b_display_seekpoint)
p_sys->title->seekpoint = (seekpoint_t**)realloc( p_sys->title->seekpoint, p_sys->title->i_seekpoint * sizeof( seekpoint_t* ) ); {
p_sys->title->seekpoint[p_sys->title->i_seekpoint-1] = sk; // A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
p_sys->title->i_seekpoint++;
p_sys->title->seekpoint = (seekpoint_t**)realloc( p_sys->title->seekpoint, p_sys->title->i_seekpoint * sizeof( seekpoint_t* ) );
p_sys->title->seekpoint[p_sys->title->i_seekpoint-1] = sk;
}
else
{
vlc_seekpoint_Delete(sk);
}
} }
/***************************************************************************** /*****************************************************************************
...@@ -2717,6 +2762,7 @@ static void ParseChapters( demux_t *p_demux, EbmlElement *chapters ) ...@@ -2717,6 +2762,7 @@ static void ParseChapters( demux_t *p_demux, EbmlElement *chapters )
EbmlMaster *E = static_cast<EbmlMaster *>(l ); EbmlMaster *E = static_cast<EbmlMaster *>(l );
unsigned int j; unsigned int j;
msg_Dbg( p_demux, "| | + EditionEntry" ); msg_Dbg( p_demux, "| | + EditionEntry" );
p_sys->edition_ordered = false;
for( j = 0; j < E->ListSize(); j++ ) for( j = 0; j < E->ListSize(); j++ )
{ {
EbmlElement *l = (*E)[j]; EbmlElement *l = (*E)[j];
...@@ -2725,6 +2771,14 @@ static void ParseChapters( demux_t *p_demux, EbmlElement *chapters ) ...@@ -2725,6 +2771,14 @@ static void ParseChapters( demux_t *p_demux, EbmlElement *chapters )
{ {
ParseChapterAtom( p_demux, 0, static_cast<EbmlMaster *>(l) ); ParseChapterAtom( p_demux, 0, static_cast<EbmlMaster *>(l) );
} }
else if( MKV_IS_ID( l, KaxEditionUID ) )
{
p_sys->edition_uid = uint64(*static_cast<KaxEditionUID *>(l));
}
else if( MKV_IS_ID( l, KaxEditionFlagOrdered ) )
{
p_sys->edition_ordered = uint8(*static_cast<KaxEditionFlagOrdered *>(l)) != 0;
}
else else
{ {
msg_Dbg( p_demux, "| | | + Unknown (%s)", typeid(*l).name() ); msg_Dbg( p_demux, "| | | + Unknown (%s)", typeid(*l).name() );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment