xref: /haiku/src/add-ons/media/plugins/ffmpeg/Utilities.h (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 pixelChunk;
181 	size_t rowAlignment;
182 	size_t pixelsPerChunk;
183 
184 	if (get_pixel_size_for(colorSpace, &pixelChunk, &rowAlignment, &pixelsPerChunk) != B_OK)
185 		return kBytesPerRowUnknown;
186 
187 	uint32 bytesPerRow = pixelChunk * videoWidth / pixelsPerChunk;
188 	uint32 numberOfUnalignedBytes = bytesPerRow % rowAlignment;
189 
190 	if (numberOfUnalignedBytes == 0)
191 		return bytesPerRow;
192 
193 	uint32 numberOfBytesNeededForAlignment = rowAlignment - numberOfUnalignedBytes;
194 	bytesPerRow += numberOfBytesNeededForAlignment;
195 
196 	return bytesPerRow;
197 }
198 
199 
200 /*! \brief Converts FFmpeg notation of video frame rate into the Media Kits
201 		notation.
202 
203 	\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
204 		direction.
205 
206 	\param contextIn An AVCodeContext structure of FFmpeg containing the values
207 		needed to calculate the Media Kit video frame rate.
208 		The following fields are used for the calculation:
209 			- AVCodecContext.time_base.num (must)
210 			- AVCodecContext.time_base.den (must)
211 			- AVCodecContext.ticks_per_frame (must)
212 	\param frameRateOut On return contains Media Kits notation of the video
213 		frame rate.
214 */
215 inline void
216 ConvertAVCodecContextToVideoFrameRate(AVCodecContext& contextIn, float& frameRateOut)
217 {
218 	// assert that av_q2d(contextIn.time_base) > 0 and computable
219 	assert(contextIn.time_base.num > 0);
220 	assert(contextIn.time_base.den > 0);
221 
222 	// The following code is based on private get_fps() function of FFmpeg's
223 	// ratecontrol.c:
224 	// https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2012-April/049280.html
225 	double possiblyInterlacedFrameRate = 1.0 / av_q2d(contextIn.time_base);
226 	double numberOfInterlacedFramesPerFullFrame = FFMAX(contextIn.ticks_per_frame, 1);
227 
228 	frameRateOut
229 		= possiblyInterlacedFrameRate / numberOfInterlacedFramesPerFullFrame;
230 }
231 
232 
233 /*!	\brief Converts the Media Kits notation of video frame rate to FFmpegs
234 	notation.
235 
236 	\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
237 		direction.
238 
239 	\param frameRateIn Contains Media Kits notation of the video frame rate
240 		that will be converted into FFmpegs notation. Must be greater than
241 		zero.
242 	\param contextOut An AVCodecContext structure of FFmpeg.
243 		On output contains converted values in the following fields (other
244 		fields stay as they were on input):
245 			- AVCodecContext.time_base.num
246 			- AVCodecContext.time_base.den
247 			- AVCodecContext.ticks_per_frame is set to 1
248 */
249 inline void
250 ConvertVideoFrameRateToAVCodecContext(float frameRateIn,
251 	AVCodecContext& contextOut)
252 {
253 	assert(frameRateIn > 0);
254 
255 	contextOut.ticks_per_frame = 1;
256 	contextOut.time_base = av_d2q(1.0 / frameRateIn, 1024);
257 }
258 
259 
260 /*!	\brief Converts the Media Kits notation of an audio sample format to
261 		FFmpegs notation.
262 
263 	\see ConvertAVSampleFormatToRawAudioFormat() for converting in the other
264 		direction.
265 
266 	\param rawAudioFormatIn Contains Media Kits notation of an audio sample
267 		format that will be converted into FFmpegs notation.
268 	\param sampleFormatOut On output contains FFmpegs notation of the passed
269 		audio sample format. Might return AV_SAMPLE_FMT_NONE if there is no
270 		conversion path.
271 */
272 inline void
273 ConvertRawAudioFormatToAVSampleFormat(uint32 rawAudioFormatIn,
274 	AVSampleFormat& sampleFormatOut)
275 {
276 	switch (rawAudioFormatIn) {
277 		case media_raw_audio_format::B_AUDIO_FLOAT:
278 			sampleFormatOut = AV_SAMPLE_FMT_FLT;
279 			return;
280 
281 		case media_raw_audio_format::B_AUDIO_DOUBLE:
282 			sampleFormatOut = AV_SAMPLE_FMT_DBL;
283 			return;
284 
285 		case media_raw_audio_format::B_AUDIO_INT:
286 			sampleFormatOut = AV_SAMPLE_FMT_S32;
287 			return;
288 
289 		case media_raw_audio_format::B_AUDIO_SHORT:
290 			sampleFormatOut = AV_SAMPLE_FMT_S16;
291 			return;
292 
293 		case media_raw_audio_format::B_AUDIO_UCHAR:
294 			sampleFormatOut = AV_SAMPLE_FMT_U8;
295 			return;
296 
297 		default:
298 			// Silence compiler warnings about unhandled enumeration values.
299 			break;
300 	}
301 
302 	sampleFormatOut = AV_SAMPLE_FMT_NONE;
303 }
304 
305 
306 /*!	\brief Converts FFmpegs notation of an audio sample format to the Media
307 		Kits notation.
308 
309 	\see ConvertAVSampleFormatToRawAudioFormat() for converting in the other
310 		direction.
311 
312 	\param sampleFormatIn Contains FFmpegs notation of an audio sample format
313 		that will be converted into the Media Kits notation.
314 	\param rawAudioFormatOut On output contains Media Kits notation of the
315 		passed audio sample format. Might return 0 if there is no conversion
316 		path.
317 */
318 inline void
319 ConvertAVSampleFormatToRawAudioFormat(AVSampleFormat sampleFormatIn,
320 	uint32& rawAudioFormatOut)
321 {
322 	switch (sampleFormatIn) {
323 		case AV_SAMPLE_FMT_FLT:
324 		case AV_SAMPLE_FMT_FLTP:
325 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_FLOAT;
326 			return;
327 
328 		case AV_SAMPLE_FMT_DBL:
329 		case AV_SAMPLE_FMT_DBLP:
330 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_DOUBLE;
331 			return;
332 
333 		case AV_SAMPLE_FMT_S32:
334 		case AV_SAMPLE_FMT_S32P:
335 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_INT;
336 			return;
337 
338 		case AV_SAMPLE_FMT_S16:
339 		case AV_SAMPLE_FMT_S16P:
340 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_SHORT;
341 			return;
342 
343 		case AV_SAMPLE_FMT_U8:
344 		case AV_SAMPLE_FMT_U8P:
345 			rawAudioFormatOut = media_raw_audio_format::B_AUDIO_UCHAR;
346 			return;
347 
348 		default:
349 			// Silence compiler warnings about unhandled enumeration values.
350 			break;
351 	}
352 
353 	const uint32 kBAudioNone = 0;
354 	rawAudioFormatOut = kBAudioNone;
355 }
356 
357 
358 #endif // UTILITIES_H
359