1 /*****************************************************************************
2 * render.c : Philips OGT and CVD (VCD Subtitle) blending routines
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: render.c,v 1.27 2004/01/31 05:53:35 rocky Exp $
7 * Author: Rocky Bernstein <rocky@panix.com>
9 * Sam Hocevar <sam@zoy.org>
10 * Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
11 * Roine Gustafsson <roine@popstar.com>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*#define TESTING_TRANSPARENCY 1*/
30 /*****************************************************************************
32 *****************************************************************************/
35 #include <vlc/decoder.h>
41 /* We use 4 bits for an alpha value: 0..15, 15 is completely transparent and
42 0 completely opaque. Note that although SVCD allow 8-bits, pixels
43 previously should be scaled down to 4 bits to use these routines.
45 #define ALPHA_BITS (4)
46 #define MAX_ALPHA ((1<<ALPHA_BITS) - 1)
47 #define ALPHA_SCALEDOWN (8-ALPHA_BITS)
49 /* We use a fixed-point arithmetic to scaling ratios so that we
50 can use integer arithmetic and still get fairly precise
51 results. ASCALE is a left shift amount.
53 #define ASCALE 6 /* 2^6 = 32 */
55 /* Horrible hack to get dbg_print to do the right thing */
58 /*****************************************************************************
60 *****************************************************************************/
61 static void BlendI420( vout_thread_t *, picture_t *, const subpicture_t *,
63 static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,
64 const subpicture_t *p_spu, vlc_bool_t b_crop );
65 static void BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,
66 const subpicture_t *p_spu, vlc_bool_t b_crop,
68 static void BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,
69 const subpicture_t *p_spu, vlc_bool_t b_crop );
70 static void BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,
71 const subpicture_t *p_spu, vlc_bool_t b_crop );
72 static void BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,
73 const subpicture_t *p_spu, vlc_bool_t b_crop );
75 /*****************************************************************************
76 * BlendSPU: blend a subtitle into a picture
77 *****************************************************************************
79 This blends subtitles (a subpicture) into the underlying
80 picture. Subtitle data has been preprocessed as YUV + transparancy
81 or 4 bytes per pixel with interleaving of rows in the subtitle
84 *****************************************************************************/
85 void VCDSubBlend( vout_thread_t *p_vout, picture_t *p_pic,
86 const subpicture_t *p_spu )
88 struct subpicture_sys_t *p_sys = p_spu->p_sys;
90 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
91 "chroma %x", p_vout->output.i_chroma );
93 switch( p_vout->output.i_chroma )
95 /* I420 target, no scaling */
96 case VLC_FOURCC('I','4','2','0'):
97 case VLC_FOURCC('I','Y','U','V'):
98 case VLC_FOURCC('Y','V','1','2'):
99 BlendI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
102 /* RGB 555 - scaled */
103 case VLC_FOURCC('R','V','1','5'):
104 BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,
108 case VLC_FOURCC('R','V','1','6'):
109 BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,
110 /* Not sure under what conditions RV16 is really
120 /* RV24 target, scaling */
121 case VLC_FOURCC('R','V','2','4'):
122 BlendRV24( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
125 /* RV32 target, scaling */
126 case VLC_FOURCC('R','V','3','2'):
127 BlendRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
130 /* NVidia overlay, no scaling */
131 case VLC_FOURCC('Y','U','Y','2'):
132 BlendYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
135 /* Palettized 8 bits per pixel (256 colors). Each
136 pixel is an uint8_t index in the palette
139 case VLC_FOURCC('R','G','B','2'):
140 BlendRGB2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
145 msg_Err( p_vout, "unknown chroma, can't render SPU" );
150 /* Following functions are local */
155 All Y samples are found first in memory as an array of bytes
156 (possibly with a larger stride for memory alignment), followed
157 immediately by all Cr (=U) samples (with half the stride of the Y
158 lines, and half the number of lines), then followed immediately by
159 all Cb (=V) samples in a similar fashion.
162 static void BlendI420( vout_thread_t *p_vout, picture_t *p_pic,
163 const subpicture_t *p_spu, vlc_bool_t b_crop )
165 /* Common variables */
166 uint8_t *p_pixel_base_Y, *p_pixel_base_V, *p_pixel_base_U;
167 ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
170 vlc_bool_t even_scanline = VLC_FALSE;
173 int i_x_start, i_y_start, i_x_end, i_y_end;
176 const struct subpicture_sys_t *p_sys = p_spu->p_sys;
178 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
179 "spu width x height: (%dx%d), (x,y)=(%d,%d), yuv pitch (%d,%d,%d)",
180 p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
181 p_pic->Y_PITCH, p_pic->U_PITCH, p_pic->V_PITCH );
184 p_pixel_base_Y = p_pic->p[Y_PLANE].p_pixels + p_spu->i_x
185 + p_pic->p[Y_PLANE].i_pitch * p_spu->i_y;
187 p_pixel_base_U = p_pic->p[U_PLANE].p_pixels + p_spu->i_x/2
188 + p_pic->p[U_PLANE].i_pitch * p_spu->i_y/2;
190 p_pixel_base_V = p_pic->p[V_PLANE].p_pixels + p_spu->i_x/2
191 + p_pic->p[V_PLANE].i_pitch * p_spu->i_y/2;
193 i_x_start = p_sys->i_x_start;
194 i_y_start = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_start;
196 i_x_end = p_sys->i_x_end;
197 i_y_end = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_end;
199 p_source = (ogt_yuvt_t *)p_sys->p_data;
201 /* Draw until we reach the bottom of the subtitle */
203 i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
204 i_y += p_pic->p[Y_PLANE].i_pitch )
206 uint8_t *p_pixel_base_Y_y = p_pixel_base_Y + i_y;
207 uint8_t *p_pixel_base_U_y = p_pixel_base_U + i_y/4;
208 uint8_t *p_pixel_base_V_y = p_pixel_base_V + i_y/4;
213 if ( i_y > i_y_end ) break;
216 p_source += i_x_start;
220 even_scanline = !even_scanline;
222 /* Draw until we reach the end of the line */
223 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
228 /* FIXME: y cropping should be dealt with outside of this loop.*/
229 if ( i_y < i_y_start) continue;
233 p_source += p_spu->i_width - i_x;
238 #ifdef TESTING_TRANSPARENCY
239 if (p_source->s.t == MAX_ALPHA) p_source->s.t >>= 1;
242 switch( p_source->s.t )
245 /* Completely transparent. Don't change pixel. */
250 /* Completely opaque. Completely overwrite underlying
251 pixel with subtitle pixel. */
253 /* This is the location that's going to get changed.*/
254 uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;
256 *p_pixel_Y = p_source->plane[Y_PLANE];
258 if ( even_scanline && i_x % 2 == 0 ) {
259 uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2;
260 uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2;
261 *p_pixel_U = p_source->plane[U_PLANE];
262 *p_pixel_V = p_source->plane[V_PLANE];
270 /* Blend in underlying subtitle pixel. */
272 /* This is the location that's going to get changed. */
273 uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;
276 /* This is the weighted part of the subtitle. The
277 color plane is 8 bits and transparancy is 4 bits so
278 when multiplied we get up to 12 bits.
280 uint16_t i_sub_color_Y =
281 (uint16_t) ( p_source->plane[Y_PLANE] *
282 (uint16_t) (p_source->s.t) );
284 /* This is the weighted part of the underlying pixel.
285 For the same reasons above, the result is up to 12
286 bits. However since the transparancies are
287 inverses, the sum of i_sub_color and i_pixel_color
288 will not exceed 12 bits.
290 uint16_t i_pixel_color_Y =
291 (uint16_t) ( *p_pixel_Y *
292 (uint16_t) (MAX_ALPHA - p_source->s.t) ) ;
294 /* Scale the 12-bit result back down to 8 bits. A
295 precise scaling after adding the two components,
296 would divide by one less than a power of 2. However
297 to simplify and speed things we use a power of
298 2. This means the boundaries (either all
299 transparent and all opaque) aren't handled properly.
300 But we deal with them in special cases above. */
302 *p_pixel_Y = ( i_sub_color_Y + i_pixel_color_Y ) >> ALPHA_BITS;
304 if ( even_scanline && i_x % 2 == 0 ) {
305 uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2
306 - p_pic->p[U_PLANE].i_pitch / 2;
307 uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2
308 - p_pic->p[V_PLANE].i_pitch / 2;
309 uint16_t i_sub_color_U =
310 (uint16_t) ( p_source->plane[U_PLANE] *
311 (uint16_t) (p_source->s.t) );
313 uint16_t i_sub_color_V =
314 (uint16_t) ( p_source->plane[V_PLANE] *
315 (uint16_t) (p_source->s.t) );
316 uint16_t i_pixel_color_U =
317 (uint16_t) ( *p_pixel_U *
318 (uint16_t) (MAX_ALPHA - p_source->s.t) ) ;
319 uint16_t i_pixel_color_V =
320 (uint16_t) ( *p_pixel_V *
321 (uint16_t) (MAX_ALPHA - p_source->s.t) ) ;
322 *p_pixel_U = ( i_sub_color_U + i_pixel_color_U )>>ALPHA_BITS;
323 *p_pixel_V = ( i_sub_color_V + i_pixel_color_V )>>ALPHA_BITS;
337 Data is found in memory as an array of bytes in which the first byte
338 contains the first sample of Y, the second byte contains the first
339 sample of Cb (=U), the third byte contains the second sample of Y,
340 the fourth byte contains the first sample of Cr (=V); and so
341 on. Each 32-bit word then contains information for two contiguous
342 horizontal pixels, two 8-bit Y values plus a single Cb and Cr which
343 spans the two pixels.
346 #define BYTES_PER_PIXEL 4
348 static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,
349 const subpicture_t *p_spu, vlc_bool_t b_crop )
351 /* Common variables */
352 uint8_t *p_pixel_base;
354 /* This is the where the subtitle pixels come from */
355 ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;;
357 ogt_yuvt_t *p_source_end = (ogt_yuvt_t *)p_spu->p_sys->p_data +
358 (p_spu->i_width * p_spu->i_height);
362 /* Make sure we start on a word (4-byte) boundary. */
363 uint16_t i_spu_x = (p_spu->i_x & 0xFFFE) * 2;
366 int i_x_start, i_y_start, i_x_end, i_y_end;
368 const struct subpicture_sys_t *p_sys = p_spu->p_sys;
370 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
371 "spu width x height: (%dx%d), (x,y)=(%d,%d), pitch: %d",
372 p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
376 p_pixel_base = p_pic->p->p_pixels +
377 + ( p_spu->i_y * p_pic->p->i_pitch ) + i_spu_x;
379 i_x_start = p_sys->i_x_start;
380 i_y_start = p_sys->i_y_start * p_pic->p->i_pitch;
382 i_x_end = p_sys->i_x_end;
383 i_y_end = p_sys->i_y_end * p_pic->p->i_pitch;
385 /* Draw until we reach the bottom of the subtitle */
387 i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
388 i_y += p_pic->p[Y_PLANE].i_pitch )
390 uint8_t *p_pixel_base_y = p_pixel_base + i_y;
395 if ( i_y > i_y_end ) break;
398 p_source += (i_x_start*2);
403 /* Draw until we reach the end of the line. Each output pixel
404 is a combination of two source pixels.
406 for( i_x = 0; i_x < p_spu->i_width / 2; i_x++, p_source +=2 )
408 uint16_t i_avg_tr; /* transparancy sort of averaged over 2 pixels*/
410 if (p_source > p_source_end-1) {
411 msg_Err( p_vout, "Trying to access beyond subtitle x: %d y: %d",
418 /* FIXME: y cropping should be dealt with outside of this loop.*/
419 if ( i_y < i_y_start) continue;
423 p_source += p_spu->i_width - (i_x*2);
429 /* Favor opaque subtitle pixels. */
430 if ( (p_source->s.t == 0) && (p_source+1)->s.t == MAX_ALPHA )
431 i_avg_tr = (p_source+1)->s.t;
432 else if ( (p_source->s.t == MAX_ALPHA) && (p_source+1)->s.t == 0 )
433 i_avg_tr = p_source->s.t;
435 i_avg_tr = ( p_source->s.t + (p_source+1)->s.t ) / 2;
437 #ifdef TESTING_TRANSPARENCY
438 if (i_avg_tr == MAX_ALPHA) i_avg_tr >>= 1;
444 /* Completely transparent. Don't change pixel. */
449 /* Completely opaque. Completely overwrite underlying
450 pixel with subtitle pixel. */
452 /* This is the location that's going to get changed. */
453 uint8_t *p_pixel = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
457 /* Favor opaque subtitle pixel. */
458 if (p_source->s.t == MAX_ALPHA ) {
459 i_avg_u = p_source->plane[U_PLANE] ;
460 i_avg_v = p_source->plane[V_PLANE] ;
461 } else if ( (p_source+1)->s.t == MAX_ALPHA ) {
462 i_avg_u = (p_source+1)->plane[U_PLANE] ;
463 i_avg_v = (p_source+1)->plane[V_PLANE] ;
465 i_avg_u = ( p_source->plane[U_PLANE]
466 + (p_source+1)->plane[U_PLANE] ) / 2;
467 i_avg_v = ( p_source->plane[V_PLANE]
468 + (p_source+1)->plane[V_PLANE] ) / 2;
471 /* draw a two contiguous pixels: 2 Y values, 1 U, and 1 V. */
472 *p_pixel++ = p_source->plane[Y_PLANE] ;
473 *p_pixel++ = i_avg_u;
474 *p_pixel++ = (p_source+1)->plane[Y_PLANE] ;
475 *p_pixel++ = i_avg_v;
482 /* Blend in underlying subtitle pixels. */
484 /* This is the location that's going to get changed. */
485 uint8_t *p_pixel = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
486 uint8_t i_avg_u = ( p_source->plane[U_PLANE]
487 + (p_source+1)->plane[U_PLANE] ) / 2;
488 uint8_t i_avg_v = ( p_source->plane[V_PLANE]
489 + (p_source+1)->plane[V_PLANE] ) / 2;
491 /* This is the weighted part of the two subtitle
492 pixels. The color plane is 8 bits and transparancy
493 is 4 bits so when multiplied we get up to 12 bits.
495 uint16_t i_sub_color_Y1 =
496 (uint16_t) ( p_source->plane[Y_PLANE] *
497 (uint16_t) (p_source->s.t) );
499 uint16_t i_sub_color_Y2 =
500 (uint16_t) ( (p_source+1)->plane[Y_PLANE] *
501 (uint16_t) ((p_source+1)->s.t) );
503 /* This is the weighted part of the underlying pixels.
504 For the same reasons above, the result is up to 12
505 bits. However since the transparancies are
506 inverses, the sum of i_sub_color and i_pixel_color
507 will not exceed 12 bits.
509 uint16_t i_sub_color_U =
510 (uint16_t) ( i_avg_u * (uint16_t) i_avg_tr );
512 uint16_t i_sub_color_V =
513 (uint16_t) ( i_avg_v * (uint16_t) i_avg_tr );
515 uint16_t i_pixel_color_Y1 =
516 (uint16_t) ( *(p_pixel) *
517 (uint16_t) (MAX_ALPHA - i_avg_tr) ) ;
518 uint16_t i_pixel_color_Y2 =
519 (uint16_t) ( *(p_pixel+2) *
520 (uint16_t) (MAX_ALPHA - i_avg_tr) ) ;
521 uint16_t i_pixel_color_U =
522 (uint16_t) ( *(p_pixel+1) *
523 (uint16_t) (MAX_ALPHA - i_avg_tr) ) ;
524 uint16_t i_pixel_color_V =
525 (uint16_t) ( *(p_pixel+3) *
526 (uint16_t) (MAX_ALPHA - i_avg_tr) ) ;
528 /* draw a two contiguous pixels: 2 Y values, 1 U, and 1 V. */
530 /* Scale the 12-bit result back down to 8 bits. A
531 precise scaling after adding the two components,
532 would divide by one less than a power of 2. However
533 to simplify and speed things we use a power of
534 2. This means the boundaries (either all
535 transparent and all opaque) aren't handled properly.
536 But we deal with them in special cases above. */
538 *p_pixel++ = ( i_sub_color_Y1 + i_pixel_color_Y1 )>>ALPHA_BITS;
539 *p_pixel++ = ( i_sub_color_U + i_pixel_color_U ) >>ALPHA_BITS;
540 *p_pixel++ = ( i_sub_color_Y2 + i_pixel_color_Y2 )>>ALPHA_BITS;
541 *p_pixel++ = ( i_sub_color_V + i_pixel_color_V ) >>ALPHA_BITS;
547 /* For an odd width source, we'll just have to drop off a pixel. */
548 if (p_spu->i_width % 2) p_source++;
553 Convert a YUV pixel into a 16-bit RGB 5-5-5 pixel.
555 A RGB 5-5-5 pixel looks like this:
556 RGB 5-5-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
557 p ? B4 B3 B2 B1 B0 R4 R3
558 q R2 R1 R0 G4 G3 G2 G1 G0
563 yuv2rgb555(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
566 uint8_t rgb[RGB_SIZE];
570 /* Scale RGB from 8 bits down to 5. */
571 rgb[RED_PIXEL] >>= (8-5);
572 rgb[GREEN_PIXEL] >>= (8-5);
573 rgb[BLUE_PIXEL] >>= (8-5);
575 *p_rgb1 = ( (rgb[BLUE_PIXEL] << 2)&0x7c ) | ( (rgb[RED_PIXEL]>>3) & 0x03 );
576 *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
579 printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
580 "rgb1: %02x, rgb2 %02x\n",
581 p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
582 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
589 Convert a YUV pixel into a 16-bit RGB 5-6-5 pixel.
591 A RGB 5-6-5 pixel looks like this:
592 RGB 5-6-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
593 p B4 B3 B2 B1 B0 R5 R4 R3
594 q R2 R1 R0 G4 G3 G2 G1 G0
599 yuv2rgb565(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
602 uint8_t rgb[RGB_SIZE];
606 /* Scale RGB from 8 bits down to 5 or 6 bits. */
607 rgb[RED_PIXEL] >>= (8-6);
608 rgb[GREEN_PIXEL] >>= (8-5);
609 rgb[BLUE_PIXEL] >>= (8-5);
611 *p_rgb1 = ( (rgb[BLUE_PIXEL] << 3)&0xF8 ) | ( (rgb[RED_PIXEL]>>3) & 0x07 );
612 *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
615 printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
616 "rgb1: %02x, rgb2 %02x\n",
617 p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
618 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
625 rv16_pack_blend(uint8_t *p_pixel, ogt_yuvt_t *p_source, uint8_t *p_rgb1,
626 uint8_t *p_rgb2, vlc_bool_t b_15bpp, uint8_t i_alpha,
629 uint8_t rgb_source[3];
630 uint8_t rgb[RGB_SIZE];
632 #ifdef FIXED_RV16_TRANSPARENCY
633 uint8_t i_dest_alpha = MAX_ALPHA - i_alpha;
636 yuv2rgb(p_source, rgb_source);
638 /* Scale RGB from 8 bits down to 6 or 5. */
639 rgb_source[GREEN_PIXEL] >>= (8-5);
640 rgb_source[BLUE_PIXEL] >>= (8-5);
642 rgb[GREEN_PIXEL] = *(p_pixel+1) & 0x1f;
644 rgb_source[RED_PIXEL] >>= (8-5);
645 rgb[BLUE_PIXEL] = ((*p_pixel)>>2) & 0x1f;
646 rgb[RED_PIXEL] = ((*p_pixel & 0x03) << 3) | ((*(p_pixel+1)&0xe0)>>5);
648 rgb_source[RED_PIXEL] >>= (8-6);
649 rgb[BLUE_PIXEL] = ((*p_pixel)>>3) & 0x1f;
650 rgb[RED_PIXEL] = ((*p_pixel & 0x07) << 3) | ((*(p_pixel+1)&0xe0)>>5);
655 printf("r,g,b=(%d,%d,%d), source r,g,b=(%d,%d,%d), alpha %d, dest_alpha %d\n",
656 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
657 rgb_source[RED_PIXEL], rgb_source[GREEN_PIXEL],
658 rgb_source[BLUE_PIXEL], i_alpha, i_dest_alpha);
661 for (i=0; i < RGB_SIZE; i++) {
662 /* Average the two pixels. */
664 #ifdef FIXED_RV16_TRANSPARENCY
665 rgb[i] = ( (uint16_t) rgb_source[i]*i_alpha + rgb[i]*i_dest_alpha) >>
668 /* For now the Best we can do is fade the color. Picking up
669 video underneath doesn't work. */
670 /* rgb[i] = ( (uint16_t) rgb[i]*i_dest_alpha ) >> ALPHA_BITS; */
671 rgb[i] = ( (uint16_t) rgb_source[i]*i_alpha ) >> ALPHA_BITS;
677 printf("avg r,g,b=(%d,%d,%d)\n",
678 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL] );
683 *p_rgb1 = ( (rgb[BLUE_PIXEL] << 2)&0x7c )|( (rgb[RED_PIXEL]>>3)&0x03 );
685 *p_rgb1 = ( (rgb[BLUE_PIXEL] << 3)&0xF8 )|( (rgb[RED_PIXEL]>>3)&0x07 );
687 *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
689 *p_rgb1 = (*p_rgb1)+1;
690 *p_rgb2 = (*p_rgb2)+1;
695 #undef BYTES_PER_PIXEL
696 #define BYTES_PER_PIXEL 2
699 BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,
700 const subpicture_t *p_spu, vlc_bool_t b_crop,
703 /* Common variables */
704 uint8_t *p_pixel_base;
705 ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
706 ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
707 ogt_yuvt_t *p_source;
712 /* Chroma specific */
713 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
714 multiplied by 2**ASCALE. */
715 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
716 multiplied by 2**ASCALE. */
718 int i_width, i_height, i_ytmp, i_ynext;
721 int i_x_start, i_y_start, i_x_end, i_y_end;
723 struct subpicture_sys_t *p_sys = p_spu->p_sys;
725 i_xscale = ( p_vout->output.i_width << ASCALE ) / p_vout->render.i_width;
726 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
728 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
729 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
730 p_spu->i_width, p_spu->i_height,
731 p_vout->output.i_width, p_vout->output.i_height,
732 p_vout->render.i_width, p_vout->render.i_height,
736 i_width = p_spu->i_width * i_xscale;
737 i_height = p_spu->i_height * i_yscale;
739 /* Set where we will start blending subtitle from using
740 the picture coordinates subtitle offsets
742 p_pixel_base = p_pic->p->p_pixels
743 + ( (p_spu->i_x * i_xscale) >> ASCALE ) * BYTES_PER_PIXEL
744 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
746 i_x_start = p_sys->i_x_start;
747 i_y_start = i_yscale * p_sys->i_y_start;
748 i_x_end = p_sys->i_x_end;
749 i_y_end = i_yscale * p_sys->i_y_end;
751 p_source = (ogt_yuvt_t *)p_sys->p_data;
753 /* Draw until we reach the bottom of the subtitle */
755 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
756 i_y_src += p_spu->i_width )
758 uint8_t *p_pixel_base_y;
759 i_ytmp = i_y >> ASCALE;
761 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
765 if ( i_y > i_y_end ) break;
768 p_source += i_x_start;
772 /* Check whether we need to draw one line or more than one */
773 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
775 /* Draw until we reach the end of the line */
776 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
780 uint8_t *p=(uint8_t *) p_source;
781 printf("+++ %02x %02x %02x %02x\n",
782 p[0], p[1], p[2], p[3]);
787 /* FIXME: y cropping should be dealt with outside of this
789 if ( i_y < i_y_start) continue;
793 p_source += p_spu->i_width - i_x;
798 if (p_source >= p_src_end) {
799 msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
800 i_x, i_y / i_yscale, i_height);
804 #ifdef TESTING_TRANSPARENCY
805 if (p_source->s.t == MAX_ALPHA) p_source->s.t >>= 1;
808 switch( p_source->s.t )
811 /* Completely transparent. Don't change pixel. */
816 /* Completely opaque. Completely overwrite underlying
817 pixel with subtitle pixel. */
819 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
821 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
823 uint32_t len = i_xlast - i_xdest;
828 /* This is the location that's going to get changed. */
829 uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
832 yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
834 yuv2rgb565(p_source, &i_rgb1, &i_rgb2);
836 for ( len = i_xlast - i_xdest; len ; len--) {
845 /* Blend in underlying pixel subtitle pixel. */
847 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
849 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
853 uint32_t len = i_xlast - i_xdest;
855 /* This is the location that's going to get changed. */
856 uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
858 for ( len = i_xlast - i_xdest; len ; len--) {
859 rv16_pack_blend(p_dest, p_source, &i_rgb1, &i_rgb2,
860 b_15bpp, p_source->s.t, ALPHA_SCALEDOWN);
871 i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
874 /* Draw until we reach the end of the line */
875 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
880 /* FIXME: y cropping should be dealt with outside of this
882 if ( i_y < i_y_start) continue;
886 p_source += p_spu->i_width - i_x;
891 if (p_source >= p_src_end) {
892 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
893 i_x, i_y / i_yscale, i_height);
897 switch( p_source->s.t )
900 /* Completely transparent. Don't change pixel. */
905 /* Completely opaque. Completely overwrite underlying
906 pixel with subtitle pixel. */
908 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
910 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
912 uint32_t len = i_xlast - i_xdest;
914 uint8_t *p_pixel_base_x = p_pixel_base + i_xdest;
916 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
918 /* This is the location that's going to get changed. */
919 uint8_t *p_dest = p_pixel_base_x + i_ytmp;
920 uint8_t i_rgb1, i_rgb2;
922 yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
924 yuv2rgb565(p_source, &i_rgb1, &i_rgb2);
926 for ( len = i_xlast - i_xdest; len ; len--) {
935 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
937 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
939 uint32_t len = i_xlast - i_xdest;
940 uint8_t i_rgb1, i_rgb2;
941 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
943 /* Blend in underlying pixel subtitle pixel. */
944 uint8_t *p_dest = p_pixel_base + i_ytmp;
945 for ( len = i_xlast - i_xdest; len ; len--) {
946 rv16_pack_blend(p_dest, p_source, &i_rgb1, &i_rgb2,
947 b_15bpp, p_source->s.t, ALPHA_SCALEDOWN);
960 #undef BYTES_PER_PIXEL
961 #define BYTES_PER_PIXEL 4
964 rv24_pack_blend(uint8_t *p_pixel, uint8_t *rgb_source, uint8_t i_alpha,
968 uint8_t i_dest_alpha = MAX_ALPHA - i_alpha;
971 printf("r,g,b=(%d,%d,%d), source r,g,b=(%d,%d,%d), alpha %d, dest_alpha %d\n",
972 p_pixel[RED_PIXEL], p_pixel[GREEN_PIXEL], p_pixel[BLUE_PIXEL],
973 rgb_source[RED_PIXEL], rgb_source[GREEN_PIXEL],
974 rgb_source[BLUE_PIXEL], i_alpha, i_dest_alpha);
977 #ifdef WORDS_BIGENDIAN
981 for (i=0; i < RGB_SIZE; i++) {
982 /* Average the two pixels. */
984 p_pixel[i] = ( (uint16_t) rgb_source[i]*i_alpha + p_pixel[i]*i_dest_alpha)
989 printf("avg r,g,b=(%d,%d,%d)\n",
990 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL] );
996 RV24 format??? Is this just for X11? Or just not for Win32? Is this
999 a pixel is represented by 3 bytes containing a red,
1000 blue and green sample with blue stored at the lowest address, green
1001 next then red. One padding byte is added between pixels. Although
1002 this may not be part of a spec, images should be stored with each
1003 line padded to a u_int32 boundary.
1006 BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,
1007 const subpicture_t *p_spu, vlc_bool_t b_crop )
1009 /* Common variables */
1010 uint8_t *p_pixel_base;
1011 ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
1012 ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
1013 ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
1018 /* Make sure we start on a word (4-byte) boundary. */
1021 /* Chroma specific */
1022 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
1023 multiplied by 2**ASCALE. */
1024 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
1025 multiplied by 2**ASCALE. */
1027 int i_width, i_height, i_ytmp, i_ynext;
1030 int32_t i_x_start, i_y_start, i_x_end, i_y_end;
1032 struct subpicture_sys_t *p_sys = p_spu->p_sys;
1033 unsigned int i_aspect_x, i_aspect_y;
1035 vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
1038 i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
1039 / (i_aspect_y * p_vout->render.i_width);
1040 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
1042 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
1043 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
1044 p_spu->i_width, p_spu->i_height,
1045 p_vout->output.i_width, p_vout->output.i_height,
1046 p_vout->render.i_width, p_vout->render.i_height,
1050 i_width = p_spu->i_width * i_xscale;
1051 i_height = p_spu->i_height * i_yscale;
1053 /* Set where we will start blending subtitle from using
1054 the picture coordinates subtitle offsets.
1056 i_spu_x = ((p_spu->i_x * i_xscale) >> ASCALE) * BYTES_PER_PIXEL;
1058 p_pixel_base = p_pic->p->p_pixels + i_spu_x
1059 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
1061 i_x_start = p_sys->i_x_start;
1062 i_y_start = i_yscale * p_sys->i_y_start;
1063 i_x_end = p_sys->i_x_end;
1064 i_y_end = i_yscale * p_sys->i_y_end;
1066 p_source = (ogt_yuvt_t *)p_sys->p_data;
1068 /* Draw until we reach the bottom of the subtitle */
1070 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
1071 i_y_src += p_spu->i_width )
1073 uint8_t *p_pixel_base_y;
1074 i_ytmp = i_y >> ASCALE;
1076 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
1080 if ( i_y > i_y_end ) break;
1083 p_source += i_x_start;
1087 /* Check whether we need to draw one line or more than one */
1088 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
1090 /* Draw until we reach the end of the line */
1091 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1096 /* FIXME: y cropping should be dealt with outside of this
1098 if ( i_y < i_y_start) continue;
1100 if ( i_x > i_x_end )
1102 p_source += p_spu->i_width - i_x;
1107 if (p_source >= p_src_end) {
1108 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1109 i_x, i_y / i_yscale, i_height);
1113 #ifdef TESTING_TRANSPARENCY
1114 if (p_source->s.t == MAX_ALPHA) p_source->s.t >>= 2;
1117 switch( p_source->s.t )
1120 /* Completely transparent. Don't change pixel. */
1125 /* Completely opaque. Completely overwrite underlying
1126 pixel with subtitle pixel. */
1128 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1129 * BYTES_PER_PIXEL );
1130 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1131 * BYTES_PER_PIXEL );
1132 uint32_t len = i_xlast - i_xdest;
1134 uint8_t rgb[RGB_SIZE];
1136 /* This is the location that's going to get changed. */
1137 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1139 yuv2rgb(p_source, rgb);
1141 for ( len = i_xlast - i_xdest; len ; len--) {
1142 put_rgb24_pixel(rgb, p_dest);
1143 p_dest += BYTES_PER_PIXEL;
1148 /* Blend in underlying pixel subtitle pixel. */
1150 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1151 * BYTES_PER_PIXEL );
1152 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1153 * BYTES_PER_PIXEL );
1154 uint32_t len = i_xlast - i_xdest * BYTES_PER_PIXEL;
1156 /* To be able to scale correctly for full opaqueness, we
1157 add 1 to the alpha. This means alpha value 0 won't
1158 be completely transparent and is not correct, but
1159 that's handled in a special case above anyway. */
1161 /* This is the location that's going to get changed. */
1162 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1163 uint8_t rgb[RGB_SIZE];
1165 yuv2rgb(p_source, rgb);
1167 for ( len = i_xlast - i_xdest; len ; len--) {
1168 rv24_pack_blend(p_dest, rgb, p_source->s.t,
1170 p_dest += BYTES_PER_PIXEL;
1180 i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
1183 /* Draw until we reach the end of the line */
1184 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1189 /* FIXME: y cropping should be dealt with outside of this
1191 if ( i_y < i_y_start) continue;
1193 if ( i_x > i_x_end )
1195 p_source += p_spu->i_width - i_x;
1200 if (p_source >= p_src_end) {
1201 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1202 i_x, i_y / i_yscale, i_height);
1206 switch( p_source->s.t )
1209 /* Completely transparent. Don't change pixel. */
1214 /* Completely opaque. Completely overwrite underlying
1215 pixel with subtitle pixel. */
1217 /* This is the location that's going to get changed. */
1218 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1219 * BYTES_PER_PIXEL );
1220 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1221 * BYTES_PER_PIXEL );
1222 uint32_t len = i_xlast - i_xdest;
1224 uint8_t rgb[RGB_SIZE];
1226 yuv2rgb(p_source, rgb);
1228 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
1230 /* Completely opaque. Completely overwrite underlying
1231 pixel with subtitle pixel. */
1233 /* This is the location that's going to get changed. */
1234 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1236 for ( len = i_xlast - i_xdest; len ; len--) {
1237 put_rgb24_pixel(rgb, p_dest);
1238 p_dest += BYTES_PER_PIXEL;
1247 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1248 * BYTES_PER_PIXEL );
1249 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1250 * BYTES_PER_PIXEL );
1251 uint32_t len = i_xlast - i_xdest;
1252 uint8_t rgb[RGB_SIZE];
1254 yuv2rgb(p_source, rgb);
1256 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
1258 /* Blend in underlying pixel subtitle pixel. */
1260 /* This is the location that's going to get changed. */
1261 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1263 /* To be able to scale correctly for full opaqueness, we
1264 add 1 to the alpha. This means alpha value 0 won't
1265 be completely transparent and is not correct, but
1266 that's handled in a special case above anyway. */
1268 for ( len = i_xlast - i_xdest; len ; len--) {
1269 rv24_pack_blend(p_dest, rgb, p_source->s.t,
1271 p_dest += BYTES_PER_PIXEL;
1282 #undef BYTES_PER_PIXEL
1283 #define BYTES_PER_PIXEL 4
1286 RV32 format??? Is this just for X11? Or just not for Win32? Is this
1289 RV32 format: a pixel is represented by 4 bytes containing a red,
1290 blue and green sample with blue stored at the lowest address, green
1291 next then red. One padding byte is added between pixels. Although
1292 this may not be part of a spec, images should be stored with each
1293 line padded to a u_int32 boundary.
1296 BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,
1297 const subpicture_t *p_spu, vlc_bool_t b_crop )
1299 /* Common variables */
1300 uint8_t *p_pixel_base;
1301 ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
1302 ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
1303 ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
1308 /* Make sure we start on a word (4-byte) boundary. */
1311 /* Chroma specific */
1312 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
1313 multiplied by 2**ASCALE. */
1314 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
1315 multiplied by 2**ASCALE. */
1317 int i_width, i_height, i_ytmp, i_ynext;
1320 int32_t i_x_start, i_y_start, i_x_end, i_y_end;
1322 struct subpicture_sys_t *p_sys = p_spu->p_sys;
1323 unsigned int i_aspect_x, i_aspect_y;
1325 vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
1328 i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
1329 / (i_aspect_y * p_vout->render.i_width);
1330 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
1332 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
1333 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
1334 p_spu->i_width, p_spu->i_height,
1335 p_vout->output.i_width, p_vout->output.i_height,
1336 p_vout->render.i_width, p_vout->render.i_height,
1340 i_width = p_spu->i_width * i_xscale;
1341 i_height = p_spu->i_height * i_yscale;
1343 /* Set where we will start blending subtitle from using
1344 the picture coordinates subtitle offsets.
1346 i_spu_x = ((p_spu->i_x * i_xscale) >> ASCALE) * BYTES_PER_PIXEL;
1348 p_pixel_base = p_pic->p->p_pixels + i_spu_x
1349 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
1351 i_x_start = p_sys->i_x_start;
1352 i_y_start = i_yscale * p_sys->i_y_start;
1353 i_x_end = p_sys->i_x_end;
1354 i_y_end = i_yscale * p_sys->i_y_end;
1356 p_source = (ogt_yuvt_t *)p_sys->p_data;
1358 /* Draw until we reach the bottom of the subtitle */
1360 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
1361 i_y_src += p_spu->i_width )
1363 uint8_t *p_pixel_base_y;
1364 i_ytmp = i_y >> ASCALE;
1366 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
1370 if ( i_y > i_y_end ) break;
1373 p_source += i_x_start;
1377 /* Check whether we need to draw one line or more than one */
1378 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
1380 /* Draw until we reach the end of the line */
1381 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1386 /* FIXME: y cropping should be dealt with outside of this
1388 if ( i_y < i_y_start) continue;
1390 if ( i_x > i_x_end )
1392 p_source += p_spu->i_width - i_x;
1397 if (p_source >= p_src_end) {
1398 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1399 i_x, i_y / i_yscale, i_height);
1403 switch( p_source->s.t )
1406 /* Completely transparent. Don't change pixel. */
1412 /* Completely opaque. Completely overwrite underlying
1413 pixel with subtitle pixel. */
1415 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1416 * BYTES_PER_PIXEL );
1417 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1418 * BYTES_PER_PIXEL );
1419 uint32_t len = i_xlast - i_xdest;
1421 uint8_t rgb[RGB_SIZE];
1423 /* This is the location that's going to get changed. */
1424 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1426 yuv2rgb(p_source, rgb);
1428 for ( len = i_xlast - i_xdest; len ; len--) {
1429 *p_dest++ = rgb[BLUE_PIXEL];
1430 *p_dest++ = rgb[GREEN_PIXEL];
1431 *p_dest++ = rgb[RED_PIXEL];
1435 #ifdef TRANSPARENCY_FINISHED
1438 /* Blend in underlying pixel subtitle pixel. */
1440 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1441 * BYTES_PER_PIXEL );
1442 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1443 * BYTES_PER_PIXEL );
1444 uint32_t len = i_xlast - i_xdest;
1446 /* To be able to scale correctly for full opaqueness, we
1447 add 1 to the alpha. This means alpha value 0 won't
1448 be completely transparent and is not correct, but
1449 that's handled in a special case above anyway. */
1451 uint8_t i_destalpha = MAX_ALPHA - p_source->s.t;
1452 uint8_t rgb[RGB_SIZE];
1454 /* This is the location that's going to get changed. */
1455 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1457 yuv2rgb(p_source, rgb);
1458 rv32_pack_blend(p_dest, rgb, dest_alpha,
1461 for ( len = i_xlast - i_xdest; len ; len--) {
1462 *p_dest++ = rgb[BLUE_PIXEL];
1463 *p_dest++ = rgb[GREEN_PIXEL];
1464 *p_dest++ = rgb[RED_PIXEL];
1469 #endif /*TRANSPARENCY_FINISHED*/
1476 i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
1479 /* Draw until we reach the end of the line */
1480 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1485 /* FIXME: y cropping should be dealt with outside of this
1487 if ( i_y < i_y_start) continue;
1489 if ( i_x > i_x_end )
1491 p_source += p_spu->i_width - i_x;
1496 if (p_source >= p_src_end) {
1497 msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
1498 i_x, i_y / i_yscale, i_height);
1502 switch( p_source->s.t )
1505 /* Completely transparent. Don't change pixel. */
1511 /* Completely opaque. Completely overwrite underlying
1512 pixel with subtitle pixel. */
1514 /* This is the location that's going to get changed. */
1515 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1516 * BYTES_PER_PIXEL );
1517 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1518 * BYTES_PER_PIXEL );
1519 uint32_t len = i_xlast - i_xdest;
1521 uint8_t rgb[RGB_SIZE];
1523 yuv2rgb(p_source, rgb);
1525 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
1527 /* Completely opaque. Completely overwrite underlying
1528 pixel with subtitle pixel. */
1530 /* This is the location that's going to get changed. */
1531 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1533 for ( len = i_xlast - i_xdest; len ; len--) {
1534 put_rgb24_pixel(rgb, p_dest);
1539 #ifdef TRANSPARENCY_FINISHED
1544 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1545 * BYTES_PER_PIXEL );
1546 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1547 * BYTES_PER_PIXEL );
1548 uint32_t len = i_xlast - i_xdest;
1549 uint8_t rgb[RGB_SIZE];
1551 yuv2rgb(p_source, rgb);
1553 for( ; i_ytmp < i_ynext ; y_ytmp += p_pic->p->i_pitch )
1555 /* Blend in underlying pixel subtitle pixel. */
1557 /* This is the location that's going to get changed. */
1558 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1560 /* To be able to scale correctly for full opaqueness, we
1561 add 1 to the alpha. This means alpha value 0 won't
1562 be completely transparent and is not correct, but
1563 that's handled in a special case above anyway. */
1565 uint8_t i_destalpha = MAX_ALPHA - p_source->s.t;
1566 rv32_pack_blend(p_dest, rgb, dest_alpha,
1570 #endif /*TRANSPARENCY_FINISHED*/
1578 Return the colormap index for the average of p_pixel and a subtitle
1581 static inline cmap_t
1582 avg_rgb2(const vout_thread_t *p_vout, uint8_t i_pixel, cmap_t i_cmap_sub,
1583 const uint8_t rgb_sub[] )
1585 uint8_t rgb_vout[RGB_SIZE];
1586 static cmap_t avg_cache[CMAP_RGB2_SIZE][NUM_SUBTITLE_COLORS];
1587 static vlc_bool_t b_first_time = VLC_TRUE;
1590 /* FIXME: really we need to save subtitle number since in theory
1591 the palette can change each on each distinct subtitle. In practice
1592 this doesn't happen that much.
1597 for (i=0; i<CMAP_RGB2_SIZE; i++)
1598 for (j=0; j<NUM_SUBTITLE_COLORS; j++)
1599 avg_cache[i][j] = INVALID_CMAP_ENTRY;
1602 if ( avg_cache[i_pixel][i_cmap_sub] != INVALID_CMAP_ENTRY )
1603 return avg_cache[i_pixel][i_cmap_sub];
1605 if ( !query_color(p_vout, i_pixel, rgb_vout) ) return INVALID_CMAP_ENTRY;
1607 for (i = 0; i < RGB_SIZE; i++)
1609 rgb_vout[i] = (rgb_vout[i] + rgb_sub[i]) / 2;
1614 uint8_t rgb_approx[RGB_SIZE];
1616 avg_cache[i_pixel][i_cmap_sub] =
1617 find_cmap_rgb8_nearest(p_vout, rgb_vout, rgb_approx);
1619 "cmap old %0x new 0%x sub=(%0x, %0x, %0x) "
1620 "avg=(%0x, %0x, %0x) vout=(%0x, %0x, %0x)\n",
1622 rgb_sub[RED_PIXEL], rgb_sub[GREEN_PIXEL], rgb_sub[BLUE_PIXEL],
1623 rgb_approx[RED_PIXEL], rgb_approx[GREEN_PIXEL], rgb_approx[BLUE_PIXEL],
1624 rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL]);
1627 avg_cache[i_pixel][i_cmap_sub] =
1628 find_cmap_rgb8_nearest(p_vout, rgb_vout, NULL);
1630 return avg_cache[i_pixel][i_cmap_sub];
1633 #undef BYTES_PER_PIXEL
1634 #define BYTES_PER_PIXEL 1
1637 BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,
1638 const subpicture_t *p_spu, vlc_bool_t b_crop )
1640 /* Common variables */
1641 uint8_t *p_pixel_base;
1642 uint8_t *p_src_start = (uint8_t *)p_spu->p_sys->p_data;
1643 uint8_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
1644 uint8_t *p_source; /* This is the where the subtitle pixels come from */
1649 /* Chroma specific */
1650 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
1651 multiplied by 2**ASCALE. */
1652 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
1653 multiplied by 2**ASCALE. */
1655 int i_width, i_height, i_ytmp;
1658 int i_x_start, i_y_start, i_x_end, i_y_end;
1660 /* 4-entry array of colormap indices */
1661 uint8_t cmap[NUM_SUBTITLE_COLORS];
1664 /* Actual RGB values for above; this is used in blending.*/
1665 uint8_t cmap_rgb[NUM_SUBTITLE_COLORS][RGB_SIZE];
1667 struct subpicture_sys_t *p_sys = p_spu->p_sys;
1668 unsigned int i_aspect_x, i_aspect_y;
1670 vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
1673 i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
1674 / (i_aspect_y * p_vout->render.i_width);
1675 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
1677 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
1678 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
1679 p_spu->i_width, p_spu->i_height,
1680 p_vout->output.i_width, p_vout->output.i_height,
1681 p_vout->render.i_width, p_vout->render.i_height,
1685 i_width = p_spu->i_width * i_xscale;
1686 i_height = p_spu->i_height * i_yscale;
1689 /** FIXME: do once per subtitle in subtitle processing, not here
1690 each time we render. */
1691 /* Find a corresponding colormap entries for our palette entries. */
1692 for( i = 0; i < NUM_SUBTITLE_COLORS; i++ )
1695 if ( p_sys->p_palette[i].s.t != 0 ) {
1696 uint8_t rgb[RGB_SIZE];
1697 uint8_t approx_rgb[RGB_SIZE];
1698 yuv2rgb(&(p_sys->p_palette[i]), rgb);
1700 find_cmap_rgb8_nearest(p_vout, rgb, approx_rgb);
1701 dbg_print( (DECODE_DBG_RENDER),
1702 "palette %d RGB=(%0x, %0x, %0x)\n", i,
1703 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL]);
1707 /* Set where we will start blending subtitle from using
1708 the picture coordinates subtitle offsets
1710 p_pixel_base = p_pic->p->p_pixels
1711 + ( (p_spu->i_x * i_xscale) >> ASCALE ) * BYTES_PER_PIXEL
1712 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
1714 i_x_start = p_sys->i_x_start;
1715 i_y_start = i_yscale * p_sys->i_y_start;
1716 i_x_end = p_sys->i_x_end;
1717 i_y_end = i_yscale * p_sys->i_y_end;
1719 p_source = (uint8_t *)p_sys->p_data;
1721 /* Draw until we reach the bottom of the subtitle */
1723 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
1724 i_y_src += p_spu->i_width )
1726 uint8_t *p_pixel_base_y;
1727 i_ytmp = i_y >> ASCALE;
1729 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
1733 if ( i_y > i_y_end ) break;
1736 p_source += i_x_start;
1740 /* Check whether we need to draw one line or more than one */
1741 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
1744 /* Draw until we reach the end of the line */
1745 for( ; i_x < p_spu->i_width; i_x ++, p_source++ )
1751 /* FIXME: y cropping should be dealt with outside of this
1753 if ( i_y < i_y_start) continue;
1755 if ( i_x > i_x_end )
1757 p_source += p_spu->i_width - i_x;
1762 if (p_source >= p_src_end) {
1763 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1764 i_x, i_y / i_yscale, i_height);
1768 p_yuvt = p_sys->p_palette[*p_source & 0x3];
1770 #ifdef TESTING_TRANSPARENCY
1771 if (p_yuvt.s.t == MAX_ALPHA) p_yuvt.s.t >>= 1;
1774 switch ( p_yuvt.s.t )
1777 /* Completely transparent. Don't change pixel. */
1779 printf(" "); /*++++*/
1784 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1785 * BYTES_PER_PIXEL );
1786 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1787 * BYTES_PER_PIXEL );
1788 /* This is the pixel that's going to change;*/
1789 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1790 memset( p_dest, cmap[*p_source & 0x3], i_xlast - i_xdest );
1792 printf("%1d", *p_source); /*++++*/
1798 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1799 * BYTES_PER_PIXEL );
1800 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1801 * BYTES_PER_PIXEL );
1802 /* This is the pixel that's going to change;*/
1803 uint8_t *p_pixel = p_pixel_base_y + i_xdest;
1804 uint32_t len = i_xlast - i_xdest;
1806 for ( len = i_xlast - i_xdest -1; len >= 0; len-- )
1808 cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel,
1810 cmap_rgb[*p_source]);
1811 if (i_cmap != INVALID_CMAP_ENTRY)
1812 *p_pixel= (uint8_t) i_cmap;
1816 printf("%1d", *p_source); /*++++*/
1822 printf("\n"); /*++++*/
1825 /* Have to scale over many lines. */
1826 int i_yreal = p_pic->p->i_pitch * i_ytmp;
1827 int i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
1829 /* Draw until we reach the end of the line */
1830 for( ; i_x < p_spu->i_width; i_x ++, p_source++ )
1832 ogt_yuvt_t p_yuvt = p_sys->p_palette[*p_source & 0x3];
1836 /* FIXME: y cropping should be dealt with outside of this
1838 if ( i_y < i_y_start) continue;
1840 if ( i_x > i_x_end )
1842 p_source += p_spu->i_width - i_x;
1847 if (p_source >= p_src_end) {
1848 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1849 i_x, i_y / i_yscale, i_height);
1853 #ifdef TESTING_TRANSPARENCY
1854 if (p_yuvt.s.t == MAX_ALPHA) p_yuvt.s.t >>= 1;
1856 switch ( p_yuvt.s.t )
1859 /* Completely transparent. Don't change pixel. */
1861 printf(" "); /*++++*/
1866 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1867 * BYTES_PER_PIXEL );
1868 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1869 * BYTES_PER_PIXEL );
1870 uint32_t len = i_xlast - i_xdest;
1872 printf("%1d", *p_source); /*++++*/
1874 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1875 i_ytmp += p_pic->p->i_pitch ) {
1876 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1877 memset( p_dest, cmap[*p_source & 0x3], len );
1883 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1884 * BYTES_PER_PIXEL );
1885 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1886 * BYTES_PER_PIXEL );
1889 printf("%1d", *p_source); /*++++*/
1892 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1893 i_ytmp += p_pic->p->i_pitch ) {
1894 /* This is the pixel that's going to change;*/
1895 uint8_t *p_pixel = p_pixel_base + i_ytmp + i_xdest;
1896 for ( len = i_xlast - i_xdest -1; len >= 0; len-- )
1898 cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel,
1900 cmap_rgb[*p_source]);
1901 if (i_cmap != INVALID_CMAP_ENTRY)
1902 *p_pixel= (uint8_t) i_cmap;
1916 * c-file-style: "gnu"
1918 * indent-tabs-mode: nil