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 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 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 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 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 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 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 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