1 /*****************************************************************************
2 * render.c : Philips OGT and CVD (VCD Subtitle) blending routines.
3 * stuff from here might be pulled out, abstracted or used
5 *****************************************************************************
6 * Copyright (C) 2003, 2004 VideoLAN
9 * Author: Rocky Bernstein <rocky@panix.com>
11 * Sam Hocevar <sam@zoy.org>
12 * Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
13 * Roine Gustafsson <roine@popstar.com>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
28 *****************************************************************************/
30 /*#define TESTING_TRANSPARENCY 1*/
32 /*****************************************************************************
34 *****************************************************************************/
37 #include <vlc/decoder.h>
43 /* We use 4 bits for an transparency value: 0..15, 15 is completely
44 transparent and 0 completely opaque. Note that although SVCD allow
45 8-bits, for these routines pixels should previously have been be
46 scaled down to 4 bits (the range used by DVDs).
48 #define TRANS_BITS (4)
49 #define MAX_TRANS ((1<<TRANS_BITS) - 1)
50 #define TRANS_SCALEDOWN (8-TRANS_BITS)
52 /* We use a fixed-point arithmetic in scaling ratios so that we
53 can use integer arithmetic and still get fairly precise
54 results. ASCALE is a left shift amount.
56 #define ASCALE 6 /* 2^6 = 32 */
58 /* Horrible hack to get dbg_print to do the right thing */
62 Take two 8-bit RGB values and a transparency and do a weighted
63 average of them. The "weight" comes from i_trans which is in the
64 range 0..MAX_TRANS. To have greater precision using integer
65 arithmetic, the RGB values are scaled. The uint16_t cast below is
66 to make sure we don't overflow the product in the multiplication
68 (MAX_TRANS - i_trans) is the additive "inverse" of i_trans, i.e.
69 i_trans + (MAX_TRANS - i_trans) = MAX_TRANS. So the resulting sum
70 of rgb1*i_trans + rgb2*(MAX_TRANS-i_trans) will be scaled by
71 MAX_TRANS. To reduce the value back down to 8 bits, we shift by
72 TRANS_BITS, noting that 1 << TRANS_BITS is roughly
73 MAX_TRANS. (Actually it is MAX_TRANS - 1).
75 #define avg_8bit_rgb(rgb_vout, rgb_sub, i_trans) \
78 for (i=0; i < RGB_SIZE; i++) { \
79 rgb_vout[i] = ( (uint16_t) rgb_vout[i]*(MAX_TRANS-i_trans) + \
80 (uint16_t) rgb_sub [i]*i_trans ) >> TRANS_BITS; \
85 /*****************************************************************************
87 *****************************************************************************/
88 static void BlendI420( vout_thread_t *, picture_t *, const subpicture_t *,
90 static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,
91 const subpicture_t *p_spu, vlc_bool_t b_crop );
92 static void BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,
93 const subpicture_t *p_spu, vlc_bool_t b_crop,
95 static void BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,
96 const subpicture_t *p_spu, vlc_bool_t b_crop );
97 static void BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,
98 const subpicture_t *p_spu, vlc_bool_t b_crop );
99 static void BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,
100 const subpicture_t *p_spu, vlc_bool_t b_crop );
102 /*****************************************************************************
103 * BlendSPU: blend a subtitle into a picture
104 *****************************************************************************
106 This blends subtitles (a subpicture) into the underlying
107 picture. Subtitle data has been preprocessed as YUV + transparancy
108 or 4 bytes per pixel with interleaving of rows in the subtitle
111 *****************************************************************************/
112 void VCDSubBlend( vout_thread_t *p_vout, picture_t *p_pic,
113 const subpicture_t *p_spu )
115 struct subpicture_sys_t *p_sys = p_spu->p_sys;
117 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
118 "chroma %x", p_vout->output.i_chroma );
120 switch( p_vout->output.i_chroma )
122 /* I420 target, no scaling */
123 case VLC_FOURCC('I','4','2','0'):
124 case VLC_FOURCC('I','Y','U','V'):
125 case VLC_FOURCC('Y','V','1','2'):
126 BlendI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
129 /* RGB 555 - scaled */
130 case VLC_FOURCC('R','V','1','5'):
131 BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,
135 case VLC_FOURCC('R','V','1','6'):
136 BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,
137 /* Not sure under what conditions RV16 is really
147 /* RV24 target, scaling */
148 case VLC_FOURCC('R','V','2','4'):
149 BlendRV24( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
152 /* RV32 target, scaling */
153 case VLC_FOURCC('R','V','3','2'):
154 BlendRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
157 /* NVidia overlay, no scaling */
158 case VLC_FOURCC('Y','U','Y','2'):
159 BlendYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
162 /* Palettized 8 bits per pixel (256 colors). Each
163 pixel is an uint8_t index in the palette
166 case VLC_FOURCC('R','G','B','2'):
167 BlendRGB2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
172 msg_Err( p_vout, "unknown chroma, can't render SPU" );
177 /* Following functions are local */
182 All Y samples are found first in memory as an array of bytes
183 (possibly with a larger stride for memory alignment), followed
184 immediately by all Cr (=U) samples (with half the stride of the Y
185 lines, and half the number of lines), then followed immediately by
186 all Cb (=V) samples in a similar fashion.
189 static void BlendI420( vout_thread_t *p_vout, picture_t *p_pic,
190 const subpicture_t *p_spu, vlc_bool_t b_crop )
192 /* Common variables */
193 uint8_t *p_pixel_base_Y, *p_pixel_base_V, *p_pixel_base_U;
194 ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
197 vlc_bool_t even_scanline = VLC_FALSE;
200 int i_x_start, i_y_start, i_x_end, i_y_end;
203 const struct subpicture_sys_t *p_sys = p_spu->p_sys;
205 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
206 "spu width x height: (%dx%d), (x,y)=(%d,%d), yuv pitch (%d,%d,%d)",
207 p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
208 p_pic->Y_PITCH, p_pic->U_PITCH, p_pic->V_PITCH );
211 p_pixel_base_Y = p_pic->p[Y_PLANE].p_pixels + p_spu->i_x
212 + p_pic->p[Y_PLANE].i_pitch * p_spu->i_y;
214 p_pixel_base_U = p_pic->p[U_PLANE].p_pixels + p_spu->i_x/2
215 + p_pic->p[U_PLANE].i_pitch * p_spu->i_y/2;
217 p_pixel_base_V = p_pic->p[V_PLANE].p_pixels + p_spu->i_x/2
218 + p_pic->p[V_PLANE].i_pitch * p_spu->i_y/2;
220 i_x_start = p_sys->i_x_start;
221 i_y_start = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_start;
223 i_x_end = p_sys->i_x_end;
224 i_y_end = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_end;
226 p_source = (ogt_yuvt_t *)p_sys->p_data;
228 /* Draw until we reach the bottom of the subtitle */
230 i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
231 i_y += p_pic->p[Y_PLANE].i_pitch )
233 uint8_t *p_pixel_base_Y_y = p_pixel_base_Y + i_y;
234 uint8_t *p_pixel_base_U_y = p_pixel_base_U + i_y/4;
235 uint8_t *p_pixel_base_V_y = p_pixel_base_V + i_y/4;
240 if ( i_y > i_y_end ) break;
243 p_source += i_x_start;
247 even_scanline = !even_scanline;
249 /* Draw until we reach the end of the line */
250 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
255 /* FIXME: y cropping should be dealt with outside of this loop.*/
256 if ( i_y < i_y_start) continue;
260 p_source += p_spu->i_width - i_x;
265 #ifdef TESTING_TRANSPARENCY
266 if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 1;
269 switch( p_source->s.t )
272 /* Completely transparent. Don't change pixel. */
277 /* Completely opaque. Completely overwrite underlying
278 pixel with subtitle pixel. */
280 /* This is the location that's going to get changed.*/
281 uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;
283 *p_pixel_Y = p_source->plane[Y_PLANE];
285 if ( even_scanline && i_x % 2 == 0 ) {
286 uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2;
287 uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2;
288 *p_pixel_U = p_source->plane[U_PLANE];
289 *p_pixel_V = p_source->plane[V_PLANE];
297 /* Blend in underlying subtitle pixel. */
299 /* This is the location that's going to get changed. */
300 uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;
303 /* This is the weighted part of the subtitle. The
304 color plane is 8 bits and transparancy is 4 bits so
305 when multiplied we get up to 12 bits.
307 uint16_t i_sub_color_Y =
308 (uint16_t) ( p_source->plane[Y_PLANE] *
309 (uint16_t) (p_source->s.t) );
311 /* This is the weighted part of the underlying pixel.
312 For the same reasons above, the result is up to 12
313 bits. However since the transparancies are
314 inverses, the sum of i_sub_color and i_pixel_color
315 will not exceed 12 bits.
317 uint16_t i_pixel_color_Y =
318 (uint16_t) ( *p_pixel_Y *
319 (uint16_t) (MAX_TRANS - p_source->s.t) ) ;
321 /* Scale the 12-bit result back down to 8 bits. A
322 precise scaling after adding the two components,
323 would divide by one less than a power of 2. However
324 to simplify and speed things we use a power of
325 2. This means the boundaries (either all
326 transparent and all opaque) aren't handled properly.
327 But we deal with them in special cases above. */
329 *p_pixel_Y = ( i_sub_color_Y + i_pixel_color_Y ) >> TRANS_BITS;
331 if ( even_scanline && i_x % 2 == 0 ) {
332 uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2
333 - p_pic->p[U_PLANE].i_pitch / 2;
334 uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2
335 - p_pic->p[V_PLANE].i_pitch / 2;
336 uint16_t i_sub_color_U =
337 (uint16_t) ( p_source->plane[U_PLANE] *
338 (uint16_t) (p_source->s.t) );
340 uint16_t i_sub_color_V =
341 (uint16_t) ( p_source->plane[V_PLANE] *
342 (uint16_t) (p_source->s.t) );
343 uint16_t i_pixel_color_U =
344 (uint16_t) ( *p_pixel_U *
345 (uint16_t) (MAX_TRANS - p_source->s.t) ) ;
346 uint16_t i_pixel_color_V =
347 (uint16_t) ( *p_pixel_V *
348 (uint16_t) (MAX_TRANS - p_source->s.t) ) ;
349 *p_pixel_U = ( i_sub_color_U + i_pixel_color_U )>>TRANS_BITS;
350 *p_pixel_V = ( i_sub_color_V + i_pixel_color_V )>>TRANS_BITS;
364 Data is found in memory as an array of bytes in which the first byte
365 contains the first sample of Y, the second byte contains the first
366 sample of Cb (=U), the third byte contains the second sample of Y,
367 the fourth byte contains the first sample of Cr (=V); and so
368 on. Each 32-bit word then contains information for two contiguous
369 horizontal pixels, two 8-bit Y values plus a single Cb and Cr which
370 spans the two pixels.
373 #define BYTES_PER_PIXEL 4
375 static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,
376 const subpicture_t *p_spu, vlc_bool_t b_crop )
378 /* Common variables */
379 uint8_t *p_pixel_base;
381 /* This is the where the subtitle pixels come from */
382 ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
384 ogt_yuvt_t *p_source_end = (ogt_yuvt_t *)p_spu->p_sys->p_data +
385 (p_spu->i_width * p_spu->i_height);
389 /* Make sure we start on a word (4-byte) boundary. */
390 uint16_t i_spu_x = (p_spu->i_x & 0xFFFE) * 2;
393 int i_x_start, i_y_start, i_x_end, i_y_end;
395 const struct subpicture_sys_t *p_sys = p_spu->p_sys;
397 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
398 "spu width x height: (%dx%d), (x,y)=(%d,%d), pitch: %d",
399 p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
403 p_pixel_base = p_pic->p->p_pixels +
404 + ( p_spu->i_y * p_pic->p->i_pitch ) + i_spu_x;
406 i_x_start = p_sys->i_x_start;
407 i_y_start = p_sys->i_y_start * p_pic->p->i_pitch;
409 i_x_end = p_sys->i_x_end;
410 i_y_end = p_sys->i_y_end * p_pic->p->i_pitch;
412 /* Draw until we reach the bottom of the subtitle */
414 i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
415 i_y += p_pic->p[Y_PLANE].i_pitch )
417 uint8_t *p_pixel_base_y = p_pixel_base + i_y;
422 if ( i_y > i_y_end ) break;
425 p_source += (i_x_start*2);
430 /* Draw until we reach the end of the line. Each output pixel
431 is a combination of two source pixels.
433 for( i_x = 0; i_x < p_spu->i_width / 2; i_x++, p_source +=2 )
435 uint16_t i_avg_tr; /* transparancy sort of averaged over 2 pixels*/
437 if (p_source > p_source_end-1) {
438 msg_Err( p_vout, "Trying to access beyond subtitle x: %d y: %d",
445 /* FIXME: y cropping should be dealt with outside of this loop.*/
446 if ( i_y < i_y_start) continue;
450 p_source += p_spu->i_width - (i_x*2);
456 /* Favor opaque subtitle pixels. */
457 if ( (p_source->s.t == 0) && (p_source+1)->s.t == MAX_TRANS )
458 i_avg_tr = (p_source+1)->s.t;
459 else if ( (p_source->s.t == MAX_TRANS) && (p_source+1)->s.t == 0 )
460 i_avg_tr = p_source->s.t;
462 i_avg_tr = ( p_source->s.t + (p_source+1)->s.t ) / 2;
464 #ifdef TESTING_TRANSPARENCY
465 if (i_avg_tr == MAX_TRANS) i_avg_tr >>= 1;
471 /* Completely transparent. Don't change pixel. */
476 /* Completely opaque. Completely overwrite underlying
477 pixel with subtitle pixel. */
479 /* This is the location that's going to get changed. */
480 uint8_t *p_pixel = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
484 /* Favor opaque subtitle pixel. */
485 if (p_source->s.t == MAX_TRANS ) {
486 i_avg_u = p_source->plane[U_PLANE] ;
487 i_avg_v = p_source->plane[V_PLANE] ;
488 } else if ( (p_source+1)->s.t == MAX_TRANS ) {
489 i_avg_u = (p_source+1)->plane[U_PLANE] ;
490 i_avg_v = (p_source+1)->plane[V_PLANE] ;
492 i_avg_u = ( p_source->plane[U_PLANE]
493 + (p_source+1)->plane[U_PLANE] ) / 2;
494 i_avg_v = ( p_source->plane[V_PLANE]
495 + (p_source+1)->plane[V_PLANE] ) / 2;
498 /* draw a two contiguous pixels: 2 Y values, 1 U, and 1 V. */
499 *p_pixel++ = p_source->plane[Y_PLANE] ;
500 *p_pixel++ = i_avg_u;
501 *p_pixel++ = (p_source+1)->plane[Y_PLANE] ;
502 *p_pixel++ = i_avg_v;
509 /* Blend in underlying subtitle pixels. */
511 /* This is the location that's going to get changed. */
512 uint8_t *p_pixel = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
513 uint8_t i_avg_u = ( p_source->plane[U_PLANE]
514 + (p_source+1)->plane[U_PLANE] ) / 2;
515 uint8_t i_avg_v = ( p_source->plane[V_PLANE]
516 + (p_source+1)->plane[V_PLANE] ) / 2;
518 /* This is the weighted part of the two subtitle
519 pixels. The color plane is 8 bits and transparancy
520 is 4 bits so when multiplied we get up to 12 bits.
522 uint16_t i_sub_color_Y1 =
523 (uint16_t) ( p_source->plane[Y_PLANE] *
524 (uint16_t) (p_source->s.t) );
526 uint16_t i_sub_color_Y2 =
527 (uint16_t) ( (p_source+1)->plane[Y_PLANE] *
528 (uint16_t) ((p_source+1)->s.t) );
530 /* This is the weighted part of the underlying pixels.
531 For the same reasons above, the result is up to 12
532 bits. However since the transparancies are
533 inverses, the sum of i_sub_color and i_pixel_color
534 will not exceed 12 bits.
536 uint16_t i_sub_color_U =
537 (uint16_t) ( i_avg_u * (uint16_t) i_avg_tr );
539 uint16_t i_sub_color_V =
540 (uint16_t) ( i_avg_v * (uint16_t) i_avg_tr );
542 uint16_t i_pixel_color_Y1 =
543 (uint16_t) ( *(p_pixel) *
544 (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
545 uint16_t i_pixel_color_Y2 =
546 (uint16_t) ( *(p_pixel+2) *
547 (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
548 uint16_t i_pixel_color_U =
549 (uint16_t) ( *(p_pixel+1) *
550 (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
551 uint16_t i_pixel_color_V =
552 (uint16_t) ( *(p_pixel+3) *
553 (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
555 /* draw a two contiguous pixels: 2 Y values, 1 U, and 1 V. */
557 /* Scale the 12-bit result back down to 8 bits. A
558 precise scaling after adding the two components,
559 would divide by one less than a power of 2. However
560 to simplify and speed things we use a power of
561 2. This means the boundaries (either all
562 transparent and all opaque) aren't handled properly.
563 But we deal with them in special cases above. */
565 *p_pixel++ = ( i_sub_color_Y1 + i_pixel_color_Y1 )>>TRANS_BITS;
566 *p_pixel++ = ( i_sub_color_U + i_pixel_color_U ) >>TRANS_BITS;
567 *p_pixel++ = ( i_sub_color_Y2 + i_pixel_color_Y2 )>>TRANS_BITS;
568 *p_pixel++ = ( i_sub_color_V + i_pixel_color_V ) >>TRANS_BITS;
574 /* For an odd width source, we'll just have to drop off a pixel. */
575 if (p_spu->i_width % 2) p_source++;
580 Convert a YUV pixel into a 16-bit RGB 5-5-5 pixel.
582 A RGB 5-5-5 pixel looks like this:
583 RGB 5-5-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
584 p ? B4 B3 B2 B1 B0 R4 R3
585 q R2 R1 R0 G4 G3 G2 G1 G0
590 yuv2rgb555(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
593 uint8_t rgb[RGB_SIZE];
597 /* Scale RGB from 8 bits down to 5. */
598 rgb[RED_PIXEL] >>= (8-5);
599 rgb[GREEN_PIXEL] >>= (8-5);
600 rgb[BLUE_PIXEL] >>= (8-5);
602 *p_rgb1 = ( (rgb[BLUE_PIXEL] << 2)&0x7c ) | ( (rgb[RED_PIXEL]>>3) & 0x03 );
603 *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
606 printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
607 "rgb1: %02x, rgb2 %02x\n",
608 p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
609 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
616 Convert a YUV pixel into a 16-bit RGB 5-6-5 pixel.
618 A RGB 5-6-5 pixel looks like this:
619 RGB 5-6-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
620 p B4 B3 B2 B1 B0 R5 R4 R3
621 q R2 R1 R0 G4 G3 G2 G1 G0
626 yuv2rgb565(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
629 uint8_t rgb[RGB_SIZE];
633 /* Scale RGB from 8 bits down to 5 or 6 bits. */
634 rgb[RED_PIXEL] >>= (8-6);
635 rgb[GREEN_PIXEL] >>= (8-5);
636 rgb[BLUE_PIXEL] >>= (8-5);
638 *p_rgb1 = ( (rgb[BLUE_PIXEL] << 3)&0xF8 ) | ( (rgb[RED_PIXEL]>>3) & 0x07 );
639 *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
642 printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
643 "rgb1: %02x, rgb2 %02x\n",
644 p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
645 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
652 rv16_pack_blend(uint8_t *p_pixel, ogt_yuvt_t *p_source, uint8_t *p_rgb1,
653 uint8_t *p_rgb2, vlc_bool_t b_15bpp, uint8_t i_trans,
657 uint8_t rgb_vout[RGB_SIZE];
660 yuv2rgb(p_source, rgb_sub);
662 /* Scale RGB from 8 bits down to 6 or 5. */
663 rgb_sub[GREEN_PIXEL] >>= (8-5);
664 rgb_sub[BLUE_PIXEL] >>= (8-5);
666 rgb_vout[GREEN_PIXEL] = *(p_pixel+1) & 0x1f;
668 rgb_sub[RED_PIXEL] >>= (8-5);
669 rgb_vout[BLUE_PIXEL] = ((*p_pixel)>>2) & 0x1f;
670 rgb_vout[RED_PIXEL] = ((*p_pixel & 0x03) << 3) | ((*(p_pixel+1)&0xe0)>>5);
672 rgb_sub[RED_PIXEL] >>= (8-6);
673 rgb_vout[BLUE_PIXEL] = ((*p_pixel)>>3) & 0x1f;
674 rgb_vout[RED_PIXEL] = ((*p_pixel & 0x07) << 3) | ((*(p_pixel+1)&0xe0)>>5);
679 printf("r,g,b=(%d,%d,%d), sub r,g,b=(%d,%d,%d), trans %d, inv_trans %d\n",
680 rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL],
681 rgb_sub[RED_PIXEL], rgb_sub[GREEN_PIXEL],
682 rgb_sub[BLUE_PIXEL], i_trans, i_inv_trans);
685 #ifdef FIXED_RV16_TRANSPARENCY
686 avg_8bit_rgb(rgb_vout, rgb_sub, i_trans);
688 for (i=0; i < RGB_SIZE; i++) {
689 /* For now the Best we can do is fade the color. Picking up
690 video underneath doesn't work. */
691 /* rgb_vout[i] = ( (uint16_t) rgb_vout[i]*i_inv_trans ) >> TRANS_BITS; */
692 rgb_vout[i] = ( (uint16_t) rgb_sub[i]*i_trans ) >> TRANS_BITS;
698 printf("avg r,g,b=(%d,%d,%d)\n",
699 rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL] );
704 *p_rgb1 = ( (rgb_vout[BLUE_PIXEL] << 2)&0x7c )|( (rgb_vout[RED_PIXEL]>>3)&0x03 );
706 *p_rgb1 = ( (rgb_vout[BLUE_PIXEL] << 3)&0xF8 )|( (rgb_vout[RED_PIXEL]>>3)&0x07 );
708 *p_rgb2 = ( (rgb_vout[RED_PIXEL] << 5)&0xe0 ) | ( rgb_vout[GREEN_PIXEL]&0x1f );
710 *p_rgb1 = (*p_rgb1)+1;
711 *p_rgb2 = (*p_rgb2)+1;
716 #undef BYTES_PER_PIXEL
717 #define BYTES_PER_PIXEL 2
720 BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,
721 const subpicture_t *p_spu, vlc_bool_t b_crop,
724 /* Common variables */
725 uint8_t *p_pixel_base;
726 ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
727 ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
728 ogt_yuvt_t *p_source;
733 /* Chroma specific */
734 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
735 multiplied by 2**ASCALE. */
736 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
737 multiplied by 2**ASCALE. */
739 int i_width, i_height, i_ytmp, i_ynext;
742 int i_x_start, i_y_start, i_x_end, i_y_end;
744 struct subpicture_sys_t *p_sys = p_spu->p_sys;
746 i_xscale = ( p_vout->output.i_width << ASCALE ) / p_vout->render.i_width;
747 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
749 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
750 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
751 p_spu->i_width, p_spu->i_height,
752 p_vout->output.i_width, p_vout->output.i_height,
753 p_vout->render.i_width, p_vout->render.i_height,
757 i_width = p_spu->i_width * i_xscale;
758 i_height = p_spu->i_height * i_yscale;
760 /* Set where we will start blending subtitle from using
761 the picture coordinates subtitle offsets
763 p_pixel_base = p_pic->p->p_pixels
764 + ( (p_spu->i_x * i_xscale) >> ASCALE ) * BYTES_PER_PIXEL
765 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
767 i_x_start = p_sys->i_x_start;
768 i_y_start = i_yscale * p_sys->i_y_start;
769 i_x_end = p_sys->i_x_end;
770 i_y_end = i_yscale * p_sys->i_y_end;
772 p_source = (ogt_yuvt_t *)p_sys->p_data;
774 /* Draw until we reach the bottom of the subtitle */
776 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
777 i_y_src += p_spu->i_width )
779 uint8_t *p_pixel_base_y;
780 i_ytmp = i_y >> ASCALE;
782 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
786 if ( i_y > i_y_end ) break;
789 p_source += i_x_start;
793 /* Check whether we need to draw one line or more than one */
794 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
796 /* Draw until we reach the end of the line */
797 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
801 uint8_t *p=(uint8_t *) p_source;
802 printf("+++ %02x %02x %02x %02x\n",
803 p[0], p[1], p[2], p[3]);
808 /* FIXME: y cropping should be dealt with outside of this
810 if ( i_y < i_y_start) continue;
814 p_source += p_spu->i_width - i_x;
819 if (p_source >= p_src_end) {
820 msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
821 i_x, i_y / i_yscale, i_height);
825 #ifdef TESTING_TRANSPARENCY
826 if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 1;
829 switch( p_source->s.t )
832 /* Completely transparent. Don't change pixel. */
837 /* Completely opaque. Completely overwrite underlying
838 pixel with subtitle pixel. */
840 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
842 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
844 uint32_t len = i_xlast - i_xdest;
849 /* This is the location that's going to get changed. */
850 uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
853 yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
855 yuv2rgb565(p_source, &i_rgb1, &i_rgb2);
857 for ( len = i_xlast - i_xdest; len ; len--) {
866 /* Blend in underlying pixel subtitle pixel. */
868 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
870 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
874 uint32_t len = i_xlast - i_xdest;
876 /* This is the location that's going to get changed. */
877 uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
879 for ( len = i_xlast - i_xdest; len ; len--) {
880 rv16_pack_blend(p_dest, p_source, &i_rgb1, &i_rgb2,
881 b_15bpp, p_source->s.t, TRANS_SCALEDOWN);
892 i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
895 /* Draw until we reach the end of the line */
896 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
901 /* FIXME: y cropping should be dealt with outside of this
903 if ( i_y < i_y_start) continue;
907 p_source += p_spu->i_width - i_x;
912 if (p_source >= p_src_end) {
913 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
914 i_x, i_y / i_yscale, i_height);
918 switch( p_source->s.t )
921 /* Completely transparent. Don't change pixel. */
926 /* Completely opaque. Completely overwrite underlying
927 pixel with subtitle pixel. */
929 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
931 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
933 uint32_t len = i_xlast - i_xdest;
935 uint8_t *p_pixel_base_x = p_pixel_base + i_xdest;
937 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
939 /* This is the location that's going to get changed. */
940 uint8_t *p_dest = p_pixel_base_x + i_ytmp;
941 uint8_t i_rgb1, i_rgb2;
943 yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
945 yuv2rgb565(p_source, &i_rgb1, &i_rgb2);
947 for ( len = i_xlast - i_xdest; len ; len--) {
956 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
958 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
960 uint32_t len = i_xlast - i_xdest;
961 uint8_t i_rgb1, i_rgb2;
962 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
964 /* Blend in underlying pixel subtitle pixel. */
965 uint8_t *p_dest = p_pixel_base + i_ytmp;
966 for ( len = i_xlast - i_xdest; len ; len--) {
967 rv16_pack_blend(p_dest, p_source, &i_rgb1, &i_rgb2,
968 b_15bpp, p_source->s.t, TRANS_SCALEDOWN);
981 #undef BYTES_PER_PIXEL
982 #define BYTES_PER_PIXEL 4
985 rv24_pack_blend(uint8_t *rgb_vout, const uint8_t *rgb_sub, uint8_t i_trans,
990 printf("r,g,b=(%d,%d,%d), source r,g,b=(%d,%d,%d), trans %d\n",
991 rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL],
992 rgb_sub[RED_PIXEL], rgb_sub[GREEN_PIXEL],
993 rgb_sub[BLUE_PIXEL], i_trans);
996 #ifdef WORDS_BIGENDIAN
1000 avg_8bit_rgb(rgb_vout, rgb_sub, i_trans);
1003 printf("avg r,g,b=(%d,%d,%d)\n",
1004 rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL] );
1010 RV24 format??? Is this just for X11? Or just not for Win32? Is this
1013 a pixel is represented by 3 bytes containing a red,
1014 blue and green sample with blue stored at the lowest address, green
1015 next then red. One padding byte is added between pixels. Although
1016 this may not be part of a spec, images should be stored with each
1017 line padded to a u_int32 boundary.
1020 BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,
1021 const subpicture_t *p_spu, vlc_bool_t b_crop )
1023 /* Common variables */
1024 uint8_t *p_pixel_base;
1025 ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
1026 ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
1027 ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
1032 /* Make sure we start on a word (4-byte) boundary. */
1035 /* Chroma specific */
1036 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
1037 multiplied by 2**ASCALE. */
1038 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
1039 multiplied by 2**ASCALE. */
1041 int i_width, i_height, i_ytmp, i_ynext;
1044 int32_t i_x_start, i_y_start, i_x_end, i_y_end;
1046 struct subpicture_sys_t *p_sys = p_spu->p_sys;
1047 int i_aspect_x, i_aspect_y;
1049 vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
1050 VOUT_ASPECT_FACTOR, 0 );
1052 i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
1053 / (i_aspect_y * p_vout->render.i_width);
1054 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
1056 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
1057 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
1058 p_spu->i_width, p_spu->i_height,
1059 p_vout->output.i_width, p_vout->output.i_height,
1060 p_vout->render.i_width, p_vout->render.i_height,
1064 i_width = p_spu->i_width * i_xscale;
1065 i_height = p_spu->i_height * i_yscale;
1067 /* Set where we will start blending subtitle from using
1068 the picture coordinates subtitle offsets.
1070 i_spu_x = ((p_spu->i_x * i_xscale) >> ASCALE) * BYTES_PER_PIXEL;
1072 p_pixel_base = p_pic->p->p_pixels + i_spu_x
1073 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
1075 i_x_start = p_sys->i_x_start;
1076 i_y_start = i_yscale * p_sys->i_y_start;
1077 i_x_end = p_sys->i_x_end;
1078 i_y_end = i_yscale * p_sys->i_y_end;
1080 p_source = (ogt_yuvt_t *)p_sys->p_data;
1082 /* Draw until we reach the bottom of the subtitle */
1084 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
1085 i_y_src += p_spu->i_width )
1087 uint8_t *p_pixel_base_y;
1088 i_ytmp = i_y >> ASCALE;
1090 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
1094 if ( i_y > i_y_end ) break;
1097 p_source += i_x_start;
1101 /* Check whether we need to draw one line or more than one */
1102 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
1104 /* Draw until we reach the end of the line */
1105 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1110 /* FIXME: y cropping should be dealt with outside of this
1112 if ( i_y < i_y_start) continue;
1114 if ( i_x > i_x_end )
1116 p_source += p_spu->i_width - i_x;
1121 if (p_source >= p_src_end) {
1122 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1123 i_x, i_y / i_yscale, i_height);
1127 #ifdef TESTING_TRANSPARENCY
1128 if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 2;
1131 switch( p_source->s.t )
1134 /* Completely transparent. Don't change pixel. */
1139 /* Completely opaque. Completely overwrite underlying
1140 pixel with subtitle pixel. */
1142 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1143 * BYTES_PER_PIXEL );
1144 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1145 * BYTES_PER_PIXEL );
1146 uint32_t len = i_xlast - i_xdest;
1148 uint8_t rgb[RGB_SIZE];
1150 /* This is the location that's going to get changed. */
1151 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1153 yuv2rgb(p_source, rgb);
1155 for ( len = i_xlast - i_xdest; len ; len--) {
1156 put_rgb24_pixel(rgb, p_dest);
1157 p_dest += BYTES_PER_PIXEL;
1162 /* Blend in underlying pixel subtitle pixel. */
1164 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1165 * BYTES_PER_PIXEL );
1166 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1167 * BYTES_PER_PIXEL );
1168 uint32_t len = i_xlast - i_xdest * BYTES_PER_PIXEL;
1170 /* To be able to scale correctly for full
1171 opaqueness, we add 1 to the transparency.
1172 This means transparency value 0 won't be
1173 completely transparent which is not correct.
1174 But that's handled in a special case above
1177 /* This is the location that's going to get changed. */
1178 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1179 uint8_t rgb[RGB_SIZE];
1181 yuv2rgb(p_source, rgb);
1183 for ( len = i_xlast - i_xdest; len ; len--) {
1184 rv24_pack_blend(p_dest, rgb, p_source->s.t,
1186 p_dest += BYTES_PER_PIXEL;
1196 i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
1199 /* Draw until we reach the end of the line */
1200 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1205 /* FIXME: y cropping should be dealt with outside of this
1207 if ( i_y < i_y_start) continue;
1209 if ( i_x > i_x_end )
1211 p_source += p_spu->i_width - i_x;
1216 if (p_source >= p_src_end) {
1217 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1218 i_x, i_y / i_yscale, i_height);
1222 switch( p_source->s.t )
1225 /* Completely transparent. Don't change pixel. */
1230 /* Completely opaque. Completely overwrite underlying
1231 pixel with subtitle pixel. */
1233 /* This is the location that's going to get changed. */
1234 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1235 * BYTES_PER_PIXEL );
1236 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1237 * BYTES_PER_PIXEL );
1238 uint32_t len = i_xlast - i_xdest;
1240 uint8_t rgb[RGB_SIZE];
1242 yuv2rgb(p_source, rgb);
1244 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
1246 /* Completely opaque. Completely overwrite underlying
1247 pixel with subtitle pixel. */
1249 /* This is the location that's going to get changed. */
1250 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1252 for ( len = i_xlast - i_xdest; len ; len--) {
1253 put_rgb24_pixel(rgb, p_dest);
1254 p_dest += BYTES_PER_PIXEL;
1263 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1264 * BYTES_PER_PIXEL );
1265 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1266 * BYTES_PER_PIXEL );
1267 uint32_t len = i_xlast - i_xdest;
1268 uint8_t rgb[RGB_SIZE];
1270 yuv2rgb(p_source, rgb);
1272 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
1274 /* Blend in underlying pixel subtitle pixel. */
1276 /* This is the location that's going to get changed. */
1277 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1279 /* To be able to scale correctly for full opaqueness, we
1280 add 1 to the alpha. This means alpha value 0 won't
1281 be completely transparent and is not correct, but
1282 that's handled in a special case above anyway. */
1284 for ( len = i_xlast - i_xdest; len ; len--) {
1285 rv24_pack_blend(p_dest, rgb, p_source->s.t,
1287 p_dest += BYTES_PER_PIXEL;
1298 #undef BYTES_PER_PIXEL
1299 #define BYTES_PER_PIXEL 4
1302 RV32 format??? Is this just for X11? Or just not for Win32? Is this
1305 RV32 format: a pixel is represented by 4 bytes containing a red,
1306 blue and green sample with blue stored at the lowest address, green
1307 next then red. One padding byte is added between pixels. Although
1308 this may not be part of a spec, images should be stored with each
1309 line padded to a u_int32 boundary.
1312 BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,
1313 const subpicture_t *p_spu, vlc_bool_t b_crop )
1315 /* Common variables */
1316 uint8_t *p_pixel_base;
1317 ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
1318 ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
1319 ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
1324 /* Make sure we start on a word (4-byte) boundary. */
1327 /* Chroma specific */
1328 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
1329 multiplied by 2**ASCALE. */
1330 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
1331 multiplied by 2**ASCALE. */
1333 int i_width, i_height, i_ytmp, i_ynext;
1336 int32_t i_x_start, i_y_start, i_x_end, i_y_end;
1338 struct subpicture_sys_t *p_sys = p_spu->p_sys;
1339 int i_aspect_x, i_aspect_y;
1341 vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
1342 VOUT_ASPECT_FACTOR, 0 );
1344 i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
1345 / (i_aspect_y * p_vout->render.i_width);
1346 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
1348 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
1349 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
1350 p_spu->i_width, p_spu->i_height,
1351 p_vout->output.i_width, p_vout->output.i_height,
1352 p_vout->render.i_width, p_vout->render.i_height,
1356 i_width = p_spu->i_width * i_xscale;
1357 i_height = p_spu->i_height * i_yscale;
1359 /* Set where we will start blending subtitle from using
1360 the picture coordinates subtitle offsets.
1362 i_spu_x = ((p_spu->i_x * i_xscale) >> ASCALE) * BYTES_PER_PIXEL;
1364 p_pixel_base = p_pic->p->p_pixels + i_spu_x
1365 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
1367 i_x_start = p_sys->i_x_start;
1368 i_y_start = i_yscale * p_sys->i_y_start;
1369 i_x_end = p_sys->i_x_end;
1370 i_y_end = i_yscale * p_sys->i_y_end;
1372 p_source = (ogt_yuvt_t *)p_sys->p_data;
1374 /* Draw until we reach the bottom of the subtitle */
1376 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
1377 i_y_src += p_spu->i_width )
1379 uint8_t *p_pixel_base_y;
1380 i_ytmp = i_y >> ASCALE;
1382 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
1386 if ( i_y > i_y_end ) break;
1389 p_source += i_x_start;
1393 /* Check whether we need to draw one line or more than one */
1394 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
1396 /* Draw until we reach the end of the line */
1397 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1402 /* FIXME: y cropping should be dealt with outside of this
1404 if ( i_y < i_y_start) continue;
1406 if ( i_x > i_x_end )
1408 p_source += p_spu->i_width - i_x;
1413 if (p_source >= p_src_end) {
1414 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1415 i_x, i_y / i_yscale, i_height);
1419 switch( p_source->s.t )
1422 /* Completely transparent. Don't change pixel. */
1428 /* Completely opaque. Completely overwrite underlying
1429 pixel with subtitle pixel. */
1431 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1432 * BYTES_PER_PIXEL );
1433 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1434 * BYTES_PER_PIXEL );
1435 uint32_t len = i_xlast - i_xdest;
1437 uint8_t rgb[RGB_SIZE];
1439 /* This is the location that's going to get changed. */
1440 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1442 yuv2rgb(p_source, rgb);
1444 for ( len = i_xlast - i_xdest; len ; len--) {
1445 *p_dest++ = rgb[BLUE_PIXEL];
1446 *p_dest++ = rgb[GREEN_PIXEL];
1447 *p_dest++ = rgb[RED_PIXEL];
1451 #ifdef TRANSPARENCY_FINISHED
1454 /* Blend in underlying pixel subtitle pixel. */
1456 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1457 * BYTES_PER_PIXEL );
1458 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1459 * BYTES_PER_PIXEL );
1460 uint32_t len = i_xlast - i_xdest;
1462 /* To be able to scale correctly for full opaqueness, we
1463 add 1 to the alpha. This means alpha value 0 won't
1464 be completely transparent and is not correct, but
1465 that's handled in a special case above anyway. */
1467 uint8_t i_destalpha = MAX_TRANS - p_source->s.t;
1468 uint8_t rgb[RGB_SIZE];
1470 /* This is the location that's going to get changed. */
1471 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1473 yuv2rgb(p_source, rgb);
1474 rv32_pack_blend(p_dest, rgb, dest_alpha,
1477 for ( len = i_xlast - i_xdest; len ; len--) {
1478 *p_dest++ = rgb[BLUE_PIXEL];
1479 *p_dest++ = rgb[GREEN_PIXEL];
1480 *p_dest++ = rgb[RED_PIXEL];
1485 #endif /*TRANSPARENCY_FINISHED*/
1492 i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
1495 /* Draw until we reach the end of the line */
1496 for( ; i_x < p_spu->i_width; i_x++, p_source++ )
1501 /* FIXME: y cropping should be dealt with outside of this
1503 if ( i_y < i_y_start) continue;
1505 if ( i_x > i_x_end )
1507 p_source += p_spu->i_width - i_x;
1512 if (p_source >= p_src_end) {
1513 msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
1514 i_x, i_y / i_yscale, i_height);
1518 switch( p_source->s.t )
1521 /* Completely transparent. Don't change pixel. */
1527 /* Completely opaque. Completely overwrite underlying
1528 pixel with subtitle pixel. */
1530 /* This is the location that's going to get changed. */
1531 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1532 * BYTES_PER_PIXEL );
1533 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1534 * BYTES_PER_PIXEL );
1535 uint32_t len = i_xlast - i_xdest;
1537 uint8_t rgb[RGB_SIZE];
1539 yuv2rgb(p_source, rgb);
1541 for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
1543 /* Completely opaque. Completely overwrite underlying
1544 pixel with subtitle pixel. */
1546 /* This is the location that's going to get changed. */
1547 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1549 for ( len = i_xlast - i_xdest; len ; len--) {
1550 put_rgb24_pixel(rgb, p_dest);
1555 #ifdef TRANSPARENCY_FINISHED
1560 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1561 * BYTES_PER_PIXEL );
1562 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1563 * BYTES_PER_PIXEL );
1564 uint32_t len = i_xlast - i_xdest;
1565 uint8_t rgb[RGB_SIZE];
1567 yuv2rgb(p_source, rgb);
1569 for( ; i_ytmp < i_ynext ; y_ytmp += p_pic->p->i_pitch )
1571 /* Blend in underlying pixel subtitle pixel. */
1573 /* This is the location that's going to get changed. */
1574 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1576 /* To be able to scale correctly for full opaqueness, we
1577 add 1 to the alpha. This means alpha value 0 won't
1578 be completely transparent and is not correct, but
1579 that's handled in a special case above anyway. */
1581 uint8_t i_destalpha = MAX_TRANS - p_source->s.t;
1582 rv32_pack_blend(p_dest, rgb, dest_alpha,
1586 #endif /*TRANSPARENCY_FINISHED*/
1593 /* 4-entry array of colormap indices */
1594 static uint8_t cmap[NUM_SUBTITLE_COLORS];
1596 /* Actual RGB values for above; this is used in blending.*/
1597 static uint8_t cmap_rgb[NUM_SUBTITLE_COLORS][RGB_SIZE];
1600 Return the colormap index for the average of i_pixel and a subtitle
1601 pixel whose subtitle palette entry is i_cmap.
1603 static inline cmap_t
1604 avg_rgb2(const vout_thread_t *p_vout, uint8_t i_pixel, uint8_t i_trans,
1605 int i_cmap, mtime_t i_pts)
1607 uint8_t rgb_vout[RGB_SIZE];
1609 /* Cache the average of a vout colormap entry and a subtitle palette
1610 entry. There are not too many of these 256*4 = 1024.
1612 static cmap_t avg_cache[CMAP_RGB2_SIZE][NUM_SUBTITLE_COLORS];
1614 /* subtitle palettes might change between two subtitles. i_last_pts
1615 will be used to figure out if the subtitle has changed, and
1616 we have to invalidate the cache. */
1617 static mtime_t i_last_pts = -1;
1619 if (i_pts != i_last_pts)
1621 /* Hack: We rely on the fact that INVALID_CMAP_ENTRY is repeated
1624 memset(avg_cache, 0xFF, sizeof(avg_cache));
1628 if ( avg_cache[i_pixel][i_cmap] != INVALID_CMAP_ENTRY )
1629 return avg_cache[i_pixel][i_cmap];
1631 if ( !query_color(p_vout, i_pixel, rgb_vout) ) return INVALID_CMAP_ENTRY;
1633 avg_8bit_rgb(rgb_vout, cmap_rgb[i_cmap], i_trans);
1637 uint8_t rgb_approx[RGB_SIZE];
1639 avg_cache[i_pixel][i_cmap] =
1640 find_cmap_rgb8_nearest(p_vout, rgb_vout, rgb_approx);
1642 "cmap old %0x avg approx 0%x sub: %d sub=(%0x, %0x, %0x) "
1643 "approx=(%0x, %0x, %0x) avg vout=(%0x, %0x, %0x)\n",
1644 i_pixel, avg_cache[i_pixel][i_cmap], i_cmap,
1645 cmap_rgb[i_cmap][RED_PIXEL], cmap_rgb[i_cmap][GREEN_PIXEL],
1646 cmap_rgb[i_cmap][BLUE_PIXEL],
1647 rgb_approx[RED_PIXEL], rgb_approx[GREEN_PIXEL], rgb_approx[BLUE_PIXEL],
1648 rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL]);
1651 avg_cache[i_pixel][i_cmap] =
1652 find_cmap_rgb8_nearest(p_vout, rgb_vout, NULL);
1654 return avg_cache[i_pixel][i_cmap];
1657 #undef BYTES_PER_PIXEL
1658 #define BYTES_PER_PIXEL 1
1661 BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,
1662 const subpicture_t *p_spu, vlc_bool_t b_crop )
1664 /* Common variables */
1665 uint8_t *p_pixel_base;
1666 uint8_t *p_src_start = (uint8_t *)p_spu->p_sys->p_data;
1667 uint8_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
1668 uint8_t *p_source; /* This is the where the subtitle pixels come from */
1674 /* Chroma specific */
1675 uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
1676 multiplied by 2**ASCALE. */
1677 uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
1678 multiplied by 2**ASCALE. */
1680 int i_width, i_height, i_ytmp;
1683 int i_x_start, i_y_start, i_x_end, i_y_end;
1685 struct subpicture_sys_t *p_sys = p_spu->p_sys;
1686 int i_aspect_x, i_aspect_y;
1688 vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
1689 VOUT_ASPECT_FACTOR, 0 );
1691 i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
1692 / (i_aspect_y * p_vout->render.i_width);
1693 i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
1695 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
1696 "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
1697 p_spu->i_width, p_spu->i_height,
1698 p_vout->output.i_width, p_vout->output.i_height,
1699 p_vout->render.i_width, p_vout->render.i_height,
1703 i_width = p_spu->i_width * i_xscale;
1704 i_height = p_spu->i_height * i_yscale;
1707 /** FIXME: do once per subtitle in subtitle processing, not here
1708 each time we render. */
1709 /* Find a corresponding colormap entries for our palette entries. */
1710 for( i = 0; i < NUM_SUBTITLE_COLORS; i++ )
1713 if ( p_sys->p_palette[i].s.t != 0 ) {
1714 uint8_t rgb[RGB_SIZE];
1715 yuv2rgb(&(p_sys->p_palette[i]), rgb);
1717 find_cmap_rgb8_nearest(p_vout, rgb, cmap_rgb[i]);
1718 dbg_print( (DECODE_DBG_RENDER),
1719 "palette %d RGB=(%0x, %0x, %0x)\n", i,
1720 rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL]);
1724 /* Set where we will start blending subtitle from using
1725 the picture coordinates subtitle offsets
1727 p_pixel_base = p_pic->p->p_pixels
1728 + ( (p_spu->i_x * i_xscale) >> ASCALE ) * BYTES_PER_PIXEL
1729 + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
1731 i_x_start = p_sys->i_x_start;
1732 i_y_start = i_yscale * p_sys->i_y_start;
1733 i_x_end = p_sys->i_x_end;
1734 i_y_end = i_yscale * p_sys->i_y_end;
1736 p_source = (uint8_t *)p_sys->p_data;
1738 /* Draw until we reach the bottom of the subtitle */
1740 for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
1741 i_y_src += p_spu->i_width )
1743 uint8_t *p_pixel_base_y;
1744 i_ytmp = i_y >> ASCALE;
1746 p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
1750 if ( i_y > i_y_end ) break;
1753 p_source += i_x_start;
1757 /* Check whether we need to draw one line or more than one */
1758 if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
1761 /* Draw until we reach the end of the line */
1762 for( ; i_x < p_spu->i_width; i_x ++, p_source++ )
1768 /* FIXME: y cropping should be dealt with outside of this
1770 if ( i_y < i_y_start) continue;
1772 if ( i_x > i_x_end )
1774 p_source += p_spu->i_width - i_x;
1779 if (p_source >= p_src_end) {
1780 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1781 i_x, i_y / i_yscale, i_height);
1785 p_yuvt = p_sys->p_palette[*p_source & 0x3];
1787 #ifdef TESTING_TRANSPARENCY
1788 if (p_yuvt.s.t == MAX_TRANS) p_yuvt.s.t >>= 1;
1791 switch ( p_yuvt.s.t )
1794 /* Completely transparent. Don't change pixel. */
1796 printf(" "); /*++++*/
1801 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1802 * BYTES_PER_PIXEL );
1803 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1804 * BYTES_PER_PIXEL );
1805 /* This is the pixel that's going to change;*/
1806 uint8_t *p_dest = p_pixel_base_y + i_xdest;
1807 memset( p_dest, cmap[*p_source & 0x3], i_xlast - i_xdest );
1809 printf("%1d", *p_source); /*++++*/
1815 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1816 * BYTES_PER_PIXEL );
1817 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1818 * BYTES_PER_PIXEL );
1819 /* This is the pixel that's going to change;*/
1820 uint8_t *p_pixel = p_pixel_base_y + i_xdest;
1821 uint32_t len = i_xlast - i_xdest;
1823 #if FULL_TRANSPARENCY
1824 /* This is what should be done, but it may be too
1826 for ( len = i_xlast - i_xdest -1; len >= 0; len-- )
1828 cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel, p_yuvt.s.t,
1829 *p_source, p_sys->i_pts);
1831 if (i_cmap != INVALID_CMAP_ENTRY)
1832 *p_pixel= (uint8_t) i_cmap;
1836 cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel, p_yuvt.s.t,
1837 *p_source, p_sys->i_pts);
1838 if (i_cmap != INVALID_CMAP_ENTRY)
1839 memset(p_pixel, i_cmap, len);
1843 printf("%1d", *p_source); /*++++*/
1849 printf("\n"); /*++++*/
1852 /* Have to scale over many lines. */
1853 int i_yreal = p_pic->p->i_pitch * i_ytmp;
1854 int i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
1856 /* Draw until we reach the end of the line */
1857 for( ; i_x < p_spu->i_width; i_x ++, p_source++ )
1859 ogt_yuvt_t p_yuvt = p_sys->p_palette[*p_source & 0x3];
1863 /* FIXME: y cropping should be dealt with outside of this
1865 if ( i_y < i_y_start) continue;
1867 if ( i_x > i_x_end )
1869 p_source += p_spu->i_width - i_x;
1874 if (p_source >= p_src_end) {
1875 msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
1876 i_x, i_y / i_yscale, i_height);
1880 #ifdef TESTING_TRANSPARENCY
1881 if (p_yuvt.s.t == MAX_TRANS) p_yuvt.s.t >>= 1;
1883 switch ( p_yuvt.s.t )
1886 /* Completely transparent. Don't change pixel. */
1888 printf(" "); /*++++*/
1893 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1894 * BYTES_PER_PIXEL );
1895 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1896 * BYTES_PER_PIXEL );
1897 uint32_t len = i_xlast - i_xdest;
1899 printf("%1d", *p_source); /*++++*/
1901 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1902 i_ytmp += p_pic->p->i_pitch ) {
1903 uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
1904 memset( p_dest, cmap[*p_source & 0x3], len );
1910 uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
1911 * BYTES_PER_PIXEL );
1912 uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
1913 * BYTES_PER_PIXEL );
1914 int32_t len = i_xlast - i_xdest;
1916 printf("%1d", *p_source); /*++++*/
1919 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1920 i_ytmp += p_pic->p->i_pitch ) {
1921 /* This is the pixel that's going to change;*/
1922 uint8_t *p_pixel = p_pixel_base + i_ytmp + i_xdest;
1924 #if FULL_TRANSPARENCY
1925 /* This is what should be done, but it may be too
1927 for ( len = i_xlast - i_xdest -1; len >= 0; len-- )
1929 cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel,
1930 p_yuvt.s.t, *p_source,
1932 if (i_cmap != INVALID_CMAP_ENTRY)
1933 *p_pixel= (uint8_t) i_cmap;
1937 cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel, p_yuvt.s.t,
1938 *p_source, p_sys->i_pts);
1939 if (i_cmap != INVALID_CMAP_ENTRY)
1940 memset(p_pixel, i_cmap, len);
1954 * c-file-style: "gnu"
1956 * indent-tabs-mode: nil