ffmpeg / libavcodec / pgssubdec.c @ d36beb3f
History | View | Annotate | Download (14.1 KB)
1 |
/*
|
---|---|
2 |
* PGS subtitle decoder
|
3 |
* Copyright (c) 2009 Stephen Backway
|
4 |
*
|
5 |
* This file is part of FFmpeg.
|
6 |
*
|
7 |
* FFmpeg is free software; you can redistribute it and/or
|
8 |
* modify it under the terms of the GNU Lesser General Public
|
9 |
* License as published by the Free Software Foundation; either
|
10 |
* version 2.1 of the License, or (at your option) any later version.
|
11 |
*
|
12 |
* FFmpeg is distributed in the hope that it will be useful,
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 |
* Lesser General Public License for more details.
|
16 |
*
|
17 |
* You should have received a copy of the GNU Lesser General Public
|
18 |
* License along with FFmpeg; if not, write to the Free Software
|
19 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
*/
|
21 |
|
22 |
/**
|
23 |
* @file
|
24 |
* PGS subtitle decoder
|
25 |
*/
|
26 |
|
27 |
#include "avcodec.h" |
28 |
#include "dsputil.h" |
29 |
#include "bytestream.h" |
30 |
#include "libavutil/colorspace.h" |
31 |
#include "libavcore/imgutils.h" |
32 |
|
33 |
//#define DEBUG_PACKET_CONTENTS
|
34 |
|
35 |
#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) |
36 |
|
37 |
enum SegmentType {
|
38 |
PALETTE_SEGMENT = 0x14,
|
39 |
PICTURE_SEGMENT = 0x15,
|
40 |
PRESENTATION_SEGMENT = 0x16,
|
41 |
WINDOW_SEGMENT = 0x17,
|
42 |
DISPLAY_SEGMENT = 0x80,
|
43 |
}; |
44 |
|
45 |
typedef struct PGSSubPresentation { |
46 |
int x;
|
47 |
int y;
|
48 |
int id_number;
|
49 |
int object_number;
|
50 |
} PGSSubPresentation; |
51 |
|
52 |
typedef struct PGSSubPicture { |
53 |
int w;
|
54 |
int h;
|
55 |
uint8_t *rle; |
56 |
unsigned int rle_buffer_size, rle_data_len; |
57 |
unsigned int rle_remaining_len; |
58 |
} PGSSubPicture; |
59 |
|
60 |
typedef struct PGSSubContext { |
61 |
PGSSubPresentation presentation; |
62 |
uint32_t clut[256];
|
63 |
PGSSubPicture picture; |
64 |
} PGSSubContext; |
65 |
|
66 |
static av_cold int init_decoder(AVCodecContext *avctx) |
67 |
{ |
68 |
avctx->pix_fmt = PIX_FMT_PAL8; |
69 |
|
70 |
return 0; |
71 |
} |
72 |
|
73 |
static av_cold int close_decoder(AVCodecContext *avctx) |
74 |
{ |
75 |
PGSSubContext *ctx = avctx->priv_data; |
76 |
|
77 |
av_freep(&ctx->picture.rle); |
78 |
ctx->picture.rle_buffer_size = 0;
|
79 |
|
80 |
return 0; |
81 |
} |
82 |
|
83 |
/**
|
84 |
* Decode the RLE data.
|
85 |
*
|
86 |
* The subtitle is stored as an Run Length Encoded image.
|
87 |
*
|
88 |
* @param avctx contains the current codec context
|
89 |
* @param sub pointer to the processed subtitle data
|
90 |
* @param buf pointer to the RLE data to process
|
91 |
* @param buf_size size of the RLE data to process
|
92 |
*/
|
93 |
static int decode_rle(AVCodecContext *avctx, AVSubtitle *sub, |
94 |
const uint8_t *buf, unsigned int buf_size) |
95 |
{ |
96 |
const uint8_t *rle_bitmap_end;
|
97 |
int pixel_count, line_count;
|
98 |
|
99 |
rle_bitmap_end = buf + buf_size; |
100 |
|
101 |
sub->rects[0]->pict.data[0] = av_malloc(sub->rects[0]->w * sub->rects[0]->h); |
102 |
|
103 |
if (!sub->rects[0]->pict.data[0]) |
104 |
return -1; |
105 |
|
106 |
pixel_count = 0;
|
107 |
line_count = 0;
|
108 |
|
109 |
while (buf < rle_bitmap_end && line_count < sub->rects[0]->h) { |
110 |
uint8_t flags, color; |
111 |
int run;
|
112 |
|
113 |
color = bytestream_get_byte(&buf); |
114 |
run = 1;
|
115 |
|
116 |
if (color == 0x00) { |
117 |
flags = bytestream_get_byte(&buf); |
118 |
run = flags & 0x3f;
|
119 |
if (flags & 0x40) |
120 |
run = (run << 8) + bytestream_get_byte(&buf);
|
121 |
color = flags & 0x80 ? bytestream_get_byte(&buf) : 0; |
122 |
} |
123 |
|
124 |
if (run > 0 && pixel_count + run <= sub->rects[0]->w * sub->rects[0]->h) { |
125 |
memset(sub->rects[0]->pict.data[0] + pixel_count, color, run); |
126 |
pixel_count += run; |
127 |
} else if (!run) { |
128 |
/*
|
129 |
* New Line. Check if correct pixels decoded, if not display warning
|
130 |
* and adjust bitmap pointer to correct new line position.
|
131 |
*/
|
132 |
if (pixel_count % sub->rects[0]->w > 0) |
133 |
av_log(avctx, AV_LOG_ERROR, "Decoded %d pixels, when line should be %d pixels\n",
|
134 |
pixel_count % sub->rects[0]->w, sub->rects[0]->w); |
135 |
line_count++; |
136 |
} |
137 |
} |
138 |
|
139 |
if (pixel_count < sub->rects[0]->w * sub->rects[0]->h) { |
140 |
av_log(avctx, AV_LOG_ERROR, "Insufficient RLE data for subtitle\n");
|
141 |
return -1; |
142 |
} |
143 |
|
144 |
dprintf(avctx, "Pixel Count = %d, Area = %d\n", pixel_count, sub->rects[0]->w * sub->rects[0]->h); |
145 |
|
146 |
return 0; |
147 |
} |
148 |
|
149 |
/**
|
150 |
* Parse the picture segment packet.
|
151 |
*
|
152 |
* The picture segment contains details on the sequence id,
|
153 |
* width, height and Run Length Encoded (RLE) bitmap data.
|
154 |
*
|
155 |
* @param avctx contains the current codec context
|
156 |
* @param buf pointer to the packet to process
|
157 |
* @param buf_size size of packet to process
|
158 |
* @todo TODO: Enable support for RLE data over multiple packets
|
159 |
*/
|
160 |
static int parse_picture_segment(AVCodecContext *avctx, |
161 |
const uint8_t *buf, int buf_size) |
162 |
{ |
163 |
PGSSubContext *ctx = avctx->priv_data; |
164 |
|
165 |
uint8_t sequence_desc; |
166 |
unsigned int rle_bitmap_len, width, height; |
167 |
|
168 |
if (buf_size <= 4) |
169 |
return -1; |
170 |
buf_size -= 4;
|
171 |
|
172 |
/* skip 3 unknown bytes: Object ID (2 bytes), Version Number */
|
173 |
buf += 3;
|
174 |
|
175 |
/* Read the Sequence Description to determine if start of RLE data or appended to previous RLE */
|
176 |
sequence_desc = bytestream_get_byte(&buf); |
177 |
|
178 |
if (!(sequence_desc & 0x80)) { |
179 |
/* Additional RLE data */
|
180 |
if (buf_size > ctx->picture.rle_remaining_len)
|
181 |
return -1; |
182 |
|
183 |
memcpy(ctx->picture.rle + ctx->picture.rle_data_len, buf, buf_size); |
184 |
ctx->picture.rle_data_len += buf_size; |
185 |
ctx->picture.rle_remaining_len -= buf_size; |
186 |
|
187 |
return 0; |
188 |
} |
189 |
|
190 |
if (buf_size <= 7) |
191 |
return -1; |
192 |
buf_size -= 7;
|
193 |
|
194 |
/* Decode rle bitmap length, stored size includes width/height data */
|
195 |
rle_bitmap_len = bytestream_get_be24(&buf) - 2*2; |
196 |
|
197 |
/* Get bitmap dimensions from data */
|
198 |
width = bytestream_get_be16(&buf); |
199 |
height = bytestream_get_be16(&buf); |
200 |
|
201 |
/* Make sure the bitmap is not too large */
|
202 |
if (avctx->width < width || avctx->height < height) {
|
203 |
av_log(avctx, AV_LOG_ERROR, "Bitmap dimensions larger then video.\n");
|
204 |
return -1; |
205 |
} |
206 |
|
207 |
ctx->picture.w = width; |
208 |
ctx->picture.h = height; |
209 |
|
210 |
av_fast_malloc(&ctx->picture.rle, &ctx->picture.rle_buffer_size, rle_bitmap_len); |
211 |
|
212 |
if (!ctx->picture.rle)
|
213 |
return -1; |
214 |
|
215 |
memcpy(ctx->picture.rle, buf, buf_size); |
216 |
ctx->picture.rle_data_len = buf_size; |
217 |
ctx->picture.rle_remaining_len = rle_bitmap_len - buf_size; |
218 |
|
219 |
return 0; |
220 |
} |
221 |
|
222 |
/**
|
223 |
* Parse the palette segment packet.
|
224 |
*
|
225 |
* The palette segment contains details of the palette,
|
226 |
* a maximum of 256 colors can be defined.
|
227 |
*
|
228 |
* @param avctx contains the current codec context
|
229 |
* @param buf pointer to the packet to process
|
230 |
* @param buf_size size of packet to process
|
231 |
*/
|
232 |
static void parse_palette_segment(AVCodecContext *avctx, |
233 |
const uint8_t *buf, int buf_size) |
234 |
{ |
235 |
PGSSubContext *ctx = avctx->priv_data; |
236 |
|
237 |
const uint8_t *buf_end = buf + buf_size;
|
238 |
const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
|
239 |
int color_id;
|
240 |
int y, cb, cr, alpha;
|
241 |
int r, g, b, r_add, g_add, b_add;
|
242 |
|
243 |
/* Skip two null bytes */
|
244 |
buf += 2;
|
245 |
|
246 |
while (buf < buf_end) {
|
247 |
color_id = bytestream_get_byte(&buf); |
248 |
y = bytestream_get_byte(&buf); |
249 |
cb = bytestream_get_byte(&buf); |
250 |
cr = bytestream_get_byte(&buf); |
251 |
alpha = bytestream_get_byte(&buf); |
252 |
|
253 |
YUV_TO_RGB1(cb, cr); |
254 |
YUV_TO_RGB2(r, g, b, y); |
255 |
|
256 |
dprintf(avctx, "Color %d := (%d,%d,%d,%d)\n", color_id, r, g, b, alpha);
|
257 |
|
258 |
/* Store color in palette */
|
259 |
ctx->clut[color_id] = RGBA(r,g,b,alpha); |
260 |
} |
261 |
} |
262 |
|
263 |
/**
|
264 |
* Parse the presentation segment packet.
|
265 |
*
|
266 |
* The presentation segment contains details on the video
|
267 |
* width, video height, x & y subtitle position.
|
268 |
*
|
269 |
* @param avctx contains the current codec context
|
270 |
* @param buf pointer to the packet to process
|
271 |
* @param buf_size size of packet to process
|
272 |
* @todo TODO: Implement cropping
|
273 |
* @todo TODO: Implement forcing of subtitles
|
274 |
*/
|
275 |
static void parse_presentation_segment(AVCodecContext *avctx, |
276 |
const uint8_t *buf, int buf_size) |
277 |
{ |
278 |
PGSSubContext *ctx = avctx->priv_data; |
279 |
|
280 |
int x, y;
|
281 |
|
282 |
int w = bytestream_get_be16(&buf);
|
283 |
int h = bytestream_get_be16(&buf);
|
284 |
|
285 |
dprintf(avctx, "Video Dimensions %dx%d\n",
|
286 |
w, h); |
287 |
if (av_image_check_size(w, h, 0, avctx) >= 0) |
288 |
avcodec_set_dimensions(avctx, w, h); |
289 |
|
290 |
/* Skip 1 bytes of unknown, frame rate? */
|
291 |
buf++; |
292 |
|
293 |
ctx->presentation.id_number = bytestream_get_be16(&buf); |
294 |
|
295 |
/*
|
296 |
* Skip 3 bytes of unknown:
|
297 |
* state
|
298 |
* palette_update_flag (0x80),
|
299 |
* palette_id_to_use,
|
300 |
*/
|
301 |
buf += 3;
|
302 |
|
303 |
ctx->presentation.object_number = bytestream_get_byte(&buf); |
304 |
if (!ctx->presentation.object_number)
|
305 |
return;
|
306 |
|
307 |
/*
|
308 |
* Skip 4 bytes of unknown:
|
309 |
* object_id_ref (2 bytes),
|
310 |
* window_id_ref,
|
311 |
* composition_flag (0x80 - object cropped, 0x40 - object forced)
|
312 |
*/
|
313 |
buf += 4;
|
314 |
|
315 |
x = bytestream_get_be16(&buf); |
316 |
y = bytestream_get_be16(&buf); |
317 |
|
318 |
/* TODO If cropping, cropping_x, cropping_y, cropping_width, cropping_height (all 2 bytes).*/
|
319 |
|
320 |
dprintf(avctx, "Subtitle Placement x=%d, y=%d\n", x, y);
|
321 |
|
322 |
if (x > avctx->width || y > avctx->height) {
|
323 |
av_log(avctx, AV_LOG_ERROR, "Subtitle out of video bounds. x = %d, y = %d, video width = %d, video height = %d.\n",
|
324 |
x, y, avctx->width, avctx->height); |
325 |
x = 0; y = 0; |
326 |
} |
327 |
|
328 |
/* Fill in dimensions */
|
329 |
ctx->presentation.x = x; |
330 |
ctx->presentation.y = y; |
331 |
} |
332 |
|
333 |
/**
|
334 |
* Parse the display segment packet.
|
335 |
*
|
336 |
* The display segment controls the updating of the display.
|
337 |
*
|
338 |
* @param avctx contains the current codec context
|
339 |
* @param data pointer to the data pertaining the subtitle to display
|
340 |
* @param buf pointer to the packet to process
|
341 |
* @param buf_size size of packet to process
|
342 |
* @todo TODO: Fix start time, relies on correct PTS, currently too late
|
343 |
*
|
344 |
* @todo TODO: Fix end time, normally cleared by a second display
|
345 |
* @todo segment, which is currently ignored as it clears
|
346 |
* @todo the subtitle too early.
|
347 |
*/
|
348 |
static int display_end_segment(AVCodecContext *avctx, void *data, |
349 |
const uint8_t *buf, int buf_size) |
350 |
{ |
351 |
AVSubtitle *sub = data; |
352 |
PGSSubContext *ctx = avctx->priv_data; |
353 |
|
354 |
/*
|
355 |
* The end display time is a timeout value and is only reached
|
356 |
* if the next subtitle is later then timeout or subtitle has
|
357 |
* not been cleared by a subsequent empty display command.
|
358 |
*/
|
359 |
|
360 |
memset(sub, 0, sizeof(*sub)); |
361 |
// Blank if last object_number was 0.
|
362 |
// Note that this may be wrong for more complex subtitles.
|
363 |
if (!ctx->presentation.object_number)
|
364 |
return 1; |
365 |
sub->start_display_time = 0;
|
366 |
sub->end_display_time = 20000;
|
367 |
sub->format = 0;
|
368 |
|
369 |
sub->rects = av_mallocz(sizeof(*sub->rects));
|
370 |
sub->rects[0] = av_mallocz(sizeof(*sub->rects[0])); |
371 |
sub->num_rects = 1;
|
372 |
|
373 |
sub->rects[0]->x = ctx->presentation.x;
|
374 |
sub->rects[0]->y = ctx->presentation.y;
|
375 |
sub->rects[0]->w = ctx->picture.w;
|
376 |
sub->rects[0]->h = ctx->picture.h;
|
377 |
sub->rects[0]->type = SUBTITLE_BITMAP;
|
378 |
|
379 |
/* Process bitmap */
|
380 |
sub->rects[0]->pict.linesize[0] = ctx->picture.w; |
381 |
|
382 |
if (ctx->picture.rle) {
|
383 |
if (ctx->picture.rle_remaining_len)
|
384 |
av_log(avctx, AV_LOG_ERROR, "RLE data length %u is %u bytes shorter than expected\n",
|
385 |
ctx->picture.rle_data_len, ctx->picture.rle_remaining_len); |
386 |
if(decode_rle(avctx, sub, ctx->picture.rle, ctx->picture.rle_data_len) < 0) |
387 |
return 0; |
388 |
} |
389 |
/* Allocate memory for colors */
|
390 |
sub->rects[0]->nb_colors = 256; |
391 |
sub->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE); |
392 |
|
393 |
memcpy(sub->rects[0]->pict.data[1], ctx->clut, sub->rects[0]->nb_colors * sizeof(uint32_t)); |
394 |
|
395 |
return 1; |
396 |
} |
397 |
|
398 |
static int decode(AVCodecContext *avctx, void *data, int *data_size, |
399 |
AVPacket *avpkt) |
400 |
{ |
401 |
const uint8_t *buf = avpkt->data;
|
402 |
int buf_size = avpkt->size;
|
403 |
|
404 |
const uint8_t *buf_end;
|
405 |
uint8_t segment_type; |
406 |
int segment_length;
|
407 |
|
408 |
#ifdef DEBUG_PACKET_CONTENTS
|
409 |
int i;
|
410 |
|
411 |
av_log(avctx, AV_LOG_INFO, "PGS sub packet:\n");
|
412 |
|
413 |
for (i = 0; i < buf_size; i++) { |
414 |
av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]);
|
415 |
if (i % 16 == 15) |
416 |
av_log(avctx, AV_LOG_INFO, "\n");
|
417 |
} |
418 |
|
419 |
if (i & 15) |
420 |
av_log(avctx, AV_LOG_INFO, "\n");
|
421 |
#endif
|
422 |
|
423 |
*data_size = 0;
|
424 |
|
425 |
/* Ensure that we have received at a least a segment code and segment length */
|
426 |
if (buf_size < 3) |
427 |
return -1; |
428 |
|
429 |
buf_end = buf + buf_size; |
430 |
|
431 |
/* Step through buffer to identify segments */
|
432 |
while (buf < buf_end) {
|
433 |
segment_type = bytestream_get_byte(&buf); |
434 |
segment_length = bytestream_get_be16(&buf); |
435 |
|
436 |
dprintf(avctx, "Segment Length %d, Segment Type %x\n", segment_length, segment_type);
|
437 |
|
438 |
if (segment_type != DISPLAY_SEGMENT && segment_length > buf_end - buf)
|
439 |
break;
|
440 |
|
441 |
switch (segment_type) {
|
442 |
case PALETTE_SEGMENT:
|
443 |
parse_palette_segment(avctx, buf, segment_length); |
444 |
break;
|
445 |
case PICTURE_SEGMENT:
|
446 |
parse_picture_segment(avctx, buf, segment_length); |
447 |
break;
|
448 |
case PRESENTATION_SEGMENT:
|
449 |
parse_presentation_segment(avctx, buf, segment_length); |
450 |
break;
|
451 |
case WINDOW_SEGMENT:
|
452 |
/*
|
453 |
* Window Segment Structure (No new information provided):
|
454 |
* 2 bytes: Unkown,
|
455 |
* 2 bytes: X position of subtitle,
|
456 |
* 2 bytes: Y position of subtitle,
|
457 |
* 2 bytes: Width of subtitle,
|
458 |
* 2 bytes: Height of subtitle.
|
459 |
*/
|
460 |
break;
|
461 |
case DISPLAY_SEGMENT:
|
462 |
*data_size = display_end_segment(avctx, data, buf, segment_length); |
463 |
break;
|
464 |
default:
|
465 |
av_log(avctx, AV_LOG_ERROR, "Unknown subtitle segment type 0x%x, length %d\n",
|
466 |
segment_type, segment_length); |
467 |
break;
|
468 |
} |
469 |
|
470 |
buf += segment_length; |
471 |
} |
472 |
|
473 |
return buf_size;
|
474 |
} |
475 |
|
476 |
AVCodec ff_pgssub_decoder = { |
477 |
"pgssub",
|
478 |
AVMEDIA_TYPE_SUBTITLE, |
479 |
CODEC_ID_HDMV_PGS_SUBTITLE, |
480 |
sizeof(PGSSubContext),
|
481 |
init_decoder, |
482 |
NULL,
|
483 |
close_decoder, |
484 |
decode, |
485 |
.long_name = NULL_IF_CONFIG_SMALL("HDMV Presentation Graphic Stream subtitles"),
|
486 |
}; |