10 #include "img_format.h"
14 #include "../libvo/fastmemcpy.h"
17 #include "../libvo/sub.h"
18 #include "../libvo/osd.h"
24 #define MAX(a,b) ((a) > (b) ? (a) : (b))
26 static struct vf_priv_s
{
30 unsigned char* fb_ptr
;
38 extern int opt_screen_size_x
;
39 extern int opt_screen_size_y
;
41 //===========================================================================//
44 static struct vf_instance_s
* vf
=NULL
; // fixme (needs sub.c changes)
45 static int orig_w
,orig_h
;
47 static void remove_func_2(int x0
,int y0
, int w
,int h
){
48 // TODO: let's cleanup the place
49 //printf("OSD clear: %d;%d %dx%d \n",x0,y0,w,h);
50 vf_mpi_clear(vf
->dmpi
,x0
,y0
,w
,h
);
53 static void remove_func(int x0
,int y0
, int w
,int h
){
54 if(!vo_osd_changed_flag
) return;
55 // split it to 4 parts:
56 if(y0
<vf
->priv
->exp_y
){
57 // it has parts above the image:
59 if(y
>vf
->priv
->exp_y
) y
=vf
->priv
->exp_y
;
60 remove_func_2(x0
,y0
,w
,y
-y0
);
61 if(y0
+h
<=vf
->priv
->exp_y
) return;
64 if(y0
+h
>vf
->priv
->exp_y
+orig_h
){
65 // it has parts under the image:
67 if(y
<vf
->priv
->exp_y
+orig_h
) y
=vf
->priv
->exp_y
+orig_h
;
68 remove_func_2(x0
,y
,w
,y0
+h
-y
);
69 if(y0
>=vf
->priv
->exp_y
+orig_h
) return;
72 if(x0
>=vf
->priv
->exp_x
|| x0
+w
<=vf
->priv
->exp_x
+orig_w
) return;
73 // TODO clear left and right side of the image if needed
76 static void draw_func(int x0
,int y0
, int w
,int h
,unsigned char* src
, unsigned char *srca
, int stride
){
78 if(!vo_osd_changed_flag
&& vf
->dmpi
->planes
[0]==vf
->priv
->fb_ptr
){
79 // ok, enough to update the area inside the video, leave the black bands
81 if(x0
<vf
->priv
->exp_x
){
82 int tmp
=vf
->priv
->exp_x
-x0
;
83 w
-=tmp
; src
+=tmp
; srca
+=tmp
; x0
+=tmp
;
85 if(y0
<vf
->priv
->exp_y
){
86 int tmp
=vf
->priv
->exp_y
-y0
;
87 h
-=tmp
; src
+=tmp
*stride
; srca
+=tmp
*stride
; y0
+=tmp
;
89 if(x0
+w
>vf
->priv
->exp_x
+orig_w
){
90 w
=vf
->priv
->exp_x
+orig_w
-x0
;
92 if(y0
+h
>vf
->priv
->exp_y
+orig_h
){
93 h
=vf
->priv
->exp_y
+orig_h
-y0
;
96 if(w
<=0 || h
<=0) return; // nothing to do...
97 // printf("OSD redraw: %d;%d %dx%d \n",x0,y0,w,h);
98 dst
=vf
->dmpi
->planes
[0]+
99 vf
->dmpi
->stride
[0]*y0
+
100 (vf
->dmpi
->bpp
>>3)*x0
;
101 switch(vf
->dmpi
->imgfmt
){
104 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dst
,vf
->dmpi
->stride
[0]);
108 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dst
,vf
->dmpi
->stride
[0]);
112 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dst
,vf
->dmpi
->stride
[0]);
116 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dst
,vf
->dmpi
->stride
[0]);
125 vo_draw_alpha_yv12(w
,h
,src
,srca
,stride
,dst
,vf
->dmpi
->stride
[0]);
128 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,dst
,vf
->dmpi
->stride
[0]);
131 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,dst
+1,vf
->dmpi
->stride
[0]);
136 static void draw_osd(struct vf_instance_s
* vf_
,int w
,int h
){
137 vf
=vf_
;orig_w
=w
;orig_h
=h
;
138 // printf("======================================\n");
139 if(vf
->priv
->exp_w
!=w
|| vf
->priv
->exp_h
!=h
||
140 vf
->priv
->exp_x
|| vf
->priv
->exp_y
){
141 // yep, we're expanding image, not just copy.
142 if(vf
->dmpi
->planes
[0]!=vf
->priv
->fb_ptr
){
143 // double buffering, so we need full clear :(
144 remove_func(0,0,vf
->priv
->exp_w
,vf
->priv
->exp_h
);
147 vo_remove_text(vf
->priv
->exp_w
,vf
->priv
->exp_h
,remove_func
);
150 vo_draw_text(vf
->priv
->exp_w
,vf
->priv
->exp_h
,draw_func
);
151 // save buffer pointer for double buffering detection - yes, i know it's
152 // ugly method, but note that codecs with DR support does the same...
154 vf
->priv
->fb_ptr
=vf
->dmpi
->planes
[0];
158 //===========================================================================//
160 static int config(struct vf_instance_s
* vf
,
161 int width
, int height
, int d_width
, int d_height
,
162 unsigned int flags
, unsigned int outfmt
){
163 if (outfmt
== IMGFMT_IF09
) return 0;
164 // calculate the missing parameters:
166 if(vf
->priv
->exp_w
<width
) vf
->priv
->exp_w
=width
;
167 if(vf
->priv
->exp_h
<height
) vf
->priv
->exp_h
=height
;
169 if ( vf
->priv
->exp_w
== -1 ) vf
->priv
->exp_w
=width
;
170 else if (vf
->priv
->exp_w
< -1 ) vf
->priv
->exp_w
=width
- vf
->priv
->exp_w
;
171 else if ( vf
->priv
->exp_w
<width
) vf
->priv
->exp_w
=width
;
172 if ( vf
->priv
->exp_h
== -1 ) vf
->priv
->exp_h
=height
;
173 else if ( vf
->priv
->exp_h
< -1 ) vf
->priv
->exp_h
=height
- vf
->priv
->exp_h
;
174 else if( vf
->priv
->exp_h
<height
) vf
->priv
->exp_h
=height
;
176 if(vf
->priv
->exp_x
<0 || vf
->priv
->exp_x
+width
>vf
->priv
->exp_w
) vf
->priv
->exp_x
=(vf
->priv
->exp_w
-width
)/2;
177 if(vf
->priv
->exp_y
<0 || vf
->priv
->exp_y
+height
>vf
->priv
->exp_h
) vf
->priv
->exp_y
=(vf
->priv
->exp_h
-height
)/2;
178 vf
->priv
->fb_ptr
=NULL
;
180 if(!opt_screen_size_x
&& !opt_screen_size_y
){
181 d_width
=d_width
*vf
->priv
->exp_w
/width
;
182 d_height
=d_height
*vf
->priv
->exp_h
/height
;
184 return vf_next_config(vf
,vf
->priv
->exp_w
,vf
->priv
->exp_h
,d_width
,d_height
,flags
,outfmt
);
187 // there are 4 cases:
188 // codec --DR--> expand --DR--> vo
189 // codec --DR--> expand -copy-> vo
190 // codec -copy-> expand --DR--> vo
191 // codec -copy-> expand -copy-> vo (worst case)
193 static void get_image(struct vf_instance_s
* vf
, mp_image_t
*mpi
){
194 // if(mpi->type==MP_IMGTYPE_IPB) return; // not yet working
196 if(vf
->priv
->osd
&& (mpi
->flags
&MP_IMGFLAG_PRESERVE
)){
197 // check if we have to render osd!
198 vo_update_osd(vf
->priv
->exp_w
, vf
->priv
->exp_h
);
199 if(vo_osd_check_range_update(vf
->priv
->exp_x
,vf
->priv
->exp_y
,
200 vf
->priv
->exp_x
+mpi
->w
,vf
->priv
->exp_y
+mpi
->h
)) return;
203 if(vf
->priv
->exp_w
==mpi
->width
||
204 (mpi
->flags
&(MP_IMGFLAG_ACCEPT_STRIDE
|MP_IMGFLAG_ACCEPT_WIDTH
)) ){
206 mpi
->priv
=vf
->dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
207 mpi
->type
, mpi
->flags
,
208 MAX(vf
->priv
->exp_w
, mpi
->width
+vf
->priv
->exp_x
),
209 MAX(vf
->priv
->exp_h
, mpi
->height
+vf
->priv
->exp_y
));
211 if((vf
->dmpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
) &&
212 !(vf
->dmpi
->flags
& MP_IMGFLAG_DIRECT
)){
213 printf("Full DR not possible, trying SLICES instead!\n");
217 // set up mpi as a cropped-down image of dmpi:
218 if(mpi
->flags
&MP_IMGFLAG_PLANAR
){
219 mpi
->planes
[0]=vf
->dmpi
->planes
[0]+
220 vf
->priv
->exp_y
*vf
->dmpi
->stride
[0]+vf
->priv
->exp_x
;
221 mpi
->planes
[1]=vf
->dmpi
->planes
[1]+
222 (vf
->priv
->exp_y
>>mpi
->chroma_y_shift
)*vf
->dmpi
->stride
[1]+(vf
->priv
->exp_x
>>mpi
->chroma_x_shift
);
223 mpi
->planes
[2]=vf
->dmpi
->planes
[2]+
224 (vf
->priv
->exp_y
>>mpi
->chroma_y_shift
)*vf
->dmpi
->stride
[2]+(vf
->priv
->exp_x
>>mpi
->chroma_x_shift
);
225 mpi
->stride
[1]=vf
->dmpi
->stride
[1];
226 mpi
->stride
[2]=vf
->dmpi
->stride
[2];
228 mpi
->planes
[0]=vf
->dmpi
->planes
[0]+
229 vf
->priv
->exp_y
*vf
->dmpi
->stride
[0]+
230 vf
->priv
->exp_x
*(vf
->dmpi
->bpp
/8);
232 mpi
->stride
[0]=vf
->dmpi
->stride
[0];
233 mpi
->width
=vf
->dmpi
->width
;
234 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
235 mpi
->flags
&=~MP_IMGFLAG_DRAW_CALLBACK
;
236 // vf->dmpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
240 static void start_slice(struct vf_instance_s
* vf
, mp_image_t
*mpi
){
241 // printf("start_slice called! flag=%d\n",mpi->flags&MP_IMGFLAG_DRAW_CALLBACK);
242 if(!vf
->next
->draw_slice
){
243 mpi
->flags
&=~MP_IMGFLAG_DRAW_CALLBACK
;
246 // they want slices!!! allocate the buffer.
248 mpi
->priv
=vf
->dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
249 // MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
250 mpi
->type
, mpi
->flags
,
251 MAX(vf
->priv
->exp_w
, mpi
->width
+vf
->priv
->exp_x
),
252 MAX(vf
->priv
->exp_h
, mpi
->height
+vf
->priv
->exp_y
));
253 if(!(vf
->dmpi
->flags
&MP_IMGFLAG_DRAW_CALLBACK
))
254 printf("WARNING! next filter doesn't support SLICES, get ready for sig11...\n"); // shouldn't happen.
257 static void draw_slice(struct vf_instance_s
* vf
,
258 unsigned char** src
, int* stride
, int w
,int h
, int x
, int y
){
259 // printf("draw_slice() called %d at %d\n",h,y);
260 vf_next_draw_slice(vf
,src
,stride
,w
,h
,x
+vf
->priv
->exp_x
,y
+vf
->priv
->exp_y
);
263 static int put_image(struct vf_instance_s
* vf
, mp_image_t
*mpi
){
264 if(mpi
->flags
&MP_IMGFLAG_DIRECT
|| mpi
->flags
&MP_IMGFLAG_DRAW_CALLBACK
){
266 if(!vf
->dmpi
) { printf("Why do we get NULL \n"); return 0; }
268 if(mpi
->flags
&MP_IMGFLAG_DRAW_CALLBACK
){
269 if(vf
->priv
->exp_y
>0)
270 vf_next_draw_slice(vf
, vf
->dmpi
->planes
, vf
->dmpi
->stride
,
271 vf
->dmpi
->w
,vf
->priv
->exp_y
,0,0);
272 if(vf
->priv
->exp_y
+mpi
->h
<vf
->dmpi
->h
)
273 vf_next_draw_slice(vf
, vf
->dmpi
->planes
, vf
->dmpi
->stride
,
274 vf
->dmpi
->w
,vf
->dmpi
->h
-(vf
->priv
->exp_y
+mpi
->h
),
275 0,vf
->priv
->exp_y
+mpi
->h
);
278 if(vf
->priv
->osd
) draw_osd(vf
,mpi
->w
,mpi
->h
);
280 // we've used DR, so we're ready...
281 if(!(mpi
->flags
&MP_IMGFLAG_PLANAR
))
282 vf
->dmpi
->planes
[1] = mpi
->planes
[1]; // passthrough rgb8 palette
283 return vf_next_put_image(vf
,vf
->dmpi
);
286 // hope we'll get DR buffer:
287 vf
->dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
288 MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
289 vf
->priv
->exp_w
, vf
->priv
->exp_h
);
292 if(mpi
->flags
&MP_IMGFLAG_PLANAR
){
293 memcpy_pic(vf
->dmpi
->planes
[0]+
294 vf
->priv
->exp_y
*vf
->dmpi
->stride
[0]+vf
->priv
->exp_x
,
295 mpi
->planes
[0], mpi
->w
, mpi
->h
,
296 vf
->dmpi
->stride
[0],mpi
->stride
[0]);
297 memcpy_pic(vf
->dmpi
->planes
[1]+
298 (vf
->priv
->exp_y
>>mpi
->chroma_y_shift
)*vf
->dmpi
->stride
[1]+(vf
->priv
->exp_x
>>mpi
->chroma_x_shift
),
299 mpi
->planes
[1], mpi
->chroma_width
, mpi
->chroma_height
,
300 vf
->dmpi
->stride
[1],mpi
->stride
[1]);
301 memcpy_pic(vf
->dmpi
->planes
[2]+
302 (vf
->priv
->exp_y
>>mpi
->chroma_y_shift
)*vf
->dmpi
->stride
[2]+(vf
->priv
->exp_x
>>mpi
->chroma_x_shift
),
303 mpi
->planes
[2], mpi
->chroma_width
, mpi
->chroma_height
,
304 vf
->dmpi
->stride
[2],mpi
->stride
[2]);
306 memcpy_pic(vf
->dmpi
->planes
[0]+
307 vf
->priv
->exp_y
*vf
->dmpi
->stride
[0]+vf
->priv
->exp_x
*(vf
->dmpi
->bpp
/8),
308 mpi
->planes
[0], mpi
->w
*(vf
->dmpi
->bpp
/8), mpi
->h
,
309 vf
->dmpi
->stride
[0],mpi
->stride
[0]);
310 vf
->dmpi
->planes
[1] = mpi
->planes
[1]; // passthrough rgb8 palette
313 if(vf
->priv
->osd
) draw_osd(vf
,mpi
->w
,mpi
->h
);
315 return vf_next_put_image(vf
,vf
->dmpi
);
318 //===========================================================================//
320 static int control(struct vf_instance_s
* vf
, int request
, void* data
){
323 case VFCTRL_DRAW_OSD
:
324 if(vf
->priv
->osd
) return CONTROL_TRUE
;
327 return vf_next_control(vf
,request
,data
);
330 static int open(vf_instance_t
*vf
, char* args
){
333 vf
->start_slice
=start_slice
;
334 vf
->draw_slice
=draw_slice
;
335 vf
->get_image
=get_image
;
336 vf
->put_image
=put_image
;
338 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
346 if(args
) sscanf(args
, "%d:%d:%d:%d:%d",
352 mp_msg(MSGT_VFILTER
, MSGL_INFO
, "Expand: %d x %d, %d ; %d (-1=autodetect) osd: %d\n",
361 #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
362 static m_option_t vf_opts_fields
[] = {
363 {"w", ST_OFF(exp_w
), CONF_TYPE_INT
, 0, 0 ,0, NULL
},
364 {"h", ST_OFF(exp_h
), CONF_TYPE_INT
, 0, 0 ,0, NULL
},
365 {"x", ST_OFF(exp_x
), CONF_TYPE_INT
, M_OPT_MIN
, -1, 0, NULL
},
366 {"y", ST_OFF(exp_y
), CONF_TYPE_INT
, M_OPT_MIN
, -1, 0, NULL
},
367 {"osd", ST_OFF(osd
), CONF_TYPE_FLAG
, 0 , 0, 1, NULL
},
368 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
371 static m_struct_t vf_opts
= {
373 sizeof(struct vf_priv_s
),
380 vf_info_t vf_info_expand
= {
393 //===========================================================================//