]> git.sesse.net Git - vlc/blob - modules/demux/mkv/virtual_segment.cpp
Use var_Inherit* instead of var_CreateGet*.
[vlc] / modules / demux / mkv / virtual_segment.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 "virtual_segment.hpp"
26
27 #include "demux.hpp"
28
29 void virtual_segment_c::PrepareChapters( )
30 {
31     if ( linked_segments.size() == 0 )
32         return;
33
34     // !!! should be called only once !!!
35     matroska_segment_c *p_segment;
36
37     // copy editions from the first segment
38     p_segment = linked_segments[0];
39     p_editions = &p_segment->stored_editions;
40
41     for ( size_t i=1 ; i<linked_segments.size(); i++ )
42     {
43         p_segment = linked_segments[i];
44         // FIXME assume we have the same editions in all segments
45         for ( size_t j=0; j<p_segment->stored_editions.size(); j++)
46         {
47             if( j >= p_editions->size() ) /* Protect against broken files (?) */
48                 break;
49             (*p_editions)[j]->Append( *p_segment->stored_editions[j] );
50         }
51     }
52 }
53
54 bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
55 {
56     demux_sys_t & sys = *demux.p_sys;
57     chapter_item_c *psz_curr_chapter;
58     bool b_has_seeked = false;
59
60     /* update current chapter/seekpoint */
61     if ( p_editions->size() )
62     {
63         /* 1st, we need to know in which chapter we are */
64         psz_curr_chapter = (*p_editions)[i_current_edition]->FindTimecode( sys.i_pts, psz_current_chapter );
65
66         /* we have moved to a new chapter */
67         if (psz_curr_chapter != NULL && psz_current_chapter != psz_curr_chapter)
68         {
69             if ( (*p_editions)[i_current_edition]->b_ordered )
70             {
71                 // Leave/Enter up to the link point
72                 b_has_seeked = psz_curr_chapter->EnterAndLeave( psz_current_chapter );
73                 if ( !b_has_seeked )
74                 {
75                     // only physically seek if necessary
76                     if ( psz_current_chapter == NULL || (psz_current_chapter->i_end_time != psz_curr_chapter->i_start_time) )
77                         Seek( demux, sys.i_pts, 0, psz_curr_chapter, -1 );
78                 }
79             }
80  
81             if ( !b_has_seeked )
82             {
83                 psz_current_chapter = psz_curr_chapter;
84                 if ( psz_curr_chapter->i_seekpoint_num > 0 )
85                 {
86                     demux.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
87                     demux.info.i_title = sys.i_current_title = i_sys_title;
88                     demux.info.i_seekpoint = psz_curr_chapter->i_seekpoint_num - 1;
89                 }
90             }
91
92             return true;
93         }
94         else if (psz_curr_chapter == NULL)
95         {
96             // out of the scope of the data described by chapters, leave the edition
97             if ( (*p_editions)[i_current_edition]->b_ordered && psz_current_chapter != NULL )
98             {
99                 if ( !(*p_editions)[i_current_edition]->EnterAndLeave( psz_current_chapter, false ) )
100                     psz_current_chapter = NULL;
101                 else
102                     return true;
103             }
104         }
105     }
106     return false;
107 }
108
109 chapter_item_c *virtual_segment_c::BrowseCodecPrivate( unsigned int codec_id,
110                                     bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
111                                     const void *p_cookie,
112                                     size_t i_cookie_size )
113 {
114     // FIXME don't assume it is the first edition
115     std::vector<chapter_edition_c*>::iterator index = p_editions->begin();
116     if ( index != p_editions->end() )
117     {
118         chapter_item_c *p_result = (*index)->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
119         if ( p_result != NULL )
120             return p_result;
121     }
122     return NULL;
123 }
124
125
126 void virtual_segment_c::Sort()
127 {
128     // keep the current segment index
129     matroska_segment_c *p_segment = linked_segments[i_current_segment];
130
131     std::sort( linked_segments.begin(), linked_segments.end(), matroska_segment_c::CompareSegmentUIDs );
132
133     for ( i_current_segment=0; i_current_segment<linked_segments.size(); i_current_segment++)
134         if ( linked_segments[i_current_segment] == p_segment )
135             break;
136 }
137
138 size_t virtual_segment_c::AddSegment( matroska_segment_c *p_segment )
139 {
140     size_t i;
141     // check if it's not already in here
142     for ( i=0; i<linked_segments.size(); i++ )
143     {
144         if ( linked_segments[i]->p_segment_uid != NULL
145             && p_segment->p_segment_uid != NULL
146             && *p_segment->p_segment_uid == *linked_segments[i]->p_segment_uid )
147             return 0;
148     }
149
150     // find possible mates
151     for ( i=0; i<linked_uids.size(); i++ )
152     {
153         if (   (p_segment->p_segment_uid != NULL && *p_segment->p_segment_uid == linked_uids[i])
154             || (p_segment->p_prev_segment_uid != NULL && *p_segment->p_prev_segment_uid == linked_uids[i])
155             || (p_segment->p_next_segment_uid !=NULL && *p_segment->p_next_segment_uid == linked_uids[i]) )
156         {
157             linked_segments.push_back( p_segment );
158
159             AppendUID( p_segment->p_prev_segment_uid );
160             AppendUID( p_segment->p_next_segment_uid );
161
162             return 1;
163         }
164     }
165     return 0;
166 }
167
168 void virtual_segment_c::PreloadLinked( )
169 {
170     for ( size_t i=0; i<linked_segments.size(); i++ )
171     {
172         linked_segments[i]->Preload( );
173     }
174     i_current_edition = linked_segments[0]->i_default_edition;
175 }
176
177 mtime_t virtual_segment_c::Duration() const
178 {
179     mtime_t i_duration;
180     if ( linked_segments.size() == 0 )
181         i_duration = 0;
182     else {
183         matroska_segment_c *p_last_segment = linked_segments[linked_segments.size()-1];
184 //        p_last_segment->ParseCluster( );
185
186         i_duration = p_last_segment->i_start_time / 1000 + p_last_segment->i_duration;
187     }
188     return i_duration;
189 }
190
191 void virtual_segment_c::AppendUID( const EbmlBinary * p_UID )
192 {
193     if ( p_UID == NULL )
194         return;
195     if ( p_UID->GetBuffer() == NULL )
196         return;
197
198     for (size_t i=0; i<linked_uids.size(); i++)
199     {
200         if ( *p_UID == linked_uids[i] )
201             return;
202     }
203     linked_uids.push_back( *(KaxSegmentUID*)(p_UID) );
204 }
205
206 void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter, int64_t i_global_position )
207 {
208     demux_sys_t *p_sys = demuxer.p_sys;
209     size_t i;
210
211     // find the actual time for an ordered edition
212     if ( psz_chapter == NULL )
213     {
214         if ( Edition() && Edition()->b_ordered )
215         {
216             /* 1st, we need to know in which chapter we are */
217             psz_chapter = (*p_editions)[i_current_edition]->FindTimecode( i_date, psz_current_chapter );
218         }
219     }
220
221     if ( psz_chapter != NULL )
222     {
223         psz_current_chapter = psz_chapter;
224         p_sys->i_chapter_time = i_time_offset = psz_chapter->i_user_start_time - psz_chapter->i_start_time;
225         if ( psz_chapter->i_seekpoint_num > 0 )
226         {
227             demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
228             demuxer.info.i_title = p_sys->i_current_title = i_sys_title;
229             demuxer.info.i_seekpoint = psz_chapter->i_seekpoint_num - 1;
230         }
231     }
232
233     // find the best matching segment
234     for ( i=0; i<linked_segments.size(); i++ )
235     {
236         if ( i_date < linked_segments[i]->i_start_time )
237             break;
238     }
239
240     if ( i > 0 )
241         i--;
242
243     if ( i_current_segment != i  )
244     {
245         linked_segments[i_current_segment]->UnSelect();
246         linked_segments[i]->Select( i_date );
247         i_current_segment = i;
248     }
249
250     linked_segments[i]->Seek( i_date, i_time_offset, i_global_position );
251 }
252
253 chapter_item_c *virtual_segment_c::FindChapter( int64_t i_find_uid )
254 {
255     // FIXME don't assume it is the first edition
256     std::vector<chapter_edition_c*>::iterator index = p_editions->begin();
257     if ( index != p_editions->end() )
258     {
259         chapter_item_c *p_result = (*index)->FindChapter( i_find_uid );
260         if ( p_result != NULL )
261             return p_result;
262     }
263     return NULL;
264 }