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