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 "bitstream.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#ifdef DEBUG 59 av_log(avctx, AV_LOG_INFO, "DVB parse packet pts=%"PRIx64", lpts=%"PRIx64", cpts=%"PRIx64":\n", 60 s->pts, s->last_pts, s->cur_frame_pts[s->cur_frame_start_index]); 61#endif 62 63#ifdef DEBUG_PACKET_CONTENTS 64 int i; 65 66 for (i=0; i < buf_size; i++) 67 { 68 av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); 69 if (i % 16 == 15) 70 av_log(avctx, AV_LOG_INFO, "\n"); 71 } 72 73 if (i % 16 != 0) 74 av_log(avctx, AV_LOG_INFO, "\n"); 75 76#endif 77 78 *poutbuf = NULL; 79 *poutbuf_size = 0; 80 81 s->fetch_timestamp = 1; 82 83 if (s->last_pts != s->pts && s->pts != AV_NOPTS_VALUE) /* Start of a new packet */ 84 { 85 if (pc->packet_index != pc->packet_start) 86 { 87#ifdef DEBUG 88 av_log(avctx, AV_LOG_INFO, "Discarding %d bytes\n", 89 pc->packet_index - pc->packet_start); 90#endif 91 } 92 93 pc->packet_start = 0; 94 pc->packet_index = 0; 95 96 if (buf_size < 2 || buf[0] != 0x20 || buf[1] != 0x00) { 97#ifdef DEBUG 98 av_log(avctx, AV_LOG_INFO, "Bad packet header\n"); 99#endif 100 return -1; 101 } 102 103 buf_pos = 2; 104 105 pc->in_packet = 1; 106 } else { 107 if (pc->packet_start != 0) 108 { 109 if (pc->packet_index != pc->packet_start) 110 { 111 memmove(pc->packet_buf, pc->packet_buf + pc->packet_start, 112 pc->packet_index - pc->packet_start); 113 114 pc->packet_index -= pc->packet_start; 115 pc->packet_start = 0; 116 } else { 117 pc->packet_start = 0; 118 pc->packet_index = 0; 119 } 120 } 121 } 122 123 if (buf_size - buf_pos + pc->packet_index > PARSE_BUF_SIZE) 124 return -1; 125 126/* if not currently in a packet, discard data */ 127 if (pc->in_packet == 0) 128 return buf_size; 129 130 memcpy(pc->packet_buf + pc->packet_index, buf + buf_pos, buf_size - buf_pos); 131 pc->packet_index += buf_size - buf_pos; 132 133 p = pc->packet_buf; 134 p_end = pc->packet_buf + pc->packet_index; 135 136 while (p < p_end) 137 { 138 if (*p == 0x0f) 139 { 140 if (p + 6 <= p_end) 141 { 142 len = AV_RB16(p + 4); 143 144 if (p + len + 6 <= p_end) 145 { 146 *poutbuf_size += len + 6; 147 148 p += len + 6; 149 } else 150 break; 151 } else 152 break; 153 } else if (*p == 0xff) { 154 if (p + 1 < p_end) 155 { 156#ifdef DEBUG 157 av_log(avctx, AV_LOG_INFO, "Junk at end of packet\n"); 158#endif 159 } 160 pc->packet_index = p - pc->packet_buf; 161 pc->in_packet = 0; 162 break; 163 } else { 164 av_log(avctx, AV_LOG_ERROR, "Junk in packet\n"); 165 166 pc->packet_index = p - pc->packet_buf; 167 pc->in_packet = 0; 168 break; 169 } 170 } 171 172 if (*poutbuf_size > 0) 173 { 174 *poutbuf = pc->packet_buf; 175 pc->packet_start = *poutbuf_size; 176 } 177 178 if (s->pts == AV_NOPTS_VALUE) 179 s->pts = s->last_pts; 180 181 return buf_size; 182} 183 184static av_cold void dvbsub_parse_close(AVCodecParserContext *s) 185{ 186 DVBSubParseContext *pc = s->priv_data; 187 av_freep(&pc->packet_buf); 188} 189 190AVCodecParser dvbsub_parser = { 191 { CODEC_ID_DVB_SUBTITLE }, 192 sizeof(DVBSubParseContext), 193 dvbsub_parse_init, 194 dvbsub_parse, 195 dvbsub_parse_close, 196}; 197