1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* This is the BeOS version of SDL YUV video overlays */
25
26#include "SDL_video.h"
27#include "SDL_sysyuv.h"
28#include "../SDL_yuvfuncs.h"
29
30extern "C" {
31
32/* The functions used to manipulate software video overlays */
33static struct private_yuvhwfuncs be_yuvfuncs =
34{
35    BE_LockYUVOverlay,
36    BE_UnlockYUVOverlay,
37    BE_DisplayYUVOverlay,
38    BE_FreeYUVOverlay
39};
40
41BBitmap * BE_GetOverlayBitmap(BRect bounds, color_space cs) {
42	BBitmap *bbitmap;
43	bbitmap = new BBitmap(bounds,B_BITMAP_WILL_OVERLAY,cs);
44	if (!bbitmap || bbitmap->InitCheck() != B_OK) {
45		delete bbitmap;
46		return 0;
47	}
48	overlay_restrictions r;
49	bbitmap->GetOverlayRestrictions(&r);
50	uint32 width = bounds.IntegerWidth() + 1;
51	uint32 height = bounds.IntegerHeight() + 1;
52	uint32 width_padding = 0;
53	uint32 height_padding = 0;
54	if ((r.source.horizontal_alignment != 0) ||
55	    (r.source.vertical_alignment != 0)) {
56		delete bbitmap;
57		return 0;
58	}
59	if (r.source.width_alignment != 0) {
60		uint32 aligned_width = r.source.width_alignment + 1;
61		if (width % aligned_width > 0) {
62			width_padding = aligned_width - width % aligned_width;
63		}
64	}
65	if (r.source.height_alignment != 0) {
66		uint32 aligned_height = r.source.height_alignment + 1;
67		if (height % aligned_height > 0) {
68			fprintf(stderr,"GetOverlayBitmap failed height alignment\n");
69			fprintf(stderr,"- height = %lu, aligned_height = %lu\n",height,aligned_height);
70			delete bbitmap;
71			return 0;
72		}
73	}
74	if ((r.source.min_width > width) ||
75	    (r.source.min_height > height) ||
76	    (r.source.max_width < width) ||
77	    (r.source.max_height < height)) {
78		fprintf(stderr,"GetOverlayBitmap failed bounds tests\n");
79	    delete bbitmap;
80	    return 0;
81	}
82	if ((width_padding != 0) || (height_padding != 0)) {
83		delete bbitmap;
84		bounds.Set(bounds.left,bounds.top,bounds.right+width_padding,bounds.bottom+height_padding);
85		bbitmap = new BBitmap(bounds,B_BITMAP_WILL_OVERLAY,cs);
86		if (!bbitmap || bbitmap->InitCheck() != B_OK) {
87			fprintf(stderr,"GetOverlayBitmap failed late\n");
88			delete bbitmap;
89			return 0;
90		}
91	}
92	return bbitmap;
93}
94
95// See <GraphicsDefs.h> [btw: Cb=U, Cr=V]
96// See also http://www.fourcc.org/indexyuv.htm
97color_space convert_color_space(Uint32 format) {
98	switch (format) {
99	case SDL_YV12_OVERLAY:
100		return B_YUV9;
101	case SDL_IYUV_OVERLAY:
102		return B_YUV12;
103	case SDL_YUY2_OVERLAY:
104		return B_YCbCr422;
105	case SDL_UYVY_OVERLAY:
106		return B_YUV422;
107	case SDL_YVYU_OVERLAY: // not supported on beos?
108		return B_NO_COLOR_SPACE;
109	default:
110		return B_NO_COLOR_SPACE;
111	}
112}
113
114// See SDL_video.h
115int count_planes(Uint32 format) {
116	switch (format) {
117	case SDL_YV12_OVERLAY:
118	case SDL_IYUV_OVERLAY:
119		return 3;
120	case SDL_YUY2_OVERLAY:
121	case SDL_UYVY_OVERLAY:
122	case SDL_YVYU_OVERLAY:
123		return 1;
124	default:
125		return 0;
126	}
127}
128
129SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) {
130	SDL_Overlay* overlay;
131	struct private_yuvhwdata* hwdata;
132	BBitmap *bbitmap;
133	int planes;
134	BRect bounds;
135	color_space cs;
136
137	/* find the appropriate BeOS colorspace descriptor */
138	cs = convert_color_space(format);
139	if (cs == B_NO_COLOR_SPACE)
140	{
141		return NULL;
142	}
143
144	/* count planes */
145	planes = count_planes(format);
146	if (planes == 0)
147	{
148		return NULL;
149	}
150	/* TODO: figure out planar modes, if anyone cares */
151	if (planes == 3)
152	{
153		return NULL;
154	}
155
156    /* Create the overlay structure */
157    overlay = (SDL_Overlay*)SDL_calloc(1, sizeof(SDL_Overlay));
158
159    if (overlay == NULL)
160    {
161        SDL_OutOfMemory();
162        return NULL;
163    }
164
165    /* Fill in the basic members */
166    overlay->format = format;
167    overlay->w = width;
168    overlay->h = height;
169    overlay->hwdata = NULL;
170
171    /* Set up the YUV surface function structure */
172    overlay->hwfuncs = &be_yuvfuncs;
173
174    /* Create the pixel data and lookup tables */
175    hwdata = (struct private_yuvhwdata*)SDL_calloc(1, sizeof(struct private_yuvhwdata));
176
177    if (hwdata == NULL)
178    {
179        SDL_OutOfMemory();
180        SDL_FreeYUVOverlay(overlay);
181        return NULL;
182    }
183
184    overlay->hwdata = hwdata;
185	overlay->hwdata->display = display;
186	overlay->hwdata->bview = NULL;
187	overlay->hwdata->bbitmap = NULL;
188	overlay->hwdata->locked = 0;
189
190	/* Create the BBitmap framebuffer */
191	bounds.top = 0;	bounds.left = 0;
192	bounds.right = width-1;
193	bounds.bottom = height-1;
194
195	BView * bview = new BView(bounds,"overlay",B_FOLLOW_NONE,B_WILL_DRAW);
196	if (!bview) {
197		SDL_OutOfMemory();
198        SDL_FreeYUVOverlay(overlay);
199        return NULL;
200	}
201	overlay->hwdata->bview = bview;
202	overlay->hwdata->first_display = true;
203	bview->Hide();
204
205	bbitmap = BE_GetOverlayBitmap(bounds,cs);
206	if (!bbitmap) {
207		overlay->hwdata->bbitmap = NULL;
208		SDL_FreeYUVOverlay(overlay);
209		return NULL;
210	}
211	overlay->hwdata->bbitmap = bbitmap;
212
213	overlay->planes = planes;
214	overlay->pitches = (Uint16*)SDL_calloc(overlay->planes, sizeof(Uint16));
215	overlay->pixels  = (Uint8**)SDL_calloc(overlay->planes, sizeof(Uint8*));
216	if (!overlay->pitches || !overlay->pixels)
217	{
218        SDL_OutOfMemory();
219        SDL_FreeYUVOverlay(overlay);
220        return(NULL);
221    }
222
223   	overlay->pitches[0] = bbitmap->BytesPerRow();
224   	overlay->pixels[0]  = (Uint8 *)bbitmap->Bits();
225	overlay->hw_overlay = 1;
226
227	if (SDL_Win->LockWithTimeout(1000000) != B_OK) {
228        SDL_FreeYUVOverlay(overlay);
229        return(NULL);
230    }
231	BView * view = SDL_Win->View();
232    view->AddChild(bview);
233    rgb_color key;
234    bview->SetViewOverlay(bbitmap,bounds,bview->Bounds(),&key,B_FOLLOW_ALL,
235                         B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
236    bview->SetViewColor(key);
237    bview->Flush();
238	SDL_Win->Unlock();
239
240	current_overlay=overlay;
241
242	return overlay;
243}
244
245int BE_LockYUVOverlay(_THIS, SDL_Overlay* overlay)
246{
247    if (overlay == NULL)
248    {
249        return 0;
250    }
251
252    overlay->hwdata->locked = 1;
253    return 0;
254}
255
256void BE_UnlockYUVOverlay(_THIS, SDL_Overlay* overlay)
257{
258    if (overlay == NULL)
259    {
260         return;
261    }
262
263    overlay->hwdata->locked = 0;
264}
265
266int BE_DisplayYUVOverlay(_THIS, SDL_Overlay* overlay, SDL_Rect* src, SDL_Rect *dst)
267{
268    if ((overlay == NULL) || (overlay->hwdata==NULL)
269        || (overlay->hwdata->bview==NULL) || (SDL_Win->View() == NULL))
270    {
271        return -1;
272    }
273    if (SDL_Win->LockWithTimeout(50000) != B_OK) {
274        return 0;
275    }
276    BView * bview = overlay->hwdata->bview;
277    if (SDL_Win->IsFullScreen()) {
278    	int left,top;
279    	SDL_Win->GetXYOffset(left,top);
280	    bview->MoveTo(left+dst->x,top+dst->y);
281    } else {
282	    bview->MoveTo(dst->x,dst->y);
283    }
284    bview->ResizeTo(dst->w,dst->h);
285    bview->Flush();
286	if (overlay->hwdata->first_display) {
287		bview->Show();
288		overlay->hwdata->first_display = false;
289	}
290    SDL_Win->Unlock();
291
292	return 0;
293}
294
295void BE_FreeYUVOverlay(_THIS, SDL_Overlay *overlay)
296{
297    if (overlay == NULL)
298    {
299        return;
300    }
301
302    if (overlay->hwdata == NULL)
303    {
304        return;
305    }
306
307    current_overlay=NULL;
308
309	delete overlay->hwdata->bbitmap;
310
311    SDL_free(overlay->hwdata);
312}
313
314}; // extern "C"
315