DecodeSubtitle: mark func parameters as unused
[vlc.git] / modules / codec / avcodec / subtitle.c
1 /*****************************************************************************
2  * subtitle.c: subtitle decoder using ffmpeg 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
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_codec.h>
34 #include <vlc_avcodec.h>
35 #include <vlc_osd.h>
36
37 /* ffmpeg header */
38 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
39 #   include <libavcodec/avcodec.h>
40 #   ifdef HAVE_AVCODEC_VAAPI
41 #       include <libavcodec/vaapi.h>
42 #   endif
43 #elif defined(HAVE_FFMPEG_AVCODEC_H)
44 #   include <ffmpeg/avcodec.h>
45 #else
46 #   include <avcodec.h>
47 #endif
48
49 #include "avcodec.h"
50
51 struct decoder_sys_t {
52     FFMPEG_COMMON_MEMBERS
53 };
54
55 static subpicture_t *ConvertSubtitle(decoder_t *, AVSubtitle *, mtime_t pts);
56
57 /**
58  * Initialize subtitle decoder
59  */
60 int InitSubtitleDec(decoder_t *dec, AVCodecContext *context,
61                     AVCodec *codec, int codec_id, const char *namecodec)
62 {
63     decoder_sys_t *sys;
64
65     /* */
66     dec->p_sys = sys = malloc(sizeof(*sys));
67     if (!sys)
68         return VLC_ENOMEM;
69
70     sys->p_context = context;
71     sys->p_codec = codec;
72     sys->i_codec_id = codec_id;
73     sys->psz_namecodec = namecodec;
74     sys->b_delayed_open = false;
75
76     /* */
77     context->extradata_size = 0;
78     context->extradata = NULL;
79
80     /* */
81     vlc_avcodec_lock();
82     if (avcodec_open(context, codec) < 0) {
83         vlc_avcodec_unlock();
84         msg_Err(dec, "cannot open codec (%s)", namecodec);
85         free(context->extradata);
86         free(sys);
87         return VLC_EGENERIC;
88     }
89     vlc_avcodec_unlock();
90
91     /* */
92     msg_Dbg(dec, "ffmpeg codec (%s) started", namecodec);
93     dec->fmt_out.i_cat = SPU_ES;
94
95     return VLC_SUCCESS;
96 }
97
98 /**
99  * Decode one subtitle
100  */
101 subpicture_t *DecodeSubtitle(decoder_t *dec, block_t **block_ptr)
102 {
103 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( 52, 25, 0 )
104     decoder_sys_t *sys = dec->p_sys;
105
106     if (!block_ptr || !*block_ptr)
107         return NULL;
108
109     block_t *block = *block_ptr;
110
111     if (block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
112         block_Release(block);
113         avcodec_flush_buffers(sys->p_context);
114         return NULL;
115     }
116
117     if (block->i_buffer <= 0) {
118         block_Release(block);
119         return NULL;
120     }
121
122     *block_ptr =
123     block      = block_Realloc(block,
124                                0,
125                                block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE);
126     if (!block)
127         return NULL;
128     block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
129     memset(&block->p_buffer[block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE);
130
131     /* */
132     AVSubtitle subtitle;
133     memset(&subtitle, 0, sizeof(subtitle));
134
135     AVPacket pkt;
136     av_init_packet(&pkt);
137     pkt.data = block->p_buffer;
138     pkt.size = block->i_buffer;
139
140     int has_subtitle = 0;
141     int used = avcodec_decode_subtitle2(sys->p_context,
142                                         &subtitle, &has_subtitle, &pkt);
143
144     if (used < 0) {
145         msg_Warn(dec, "cannot decode one subtitle (%zu bytes)",
146                  block->i_buffer);
147
148         block_Release(block);
149         return NULL;
150     } else if ((size_t)used > block->i_buffer) {
151         used = block->i_buffer;
152     }
153
154     block->i_buffer -= used;
155     block->p_buffer += used;
156
157     /* */
158     subpicture_t *spu = NULL;
159     if (has_subtitle)
160         spu = ConvertSubtitle(dec, &subtitle,
161                               block->i_pts > 0 ? block->i_pts : block->i_dts);
162
163     /* */
164     if (!spu)
165         block_Release(block);
166     return spu;
167 #else
168     VLC_UNUSED(dec);
169     VLC_UNUSED(block_ptr);
170     return NULL;
171 #endif
172 }
173
174 /**
175  * Clean up private data
176  */
177 void EndSubtitleDec(decoder_t *dec)
178 {
179     VLC_UNUSED(dec);
180 }
181
182 /**
183  * Convert a RGBA ffmpeg region to our format.
184  */
185 static subpicture_region_t *ConvertRegionRGBA(AVSubtitleRect *ffregion)
186 {
187     video_format_t fmt;
188
189     memset(&fmt, 0, sizeof(fmt));
190     fmt.i_chroma         = VLC_FOURCC('R','G','B','A');
191     fmt.i_aspect         = 0;
192     fmt.i_width          =
193     fmt.i_visible_width  = ffregion->w;
194     fmt.i_height         =
195     fmt.i_visible_height = ffregion->h;
196     fmt.i_x_offset       = 0;
197     fmt.i_y_offset       = 0;
198
199     subpicture_region_t *region = subpicture_region_New(&fmt);
200     if (!region)
201         return NULL;
202
203     region->i_x = ffregion->x;
204     region->i_y = ffregion->y;
205     region->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
206
207     const plane_t *p = &region->p_picture->p[0];
208     for (int y = 0; y < ffregion->h; y++) {
209         for (int x = 0; x < ffregion->w; x++) {
210             /* I don't think don't have paletized RGB_A_ */
211             const uint8_t index = ffregion->pict.data[0][y * ffregion->w+x];
212             assert(index < ffregion->nb_colors);
213
214             uint32_t color;
215             memcpy(&color, &ffregion->pict.data[1][4*index], 4);
216
217             uint8_t *p_rgba = &p->p_pixels[y * p->i_pitch + x * p->i_pixel_pitch];
218             p_rgba[0] = (color >> 16) & 0xff;
219             p_rgba[1] = (color >>  8) & 0xff;
220             p_rgba[2] = (color >>  0) & 0xff;
221             p_rgba[3] = (color >> 24) & 0xff;
222         }
223     }
224
225     return region;
226 }
227
228 /**
229  * Convert a ffmpeg subtitle to our format.
230  */
231 static subpicture_t *ConvertSubtitle(decoder_t *dec, AVSubtitle *ffsub, mtime_t pts)
232 {
233     subpicture_t *spu = decoder_NewSubpicture(dec);
234     if (!spu)
235         return NULL;
236
237     //msg_Err(dec, "%lld %d %d",
238     //        pts, ffsub->start_display_time, ffsub->end_display_time);
239     spu->i_start    = pts + ffsub->start_display_time * INT64_C(1000);
240     spu->i_stop     = pts + ffsub->end_display_time * INT64_C(1000);
241     spu->b_absolute = true; /* FIXME How to set it right ? */
242     spu->b_ephemer  = true; /* FIXME How to set it right ? */
243     spu->i_original_picture_width =
244         dec->fmt_in.subs.spu.i_original_frame_width;
245     spu->i_original_picture_height =
246         dec->fmt_in.subs.spu.i_original_frame_height;
247
248     subpicture_region_t **region_next = &spu->p_region;
249
250     for (unsigned i = 0; i < ffsub->num_rects; i++) {
251         AVSubtitleRect *rec = ffsub->rects[i];
252
253         msg_Err(dec, "SUBS RECT[%d]: %dx%d @%dx%d",
254                  i, rec->w, rec->h, rec->x, rec->y);
255
256         subpicture_region_t *region;
257         switch (ffsub->format) {
258         case 0:
259             region = ConvertRegionRGBA(rec);
260             break;
261         default:
262             msg_Warn(dec, "unsupported subtitle type");
263             region = NULL;
264             break;
265         }
266         if (region) {
267             *region_next = region;
268             region_next = &region->p_next;
269         }
270         /* Free AVSubtitleRect
271          * FIXME isn't there an avcodec function ? */
272         free(rec->pict.data[0]); /* Plane */
273         free(rec->pict.data[1]); /* Palette */
274         free(rec);
275     }
276     free(ffsub->rects);
277
278     return spu;
279 }
280