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 设置

原文地址:https://www.cnblogs.com/standardzero/p/12557344.html