xref: /haiku/src/add-ons/media/plugins/ffmpeg/Utilities.h (revision 5629675a326ecf2ff3fd23f154beb525c171048d)
1 /*
2  * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
3  * Copyright 2014, Colin Günther <coling@gmx.de>
4  * Copyright 2018, Dario Casalinuovo
5  * All rights reserved. Distributed under the terms of the GNU L-GPL license.
6  */
7 #ifndef UTILITIES_H
8 #define UTILITIES_H
9 
10 
11 /*! \brief This file contains functions to convert and calculate values from
12 		FFmpeg to Media Kit and vice versa.
13 */
14 
15 
16 #include <assert.h>
17 
18 #include <GraphicsDefs.h>
19 
20 extern "C" {
21 	#include "avcodec.h"
22 }
23 
24 
25 /*! \brief Converts FFmpeg notation of video aspect ratio into the Media Kits
26 		notation.
27 
28 	\see ConvertVideoAspectWidthAndHeightToAVCodecContext() for converting in
29 		the other direction.
30 
31 	\param contextIn An AVCodeContext structure of FFmpeg containing the values
32 		needed to calculate the Media Kit video aspect ratio.
33 		The following fields are used for the calculation:
34 			- AVCodecContext.sample_aspect_ratio.num (optional)
35 			- AVCodecContext.sample_aspect_ratio.den (optional)
36 			- AVCodecContext.width (must)
37 			- AVCodecContext.height (must)
38 	\param pixelWidthAspectOut On return contains Media Kits notation of the
39 		video aspect ratio width. E.g. 16:9 -> 16 is returned here
40 	\param pixelHeightAspectOut On return contains Media Kits notation of the
41 		video aspect ratio height. E.g. 16:9 -> 9 is returned here
42 */
43 inline void
44 ConvertAVCodecContextToVideoAspectWidthAndHeight(AVCodecContext& contextIn,
45 	uint16& pixelWidthAspectOut, uint16& pixelHeightAspectOut)
46 {
47 	assert(contextIn.sample_aspect_ratio.num >= 0);
48 	assert(contextIn.width > 0);
49 	assert(contextIn.height > 0);
50 
51 	// The following code is based on code originally located in
52 	// AVFormatReader::Stream::Init() and thus should be copyrighted to Stephan
53 	// Aßmus
54 	AVRational pixelAspectRatio;
55 
56 	if (contextIn.sample_aspect_ratio.num == 0
57 		|| contextIn.sample_aspect_ratio.den == 0) {
58 		// AVCodecContext doesn't contain a video aspect ratio, so calculate it
59 		// ourselve based solely on the video dimensions
60 		av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, contextIn.width,
61 			contextIn.height, 1024 * 1024);
62 
63 		pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
64 		pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
65 		return;
66 	}
67 
68 	// AVCodecContext contains a video aspect ratio, so use it
69 	av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den,
70 		contextIn.width * contextIn.sample_aspect_ratio.num,
71 		contextIn.height * contextIn.sample_aspect_ratio.den,
72 		1024 * 1024);
73 
74 	pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
75 	pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
76 }
77 
78 
79 inline void
80 ConvertAVCodecParametersToVideoAspectWidthAndHeight(AVCodecParameters& parametersIn,
81 	uint16& pixelWidthAspectOut, uint16& pixelHeightAspectOut)
82 {
83 	assert(parametersIn.sample_aspect_ratio.num >= 0);
84 	assert(parametersIn.width > 0);
85 	assert(parametersIn.height > 0);
86 
87 	// The following code is based on code originally located in
88 	// AVFormatReader::Stream::Init() and thus should be copyrighted to Stephan
89 	// Aßmus
90 	AVRational pixelAspectRatio;
91 
92 	if (parametersIn.sample_aspect_ratio.num == 0
93 		|| parametersIn.sample_aspect_ratio.den == 0) {
94 		// AVCodecContext doesn't contain a video aspect ratio, so calculate it
95 		// ourselve based solely on the video dimensions
96 		av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, parametersIn.width,
97 			parametersIn.height, 1024 * 1024);
98 
99 		pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
100 		pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
101 		return;
102 	}
103 
104 	// AVCodecContext contains a video aspect ratio, so use it
105 	av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den,
106 		parametersIn.width * parametersIn.sample_aspect_ratio.num,
107 		parametersIn.height * parametersIn.sample_aspect_ratio.den,
108 		1024 * 1024);
109 
110 	pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
111 	pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
112 }
113 
114 
115 /*!	\brief Converts the Media Kits notation of video aspect ratio into FFmpegs
116 		notation.
117 
118 	\see ConvertAVCodecContextToVideoAspectWidthAndHeight() for converting in
119 		the other direction.
120 
121 	\param pixelWidthAspectIn Contains Media Kits notation of the video aspect
122 		ratio width. E.g. 16:9 -> 16 is passed here.
123 	\param pixelHeightAspectIn Contains Media Kits notation of the video aspect
124 		ratio height. E.g. 16:9 -> 9 is passed here.
125 	\param contextInOut	An AVCodecContext structure of FFmpeg.
126 		On input must contain the following fields already initialized
127 		otherwise the behaviour is undefined:
128 			- AVCodecContext.width (must)
129 			- AVCodecContext.height (must)
130 		On output contains converted values in the following fields (other
131 		fields stay as they were on input):
132 			- AVCodecContext.sample_aspect_ratio.num
133 			- AVCodecContext.sample_aspect_ratio.den
134 */
135 inline void
136 ConvertVideoAspectWidthAndHeightToAVCodecContext(uint16 pixelWidthAspectIn,
137 	uint16 pixelHeightAspectIn, AVCodecContext& contextInOut)
138 {
139 	assert(pixelWidthAspectIn > 0);
140 	assert(pixelHeightAspectIn > 0);
141 	assert(contextInOut.width > 0);
142 	assert(contextInOut.height > 0);
143 
144 	AVRational pureVideoDimensionAspectRatio;
145 	av_reduce(&pureVideoDimensionAspectRatio.num,
146 		&pureVideoDimensionAspectRatio.den, contextInOut.width,
147 		contextInOut.height, 1024 * 1024);
148 
149 	if (pureVideoDimensionAspectRatio.num == pixelWidthAspectIn
150 		&& pureVideoDimensionAspectRatio.den == pixelHeightAspectIn) {
151 		// The passed Media Kit pixel aspect ratio equals the video dimension
152 		// aspect ratio. Set sample_aspect_ratio to "ignore".
153 		contextInOut.sample_aspect_ratio.num = 0;
154 		contextInOut.sample_aspect_ratio.den = 1;
155 		return;
156 	}
157 
158 	av_reduce(&contextInOut.sample_aspect_ratio.num,
159 		&contextInOut.sample_aspect_ratio.den,
160 		contextInOut.height * pixelWidthAspectIn,
161 		contextInOut.width * pixelHeightAspectIn,
162 		1024 * 1024);
163 }
164 
165 
166 /*! \brief Calculates bytes per row for a video frame.
167 
168 	\param colorSpace The Media Kit color space the video frame uses.
169 	\param videoWidth The width of the video frame.
170 
171 	\returns bytes per video frame row
172 	\returns Zero, when bytes per video frame cannot be calculated.
173 */
174 inline uint32
175 CalculateBytesPerRowWithColorSpaceAndVideoWidth(color_space colorSpace, int videoWidth)
176 {
177 	assert(videoWidth >= 0);
178 
179 	const uint32 kBytesPerRowUnknown = 0;
180 	size_t bytesPerPixel;
181 	size_t rowAlignment;
182 
183 	if (get_pixel_size_for(colorSpace, &bytesPerPixel, &rowAlignment, NULL) != B_OK)
184 		return kBytesPerRowUnknown;
185 
186 	uint32 bytesPerRow = bytesPerPixel * videoWidth;
187 	uint32 numberOfUnalignedBytes = bytesPerRow % rowAlignment;
188 
189 	if (numberOfUnalignedBytes == 0)
190 		return bytesPerRow;
191 
192 	uint32 numberOfBytesNeededForAlignment = rowAlignment - numberOfUnalignedBytes;
193 	bytesPerRow += numberOfBytesNeededForAlignment;
194 
195 	return bytesPerRow;
196 }
197 
198 
199 /*! \brief Converts FFmpeg notation of video frame rate into the Media Kits
200 		notation.
201 
202 	\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
203 		direction.
204 
205 	\param contextIn An AVCodeContext structure of FFmpeg containing the values
206 		needed to calculate the Media Kit video frame rate.
207 		The following fields are used for the calculation:
208 			- AVCodecContext.time_base.num (must)
209 			- AVCodecContext.time_base.den (must)
210 			- AVCodecContext.ticks_per_frame (must)
211 	\param frameRateOut On return contains Media Kits notation of the video
212 		frame rate.
213 */
214 inline void
215 ConvertAVCodecContextToVideoFrameRate(AVCodecContext& contextIn, float& frameRateOut)
216 {
217 	// assert that av_q2d(contextIn.time_base) > 0 and computable
218 	assert(contextIn.time_base.num > 0);
219 	assert(contextIn.time_base.den > 0);
220 
221 	// The following code is based on private get_fps() function of FFmpeg's
222 	// ratecontrol.c:
223 	// https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2012-April/049280.html
224 	double possiblyInterlacedFrameRate = 1.0 / av_q2d(contextIn.time_base);
225 	double numberOfInterlacedFramesPerFullFrame = FFMAX(contextIn.ticks_per_frame, 1);
226 
227 	frameRateOut
228 		= possiblyInterlacedFrameRate / numberOfInterlacedFramesPerFullFrame;
229 }
230 
231 
232 /*!	\brief Converts the Media Kits notation of video frame rate to FFmpegs
233 	notation.
234 
235 	\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
236 		direction.
237 
238 	\param frameRateIn Contains Media Kits notation of the video frame rate
239 		that will be converted into FFmpegs notation. Must be greater than
240 		zero.
241 	\param contextOut An AVCodecContext structure of FFmpeg.
242 		On output contains converted values in the following fields (other
243 		fields stay as they were on input):
244 			- AVCodecContext.time_base.num
245 			- AVCodecContext.time_base.den
246 			- AVCodecContext.ticks_per_frame is set to 1
247 */
248 inline void
249 ConvertVideoFrameRateToAVCodecContext(float frameRateIn,
250 	AVCodecContext& contextOut)
251 {
252 	assert(frameRateIn > 0);
253 
254 	contextOut.ticks_per_frame = 1;
255 	contextOut.time_base = av_d2q(1.0 / frameRateIn, 1024);
256 }
257 
258 
259 /*!	\brief Converts the Media Kits notation of an audio sample format to
260 		FFmpegs notation.
261 
262 	\see ConvertAVSampleFormatToRawAudioFormat() for converting in the other
263 		direction.
264 
265 	\param rawAudioFormatIn Contains Media Kits notation of an audio sample
266 		format that will be converted into FFmpegs notation.
267 	\param sampleFormatOut On output contains FFmpegs notation of the passed
268 		audio sample format. Might return AV_SAMPLE_FMT_NONE if there is no
269 		conversion path.
270 */
271 inline void
272 ConvertRawAudioFormatToAVSampleFormat(uint32 rawAudioFormatIn,
273 	AVSampleFormat& sampleFormatOut)
274 {
275 	switch (rawAudioFormatIn) {
276 		case media_raw_audio_format::B_AUDIO_FLOAT:
277 			sampleFormatOut = AV_SAMPLE_FMT_FLT;
278 			return;
279 
280 		case media_raw_audio_format::B_AUDIO_DOUBLE:
281 			sampleFormatOut = AV_SAMPLE_FMT_DBL;
282 			return;
283 
284 		case media_raw_audio_format::B_AUDIO_INT:
285 			sampleFormatOut = AV_SAMPLE_FMT_S32;
286 			return;
287 
288 		case media_raw_audio_format::B_AUDIO_SHORT:
289 			sampleFormatOut = AV_SAMPLE_FMT_S16;
290 			return;
291 
292 		case media_raw_audio_format::B_AUDIO_UCHAR:
293 			sampleFormatOut = AV_SAMPLE_FMT_U8;
294 			return;
295 
296 		default:
297 			// Silence compiler warnings about unhandled enumeration values.
298 			break;
299 	}
300 
301 	sampleFormatOut = AV_SAMPLE_FMT_NONE;
302 }
303 
304 
305 /*!	\brief Converts FFmpegs notation of an audio sample format to the Media
306 		Kits notation.
307 
308 	\see ConvertAVSampleFormatToRawAudioFormat() for converting in the other
309 		direction.
310 
311 	\param sampleFormatIn Contains FFmpegs notation of an audio sample format
312 		that will be converted into the Media Kits notation.
313 	\param rawAudioFormatOut On output contains Media Kits notation of the
314 		passed audio sample format. Might return 0 if there is no conversion
315 		path.
316 */
317 inline void
318 ConvertAVSampleFormatToRawAudioFormat(AVSampleFormat sampleFormatIn,
319 	uint32& rawAudioFormatOut)
320 {
321 	switch (sampleFormatIn) {
322 		case AV_SAMPLE_FMT_FLT:
323 		case AV_SAMPLE_FMT_FLTP:
324 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_FLOAT;
325 			return;
326 
327 		case AV_SAMPLE_FMT_DBL:
328 		case AV_SAMPLE_FMT_DBLP:
329 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_DOUBLE;
330 			return;
331 
332 		case AV_SAMPLE_FMT_S32:
333 		case AV_SAMPLE_FMT_S32P:
334 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_INT;
335 			return;
336 
337 		case AV_SAMPLE_FMT_S16:
338 		case AV_SAMPLE_FMT_S16P:
339 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_SHORT;
340 			return;
341 
342 		case AV_SAMPLE_FMT_U8:
343 		case AV_SAMPLE_FMT_U8P:
344 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_UCHAR;
345 			return;
346 
347 		default:
348 			// Silence compiler warnings about unhandled enumeration values.
349 			break;
350 	}
351 
352 	const uint32 kBAudioNone = 0;
353 	rawAudioFormatOut = kBAudioNone;
354 }
355 
356 
357 #endif // UTILITIES_H
358