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