📄 mpegts.c
字号:
} return 0;}static int mpegts_probe(AVProbeData *p){#if 1 const int size= p->buf_size; int score, fec_score;#define CHECK_COUNT 10 if (size < (TS_FEC_PACKET_SIZE * CHECK_COUNT)) return -1; score = analyze(p->buf, TS_PACKET_SIZE *CHECK_COUNT, TS_PACKET_SIZE, NULL); fec_score= analyze(p->buf, TS_FEC_PACKET_SIZE*CHECK_COUNT, TS_FEC_PACKET_SIZE, NULL);// av_log(NULL, AV_LOG_DEBUG, "score: %d, fec_score: %d \n", score, fec_score); // we need a clear definition for the returned score otherwise things will become messy sooner or later if (score > fec_score && score > 6) return AVPROBE_SCORE_MAX + score - CHECK_COUNT; else if( fec_score > 6) return AVPROBE_SCORE_MAX + fec_score - CHECK_COUNT; else return -1;#else /* only use the extension for safer guess */ if (match_ext(p->filename, "ts")) return AVPROBE_SCORE_MAX; else return 0;#endif}void set_service_cb(void *opaque, int ret){ MpegTSContext *ts = opaque; ts->set_service_ret = ret; ts->stop_parse = 1;}/* return the 90 kHz PCR and the extension for the 27 MHz PCR. return (-1) if not available */static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet){ int afc, len, flags; const uint8_t *p; unsigned int v; afc = (packet[3] >> 4) & 3; if (afc <= 1) return -1; p = packet + 4; len = p[0]; p++; if (len == 0) return -1; flags = *p++; len--; if (!(flags & 0x10)) return -1; if (len < 6) return -1; v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; *ppcr_high = ((int64_t)v << 1) | (p[4] >> 7); *ppcr_low = ((p[4] & 1) << 8) | p[5]; return 0;}static int mpegts_read_header(AVFormatContext *s, AVFormatParameters *ap){ MpegTSContext *ts = s->priv_data; ByteIOContext *pb = &s->pb; uint8_t buf[1024]; int len, sid; int64_t pos; MpegTSService *service; if (ap) { ts->mpeg2ts_raw = ap->mpeg2ts_raw; ts->mpeg2ts_compute_pcr = ap->mpeg2ts_compute_pcr; } /* read the first 1024 bytes to get packet size */ pos = url_ftell(pb); len = get_buffer(pb, buf, sizeof(buf)); if (len != sizeof(buf)) goto fail; ts->raw_packet_size = get_packet_size(buf, sizeof(buf)); if (ts->raw_packet_size <= 0) goto fail; ts->stream = s; ts->auto_guess = 0; if (!ts->mpeg2ts_raw) { /* normal demux */ if (!ts->auto_guess) { ts->set_service_ret = -1; /* first do a scaning to get all the services */ url_fseek(pb, pos, SEEK_SET); mpegts_scan_sdt(ts); handle_packets(ts, MAX_SCAN_PACKETS); if (ts->nb_services <= 0) { /* no SDT found, we try to look at the PAT */ /* First remove the SDT filters from each PID */ int i; for (i=0; i < NB_PID_MAX; i++) { if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]); } url_fseek(pb, pos, SEEK_SET); mpegts_scan_pat(ts); handle_packets(ts, MAX_SCAN_PACKETS); } if (ts->nb_services <= 0) { /* raw transport stream */ ts->auto_guess = 1; s->ctx_flags |= AVFMTCTX_NOHEADER; goto do_pcr; } /* tune to first service found */ service = ts->services[0]; sid = service->sid;#ifdef DEBUG_SI printf("tuning to '%s'\n", service->name);#endif /* now find the info for the first service if we found any, otherwise try to filter all PATs */ url_fseek(pb, pos, SEEK_SET); mpegts_set_service(ts, sid, set_service_cb, ts); handle_packets(ts, MAX_SCAN_PACKETS); /* if could not find service, exit */ if (ts->set_service_ret != 0) return -1; #ifdef DEBUG_SI printf("tuning done\n");#endif } s->ctx_flags |= AVFMTCTX_NOHEADER; } else { AVStream *st; int pcr_pid, pid, nb_packets, nb_pcrs, ret, pcr_l; int64_t pcrs[2], pcr_h; int packet_count[2]; uint8_t packet[TS_PACKET_SIZE]; /* only read packets */ s->pts_num = 1; s->pts_den = 27000000; do_pcr: st = av_new_stream(s, 0); if (!st) goto fail; st->codec.codec_type = CODEC_TYPE_DATA; st->codec.codec_id = CODEC_ID_MPEG2TS; /* we iterate until we find two PCRs to estimate the bitrate */ pcr_pid = -1; nb_pcrs = 0; nb_packets = 0; for(;;) { ret = read_packet(&s->pb, packet, ts->raw_packet_size); if (ret < 0) return -1; pid = ((packet[1] & 0x1f) << 8) | packet[2]; if ((pcr_pid == -1 || pcr_pid == pid) && parse_pcr(&pcr_h, &pcr_l, packet) == 0) { pcr_pid = pid; packet_count[nb_pcrs] = nb_packets; pcrs[nb_pcrs] = pcr_h * 300 + pcr_l; nb_pcrs++; if (nb_pcrs >= 2) break; } nb_packets++; } ts->pcr_pid = pcr_pid; /* NOTE1: the bitrate is computed without the FEC */ /* NOTE2: it is only the bitrate of the start of the stream */ ts->pcr_incr = (pcrs[1] - pcrs[0]) / (packet_count[1] - packet_count[0]); ts->cur_pcr = pcrs[0] - ts->pcr_incr * packet_count[0]; s->bit_rate = (TS_PACKET_SIZE * 8) * 27e6 / ts->pcr_incr; st->codec.bit_rate = s->bit_rate; st->start_time = ts->cur_pcr * 1000000.0 / 27.0e6;#if 0 printf("start=%0.3f pcr=%0.3f incr=%d\n", st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);#endif } url_fseek(pb, pos, SEEK_SET); return 0; fail: return -1;}#define MAX_PACKET_READAHEAD ((128 * 1024) / 188)static int mpegts_raw_read_packet(AVFormatContext *s, AVPacket *pkt){ MpegTSContext *ts = s->priv_data; int ret, i; int64_t pcr_h, next_pcr_h, pos; int pcr_l, next_pcr_l; uint8_t pcr_buf[12]; if (av_new_packet(pkt, TS_PACKET_SIZE) < 0) return -ENOMEM; ret = read_packet(&s->pb, pkt->data, ts->raw_packet_size); if (ret < 0) { av_free_packet(pkt); return ret; } if (ts->mpeg2ts_compute_pcr) { /* compute exact PCR for each packet */ if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) { /* we read the next PCR (XXX: optimize it by using a bigger buffer */ pos = url_ftell(&s->pb); for(i = 0; i < MAX_PACKET_READAHEAD; i++) { url_fseek(&s->pb, pos + i * ts->raw_packet_size, SEEK_SET); get_buffer(&s->pb, pcr_buf, 12); if (parse_pcr(&next_pcr_h, &next_pcr_l, pcr_buf) == 0) { /* XXX: not precise enough */ ts->pcr_incr = ((next_pcr_h - pcr_h) * 300 + (next_pcr_l - pcr_l)) / (i + 1); break; } } url_fseek(&s->pb, pos, SEEK_SET); /* no next PCR found: we use previous increment */ ts->cur_pcr = pcr_h * 300 + pcr_l; } pkt->pts = ts->cur_pcr; pkt->duration = ts->pcr_incr; ts->cur_pcr += ts->pcr_incr; } pkt->stream_index = 0; return 0;}static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt){ MpegTSContext *ts = s->priv_data; if (!ts->mpeg2ts_raw) { ts->pkt = pkt; return handle_packets(ts, 0); } else { return mpegts_raw_read_packet(s, pkt); }}static int mpegts_read_close(AVFormatContext *s){ MpegTSContext *ts = s->priv_data; int i; for(i=0;i<NB_PID_MAX;i++) if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]); return 0;}static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, int64_t *ppos, int find_next){ MpegTSContext *ts = s->priv_data; int64_t pos, timestamp; uint8_t buf[TS_PACKET_SIZE]; int pcr_l, pid; pos = *ppos; if (find_next) { for(;;) { url_fseek(&s->pb, pos, SEEK_SET); if (get_buffer(&s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) return AV_NOPTS_VALUE; pid = ((buf[1] & 0x1f) << 8) | buf[2]; if (pid == ts->pcr_pid && parse_pcr(×tamp, &pcr_l, buf) == 0) { break; } pos += ts->raw_packet_size; } } else { for(;;) { pos -= ts->raw_packet_size; if (pos < 0) return AV_NOPTS_VALUE; url_fseek(&s->pb, pos, SEEK_SET); if (get_buffer(&s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) return AV_NOPTS_VALUE; pid = ((buf[1] & 0x1f) << 8) | buf[2]; if (pid == ts->pcr_pid && parse_pcr(×tamp, &pcr_l, buf) == 0) { break; } } } *ppos = pos; return timestamp;}typedef int64_t ReadTimestampFunc(AVFormatContext *s, int stream_index, int64_t *ppos, int find_next);static int64_t do_block_align(int64_t val, int block_align){ return (val / block_align) * block_align;}/* XXX: use it in other formats */static int timestamp_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, ReadTimestampFunc *read_timestamp, int block_align){ int64_t pos_min, pos_max, pos; int64_t dts_min, dts_max, dts;#ifdef DEBUG_SEEK printf("read_seek: %d %0.3f\n", stream_index, timestamp / 90000.0);#endif pos_min = 0; dts_min = read_timestamp(s, stream_index, &pos_min, 1); if (dts_min == AV_NOPTS_VALUE) { /* we can reach this case only if no PTS are present in the whole stream */ return -1; } pos_max = do_block_align(url_filesize(url_fileno(&s->pb)), block_align) - block_align; dts_max = read_timestamp(s, stream_index, &pos_max, 0); while (pos_min <= pos_max) {#ifdef DEBUG_SEEK printf("pos_min=0x%llx pos_max=0x%llx dts_min=%0.3f dts_max=%0.3f\n", pos_min, pos_max, dts_min / 90000.0, dts_max / 90000.0);#endif if (timestamp <= dts_min) { pos = pos_min; goto found; } else if (timestamp >= dts_max) { pos = pos_max; goto found; } else { /* interpolate position (better than dichotomy) */ pos = (int64_t)((double)(pos_max - pos_min) * (double)(timestamp - dts_min) / (double)(dts_max - dts_min)) + pos_min; pos = do_block_align(pos, block_align); }#ifdef DEBUG_SEEK printf("pos=0x%llx\n", pos);#endif /* read the next timestamp */ dts = read_timestamp(s, stream_index, &pos, 1); /* check if we are lucky */ if (dts == AV_NOPTS_VALUE) { /* should never happen */ pos = pos_min; goto found; } else if (timestamp == dts) { goto found; } else if (timestamp < dts) { pos_max = pos; dts_max = read_timestamp(s, stream_index, &pos_max, 0); if (dts_max == AV_NOPTS_VALUE) { /* should never happen */ break; } else if (timestamp >= dts_max) { pos = pos_max; goto found; } } else { pos_min = pos + block_align; dts_min = read_timestamp(s, stream_index, &pos_min, 1); if (dts_min == AV_NOPTS_VALUE) { /* should never happen */ goto found; } else if (timestamp <= dts_min) { goto found; } } } pos = pos_min; found:#ifdef DEBUG_SEEK pos_min = pos; dts_min = read_timestamp(s, stream_index, &pos_min, 1); pos_min += block_align; dts_max = read_timestamp(s, stream_index, &pos_min, 1); printf("pos=0x%llx %0.3f<=%0.3f<=%0.3f\n", pos, dts_min / 90000.0, timestamp / 90000.0, dts_max / 90000.0);#endif /* do the seek */ url_fseek(&s->pb, pos, SEEK_SET); return 0;}static int mpegts_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp){ MpegTSContext *ts = s->priv_data; timestamp = (timestamp * 90000) / AV_TIME_BASE; return timestamp_read_seek(s, stream_index, timestamp, mpegts_get_pcr, ts->raw_packet_size);}/**************************************************************//* parsing functions - called from other demuxers such as RTP */MpegTSContext *mpegts_parse_open(AVFormatContext *s){ MpegTSContext *ts; ts = av_mallocz(sizeof(MpegTSContext)); if (!ts) return NULL; /* no stream case, currently used by RTP */ ts->raw_packet_size = TS_PACKET_SIZE; ts->stream = s; ts->auto_guess = 1; return ts;}/* return the consumed length if a packet was output, or -1 if no packet is output */int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, const uint8_t *buf, int len){ int len1; len1 = len; ts->pkt = pkt; ts->stop_parse = 0; for(;;) { if (ts->stop_parse) break; if (len < TS_PACKET_SIZE) return -1; if (buf[0] != 0x47) { buf++; len--; } else { handle_packet(ts, buf); buf += TS_PACKET_SIZE; len -= TS_PACKET_SIZE; } } return len1 - len;}void mpegts_parse_close(MpegTSContext *ts){ int i; for(i=0;i<NB_PID_MAX;i++) av_free(ts->pids[i]); av_free(ts);}AVInputFormat mpegts_demux = { "mpegts", "MPEG2 transport stream format", sizeof(MpegTSContext), mpegts_probe, mpegts_read_header, mpegts_read_packet, mpegts_read_close, mpegts_read_seek, .flags = AVFMT_SHOW_IDS,};int mpegts_init(void){ av_register_input_format(&mpegts_demux);#ifdef CONFIG_ENCODERS av_register_output_format(&mpegts_mux);#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -