1#include "gfx_util.h"
2
3#include <strings.h>
4#include <stdio.h>
5
6extern "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.
28gfx_convert_func
29resolve_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
154const char*
155pixfmt_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
164color_space
165pixfmt_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
216AVPixelFormat
217colorspace_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
269void
270dump_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
281void
282dump_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