1 /* 2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de> 3 * Copyright 2014, Colin Günther <coling@gmx.de> 4 * All rights reserved. Distributed under the terms of the GNU L-GPL license. 5 */ 6 #ifndef UTILITIES_H 7 #define UTILITIES_H 8 9 10 /*! \brief This file contains functions to convert and calculate values from 11 FFmpeg to Media Kit and vice versa. 12 */ 13 14 15 #include <assert.h> 16 17 #include <GraphicsDefs.h> 18 19 extern "C" { 20 #include "avcodec.h" 21 } 22 23 24 /*! \brief Converts FFmpeg notation of video aspect ratio into the Media Kits 25 notation. 26 27 \see ConvertVideoAspectWidthAndHeightToAVCodecContext() for converting in 28 the other direction. 29 30 \param contextIn An AVCodeContext structure of FFmpeg containing the values 31 needed to calculate the Media Kit video aspect ratio. 32 The following fields are used for the calculation: 33 - AVCodecContext.sample_aspect_ratio.num (optional) 34 - AVCodecContext.sample_aspect_ratio.den (optional) 35 - AVCodecContext.width (must) 36 - AVCodecContext.height (must) 37 \param pixelWidthAspectOut On return contains Media Kits notation of the 38 video aspect ratio width. E.g. 16:9 -> 16 is returned here 39 \param pixelHeightAspectOut On return contains Media Kits notation of the 40 video aspect ratio height. E.g. 16:9 -> 9 is returned here 41 */ 42 inline void 43 ConvertAVCodecContextToVideoAspectWidthAndHeight(AVCodecContext& contextIn, 44 uint16& pixelWidthAspectOut, uint16& pixelHeightAspectOut) 45 { 46 assert(contextIn.sample_aspect_ratio.num >= 0); 47 assert(contextIn.sample_aspect_ratio.den > 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 // AVCodecContext doesn't contain a video aspect ratio, so calculate it 58 // ourselve based solely on the video dimensions 59 av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, contextIn.width, 60 contextIn.height, 1024 * 1024); 61 62 pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num); 63 pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den); 64 return; 65 } 66 67 // AVCodecContext contains a video aspect ratio, so use it 68 av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, 69 contextIn.width * contextIn.sample_aspect_ratio.num, 70 contextIn.height * contextIn.sample_aspect_ratio.den, 71 1024 * 1024); 72 73 pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num); 74 pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den); 75 } 76 77 78 /*! \brief Converts the Media Kits notation of video aspect ratio into FFmpegs 79 notation. 80 81 \see ConvertAVCodecContextToVideoAspectWidthAndHeight() for converting in 82 the other direction. 83 84 \param pixelWidthAspectIn Contains Media Kits notation of the video aspect 85 ratio width. E.g. 16:9 -> 16 is passed here. 86 \param pixelHeightAspectIn Contains Media Kits notation of the video aspect 87 ratio height. E.g. 16:9 -> 9 is passed here. 88 \param contextInOut An AVCodecContext structure of FFmpeg. 89 On input must contain the following fields already initialized 90 otherwise the behaviour is undefined: 91 - AVCodecContext.width (must) 92 - AVCodecContext.height (must) 93 On output contains converted values in the following fields (other 94 fields stay as they were on input): 95 - AVCodecContext.sample_aspect_ratio.num 96 - AVCodecContext.sample_aspect_ratio.den 97 */ 98 inline void 99 ConvertVideoAspectWidthAndHeightToAVCodecContext(uint16 pixelWidthAspectIn, 100 uint16 pixelHeightAspectIn, AVCodecContext& contextInOut) 101 { 102 assert(pixelWidthAspectIn > 0); 103 assert(pixelHeightAspectIn > 0); 104 assert(contextInOut.width > 0); 105 assert(contextInOut.height > 0); 106 107 AVRational pureVideoDimensionAspectRatio; 108 av_reduce(&pureVideoDimensionAspectRatio.num, 109 &pureVideoDimensionAspectRatio.den, contextInOut.width, 110 contextInOut.height, 1024 * 1024); 111 112 if (pureVideoDimensionAspectRatio.num == pixelWidthAspectIn 113 && pureVideoDimensionAspectRatio.den == pixelHeightAspectIn) { 114 // The passed Media Kit pixel aspect ratio equals the video dimension 115 // aspect ratio. Set sample_aspect_ratio to "ignore". 116 contextInOut.sample_aspect_ratio.num = 0; 117 contextInOut.sample_aspect_ratio.den = 1; 118 return; 119 } 120 121 av_reduce(&contextInOut.sample_aspect_ratio.num, 122 &contextInOut.sample_aspect_ratio.den, 123 contextInOut.height * pixelWidthAspectIn, 124 contextInOut.width * pixelHeightAspectIn, 125 1024 * 1024); 126 } 127 128 129 /*! \brief Calculates bytes per row for a video frame. 130 131 \param colorSpace The Media Kit color space the video frame uses. 132 \param videoWidth The width of the video frame. 133 134 \returns bytes per video frame row 135 \returns Zero, when bytes per video frame cannot be calculated. 136 */ 137 inline uint32 138 CalculateBytesPerRowWithColorSpaceAndVideoWidth(color_space colorSpace, int videoWidth) 139 { 140 assert(videoWidth >= 0); 141 142 const uint32 kBytesPerRowUnknown = 0; 143 size_t bytesPerPixel; 144 size_t rowAlignment; 145 146 if (get_pixel_size_for(colorSpace, &bytesPerPixel, &rowAlignment, NULL) != B_OK) 147 return kBytesPerRowUnknown; 148 149 uint32 bytesPerRow = bytesPerPixel * videoWidth; 150 uint32 numberOfUnalignedBytes = bytesPerRow % rowAlignment; 151 152 if (numberOfUnalignedBytes == 0) 153 return bytesPerRow; 154 155 uint32 numberOfBytesNeededForAlignment = rowAlignment - numberOfUnalignedBytes; 156 bytesPerRow += numberOfBytesNeededForAlignment; 157 158 return bytesPerRow; 159 } 160 161 162 /*! \brief Converts FFmpeg notation of video frame rate into the Media Kits 163 notation. 164 165 \see ConvertAVCodecContextToVideoFrameRate() for converting in the other 166 direction. 167 168 \param contextIn An AVCodeContext structure of FFmpeg containing the values 169 needed to calculate the Media Kit video frame rate. 170 The following fields are used for the calculation: 171 - AVCodecContext.time_base.num (must) 172 - AVCodecContext.time_base.den (must) 173 - AVCodecContext.ticks_per_frame (must) 174 \param frameRateOut On return contains Media Kits notation of the video 175 frame rate. 176 */ 177 inline void 178 ConvertAVCodecContextToVideoFrameRate(AVCodecContext& contextIn, float& frameRateOut) 179 { 180 // assert that av_q2d(contextIn.time_base) > 0 and computable 181 assert(contextIn.time_base.num > 0); 182 assert(contextIn.time_base.den > 0); 183 184 // The following code is based on private get_fps() function of FFmpeg's 185 // ratecontrol.c: 186 // https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2012-April/049280.html 187 double possiblyInterlacedFrameRate = 1.0 / av_q2d(contextIn.time_base); 188 double numberOfInterlacedFramesPerFullFrame = FFMAX(contextIn.ticks_per_frame, 1); 189 190 frameRateOut 191 = possiblyInterlacedFrameRate / numberOfInterlacedFramesPerFullFrame; 192 } 193 194 195 /*! \brief Converts the Media Kits notation of video frame rate to FFmpegs 196 notation. 197 198 \see ConvertAVCodecContextToVideoFrameRate() for converting in the other 199 direction. 200 201 \param frameRateIn Contains Media Kits notation of the video frame rate 202 that will be converted into FFmpegs notation. Must be greater than 203 zero. 204 \param contextOut An AVCodecContext structure of FFmpeg. 205 On output contains converted values in the following fields (other 206 fields stay as they were on input): 207 - AVCodecContext.time_base.num 208 - AVCodecContext.time_base.den 209 - AVCodecContext.ticks_per_frame is set to 1 210 */ 211 inline void 212 ConvertVideoFrameRateToAVCodecContext(float frameRateIn, 213 AVCodecContext& contextOut) 214 { 215 assert(frameRateIn > 0); 216 217 contextOut.ticks_per_frame = 1; 218 contextOut.time_base = av_d2q(1.0 / frameRateIn, 1024); 219 } 220 221 222 /*! \brief Converts the Media Kits notation of an audio sample format to 223 FFmpegs notation. 224 225 \see ConvertAVSampleFormatToRawAudioFormat() for converting in the other 226 direction. 227 228 \param rawAudioFormatIn Contains Media Kits notation of an audio sample 229 format that will be converted into FFmpegs notation. 230 \param sampleFormatOut On output contains FFmpegs notation of the passed 231 audio sample format. Might return AV_SAMPLE_FMT_NONE if there is no 232 conversion path. 233 */ 234 inline void 235 ConvertRawAudioFormatToAVSampleFormat(uint32 rawAudioFormatIn, 236 AVSampleFormat& sampleFormatOut) 237 { 238 switch (rawAudioFormatIn) { 239 case media_raw_audio_format::B_AUDIO_FLOAT: 240 sampleFormatOut = AV_SAMPLE_FMT_FLT; 241 return; 242 243 case media_raw_audio_format::B_AUDIO_DOUBLE: 244 sampleFormatOut = AV_SAMPLE_FMT_DBL; 245 return; 246 247 case media_raw_audio_format::B_AUDIO_INT: 248 sampleFormatOut = AV_SAMPLE_FMT_S32; 249 return; 250 251 case media_raw_audio_format::B_AUDIO_SHORT: 252 sampleFormatOut = AV_SAMPLE_FMT_S16; 253 return; 254 255 case media_raw_audio_format::B_AUDIO_UCHAR: 256 sampleFormatOut = AV_SAMPLE_FMT_U8; 257 return; 258 259 default: 260 // Silence compiler warnings about unhandled enumeration values. 261 break; 262 } 263 264 sampleFormatOut = AV_SAMPLE_FMT_NONE; 265 } 266 267 268 /*! \brief Converts FFmpegs notation of an audio sample format to the Media 269 Kits notation. 270 271 \see ConvertAVSampleFormatToRawAudioFormat() for converting in the other 272 direction. 273 274 \param sampleFormatIn Contains FFmpegs notation of an audio sample format 275 that will be converted into the Media Kits notation. 276 \param rawAudioFormatOut On output contains Media Kits notation of the 277 passed audio sample format. Might return 0 if there is no conversion 278 path. 279 */ 280 inline void 281 ConvertAVSampleFormatToRawAudioFormat(AVSampleFormat sampleFormatIn, 282 uint32& rawAudioFormatOut) 283 { 284 switch (sampleFormatIn) { 285 case AV_SAMPLE_FMT_FLT: 286 case AV_SAMPLE_FMT_FLTP: 287 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_FLOAT; 288 return; 289 290 case AV_SAMPLE_FMT_DBL: 291 case AV_SAMPLE_FMT_DBLP: 292 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_DOUBLE; 293 return; 294 295 case AV_SAMPLE_FMT_S32: 296 case AV_SAMPLE_FMT_S32P: 297 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_INT; 298 return; 299 300 case AV_SAMPLE_FMT_S16: 301 case AV_SAMPLE_FMT_S16P: 302 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_SHORT; 303 return; 304 305 case AV_SAMPLE_FMT_U8: 306 case AV_SAMPLE_FMT_U8P: 307 rawAudioFormatOut = media_raw_audio_format::B_AUDIO_UCHAR; 308 return; 309 310 default: 311 // Silence compiler warnings about unhandled enumeration values. 312 break; 313 } 314 315 const uint32 kBAudioNone = 0; 316 rawAudioFormatOut = kBAudioNone; 317 } 318 319 320 #endif // UTILITIES_H 321