yading@10: /* yading@10: * DVB subtitle parser for FFmpeg yading@10: * Copyright (c) 2005 Ian Caulfield yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: #include "avcodec.h" yading@10: #include "get_bits.h" yading@10: yading@10: /* Parser (mostly) copied from dvdsub.c */ yading@10: yading@10: #define PARSE_BUF_SIZE (65536) yading@10: yading@10: yading@10: /* parser definition */ yading@10: typedef struct DVBSubParseContext { yading@10: uint8_t *packet_buf; yading@10: int packet_start; yading@10: int packet_index; yading@10: int in_packet; yading@10: } DVBSubParseContext; yading@10: yading@10: static av_cold int dvbsub_parse_init(AVCodecParserContext *s) yading@10: { yading@10: DVBSubParseContext *pc = s->priv_data; yading@10: pc->packet_buf = av_malloc(PARSE_BUF_SIZE); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static int dvbsub_parse(AVCodecParserContext *s, yading@10: AVCodecContext *avctx, yading@10: const uint8_t **poutbuf, int *poutbuf_size, yading@10: const uint8_t *buf, int buf_size) yading@10: { yading@10: DVBSubParseContext *pc = s->priv_data; yading@10: uint8_t *p, *p_end; yading@10: int i, len, buf_pos = 0; yading@10: yading@10: av_dlog(avctx, "DVB parse packet pts=%"PRIx64", lpts=%"PRIx64", cpts=%"PRIx64":\n", yading@10: s->pts, s->last_pts, s->cur_frame_pts[s->cur_frame_start_index]); yading@10: yading@10: for (i=0; i < buf_size; i++) yading@10: { yading@10: av_dlog(avctx, "%02x ", buf[i]); yading@10: if (i % 16 == 15) yading@10: av_dlog(avctx, "\n"); yading@10: } yading@10: yading@10: if (i % 16 != 0) yading@10: av_dlog(avctx, "\n"); yading@10: yading@10: *poutbuf = NULL; yading@10: *poutbuf_size = 0; yading@10: yading@10: s->fetch_timestamp = 1; yading@10: yading@10: if (s->last_pts != s->pts && s->pts != AV_NOPTS_VALUE) /* Start of a new packet */ yading@10: { yading@10: if (pc->packet_index != pc->packet_start) yading@10: { yading@10: av_dlog(avctx, "Discarding %d bytes\n", yading@10: pc->packet_index - pc->packet_start); yading@10: } yading@10: yading@10: pc->packet_start = 0; yading@10: pc->packet_index = 0; yading@10: yading@10: if (buf_size < 2 || buf[0] != 0x20 || buf[1] != 0x00) { yading@10: av_dlog(avctx, "Bad packet header\n"); yading@10: return -1; yading@10: } yading@10: yading@10: buf_pos = 2; yading@10: yading@10: pc->in_packet = 1; yading@10: } else { yading@10: if (pc->packet_start != 0) yading@10: { yading@10: if (pc->packet_index != pc->packet_start) yading@10: { yading@10: memmove(pc->packet_buf, pc->packet_buf + pc->packet_start, yading@10: pc->packet_index - pc->packet_start); yading@10: yading@10: pc->packet_index -= pc->packet_start; yading@10: pc->packet_start = 0; yading@10: } else { yading@10: pc->packet_start = 0; yading@10: pc->packet_index = 0; yading@10: } yading@10: } yading@10: } yading@10: yading@10: if (buf_size - buf_pos + pc->packet_index > PARSE_BUF_SIZE) yading@10: return -1; yading@10: yading@10: /* if not currently in a packet, discard data */ yading@10: if (pc->in_packet == 0) yading@10: return buf_size; yading@10: yading@10: memcpy(pc->packet_buf + pc->packet_index, buf + buf_pos, buf_size - buf_pos); yading@10: pc->packet_index += buf_size - buf_pos; yading@10: yading@10: p = pc->packet_buf; yading@10: p_end = pc->packet_buf + pc->packet_index; yading@10: yading@10: while (p < p_end) yading@10: { yading@10: if (*p == 0x0f) yading@10: { yading@10: if (p + 6 <= p_end) yading@10: { yading@10: len = AV_RB16(p + 4); yading@10: yading@10: if (p + len + 6 <= p_end) yading@10: { yading@10: *poutbuf_size += len + 6; yading@10: yading@10: p += len + 6; yading@10: } else yading@10: break; yading@10: } else yading@10: break; yading@10: } else if (*p == 0xff) { yading@10: if (p + 1 < p_end) yading@10: { yading@10: av_dlog(avctx, "Junk at end of packet\n"); yading@10: } yading@10: pc->packet_index = p - pc->packet_buf; yading@10: pc->in_packet = 0; yading@10: break; yading@10: } else { yading@10: av_log(avctx, AV_LOG_ERROR, "Junk in packet\n"); yading@10: yading@10: pc->packet_index = p - pc->packet_buf; yading@10: pc->in_packet = 0; yading@10: break; yading@10: } yading@10: } yading@10: yading@10: if (*poutbuf_size > 0) yading@10: { yading@10: *poutbuf = pc->packet_buf; yading@10: pc->packet_start = *poutbuf_size; yading@10: } yading@10: yading@10: if (s->pts == AV_NOPTS_VALUE) yading@10: s->pts = s->last_pts; yading@10: yading@10: return buf_size; yading@10: } yading@10: yading@10: static av_cold void dvbsub_parse_close(AVCodecParserContext *s) yading@10: { yading@10: DVBSubParseContext *pc = s->priv_data; yading@10: av_freep(&pc->packet_buf); yading@10: } yading@10: yading@10: AVCodecParser ff_dvbsub_parser = { yading@10: .codec_ids = { AV_CODEC_ID_DVB_SUBTITLE }, yading@10: .priv_data_size = sizeof(DVBSubParseContext), yading@10: .parser_init = dvbsub_parse_init, yading@10: .parser_parse = dvbsub_parse, yading@10: .parser_close = dvbsub_parse_close, yading@10: };