mirror of
https://code.videolan.org/videolan/vlc
synced 2024-09-12 13:44:56 +02:00
* 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).
This commit is contained in:
parent
191b359eac
commit
11d6a0719f
@ -169,6 +169,7 @@ struct seekpoint_t
|
||||
int64_t i_byte_offset;
|
||||
int64_t i_time_offset;
|
||||
char *psz_name;
|
||||
int i_level;
|
||||
};
|
||||
|
||||
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 ) );
|
||||
point->i_byte_offset =
|
||||
point->i_time_offset = 0;
|
||||
point->i_level = 0;
|
||||
point->psz_name = NULL;
|
||||
return point;
|
||||
}
|
||||
|
@ -56,7 +56,6 @@
|
||||
#include "ebml/EbmlSubHead.h"
|
||||
#include "ebml/EbmlStream.h"
|
||||
#include "ebml/EbmlContexts.h"
|
||||
#include "ebml/EbmlVersion.h"
|
||||
#include "ebml/EbmlVoid.h"
|
||||
#include "ebml/StdIOCallback.h"
|
||||
|
||||
@ -333,6 +332,7 @@ public:
|
||||
,segment(NULL)
|
||||
,cluster(NULL)
|
||||
,i_pts(0)
|
||||
,i_start_pts(0)
|
||||
,b_cues(false)
|
||||
,i_index(0)
|
||||
,i_index_max(0)
|
||||
@ -371,6 +371,7 @@ public:
|
||||
KaxSegmentUID segment_uid;
|
||||
|
||||
mtime_t i_pts;
|
||||
mtime_t i_start_pts;
|
||||
|
||||
vlc_bool_t b_cues;
|
||||
int i_index;
|
||||
@ -390,6 +391,9 @@ public:
|
||||
|
||||
std::vector<KaxSegmentFamily> families;
|
||||
std::vector<KaxSegment*> family_members;
|
||||
|
||||
int64_t edition_uid;
|
||||
bool edition_ordered;
|
||||
};
|
||||
|
||||
#define MKVD_TIMECODESCALE 1000000
|
||||
@ -757,6 +761,10 @@ static int Open( vlc_object_t * p_this )
|
||||
else if( !strcmp( tk.psz_codec, "V_MPEG4/ISO/AVC" ) )
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -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;
|
||||
int64_t *pi64;
|
||||
double *pf, f;
|
||||
int i_skp;
|
||||
|
||||
vlc_meta_t **pp_meta;
|
||||
|
||||
@ -1125,11 +1134,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
|
||||
|
||||
case DEMUX_SET_SEEKPOINT:
|
||||
/* FIXME do a better implementation */
|
||||
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
|
||||
{
|
||||
int i_skp = (int)va_arg( args, 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);
|
||||
p_demux->info.i_seekpoint |= INPUT_UPDATE_SEEKPOINT;
|
||||
p_demux->info.i_seekpoint = i_skp;
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
return VLC_EGENERIC;
|
||||
@ -1344,8 +1355,16 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
|
||||
}
|
||||
#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;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_block->i_dts = i_pts;
|
||||
@ -1390,7 +1409,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent)
|
||||
p_sys->cluster = NULL;
|
||||
|
||||
/* 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;
|
||||
|
||||
@ -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 )
|
||||
{
|
||||
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)
|
||||
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++ )
|
||||
{
|
||||
@ -1536,7 +1557,7 @@ static int Demux( demux_t *p_demux)
|
||||
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 )
|
||||
{
|
||||
@ -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;
|
||||
unsigned int i;
|
||||
seekpoint_t *sk;
|
||||
bool b_display_seekpoint = true;
|
||||
|
||||
if( p_sys->title == NULL )
|
||||
{
|
||||
@ -2623,6 +2645,8 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
|
||||
}
|
||||
sk = vlc_seekpoint_New();
|
||||
|
||||
sk->i_level = i_level;
|
||||
|
||||
msg_Dbg( p_demux, "| | | + ChapterAtom (level=%d)", i_level );
|
||||
for( i = 0; i < ca->ListSize(); i++ )
|
||||
{
|
||||
@ -2634,6 +2658,13 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
|
||||
uint32_t i_uid = uint32( 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 ) )
|
||||
{
|
||||
KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
|
||||
@ -2660,10 +2691,16 @@ static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
|
||||
|
||||
if( MKV_IS_ID( l, KaxChapterString ) )
|
||||
{
|
||||
std::string psz;
|
||||
int k;
|
||||
|
||||
KaxChapterString &name =*(KaxChapterString*)l;
|
||||
char *psz = UTF8ToStr( UTFstring( name ) );
|
||||
sk->psz_name = strdup( psz );
|
||||
msg_Dbg( p_demux, "| | | | | + ChapterString '%s'", psz );
|
||||
for (k = 0; k < i_level; k++)
|
||||
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 ) )
|
||||
{
|
||||
@ -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) );
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
|
||||
if (b_display_seekpoint)
|
||||
{
|
||||
// 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 )
|
||||
EbmlMaster *E = static_cast<EbmlMaster *>(l );
|
||||
unsigned int j;
|
||||
msg_Dbg( p_demux, "| | + EditionEntry" );
|
||||
p_sys->edition_ordered = false;
|
||||
for( j = 0; j < E->ListSize(); j++ )
|
||||
{
|
||||
EbmlElement *l = (*E)[j];
|
||||
@ -2725,6 +2771,14 @@ static void ParseChapters( demux_t *p_demux, EbmlElement *chapters )
|
||||
{
|
||||
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
|
||||
{
|
||||
msg_Dbg( p_demux, "| | | + Unknown (%s)", typeid(*l).name() );
|
||||
|
Loading…
Reference in New Issue
Block a user