/src/vlc/modules/demux/mkv/matroska_segment.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * matroska_segment.cpp : matroska demuxer |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2003-2010 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * Steve Lhomme <steve.lhomme@free.fr> |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify it |
10 | | * under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation; either version 2.1 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program; if not, write to the Free Software Foundation, |
21 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
22 | | *****************************************************************************/ |
23 | | |
24 | | #include "matroska_segment.hpp" |
25 | | #include "chapters.hpp" |
26 | | #include "demux.hpp" |
27 | | #include "util.hpp" |
28 | | #include "Ebml_dispatcher.hpp" |
29 | | |
30 | | #include <vlc_arrays.h> |
31 | | |
32 | | #include <new> |
33 | | #include <iterator> |
34 | | #include <limits> |
35 | | |
36 | | namespace mkv { |
37 | | |
38 | | matroska_segment_c::matroska_segment_c( demux_sys_t & demuxer, matroska_iostream_c & estream, KaxSegment *p_seg ) |
39 | 17 | :segment(p_seg) |
40 | 17 | ,es(estream) |
41 | 17 | ,i_timescale(MKVD_TIMECODESCALE) |
42 | 17 | ,i_duration(-1) |
43 | 17 | ,i_mk_start_time(0) |
44 | 17 | ,i_seekhead_count(0) |
45 | 17 | ,i_seekhead_position(-1) |
46 | 17 | ,i_cues_position(-1) |
47 | 17 | ,i_tracks_position(-1) |
48 | 17 | ,i_info_position(-1) |
49 | 17 | ,i_chapters_position(-1) |
50 | 17 | ,i_attachments_position(-1) |
51 | | ,cluster(NULL) |
52 | 17 | ,i_block_pos(0) |
53 | | ,p_segment_uid(NULL) |
54 | | ,p_prev_segment_uid(NULL) |
55 | | ,p_next_segment_uid(NULL) |
56 | 17 | ,b_cues(false) |
57 | | ,psz_muxing_application(NULL) |
58 | | ,psz_writing_application(NULL) |
59 | | ,psz_segment_filename(NULL) |
60 | | ,psz_title(NULL) |
61 | | ,psz_date_utc(NULL) |
62 | 17 | ,i_default_edition(0) |
63 | 17 | ,sys(demuxer) |
64 | 17 | ,ep( EbmlParser(&estream, p_seg, &demuxer.demuxer )) |
65 | 17 | ,b_preloaded(false) |
66 | 17 | ,b_ref_external_segments(false) |
67 | 17 | { |
68 | 17 | } |
69 | | |
70 | | matroska_segment_c::~matroska_segment_c() |
71 | 17 | { |
72 | 17 | free( psz_writing_application ); |
73 | 17 | free( psz_muxing_application ); |
74 | 17 | free( psz_segment_filename ); |
75 | 17 | free( psz_title ); |
76 | 17 | free( psz_date_utc ); |
77 | | |
78 | 17 | delete segment; |
79 | 17 | delete p_segment_uid; |
80 | 17 | delete p_prev_segment_uid; |
81 | 17 | delete p_next_segment_uid; |
82 | | |
83 | 17 | vlc_delete_all( stored_editions ); |
84 | 17 | vlc_delete_all( translations ); |
85 | 17 | vlc_delete_all( families ); |
86 | 17 | } |
87 | | |
88 | | |
89 | | /***************************************************************************** |
90 | | * Tools * |
91 | | ***************************************************************************** |
92 | | * * LoadCues : load the cues element and update index |
93 | | * * LoadTags : load ... the tags element |
94 | | * * InformationCreate : create all information, load tags if present |
95 | | *****************************************************************************/ |
96 | | void matroska_segment_c::LoadCues( KaxCues *cues ) |
97 | 4 | { |
98 | 4 | EbmlElement *el; |
99 | | |
100 | 4 | if( b_cues ) |
101 | 0 | { |
102 | 0 | msg_Warn( &sys.demuxer, "There can be only 1 Cues per section." ); |
103 | 0 | return; |
104 | 0 | } |
105 | | |
106 | 4 | EbmlParser eparser (&es, cues, &sys.demuxer ); |
107 | 176 | while( ( el = eparser.Get() ) != NULL ) |
108 | 172 | { |
109 | 172 | if( MKV_IS_ID( el, KaxCuePoint ) ) |
110 | 168 | { |
111 | 168 | uint64_t cue_position = -1; |
112 | 168 | vlc_tick_t cue_mk_time = -1; |
113 | | |
114 | 168 | unsigned int track_id = 0; |
115 | 168 | bool b_invalid_cue = false; |
116 | | |
117 | 168 | eparser.Down(); |
118 | 504 | while( ( el = eparser.Get() ) != NULL ) |
119 | 336 | { |
120 | 336 | if ( MKV_CHECKED_PTR_DECL( cuetime, KaxCueTime, el ) ) |
121 | 168 | { |
122 | 168 | try |
123 | 168 | { |
124 | 168 | if( unlikely( !cuetime->ValidateSize() ) ) |
125 | 0 | { |
126 | 0 | msg_Err( &sys.demuxer, "CueTime size too big"); |
127 | 0 | b_invalid_cue = true; |
128 | 0 | break; |
129 | 0 | } |
130 | 168 | cuetime->ReadData( es.I_O() ); |
131 | 168 | } |
132 | 168 | catch(...) |
133 | 168 | { |
134 | 0 | msg_Err( &sys.demuxer, "Error while reading CueTime" ); |
135 | 0 | b_invalid_cue = true; |
136 | 0 | break; |
137 | 0 | } |
138 | 168 | cue_mk_time = VLC_TICK_FROM_NS(static_cast<uint64_t>( *cuetime ) * i_timescale); |
139 | 168 | } |
140 | 168 | else if( MKV_IS_ID( el, KaxCueTrackPositions ) ) |
141 | 168 | { |
142 | 168 | eparser.Down(); |
143 | 168 | try |
144 | 168 | { |
145 | 504 | while( ( el = eparser.Get() ) != NULL ) |
146 | 336 | { |
147 | 336 | if( unlikely( !el->ValidateSize() ) ) |
148 | 0 | { |
149 | 0 | eparser.Up(); |
150 | 0 | msg_Err( &sys.demuxer, "Error %s too big, aborting", EBML_NAME(el) ); |
151 | 0 | b_invalid_cue = true; |
152 | 0 | break; |
153 | 0 | } |
154 | | |
155 | 336 | if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxCueTrack, el ) ) |
156 | 168 | { |
157 | 168 | kct_ptr->ReadData( es.I_O() ); |
158 | 168 | track_id = static_cast<uint16_t>( *kct_ptr ); |
159 | 168 | } |
160 | 168 | else if( MKV_CHECKED_PTR_DECL ( kccp_ptr, KaxCueClusterPosition, el ) ) |
161 | 168 | { |
162 | 168 | kccp_ptr->ReadData( es.I_O() ); |
163 | 168 | cue_position = segment->GetGlobalPosition( static_cast<uint64_t>( *kccp_ptr ) ); |
164 | | |
165 | 168 | _seeker.add_cluster_position( cue_position ); |
166 | 168 | } |
167 | 0 | else if( MKV_CHECKED_PTR_DECL ( kcbn_ptr, KaxCueBlockNumber, el ) ) |
168 | 0 | { |
169 | 0 | VLC_UNUSED( kcbn_ptr ); |
170 | 0 | } |
171 | 0 | #if LIBMATROSKA_VERSION >= 0x010401 |
172 | 0 | else if( MKV_CHECKED_PTR_DECL( cuerelative, KaxCueRelativePosition, el ) ) |
173 | 0 | { |
174 | | // IGNORE |
175 | 0 | cuerelative->ReadData( es.I_O() ); |
176 | 0 | } |
177 | 0 | else if( MKV_CHECKED_PTR_DECL( cueblock, KaxCueBlockNumber, el ) ) |
178 | 0 | { |
179 | | // IGNORE |
180 | 0 | cueblock->ReadData( es.I_O() ); |
181 | 0 | } |
182 | 0 | else if( MKV_CHECKED_PTR_DECL( cueref, KaxCueReference, el ) ) |
183 | 0 | { |
184 | | // IGNORE |
185 | 0 | cueref->ReadData( es.I_O(), SCOPE_ALL_DATA ); |
186 | 0 | } |
187 | 0 | else if( MKV_CHECKED_PTR_DECL( cueduration, KaxCueDuration, el ) ) |
188 | 0 | { |
189 | | /* For future use */ |
190 | 0 | cueduration->ReadData( es.I_O() ); |
191 | 0 | } |
192 | 0 | #endif |
193 | 0 | else |
194 | 0 | { |
195 | 0 | msg_Dbg( &sys.demuxer, " * Unknown (%s)", EBML_NAME(el) ); |
196 | 0 | } |
197 | 336 | } |
198 | 168 | } |
199 | 168 | catch(...) |
200 | 168 | { |
201 | 0 | eparser.Up(); |
202 | 0 | msg_Err( &sys.demuxer, "Error while reading %s", EBML_NAME(el) ); |
203 | 0 | b_invalid_cue = true; |
204 | 0 | break; |
205 | 0 | } |
206 | 168 | eparser.Up(); |
207 | 168 | } |
208 | 0 | else |
209 | 0 | { |
210 | 0 | msg_Dbg( &sys.demuxer, " * Unknown (%s)", EBML_NAME(el) ); |
211 | 0 | } |
212 | 336 | } |
213 | 168 | eparser.Up(); |
214 | | |
215 | 168 | if( track_id != 0 && cue_mk_time != -1 && cue_position != static_cast<uint64_t>( -1 ) ) { |
216 | | |
217 | 168 | SegmentSeeker::Seekpoint::TrustLevel level = SegmentSeeker::Seekpoint::DISABLED; |
218 | | |
219 | 168 | if( ! b_invalid_cue && tracks.find( track_id ) != tracks.end() ) |
220 | 168 | { |
221 | 168 | level = sys.trust_cues ? |
222 | 0 | SegmentSeeker::Seekpoint::TRUSTED : |
223 | 168 | SegmentSeeker::Seekpoint::QUESTIONABLE; |
224 | 168 | } |
225 | | |
226 | 168 | _seeker.add_seekpoint( track_id, |
227 | 168 | SegmentSeeker::Seekpoint( cue_position, cue_mk_time, level ) ); |
228 | 168 | } |
229 | 168 | } |
230 | 4 | else |
231 | 4 | { |
232 | 4 | msg_Dbg( &sys.demuxer, " * Unknown (%s)", EBML_NAME(el) ); |
233 | 4 | } |
234 | 172 | } |
235 | 4 | b_cues = true; |
236 | 4 | msg_Dbg( &sys.demuxer, "| - loading cues done." ); |
237 | 4 | } |
238 | | |
239 | | |
240 | | static const struct { |
241 | | vlc_meta_type_t type; |
242 | | const char *key; |
243 | | int target_type; /* 0 is valid for all target_type */ |
244 | | } metadata_map[] = { |
245 | | {vlc_meta_ShowName, "TITLE", 70}, |
246 | | {vlc_meta_Album, "TITLE", 50}, |
247 | | {vlc_meta_Title, "TITLE", 30}, |
248 | | {vlc_meta_DiscNumber, "PART_NUMBER", 60}, |
249 | | {vlc_meta_Season, "PART_NUMBER", 60}, |
250 | | {vlc_meta_Episode, "PART_NUMBER", 50}, |
251 | | {vlc_meta_TrackNumber, "PART_NUMBER", 30}, |
252 | | {vlc_meta_DiscTotal, "TOTAL_PARTS", 70}, |
253 | | {vlc_meta_TrackTotal, "TOTAL_PARTS", 30}, |
254 | | {vlc_meta_Setting, "ENCODER_SETTINGS", 0}, |
255 | | /* TODO read TagLanguage {vlc_meta_Language} */ |
256 | | /* TODO read tags targeting attachments {vlc_meta_ArtworkURL, */ |
257 | | {vlc_meta_AlbumArtist, "ARTIST", 50}, |
258 | | {vlc_meta_Artist, "ARTIST", 0}, |
259 | | {vlc_meta_Director, "DIRECTOR", 0}, |
260 | | {vlc_meta_Actors, "ACTOR", 0}, |
261 | | {vlc_meta_Genre, "GENRE", 0}, |
262 | | {vlc_meta_Copyright, "COPYRIGHT", 0}, |
263 | | {vlc_meta_Description, "DESCRIPTION", 0}, |
264 | | {vlc_meta_Description, "COMMENT", 0}, |
265 | | {vlc_meta_Rating, "RATING", 0}, |
266 | | {vlc_meta_Date, "DATE_RELEASED", 0}, |
267 | | {vlc_meta_Date, "DATE_RELEASE", 0}, |
268 | | {vlc_meta_Date, "DATE_RECORDED", 0}, |
269 | | {vlc_meta_URL, "URL", 0}, |
270 | | {vlc_meta_Publisher, "PUBLISHER", 0}, |
271 | | {vlc_meta_EncodedBy, "ENCODED_BY", 0}, |
272 | | {vlc_meta_Album, "ALBUM", 0}, /* invalid tag */ |
273 | | {vlc_meta_Title, NULL, 0}, |
274 | | }; |
275 | | |
276 | | bool matroska_segment_c::ParseSimpleTags( SimpleTag* pout_simple, KaxTagSimple *tag, int target_type ) |
277 | 28 | { |
278 | 28 | msg_Dbg( &sys.demuxer, "| + Simple Tag "); |
279 | 28 | struct SimpleTagHandlerPayload |
280 | 28 | { |
281 | 28 | matroska_segment_c * const obj; |
282 | 28 | EbmlParser * const ep; |
283 | 28 | demux_sys_t & sys; |
284 | 28 | SimpleTag & out; |
285 | 28 | int target_type; |
286 | 28 | } payload = { this, &ep, sys, *pout_simple, 50 }; |
287 | 28 | MKV_SWITCH_CREATE( EbmlTypeDispatcher, SimpleTagHandler, SimpleTagHandlerPayload ) |
288 | 28 | { |
289 | 28 | MKV_SWITCH_INIT(); |
290 | 28 | E_CASE( KaxTagName, entry ) |
291 | 28 | { |
292 | 28 | vars.out.tag_name = UTFstring( entry ).GetUTF8().c_str(); |
293 | 28 | } |
294 | 28 | E_CASE( KaxTagString, entry ) |
295 | 28 | { |
296 | 28 | vars.out.value = UTFstring( entry ).GetUTF8().c_str(); |
297 | 28 | } |
298 | 28 | E_CASE( KaxTagLangue, entry ) |
299 | 28 | { |
300 | 0 | vars.out.lang = entry.GetValue(); |
301 | 0 | } |
302 | 28 | E_CASE( KaxTagDefault, unused ) |
303 | 28 | { |
304 | 0 | VLC_UNUSED(unused); |
305 | 0 | VLC_UNUSED(vars); |
306 | 0 | } |
307 | 28 | E_CASE( KaxTagSimple, simple ) |
308 | 28 | { |
309 | 0 | SimpleTag st; // ParseSimpleTags will write to this variable |
310 | | // the SimpleTag is valid if ParseSimpleTags returns `true` |
311 | |
|
312 | 0 | if (vars.obj->ParseSimpleTags( &st, &simple, vars.target_type )) |
313 | 0 | vars.out.sub_tags.push_back( st ); |
314 | 0 | } |
315 | 28 | }; |
316 | 28 | SimpleTagHandler::Dispatcher().iterate( tag->begin(), tag->end(), &payload ); |
317 | | |
318 | 28 | if( pout_simple->tag_name.empty() ) |
319 | 0 | { |
320 | 0 | msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found."); |
321 | 0 | return false; |
322 | 0 | } |
323 | 28 | if( !sys.meta ) |
324 | 7 | sys.meta = vlc_meta_New(); |
325 | 633 | for( int i = 0; metadata_map[i].key; i++ ) |
326 | 614 | { |
327 | 614 | if( pout_simple->tag_name == metadata_map[i].key && |
328 | 614 | (metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) ) |
329 | 9 | { |
330 | 9 | vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () ); |
331 | 9 | msg_Dbg( &sys.demuxer, "| | + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ()); |
332 | 9 | goto done; |
333 | 9 | } |
334 | 614 | } |
335 | 19 | msg_Dbg( &sys.demuxer, "| | + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ()); |
336 | 19 | vlc_meta_SetExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ()); |
337 | 28 | done: |
338 | 28 | return true; |
339 | 19 | } |
340 | | |
341 | | void matroska_segment_c::LoadTags( KaxTags *tags_ ) |
342 | 7 | { |
343 | 7 | if ( !ReadMaster( *tags_ ) ) |
344 | 0 | return; |
345 | | |
346 | 7 | struct TagsHandlerPayload |
347 | 7 | { |
348 | 7 | matroska_segment_c * const obj; |
349 | 7 | EbmlParser * const ep; |
350 | 7 | demux_sys_t & sys; |
351 | 7 | int target_type; |
352 | 7 | } payload = { this, &ep, sys, 50 }; |
353 | 7 | MKV_SWITCH_CREATE( EbmlTypeDispatcher, KaxTagsHandler, TagsHandlerPayload ) |
354 | 7 | { |
355 | 7 | MKV_SWITCH_INIT(); |
356 | 7 | E_CASE( KaxTag, entry ) |
357 | 22 | { |
358 | 22 | msg_Dbg( &vars.sys.demuxer, "+ Tag" ); |
359 | 22 | Tag tag; |
360 | 22 | struct TagHandlerPayload |
361 | 22 | { |
362 | 22 | matroska_segment_c * const obj; |
363 | 22 | EbmlParser * const ep; |
364 | 22 | demux_sys_t & sys; |
365 | 22 | Tag & tag; |
366 | 22 | int target_type; |
367 | 22 | } payload = { vars.obj, vars.ep, vars.sys, tag, 50 }; |
368 | 22 | MKV_SWITCH_CREATE( EbmlTypeDispatcher, TagHandler, TagHandlerPayload ) |
369 | 22 | { |
370 | 22 | MKV_SWITCH_INIT(); |
371 | 22 | E_CASE( KaxTagTargets, targets ) |
372 | 22 | { |
373 | 22 | msg_Dbg( &vars.sys.demuxer, "| + Targets" ); |
374 | | |
375 | 22 | MKV_SWITCH_CREATE( EbmlTypeDispatcher, TargetsHandler, TagHandlerPayload ) |
376 | 22 | { |
377 | 22 | MKV_SWITCH_INIT(); |
378 | 22 | E_CASE( KaxTagTargetTypeValue, entry ) |
379 | 22 | { |
380 | 0 | vars.target_type = static_cast<uint32_t>( entry ); |
381 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + TargetTypeValue: %u", vars.target_type); |
382 | 0 | } |
383 | 22 | E_CASE( KaxTagTrackUID, entry ) |
384 | 22 | { |
385 | 15 | vars.tag.i_tag_type = TRACK_UID; |
386 | 15 | vars.tag.i_uid = static_cast<uint64_t>( entry ); |
387 | 15 | msg_Dbg( &vars.sys.demuxer, "| | + TrackUID: %" PRIu64, vars.tag.i_uid); |
388 | 15 | } |
389 | 22 | E_CASE( KaxTagEditionUID, entry ) |
390 | 22 | { |
391 | 0 | vars.tag.i_tag_type = EDITION_UID; |
392 | 0 | vars.tag.i_uid = static_cast<uint64_t>( entry ); |
393 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + EditionUID: %" PRIu64, vars.tag.i_uid); |
394 | 0 | } |
395 | 22 | E_CASE( KaxTagChapterUID, entry ) |
396 | 22 | { |
397 | 0 | vars.tag.i_tag_type = CHAPTER_UID; |
398 | 0 | vars.tag.i_uid = static_cast<uint64_t>( entry ); |
399 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + ChapterUID: %" PRIu64, vars.tag.i_uid); |
400 | 0 | } |
401 | 22 | E_CASE( KaxTagAttachmentUID, entry ) |
402 | 22 | { |
403 | 0 | vars.tag.i_tag_type = ATTACHMENT_UID; |
404 | 0 | vars.tag.i_uid = static_cast<uint64_t>( entry ); |
405 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + AttachmentUID: %" PRIu64, vars.tag.i_uid); |
406 | 0 | } |
407 | 22 | E_CASE( KaxTagTargetType, entry ) |
408 | 22 | { |
409 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + TargetType: %s", entry.GetValue().c_str()); |
410 | 0 | } |
411 | 22 | E_CASE_DEFAULT( el ) |
412 | 22 | { |
413 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + Unknown (%s)", EBML_NAME(&el) ); |
414 | 0 | } |
415 | 22 | }; |
416 | | |
417 | 22 | TargetsHandler::Dispatcher().iterate( targets.begin(), targets.end(), &vars ); |
418 | 22 | } |
419 | 22 | E_CASE( KaxTagSimple, entry ) |
420 | 28 | { |
421 | 28 | SimpleTag simple; |
422 | | |
423 | 28 | if (vars.obj->ParseSimpleTags( &simple, &entry, vars.target_type )) |
424 | 28 | vars.tag.simple_tags.push_back( simple ); |
425 | 28 | } |
426 | 22 | E_CASE_DEFAULT( el ) |
427 | 22 | { |
428 | 0 | msg_Dbg( &vars.sys.demuxer, "| | + Unknown (%s)", EBML_NAME(&el) ); |
429 | 0 | } |
430 | 22 | }; |
431 | | |
432 | 22 | TagHandler::Dispatcher().iterate( entry.begin(), entry.end(), &payload ); |
433 | 22 | vars.obj->tags.push_back(tag); |
434 | 22 | } |
435 | 7 | E_CASE_DEFAULT( el ) |
436 | 7 | { |
437 | 2 | msg_Dbg( &vars.sys.demuxer, "| + LoadTag Unknown (%s)", EBML_NAME(&el) ); |
438 | 2 | } |
439 | 7 | }; |
440 | | |
441 | 7 | KaxTagsHandler::Dispatcher().iterate( tags_->begin(), tags_->end(), &payload ); |
442 | 7 | msg_Dbg( &sys.demuxer, "loading tags done." ); |
443 | 7 | } |
444 | | |
445 | | /***************************************************************************** |
446 | | * InformationCreate: |
447 | | *****************************************************************************/ |
448 | | void matroska_segment_c::InformationCreate( ) |
449 | 17 | { |
450 | 17 | if( !sys.meta ) |
451 | 10 | sys.meta = vlc_meta_New(); |
452 | | |
453 | 17 | if( psz_title ) |
454 | 0 | { |
455 | 0 | vlc_meta_SetTitle( sys.meta, psz_title ); |
456 | 0 | } |
457 | 17 | } |
458 | | |
459 | | |
460 | | /***************************************************************************** |
461 | | * Misc |
462 | | *****************************************************************************/ |
463 | | |
464 | | bool matroska_segment_c::PreloadClusters(uint64_t i_cluster_pos) |
465 | 0 | { |
466 | 0 | struct ClusterHandlerPayload |
467 | 0 | { |
468 | 0 | matroska_segment_c * const obj; |
469 | 0 | bool stop_parsing; |
470 | |
|
471 | 0 | } payload = { this, false }; |
472 | |
|
473 | 0 | MKV_SWITCH_CREATE(EbmlTypeDispatcher, ClusterHandler, ClusterHandlerPayload ) |
474 | 0 | { |
475 | 0 | MKV_SWITCH_INIT(); |
476 | |
|
477 | 0 | E_CASE( KaxCluster, kcluster ) |
478 | 0 | { |
479 | 0 | vars.obj->ParseCluster( &kcluster, false ); |
480 | 0 | } |
481 | |
|
482 | 0 | E_CASE_DEFAULT( el ) |
483 | 0 | { |
484 | 0 | VLC_UNUSED( el ); |
485 | 0 | vars.stop_parsing = true; |
486 | 0 | } |
487 | 0 | }; |
488 | |
|
489 | 0 | { |
490 | 0 | es.I_O().setFilePointer( i_cluster_pos ); |
491 | |
|
492 | 0 | while (payload.stop_parsing == false) |
493 | 0 | { |
494 | 0 | EbmlParser parser ( &es, segment, &sys.demuxer ); |
495 | 0 | EbmlElement* el = parser.Get(); |
496 | |
|
497 | 0 | if( el == NULL ) |
498 | 0 | break; |
499 | | |
500 | 0 | ClusterHandler::Dispatcher().send( el, &payload ); |
501 | 0 | } |
502 | 0 | } |
503 | |
|
504 | 0 | return true; |
505 | 0 | } |
506 | | |
507 | | bool matroska_segment_c::PreloadFamily( const matroska_segment_c & of_segment ) |
508 | 0 | { |
509 | 0 | if ( b_preloaded ) |
510 | 0 | return false; |
511 | | |
512 | 0 | if ( SameFamily( of_segment ) ) |
513 | 0 | return Preload( ); |
514 | | |
515 | 0 | return false; |
516 | 0 | } |
517 | | |
518 | | bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b ) |
519 | 0 | { |
520 | 0 | EbmlBinary *p_tmp; |
521 | |
|
522 | 0 | if ( p_item_a == NULL || p_item_b == NULL ) |
523 | 0 | return false; |
524 | | |
525 | 0 | p_tmp = static_cast<EbmlBinary *>( p_item_a->p_segment_uid ); |
526 | 0 | if ( !p_tmp ) |
527 | 0 | return false; |
528 | 0 | if ( p_item_b->p_prev_segment_uid != NULL |
529 | 0 | && *p_tmp == *p_item_b->p_prev_segment_uid ) |
530 | 0 | return true; |
531 | | |
532 | 0 | p_tmp = static_cast<EbmlBinary *>( p_item_a->p_next_segment_uid ); |
533 | 0 | if ( !p_tmp ) |
534 | 0 | return false; |
535 | | |
536 | 0 | if ( p_item_b->p_segment_uid != NULL |
537 | 0 | && *p_tmp == *p_item_b->p_segment_uid ) |
538 | 0 | return true; |
539 | | |
540 | 0 | if ( p_item_b->p_prev_segment_uid != NULL |
541 | 0 | && *p_tmp == *p_item_b->p_prev_segment_uid ) |
542 | 0 | return true; |
543 | | |
544 | 0 | return false; |
545 | 0 | } |
546 | | |
547 | | bool matroska_segment_c::SameFamily( const matroska_segment_c & of_segment ) const |
548 | 0 | { |
549 | 0 | for (size_t i=0; i<families.size(); i++) |
550 | 0 | { |
551 | 0 | for (size_t j=0; j<of_segment.families.size(); j++) |
552 | 0 | { |
553 | 0 | if ( *(families[i]) == *(of_segment.families[j]) ) |
554 | 0 | return true; |
555 | 0 | } |
556 | 0 | } |
557 | 0 | return false; |
558 | 0 | } |
559 | | |
560 | | bool matroska_segment_c::Preload( ) |
561 | 34 | { |
562 | 34 | if ( b_preloaded ) |
563 | 17 | return false; |
564 | | |
565 | 17 | EbmlElement *el = NULL; |
566 | | |
567 | 17 | ep.Reset( &sys.demuxer ); |
568 | | |
569 | 111 | while( ( el = ep.Get() ) != NULL ) |
570 | 111 | { |
571 | 111 | if( MKV_IS_ID( el, KaxSeekHead ) ) |
572 | 15 | { |
573 | | /* Multiple allowed */ |
574 | | /* We bail at 10, to prevent possible recursion */ |
575 | 15 | msg_Dbg( &sys.demuxer, "| + Seek head" ); |
576 | 15 | if( i_seekhead_count < 10 ) |
577 | 15 | { |
578 | 15 | i_seekhead_position = el->GetElementPosition(); |
579 | 15 | ParseSeekHead( static_cast<KaxSeekHead*>( el ) ); |
580 | 15 | } |
581 | 15 | } |
582 | 96 | else if( MKV_IS_ID( el, KaxInfo ) ) |
583 | 16 | { |
584 | | /* Multiple allowed, mandatory */ |
585 | 16 | msg_Dbg( &sys.demuxer, "| + Information" ); |
586 | 16 | if( i_info_position < 0 ) |
587 | 2 | { |
588 | 2 | ParseInfo( static_cast<KaxInfo*>( el ) ); |
589 | 2 | i_info_position = el->GetElementPosition(); |
590 | 2 | } |
591 | 16 | } |
592 | 80 | else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) ) |
593 | 16 | { |
594 | | /* Multiple allowed */ |
595 | 16 | msg_Dbg( &sys.demuxer, "| + Tracks" ); |
596 | 16 | if( i_tracks_position < 0 ) |
597 | 2 | { |
598 | 2 | ParseTracks( kt_ptr ); |
599 | 2 | } |
600 | 16 | if ( tracks.size() == 0 ) |
601 | 0 | { |
602 | 0 | msg_Err( &sys.demuxer, "No tracks supported" ); |
603 | 0 | } |
604 | 16 | i_tracks_position = el->GetElementPosition(); |
605 | 16 | } |
606 | 64 | else if( MKV_CHECKED_PTR_DECL ( cues, KaxCues, el ) ) |
607 | 4 | { |
608 | 4 | msg_Dbg( &sys.demuxer, "| + Cues" ); |
609 | 4 | if( i_cues_position < 0 ) |
610 | 1 | { |
611 | 1 | LoadCues( cues ); |
612 | 1 | i_cues_position = el->GetElementPosition(); |
613 | 1 | } |
614 | 4 | } |
615 | 60 | else if( MKV_CHECKED_PTR_DECL ( cluster_, KaxCluster, el ) ) |
616 | 17 | { |
617 | 17 | if( sys.b_seekable && |
618 | 17 | var_InheritBool( &sys.demuxer, "mkv-preload-clusters" ) ) |
619 | 0 | { |
620 | 0 | PreloadClusters ( cluster_->GetElementPosition() ); |
621 | 0 | es.I_O().setFilePointer( cluster_->GetElementPosition() ); |
622 | 0 | } |
623 | 17 | msg_Dbg( &sys.demuxer, "| + Cluster" ); |
624 | | |
625 | | |
626 | 17 | cluster = cluster_; |
627 | | |
628 | | // add first cluster as trusted seekpoint for all tracks |
629 | 17 | for( tracks_map_t::const_iterator it = tracks.begin(); |
630 | 52 | it != tracks.end(); ++it ) |
631 | 35 | { |
632 | 35 | _seeker.add_seekpoint( it->first, |
633 | 35 | SegmentSeeker::Seekpoint( cluster->GetElementPosition(), -1, |
634 | 35 | SegmentSeeker::Seekpoint::TrustLevel::QUESTIONABLE ) ); |
635 | 35 | } |
636 | | |
637 | | /* stop pre-parsing the stream */ |
638 | 17 | break; |
639 | 17 | } |
640 | 43 | else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) ) |
641 | 0 | { |
642 | 0 | msg_Dbg( &sys.demuxer, "| + Attachments" ); |
643 | 0 | if( i_attachments_position < 0 ) |
644 | 0 | { |
645 | 0 | ParseAttachments( ka_ptr ); |
646 | 0 | i_attachments_position = el->GetElementPosition(); |
647 | 0 | } |
648 | 0 | } |
649 | 43 | else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) ) |
650 | 0 | { |
651 | 0 | msg_Dbg( &sys.demuxer, "| + Chapters" ); |
652 | 0 | if( i_chapters_position < 0 ) |
653 | 0 | { |
654 | 0 | ParseChapters( chapters ); |
655 | 0 | i_chapters_position = el->GetElementPosition(); |
656 | 0 | } |
657 | 0 | } |
658 | 43 | else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) ) |
659 | 7 | { |
660 | 7 | msg_Dbg( &sys.demuxer, "| + Tags" ); |
661 | 7 | if(tags.empty ()) |
662 | 0 | { |
663 | 0 | LoadTags( tags_ ); |
664 | 0 | } |
665 | 7 | } |
666 | 36 | else if( MKV_IS_ID ( el, EbmlVoid ) ) |
667 | 36 | msg_Dbg( &sys.demuxer, "| + Void" ); |
668 | 1 | else |
669 | 1 | msg_Dbg( &sys.demuxer, "| + Preload Unknown (%s)", EBML_NAME(el) ); |
670 | 111 | } |
671 | | |
672 | 17 | ComputeTrackPriority(); |
673 | | |
674 | 17 | b_preloaded = true; |
675 | | |
676 | 17 | if( cluster ) |
677 | 17 | EnsureDuration(); |
678 | | |
679 | 17 | return true; |
680 | 34 | } |
681 | | |
682 | | /* Here we try to load elements that were found in Seek Heads, but not yet parsed */ |
683 | | bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int64_t i_element_position ) |
684 | 54 | { |
685 | 54 | int64_t i_sav_position = static_cast<int64_t>( es.I_O().getFilePointer() ); |
686 | 54 | EbmlElement *el; |
687 | | |
688 | 54 | es.I_O().setFilePointer( i_element_position, seek_beginning ); |
689 | 54 | el = es.FindNextID( ClassInfos, 0xFFFFFFFFL); |
690 | | |
691 | 54 | if( el == nullptr || el->IsDummy() ) |
692 | 16 | { |
693 | 16 | msg_Err( &sys.demuxer, "cannot load some cues/chapters/tags etc. (broken seekhead or file)" ); |
694 | 16 | es.I_O().setFilePointer( i_sav_position, seek_beginning ); |
695 | 16 | delete el; |
696 | 16 | return false; |
697 | 16 | } |
698 | | |
699 | 38 | if( MKV_CHECKED_PTR_DECL ( ksh_ptr, KaxSeekHead, el ) ) |
700 | 0 | { |
701 | | /* Multiple allowed */ |
702 | 0 | msg_Dbg( &sys.demuxer, "| + Seek head" ); |
703 | 0 | if( i_seekhead_count < 10 ) |
704 | 0 | { |
705 | 0 | if ( i_seekhead_position != i_element_position ) |
706 | 0 | { |
707 | 0 | i_seekhead_position = i_element_position; |
708 | 0 | ParseSeekHead( ksh_ptr ); |
709 | 0 | } |
710 | 0 | } |
711 | 0 | } |
712 | 38 | else if( MKV_CHECKED_PTR_DECL ( ki_ptr, KaxInfo, el ) ) // FIXME |
713 | 14 | { |
714 | | /* Multiple allowed, mandatory */ |
715 | 14 | msg_Dbg( &sys.demuxer, "| + Information" ); |
716 | 14 | if( i_info_position < 0 ) |
717 | 14 | { |
718 | 14 | ParseInfo( ki_ptr ); |
719 | 14 | i_info_position = i_element_position; |
720 | 14 | } |
721 | 14 | } |
722 | 24 | else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) ) // FIXME |
723 | 14 | { |
724 | | /* Multiple allowed */ |
725 | 14 | msg_Dbg( &sys.demuxer, "| + Tracks" ); |
726 | 14 | if( i_tracks_position < 0 ) |
727 | 14 | ParseTracks( kt_ptr ); |
728 | 14 | if ( tracks.size() == 0 ) |
729 | 0 | { |
730 | 0 | msg_Err( &sys.demuxer, "No tracks supported" ); |
731 | 0 | delete el; |
732 | 0 | es.I_O().setFilePointer( i_sav_position, seek_beginning ); |
733 | 0 | return false; |
734 | 0 | } |
735 | 14 | i_tracks_position = i_element_position; |
736 | 14 | } |
737 | 10 | else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCues, el ) ) |
738 | 3 | { |
739 | 3 | msg_Dbg( &sys.demuxer, "| + Cues" ); |
740 | 3 | if( i_cues_position < 0 ) |
741 | 3 | { |
742 | 3 | LoadCues( kc_ptr ); |
743 | 3 | i_cues_position = i_element_position; |
744 | 3 | } |
745 | 3 | } |
746 | 7 | else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) ) |
747 | 0 | { |
748 | 0 | msg_Dbg( &sys.demuxer, "| + Attachments" ); |
749 | 0 | if( i_attachments_position < 0 ) |
750 | 0 | { |
751 | 0 | ParseAttachments( ka_ptr ); |
752 | 0 | i_attachments_position = i_element_position; |
753 | 0 | } |
754 | 0 | } |
755 | 7 | else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) ) |
756 | 0 | { |
757 | 0 | msg_Dbg( &sys.demuxer, "| + Chapters" ); |
758 | 0 | if( i_chapters_position < 0 ) |
759 | 0 | { |
760 | 0 | ParseChapters( chapters ); |
761 | 0 | i_chapters_position = i_element_position; |
762 | 0 | } |
763 | 0 | } |
764 | 7 | else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) ) |
765 | 7 | { |
766 | 7 | msg_Dbg( &sys.demuxer, "| + Tags" ); |
767 | 7 | if(tags.empty ()) |
768 | 7 | { |
769 | 7 | LoadTags( tags_ ); |
770 | 7 | } |
771 | 7 | } |
772 | 0 | else |
773 | 0 | { |
774 | 0 | msg_Dbg( &sys.demuxer, "| + LoadSeekHeadItem Unknown (%s)", EBML_NAME(el) ); |
775 | 0 | } |
776 | 38 | delete el; |
777 | | |
778 | 38 | es.I_O().setFilePointer( i_sav_position, seek_beginning ); |
779 | 38 | return true; |
780 | 38 | } |
781 | | |
782 | | bool matroska_segment_c::Seek( demux_t &demuxer, vlc_tick_t i_absolute_mk_date, vlc_tick_t i_mk_time_offset, bool b_accurate ) |
783 | 17 | { |
784 | 17 | SegmentSeeker::tracks_seekpoint_t seekpoints; |
785 | | |
786 | 17 | SegmentSeeker::fptr_t i_seek_position = std::numeric_limits<SegmentSeeker::fptr_t>::max(); |
787 | 17 | vlc_tick_t i_mk_seek_time = -1; |
788 | 17 | vlc_tick_t i_mk_date = i_absolute_mk_date - i_mk_time_offset; |
789 | 17 | SegmentSeeker::track_ids_t selected_tracks; |
790 | 17 | SegmentSeeker::track_ids_t priority; |
791 | | |
792 | | // reset information for all tracks // |
793 | | |
794 | 52 | for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it ) |
795 | 35 | { |
796 | 35 | mkv_track_t &track = *it->second; |
797 | | |
798 | 35 | track.i_skip_until_fpos = std::numeric_limits<uint64_t>::max(); |
799 | 35 | if( track.i_last_dts != VLC_TICK_INVALID ) |
800 | 0 | track.b_discontinuity = true; |
801 | 35 | track.i_last_dts = VLC_TICK_INVALID; |
802 | | |
803 | 35 | bool selected; |
804 | 35 | if (track.p_es == NULL) |
805 | 0 | selected = false; |
806 | 35 | else |
807 | 35 | es_out_Control( demuxer.out, ES_OUT_GET_ES_STATE, track.p_es, &selected ); |
808 | 35 | if ( selected ) |
809 | 35 | selected_tracks.push_back( track.i_number ); |
810 | 35 | } |
811 | | |
812 | 17 | if ( selected_tracks.empty() ) |
813 | 1 | { |
814 | 1 | selected_tracks = priority_tracks; |
815 | 1 | priority = priority_tracks; |
816 | 1 | } |
817 | 16 | else |
818 | 16 | { |
819 | 16 | std::set_intersection(priority_tracks.begin(),priority_tracks.end(), |
820 | 16 | selected_tracks.begin(),selected_tracks.end(), |
821 | 16 | std::back_inserter(priority)); |
822 | 16 | if (priority.empty()) // no video selected ? |
823 | 0 | priority = selected_tracks; |
824 | 16 | } |
825 | | |
826 | | // find appropriate seekpoints // |
827 | | |
828 | 17 | try { |
829 | 17 | seekpoints = _seeker.get_seekpoints( *this, i_mk_date, priority, selected_tracks ); |
830 | 17 | } |
831 | 17 | catch( std::exception const& e ) |
832 | 17 | { |
833 | 0 | msg_Err( &sys.demuxer, "error during seek: \"%s\", aborting!", e.what() ); |
834 | 0 | return false; |
835 | 0 | } |
836 | | |
837 | | // initialize seek information in order to set up playback // |
838 | | |
839 | 52 | for( SegmentSeeker::tracks_seekpoint_t::const_iterator it = seekpoints.begin(); it != seekpoints.end(); ++it ) |
840 | 35 | { |
841 | 35 | tracks_map_t::iterator trackit = tracks.find( it->first ); |
842 | 35 | if ( trackit == tracks.end() ) |
843 | 0 | continue; // there were blocks with unknown tracks |
844 | | |
845 | 35 | if( i_seek_position > it->second.fpos ) |
846 | 19 | { |
847 | 19 | i_seek_position = it->second.fpos; |
848 | 19 | i_mk_seek_time = it->second.pts; |
849 | 19 | } |
850 | | |
851 | | // blocks that will be not be read until this fpos |
852 | 35 | if ( b_accurate ) |
853 | 35 | trackit->second->i_skip_until_fpos = it->second.fpos; |
854 | 0 | else |
855 | 0 | trackit->second->i_skip_until_fpos = std::numeric_limits<uint64_t>::max(); |
856 | 35 | if (it->second.pts != -1) |
857 | 12 | trackit->second->i_last_dts = it->second.pts + i_mk_time_offset; |
858 | | |
859 | 35 | msg_Dbg( &sys.demuxer, "seek: preroll{ track: %u, pts: %" PRId64 ", fpos: %" PRIu64 " skip: %" PRIu64 "} ", |
860 | 35 | it->first, it->second.pts, it->second.fpos, trackit->second->i_skip_until_fpos ); |
861 | 35 | } |
862 | | |
863 | 17 | if ( i_seek_position == std::numeric_limits<SegmentSeeker::fptr_t>::max() ) |
864 | 1 | return false; |
865 | | |
866 | | // propagate seek information // |
867 | | |
868 | 16 | sys.i_pcr = VLC_TICK_INVALID; |
869 | 16 | sys.i_pts = VLC_TICK_0 + i_mk_seek_time + i_mk_time_offset; |
870 | 16 | if (b_accurate) |
871 | 16 | sys.i_start_pts = VLC_TICK_0 + i_absolute_mk_date; |
872 | 0 | else |
873 | 0 | sys.i_start_pts = sys.i_pts; |
874 | | |
875 | | // make the jump // |
876 | | |
877 | 16 | _seeker.mkv_jump_to( *this, i_seek_position ); |
878 | | |
879 | | // debug diagnostics // |
880 | | |
881 | 16 | msg_Dbg( &sys.demuxer, "seek: preroll{ req: %" PRId64 ", start-pts: %" PRId64 ", start-fpos: %" PRIu64 "} ", |
882 | 16 | sys.i_start_pts, sys.i_pts, i_seek_position ); |
883 | | |
884 | | // blocks that will be read and decoded but discarded until this pts |
885 | 16 | es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, sys.i_start_pts ); |
886 | 16 | return true; |
887 | 17 | } |
888 | | |
889 | | |
890 | | mkv_track_t * matroska_segment_c::FindTrackByBlock( |
891 | | const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock ) |
892 | 4.87k | { |
893 | 4.87k | tracks_map_t::iterator track_it; |
894 | | |
895 | 4.87k | if (p_block != NULL) |
896 | 4.30k | track_it = tracks.find( p_block->TrackNum() ); |
897 | 574 | else if( p_simpleblock != NULL) |
898 | 574 | track_it = tracks.find( p_simpleblock->TrackNum() ); |
899 | 0 | else |
900 | 0 | track_it = tracks.end(); |
901 | | |
902 | 4.87k | if (track_it == tracks.end()) |
903 | 39 | return NULL; |
904 | | |
905 | 4.84k | return track_it->second.get(); |
906 | 4.87k | } |
907 | | |
908 | | void matroska_segment_c::ComputeTrackPriority() |
909 | 17 | { |
910 | 17 | bool b_has_default_video = false; |
911 | 17 | bool b_has_default_audio = false; |
912 | | /* check for default */ |
913 | 52 | for( tracks_map_t::const_iterator it = tracks.begin(); it != tracks.end(); |
914 | 35 | ++it ) |
915 | 35 | { |
916 | 35 | mkv_track_t &track = *it->second; |
917 | | |
918 | 35 | bool flag = track.b_enabled && ( track.b_default || track.b_forced ); |
919 | | |
920 | 35 | switch( track.fmt.i_cat ) |
921 | 35 | { |
922 | 16 | case VIDEO_ES: b_has_default_video |= flag; break; |
923 | 11 | case AUDIO_ES: b_has_default_audio |= flag; break; |
924 | 8 | default: break; // ignore |
925 | 35 | } |
926 | 35 | } |
927 | | |
928 | 52 | for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it ) |
929 | 35 | { |
930 | 35 | tracks_map_t::key_type track_id = it->first; |
931 | 35 | mkv_track_t & track = *it->second; |
932 | | |
933 | 35 | if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) ) |
934 | 0 | { |
935 | 0 | msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) ); |
936 | 0 | track.p_es = NULL; |
937 | 0 | continue; |
938 | 0 | } |
939 | 35 | else if( unlikely( !b_has_default_video && track.fmt.i_cat == VIDEO_ES ) ) |
940 | 3 | { |
941 | 3 | track.b_default = true; |
942 | 3 | b_has_default_video = true; |
943 | 3 | } |
944 | 32 | else if( unlikely( !b_has_default_audio && track.fmt.i_cat == AUDIO_ES ) ) |
945 | 2 | { |
946 | 2 | track.b_default = true; |
947 | 2 | b_has_default_audio = true; |
948 | 2 | } |
949 | 35 | if( unlikely( !track.b_enabled ) ) |
950 | 0 | track.fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE; |
951 | 35 | else if( track.b_forced ) |
952 | 0 | track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2; |
953 | 35 | else if( track.b_default ) |
954 | 27 | track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1; |
955 | 8 | else |
956 | 8 | track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN; |
957 | | |
958 | | /* Avoid multivideo tracks when unnecessary */ |
959 | 35 | if( track.fmt.i_cat == VIDEO_ES ) |
960 | 16 | track.fmt.i_priority--; |
961 | 35 | } |
962 | | |
963 | | // find track(s) with highest priority // |
964 | 17 | { |
965 | 17 | int score = -1; |
966 | 17 | int es_type = -1; |
967 | | |
968 | 52 | for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it ) |
969 | 35 | { |
970 | 35 | int track_score = -1; |
971 | | |
972 | 35 | switch( it->second->fmt.i_cat ) |
973 | 35 | { |
974 | 16 | case VIDEO_ES: ++track_score; |
975 | | /* fallthrough */ |
976 | 27 | case AUDIO_ES: ++track_score; |
977 | | /* fallthrough */ |
978 | 35 | case SPU_ES: ++track_score; |
979 | | /* fallthrough */ |
980 | 35 | default: |
981 | 35 | if( score < track_score ) |
982 | 16 | { |
983 | 16 | es_type = it->second->fmt.i_cat; |
984 | 16 | score = track_score; |
985 | 16 | } |
986 | 35 | } |
987 | 35 | } |
988 | | |
989 | 52 | for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it ) |
990 | 35 | { |
991 | 35 | if( it->second->fmt.i_cat == es_type ) |
992 | 16 | priority_tracks.push_back( it->first ); |
993 | 35 | } |
994 | 17 | } |
995 | 17 | } |
996 | | |
997 | | void matroska_segment_c::EnsureDuration() |
998 | 17 | { |
999 | 17 | if ( i_duration > 0 ) |
1000 | 14 | return; |
1001 | | |
1002 | 3 | i_duration = -1; |
1003 | | |
1004 | 3 | if( !sys.b_fastseekable ) |
1005 | 0 | { |
1006 | 0 | msg_Warn( &sys.demuxer, "could not look for the segment duration" ); |
1007 | 0 | return; |
1008 | 0 | } |
1009 | | |
1010 | 3 | uint64_t i_current_position = es.I_O().getFilePointer(); |
1011 | 3 | uint64_t i_last_cluster_pos = cluster->GetElementPosition(); |
1012 | | |
1013 | | // find the last Cluster from the Cues |
1014 | | |
1015 | 3 | if ( b_cues && _seeker._cluster_positions.size() ) |
1016 | 0 | i_last_cluster_pos = *_seeker._cluster_positions.rbegin(); |
1017 | 3 | else if( !cluster->IsFiniteSize() ) |
1018 | 2 | { |
1019 | 2 | if ( i_last_cluster_pos == cluster->GetElementPosition() ) |
1020 | | // make sure our first Cluster has a timestamp |
1021 | 2 | ParseCluster( cluster, false, SCOPE_PARTIAL_DATA ); |
1022 | 2 | return; |
1023 | 2 | } |
1024 | | |
1025 | 1 | es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning ); |
1026 | | |
1027 | 1 | EbmlParser eparser ( &es, segment, &sys.demuxer ); |
1028 | | |
1029 | | // locate the definitely last cluster in the stream |
1030 | | |
1031 | 2 | while( EbmlElement* el = eparser.Get() ) |
1032 | 1 | { |
1033 | 1 | if( !el->IsFiniteSize() && el->GetElementPosition() != i_last_cluster_pos ) |
1034 | 0 | { |
1035 | 0 | es.I_O().setFilePointer( i_current_position, seek_beginning ); |
1036 | 0 | return; |
1037 | 0 | } |
1038 | | |
1039 | 1 | if( MKV_IS_ID( el, KaxCluster ) ) |
1040 | 1 | { |
1041 | 1 | i_last_cluster_pos = el->GetElementPosition(); |
1042 | 1 | if ( i_last_cluster_pos == cluster->GetElementPosition() ) |
1043 | | // make sure our first Cluster has a timestamp |
1044 | 1 | ParseCluster( cluster, false, SCOPE_PARTIAL_DATA ); |
1045 | 1 | } |
1046 | 1 | } |
1047 | | |
1048 | | // find the last timecode in the Cluster |
1049 | | |
1050 | 1 | eparser.Reset( &sys.demuxer ); |
1051 | 1 | es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning ); |
1052 | | |
1053 | 1 | EbmlElement* el = eparser.Get(); |
1054 | 1 | MKV_CHECKED_PTR_DECL( p_last_cluster, KaxCluster, el ); |
1055 | | |
1056 | 1 | if( p_last_cluster && |
1057 | 1 | ParseCluster( p_last_cluster, false, SCOPE_PARTIAL_DATA ) ) |
1058 | 1 | { |
1059 | | // use the last block + duration |
1060 | 1 | uint64_t i_last_timecode = p_last_cluster->GlobalTimestamp(); |
1061 | 1 | for (auto l : *p_last_cluster) |
1062 | 42 | { |
1063 | 42 | if( MKV_CHECKED_PTR_DECL ( simpleblock, KaxSimpleBlock, l ) ) |
1064 | 34 | { |
1065 | 34 | simpleblock->SetParent( *p_last_cluster ); |
1066 | 34 | i_last_timecode = std::max(i_last_timecode, simpleblock->GlobalTimestamp()); |
1067 | 34 | } |
1068 | 8 | else if( MKV_CHECKED_PTR_DECL_CONST ( group, KaxBlockGroup, l ) ) |
1069 | 7 | { |
1070 | 7 | uint64_t i_group_timecode = 0; |
1071 | 7 | for (auto g : *group) |
1072 | 14 | { |
1073 | 14 | if( MKV_CHECKED_PTR_DECL ( block, KaxBlock, g ) ) |
1074 | 7 | { |
1075 | 7 | block->SetParent( *p_last_cluster ); |
1076 | 7 | i_group_timecode += block->GlobalTimestamp(); |
1077 | 7 | } |
1078 | 7 | else if( MKV_CHECKED_PTR_DECL_CONST ( kbd_ptr, KaxBlockDuration, g ) ) |
1079 | 7 | { |
1080 | 7 | i_group_timecode += static_cast<uint64_t>( *kbd_ptr ); |
1081 | 7 | } |
1082 | 14 | } |
1083 | 7 | i_last_timecode = std::max(i_last_timecode, i_group_timecode); |
1084 | 7 | } |
1085 | 42 | } |
1086 | | |
1087 | 1 | i_duration = VLC_TICK_FROM_NS( i_last_timecode - cluster->GlobalTimestamp() ); |
1088 | 1 | msg_Dbg( &sys.demuxer, " extracted Duration=%" PRId64, SEC_FROM_VLC_TICK(i_duration) ); |
1089 | 1 | } |
1090 | | |
1091 | | // get back to the reading position we were at before looking for a duration |
1092 | 1 | es.I_O().setFilePointer( i_current_position, seek_beginning ); |
1093 | 1 | } |
1094 | | |
1095 | | bool matroska_segment_c::ESCreate() |
1096 | 17 | { |
1097 | | /* add all es */ |
1098 | 17 | msg_Dbg( &sys.demuxer, "found %d es", static_cast<int>( tracks.size() ) ); |
1099 | | |
1100 | 17 | mkv_track_t *default_tracks[ES_CATEGORY_COUNT] = {}; |
1101 | 52 | for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it ) |
1102 | 35 | { |
1103 | 35 | tracks_map_t::key_type track_id = it->first; |
1104 | 35 | mkv_track_t & track = *it->second; |
1105 | | |
1106 | 35 | if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) ) |
1107 | 0 | { |
1108 | 0 | msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) ); |
1109 | 0 | track.p_es = NULL; |
1110 | 0 | continue; |
1111 | 0 | } |
1112 | 35 | track.fmt.i_id = static_cast<int>( track_id ); |
1113 | | |
1114 | 35 | if( !track.p_es ) |
1115 | 35 | { |
1116 | 35 | track.p_es = es_out_Add( sys.demuxer.out, &track.fmt ); |
1117 | | |
1118 | 35 | if( track.p_es && |
1119 | 35 | !sys.ev.AddTrack( track ) ) |
1120 | 16 | { |
1121 | 16 | msg_Warn( &sys.demuxer, "Could not register events, interactive menus will not work"); |
1122 | 16 | } |
1123 | 35 | } |
1124 | | |
1125 | | /* Turn on a subtitles track if it has been flagged as default - |
1126 | | * but only do this if no subtitles track has already been engaged, |
1127 | | * either by an earlier 'default track' (??) or by default |
1128 | | * language choice behaviour. |
1129 | | */ |
1130 | 35 | if( track.b_default || track.b_forced ) |
1131 | 27 | { |
1132 | 27 | mkv_track_t *&default_track = default_tracks[track.fmt.i_cat]; |
1133 | 27 | if( !default_track || track.b_default ) |
1134 | 27 | default_track = &track; |
1135 | 27 | } |
1136 | 35 | } |
1137 | | |
1138 | 17 | for( mkv_track_t *track : default_tracks ) |
1139 | 85 | { |
1140 | 85 | if( track ) |
1141 | 27 | es_out_Control( sys.demuxer.out, ES_OUT_SET_ES_DEFAULT, track->p_es ); |
1142 | 85 | } |
1143 | | |
1144 | 17 | return true; |
1145 | 17 | } |
1146 | | |
1147 | | void matroska_segment_c::ESDestroy( ) |
1148 | 17 | { |
1149 | 17 | sys.ev.AbortThread(); |
1150 | | |
1151 | 52 | for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it ) |
1152 | 35 | { |
1153 | 35 | mkv_track_t & track = *it->second; |
1154 | | |
1155 | 35 | if( track.p_es != NULL ) |
1156 | 35 | { |
1157 | 35 | es_out_Del( sys.demuxer.out, track.p_es ); |
1158 | 35 | sys.ev.DelTrack( track ); |
1159 | 35 | track.p_es = NULL; |
1160 | 35 | } |
1161 | 35 | } |
1162 | 17 | } |
1163 | | |
1164 | | int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_simpleblock, |
1165 | | KaxBlockAdditions * & pp_additions, |
1166 | | bool *pb_key_picture, bool *pb_discardable_picture, |
1167 | | int64_t *pi_duration ) |
1168 | 1.26k | { |
1169 | 1.26k | pp_simpleblock = NULL; |
1170 | 1.26k | pp_block = NULL; |
1171 | 1.26k | pp_additions = NULL; |
1172 | | |
1173 | 1.26k | *pb_key_picture = true; |
1174 | 1.26k | *pb_discardable_picture = false; |
1175 | 1.26k | *pi_duration = 0; |
1176 | | |
1177 | 1.26k | struct BlockPayload { |
1178 | 1.26k | matroska_segment_c * const obj; |
1179 | 1.26k | EbmlParser * const ep; |
1180 | 1.26k | demux_t * const p_demuxer; |
1181 | 1.26k | KaxBlock *& block; |
1182 | 1.26k | KaxSimpleBlock *& simpleblock; |
1183 | 1.26k | KaxBlockAdditions *& additions; |
1184 | | |
1185 | 1.26k | int64_t & i_duration; |
1186 | 1.26k | bool & b_key_picture; |
1187 | 1.26k | bool & b_discardable_picture; |
1188 | 1.26k | bool b_cluster_timecode; |
1189 | | |
1190 | 1.26k | } payload = { |
1191 | 1.26k | this, &ep, &sys.demuxer, pp_block, pp_simpleblock, pp_additions, |
1192 | 1.26k | *pi_duration, *pb_key_picture, *pb_discardable_picture, true |
1193 | 1.26k | }; |
1194 | | |
1195 | 1.26k | MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l1, BlockPayload ) |
1196 | 1.26k | { |
1197 | 1.26k | MKV_SWITCH_INIT(); |
1198 | | |
1199 | 1.26k | E_CASE( KaxCluster, kcluster ) |
1200 | 1.26k | { |
1201 | 20 | vars.obj->cluster = &kcluster; |
1202 | 20 | vars.b_cluster_timecode = false; |
1203 | 20 | vars.ep->Down (); |
1204 | 20 | } |
1205 | 1.26k | E_CASE( KaxCues, kcue ) |
1206 | 1.26k | { |
1207 | 0 | VLC_UNUSED( kcue ); |
1208 | 0 | msg_Warn( vars.p_demuxer, "find KaxCues FIXME" ); |
1209 | 0 | } |
1210 | 1.26k | E_CASE_DEFAULT(element) |
1211 | 1.26k | { |
1212 | 476 | msg_Dbg( vars.p_demuxer, "Unknown (%s)", EBML_NAME(&element) ); |
1213 | 476 | } |
1214 | 1.26k | }; |
1215 | | |
1216 | 1.26k | MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l2, BlockPayload ) |
1217 | 1.26k | { |
1218 | 1.26k | MKV_SWITCH_INIT(); |
1219 | | |
1220 | 1.26k | E_CASE( KaxClusterTimestamp, ktimecode ) |
1221 | 1.26k | { |
1222 | 22 | ktimecode.ReadData( vars.obj->es.I_O(), SCOPE_ALL_DATA ); |
1223 | 22 | vars.obj->cluster->InitTimestamp( static_cast<uint64_t>( ktimecode ), vars.obj->i_timescale ); |
1224 | 22 | vars.obj->_seeker.add_cluster( vars.obj->cluster ); |
1225 | 22 | vars.b_cluster_timecode = true; |
1226 | 22 | } |
1227 | 1.26k | E_CASE( KaxClusterSilentTracks, ksilent ) |
1228 | 1.26k | { |
1229 | 0 | vars.ep->Down (); |
1230 | |
|
1231 | 0 | VLC_UNUSED( ksilent ); |
1232 | 0 | } |
1233 | 1.26k | E_CASE( KaxBlockGroup, kbgroup ) |
1234 | 1.26k | { |
1235 | 1.08k | vars.obj->i_block_pos = kbgroup.GetElementPosition(); |
1236 | 1.08k | vars.ep->Down (); |
1237 | 1.08k | } |
1238 | 1.26k | E_CASE( KaxSimpleBlock, ksblock ) |
1239 | 1.26k | { |
1240 | 184 | if( vars.b_cluster_timecode == false ) |
1241 | 0 | { |
1242 | 0 | msg_Warn( vars.p_demuxer, "ignoring SimpleBlock prior to mandatory Timecode" ); |
1243 | 0 | return; |
1244 | 0 | } |
1245 | | |
1246 | 184 | vars.simpleblock = &ksblock; |
1247 | 184 | vars.simpleblock->ReadData( vars.obj->es.I_O() ); |
1248 | 184 | vars.simpleblock->SetParent( *vars.obj->cluster ); |
1249 | | |
1250 | 184 | if( ksblock.IsKeyframe() ) |
1251 | 65 | { |
1252 | 65 | bool const b_valid_track = vars.obj->FindTrackByBlock( NULL, &ksblock ) != NULL; |
1253 | 65 | if (b_valid_track) |
1254 | 52 | vars.obj->_seeker.add_seekpoint( ksblock.TrackNum(), |
1255 | 52 | SegmentSeeker::Seekpoint( ksblock.GetElementPosition(), VLC_TICK_FROM_NS(ksblock.GlobalTimestamp()) ) ); |
1256 | 65 | } |
1257 | 184 | } |
1258 | 1.26k | }; |
1259 | | |
1260 | 1.26k | MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l3, BlockPayload ) |
1261 | 1.26k | { |
1262 | 1.26k | MKV_SWITCH_INIT(); |
1263 | | |
1264 | 1.26k | E_CASE( KaxBlock, kblock ) |
1265 | 1.26k | { |
1266 | 1.08k | vars.block = &kblock; |
1267 | 1.08k | vars.block->ReadData( vars.obj->es.I_O() ); |
1268 | 1.08k | vars.block->SetParent( *vars.obj->cluster ); |
1269 | | |
1270 | 1.08k | const mkv_track_t *p_track = vars.obj->FindTrackByBlock( &kblock, NULL ); |
1271 | 1.08k | if( p_track != NULL && p_track->fmt.i_cat == SPU_ES ) |
1272 | 0 | { |
1273 | 0 | vars.obj->_seeker.add_seekpoint( kblock.TrackNum(), |
1274 | 0 | SegmentSeeker::Seekpoint( kblock.GetElementPosition(), VLC_TICK_FROM_NS(kblock.GlobalTimestamp()) ) ); |
1275 | 0 | } |
1276 | | |
1277 | 1.08k | vars.ep->Keep (); |
1278 | 1.08k | } |
1279 | 1.26k | E_CASE( KaxBlockAdditions, kadditions ) |
1280 | 1.26k | { |
1281 | 795 | if ( vars.obj->ReadMaster( kadditions ) ) |
1282 | 795 | { |
1283 | 795 | vars.additions = &kadditions; |
1284 | 795 | vars.ep->Keep (); |
1285 | 795 | } |
1286 | 795 | } |
1287 | 1.26k | E_CASE( KaxBlockDuration, kduration ) |
1288 | 1.26k | { |
1289 | 2 | kduration.ReadData( vars.obj->es.I_O() ); |
1290 | 2 | vars.i_duration = static_cast<uint64_t>( kduration ); |
1291 | 2 | } |
1292 | 1.26k | E_CASE( KaxReferenceBlock, kreference ) |
1293 | 1.26k | { |
1294 | 206 | kreference.ReadData( vars.obj->es.I_O() ); |
1295 | | |
1296 | 206 | if( vars.b_key_picture ) |
1297 | 206 | vars.b_key_picture = false; |
1298 | 0 | else if( static_cast<int64_t>( kreference ) ) |
1299 | 0 | vars.b_discardable_picture = true; |
1300 | 206 | } |
1301 | 1.26k | E_CASE( KaxClusterSilentTrackNumber, kstrackn ) |
1302 | 1.26k | { |
1303 | 0 | VLC_UNUSED( kstrackn ); |
1304 | 0 | VLC_UNUSED( vars ); |
1305 | 0 | } |
1306 | 1.26k | #if LIBMATROSKA_VERSION >= 0x010401 |
1307 | 1.26k | E_CASE( KaxDiscardPadding, kdiscardp ) |
1308 | 1.26k | { |
1309 | 0 | kdiscardp.ReadData( vars.obj->es.I_O() ); |
1310 | 0 | int64_t i_duration = static_cast<int64_t>( kdiscardp ); |
1311 | |
|
1312 | 0 | if( vars.i_duration < i_duration ) |
1313 | 0 | vars.i_duration = 0; |
1314 | 0 | else |
1315 | 0 | vars.i_duration -= i_duration; |
1316 | 0 | } |
1317 | 1.26k | #endif |
1318 | 1.26k | E_CASE_DEFAULT( element ) |
1319 | 1.26k | { |
1320 | 6 | VLC_UNUSED(element); |
1321 | | |
1322 | 6 | msg_Warn( vars.p_demuxer, "unknown element at { fpos: %" PRId64 ", '%s' }", |
1323 | 6 | element.GetElementPosition(), EBML_NAME( &element ) ); |
1324 | 6 | } |
1325 | 1.26k | }; |
1326 | | |
1327 | 1.26k | static EbmlTypeDispatcher const * const dispatchers[] = { |
1328 | 1.26k | &BlockGetHandler_l1::Dispatcher(), |
1329 | 1.26k | &BlockGetHandler_l2::Dispatcher(), |
1330 | 1.26k | &BlockGetHandler_l3::Dispatcher() |
1331 | 1.26k | }; |
1332 | | |
1333 | 1.26k | for( ;; ) |
1334 | 6.33k | { |
1335 | 6.33k | EbmlElement *el = NULL; |
1336 | 6.33k | int i_level; |
1337 | | |
1338 | 6.33k | if( pp_simpleblock != NULL || ((el = ep.Get()) == NULL && pp_block != NULL) ) |
1339 | 1.26k | { |
1340 | | /* Check blocks validity to protect against broken files */ |
1341 | 1.26k | const mkv_track_t *p_track = FindTrackByBlock( pp_block , pp_simpleblock ); |
1342 | 1.26k | if( p_track == NULL ) |
1343 | 22 | { |
1344 | 22 | ep.Unkeep(); |
1345 | 22 | pp_simpleblock = NULL; |
1346 | 22 | pp_block = NULL; |
1347 | 22 | continue; |
1348 | 22 | } |
1349 | 1.24k | if( pp_simpleblock != NULL ) |
1350 | 166 | { |
1351 | 166 | *pb_key_picture = pp_simpleblock->IsKeyframe(); |
1352 | 166 | *pb_discardable_picture = pp_simpleblock->IsDiscardable(); |
1353 | 166 | } |
1354 | | /* We have block group let's check if the picture is a keyframe */ |
1355 | 1.07k | else if( *pb_key_picture ) |
1356 | 871 | { |
1357 | 871 | if( p_track->fmt.i_codec == VLC_CODEC_THEORA ) |
1358 | 8 | { |
1359 | 8 | DataBuffer * p_data = &pp_block->GetBuffer(0); |
1360 | 8 | const uint8_t * p_buff = p_data->Buffer(); |
1361 | | /* if the second bit of a Theora frame is 1 |
1362 | | it's not a keyframe */ |
1363 | 8 | if( p_data->Size() && p_buff ) |
1364 | 8 | { |
1365 | 8 | if( p_buff[0] & 0x40 ) |
1366 | 0 | *pb_key_picture = false; |
1367 | 8 | } |
1368 | 0 | else |
1369 | 0 | *pb_key_picture = false; |
1370 | 8 | } |
1371 | 871 | } |
1372 | | |
1373 | 1.24k | return VLC_SUCCESS; |
1374 | 1.26k | } |
1375 | | |
1376 | 5.06k | i_level = ep.GetLevel(); |
1377 | | |
1378 | 5.06k | if( el == NULL ) |
1379 | 1.14k | { |
1380 | 1.14k | if( i_level > 1 ) |
1381 | 1.12k | { |
1382 | 1.12k | ep.Up(); |
1383 | 1.12k | continue; |
1384 | 1.12k | } |
1385 | 25 | msg_Warn( &sys.demuxer, "EOF" ); |
1386 | 25 | return VLC_EGENERIC; |
1387 | 1.14k | } |
1388 | | |
1389 | | /* Verify that we are still inside our cluster |
1390 | | * It can happens with broken files and when seeking |
1391 | | * without index */ |
1392 | 3.91k | if( i_level > 1 ) |
1393 | 3.42k | { |
1394 | 3.42k | if( cluster && !ep.IsTopPresent( cluster ) ) |
1395 | 0 | { |
1396 | 0 | msg_Warn( &sys.demuxer, "Unexpected escape from current cluster" ); |
1397 | 0 | cluster = NULL; |
1398 | 0 | } |
1399 | 3.42k | if( !cluster ) |
1400 | 0 | continue; |
1401 | 3.42k | } |
1402 | | |
1403 | | /* do parsing */ |
1404 | | |
1405 | 3.91k | try { |
1406 | 3.91k | switch( i_level ) |
1407 | 3.91k | { |
1408 | 1.33k | case 2: |
1409 | | /* fallthrough */ |
1410 | 3.42k | case 3: |
1411 | 3.42k | if( unlikely( !el->ValidateSize() || ( el->IsFiniteSize() && el->GetSize() >= SIZE_MAX ) ) ) |
1412 | 0 | { |
1413 | 0 | msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el)); |
1414 | 0 | ep.Up(); |
1415 | |
|
1416 | 0 | if ( i_level == 2 ) |
1417 | 0 | break; |
1418 | | |
1419 | 0 | ep.Unkeep(); |
1420 | 0 | pp_simpleblock = NULL; |
1421 | 0 | pp_block = NULL; |
1422 | |
|
1423 | 0 | break; |
1424 | 0 | } |
1425 | | /* fallthrough */ |
1426 | 3.91k | case 1: |
1427 | 3.91k | { |
1428 | 3.91k | EbmlTypeDispatcher const * dispatcher = dispatchers[i_level - 1]; |
1429 | 3.91k | dispatcher->send( el, &payload ); |
1430 | 3.91k | } |
1431 | 3.91k | break; |
1432 | | |
1433 | 0 | default: |
1434 | 0 | msg_Err( &sys.demuxer, "invalid level = %d", i_level ); |
1435 | 0 | return VLC_EGENERIC; |
1436 | 3.91k | } |
1437 | 3.91k | } |
1438 | 3.91k | catch (int ret_code) |
1439 | 3.91k | { |
1440 | 0 | return ret_code; |
1441 | 0 | } |
1442 | 3.91k | catch (...) |
1443 | 3.91k | { |
1444 | 0 | msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el)); |
1445 | 0 | ep.Up(); |
1446 | 0 | ep.Unkeep(); |
1447 | 0 | pp_simpleblock = NULL; |
1448 | 0 | pp_block = NULL; |
1449 | 0 | } |
1450 | 3.91k | } |
1451 | 1.26k | } |
1452 | | |
1453 | | } // namespace |