Commit 2f4bc2d8 authored by Steve Lhomme's avatar Steve Lhomme

mkv.cpp: make editions children of chapters

parent 6a1d2a02
...@@ -123,11 +123,11 @@ vlc_module_begin(); ...@@ -123,11 +123,11 @@ vlc_module_begin();
add_bool( "mkv-use-ordered-chapters", 1, NULL, add_bool( "mkv-use-ordered-chapters", 1, NULL,
N_("Ordered chapters"), N_("Ordered chapters"),
N_("Play chapters in the specified order as specified in the file"), VLC_TRUE ); N_("Play ordered chapters as specified in the segment"), VLC_TRUE );
add_bool( "mkv-use-chapter-codec", 1, NULL, add_bool( "mkv-use-chapter-codec", 1, NULL,
N_("Chapter codecs"), N_("Chapter codecs"),
N_("Use chapter codecs found in the file"), VLC_TRUE ); N_("Use chapter codecs found in the segment"), VLC_TRUE );
add_bool( "mkv-seek-percent", 0, NULL, add_bool( "mkv-seek-percent", 0, NULL,
N_("Seek based on percent not time"), N_("Seek based on percent not time"),
...@@ -336,7 +336,8 @@ public: ...@@ -336,7 +336,8 @@ public:
,psz_parent(NULL) ,psz_parent(NULL)
{} {}
int64_t RefreshChapters( bool b_ordered, int64_t i_prev_user_time, input_title_t & title ); int64_t RefreshChapters( bool b_ordered, int64_t i_prev_user_time );
void PublishChapters( input_title_t & title, int i_level );
const chapter_item_t * FindTimecode( mtime_t i_timecode ) const; const chapter_item_t * FindTimecode( mtime_t i_timecode ) const;
int64_t i_start_time, i_end_time; int64_t i_start_time, i_end_time;
...@@ -358,20 +359,19 @@ protected: ...@@ -358,20 +359,19 @@ protected:
bool Leave(); bool Leave();
}; };
class chapter_edition_t class chapter_edition_t : public chapter_item_t
{ {
public: public:
chapter_edition_t() chapter_edition_t()
:i_uid(-1) :b_ordered(false)
,b_ordered(false)
{} {}
void RefreshChapters( input_title_t & title ); void RefreshChapters( );
double Duration() const; mtime_t Duration() const;
const chapter_item_t * FindTimecode( mtime_t i_timecode ) const; void PublishChapters( input_title_t & title );
void Append( const chapter_edition_t & edition );
chapter_item_t * FindChapter( const chapter_item_t & chapter ) const;
std::vector<chapter_item_t> chapters;
int64_t i_uid;
bool b_ordered; bool b_ordered;
}; };
...@@ -577,6 +577,7 @@ public: ...@@ -577,6 +577,7 @@ public:
/* TODO handle/merge chapters here */ /* TODO handle/merge chapters here */
void UpdateCurrentToChapter( demux_t & demux ); void UpdateCurrentToChapter( demux_t & demux );
bool Select( input_title_t & title );
protected: protected:
std::vector<matroska_segment_t*> linked_segments; std::vector<matroska_segment_t*> linked_segments;
...@@ -658,7 +659,7 @@ public: ...@@ -658,7 +659,7 @@ public:
matroska_segment_t *FindSegment( const EbmlBinary & uid ) const; matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( ); void PreloadFamily( );
void PreloadLinked( matroska_segment_t *p_segment ); void PreloadLinked( matroska_segment_t *p_segment );
void PreparePlayback( ); bool PreparePlayback( );
matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream ); matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream );
}; };
...@@ -798,12 +799,7 @@ static int Open( vlc_object_t * p_this ) ...@@ -798,12 +799,7 @@ static int Open( vlc_object_t * p_this )
p_sys->PreloadFamily( ); p_sys->PreloadFamily( );
p_sys->PreloadLinked( p_segment ); p_sys->PreloadLinked( p_segment );
p_sys->PreparePlayback( ); if ( !p_sys->PreparePlayback( ) )
/* add information */
p_segment->InformationCreate( );
if ( !p_segment->Select( 0 ) )
{ {
msg_Err( p_demux, "cannot use the segment" ); msg_Err( p_demux, "cannot use the segment" );
goto error; goto error;
...@@ -1332,10 +1328,16 @@ bool matroska_segment_t::Select( mtime_t i_start_time ) ...@@ -1332,10 +1328,16 @@ bool matroska_segment_t::Select( mtime_t i_start_time )
else if( !strcmp( tk->psz_codec, "V_QUICKTIME" ) ) else if( !strcmp( tk->psz_codec, "V_QUICKTIME" ) )
{ {
MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) ); MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
#ifdef VSLHC
stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(&sys.demuxer),
tk->p_extra_data,
tk->i_extra_data );
#else
stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(&sys.demuxer), stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(&sys.demuxer),
tk->p_extra_data, tk->p_extra_data,
tk->i_extra_data, tk->i_extra_data,
VLC_FALSE ); VLC_FALSE );
#endif
MP4_ReadBoxCommon( p_mp4_stream, p_box ); MP4_ReadBoxCommon( p_mp4_stream, p_box );
MP4_ReadBox_sample_vide( p_mp4_stream, p_box ); MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
tk->fmt.i_codec = p_box->i_type; tk->fmt.i_codec = p_box->i_type;
...@@ -1345,7 +1347,11 @@ bool matroska_segment_t::Select( mtime_t i_start_time ) ...@@ -1345,7 +1347,11 @@ bool matroska_segment_t::Select( mtime_t i_start_time )
tk->fmt.p_extra = malloc( tk->fmt.i_extra ); 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 ); 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 ); MP4_FreeBox_sample_vide( p_box );
#ifdef VSLHC
stream_MemoryDelete( p_mp4_stream, VLC_TRUE );
#else
stream_Delete( p_mp4_stream ); stream_Delete( p_mp4_stream );
#endif
} }
else if( !strcmp( tk->psz_codec, "A_MS/ACM" ) ) else if( !strcmp( tk->psz_codec, "A_MS/ACM" ) )
{ {
...@@ -1586,6 +1592,65 @@ void matroska_segment_t::UnSelect( ) ...@@ -1586,6 +1592,65 @@ void matroska_segment_t::UnSelect( )
} }
} }
bool virtual_segment_t::Select( input_title_t & title )
{
if ( linked_segments.size() == 0 )
return false;
// !!! should be called only once !!!
matroska_segment_t *p_segment;
size_t i, j;
// copy editions from the first segment
p_segment = linked_segments[0];
editions = p_segment->stored_editions;
i_current_edition = p_segment->i_default_edition;
for ( i=1 ; i<linked_segments.size(); i++ )
{
p_segment = linked_segments[i];
// FIXME assume we have the same editions in all segments
for (j=0; j<p_segment->stored_editions.size(); j++)
editions[j].Append( p_segment->stored_editions[j] );
}
Edition()->PublishChapters( title );
return true;
}
void chapter_edition_t::PublishChapters( input_title_t & title )
{
title.i_seekpoint = 0;
if ( title.seekpoint != NULL )
free( title.seekpoint );
chapter_item_t::PublishChapters( title, 0 );
}
void chapter_item_t::PublishChapters( input_title_t & title, int i_level )
{
if (b_display_seekpoint)
{
seekpoint_t *sk = vlc_seekpoint_New();
sk->i_level = i_level;
sk->i_time_offset = i_start_time;
sk->psz_name = strdup( psz_name.c_str() );
// A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
title.i_seekpoint++;
title.seekpoint = (seekpoint_t**)realloc( title.seekpoint, title.i_seekpoint * sizeof( seekpoint_t* ) );
title.seekpoint[title.i_seekpoint-1] = sk;
}
i_seekpoint_num = title.i_seekpoint;
for ( size_t i=0; i<sub_chapters.size() ; i++)
{
sub_chapters[i].PublishChapters( title, i_level+1 );
}
}
void virtual_segment_t::UpdateCurrentToChapter( demux_t & demux ) void virtual_segment_t::UpdateCurrentToChapter( demux_t & demux )
{ {
demux_sys_t & sys = *demux.p_sys; demux_sys_t & sys = *demux.p_sys;
...@@ -1598,7 +1663,7 @@ void virtual_segment_t::UpdateCurrentToChapter( demux_t & demux ) ...@@ -1598,7 +1663,7 @@ void virtual_segment_t::UpdateCurrentToChapter( demux_t & demux )
psz_curr_chapter = editions[i_current_edition].FindTimecode( sys.i_pts ); psz_curr_chapter = editions[i_current_edition].FindTimecode( sys.i_pts );
/* we have moved to a new chapter */ /* we have moved to a new chapter */
if (psz_curr_chapter != NULL && psz_current_chapter != psz_curr_chapter) if (psz_curr_chapter != NULL && psz_current_chapter != NULL && psz_current_chapter != psz_curr_chapter)
{ {
if (psz_current_chapter->i_seekpoint_num != psz_curr_chapter->i_seekpoint_num && psz_curr_chapter->i_seekpoint_num > 0) if (psz_current_chapter->i_seekpoint_num != psz_curr_chapter->i_seekpoint_num && psz_curr_chapter->i_seekpoint_num > 0)
{ {
...@@ -1622,6 +1687,28 @@ void virtual_segment_t::UpdateCurrentToChapter( demux_t & demux ) ...@@ -1622,6 +1687,28 @@ void virtual_segment_t::UpdateCurrentToChapter( demux_t & demux )
} }
} }
void chapter_edition_t::Append( const chapter_edition_t & edition )
{
size_t i;
chapter_item_t *p_chapter;
for ( i=0; i<edition.sub_chapters.size(); i++ )
{
p_chapter = FindChapter( edition.sub_chapters[i] );
if ( p_chapter != NULL )
{
}
else
{
}
}
}
chapter_item_t * chapter_edition_t::FindChapter( const chapter_item_t & chapter ) const
{
return NULL;
}
static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, const chapter_item_t *psz_chapter ) static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, const chapter_item_t *psz_chapter )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
...@@ -2986,7 +3073,7 @@ void matroska_segment_t::ParseChapters( EbmlElement *chapters ) ...@@ -2986,7 +3073,7 @@ void matroska_segment_t::ParseChapters( EbmlElement *chapters )
EbmlMaster *m; EbmlMaster *m;
unsigned int i; unsigned int i;
int i_upper_level = 0; int i_upper_level = 0;
float f_dur; mtime_t i_dur;
/* Master elements */ /* Master elements */
m = static_cast<EbmlMaster *>(chapters); m = static_cast<EbmlMaster *>(chapters);
...@@ -3011,7 +3098,7 @@ void matroska_segment_t::ParseChapters( EbmlElement *chapters ) ...@@ -3011,7 +3098,7 @@ void matroska_segment_t::ParseChapters( EbmlElement *chapters )
{ {
chapter_item_t new_sub_chapter; chapter_item_t new_sub_chapter;
ParseChapterAtom( 0, static_cast<EbmlMaster *>(l), new_sub_chapter ); ParseChapterAtom( 0, static_cast<EbmlMaster *>(l), new_sub_chapter );
edition.chapters.push_back( new_sub_chapter ); edition.sub_chapters.push_back( new_sub_chapter );
} }
else if( MKV_IS_ID( l, KaxEditionUID ) ) else if( MKV_IS_ID( l, KaxEditionUID ) )
{ {
...@@ -3041,15 +3128,15 @@ void matroska_segment_t::ParseChapters( EbmlElement *chapters ) ...@@ -3041,15 +3128,15 @@ void matroska_segment_t::ParseChapters( EbmlElement *chapters )
for( i = 0; i < stored_editions.size(); i++ ) for( i = 0; i < stored_editions.size(); i++ )
{ {
stored_editions[i].RefreshChapters( *sys.title ); stored_editions[i].RefreshChapters( );
} }
if ( stored_editions[i_default_edition].b_ordered ) if ( stored_editions[i_default_edition].b_ordered )
{ {
/* update the duration of the segment according to the sum of all sub chapters */ /* update the duration of the segment according to the sum of all sub chapters */
f_dur = stored_editions[i_default_edition].Duration() / I64C(1000); i_dur = stored_editions[i_default_edition].Duration() / I64C(1000);
if (f_dur > 0.0) if (i_dur > 0)
i_duration = f_dur; i_duration = i_dur;
} }
} }
...@@ -3204,19 +3291,13 @@ static char * UTF8ToStr( const UTFstring &u ) ...@@ -3204,19 +3291,13 @@ static char * UTF8ToStr( const UTFstring &u )
return dst; return dst;
} }
void chapter_edition_t::RefreshChapters( input_title_t & title ) void chapter_edition_t::RefreshChapters( )
{ {
int64_t i_prev_user_time = 0; chapter_item_t::RefreshChapters( b_ordered, -1 );
std::vector<chapter_item_t>::iterator index = chapters.begin(); b_display_seekpoint = false;
while ( index != chapters.end() )
{
i_prev_user_time = (*index).RefreshChapters( b_ordered, i_prev_user_time, title );
index++;
}
} }
int64_t chapter_item_t::RefreshChapters( bool b_ordered, int64_t i_prev_user_time, input_title_t & title ) int64_t chapter_item_t::RefreshChapters( bool b_ordered, int64_t i_prev_user_time )
{ {
int64_t i_user_time = i_prev_user_time; int64_t i_user_time = i_prev_user_time;
...@@ -3224,7 +3305,7 @@ int64_t chapter_item_t::RefreshChapters( bool b_ordered, int64_t i_prev_user_tim ...@@ -3224,7 +3305,7 @@ int64_t chapter_item_t::RefreshChapters( bool b_ordered, int64_t i_prev_user_tim
std::vector<chapter_item_t>::iterator index = sub_chapters.begin(); std::vector<chapter_item_t>::iterator index = sub_chapters.begin();
while ( index != sub_chapters.end() ) while ( index != sub_chapters.end() )
{ {
i_user_time = (*index).RefreshChapters( b_ordered, i_user_time, title ); i_user_time = (*index).RefreshChapters( b_ordered, i_user_time );
index++; index++;
} }
...@@ -3244,40 +3325,29 @@ int64_t chapter_item_t::RefreshChapters( bool b_ordered, int64_t i_prev_user_tim ...@@ -3244,40 +3325,29 @@ int64_t chapter_item_t::RefreshChapters( bool b_ordered, int64_t i_prev_user_tim
{ {
std::sort( sub_chapters.begin(), sub_chapters.end() ); std::sort( sub_chapters.begin(), sub_chapters.end() );
i_user_start_time = i_start_time; i_user_start_time = i_start_time;
i_user_end_time = i_end_time; if ( i_end_time != -1 )
} i_user_end_time = i_end_time;
else if ( i_user_time != -1 )
if (b_display_seekpoint) i_user_end_time = i_user_time;
{ else
seekpoint_t *sk = vlc_seekpoint_New(); i_user_end_time = i_user_start_time;
// sk->i_level = i_level;
sk->i_time_offset = i_start_time;
sk->psz_name = strdup( psz_name.c_str() );
// A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
title.i_seekpoint++;
title.seekpoint = (seekpoint_t**)realloc( title.seekpoint, title.i_seekpoint * sizeof( seekpoint_t* ) );
title.seekpoint[title.i_seekpoint-1] = sk;
} }
i_seekpoint_num = title.i_seekpoint;
return i_user_end_time; return i_user_end_time;
} }
double chapter_edition_t::Duration() const mtime_t chapter_edition_t::Duration() const
{ {
double f_result = 0.0; mtime_t i_result = 0.0;
if ( chapters.size() ) if ( sub_chapters.size() )
{ {
std::vector<chapter_item_t>::const_iterator index = chapters.end(); std::vector<chapter_item_t>::const_iterator index = sub_chapters.end();
index--; index--;
f_result = (*index).i_user_end_time; i_result = (*index).i_user_end_time;
} }
return f_result; return i_result;
} }
const chapter_item_t *chapter_item_t::FindTimecode( mtime_t i_user_timecode ) const const chapter_item_t *chapter_item_t::FindTimecode( mtime_t i_user_timecode ) const
...@@ -3300,20 +3370,6 @@ const chapter_item_t *chapter_item_t::FindTimecode( mtime_t i_user_timecode ) co ...@@ -3300,20 +3370,6 @@ const chapter_item_t *chapter_item_t::FindTimecode( mtime_t i_user_timecode ) co
return psz_result; return psz_result;
} }
const chapter_item_t *chapter_edition_t::FindTimecode( mtime_t i_user_timecode ) const
{
const chapter_item_t *psz_result = NULL;
std::vector<chapter_item_t>::const_iterator index = chapters.begin();
while ( index != chapters.end() && psz_result == NULL )
{
psz_result = (*index).FindTimecode( i_user_timecode );
index++;
}
return psz_result;
}
void demux_sys_t::PreloadFamily( ) void demux_sys_t::PreloadFamily( )
{ {
/* TODO enable family handling again /* TODO enable family handling again
...@@ -3379,10 +3435,15 @@ void demux_sys_t::PreloadLinked( matroska_segment_t *p_segment ) ...@@ -3379,10 +3435,15 @@ void demux_sys_t::PreloadLinked( matroska_segment_t *p_segment )
p_current_segment->PreloadLinked( ); p_current_segment->PreloadLinked( );
} }
void demux_sys_t::PreparePlayback( ) bool demux_sys_t::PreparePlayback( )
{ {
p_current_segment->LoadCues(); p_current_segment->LoadCues();
f_duration = p_current_segment->Duration(); f_duration = p_current_segment->Duration();
/* add information */
p_current_segment->Segment()->InformationCreate( );
return p_current_segment->Select( *title );
} }
bool matroska_segment_t::CompareSegmentUIDs( const matroska_segment_t * p_item_a, const matroska_segment_t * p_item_b ) bool matroska_segment_t::CompareSegmentUIDs( const matroska_segment_t * p_item_a, const matroska_segment_t * p_item_b )
......
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