/*
Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
- This program is free software; you can redistribute it and/or modify
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
- This program is distributed in the hope that it will be useful,
+ DCP-o-matic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
*/
list<ContentVideo> output;
BOOST_FOREACH (ContentVideo const & i, _decoded) {
- if (i.frame == frame) {
+ if (i.frame.index() == frame) {
output.push_back (i);
}
}
_log->log (String::compose ("VD has request for %1", frame), LogEntry::TYPE_DEBUG_DECODE);
- if (_decoded.empty() || frame < _decoded.front().frame || frame > (_decoded.back().frame + 1)) {
+ if (_decoded.empty() || frame < _decoded.front().frame.index() || frame > (_decoded.back().frame.index() + 1)) {
_parent->seek (ContentTime::from_frames (frame, _content->active_video_frame_rate()), accurate);
}
+ unsigned int const frames_wanted = _content->video->frame_type() == VIDEO_FRAME_TYPE_2D ? 1 : 2;
+
list<ContentVideo> dec;
/* Now enough pass() calls should either:
bool no_data = false;
while (true) {
- if (!decoded(frame).empty ()) {
+ if (decoded(frame).size() == frames_wanted) {
/* We got what we want */
break;
}
break;
}
- if (!_decoded.empty() && _decoded.front().frame > frame) {
+ if (!_decoded.empty() && _decoded.front().frame.index() > frame) {
/* We're never going to get the frame we want. Perhaps the caller is asking
* for a video frame before the content's video starts (if its audio
* begins before its video, for example).
}
} else {
- /* Any frame will do: use the first one that comes out of pass() */
- while (_decoded.empty() && !_parent->pass (Decoder::PASS_REASON_VIDEO, accurate)) {}
- if (!_decoded.empty ()) {
- dec.push_back (_decoded.front ());
+ /* Any frame(s) will do: use the first one(s) that comes out of pass() */
+ while (_decoded.size() < frames_wanted && !_parent->pass (Decoder::PASS_REASON_VIDEO, accurate)) {}
+ list<ContentVideo>::const_iterator i = _decoded.begin();
+ unsigned int j = 0;
+ while (i != _decoded.end() && j < frames_wanted) {
+ dec.push_back (*i);
+ ++i;
+ ++j;
}
}
/* Clean up _decoded; keep the frame we are returning, if any (which may have two images
for 3D), but nothing before that */
- while (!_decoded.empty() && !dec.empty() && _decoded.front().frame < dec.front().frame) {
+ while (!_decoded.empty() && !dec.empty() && _decoded.front().frame.index() < dec.front().frame.index()) {
_decoded.pop_front ();
}
test_gaps++;
#endif
_decoded.push_back (
- ContentVideo (filler_image, eye, filler_part, i)
+ ContentVideo (filler_image, VideoFrame (i, eye), filler_part)
);
}
}
* adding both left and right eye frames.
*/
void
-VideoDecoder::fill_both_eyes (Frame from, Frame to, Eyes eye)
+VideoDecoder::fill_both_eyes (VideoFrame from, VideoFrame to)
{
- if (to == 0 && eye == EYES_LEFT) {
- /* Already OK */
- return;
- }
-
/* Fill with black... */
shared_ptr<const ImageProxy> filler_left_image (new RawImageProxy (_black_image));
shared_ptr<const ImageProxy> filler_right_image (new RawImageProxy (_black_image));
/* ...unless there's some video we can fill with */
for (list<ContentVideo>::const_reverse_iterator i = _decoded.rbegin(); i != _decoded.rend(); ++i) {
- if (i->eyes == EYES_LEFT && !filler_left_image) {
+ if (i->frame.eyes() == EYES_LEFT && !filler_left_image) {
filler_left_image = i->image;
filler_left_part = i->part;
- } else if (i->eyes == EYES_RIGHT && !filler_right_image) {
+ } else if (i->frame.eyes() == EYES_RIGHT && !filler_right_image) {
filler_right_image = i->image;
filler_right_part = i->part;
}
}
}
- Frame filler_frame = from;
- Eyes filler_eye = _decoded.empty() ? EYES_LEFT : _decoded.back().eyes;
-
- if (_decoded.empty ()) {
- filler_frame = 0;
- filler_eye = EYES_LEFT;
- } else if (_decoded.back().eyes == EYES_LEFT) {
- filler_frame = _decoded.back().frame;
- filler_eye = EYES_RIGHT;
- } else if (_decoded.back().eyes == EYES_RIGHT) {
- filler_frame = _decoded.back().frame + 1;
- filler_eye = EYES_LEFT;
- }
-
- while (filler_frame != to || filler_eye != eye) {
+ while (from != to) {
#ifdef DCPOMATIC_DEBUG
test_gaps++;
_decoded.push_back (
ContentVideo (
- filler_eye == EYES_LEFT ? filler_left_image : filler_right_image,
- filler_eye,
- filler_eye == EYES_LEFT ? filler_left_part : filler_right_part,
- filler_frame
+ from.eyes() == EYES_LEFT ? filler_left_image : filler_right_image,
+ from,
+ from.eyes() == EYES_LEFT ? filler_left_part : filler_right_part
)
);
- if (filler_eye == EYES_LEFT) {
- filler_eye = EYES_RIGHT;
- } else {
- filler_eye = EYES_LEFT;
- ++filler_frame;
- }
+ ++from;
}
}
list<ContentVideo> to_push;
switch (_content->video->frame_type ()) {
case VIDEO_FRAME_TYPE_2D:
- to_push.push_back (ContentVideo (image, EYES_BOTH, PART_WHOLE, frame));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_BOTH), PART_WHOLE));
break;
+ case VIDEO_FRAME_TYPE_3D:
case VIDEO_FRAME_TYPE_3D_ALTERNATE:
{
/* We receive the same frame index twice for 3D-alternate; hence we know which
frame this one is.
*/
- bool const same = (!_decoded.empty() && frame == _decoded.back().frame);
- to_push.push_back (ContentVideo (image, same ? EYES_RIGHT : EYES_LEFT, PART_WHOLE, frame));
+ bool const same = (!_decoded.empty() && frame == _decoded.back().frame.index());
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, same ? EYES_RIGHT : EYES_LEFT), PART_WHOLE));
break;
}
case VIDEO_FRAME_TYPE_3D_LEFT_RIGHT:
- to_push.push_back (ContentVideo (image, EYES_LEFT, PART_LEFT_HALF, frame));
- to_push.push_back (ContentVideo (image, EYES_RIGHT, PART_RIGHT_HALF, frame));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_LEFT), PART_LEFT_HALF));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_RIGHT), PART_RIGHT_HALF));
break;
case VIDEO_FRAME_TYPE_3D_TOP_BOTTOM:
- to_push.push_back (ContentVideo (image, EYES_LEFT, PART_TOP_HALF, frame));
- to_push.push_back (ContentVideo (image, EYES_RIGHT, PART_BOTTOM_HALF, frame));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_LEFT), PART_TOP_HALF));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_RIGHT), PART_BOTTOM_HALF));
break;
case VIDEO_FRAME_TYPE_3D_LEFT:
- to_push.push_back (ContentVideo (image, EYES_LEFT, PART_WHOLE, frame));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_LEFT), PART_WHOLE));
break;
case VIDEO_FRAME_TYPE_3D_RIGHT:
- to_push.push_back (ContentVideo (image, EYES_RIGHT, PART_WHOLE, frame));
+ to_push.push_back (ContentVideo (image, VideoFrame (frame, EYES_RIGHT), PART_WHOLE));
break;
default:
DCPOMATIC_ASSERT (false);
and the things we are about to push.
*/
- optional<Frame> from;
- optional<Frame> to;
+ optional<VideoFrame> from;
if (_decoded.empty() && _last_seek_time && _last_seek_accurate) {
- from = _last_seek_time->frames_round (_content->active_video_frame_rate ());
- to = to_push.front().frame;
+ from = VideoFrame (
+ _last_seek_time->frames_round (_content->active_video_frame_rate ()),
+ _content->video->frame_type() == VIDEO_FRAME_TYPE_2D ? EYES_BOTH : EYES_LEFT
+ );
} else if (!_decoded.empty ()) {
- from = _decoded.back().frame + 1;
- to = to_push.front().frame;
+ from = _decoded.back().frame;
+ ++(*from);
}
/* If we've pre-rolled on a seek we may now receive out-of-order frames
(frames before the last seek time) which we can just ignore.
*/
- if (from && to && from.get() > to.get()) {
+ if (from && (*from) > to_push.front().frame) {
return;
}
if (from) {
switch (_content->video->frame_type ()) {
case VIDEO_FRAME_TYPE_2D:
- fill_one_eye (from.get(), to.get (), EYES_BOTH);
+ fill_one_eye (from->index(), to_push.front().frame.index(), EYES_BOTH);
break;
+ case VIDEO_FRAME_TYPE_3D:
case VIDEO_FRAME_TYPE_3D_LEFT_RIGHT:
case VIDEO_FRAME_TYPE_3D_TOP_BOTTOM:
case VIDEO_FRAME_TYPE_3D_ALTERNATE:
- fill_both_eyes (from.get(), to.get(), to_push.front().eyes);
+ fill_both_eyes (from.get(), to_push.front().frame);
break;
case VIDEO_FRAME_TYPE_3D_LEFT:
- fill_one_eye (from.get(), to.get (), EYES_LEFT);
+ fill_one_eye (from->index(), to_push.front().frame.index(), EYES_LEFT);
break;
case VIDEO_FRAME_TYPE_3D_RIGHT:
- fill_one_eye (from.get(), to.get (), EYES_RIGHT);
+ fill_one_eye (from->index(), to_push.front().frame.index(), EYES_RIGHT);
break;
}
}