Libav
|
00001 /* 00002 * PGS subtitle decoder 00003 * Copyright (c) 2009 Stephen Backway 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00027 #include "avcodec.h" 00028 #include "dsputil.h" 00029 #include "colorspace.h" 00030 #include "bytestream.h" 00031 00032 //#define DEBUG_PACKET_CONTENTS 00033 00034 #define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) 00035 00036 enum SegmentType { 00037 PALETTE_SEGMENT = 0x14, 00038 PICTURE_SEGMENT = 0x15, 00039 PRESENTATION_SEGMENT = 0x16, 00040 WINDOW_SEGMENT = 0x17, 00041 DISPLAY_SEGMENT = 0x80, 00042 }; 00043 00044 typedef struct PGSSubPresentation { 00045 int x; 00046 int y; 00047 int video_w; 00048 int video_h; 00049 int id_number; 00050 } PGSSubPresentation; 00051 00052 typedef struct PGSSubPicture { 00053 int w; 00054 int h; 00055 uint8_t *rle; 00056 unsigned int rle_buffer_size, rle_data_len; 00057 } PGSSubPicture; 00058 00059 typedef struct PGSSubContext { 00060 PGSSubPresentation presentation; 00061 uint32_t clut[256]; 00062 PGSSubPicture picture; 00063 } PGSSubContext; 00064 00065 static av_cold int init_decoder(AVCodecContext *avctx) 00066 { 00067 avctx->pix_fmt = PIX_FMT_RGB32; 00068 00069 return 0; 00070 } 00071 00072 static av_cold int close_decoder(AVCodecContext *avctx) 00073 { 00074 PGSSubContext *ctx = avctx->priv_data; 00075 00076 av_freep(&ctx->picture.rle); 00077 ctx->picture.rle_buffer_size = 0; 00078 00079 return 0; 00080 } 00081 00092 static int decode_rle(AVCodecContext *avctx, AVSubtitle *sub, 00093 const uint8_t *buf, unsigned int buf_size) 00094 { 00095 const uint8_t *rle_bitmap_end; 00096 int pixel_count, line_count; 00097 00098 rle_bitmap_end = buf + buf_size; 00099 00100 sub->rects[0]->pict.data[0] = av_malloc(sub->rects[0]->w * sub->rects[0]->h); 00101 00102 if (!sub->rects[0]->pict.data[0]) 00103 return -1; 00104 00105 pixel_count = 0; 00106 line_count = 0; 00107 00108 while (buf < rle_bitmap_end && line_count < sub->rects[0]->h) { 00109 uint8_t flags, color; 00110 int run; 00111 00112 color = bytestream_get_byte(&buf); 00113 run = 1; 00114 00115 if (color == 0x00) { 00116 flags = bytestream_get_byte(&buf); 00117 run = flags & 0x3f; 00118 if (flags & 0x40) 00119 run = (run << 8) + bytestream_get_byte(&buf); 00120 color = flags & 0x80 ? bytestream_get_byte(&buf) : 0; 00121 } 00122 00123 if (run > 0 && pixel_count + run <= sub->rects[0]->w * sub->rects[0]->h) { 00124 memset(sub->rects[0]->pict.data[0] + pixel_count, color, run); 00125 pixel_count += run; 00126 } else if (!run) { 00127 /* 00128 * New Line. Check if correct pixels decoded, if not display warning 00129 * and adjust bitmap pointer to correct new line position. 00130 */ 00131 if (pixel_count % sub->rects[0]->w > 0) 00132 av_log(avctx, AV_LOG_ERROR, "Decoded %d pixels, when line should be %d pixels\n", 00133 pixel_count % sub->rects[0]->w, sub->rects[0]->w); 00134 line_count++; 00135 } 00136 } 00137 00138 dprintf(avctx, "Pixel Count = %d, Area = %d\n", pixel_count, sub->rects[0]->w * sub->rects[0]->h); 00139 00140 return 0; 00141 } 00142 00154 static int parse_picture_segment(AVCodecContext *avctx, 00155 const uint8_t *buf, int buf_size) 00156 { 00157 PGSSubContext *ctx = avctx->priv_data; 00158 00159 uint8_t sequence_desc; 00160 unsigned int rle_bitmap_len, width, height; 00161 00162 /* skip 3 unknown bytes: Object ID (2 bytes), Version Number */ 00163 buf += 3; 00164 00165 /* Read the Sequence Description to determine if start of RLE data or appended to previous RLE */ 00166 sequence_desc = bytestream_get_byte(&buf); 00167 00168 if (!(sequence_desc & 0x80)) { 00169 av_log(avctx, AV_LOG_ERROR, "Decoder does not support object data over multiple packets.\n"); 00170 return -1; 00171 } 00172 00173 /* Decode rle bitmap length */ 00174 rle_bitmap_len = bytestream_get_be24(&buf); 00175 00176 /* Check to ensure we have enough data for rle_bitmap_length if just a single packet */ 00177 if (rle_bitmap_len > buf_size - 7) { 00178 av_log(avctx, AV_LOG_ERROR, "Not enough RLE data for specified length of %d.\n", rle_bitmap_len); 00179 return -1; 00180 } 00181 00182 ctx->picture.rle_data_len = rle_bitmap_len; 00183 00184 /* Get bitmap dimensions from data */ 00185 width = bytestream_get_be16(&buf); 00186 height = bytestream_get_be16(&buf); 00187 00188 /* Make sure the bitmap is not too large */ 00189 if (ctx->presentation.video_w < width || ctx->presentation.video_h < height) { 00190 av_log(avctx, AV_LOG_ERROR, "Bitmap dimensions larger then video.\n"); 00191 return -1; 00192 } 00193 00194 ctx->picture.w = width; 00195 ctx->picture.h = height; 00196 00197 av_fast_malloc(&ctx->picture.rle, &ctx->picture.rle_buffer_size, rle_bitmap_len); 00198 00199 if (!ctx->picture.rle) 00200 return -1; 00201 00202 memcpy(ctx->picture.rle, buf, rle_bitmap_len); 00203 00204 return 0; 00205 } 00206 00217 static void parse_palette_segment(AVCodecContext *avctx, 00218 const uint8_t *buf, int buf_size) 00219 { 00220 PGSSubContext *ctx = avctx->priv_data; 00221 00222 const uint8_t *buf_end = buf + buf_size; 00223 const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; 00224 int color_id; 00225 int y, cb, cr, alpha; 00226 int r, g, b, r_add, g_add, b_add; 00227 00228 /* Skip two null bytes */ 00229 buf += 2; 00230 00231 while (buf < buf_end) { 00232 color_id = bytestream_get_byte(&buf); 00233 y = bytestream_get_byte(&buf); 00234 cb = bytestream_get_byte(&buf); 00235 cr = bytestream_get_byte(&buf); 00236 alpha = bytestream_get_byte(&buf); 00237 00238 YUV_TO_RGB1(cb, cr); 00239 YUV_TO_RGB2(r, g, b, y); 00240 00241 dprintf(avctx, "Color %d := (%d,%d,%d,%d)\n", color_id, r, g, b, alpha); 00242 00243 /* Store color in palette */ 00244 ctx->clut[color_id] = RGBA(r,g,b,alpha); 00245 } 00246 } 00247 00261 static void parse_presentation_segment(AVCodecContext *avctx, 00262 const uint8_t *buf, int buf_size) 00263 { 00264 PGSSubContext *ctx = avctx->priv_data; 00265 00266 int x, y; 00267 uint8_t block; 00268 00269 ctx->presentation.video_w = bytestream_get_be16(&buf); 00270 ctx->presentation.video_h = bytestream_get_be16(&buf); 00271 00272 dprintf(avctx, "Video Dimensions %dx%d\n", 00273 ctx->presentation.video_w, ctx->presentation.video_h); 00274 00275 /* Skip 1 bytes of unknown, frame rate? */ 00276 buf++; 00277 00278 ctx->presentation.id_number = bytestream_get_be16(&buf); 00279 00280 /* Next byte is the state. */ 00281 block = bytestream_get_byte(&buf);; 00282 if (block == 0x80) { 00283 /* 00284 * Skip 7 bytes of unknown: 00285 * palette_update_flag (0x80), 00286 * palette_id_to_use, 00287 * Object Number (if > 0 determines if more data to process), 00288 * object_id_ref (2 bytes), 00289 * window_id_ref, 00290 * composition_flag (0x80 - object cropped, 0x40 - object forced) 00291 */ 00292 buf += 7; 00293 00294 x = bytestream_get_be16(&buf); 00295 y = bytestream_get_be16(&buf); 00296 00297 /* TODO If cropping, cropping_x, cropping_y, cropping_width, cropping_height (all 2 bytes).*/ 00298 00299 dprintf(avctx, "Subtitle Placement x=%d, y=%d\n", x, y); 00300 00301 if (x > ctx->presentation.video_w || y > ctx->presentation.video_h) { 00302 av_log(avctx, AV_LOG_ERROR, "Subtitle out of video bounds. x = %d, y = %d, video width = %d, video height = %d.\n", 00303 x, y, ctx->presentation.video_w, ctx->presentation.video_h); 00304 x = 0; y = 0; 00305 } 00306 00307 /* Fill in dimensions */ 00308 ctx->presentation.x = x; 00309 ctx->presentation.y = y; 00310 } else if (block == 0x00) { 00311 /* TODO: Blank context as subtitle should not be displayed. 00312 * If the subtitle is blanked now the subtitle is not 00313 * on screen long enough to read, due to a delay in 00314 * initial display timing. 00315 */ 00316 } 00317 } 00318 00334 static int display_end_segment(AVCodecContext *avctx, void *data, 00335 const uint8_t *buf, int buf_size) 00336 { 00337 AVSubtitle *sub = data; 00338 PGSSubContext *ctx = avctx->priv_data; 00339 00340 /* 00341 * The end display time is a timeout value and is only reached 00342 * if the next subtitle is later then timeout or subtitle has 00343 * not been cleared by a subsequent empty display command. 00344 */ 00345 00346 memset(sub, 0, sizeof(*sub)); 00347 sub->start_display_time = 0; 00348 sub->end_display_time = 20000; 00349 sub->format = 0; 00350 00351 sub->rects = av_mallocz(sizeof(*sub->rects)); 00352 sub->rects[0] = av_mallocz(sizeof(*sub->rects[0])); 00353 sub->num_rects = 1; 00354 00355 sub->rects[0]->x = ctx->presentation.x; 00356 sub->rects[0]->y = ctx->presentation.y; 00357 sub->rects[0]->w = ctx->picture.w; 00358 sub->rects[0]->h = ctx->picture.h; 00359 sub->rects[0]->type = SUBTITLE_BITMAP; 00360 00361 /* Process bitmap */ 00362 sub->rects[0]->pict.linesize[0] = ctx->picture.w; 00363 00364 if (ctx->picture.rle) 00365 if(decode_rle(avctx, sub, ctx->picture.rle, ctx->picture.rle_data_len) < 0) 00366 return 0; 00367 00368 /* Allocate memory for colors */ 00369 sub->rects[0]->nb_colors = 256; 00370 sub->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE); 00371 00372 memcpy(sub->rects[0]->pict.data[1], ctx->clut, sub->rects[0]->nb_colors * sizeof(uint32_t)); 00373 00374 return 1; 00375 } 00376 00377 static int decode(AVCodecContext *avctx, void *data, int *data_size, 00378 AVPacket *avpkt) 00379 { 00380 const uint8_t *buf = avpkt->data; 00381 int buf_size = avpkt->size; 00382 00383 const uint8_t *buf_end; 00384 uint8_t segment_type; 00385 int segment_length; 00386 00387 #ifdef DEBUG_PACKET_CONTENTS 00388 int i; 00389 00390 av_log(avctx, AV_LOG_INFO, "PGS sub packet:\n"); 00391 00392 for (i = 0; i < buf_size; i++) { 00393 av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); 00394 if (i % 16 == 15) 00395 av_log(avctx, AV_LOG_INFO, "\n"); 00396 } 00397 00398 if (i & 15) 00399 av_log(avctx, AV_LOG_INFO, "\n"); 00400 #endif 00401 00402 *data_size = 0; 00403 00404 /* Ensure that we have received at a least a segment code and segment length */ 00405 if (buf_size < 3) 00406 return -1; 00407 00408 buf_end = buf + buf_size; 00409 00410 /* Step through buffer to identify segments */ 00411 while (buf < buf_end) { 00412 segment_type = bytestream_get_byte(&buf); 00413 segment_length = bytestream_get_be16(&buf); 00414 00415 dprintf(avctx, "Segment Length %d, Segment Type %x\n", segment_length, segment_type); 00416 00417 if (segment_type != DISPLAY_SEGMENT && segment_length > buf_end - buf) 00418 break; 00419 00420 switch (segment_type) { 00421 case PALETTE_SEGMENT: 00422 parse_palette_segment(avctx, buf, segment_length); 00423 break; 00424 case PICTURE_SEGMENT: 00425 parse_picture_segment(avctx, buf, segment_length); 00426 break; 00427 case PRESENTATION_SEGMENT: 00428 parse_presentation_segment(avctx, buf, segment_length); 00429 break; 00430 case WINDOW_SEGMENT: 00431 /* 00432 * Window Segment Structure (No new information provided): 00433 * 2 bytes: Unkown, 00434 * 2 bytes: X position of subtitle, 00435 * 2 bytes: Y position of subtitle, 00436 * 2 bytes: Width of subtitle, 00437 * 2 bytes: Height of subtitle. 00438 */ 00439 break; 00440 case DISPLAY_SEGMENT: 00441 *data_size = display_end_segment(avctx, data, buf, segment_length); 00442 break; 00443 default: 00444 av_log(avctx, AV_LOG_ERROR, "Unknown subtitle segment type 0x%x, length %d\n", 00445 segment_type, segment_length); 00446 break; 00447 } 00448 00449 buf += segment_length; 00450 } 00451 00452 return buf_size; 00453 } 00454 00455 AVCodec pgssub_decoder = { 00456 "pgssub", 00457 AVMEDIA_TYPE_SUBTITLE, 00458 CODEC_ID_HDMV_PGS_SUBTITLE, 00459 sizeof(PGSSubContext), 00460 init_decoder, 00461 NULL, 00462 close_decoder, 00463 decode, 00464 .long_name = NULL_IF_CONFIG_SMALL("HDMV Presentation Graphic Stream subtitles"), 00465 };