blob: a7874cdae861bbdbda4d514636dab83217ade32a [file] [log] [blame]
Fabrice Bellardde6d9b62001-07-22 14:18:561/*
Vittorio Giovara41ed7ab2016-04-27 17:45:232 * MPEG-1/2 demuxer
Diego Biurrun406792e2009-01-19 15:46:403 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
Fabrice Bellardde6d9b62001-07-22 14:18:564 *
Diego Biurrunb78e7192006-10-07 15:30:465 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
Fabrice Bellard19720f12002-05-25 22:34:328 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
Diego Biurrunb78e7192006-10-07 15:30:4610 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellardde6d9b62001-07-22 14:18:5611 *
Diego Biurrunb78e7192006-10-07 15:30:4612 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellardde6d9b62001-07-22 14:18:5613 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Fabrice Bellard19720f12002-05-25 22:34:3214 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
Fabrice Bellardde6d9b62001-07-22 14:18:5616 *
Fabrice Bellard19720f12002-05-25 22:34:3217 * You should have received a copy of the GNU Lesser General Public
Diego Biurrunb78e7192006-10-07 15:30:4618 * License along with FFmpeg; if not, write to the Free Software
Diego Biurrun5509bff2006-01-12 22:43:2619 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellardde6d9b62001-07-22 14:18:5620 */
Fabrice Bellardde6d9b62001-07-22 14:18:5621
Andreas Rheinhardt1be3d8a2021-06-11 23:10:5822#include "libavutil/channel_layout.h"
Baptiste Coudurier2abe5a02007-06-21 09:39:2923#include "avformat.h"
Paul B Mahol7643e272018-03-30 16:44:3424#include "avio_internal.h"
Anton Khirnovf8194672011-02-06 14:38:5525#include "internal.h"
Baptiste Coudurier2abe5a02007-06-21 09:39:2926#include "mpeg.h"
27
Fabrice Bellardde6d9b62001-07-22 14:18:5628/*********************************************/
29/* demux code */
30
31#define MAX_SYNC_SIZE 100000
32
Michael Niedermayerfecebb72014-03-24 04:28:0733static int check_pes(const uint8_t *p, const uint8_t *end)
Tanja Batchelor5b8f0a52014-03-20 01:02:4234{
Michael Niedermayerc6dcd0d2007-11-03 13:48:3035 int pes1;
Tanja Batchelor5b8f0a52014-03-20 01:02:4236 int pes2 = (p[3] & 0xC0) == 0x80 &&
37 (p[4] & 0xC0) != 0x40 &&
38 ((p[4] & 0xC0) == 0x00 ||
39 (p[4] & 0xC0) >> 2 == (p[6] & 0xF0));
Michael Niedermayerc6dcd0d2007-11-03 13:48:3040
Tanja Batchelor5b8f0a52014-03-20 01:02:4241 for (p += 3; p < end && *p == 0xFF; p++) ;
42 if ((*p & 0xC0) == 0x40)
43 p += 2;
44
45 if ((*p & 0xF0) == 0x20)
46 pes1 = p[0] & p[2] & p[4] & 1;
47 else if ((*p & 0xF0) == 0x30)
48 pes1 = p[0] & p[2] & p[4] & p[5] & p[7] & p[9] & 1;
49 else
Michael Niedermayerc6dcd0d2007-11-03 13:48:3050 pes1 = *p == 0x0F;
51
Tanja Batchelor5b8f0a52014-03-20 01:02:4252 return pes1 || pes2;
Michael Niedermayerc6dcd0d2007-11-03 13:48:3053}
54
Tanja Batchelor5b8f0a52014-03-20 01:02:4255static int check_pack_header(const uint8_t *buf)
56{
Alex Conversefe21f782011-09-28 22:43:2457 return (buf[1] & 0xC0) == 0x40 || (buf[1] & 0xF0) == 0x20;
58}
59
Carl Eugen Hoyos4d8875e2019-03-21 00:18:3760static int mpegps_probe(const AVProbeData *p)
Fabrice Bellarddb7f1f92002-05-20 16:29:4061{
Tanja Batchelor5b8f0a52014-03-20 01:02:4262 uint32_t code = -1;
Michael Niedermayer95f97de2004-10-01 16:00:0063 int i;
Tanja Batchelor5b8f0a52014-03-20 01:02:4264 int sys = 0, pspack = 0, priv1 = 0, vid = 0;
65 int audio = 0, invalid = 0, score = 0;
Michael Niedermayere15b29b2014-12-06 21:33:0966 int endpes = 0;
Fabrice Bellarddb7f1f92002-05-20 16:29:4067
Tanja Batchelor5b8f0a52014-03-20 01:02:4268 for (i = 0; i < p->buf_size; i++) {
69 code = (code << 8) + p->buf[i];
Isaac Richardsec23a472003-07-10 09:04:0470 if ((code & 0xffffff00) == 0x100) {
Tanja Batchelor5b8f0a52014-03-20 01:02:4271 int len = p->buf[i + 1] << 8 | p->buf[i + 2];
Michael Niedermayere15b29b2014-12-06 21:33:0972 int pes = endpes <= i && check_pes(p->buf + i, p->buf + p->buf_size);
Tanja Batchelor5b8f0a52014-03-20 01:02:4273 int pack = check_pack_header(p->buf + i);
Michael Niedermayerc6dcd0d2007-11-03 13:48:3074
Tanja Batchelor5b8f0a52014-03-20 01:02:4275 if (code == SYSTEM_HEADER_START_CODE)
76 sys++;
77 else if (code == PACK_START_CODE && pack)
78 pspack++;
Michael Niedermayere15b29b2014-12-06 21:33:0979 else if ((code & 0xf0) == VIDEO_ID && pes) {
80 endpes = i + len;
Tanja Batchelor5b8f0a52014-03-20 01:02:4281 vid++;
Michael Niedermayere15b29b2014-12-06 21:33:0982 }
Janne Grunau612dc022010-05-24 12:32:1383 // skip pes payload to avoid start code emulation for private
84 // and audio streams
Michael Niedermayerfecebb72014-03-24 04:28:0785 else if ((code & 0xe0) == AUDIO_ID && pes) {audio++; i+=len;}
86 else if (code == PRIVATE_STREAM_1 && pes) {priv1++; i+=len;}
87 else if (code == 0x1fd && pes) vid++; //VC1
Michael Niedermayer7e1720d2007-12-03 09:37:0688
Michael Niedermayerfecebb72014-03-24 04:28:0789 else if ((code & 0xf0) == VIDEO_ID && !pes) invalid++;
90 else if ((code & 0xe0) == AUDIO_ID && !pes) invalid++;
91 else if (code == PRIVATE_STREAM_1 && !pes) invalid++;
Isaac Richardsec23a472003-07-10 09:04:0492 }
Fabrice Bellarddb7f1f92002-05-20 16:29:4093 }
Michael Niedermayera1c69e02006-08-19 08:39:0094
Michael Niedermayerfecebb72014-03-24 04:28:0795 if (vid + audio > invalid + 1) /* invalid VDR files nd short PES streams */
Diego Biurrune0f8be62013-03-25 15:12:5196 score = AVPROBE_SCORE_EXTENSION / 2;
Michael Niedermayera1c69e02006-08-19 08:39:0097
Michael Niedermayer74080de2014-12-06 21:38:3898// av_log(NULL, AV_LOG_ERROR, "vid:%d aud:%d sys:%d pspack:%d invalid:%d size:%d \n",
99// vid, audio, sys, pspack, invalid, p->buf_size);
100
Tanja Batchelor5b8f0a52014-03-20 01:02:42101 if (sys > invalid && sys * 9 <= pspack * 10)
Michael Niedermayerfecebb72014-03-24 04:28:07102 return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2
Michael Niedermayer20f7b4d2020-04-13 22:03:30103 : AVPROBE_SCORE_EXTENSION / 2 + (audio + vid + pspack > 1); // 1 more than mp3
Tanja Batchelor5b8f0a52014-03-20 01:02:42104 if (pspack > invalid && (priv1 + vid + audio) * 10 >= pspack * 9)
105 return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2
106 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg
107 if ((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys &&
108 !pspack && p->buf_size > 2048 && vid + audio > invalid) /* PES stream */
Michael Niedermayer4e5049a2016-11-15 19:06:42109 return (audio > 12 || vid > 6 + 2 * invalid) ? AVPROBE_SCORE_EXTENSION + 2
Michael Niedermayerfecebb72014-03-24 04:28:07110 : AVPROBE_SCORE_EXTENSION / 2;
Michael Niedermayera1c69e02006-08-19 08:39:00111
Tanja Batchelor5b8f0a52014-03-20 01:02:42112 // 02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1
113 // mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6
Michael Niedermayerfecebb72014-03-24 04:28:07114 // Have\ Yourself\ a\ Merry\ Little\ Christmas.mp3 0 0 0 5 0 1 len:21618
Michael Niedermayera1c69e02006-08-19 08:39:00115 return score;
Fabrice Bellarddb7f1f92002-05-20 16:29:40116}
117
Fabrice Bellardde6d9b62001-07-22 14:18:56118typedef struct MpegDemuxContext {
Måns Rullgård191e8ca2006-09-27 19:47:39119 int32_t header_state;
Måns Rullgårde3d1cd82005-03-28 17:33:21120 unsigned char psm_es_type[256];
Aurelien Jacobs8cd4ac32007-11-07 23:56:00121 int sofdec;
Richard9cde9f72013-03-17 09:21:12122 int dvd;
Carl Eugen Hoyos92a9a302013-03-27 00:48:07123 int imkh_cctv;
Paul B Mahol7643e272018-03-30 16:44:34124 int raw_ac3;
Fabrice Bellardde6d9b62001-07-22 14:18:56125} MpegDemuxContext;
126
Anton Khirnov6e9651d2012-01-12 12:20:36127static int mpegps_read_header(AVFormatContext *s)
Fabrice Bellard27f388a2003-11-10 18:47:52128{
129 MpegDemuxContext *m = s->priv_data;
Carl Eugen Hoyosa5c1c7a2017-02-19 15:15:34130 char buffer[7] = { 0 };
Arne de Bruijnb2f230e2011-09-17 12:59:00131 int64_t last_pos = avio_tell(s->pb);
Aurelien Jacobs8cd4ac32007-11-07 23:56:00132
Fabrice Bellard27f388a2003-11-10 18:47:52133 m->header_state = 0xff;
Tanja Batchelor5b8f0a52014-03-20 01:02:42134 s->ctx_flags |= AVFMTCTX_NOHEADER;
Fabrice Bellard27f388a2003-11-10 18:47:52135
Carl Eugen Hoyos92a9a302013-03-27 00:48:07136 avio_get_str(s->pb, 6, buffer, sizeof(buffer));
137 if (!memcmp("IMKH", buffer, 4)) {
138 m->imkh_cctv = 1;
139 } else if (!memcmp("Sofdec", buffer, 6)) {
140 m->sofdec = 1;
141 } else
Arne de Bruijnb2f230e2011-09-17 12:59:00142 avio_seek(s->pb, last_pos, SEEK_SET);
143
Fabrice Bellard27f388a2003-11-10 18:47:52144 /* no need to do more */
145 return 0;
146}
147
Anton Khirnov471fe572011-02-20 10:04:12148static int64_t get_pts(AVIOContext *pb, int c)
Fabrice Bellard27f388a2003-11-10 18:47:52149{
Ivo van Poorten66e9e302008-01-07 23:32:57150 uint8_t buf[5];
Michael Niedermayere8a88a12020-08-14 23:07:44151 int ret;
Fabrice Bellard27f388a2003-11-10 18:47:52152
Tanja Batchelor5b8f0a52014-03-20 01:02:42153 buf[0] = c < 0 ? avio_r8(pb) : c;
Michael Niedermayere8a88a12020-08-14 23:07:44154 ret = avio_read(pb, buf + 1, 4);
155 if (ret < 4)
156 return AV_NOPTS_VALUE;
Ivo van Poorten66e9e302008-01-07 23:32:57157
158 return ff_parse_pes_pts(buf);
Fabrice Bellard27f388a2003-11-10 18:47:52159}
160
Anton Khirnov471fe572011-02-20 10:04:12161static int find_next_start_code(AVIOContext *pb, int *size_ptr,
Måns Rullgård191e8ca2006-09-27 19:47:39162 int32_t *header_state)
Fabrice Bellardde6d9b62001-07-22 14:18:56163{
164 unsigned int state, v;
165 int val, n;
166
167 state = *header_state;
Tanja Batchelor5b8f0a52014-03-20 01:02:42168 n = *size_ptr;
Fabrice Bellardde6d9b62001-07-22 14:18:56169 while (n > 0) {
James Almerd34ec642014-08-07 20:12:41170 if (avio_feof(pb))
Fabrice Bellardde6d9b62001-07-22 14:18:56171 break;
Anton Khirnove63a3622011-02-21 15:43:01172 v = avio_r8(pb);
Fabrice Bellardde6d9b62001-07-22 14:18:56173 n--;
174 if (state == 0x000001) {
175 state = ((state << 8) | v) & 0xffffff;
Tanja Batchelor5b8f0a52014-03-20 01:02:42176 val = state;
Fabrice Bellardde6d9b62001-07-22 14:18:56177 goto found;
178 }
179 state = ((state << 8) | v) & 0xffffff;
180 }
181 val = -1;
Tanja Batchelor5b8f0a52014-03-20 01:02:42182
183found:
Fabrice Bellardde6d9b62001-07-22 14:18:56184 *header_state = state;
Tanja Batchelor5b8f0a52014-03-20 01:02:42185 *size_ptr = n;
Fabrice Bellardde6d9b62001-07-22 14:18:56186 return val;
187}
188
Måns Rullgårde3d1cd82005-03-28 17:33:21189/**
Måns Rullgård49bd8e42010-06-30 15:38:06190 * Extract stream types from a program stream map
Måns Rullgårde3d1cd82005-03-28 17:33:21191 * According to ISO/IEC 13818-1 ('MPEG-2 Systems') table 2-35
Diego Biurrun115329f2005-12-17 18:14:38192 *
Måns Rullgårde3d1cd82005-03-28 17:33:21193 * @return number of bytes occupied by PSM in the bitstream
194 */
Anton Khirnov471fe572011-02-20 10:04:12195static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb)
Måns Rullgårde3d1cd82005-03-28 17:33:21196{
197 int psm_length, ps_info_length, es_map_length;
198
Anton Khirnove63a3622011-02-21 15:43:01199 psm_length = avio_rb16(pb);
200 avio_r8(pb);
201 avio_r8(pb);
202 ps_info_length = avio_rb16(pb);
Måns Rullgårde3d1cd82005-03-28 17:33:21203
204 /* skip program_stream_info */
Anton Khirnov45a8a022011-03-15 08:14:38205 avio_skip(pb, ps_info_length);
Michael Niedermayer8d7d8812015-01-13 23:06:43206 /*es_map_length = */avio_rb16(pb);
Carl Eugen Hoyosaf7562a2013-12-05 20:17:21207 /* Ignore es_map_length, trust psm_length */
208 es_map_length = psm_length - ps_info_length - 10;
Måns Rullgårde3d1cd82005-03-28 17:33:21209
210 /* at least one es available? */
Tanja Batchelor5b8f0a52014-03-20 01:02:42211 while (es_map_length >= 4) {
Anton Khirnove63a3622011-02-21 15:43:01212 unsigned char type = avio_r8(pb);
213 unsigned char es_id = avio_r8(pb);
214 uint16_t es_info_length = avio_rb16(pb);
Tanja Batchelor5b8f0a52014-03-20 01:02:42215
Måns Rullgårde3d1cd82005-03-28 17:33:21216 /* remember mapping from stream id to stream type */
217 m->psm_es_type[es_id] = type;
218 /* skip program_stream_info */
Anton Khirnov45a8a022011-03-15 08:14:38219 avio_skip(pb, es_info_length);
Måns Rullgårde3d1cd82005-03-28 17:33:21220 es_map_length -= 4 + es_info_length;
221 }
Anton Khirnove63a3622011-02-21 15:43:01222 avio_rb32(pb); /* crc32 */
Måns Rullgårde3d1cd82005-03-28 17:33:21223 return 2 + psm_length;
224}
225
Diego Biurrun115329f2005-12-17 18:14:38226/* read the next PES header. Return its position in ppos
Tanja Batchelor5b8f0a52014-03-20 01:02:42227 * (if not NULL), and its start code, pts and dts.
Fabrice Bellard27f388a2003-11-10 18:47:52228 */
229static int mpegps_read_pes_header(AVFormatContext *s,
Diego Biurrun115329f2005-12-17 18:14:38230 int64_t *ppos, int *pstart_code,
Michael Niedermayer8d14a252004-04-12 16:50:03231 int64_t *ppts, int64_t *pdts)
Fabrice Bellardde6d9b62001-07-22 14:18:56232{
233 MpegDemuxContext *m = s->priv_data;
Fabrice Bellard27f388a2003-11-10 18:47:52234 int len, size, startcode, c, flags, header_len;
Michael Niedermayeraad512b2007-02-06 19:14:16235 int pes_ext, ext2_len, id_ext, skip;
Michael Niedermayere56cfad2007-01-17 10:19:10236 int64_t pts, dts;
Tanja Batchelor5b8f0a52014-03-20 01:02:42237 int64_t last_sync = avio_tell(s->pb);
Fabrice Bellardde6d9b62001-07-22 14:18:56238
Tanja Batchelor5b8f0a52014-03-20 01:02:42239error_redo:
240 avio_seek(s->pb, last_sync, SEEK_SET);
241redo:
242 /* next start code (should be immediately after) */
243 m->header_state = 0xff;
244 size = MAX_SYNC_SIZE;
245 startcode = find_next_start_code(s->pb, &size, &m->header_state);
246 last_sync = avio_tell(s->pb);
247 if (startcode < 0) {
James Almerd34ec642014-08-07 20:12:41248 if (avio_feof(s->pb))
Michael Niedermayer03323242010-02-10 14:25:57249 return AVERROR_EOF;
Tanja Batchelor5b8f0a52014-03-20 01:02:42250 // FIXME we should remember header_state
Nicolas Georgecb14d302015-11-27 17:58:38251 return FFERROR_REDO;
Michael Niedermayer03323242010-02-10 14:25:57252 }
253
Fabrice Bellardde6d9b62001-07-22 14:18:56254 if (startcode == PACK_START_CODE)
255 goto redo;
256 if (startcode == SYSTEM_HEADER_START_CODE)
257 goto redo;
Måns Rullgård2c187842007-11-08 21:27:37258 if (startcode == PADDING_STREAM) {
Anton Khirnov45a8a022011-03-15 08:14:38259 avio_skip(s->pb, avio_rb16(s->pb));
Måns Rullgård2c187842007-11-08 21:27:37260 goto redo;
261 }
262 if (startcode == PRIVATE_STREAM_2) {
Måns Rullgård2c187842007-11-08 21:27:37263 if (!m->sofdec) {
Richard9cde9f72013-03-17 09:21:12264 /* Need to detect whether this from a DVD or a 'Sofdec' stream */
265 int len = avio_rb16(s->pb);
266 int bytesread = 0;
267 uint8_t *ps2buf = av_malloc(len);
268
269 if (ps2buf) {
270 bytesread = avio_read(s->pb, ps2buf, len);
271
272 if (bytesread != len) {
273 avio_skip(s->pb, len - bytesread);
274 } else {
275 uint8_t *p = 0;
276 if (len >= 6)
277 p = memchr(ps2buf, 'S', len - 5);
278
279 if (p)
280 m->sofdec = !memcmp(p+1, "ofdec", 5);
281
282 m->sofdec -= !m->sofdec;
283
284 if (m->sofdec < 0) {
285 if (len == 980 && ps2buf[0] == 0) {
286 /* PCI structure? */
287 uint32_t startpts = AV_RB32(ps2buf + 0x0d);
288 uint32_t endpts = AV_RB32(ps2buf + 0x11);
289 uint8_t hours = ((ps2buf[0x19] >> 4) * 10) + (ps2buf[0x19] & 0x0f);
290 uint8_t mins = ((ps2buf[0x1a] >> 4) * 10) + (ps2buf[0x1a] & 0x0f);
291 uint8_t secs = ((ps2buf[0x1b] >> 4) * 10) + (ps2buf[0x1b] & 0x0f);
292
293 m->dvd = (hours <= 23 &&
294 mins <= 59 &&
295 secs <= 59 &&
296 (ps2buf[0x19] & 0x0f) < 10 &&
297 (ps2buf[0x1a] & 0x0f) < 10 &&
298 (ps2buf[0x1b] & 0x0f) < 10 &&
299 endpts >= startpts);
300 } else if (len == 1018 && ps2buf[0] == 1) {
301 /* DSI structure? */
302 uint8_t hours = ((ps2buf[0x1d] >> 4) * 10) + (ps2buf[0x1d] & 0x0f);
303 uint8_t mins = ((ps2buf[0x1e] >> 4) * 10) + (ps2buf[0x1e] & 0x0f);
304 uint8_t secs = ((ps2buf[0x1f] >> 4) * 10) + (ps2buf[0x1f] & 0x0f);
305
306 m->dvd = (hours <= 23 &&
307 mins <= 59 &&
308 secs <= 59 &&
309 (ps2buf[0x1d] & 0x0f) < 10 &&
310 (ps2buf[0x1e] & 0x0f) < 10 &&
311 (ps2buf[0x1f] & 0x0f) < 10);
312 }
313 }
Måns Rullgård2c187842007-11-08 21:27:37314 }
Richard9cde9f72013-03-17 09:21:12315
316 av_free(ps2buf);
317
318 /* If this isn't a DVD packet or no memory
319 * could be allocated, just ignore it.
320 * If we did, move back to the start of the
321 * packet (plus 'length' field) */
322 if (!m->dvd || avio_skip(s->pb, -(len + 2)) < 0) {
323 /* Skip back failed.
324 * This packet will be lost but that can't be helped
325 * if we can't skip back
326 */
327 goto redo;
328 }
329 } else {
330 /* No memory */
331 avio_skip(s->pb, len);
332 goto redo;
Måns Rullgård2c187842007-11-08 21:27:37333 }
Richard9cde9f72013-03-17 09:21:12334 } else if (!m->dvd) {
335 int len = avio_rb16(s->pb);
336 avio_skip(s->pb, len);
337 goto redo;
Måns Rullgård2c187842007-11-08 21:27:37338 }
Fabrice Bellardde6d9b62001-07-22 14:18:56339 }
Måns Rullgårde3d1cd82005-03-28 17:33:21340 if (startcode == PROGRAM_STREAM_MAP) {
Björn Axelsson899681c2007-11-21 07:41:00341 mpegps_psm_parse(m, s->pb);
Måns Rullgårde3d1cd82005-03-28 17:33:21342 goto redo;
343 }
Diego Biurrun115329f2005-12-17 18:14:38344
Fabrice Bellardde6d9b62001-07-22 14:18:56345 /* find matching stream */
346 if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
347 (startcode >= 0x1e0 && startcode <= 0x1ef) ||
Richard9cde9f72013-03-17 09:21:12348 (startcode == 0x1bd) ||
349 (startcode == PRIVATE_STREAM_2) ||
350 (startcode == 0x1fd)))
Fabrice Bellardde6d9b62001-07-22 14:18:56351 goto redo;
Fabrice Bellard27f388a2003-11-10 18:47:52352 if (ppos) {
Anton Khirnov384c9c22011-03-03 19:11:45353 *ppos = avio_tell(s->pb) - 4;
Fabrice Bellard27f388a2003-11-10 18:47:52354 }
Anton Khirnove63a3622011-02-21 15:43:01355 len = avio_rb16(s->pb);
Michael Niedermayer75a9fbb2007-01-17 10:45:59356 pts =
Fabrice Bellardb2cac182002-10-21 15:57:21357 dts = AV_NOPTS_VALUE;
Richard9cde9f72013-03-17 09:21:12358 if (startcode != PRIVATE_STREAM_2)
359 {
Fabrice Bellardde6d9b62001-07-22 14:18:56360 /* stuffing */
Tanja Batchelor5b8f0a52014-03-20 01:02:42361 for (;;) {
Fabrice Bellard27f388a2003-11-10 18:47:52362 if (len < 1)
Michael Niedermayere56cfad2007-01-17 10:19:10363 goto error_redo;
Anton Khirnove63a3622011-02-21 15:43:01364 c = avio_r8(s->pb);
Fabrice Bellardde6d9b62001-07-22 14:18:56365 len--;
Vittorio Giovara41ed7ab2016-04-27 17:45:23366 /* XXX: for MPEG-1, should test only bit 7 */
Diego Biurrun115329f2005-12-17 18:14:38367 if (c != 0xff)
Fabrice Bellardde6d9b62001-07-22 14:18:56368 break;
369 }
370 if ((c & 0xc0) == 0x40) {
371 /* buffer scale & size */
Anton Khirnove63a3622011-02-21 15:43:01372 avio_r8(s->pb);
Tanja Batchelor5b8f0a52014-03-20 01:02:42373 c = avio_r8(s->pb);
Fabrice Bellardde6d9b62001-07-22 14:18:56374 len -= 2;
375 }
Michael Niedermayerb90ba242007-01-17 10:55:01376 if ((c & 0xe0) == 0x20) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42377 dts =
378 pts = get_pts(s->pb, c);
Fabrice Bellardde6d9b62001-07-22 14:18:56379 len -= 4;
Tanja Batchelor5b8f0a52014-03-20 01:02:42380 if (c & 0x10) {
381 dts = get_pts(s->pb, -1);
Michael Niedermayerb90ba242007-01-17 10:55:01382 len -= 5;
383 }
Fabrice Bellardde6d9b62001-07-22 14:18:56384 } else if ((c & 0xc0) == 0x80) {
385 /* mpeg 2 PES */
Tanja Batchelor5b8f0a52014-03-20 01:02:42386 flags = avio_r8(s->pb);
Anton Khirnove63a3622011-02-21 15:43:01387 header_len = avio_r8(s->pb);
Tanja Batchelor5b8f0a52014-03-20 01:02:42388 len -= 2;
Fabrice Bellardde6d9b62001-07-22 14:18:56389 if (header_len > len)
Michael Niedermayere56cfad2007-01-17 10:19:10390 goto error_redo;
Michael Niedermayer80036202007-01-17 12:06:31391 len -= header_len;
Michael Niedermayerb90ba242007-01-17 10:55:01392 if (flags & 0x80) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42393 dts = pts = get_pts(s->pb, -1);
Fabrice Bellardde6d9b62001-07-22 14:18:56394 header_len -= 5;
Michael Niedermayerb90ba242007-01-17 10:55:01395 if (flags & 0x40) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42396 dts = get_pts(s->pb, -1);
Michael Niedermayerb90ba242007-01-17 10:55:01397 header_len -= 5;
Michael Niedermayerb90ba242007-01-17 10:55:01398 }
Fabrice Bellardde6d9b62001-07-22 14:18:56399 }
Tanja Batchelor5b8f0a52014-03-20 01:02:42400 if (flags & 0x3f && header_len == 0) {
Michael Niedermayer675b8392008-03-04 01:31:15401 flags &= 0xC0;
402 av_log(s, AV_LOG_WARNING, "Further flags set but no bytes left\n");
403 }
Michael Niedermayeraad512b2007-02-06 19:14:16404 if (flags & 0x01) { /* PES extension */
Anton Khirnove63a3622011-02-21 15:43:01405 pes_ext = avio_r8(s->pb);
Michael Niedermayeraad512b2007-02-06 19:14:16406 header_len--;
Tanja Batchelor5b8f0a52014-03-20 01:02:42407 /* Skip PES private data, program packet sequence counter
408 * and P-STD buffer */
409 skip = (pes_ext >> 4) & 0xb;
Michael Niedermayeraad512b2007-02-06 19:14:16410 skip += skip & 0x9;
Tanja Batchelor5b8f0a52014-03-20 01:02:42411 if (pes_ext & 0x40 || skip > header_len) {
Michael Niedermayerb22d0c02008-04-29 00:12:49412 av_log(s, AV_LOG_WARNING, "pes_ext %X is invalid\n", pes_ext);
Tanja Batchelor5b8f0a52014-03-20 01:02:42413 pes_ext = skip = 0;
Michael Niedermayerb22d0c02008-04-29 00:12:49414 }
Anton Khirnov45a8a022011-03-15 08:14:38415 avio_skip(s->pb, skip);
Michael Niedermayeraad512b2007-02-06 19:14:16416 header_len -= skip;
417
418 if (pes_ext & 0x01) { /* PES extension 2 */
Anton Khirnove63a3622011-02-21 15:43:01419 ext2_len = avio_r8(s->pb);
Michael Niedermayeraad512b2007-02-06 19:14:16420 header_len--;
421 if ((ext2_len & 0x7f) > 0) {
Anton Khirnove63a3622011-02-21 15:43:01422 id_ext = avio_r8(s->pb);
Michael Niedermayeraad512b2007-02-06 19:14:16423 if ((id_ext & 0x80) == 0)
424 startcode = ((startcode & 0xff) << 8) | id_ext;
425 header_len--;
426 }
427 }
428 }
Tanja Batchelor5b8f0a52014-03-20 01:02:42429 if (header_len < 0)
Michael Niedermayer80036202007-01-17 12:06:31430 goto error_redo;
Anton Khirnov45a8a022011-03-15 08:14:38431 avio_skip(s->pb, header_len);
Tanja Batchelor5b8f0a52014-03-20 01:02:42432 } else if (c != 0xf)
Dmitry Borisovdf70de12004-04-23 21:02:01433 goto redo;
Richard9cde9f72013-03-17 09:21:12434 }
Dmitry Borisovdf70de12004-04-23 21:02:01435
Michael Niedermayerafa6afc2012-07-31 17:20:00436 if (startcode == PRIVATE_STREAM_1) {
Paul B Mahol7643e272018-03-30 16:44:34437 int ret = ffio_ensure_seekback(s->pb, 2);
438
439 if (ret < 0)
440 return ret;
441
Anton Khirnove63a3622011-02-21 15:43:01442 startcode = avio_r8(s->pb);
Paul B Mahol1f7705e2018-04-01 18:58:48443 m->raw_ac3 = 0;
444 if (startcode == 0x0b) {
445 if (avio_r8(s->pb) == 0x77) {
446 startcode = 0x80;
447 m->raw_ac3 = 1;
448 avio_skip(s->pb, -2);
Paul B Mahol09956412018-04-01 19:08:16449 } else {
450 avio_skip(s->pb, -1);
Paul B Mahol1f7705e2018-04-01 18:58:48451 }
Paul B Mahol7643e272018-03-30 16:44:34452 } else {
Paul B Mahol7643e272018-03-30 16:44:34453 len--;
454 }
Fabrice Bellardde6d9b62001-07-22 14:18:56455 }
Tanja Batchelor5b8f0a52014-03-20 01:02:42456 if (len < 0)
Michael Niedermayer7e4709b2007-01-17 10:44:57457 goto error_redo;
Tanja Batchelor5b8f0a52014-03-20 01:02:42458 if (dts != AV_NOPTS_VALUE && ppos) {
Michael Niedermayerb7549782004-01-13 22:02:49459 int i;
Tanja Batchelor5b8f0a52014-03-20 01:02:42460 for (i = 0; i < s->nb_streams; i++) {
461 if (startcode == s->streams[i]->id &&
Anton Khirnov83548fe2016-09-27 14:26:37462 (s->pb->seekable & AVIO_SEEKABLE_NORMAL) /* index useless on streams anyway */) {
Paul Kelly3dea63b2008-01-13 13:33:37463 ff_reduce_index(s, i);
Tanja Batchelor5b8f0a52014-03-20 01:02:42464 av_add_index_entry(s->streams[i], *ppos, dts, 0, 0,
465 AVINDEX_KEYFRAME /* FIXME keyframe? */);
Michael Niedermayerb7549782004-01-13 22:02:49466 }
467 }
468 }
Diego Biurrun115329f2005-12-17 18:14:38469
Fabrice Bellard27f388a2003-11-10 18:47:52470 *pstart_code = startcode;
Tanja Batchelor5b8f0a52014-03-20 01:02:42471 *ppts = pts;
472 *pdts = dts;
Fabrice Bellard27f388a2003-11-10 18:47:52473 return len;
474}
475
476static int mpegps_read_packet(AVFormatContext *s,
477 AVPacket *pkt)
478{
Måns Rullgårde3d1cd82005-03-28 17:33:21479 MpegDemuxContext *m = s->priv_data;
Fabrice Bellard27f388a2003-11-10 18:47:52480 AVStream *st;
Alex Converse9fba8eb2011-09-23 23:28:23481 int len, startcode, i, es_type, ret;
Paul B Mahol7da57872019-10-01 09:34:09482 int pcm_dvd = 0;
Michael Niedermayer5b56ad02011-03-04 00:12:17483 int request_probe= 0;
Anton Khirnov36ef5362012-08-05 09:11:04484 enum AVCodecID codec_id = AV_CODEC_ID_NONE;
Stefano Sabatini72415b22010-03-30 23:30:55485 enum AVMediaType type;
Tanja Batchelor5b8f0a52014-03-20 01:02:42486 int64_t pts, dts, dummy_pos; // dummy_pos is needed for the index building to work
Fabrice Bellard27f388a2003-11-10 18:47:52487
Tanja Batchelor5b8f0a52014-03-20 01:02:42488redo:
Michael Niedermayer8d14a252004-04-12 16:50:03489 len = mpegps_read_pes_header(s, &dummy_pos, &startcode, &pts, &dts);
Fabrice Bellard27f388a2003-11-10 18:47:52490 if (len < 0)
491 return len;
Diego Biurrun115329f2005-12-17 18:14:38492
Michael Niedermayerce7cf602012-07-31 17:43:20493 if (startcode >= 0x80 && startcode <= 0xcf) {
Michael Niedermayerfecebb72014-03-24 04:28:07494 if (len < 4)
Michael Niedermayerce7cf602012-07-31 17:43:20495 goto skip;
496
Paul B Mahol7643e272018-03-30 16:44:34497 if (!m->raw_ac3) {
498 /* audio: skip header */
Andreas Rheinhardtffb32d32019-10-08 05:41:13499 avio_skip(s->pb, 3);
Paul B Mahol7643e272018-03-30 16:44:34500 len -= 3;
501 if (startcode >= 0xb0 && startcode <= 0xbf) {
502 /* MLP/TrueHD audio has a 4-byte header */
503 avio_r8(s->pb);
504 len--;
Paul B Mahol7da57872019-10-01 09:34:09505 } else if (startcode >= 0xa0 && startcode <= 0xaf) {
506 ret = ffio_ensure_seekback(s->pb, 3);
507 if (ret < 0)
508 return ret;
509 pcm_dvd = (avio_rb24(s->pb) & 0xFF) == 0x80;
510 avio_skip(s->pb, -3);
Paul B Mahol7643e272018-03-30 16:44:34511 }
Michael Niedermayerce7cf602012-07-31 17:43:20512 }
513 }
514
Fabrice Bellardde6d9b62001-07-22 14:18:56515 /* now find stream */
Tanja Batchelor5b8f0a52014-03-20 01:02:42516 for (i = 0; i < s->nb_streams; i++) {
Fabrice Bellardde6d9b62001-07-22 14:18:56517 st = s->streams[i];
518 if (st->id == startcode)
519 goto found;
520 }
Måns Rullgårde3d1cd82005-03-28 17:33:21521
522 es_type = m->psm_es_type[startcode & 0xff];
Xiaofeng Wang821791c2019-02-18 01:16:58523 if (es_type == STREAM_TYPE_VIDEO_MPEG1) {
524 codec_id = AV_CODEC_ID_MPEG2VIDEO;
525 type = AVMEDIA_TYPE_VIDEO;
526 } else if (es_type == STREAM_TYPE_VIDEO_MPEG2) {
527 codec_id = AV_CODEC_ID_MPEG2VIDEO;
528 type = AVMEDIA_TYPE_VIDEO;
529 } else if (es_type == STREAM_TYPE_AUDIO_MPEG1 ||
530 es_type == STREAM_TYPE_AUDIO_MPEG2) {
531 codec_id = AV_CODEC_ID_MP3;
532 type = AVMEDIA_TYPE_AUDIO;
533 } else if (es_type == STREAM_TYPE_AUDIO_AAC) {
534 codec_id = AV_CODEC_ID_AAC;
535 type = AVMEDIA_TYPE_AUDIO;
536 } else if (es_type == STREAM_TYPE_VIDEO_MPEG4) {
537 codec_id = AV_CODEC_ID_MPEG4;
538 type = AVMEDIA_TYPE_VIDEO;
539 } else if (es_type == STREAM_TYPE_VIDEO_H264) {
540 codec_id = AV_CODEC_ID_H264;
541 type = AVMEDIA_TYPE_VIDEO;
542 } else if (es_type == STREAM_TYPE_VIDEO_HEVC) {
543 codec_id = AV_CODEC_ID_HEVC;
544 type = AVMEDIA_TYPE_VIDEO;
545 } else if (es_type == STREAM_TYPE_AUDIO_AC3) {
546 codec_id = AV_CODEC_ID_AC3;
547 type = AVMEDIA_TYPE_AUDIO;
548 } else if (m->imkh_cctv && es_type == 0x91) {
549 codec_id = AV_CODEC_ID_PCM_MULAW;
550 type = AVMEDIA_TYPE_AUDIO;
Måns Rullgårde3d1cd82005-03-28 17:33:21551 } else if (startcode >= 0x1e0 && startcode <= 0x1ef) {
Måns Rullgård83d07312006-07-03 21:40:01552 static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
553 unsigned char buf[8];
Tanja Batchelor5b8f0a52014-03-20 01:02:42554
Anton Khirnove63a3622011-02-21 15:43:01555 avio_read(s->pb, buf, 8);
Anton Khirnovf59d8ff2011-02-28 13:57:54556 avio_seek(s->pb, -8, SEEK_CUR);
Tanja Batchelor5b8f0a52014-03-20 01:02:42557 if (!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1))
Anton Khirnov36ef5362012-08-05 09:11:04558 codec_id = AV_CODEC_ID_CAVS;
Måns Rullgård83d07312006-07-03 21:40:01559 else
Michael Niedermayer5b56ad02011-03-04 00:12:17560 request_probe= 1;
Stefano Sabatini72415b22010-03-30 23:30:55561 type = AVMEDIA_TYPE_VIDEO;
Richard9cde9f72013-03-17 09:21:12562 } else if (startcode == PRIVATE_STREAM_2) {
563 type = AVMEDIA_TYPE_DATA;
564 codec_id = AV_CODEC_ID_DVD_NAV;
Fabrice Bellarddb7f1f92002-05-20 16:29:40565 } else if (startcode >= 0x1c0 && startcode <= 0x1df) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42566 type = AVMEDIA_TYPE_AUDIO;
Carl Eugen Hoyos4ba90392013-12-01 11:02:21567 if (m->sofdec > 0) {
568 codec_id = AV_CODEC_ID_ADPCM_ADX;
569 // Auto-detect AC-3
570 request_probe = 50;
Carl Eugen Hoyosee8c1832015-05-17 10:57:27571 } else if (m->imkh_cctv && startcode == 0x1c0 && len > 80) {
Carl Eugen Hoyos036079c2015-04-03 19:04:43572 codec_id = AV_CODEC_ID_PCM_ALAW;
573 request_probe = 50;
Carl Eugen Hoyos4ba90392013-12-01 11:02:21574 } else {
575 codec_id = AV_CODEC_ID_MP2;
Carl Eugen Hoyosf8413f72015-04-03 18:58:20576 if (m->imkh_cctv)
577 request_probe = 25;
Carl Eugen Hoyos4ba90392013-12-01 11:02:21578 }
Joakim Plate3f2bf072005-05-20 13:10:09579 } else if (startcode >= 0x80 && startcode <= 0x87) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42580 type = AVMEDIA_TYPE_AUDIO;
Anton Khirnov36ef5362012-08-05 09:11:04581 codec_id = AV_CODEC_ID_AC3;
Tanja Batchelor5b8f0a52014-03-20 01:02:42582 } else if ((startcode >= 0x88 && startcode <= 0x8f) ||
583 (startcode >= 0x98 && startcode <= 0x9f)) {
Michael Niedermayeraad512b2007-02-06 19:14:16584 /* 0x90 - 0x97 is reserved for SDDS in DVD specs */
Tanja Batchelor5b8f0a52014-03-20 01:02:42585 type = AVMEDIA_TYPE_AUDIO;
Anton Khirnov36ef5362012-08-05 09:11:04586 codec_id = AV_CODEC_ID_DTS;
Michael Niedermayeraad512b2007-02-06 19:14:16587 } else if (startcode >= 0xa0 && startcode <= 0xaf) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42588 type = AVMEDIA_TYPE_AUDIO;
Paul B Mahol7da57872019-10-01 09:34:09589 if (!pcm_dvd) {
Michael Niedermayer7a726952012-08-07 20:45:46590 codec_id = AV_CODEC_ID_MLP;
Michael Niedermayer759901f2012-07-31 18:54:33591 } else {
Michael Niedermayer7a726952012-08-07 20:45:46592 codec_id = AV_CODEC_ID_PCM_DVD;
Michael Niedermayer759901f2012-07-31 18:54:33593 }
Michael Niedermayeraad512b2007-02-06 19:14:16594 } else if (startcode >= 0xb0 && startcode <= 0xbf) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42595 type = AVMEDIA_TYPE_AUDIO;
Anton Khirnov36ef5362012-08-05 09:11:04596 codec_id = AV_CODEC_ID_TRUEHD;
Michael Niedermayeraad512b2007-02-06 19:14:16597 } else if (startcode >= 0xc0 && startcode <= 0xcf) {
598 /* Used for both AC-3 and E-AC-3 in EVOB files */
Tanja Batchelor5b8f0a52014-03-20 01:02:42599 type = AVMEDIA_TYPE_AUDIO;
Anton Khirnov36ef5362012-08-05 09:11:04600 codec_id = AV_CODEC_ID_AC3;
Fabrice Bellarda9c32132005-06-03 14:01:49601 } else if (startcode >= 0x20 && startcode <= 0x3f) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42602 type = AVMEDIA_TYPE_SUBTITLE;
Anton Khirnov36ef5362012-08-05 09:11:04603 codec_id = AV_CODEC_ID_DVD_SUBTITLE;
Michael Niedermayeraad512b2007-02-06 19:14:16604 } else if (startcode >= 0xfd55 && startcode <= 0xfd5f) {
Tanja Batchelor5b8f0a52014-03-20 01:02:42605 type = AVMEDIA_TYPE_VIDEO;
Anton Khirnov36ef5362012-08-05 09:11:04606 codec_id = AV_CODEC_ID_VC1;
Fabrice Bellarddb7f1f92002-05-20 16:29:40607 } else {
Tanja Batchelor5b8f0a52014-03-20 01:02:42608skip:
Fabrice Bellarddb7f1f92002-05-20 16:29:40609 /* skip packet */
Anton Khirnov45a8a022011-03-15 08:14:38610 avio_skip(s->pb, len);
Fabrice Bellarddb7f1f92002-05-20 16:29:40611 goto redo;
612 }
Fabrice Bellard1e5c6672002-10-04 15:46:59613 /* no stream found: add a new stream */
Anton Khirnov84ad31f2011-06-18 09:43:24614 st = avformat_new_stream(s, NULL);
Diego Biurrun115329f2005-12-17 18:14:38615 if (!st)
Fabrice Bellard1e5c6672002-10-04 15:46:59616 goto skip;
Tanja Batchelor5b8f0a52014-03-20 01:02:42617 st->id = startcode;
Anton Khirnov92005142014-06-18 18:42:52618 st->codecpar->codec_type = type;
619 st->codecpar->codec_id = codec_id;
Derek Buitenhuis6f69f7a2016-04-10 19:58:15620 if ( st->codecpar->codec_id == AV_CODEC_ID_PCM_MULAW
621 || st->codecpar->codec_id == AV_CODEC_ID_PCM_ALAW) {
622 st->codecpar->channels = 1;
623 st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
624 st->codecpar->sample_rate = 8000;
Carl Eugen Hoyos92a9a302013-03-27 00:48:07625 }
Anton Khirnov108864a2020-10-09 07:22:36626 st->internal->request_probe = request_probe;
James Almerb9c5fdf2021-05-02 02:28:18627 st->internal->need_parsing = AVSTREAM_PARSE_FULL;
Tanja Batchelor5b8f0a52014-03-20 01:02:42628
629found:
630 if (st->discard >= AVDISCARD_ALL)
Michael Niedermayerb9866eb2005-01-22 13:36:02631 goto skip;
Michael Niedermayerafa6afc2012-07-31 17:20:00632 if (startcode >= 0xa0 && startcode <= 0xaf) {
Derek Buitenhuis6f69f7a2016-04-10 19:58:15633 if (st->codecpar->codec_id == AV_CODEC_ID_MLP) {
Michael Niedermayer759901f2012-07-31 18:54:33634 if (len < 6)
635 goto skip;
636 avio_skip(s->pb, 6);
637 len -=6;
Michael Niedermayer759901f2012-07-31 18:54:33638 }
Fabrice Bellard9ec05e32003-01-31 17:04:46639 }
Alex Converse98ef8872011-10-08 00:02:36640 ret = av_get_packet(s->pb, pkt, len);
Tanja Batchelor5b8f0a52014-03-20 01:02:42641
642 pkt->pts = pts;
643 pkt->dts = dts;
644 pkt->pos = dummy_pos;
Fabrice Bellarddb7f1f92002-05-20 16:29:40645 pkt->stream_index = st->index;
Michael Niedermayer57865a92015-04-20 15:41:22646
647 if (s->debug & FF_FDEBUG_TS)
Gyan Doshi02741852018-08-13 07:02:41648 av_log(s, AV_LOG_DEBUG, "%d: pts=%0.3f dts=%0.3f size=%d\n",
Diego Biurrun045dd4b2011-04-29 15:27:01649 pkt->stream_index, pkt->pts / 90000.0, pkt->dts / 90000.0,
650 pkt->size);
Mike Melanson0bd586c2004-06-19 03:59:34651
Alex Converse9fba8eb2011-09-23 23:28:23652 return (ret < 0) ? ret : 0;
Fabrice Bellardde6d9b62001-07-22 14:18:56653}
654
Diego Biurrun115329f2005-12-17 18:14:38655static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
Michael Niedermayer8d14a252004-04-12 16:50:03656 int64_t *ppos, int64_t pos_limit)
Fabrice Bellard27f388a2003-11-10 18:47:52657{
658 int len, startcode;
659 int64_t pos, pts, dts;
660
661 pos = *ppos;
Anton Khirnovf59d8ff2011-02-28 13:57:54662 if (avio_seek(s->pb, pos, SEEK_SET) < 0)
Joakim Plate5faf1682008-05-29 09:50:17663 return AV_NOPTS_VALUE;
664
Tanja Batchelor5b8f0a52014-03-20 01:02:42665 for (;;) {
Michael Niedermayer8d14a252004-04-12 16:50:03666 len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts);
Fabrice Bellard27f388a2003-11-10 18:47:52667 if (len < 0) {
Michael Niedermayer57865a92015-04-20 15:41:22668 if (s->debug & FF_FDEBUG_TS)
Gyan Doshi02741852018-08-13 07:02:41669 av_log(s, AV_LOG_DEBUG, "none (ret=%d)\n", len);
Fabrice Bellard27f388a2003-11-10 18:47:52670 return AV_NOPTS_VALUE;
671 }
Diego Biurrun115329f2005-12-17 18:14:38672 if (startcode == s->streams[stream_index]->id &&
Fabrice Bellard27f388a2003-11-10 18:47:52673 dts != AV_NOPTS_VALUE) {
674 break;
675 }
Anton Khirnov45a8a022011-03-15 08:14:38676 avio_skip(s->pb, len);
Fabrice Bellard27f388a2003-11-10 18:47:52677 }
Michael Niedermayer57865a92015-04-20 15:41:22678 if (s->debug & FF_FDEBUG_TS)
Gyan Doshi02741852018-08-13 07:02:41679 av_log(s, AV_LOG_DEBUG, "pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n",
Diego Biurrun919d7a32011-06-07 11:18:12680 pos, dts, dts / 90000.0);
Fabrice Bellard27f388a2003-11-10 18:47:52681 *ppos = pos;
Michael Niedermayercdd50342004-05-23 16:26:12682 return dts;
Fabrice Bellard27f388a2003-11-10 18:47:52683}
684
Andreas Rheinhardtbc706842021-04-19 17:45:24685const AVInputFormat ff_mpegps_demuxer = {
Anton Khirnovdfc2c4d2011-07-16 20:18:12686 .name = "mpeg",
Diego Biurrun0177b7d2012-07-24 01:23:48687 .long_name = NULL_IF_CONFIG_SMALL("MPEG-PS (MPEG-2 Program Stream)"),
Anton Khirnovdfc2c4d2011-07-16 20:18:12688 .priv_data_size = sizeof(MpegDemuxContext),
689 .read_probe = mpegps_probe,
690 .read_header = mpegps_read_header,
691 .read_packet = mpegps_read_packet,
Anton Khirnovdfc2c4d2011-07-16 20:18:12692 .read_timestamp = mpegps_read_dts,
Martin Storsjö20234a42012-04-06 14:50:48693 .flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
Fabrice Bellarddb7f1f92002-05-20 16:29:40694};
Clément Bœsch710c4ba2012-09-03 00:51:00695
696#if CONFIG_VOBSUB_DEMUXER
697
Andreas Rheinhardt3f378802019-12-04 12:37:12698#include "subtitles.h"
699#include "libavutil/avassert.h"
700#include "libavutil/bprint.h"
701#include "libavutil/opt.h"
702
Clément Bœsch710c4ba2012-09-03 00:51:00703#define REF_STRING "# VobSub index file,"
Clément Bœschcba92a22014-05-24 09:03:23704#define MAX_LINE_SIZE 2048
Clément Bœsch710c4ba2012-09-03 00:51:00705
Andreas Rheinhardt3f378802019-12-04 12:37:12706typedef struct VobSubDemuxContext {
707 const AVClass *class;
708 AVFormatContext *sub_ctx;
709 FFDemuxSubtitlesQueue q[32];
710 char *sub_name;
711} VobSubDemuxContext;
712
Carl Eugen Hoyos4d8875e2019-03-21 00:18:37713static int vobsub_probe(const AVProbeData *p)
Clément Bœsch710c4ba2012-09-03 00:51:00714{
715 if (!strncmp(p->buf, REF_STRING, sizeof(REF_STRING) - 1))
716 return AVPROBE_SCORE_MAX;
717 return 0;
718}
719
Andreas Rheinhardt4825d8a2019-12-04 12:37:14720static int vobsub_read_close(AVFormatContext *s)
721{
722 VobSubDemuxContext *vobsub = s->priv_data;
723 int i;
724
725 for (i = 0; i < s->nb_streams; i++)
726 ff_subtitles_queue_clean(&vobsub->q[i]);
Andreas Rheinhardtbcdc1d12020-03-21 20:03:44727 avformat_close_input(&vobsub->sub_ctx);
Andreas Rheinhardt4825d8a2019-12-04 12:37:14728 return 0;
729}
730
Clément Bœsch710c4ba2012-09-03 00:51:00731static int vobsub_read_header(AVFormatContext *s)
732{
Clément Bœsch5a2f3f0b2013-01-02 08:31:07733 int i, ret = 0, header_parsed = 0, langidx = 0;
Andreas Rheinhardt3f378802019-12-04 12:37:12734 VobSubDemuxContext *vobsub = s->priv_data;
Andreas Rheinhardt56450a02021-02-25 02:11:32735 const AVInputFormat *iformat;
Clément Bœsch710c4ba2012-09-03 00:51:00736 size_t fname_len;
Clément Bœsch710c4ba2012-09-03 00:51:00737 AVBPrint header;
738 int64_t delay = 0;
739 AVStream *st = NULL;
Clément Bœschcba92a22014-05-24 09:03:23740 int stream_id = -1;
741 char id[64] = {0};
742 char alt[MAX_LINE_SIZE] = {0};
Clément Bœsch710c4ba2012-09-03 00:51:00743
Rodger Combsc69ff122015-04-13 06:17:28744 if (!vobsub->sub_name) {
745 char *ext;
Marton Balint18ac6422017-12-29 22:30:14746 vobsub->sub_name = av_strdup(s->url);
Rodger Combsc69ff122015-04-13 06:17:28747 if (!vobsub->sub_name) {
Andreas Rheinhardtbc3cf2b2019-12-04 12:37:13748 return AVERROR(ENOMEM);
Rodger Combsc69ff122015-04-13 06:17:28749 }
750
751 fname_len = strlen(vobsub->sub_name);
752 ext = vobsub->sub_name - 3 + fname_len;
753 if (fname_len < 4 || *(ext - 1) != '.') {
754 av_log(s, AV_LOG_ERROR, "The input index filename is too short "
755 "to guess the associated .SUB file\n");
Andreas Rheinhardtbc3cf2b2019-12-04 12:37:13756 return AVERROR_INVALIDDATA;
Rodger Combsc69ff122015-04-13 06:17:28757 }
758 memcpy(ext, !strncmp(ext, "IDX", 3) ? "SUB" : "sub", 3);
Marton Balint18ac6422017-12-29 22:30:14759 av_log(s, AV_LOG_VERBOSE, "IDX/SUB: %s -> %s\n", s->url, vobsub->sub_name);
Clément Bœsch710c4ba2012-09-03 00:51:00760 }
Michael Niedermayerad83cfe2014-10-23 14:07:00761
Michael Niedermayer51ddaf62014-11-16 18:17:34762 if (!(iformat = av_find_input_format("mpeg"))) {
Andreas Rheinhardtbc3cf2b2019-12-04 12:37:13763 return AVERROR_DEMUXER_NOT_FOUND;
Michael Niedermayer51ddaf62014-11-16 18:17:34764 }
Michael Niedermayerff03df62014-10-25 14:28:41765
Michael Niedermayerad83cfe2014-10-23 14:07:00766 vobsub->sub_ctx = avformat_alloc_context();
Michael Niedermayer51ddaf62014-11-16 18:17:34767 if (!vobsub->sub_ctx) {
Andreas Rheinhardtbc3cf2b2019-12-04 12:37:13768 return AVERROR(ENOMEM);
Michael Niedermayer51ddaf62014-11-16 18:17:34769 }
Michael Niedermayerad83cfe2014-10-23 14:07:00770
Derek Buitenhuis93629732016-03-03 17:14:26771 if ((ret = ff_copy_whiteblacklists(vobsub->sub_ctx, s)) < 0)
Andreas Rheinhardtbcdc1d12020-03-21 20:03:44772 return ret;
Michael Niedermayerad83cfe2014-10-23 14:07:00773
Rodger Combsc69ff122015-04-13 06:17:28774 ret = avformat_open_input(&vobsub->sub_ctx, vobsub->sub_name, iformat, NULL);
Clément Bœsch710c4ba2012-09-03 00:51:00775 if (ret < 0) {
Rodger Combsc69ff122015-04-13 06:17:28776 av_log(s, AV_LOG_ERROR, "Unable to open %s as MPEG subtitles\n", vobsub->sub_name);
Andreas Rheinhardtbcdc1d12020-03-21 20:03:44777 return ret;
Clément Bœsch710c4ba2012-09-03 00:51:00778 }
779
Andreas Rheinhardtbcdc1d12020-03-21 20:03:44780 av_bprint_init(&header, 0, INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE);
781
James Almerd34ec642014-08-07 20:12:41782 while (!avio_feof(s->pb)) {
Clément Bœschcba92a22014-05-24 09:03:23783 char line[MAX_LINE_SIZE];
Clément Bœsch710c4ba2012-09-03 00:51:00784 int len = ff_get_line(s->pb, line, sizeof(line));
785
786 if (!len)
787 break;
788
789 line[strcspn(line, "\r\n")] = 0;
790
791 if (!strncmp(line, "id:", 3)) {
Clément Bœschcba92a22014-05-24 09:03:23792 if (sscanf(line, "id: %63[^,], index: %u", id, &stream_id) != 2) {
Clément Bœsch710c4ba2012-09-03 00:51:00793 av_log(s, AV_LOG_WARNING, "Unable to parse index line '%s', "
794 "assuming 'id: und, index: 0'\n", line);
795 strcpy(id, "und");
796 stream_id = 0;
797 }
798
Clément Bœschdbfe6112013-09-29 20:05:14799 if (stream_id >= FF_ARRAY_ELEMS(vobsub->q)) {
800 av_log(s, AV_LOG_ERROR, "Maximum number of subtitles streams reached\n");
801 ret = AVERROR(EINVAL);
802 goto end;
803 }
804
Clément Bœsch710c4ba2012-09-03 00:51:00805 header_parsed = 1;
Clément Bœschcba92a22014-05-24 09:03:23806 alt[0] = '\0';
807 /* We do not create the stream immediately to avoid adding empty
808 * streams. See the following timestamp entry. */
Clément Bœsch710c4ba2012-09-03 00:51:00809
Clément Bœschcba92a22014-05-24 09:03:23810 av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id);
811
812 } else if (!strncmp(line, "timestamp:", 10)) {
Clément Bœsch710c4ba2012-09-03 00:51:00813 AVPacket *sub;
814 int hh, mm, ss, ms;
815 int64_t pos, timestamp;
816 const char *p = line + 10;
817
Clément Bœschcba92a22014-05-24 09:03:23818 if (stream_id == -1) {
Clément Bœschdbfe6112013-09-29 20:05:14819 av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n");
820 ret = AVERROR_INVALIDDATA;
821 goto end;
822 }
823
Clément Bœschcba92a22014-05-24 09:03:23824 if (!st || st->id != stream_id) {
825 st = avformat_new_stream(s, NULL);
826 if (!st) {
827 ret = AVERROR(ENOMEM);
828 goto end;
829 }
830 st->id = stream_id;
Derek Buitenhuis6f69f7a2016-04-10 19:58:15831 st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
832 st->codecpar->codec_id = AV_CODEC_ID_DVD_SUBTITLE;
Clément Bœschcba92a22014-05-24 09:03:23833 avpriv_set_pts_info(st, 64, 1, 1000);
834 av_dict_set(&st->metadata, "language", id, 0);
835 if (alt[0])
836 av_dict_set(&st->metadata, "title", alt, 0);
837 }
838
James Almer89388a92013-04-10 07:52:08839 if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"SCNx64,
Clément Bœsch710c4ba2012-09-03 00:51:00840 &hh, &mm, &ss, &ms, &pos) != 5) {
841 av_log(s, AV_LOG_ERROR, "Unable to parse timestamp line '%s', "
842 "abort parsing\n", line);
Clément Bœschcba92a22014-05-24 09:03:23843 ret = AVERROR_INVALIDDATA;
844 goto end;
Clément Bœsch710c4ba2012-09-03 00:51:00845 }
846 timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay;
Clément Bœschb7dd2502014-05-01 14:18:12847 timestamp = av_rescale_q(timestamp, av_make_q(1, 1000), st->time_base);
Clément Bœsch710c4ba2012-09-03 00:51:00848
Clément Bœschdbfe6112013-09-29 20:05:14849 sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0);
Clément Bœsch710c4ba2012-09-03 00:51:00850 if (!sub) {
851 ret = AVERROR(ENOMEM);
852 goto end;
853 }
854 sub->pos = pos;
855 sub->pts = timestamp;
856 sub->stream_index = s->nb_streams - 1;
857
Clément Bœschcba92a22014-05-24 09:03:23858 } else if (!strncmp(line, "alt:", 4)) {
Clément Bœsch710c4ba2012-09-03 00:51:00859 const char *p = line + 4;
860
861 while (*p == ' ')
862 p++;
Clément Bœschd86cf4a2014-09-13 13:15:32863 av_log(s, AV_LOG_DEBUG, "IDX stream[%d] name=%s\n", stream_id, p);
Clément Bœschcba92a22014-05-24 09:03:23864 av_strlcpy(alt, p, sizeof(alt));
Clément Bœsch710c4ba2012-09-03 00:51:00865 header_parsed = 1;
866
867 } else if (!strncmp(line, "delay:", 6)) {
868 int sign = 1, hh = 0, mm = 0, ss = 0, ms = 0;
869 const char *p = line + 6;
870
871 while (*p == ' ')
872 p++;
873 if (*p == '-' || *p == '+') {
874 sign = *p == '-' ? -1 : 1;
875 p++;
876 }
877 sscanf(p, "%d:%d:%d:%d", &hh, &mm, &ss, &ms);
878 delay = ((hh*3600LL + mm*60LL + ss) * 1000LL + ms) * sign;
879
880 } else if (!strncmp(line, "langidx:", 8)) {
881 const char *p = line + 8;
882
883 if (sscanf(p, "%d", &langidx) != 1)
884 av_log(s, AV_LOG_ERROR, "Invalid langidx specified\n");
885
886 } else if (!header_parsed) {
887 if (line[0] && line[0] != '#')
888 av_bprintf(&header, "%s\n", line);
889 }
890 }
891
892 if (langidx < s->nb_streams)
893 s->streams[langidx]->disposition |= AV_DISPOSITION_DEFAULT;
894
Clément Bœschdbfe6112013-09-29 20:05:14895 for (i = 0; i < s->nb_streams; i++) {
896 vobsub->q[i].sort = SUB_SORT_POS_TS;
wm45c93e572015-09-21 11:43:32897 vobsub->q[i].keep_duplicates = 1;
Clément Bœschaf924fd2015-09-10 19:40:07898 ff_subtitles_queue_finalize(s, &vobsub->q[i]);
Clément Bœschdbfe6112013-09-29 20:05:14899 }
Clément Bœsch710c4ba2012-09-03 00:51:00900
901 if (!av_bprint_is_complete(&header)) {
Clément Bœsch710c4ba2012-09-03 00:51:00902 ret = AVERROR(ENOMEM);
903 goto end;
904 }
Clément Bœsch710c4ba2012-09-03 00:51:00905 for (i = 0; i < s->nb_streams; i++) {
Andreas Rheinhardtc36eae62019-10-22 13:16:42906 AVCodecParameters *par = s->streams[i]->codecpar;
907 ret = ff_alloc_extradata(par, header.len);
908 if (ret < 0) {
Steven Liuf5263172019-10-10 02:47:22909 goto end;
910 }
Andreas Rheinhardtbc3cf2b2019-12-04 12:37:13911 memcpy(par->extradata, header.str, header.len);
Clément Bœsch710c4ba2012-09-03 00:51:00912 }
Clément Bœsch710c4ba2012-09-03 00:51:00913end:
Andreas Rheinhardtbc3cf2b2019-12-04 12:37:13914 av_bprint_finalize(&header, NULL);
Clément Bœsch710c4ba2012-09-03 00:51:00915 return ret;
916}
917
918static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
919{
Andreas Rheinhardt3f378802019-12-04 12:37:12920 VobSubDemuxContext *vobsub = s->priv_data;
Clément Bœschdbfe6112013-09-29 20:05:14921 FFDemuxSubtitlesQueue *q;
Clément Bœsch710c4ba2012-09-03 00:51:00922 AVIOContext *pb = vobsub->sub_ctx->pb;
Clément Bœschdbfe6112013-09-29 20:05:14923 int ret, psize, total_read = 0, i;
Clément Bœsch710c4ba2012-09-03 00:51:00924
Clément Bœschdbfe6112013-09-29 20:05:14925 int64_t min_ts = INT64_MAX;
926 int sid = 0;
927 for (i = 0; i < s->nb_streams; i++) {
928 FFDemuxSubtitlesQueue *tmpq = &vobsub->q[i];
Clément Bœschcba92a22014-05-24 09:03:23929 int64_t ts;
930 av_assert0(tmpq->nb_subs);
Andreas Rheinhardta39536c2019-10-22 12:54:09931
932 if (tmpq->current_sub_idx >= tmpq->nb_subs)
933 continue;
934
James Almer98a776b2021-02-03 23:55:27935 ts = tmpq->subs[tmpq->current_sub_idx]->pts;
Clément Bœschdbfe6112013-09-29 20:05:14936 if (ts < min_ts) {
937 min_ts = ts;
938 sid = i;
939 }
940 }
941 q = &vobsub->q[sid];
Andreas Rheinhardt6d354ae2019-10-08 05:41:14942 /* The returned packet will have size zero,
943 * so that it can be directly used with av_grow_packet. */
944 ret = ff_subtitles_queue_read_packet(q, pkt);
Clément Bœsch710c4ba2012-09-03 00:51:00945 if (ret < 0)
946 return ret;
947
948 /* compute maximum packet size using the next packet position. This is
949 * useful when the len in the header is non-sense */
950 if (q->current_sub_idx < q->nb_subs) {
James Almer98a776b2021-02-03 23:55:27951 psize = q->subs[q->current_sub_idx]->pos - pkt->pos;
Clément Bœsch710c4ba2012-09-03 00:51:00952 } else {
953 int64_t fsize = avio_size(pb);
Andreas Rheinhardt6d354ae2019-10-08 05:41:14954 psize = fsize < 0 ? 0xffff : fsize - pkt->pos;
Clément Bœsch710c4ba2012-09-03 00:51:00955 }
956
Andreas Rheinhardt6d354ae2019-10-08 05:41:14957 avio_seek(pb, pkt->pos, SEEK_SET);
Clément Bœsch710c4ba2012-09-03 00:51:00958
959 do {
960 int n, to_read, startcode;
961 int64_t pts, dts;
Clément Bœschdbfe6112013-09-29 20:05:14962 int64_t old_pos = avio_tell(pb), new_pos;
963 int pkt_size;
Clément Bœsch710c4ba2012-09-03 00:51:00964
965 ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts);
Clément Bœschd4dc6732013-10-04 09:25:08966 if (ret < 0) {
967 if (pkt->size) // raise packet even if incomplete
968 break;
Andreas Rheinhardt3875af82020-03-21 20:08:04969 return ret;
Clément Bœschd4dc6732013-10-04 09:25:08970 }
Clément Bœsch710c4ba2012-09-03 00:51:00971 to_read = ret & 0xffff;
Clément Bœschdbfe6112013-09-29 20:05:14972 new_pos = avio_tell(pb);
973 pkt_size = ret + (new_pos - old_pos);
Clément Bœsch710c4ba2012-09-03 00:51:00974
975 /* this prevents reads above the current packet */
Clément Bœschdbfe6112013-09-29 20:05:14976 if (total_read + pkt_size > psize)
Clément Bœsch710c4ba2012-09-03 00:51:00977 break;
Clément Bœschdbfe6112013-09-29 20:05:14978 total_read += pkt_size;
Clément Bœsch710c4ba2012-09-03 00:51:00979
980 /* the current chunk doesn't match the stream index (unlikely) */
Andreas Rheinhardt6d354ae2019-10-08 05:41:14981 if ((startcode & 0x1f) != s->streams[pkt->stream_index]->id)
Clément Bœsch710c4ba2012-09-03 00:51:00982 break;
983
984 ret = av_grow_packet(pkt, to_read);
985 if (ret < 0)
Andreas Rheinhardt3875af82020-03-21 20:08:04986 return ret;
Clément Bœsch710c4ba2012-09-03 00:51:00987
988 n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read);
989 if (n < to_read)
990 pkt->size -= to_read - n;
Clément Bœschdbfe6112013-09-29 20:05:14991 } while (total_read < psize);
Clément Bœsch710c4ba2012-09-03 00:51:00992
Clément Bœsch710c4ba2012-09-03 00:51:00993 return 0;
Clément Bœsch710c4ba2012-09-03 00:51:00994}
995
996static int vobsub_read_seek(AVFormatContext *s, int stream_index,
997 int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
998{
Andreas Rheinhardt3f378802019-12-04 12:37:12999 VobSubDemuxContext *vobsub = s->priv_data;
Clément Bœschf8678dc2013-09-08 07:43:531000
1001 /* Rescale requested timestamps based on the first stream (timebase is the
1002 * same for all subtitles stream within a .idx/.sub). Rescaling is done just
1003 * like in avformat_seek_file(). */
1004 if (stream_index == -1 && s->nb_streams != 1) {
Clément Bœschdbfe6112013-09-29 20:05:141005 int i, ret = 0;
Clément Bœschf8678dc2013-09-08 07:43:531006 AVRational time_base = s->streams[0]->time_base;
1007 ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
1008 min_ts = av_rescale_rnd(min_ts, time_base.den,
1009 time_base.num * (int64_t)AV_TIME_BASE,
1010 AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
1011 max_ts = av_rescale_rnd(max_ts, time_base.den,
1012 time_base.num * (int64_t)AV_TIME_BASE,
1013 AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
Clément Bœschdbfe6112013-09-29 20:05:141014 for (i = 0; i < s->nb_streams; i++) {
1015 int r = ff_subtitles_queue_seek(&vobsub->q[i], s, stream_index,
1016 min_ts, ts, max_ts, flags);
1017 if (r < 0)
1018 ret = r;
1019 }
1020 return ret;
Clément Bœschf8678dc2013-09-08 07:43:531021 }
1022
Clément Bœsch4189fe12013-10-20 19:23:431023 if (stream_index == -1) // only 1 stream
1024 stream_index = 0;
Clément Bœschdbfe6112013-09-29 20:05:141025 return ff_subtitles_queue_seek(&vobsub->q[stream_index], s, stream_index,
Clément Bœsch710c4ba2012-09-03 00:51:001026 min_ts, ts, max_ts, flags);
1027}
1028
Rodger Combsc69ff122015-04-13 06:17:281029static const AVOption options[] = {
Andreas Rheinhardt3f378802019-12-04 12:37:121030 { "sub_name", "URI for .sub file", offsetof(VobSubDemuxContext, sub_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
Rodger Combsc69ff122015-04-13 06:17:281031 { NULL }
1032};
1033
1034static const AVClass vobsub_demuxer_class = {
1035 .class_name = "vobsub",
1036 .item_name = av_default_item_name,
1037 .option = options,
1038 .version = LIBAVUTIL_VERSION_INT,
1039};
1040
Andreas Rheinhardtbc706842021-04-19 17:45:241041const AVInputFormat ff_vobsub_demuxer = {
Clément Bœsch710c4ba2012-09-03 00:51:001042 .name = "vobsub",
1043 .long_name = NULL_IF_CONFIG_SMALL("VobSub subtitle format"),
Andreas Rheinhardt3f378802019-12-04 12:37:121044 .priv_data_size = sizeof(VobSubDemuxContext),
Andreas Rheinhardtbcdc1d12020-03-21 20:03:441045 .flags_internal = FF_FMT_INIT_CLEANUP,
Clément Bœsch710c4ba2012-09-03 00:51:001046 .read_probe = vobsub_probe,
1047 .read_header = vobsub_read_header,
1048 .read_packet = vobsub_read_packet,
1049 .read_seek2 = vobsub_read_seek,
1050 .read_close = vobsub_read_close,
1051 .flags = AVFMT_SHOW_IDS,
1052 .extensions = "idx",
Rodger Combsc69ff122015-04-13 06:17:281053 .priv_class = &vobsub_demuxer_class,
Clément Bœsch710c4ba2012-09-03 00:51:001054};
1055#endif