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