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 the Media Kits notation of video frame rate to FFmpegs 212 notation. 213 214 \see ConvertAVCodecContextToVideoFrameRate() for converting in the other 215 direction. 216 217 \param frameRateIn Contains Media Kits notation of the video frame rate 218 that will be converted into FFmpegs notation. Must be greater than 219 zero. 220 \param contextOut An AVCodecContext structure of FFmpeg. 221 On output contains converted values in the following fields (other 222 fields stay as they were on input): 223 - AVCodecContext.time_base.num 224 - AVCodecContext.time_base.den 225 - AVCodecContext.framerate.num 226 - AVCodecContext.framerate.den 227 */ 228 inline void 229 ConvertVideoFrameRateToAVCodecContext(float frameRateIn, 230 AVCodecContext& contextOut) 231 { 232 assert(frameRateIn > 0); 233 234 contextOut.framerate = av_d2q(frameRateIn, 1024); 235 contextOut.time_base = av_d2q(1.0 / frameRateIn, 1024); 236 } 237 238 239 /*! \brief Converts the Media Kits notation of an audio sample format to 240 FFmpegs notation. 241 242 \see ConvertAVSampleFormatToRawAudioFormat() for converting in the other 243 direction. 244 245 \param rawAudioFormatIn Contains Media Kits notation of an audio sample 246 format that will be converted into FFmpegs notation. 247 \param sampleFormatOut On output contains FFmpegs notation of the passed 248 audio sample format. Might return AV_SAMPLE_FMT_NONE if there is no 249 conversion path. 250 */ 251 inline void 252 ConvertRawAudioFormatToAVSampleFormat(uint32 rawAudioFormatIn, 253 AVSampleFormat& sampleFormatOut) 254 { 255 switch (rawAudioFormatIn) { 256 case media_raw_audio_format::B_AUDIO_FLOAT: 257 sampleFormatOut = AV_SAMPLE_FMT_FLT; 258 return; 259 260 case media_raw_audio_format::B_AUDIO_DOUBLE: 261 sampleFormatOut = AV_SAMPLE_FMT_DBL; 262 return; 263 264 case media_raw_audio_format::B_AUDIO_INT: 265 sampleFormatOut = AV_SAMPLE_FMT_S32; 266 return; 267 268 case media_raw_audio_format::B_AUDIO_SHORT: 269 sampleFormatOut = AV_SAMPLE_FMT_S16; 270 return; 271 272 case media_raw_audio_format::B_AUDIO_UCHAR: 273 sampleFormatOut = AV_SAMPLE_FMT_U8; 274 return; 275 276 default: 277 // Silence compiler warnings about unhandled enumeration values. 278 break; 279 } 280 281 sampleFormatOut = AV_SAMPLE_FMT_NONE; 282 } 283 284 285 /*! \brief Converts FFmpegs notation of an audio sample format to the Media 286 Kits notation. 287 288 \see ConvertAVSampleFormatToRawAudioFormat() for converting in the other 289 direction. 290 291 \param sampleFormatIn Contains FFmpegs notation of an audio sample format 292 that will be converted into the Media Kits notation. 293 \param rawAudioFormatOut On output contains Media Kits notation of the 294 passed audio sample format. Might return 0 if there is no conversion 295 path. 296 */ 297 inline void 298 ConvertAVSampleFormatToRawAudioFormat(AVSampleFormat sampleFormatIn, 299 uint32& rawAudioFormatOut) 300 { 301 switch (sampleFormatIn) { 302 case AV_SAMPLE_FMT_FLT: 303 case AV_SAMPLE_FMT_FLTP: 304 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_FLOAT; 305 return; 306 307 case AV_SAMPLE_FMT_DBL: 308 case AV_SAMPLE_FMT_DBLP: 309 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_DOUBLE; 310 return; 311 312 case AV_SAMPLE_FMT_S32: 313 case AV_SAMPLE_FMT_S32P: 314 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_INT; 315 return; 316 317 case AV_SAMPLE_FMT_S16: 318 case AV_SAMPLE_FMT_S16P: 319 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_SHORT; 320 return; 321 322 case AV_SAMPLE_FMT_U8: 323 case AV_SAMPLE_FMT_U8P: 324 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_UCHAR; 325 return; 326 327 default: 328 // Silence compiler warnings about unhandled enumeration values. 329 break; 330 } 331 332 const uint32 kBAudioNone = 0; 333 rawAudioFormatOut = kBAudioNone; 334 } 335 336 337 #endif // UTILITIES_H 338