From: Carl Hetherington Date: Tue, 14 Jun 2016 10:48:37 +0000 (+0100) Subject: Add VideoFrame class. X-Git-Tag: v2.8.10~24 X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=4b7b0edb359ae68f2dbcab90c7c10382f507fa5b;hp=3d6501346b187f35d0f55d16e13f8817f505a82f Add VideoFrame class. This puts a frame index with an Eyes, which simplifies code in some areas. I can't think of a better name for it, unfortunately. --- diff --git a/src/lib/content_video.h b/src/lib/content_video.h index 21a600709..8e5f2fd09 100644 --- a/src/lib/content_video.h +++ b/src/lib/content_video.h @@ -21,6 +21,8 @@ #ifndef DCPOMATIC_CONTENT_VIDEO_H #define DCPOMATIC_CONTENT_VIDEO_H +#include "video_frame.h" + class ImageProxy; /** @class ContentVideo @@ -30,22 +32,18 @@ class ContentVideo { public: ContentVideo () - : eyes (EYES_BOTH) - , part (PART_WHOLE) - , frame (0) + : part (PART_WHOLE) {} - ContentVideo (boost::shared_ptr i, Eyes e, Part p, Frame f) + ContentVideo (boost::shared_ptr i, VideoFrame f, Part p) : image (i) - , eyes (e) - , part (p) , frame (f) + , part (p) {} boost::shared_ptr image; - Eyes eyes; + VideoFrame frame; Part part; - Frame frame; }; #endif diff --git a/src/lib/player.cc b/src/lib/player.cc index f22a6480f..c70ac8852 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -374,12 +374,12 @@ Player::get_video (DCPTime time, bool accurate) shared_ptr ( new PlayerVideo ( i->image, - content_video_to_dcp (piece, i->frame), + content_video_to_dcp (piece, i->frame.index()), piece->content->video->crop (), - piece->content->video->fade (i->frame), + piece->content->video->fade (i->frame.index()), image_size, _video_container_size, - i->eyes, + i->frame.eyes(), i->part, piece->content->video->colour_conversion () ) diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index cc6cbfc30..ec5ae8884 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -59,7 +59,7 @@ VideoDecoder::decoded (Frame frame) list output; BOOST_FOREACH (ContentVideo const & i, _decoded) { - if (i.frame == frame) { + if (i.frame.index() == frame) { output.push_back (i); } } @@ -86,7 +86,7 @@ VideoDecoder::get (Frame frame, bool accurate) _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); } @@ -117,7 +117,7 @@ VideoDecoder::get (Frame frame, bool accurate) 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). @@ -146,7 +146,7 @@ VideoDecoder::get (Frame frame, bool accurate) /* 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 (); } @@ -180,7 +180,7 @@ VideoDecoder::fill_one_eye (Frame from, Frame to, Eyes eye) test_gaps++; #endif _decoded.push_back ( - ContentVideo (filler_image, eye, filler_part, i) + ContentVideo (filler_image, VideoFrame (i, eye), filler_part) ); } } @@ -189,7 +189,7 @@ VideoDecoder::fill_one_eye (Frame from, Frame to, Eyes eye) * adding both left and right eye frames. */ void -VideoDecoder::fill_both_eyes (Frame from_frame, Eyes from_eye, Frame to_frame, Eyes to_eye) +VideoDecoder::fill_both_eyes (VideoFrame from, VideoFrame to) { /* Fill with black... */ shared_ptr filler_left_image (new RawImageProxy (_black_image)); @@ -199,10 +199,10 @@ VideoDecoder::fill_both_eyes (Frame from_frame, Eyes from_eye, Frame to_frame, E /* ...unless there's some video we can fill with */ for (list::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; } @@ -212,7 +212,7 @@ VideoDecoder::fill_both_eyes (Frame from_frame, Eyes from_eye, Frame to_frame, E } } - while (from_frame != to_frame || from_eye != to_eye) { + while (from != to) { #ifdef DCPOMATIC_DEBUG test_gaps++; @@ -220,19 +220,13 @@ VideoDecoder::fill_both_eyes (Frame from_frame, Eyes from_eye, Frame to_frame, E _decoded.push_back ( ContentVideo ( - from_eye == EYES_LEFT ? filler_left_image : filler_right_image, - from_eye, - from_eye == EYES_LEFT ? filler_left_part : filler_right_part, - from_frame + from.eyes() == EYES_LEFT ? filler_left_image : filler_right_image, + from, + from.eyes() == EYES_LEFT ? filler_left_part : filler_right_part ) ); - if (from_eye == EYES_LEFT) { - from_eye = EYES_RIGHT; - } else { - from_eye = EYES_LEFT; - ++from_frame; - } + ++from; } } @@ -250,7 +244,7 @@ VideoDecoder::give (shared_ptr image, Frame frame) list 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: @@ -259,22 +253,22 @@ VideoDecoder::give (shared_ptr image, Frame frame) 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)); + 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); @@ -285,60 +279,39 @@ VideoDecoder::give (shared_ptr image, Frame frame) and the things we are about to push. */ - optional from_frame; - optional from_eye; + optional from; if (_decoded.empty() && _last_seek_time && _last_seek_accurate) { - from_frame = _last_seek_time->frames_round (_content->active_video_frame_rate ()); - from_eye = EYES_LEFT; + from = VideoFrame (_last_seek_time->frames_round (_content->active_video_frame_rate ()), EYES_LEFT); } else if (!_decoded.empty ()) { - switch (_content->video->frame_type()) { - case VIDEO_FRAME_TYPE_2D: - case VIDEO_FRAME_TYPE_3D_LEFT: - case VIDEO_FRAME_TYPE_3D_RIGHT: - from_frame = _decoded.back().frame + 1; - 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: - /* Get the last frame that we have */ - from_frame = _decoded.back().frame; - from_eye = _decoded.back().eyes; - /* And increment */ - if (from_eye.get() == EYES_LEFT) { - from_eye = EYES_RIGHT; - } else { - from_eye = EYES_LEFT; - from_frame = from_frame.get() + 1; - } - } + 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_frame && from_frame.get() > to_push.front().frame) { + if (from && from->index() > to_push.front().frame.index()) { return; } - if (from_frame) { + if (from) { switch (_content->video->frame_type ()) { case VIDEO_FRAME_TYPE_2D: - fill_one_eye (from_frame.get(), to_push.front().frame, 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_frame.get(), from_eye.get(), to_push.front().frame, to_push.front().eyes); + fill_both_eyes (from.get(), to_push.front().frame); break; case VIDEO_FRAME_TYPE_3D_LEFT: - fill_one_eye (from_frame.get(), to_push.front().frame, 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_frame.get(), to_push.front().frame, EYES_RIGHT); + fill_one_eye (from->index(), to_push.front().frame.index(), EYES_RIGHT); break; } } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 7c2374dd8..692702444 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -68,7 +68,7 @@ private: std::list decoded (Frame frame); void fill_one_eye (Frame from, Frame to, Eyes); - void fill_both_eyes (Frame from_frame, Eyes from_eyes, Frame to_frame, Eyes to_eyes); + void fill_both_eyes (VideoFrame from, VideoFrame to); Decoder* _parent; boost::shared_ptr _content; diff --git a/src/lib/video_frame.cc b/src/lib/video_frame.cc new file mode 100644 index 000000000..e2223ff9e --- /dev/null +++ b/src/lib/video_frame.cc @@ -0,0 +1,48 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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. + + 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 DCP-o-matic. If not, see . + +*/ + +#include "video_frame.h" + +VideoFrame & +VideoFrame::operator++ () +{ + if (_eyes == EYES_BOTH) { + ++_index; + } else if (_eyes == EYES_LEFT) { + _eyes = EYES_RIGHT; + } else { + _eyes = EYES_LEFT; + ++_index; + } + + return *this; +} + +bool +operator== (VideoFrame const & a, VideoFrame const & b) +{ + return a.index() == b.index() && a.eyes() == b.eyes(); +} + +bool +operator!= (VideoFrame const & a, VideoFrame const & b) +{ + return !(a == b); +} diff --git a/src/lib/video_frame.h b/src/lib/video_frame.h new file mode 100644 index 000000000..abb25ec37 --- /dev/null +++ b/src/lib/video_frame.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2016 Carl Hetherington + + 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. + + 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 DCP-o-matic. If not, see . + +*/ + +#ifndef DCPOMATIC_VIDEO_FRAME_H +#define DCPOMATIC_VIDEO_FRAME_H + +#include "types.h" + +class VideoFrame +{ +public: + VideoFrame () + : _index (0) + , _eyes (EYES_BOTH) + {} + + VideoFrame (Frame i) + : _index (i) + , _eyes (EYES_BOTH) + {} + + VideoFrame (Frame i, Eyes e) + : _index (i) + , _eyes (e) + {} + + Frame index () const { + return _index; + } + + Eyes eyes () const { + return _eyes; + } + + VideoFrame& operator++ (); + +private: + Frame _index; + Eyes _eyes; +}; + +extern bool operator== (VideoFrame const & a, VideoFrame const & b); +extern bool operator!= (VideoFrame const & a, VideoFrame const & b); + +#endif diff --git a/src/lib/wscript b/src/lib/wscript index 22d8c4477..f5fc6f539 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -139,6 +139,7 @@ sources = """ video_content_scale.cc video_decoder.cc video_filter_graph.cc + video_frame.cc video_mxf_content.cc video_mxf_decoder.cc video_mxf_examiner.cc diff --git a/test/ffmpeg_decoder_seek_test.cc b/test/ffmpeg_decoder_seek_test.cc index 93c447591..8a854b01b 100644 --- a/test/ffmpeg_decoder_seek_test.cc +++ b/test/ffmpeg_decoder_seek_test.cc @@ -49,7 +49,7 @@ check (shared_ptr decoder, int frame) list v; v = decoder->video->get (frame, true); BOOST_CHECK (v.size() == 1); - BOOST_CHECK_EQUAL (v.front().frame, frame); + BOOST_CHECK_EQUAL (v.front().frame.index(), frame); } static void diff --git a/test/ffmpeg_decoder_sequential_test.cc b/test/ffmpeg_decoder_sequential_test.cc index 7435a4af0..6a27d698f 100644 --- a/test/ffmpeg_decoder_sequential_test.cc +++ b/test/ffmpeg_decoder_sequential_test.cc @@ -66,7 +66,7 @@ ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int list v; v = decoder->video->get (i, true); BOOST_REQUIRE_EQUAL (v.size(), 1U); - BOOST_CHECK_EQUAL (v.front().frame, i); + BOOST_CHECK_EQUAL (v.front().frame.index(), i); } #ifdef DCPOMATIC_DEBUG BOOST_CHECK_EQUAL (decoder->video->test_gaps, gaps); diff --git a/test/seek_zero_test.cc b/test/seek_zero_test.cc index f1f137d38..05bf1b5bf 100644 --- a/test/seek_zero_test.cc +++ b/test/seek_zero_test.cc @@ -67,5 +67,5 @@ BOOST_AUTO_TEST_CASE (seek_zero_test) FFmpegDecoder decoder (content, film->log(), false); list a = decoder.video->get (first_frame, true); BOOST_CHECK (a.size() == 1); - BOOST_CHECK_EQUAL (a.front().frame, first_frame); + BOOST_CHECK_EQUAL (a.front().frame.index(), first_frame); } diff --git a/test/video_decoder_fill_test.cc b/test/video_decoder_fill_test.cc index 737bc883c..2d783f52d 100644 --- a/test/video_decoder_fill_test.cc +++ b/test/video_decoder_fill_test.cc @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test1) BOOST_CHECK_EQUAL (decoder.video->_decoded.size(), 4U); list::iterator i = decoder.video->_decoded.begin(); for (int j = 0; j < 4; ++j) { - BOOST_CHECK_EQUAL (i->frame, j); + BOOST_CHECK_EQUAL (i->frame.index(), j); ++i; } @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test1) BOOST_CHECK_EQUAL (decoder.video->_decoded.size(), 7); i = decoder.video->_decoded.begin(); for (int j = 0; j < 7; ++j) { - BOOST_CHECK_EQUAL (i->frame, j); + BOOST_CHECK_EQUAL (i->frame.index(), j); ++i; } } @@ -62,32 +62,32 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test2) shared_ptr c (new ImageContent (film, "test/data/simple_testcard_640x480.png")); ImageDecoder decoder (c, film->log()); - decoder.video->fill_both_eyes (0, EYES_LEFT, 4, EYES_LEFT); + decoder.video->fill_both_eyes (VideoFrame (0, EYES_LEFT), VideoFrame (4, EYES_LEFT)); BOOST_CHECK_EQUAL (decoder.video->_decoded.size(), 8); list::iterator i = decoder.video->_decoded.begin(); for (int j = 0; j < 8; ++j) { - BOOST_CHECK_EQUAL (i->frame, j / 2); - BOOST_CHECK_EQUAL (i->eyes, (j % 2) == 0 ? EYES_LEFT : EYES_RIGHT); + BOOST_CHECK_EQUAL (i->frame.index(), j / 2); + BOOST_CHECK_EQUAL (i->frame.eyes(), (j % 2) == 0 ? EYES_LEFT : EYES_RIGHT); ++i; } decoder.video->_decoded.clear (); - decoder.video->fill_both_eyes (0, EYES_LEFT, 7, EYES_RIGHT); + decoder.video->fill_both_eyes (VideoFrame (0, EYES_LEFT), VideoFrame (7, EYES_RIGHT)); BOOST_CHECK_EQUAL (decoder.video->_decoded.size(), 15); i = decoder.video->_decoded.begin(); for (int j = 0; j < 15; ++j) { - BOOST_CHECK_EQUAL (i->frame, j / 2); - BOOST_CHECK_EQUAL (i->eyes, (j % 2) == 0 ? EYES_LEFT : EYES_RIGHT); + BOOST_CHECK_EQUAL (i->frame.index(), j / 2); + BOOST_CHECK_EQUAL (i->frame.eyes(), (j % 2) == 0 ? EYES_LEFT : EYES_RIGHT); ++i; } decoder.video->_decoded.clear (); - decoder.video->fill_both_eyes (0, EYES_RIGHT, 7, EYES_RIGHT); + decoder.video->fill_both_eyes (VideoFrame (0, EYES_RIGHT), VideoFrame (7, EYES_RIGHT)); BOOST_CHECK_EQUAL (decoder.video->_decoded.size(), 14); i = decoder.video->_decoded.begin(); for (int j = 0; j < 14; ++j) { - BOOST_CHECK_EQUAL (i->frame, (j + 1) / 2); - BOOST_CHECK_EQUAL (i->eyes, (j % 2) == 0 ? EYES_RIGHT : EYES_LEFT); + BOOST_CHECK_EQUAL (i->frame.index(), (j + 1) / 2); + BOOST_CHECK_EQUAL (i->frame.eyes(), (j % 2) == 0 ? EYES_RIGHT : EYES_LEFT); ++i; } }