1 /* vf_bmovl.c v0.9.1 - BitMap OVerLay videofilter for MPlayer
3 * (C) 2002 Per Wigren <wigren@home.se>
4 * Licenced under the GNU General Public License
6 * Use MPlayer as a framebuffer to read bitmaps and commands from a FIFO
7 * and display them in the window.
11 * RGBA32 width height xpos ypos alpha clear
12 * * Followed by width*height*4 bytes of raw RGBA32 data.
13 * ABGR32 width height xpos ypos alpha clear
14 * * Followed by width*height*4 bytes of raw ABGR32 data.
15 * RGB24 width height xpos ypos alpha clear
16 * * Followed by width*height*3 bytes of raw RGB32 data.
17 * BGR24 width height xpos ypos alpha clear
18 * * Followed by width*height*3 bytes of raw BGR32 data.
20 * ALPHA width height xpos ypos alpha
21 * * Change alpha for area
22 * CLEAR width height xpos ypos
25 * * Disable all alpha transparency!
26 * Send "ALPHA 0 0 0 0 0" to enable again!
33 * width, height Size of image/area
34 * xpos, ypos Start blitting at X/Y position
35 * alpha Set alpha difference. 0 means same as original.
36 * 255 makes everything opaque
37 * -255 makes everything transparent
38 * If you set this to -255 you can then send a sequence of
39 * ALPHA-commands to set the area to -225, -200, -175 etc
40 * for a nice fade-in-effect! ;)
41 * clear Clear the framebuffer before blitting. 1 means clear.
42 * If 0, the image will just be blitted on top of the old
43 * one, so you don't need to send 1,8MB of RGBA32 data
44 * everytime a small part of the screen is updated.
46 * Arguments for the filter are hidden:opaque:fifo
47 * For example 1:0:/tmp/myfifo.fifo will start the filter hidden, transparent
48 * and use /tmp/myfifo.fifo as the fifo.
50 * If you find bugs, please send me patches! ;)
52 * This filter was developed for use in Freevo (http://freevo.sf.net), but
53 * anyone is free to use it! ;)
63 #include <sys/types.h>
69 #include "img_format.h"
71 #ifndef HAVE_NO_POSIX_SELECT
75 #include "libvo/fastmemcpy.h"
77 #define IS_RAWIMG 0x100
81 #define IMG_RGBA32 0x101
82 #define IMG_ABGR32 0x102
83 #define IMG_RGB24 0x103
84 #define IMG_BGR24 0x104
86 #define CMD_CLEAR 0x001
87 #define CMD_ALPHA 0x002
92 #define MAX(a,b) ((a) > (b) ? (a) : (b))
93 #define MIN(a,b) ((a) < (b) ? (a) : (b))
94 #define INRANGE(a,b,c) ( ((a) < (b)) ? (b) : ( ((a) > (c)) ? (c) : (a) ) )
96 #define rgb2y(R,G,B) ( (( 263*R + 516*G + 100*B) >> 10) + 16 )
97 #define rgb2u(R,G,B) ( ((-152*R - 298*G + 450*B) >> 10) + 128 )
98 #define rgb2v(R,G,B) ( (( 450*R - 376*G - 73*B) >> 10) + 128 )
100 #define DBG(a) (mp_msg(MSGT_VFILTER, MSGL_DBG2, "DEBUG: %d\n", a))
103 int w
, h
, x1
, y1
, x2
, y2
;
105 unsigned char *y
, *u
, *v
, *a
, *oa
;
113 query_format(struct vf_instance_s
* vf
, unsigned int fmt
){
114 if(fmt
==IMGFMT_YV12
) return VFCAP_CSP_SUPPORTED
;
120 config(struct vf_instance_s
* vf
,
121 int width
, int height
, int d_width
, int d_height
,
122 unsigned int flags
, unsigned int outfmt
)
124 vf
->priv
->bitmap
.y
= malloc( width
*height
);
125 vf
->priv
->bitmap
.u
= malloc( width
*height
/4 );
126 vf
->priv
->bitmap
.v
= malloc( width
*height
/4 );
127 vf
->priv
->bitmap
.a
= malloc( width
*height
);
128 vf
->priv
->bitmap
.oa
= malloc( width
*height
);
129 if(!( vf
->priv
->bitmap
.y
&&
130 vf
->priv
->bitmap
.u
&&
131 vf
->priv
->bitmap
.v
&&
132 vf
->priv
->bitmap
.a
&&
133 vf
->priv
->bitmap
.oa
)) {
134 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Could not allocate memory for bitmap buffer: %s\n", strerror(errno
) );
138 // Set default to black...
139 memset( vf
->priv
->bitmap
.u
, 128, width
*height
/4 );
140 memset( vf
->priv
->bitmap
.v
, 128, width
*height
/4 );
142 vf
->priv
->w
= vf
->priv
->x1
= width
;
143 vf
->priv
->h
= vf
->priv
->y1
= height
;
144 vf
->priv
->y2
= vf
->priv
->x2
= 0;
146 return vf_next_config(vf
, width
, height
, d_width
, d_height
, flags
, outfmt
);
150 uninit(struct vf_instance_s
*vf
)
153 free(vf
->priv
->bitmap
.y
);
154 free(vf
->priv
->bitmap
.u
);
155 free(vf
->priv
->bitmap
.v
);
156 free(vf
->priv
->bitmap
.a
);
157 free(vf
->priv
->bitmap
.oa
);
158 if (vf
->priv
->stream_fd
>= 0)
159 close(vf
->priv
->stream_fd
);
165 _read_cmd(int fd
, char *cmd
, char *args
) {
166 int done
=FALSE
, pos
=0;
170 if(! read( fd
, &tmp
, 1 ) ) return FALSE
;
171 if( (tmp
>='A' && tmp
<='Z') || (tmp
>='0' && tmp
<='9') )
173 else if(tmp
== ' ') {
177 else if(tmp
== '\n') {
189 if(! read( fd
, &tmp
, 1 ) ) return FALSE
;
190 if( (tmp
>= ' ') && (pos
<100) ) args
[pos
]=tmp
;
202 put_image(struct vf_instance_s
* vf
, mp_image_t
* mpi
, double pts
){
203 int buf_x
=0, buf_y
=0, buf_pos
=0;
205 int xpos
=0, ypos
=0, pos
=0;
206 unsigned char red
=0, green
=0, blue
=0;
210 dmpi
= vf_get_image(vf
->next
, mpi
->imgfmt
, MP_IMGTYPE_TEMP
,
211 MP_IMGFLAG_ACCEPT_STRIDE
| MP_IMGFLAG_PREFER_ALIGNED_STRIDE
,
214 memcpy( dmpi
->planes
[0], mpi
->planes
[0], mpi
->stride
[0] * mpi
->height
);
215 memcpy( dmpi
->planes
[1], mpi
->planes
[1], mpi
->stride
[1] * mpi
->chroma_height
);
216 memcpy( dmpi
->planes
[2], mpi
->planes
[2], mpi
->stride
[2] * mpi
->chroma_height
);
218 if(vf
->priv
->stream_fd
>= 0) {
222 FD_SET( vf
->priv
->stream_fd
, &vf
->priv
->stream_fdset
);
223 tv
.tv_sec
=0; tv
.tv_usec
=0;
225 ready
= select( vf
->priv
->stream_fd
+1, &vf
->priv
->stream_fdset
, NULL
, NULL
, &tv
);
227 // We've got new data from the FIFO
229 char cmd
[20], args
[100];
230 int imgw
,imgh
,imgx
,imgy
,clear
,imgalpha
,pxsz
=1,command
;
231 unsigned char *buffer
= NULL
;
233 if(! _read_cmd( vf
->priv
->stream_fd
, cmd
, args
) ) {
234 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "\nvf_bmovl: Error reading commands: %s\n\n", strerror(errno
));
237 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: Got: %s+%s\n", cmd
, args
);
240 if ( strncmp(cmd
,"RGBA32",6)==0 ) { pxsz
=4; command
= IMG_RGBA32
; }
241 else if( strncmp(cmd
,"ABGR32",6)==0 ) { pxsz
=4; command
= IMG_ABGR32
; }
242 else if( strncmp(cmd
,"RGB24" ,5)==0 ) { pxsz
=3; command
= IMG_RGB24
; }
243 else if( strncmp(cmd
,"BGR24" ,5)==0 ) { pxsz
=3; command
= IMG_BGR24
; }
244 else if( strncmp(cmd
,"CLEAR" ,5)==0 ) { pxsz
=1; command
= CMD_CLEAR
; }
245 else if( strncmp(cmd
,"ALPHA" ,5)==0 ) { pxsz
=1; command
= CMD_ALPHA
; }
246 else if( strncmp(cmd
,"OPAQUE",6)==0 ) vf
->priv
->opaque
=TRUE
;
247 else if( strncmp(cmd
,"SHOW", 4)==0 ) vf
->priv
->hidden
=FALSE
;
248 else if( strncmp(cmd
,"HIDE", 4)==0 ) vf
->priv
->hidden
=TRUE
;
249 else if( strncmp(cmd
,"FLUSH" ,5)==0 ) return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
251 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: Unknown command: '%s'. Ignoring.\n", cmd
);
252 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
255 if(command
== CMD_ALPHA
) {
256 sscanf( args
, "%d %d %d %d %d", &imgw
, &imgh
, &imgx
, &imgy
, &imgalpha
);
257 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: ALPHA: %d %d %d %d %d\n\n",
258 imgw
, imgh
, imgx
, imgy
, imgalpha
);
259 if(imgw
==0 && imgh
==0) vf
->priv
->opaque
=FALSE
;
262 if(command
& IS_RAWIMG
) {
263 sscanf( args
, "%d %d %d %d %d %d",
264 &imgw
, &imgh
, &imgx
, &imgy
, &imgalpha
, &clear
);
265 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: RAWIMG: %d %d %d %d %d %d\n\n",
266 imgw
, imgh
, imgx
, imgy
, imgalpha
, clear
);
268 buffer
= malloc(imgw
*imgh
*pxsz
);
270 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: Couldn't allocate temporary buffer! Skipping...\n\n");
271 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
273 /* pipes/sockets might need multiple calls to read(): */
274 want
= (imgw
*imgh
*pxsz
);
276 while (have
< want
) {
277 got
= read( vf
->priv
->stream_fd
, buffer
+have
, want
-have
);
279 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: premature EOF...\n\n");
283 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: read error: %s\n\n", strerror(errno
));
288 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "Got %d bytes... (wanted %d)\n", have
, want
);
291 memset( vf
->priv
->bitmap
.y
, 0, vf
->priv
->w
*vf
->priv
->h
);
292 memset( vf
->priv
->bitmap
.u
, 128, vf
->priv
->w
*vf
->priv
->h
/4 );
293 memset( vf
->priv
->bitmap
.v
, 128, vf
->priv
->w
*vf
->priv
->h
/4 );
294 memset( vf
->priv
->bitmap
.a
, 0, vf
->priv
->w
*vf
->priv
->h
);
295 memset( vf
->priv
->bitmap
.oa
, 0, vf
->priv
->w
*vf
->priv
->h
);
296 vf
->priv
->x1
= dmpi
->width
;
297 vf
->priv
->y1
= dmpi
->height
;
298 vf
->priv
->x2
= vf
->priv
->y2
= 0;
300 // Define how much of our bitmap that contains graphics!
301 vf
->priv
->x1
= MAX( 0, MIN(vf
->priv
->x1
, imgx
) );
302 vf
->priv
->y1
= MAX( 0, MIN(vf
->priv
->y1
, imgy
) );
303 vf
->priv
->x2
= MIN( vf
->priv
->w
, MAX(vf
->priv
->x2
, ( imgx
+ imgw
)) );
304 vf
->priv
->y2
= MIN( vf
->priv
->h
, MAX(vf
->priv
->y2
, ( imgy
+ imgh
)) );
307 if( command
== CMD_CLEAR
) {
308 sscanf( args
, "%d %d %d %d", &imgw
, &imgh
, &imgx
, &imgy
);
309 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: CLEAR: %d %d %d %d\n\n", imgw
, imgh
, imgx
, imgy
);
311 for( ypos
=imgy
; (ypos
< (imgy
+imgh
)) && (ypos
< vf
->priv
->y2
) ; ypos
++ ) {
312 memset( vf
->priv
->bitmap
.y
+ (ypos
*vf
->priv
->w
) + imgx
, 0, imgw
);
313 memset( vf
->priv
->bitmap
.a
+ (ypos
*vf
->priv
->w
) + imgx
, 0, imgw
);
314 memset( vf
->priv
->bitmap
.oa
+ (ypos
*vf
->priv
->w
) + imgx
, 0, imgw
);
316 memset( vf
->priv
->bitmap
.u
+ ((ypos
/2)*dmpi
->stride
[1]) + (imgx
/2), 128, imgw
/2 );
317 memset( vf
->priv
->bitmap
.v
+ ((ypos
/2)*dmpi
->stride
[2]) + (imgx
/2), 128, imgw
/2 );
319 } // Recalculate area that contains graphics
320 if( (imgx
<= vf
->priv
->x1
) && ( (imgw
+imgx
) >= vf
->priv
->x2
) ) {
321 if( (imgy
<= vf
->priv
->y1
) && ( (imgy
+imgh
) >= vf
->priv
->y1
) )
322 vf
->priv
->y1
= imgy
+imgh
;
323 if( (imgy
<= vf
->priv
->y2
) && ( (imgy
+imgh
) >= vf
->priv
->y2
) )
326 if( (imgy
<= vf
->priv
->y1
) && ( (imgy
+imgh
) >= vf
->priv
->y2
) ) {
327 if( (imgx
<= vf
->priv
->x1
) && ( (imgx
+imgw
) >= vf
->priv
->x1
) )
328 vf
->priv
->x1
= imgx
+imgw
;
329 if( (imgx
<= vf
->priv
->x2
) && ( (imgx
+imgw
) >= vf
->priv
->x2
) )
332 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
335 for( buf_y
=0 ; (buf_y
< imgh
) && (buf_y
< (vf
->priv
->h
-imgy
)) ; buf_y
++ ) {
336 for( buf_x
=0 ; (buf_x
< (imgw
*pxsz
)) && (buf_x
< ((vf
->priv
->w
+imgx
)*pxsz
)) ; buf_x
+= pxsz
) {
337 if(command
& IS_RAWIMG
) buf_pos
= (buf_y
* imgw
* pxsz
) + buf_x
;
338 pos
= ((buf_y
+imgy
) * vf
->priv
->w
) + ((buf_x
/pxsz
)+imgx
);
342 red
= buffer
[buf_pos
+0];
343 green
= buffer
[buf_pos
+1];
344 blue
= buffer
[buf_pos
+2];
345 alpha
= buffer
[buf_pos
+3];
348 alpha
= buffer
[buf_pos
+0];
349 blue
= buffer
[buf_pos
+1];
350 green
= buffer
[buf_pos
+2];
351 red
= buffer
[buf_pos
+3];
354 red
= buffer
[buf_pos
+0];
355 green
= buffer
[buf_pos
+1];
356 blue
= buffer
[buf_pos
+2];
360 blue
= buffer
[buf_pos
+0];
361 green
= buffer
[buf_pos
+1];
362 red
= buffer
[buf_pos
+2];
366 vf
->priv
->bitmap
.a
[pos
] = INRANGE((vf
->priv
->bitmap
.oa
[pos
]+imgalpha
),0,255);
369 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Internal error!\n");
372 if( command
& IS_RAWIMG
) {
373 vf
->priv
->bitmap
.y
[pos
] = rgb2y(red
,green
,blue
);
374 vf
->priv
->bitmap
.oa
[pos
] = alpha
;
375 vf
->priv
->bitmap
.a
[pos
] = INRANGE((alpha
+imgalpha
),0,255);
376 if((buf_y
%2) && ((buf_x
/pxsz
)%2)) {
377 pos
= ( ((buf_y
+imgy
)/2) * dmpi
->stride
[1] ) + (((buf_x
/pxsz
)+imgx
)/2);
378 vf
->priv
->bitmap
.u
[pos
] = rgb2u(red
,green
,blue
);
379 vf
->priv
->bitmap
.v
[pos
] = rgb2v(red
,green
,blue
);
385 } else if(ready
< 0) {
386 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: Error %d in fifo: %s\n\n", errno
, strerror(errno
));
390 if(vf
->priv
->hidden
) return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
392 if(vf
->priv
->opaque
) { // Just copy buffer memory to screen
393 for( ypos
=vf
->priv
->y1
; ypos
< vf
->priv
->y2
; ypos
++ ) {
394 memcpy( dmpi
->planes
[0] + (ypos
*dmpi
->stride
[0]) + vf
->priv
->x1
,
395 vf
->priv
->bitmap
.y
+ (ypos
*vf
->priv
->w
) + vf
->priv
->x1
,
396 vf
->priv
->x2
- vf
->priv
->x1
);
398 memcpy( dmpi
->planes
[1] + ((ypos
/2)*dmpi
->stride
[1]) + (vf
->priv
->x1
/2),
399 vf
->priv
->bitmap
.u
+ (((ypos
/2)*(vf
->priv
->w
)/2)) + (vf
->priv
->x1
/2),
400 (vf
->priv
->x2
- vf
->priv
->x1
)/2 );
401 memcpy( dmpi
->planes
[2] + ((ypos
/2)*dmpi
->stride
[2]) + (vf
->priv
->x1
/2),
402 vf
->priv
->bitmap
.v
+ (((ypos
/2)*(vf
->priv
->w
)/2)) + (vf
->priv
->x1
/2),
403 (vf
->priv
->x2
- vf
->priv
->x1
)/2 );
406 } else { // Blit the bitmap to the videoscreen, pixel for pixel
407 for( ypos
=vf
->priv
->y1
; ypos
< vf
->priv
->y2
; ypos
++ ) {
408 for ( xpos
=vf
->priv
->x1
; xpos
< vf
->priv
->x2
; xpos
++ ) {
409 pos
= (ypos
* dmpi
->stride
[0]) + xpos
;
411 alpha
= vf
->priv
->bitmap
.a
[pos
];
413 if (alpha
== 0) continue; // Completly transparent pixel
415 if (alpha
== 255) { // Opaque pixel
416 dmpi
->planes
[0][pos
] = vf
->priv
->bitmap
.y
[pos
];
417 if ((ypos
%2) && (xpos
%2)) {
418 pos
= ( (ypos
/2) * dmpi
->stride
[1] ) + (xpos
/2);
419 dmpi
->planes
[1][pos
] = vf
->priv
->bitmap
.u
[pos
];
420 dmpi
->planes
[2][pos
] = vf
->priv
->bitmap
.v
[pos
];
422 } else { // Alphablended pixel
423 dmpi
->planes
[0][pos
] =
424 ((255 - alpha
) * (int)dmpi
->planes
[0][pos
] +
425 alpha
* (int)vf
->priv
->bitmap
.y
[pos
]) >> 8;
427 if ((ypos
%2) && (xpos
%2)) {
428 pos
= ( (ypos
/2) * dmpi
->stride
[1] ) + (xpos
/2);
430 dmpi
->planes
[1][pos
] =
431 ((255 - alpha
) * (int)dmpi
->planes
[1][pos
] +
432 alpha
* (int)vf
->priv
->bitmap
.u
[pos
]) >> 8;
434 dmpi
->planes
[2][pos
] =
435 ((255 - alpha
) * (int)dmpi
->planes
[2][pos
] +
436 alpha
* (int)vf
->priv
->bitmap
.v
[pos
]) >> 8;
442 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
446 vf_open(vf_instance_t
* vf
, char* args
)
451 vf
->put_image
= put_image
;
452 vf
->query_format
= query_format
;
455 vf
->priv
= malloc(sizeof(struct vf_priv_s
));
457 if(!args
|| sscanf(args
, "%d:%d:%s", &vf
->priv
->hidden
, &vf
->priv
->opaque
, filename
) < 3 ) {
458 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Bad arguments!\n");
459 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Arguments are 'bool hidden:bool opaque:string fifo'\n");
463 vf
->priv
->stream_fd
= open(filename
, O_RDWR
);
464 if(vf
->priv
->stream_fd
>= 0) {
465 FD_ZERO( &vf
->priv
->stream_fdset
);
466 mp_msg(MSGT_VFILTER
, MSGL_INFO
, "vf_bmovl: Opened fifo %s as FD %d\n", filename
, vf
->priv
->stream_fd
);
468 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "vf_bmovl: Error! Couldn't open FIFO %s: %s\n", filename
, strerror(errno
));
469 vf
->priv
->stream_fd
= -1;
475 vf_info_t vf_info_bmovl
= {
476 "Read bitmaps from a FIFO and display them in window",