xref: /haiku/src/add-ons/media/plugins/ffmpeg/gfx_util.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
1 #include "gfx_util.h"
2 
3 #include <strings.h>
4 #include <stdio.h>
5 
6 extern "C" {
7 #include <libavutil/pixdesc.h>
8 }
9 
10 #include "CpuCapabilities.h"
11 #include "gfx_conv_c.h"
12 #include "gfx_conv_mmx.h"
13 
14 
15 // ref docs
16 // http://www.joemaller.com/fcp/fxscript_yuv_color.shtml
17 
18 
19 #if DEBUG
20   #define TRACE(a...) printf(a)
21 #else
22   #define TRACE(a...)
23 #endif
24 
25 
26 //! This function will try to find the best colorspaces for both the ff-codec
27 // and the Media Kit sides.
28 gfx_convert_func
29 resolve_colorspace(color_space colorSpace, AVPixelFormat pixelFormat, int width,
30 	int height)
31 {
32 	CPUCapabilities cpu;
33 
34 	switch (colorSpace) {
35 		case B_RGB32:
36 			// Planar Formats
37 			if (pixelFormat == AV_PIX_FMT_YUV410P) {
38 				TRACE("resolve_colorspace: gfx_conv_yuv410p_rgb32_c\n");
39 				return gfx_conv_yuv410p_rgb32_c;
40 			}
41 
42 			if (pixelFormat == AV_PIX_FMT_YUV411P) {
43 				TRACE("resolve_colorspace: gfx_conv_yuv411p_rgb32_c\n");
44 				return gfx_conv_yuv411p_rgb32_c;
45 			}
46 
47 			if (pixelFormat == AV_PIX_FMT_YUV420P
48 				|| pixelFormat == AV_PIX_FMT_YUVJ420P) {
49 #if 0
50 				if (cpu.HasSSSE3() && width % 8 == 0 && height % 2 == 0) {
51 					TRACE("resolve_colorspace: gfx_conv_yuv420p_rgba32_ssse3\n");
52 					return gfx_conv_yuv420p_rgba32_ssse3;
53 				} else if (cpu.HasSSE2() && width % 8 == 0 && height % 2 == 0) {
54 					TRACE("resolve_colorspace: gfx_conv_yuv420p_rgba32_sse2\n");
55 					return gfx_conv_yuv420p_rgba32_sse2;
56 				} else if (cpu.HasSSE1() && width % 4 == 0
57 					&& height % 2 == 0) {
58 					TRACE("resolve_colorspace: gfx_conv_yuv420p_rgba32_sse\n");
59 					return gfx_conv_yuv420p_rgba32_sse;
60 				}
61 #endif
62 				TRACE("resolve_colorspace: gfx_conv_YCbCr420p_RGB32_c\n");
63 				return gfx_conv_YCbCr420p_RGB32_c;
64 			}
65 
66 			if (pixelFormat == AV_PIX_FMT_YUV422P
67 				|| pixelFormat == AV_PIX_FMT_YUVJ422P) {
68 #if 0
69 				if (cpu.HasSSSE3() && width % 8 == 0) {
70 					TRACE("resolve_colorspace: gfx_conv_yuv422p_RGB32_ssse3\n");
71 					return gfx_conv_yuv422p_rgba32_ssse3;
72 				} else if (cpu.HasSSE2() && width % 8 == 0) {
73 					TRACE("resolve_colorspace: gfx_conv_yuv422p_RGB32_sse2\n");
74 					return gfx_conv_yuv422p_rgba32_sse2;
75 				} else if (cpu.HasSSE1() && width % 4 == 0) {
76 					TRACE("resolve_colorspace: gfx_conv_yuv422p_RGB32_sse\n");
77 					return gfx_conv_yuv422p_rgba32_sse;
78 				}
79 #endif
80 				TRACE("resolve_colorspace: gfx_conv_YCbCr422p_RGB32_c\n");
81 				return gfx_conv_YCbCr422_RGB32_c;
82 			}
83 
84 			if (pixelFormat == AV_PIX_FMT_GBRP) {
85 				return gfx_conv_GBRP_RGB32_c;
86 			}
87 
88 			// Packed Formats
89 			if (pixelFormat == AV_PIX_FMT_YUYV422) {
90 #if 0
91 				if (cpu.HasSSSE3() && width % 8 == 0) {
92 					return gfx_conv_yuv422_rgba32_ssse3;
93 				} else if (cpu.HasSSE2() && width % 8 == 0) {
94 					return gfx_conv_yuv422_rgba32_sse2;
95 				} else if (cpu.HasSSE1() && width % 4 == 0
96 					&& height % 2 == 0) {
97 					return gfx_conv_yuv422_rgba32_sse;
98 				}
99 #endif
100 				return gfx_conv_YCbCr422_RGB32_c;
101 			}
102 
103 			if (pixelFormat == AV_PIX_FMT_YUV420P10LE)
104 				return gfx_conv_yuv420p10le_rgb32_c;
105 
106 			TRACE("resolve_colorspace: %s => B_RGB32: NULL\n",
107 				pixfmt_to_string(pixelFormat));
108 			return NULL;
109 
110 		case B_RGB24_BIG:
111 			TRACE("resolve_colorspace: %s => B_RGB24_BIG: NULL\n",
112 				pixfmt_to_string(pixelFormat));
113 			return NULL;
114 
115 		case B_RGB24:
116 			TRACE("resolve_colorspace: %s => B_RGB24: NULL\n",
117 				pixfmt_to_string(pixelFormat));
118 			return NULL;
119 
120 		case B_YCbCr422:
121 			if (pixelFormat == AV_PIX_FMT_YUV410P) {
122 				TRACE("resolve_colorspace: gfx_conv_yuv410p_ycbcr422_c\n");
123 				return gfx_conv_yuv410p_ycbcr422_c;
124 			}
125 
126 			if (pixelFormat == AV_PIX_FMT_YUV411P) {
127 				TRACE("resolve_colorspace: gfx_conv_yuv411p_ycbcr422_c\n");
128 				return gfx_conv_yuv411p_ycbcr422_c;
129 			}
130 
131 			if (pixelFormat == AV_PIX_FMT_YUV420P
132 				|| pixelFormat == AV_PIX_FMT_YUVJ420P) {
133 				TRACE("resolve_colorspace: gfx_conv_yuv420p_ycbcr422_c\n");
134 				return gfx_conv_yuv420p_ycbcr422_c;
135 			}
136 
137 			if (pixelFormat == AV_PIX_FMT_YUYV422) {
138 				TRACE("resolve_colorspace: PIX_FMT_YUV422 => B_YCbCr422: "
139 					"gfx_conv_null\n");
140 				return gfx_conv_null;
141 			}
142 
143 			TRACE("resolve_colorspace: %s => B_YCbCr422: NULL\n",
144 				pixfmt_to_string(pixelFormat));
145 			return NULL;
146 
147 		default:
148 			TRACE("resolve_colorspace: default: NULL!!!\n");
149 			return NULL;
150 	}
151 }
152 
153 
154 const char*
155 pixfmt_to_string(int pixFormat)
156 {
157 	const char* name = av_get_pix_fmt_name((enum AVPixelFormat)pixFormat);
158 	if (name == NULL)
159 		return "(unknown)";
160 	return name;
161 }
162 
163 
164 color_space
165 pixfmt_to_colorspace(int pixFormat)
166 {
167 	switch (pixFormat) {
168 		default:
169 			TRACE("No BE API colorspace definition for pixel format "
170 				"\"%s\".\n", pixfmt_to_string(pixFormat));
171 			// Supposed to fall through.
172 		case AV_PIX_FMT_NONE:
173 			return B_NO_COLOR_SPACE;
174 
175 		// NOTE: See pixfmt_to_colorspace() for what these are.
176 		case AV_PIX_FMT_YUV420P:
177 			return B_YUV420;
178 		case AV_PIX_FMT_RGB24:
179 			return B_RGB24_BIG;
180 		case AV_PIX_FMT_BGR24:
181 			return B_RGB24;
182 		case AV_PIX_FMT_YUV422P:
183 			return B_YUV422;
184 		case AV_PIX_FMT_YUV444P:
185 			return B_YUV444;
186 		case AV_PIX_FMT_RGB32:
187 			return B_RGBA32_BIG;
188 		case AV_PIX_FMT_YUV410P:
189 			return B_YUV9;
190 		case AV_PIX_FMT_YUV411P:
191 			return B_YUV12;
192 		case AV_PIX_FMT_RGB565:
193 			return B_RGB16_BIG;
194 		case AV_PIX_FMT_RGB555:
195 			return B_RGB15_BIG;
196 		case AV_PIX_FMT_GRAY8:
197 			return B_GRAY8;
198 		case AV_PIX_FMT_MONOBLACK:
199 			return B_GRAY1;
200 		case AV_PIX_FMT_PAL8:
201 			return B_CMAP8;
202 		case AV_PIX_FMT_BGR32:
203 			return B_RGB32;
204 		case AV_PIX_FMT_BGR565:
205 			return B_RGB16;
206 		case AV_PIX_FMT_BGR555:
207 			return B_RGB15;
208 		// TODO: more YCbCr color spaces! These are not the same as YUV!
209 		case AV_PIX_FMT_YUYV422:
210 			return B_YCbCr422;
211 
212 	}
213 }
214 
215 
216 AVPixelFormat
217 colorspace_to_pixfmt(color_space format)
218 {
219 	switch(format) {
220 		default:
221 		case B_NO_COLOR_SPACE:
222 			return AV_PIX_FMT_NONE;
223 
224 		// NOTE: See pixfmt_to_colorspace() for what these are.
225 		case B_YUV420:
226 			return AV_PIX_FMT_YUV420P;
227 		case B_YUV422:
228 			return AV_PIX_FMT_YUV422P;
229 		case B_RGB24_BIG:
230 			return AV_PIX_FMT_RGB24;
231 		case B_RGB24:
232 			return AV_PIX_FMT_BGR24;
233 		case B_YUV444:
234 			return AV_PIX_FMT_YUV444P;
235 		case B_RGBA32_BIG:
236 		case B_RGB32_BIG:
237 			return AV_PIX_FMT_BGR32;
238 		case B_YUV9:
239 			return AV_PIX_FMT_YUV410P;
240 		case B_YUV12:
241 			return AV_PIX_FMT_YUV411P;
242 		case B_RGB16_BIG:
243 			return AV_PIX_FMT_RGB565;
244 		case B_RGB15_BIG:
245 			return AV_PIX_FMT_RGB555;
246 		case B_GRAY8:
247 			return AV_PIX_FMT_GRAY8;
248 		case B_GRAY1:
249 			return AV_PIX_FMT_MONOBLACK;
250 		case B_CMAP8:
251 			return AV_PIX_FMT_PAL8;
252 		case B_RGBA32:
253 		case B_RGB32:
254 			return AV_PIX_FMT_RGB32;
255 		case B_RGB16:
256 			return AV_PIX_FMT_BGR565;
257 		case B_RGB15:
258 			return AV_PIX_FMT_BGR555;
259 		// TODO: more YCbCr color spaces! These are not the same as YUV!
260 		case B_YCbCr422:
261 			return AV_PIX_FMT_YUYV422;
262 	}
263 }
264 
265 
266 #define BEGIN_TAG "\033[31m"
267 #define END_TAG "\033[0m"
268 
269 void
270 dump_ffframe_audio(AVFrame* frame, const char* name)
271 {
272 	printf(BEGIN_TAG "AVFrame(%s) [ pkt_dts:%-10" PRId64 " #samples:%-5d %s"
273 		" ]\n" END_TAG,
274 		name,
275 		frame->pkt_dts,
276 		frame->nb_samples,
277 		av_get_sample_fmt_name(static_cast<AVSampleFormat>(frame->format)));
278 }
279 
280 
281 void
282 dump_ffframe_video(AVFrame* frame, const char* name)
283 {
284 	const char* picttypes[] = {"no pict type", "intra", "predicted",
285 		"bidir pre", "s(gmc)-vop", "switching intra", "switching predicted", "BI"};
286 #if LIBAVCODEC_VERSION_MAJOR >= 60
287 	printf(BEGIN_TAG "AVFrame(%s) [ pkt_dts:%-10" PRId64 " %s%s%s%s%s%s ]\n" END_TAG, name,
288 		frame->pkt_dts,
289 		(frame->flags & AV_FRAME_FLAG_CORRUPT) ? "corrupt, " : "",
290 		(frame->flags & AV_FRAME_FLAG_KEY) ? "keyframe, " : "",
291 		(frame->flags & AV_FRAME_FLAG_DISCARD) ? "discard, " : "",
292 		(frame->flags & AV_FRAME_FLAG_INTERLACED) ? "interlaced, " : "",
293 		(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? "top field first, " : "",
294 		picttypes[frame->pict_type]);
295 #else
296 	printf(BEGIN_TAG "AVFrame(%s) [ pkt_dts:%-10" PRId64 " %s%s ]\n" END_TAG, name, frame->pkt_dts,
297 		frame->key_frame ? "keyframe, " : "", picttypes[frame->pict_type]);
298 #endif
299 }
300