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 FFmpeg notation of video frame rate into the Media Kits 212 notation. 213 214 \see ConvertAVCodecContextToVideoFrameRate() for converting in the other 215 direction. 216 217 \param contextIn An AVCodeContext structure of FFmpeg containing the values 218 needed to calculate the Media Kit video frame rate. 219 The following fields are used for the calculation: 220 - AVCodecContext.time_base.num (must) 221 - AVCodecContext.time_base.den (must) 222 - AVCodecContext.ticks_per_frame (must) 223 \param frameRateOut On return contains Media Kits notation of the video 224 frame rate. 225 */ 226 inline void 227 ConvertAVCodecContextToVideoFrameRate(AVCodecContext& contextIn, float& frameRateOut) 228 { 229 // A framerate of 0 is allowed for single-frame "video" (cover art, for 230 // example) 231 if (contextIn.time_base.num == 0) 232 frameRateOut = 0.0f; 233 234 // assert that we can compute something 235 assert(contextIn.time_base.den > 0); 236 237 // The following code is based on private get_fps() function of FFmpeg's 238 // ratecontrol.c: 239 // https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2012-April/049280.html 240 double possiblyInterlacedFrameRate = 1.0 / av_q2d(contextIn.time_base); 241 double numberOfInterlacedFramesPerFullFrame = FFMAX(contextIn.ticks_per_frame, 1); 242 243 frameRateOut 244 = possiblyInterlacedFrameRate / numberOfInterlacedFramesPerFullFrame; 245 } 246 247 248 /*! \brief Converts the Media Kits notation of video frame rate to FFmpegs 249 notation. 250 251 \see ConvertAVCodecContextToVideoFrameRate() for converting in the other 252 direction. 253 254 \param frameRateIn Contains Media Kits notation of the video frame rate 255 that will be converted into FFmpegs notation. Must be greater than 256 zero. 257 \param contextOut An AVCodecContext structure of FFmpeg. 258 On output contains converted values in the following fields (other 259 fields stay as they were on input): 260 - AVCodecContext.time_base.num 261 - AVCodecContext.time_base.den 262 - AVCodecContext.ticks_per_frame is set to 1 263 */ 264 inline void 265 ConvertVideoFrameRateToAVCodecContext(float frameRateIn, 266 AVCodecContext& contextOut) 267 { 268 assert(frameRateIn > 0); 269 270 contextOut.ticks_per_frame = 1; 271 contextOut.time_base = av_d2q(1.0 / frameRateIn, 1024); 272 } 273 274 275 /*! \brief Converts the Media Kits notation of an audio sample format to 276 FFmpegs notation. 277 278 \see ConvertAVSampleFormatToRawAudioFormat() for converting in the other 279 direction. 280 281 \param rawAudioFormatIn Contains Media Kits notation of an audio sample 282 format that will be converted into FFmpegs notation. 283 \param sampleFormatOut On output contains FFmpegs notation of the passed 284 audio sample format. Might return AV_SAMPLE_FMT_NONE if there is no 285 conversion path. 286 */ 287 inline void 288 ConvertRawAudioFormatToAVSampleFormat(uint32 rawAudioFormatIn, 289 AVSampleFormat& sampleFormatOut) 290 { 291 switch (rawAudioFormatIn) { 292 case media_raw_audio_format::B_AUDIO_FLOAT: 293 sampleFormatOut = AV_SAMPLE_FMT_FLT; 294 return; 295 296 case media_raw_audio_format::B_AUDIO_DOUBLE: 297 sampleFormatOut = AV_SAMPLE_FMT_DBL; 298 return; 299 300 case media_raw_audio_format::B_AUDIO_INT: 301 sampleFormatOut = AV_SAMPLE_FMT_S32; 302 return; 303 304 case media_raw_audio_format::B_AUDIO_SHORT: 305 sampleFormatOut = AV_SAMPLE_FMT_S16; 306 return; 307 308 case media_raw_audio_format::B_AUDIO_UCHAR: 309 sampleFormatOut = AV_SAMPLE_FMT_U8; 310 return; 311 312 default: 313 // Silence compiler warnings about unhandled enumeration values. 314 break; 315 } 316 317 sampleFormatOut = AV_SAMPLE_FMT_NONE; 318 } 319 320 321 /*! \brief Converts FFmpegs notation of an audio sample format to the Media 322 Kits notation. 323 324 \see ConvertAVSampleFormatToRawAudioFormat() for converting in the other 325 direction. 326 327 \param sampleFormatIn Contains FFmpegs notation of an audio sample format 328 that will be converted into the Media Kits notation. 329 \param rawAudioFormatOut On output contains Media Kits notation of the 330 passed audio sample format. Might return 0 if there is no conversion 331 path. 332 */ 333 inline void 334 ConvertAVSampleFormatToRawAudioFormat(AVSampleFormat sampleFormatIn, 335 uint32& rawAudioFormatOut) 336 { 337 switch (sampleFormatIn) { 338 case AV_SAMPLE_FMT_FLT: 339 case AV_SAMPLE_FMT_FLTP: 340 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_FLOAT; 341 return; 342 343 case AV_SAMPLE_FMT_DBL: 344 case AV_SAMPLE_FMT_DBLP: 345 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_DOUBLE; 346 return; 347 348 case AV_SAMPLE_FMT_S32: 349 case AV_SAMPLE_FMT_S32P: 350 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_INT; 351 return; 352 353 case AV_SAMPLE_FMT_S16: 354 case AV_SAMPLE_FMT_S16P: 355 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_SHORT; 356 return; 357 358 case AV_SAMPLE_FMT_U8: 359 case AV_SAMPLE_FMT_U8P: 360 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_UCHAR; 361 return; 362 363 default: 364 // Silence compiler warnings about unhandled enumeration values. 365 break; 366 } 367 368 const uint32 kBAudioNone = 0; 369 rawAudioFormatOut = kBAudioNone; 370 } 371 372 373 #endif // UTILITIES_H 374