当前位置:   article > 正文

基于ffmpeg的播放器,播放m3u8文件时,seek问题_ffmpeg.c m3u8

ffmpeg.c m3u8

1,准备知识,

seek代码流程:

首先,调用seek设置pls->seek_timestamp等参数

ffplay.c:avformat_seek_file->av_seek_frame -> utils.c:seek_frame_internal -> hls.c:hls_read_seek

然后,在read_thread里读取packet时是否有seek操作,有的话则判断当前packet和seek time比较是否有效

utils:av_read_frame->…->hls.c:hls_read_packet

策略:

当seek时间值超过了视频结束时间 即seek_timestamp - HLSContext:first_timestamp > duration时直接返回错误;

当seek时间值小于视频开始时间 即seek_timestamp < HLSContext:first_timestamp时返回错误(find_timestamp_in_playlist函数里);

在hls.c:hls_read_packet读取packet时,会去查看当前的pls->seek_timestamp值,如果有seek操作这里pls->seek_timestamp会有赋值,将pls->seek_timestamp和读取到的packet dts比较,如果小于0则直接调用av_packet_unref(&pls->pkt)回收掉这个packet(这里会循环读取packet值的,不会返回空的packet给ffplay的),大于零才会返回当前的读取的packet。

2,问题描述,

基于ffmpeg的播放器播放m3u8文件的ts视频,seek时,有的视频出现无法seek到0或者结尾,有的就是无法seek到任何地方。

3,原因分析及其修改,

拿到这个问题,在不debug代码或查看日志的情况下,根据上面1的准备知识,可以大概判断出原因。
  1. 有的视频出现无法seek到0的问题,可以考虑是在如上策略中描述的,seek时间值(0)小于视频开始时间HLSContext:first_timestamp导致的。
  2. 有的视频出现无法seek到结尾的问题,可以考虑是在如上策略中描述的,seek时间值与HLSContext:first_timestamp的差大于视频duration导致的。
  3. 至于其它的seek无法到达,可能大概率是在如上策略中描述的第三种情况,seek time的值与当前packet dts(解码时间戳)值的差值大于零导致认为未到达seek的time值,就丢弃了。

总的来说,大概就是相关的几个变量的值可能有异常,包括:用户传进来的seek time值、当前视频片段的起始时间值HLSContext:first_timestamp、duration值、读取出来的packet的dts值等

针对问题视频,对于上面几个值查看,以及代码修改

debug代码查看seek time传值,发现传值的确是0,可是seek后就是到不了0的位置,输出日志,发现视频文件的起始时间不是0,而是大于0的值,所以在外面传值时将ffplay.c:stream_seek方法里的代码做如下修改

		//add by lxs start
		int64_t start_time = is->ic->start_time;
         if(start_time > 0 && start_time != AV_NOPTS_VALUE){
            pos += start_time;
         }
         //add by lxs end
		is->seek_pos = pos;
		is->seek_rel = rel;
		is->seek_flags &= ~AVSEEK_FLAG_BYTE;
		if (seek_by_bytes)
			is->seek_flags |= AVSEEK_FLAG_BYTE;
		is->seek_req = 1;
		SDL_CondSignal(is->continue_read_thread);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

上面修改后大部分AVFormatContext start_time大于零的问题解决了,但是还是有些视频无法seek到0,或者结尾。怀疑是不是外面的AVFormatContext:start_time和里面的HLSContext:first_timestamp不相等,使用如下命令导出frames信息

ffprobe -show_frames /c/Users/Administrator/Downloads/2499929067_1947651037_1.ts > /c/Users/Administrator/Downloads/3hh.txt

    打开3hh.txt文件查看,发现audio第一帧和video第一帧的pts/dts不一样,所以怀疑是两个分别被赋值给了上面的AVFormatContext:start_time和HLSContext:first_timestamp导致两个值不一样。

    [FRAME]
    media_type=audio
    stream_index=1
    key_frame=1
    pkt_pts=31680
    pkt_pts_time=0.352000
    pkt_dts=31680
    pkt_dts_time=0.352000
    best_effort_timestamp=31680
    best_effort_timestamp_time=0.352000
    pkt_duration=1920
    pkt_duration_time=0.021333
    pkt_pos=34780
    pkt_size=206
    sample_fmt=fltp
    nb_samples=1024
    channels=2
    channel_layout=stereo
    [/FRAME]
    [FRAME]
    media_type=audio
    stream_index=1
    key_frame=1
    pkt_pts=35550
    pkt_pts_time=0.395000
    pkt_dts=35550
    pkt_dts_time=0.395000
    best_effort_timestamp=35550
    best_effort_timestamp_time=0.395000
    pkt_duration=1920
    pkt_duration_time=0.021333
    pkt_pos=36472
    pkt_size=215
    sample_fmt=fltp
    nb_samples=1024
    channels=2
    channel_layout=stereo
    [/FRAME]
    [FRAME]
    media_type=video
    stream_index=0
    key_frame=1
    pkt_pts=29970
    pkt_pts_time=0.333000
    pkt_dts=29970
    pkt_dts_time=0.333000
    best_effort_timestamp=29970
    best_effort_timestamp_time=0.333000
    pkt_duration=3000
    pkt_duration_time=0.033333
    pkt_pos=564
    pkt_size=31935
    width=1920
    height=1080
    pix_fmt=yuv420p
    sample_aspect_ratio=N/A
    pict_type=I
    coded_picture_number=0
    display_picture_number=0
    interlaced_frame=0
    top_field_first=0
    repeat_pict=0
    color_range=unknown
    color_space=unknown
    color_primaries=unknown
    color_transfer=unknown
    chroma_location=left
    [/FRAME]
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    结合日志的确两者值不一样。所以在hls.c:hls_read_packet方法里给HLSContext:first_timestamp赋值的地方,将值修改为AVFormatContext:start_time,这样保证两者值一样。修改如下

                        /*if (c->first_timestamp == AV_NOPTS_VALUE &&
                            pls->pkt.dts       != AV_NOPTS_VALUE)
                            c->first_timestamp = av_rescale_q(pls->pkt.dts,
                                get_timebase(pls), AV_TIME_BASE_Q);*/
                        if(c->first_timestamp != (s->start_time != AV_NOPTS_VALUE ? s->start_time : 0))
                            c->first_timestamp = s->start_time != AV_NOPTS_VALUE ? s->start_time : 0 ;
    • 1
    • 2
    • 3
    • 4
    • 5

    这样大部分问题解决了。可是还是一些视频源无法seek到某些位置。

    最后发现一些dts值异常,比如我的这个视频源,在seek 传start time值的位置packet的dts为0,但是start time并不为0,导致计算异常。在hls.c:hls_read_packet方法里修改如下:

    				 //modify by lxs start
                        int64_t pkt_ts;
                        if (pls->pkt.pts != AV_NOPTS_VALUE)
                            pkt_ts =  pls->pkt.pts;
                        else if (pls->pkt.dts != AV_NOPTS_VALUE)
                            pkt_ts =  pls->pkt.dts;
                        else
                            pkt_ts = AV_NOPTS_VALUE;
                        tb = get_timebase(pls);
                        ts_diff = av_rescale_rnd(pkt_ts/*pls->pkt.dts*/, AV_TIME_BASE,
                                                tb.den, AV_ROUND_DOWN) -
                                pls->seek_timestamp;
                       //modify by lxs end
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    好了,目前就发现这些问题,后面有新的再增加。

    声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
    推荐阅读
    相关标签
      

    闽ICP备14008679号