LGPL
[vlc.git] / src / misc / subpicture.c
1 /*****************************************************************************
2  * subpicture.c: Subpicture functions
3  *****************************************************************************
4  * Copyright (C) 2010 Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_image.h>
35 #include <vlc_subpicture.h>
36 #include "subpicture.h"
37
38 struct subpicture_private_t
39 {
40     video_format_t src;
41     video_format_t dst;
42 };
43
44 subpicture_t *subpicture_New( const subpicture_updater_t *p_upd )
45 {
46     subpicture_t *p_subpic = calloc( 1, sizeof(*p_subpic) );
47     if( !p_subpic )
48         return NULL;
49
50     p_subpic->i_order    = 0;
51     p_subpic->b_absolute = true;
52     p_subpic->b_fade     = false;
53     p_subpic->b_subtitle = false;
54     p_subpic->i_alpha    = 0xFF;
55     p_subpic->p_region   = NULL;
56
57     if( p_upd )
58     {
59         subpicture_private_t *p_private = malloc( sizeof(*p_private) );
60         if( !p_private )
61         {
62             free( p_subpic );
63             return NULL;
64         }
65         video_format_Init( &p_private->src, 0 );
66         video_format_Init( &p_private->dst, 0 );
67
68         p_subpic->updater   = *p_upd;
69         p_subpic->p_private = p_private;
70     }
71     else
72     {
73         p_subpic->p_private = NULL;
74
75         p_subpic->updater.pf_validate = NULL;
76         p_subpic->updater.pf_update   = NULL;
77         p_subpic->updater.pf_destroy  = NULL;
78         p_subpic->updater.p_sys       = NULL;
79     }
80     return p_subpic;
81 }
82
83 void subpicture_Delete( subpicture_t *p_subpic )
84 {
85     subpicture_region_ChainDelete( p_subpic->p_region );
86     p_subpic->p_region = NULL;
87
88     if( p_subpic->updater.pf_destroy )
89         p_subpic->updater.pf_destroy( p_subpic );
90
91     free( p_subpic->p_private );
92     free( p_subpic );
93 }
94
95 subpicture_t *subpicture_NewFromPicture( vlc_object_t *p_obj,
96                                          picture_t *p_picture, vlc_fourcc_t i_chroma )
97 {
98     /* */
99     video_format_t fmt_in = p_picture->format;
100
101     /* */
102     video_format_t fmt_out;
103     fmt_out = fmt_in;
104     fmt_out.i_chroma = i_chroma;
105
106     /* */
107     image_handler_t *p_image = image_HandlerCreate( p_obj );
108     if( !p_image )
109         return NULL;
110
111     picture_t *p_pip = image_Convert( p_image, p_picture, &fmt_in, &fmt_out );
112
113     image_HandlerDelete( p_image );
114
115     if( !p_pip )
116         return NULL;
117
118     subpicture_t *p_subpic = subpicture_New( NULL );
119     if( !p_subpic )
120     {
121          picture_Release( p_pip );
122          return NULL;
123     }
124
125     p_subpic->i_original_picture_width  = fmt_out.i_width;
126     p_subpic->i_original_picture_height = fmt_out.i_height;
127
128     fmt_out.i_sar_num =
129     fmt_out.i_sar_den = 0;
130
131     p_subpic->p_region = subpicture_region_New( &fmt_out );
132     if( p_subpic->p_region )
133     {
134         picture_Release( p_subpic->p_region->p_picture );
135         p_subpic->p_region->p_picture = p_pip;
136     }
137     else
138     {
139         picture_Release( p_pip );
140     }
141     return p_subpic;
142 }
143
144 void subpicture_Update( subpicture_t *p_subpicture,
145                         const video_format_t *p_fmt_src,
146                         const video_format_t *p_fmt_dst,
147                         mtime_t i_ts )
148 {
149     subpicture_updater_t *p_upd = &p_subpicture->updater;
150     subpicture_private_t *p_private = p_subpicture->p_private;
151
152     if( !p_upd->pf_validate )
153         return;
154     if( !p_upd->pf_validate( p_subpicture,
155                           !video_format_IsSimilar( p_fmt_src,
156                                                    &p_private->src ), p_fmt_src,
157                           !video_format_IsSimilar( p_fmt_dst,
158                                                    &p_private->dst ), p_fmt_dst,
159                           i_ts ) )
160         return;
161
162     subpicture_region_ChainDelete( p_subpicture->p_region );
163     p_subpicture->p_region = NULL;
164
165     p_upd->pf_update( p_subpicture, p_fmt_src, p_fmt_dst, i_ts );
166
167     video_format_Clean( &p_private->src );
168     video_format_Clean( &p_private->dst );
169
170     video_format_Copy( &p_private->src, p_fmt_src );
171     video_format_Copy( &p_private->dst, p_fmt_dst );
172 }
173
174
175 subpicture_region_private_t *subpicture_region_private_New( video_format_t *p_fmt )
176 {
177     subpicture_region_private_t *p_private = malloc( sizeof(*p_private) );
178
179     if( !p_private )
180         return NULL;
181
182     p_private->fmt = *p_fmt;
183     if( p_fmt->p_palette )
184     {
185         p_private->fmt.p_palette = malloc( sizeof(*p_private->fmt.p_palette) );
186         if( p_private->fmt.p_palette )
187             *p_private->fmt.p_palette = *p_fmt->p_palette;
188     }
189     p_private->p_picture = NULL;
190
191     return p_private;
192 }
193
194 void subpicture_region_private_Delete( subpicture_region_private_t *p_private )
195 {
196     if( p_private->p_picture )
197         picture_Release( p_private->p_picture );
198     free( p_private->fmt.p_palette );
199     free( p_private );
200 }
201
202 subpicture_region_t *subpicture_region_New( const video_format_t *p_fmt )
203 {
204     subpicture_region_t *p_region = calloc( 1, sizeof(*p_region ) );
205     if( !p_region )
206         return NULL;
207
208     p_region->fmt = *p_fmt;
209     p_region->fmt.p_palette = NULL;
210     if( p_fmt->i_chroma == VLC_CODEC_YUVP )
211     {
212         p_region->fmt.p_palette = calloc( 1, sizeof(*p_region->fmt.p_palette) );
213         if( p_fmt->p_palette )
214             *p_region->fmt.p_palette = *p_fmt->p_palette;
215     }
216     p_region->i_alpha = 0xff;
217     p_region->p_next = NULL;
218     p_region->p_private = NULL;
219     p_region->psz_text = NULL;
220     p_region->p_style = NULL;
221     p_region->p_picture = NULL;
222
223     if( p_fmt->i_chroma == VLC_CODEC_TEXT )
224         return p_region;
225
226     p_region->p_picture = picture_NewFromFormat( p_fmt );
227     if( !p_region->p_picture )
228     {
229         free( p_region->fmt.p_palette );
230         free( p_region );
231         return NULL;
232     }
233
234     return p_region;
235 }
236
237 void subpicture_region_Delete( subpicture_region_t *p_region )
238 {
239     if( !p_region )
240         return;
241
242     if( p_region->p_private )
243         subpicture_region_private_Delete( p_region->p_private );
244
245     if( p_region->p_picture )
246         picture_Release( p_region->p_picture );
247
248     free( p_region->fmt.p_palette );
249
250     free( p_region->psz_text );
251     free( p_region->psz_html );
252     if( p_region->p_style )
253         text_style_Delete( p_region->p_style );
254     free( p_region );
255 }
256
257 void subpicture_region_ChainDelete( subpicture_region_t *p_head )
258 {
259     while( p_head )
260     {
261         subpicture_region_t *p_next = p_head->p_next;
262
263         subpicture_region_Delete( p_head );
264
265         p_head = p_next;
266     }
267 }
268