xref: /haiku/src/add-ons/media/plugins/ffmpeg/Utilities.h (revision 6288f7b4537703bfaa43bf8f8fa0c58e4c8dd82b)
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 	\param contextIn An AVCodeContext structure of FFmpeg containing the values
28 		needed to calculate the Media Kit video aspect ratio.
29 		The following fields are used for the calculation:
30 			- AVCodecContext.sample_aspect_ratio.num (optional)
31 			- AVCodecContext.sample_aspect_ratio.den (optional)
32 			- AVCodecContext.width (must)
33 			- AVCodecContext.height (must)
34 	\param pixelWidthAspectOut On return contains Media Kits notation of the
35 		video aspect ratio width. E.g. 16:9 -> 16 is returned here
36 	\param pixelHeightAspectOut On return contains Media Kits notation of the
37 		video aspect ratio height. E.g. 16:9 -> 9 is returned here
38 */
39 inline void
40 ConvertAVCodecContextToVideoAspectWidthAndHeight(AVCodecContext& contextIn,
41 	uint16& pixelWidthAspectOut, uint16& pixelHeightAspectOut)
42 {
43 	assert(contextIn.sample_aspect_ratio.num >= 0);
44 	assert(contextIn.sample_aspect_ratio.den > 0);
45 	assert(contextIn.width > 0);
46 	assert(contextIn.height > 0);
47 
48 	// The following code is based on code originally located in
49 	// AVFormatReader::Stream::Init() and thus should be copyrighted to Stephan
50 	// Aßmus
51 	AVRational pixelAspectRatio;
52 
53 	if (contextIn.sample_aspect_ratio.num == 0) {
54 		// AVCodecContext doesn't contain a video aspect ratio, so calculate it
55 		// ourselve based solely on the video dimensions
56 		av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, contextIn.width,
57 			contextIn.height, 1024 * 1024);
58 
59 		pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
60 		pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
61 		return;
62 	}
63 
64 	// AVCodecContext contains a video aspect ratio, so use it
65 	av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den,
66 		contextIn.width * contextIn.sample_aspect_ratio.num,
67 		contextIn.height * contextIn.sample_aspect_ratio.den,
68 		1024 * 1024);
69 
70 	pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
71 	pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
72 }
73 
74 
75 /*! \brief Calculates bytes per row for a video frame.
76 
77 	\param colorSpace The Media Kit color space the video frame uses.
78 	\param videoWidth The width of the video frame.
79 
80 	\returns bytes per video frame row
81 	\returns Zero, when bytes per video frame cannot be calculated.
82 */
83 inline uint32
84 CalculateBytesPerRowWithColorSpaceAndVideoWidth(color_space colorSpace, int videoWidth)
85 {
86 	assert(videoWidth >= 0);
87 
88 	const uint32 kBytesPerRowUnknown = 0;
89 	size_t bytesPerPixel;
90 	size_t rowAlignment;
91 
92 	if (get_pixel_size_for(colorSpace, &bytesPerPixel, &rowAlignment, NULL) != B_OK)
93 		return kBytesPerRowUnknown;
94 
95 	uint32 bytesPerRow = bytesPerPixel * videoWidth;
96 	uint32 numberOfUnalignedBytes = bytesPerRow % rowAlignment;
97 
98 	if (numberOfUnalignedBytes == 0)
99 		return bytesPerRow;
100 
101 	uint32 numberOfBytesNeededForAlignment = rowAlignment - numberOfUnalignedBytes;
102 	bytesPerRow += numberOfBytesNeededForAlignment;
103 
104 	return bytesPerRow;
105 }
106 
107 
108 /*! \brief Converts FFmpeg notation of video frame rate into the Media Kits
109 		notation.
110 
111 	\param contextIn An AVCodeContext structure of FFmpeg containing the values
112 		needed to calculate the Media Kit video frame rate.
113 		The following fields are used for the calculation:
114 			- AVCodecContext.time_base.num (must)
115 			- AVCodecContext.time_base.den (must)
116 			- AVCodecContext.ticks_per_frame (must)
117 	\param frameRateOut On return contains Media Kits notation of the video
118 		frame rate.
119 */
120 inline void
121 ConvertAVCodecContextToVideoFrameRate(AVCodecContext& contextIn, float& frameRateOut)
122 {
123 	// assert that av_q2d(contextIn.time_base) > 0 and computable
124 	assert(contextIn.time_base.num > 0);
125 	assert(contextIn.time_base.den > 0);
126 
127 	// The following code is based on private get_fps() function of FFmpeg's
128 	// ratecontrol.c:
129 	// https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2012-April/049280.html
130 	double possiblyInterlacedFrameRate = 1.0 / av_q2d(contextIn.time_base);
131 	double numberOfInterlacedFramesPerFullFrame = FFMAX(contextIn.ticks_per_frame, 1);
132 
133 	frameRateOut
134 		= possiblyInterlacedFrameRate / numberOfInterlacedFramesPerFullFrame;
135 }
136 
137 #endif // UTILITIES_H
138