ffmpeg --hlsenc.c

依次介绍hlsenc.c

hls_write_header,hls_start,hls_write_packet,hls_window,hls_append_segment,hls_write_trailer。 

 

hls_write_header              

 

此函数一开始就被调用,只会被调1次。

static int hls_write_header(AVFormatContext*s)

{

   HLSContext *hls = s->priv_data;

   int ret, i;

   char *p;

   const char *pattern = "%d.ts";

   const char *pattern_localtime_fmt = "-%s.ts";

   const char *vtt_pattern = "%d.vtt";

   AVDictionary *options = NULL;

   int basename_size;

   int vtt_basename_size;

   hls->sequence       =hls->start_sequence;

   hls->recording_time = hls->time * AV_TIME_BASE;

   hls->start_pts      = AV_NOPTS_VALUE;

   if (hls->format_options_str) {

       ret = av_dict_parse_string(&hls->format_options,hls->format_options_str, "=", ":", 0);

       if (ret < 0) {

           av_log(s, AV_LOG_ERROR, "Could not parse format options list'%s'\n", hls->format_options_str);

           goto fail;

       }

    }

   for (i = 0; i < s->nb_streams; i++) {

       hls->has_video +=

           s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;

       hls->has_subtitle +=

           s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;

    }

   if (hls->has_video > 1)

       av_log(s, AV_LOG_WARNING,

               "More than a single videostream present, "

               "expect issues decodingit.\n");

   hls->oformat = av_guess_format("mpegts", NULL, NULL);

   if (!hls->oformat) {

       ret = AVERROR_MUXER_NOT_FOUND;

       goto fail;

    }

   if(hls->has_subtitle) {

       hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL);

       if (!hls->oformat) {

           ret = AVERROR_MUXER_NOT_FOUND;

           goto fail;

       }

    }

   if (hls->segment_filename) {

       hls->basename = av_strdup(hls->segment_filename);

       if (!hls->basename) {

           ret = AVERROR(ENOMEM);

           goto fail;

       }

    }else {

       if (hls->flags & HLS_SINGLE_FILE)

           pattern = ".ts";

       if (hls->use_localtime) {

           basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) +1;

       } else {

           basename_size = strlen(s->filename) + strlen(pattern) + 1;

       }

       hls->basename = av_malloc(basename_size);

       if (!hls->basename) {

           ret = AVERROR(ENOMEM);

           goto fail;

       }

       av_strlcpy(hls->basename, s->filename, basename_size);

        // s->filenamem3u8名称,如:/home/a.m3u8

        p = strrchr(hls->basename, '.');

       if (p)

           *p = '\0';

       if (hls->use_localtime) {

           av_strlcat(hls->basename, pattern_localtime_fmt, basename_size);

       } else {

           av_strlcat(hls->basename, pattern, basename_size);

           hls->basename ts名称,如:/home/a.ts

       }

    }

   if(hls->has_subtitle) {

       if (hls->flags & HLS_SINGLE_FILE)

           vtt_pattern = ".vtt";

       vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1;

       hls->vtt_basename = av_malloc(vtt_basename_size);

       if (!hls->vtt_basename) {

           ret = AVERROR(ENOMEM);

           goto fail;

       }

       hls->vtt_m3u8_name = av_malloc(vtt_basename_size);

       if (!hls->vtt_m3u8_name ) {

           ret = AVERROR(ENOMEM);

           goto fail;

       }

       av_strlcpy(hls->vtt_basename, s->filename, vtt_basename_size);

       p = strrchr(hls->vtt_basename, '.');

       if (p)

           *p = '\0';

       if( hls->subtitle_filename ) {

           strcpy(hls->vtt_m3u8_name, hls->subtitle_filename);

       } else {

           strcpy(hls->vtt_m3u8_name, hls->vtt_basename);

           av_strlcat(hls->vtt_m3u8_name, "_vtt.m3u8",vtt_basename_size);

       }

       av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size);

    }

   if ((ret = hls_mux_init(s)) < 0)

       goto fail;

   if ((ret = hls_start(s)) < 0)  //打开一个文件

       goto fail;

   av_dict_copy(&options, hls->format_options, 0);

   ret = avformat_write_header(hls->avf, &options);

   if (av_dict_count(options)) {

       av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s'are not recognized\n", hls->format_options_str);

       ret = AVERROR(EINVAL);

       goto fail;

    }

   //av_assert0(s->nb_streams == hls->avf->nb_streams);

   for (i = 0; i < s->nb_streams; i++) {

       AVStream *inner_st;

       AVStream *outer_st = s->streams[i];

       if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)

           inner_st = hls->avf->streams[i];

       else if (hls->vtt_avf)

           inner_st = hls->vtt_avf->streams[0];

       else {

           /* We have a subtitle stream, when the user does not want one */

           inner_st = NULL;

           continue;

       }

       avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits,inner_st->time_base.num, inner_st->time_base.den);

    }

fail:

   av_dict_free(&options);

   if (ret < 0) {

       av_freep(&hls->basename);

       av_freep(&hls->vtt_basename);

       if (hls->avf)

           avformat_free_context(hls->avf);

       if (hls->vtt_avf)

           avformat_free_context(hls->vtt_avf);

    }

   return ret;

}

hls_start

打开ts文件。

static int hls_start(AVFormatContext *s)

{

...

  if((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE,&options)) < 0)

           goto fail;

...

}

hls_write_packet

写入每个音视频包,即处理do_video_out/do_audio_out。

static int hls_write_packet(AVFormatContext*s, AVPacket *pkt)

{

   HLSContext *hls = s->priv_data;

   AVFormatContext *oc = NULL;

   AVStream *st = s->streams[pkt->stream_index];

   int64_t end_pts = hls->recording_time * hls->number;

   int is_ref_pkt = 1;

   int ret, can_split = 1;

    int stream_index = 0;

   if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) {

       oc = hls->vtt_avf;

       stream_index = 0;

    }else {

       oc = hls->avf;

       stream_index = pkt->stream_index;

    }

   if (hls->start_pts == AV_NOPTS_VALUE) {

       hls->start_pts = pkt->pts;

       hls->end_pts   = pkt->pts;

    }

    if (hls->has_video) {

       can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO&&

                    pkt->flags &AV_PKT_FLAG_KEY;

        is_ref_pkt =st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;

    }

   if (pkt->pts == AV_NOPTS_VALUE)

       is_ref_pkt = can_split = 0;

   if (is_ref_pkt)

       hls->duration = (double)(pkt->pts - hls->end_pts)

                                   * st->time_base.num /st->time_base.den;

   if (can_split && av_compare_ts(pkt->pts - hls->start_pts,st->time_base,

                                   end_pts,AV_TIME_BASE_Q) >= 0) {

      //根据can_split ,需要重新打开一个文件,例如跑了一会,打印:

    printf("%ld,%ld,%ld\n", pkt->pts, hls->start_pts, end_pts);       8528771,7176,22000000

end_pts为hls_time乘以帧数。

       int64_t new_start_pos;

       av_write_frame(oc, NULL); /* Flush any buffered data */

       new_start_pos = avio_tell(hls->avf->pb);

       hls->size = new_start_pos - hls->start_pos;

       ret = hls_append_segment(s, hls, hls->duration, hls->start_pos,hls->size);

       hls->start_pos = new_start_pos;

       if (ret < 0)

           return ret;

       hls->end_pts = pkt->pts;

       hls->duration = 0;

       if (hls->flags & HLS_SINGLE_FILE) {

           if (hls->avf->oformat->priv_class &&hls->avf->priv_data)

                av_opt_set(hls->avf->priv_data,"mpegts_flags", "resend_headers", 0);

           hls->number++;

       } else {

           //关闭文件。

           ff_format_io_close(s, &oc->pb);

           if (hls->vtt_avf)

                ff_format_io_close(s,&hls->vtt_avf->pb);

                  //重现打开一个文件。

                  ret =hls_start(s);

       }

       if (ret < 0)

           return ret;

       if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE )

           oc = hls->vtt_avf;

       else

       oc = hls->avf;

        //生成2级m3u8

       if ((ret = hls_window(s, 0)) < 0)

           return ret;

    }

   ret = ff_write_chained(oc, stream_index, pkt, s, 0);

   return ret;

}

hls_window 

此函数用于生成2级m3u8,先写个临时文件,再rename,包括EXT-X-DISCONTINUITY等信息。

static int hls_window(AVFormatContext *s,int last){

     ff_rename(temp_filename, s->filename, s);

}

hls_append_segment

新生成的片加入到链表中,后面用于生成二级m3u8

这个函数还可以根据配置执行hls_delete_old_segments,也就是删除旧的切片。

static int

(struct AVFormatContext *s, HLSContext*hls, double duration,

                              int64_t pos,int64_t size)

{

   HLSSegment *en = av_malloc(sizeof(*en));

  。。。。。。

}

hls_write_trailer

只调用一次,做一些清理工作。

static int hls_write_trailer(structAVFormatContext *s)

{

  ...

         av_freep(&hls->basename); 

  ...

}

问题

 

转码后TS时长变少

DURATION_MAX_READ_SIZE设置的小了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山西茄子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值