Commit 0e7ed503 authored by Rocky Bernstein's avatar Rocky Bernstein

render.c: RV16 now works great - uses all colors, but no transparancy.

Started RV32 and- has bugs. (It'd be nice if something in rendering
worked the first time without a hassle).

Modules.am, pixmap.h, subtitle.h: Some of the pixel stuff has been
moved here.

cvd.c: remove option duplicated with ogt.c Probably should be hoisted more
to a main routine. Perhaps if spudec is folded in.
parent edb034c3
SOURCES_svcdsub = \
common.c \
common.h \
subtitle.h \
ogt.c \
ogt.h \
subtitle.h \
ogt_parse.c \
pixmap.h \
render.c \
render.h \
write_png.c \
......@@ -18,6 +19,7 @@ SOURCES_cvdsub = \
cvd.h \
subtitle.h \
cvd_parse.c \
pixmap.h \
render.c \
render.h \
write_png.c \
......
......@@ -2,7 +2,7 @@
* Common SVCD and VCD subtitle routines.
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
* $Id: common.c,v 1.6 2004/01/14 11:47:19 rocky Exp $
* $Id: common.c,v 1.7 2004/01/16 04:14:54 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
......@@ -33,6 +33,7 @@
#include <vlc/decoder.h>
#include "subtitle.h"
#include "pixmap.h"
#include "common.h"
#ifdef HAVE_LIBPNG
#include "write_png.h"
......@@ -346,49 +347,50 @@ VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
if (p_vout) {
/* Check for user-configuration override. */
unsigned int i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
if (i_new_aspect == VOUT_ASPECT_FACTOR) {
/* For scaling 1:1, nothing needs to be done. Note this means
subtitles will get scaled the same way the video does.
*/
;
} else {
if (0 == i_new_aspect) {
/* Counteract the effects of background video scaling when
there is scaling. That's why x and y are reversed from
the else branch in the call below.
*/
switch( p_vout->output.i_chroma )
{
/* chromas which are not scaled: */
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
case VLC_FOURCC('Y','U','Y','2'):
return;
break;
/* chromas which are scaled: */
case VLC_FOURCC('R','V','1','6'):
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
case VLC_FOURCC('R','G','B','2'):
break;
default:
msg_Err( p_vout, "unknown chroma %x",
p_vout->output.i_chroma );
return;
break;
}
/* We get here only for scaled chromas. */
vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
&i_aspect_x );
} else {
/* User knows best? */
vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
if (i_new_aspect == VOUT_ASPECT_FACTOR) {
/* For scaling 1:1, nothing needs to be done. Note this means
subtitles will get scaled the same way the video does.
*/
;
} else {
if (0 == i_new_aspect) {
/* Counteract the effects of background video scaling when
there is scaling. That's why x and y are reversed from
the else branch in the call below.
*/
switch( p_vout->output.i_chroma )
{
/* chromas which are not scaled: */
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
case VLC_FOURCC('Y','U','Y','2'):
break;
/* chromas which are scaled: */
case VLC_FOURCC('R','V','1','6'):
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
case VLC_FOURCC('R','G','B','2'):
return;
break;
default:
msg_Err( p_vout, "unknown chroma %x",
p_vout->output.i_chroma );
return;
break;
}
VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
}
/* We get here only for scaled chromas. */
vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
&i_aspect_x );
} else {
/* User knows best? */
vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
}
VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
}
}
}
......@@ -466,20 +468,6 @@ void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
printf("\n-------------------------------------\n");
}
/*
FIXME:
MOVE clip_8_bit and uuv2rgb TO A MORE GENERIC PLACE.
*/
/* Force v in the range 0.255 */
static inline uint8_t
clip_8_bit(int v)
{
if (v<0) return 0;
if (v>255) return 255;
return (uint8_t) v;
}
/***************************************************
Color conversion from
http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
......@@ -499,28 +487,6 @@ clip_8_bit(int v)
***************************************************/
static inline void
yuv2rgb(ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
{
int i_Y = p_yuv->s.y - 16;
int i_Cb = p_yuv->s.v - 128;
int i_Cr = p_yuv->s.u - 128;
int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
i_red = clip_8_bit( i_red );
i_green = clip_8_bit( i_green );
i_blue = clip_8_bit( i_blue );
*p_rgb_out++ = i_red;
*p_rgb_out++ = i_green;
*p_rgb_out++ = i_blue;
}
#ifdef HAVE_LIBPNG
#define BYTES_PER_RGB 3
......
......@@ -2,7 +2,7 @@
* cvd.c : CVD Subtitle decoder thread
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: cvd.c,v 1.10 2004/01/14 11:47:19 rocky Exp $
* $Id: cvd.c,v 1.11 2004/01/16 04:14:54 rocky Exp $
*
* Authors: Rocky Bernstein
* based on code from:
......@@ -51,10 +51,6 @@ vlc_module_begin();
N_("set debug mask for additional debugging."),
N_(DEBUG_LONGTEXT), VLC_TRUE );
add_string( "sub-aspect-ratio", "", NULL,
SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT,
VLC_TRUE );
add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT,
VLC_TRUE );
......
/*****************************************************************************
* Common pixel/chroma manipulation routines.
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
* $Id: pixmap.h,v 1.1 2004/01/16 04:14:54 rocky Exp $
*
* Author: Rocky Bernstein
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#ifndef PIXMAP_H
#define PIXMAP_H
/* Color and transparency of a pixel or a palette (CLUT) entry */
typedef union {
uint8_t plane[4];
struct {
uint8_t y;
uint8_t v;
uint8_t u;
uint8_t t;
} s;
} ogt_yuvt_t;
/* Force v in the range 0.255 */
static inline uint8_t
clip_8_bit(int v)
{
if (v<0) return 0;
if (v>255) return 255;
return (uint8_t) v;
}
static inline void
yuv2rgb(ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
{
int i_Y = p_yuv->s.y - 16;
int i_Cb = p_yuv->s.v - 128;
int i_Cr = p_yuv->s.u - 128;
int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
i_red = clip_8_bit( i_red );
i_green = clip_8_bit( i_green );
i_blue = clip_8_bit( i_blue );
*p_rgb_out++ = i_red;
*p_rgb_out++ = i_green;
*p_rgb_out++ = i_blue;
}
#endif /* PIXMAP_H */
......@@ -2,7 +2,7 @@
* render.c : Philips OGT (SVCD Subtitle) renderer
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
* $Id: render.c,v 1.13 2004/01/14 11:47:19 rocky Exp $
* $Id: render.c,v 1.14 2004/01/16 04:14:54 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
......@@ -32,6 +32,7 @@
#include <vlc/vout.h>
#include <vlc/decoder.h>
#include "pixmap.h"
#include "subtitle.h"
#include "render.h"
......@@ -76,7 +77,7 @@ void VCDSubRender( vout_thread_t *p_vout, picture_t *p_pic,
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
"chroma %x", p_vout->output.i_chroma );
switch( p_vout->output.i_chroma )
{
/* I420 target, no scaling */
......@@ -86,7 +87,7 @@ void VCDSubRender( vout_thread_t *p_vout, picture_t *p_pic,
RenderI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break;
/* RV16 target, scaling */
/* RGB 555 - scaled */
case VLC_FOURCC('R','V','1','6'):
RenderRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break;
......@@ -102,7 +103,7 @@ void VCDSubRender( vout_thread_t *p_vout, picture_t *p_pic,
RenderYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break;
/* Used in ASCII art */
/* Used in ASCII Art. */
case VLC_FOURCC('R','G','B','2'):
msg_Err( p_vout, "RGB2 not implemented yet" );
break;
......@@ -454,48 +455,54 @@ static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
}
}
/*
FIXME:
MOVE clip_8_bit and uuv2rgb TO A MORE GENERIC PLACE.
*/
/**
Convert a YUV pixel into a 16-bit RGB 5-5-5 pixel.
/* Force v in the range 0.255 */
static inline uint8_t
clip_5_bit(int v)
{
if (v<0) return 0;
if (v>31) return 31;
return (uint8_t) v;
}
A RGB 5-5-5 pixel looks like this:
RGB 5-5-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
p ? B4 B3 B2 B1 B0 R4 R3
q R2 R1 R0 G4 G3 G2 G1 G0
**/
static inline void
yuv2rgb16(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
yuv2rgb555(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
{
uint8_t rgb[3];
#define RED_PIXEL 0
#define GREEN_PIXEL 1
#define BLUE_PIXEL 2
yuv2rgb(p_yuv, rgb);
int i_Y = p_yuv->s.y - 16;
int i_Cb = p_yuv->s.v - 128;
int i_Cr = p_yuv->s.u - 128;
int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
i_red = clip_5_bit( i_red >> 3 );
i_green = clip_5_bit( i_green >> 3 );
i_blue = clip_5_bit( i_blue >> 3 );
/* Scale RGB from 8 bits down to 5. */
rgb[RED_PIXEL] >>= (8-5);
rgb[GREEN_PIXEL] >>= (8-5);
rgb[BLUE_PIXEL] >>= (8-5);
*p_rgb1 = ((i_blue & 0x1F) << 3) | (i_red & 0x18 >> 3);
*p_rgb2 = (i_red & 0x07 << 5) | (i_green & 0x1F);
*p_rgb1 = ( (rgb[BLUE_PIXEL] << 2)&0x7c ) | ( (rgb[RED_PIXEL]>>3) & 0x03 );
*p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
#if 0
printf("Y,Cb,Cr = (%d,%d,%d), r,g,b=(%d,%d,%d), rgb1: %x, rgb2 %x\n",
i_Y, i_Cb, i_Cr, i_red, i_green, i_blue, *p_rgb1, *p_rgb2);
printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
"rgb1: %02x, rgb2 %02x\n",
p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
*p_rgb1, *p_rgb2);
#endif
#undef RED_PIXEL
#undef GREEN_PIXEL
#undef BLUE_PIXEL
}
static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
#define BYTES_PER_PIXEL 2
static void
RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{
/* Common variables */
uint8_t *p_pixel_base;
......@@ -531,7 +538,8 @@ static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
/* Set where we will start blending subtitle from using
the picture coordinates subtitle offsets
*/
p_pixel_base = p_pic->p->p_pixels + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
p_pixel_base = p_pic->p->p_pixels
+ ( (p_spu->i_x * i_xscale) >> 6 ) * BYTES_PER_PIXEL
+ ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
i_x_start = p_sys->i_x_start;
......@@ -567,6 +575,12 @@ static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
for( ; i_x < p_spu->i_width; i_x++, p_source++ )
{
#if 0
uint8_t *p=(uint8_t *) p_source;
printf("+++ %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3]);
#endif
if( b_crop ) {
/* FIXME: y cropping should be dealt with outside of this
......@@ -600,19 +614,16 @@ static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
/* This is the location that's going to get changed.
*/
uint8_t *p_dest = p_pixel_base_y + 2 * i_x;
int i;
uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
uint8_t i_rgb1;
uint8_t i_rgb2;
yuv2rgb16(p_source, &i_rgb1, &i_rgb2);
for (i=0; i < i_xscale; i++) {
*p_dest++ = i_rgb1;
*p_dest++ = i_rgb2;
}
yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
*p_dest++ = i_rgb1;
*p_dest++ = i_rgb2;
break;
}
#if FINISHED
#ifdef TRANSPARENCY_FINISHED
default:
{
/* Blend in underlying pixel subtitle pixel. */
......@@ -622,19 +633,15 @@ static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
be completely transparent and is not correct, but
that's handled in a special case above anyway. */
uint8_t *p_pixel = p_pixel_base + 2*i_x;
uint16_t i_colprecomp = Y2RV16(p_source->plane[Y_PLANE])
* ( (uint16_t) (p_source->s.t+1) );
uint16_t i_destalpha = MAX_ALPHA - p_source->s.t;
*p_pixel++ = ( i_colprecomp +
(uint16_t) (*p_pixel) * i_destalpha )
>> ALPHA_SCALEDOWN;
*p_pixel = ( i_colprecomp +
(uint16_t) (*p_pixel) * i_destalpha )
>> ALPHA_SCALEDOWN;
uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
uint8_t i_destalpha = MAX_ALPHA - p_source->s.t;
uint8_t rgb[3];
yuv2rgb(p_source, rgb);
rv16_pack_blend(p_dest, rgb, dest_alpha, ALPHA_SCALEDOWN);
break;
}
#endif
#endif /*TRANSPARENCY_FINISHED*/
}
}
}
......@@ -680,24 +687,22 @@ static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
/* This is the location that's going to get changed.
*/
uint8_t *p_pixel_base_x = p_pixel_base + 2 * i_x;
uint8_t *p_pixel_base_x = p_pixel_base
+ i_x * BYTES_PER_PIXEL;
for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
{
/* This is the location that's going to get changed. */
uint8_t *p_dest = p_pixel_base_x + i_ytmp;
int i;
uint8_t i_rgb1;
uint8_t i_rgb2;
yuv2rgb16(p_source, &i_rgb1, &i_rgb2);
for (i=0; i < i_xscale; i++) {
*p_dest++ = i_rgb1;
*p_dest++ = i_rgb2;
}
yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
*p_dest++ = i_rgb1;
*p_dest++ = i_rgb2;
}
break;
}
#ifdef FINISHED
#ifdef TRANSPARENCY_FINISHED
default:
for( ; i_ytmp < i_ynext ; y_ytmp += p_pic->p->i_pitch )
{
......@@ -708,30 +713,248 @@ static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
be completely transparent and is not correct, but
that's handled in a special case above anyway. */
uint8_t *p_pixel = p_pixel_base + i_ytmp;
uint16_t i_colprecomp = Y2RV16(p_source->plane[Y_PLANE])
* ( (uint16_t) (p_source->s.t+1) );
uint16_t i_destalpha = MAX_ALPHA - p_source->s.t;
*p_pixel = ( i_colprecomp +
(uint16_t) (*p_pixel) * i_destalpha )
>> ALPHA_SCALEDOWN;
uint8_t *p_dest = p_pixel_base + i_ytmp;
uint8_t i_destalpha = MAX_ALPHA - p_source->s.t;
uint8_t rgb[3];
yuv2rgb(p_source, rgb);
rv16_pack_blend(p_dest, rgb, dest_alpha,ALPHA_SCALEDOWN);
}
break;
#endif
#endif /*TRANSPARENCY_FINISHED*/
}
}
}
}
}
#define Y2RV32(val) ((uint32_t) (0x11111111 * ( (uint32_t) (val) >> 4 )))
#undef BYTES_PER_PIXEL
#define BYTES_PER_PIXEL 4
static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
static void
RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{
/* Common variables */
msg_Err( p_vout, "RV32 not implemented yet" );
uint8_t *p_pixel_base;
ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
ogt_yuvt_t *p_source;
int i_x, i_y;
int i_y_src;
/* RGB-specific */
int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_ynext;
/* Crop-specific */
int i_x_start, i_y_start, i_x_end, i_y_end;
struct subpicture_sys_t *p_sys = p_spu->p_sys;
i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width;
i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height;
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
"spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
p_spu->i_width, p_spu->i_height,
p_vout->output.i_width, p_vout->output.i_height,
p_vout->render.i_width, p_vout->render.i_height,
i_xscale, i_yscale
);
i_width = p_spu->i_width * i_xscale;
i_height = p_spu->i_height * i_yscale;
/* Set where we will start blending subtitle from using
the picture coordinates subtitle offsets
*/
p_pixel_base = p_pic->p->p_pixels
+ ( (p_spu->i_x * i_xscale) >> 6 ) * BYTES_PER_PIXEL
+ ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
i_x_start = p_sys->i_x_start;
i_y_start = i_yscale * p_sys->i_y_start;
i_x_end = p_sys->i_x_end;
i_y_end = i_yscale * p_sys->i_y_end;
p_source = (ogt_yuvt_t *)p_sys->p_data;
/* Draw until we reach the bottom of the subtitle */
i_y = 0;
for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
i_y_src += p_spu->i_width )
{
uint8_t *p_pixel_base_y;
i_ytmp = i_y >> 6;
i_y += i_yscale;
p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
i_x = 0;
if ( b_crop ) {
if ( i_y > i_y_end ) break;
if (i_x_start) {
i_x = i_x_start;
p_source += i_x_start;
}
}
/* Check whether we need to draw one line or more than one */
if( i_ytmp + 1 >= ( i_y >> 6 ) )
{
/* Draw until we reach the end of the line */
for( ; i_x < p_spu->i_width; i_x++, p_source++ )
{
#if 0
uint8_t *p=(uint8_t *) p_source;
printf("+++ %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3]);
#endif
if( b_crop ) {
/* FIXME: y cropping should be dealt with outside of this
loop.*/
if ( i_y < i_y_start) continue;
if ( i_x > i_x_end )