1 /*****************************************************************************
2 * subtitle.c: subtitle decoder using libavcodec library
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_codec.h>
34 #include <vlc_avcodec.h>
36 #include <libavcodec/avcodec.h>
37 #include <libavutil/mem.h>
41 struct decoder_sys_t {
42 AVCODEC_COMMON_MEMBERS
45 static subpicture_t *ConvertSubtitle(decoder_t *, AVSubtitle *, mtime_t pts,
46 AVCodecContext *avctx);
47 static subpicture_t *DecodeSubtitle(decoder_t *, block_t **);
50 * Initialize subtitle decoder
52 int InitSubtitleDec(decoder_t *dec, AVCodecContext *context,
59 case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
60 case AV_CODEC_ID_XSUB:
61 case AV_CODEC_ID_DVB_SUBTITLE:
64 msg_Warn(dec, "refusing to decode non validated subtitle codec");
69 dec->p_sys = sys = malloc(sizeof(*sys));
73 sys->p_context = context;
75 sys->b_delayed_open = false;
78 context->extradata_size = 0;
79 context->extradata = NULL;
83 char *psz_opts = var_InheritString(dec, "avcodec-options");
84 AVDictionary *options = NULL;
85 if (psz_opts && *psz_opts)
86 options = vlc_av_get_options(psz_opts);
90 ret = avcodec_open2(context, codec, options ? &options : NULL);
93 AVDictionaryEntry *t = NULL;
94 while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) {
95 msg_Err(dec, "Unknown option \"%s\"", t->key);
97 av_dict_free(&options);
100 msg_Err(dec, "cannot open codec (%s)", codec->name);
101 free(context->extradata);
107 msg_Dbg(dec, "libavcodec codec (%s) started", codec->name);
108 dec->fmt_out.i_cat = SPU_ES;
109 dec->pf_decode_sub = DecodeSubtitle;
115 * Decode one subtitle
117 static subpicture_t *DecodeSubtitle(decoder_t *dec, block_t **block_ptr)
119 decoder_sys_t *sys = dec->p_sys;
121 if (!block_ptr || !*block_ptr)
124 block_t *block = *block_ptr;
126 if (block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
127 block_Release(block);
128 avcodec_flush_buffers(sys->p_context);
132 if (block->i_buffer <= 0) {
133 block_Release(block);
138 block = block_Realloc(block,
140 block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE);
143 block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
144 memset(&block->p_buffer[block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE);
148 memset(&subtitle, 0, sizeof(subtitle));
151 av_init_packet(&pkt);
152 pkt.data = block->p_buffer;
153 pkt.size = block->i_buffer;
155 int has_subtitle = 0;
156 int used = avcodec_decode_subtitle2(sys->p_context,
157 &subtitle, &has_subtitle, &pkt);
160 msg_Warn(dec, "cannot decode one subtitle (%zu bytes)",
163 block_Release(block);
165 } else if ((size_t)used > block->i_buffer) {
166 used = block->i_buffer;
169 block->i_buffer -= used;
170 block->p_buffer += used;
173 subpicture_t *spu = NULL;
175 spu = ConvertSubtitle(dec, &subtitle,
176 block->i_pts > 0 ? block->i_pts : block->i_dts,
181 block_Release(block);
186 * Convert a RGBA libavcodec region to our format.
188 static subpicture_region_t *ConvertRegionRGBA(AVSubtitleRect *ffregion)
190 if (ffregion->w <= 0 || ffregion->h <= 0)
194 memset(&fmt, 0, sizeof(fmt));
195 fmt.i_chroma = VLC_FOURCC('R','G','B','A');
197 fmt.i_visible_width = ffregion->w;
199 fmt.i_visible_height = ffregion->h;
203 subpicture_region_t *region = subpicture_region_New(&fmt);
207 region->i_x = ffregion->x;
208 region->i_y = ffregion->y;
209 region->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
211 const plane_t *p = ®ion->p_picture->p[0];
212 for (int y = 0; y < ffregion->h; y++) {
213 for (int x = 0; x < ffregion->w; x++) {
214 /* I don't think don't have paletized RGB_A_ */
215 const uint8_t index = ffregion->pict.data[0][y * ffregion->w+x];
216 assert(index < ffregion->nb_colors);
219 memcpy(&color, &ffregion->pict.data[1][4*index], 4);
221 uint8_t *p_rgba = &p->p_pixels[y * p->i_pitch + x * p->i_pixel_pitch];
222 p_rgba[0] = (color >> 16) & 0xff;
223 p_rgba[1] = (color >> 8) & 0xff;
224 p_rgba[2] = (color >> 0) & 0xff;
225 p_rgba[3] = (color >> 24) & 0xff;
233 * Convert a libavcodec subtitle to our format.
235 static subpicture_t *ConvertSubtitle(decoder_t *dec, AVSubtitle *ffsub, mtime_t pts,
236 AVCodecContext *avctx)
238 subpicture_t *spu = decoder_NewSubpicture(dec, NULL);
242 //msg_Err(dec, "%lld %d %d",
243 // pts, ffsub->start_display_time, ffsub->end_display_time);
244 spu->i_start = pts + ffsub->start_display_time * INT64_C(1000);
245 spu->i_stop = pts + ffsub->end_display_time * INT64_C(1000);
246 spu->b_absolute = true; /* FIXME How to set it right ? */
247 spu->b_ephemer = true; /* FIXME How to set it right ? */
249 if (avctx->coded_width != 0 && avctx->coded_height != 0) {
250 spu->i_original_picture_width = avctx->coded_width;
251 spu->i_original_picture_height = avctx->coded_height;
253 spu->i_original_picture_width =
254 dec->fmt_in.subs.spu.i_original_frame_width;
255 spu->i_original_picture_height =
256 dec->fmt_in.subs.spu.i_original_frame_height;
259 subpicture_region_t **region_next = &spu->p_region;
261 for (unsigned i = 0; i < ffsub->num_rects; i++) {
262 AVSubtitleRect *rec = ffsub->rects[i];
264 //msg_Err(dec, "SUBS RECT[%d]: %dx%d @%dx%d",
265 // i, rec->w, rec->h, rec->x, rec->y);
267 subpicture_region_t *region = NULL;
268 switch (ffsub->format) {
270 region = ConvertRegionRGBA(rec);
273 msg_Warn(dec, "unsupported subtitle type");
278 *region_next = region;
279 region_next = ®ion->p_next;
281 /* Free AVSubtitleRect */
282 avpicture_free(&rec->pict);
285 av_free(ffsub->rects);