]> git.sesse.net Git - vlc/blob - modules/codec/stl.c
MP4: fix a typo
[vlc] / modules / codec / stl.c
1 /*****************************************************************************
2  * stl.c: EBU STL decoder
3  *****************************************************************************
4  * Copyright (C) 2010 Laurent Aimar
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
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_codec.h>
35 #include <vlc_memory.h>
36 #include <vlc_charset.h>
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 static int  Open (vlc_object_t *);
42 static void Close(vlc_object_t *);
43
44 vlc_module_begin()
45     set_description(N_("EBU STL subtitles decoder"))
46     set_category(CAT_INPUT)
47     set_subcategory(SUBCAT_INPUT_SCODEC)
48     set_capability("decoder", 10)
49     set_callbacks(Open, Close)
50 vlc_module_end()
51
52 /*****************************************************************************
53  * Local definitions/prototypes
54  *****************************************************************************/
55 #define GSI_BLOCK_SIZE 1024
56
57 typedef enum {
58     CCT_ISO_6937_2 = 0x3030, CCT_BEGIN = CCT_ISO_6937_2,
59     CCT_ISO_8859_5 = 0x3031,
60     CCT_ISO_8859_6 = 0x3032,
61     CCT_ISO_8859_7 = 0x3033,
62     CCT_ISO_8859_8 = 0x3034, CCT_END = CCT_ISO_8859_8
63 } cct_number_value_t;
64
65 typedef struct {
66     cct_number_value_t value;
67     const char *str;
68 } cct_number_t;
69
70 struct decoder_sys_t {
71     cct_number_value_t cct;
72 };
73
74 static cct_number_t cct_nums[] = { {CCT_ISO_6937_2, "ISO_6937-2"},
75                                    {CCT_ISO_8859_5, "ISO_8859-5"},
76                                    {CCT_ISO_8859_6, "ISO_8859-6"},
77                                    {CCT_ISO_8859_7, "ISO_8859-7"},
78                                    {CCT_ISO_8859_8, "ISO_8859-8"} };
79
80
81 static char *ParseText(uint8_t *data, int size, const char *charset)
82 {
83     char *text = strdup("");
84     int  text_size = 0;
85
86     for (int i = 0; i < size; i++) {
87         uint8_t code = data[i];
88
89         if (code == 0x8f)
90             break;
91
92         char tmp[16] = "";
93         char *t = tmp;
94         if ((code >= 0x20 && code <= 0x7e) ||
95             (code >= 0xa0 && code <= 0xff) )
96             snprintf(tmp, sizeof(tmp), "%c", code);
97 #if 0
98         else if (code == 0x80)
99             snprintf(tmp, sizeof(tmp), "<i>");
100         else if (code == 0x81)
101             snprintf(tmp, sizeof(tmp), "</i>");
102         else if (code == 0x82)
103             snprintf(tmp, sizeof(tmp), "<u>");
104         else if (code == 0x83)
105             snprintf(tmp, sizeof(tmp), "</u>");
106         else if (code == 0x8a)
107             snprintf(tmp, sizeof(tmp), "\n");
108 #endif
109         else {
110             t = NULL;
111         }
112
113         if (!t)
114             continue;
115         size_t t_size = strlen(t);
116         text = realloc_or_free(text, t_size + text_size + 1);
117         if (!text)
118             continue;
119         memcpy(&text[text_size], t, t_size);
120         text_size += t_size;
121         text[text_size]   = '\0';
122     }
123     return FromCharset(charset, text, text_size);
124 }
125
126 static subpicture_t *Decode(decoder_t *dec, block_t **block)
127 {
128     if (block == NULL || *block == NULL)
129         return NULL;
130
131     subpicture_t *sub = NULL;
132
133     block_t *b = *block; *block = NULL;
134     if (b->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
135         goto exit;
136     if (b->i_buffer < 128)
137         goto exit;
138
139     int     payload_size = (b->i_buffer / 128) * 112;
140     uint8_t *payload = malloc(payload_size);
141     if (!payload)
142         goto exit;
143     for (int i = 0; i < b->i_buffer / 128; i++)
144         memcpy(&payload[112 * i], &b->p_buffer[128 * i + 16], 112);
145
146     sub = decoder_NewSubpicture(dec, NULL);
147     if (!sub) {
148         free(payload);
149         goto exit;
150     }
151     sub->i_start    = b->i_pts;
152     sub->i_stop     = b->i_pts + b->i_length;
153     sub->b_ephemer  = b->i_length == 0;
154     sub->b_absolute = false;
155     //sub->i_original_picture_width  = 0;
156     //sub->i_original_picture_height = 0;
157
158     video_format_t fmt;
159     video_format_Init(&fmt, VLC_CODEC_TEXT);
160     sub->p_region = subpicture_region_New(&fmt);
161     video_format_Clean(&fmt);
162
163     if (sub->p_region) {
164         sub->p_region->psz_text = ParseText(payload,
165                                             payload_size,
166                                             cct_nums[dec->p_sys->cct - CCT_BEGIN].str);
167         sub->p_region->psz_html = NULL;
168     }
169
170     free(payload);
171
172 exit:
173     block_Release(b);
174     return sub;
175 }
176
177 static int ExtractCCT(const decoder_t *dec, cct_number_value_t *cct_number)
178 {
179     uint8_t *header = dec->fmt_in.p_extra;
180     if (!header) {
181         msg_Err(dec, "NULL EBU header (GSI block)\n");
182         return VLC_EGENERIC;
183     }
184
185     if (GSI_BLOCK_SIZE != dec->fmt_in.i_extra) {
186         msg_Err(dec, "EBU header is not in expected size (%d)\n", dec->fmt_in.i_extra);
187         return VLC_EGENERIC;
188     }
189
190     int cct = (header[12] << 8) | header[13];
191     if (CCT_BEGIN > cct || CCT_END < cct) {
192         msg_Err(dec, "EBU header contains illegal CCT (0x%x)\n", cct);
193         return VLC_EGENERIC;
194     }
195
196     *cct_number = cct;
197
198     return VLC_SUCCESS;
199 }
200
201 static int Open(vlc_object_t *object)
202 {
203     decoder_t *dec = (decoder_t*)object;
204
205     if (dec->fmt_in.i_codec != VLC_CODEC_EBU_STL)
206         return VLC_EGENERIC;
207
208     cct_number_value_t cct;
209     int rc = ExtractCCT(dec, &cct);
210     if (VLC_SUCCESS != rc)
211         return rc;
212
213     msg_Dbg(dec, "CCT=0x%x", cct);
214
215     decoder_sys_t *sys = malloc(sizeof(*sys));
216     if (!sys)
217         return VLC_ENOMEM;
218
219     sys->cct = cct;
220
221     dec->p_sys = sys;
222     dec->pf_decode_sub = Decode;
223     dec->fmt_out.i_cat = SPU_ES;
224     dec->fmt_out.i_codec = 0;
225     return VLC_SUCCESS;
226 }
227
228 static void Close(vlc_object_t *object)
229 {
230     decoder_t *dec = (decoder_t*)object;
231     decoder_sys_t *sys = dec->p_sys;
232
233     free(sys);
234 }