Mercurial > libavformat.hg
annotate mpegts.c @ 107:d73becdbbda5 libavformat
avoid detecting mpeg stream when other formats embed mp3 tracks.
| author | mmu_man |
|---|---|
| date | Fri, 18 Apr 2003 14:35:15 +0000 |
| parents | a58a8a53eb46 |
| children | cc03a75cbde4 |
| rev | line source |
|---|---|
| 0 | 1 /* |
| 2 * MPEG2 transport stream (aka DVB) demux | |
| 3 * Copyright (c) 2002 Fabrice Bellard. | |
| 4 * | |
| 5 * This library is free software; you can redistribute it and/or | |
| 6 * modify it under the terms of the GNU Lesser General Public | |
| 7 * License as published by the Free Software Foundation; either | |
| 8 * version 2 of the License, or (at your option) any later version. | |
| 9 * | |
| 10 * This library is distributed in the hope that it will be useful, | |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 * Lesser General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU Lesser General Public | |
| 16 * License along with this library; if not, write to the Free Software | |
| 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 18 */ | |
| 19 #include "avformat.h" | |
| 20 | |
| 21 #define TS_FEC_PACKET_SIZE 204 | |
| 22 #define TS_PACKET_SIZE 188 | |
| 23 #define NB_PID_MAX 8192 | |
| 24 | |
| 25 enum MpegTSState { | |
| 26 MPEGTS_HEADER = 0, | |
| 27 MPEGTS_PESHEADER_FILL, | |
| 28 MPEGTS_PESHEADER_FLAGS, | |
| 29 MPEGTS_PESHEADER_SIZE, | |
| 30 MPEGTS_PESHEADER_READ, | |
| 31 MPEGTS_PAYLOAD, | |
| 32 MPEGTS_SKIP, | |
| 33 }; | |
| 34 | |
| 35 /* enough for PES header + length */ | |
| 36 #define MAX_HEADER_SIZE 6 | |
| 37 | |
| 38 typedef struct MpegTSStream { | |
| 39 int pid; | |
| 40 enum MpegTSState state; | |
| 41 int last_cc; /* last cc code (-1 if first packet) */ | |
| 42 /* used to get the format */ | |
| 43 int header_size; | |
| 44 int payload_size; | |
| 45 int pes_header_size; | |
| 46 AVStream *st; | |
| 47 unsigned char header[MAX_HEADER_SIZE]; | |
| 48 } MpegTSStream; | |
| 49 | |
| 50 typedef struct MpegTSContext { | |
| 51 int raw_packet_size; /* raw packet size, including FEC if present */ | |
| 52 MpegTSStream *pids[NB_PID_MAX]; | |
| 53 } MpegTSContext; | |
| 54 | |
| 55 /* autodetect fec presence. Must have at least 1024 bytes */ | |
| 56 static int get_packet_size(const unsigned char *buf, int size) | |
| 57 { | |
| 58 int i; | |
| 59 | |
| 60 if (size < (TS_FEC_PACKET_SIZE * 5 + 1)) | |
| 61 return -1; | |
| 62 for(i=0;i<5;i++) { | |
| 63 if (buf[i * TS_PACKET_SIZE] != 0x47) | |
| 64 goto try_fec; | |
| 65 } | |
| 66 return TS_PACKET_SIZE; | |
| 67 try_fec: | |
| 68 for(i=0;i<5;i++) { | |
| 69 if (buf[i * TS_FEC_PACKET_SIZE] != 0x47) | |
| 70 return -1; | |
| 71 } | |
| 72 return TS_FEC_PACKET_SIZE; | |
| 73 } | |
| 74 | |
| 75 static int mpegts_probe(AVProbeData *p) | |
| 76 { | |
| 77 int size; | |
| 78 size = get_packet_size(p->buf, p->buf_size); | |
| 79 if (size < 0) | |
| 80 return 0; | |
|
107
d73becdbbda5
avoid detecting mpeg stream when other formats embed mp3 tracks.
mmu_man
parents:
65
diff
changeset
|
81 return AVPROBE_SCORE_MAX - 1; |
| 0 | 82 } |
| 83 | |
| 84 static int mpegts_read_header(AVFormatContext *s, | |
| 85 AVFormatParameters *ap) | |
| 86 { | |
| 87 MpegTSContext *ts = s->priv_data; | |
| 88 ByteIOContext *pb = &s->pb; | |
| 89 unsigned char buf[1024]; | |
| 90 int len; | |
| 65 | 91 int64_t pos; |
| 0 | 92 |
| 93 /* read the first 1024 bytes to get packet size */ | |
| 94 pos = url_ftell(pb); | |
| 95 len = get_buffer(pb, buf, sizeof(buf)); | |
| 96 if (len != sizeof(buf)) | |
| 97 goto fail; | |
| 98 ts->raw_packet_size = get_packet_size(buf, sizeof(buf)); | |
| 99 if (ts->raw_packet_size <= 0) | |
| 100 goto fail; | |
| 101 /* go again to the start */ | |
| 102 url_fseek(pb, pos, SEEK_SET); | |
| 103 return 0; | |
| 104 fail: | |
| 105 return -1; | |
| 106 } | |
| 107 | |
| 108 /* return non zero if a packet could be constructed */ | |
| 109 static int mpegts_push_data(AVFormatContext *s, MpegTSStream *tss, | |
| 110 AVPacket *pkt, | |
| 111 const unsigned char *buf, int buf_size, int is_start) | |
| 112 { | |
| 113 AVStream *st; | |
| 114 const unsigned char *p; | |
| 115 int len, code, codec_type, codec_id; | |
| 116 | |
| 117 if (is_start) { | |
| 118 tss->state = MPEGTS_HEADER; | |
| 119 tss->header_size = 0; | |
| 120 } | |
| 121 p = buf; | |
| 122 while (buf_size > 0) { | |
| 123 len = buf_size; | |
| 124 switch(tss->state) { | |
| 125 case MPEGTS_HEADER: | |
| 126 if (len > MAX_HEADER_SIZE - tss->header_size) | |
| 127 len = MAX_HEADER_SIZE - tss->header_size; | |
| 128 memcpy(tss->header, p, len); | |
| 129 tss->header_size += len; | |
| 130 p += len; | |
| 131 buf_size -= len; | |
| 132 if (tss->header_size == MAX_HEADER_SIZE) { | |
| 133 /* we got all the PES or section header. We can now | |
| 134 decide */ | |
| 135 #if 0 | |
| 136 av_hex_dump(tss->header, tss->header_size); | |
| 137 #endif | |
| 138 if (tss->header[0] == 0x00 && tss->header[1] == 0x00 && | |
| 139 tss->header[2] == 0x01) { | |
| 140 /* it must be an mpeg2 PES stream */ | |
| 141 /* XXX: add AC3 support */ | |
| 142 code = tss->header[3] | 0x100; | |
| 143 if (!((code >= 0x1c0 && code <= 0x1df) || | |
| 144 (code >= 0x1e0 && code <= 0x1ef))) | |
| 145 goto skip; | |
| 146 if (!tss->st) { | |
| 147 /* allocate stream */ | |
| 148 if (code >= 0x1c0 && code <= 0x1df) { | |
| 149 codec_type = CODEC_TYPE_AUDIO; | |
| 150 codec_id = CODEC_ID_MP2; | |
| 151 } else { | |
| 152 codec_type = CODEC_TYPE_VIDEO; | |
| 153 codec_id = CODEC_ID_MPEG1VIDEO; | |
| 154 } | |
| 155 st = av_new_stream(s, tss->pid); | |
| 156 if (st) { | |
| 157 st->priv_data = tss; | |
| 158 st->codec.codec_type = codec_type; | |
| 159 st->codec.codec_id = codec_id; | |
| 160 tss->st = st; | |
| 161 } | |
| 162 } | |
| 163 tss->state = MPEGTS_PESHEADER_FILL; | |
| 164 tss->payload_size = (tss->header[4] << 8) | tss->header[5]; | |
| 165 if (tss->payload_size == 0) | |
| 166 tss->payload_size = 65536; | |
| 167 } else { | |
| 168 /* otherwise, it should be a table */ | |
| 169 /* skip packet */ | |
| 170 skip: | |
| 171 tss->state = MPEGTS_SKIP; | |
| 172 continue; | |
| 173 } | |
| 174 } | |
| 175 break; | |
| 176 /**********************************************/ | |
| 177 /* PES packing parsing */ | |
| 178 case MPEGTS_PESHEADER_FILL: | |
| 179 /* skip filling */ | |
| 180 code = *p++; | |
| 181 buf_size--; | |
| 182 tss->payload_size--; | |
| 183 if (code != 0xff) { | |
| 184 if ((code & 0xc0) != 0x80) | |
| 185 goto skip; | |
| 186 tss->state = MPEGTS_PESHEADER_FLAGS; | |
| 187 } | |
| 188 break; | |
| 189 case MPEGTS_PESHEADER_FLAGS: | |
| 190 code = *p++; | |
| 191 buf_size--; | |
| 192 tss->payload_size--; | |
| 193 tss->state = MPEGTS_PESHEADER_SIZE; | |
| 194 break; | |
| 195 case MPEGTS_PESHEADER_SIZE: | |
| 196 tss->pes_header_size = *p++; | |
| 197 buf_size--; | |
| 198 tss->payload_size--; | |
| 199 tss->state = MPEGTS_PESHEADER_READ; | |
| 200 break; | |
| 201 case MPEGTS_PESHEADER_READ: | |
| 202 /* currently we do nothing except skipping */ | |
| 203 if (len > tss->pes_header_size) | |
| 204 len = tss->pes_header_size; | |
| 205 p += len; | |
| 206 buf_size -= len; | |
| 207 tss->pes_header_size -= len; | |
| 208 tss->payload_size -= len; | |
| 209 if (tss->pes_header_size == 0) | |
| 210 tss->state = MPEGTS_PAYLOAD; | |
| 211 break; | |
| 212 case MPEGTS_PAYLOAD: | |
| 213 if (len > tss->payload_size) | |
| 214 len = tss->payload_size; | |
| 215 if (len > 0) { | |
| 216 if (tss->st && av_new_packet(pkt, buf_size) == 0) { | |
| 217 memcpy(pkt->data, p, buf_size); | |
| 218 pkt->stream_index = tss->st->index; | |
| 219 return 1; | |
| 220 } | |
| 221 tss->payload_size -= len; | |
| 222 } | |
| 223 buf_size = 0; | |
| 224 break; | |
| 225 case MPEGTS_SKIP: | |
| 226 buf_size = 0; | |
| 227 break; | |
| 228 } | |
| 229 } | |
| 230 return 0; | |
| 231 } | |
| 232 | |
| 233 static int mpegts_read_packet(AVFormatContext *s, | |
| 234 AVPacket *pkt) | |
| 235 { | |
| 236 MpegTSContext *ts = s->priv_data; | |
| 237 MpegTSStream *tss; | |
| 238 ByteIOContext *pb = &s->pb; | |
| 239 unsigned char packet[TS_FEC_PACKET_SIZE]; | |
| 240 int len, pid, cc, cc_ok, afc; | |
| 241 const unsigned char *p; | |
| 242 | |
| 243 for(;;) { | |
| 244 len = get_buffer(pb, packet, ts->raw_packet_size); | |
| 245 if (len != ts->raw_packet_size) | |
| 246 return AVERROR_IO; | |
| 247 /* check paquet sync byte */ | |
| 248 /* XXX: accept to resync ? */ | |
| 249 if (packet[0] != 0x47) | |
| 250 return AVERROR_INVALIDDATA; | |
| 251 | |
| 252 pid = ((packet[1] & 0x1f) << 8) | packet[2]; | |
| 253 tss = ts->pids[pid]; | |
| 254 if (tss == NULL) { | |
| 255 /* if no pid found, then add a pid context */ | |
| 256 tss = av_mallocz(sizeof(MpegTSStream)); | |
| 257 if (!tss) | |
| 258 continue; | |
| 259 ts->pids[pid] = tss; | |
| 260 tss->pid = pid; | |
| 261 tss->last_cc = -1; | |
| 262 // printf("new pid=0x%x\n", pid); | |
| 263 } | |
| 264 | |
| 265 /* continuity check (currently not used) */ | |
| 266 cc = (packet[3] & 0xf); | |
| 267 cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); | |
| 268 tss->last_cc = cc; | |
| 269 | |
| 270 /* skip adaptation field */ | |
| 271 afc = (packet[3] >> 4) & 3; | |
| 272 p = packet + 4; | |
| 273 if (afc == 0) /* reserved value */ | |
| 274 continue; | |
| 275 if (afc == 2) /* adaptation field only */ | |
| 276 continue; | |
| 277 if (afc == 3) { | |
| 278 /* skip adapation field */ | |
| 279 p += p[0] + 1; | |
| 280 } | |
| 281 /* if past the end of packet, ignore */ | |
| 282 if (p >= packet + TS_PACKET_SIZE) | |
| 283 continue; | |
| 284 | |
| 285 if (mpegts_push_data(s, tss, pkt, p, TS_PACKET_SIZE - (p - packet), | |
| 286 packet[1] & 0x40)) | |
| 287 break; | |
| 288 } | |
| 289 return 0; | |
| 290 } | |
| 291 | |
| 292 static int mpegts_read_close(AVFormatContext *s) | |
| 293 { | |
| 294 MpegTSContext *ts = s->priv_data; | |
| 295 int i; | |
| 296 for(i=0;i<NB_PID_MAX;i++) | |
| 297 av_free(ts->pids[i]); | |
| 298 return 0; | |
| 299 } | |
| 300 | |
| 301 AVInputFormat mpegts_demux = { | |
| 302 "mpegts", | |
| 303 "MPEG2 transport stream format", | |
| 304 sizeof(MpegTSContext), | |
| 305 mpegts_probe, | |
| 306 mpegts_read_header, | |
| 307 mpegts_read_packet, | |
| 308 mpegts_read_close, | |
| 309 .flags = AVFMT_NOHEADER | AVFMT_SHOW_IDS, | |
| 310 }; | |
| 311 | |
| 312 int mpegts_init(void) | |
| 313 { | |
| 314 av_register_input_format(&mpegts_demux); | |
| 315 return 0; | |
| 316 } |
