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