zoukankan      html  css  js  c++  java
  • FFMPEG 4.0 版本 支持PSI设置

    TOC

    1. 支持 PSI 相关 PID 设置

    1.1 给结构体 MpegTSWrite 添加如下相关PID成员

    文件:mpegtsenc.c

    typedef struct MpegTSWrite {
        ...
        int pmt_pid;    //自定义pmt_pid
        int pcr_pid;    //自定义pcr_pid
        int pcr_cc;        //自定义pcr连续计算
        int video_pid;    //自定义video_pid
        int audio_pid;    //自定义audio_pid
        int audio1_pid;    //自定义audio1_pid
        }MpegTSWrite;

    1.2 设置 PCR PID 和 PMT PID

    修改函数:mpegts_add_service

    static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid,
                                             const char *provider_name,
                                             const char *name)
    {
        MpegTSService *service;
    
    
        service = av_mallocz(sizeof(MpegTSService));
        if (!service)
            return NULL;    
    
        //设置pmt pid,自定义PID最小为32,小于32采用原来方案
        //service->pmt.pid       = ts->pmt_start_pid + ts->nb_services;   
        if (ts->pmt_pid >= MIN_PID_SET)
        {
            service->pmt.pid          = ts->pmt_pid;    
        }else
        {
            service->pmt.pid       = ts->pmt_start_pid + ts->nb_services;
        }
    
        //设置PCR PID
        //service->pcr_pid       = ts->pcr_pid;
    
        service->sid           = sid;
        service->pcr_pid       = 0x1fff;
        service->provider_name = av_strdup(provider_name);
        service->name          = av_strdup(name);
        if (!service->provider_name || !service->name)
            goto fail;
        if (av_dynarray_add_nofree(&ts->services, &ts->nb_services, service) < 0)
            goto fail;
    
    
        return service;
    fail:
        av_freep(&service->provider_name);
        av_freep(&service->name);
        av_free(service);
        return NULL;
    }

    1.3 设置 audio pid 和 video pid

    修改函数 :mpegts_init

    static int mpegts_init(AVFormatContext *s)
    {
        ...
        //设置 video pid 和 audio pid
            if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
            {
                if ( ts->video_pid >= MIN_PID_SET)
                {
                    ts_st->pid = ts->video_pid;
                }
            }
            if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
            {
                if ((ts->audio_pid >= MIN_PID_SET) && (!hasSetAudio0PID))
                {
                    ts_st->pid = ts->audio_pid;
                    hasSetAudio0PID = 1;
                }
                else
                {
                    if ((ts->audio1_pid >= MIN_PID_SET))
                    {
                        ts_st->pid = ts->audio1_pid;
                    }
                }
            }
    
            pids[i]                = ts_st->pid;
            ts_st->payload_pts     = AV_NOPTS_VALUE;
            ts_st->payload_dts     = AV_NOPTS_VALUE;
            ts_st->first_pts_check = 1;
            ts_st->cc              = 15;
            ts_st->discontinuity   = ts->flags & MPEGTS_FLAG_DISCONT;
            ...       
    }

    1.4 注册 options 命令

    在结构体AVOption 后添加如下命令

    static const AVOption options[] = {
        ...
        { "mpegts_pmt_pid", "Set the first pid of the PMT.",
          offsetof(MpegTSWrite, pmt_pid), AV_OPT_TYPE_INT, 
          {.i64 = 0x333 }, 0x10, 0x1fff, AV_OPT_FLAG_ENCODING_PARAM},
        { "mpegts_pcr_pid", "Set the pcr pid.",
          offsetof(MpegTSWrite, pcr_pid), AV_OPT_TYPE_INT, 
          {.i64 = 0x1fff }, 0x0, 0x1fff, AV_OPT_FLAG_ENCODING_PARAM},
        { "mpegts_video_pid", "Set the video pid.",
          offsetof(MpegTSWrite, video_pid), AV_OPT_TYPE_INT, 
          {.i64 = 0x1fff }, 0x10, 0x1fff, AV_OPT_FLAG_ENCODING_PARAM},
        { "mpegts_audio_pid", "Set the audio pid.",
          offsetof(MpegTSWrite, audio_pid), AV_OPT_TYPE_INT, 
          {.i64 = 0x222 }, 0x10, 0x1fff, AV_OPT_FLAG_ENCODING_PARAM},  
        { "mpegts_audio1_pid", "Set the audio1 pid.",
          offsetof(MpegTSWrite, audio1_pid), AV_OPT_TYPE_INT, 
          {.i64 = 0x223 }, 0x10, 0x1fff, AV_OPT_FLAG_ENCODING_PARAM},  
        { NULL },
    }

    2. PSI 的节目名和提供商名

    直接调用 API 即可

    3. 支持 PCR PID 和 VIDEO PID 不一致的情况

    修改函数:mpegts_write_pes

    while (payload_size > 0) {
            ...
            write_pcr = 0;
            //if (ts_st->pid == ts_st->service->pcr_pid) { //去掉视频pid和pcr pid必须一样的限制 
                if (ts->mux_rate > 1 || is_start) // VBR pcr period is based on frames
                    ts_st->service->pcr_packet_count++;
                if (ts_st->service->pcr_packet_count >=
                    ts_st->service->pcr_packet_period) {
                    ts_st->service->pcr_packet_count = 0;
                    write_pcr = 1;
                }
            //}
    
    
            if (ts->mux_rate > 1 && dts != AV_NOPTS_VALUE &&
                (dts - get_pcr(ts, s->pb) / 300) > delay) {
                /* pcr insert gets priority over null packet insert */
                if (write_pcr)
                    mpegts_insert_pcr_only(s, st);
                else
                    mpegts_insert_null_packet(s);
                /* recalculate write_pcr and possibly retransmit si_info */
                continue;
            }
    
    
            /* prepare packet header */
            q    = buf;
            *q++ = 0x47;
            val  = ts_st->pid >> 8;
            if (is_start)
                val |= 0x40;
            *q++      = val;
            *q++      = ts_st->pid;
            ts_st->cc = ts_st->cc + 1 & 0xf;
            *q++      = 0x10 | ts_st->cc; // payload indicator + CC
            if (ts_st->discontinuity) {
                set_af_flag(buf, 0x80);
                q = get_ts_payload_start(buf);
                ts_st->discontinuity = 0;
            }
            if (key && is_start && pts != AV_NOPTS_VALUE) {
                // set Random Access for key frames
                //if (ts_st->pid == ts_st->service->pcr_pid) //去掉视频pid和pcr pid必须一样的限制 
                    write_pcr = 1;
                set_af_flag(buf, 0x40);
                q = get_ts_payload_start(buf);
            }
            if (write_pcr) {
    
    
                #if 0
                    #if 0
                    set_af_flag(buf, 0x10);
                    q = get_ts_payload_start(buf);
                    // add 11, pcr references the last byte of program clock reference base
                    if (ts->mux_rate > 1)
                        pcr = get_pcr(ts, s->pb);
                    else
                        pcr = (dts - delay) * 300;
                    if (dts != AV_NOPTS_VALUE && dts < pcr / 300)
                        av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid
    ");
                    extend_af(buf, write_pcr_bits(q, pcr));
                    q = get_ts_payload_start(buf);
                    #else
                    mpegts_insert_pcr_only(s, st);
                    #endif    
                #endif
    
    
                if (ts->video_pid == ts->pcr_pid)    
                {
                    //视频包附带PCR
                    set_af_flag(buf, 0x10);
                    q = get_ts_payload_start(buf);
                    // add 11, pcr references the last byte of program clock reference base
                    if (ts->mux_rate > 1)
                        pcr = get_pcr(ts, s->pb);
                    else
                        pcr = (dts - delay) * 300;
                    if (dts != AV_NOPTS_VALUE && dts < pcr / 300)
                        av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid
    ");
                    extend_af(buf, write_pcr_bits(q, pcr));
                    q = get_ts_payload_start(buf);
                }
                else
                {
                    //只插入PCR包
                    mpegts_insert_pcr_only(s, st);
                }
    
            }
            ...
        }

    修改函数:mpegts_insert_pcr_only

    /* Write a single transport stream packet with a PCR and no payload */
    static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
    {
        MpegTSWrite *ts = s->priv_data;
        MpegTSWriteStream *ts_st = st->priv_data;
        uint8_t *q;
        uint8_t buf[TS_PACKET_SIZE];
    
    
        q    = buf;
        *q++ = 0x47;
    
    
        #if 0
            #if 0
            *q++ = ts_st->pid >> 8;
            *q++ = ts_st->pid;
            *q++ = 0x20 | ts_st->cc;   /* Adaptation only */
            #else
            *q++ = ts->pcr_pid >> 8;
            *q++ = ts->pcr_pid;
            *q++ = 0x20 | (ts->pcr_cc & 0xF);   /* Adaptation only */
            #endif
        #endif
    
        if (ts->video_pid == ts->pcr_pid)
        {
            *q++ = ts_st->pid >> 8;
            *q++ = ts_st->pid;
            *q++ = 0x20 | ts_st->cc;   /* Adaptation only */    
        }
        else
        {
            *q++ = ts->pcr_pid >> 8;
            *q++ = ts->pcr_pid;
            *q++ = 0x20 | (ts->pcr_cc & 0xF);   /* Adaptation only */    
        }
    
        /* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */
        *q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */
        *q++ = 0x10;               /* Adaptation flags: PCR present */
        if (ts_st->discontinuity) {
            q[-1] |= 0x80;
            ts_st->discontinuity = 0;
        }
    
    
        /* PCR coded into 6 bytes */
        q += write_pcr_bits(q, get_pcr(ts, s->pb));
    
    
        /* stuffing bytes */
        memset(q, 0xFF, TS_PACKET_SIZE - (q - buf));
        mpegts_prefix_m2ts_header(s);
        avio_write(s->pb, buf, TS_PACKET_SIZE);
    }

    4. 将空包改为视频无效包

    空包接口函数

    /* Write a single null transport stream packet */
    static void mpegts_insert_null_packet(AVFormatContext *s)
    {
        uint8_t *q;
        uint8_t buf[TS_PACKET_SIZE];
    
    
        q    = buf;
        *q++ = 0x47;
        *q++ = 0x00 | 0x1f;
        *q++ = 0xff;
        *q++ = 0x10;
        memset(q, 0x0FF, TS_PACKET_SIZE - (q - buf));
        mpegts_prefix_m2ts_header(s);
        avio_write(s->pb, buf, TS_PACKET_SIZE);
    }

    视频无效包函数

    /* Write a single filled video packet */
    static void mpegts_insert_filled_packet(AVFormatContext *s, AVStream *st)
    {
        MpegTSWrite *ts = s->priv_data;
        MpegTSWriteStream *ts_st = st->priv_data;
        uint8_t *q;
        uint8_t buf[TS_PACKET_SIZE];
    
    
        q     = buf;
        *q++ = 0x47;
        *q++ = ts_st->pid >> 8;
        *q++ = ts_st->pid;
        *q++ = 0x20 | ts_st->cc;   /* Adaptation only */
        /* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */
        *q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */
        *q++ = 0x00;               /* Adaptation flags: PCR present */
    
    
        ///* PCR coded into 6 bytes */
        //q += write_pcr_bits(q, get_pcr(ts, s->pb));
    
    
        /* stuffing bytes */
        memset(q, 0xFF, TS_PACKET_SIZE - (q - buf));
        mpegts_prefix_m2ts_header(s);
        avio_write(s->pb, buf, TS_PACKET_SIZE);
    }
    
    

    5. API 设置

  • 相关阅读:
    CAS单点登录(一)——初识SSO
    Sql Server 增加字段、修改字段、修改类型、修改默认值
    SQL 聚合函数-非聚合函数
    漫画:什么是中台?
    windows下nginx的安装及使用
    sql优化点
    如何处理sql中的关键字(例如',%)
    Mysql 如何创建一张临时表
    MySQL中information_schema是什么
    mysql查看表结构命令,如下:
  • 原文地址:https://www.cnblogs.com/standardzero/p/12557344.html
Copyright © 2011-2022 走看看