/src/vlc/modules/demux/mkv/demux.cpp
Line | Count | Source |
1 | | |
2 | | /***************************************************************************** |
3 | | * mkv.cpp : matroska demuxer |
4 | | ***************************************************************************** |
5 | | * Copyright (C) 2003-2004 VLC authors and VideoLAN |
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 it |
11 | | * under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public License |
21 | | * along with this program; if not, write to the Free Software Foundation, |
22 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
23 | | *****************************************************************************/ |
24 | | |
25 | | #include "demux.hpp" |
26 | | #include "stream_io_callback.hpp" |
27 | | #include "Ebml_parser.hpp" |
28 | | #include "virtual_segment.hpp" |
29 | | |
30 | | namespace mkv { |
31 | | |
32 | | demux_sys_t::~demux_sys_t() |
33 | 7.49k | { |
34 | 7.49k | size_t i; |
35 | 14.9k | for ( i=0; i<streams.size(); i++ ) |
36 | 7.49k | delete streams[i]; |
37 | 15.0k | for ( i=0; i<opened_segments.size(); i++ ) |
38 | 7.52k | delete opened_segments[i]; |
39 | 11.4k | for ( i=0; i<used_vsegments.size(); i++ ) |
40 | 3.91k | delete used_vsegments[i]; |
41 | 7.49k | if( meta ) vlc_meta_Delete( meta ); |
42 | | |
43 | 12.6k | while( titles.size() ) |
44 | 5.16k | { vlc_input_title_Delete( titles.back() ); titles.pop_back();} |
45 | 7.49k | } |
46 | | |
47 | | |
48 | | bool demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, matroska_stream_c *p_stream1 ) |
49 | 7.49k | { |
50 | 7.49k | int i_upper_lvl = 0; |
51 | 7.49k | EbmlElement *p_l0; |
52 | 7.49k | bool b_keep_stream = false; |
53 | | |
54 | | /* verify the EBML Header... it shouldn't be bigger than 1kB */ |
55 | 7.49k | p_l0 = p_stream1->estream.FindNextID(EBML_INFO(EbmlHead), 1024); |
56 | 7.49k | if (p_l0 == nullptr || p_l0->IsDummy()) |
57 | 1 | { |
58 | 1 | msg_Err( p_demux, "No EBML header found" ); |
59 | 1 | delete p_l0; |
60 | 1 | return false; |
61 | 1 | } |
62 | | |
63 | | /* verify we can read this Segment */ |
64 | 7.49k | try |
65 | 7.49k | { |
66 | 7.49k | EbmlElement *el = nullptr; |
67 | 7.49k | p_l0->Read( p_stream1->estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, el, true); |
68 | 7.49k | if (i_upper_lvl != 0) |
69 | 3 | { |
70 | 3 | assert(el != nullptr); |
71 | 3 | delete el; |
72 | 3 | } |
73 | 7.49k | } |
74 | 7.49k | catch(...) |
75 | 7.49k | { |
76 | 0 | msg_Err(p_demux, "EBML Header Read failed"); |
77 | 0 | delete p_l0; |
78 | 0 | return false; |
79 | 0 | } |
80 | | |
81 | 7.49k | EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0)); |
82 | 7.49k | if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" ) |
83 | 51 | { |
84 | 51 | msg_Err( p_demux, "Not a Matroska file : DocType = %s ", std::string(doc_type).c_str()); |
85 | 51 | delete p_l0; |
86 | 51 | return false; |
87 | 51 | } |
88 | | |
89 | 7.44k | EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0)); |
90 | 7.44k | if (uint64_t(doc_read_version) > 5) |
91 | 0 | { |
92 | 0 | msg_Err( p_demux, "matroska file needs version %" PRId64 " but only versions 1 to 4 supported", uint64_t(doc_read_version)); |
93 | 0 | delete p_l0; |
94 | 0 | return false; |
95 | 0 | } |
96 | | |
97 | 7.44k | delete p_l0; |
98 | | |
99 | | |
100 | | // find all segments in this file |
101 | 7.44k | p_l0 = p_stream1->estream.FindNextID(EBML_INFO(KaxSegment), UINT64_MAX); |
102 | 7.44k | if (p_l0 == nullptr || p_l0->IsDummy()) |
103 | 48 | { |
104 | 48 | msg_Err( p_demux, "No segment found" ); |
105 | 48 | delete p_l0; |
106 | 48 | return false; |
107 | 48 | } |
108 | | |
109 | 14.9k | while (p_l0 != nullptr) |
110 | 7.52k | { |
111 | 7.52k | bool b_l0_handled = false; |
112 | | |
113 | 7.52k | if ( MKV_IS_ID( p_l0, KaxSegment) ) |
114 | 7.52k | { |
115 | 7.52k | matroska_segment_c *p_segment1 = new matroska_segment_c( *this, p_stream1->estream, (KaxSegment*)p_l0 ); |
116 | | |
117 | 7.52k | p_segment1->Preload(); |
118 | | |
119 | 7.52k | if ( !p_segment1->p_segment_uid || |
120 | 1.31k | !SegmentIsOpened( *p_segment1->p_segment_uid ) ) |
121 | 7.52k | { |
122 | 7.52k | opened_segments.push_back( p_segment1 ); |
123 | 7.52k | b_keep_stream = true; |
124 | 7.52k | p_stream1->segments.push_back( p_segment1 ); |
125 | 7.52k | } |
126 | 0 | else |
127 | 0 | { |
128 | 0 | p_segment1->segment = NULL; |
129 | 0 | delete p_segment1; |
130 | 0 | } |
131 | | |
132 | 7.52k | b_l0_handled = true; |
133 | 7.52k | } |
134 | | |
135 | 7.52k | if ( !b_seekable ) |
136 | 0 | break; |
137 | | |
138 | 7.52k | EbmlElement* p_l0_prev = p_l0; |
139 | | |
140 | 7.52k | if (p_l0->IsFiniteSize() ) |
141 | 7.20k | { |
142 | 7.20k | p_l0->SkipData(p_stream1->estream, Context_KaxMatroska); |
143 | 7.20k | p_l0 = p_stream1->estream.FindNextID(EBML_INFO(KaxSegment), UINT64_MAX); |
144 | 7.20k | if (p_l0 != nullptr && p_l0->IsDummy()) |
145 | 72 | { |
146 | 72 | delete p_l0; |
147 | 72 | p_l0 = nullptr; |
148 | 72 | } |
149 | 7.20k | } |
150 | 320 | else |
151 | 320 | { |
152 | 320 | p_l0 = nullptr; |
153 | 320 | } |
154 | | |
155 | 7.52k | if( b_l0_handled == false ) |
156 | 0 | delete p_l0_prev; |
157 | 7.52k | } |
158 | | |
159 | 7.39k | if ( !b_keep_stream ) |
160 | 0 | return false; |
161 | | |
162 | 7.39k | return true; |
163 | 7.39k | } |
164 | | |
165 | | void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment ) |
166 | 0 | { |
167 | 0 | for (size_t i=0; i<opened_segments.size(); i++) |
168 | 0 | { |
169 | 0 | opened_segments[i]->PreloadFamily( of_segment ); |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | // preload all the linked segments for all preloaded segments |
174 | | bool demux_sys_t::PreloadLinked() |
175 | 4.01k | { |
176 | 4.01k | size_t i, j, ij = 0; |
177 | 4.01k | virtual_segment_c *p_vseg; |
178 | | |
179 | 4.01k | if ( unlikely(opened_segments.size() == 0) ) |
180 | 0 | return false; |
181 | | |
182 | 4.01k | p_current_vsegment = new (std::nothrow) virtual_segment_c( *(opened_segments[0]), opened_segments ); |
183 | 4.01k | if ( !p_current_vsegment ) |
184 | 0 | return false; |
185 | | |
186 | 4.01k | if ( unlikely(p_current_vsegment->CurrentEdition() == NULL) ) |
187 | 95 | { |
188 | 95 | delete p_current_vsegment; |
189 | 95 | return false; |
190 | 95 | } |
191 | | |
192 | | /* Set current chapter */ |
193 | 3.91k | msg_Dbg( &demuxer, "NEW START CHAPTER uid=%" PRId64, p_current_vsegment->CurrentChapter() && p_current_vsegment->CurrentChapter()->p_chapter ? |
194 | 3.91k | p_current_vsegment->CurrentChapter()->p_chapter->i_uid : 0 ); |
195 | | |
196 | 3.91k | used_vsegments.push_back( p_current_vsegment ); |
197 | | |
198 | 3.92k | for ( i=1; i< opened_segments.size(); i++ ) |
199 | 4 | { |
200 | | /* add segments from the same family to used_segments */ |
201 | 4 | if ( opened_segments[0]->SameFamily( *(opened_segments[i]) ) ) |
202 | 0 | { |
203 | 0 | virtual_segment_c *p_vsegment = new (std::nothrow) virtual_segment_c( *(opened_segments[i]), opened_segments ); |
204 | 0 | if ( likely(p_vsegment != NULL) ) |
205 | 0 | used_vsegments.push_back( p_vsegment ); |
206 | 0 | } |
207 | 4 | } |
208 | | |
209 | | // publish all editions of all usable segment |
210 | 7.83k | for ( i=0; i< used_vsegments.size(); i++ ) |
211 | 3.91k | { |
212 | 3.91k | p_vseg = used_vsegments[i]; |
213 | 3.91k | if ( p_vseg->Editions() != NULL ) |
214 | 3.91k | { |
215 | 9.08k | for ( j=0; j<p_vseg->Editions()->size(); j++ ) |
216 | 5.16k | { |
217 | 5.16k | virtual_edition_c * p_ved = (*p_vseg->Editions())[j]; |
218 | 5.16k | input_title_t *p_title = vlc_input_title_New(); |
219 | 5.16k | int i_chapters; |
220 | | |
221 | | // TODO use a name for each edition, let the TITLE deal with a codec name |
222 | 5.16k | if ( p_title->psz_name == NULL ) |
223 | 5.16k | { |
224 | 5.16k | if( p_ved->GetMainName().length() ) |
225 | 0 | p_title->psz_name = strdup( p_ved->GetMainName().c_str() ); |
226 | 5.16k | else |
227 | 5.16k | { |
228 | | /* Check in tags if the edition has a name */ |
229 | | |
230 | | /* We use only the tags of the first segment as it contains the edition */ |
231 | 5.16k | matroska_segment_c::tags_t const& tags = opened_segments[0]->tags; |
232 | 5.16k | uint64_t i_ed_uid = 0; |
233 | 5.16k | if( p_ved->p_edition ) |
234 | 2.69k | i_ed_uid = (uint64_t) p_ved->p_edition->i_uid; |
235 | | |
236 | 6.79k | for( size_t k = 0; k < tags.size(); k++ ) |
237 | 1.62k | { |
238 | 1.62k | if( tags[k].i_tag_type == EDITION_UID && tags[k].i_uid == i_ed_uid ) |
239 | 36 | for( size_t l = 0; l < tags[k].simple_tags.size(); l++ ) |
240 | 25 | { |
241 | 25 | SimpleTag const& st = tags[k].simple_tags[l]; |
242 | 25 | if ( st.tag_name == "TITLE" ) |
243 | 11 | { |
244 | 11 | msg_Dbg( &demuxer, "Using title \"%s\" from tag for edition %" PRIu64, st.value.c_str (), i_ed_uid ); |
245 | 11 | free(p_title->psz_name); |
246 | 11 | p_title->psz_name = strdup( st.value.c_str () ); |
247 | 11 | break; |
248 | 11 | } |
249 | 25 | } |
250 | 1.62k | } |
251 | | |
252 | 5.16k | if( !p_title->psz_name && |
253 | 5.15k | asprintf(&(p_title->psz_name), "%s %d", "Segment", (int)ij) == -1 ) |
254 | 0 | p_title->psz_name = NULL; |
255 | 5.16k | } |
256 | 5.16k | } |
257 | | |
258 | 5.16k | ij++; |
259 | 5.16k | i_chapters = 0; |
260 | 5.16k | p_ved->PublishChapters( *p_title, i_chapters, 0 ); |
261 | | |
262 | | // Input duration into i_length |
263 | 5.16k | p_title->i_length = p_ved->i_duration; |
264 | | |
265 | 5.16k | titles.push_back( p_title ); |
266 | 5.16k | } |
267 | 3.91k | } |
268 | 3.91k | p_vseg->i_sys_title = p_vseg->i_current_edition; |
269 | 3.91k | } |
270 | | |
271 | | // TODO decide which segment should be first used (VMG for DVD) |
272 | | |
273 | 3.91k | return true; |
274 | 4.01k | } |
275 | | |
276 | | bool demux_sys_t::FreeUnused() |
277 | 3.73k | { |
278 | 3.73k | auto sIt = std::remove_if(begin(streams), end(streams), [](const matroska_stream_c* p_s) { |
279 | 3.73k | return !p_s->isUsed(); |
280 | 3.73k | }); |
281 | 3.73k | for (auto it = sIt; it != end(streams); ++it) |
282 | 0 | delete *it; |
283 | 3.73k | streams.erase(sIt, end(streams)); |
284 | | |
285 | 3.73k | auto sgIt = std::remove_if(begin(opened_segments), end(opened_segments), |
286 | 3.74k | [](const matroska_segment_c* p_sg) { |
287 | 3.74k | return !p_sg->b_preloaded; |
288 | 3.74k | }); |
289 | 3.73k | for (auto it = sgIt; it != end(opened_segments); ++it) |
290 | 0 | delete *it; |
291 | 3.73k | opened_segments.erase(sgIt, end(opened_segments)); |
292 | | |
293 | 3.73k | return !streams.empty() && !opened_segments.empty(); |
294 | 3.73k | } |
295 | | |
296 | | bool demux_sys_t::PreparePlayback( virtual_segment_c & new_vsegment ) |
297 | 3.91k | { |
298 | 3.91k | if ( !new_vsegment.CurrentSegment() ) |
299 | 181 | return false; |
300 | | |
301 | 3.73k | if ( p_current_vsegment != &new_vsegment ) |
302 | 0 | { |
303 | 0 | if ( p_current_vsegment->CurrentSegment() != NULL ) |
304 | 0 | p_current_vsegment->CurrentSegment()->ESDestroy(); |
305 | |
|
306 | 0 | p_current_vsegment = &new_vsegment; |
307 | 0 | p_current_vsegment->CurrentSegment()->ESCreate(); |
308 | 0 | i_current_title = p_current_vsegment->i_sys_title; |
309 | 0 | } |
310 | 3.73k | if( !p_current_vsegment->CurrentSegment()->b_cues ) |
311 | 3.73k | msg_Warn( &p_current_vsegment->CurrentSegment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" ); |
312 | | |
313 | 3.73k | i_duration = p_current_vsegment->Duration(); |
314 | | |
315 | | /* add information */ |
316 | 3.73k | p_current_vsegment->CurrentSegment()->InformationCreate( ); |
317 | 3.73k | p_current_vsegment->CurrentSegment()->ESCreate( ); |
318 | | |
319 | 3.73k | return true; |
320 | 3.91k | } |
321 | | |
322 | | void demux_sys_t::JumpTo( virtual_segment_c & vsegment, virtual_chapter_c & vchapter ) |
323 | 3 | { |
324 | 3 | if ( !vchapter.p_chapter || !vchapter.p_chapter->Enter( true ) ) |
325 | 3 | { |
326 | | // jump to the location in the found segment |
327 | 3 | vsegment.Seek( demuxer, vchapter.i_mk_virtual_start_time, &vchapter ); |
328 | 3 | } |
329 | 3 | } |
330 | | |
331 | | bool demux_sys_t::SegmentIsOpened( const EbmlBinary & uid ) const |
332 | 1.31k | { |
333 | 1.31k | for (size_t i=0; i<opened_segments.size(); i++) |
334 | 2 | { |
335 | 2 | if ( opened_segments[i]->p_segment_uid && *opened_segments[i]->p_segment_uid == uid ) |
336 | 0 | return true; |
337 | 2 | } |
338 | 1.31k | return false; |
339 | 1.31k | } |
340 | | |
341 | | virtual_chapter_c *demux_sys_t::BrowseCodecPrivate( chapter_codec_id codec_id, |
342 | | chapter_cmd_match match, |
343 | | virtual_segment_c * &p_vsegment_found ) |
344 | 0 | { |
345 | 0 | virtual_chapter_c *p_result = NULL; |
346 | 0 | for (size_t i=0; i<used_vsegments.size(); i++) |
347 | 0 | { |
348 | 0 | p_result = used_vsegments[i]->BrowseCodecPrivate( codec_id, match ); |
349 | 0 | if ( p_result != NULL ) |
350 | 0 | { |
351 | 0 | p_vsegment_found = used_vsegments[i]; |
352 | 0 | break; |
353 | 0 | } |
354 | 0 | } |
355 | 0 | return p_result; |
356 | 0 | } |
357 | | |
358 | | virtual_chapter_c *demux_sys_t::FindVChapter( chapter_uid i_find_uid, virtual_segment_c * & p_vsegment_found ) |
359 | 13 | { |
360 | 13 | virtual_chapter_c *p_result = NULL; |
361 | 23 | for (size_t i=0; i<used_vsegments.size(); i++) |
362 | 13 | { |
363 | 13 | p_result = used_vsegments[i]->FindChapter( i_find_uid ); |
364 | 13 | if ( p_result != NULL ) |
365 | 3 | { |
366 | 3 | p_vsegment_found = used_vsegments[i]; |
367 | 3 | break; |
368 | 3 | } |
369 | 13 | } |
370 | 13 | return p_result; |
371 | 13 | } |
372 | | |
373 | | void demux_sys_t::SetHighlight( vlc_spu_highlight_t & spu_hl ) |
374 | 0 | { |
375 | 0 | ev.SetHighlight( spu_hl ); |
376 | 0 | } |
377 | | |
378 | | } // namespace |