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