common.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:16k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * Common SVCD and CVD subtitle routines.
  3.  *****************************************************************************
  4.  * Copyright (C) 2003, 2004 VideoLAN
  5.  * $Id: common.c 8709 2004-09-15 15:50:54Z gbazin $
  6.  *
  7.  * Author: Rocky Bernstein <rocky@panix.com>
  8.  *   based on code from:
  9.  *       Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
  10.  *       Samuel Hocevar <sam@zoy.org>
  11.  *       Laurent Aimar <fenrir@via.ecp.fr>
  12.  *
  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.
  17.  *
  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.
  22.  *
  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.  *****************************************************************************/
  27. /*****************************************************************************
  28.  * Preamble
  29.  *****************************************************************************/
  30. #include <vlc/vlc.h>
  31. #include <vlc/vout.h>
  32. #include <vlc/decoder.h>
  33. #include "subtitle.h"
  34. #include "pixmap.h"
  35. #include "common.h"
  36. #ifdef HAVE_LIBPNG
  37. #include "write_png.h"
  38. #endif
  39. /*****************************************************************************
  40.  Free Resources associated with subtitle packet.
  41.  *****************************************************************************/
  42. void VCDSubClose( vlc_object_t *p_this )
  43. {
  44.     decoder_t     *p_dec = (decoder_t*)p_this;
  45.     decoder_sys_t *p_sys = p_dec->p_sys;
  46.     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
  47.     if( !p_sys->b_packetizer && p_sys->p_vout )
  48.     {
  49.         /* FIXME check if it's ok to not lock vout */
  50.         spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_CLEAR,
  51.                      p_sys->i_subpic_channel );
  52.     }
  53.     if( p_sys->p_block )
  54.     {
  55.         block_ChainRelease( p_sys->p_block );
  56.     }
  57.     free(p_sys->subtitle_data);
  58.     free( p_sys );
  59. }
  60. /*****************************************************************************
  61. Initialize so the next packet will start off a new one.
  62.  *****************************************************************************/
  63. void 
  64. VCDSubInitSubtitleBlock( decoder_sys_t * p_sys ) 
  65. {
  66.   p_sys->i_spu_size = 0;
  67.   p_sys->state      = SUBTITLE_BLOCK_EMPTY;
  68.   p_sys->i_spu      = 0;
  69.   p_sys->p_block    = NULL;
  70.   p_sys->subtitle_data_pos = 0;
  71. }
  72. void 
  73. VCDSubInitSubtitleData(decoder_sys_t *p_sys)
  74. {
  75.   if ( p_sys->subtitle_data ) {
  76.     if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
  77.       p_sys->subtitle_data = realloc(p_sys->subtitle_data,
  78.     p_sys->i_spu_size);
  79.       p_sys->subtitle_data_size = p_sys->i_spu_size;
  80.     }
  81.   } else {
  82.     p_sys->subtitle_data = malloc(p_sys->i_spu_size);
  83.     p_sys->subtitle_data_size = p_sys->i_spu_size;
  84.     /* FIXME: wrong place to get p_sys */
  85.     p_sys->i_image = 0;
  86.   }
  87.   p_sys->subtitle_data_pos = 0;
  88. }
  89. void 
  90. VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
  91. {
  92.   decoder_sys_t *p_sys = p_dec->p_sys;
  93.   int chunk_length = buf_len;
  94.   if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
  95.     msg_Warn( p_dec, "too much data (%d) expecting at most %u",
  96.       chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
  97.     chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
  98.   }
  99.   if ( chunk_length > 0 ) {
  100. #if 0
  101.     int i;
  102.     int8_t *b=buffer;
  103.     for (i=0; i<chunk_length; i++)
  104.       printf ("%02x", b[i]);
  105.     printf("n");
  106. #endif
  107.     
  108.     memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
  109.    buffer, chunk_length);
  110.     p_sys->subtitle_data_pos += chunk_length;
  111.     dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
  112.       chunk_length, p_sys->subtitle_data_pos);
  113.   }
  114. }
  115. /*****************************************************************************
  116.  * FindVout: Find a vout or wait for one to be created.
  117.  *****************************************************************************/
  118. vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
  119. {
  120.     vout_thread_t *p_vout = NULL;
  121.     /* Find an available video output */
  122.     do
  123.     {
  124.         if( p_dec->b_die || p_dec->b_error )
  125.         {
  126.             break;
  127.         }
  128.         p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
  129.         if( p_vout )
  130.         {
  131.             break;
  132.         }
  133.         msleep( VOUT_OUTMEM_SLEEP );
  134.     }
  135.     while( 1 );
  136.     return p_vout;
  137. }
  138. /**
  139.    Remove color palette by expanding pixel entries to contain the
  140.    palette values. We work from the free space at the end to the
  141.    beginning so we can expand inline.
  142. */
  143. static void
  144. InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
  145. {
  146.   const unsigned int i_width  = p_sys->i_width;
  147.   const unsigned int i_height = p_sys->i_height;
  148.   int n = (i_height * i_width) - 1;
  149.   uint8_t    *p_from = p_dest;
  150.   ogt_yuvt_t *p_to   = (ogt_yuvt_t *) p_dest;
  151.   
  152.   for ( ; n >= 0 ; n-- ) {
  153.     p_to[n] = p_sys->p_palette[p_from[n]];
  154.     /*p_to[n] = p_sys->p_palette[p_from[3]];*/
  155.   }
  156. }
  157. /**
  158.    Check to see if user has overridden subtitle aspect ratio. 
  159.    0 is returned for no override which means just counteract any
  160.    scaling effects.
  161. */
  162. unsigned int 
  163. VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
  164. {
  165.   char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
  166.   /* Check whether the user tried to override aspect ratio */
  167.   if( !psz_string ) return 0;
  168.   {
  169.     unsigned int i_new_aspect = 0;
  170.     char *psz_parser = strchr( psz_string, ':' );
  171.     
  172.     if( psz_parser )
  173.       {
  174. *psz_parser++ = '';
  175. i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
  176.   / atoi( psz_parser );
  177.       }
  178.     else
  179.       {
  180. i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
  181.   * atof( psz_string )
  182.   / p_vout->output.i_height;
  183.       }
  184.     
  185.     return i_new_aspect;
  186.   }
  187. }
  188. /**
  189.    Scales down (reduces size) of p_dest in the x direction as 
  190.    determined through aspect ratio x_scale by y_scale. Scaling
  191.    is done in place. p_spu->i_width, is updated to new width
  192.    The aspect ratio is assumed to be between 1/2 and 1.
  193.    Note: the scaling truncates the new width rather than rounds it.
  194.    Perhaps something one might want to address.
  195. */
  196. void
  197. VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu, 
  198.       unsigned int i_scale_x, unsigned int i_scale_y )
  199. {
  200.   int i_row, i_col;
  201.   decoder_sys_t *p_sys = p_dec->p_sys;
  202.   uint8_t *p_src1 = p_spu->p_sys->p_data;
  203.   uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
  204.   uint8_t *p_dst  = p_src1;
  205.   unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
  206.   unsigned int i_used=0;  /* Number of bytes used up in p_src1. */
  207.   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) , 
  208.      "aspect ratio %i:%i, Old width: %d, new width: %d", 
  209.      i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
  210.   if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
  211.     {
  212.       msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
  213.       return;
  214.     }
  215.   
  216.   for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
  217.     if (i_used != 0) {
  218.       /* Discard the remaining piece of the column of the previous line*/
  219.       i_used=0;
  220.       p_src1 = p_src2;
  221.       p_src2 += PIXEL_SIZE;
  222.     }
  223.     
  224.     for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
  225.       unsigned int i;
  226.       unsigned int w1= i_scale_x - i_used;
  227.       unsigned int w2;
  228.       
  229.       if ( i_scale_y - w1 <= i_scale_x ) {
  230. /* Average spans 2 pixels. */
  231. w2 = i_scale_y - w1;
  232. for (i = 0; i < PIXEL_SIZE; i++ ) {
  233.   *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
  234.   p_src1++; p_src2++; p_dst++;
  235. }
  236.       } else {
  237. /* Average spans 3 pixels. */
  238. unsigned int w0 = w1;
  239. unsigned int w1 = i_scale_x;
  240. uint8_t *p_src0 = p_src1;
  241. w2 = i_scale_y - w0 - w1;
  242. p_src1 = p_src2;
  243. p_src2 += PIXEL_SIZE;
  244. for (i = 0; i < PIXEL_SIZE; i++ ) {
  245.   *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) ) 
  246.      / i_scale_y;
  247.   p_src0++; p_src1++; p_src2++; p_dst++;
  248. }
  249. i_col++;
  250.       }
  251.       i_used = w2;
  252.       if (i_scale_x == i_used) {
  253. /* End of last pixel was end of p_src2. */
  254. p_src1 = p_src2;
  255. p_src2 += PIXEL_SIZE;
  256. i_col++;
  257. i_used = 0;
  258.       }
  259.     }
  260.   }
  261.   p_spu->i_width = i_new_width;
  262.   if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
  263.   { 
  264.     ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
  265.     for ( i_row=0; i_row < p_spu->i_height; i_row++ ) {
  266.       for ( i_col=0; i_col < p_spu->i_width; i_col++ ) {
  267. printf("%1x", p_source->s.t);
  268. p_source++;
  269.       }
  270.       printf("n");
  271.     }
  272.   }
  273. }
  274. /**
  275.    The video may be scaled. However subtitle bitmaps assume an 1:1
  276.    aspect ratio. So unless the user has specified otherwise, we
  277.    need to scale to compensate for or undo the effects of video
  278.    output scaling.
  279.    
  280.    Perhaps this should go in the Render routine? The advantage would
  281.    be that it will deal with a dynamically changing aspect ratio.
  282.    The downside is having to scale many times for each render call.
  283.    We also expand palette entries here, unless we are dealing with a 
  284.    palettized chroma (e.g. RGB2).
  285. */
  286. void 
  287. VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
  288. {
  289.   vlc_object_t * p_input = p_spu->p_sys->p_input;
  290.   vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT, 
  291.                                            FIND_CHILD );
  292.   int i_aspect_x, i_aspect_y;
  293.   uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
  294.   if (p_vout) {
  295.     /* Check for user-configuration override. */
  296.     unsigned int i_new_aspect;
  297.     
  298.     if ( p_vout->output.i_chroma == VLC_FOURCC('R','G','B','2') ) {
  299.       /* This is an unscaled palettized format. We don't allow 
  300.          user scaling here. And to make the render process faster,
  301.          we don't expand the palette entries into a color value.
  302.        */
  303.       return;
  304.     }
  305.         
  306.     InlinePalette( p_dest, p_dec->p_sys );
  307.     i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
  308.     if (i_new_aspect == VOUT_ASPECT_FACTOR) {
  309.       /* For scaling 1:1, nothing needs to be done. Note this means
  310.          subtitles will get scaled the same way the video does.
  311.       */
  312.       ;
  313.     } else {
  314.       if (0 == i_new_aspect) {
  315.         /* Counteract the effects of background video scaling when
  316.            there is scaling. That's why x and y are reversed from
  317.            the else branch in the call below.
  318.         */
  319.         switch( p_vout->output.i_chroma )
  320.           {
  321.             /* chromas in which scaling is done outside of our
  322.                blending routine, so we need to compensate for those
  323.                effects before blending gets called: */
  324.           case VLC_FOURCC('I','4','2','0'):
  325.           case VLC_FOURCC('I','Y','U','V'):
  326.           case VLC_FOURCC('Y','V','1','2'):
  327.           case VLC_FOURCC('Y','U','Y','2'):
  328.             break;
  329.             
  330.             /* chromas in which scaling is done in our blending 
  331.                routine and thus we don't do it here: */
  332.           case VLC_FOURCC('R','V','1','6'):
  333.           case VLC_FOURCC('R','V','2','4'):
  334.           case VLC_FOURCC('R','V','3','2'):
  335.           case VLC_FOURCC('R','G','B','2'):
  336.             return;
  337.             break;
  338.             
  339.           default:
  340.             msg_Err( p_vout, "unknown chroma %x", 
  341.                      p_vout->output.i_chroma );
  342.             return;
  343.             break;
  344.           }
  345.         /* We get here only for scaled chromas. */
  346.         vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
  347.                     VOUT_ASPECT_FACTOR, 0 );
  348.       } else {
  349.         /* User knows best? */
  350.         vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
  351.                     VOUT_ASPECT_FACTOR, 0 );
  352.       }
  353.       VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
  354.     }
  355.   }
  356. }
  357. /**
  358.  * DestroySPU: subpicture destructor
  359.  */
  360. void VCDSubDestroySPU( subpicture_t *p_spu )
  361. {
  362.     if( p_spu->p_sys->p_input )
  363.     {
  364.         /* Detach from our input thread */
  365.         vlc_object_release( p_spu->p_sys->p_input );
  366.     }
  367.     vlc_mutex_destroy( &p_spu->p_sys->lock );
  368.     free( p_spu->p_sys );
  369. }
  370. /*****************************************************************************
  371.   This callback is called from the input thread when we need cropping
  372.  *****************************************************************************/
  373. int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
  374.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  375. {
  376.     VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
  377.     return VLC_SUCCESS;
  378. }
  379. /*****************************************************************************
  380.   update subpicture settings
  381.  *****************************************************************************
  382.   This function is called from CropCallback and at initialization time, to
  383.   retrieve crop information from the input.
  384.  *****************************************************************************/
  385. void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
  386. {
  387.     vlc_value_t val;
  388.     p_spu->p_sys->b_crop = val.b_bool;
  389.     if( !p_spu->p_sys->b_crop )
  390.     {
  391.         return;
  392.     }
  393.     if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
  394.       p_spu->p_sys->i_x_start = val.i_int;
  395.     if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
  396.       p_spu->p_sys->i_y_start = val.i_int;
  397.     if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
  398.       p_spu->p_sys->i_x_end = val.i_int;
  399.     if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
  400.       p_spu->p_sys->i_y_end = val.i_int;
  401. }
  402. /* 
  403.    Dump an a subtitle image to standard output - for debugging.
  404.  */
  405. void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
  406. {
  407.   uint8_t *p = p_image;
  408.   unsigned int i_row;    /* scanline row number */
  409.   unsigned int i_column; /* scanline column number */
  410.   printf("-------------------------------------n++");
  411.   for ( i_row=0; i_row < i_height; i_row ++ ) {
  412.     for ( i_column=0; i_column<i_width; i_column++ ) {
  413.       printf("%1d", *p++ & 0x03);
  414.     }
  415.     printf("n++");
  416.   }
  417.   printf("n-------------------------------------n");
  418. }
  419. #ifdef HAVE_LIBPNG
  420. #define PALETTE_SIZE  4
  421. /* Note the below assumes the above is a power of 2 */
  422. #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
  423. /* 
  424.    Dump an a subtitle image to a Portable Network Graphics (PNG) file.
  425.    All we do here is convert YUV palette entries to RGB, expand
  426.    the image into a linear RGB pixel array, and call the routine
  427.    that does the PNG writing.
  428.  */
  429. void 
  430. VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
  431.        uint32_t i_height, uint32_t i_width, const char *filename,
  432.        png_text *text_ptr, int i_text_count )
  433. {
  434.   decoder_sys_t *p_sys = p_dec->p_sys;
  435.   uint8_t *p = p_image;
  436.   uint8_t *image_data = malloc(RGB_SIZE * i_height * i_width );
  437.   uint8_t *q = image_data;
  438.   unsigned int i_row;    /* scanline row number */
  439.   unsigned int i_column; /* scanline column number */
  440.   uint8_t rgb_palette[PALETTE_SIZE * RGB_SIZE];
  441.   int i;
  442.   dbg_print( (DECODE_DBG_CALL), "%s", filename);
  443.   
  444.   if (NULL == image_data) return;
  445.   /* Convert palette YUV into RGB. */
  446.   for (i=0; i<PALETTE_SIZE; i++) {
  447.     ogt_yuvt_t *p_yuv     = &(p_sys->p_palette[i]);
  448.     uint8_t   *p_rgb_out  = &(rgb_palette[i*RGB_SIZE]);
  449.     yuv2rgb( p_yuv, p_rgb_out );
  450.   }
  451.   
  452.   /* Convert palette entries into linear RGB array. */
  453.   for ( i_row=0; i_row < i_height; i_row ++ ) {
  454.     for ( i_column=0; i_column<i_width; i_column++ ) {
  455.       uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*RGB_SIZE ];
  456.       *q++ = p_rgb[0];
  457.       *q++ = p_rgb[1];
  458.       *q++ = p_rgb[2];
  459.       p++;
  460.     }
  461.   }
  462.   
  463.   write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
  464.   free(image_data);
  465. }
  466. #endif /*HAVE_LIBPNG*/
  467. /* 
  468.  * Local variables:
  469.  *  c-file-style: "gnu"
  470.  *  tab-width: 8
  471.  *  indent-tabs-mode: nil
  472.  * End:
  473.  */