⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpegts.c

📁 ffmpeg源码分析
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * MPEG2 transport stream (aka DVB) demux * Copyright (c) 2002-2003 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include "avformat.h"#include "crc.h"#include "mpegts.h"//#define DEBUG_SI//#define DEBUG_SEEK/* 1.0 second at 24Mbit/s */#define MAX_SCAN_PACKETS 32000/* maximum size in which we look for synchronisation if   synchronisation is lost */#define MAX_RESYNC_SIZE 4096typedef struct PESContext PESContext;static PESContext* add_pes_stream(MpegTSContext *ts, int pid, int stream_type);static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code);enum MpegTSFilterType {    MPEGTS_PES,    MPEGTS_SECTION,};typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start);typedef struct MpegTSPESFilter {    PESCallback *pes_cb;    void *opaque;} MpegTSPESFilter;typedef void SectionCallback(void *opaque, const uint8_t *buf, int len);typedef void SetServiceCallback(void *opaque, int ret);typedef struct MpegTSSectionFilter {    int section_index;    int section_h_size;    uint8_t *section_buf;    int check_crc:1;    int end_of_section_reached:1;    SectionCallback *section_cb;    void *opaque;} MpegTSSectionFilter;typedef struct MpegTSFilter {    int pid;    int last_cc; /* last cc code (-1 if first packet) */    enum MpegTSFilterType type;    union {        MpegTSPESFilter pes_filter;        MpegTSSectionFilter section_filter;    } u;} MpegTSFilter;typedef struct MpegTSService {    int running:1;    int sid;    char *provider_name;    char *name;} MpegTSService;struct MpegTSContext {    /* user data */    AVFormatContext *stream;    int raw_packet_size; /* raw packet size, including FEC if present */    int auto_guess; /* if true, all pids are analized to find streams */    int set_service_ret;    int mpeg2ts_raw;  /* force raw MPEG2 transport stream output, if possible */    int mpeg2ts_compute_pcr; /* compute exact PCR for each transport stream packet */    /* used to estimate the exact PCR */    int64_t cur_pcr;    int pcr_incr;    int pcr_pid;    /* data needed to handle file based ts */    int stop_parse; /* stop parsing loop */    AVPacket *pkt; /* packet containing av data */    /******************************************/    /* private mpegts data */    /* scan context */    MpegTSFilter *sdt_filter;    int nb_services;    MpegTSService **services;    /* set service context (XXX: allocated it ?) */    SetServiceCallback *set_service_cb;    void *set_service_opaque;    MpegTSFilter *pat_filter;    MpegTSFilter *pmt_filter;    int req_sid;    MpegTSFilter *pids[NB_PID_MAX];};static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,                               const uint8_t *buf, int buf_size, int is_start){    MpegTSSectionFilter *tss = &tss1->u.section_filter;    int len;    if (is_start) {        memcpy(tss->section_buf, buf, buf_size);        tss->section_index = buf_size;        tss->section_h_size = -1;        tss->end_of_section_reached = 0;    } else {        if (tss->end_of_section_reached)            return;        len = 4096 - tss->section_index;        if (buf_size < len)            len = buf_size;        memcpy(tss->section_buf + tss->section_index, buf, len);        tss->section_index += len;    }    /* compute section length if possible */    if (tss->section_h_size == -1 && tss->section_index >= 3) {        len = (((tss->section_buf[1] & 0xf) << 8) | tss->section_buf[2]) + 3;        if (len > 4096)            return;        tss->section_h_size = len;    }    if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) {        tss->end_of_section_reached = 1;        if (!tss->check_crc ||            av_crc(av_crc04C11DB7, -1, tss->section_buf, tss->section_h_size) == 0)            tss->section_cb(tss->opaque, tss->section_buf, tss->section_h_size);    }}MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int pid,                                         SectionCallback *section_cb, void *opaque,                                         int check_crc){    MpegTSFilter *filter;    MpegTSSectionFilter *sec;#ifdef DEBUG_SI    printf("Filter: pid=0x%x\n", pid);#endif    if (pid >= NB_PID_MAX || ts->pids[pid])        return NULL;    filter = av_mallocz(sizeof(MpegTSFilter));    if (!filter)        return NULL;    ts->pids[pid] = filter;    filter->type = MPEGTS_SECTION;    filter->pid = pid;    filter->last_cc = -1;    sec = &filter->u.section_filter;    sec->section_cb = section_cb;    sec->opaque = opaque;    sec->section_buf = av_malloc(MAX_SECTION_SIZE);    sec->check_crc = check_crc;    if (!sec->section_buf) {        av_free(filter);        return NULL;    }    return filter;}MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid,                                     PESCallback *pes_cb,                                     void *opaque){    MpegTSFilter *filter;    MpegTSPESFilter *pes;    if (pid >= NB_PID_MAX || ts->pids[pid])        return NULL;    filter = av_mallocz(sizeof(MpegTSFilter));    if (!filter)        return NULL;    ts->pids[pid] = filter;    filter->type = MPEGTS_PES;    filter->pid = pid;    filter->last_cc = -1;    pes = &filter->u.pes_filter;    pes->pes_cb = pes_cb;    pes->opaque = opaque;    return filter;}void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter){    int pid;    pid = filter->pid;    if (filter->type == MPEGTS_SECTION)        av_freep(&filter->u.section_filter.section_buf);    else if (filter->type == MPEGTS_PES)        av_freep(&filter->u.pes_filter.opaque);    av_free(filter);    ts->pids[pid] = NULL;}static int analyze(const uint8_t *buf, int size, int packet_size, int *index){    int stat[packet_size];    int i;    int x=0;    int best_score=0;    memset(stat, 0, packet_size*sizeof(int));    for(x=i=0; i<size; i++){        if(buf[i] == 0x47){            stat[x]++;            if(stat[x] > best_score){                best_score= stat[x];                if(index) *index= x;            }        }        x++;        if(x == packet_size) x= 0;    }    return best_score;}/* autodetect fec presence. Must have at least 1024 bytes  */static int get_packet_size(const uint8_t *buf, int size){    int score, fec_score, dvhs_score;    if (size < (TS_FEC_PACKET_SIZE * 5 + 1))        return -1;    score    = analyze(buf, size, TS_PACKET_SIZE, NULL);    dvhs_score    = analyze(buf, size, TS_DVHS_PACKET_SIZE, NULL);    fec_score= analyze(buf, size, TS_FEC_PACKET_SIZE, NULL);//    av_log(NULL, AV_LOG_DEBUG, "score: %d, dvhs_score: %d, fec_score: %d \n", score, dvhs_score, fec_score);    if     (score > fec_score && score > dvhs_score) return TS_PACKET_SIZE;    else if(dvhs_score > score && dvhs_score > fec_score) return TS_DVHS_PACKET_SIZE;    else if(score < fec_score && dvhs_score < fec_score) return TS_FEC_PACKET_SIZE;    else                       return -1;}typedef struct SectionHeader {    uint8_t tid;    uint16_t id;    uint8_t version;    uint8_t sec_num;    uint8_t last_sec_num;} SectionHeader;static inline int get8(const uint8_t **pp, const uint8_t *p_end){    const uint8_t *p;    int c;    p = *pp;    if (p >= p_end)        return -1;    c = *p++;    *pp = p;    return c;}static inline int get16(const uint8_t **pp, const uint8_t *p_end){    const uint8_t *p;    int c;    p = *pp;    if ((p + 1) >= p_end)        return -1;    c = (p[0] << 8) | p[1];    p += 2;    *pp = p;    return c;}/* read and allocate a DVB string preceeded by its length */static char *getstr8(const uint8_t **pp, const uint8_t *p_end){    int len;    const uint8_t *p;    char *str;    p = *pp;    len = get8(&p, p_end);    if (len < 0)        return NULL;    if ((p + len) > p_end)        return NULL;    str = av_malloc(len + 1);    if (!str)        return NULL;    memcpy(str, p, len);    str[len] = '\0';    p += len;    *pp = p;    return str;}static int parse_section_header(SectionHeader *h,                                const uint8_t **pp, const uint8_t *p_end){    int val;    val = get8(pp, p_end);    if (val < 0)        return -1;    h->tid = val;    *pp += 2;    val = get16(pp, p_end);    if (val < 0)        return -1;    h->id = val;    val = get8(pp, p_end);    if (val < 0)        return -1;    h->version = (val >> 1) & 0x1f;    val = get8(pp, p_end);    if (val < 0)        return -1;    h->sec_num = val;    val = get8(pp, p_end);    if (val < 0)        return -1;    h->last_sec_num = val;    return 0;}static MpegTSService *new_service(MpegTSContext *ts, int sid,                                  char *provider_name, char *name){    MpegTSService *service;#ifdef DEBUG_SI    printf("new_service: sid=0x%04x provider='%s' name='%s'\n",           sid, provider_name, name);#endif    service = av_mallocz(sizeof(MpegTSService));    if (!service)        return NULL;    service->sid = sid;    service->provider_name = provider_name;    service->name = name;    dynarray_add(&ts->services, &ts->nb_services, service);    return service;}static void pmt_cb(void *opaque, const uint8_t *section, int section_len){    MpegTSContext *ts = opaque;    SectionHeader h1, *h = &h1;    PESContext *pes;    AVStream *st;    const uint8_t *p, *p_end, *desc_list_end, *desc_end;    int program_info_length, pcr_pid, pid, stream_type;    int desc_list_len, desc_len, desc_tag;    int comp_page = 0, anc_page = 0; /* initialize to kill warnings */    char language[4];#ifdef DEBUG_SI    printf("PMT:\n");    av_hex_dump(stdout, (uint8_t *)section, section_len);#endif    p_end = section + section_len - 4;    p = section;    if (parse_section_header(h, &p, p_end) < 0)        return;#ifdef DEBUG_SI    printf("sid=0x%x sec_num=%d/%d\n", h->id, h->sec_num, h->last_sec_num);#endif    if (h->tid != PMT_TID || (ts->req_sid >= 0 && h->id != ts->req_sid) )        return;    pcr_pid = get16(&p, p_end) & 0x1fff;    if (pcr_pid < 0)        return;    ts->pcr_pid = pcr_pid;#ifdef DEBUG_SI    printf("pcr_pid=0x%x\n", pcr_pid);#endif    program_info_length = get16(&p, p_end) & 0xfff;    if (program_info_length < 0)        return;    p += program_info_length;    if (p >= p_end)        return;    for(;;) {        language[0] = 0;        st = 0;        stream_type = get8(&p, p_end);        if (stream_type < 0)            break;        pid = get16(&p, p_end) & 0x1fff;        if (pid < 0)            break;        desc_list_len = get16(&p, p_end) & 0xfff;        if (desc_list_len < 0)            break;        desc_list_end = p + desc_list_len;        if (desc_list_end > p_end)            break;        for(;;) {            desc_tag = get8(&p, desc_list_end);            if (desc_tag < 0)                break;            if (stream_type == STREAM_TYPE_PRIVATE_DATA &&                ((desc_tag == 0x6A) || (desc_tag == 0x7A))) {                    /*assume DVB AC-3 Audio*/                    stream_type = STREAM_TYPE_AUDIO_AC3;            }            desc_len = get8(&p, desc_list_end);            desc_end = p + desc_len;            if (desc_end > desc_list_end)                break;#ifdef DEBUG_SI            printf("tag: 0x%02x len=%d\n", desc_tag, desc_len);#endif            switch(desc_tag) {            case DVB_SUBT_DESCID:                if (stream_type == STREAM_TYPE_PRIVATE_DATA)                    stream_type = STREAM_TYPE_SUBTITLE_DVB;                language[0] = get8(&p, desc_end);                language[1] = get8(&p, desc_end);                language[2] = get8(&p, desc_end);                language[3] = 0;                get8(&p, desc_end);                comp_page = get16(&p, desc_end);                anc_page = get16(&p, desc_end);                break;            case 0x0a: /* ISO 639 language descriptor */                language[0] = get8(&p, desc_end);                language[1] = get8(&p, desc_end);                language[2] = get8(&p, desc_end);                language[3] = 0;                break;            default:                break;            }            p = desc_end;        }        p = desc_list_end;#ifdef DEBUG_SI        printf("stream_type=%d pid=0x%x\n", stream_type, pid);#endif        /* now create ffmpeg stream */        switch(stream_type) {        case STREAM_TYPE_AUDIO_MPEG1:        case STREAM_TYPE_AUDIO_MPEG2:        case STREAM_TYPE_VIDEO_MPEG1:        case STREAM_TYPE_VIDEO_MPEG2:        case STREAM_TYPE_VIDEO_MPEG4:        case STREAM_TYPE_VIDEO_H264:        case STREAM_TYPE_AUDIO_AAC:        case STREAM_TYPE_AUDIO_AC3:        case STREAM_TYPE_AUDIO_DTS:        case STREAM_TYPE_SUBTITLE_DVB:            pes = add_pes_stream(ts, pid, stream_type);            if (pes)                st = new_pes_av_stream(pes, 0);            break;        default:            /* we ignore the other streams */            break;        }        if (st) {            if (language[0] != 0) {                st->language[0] = language[0];                st->language[1] = language[1];                st->language[2] = language[2];                st->language[3] = language[3];            }            if (stream_type == STREAM_TYPE_SUBTITLE_DVB) {                st->codec->sub_id = (anc_page << 16) | comp_page;            }        }    }    /* all parameters are there */    ts->set_service_cb(ts->set_service_opaque, 0);    mpegts_close_filter(ts, ts->pmt_filter);    ts->pmt_filter = NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -