]> git.sesse.net Git - vlc/blob - modules/demux/mkv/chapters.cpp
Use var_InheritString for --decklink-video-connection.
[vlc] / modules / demux / mkv / chapters.cpp
1 /*****************************************************************************
2  * mkv.cpp : matroska demuxer
3  *****************************************************************************
4  * Copyright (C) 2003-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Steve Lhomme <steve.lhomme@free.fr>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 #include "chapters.hpp"
26
27 #include "chapter_command.hpp"
28
29 chapter_item_c::~chapter_item_c()
30 {
31     std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
32     while ( index != codecs.end() )
33     {
34         delete (*index);
35         index++;
36     }
37     std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
38     while ( index_ != sub_chapters.end() )
39     {
40         delete (*index_);
41         index_++;
42     }
43 }
44
45 int chapter_item_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
46 {
47     // add support for meta-elements from codec like DVD Titles
48     if ( !b_display_seekpoint || psz_name == "" )
49     {
50         psz_name = GetCodecName();
51         if ( psz_name != "" )
52             b_display_seekpoint = true;
53     }
54
55     if (b_display_seekpoint)
56     {
57         seekpoint_t *sk = vlc_seekpoint_New();
58
59         sk->i_level = i_level;
60         sk->i_time_offset = i_start_time;
61         sk->psz_name = strdup( psz_name.c_str() );
62
63         // A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
64         title.i_seekpoint++;
65         title.seekpoint = (seekpoint_t**)xrealloc( title.seekpoint,
66                                  title.i_seekpoint * sizeof( seekpoint_t* ) );
67         title.seekpoint[title.i_seekpoint-1] = sk;
68
69         if ( b_user_display )
70             i_user_chapters++;
71     }
72
73     for ( size_t i=0; i<sub_chapters.size() ; i++)
74     {
75         sub_chapters[i]->PublishChapters( title, i_user_chapters, i_level+1 );
76     }
77
78     i_seekpoint_num = i_user_chapters;
79
80     return i_user_chapters;
81 }
82
83 chapter_item_c *chapter_item_c::BrowseCodecPrivate( unsigned int codec_id,
84                                     bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
85                                     const void *p_cookie,
86                                     size_t i_cookie_size )
87 {
88     // this chapter
89     std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
90     while ( index != codecs.end() )
91     {
92         if ( match( **index ,p_cookie, i_cookie_size ) )
93             return this;
94         index++;
95     }
96  
97     // sub-chapters
98     chapter_item_c *p_result = NULL;
99     std::vector<chapter_item_c*>::const_iterator index2 = sub_chapters.begin();
100     while ( index2 != sub_chapters.end() )
101     {
102         p_result = (*index2)->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
103         if ( p_result != NULL )
104             return p_result;
105         index2++;
106     }
107  
108     return p_result;
109 }
110
111 void chapter_item_c::Append( const chapter_item_c & chapter )
112 {
113     // we are appending content for the same chapter UID
114     size_t i;
115     chapter_item_c *p_chapter;
116
117     for ( i=0; i<chapter.sub_chapters.size(); i++ )
118     {
119         p_chapter = FindChapter( chapter.sub_chapters[i]->i_uid );
120         if ( p_chapter != NULL )
121         {
122             p_chapter->Append( *chapter.sub_chapters[i] );
123         }
124         else
125         {
126             sub_chapters.push_back( chapter.sub_chapters[i] );
127         }
128     }
129
130     i_user_start_time = min( i_user_start_time, chapter.i_user_start_time );
131     i_user_end_time = max( i_user_end_time, chapter.i_user_end_time );
132 }
133
134 chapter_item_c * chapter_item_c::FindChapter( int64_t i_find_uid )
135 {
136     size_t i;
137     chapter_item_c *p_result = NULL;
138
139     if ( i_uid == i_find_uid )
140         return this;
141
142     for ( i=0; i<sub_chapters.size(); i++)
143     {
144         p_result = sub_chapters[i]->FindChapter( i_find_uid );
145         if ( p_result != NULL )
146             break;
147     }
148     return p_result;
149 }
150
151 std::string chapter_item_c::GetCodecName( bool f_for_title ) const
152 {
153     std::string result;
154
155     std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
156     while ( index != codecs.end() )
157     {
158         result = (*index)->GetCodecName( f_for_title );
159         if ( result != "" )
160             break;
161         index++;
162     }
163
164     return result;
165 }
166
167 int16 chapter_item_c::GetTitleNumber( ) const
168 {
169     int result = -1;
170
171     std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
172     while ( index != codecs.end() )
173     {
174         result = (*index)->GetTitleNumber( );
175         if ( result >= 0 )
176             break;
177         index++;
178     }
179
180     return result;
181 }
182
183 int64_t chapter_item_c::RefreshChapters( bool b_ordered, int64_t i_prev_user_time )
184 {
185     int64_t i_user_time = i_prev_user_time;
186  
187     // first the sub-chapters, and then ourself
188     std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
189     while ( index != sub_chapters.end() )
190     {
191         i_user_time = (*index)->RefreshChapters( b_ordered, i_user_time );
192         index++;
193     }
194
195     if ( b_ordered )
196     {
197         // the ordered chapters always start at zero
198         if ( i_prev_user_time == -1 )
199         {
200             if ( i_user_time == -1 )
201                 i_user_time = 0;
202             i_prev_user_time = 0;
203         }
204
205         i_user_start_time = i_prev_user_time;
206         if ( i_end_time != -1 && i_user_time == i_prev_user_time )
207         {
208             i_user_end_time = i_user_start_time - i_start_time + i_end_time;
209         }
210         else
211         {
212             i_user_end_time = i_user_time;
213         }
214     }
215     else
216     {
217         if ( sub_chapters.begin() != sub_chapters.end() )
218             std::sort( sub_chapters.begin(), sub_chapters.end(), chapter_item_c::CompareTimecode );
219         i_user_start_time = i_start_time;
220         if ( i_end_time != -1 )
221             i_user_end_time = i_end_time;
222         else if ( i_user_time != -1 )
223             i_user_end_time = i_user_time;
224         else
225             i_user_end_time = i_user_start_time;
226     }
227
228     return i_user_end_time;
229 }
230
231 chapter_item_c *chapter_item_c::FindTimecode( mtime_t i_user_timecode, const chapter_item_c * p_current, bool & b_found )
232 {
233     chapter_item_c *psz_result = NULL;
234
235     if ( p_current == this )
236         b_found = true;
237
238     if ( i_user_timecode >= i_user_start_time &&
239         ( i_user_timecode < i_user_end_time ||
240           ( i_user_start_time == i_user_end_time && i_user_timecode == i_user_end_time )))
241     {
242         std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
243         while ( index != sub_chapters.end() && ((p_current == NULL && psz_result == NULL) || (p_current != NULL && (!b_found || psz_result == NULL))))
244         {
245             psz_result = (*index)->FindTimecode( i_user_timecode, p_current, b_found );
246             index++;
247         }
248  
249         if ( psz_result == NULL )
250             psz_result = this;
251     }
252
253     return psz_result;
254 }
255
256 bool chapter_item_c::ParentOf( const chapter_item_c & item ) const
257 {
258     if ( &item == this )
259         return true;
260
261     std::vector<chapter_item_c*>::const_iterator index = sub_chapters.begin();
262     while ( index != sub_chapters.end() )
263     {
264         if ( (*index)->ParentOf( item ) )
265             return true;
266         index++;
267     }
268
269     return false;
270 }
271
272 bool chapter_item_c::Enter( bool b_do_subs )
273 {
274     bool f_result = false;
275     std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
276     while ( index != codecs.end() )
277     {
278         f_result |= (*index)->Enter();
279         index++;
280     }
281
282     if ( b_do_subs )
283     {
284         // sub chapters
285         std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
286         while ( index_ != sub_chapters.end() )
287         {
288             f_result |= (*index_)->Enter( true );
289             index_++;
290         }
291     }
292     return f_result;
293 }
294
295 bool chapter_item_c::Leave( bool b_do_subs )
296 {
297     bool f_result = false;
298     b_is_leaving = true;
299     std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
300     while ( index != codecs.end() )
301     {
302         f_result |= (*index)->Leave();
303         index++;
304     }
305
306     if ( b_do_subs )
307     {
308         // sub chapters
309         std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
310         while ( index_ != sub_chapters.end() )
311         {
312             f_result |= (*index_)->Leave( true );
313             index_++;
314         }
315     }
316     b_is_leaving = false;
317     return f_result;
318 }
319
320 bool chapter_item_c::EnterAndLeave( chapter_item_c *p_item, bool b_final_enter )
321 {
322     chapter_item_c *p_common_parent = p_item;
323
324     // leave, up to a common parent
325     while ( p_common_parent != NULL && !p_common_parent->ParentOf( *this ) )
326     {
327         if ( !p_common_parent->b_is_leaving && p_common_parent->Leave( false ) )
328             return true;
329         p_common_parent = p_common_parent->psz_parent;
330     }
331
332     // enter from the parent to <this>
333     if ( p_common_parent != NULL )
334     {
335         do
336         {
337             if ( p_common_parent == this )
338                 return Enter( true );
339
340             for ( size_t i = 0; i<p_common_parent->sub_chapters.size(); i++ )
341             {
342                 if ( p_common_parent->sub_chapters[i]->ParentOf( *this ) )
343                 {
344                     p_common_parent = p_common_parent->sub_chapters[i];
345                     if ( p_common_parent != this )
346                         if ( p_common_parent->Enter( false ) )
347                             return true;
348
349                     break;
350                 }
351             }
352         } while ( 1 );
353     }
354
355     if ( b_final_enter )
356         return Enter( true );
357     else
358         return false;
359 }
360
361
362
363 /* Chapter Edition Class */
364 std::string chapter_edition_c::GetMainName() const
365 {
366     if ( sub_chapters.size() )
367     {
368         return sub_chapters[0]->GetCodecName( true );
369     }
370     return "";
371 }
372
373 void chapter_edition_c::RefreshChapters( )
374 {
375     chapter_item_c::RefreshChapters( b_ordered, -1 );
376     b_display_seekpoint = false;
377 }
378
379 mtime_t chapter_edition_c::Duration() const
380 {
381     mtime_t i_result = 0;
382  
383     if ( sub_chapters.size() )
384     {
385         std::vector<chapter_item_c*>::const_iterator index = sub_chapters.end();
386         index--;
387         i_result = (*index)->i_user_end_time;
388     }
389  
390     return i_result;
391 }
392
393 chapter_item_c * chapter_edition_c::FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current )
394 {
395     if ( !b_ordered )
396         p_current = NULL;
397     bool b_found_current = false;
398     return chapter_item_c::FindTimecode( i_timecode, p_current, b_found_current );
399 }
400
401