/src/vlc/modules/demux/mkv/matroska_segment_seeker.cpp
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * matroska_segment.hpp : matroska demuxer |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2016 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Filip Roséen <filip@videolabs.io> |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU Lesser General Public License as published by |
10 | | * the Free Software Foundation; either version 2.1 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program; if not, write to the Free Software Foundation, |
20 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
21 | | *****************************************************************************/ |
22 | | |
23 | | #include "matroska_segment_seeker.hpp" |
24 | | #include "matroska_segment.hpp" |
25 | | #include "demux.hpp" |
26 | | #include "Ebml_parser.hpp" |
27 | | #include "Ebml_dispatcher.hpp" |
28 | | #include "util.hpp" |
29 | | #include "stream_io_callback.hpp" |
30 | | |
31 | | #include <sstream> |
32 | | #include <limits> |
33 | | |
34 | | namespace { |
35 | | template<class It, class T> |
36 | | It greatest_lower_bound( It beg, It end, T const& value ) |
37 | 11.9k | { |
38 | 11.9k | It it = std::upper_bound( beg, end, value ); |
39 | 11.9k | if( it != beg ) --it; |
40 | 11.9k | return it; |
41 | 11.9k | } matroska_segment_seeker.cpp:std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*> (anonymous namespace)::greatest_lower_bound<std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>, mkv::SegmentSeeker::Seekpoint>(std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>, std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>, mkv::SegmentSeeker::Seekpoint const&) Line | Count | Source | 37 | 5.88k | { | 38 | 5.88k | It it = std::upper_bound( beg, end, value ); | 39 | 5.88k | if( it != beg ) --it; | 40 | 5.88k | return it; | 41 | 5.88k | } |
matroska_segment_seeker.cpp:std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*> (anonymous namespace)::greatest_lower_bound<std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*>, mkv::SegmentSeeker::Range>(std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*>, std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*>, mkv::SegmentSeeker::Range const&) Line | Count | Source | 37 | 2.11k | { | 38 | 2.11k | It it = std::upper_bound( beg, end, value ); | 39 | 2.11k | if( it != beg ) --it; | 40 | 2.11k | return it; | 41 | 2.11k | } |
matroska_segment_seeker.cpp:std::__1::__wrap_iter<unsigned long*> (anonymous namespace)::greatest_lower_bound<std::__1::__wrap_iter<unsigned long*>, unsigned long>(std::__1::__wrap_iter<unsigned long*>, std::__1::__wrap_iter<unsigned long*>, unsigned long const&) Line | Count | Source | 37 | 3.91k | { | 38 | 3.91k | It it = std::upper_bound( beg, end, value ); | 39 | 3.91k | if( it != beg ) --it; | 40 | 3.91k | return it; | 41 | 3.91k | } |
|
42 | | |
43 | | // std::prev and std::next exists in C++11, in order to avoid ambiguity due |
44 | | // to ADL and iterators being defined within namespace std, these two |
45 | | // function-names have been postfixed with an underscore. |
46 | | |
47 | 28.4k | template<class It> It prev_( It it ) { return --it; } |
48 | 76.0k | template<class It> It next_( It it ) { return ++it; }matroska_segment_seeker.cpp:std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, std::__1::__tree_node<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, void*>*, long> > (anonymous namespace)::next_<std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, std::__1::__tree_node<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, void*>*, long> > >(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, std::__1::__tree_node<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, void*>*, long> >) Line | Count | Source | 48 | 73.9k | template<class It> It next_( It it ) { return ++it; } |
matroska_segment_seeker.cpp:std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*> (anonymous namespace)::next_<std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*> >(std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>) Line | Count | Source | 48 | 2.15k | template<class It> It next_( It it ) { return ++it; } |
|
49 | | } |
50 | | |
51 | | namespace mkv { |
52 | | |
53 | | SegmentSeeker::cluster_positions_t::iterator |
54 | | SegmentSeeker::add_cluster_position( fptr_t fpos ) |
55 | 58.9k | { |
56 | 58.9k | cluster_positions_t::iterator insertion_point = std::upper_bound( |
57 | 58.9k | _cluster_positions.begin(), |
58 | 58.9k | _cluster_positions.end(), |
59 | 58.9k | fpos |
60 | 58.9k | ); |
61 | | |
62 | 58.9k | return _cluster_positions.insert( insertion_point, fpos ); |
63 | 58.9k | } |
64 | | |
65 | | SegmentSeeker::cluster_map_t::iterator |
66 | | SegmentSeeker::add_cluster( KaxCluster * const p_cluster ) |
67 | 49.4k | { |
68 | 49.4k | Cluster cinfo = { |
69 | 49.4k | /* fpos */ p_cluster->GetElementPosition(), |
70 | 49.4k | /* pts */ vlc_tick_t( VLC_TICK_FROM_NS( p_cluster->GlobalTimestamp() ) ), |
71 | 49.4k | /* duration */ vlc_tick_t( -1 ), |
72 | 49.4k | /* size */ p_cluster->IsFiniteSize() |
73 | 49.4k | ? p_cluster->GetEndPosition() - p_cluster->GetElementPosition() |
74 | 49.4k | : UINT64_MAX |
75 | 49.4k | }; |
76 | | |
77 | 49.4k | add_cluster_position( cinfo.fpos ); |
78 | | |
79 | 49.4k | cluster_map_t::iterator it = _clusters.lower_bound( cinfo.pts ); |
80 | | |
81 | 49.4k | if( it != _clusters.end() && it->second.pts == cinfo.pts ) |
82 | 45.3k | { |
83 | | // cluster already known |
84 | 45.3k | } |
85 | 4.11k | else |
86 | 4.11k | { |
87 | 4.11k | it = _clusters.insert( cluster_map_t::value_type( cinfo.pts, cinfo ) ).first; |
88 | 4.11k | } |
89 | | |
90 | | // ------------------------------------------------------------------ |
91 | | // IF we have two adjecent clusters, update duration where applicable |
92 | | // ------------------------------------------------------------------ |
93 | | |
94 | 49.4k | struct Duration { |
95 | 49.4k | static void fix( Cluster& prev, Cluster& next ) |
96 | 52.8k | { |
97 | 52.8k | if( ( prev.fpos + prev.size) == next.fpos ) |
98 | 1.49k | prev.duration = next.pts - prev.pts; |
99 | 52.8k | } |
100 | 49.4k | }; |
101 | | |
102 | 49.4k | if( it != _clusters.begin() ) |
103 | 28.4k | { |
104 | 28.4k | Duration::fix( prev_( it )->second, it->second ); |
105 | 28.4k | } |
106 | | |
107 | 49.4k | if( it != _clusters.end() && next_( it ) != _clusters.end() ) |
108 | 24.4k | { |
109 | 24.4k | Duration::fix( it->second, next_( it )->second ); |
110 | 24.4k | } |
111 | | |
112 | 49.4k | return it; |
113 | 49.4k | } |
114 | | |
115 | | void |
116 | | SegmentSeeker::add_seekpoint( track_id_t track_id, Seekpoint sp ) |
117 | 28.1k | { |
118 | 28.1k | seekpoints_t& seekpoints = _tracks_seekpoints[ track_id ]; |
119 | 28.1k | seekpoints_t::iterator it = std::lower_bound( seekpoints.begin(), seekpoints.end(), sp ); |
120 | | |
121 | 28.1k | if( it != seekpoints.end() && it->fpos == sp.fpos ) |
122 | 865 | { |
123 | 865 | if (sp.trust_level <= it->trust_level) |
124 | 863 | return; |
125 | | |
126 | 2 | *it = sp; |
127 | 2 | } |
128 | 27.2k | else if( it != seekpoints.end() && it->pts == sp.pts ) |
129 | 18.1k | { |
130 | 18.1k | if (sp.trust_level <= it->trust_level) |
131 | 17.9k | return; |
132 | | |
133 | 215 | *it = sp; |
134 | 215 | } |
135 | 9.16k | else |
136 | 9.16k | { |
137 | 9.16k | seekpoints.insert( it, sp ); |
138 | 9.16k | } |
139 | 28.1k | } |
140 | | |
141 | | SegmentSeeker::tracks_seekpoint_t |
142 | | SegmentSeeker::find_greatest_seekpoints_in_range( fptr_t start_fpos, vlc_tick_t end_pts, track_ids_t const& filter_tracks ) |
143 | 2.13k | { |
144 | 2.13k | tracks_seekpoint_t tpoints; |
145 | | |
146 | 5.90k | for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it ) |
147 | 3.76k | { |
148 | 3.76k | if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() ) |
149 | 42 | continue; |
150 | | |
151 | 3.72k | Seekpoint sp = get_first_seekpoint_around( end_pts, it->second ); |
152 | | |
153 | 3.72k | if( sp.fpos < start_fpos ) |
154 | 13 | continue; |
155 | | |
156 | 3.71k | if( sp.pts > end_pts ) |
157 | 0 | continue; |
158 | | |
159 | 3.71k | tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) ); |
160 | 3.71k | } |
161 | | |
162 | 2.13k | if (tpoints.empty()) |
163 | 7 | { |
164 | | // try a further pts |
165 | 14 | for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it ) |
166 | 7 | { |
167 | 7 | if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() ) |
168 | 0 | continue; |
169 | | |
170 | 7 | Seekpoint sp = get_first_seekpoint_around( end_pts, it->second ); |
171 | | |
172 | 7 | if( sp.fpos < start_fpos ) |
173 | 7 | continue; |
174 | | |
175 | 0 | tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) ); |
176 | 0 | } |
177 | 7 | } |
178 | | |
179 | 2.13k | return tpoints; |
180 | 2.13k | } |
181 | | |
182 | | SegmentSeeker::Seekpoint |
183 | | SegmentSeeker::get_first_seekpoint_around( vlc_tick_t pts, seekpoints_t const& seekpoints, |
184 | | Seekpoint::TrustLevel trust_level ) |
185 | 3.73k | { |
186 | 3.73k | if( seekpoints.empty() ) |
187 | 0 | { |
188 | 0 | return Seekpoint(); |
189 | 0 | } |
190 | | |
191 | 3.73k | typedef seekpoints_t::const_iterator iterator; |
192 | | |
193 | 3.73k | Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts ); |
194 | | |
195 | 3.73k | iterator const it_begin = seekpoints.begin(); |
196 | 3.73k | iterator const it_end = seekpoints.end(); |
197 | 3.73k | iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle ); |
198 | | |
199 | 3.73k | iterator it_before; |
200 | | |
201 | | // rewrind to _previous_ seekpoint with appropriate trust |
202 | 3.75k | for( it_before = it_middle; it_before != it_begin; --it_before ) |
203 | 1.22k | { |
204 | 1.22k | if( it_before->trust_level >= trust_level ) |
205 | 1.19k | return *it_before; |
206 | 1.22k | } |
207 | 2.53k | return *it_begin; |
208 | 3.73k | } |
209 | | |
210 | | SegmentSeeker::seekpoint_pair_t |
211 | | SegmentSeeker::get_seekpoints_around( vlc_tick_t pts, seekpoints_t const& seekpoints ) |
212 | 2.15k | { |
213 | 2.15k | if( seekpoints.empty() ) |
214 | 0 | { |
215 | 0 | return seekpoint_pair_t(); |
216 | 0 | } |
217 | | |
218 | 2.15k | typedef seekpoints_t::const_iterator iterator; |
219 | | |
220 | 2.15k | Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts ); |
221 | | |
222 | 2.15k | iterator const it_begin = seekpoints.begin(); |
223 | 2.15k | iterator const it_end = seekpoints.end(); |
224 | 2.15k | iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle ); |
225 | | |
226 | 2.15k | if ( it_middle != it_end && (*it_middle).pts > pts) |
227 | | // found nothing low enough, use the first one |
228 | 0 | return seekpoint_pair_t( *it_begin, Seekpoint() ); |
229 | | |
230 | 2.15k | iterator it_before = it_middle; |
231 | 2.15k | iterator it_after = it_middle == it_end ? it_middle : next_( it_middle ) ; |
232 | | |
233 | 2.15k | return seekpoint_pair_t( *it_before, |
234 | 2.15k | it_after == it_end ? Seekpoint() : *it_after |
235 | 2.15k | ); |
236 | 2.15k | } |
237 | | |
238 | | SegmentSeeker::seekpoint_pair_t |
239 | | SegmentSeeker::get_seekpoints_around( vlc_tick_t target_pts, track_ids_t const& priority_tracks ) |
240 | 2.14k | { |
241 | 2.14k | seekpoint_pair_t points; |
242 | | |
243 | 2.14k | if( _tracks_seekpoints.empty() ) |
244 | 14 | return points; |
245 | | |
246 | 2.13k | { // locate the max/min seekpoints for priority_tracks // |
247 | | |
248 | 2.13k | typedef track_ids_t::const_iterator track_iterator; |
249 | | |
250 | 2.13k | track_iterator const begin = priority_tracks.begin(); |
251 | 2.13k | track_iterator const end = priority_tracks.end(); |
252 | | |
253 | 4.28k | for( track_iterator it = begin; it != end; ++it ) |
254 | 2.15k | { |
255 | 2.15k | seekpoint_pair_t track_points = get_seekpoints_around( target_pts, _tracks_seekpoints[ *it ] ); |
256 | | |
257 | 2.15k | if( it == begin ) { |
258 | 2.13k | points = track_points; |
259 | 2.13k | continue; |
260 | 2.13k | } |
261 | | |
262 | 21 | if( track_points.first.trust_level > Seekpoint::DISABLED && |
263 | 21 | points.first.fpos > track_points.first.fpos ) |
264 | 0 | points.first = track_points.first; |
265 | | |
266 | 21 | if( track_points.second.trust_level > Seekpoint::DISABLED && |
267 | 0 | points.second.fpos < track_points.second.fpos ) |
268 | 0 | points.second = track_points.second; |
269 | 21 | } |
270 | 2.13k | } |
271 | | |
272 | 2.13k | { // check if we got a cluster which is closer to target_pts than the found cues // |
273 | | |
274 | 2.13k | cluster_map_t::iterator it = _clusters.lower_bound( target_pts ); |
275 | | |
276 | 2.13k | if( it != _clusters.begin() && --it != _clusters.end() ) |
277 | 33 | { |
278 | 33 | Cluster const& cluster = it->second; |
279 | | |
280 | 33 | if( cluster.fpos > points.first.fpos ) |
281 | 11 | { |
282 | 11 | points.first = Seekpoint( cluster.fpos, cluster.pts ); |
283 | | |
284 | | // do we need to update the max point? // |
285 | | |
286 | 11 | if( points.second.fpos < points.first.fpos ) |
287 | 0 | points.second = Seekpoint( cluster.fpos + cluster.size, cluster.pts + cluster.duration ); |
288 | 11 | } |
289 | 33 | } |
290 | 2.13k | } |
291 | | |
292 | 2.13k | return points; |
293 | 2.14k | } |
294 | | |
295 | | SegmentSeeker::tracks_seekpoint_t |
296 | | SegmentSeeker::get_seekpoints( matroska_segment_c& ms, vlc_tick_t target_pts, |
297 | | track_ids_t const& priority_tracks, track_ids_t const& filter_tracks ) |
298 | 2.14k | { |
299 | 2.14k | struct contains_all_of_t { |
300 | 2.14k | bool operator()( tracks_seekpoint_t const& haystack, track_ids_t const& track_ids ) |
301 | 2.14k | { |
302 | 4.28k | for( track_ids_t::const_iterator it = track_ids.begin(); it != track_ids.end(); ++it ) { |
303 | 2.15k | if( haystack.find( *it ) == haystack.end() ) |
304 | 8 | return false; |
305 | 2.15k | } |
306 | | |
307 | 2.12k | return true; |
308 | 2.13k | } |
309 | 2.14k | }; |
310 | | |
311 | 2.14k | for( vlc_tick_t needle_pts = target_pts; ; ) |
312 | 2.14k | { |
313 | 2.14k | seekpoint_pair_t seekpoints = get_seekpoints_around( needle_pts, priority_tracks ); |
314 | | |
315 | 2.14k | Seekpoint const& start = seekpoints.first; |
316 | 2.14k | Seekpoint const& end = seekpoints.second; |
317 | | |
318 | 2.14k | if ( start.fpos == std::numeric_limits<fptr_t>::max() ) |
319 | 14 | return tracks_seekpoint_t(); |
320 | | |
321 | 2.13k | if ( ms.sys.b_fastseekable && |
322 | 2.13k | (end.fpos != std::numeric_limits<fptr_t>::max() || !ms.b_cues) && |
323 | 2.11k | (needle_pts != start.pts || start.trust_level < Seekpoint::TRUSTED)) |
324 | | // do not read the whole (infinite?) file to get seek indexes |
325 | | // do not generate an index if we already have the correct seekpoint |
326 | 2.11k | index_range( ms, Range( start.fpos, end.fpos ), needle_pts ); |
327 | | |
328 | 2.13k | tracks_seekpoint_t tpoints = find_greatest_seekpoints_in_range( start.fpos, target_pts, filter_tracks ); |
329 | | |
330 | 2.13k | if( contains_all_of_t() ( tpoints, priority_tracks ) ) |
331 | 2.12k | return tpoints; |
332 | | |
333 | | // Avoid busyloop, don't iterate on the same seekpoint |
334 | 8 | if( needle_pts == start.pts - 1 ) |
335 | | // we found the same needle twice, stop looking |
336 | 0 | return tpoints; |
337 | | |
338 | 8 | needle_pts = start.pts - 1; |
339 | 8 | } |
340 | | |
341 | 0 | vlc_assert_unreachable(); |
342 | 0 | } |
343 | | |
344 | | void |
345 | | SegmentSeeker::index_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts ) |
346 | 2.11k | { |
347 | 2.11k | ranges_t areas_to_search = get_search_areas( search_area.start, search_area.end ); |
348 | | |
349 | 4.23k | for( ranges_t::const_iterator range_it = areas_to_search.begin(); range_it != areas_to_search.end(); ++range_it ) |
350 | 2.11k | index_unsearched_range( ms, *range_it, max_pts ); |
351 | 2.11k | } |
352 | | |
353 | | void |
354 | | SegmentSeeker::index_unsearched_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts ) |
355 | 2.11k | { |
356 | 2.11k | mkv_jump_to( ms, search_area.start ); |
357 | | |
358 | 2.11k | search_area.start = ms.es.I_O().getFilePointer(); |
359 | | |
360 | 2.11k | fptr_t block_pos = search_area.start; |
361 | 2.11k | vlc_tick_t block_pts; |
362 | | |
363 | 7.80k | while( block_pos < search_area.end ) |
364 | 7.80k | { |
365 | 7.80k | KaxBlock * block; |
366 | 7.80k | KaxSimpleBlock * simpleblock; |
367 | 7.80k | KaxBlockAdditions *additions; |
368 | | |
369 | 7.80k | bool b_key_picture; |
370 | 7.80k | bool b_discardable_picture; |
371 | 7.80k | int64_t i_block_duration; |
372 | 7.80k | track_id_t track_id; |
373 | | |
374 | 7.80k | if( ms.BlockGet( block, simpleblock, additions, |
375 | 7.80k | &b_key_picture, &b_discardable_picture, &i_block_duration ) ) |
376 | 86 | { |
377 | 86 | delete additions; |
378 | 86 | break; |
379 | 86 | } |
380 | 7.71k | delete additions; |
381 | | |
382 | 7.71k | KaxInternalBlock& internal_block = simpleblock |
383 | 7.71k | ? static_cast<KaxInternalBlock&>( *simpleblock ) |
384 | 7.71k | : static_cast<KaxInternalBlock&>( *block ); |
385 | | |
386 | 7.71k | block_pos = internal_block.GetElementPosition(); |
387 | 7.71k | block_pts = VLC_TICK_FROM_NS(internal_block.GlobalTimestamp()); |
388 | 7.71k | track_id = internal_block.TrackNum(); |
389 | | |
390 | 7.71k | bool const b_valid_track = ms.FindTrackByBlock( block, simpleblock ) != NULL; |
391 | | |
392 | 7.71k | delete block; |
393 | | |
394 | 7.71k | if( b_valid_track ) |
395 | 7.71k | { |
396 | 7.71k | if( b_key_picture ) |
397 | 6.36k | add_seekpoint( track_id, Seekpoint( block_pos, block_pts ) ); |
398 | | |
399 | 7.71k | if( max_pts < block_pts ) |
400 | 2.03k | break; |
401 | 7.71k | } |
402 | 7.71k | } |
403 | | |
404 | 2.11k | search_area.end = ms.es.I_O().getFilePointer(); |
405 | | |
406 | 2.11k | mark_range_as_searched( search_area ); |
407 | 2.11k | } |
408 | | |
409 | | void |
410 | | SegmentSeeker::mark_range_as_searched( Range data ) |
411 | 10.2k | { |
412 | | /* TODO: this is utterly ugly, we should do the insertion in-place */ |
413 | | |
414 | 10.2k | _ranges_searched.insert( std::upper_bound( _ranges_searched.begin(), _ranges_searched.end(), data ), data ); |
415 | | |
416 | 10.2k | { |
417 | 10.2k | ranges_t merged; |
418 | | |
419 | 28.7k | for( ranges_t::iterator it = _ranges_searched.begin(); it != _ranges_searched.end(); ++it ) |
420 | 18.4k | { |
421 | 18.4k | if( merged.size() ) |
422 | 8.18k | { |
423 | 8.18k | Range& last_entry = *merged.rbegin(); |
424 | | |
425 | 8.18k | if( last_entry.end+1 >= it->start && last_entry.end < it->end ) |
426 | 3.49k | { |
427 | 3.49k | last_entry.end = it->end; |
428 | 3.49k | continue; |
429 | 3.49k | } |
430 | | |
431 | 4.68k | if( it->start >= last_entry.start && it->end <= last_entry.end ) |
432 | 4.66k | { |
433 | 4.66k | last_entry.end = std::max( last_entry.end, it->end ); |
434 | 4.66k | continue; |
435 | 4.66k | } |
436 | 4.68k | } |
437 | | |
438 | 10.2k | merged.push_back( *it ); |
439 | 10.2k | } |
440 | | |
441 | 10.2k | _ranges_searched = std::move(merged); |
442 | 10.2k | } |
443 | 10.2k | } |
444 | | |
445 | | |
446 | | SegmentSeeker::ranges_t |
447 | | SegmentSeeker::get_search_areas( fptr_t start, fptr_t end ) const |
448 | 2.11k | { |
449 | 2.11k | ranges_t areas_to_search; |
450 | 2.11k | Range needle ( start, end ); |
451 | | |
452 | 2.11k | ranges_t::const_iterator it = greatest_lower_bound( _ranges_searched.begin(), _ranges_searched.end(), needle ); |
453 | | |
454 | 2.14k | for( ; it != _ranges_searched.end() && needle.start < needle.end; ++it ) |
455 | 32 | { |
456 | 32 | if( needle.start < it->start ) |
457 | 2 | { |
458 | 2 | areas_to_search.push_back( Range( needle.start, it->start ) ); |
459 | 2 | } |
460 | | |
461 | 32 | if( needle.start <= it->end ) |
462 | 28 | needle.start = it->end + 1; |
463 | 32 | } |
464 | | |
465 | 2.11k | needle.start = std::max( needle.start, start ); |
466 | 2.11k | if( it == _ranges_searched.end() && needle.start < needle.end ) |
467 | 2.11k | { |
468 | 2.11k | areas_to_search.push_back( needle ); |
469 | 2.11k | } |
470 | | |
471 | 2.11k | return areas_to_search; |
472 | 2.11k | } |
473 | | |
474 | | void |
475 | | SegmentSeeker::mkv_jump_to( matroska_segment_c& ms, fptr_t fpos ) |
476 | 4.24k | { |
477 | 4.24k | fptr_t i_cluster_pos = -1; |
478 | | |
479 | 4.24k | if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() ) |
480 | 4.24k | { |
481 | 4.24k | if ( !_cluster_positions.empty() ) |
482 | 3.91k | { |
483 | 3.91k | cluster_positions_t::iterator cluster_it = greatest_lower_bound( |
484 | 3.91k | _cluster_positions.begin(), _cluster_positions.end(), fpos |
485 | 3.91k | ); |
486 | | |
487 | 3.91k | ms.es.I_O().setFilePointer( *cluster_it ); |
488 | 3.91k | ms.ep.reconstruct( &ms.es, ms.segment, &ms.sys.demuxer ); |
489 | | |
490 | 3.91k | for(;;) |
491 | 4.28k | { |
492 | 4.28k | ms.cluster = NULL; |
493 | 4.28k | EbmlElement *el = ms.ep.Get(); |
494 | 4.28k | if( el == nullptr ) |
495 | 10 | { |
496 | 10 | msg_Err( &ms.sys.demuxer, "unable to read KaxCluster during seek, giving up" ); |
497 | 10 | return; |
498 | 10 | } |
499 | 4.27k | if (!MKV_IS_ID( el, KaxCluster )) |
500 | 365 | { |
501 | 365 | ms.cluster = nullptr; // the previous cluster found is not valid anymore |
502 | 365 | continue; // look for the next element |
503 | 365 | } |
504 | | |
505 | 3.91k | ms.cluster = static_cast<KaxCluster*>( el ); |
506 | | |
507 | 3.91k | i_cluster_pos = ms.cluster->GetElementPosition(); |
508 | | |
509 | 3.91k | add_cluster_position( i_cluster_pos ); |
510 | | |
511 | 3.91k | mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) ); |
512 | | |
513 | 3.91k | if ( !ms.cluster->IsFiniteSize() || ms.cluster->GetEndPosition() >= fpos) |
514 | 3.90k | break; |
515 | 3.91k | } |
516 | 3.91k | } |
517 | 4.24k | } |
518 | 0 | else if (ms.cluster != NULL) |
519 | 0 | { |
520 | | // make sure we start reading after the Cluster start |
521 | 0 | ms.es.I_O().setFilePointer(ms.cluster->GetDataStart()); |
522 | 0 | } |
523 | | |
524 | 4.24k | assert(ms.ep.GetLevel() == 1); |
525 | 4.23k | ms.ep.Down(); |
526 | | |
527 | | /* read until cluster/timecode to initialize cluster */ |
528 | | |
529 | 4.27k | while( EbmlElement * el = ms.ep.Get() ) |
530 | 3.93k | { |
531 | 3.93k | try { |
532 | 3.93k | if( MKV_CHECKED_PTR_DECL( p_tc, KaxClusterTimestamp, el ) ) |
533 | 3.89k | { |
534 | 3.89k | p_tc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA ); |
535 | 3.89k | ms.cluster->InitTimestamp( static_cast<uint64_t>( *p_tc ), ms.i_timescale ); |
536 | 3.89k | add_cluster(ms.cluster); |
537 | 3.89k | break; |
538 | 3.89k | } |
539 | 37 | else if( MKV_CHECKED_PTR_DECL( crc, EbmlCrc32, el ) ) |
540 | 31 | { |
541 | 31 | crc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA ); /* avoid a skip that may fail */ |
542 | 31 | } |
543 | 3.93k | } |
544 | 3.93k | catch(...) |
545 | 3.93k | { |
546 | 0 | msg_Err( &ms.sys.demuxer,"Error while reading %s", EBML_NAME(el) ); |
547 | 0 | } |
548 | 3.93k | } |
549 | | |
550 | | /* TODO: add error handling; what if we never get a KaxCluster and/or KaxClusterTimestamp? */ |
551 | | |
552 | 4.23k | mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) ); |
553 | | |
554 | | /* jump to desired position */ |
555 | | |
556 | 4.23k | if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() ) |
557 | 4.23k | ms.es.I_O().setFilePointer( fpos ); |
558 | 4.23k | } |
559 | | |
560 | | } // namespace |