/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 | 21.0k | { |
38 | 21.0k | It it = std::upper_bound( beg, end, value ); |
39 | 21.0k | if( it != beg ) --it; |
40 | 21.0k | return it; |
41 | 21.0k | } 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 | 11.8k | { | 38 | 11.8k | It it = std::upper_bound( beg, end, value ); | 39 | 11.8k | if( it != beg ) --it; | 40 | 11.8k | return it; | 41 | 11.8k | } |
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 | 3.77k | { | 38 | 3.77k | It it = std::upper_bound( beg, end, value ); | 39 | 3.77k | if( it != beg ) --it; | 40 | 3.77k | return it; | 41 | 3.77k | } |
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 | 5.43k | { | 38 | 5.43k | It it = std::upper_bound( beg, end, value ); | 39 | 5.43k | if( it != beg ) --it; | 40 | 5.43k | return it; | 41 | 5.43k | } |
|
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 | 10.6k | template<class It> It prev_( It it ) { return --it; } |
48 | 37.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 | 32.4k | 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 | 4.58k | 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 | 76.2k | { |
56 | 76.2k | cluster_positions_t::iterator insertion_point = std::upper_bound( |
57 | 76.2k | _cluster_positions.begin(), |
58 | 76.2k | _cluster_positions.end(), |
59 | 76.2k | fpos |
60 | 76.2k | ); |
61 | | |
62 | 76.2k | return _cluster_positions.insert( insertion_point, fpos ); |
63 | 76.2k | } |
64 | | |
65 | | SegmentSeeker::cluster_map_t::iterator |
66 | | SegmentSeeker::add_cluster( KaxCluster * const p_cluster ) |
67 | 22.0k | { |
68 | 22.0k | Cluster cinfo = { |
69 | 22.0k | /* fpos */ p_cluster->GetElementPosition(), |
70 | 22.0k | /* pts */ vlc_tick_t( VLC_TICK_FROM_NS( p_cluster->GlobalTimestamp() ) ), |
71 | 22.0k | /* duration */ vlc_tick_t( -1 ), |
72 | 22.0k | /* size */ p_cluster->IsFiniteSize() |
73 | 22.0k | ? p_cluster->GetEndPosition() - p_cluster->GetElementPosition() |
74 | 22.0k | : UINT64_MAX |
75 | 22.0k | }; |
76 | | |
77 | 22.0k | add_cluster_position( cinfo.fpos ); |
78 | | |
79 | 22.0k | cluster_map_t::iterator it = _clusters.lower_bound( cinfo.pts ); |
80 | | |
81 | 22.0k | if( it != _clusters.end() && it->second.pts == cinfo.pts ) |
82 | 16.5k | { |
83 | | // cluster already known |
84 | 16.5k | } |
85 | 5.47k | else |
86 | 5.47k | { |
87 | 5.47k | it = _clusters.insert( cluster_map_t::value_type( cinfo.pts, cinfo ) ).first; |
88 | 5.47k | } |
89 | | |
90 | | // ------------------------------------------------------------------ |
91 | | // IF we have two adjecent clusters, update duration where applicable |
92 | | // ------------------------------------------------------------------ |
93 | | |
94 | 22.0k | struct Duration { |
95 | 22.0k | static void fix( Cluster& prev, Cluster& next ) |
96 | 22.0k | { |
97 | 21.0k | if( ( prev.fpos + prev.size) == next.fpos ) |
98 | 1.43k | prev.duration = next.pts - prev.pts; |
99 | 21.0k | } |
100 | 22.0k | }; |
101 | | |
102 | 22.0k | if( it != _clusters.begin() ) |
103 | 10.6k | { |
104 | 10.6k | Duration::fix( prev_( it )->second, it->second ); |
105 | 10.6k | } |
106 | | |
107 | 22.0k | if( it != _clusters.end() && next_( it ) != _clusters.end() ) |
108 | 10.4k | { |
109 | 10.4k | Duration::fix( it->second, next_( it )->second ); |
110 | 10.4k | } |
111 | | |
112 | 22.0k | return it; |
113 | 22.0k | } |
114 | | |
115 | | void |
116 | | SegmentSeeker::add_seekpoint( track_id_t track_id, Seekpoint sp ) |
117 | 46.5k | { |
118 | 46.5k | seekpoints_t& seekpoints = _tracks_seekpoints[ track_id ]; |
119 | 46.5k | seekpoints_t::iterator it = std::lower_bound( seekpoints.begin(), seekpoints.end(), sp ); |
120 | | |
121 | 46.5k | if( it != seekpoints.end() && it->fpos == sp.fpos ) |
122 | 16.7k | { |
123 | 16.7k | if (sp.trust_level <= it->trust_level) |
124 | 16.7k | return; |
125 | | |
126 | 7 | *it = sp; |
127 | 7 | } |
128 | 29.7k | else if( it != seekpoints.end() && it->pts == sp.pts ) |
129 | 8.12k | { |
130 | 8.12k | if (sp.trust_level <= it->trust_level) |
131 | 7.89k | return; |
132 | | |
133 | 234 | *it = sp; |
134 | 234 | } |
135 | 21.6k | else |
136 | 21.6k | { |
137 | 21.6k | seekpoints.insert( it, sp ); |
138 | 21.6k | } |
139 | 46.5k | } |
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 | 4.16k | { |
144 | 4.16k | tracks_seekpoint_t tpoints; |
145 | | |
146 | 11.5k | for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it ) |
147 | 7.34k | { |
148 | 7.34k | if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() ) |
149 | 1.27k | continue; |
150 | | |
151 | 6.07k | Seekpoint sp = get_first_seekpoint_around( end_pts, it->second ); |
152 | | |
153 | 6.07k | if( sp.fpos < start_fpos ) |
154 | 1.17k | continue; |
155 | | |
156 | 4.89k | if( sp.pts > end_pts ) |
157 | 77 | continue; |
158 | | |
159 | 4.82k | tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) ); |
160 | 4.82k | } |
161 | | |
162 | 4.16k | if (tpoints.empty()) |
163 | 985 | { |
164 | | // try a further pts |
165 | 2.58k | for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it ) |
166 | 1.59k | { |
167 | 1.59k | if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() ) |
168 | 482 | continue; |
169 | | |
170 | 1.11k | Seekpoint sp = get_first_seekpoint_around( end_pts, it->second ); |
171 | | |
172 | 1.11k | if( sp.fpos < start_fpos ) |
173 | 1.06k | continue; |
174 | | |
175 | 51 | tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) ); |
176 | 51 | } |
177 | 985 | } |
178 | | |
179 | 4.16k | return tpoints; |
180 | 4.16k | } |
181 | | |
182 | | SegmentSeeker::Seekpoint |
183 | | SegmentSeeker::get_first_seekpoint_around( vlc_tick_t pts, seekpoints_t const& seekpoints, |
184 | | Seekpoint::TrustLevel trust_level ) |
185 | 7.19k | { |
186 | 7.19k | if( seekpoints.empty() ) |
187 | 56 | { |
188 | 56 | return Seekpoint(); |
189 | 56 | } |
190 | | |
191 | 7.13k | typedef seekpoints_t::const_iterator iterator; |
192 | | |
193 | 7.13k | Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts ); |
194 | | |
195 | 7.13k | iterator const it_begin = seekpoints.begin(); |
196 | 7.13k | iterator const it_end = seekpoints.end(); |
197 | 7.13k | iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle ); |
198 | | |
199 | 7.13k | iterator it_before; |
200 | | |
201 | | // rewrind to _previous_ seekpoint with appropriate trust |
202 | 22.9k | for( it_before = it_middle; it_before != it_begin; --it_before ) |
203 | 17.3k | { |
204 | 17.3k | if( it_before->trust_level >= trust_level ) |
205 | 1.53k | return *it_before; |
206 | 17.3k | } |
207 | 5.60k | return *it_begin; |
208 | 7.13k | } |
209 | | |
210 | | SegmentSeeker::seekpoint_pair_t |
211 | | SegmentSeeker::get_seekpoints_around( vlc_tick_t pts, seekpoints_t const& seekpoints ) |
212 | 4.78k | { |
213 | 4.78k | if( seekpoints.empty() ) |
214 | 89 | { |
215 | 89 | return seekpoint_pair_t(); |
216 | 89 | } |
217 | | |
218 | 4.69k | typedef seekpoints_t::const_iterator iterator; |
219 | | |
220 | 4.69k | Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts ); |
221 | | |
222 | 4.69k | iterator const it_begin = seekpoints.begin(); |
223 | 4.69k | iterator const it_end = seekpoints.end(); |
224 | 4.69k | iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle ); |
225 | | |
226 | 4.69k | if ( it_middle != it_end && (*it_middle).pts > pts) |
227 | | // found nothing low enough, use the first one |
228 | 109 | return seekpoint_pair_t( *it_begin, Seekpoint() ); |
229 | | |
230 | 4.58k | iterator it_before = it_middle; |
231 | 4.58k | iterator it_after = it_middle == it_end ? it_middle : next_( it_middle ) ; |
232 | | |
233 | 4.58k | return seekpoint_pair_t( *it_before, |
234 | 4.58k | it_after == it_end ? Seekpoint() : *it_after |
235 | 4.58k | ); |
236 | 4.69k | } |
237 | | |
238 | | SegmentSeeker::seekpoint_pair_t |
239 | | SegmentSeeker::get_seekpoints_around( vlc_tick_t target_pts, track_ids_t const& priority_tracks ) |
240 | 8.10k | { |
241 | 8.10k | seekpoint_pair_t points; |
242 | | |
243 | 8.10k | if( _tracks_seekpoints.empty() ) |
244 | 3.66k | return points; |
245 | | |
246 | 4.43k | { // locate the max/min seekpoints for priority_tracks // |
247 | | |
248 | 4.43k | typedef track_ids_t::const_iterator track_iterator; |
249 | | |
250 | 4.43k | track_iterator const begin = priority_tracks.begin(); |
251 | 4.43k | track_iterator const end = priority_tracks.end(); |
252 | | |
253 | 9.21k | for( track_iterator it = begin; it != end; ++it ) |
254 | 4.78k | { |
255 | 4.78k | seekpoint_pair_t track_points = get_seekpoints_around( target_pts, _tracks_seekpoints[ *it ] ); |
256 | | |
257 | 4.78k | if( it == begin ) { |
258 | 4.18k | points = track_points; |
259 | 4.18k | continue; |
260 | 4.18k | } |
261 | | |
262 | 600 | if( track_points.first.trust_level > Seekpoint::DISABLED && |
263 | 557 | points.first.fpos > track_points.first.fpos ) |
264 | 87 | points.first = track_points.first; |
265 | | |
266 | 600 | if( track_points.second.trust_level > Seekpoint::DISABLED && |
267 | 111 | points.second.fpos < track_points.second.fpos ) |
268 | 39 | points.second = track_points.second; |
269 | 600 | } |
270 | 4.43k | } |
271 | | |
272 | 4.43k | { // check if we got a cluster which is closer to target_pts than the found cues // |
273 | | |
274 | 4.43k | cluster_map_t::iterator it = _clusters.lower_bound( target_pts ); |
275 | | |
276 | 4.43k | if( it != _clusters.begin() && --it != _clusters.end() ) |
277 | 667 | { |
278 | 667 | Cluster const& cluster = it->second; |
279 | | |
280 | 667 | if( cluster.fpos > points.first.fpos ) |
281 | 187 | { |
282 | 187 | points.first = Seekpoint( cluster.fpos, cluster.pts ); |
283 | | |
284 | | // do we need to update the max point? // |
285 | | |
286 | 187 | if( points.second.fpos < points.first.fpos ) |
287 | 23 | points.second = Seekpoint( cluster.fpos + cluster.size, cluster.pts + cluster.duration ); |
288 | 187 | } |
289 | 667 | } |
290 | 4.43k | } |
291 | | |
292 | 4.43k | return points; |
293 | 8.10k | } |
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 | 7.09k | { |
299 | 7.09k | struct contains_all_of_t { |
300 | 7.09k | bool operator()( tracks_seekpoint_t const& haystack, track_ids_t const& track_ids ) |
301 | 7.09k | { |
302 | 7.78k | for( track_ids_t::const_iterator it = track_ids.begin(); it != track_ids.end(); ++it ) { |
303 | 4.64k | if( haystack.find( *it ) == haystack.end() ) |
304 | 1.03k | return false; |
305 | 4.64k | } |
306 | | |
307 | 3.13k | return true; |
308 | 4.16k | } |
309 | 7.09k | }; |
310 | | |
311 | 7.09k | for( vlc_tick_t needle_pts = target_pts; ; ) |
312 | 8.10k | { |
313 | 8.10k | seekpoint_pair_t seekpoints = get_seekpoints_around( needle_pts, priority_tracks ); |
314 | | |
315 | 8.10k | Seekpoint const& start = seekpoints.first; |
316 | 8.10k | Seekpoint const& end = seekpoints.second; |
317 | | |
318 | 8.10k | if ( start.fpos == std::numeric_limits<fptr_t>::max() ) |
319 | 3.93k | return tracks_seekpoint_t(); |
320 | | |
321 | 4.16k | if ( (end.fpos != std::numeric_limits<fptr_t>::max() || !ms.b_cues) && |
322 | 3.78k | (needle_pts != start.pts || start.trust_level < Seekpoint::TRUSTED)) |
323 | | // do not read the whole (infinite?) file to get seek indexes |
324 | | // do not generate an index if we already have the correct seekpoint |
325 | 3.77k | index_range( ms, Range( start.fpos, end.fpos ), needle_pts ); |
326 | | |
327 | 4.16k | tracks_seekpoint_t tpoints = find_greatest_seekpoints_in_range( start.fpos, target_pts, filter_tracks ); |
328 | | |
329 | 4.16k | if( contains_all_of_t() ( tpoints, priority_tracks ) ) |
330 | 3.13k | return tpoints; |
331 | | |
332 | | // Avoid busyloop, don't iterate on the same seekpoint |
333 | 1.03k | if( needle_pts == start.pts - 1 ) |
334 | | // we found the same needle twice, stop looking |
335 | 29 | return tpoints; |
336 | | |
337 | 1.00k | needle_pts = start.pts - 1; |
338 | 1.00k | } |
339 | | |
340 | 0 | vlc_assert_unreachable(); |
341 | 0 | } |
342 | | |
343 | | void |
344 | | SegmentSeeker::index_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts ) |
345 | 3.77k | { |
346 | 3.77k | ranges_t areas_to_search = get_search_areas( search_area.start, search_area.end ); |
347 | | |
348 | 7.61k | for( ranges_t::const_iterator range_it = areas_to_search.begin(); range_it != areas_to_search.end(); ++range_it ) |
349 | 3.84k | index_unsearched_range( ms, *range_it, max_pts ); |
350 | 3.77k | } |
351 | | |
352 | | void |
353 | | SegmentSeeker::index_unsearched_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts ) |
354 | 3.84k | { |
355 | 3.84k | mkv_jump_to( ms, search_area.start ); |
356 | | |
357 | 3.84k | search_area.start = ms.es.I_O().getFilePointer(); |
358 | | |
359 | 3.84k | fptr_t block_pos = search_area.start; |
360 | 3.84k | vlc_tick_t block_pts; |
361 | | |
362 | 6.57k | while( block_pos < search_area.end ) |
363 | 6.37k | { |
364 | 6.37k | KaxBlock * block; |
365 | 6.37k | KaxSimpleBlock * simpleblock; |
366 | 6.37k | KaxBlockAdditions *additions; |
367 | | |
368 | 6.37k | bool b_key_picture; |
369 | 6.37k | bool b_discardable_picture; |
370 | 6.37k | int64_t i_block_duration; |
371 | 6.37k | track_id_t track_id; |
372 | | |
373 | 6.37k | if( ms.BlockGet( block, simpleblock, additions, |
374 | 6.37k | &b_key_picture, &b_discardable_picture, &i_block_duration ) ) |
375 | 2.47k | { |
376 | 2.47k | delete additions; |
377 | 2.47k | break; |
378 | 2.47k | } |
379 | 3.89k | delete additions; |
380 | | |
381 | 3.89k | KaxInternalBlock& internal_block = simpleblock |
382 | 3.89k | ? static_cast<KaxInternalBlock&>( *simpleblock ) |
383 | 3.89k | : static_cast<KaxInternalBlock&>( *block ); |
384 | | |
385 | 3.89k | block_pos = internal_block.GetElementPosition(); |
386 | 3.89k | block_pts = VLC_TICK_FROM_NS(internal_block.GlobalTimestamp()); |
387 | 3.89k | track_id = internal_block.TrackNum(); |
388 | | |
389 | 3.89k | bool const b_valid_track = ms.FindTrackByBlock( block, simpleblock ) != NULL; |
390 | | |
391 | 3.89k | delete block; |
392 | | |
393 | 3.89k | if( b_valid_track ) |
394 | 3.89k | { |
395 | 3.89k | if( b_key_picture ) |
396 | 2.02k | add_seekpoint( track_id, Seekpoint( block_pos, block_pts ) ); |
397 | | |
398 | 3.89k | if( max_pts < block_pts ) |
399 | 1.16k | break; |
400 | 3.89k | } |
401 | 3.89k | } |
402 | | |
403 | 3.84k | search_area.end = ms.es.I_O().getFilePointer(); |
404 | | |
405 | 3.84k | mark_range_as_searched( search_area ); |
406 | 3.84k | } |
407 | | |
408 | | void |
409 | | SegmentSeeker::mark_range_as_searched( Range data ) |
410 | 12.7k | { |
411 | | /* TODO: this is utterly ugly, we should do the insertion in-place */ |
412 | | |
413 | 12.7k | _ranges_searched.insert( std::upper_bound( _ranges_searched.begin(), _ranges_searched.end(), data ), data ); |
414 | | |
415 | 12.7k | { |
416 | 12.7k | ranges_t merged; |
417 | | |
418 | 37.2k | for( ranges_t::iterator it = _ranges_searched.begin(); it != _ranges_searched.end(); ++it ) |
419 | 24.4k | { |
420 | 24.4k | if( merged.size() ) |
421 | 11.6k | { |
422 | 11.6k | Range& last_entry = *merged.rbegin(); |
423 | | |
424 | 11.6k | if( last_entry.end+1 >= it->start && last_entry.end < it->end ) |
425 | 3.32k | { |
426 | 3.32k | last_entry.end = it->end; |
427 | 3.32k | continue; |
428 | 3.32k | } |
429 | | |
430 | 8.36k | if( it->start >= last_entry.start && it->end <= last_entry.end ) |
431 | 6.71k | { |
432 | 6.71k | last_entry.end = std::max( last_entry.end, it->end ); |
433 | 6.71k | continue; |
434 | 6.71k | } |
435 | 8.36k | } |
436 | | |
437 | 14.4k | merged.push_back( *it ); |
438 | 14.4k | } |
439 | | |
440 | 12.7k | _ranges_searched = std::move(merged); |
441 | 12.7k | } |
442 | 12.7k | } |
443 | | |
444 | | |
445 | | SegmentSeeker::ranges_t |
446 | | SegmentSeeker::get_search_areas( fptr_t start, fptr_t end ) const |
447 | 3.77k | { |
448 | 3.77k | ranges_t areas_to_search; |
449 | 3.77k | Range needle ( start, end ); |
450 | | |
451 | 3.77k | ranges_t::const_iterator it = greatest_lower_bound( _ranges_searched.begin(), _ranges_searched.end(), needle ); |
452 | | |
453 | 4.99k | for( ; it != _ranges_searched.end() && needle.start < needle.end; ++it ) |
454 | 1.22k | { |
455 | 1.22k | if( needle.start < it->start ) |
456 | 386 | { |
457 | 386 | areas_to_search.push_back( Range( needle.start, it->start ) ); |
458 | 386 | } |
459 | | |
460 | 1.22k | if( needle.start <= it->end ) |
461 | 803 | needle.start = it->end + 1; |
462 | 1.22k | } |
463 | | |
464 | 3.77k | needle.start = std::max( needle.start, start ); |
465 | 3.77k | if( it == _ranges_searched.end() && needle.start < needle.end ) |
466 | 3.45k | { |
467 | 3.45k | areas_to_search.push_back( needle ); |
468 | 3.45k | } |
469 | | |
470 | 3.77k | return areas_to_search; |
471 | 3.77k | } |
472 | | |
473 | | void |
474 | | SegmentSeeker::mkv_jump_to( matroska_segment_c& ms, fptr_t fpos ) |
475 | 6.98k | { |
476 | 6.98k | fptr_t i_cluster_pos = -1; |
477 | | |
478 | 6.98k | if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() ) |
479 | 6.98k | { |
480 | 6.98k | ms.cluster = NULL; |
481 | 6.98k | if ( !_cluster_positions.empty() ) |
482 | 5.43k | { |
483 | 5.43k | cluster_positions_t::iterator cluster_it = greatest_lower_bound( |
484 | 5.43k | _cluster_positions.begin(), _cluster_positions.end(), fpos |
485 | 5.43k | ); |
486 | | |
487 | 5.43k | ms.es.I_O().setFilePointer( *cluster_it ); |
488 | 5.43k | ms.ep.reconstruct( &ms.es, ms.segment, &ms.sys.demuxer ); |
489 | 5.43k | } |
490 | | |
491 | 21.5k | while( ms.cluster == NULL || ( |
492 | 4.50k | ms.cluster->IsFiniteSize() && ms.cluster->GetEndPosition() < fpos ) ) |
493 | 17.1k | { |
494 | 17.1k | EbmlElement *el = ms.ep.Get(); |
495 | 17.1k | if( el == nullptr ) |
496 | 2.56k | { |
497 | 2.56k | msg_Err( &ms.sys.demuxer, "unable to read KaxCluster during seek, giving up" ); |
498 | 2.56k | return; |
499 | 2.56k | } |
500 | 14.5k | if (!MKV_IS_ID( el, KaxCluster )) |
501 | 10.0k | continue; // look for the next element |
502 | | |
503 | 4.50k | ms.cluster = static_cast<KaxCluster*>( el ); |
504 | | |
505 | 4.50k | i_cluster_pos = ms.cluster->GetElementPosition(); |
506 | | |
507 | 4.50k | add_cluster_position( i_cluster_pos ); |
508 | | |
509 | 4.50k | mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) ); |
510 | 4.50k | } |
511 | 6.98k | } |
512 | 0 | else if (ms.cluster != NULL) |
513 | 0 | { |
514 | | // make sure we start reading after the Cluster start |
515 | 0 | ms.es.I_O().setFilePointer(ms.cluster->GetDataStart()); |
516 | 0 | } |
517 | | |
518 | 4.41k | ms.ep.Down(); |
519 | | |
520 | | /* read until cluster/timecode to initialize cluster */ |
521 | | |
522 | 5.30k | while( EbmlElement * el = ms.ep.Get() ) |
523 | 4.80k | { |
524 | 4.80k | try { |
525 | 4.80k | if( MKV_CHECKED_PTR_DECL( p_tc, KaxClusterTimestamp, el ) ) |
526 | 3.93k | { |
527 | 3.93k | p_tc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA ); |
528 | 3.93k | ms.cluster->InitTimestamp( static_cast<uint64_t>( *p_tc ), ms.i_timescale ); |
529 | 3.93k | add_cluster(ms.cluster); |
530 | 3.93k | break; |
531 | 3.93k | } |
532 | 865 | else if( MKV_CHECKED_PTR_DECL( crc, EbmlCrc32, el ) ) |
533 | 414 | { |
534 | 414 | crc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA ); /* avoid a skip that may fail */ |
535 | 414 | } |
536 | 4.80k | } |
537 | 4.80k | catch(...) |
538 | 4.80k | { |
539 | 24 | msg_Err( &ms.sys.demuxer,"Error while reading %s", EBML_NAME(el) ); |
540 | 24 | } |
541 | 4.80k | } |
542 | | |
543 | | /* TODO: add error handling; what if we never get a KaxCluster and/or KaxClusterTimestamp? */ |
544 | | |
545 | 4.44k | mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) ); |
546 | | |
547 | | /* jump to desired position */ |
548 | | |
549 | 4.44k | if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() ) |
550 | 4.41k | ms.es.I_O().setFilePointer( fpos ); |
551 | 4.44k | } |
552 | | |
553 | | } // namespace |