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