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"
72 #include "libavutil/common.h"
74 #include "libvo/fastmemcpy.h"
76 #define IS_RAWIMG 0x100
80 #define IMG_RGBA32 0x101
81 #define IMG_ABGR32 0x102
82 #define IMG_RGB24 0x103
83 #define IMG_BGR24 0x104
85 #define CMD_CLEAR 0x001
86 #define CMD_ALPHA 0x002
91 #define INRANGE(a,b,c) ( ((a) < (b)) ? (b) : ( ((a) > (c)) ? (c) : (a) ) )
93 #define rgb2y(R,G,B) ( (( 263*R + 516*G + 100*B) >> 10) + 16 )
94 #define rgb2u(R,G,B) ( ((-152*R - 298*G + 450*B) >> 10) + 128 )
95 #define rgb2v(R,G,B) ( (( 450*R - 376*G - 73*B) >> 10) + 128 )
97 #define DBG(a) (mp_msg(MSGT_VFILTER, MSGL_DBG2, "DEBUG: %d\n", a))
100 int w
, h
, x1
, y1
, x2
, y2
;
102 unsigned char *y
, *u
, *v
, *a
, *oa
;
110 query_format(struct vf_instance
* vf
, unsigned int fmt
){
111 if(fmt
==IMGFMT_YV12
) return VFCAP_CSP_SUPPORTED
;
117 config(struct vf_instance
* vf
,
118 int width
, int height
, int d_width
, int d_height
,
119 unsigned int flags
, unsigned int outfmt
)
121 vf
->priv
->bitmap
.y
= malloc( width
*height
);
122 vf
->priv
->bitmap
.u
= malloc( width
*height
/4 );
123 vf
->priv
->bitmap
.v
= malloc( width
*height
/4 );
124 vf
->priv
->bitmap
.a
= malloc( width
*height
);
125 vf
->priv
->bitmap
.oa
= malloc( width
*height
);
126 if(!( vf
->priv
->bitmap
.y
&&
127 vf
->priv
->bitmap
.u
&&
128 vf
->priv
->bitmap
.v
&&
129 vf
->priv
->bitmap
.a
&&
130 vf
->priv
->bitmap
.oa
)) {
131 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Could not allocate memory for bitmap buffer: %s\n", strerror(errno
) );
135 // Set default to black...
136 memset( vf
->priv
->bitmap
.u
, 128, width
*height
/4 );
137 memset( vf
->priv
->bitmap
.v
, 128, width
*height
/4 );
139 vf
->priv
->w
= vf
->priv
->x1
= width
;
140 vf
->priv
->h
= vf
->priv
->y1
= height
;
141 vf
->priv
->y2
= vf
->priv
->x2
= 0;
143 return vf_next_config(vf
, width
, height
, d_width
, d_height
, flags
, outfmt
);
147 uninit(struct vf_instance
*vf
)
150 free(vf
->priv
->bitmap
.y
);
151 free(vf
->priv
->bitmap
.u
);
152 free(vf
->priv
->bitmap
.v
);
153 free(vf
->priv
->bitmap
.a
);
154 free(vf
->priv
->bitmap
.oa
);
155 if (vf
->priv
->stream_fd
>= 0)
156 close(vf
->priv
->stream_fd
);
162 _read_cmd(int fd
, char *cmd
, char *args
) {
163 int done
=FALSE
, pos
=0;
167 if(! read( fd
, &tmp
, 1 ) ) return FALSE
;
168 if( (tmp
>='A' && tmp
<='Z') || (tmp
>='0' && tmp
<='9') )
170 else if(tmp
== ' ') {
174 else if(tmp
== '\n') {
186 if(! read( fd
, &tmp
, 1 ) ) return FALSE
;
187 if( (tmp
>= ' ') && (pos
<100) ) args
[pos
]=tmp
;
199 put_image(struct vf_instance
* vf
, mp_image_t
* mpi
, double pts
){
200 int buf_x
=0, buf_y
=0, buf_pos
=0;
202 int xpos
=0, ypos
=0, pos
=0;
203 unsigned char red
=0, green
=0, blue
=0;
207 dmpi
= vf_get_image(vf
->next
, mpi
->imgfmt
, MP_IMGTYPE_TEMP
,
208 MP_IMGFLAG_ACCEPT_STRIDE
| MP_IMGFLAG_PREFER_ALIGNED_STRIDE
,
211 memcpy_pic( dmpi
->planes
[0], mpi
->planes
[0], mpi
->width
, mpi
->height
, dmpi
->stride
[0], mpi
->stride
[0] );
212 memcpy_pic( dmpi
->planes
[1], mpi
->planes
[1], mpi
->chroma_width
, mpi
->chroma_height
, dmpi
->stride
[1], mpi
->stride
[1] );
213 memcpy_pic( dmpi
->planes
[2], mpi
->planes
[2], mpi
->chroma_width
, mpi
->chroma_height
, dmpi
->stride
[2], mpi
->stride
[2] );
215 if(vf
->priv
->stream_fd
>= 0) {
219 FD_SET( vf
->priv
->stream_fd
, &vf
->priv
->stream_fdset
);
220 tv
.tv_sec
=0; tv
.tv_usec
=0;
222 ready
= select( vf
->priv
->stream_fd
+1, &vf
->priv
->stream_fdset
, NULL
, NULL
, &tv
);
224 // We've got new data from the FIFO
226 char cmd
[20], args
[100];
227 int imgw
,imgh
,imgx
,imgy
,clear
,imgalpha
,pxsz
=1,command
;
228 unsigned char *buffer
= NULL
;
230 if(! _read_cmd( vf
->priv
->stream_fd
, cmd
, args
) ) {
231 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "\nvf_bmovl: Error reading commands: %s\n\n", strerror(errno
));
234 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: Got: %s+%s\n", cmd
, args
);
237 if ( strncmp(cmd
,"RGBA32",6)==0 ) { pxsz
=4; command
= IMG_RGBA32
; }
238 else if( strncmp(cmd
,"ABGR32",6)==0 ) { pxsz
=4; command
= IMG_ABGR32
; }
239 else if( strncmp(cmd
,"RGB24" ,5)==0 ) { pxsz
=3; command
= IMG_RGB24
; }
240 else if( strncmp(cmd
,"BGR24" ,5)==0 ) { pxsz
=3; command
= IMG_BGR24
; }
241 else if( strncmp(cmd
,"CLEAR" ,5)==0 ) { pxsz
=1; command
= CMD_CLEAR
; }
242 else if( strncmp(cmd
,"ALPHA" ,5)==0 ) { pxsz
=1; command
= CMD_ALPHA
; }
243 else if( strncmp(cmd
,"OPAQUE",6)==0 ) vf
->priv
->opaque
=TRUE
;
244 else if( strncmp(cmd
,"SHOW", 4)==0 ) vf
->priv
->hidden
=FALSE
;
245 else if( strncmp(cmd
,"HIDE", 4)==0 ) vf
->priv
->hidden
=TRUE
;
246 else if( strncmp(cmd
,"FLUSH" ,5)==0 ) return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
248 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: Unknown command: '%s'. Ignoring.\n", cmd
);
249 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
252 if(command
== CMD_ALPHA
) {
253 sscanf( args
, "%d %d %d %d %d", &imgw
, &imgh
, &imgx
, &imgy
, &imgalpha
);
254 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: ALPHA: %d %d %d %d %d\n\n",
255 imgw
, imgh
, imgx
, imgy
, imgalpha
);
256 if(imgw
==0 && imgh
==0) vf
->priv
->opaque
=FALSE
;
259 if(command
& IS_RAWIMG
) {
260 sscanf( args
, "%d %d %d %d %d %d",
261 &imgw
, &imgh
, &imgx
, &imgy
, &imgalpha
, &clear
);
262 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: RAWIMG: %d %d %d %d %d %d\n\n",
263 imgw
, imgh
, imgx
, imgy
, imgalpha
, clear
);
265 buffer
= malloc(imgw
*imgh
*pxsz
);
267 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: Couldn't allocate temporary buffer! Skipping...\n\n");
268 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
270 /* pipes/sockets might need multiple calls to read(): */
271 want
= (imgw
*imgh
*pxsz
);
273 while (have
< want
) {
274 got
= read( vf
->priv
->stream_fd
, buffer
+have
, want
-have
);
276 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: premature EOF...\n\n");
280 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: read error: %s\n\n", strerror(errno
));
285 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "Got %d bytes... (wanted %d)\n", have
, want
);
288 memset( vf
->priv
->bitmap
.y
, 0, vf
->priv
->w
*vf
->priv
->h
);
289 memset( vf
->priv
->bitmap
.u
, 128, vf
->priv
->w
*vf
->priv
->h
/4 );
290 memset( vf
->priv
->bitmap
.v
, 128, vf
->priv
->w
*vf
->priv
->h
/4 );
291 memset( vf
->priv
->bitmap
.a
, 0, vf
->priv
->w
*vf
->priv
->h
);
292 memset( vf
->priv
->bitmap
.oa
, 0, vf
->priv
->w
*vf
->priv
->h
);
293 vf
->priv
->x1
= dmpi
->width
;
294 vf
->priv
->y1
= dmpi
->height
;
295 vf
->priv
->x2
= vf
->priv
->y2
= 0;
297 // Define how much of our bitmap that contains graphics!
298 vf
->priv
->x1
= av_clip(imgx
, 0, vf
->priv
->x1
);
299 vf
->priv
->y1
= av_clip(imgy
, 0, vf
->priv
->y1
);
300 vf
->priv
->x2
= av_clip(imgx
+ imgw
, vf
->priv
->x2
, vf
->priv
->w
);
301 vf
->priv
->y2
= av_clip(imgy
+ imgh
, vf
->priv
->y2
, vf
->priv
->h
);
304 if( command
== CMD_CLEAR
) {
305 sscanf( args
, "%d %d %d %d", &imgw
, &imgh
, &imgx
, &imgy
);
306 mp_msg(MSGT_VFILTER
, MSGL_DBG2
, "\nDEBUG: CLEAR: %d %d %d %d\n\n", imgw
, imgh
, imgx
, imgy
);
308 for( ypos
=imgy
; (ypos
< (imgy
+imgh
)) && (ypos
< vf
->priv
->y2
) ; ypos
++ ) {
309 memset( vf
->priv
->bitmap
.y
+ (ypos
*vf
->priv
->w
) + imgx
, 0, imgw
);
310 memset( vf
->priv
->bitmap
.a
+ (ypos
*vf
->priv
->w
) + imgx
, 0, imgw
);
311 memset( vf
->priv
->bitmap
.oa
+ (ypos
*vf
->priv
->w
) + imgx
, 0, imgw
);
313 memset( vf
->priv
->bitmap
.u
+ ((ypos
/2)*dmpi
->stride
[1]) + (imgx
/2), 128, imgw
/2 );
314 memset( vf
->priv
->bitmap
.v
+ ((ypos
/2)*dmpi
->stride
[2]) + (imgx
/2), 128, imgw
/2 );
316 } // Recalculate area that contains graphics
317 if( (imgx
<= vf
->priv
->x1
) && ( (imgw
+imgx
) >= vf
->priv
->x2
) ) {
318 if( (imgy
<= vf
->priv
->y1
) && ( (imgy
+imgh
) >= vf
->priv
->y1
) )
319 vf
->priv
->y1
= imgy
+imgh
;
320 if( (imgy
<= vf
->priv
->y2
) && ( (imgy
+imgh
) >= vf
->priv
->y2
) )
323 if( (imgy
<= vf
->priv
->y1
) && ( (imgy
+imgh
) >= vf
->priv
->y2
) ) {
324 if( (imgx
<= vf
->priv
->x1
) && ( (imgx
+imgw
) >= vf
->priv
->x1
) )
325 vf
->priv
->x1
= imgx
+imgw
;
326 if( (imgx
<= vf
->priv
->x2
) && ( (imgx
+imgw
) >= vf
->priv
->x2
) )
329 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
332 for( buf_y
=0 ; (buf_y
< imgh
) && (buf_y
< (vf
->priv
->h
-imgy
)) ; buf_y
++ ) {
333 for( buf_x
=0 ; (buf_x
< (imgw
*pxsz
)) && (buf_x
< ((vf
->priv
->w
+imgx
)*pxsz
)) ; buf_x
+= pxsz
) {
334 if(command
& IS_RAWIMG
) buf_pos
= (buf_y
* imgw
* pxsz
) + buf_x
;
335 pos
= ((buf_y
+imgy
) * vf
->priv
->w
) + ((buf_x
/pxsz
)+imgx
);
339 red
= buffer
[buf_pos
+0];
340 green
= buffer
[buf_pos
+1];
341 blue
= buffer
[buf_pos
+2];
342 alpha
= buffer
[buf_pos
+3];
345 alpha
= buffer
[buf_pos
+0];
346 blue
= buffer
[buf_pos
+1];
347 green
= buffer
[buf_pos
+2];
348 red
= buffer
[buf_pos
+3];
351 red
= buffer
[buf_pos
+0];
352 green
= buffer
[buf_pos
+1];
353 blue
= buffer
[buf_pos
+2];
357 blue
= buffer
[buf_pos
+0];
358 green
= buffer
[buf_pos
+1];
359 red
= buffer
[buf_pos
+2];
363 vf
->priv
->bitmap
.a
[pos
] = INRANGE((vf
->priv
->bitmap
.oa
[pos
]+imgalpha
),0,255);
366 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Internal error!\n");
369 if( command
& IS_RAWIMG
) {
370 vf
->priv
->bitmap
.y
[pos
] = rgb2y(red
,green
,blue
);
371 vf
->priv
->bitmap
.oa
[pos
] = alpha
;
372 vf
->priv
->bitmap
.a
[pos
] = INRANGE((alpha
+imgalpha
),0,255);
373 if((buf_y
%2) && ((buf_x
/pxsz
)%2)) {
374 pos
= ( ((buf_y
+imgy
)/2) * dmpi
->stride
[1] ) + (((buf_x
/pxsz
)+imgx
)/2);
375 vf
->priv
->bitmap
.u
[pos
] = rgb2u(red
,green
,blue
);
376 vf
->priv
->bitmap
.v
[pos
] = rgb2v(red
,green
,blue
);
382 } else if(ready
< 0) {
383 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "\nvf_bmovl: Error %d in fifo: %s\n\n", errno
, strerror(errno
));
387 if(vf
->priv
->hidden
) return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
389 if(vf
->priv
->opaque
) { // Just copy buffer memory to screen
390 for( ypos
=vf
->priv
->y1
; ypos
< vf
->priv
->y2
; ypos
++ ) {
391 fast_memcpy( dmpi
->planes
[0] + (ypos
*dmpi
->stride
[0]) + vf
->priv
->x1
,
392 vf
->priv
->bitmap
.y
+ (ypos
*vf
->priv
->w
) + vf
->priv
->x1
,
393 vf
->priv
->x2
- vf
->priv
->x1
);
395 fast_memcpy( dmpi
->planes
[1] + ((ypos
/2)*dmpi
->stride
[1]) + (vf
->priv
->x1
/2),
396 vf
->priv
->bitmap
.u
+ (((ypos
/2)*(vf
->priv
->w
)/2)) + (vf
->priv
->x1
/2),
397 (vf
->priv
->x2
- vf
->priv
->x1
)/2 );
398 fast_memcpy( dmpi
->planes
[2] + ((ypos
/2)*dmpi
->stride
[2]) + (vf
->priv
->x1
/2),
399 vf
->priv
->bitmap
.v
+ (((ypos
/2)*(vf
->priv
->w
)/2)) + (vf
->priv
->x1
/2),
400 (vf
->priv
->x2
- vf
->priv
->x1
)/2 );
403 } else { // Blit the bitmap to the videoscreen, pixel for pixel
404 for( ypos
=vf
->priv
->y1
; ypos
< vf
->priv
->y2
; ypos
++ ) {
405 for ( xpos
=vf
->priv
->x1
; xpos
< vf
->priv
->x2
; xpos
++ ) {
406 pos
= (ypos
* dmpi
->stride
[0]) + xpos
;
408 alpha
= vf
->priv
->bitmap
.a
[pos
];
410 if (alpha
== 0) continue; // Completly transparent pixel
412 if (alpha
== 255) { // Opaque pixel
413 dmpi
->planes
[0][pos
] = vf
->priv
->bitmap
.y
[pos
];
414 if ((ypos
%2) && (xpos
%2)) {
415 pos
= ( (ypos
/2) * dmpi
->stride
[1] ) + (xpos
/2);
416 dmpi
->planes
[1][pos
] = vf
->priv
->bitmap
.u
[pos
];
417 dmpi
->planes
[2][pos
] = vf
->priv
->bitmap
.v
[pos
];
419 } else { // Alphablended pixel
420 dmpi
->planes
[0][pos
] =
421 ((255 - alpha
) * (int)dmpi
->planes
[0][pos
] +
422 alpha
* (int)vf
->priv
->bitmap
.y
[pos
]) >> 8;
424 if ((ypos
%2) && (xpos
%2)) {
425 pos
= ( (ypos
/2) * dmpi
->stride
[1] ) + (xpos
/2);
427 dmpi
->planes
[1][pos
] =
428 ((255 - alpha
) * (int)dmpi
->planes
[1][pos
] +
429 alpha
* (int)vf
->priv
->bitmap
.u
[pos
]) >> 8;
431 dmpi
->planes
[2][pos
] =
432 ((255 - alpha
) * (int)dmpi
->planes
[2][pos
] +
433 alpha
* (int)vf
->priv
->bitmap
.v
[pos
]) >> 8;
439 return vf_next_put_image(vf
, dmpi
, MP_NOPTS_VALUE
);
443 vf_open(vf_instance_t
* vf
, char* args
)
448 vf
->put_image
= put_image
;
449 vf
->query_format
= query_format
;
452 vf
->priv
= malloc(sizeof(struct vf_priv_s
));
454 if(!args
|| sscanf(args
, "%d:%d:%s", &vf
->priv
->hidden
, &vf
->priv
->opaque
, filename
) < 3 ) {
455 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Bad arguments!\n");
456 mp_msg(MSGT_VFILTER
, MSGL_ERR
, "vf_bmovl: Arguments are 'bool hidden:bool opaque:string fifo'\n");
460 vf
->priv
->stream_fd
= open(filename
, O_RDWR
);
461 if(vf
->priv
->stream_fd
>= 0) {
462 FD_ZERO( &vf
->priv
->stream_fdset
);
463 mp_msg(MSGT_VFILTER
, MSGL_INFO
, "vf_bmovl: Opened fifo %s as FD %d\n", filename
, vf
->priv
->stream_fd
);
465 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "vf_bmovl: Error! Couldn't open FIFO %s: %s\n", filename
, strerror(errno
));
466 vf
->priv
->stream_fd
= -1;
472 const vf_info_t vf_info_bmovl
= {
473 "Read bitmaps from a FIFO and display them in window",