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