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