]> git.sesse.net Git - vlc/blob - modules/codec/avcodec/subtitle.c
udp: don't realloc in receiving, just set i_buffer
[vlc] / modules / codec / avcodec / subtitle.c
1 /*****************************************************************************
2  * subtitle.c: subtitle decoder using libavcodec library
3  *****************************************************************************
4  * Copyright (C) 2009 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 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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
31
32 #include <vlc_common.h>
33 #include <vlc_codec.h>
34 #include <vlc_avcodec.h>
35
36 #include <libavcodec/avcodec.h>
37 #include <libavutil/mem.h>
38
39 #include "avcodec.h"
40
41 struct decoder_sys_t {
42     AVCODEC_COMMON_MEMBERS
43 };
44
45 static subpicture_t *ConvertSubtitle(decoder_t *, AVSubtitle *, mtime_t pts,
46                                      AVCodecContext *avctx);
47 static subpicture_t *DecodeSubtitle(decoder_t *, block_t **);
48
49 /**
50  * Initialize subtitle decoder
51  */
52 int InitSubtitleDec(decoder_t *dec, AVCodecContext *context,
53                     const AVCodec *codec)
54 {
55     decoder_sys_t *sys;
56
57     /* */
58     switch (codec->id) {
59     case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
60     case AV_CODEC_ID_XSUB:
61     case AV_CODEC_ID_DVB_SUBTITLE:
62         break;
63     default:
64         msg_Warn(dec, "refusing to decode non validated subtitle codec");
65         return VLC_EGENERIC;
66     }
67
68     /* */
69     dec->p_sys = sys = malloc(sizeof(*sys));
70     if (!sys)
71         return VLC_ENOMEM;
72
73     sys->p_context = context;
74     sys->p_codec = codec;
75     sys->b_delayed_open = false;
76
77     /* */
78     context->extradata_size = 0;
79     context->extradata = NULL;
80
81     /* */
82     int ret;
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);
87     free(psz_opts);
88
89     vlc_avcodec_lock();
90     ret = avcodec_open2(context, codec, options ? &options : NULL);
91     vlc_avcodec_unlock();
92
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);
96     }
97     av_dict_free(&options);
98
99     if (ret < 0) {
100         msg_Err(dec, "cannot open codec (%s)", codec->name);
101         free(context->extradata);
102         free(sys);
103         return VLC_EGENERIC;
104     }
105
106     /* */
107     msg_Dbg(dec, "libavcodec codec (%s) started", codec->name);
108     dec->fmt_out.i_cat = SPU_ES;
109     dec->pf_decode_sub = DecodeSubtitle;
110
111     return VLC_SUCCESS;
112 }
113
114 /**
115  * Decode one subtitle
116  */
117 static subpicture_t *DecodeSubtitle(decoder_t *dec, block_t **block_ptr)
118 {
119     decoder_sys_t *sys = dec->p_sys;
120
121     if (!block_ptr || !*block_ptr)
122         return NULL;
123
124     block_t *block = *block_ptr;
125
126     if (block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
127         block_Release(block);
128         avcodec_flush_buffers(sys->p_context);
129         return NULL;
130     }
131
132     if (block->i_buffer <= 0) {
133         block_Release(block);
134         return NULL;
135     }
136
137     *block_ptr =
138     block      = block_Realloc(block,
139                                0,
140                                block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE);
141     if (!block)
142         return NULL;
143     block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
144     memset(&block->p_buffer[block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE);
145
146     /* */
147     AVSubtitle subtitle;
148     memset(&subtitle, 0, sizeof(subtitle));
149
150     AVPacket pkt;
151     av_init_packet(&pkt);
152     pkt.data = block->p_buffer;
153     pkt.size = block->i_buffer;
154
155     int has_subtitle = 0;
156     int used = avcodec_decode_subtitle2(sys->p_context,
157                                         &subtitle, &has_subtitle, &pkt);
158
159     if (used < 0) {
160         msg_Warn(dec, "cannot decode one subtitle (%zu bytes)",
161                  block->i_buffer);
162
163         block_Release(block);
164         return NULL;
165     } else if ((size_t)used > block->i_buffer) {
166         used = block->i_buffer;
167     }
168
169     block->i_buffer -= used;
170     block->p_buffer += used;
171
172     /* */
173     subpicture_t *spu = NULL;
174     if (has_subtitle)
175         spu = ConvertSubtitle(dec, &subtitle,
176                               block->i_pts > 0 ? block->i_pts : block->i_dts,
177                               sys->p_context);
178
179     /* */
180     if (!spu)
181         block_Release(block);
182     return spu;
183 }
184
185 /**
186  * Convert a RGBA libavcodec region to our format.
187  */
188 static subpicture_region_t *ConvertRegionRGBA(AVSubtitleRect *ffregion)
189 {
190     if (ffregion->w <= 0 || ffregion->h <= 0)
191         return NULL;
192
193     video_format_t fmt;
194     memset(&fmt, 0, sizeof(fmt));
195     fmt.i_chroma         = VLC_FOURCC('R','G','B','A');
196     fmt.i_width          =
197     fmt.i_visible_width  = ffregion->w;
198     fmt.i_height         =
199     fmt.i_visible_height = ffregion->h;
200     fmt.i_x_offset       = 0;
201     fmt.i_y_offset       = 0;
202
203     subpicture_region_t *region = subpicture_region_New(&fmt);
204     if (!region)
205         return NULL;
206
207     region->i_x = ffregion->x;
208     region->i_y = ffregion->y;
209     region->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
210
211     const plane_t *p = &region->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);
217
218             uint32_t color;
219             memcpy(&color, &ffregion->pict.data[1][4*index], 4);
220
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;
226         }
227     }
228
229     return region;
230 }
231
232 /**
233  * Convert a libavcodec subtitle to our format.
234  */
235 static subpicture_t *ConvertSubtitle(decoder_t *dec, AVSubtitle *ffsub, mtime_t pts,
236                                      AVCodecContext *avctx)
237 {
238     subpicture_t *spu = decoder_NewSubpicture(dec, NULL);
239     if (!spu)
240         return NULL;
241
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 ? */
248
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;
252     } else {
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;
257     }
258
259     subpicture_region_t **region_next = &spu->p_region;
260
261     for (unsigned i = 0; i < ffsub->num_rects; i++) {
262         AVSubtitleRect *rec = ffsub->rects[i];
263
264         //msg_Err(dec, "SUBS RECT[%d]: %dx%d @%dx%d",
265         //         i, rec->w, rec->h, rec->x, rec->y);
266
267         subpicture_region_t *region = NULL;
268         switch (ffsub->format) {
269         case 0:
270             region = ConvertRegionRGBA(rec);
271             break;
272         default:
273             msg_Warn(dec, "unsupported subtitle type");
274             region = NULL;
275             break;
276         }
277         if (region) {
278             *region_next = region;
279             region_next = &region->p_next;
280         }
281         /* Free AVSubtitleRect */
282         avpicture_free(&rec->pict);
283         av_free(rec);
284     }
285     av_free(ffsub->rects);
286
287     return spu;
288 }
289