1 /*
2 * This file is part of bino, a 3D video player.
3 *
4 * Copyright (C) 2010, 2011, 2012, 2015
5 * Martin Lambers <marlam@marlam.de>
6 * Frédéric Devernay <frederic.devernay@inrialpes.fr>
7 * Joe <cuchac@email.cz>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 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 General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include <limits>
26
27 #include "base/dbg.h"
28 #include "base/exc.h"
29 #include "base/msg.h"
30 #include "base/str.h"
31
32 #include "base/gettext.h"
33 #define _(string) gettext(string)
34
35 #include "media_input.h"
36
37
media_input()38 media_input::media_input() :
39 _active_video_stream(-1), _active_audio_stream(-1), _active_subtitle_stream(-1),
40 _have_active_video_read(false), _have_active_audio_read(false), _have_active_subtitle_read(false),
41 _last_audio_data_size(0), _initial_skip(0), _duration(-1)
42 {
43 }
44
~media_input()45 media_input::~media_input()
46 {
47 }
48
get_video_stream(int stream,int & media_object,int & media_object_video_stream) const49 void media_input::get_video_stream(int stream, int &media_object, int &media_object_video_stream) const
50 {
51 assert(stream < video_streams());
52
53 size_t i = 0;
54 while (_media_objects[i].video_streams() < stream + 1)
55 {
56 stream -= _media_objects[i].video_streams();
57 i++;
58 }
59 media_object = i;
60 media_object_video_stream = stream;
61 }
62
get_audio_stream(int stream,int & media_object,int & media_object_audio_stream) const63 void media_input::get_audio_stream(int stream, int &media_object, int &media_object_audio_stream) const
64 {
65 assert(stream < audio_streams());
66
67 size_t i = 0;
68 while (_media_objects[i].audio_streams() < stream + 1)
69 {
70 stream -= _media_objects[i].audio_streams();
71 i++;
72 }
73 media_object = i;
74 media_object_audio_stream = stream;
75 }
76
get_subtitle_stream(int stream,int & media_object,int & media_object_subtitle_stream) const77 void media_input::get_subtitle_stream(int stream, int &media_object, int &media_object_subtitle_stream) const
78 {
79 assert(stream < subtitle_streams());
80
81 size_t i = 0;
82 while (_media_objects[i].subtitle_streams() < stream + 1)
83 {
84 stream -= _media_objects[i].subtitle_streams();
85 i++;
86 }
87 media_object = i;
88 media_object_subtitle_stream = stream;
89 }
90
91 // Get the basename of an URL (just the file name, without leading paths)
basename(const std::string & url)92 static std::string basename(const std::string &url)
93 {
94 size_t last_slash = url.find_last_of('/');
95 size_t last_backslash = url.find_last_of('\\');
96 size_t i = std::min(last_slash, last_backslash);
97 if (last_slash != std::string::npos && last_backslash != std::string::npos)
98 {
99 i = std::max(last_slash, last_backslash);
100 }
101 if (i == std::string::npos)
102 {
103 return url;
104 }
105 else
106 {
107 return url.substr(i + 1);
108 }
109 }
110
open(const std::vector<std::string> & urls,const device_request & dev_request)111 void media_input::open(const std::vector<std::string> &urls, const device_request &dev_request)
112 {
113 assert(urls.size() > 0);
114
115 // Open media objects
116 _is_device = dev_request.is_device();
117 _media_objects.resize(urls.size());
118 for (size_t i = 0; i < urls.size(); i++)
119 {
120 _media_objects[i].open(urls[i], dev_request);
121 }
122
123 // Construct id for this input
124 _id = basename(_media_objects[0].url());
125 for (size_t i = 1; i < _media_objects.size(); i++)
126 {
127 _id += '/';
128 _id += basename(_media_objects[i].url());
129 }
130
131 // Gather metadata
132 for (size_t i = 0; i < _media_objects.size(); i++)
133 {
134 // Note that we may have multiple identical tag names in our metadata
135 for (size_t j = 0; j < _media_objects[i].tags(); j++)
136 {
137 _tag_names.push_back(_media_objects[i].tag_name(j));
138 _tag_values.push_back(_media_objects[i].tag_value(j));
139 }
140 }
141
142 // Gather streams and stream names
143 for (size_t i = 0; i < _media_objects.size(); i++)
144 {
145 for (int j = 0; j < _media_objects[i].video_streams(); j++)
146 {
147 _video_stream_names.push_back(_media_objects[i].video_frame_template(j).format_info());
148 }
149 }
150 if (_video_stream_names.size() > 1)
151 {
152 for (size_t i = 0; i < _video_stream_names.size(); i++)
153 {
154 _video_stream_names[i].insert(0,
155 std::string(1, '#') + str::from(i + 1) + '/'
156 + str::from(_video_stream_names.size()) + ": ");
157 }
158 }
159 for (size_t i = 0; i < _media_objects.size(); i++)
160 {
161 for (int j = 0; j < _media_objects[i].audio_streams(); j++)
162 {
163 _audio_stream_names.push_back(_media_objects[i].audio_blob_template(j).format_info());
164 }
165 }
166 if (_audio_stream_names.size() > 1)
167 {
168 for (size_t i = 0; i < _audio_stream_names.size(); i++)
169 {
170 _audio_stream_names[i].insert(0,
171 std::string(1, '#') + str::from(i + 1) + '/'
172 + str::from(_audio_stream_names.size()) + ": ");
173 }
174 }
175 for (size_t i = 0; i < _media_objects.size(); i++)
176 {
177 for (int j = 0; j < _media_objects[i].subtitle_streams(); j++)
178 {
179 _subtitle_stream_names.push_back(_media_objects[i].subtitle_box_template(j).format_info());
180 }
181 }
182 if (_subtitle_stream_names.size() > 1)
183 {
184 for (size_t i = 0; i < _subtitle_stream_names.size(); i++)
185 {
186 _subtitle_stream_names[i].insert(0,
187 std::string(1, '#') + str::from(i + 1) + '/'
188 + str::from(_subtitle_stream_names.size()) + ": ");
189 }
190 }
191
192 // Set duration information
193 _duration = std::numeric_limits<int64_t>::max();
194 for (size_t i = 0; i < _media_objects.size(); i++)
195 {
196 for (int j = 0; j < _media_objects[i].video_streams(); j++)
197 {
198 int64_t d = _media_objects[i].video_duration(j);
199 if (d < _duration)
200 {
201 _duration = d;
202 }
203 }
204 for (int j = 0; j < _media_objects[i].audio_streams(); j++)
205 {
206 int64_t d = _media_objects[i].audio_duration(j);
207 if (d < _duration)
208 {
209 _duration = d;
210 }
211 }
212 // Ignore subtitle stream duration; it seems unreliable and is not important anyway.
213 }
214
215 // Skip advertisement in 3dtv.at movies. Only works for single media objects.
216 try { _initial_skip = str::to<int64_t>(tag_value("StereoscopicSkip")); } catch (...) { }
217
218 // Find stereo layout and set active video stream(s)
219 _supports_stereo_layout_separate = false;
220 if (video_streams() == 2)
221 {
222 int o0, o1, v0, v1;
223 get_video_stream(0, o0, v0);
224 get_video_stream(1, o1, v1);
225 video_frame t0 = _media_objects[o0].video_frame_template(v0);
226 video_frame t1 = _media_objects[o1].video_frame_template(v1);
227 if (t0.width == t1.width
228 && t0.height == t1.height
229 && (t0.aspect_ratio <= t1.aspect_ratio && t0.aspect_ratio >= t1.aspect_ratio)
230 && t0.layout == t1.layout
231 && t0.color_space == t1.color_space
232 && t0.value_range == t1.value_range
233 && t0.chroma_location == t1.chroma_location)
234 {
235 _supports_stereo_layout_separate = true;
236 }
237 }
238 if (_supports_stereo_layout_separate)
239 {
240 _active_video_stream = 0;
241 int o, s;
242 get_video_stream(_active_video_stream, o, s);
243 _video_frame = _media_objects[o].video_frame_template(s);
244 _video_frame.stereo_layout = parameters::layout_separate;
245 }
246 else if (video_streams() > 0)
247 {
248 _active_video_stream = 0;
249 int o, s;
250 get_video_stream(_active_video_stream, o, s);
251 _video_frame = _media_objects[o].video_frame_template(s);
252 }
253 else
254 {
255 _active_video_stream = -1;
256 }
257 if (_active_video_stream >= 0)
258 {
259 select_video_stream(_active_video_stream);
260 }
261
262 // Set active audio stream
263 _active_audio_stream = (audio_streams() > 0 ? 0 : -1);
264 if (_active_audio_stream >= 0)
265 {
266 int o, s;
267 get_audio_stream(_active_audio_stream, o, s);
268 _audio_blob = _media_objects[o].audio_blob_template(s);
269 select_audio_stream(_active_audio_stream);
270 }
271
272 // Set active subtitle stream
273 _active_subtitle_stream = -1; // no subtitles by default
274
275 // Print summary
276 msg::inf(_("Input:"));
277 for (int i = 0; i < video_streams(); i++)
278 {
279 int o, s;
280 get_video_stream(i, o, s);
281 msg::inf(4, _("Video %s: %s"), video_stream_name(i).c_str(),
282 _media_objects[o].video_frame_template(s).format_name().c_str());
283 }
284 if (video_streams() == 0)
285 {
286 msg::inf(4, _("No video."));
287 }
288 for (int i = 0; i < audio_streams(); i++)
289 {
290 int o, s;
291 get_audio_stream(i, o, s);
292 msg::inf(4, _("Audio %s: %s"), audio_stream_name(i).c_str(),
293 _media_objects[o].audio_blob_template(s).format_name().c_str());
294 }
295 if (audio_streams() == 0)
296 {
297 msg::inf(4, _("No audio."));
298 }
299 for (int i = 0; i < subtitle_streams(); i++)
300 {
301 int o, s;
302 get_subtitle_stream(i, o, s);
303 msg::inf(4, _("Subtitle %s: %s"), subtitle_stream_name(i).c_str(),
304 _media_objects[o].subtitle_box_template(s).format_name().c_str());
305 }
306 if (subtitle_streams() == 0)
307 {
308 msg::inf(4, _("No subtitle."));
309 }
310 msg::inf(4, _("Duration: %g seconds"), duration() / 1e6f);
311 if (video_streams() > 0)
312 {
313 msg::inf(4, _("Stereo layout: %s"), parameters::stereo_layout_to_string(
314 video_frame_template().stereo_layout, video_frame_template().stereo_layout_swap).c_str());
315 }
316 }
317
urls() const318 size_t media_input::urls() const
319 {
320 return _media_objects.size();
321 }
322
url(size_t i) const323 const std::string &media_input::url(size_t i) const
324 {
325 return _media_objects[i].url();
326 }
327
id() const328 const std::string &media_input::id() const
329 {
330 return _id;
331 }
332
is_device() const333 bool media_input::is_device() const
334 {
335 return _is_device;
336 }
337
tags() const338 size_t media_input::tags() const
339 {
340 return _tag_names.size();
341 }
342
tag_name(size_t i) const343 const std::string &media_input::tag_name(size_t i) const
344 {
345 assert(_tag_names.size() > i);
346 return _tag_names[i];
347 }
348
tag_value(size_t i) const349 const std::string &media_input::tag_value(size_t i) const
350 {
351 assert(_tag_values.size() > i);
352 return _tag_values[i];
353 }
354
tag_value(const std::string & tag_name) const355 const std::string &media_input::tag_value(const std::string &tag_name) const
356 {
357 static std::string empty;
358 for (size_t i = 0; i < _tag_names.size(); i++)
359 {
360 if (std::string(tag_name) == _tag_names[i])
361 {
362 return _tag_values[i];
363 }
364 }
365 return empty;
366 }
367
video_frame_template() const368 const video_frame &media_input::video_frame_template() const
369 {
370 assert(_active_video_stream >= 0);
371 return _video_frame;
372 }
373
video_frame_rate_numerator() const374 int media_input::video_frame_rate_numerator() const
375 {
376 assert(_active_video_stream >= 0);
377 int o, s;
378 get_video_stream(_active_video_stream, o, s);
379 return _media_objects[o].video_frame_rate_numerator(s);
380 }
381
video_frame_rate_denominator() const382 int media_input::video_frame_rate_denominator() const
383 {
384 assert(_active_video_stream >= 0);
385 int o, s;
386 get_video_stream(_active_video_stream, o, s);
387 return _media_objects[o].video_frame_rate_denominator(s);
388 }
389
video_frame_duration() const390 int64_t media_input::video_frame_duration() const
391 {
392 assert(_active_video_stream >= 0);
393 return static_cast<int64_t>(video_frame_rate_denominator()) * 1000000 / video_frame_rate_numerator();
394 }
395
audio_blob_template() const396 const audio_blob &media_input::audio_blob_template() const
397 {
398 assert(_active_audio_stream >= 0);
399 return _audio_blob;
400 }
401
subtitle_box_template() const402 const subtitle_box &media_input::subtitle_box_template() const
403 {
404 assert(_active_subtitle_stream >= 0);
405 return _subtitle_box;
406 }
407
stereo_layout_is_supported(parameters::stereo_layout_t layout,bool) const408 bool media_input::stereo_layout_is_supported(parameters::stereo_layout_t layout, bool) const
409 {
410 if (video_streams() < 1)
411 {
412 return false;
413 }
414 assert(_active_video_stream >= 0);
415 assert(_active_video_stream < video_streams());
416 int o, s;
417 get_video_stream(_active_video_stream, o, s);
418 const video_frame &t = _media_objects[o].video_frame_template(s);
419 bool supported = true;
420 if (((layout == parameters::layout_left_right || layout == parameters::layout_left_right_half) && t.raw_width % 2 != 0)
421 || ((layout == parameters::layout_top_bottom || layout == parameters::layout_top_bottom_half) && t.raw_height % 2 != 0)
422 || (layout == parameters::layout_even_odd_rows && t.raw_height % 2 != 0)
423 || (layout == parameters::layout_separate && !_supports_stereo_layout_separate))
424 {
425 supported = false;
426 }
427 return supported;
428 }
429
set_stereo_layout(parameters::stereo_layout_t layout,bool swap)430 void media_input::set_stereo_layout(parameters::stereo_layout_t layout, bool swap)
431 {
432 assert(stereo_layout_is_supported(layout, swap));
433 if (_have_active_video_read)
434 {
435 (void)finish_video_frame_read();
436 }
437 if (_have_active_audio_read)
438 {
439 (void)finish_audio_blob_read();
440 }
441 if (_have_active_subtitle_read)
442 {
443 (void)finish_subtitle_box_read();
444 }
445 int o, s;
446 get_video_stream(_active_video_stream, o, s);
447 const video_frame &t = _media_objects[o].video_frame_template(s);
448 _video_frame = t;
449 _video_frame.stereo_layout = layout;
450 _video_frame.stereo_layout_swap = swap;
451 _video_frame.set_view_dimensions();
452 // Reset active stream in case we switched to or from 'separate'.
453 select_video_stream(_active_video_stream);
454 if (layout == parameters::layout_separate)
455 {
456 // If we switched the layout to 'separate', then we have to seek to the
457 // position of the first video stream, or else the second video stream
458 // is out of sync.
459 int64_t pos = _media_objects[o].tell();
460 if (pos > std::numeric_limits<int64_t>::min())
461 {
462 seek(pos);
463 }
464 }
465 }
466
select_video_stream(int video_stream)467 void media_input::select_video_stream(int video_stream)
468 {
469 if (_have_active_video_read)
470 {
471 (void)finish_video_frame_read();
472 }
473 if (_have_active_audio_read)
474 {
475 (void)finish_audio_blob_read();
476 }
477 if (_have_active_subtitle_read)
478 {
479 (void)finish_subtitle_box_read();
480 }
481 assert(video_stream >= 0);
482 assert(video_stream < video_streams());
483 if (_video_frame.stereo_layout == parameters::layout_separate)
484 {
485 _active_video_stream = 0;
486 for (size_t i = 0; i < _media_objects.size(); i++)
487 {
488 for (int j = 0; j < _media_objects[i].video_streams(); j++)
489 {
490 _media_objects[i].video_stream_set_active(j, true);
491 }
492 }
493 }
494 else
495 {
496 _active_video_stream = video_stream;
497 int o, s;
498 get_video_stream(_active_video_stream, o, s);
499 for (size_t i = 0; i < _media_objects.size(); i++)
500 {
501 for (int j = 0; j < _media_objects[i].video_streams(); j++)
502 {
503 _media_objects[i].video_stream_set_active(j, (i == static_cast<size_t>(o) && j == s));
504 }
505 }
506 }
507 // Re-set video frame template
508 parameters::stereo_layout_t stereo_layout_bak = _video_frame.stereo_layout;
509 bool stereo_layout_swap_bak = _video_frame.stereo_layout_swap;
510 int o, s;
511 get_video_stream(_active_video_stream, o, s);
512 _video_frame = _media_objects[o].video_frame_template(s);
513 _video_frame.stereo_layout = stereo_layout_bak;
514 _video_frame.stereo_layout_swap = stereo_layout_swap_bak;
515 _video_frame.set_view_dimensions();
516 }
517
select_audio_stream(int audio_stream)518 void media_input::select_audio_stream(int audio_stream)
519 {
520 if (_have_active_video_read)
521 {
522 (void)finish_video_frame_read();
523 }
524 if (_have_active_audio_read)
525 {
526 (void)finish_audio_blob_read();
527 }
528 if (_have_active_subtitle_read)
529 {
530 (void)finish_subtitle_box_read();
531 }
532 assert(audio_stream >= 0);
533 assert(audio_stream < audio_streams());
534 _active_audio_stream = audio_stream;
535 int o, s;
536 get_audio_stream(_active_audio_stream, o, s);
537 for (size_t i = 0; i < _media_objects.size(); i++)
538 {
539 for (int j = 0; j < _media_objects[i].audio_streams(); j++)
540 {
541 _media_objects[i].audio_stream_set_active(j, (i == static_cast<size_t>(o) && j == s));
542 }
543 }
544 // Re-set audio blob template
545 _audio_blob = _media_objects[o].audio_blob_template(s);
546 }
547
select_subtitle_stream(int subtitle_stream)548 void media_input::select_subtitle_stream(int subtitle_stream)
549 {
550 if (_have_active_video_read)
551 {
552 (void)finish_video_frame_read();
553 }
554 if (_have_active_audio_read)
555 {
556 (void)finish_audio_blob_read();
557 }
558 if (_have_active_subtitle_read)
559 {
560 (void)finish_subtitle_box_read();
561 }
562 assert(subtitle_stream >= -1);
563 assert(subtitle_stream < subtitle_streams());
564 _active_subtitle_stream = subtitle_stream;
565 int o = -1, s = -1;
566 if (_active_subtitle_stream >= 0)
567 {
568 get_subtitle_stream(_active_subtitle_stream, o, s);
569 }
570 for (size_t i = 0; i < _media_objects.size(); i++)
571 {
572 for (int j = 0; j < _media_objects[i].subtitle_streams(); j++)
573 {
574 _media_objects[i].subtitle_stream_set_active(j, (i == static_cast<size_t>(o) && j == s));
575 }
576 }
577 // Re-set subtitle box template
578 if (_active_subtitle_stream >= 0)
579 _subtitle_box = _media_objects[o].subtitle_box_template(s);
580 else
581 _subtitle_box = subtitle_box();
582 }
583
start_video_frame_read()584 void media_input::start_video_frame_read()
585 {
586 assert(_active_video_stream >= 0);
587 if (_have_active_video_read)
588 {
589 return;
590 }
591 if (_video_frame.stereo_layout == parameters::layout_separate)
592 {
593 int o0, s0, o1, s1;
594 get_video_stream(0, o0, s0);
595 get_video_stream(1, o1, s1);
596 _media_objects[o0].start_video_frame_read(s0, 1);
597 _media_objects[o1].start_video_frame_read(s1, 1);
598 }
599 else
600 {
601 int o, s;
602 get_video_stream(_active_video_stream, o, s);
603 _media_objects[o].start_video_frame_read(s,
604 _video_frame.stereo_layout == parameters::layout_alternating ? 2 : 1);
605 }
606 _have_active_video_read = true;
607 }
608
finish_video_frame_read()609 video_frame media_input::finish_video_frame_read()
610 {
611 assert(_active_video_stream >= 0);
612 if (!_have_active_video_read)
613 {
614 start_video_frame_read();
615 }
616 video_frame frame;
617 if (_video_frame.stereo_layout == parameters::layout_separate)
618 {
619 int o0, s0, o1, s1;
620 get_video_stream(0, o0, s0);
621 get_video_stream(1, o1, s1);
622 video_frame f0 = _media_objects[o0].finish_video_frame_read(s0);
623 video_frame f1 = _media_objects[o1].finish_video_frame_read(s1);
624 if (f0.is_valid() && f1.is_valid())
625 {
626 frame = _video_frame;
627 for (int p = 0; p < 3; p++)
628 {
629 frame.data[0][p] = f0.data[0][p];
630 frame.data[1][p] = f1.data[0][p];
631 frame.line_size[0][p] = f0.line_size[0][p];
632 frame.line_size[1][p] = f1.line_size[0][p];
633 }
634 frame.presentation_time = f0.presentation_time;
635 }
636 }
637 else
638 {
639 int o, s;
640 get_video_stream(_active_video_stream, o, s);
641 video_frame f = _media_objects[o].finish_video_frame_read(s);
642 if (f.is_valid())
643 {
644 frame = _video_frame;
645 for (int v = 0; v < 2; v++)
646 {
647 for (int p = 0; p < 3; p++)
648 {
649 frame.data[v][p] = f.data[v][p];
650 frame.line_size[v][p] = f.line_size[v][p];
651 }
652 }
653 frame.presentation_time = f.presentation_time;
654 }
655 }
656 _have_active_video_read = false;
657 return frame;
658 }
659
start_audio_blob_read(size_t size)660 void media_input::start_audio_blob_read(size_t size)
661 {
662 assert(_active_audio_stream >= 0);
663 if (_have_active_audio_read)
664 {
665 return;
666 }
667 int o, s;
668 get_audio_stream(_active_audio_stream, o, s);
669 _media_objects[o].start_audio_blob_read(s, size);
670 _last_audio_data_size = size;
671 _have_active_audio_read = true;
672 }
673
finish_audio_blob_read()674 audio_blob media_input::finish_audio_blob_read()
675 {
676 assert(_active_audio_stream >= 0);
677 int o, s;
678 get_audio_stream(_active_audio_stream, o, s);
679 if (!_have_active_audio_read)
680 {
681 start_audio_blob_read(_last_audio_data_size);
682 }
683 _have_active_audio_read = false;
684 return _media_objects[o].finish_audio_blob_read(s);
685 }
686
start_subtitle_box_read()687 void media_input::start_subtitle_box_read()
688 {
689 assert(_active_subtitle_stream >= 0);
690 if (_have_active_subtitle_read)
691 {
692 return;
693 }
694 int o, s;
695 get_subtitle_stream(_active_subtitle_stream, o, s);
696 _media_objects[o].start_subtitle_box_read(s);
697 _have_active_subtitle_read = true;
698 }
699
finish_subtitle_box_read()700 subtitle_box media_input::finish_subtitle_box_read()
701 {
702 assert(_active_subtitle_stream >= 0);
703 int o, s;
704 get_subtitle_stream(_active_subtitle_stream, o, s);
705 if (!_have_active_subtitle_read)
706 {
707 start_subtitle_box_read();
708 }
709 _have_active_subtitle_read = false;
710 return _media_objects[o].finish_subtitle_box_read(s);
711 }
712
tell()713 int64_t media_input::tell()
714 {
715 int64_t pos = std::numeric_limits<int64_t>::min();
716 int o, s;
717 if (_active_audio_stream >= 0)
718 {
719 get_audio_stream(_active_audio_stream, o, s);
720 pos = _media_objects[o].tell();
721 }
722 else if (_active_video_stream >= 0)
723 {
724 get_video_stream(_active_video_stream, o, s);
725 pos = _media_objects[o].tell();
726 }
727 return pos;
728 }
729
seek(int64_t pos)730 void media_input::seek(int64_t pos)
731 {
732 if (_have_active_video_read)
733 {
734 (void)finish_video_frame_read();
735 }
736 if (_have_active_audio_read)
737 {
738 (void)finish_audio_blob_read();
739 }
740 if (_have_active_subtitle_read)
741 {
742 (void)finish_subtitle_box_read();
743 }
744 for (size_t i = 0; i < _media_objects.size(); i++)
745 {
746 _media_objects[i].seek(pos);
747 }
748 }
749
close()750 void media_input::close()
751 {
752 try
753 {
754 if (_have_active_video_read)
755 {
756 (void)finish_video_frame_read();
757 }
758 if (_have_active_audio_read)
759 {
760 (void)finish_audio_blob_read();
761 }
762 if (_have_active_subtitle_read)
763 {
764 (void)finish_subtitle_box_read();
765 }
766 for (size_t i = 0; i < _media_objects.size(); i++)
767 {
768 _media_objects[i].close();
769 }
770 }
771 catch (...)
772 {
773 }
774 _is_device = false;
775 _id = "";
776 _media_objects.clear();
777 _tag_names.clear();
778 _tag_values.clear();
779 _video_stream_names.clear();
780 _audio_stream_names.clear();
781 _subtitle_stream_names.clear();
782 _active_video_stream = -1;
783 _active_audio_stream = -1;
784 _active_subtitle_stream = -1;
785 _initial_skip = 0;
786 _duration = -1;
787 _video_frame = video_frame();
788 _audio_blob = audio_blob();
789 _subtitle_box = subtitle_box();
790 }
791