Add VideoFrame class.
authorCarl Hetherington <cth@carlh.net>
Tue, 14 Jun 2016 10:48:37 +0000 (11:48 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 14 Jun 2016 10:48:37 +0000 (11:48 +0100)
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.

src/lib/content_video.h
src/lib/player.cc
src/lib/video_decoder.cc
src/lib/video_decoder.h
src/lib/video_frame.cc [new file with mode: 0644]
src/lib/video_frame.h [new file with mode: 0644]
src/lib/wscript
test/ffmpeg_decoder_seek_test.cc
test/ffmpeg_decoder_sequential_test.cc
test/seek_zero_test.cc
test/video_decoder_fill_test.cc

index 21a600709e9076e802c944c366a6fe9bbb68f54b..8e5f2fd094d408d6433fb012c3a3a35385c9375c 100644 (file)
@@ -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<const ImageProxy> i, Eyes e, Part p, Frame f)
+       ContentVideo (boost::shared_ptr<const ImageProxy> i, VideoFrame f, Part p)
                : image (i)
-               , eyes (e)
-               , part (p)
                , frame (f)
+               , part (p)
        {}
 
        boost::shared_ptr<const ImageProxy> image;
-       Eyes eyes;
+       VideoFrame frame;
        Part part;
-       Frame frame;
 };
 
 #endif
index f22a6480f224f678dc803b08fdd9844e647e9b1a..c70ac8852baf27b9b7c9ebbd6a7e3e9270e65517 100644 (file)
@@ -374,12 +374,12 @@ Player::get_video (DCPTime time, bool accurate)
                                                        shared_ptr<PlayerVideo> (
                                                                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 ()
                                                                        )
index cc6cbfc308d53ad065032f24ffc627668911d374..ec5ae8884b730cfc5f02c40f30e03ff3da2add29 100644 (file)
@@ -59,7 +59,7 @@ VideoDecoder::decoded (Frame frame)
        list<ContentVideo> 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<const ImageProxy> 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<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;
                }
@@ -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<const ImageProxy> image, Frame frame)
        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:
@@ -259,22 +253,22 @@ VideoDecoder::give (shared_ptr<const ImageProxy> 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<const ImageProxy> image, Frame frame)
           and the things we are about to push.
        */
 
-       optional<Frame> from_frame;
-       optional<Eyes> from_eye;
+       optional<VideoFrame> 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;
                }
        }
index 7c2374dd8f154eaf370022c031824f04decd5b89..69270244430d1a29fc4778026eab51fa57417580 100644 (file)
@@ -68,7 +68,7 @@ private:
 
        std::list<ContentVideo> 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<const Content> _content;
diff --git a/src/lib/video_frame.cc b/src/lib/video_frame.cc
new file mode 100644 (file)
index 0000000..e2223ff
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#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 (file)
index 0000000..abb25ec
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#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
index 22d8c4477202940aa8bdc8bcc447e35f6c512140..f5fc6f539adcde41eb5c3ae776dbd8e505263f62 100644 (file)
@@ -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
index 93c4475918f9182b08648c6482b2cf0fa38b0b88..8a854b01b7e0d8671d5e7ee3f7646730e1eceb99 100644 (file)
@@ -49,7 +49,7 @@ check (shared_ptr<FFmpegDecoder> decoder, int frame)
        list<ContentVideo> 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
index 7435a4af04d334bbd356a1c54405c603d18d53fb..6a27d698f5713997c0c0fd4d7e68caec77e8831c 100644 (file)
@@ -66,7 +66,7 @@ ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int
                list<ContentVideo> 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);
index f1f137d3864b00ef0c57ceb534e9e00309b024fe..05bf1b5bf4e519916cacb3bf263c45e1c7b72ebc 100644 (file)
@@ -67,5 +67,5 @@ BOOST_AUTO_TEST_CASE (seek_zero_test)
        FFmpegDecoder decoder (content, film->log(), false);
        list<ContentVideo> 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);
 }
index 737bc883c62486b36f40516f27d77b66850e2d68..2d783f52d72ae357d033ab70847902d98903333b 100644 (file)
@@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test1)
        BOOST_CHECK_EQUAL (decoder.video->_decoded.size(), 4U);
        list<ContentVideo>::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<ImageContent> 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<ContentVideo>::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;
        }
 }