1 /**
2  * @file
3  * @brief Header file for the FrameMapper class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  *
6  * @ref License
7  */
8 
9 /* LICENSE
10  *
11  * Copyright (c) 2008-2019 OpenShot Studios, LLC
12  * <http://www.openshotstudios.com/>. This file is part of
13  * OpenShot Library (libopenshot), an open-source project dedicated to
14  * delivering high quality video editing and animation solutions to the
15  * world. For more information visit <http://www.openshot.org/>.
16  *
17  * OpenShot Library (libopenshot) is free software: you can redistribute it
18  * and/or modify it under the terms of the GNU Lesser General Public License
19  * as published by the Free Software Foundation, either version 3 of the
20  * License, or (at your option) any later version.
21  *
22  * OpenShot Library (libopenshot) is distributed in the hope that it will be
23  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 #ifndef OPENSHOT_FRAMEMAPPER_H
32 #define OPENSHOT_FRAMEMAPPER_H
33 
34 #include <assert.h>
35 #include <iostream>
36 #include <cmath>
37 #include <vector>
38 #include <memory>
39 #include "CacheMemory.h"
40 #include "ReaderBase.h"
41 #include "Frame.h"
42 #include "Fraction.h"
43 #include "KeyFrame.h"
44 
45 
46 // Include FFmpeg headers and macros
47 #include "FFmpegUtilities.h"
48 #include "OpenMPUtilities.h"
49 
50 
51 namespace openshot
52 {
53 	/**
54 	 * @brief This enumeration determines how frame rates are increased or decreased.
55 	 *
56 	 * Pull-down techniques are only needed to remove artificial fields added when converting
57 	 * between 24 fps (film) and television fps (29.97 fps NTSC or 25 fps PAL).
58 	 */
59 	enum PulldownType
60 	{
61 		PULLDOWN_CLASSIC,	///< Classic 2:3:2:3 pull-down
62 		PULLDOWN_ADVANCED,	///< Advanced 2:3:3:2 pull-down (minimal dirty frames)
63 		PULLDOWN_NONE,		///< Do not apply pull-down techniques, just repeat or skip entire frames
64 	};
65 
66 	/**
67 	 * @brief This struct holds a single field (half a frame).
68 	 *
69 	 * A frame of video is made up of 2 fields (half a frame).  This struct points to which original
70 	 * frame, and whether this is the ODD or EVEN lines (i.e. top or bottom).
71 	 */
72 	struct Field
73 	{
74 		int64_t Frame;
75 		bool isOdd;
76 
FieldField77 		Field() : Frame(0), isOdd(true) { };
78 
FieldField79 		Field(int64_t frame, bool isodd)
80 		{
81 			Frame = frame;
82 			isOdd = isodd;
83 		}
84 	};
85 
86 	/**
87 	 * @brief This struct holds a the range of samples needed by this frame
88 	 *
89 	 * When frame rate is changed, the audio needs to be redistributed among the remaining
90 	 * frames.  This struct holds the range samples needed by the this frame.
91 	 */
92 	struct SampleRange
93 	{
94 		int64_t frame_start;
95 		int sample_start;
96 
97 		int64_t frame_end;
98 		int sample_end;
99 
100 		int total;
101 	};
102 
103 	/**
104 	 * @brief This struct holds two fields which together make up a complete video frame.
105 	 *
106 	 * These fields can point at different original frame numbers, for example the odd lines from
107 	 * frame 3, and the even lines of frame 4, if required by a pull-down technique.
108 	 */
109 	struct MappedFrame
110 	{
111 		Field Odd;
112 		Field Even;
113 		SampleRange Samples;
114 	};
115 
116 
117 	/**
118 	 * @brief This class creates a mapping between 2 different frame rates, applying a specific pull-down technique.
119 	 *
120 	 * This class creates a mapping between 2 different video files, and supports many pull-down techniques,
121 	 * such as 2:3:2:3 or 2:3:3:2, and also supports inverse telecine. Pull-down techniques are only needed to remove
122 	 * artificial fields added when converting between 24 fps (film) and television fps (29.97 fps NTSC or 25 fps PAL).
123 	 *
124 	 * The <b>following graphic</b> displays a how frame rates are mapped, and how time remapping affects the order
125 	 * of frames returned from the FrameMapper.
126 	 * \image html /doc/images/FrameMapper.png
127 	 *
128 	 * Please see the following <b>Example Code</b>:
129 	 * \code
130 	 * // Create a frame mapper for a reader, and convert the frame rate (from 24 fps to 29.97 fps)
131 	 * FrameMapper mapping(reader, Fraction(30000, 1001), PULLDOWN_CLASSIC, 44100, 2, LAYOUT_STEREO);
132 	 * std::shared_ptr<Frame> frame2 = mapping.GetFrame(2);
133 
134 	 * // If you need to change the mapping...
135 	 * mapping.ChangeMapping(Fraction(24, 1), PULLDOWN_CLASSIC, 48000, 2, LAYOUT_MONO)
136 	 * \endcode
137 	 */
138 	class FrameMapper : public ReaderBase {
139 	private:
140 		bool field_toggle;		// Internal odd / even toggle (used when building the mapping)
141 		Fraction original;		// The original frame rate
142 		Fraction target;		// The target frame rate
143 		PulldownType pulldown;	// The pull-down technique
144 		ReaderBase *reader;		// The source video reader
145 		CacheMemory final_cache; 		// Cache of actual Frame objects
146 		bool is_dirty; 			// When this is true, the next call to GetFrame will re-init the mapping
147 		float parent_position;  // Position of parent clip (which is used to generate the audio mapping)
148 		float parent_start;     // Start of parent clip (which is used to generate the audio mapping)
149 		SWRCONTEXT *avr;	// Audio resampling context object
150 
151 		// Internal methods used by init
152 		void AddField(int64_t frame);
153 		void AddField(Field field);
154 
155 		// Get Frame or Generate Blank Frame
156 		std::shared_ptr<Frame> GetOrCreateFrame(int64_t number);
157 
158 		/// Adjust frame number for Clip position and start (which can result in a different number)
159 		int64_t AdjustFrameNumber(int64_t clip_frame_number);
160 
161 		// Use the original and target frame rates and a pull-down technique to create
162 		// a mapping between the original fields and frames or a video to a new frame rate.
163 		// This might repeat or skip fields and frames of the original video, depending on
164 		// whether the frame rate is increasing or decreasing.
165 		void Init();
166 
167 	public:
168 		// Init some containers
169 		std::vector<Field> fields;		// List of all fields
170 		std::vector<MappedFrame> frames;	// List of all frames
171 
172 		/// Default constructor for openshot::FrameMapper class
173 		FrameMapper(ReaderBase *reader, Fraction target_fps, PulldownType target_pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout);
174 
175 		/// Destructor
176 		virtual ~FrameMapper();
177 
178 		/// Change frame rate or audio mapping details
179 		void ChangeMapping(Fraction target_fps, PulldownType pulldown,  int target_sample_rate, int target_channels, ChannelLayout target_channel_layout);
180 
181 		/// Close the openshot::FrameMapper and internal reader
182 		void Close() override;
183 
184 		/// Get a frame based on the target frame rate and the new frame number of a frame
185 		MappedFrame GetMappedFrame(int64_t TargetFrameNumber);
186 
187 		/// Get the cache object used by this reader
GetCache()188 		CacheMemory* GetCache() override { return &final_cache; };
189 
190 		/// @brief This method is required for all derived classes of ReaderBase, and return the
191 		/// openshot::Frame object, which contains the image and audio information for that
192 		/// frame of video.
193 		///
194 		/// @returns The requested frame of video
195 		/// @param requested_frame The frame number that is requested.
196 		std::shared_ptr<Frame> GetFrame(int64_t requested_frame) override;
197 
198 		/// Determine if reader is open or closed
199 		bool IsOpen() override;
200 
201 		/// Return the type name of the class
Name()202 		std::string Name() override { return "FrameMapper"; };
203 
204 		// Get and Set JSON methods
205 		std::string Json() const override; ///< Generate JSON string of this object
206 		void SetJson(const std::string value) override; ///< Load JSON string into this object
207 		Json::Value JsonValue() const override; ///< Generate Json::Value for this object
208 		void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object
209 
210 		/// Open the internal reader
211 		void Open() override;
212 
213 		/// Print all of the original frames and which new frames they map to
214 		void PrintMapping();
215 
216 		/// Get the current reader
217 		ReaderBase* Reader();
218 
219 		/// Set the current reader
Reader(ReaderBase * new_reader)220 		void Reader(ReaderBase *new_reader) { reader = new_reader; }
221 
222 		/// Resample audio and map channels (if needed)
223 		void ResampleMappedAudio(std::shared_ptr<Frame> frame, int64_t original_frame_number);
224 	};
225 }
226 
227 #endif
228