Skip to content
Snippets Groups Projects
mpegts.c 34.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • static int mpegts_read_header(AVFormatContext *s,
                                  AVFormatParameters *ap)
    {
        MpegTSContext *ts = s->priv_data;
        ByteIOContext *pb = &s->pb;
        uint8_t buf[1024];
    
        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;
    
                /* first do a scaning to get all the services */
    
                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)
                    return -1;
                
                /* tune to first service found */
                service = ts->services[0];
                sid = service->sid;
    
                
                /* 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;
            
            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++;
            }
    
            /* 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);
    
    #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++)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            av_free(ts->pids[i]);
    
    /**************************************************************/
    /* 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,
    
    };
    
    int mpegts_init(void)
    {
        av_register_input_format(&mpegts_demux);