* ALL: separation of the SPU engine from the VOUT.
[vlc.git] / modules / codec / ogt / common.c
index 5c91507..e12aebf 100644 (file)
@@ -1,10 +1,10 @@
 /*****************************************************************************
- * Common SVCD and VCD subtitle routines.
+ * Common SVCD and CVD subtitle routines.
  *****************************************************************************
  * Copyright (C) 2003, 2004 VideoLAN
- * $Id: common.c,v 1.5 2004/01/11 01:54:20 rocky Exp $
+ * $Id$
  *
- * Author: Rocky Bernstein
+ * Author: Rocky Bernstein <rocky@panix.com>
  *   based on code from:
  *       Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
  *       Samuel Hocevar <sam@zoy.org>
@@ -33,6 +33,7 @@
 #include <vlc/decoder.h>
 
 #include "subtitle.h"
+#include "pixmap.h"
 #include "common.h"
 #ifdef HAVE_LIBPNG
 #include "write_png.h"
@@ -48,26 +49,11 @@ void VCDSubClose( vlc_object_t *p_this )
 
     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
 
-    if( !p_sys->b_packetizer )
+    if( !p_sys->b_packetizer && p_sys->p_vout )
     {
         /* FIXME check if it's ok to not lock vout */
-        if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL )
-        {
-            subpicture_t *  p_subpic;
-            int             i_subpic;
-
-            for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
-            {
-                p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
-
-                if( p_subpic != NULL &&
-                    ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
-                      ( p_subpic->i_status == READY_SUBPICTURE ) ) )
-                {
-                    vout_DestroySubPicture( p_sys->p_vout, p_subpic );
-                }
-            }
-        }
+        spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_CLEAR,
+                     p_sys->i_subpic_channel );
     }
 
     if( p_sys->p_block )
@@ -75,6 +61,7 @@ void VCDSubClose( vlc_object_t *p_this )
         block_ChainRelease( p_sys->p_block );
     }
 
+    free(p_sys->subtitle_data);
     free( p_sys );
 }
 
@@ -178,16 +165,18 @@ vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
    palette values. We work from the free space at the end to the
    beginning so we can expand inline.
 */
-void
-VCDInlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys,
-                  unsigned int i_height, unsigned int i_width ) 
+static void
+InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
 {
+  const unsigned int i_width  = p_sys->i_width;
+  const unsigned int i_height = p_sys->i_height;
   int n = (i_height * i_width) - 1;
   uint8_t    *p_from = p_dest;
   ogt_yuvt_t *p_to   = (ogt_yuvt_t *) p_dest;
   
   for ( ; n >= 0 ; n-- ) {
     p_to[n] = p_sys->p_palette[p_from[n]];
+    /*p_to[n] = p_sys->p_palette[p_from[3]];*/
   }
 }
 
@@ -199,7 +188,7 @@ VCDInlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys,
 unsigned int 
 VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
 {
-  char *psz_string = config_GetPsz( p_input, "sub-aspect-ratio" );
+  char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
 
   /* Check whether the user tried to override aspect ratio */
   if( !psz_string ) return 0;
@@ -325,6 +314,95 @@ VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
 
 }
 
+/**
+   The video may be scaled. However subtitle bitmaps assume an 1:1
+   aspect ratio. So unless the user has specified otherwise, we
+   need to scale to compensate for or undo the effects of video
+   output scaling.
+   
+   Perhaps this should go in the Render routine? The advantage would
+   be that it will deal with a dynamically changing aspect ratio.
+   The downside is having to scale many times for each render call.
+
+   We also expand palette entries here, unless we are dealing with a 
+   palettized chroma (e.g. RGB2).
+*/
+
+void 
+VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
+{
+  vlc_object_t * p_input = p_spu->p_sys->p_input;
+  vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT, 
+                                           FIND_CHILD );
+  int i_aspect_x, i_aspect_y;
+  uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
+
+  if (p_vout) {
+    /* Check for user-configuration override. */
+    unsigned int i_new_aspect;
+    
+    if ( p_vout->output.i_chroma == VLC_FOURCC('R','G','B','2') ) {
+      /* This is an unscaled palettized format. We don't allow 
+         user scaling here. And to make the render process faster,
+         we don't expand the palette entries into a color value.
+       */
+      return;
+    }
+        
+    InlinePalette( p_dest, p_dec->p_sys );
+    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 in which scaling is done outside of our
+               blending routine, so we need to compensate for those
+               effects before blending gets called: */
+          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 in which scaling is done in our blending 
+               routine and thus we don't do it here: */
+          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;
+          }
+        /* We get here only for scaled chromas. */
+        vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
+                    VOUT_ASPECT_FACTOR, 0 );
+      } else {
+        /* User knows best? */
+        vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
+                    VOUT_ASPECT_FACTOR, 0 );
+      }
+      VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
+    }
+  }
+}
+
+
 /**
  * DestroySPU: subpicture destructor
  */
@@ -398,64 +476,8 @@ 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
-    http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
-    Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
-    the following conversion.
-    R' = [ 1.1644         0    1.5960 ]   ([ Y' ]   [  16 ])
-    G' = [ 1.1644   -0.3918   -0.8130 ] * ([ Cb ] - [ 128 ])
-    B' = [ 1.1644    2.0172         0 ]   ([ Cr ]   [ 128 ])
-
-  See also vlc/modules/video_chroma/i420_rgb.h and
-  vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
-  more optimized for integer arithmetic. Would be nice to merge the
-  two routines.
-***************************************************/
-
-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
 #define PALETTE_SIZE  4
 /* Note the below assumes the above is a power of 2 */
 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
@@ -474,11 +496,11 @@ VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
 {
   decoder_sys_t *p_sys = p_dec->p_sys;
   uint8_t *p = p_image;
-  uint8_t *image_data = malloc(BYTES_PER_RGB * i_height * i_width );
+  uint8_t *image_data = malloc(RGB_SIZE * i_height * i_width );
   uint8_t *q = image_data;
   unsigned int i_row;    /* scanline row number */
   unsigned int i_column; /* scanline column number */
-  uint8_t rgb_palette[PALETTE_SIZE * BYTES_PER_RGB];
+  uint8_t rgb_palette[PALETTE_SIZE * RGB_SIZE];
   int i;
 
   dbg_print( (DECODE_DBG_CALL), "%s", filename);
@@ -488,14 +510,14 @@ VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
   /* Convert palette YUV into RGB. */
   for (i=0; i<PALETTE_SIZE; i++) {
     ogt_yuvt_t *p_yuv     = &(p_sys->p_palette[i]);
-    uint8_t   *p_rgb_out  = &(rgb_palette[i*BYTES_PER_RGB]);
+    uint8_t   *p_rgb_out  = &(rgb_palette[i*RGB_SIZE]);
     yuv2rgb( p_yuv, p_rgb_out );
   }
   
   /* Convert palette entries into linear RGB array. */
   for ( i_row=0; i_row < i_height; i_row ++ ) {
     for ( i_column=0; i_column<i_width; i_column++ ) {
-      uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*BYTES_PER_RGB ];
+      uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*RGB_SIZE ];
       *q++ = p_rgb[0];
       *q++ = p_rgb[1];
       *q++ = p_rgb[2];