00001 /* 00002 * MPEG1/2 demuxer 00003 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "avformat.h" 00023 #include "mpeg.h" 00024 00025 //#define DEBUG_SEEK 00026 00027 #undef NDEBUG 00028 #include <assert.h> 00029 00030 /*********************************************/ 00031 /* demux code */ 00032 00033 #define MAX_SYNC_SIZE 100000 00034 00035 static int check_pes(uint8_t *p, uint8_t *end){ 00036 int pes1; 00037 int pes2= (p[3] & 0xC0) == 0x80 00038 && (p[4] & 0xC0) != 0x40 00039 &&((p[4] & 0xC0) == 0x00 || (p[4]&0xC0)>>2 == (p[6]&0xF0)); 00040 00041 for(p+=3; p<end && *p == 0xFF; p++); 00042 if((*p&0xC0) == 0x40) p+=2; 00043 if((*p&0xF0) == 0x20){ 00044 pes1= p[0]&p[2]&p[4]&1; 00045 p+=5; 00046 }else if((*p&0xF0) == 0x30){ 00047 pes1= p[0]&p[2]&p[4]&p[5]&p[7]&p[9]&1; 00048 p+=10; 00049 }else 00050 pes1 = *p == 0x0F; 00051 00052 return pes1||pes2; 00053 } 00054 00055 static int mpegps_probe(AVProbeData *p) 00056 { 00057 uint32_t code= -1; 00058 int sys=0, pspack=0, priv1=0, vid=0, audio=0, invalid=0; 00059 int i; 00060 int score=0; 00061 00062 for(i=0; i<p->buf_size; i++){ 00063 code = (code<<8) + p->buf[i]; 00064 if ((code & 0xffffff00) == 0x100) { 00065 int pes= check_pes(p->buf+i, p->buf+p->buf_size); 00066 00067 if(code == SYSTEM_HEADER_START_CODE) sys++; 00068 else if(code == PRIVATE_STREAM_1) priv1++; 00069 else if(code == PACK_START_CODE) pspack++; 00070 else if((code & 0xf0) == VIDEO_ID && pes) vid++; 00071 else if((code & 0xe0) == AUDIO_ID && pes) audio++; 00072 00073 else if((code & 0xf0) == VIDEO_ID && !pes) invalid++; 00074 else if((code & 0xe0) == AUDIO_ID && !pes) invalid++; 00075 } 00076 } 00077 00078 if(vid+audio > invalid) /* invalid VDR files nd short PES streams */ 00079 score= AVPROBE_SCORE_MAX/4; 00080 00081 //av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d len:%d\n", sys, priv1, pspack,vid, audio, p->buf_size); 00082 if(sys>invalid && sys*9 <= pspack*10) 00083 return AVPROBE_SCORE_MAX/2+2; // +1 for .mpg 00084 if(priv1 + vid + audio > invalid && (priv1+vid+audio)*9 <= pspack*10) 00085 return AVPROBE_SCORE_MAX/2+2; // +1 for .mpg 00086 if((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys && !pspack && p->buf_size>2048) /* PES stream */ 00087 return AVPROBE_SCORE_MAX/2+2; 00088 00089 //02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1 00090 return score; 00091 } 00092 00093 00094 typedef struct MpegDemuxContext { 00095 int32_t header_state; 00096 unsigned char psm_es_type[256]; 00097 int sofdec; 00098 } MpegDemuxContext; 00099 00100 static int mpegps_read_header(AVFormatContext *s, 00101 AVFormatParameters *ap) 00102 { 00103 MpegDemuxContext *m = s->priv_data; 00104 const char *sofdec = "Sofdec"; 00105 int v, i = 0; 00106 00107 m->header_state = 0xff; 00108 s->ctx_flags |= AVFMTCTX_NOHEADER; 00109 00110 m->sofdec = -1; 00111 do { 00112 v = get_byte(s->pb); 00113 m->header_state = m->header_state << 8 | v; 00114 m->sofdec++; 00115 } while (v == sofdec[i] && i++ < 6); 00116 00117 /* no need to do more */ 00118 return 0; 00119 } 00120 00121 static int64_t get_pts(ByteIOContext *pb, int c) 00122 { 00123 uint8_t buf[5]; 00124 00125 buf[0] = c<0 ? get_byte(pb) : c; 00126 get_buffer(pb, buf+1, 4); 00127 00128 return ff_parse_pes_pts(buf); 00129 } 00130 00131 static int find_next_start_code(ByteIOContext *pb, int *size_ptr, 00132 int32_t *header_state) 00133 { 00134 unsigned int state, v; 00135 int val, n; 00136 00137 state = *header_state; 00138 n = *size_ptr; 00139 while (n > 0) { 00140 if (url_feof(pb)) 00141 break; 00142 v = get_byte(pb); 00143 n--; 00144 if (state == 0x000001) { 00145 state = ((state << 8) | v) & 0xffffff; 00146 val = state; 00147 goto found; 00148 } 00149 state = ((state << 8) | v) & 0xffffff; 00150 } 00151 val = -1; 00152 found: 00153 *header_state = state; 00154 *size_ptr = n; 00155 return val; 00156 } 00157 00158 #if 0 /* unused, remove? */ 00159 /* XXX: optimize */ 00160 static int find_prev_start_code(ByteIOContext *pb, int *size_ptr) 00161 { 00162 int64_t pos, pos_start; 00163 int max_size, start_code; 00164 00165 max_size = *size_ptr; 00166 pos_start = url_ftell(pb); 00167 00168 /* in order to go faster, we fill the buffer */ 00169 pos = pos_start - 16386; 00170 if (pos < 0) 00171 pos = 0; 00172 url_fseek(pb, pos, SEEK_SET); 00173 get_byte(pb); 00174 00175 pos = pos_start; 00176 for(;;) { 00177 pos--; 00178 if (pos < 0 || (pos_start - pos) >= max_size) { 00179 start_code = -1; 00180 goto the_end; 00181 } 00182 url_fseek(pb, pos, SEEK_SET); 00183 start_code = get_be32(pb); 00184 if ((start_code & 0xffffff00) == 0x100) 00185 break; 00186 } 00187 the_end: 00188 *size_ptr = pos_start - pos; 00189 return start_code; 00190 } 00191 #endif 00192 00199 static long mpegps_psm_parse(MpegDemuxContext *m, ByteIOContext *pb) 00200 { 00201 int psm_length, ps_info_length, es_map_length; 00202 00203 psm_length = get_be16(pb); 00204 get_byte(pb); 00205 get_byte(pb); 00206 ps_info_length = get_be16(pb); 00207 00208 /* skip program_stream_info */ 00209 url_fskip(pb, ps_info_length); 00210 es_map_length = get_be16(pb); 00211 00212 /* at least one es available? */ 00213 while (es_map_length >= 4){ 00214 unsigned char type = get_byte(pb); 00215 unsigned char es_id = get_byte(pb); 00216 uint16_t es_info_length = get_be16(pb); 00217 /* remember mapping from stream id to stream type */ 00218 m->psm_es_type[es_id] = type; 00219 /* skip program_stream_info */ 00220 url_fskip(pb, es_info_length); 00221 es_map_length -= 4 + es_info_length; 00222 } 00223 get_be32(pb); /* crc32 */ 00224 return 2 + psm_length; 00225 } 00226 00227 /* read the next PES header. Return its position in ppos 00228 (if not NULL), and its start code, pts and dts. 00229 */ 00230 static int mpegps_read_pes_header(AVFormatContext *s, 00231 int64_t *ppos, int *pstart_code, 00232 int64_t *ppts, int64_t *pdts) 00233 { 00234 MpegDemuxContext *m = s->priv_data; 00235 int len, size, startcode, c, flags, header_len; 00236 int pes_ext, ext2_len, id_ext, skip; 00237 int64_t pts, dts; 00238 int64_t last_sync= url_ftell(s->pb); 00239 00240 error_redo: 00241 url_fseek(s->pb, last_sync, SEEK_SET); 00242 redo: 00243 /* next start code (should be immediately after) */ 00244 m->header_state = 0xff; 00245 size = MAX_SYNC_SIZE; 00246 startcode = find_next_start_code(s->pb, &size, &m->header_state); 00247 last_sync = url_ftell(s->pb); 00248 //printf("startcode=%x pos=0x%"PRIx64"\n", startcode, url_ftell(s->pb)); 00249 if (startcode < 0) 00250 return AVERROR(EIO); 00251 if (startcode == PACK_START_CODE) 00252 goto redo; 00253 if (startcode == SYSTEM_HEADER_START_CODE) 00254 goto redo; 00255 if (startcode == PADDING_STREAM) { 00256 url_fskip(s->pb, get_be16(s->pb)); 00257 goto redo; 00258 } 00259 if (startcode == PRIVATE_STREAM_2) { 00260 len = get_be16(s->pb); 00261 if (!m->sofdec) { 00262 while (len-- >= 6) { 00263 if (get_byte(s->pb) == 'S') { 00264 uint8_t buf[5]; 00265 get_buffer(s->pb, buf, sizeof(buf)); 00266 m->sofdec = !memcmp(buf, "ofdec", 5); 00267 len -= sizeof(buf); 00268 break; 00269 } 00270 } 00271 m->sofdec -= !m->sofdec; 00272 } 00273 url_fskip(s->pb, len); 00274 goto redo; 00275 } 00276 if (startcode == PROGRAM_STREAM_MAP) { 00277 mpegps_psm_parse(m, s->pb); 00278 goto redo; 00279 } 00280 00281 /* find matching stream */ 00282 if (!((startcode >= 0x1c0 && startcode <= 0x1df) || 00283 (startcode >= 0x1e0 && startcode <= 0x1ef) || 00284 (startcode == 0x1bd) || (startcode == 0x1fd))) 00285 goto redo; 00286 if (ppos) { 00287 *ppos = url_ftell(s->pb) - 4; 00288 } 00289 len = get_be16(s->pb); 00290 pts = 00291 dts = AV_NOPTS_VALUE; 00292 /* stuffing */ 00293 for(;;) { 00294 if (len < 1) 00295 goto error_redo; 00296 c = get_byte(s->pb); 00297 len--; 00298 /* XXX: for mpeg1, should test only bit 7 */ 00299 if (c != 0xff) 00300 break; 00301 } 00302 if ((c & 0xc0) == 0x40) { 00303 /* buffer scale & size */ 00304 get_byte(s->pb); 00305 c = get_byte(s->pb); 00306 len -= 2; 00307 } 00308 if ((c & 0xe0) == 0x20) { 00309 dts = pts = get_pts(s->pb, c); 00310 len -= 4; 00311 if (c & 0x10){ 00312 dts = get_pts(s->pb, -1); 00313 len -= 5; 00314 } 00315 } else if ((c & 0xc0) == 0x80) { 00316 /* mpeg 2 PES */ 00317 #if 0 /* some streams have this field set for no apparent reason */ 00318 if ((c & 0x30) != 0) { 00319 /* Encrypted multiplex not handled */ 00320 goto redo; 00321 } 00322 #endif 00323 flags = get_byte(s->pb); 00324 header_len = get_byte(s->pb); 00325 len -= 2; 00326 if (header_len > len) 00327 goto error_redo; 00328 len -= header_len; 00329 if (flags & 0x80) { 00330 dts = pts = get_pts(s->pb, -1); 00331 header_len -= 5; 00332 if (flags & 0x40) { 00333 dts = get_pts(s->pb, -1); 00334 header_len -= 5; 00335 } 00336 } 00337 if (flags & 0x3f && header_len == 0){ 00338 flags &= 0xC0; 00339 av_log(s, AV_LOG_WARNING, "Further flags set but no bytes left\n"); 00340 } 00341 if (flags & 0x01) { /* PES extension */ 00342 pes_ext = get_byte(s->pb); 00343 header_len--; 00344 /* Skip PES private data, program packet sequence counter and P-STD buffer */ 00345 skip = (pes_ext >> 4) & 0xb; 00346 skip += skip & 0x9; 00347 if (pes_ext & 0x40 || skip > header_len){ 00348 av_log(s, AV_LOG_WARNING, "pes_ext %X is invalid\n", pes_ext); 00349 pes_ext=skip=0; 00350 } 00351 url_fskip(s->pb, skip); 00352 header_len -= skip; 00353 00354 if (pes_ext & 0x01) { /* PES extension 2 */ 00355 ext2_len = get_byte(s->pb); 00356 header_len--; 00357 if ((ext2_len & 0x7f) > 0) { 00358 id_ext = get_byte(s->pb); 00359 if ((id_ext & 0x80) == 0) 00360 startcode = ((startcode & 0xff) << 8) | id_ext; 00361 header_len--; 00362 } 00363 } 00364 } 00365 if(header_len < 0) 00366 goto error_redo; 00367 url_fskip(s->pb, header_len); 00368 } 00369 else if( c!= 0xf ) 00370 goto redo; 00371 00372 if (startcode == PRIVATE_STREAM_1 && !m->psm_es_type[startcode & 0xff]) { 00373 startcode = get_byte(s->pb); 00374 len--; 00375 if (startcode >= 0x80 && startcode <= 0xcf) { 00376 /* audio: skip header */ 00377 get_byte(s->pb); 00378 get_byte(s->pb); 00379 get_byte(s->pb); 00380 len -= 3; 00381 if (startcode >= 0xb0 && startcode <= 0xbf) { 00382 /* MLP/TrueHD audio has a 4-byte header */ 00383 get_byte(s->pb); 00384 len--; 00385 } 00386 } 00387 } 00388 if(len<0) 00389 goto error_redo; 00390 if(dts != AV_NOPTS_VALUE && ppos){ 00391 int i; 00392 for(i=0; i<s->nb_streams; i++){ 00393 if(startcode == s->streams[i]->id && 00394 !url_is_streamed(s->pb) /* index useless on streams anyway */) { 00395 ff_reduce_index(s, i); 00396 av_add_index_entry(s->streams[i], *ppos, dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */); 00397 } 00398 } 00399 } 00400 00401 *pstart_code = startcode; 00402 *ppts = pts; 00403 *pdts = dts; 00404 return len; 00405 } 00406 00407 static int mpegps_read_packet(AVFormatContext *s, 00408 AVPacket *pkt) 00409 { 00410 MpegDemuxContext *m = s->priv_data; 00411 AVStream *st; 00412 int len, startcode, i, es_type; 00413 enum CodecID codec_id = CODEC_ID_NONE; 00414 enum CodecType type; 00415 int64_t pts, dts, dummy_pos; //dummy_pos is needed for the index building to work 00416 uint8_t dvdaudio_substream_type; 00417 00418 redo: 00419 len = mpegps_read_pes_header(s, &dummy_pos, &startcode, &pts, &dts); 00420 if (len < 0) 00421 return len; 00422 00423 if(startcode == 0x1bd) { 00424 dvdaudio_substream_type = get_byte(s->pb); 00425 url_fskip(s->pb, 3); 00426 len -= 4; 00427 } 00428 00429 /* now find stream */ 00430 for(i=0;i<s->nb_streams;i++) { 00431 st = s->streams[i]; 00432 if (st->id == startcode) 00433 goto found; 00434 } 00435 00436 es_type = m->psm_es_type[startcode & 0xff]; 00437 if(es_type > 0 && es_type != STREAM_TYPE_PRIVATE_DATA){ 00438 if(es_type == STREAM_TYPE_VIDEO_MPEG1){ 00439 codec_id = CODEC_ID_MPEG2VIDEO; 00440 type = CODEC_TYPE_VIDEO; 00441 } else if(es_type == STREAM_TYPE_VIDEO_MPEG2){ 00442 codec_id = CODEC_ID_MPEG2VIDEO; 00443 type = CODEC_TYPE_VIDEO; 00444 } else if(es_type == STREAM_TYPE_AUDIO_MPEG1 || 00445 es_type == STREAM_TYPE_AUDIO_MPEG2){ 00446 codec_id = CODEC_ID_MP3; 00447 type = CODEC_TYPE_AUDIO; 00448 } else if(es_type == STREAM_TYPE_AUDIO_AAC){ 00449 codec_id = CODEC_ID_AAC; 00450 type = CODEC_TYPE_AUDIO; 00451 } else if(es_type == STREAM_TYPE_VIDEO_MPEG4){ 00452 codec_id = CODEC_ID_MPEG4; 00453 type = CODEC_TYPE_VIDEO; 00454 } else if(es_type == STREAM_TYPE_VIDEO_H264){ 00455 codec_id = CODEC_ID_H264; 00456 type = CODEC_TYPE_VIDEO; 00457 } else if(es_type == STREAM_TYPE_AUDIO_AC3){ 00458 codec_id = CODEC_ID_AC3; 00459 type = CODEC_TYPE_AUDIO; 00460 } else { 00461 goto skip; 00462 } 00463 } else if (startcode >= 0x1e0 && startcode <= 0x1ef) { 00464 static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 }; 00465 unsigned char buf[8]; 00466 get_buffer(s->pb, buf, 8); 00467 url_fseek(s->pb, -8, SEEK_CUR); 00468 if(!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1)) 00469 codec_id = CODEC_ID_CAVS; 00470 else 00471 codec_id = CODEC_ID_PROBE; 00472 type = CODEC_TYPE_VIDEO; 00473 } else if (startcode >= 0x1c0 && startcode <= 0x1df) { 00474 type = CODEC_TYPE_AUDIO; 00475 codec_id = m->sofdec > 0 ? CODEC_ID_ADPCM_ADX : CODEC_ID_MP2; 00476 } else if (startcode >= 0x80 && startcode <= 0x87) { 00477 type = CODEC_TYPE_AUDIO; 00478 codec_id = CODEC_ID_AC3; 00479 } else if ( ( startcode >= 0x88 && startcode <= 0x8f) 00480 ||( startcode >= 0x98 && startcode <= 0x9f)) { 00481 /* 0x90 - 0x97 is reserved for SDDS in DVD specs */ 00482 type = CODEC_TYPE_AUDIO; 00483 codec_id = CODEC_ID_DTS; 00484 } else if (startcode >= 0xa0 && startcode <= 0xaf) { 00485 type = CODEC_TYPE_AUDIO; 00486 /* 16 bit form will be handled as CODEC_ID_PCM_S16BE */ 00487 codec_id = CODEC_ID_PCM_DVD; 00488 } else if (startcode >= 0xb0 && startcode <= 0xbf) { 00489 type = CODEC_TYPE_AUDIO; 00490 codec_id = CODEC_ID_MLP; 00491 } else if (startcode >= 0xc0 && startcode <= 0xcf) { 00492 /* Used for both AC-3 and E-AC-3 in EVOB files */ 00493 type = CODEC_TYPE_AUDIO; 00494 codec_id = CODEC_ID_AC3; 00495 } else if (startcode >= 0x20 && startcode <= 0x3f) { 00496 type = CODEC_TYPE_SUBTITLE; 00497 codec_id = CODEC_ID_DVD_SUBTITLE; 00498 } else if (startcode >= 0xfd55 && startcode <= 0xfd5f) { 00499 type = CODEC_TYPE_VIDEO; 00500 codec_id = CODEC_ID_VC1; 00501 } else if (startcode == 0x1bd) { 00502 // check dvd audio substream type 00503 type = CODEC_TYPE_AUDIO; 00504 switch(dvdaudio_substream_type & 0xe0) { 00505 case 0xa0: codec_id = CODEC_ID_PCM_DVD; 00506 break; 00507 case 0x80: if((dvdaudio_substream_type & 0xf8) == 0x88) 00508 codec_id = CODEC_ID_DTS; 00509 else codec_id = CODEC_ID_AC3; 00510 break; 00511 default: av_log(s, AV_LOG_ERROR, "Unknown 0x1bd sub-stream\n"); 00512 goto skip; 00513 } 00514 } else { 00515 skip: 00516 /* skip packet */ 00517 url_fskip(s->pb, len); 00518 goto redo; 00519 } 00520 /* no stream found: add a new stream */ 00521 st = av_new_stream(s, startcode); 00522 if (!st) 00523 goto skip; 00524 st->codec->codec_type = type; 00525 st->codec->codec_id = codec_id; 00526 if (codec_id != CODEC_ID_PCM_S16BE) 00527 st->need_parsing = AVSTREAM_PARSE_FULL; 00528 found: 00529 if(st->discard >= AVDISCARD_ALL) 00530 goto skip; 00531 if ((startcode >= 0xa0 && startcode <= 0xaf) || 00532 (startcode == 0x1bd && ((dvdaudio_substream_type & 0xe0) == 0xa0))) { 00533 int b1, freq; 00534 00535 /* for LPCM, we just skip the header and consider it is raw 00536 audio data */ 00537 if (len <= 3) 00538 goto skip; 00539 get_byte(s->pb); /* emphasis (1), muse(1), reserved(1), frame number(5) */ 00540 b1 = get_byte(s->pb); /* quant (2), freq(2), reserved(1), channels(3) */ 00541 get_byte(s->pb); /* dynamic range control (0x80 = off) */ 00542 len -= 3; 00543 freq = (b1 >> 4) & 3; 00544 st->codec->sample_rate = lpcm_freq_tab[freq]; 00545 st->codec->channels = 1 + (b1 & 7); 00546 st->codec->bits_per_coded_sample = 16 + ((b1 >> 6) & 3) * 4; 00547 st->codec->bit_rate = st->codec->channels * 00548 st->codec->sample_rate * 00549 st->codec->bits_per_coded_sample; 00550 if (st->codec->bits_per_coded_sample == 16) 00551 st->codec->codec_id = CODEC_ID_PCM_S16BE; 00552 else if (st->codec->bits_per_coded_sample == 28) 00553 return AVERROR(EINVAL); 00554 } 00555 av_new_packet(pkt, len); 00556 get_buffer(s->pb, pkt->data, pkt->size); 00557 pkt->pts = pts; 00558 pkt->dts = dts; 00559 pkt->stream_index = st->index; 00560 #if 0 00561 av_log(s, AV_LOG_DEBUG, "%d: pts=%0.3f dts=%0.3f size=%d\n", 00562 pkt->stream_index, pkt->pts / 90000.0, pkt->dts / 90000.0, pkt->size); 00563 #endif 00564 00565 return 0; 00566 } 00567 00568 static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, 00569 int64_t *ppos, int64_t pos_limit) 00570 { 00571 int len, startcode; 00572 int64_t pos, pts, dts; 00573 00574 pos = *ppos; 00575 #ifdef DEBUG_SEEK 00576 printf("read_dts: pos=0x%"PRIx64" next=%d -> ", pos, find_next); 00577 #endif 00578 if (url_fseek(s->pb, pos, SEEK_SET) < 0) 00579 return AV_NOPTS_VALUE; 00580 00581 for(;;) { 00582 len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts); 00583 if (len < 0) { 00584 #ifdef DEBUG_SEEK 00585 printf("none (ret=%d)\n", len); 00586 #endif 00587 return AV_NOPTS_VALUE; 00588 } 00589 if (startcode == s->streams[stream_index]->id && 00590 dts != AV_NOPTS_VALUE) { 00591 break; 00592 } 00593 url_fskip(s->pb, len); 00594 } 00595 #ifdef DEBUG_SEEK 00596 printf("pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n", pos, dts, dts / 90000.0); 00597 #endif 00598 *ppos = pos; 00599 return dts; 00600 } 00601 00602 AVInputFormat mpegps_demuxer = { 00603 "mpeg", 00604 NULL_IF_CONFIG_SMALL("MPEG-PS format"), 00605 sizeof(MpegDemuxContext), 00606 mpegps_probe, 00607 mpegps_read_header, 00608 mpegps_read_packet, 00609 NULL, 00610 NULL, //mpegps_read_seek, 00611 mpegps_read_dts, 00612 .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, 00613 };