1/* 2 * DVB subtitle parser for FFmpeg 3 * Copyright (c) 2005 Ian Caulfield 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#include "avcodec.h" 22#include "dsputil.h" 23#include "get_bits.h" 24 25//#define DEBUG 26//#define DEBUG_PACKET_CONTENTS 27 28/* Parser (mostly) copied from dvdsub.c */ 29 30#define PARSE_BUF_SIZE (65536) 31 32 33/* parser definition */ 34typedef struct DVBSubParseContext { 35 uint8_t *packet_buf; 36 int packet_start; 37 int packet_index; 38 int in_packet; 39} DVBSubParseContext; 40 41static av_cold int dvbsub_parse_init(AVCodecParserContext *s) 42{ 43 DVBSubParseContext *pc = s->priv_data; 44 pc->packet_buf = av_malloc(PARSE_BUF_SIZE); 45 46 return 0; 47} 48 49static int dvbsub_parse(AVCodecParserContext *s, 50 AVCodecContext *avctx, 51 const uint8_t **poutbuf, int *poutbuf_size, 52 const uint8_t *buf, int buf_size) 53{ 54 DVBSubParseContext *pc = s->priv_data; 55 uint8_t *p, *p_end; 56 int len, buf_pos = 0; 57 58 dprintf(avctx, "DVB parse packet pts=%"PRIx64", lpts=%"PRIx64", cpts=%"PRIx64":\n", 59 s->pts, s->last_pts, s->cur_frame_pts[s->cur_frame_start_index]); 60 61#ifdef DEBUG_PACKET_CONTENTS 62 int i; 63 64 for (i=0; i < buf_size; i++) 65 { 66 av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); 67 if (i % 16 == 15) 68 av_log(avctx, AV_LOG_INFO, "\n"); 69 } 70 71 if (i % 16 != 0) 72 av_log(avctx, AV_LOG_INFO, "\n"); 73 74#endif 75 76 *poutbuf = NULL; 77 *poutbuf_size = 0; 78 79 s->fetch_timestamp = 1; 80 81 if (s->last_pts != s->pts && s->pts != AV_NOPTS_VALUE) /* Start of a new packet */ 82 { 83 if (pc->packet_index != pc->packet_start) 84 { 85 dprintf(avctx, "Discarding %d bytes\n", 86 pc->packet_index - pc->packet_start); 87 } 88 89 pc->packet_start = 0; 90 pc->packet_index = 0; 91 92 if (buf_size < 2 || buf[0] != 0x20 || buf[1] != 0x00) { 93 dprintf(avctx, "Bad packet header\n"); 94 return -1; 95 } 96 97 buf_pos = 2; 98 99 pc->in_packet = 1; 100 } else { 101 if (pc->packet_start != 0) 102 { 103 if (pc->packet_index != pc->packet_start) 104 { 105 memmove(pc->packet_buf, pc->packet_buf + pc->packet_start, 106 pc->packet_index - pc->packet_start); 107 108 pc->packet_index -= pc->packet_start; 109 pc->packet_start = 0; 110 } else { 111 pc->packet_start = 0; 112 pc->packet_index = 0; 113 } 114 } 115 } 116 117 if (buf_size - buf_pos + pc->packet_index > PARSE_BUF_SIZE) 118 return -1; 119 120/* if not currently in a packet, discard data */ 121 if (pc->in_packet == 0) 122 return buf_size; 123 124 memcpy(pc->packet_buf + pc->packet_index, buf + buf_pos, buf_size - buf_pos); 125 pc->packet_index += buf_size - buf_pos; 126 127 p = pc->packet_buf; 128 p_end = pc->packet_buf + pc->packet_index; 129 130 while (p < p_end) 131 { 132 if (*p == 0x0f) 133 { 134 if (p + 6 <= p_end) 135 { 136 len = AV_RB16(p + 4); 137 138 if (p + len + 6 <= p_end) 139 { 140 *poutbuf_size += len + 6; 141 142 p += len + 6; 143 } else 144 break; 145 } else 146 break; 147 } else if (*p == 0xff) { 148 if (p + 1 < p_end) 149 { 150 dprintf(avctx, "Junk at end of packet\n"); 151 } 152 pc->packet_index = p - pc->packet_buf; 153 pc->in_packet = 0; 154 break; 155 } else { 156 av_log(avctx, AV_LOG_ERROR, "Junk in packet\n"); 157 158 pc->packet_index = p - pc->packet_buf; 159 pc->in_packet = 0; 160 break; 161 } 162 } 163 164 if (*poutbuf_size > 0) 165 { 166 *poutbuf = pc->packet_buf; 167 pc->packet_start = *poutbuf_size; 168 } 169 170 if (s->pts == AV_NOPTS_VALUE) 171 s->pts = s->last_pts; 172 173 return buf_size; 174} 175 176static av_cold void dvbsub_parse_close(AVCodecParserContext *s) 177{ 178 DVBSubParseContext *pc = s->priv_data; 179 av_freep(&pc->packet_buf); 180} 181 182AVCodecParser dvbsub_parser = { 183 { CODEC_ID_DVB_SUBTITLE }, 184 sizeof(DVBSubParseContext), 185 dvbsub_parse_init, 186 dvbsub_parse, 187 dvbsub_parse_close, 188}; 189