Start work on CVD subtitles.
[vlc.git] / modules / codec / ogt / common.c
1 /*****************************************************************************
2  * Common SVCD and VCD subtitle routines.
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: common.c,v 1.1 2003/12/28 04:51:52 rocky Exp $
6  *
7  * Author: Rocky Bernstein
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 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33 #include <vlc/decoder.h>
34
35 #include "subtitle.h"
36 #include "common.h"
37
38 /*****************************************************************************
39  Free Resources associated with subtitle packet.
40  *****************************************************************************/
41 void VCDSubClose( vlc_object_t *p_this )
42 {
43     decoder_t     *p_dec = (decoder_t*)p_this;
44     decoder_sys_t *p_sys = p_dec->p_sys;
45
46     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
47
48     if( !p_sys->b_packetizer )
49     {
50         /* FIXME check if it's ok to not lock vout */
51         if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL )
52         {
53             subpicture_t *  p_subpic;
54             int             i_subpic;
55
56             for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
57             {
58                 p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
59
60                 if( p_subpic != NULL &&
61                     ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
62                       ( p_subpic->i_status == READY_SUBPICTURE ) ) )
63                 {
64                     vout_DestroySubPicture( p_sys->p_vout, p_subpic );
65                 }
66             }
67         }
68     }
69
70     if( p_sys->p_block )
71     {
72         block_ChainRelease( p_sys->p_block );
73     }
74
75     free( p_sys );
76 }
77
78 /*****************************************************************************
79
80 Initialize so the next packet will start off a new one.
81
82  *****************************************************************************/
83 void 
84 VCDSubInitSubtitleBlock( decoder_sys_t * p_sys ) 
85 {
86   p_sys->i_spu_size = 0;
87   p_sys->state      = SUBTITLE_BLOCK_EMPTY;
88   p_sys->i_spu      = 0;
89   p_sys->p_block    = NULL;
90   p_sys->subtitle_data_pos = 0;
91
92 }
93
94 void 
95 VCDSubInitSubtitleData(decoder_sys_t *p_sys)
96 {
97   if ( p_sys->subtitle_data ) {
98     if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
99       p_sys->subtitle_data = realloc(p_sys->subtitle_data,
100                                     p_sys->i_spu_size);
101       p_sys->subtitle_data_size = p_sys->i_spu_size;
102     }
103   } else {
104     p_sys->subtitle_data = malloc(p_sys->i_spu_size);
105     p_sys->subtitle_data_size = p_sys->i_spu_size;
106     /* FIXME: wrong place to get p_sys */
107     p_sys->i_image = 0;
108   }
109   p_sys->subtitle_data_pos = 0;
110 }
111
112 void 
113 VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
114 {
115   decoder_sys_t *p_sys = p_dec->p_sys;
116   int chunk_length = buf_len;
117
118   if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
119     msg_Warn( p_dec, "too much data (%d) expecting at most %u",
120               chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
121
122     chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
123   }
124
125   if ( chunk_length > 0 ) {
126     memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
127            buffer, chunk_length);
128     p_sys->subtitle_data_pos += chunk_length;
129     dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
130               chunk_length, p_sys->subtitle_data_pos);
131   }
132 }
133
134
135 /*****************************************************************************
136  * FindVout: Find a vout or wait for one to be created.
137  *****************************************************************************/
138 vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
139 {
140     vout_thread_t *p_vout = NULL;
141
142     /* Find an available video output */
143     do
144     {
145         if( p_dec->b_die || p_dec->b_error )
146         {
147             break;
148         }
149
150         p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
151         if( p_vout )
152         {
153             break;
154         }
155
156         msleep( VOUT_OUTMEM_SLEEP );
157     }
158     while( 1 );
159
160     return p_vout;
161 }
162
163
164 /* Scales down (reduces size) of p_dest in the x direction as 
165    determined through aspect ratio x_scale by y_scale. Scaling
166    is done in place. p_spu->i_width, is updated to new width
167
168    The aspect ratio is assumed to be between 1/2 and 1.
169 */
170 void
171 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu, 
172               unsigned int i_scale_x, unsigned int i_scale_y )
173 {
174   int i_row, i_col;
175
176   decoder_sys_t *p_sys = p_dec->p_sys;
177   uint8_t *p_src1 = p_spu->p_sys->p_data;
178   uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
179   uint8_t *p_dst  = p_src1;
180   unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
181   unsigned int used=0;  /* Number of bytes used up in p_src1. */
182
183   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) , 
184              "Old width: %d, new width: %d", 
185              p_spu->i_width, i_new_width);
186   
187   for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
188
189     if (used != 0) {
190       /* Discard the remaining piece of the column of the previous line*/
191       used=0;
192       p_src1 = p_src2;
193       p_src2 += PIXEL_SIZE;
194     }
195     
196     for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
197       unsigned int i;
198       unsigned int w1= i_scale_x - used;
199       unsigned int w2= i_scale_y - w1;
200
201       used = w2;
202       for (i = 0; i < PIXEL_SIZE; i++ ) {
203         *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
204         p_src1++; p_src2++; p_dst++;
205       }
206
207       if (i_scale_x == used) {
208         /* End of last pixel was end of p_src2. */
209         p_src1 = p_src2;
210         p_src2 += PIXEL_SIZE;
211         i_col++;
212         used = 0;
213       }
214     }
215   }
216   p_spu->i_width = i_new_width;
217
218   if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
219   { 
220     ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
221     for ( i_row=0; i_row < p_spu->i_height - 1; i_row++ ) {
222       for ( i_col=0; i_col < p_spu->i_width - 1; i_col++ ) {
223         printf("%1x", p_source->s.t);
224         p_source++;
225       }
226       printf("\n");
227     }
228   }
229
230 }
231
232 /*****************************************************************************
233  * DestroySPU: subpicture destructor
234  *****************************************************************************/
235 void VCDSubDestroySPU( subpicture_t *p_spu )
236 {
237     if( p_spu->p_sys->p_input )
238     {
239         /* Detach from our input thread */
240         vlc_object_release( p_spu->p_sys->p_input );
241     }
242
243     vlc_mutex_destroy( &p_spu->p_sys->lock );
244     free( p_spu->p_sys );
245 }
246
247 /*****************************************************************************
248   This callback is called from the input thread when we need cropping
249  *****************************************************************************/
250 int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
251                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
252 {
253     VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
254
255     return VLC_SUCCESS;
256 }
257
258
259 /*****************************************************************************
260   update subpicture settings
261  *****************************************************************************
262   This function is called from CropCallback and at initialization time, to
263   retrieve crop information from the input.
264  *****************************************************************************/
265 void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
266 {
267     vlc_value_t val;
268
269     p_spu->p_sys->b_crop = val.b_bool;
270     if( !p_spu->p_sys->b_crop )
271     {
272         return;
273     }
274
275     var_Get( p_object, "x-start", &val );
276     p_spu->p_sys->i_x_start = val.i_int;
277     var_Get( p_object, "y-start", &val );
278     p_spu->p_sys->i_y_start = val.i_int;
279     var_Get( p_object, "x-end", &val );
280     p_spu->p_sys->i_x_end = val.i_int;
281     var_Get( p_object, "y-end", &val );
282     p_spu->p_sys->i_y_end = val.i_int;
283
284 }
285