1 /*****************************************************************************
2 * mkv.cpp : matroska demuxer
3 *****************************************************************************
4 * Copyright (C) 2003-2004 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Steve Lhomme <steve.lhomme@free.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #include "chapters.hpp"
27 #include "chapter_command.hpp"
30 #include <vlc_memory.h>
32 chapter_item_c::~chapter_item_c()
34 std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
35 while ( index != codecs.end() )
40 std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
41 while ( index_ != sub_chapters.end() )
48 int chapter_item_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
50 // add support for meta-elements from codec like DVD Titles
51 if ( !b_display_seekpoint || psz_name == "" )
53 psz_name = GetCodecName();
55 b_display_seekpoint = true;
58 if (b_display_seekpoint)
60 seekpoint_t *sk = vlc_seekpoint_New();
62 sk->i_level = i_level;
63 sk->i_time_offset = i_start_time;
64 sk->psz_name = strdup( psz_name.c_str() );
66 // A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
68 title.seekpoint = realloc_or_free( title.seekpoint,
69 title.i_seekpoint * sizeof( seekpoint_t* ) );
70 assert( title.seekpoint );
71 title.seekpoint[title.i_seekpoint-1] = sk;
77 for ( size_t i=0; i<sub_chapters.size() ; i++)
79 sub_chapters[i]->PublishChapters( title, i_user_chapters, i_level+1 );
82 i_seekpoint_num = i_user_chapters;
84 return i_user_chapters;
87 chapter_item_c *chapter_item_c::BrowseCodecPrivate( unsigned int codec_id,
88 bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
90 size_t i_cookie_size )
93 std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
94 while ( index != codecs.end() )
96 if ( match( **index ,p_cookie, i_cookie_size ) )
102 chapter_item_c *p_result = NULL;
103 std::vector<chapter_item_c*>::const_iterator index2 = sub_chapters.begin();
104 while ( index2 != sub_chapters.end() )
106 p_result = (*index2)->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
107 if ( p_result != NULL )
115 void chapter_item_c::Append( const chapter_item_c & chapter )
117 // we are appending content for the same chapter UID
119 chapter_item_c *p_chapter;
121 for ( i=0; i<chapter.sub_chapters.size(); i++ )
123 p_chapter = FindChapter( chapter.sub_chapters[i]->i_uid );
124 if ( p_chapter != NULL )
126 p_chapter->Append( *chapter.sub_chapters[i] );
130 sub_chapters.push_back( chapter.sub_chapters[i] );
134 i_user_start_time = min( i_user_start_time, chapter.i_user_start_time );
135 i_user_end_time = max( i_user_end_time, chapter.i_user_end_time );
138 chapter_item_c * chapter_item_c::FindChapter( int64_t i_find_uid )
141 chapter_item_c *p_result = NULL;
143 if ( i_uid == i_find_uid )
146 for ( i=0; i<sub_chapters.size(); i++)
148 p_result = sub_chapters[i]->FindChapter( i_find_uid );
149 if ( p_result != NULL )
155 std::string chapter_item_c::GetCodecName( bool f_for_title ) const
159 std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
160 while ( index != codecs.end() )
162 result = (*index)->GetCodecName( f_for_title );
171 int16 chapter_item_c::GetTitleNumber( ) const
175 std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
176 while ( index != codecs.end() )
178 result = (*index)->GetTitleNumber( );
187 int64_t chapter_item_c::RefreshChapters( bool b_ordered, int64_t i_prev_user_time )
189 int64_t i_user_time = i_prev_user_time;
191 // first the sub-chapters, and then ourself
192 std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
193 while ( index != sub_chapters.end() )
195 i_user_time = (*index)->RefreshChapters( b_ordered, i_user_time );
201 // the ordered chapters always start at zero
202 if ( i_prev_user_time == -1 )
204 if ( i_user_time == -1 )
206 i_prev_user_time = 0;
209 i_user_start_time = i_prev_user_time;
210 if ( i_end_time != -1 && i_user_time == i_prev_user_time )
212 i_user_end_time = i_user_start_time - i_start_time + i_end_time;
216 i_user_end_time = i_user_time;
221 if ( sub_chapters.begin() != sub_chapters.end() )
222 std::sort( sub_chapters.begin(), sub_chapters.end(), chapter_item_c::CompareTimecode );
223 i_user_start_time = i_start_time;
224 if ( i_end_time != -1 )
225 i_user_end_time = i_end_time;
226 else if ( i_user_time != -1 )
227 i_user_end_time = i_user_time;
229 i_user_end_time = i_user_start_time;
232 return i_user_end_time;
235 chapter_item_c *chapter_item_c::FindTimecode( mtime_t i_user_timecode, const chapter_item_c * p_current, bool & b_found )
237 chapter_item_c *psz_result = NULL;
239 if ( p_current == this )
242 if ( i_user_timecode >= i_user_start_time &&
243 ( i_user_timecode < i_user_end_time ||
244 ( i_user_start_time == i_user_end_time && i_user_timecode == i_user_end_time )))
246 std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
247 while ( index != sub_chapters.end() && ((p_current == NULL && psz_result == NULL) || (p_current != NULL && (!b_found || psz_result == NULL))))
249 psz_result = (*index)->FindTimecode( i_user_timecode, p_current, b_found );
253 if ( psz_result == NULL )
260 bool chapter_item_c::ParentOf( const chapter_item_c & item ) const
265 std::vector<chapter_item_c*>::const_iterator index = sub_chapters.begin();
266 while ( index != sub_chapters.end() )
268 if ( (*index)->ParentOf( item ) )
276 bool chapter_item_c::Enter( bool b_do_subs )
278 bool f_result = false;
279 std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
280 while ( index != codecs.end() )
282 f_result |= (*index)->Enter();
289 std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
290 while ( index_ != sub_chapters.end() )
292 f_result |= (*index_)->Enter( true );
299 bool chapter_item_c::Leave( bool b_do_subs )
301 bool f_result = false;
303 std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
304 while ( index != codecs.end() )
306 f_result |= (*index)->Leave();
313 std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
314 while ( index_ != sub_chapters.end() )
316 f_result |= (*index_)->Leave( true );
320 b_is_leaving = false;
324 bool chapter_item_c::EnterAndLeave( chapter_item_c *p_item, bool b_final_enter )
326 chapter_item_c *p_common_parent = p_item;
328 // leave, up to a common parent
329 while ( p_common_parent != NULL && !p_common_parent->ParentOf( *this ) )
331 if ( !p_common_parent->b_is_leaving && p_common_parent->Leave( false ) )
333 p_common_parent = p_common_parent->psz_parent;
336 // enter from the parent to <this>
337 if ( p_common_parent != NULL )
341 if ( p_common_parent == this )
342 return Enter( true );
344 for ( size_t i = 0; i<p_common_parent->sub_chapters.size(); i++ )
346 if ( p_common_parent->sub_chapters[i]->ParentOf( *this ) )
348 p_common_parent = p_common_parent->sub_chapters[i];
349 if ( p_common_parent != this )
350 if ( p_common_parent->Enter( false ) )
360 return Enter( true );
367 /* Chapter Edition Class */
368 std::string chapter_edition_c::GetMainName() const
370 if ( sub_chapters.size() )
372 return sub_chapters[0]->GetCodecName( true );
377 void chapter_edition_c::RefreshChapters( )
379 chapter_item_c::RefreshChapters( b_ordered, -1 );
380 b_display_seekpoint = false;
383 mtime_t chapter_edition_c::Duration() const
385 mtime_t i_result = 0;
387 if ( sub_chapters.size() )
389 std::vector<chapter_item_c*>::const_iterator index = sub_chapters.end();
391 i_result = (*index)->i_user_end_time;
397 chapter_item_c * chapter_edition_c::FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current )
401 bool b_found_current = false;
402 return chapter_item_c::FindTimecode( i_timecode, p_current, b_found_current );