Use dcp::file_to_string().
[dcpomatic.git] / src / lib / video_decoder.cc
1 /*
2     Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "compose.hpp"
23 #include "film.h"
24 #include "frame_interval_checker.h"
25 #include "image.h"
26 #include "j2k_image_proxy.h"
27 #include "log.h"
28 #include "raw_image_proxy.h"
29 #include "video_decoder.h"
30 #include <iostream>
31
32 #include "i18n.h"
33
34
35 using std::back_inserter;
36 using std::cout;
37 using std::dynamic_pointer_cast;
38 using std::list;
39 using std::make_shared;
40 using std::max;
41 using std::shared_ptr;
42 using boost::optional;
43 using namespace dcpomatic;
44
45
46 VideoDecoder::VideoDecoder (Decoder* parent, shared_ptr<const Content> c)
47         : DecoderPart (parent)
48         , _content (c)
49         , _frame_interval_checker (new FrameIntervalChecker())
50 {
51
52 }
53
54
55 /** Called by decoder classes when they have a video frame ready.
56  *  @param frame Frame index within the content; this does not take into account 3D
57  *  so for 3D_ALTERNATE this value goes:
58  *     0: frame 0 left
59  *     1: frame 0 right
60  *     2: frame 1 left
61  *     3: frame 1 right
62  *  and so on.
63  */
64 void
65 VideoDecoder::emit (shared_ptr<const Film> film, shared_ptr<const ImageProxy> image, Frame decoder_frame)
66 {
67         if (ignore ()) {
68                 return;
69         }
70
71         auto const afr = _content->active_video_frame_rate(film);
72         auto const vft = _content->video->frame_type();
73
74         auto frame_time = ContentTime::from_frames (decoder_frame, afr);
75
76         /* Do some heuristics to try and spot the case where the user sets content to 3D
77          * when it is not.  We try to tell this by looking at the differences in time between
78          * the first few frames.  Real 3D content should have two frames for each timestamp.
79          */
80         if (_frame_interval_checker) {
81                 _frame_interval_checker->feed (frame_time, afr);
82                 if (_frame_interval_checker->guess() == FrameIntervalChecker::PROBABLY_NOT_3D && vft == VideoFrameType::THREE_D) {
83                         boost::throw_exception (
84                                 DecodeError(
85                                         String::compose(
86                                                 _("The content file %1 is set as 3D but does not appear to contain 3D images.  Please set it to 2D.  "
87                                                   "You can still make a 3D DCP from this content by ticking the 3D option in the DCP video tab."),
88                                                 _content->path(0)
89                                                 )
90                                         )
91                                 );
92                 }
93
94                 if (_frame_interval_checker->guess() != FrameIntervalChecker::AGAIN) {
95                         _frame_interval_checker.reset ();
96                 }
97         }
98
99         Frame frame;
100         Eyes eyes = Eyes::BOTH;
101         if (!_position) {
102                 /* This is the first data we have received since initialisation or seek.  Set
103                    the position based on the frame that was given.  After this first time
104                    we just cound frames, since (as with audio) it seems that ContentTimes
105                    are unreliable from FFmpegDecoder.  They are much better than audio times
106                    but still we get the occasional one which is duplicated.  In this case
107                    ffmpeg seems to carry on regardless, processing the video frame as normal.
108                    If we drop the frame with the duplicated timestamp we obviously lose sync.
109                 */
110
111                 if (vft == VideoFrameType::THREE_D_ALTERNATE) {
112                         frame = decoder_frame / 2;
113                         eyes = (decoder_frame % 1) ? Eyes::RIGHT : Eyes::LEFT;
114                 } else {
115                         frame = decoder_frame;
116                         if (vft == VideoFrameType::THREE_D) {
117                                 auto j2k = dynamic_pointer_cast<const J2KImageProxy>(image);
118                                 /* At the moment only DCP decoders producers VideoFrameType::THREE_D, so only the J2KImageProxy
119                                  * knows which eye it is.
120                                  */
121                                 if (j2k && j2k->eye()) {
122                                         eyes = j2k->eye().get() == dcp::Eye::LEFT ? Eyes::LEFT : Eyes::RIGHT;
123                                 }
124                         }
125                 }
126
127                 _position = ContentTime::from_frames (frame, afr);
128         } else {
129                 if (vft == VideoFrameType::THREE_D) {
130                         auto j2k = dynamic_pointer_cast<const J2KImageProxy>(image);
131                         if (j2k && j2k->eye()) {
132                                 if (j2k->eye() == dcp::Eye::LEFT) {
133                                         frame = _position->frames_round(afr) + 1;
134                                         eyes = Eyes::LEFT;
135                                 } else {
136                                         frame = _position->frames_round(afr);
137                                         eyes = Eyes::RIGHT;
138                                 }
139                         } else {
140                                 /* This should not happen; see above */
141                                 frame = _position->frames_round(afr) + 1;
142                         }
143                 } else if (vft == VideoFrameType::THREE_D_ALTERNATE) {
144                         DCPOMATIC_ASSERT (_last_emitted_eyes);
145                         if (_last_emitted_eyes.get() == Eyes::RIGHT) {
146                                 frame = _position->frames_round(afr) + 1;
147                                 eyes = Eyes::LEFT;
148                         } else {
149                                 frame = _position->frames_round(afr);
150                                 eyes = Eyes::RIGHT;
151                         }
152                 } else {
153                         frame = _position->frames_round(afr) + 1;
154                 }
155         }
156
157         switch (vft) {
158         case VideoFrameType::TWO_D:
159         case VideoFrameType::THREE_D:
160                 Data (ContentVideo (image, frame, eyes, Part::WHOLE));
161                 break;
162         case VideoFrameType::THREE_D_ALTERNATE:
163         {
164                 Data (ContentVideo (image, frame, eyes, Part::WHOLE));
165                 _last_emitted_eyes = eyes;
166                 break;
167         }
168         case VideoFrameType::THREE_D_LEFT_RIGHT:
169                 Data (ContentVideo (image, frame, Eyes::LEFT, Part::LEFT_HALF));
170                 Data (ContentVideo (image, frame, Eyes::RIGHT, Part::RIGHT_HALF));
171                 break;
172         case VideoFrameType::THREE_D_TOP_BOTTOM:
173                 Data (ContentVideo (image, frame, Eyes::LEFT, Part::TOP_HALF));
174                 Data (ContentVideo (image, frame, Eyes::RIGHT, Part::BOTTOM_HALF));
175                 break;
176         case VideoFrameType::THREE_D_LEFT:
177                 Data (ContentVideo (image, frame, Eyes::LEFT, Part::WHOLE));
178                 break;
179         case VideoFrameType::THREE_D_RIGHT:
180                 Data (ContentVideo (image, frame, Eyes::RIGHT, Part::WHOLE));
181                 break;
182         default:
183                 DCPOMATIC_ASSERT (false);
184         }
185
186         _position = ContentTime::from_frames (frame, afr);
187 }
188
189
190 void
191 VideoDecoder::seek ()
192 {
193         _position = boost::none;
194         _last_emitted_eyes.reset ();
195         _frame_interval_checker.reset (new FrameIntervalChecker());
196 }