赞
踩
首先,调用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。
基于ffmpeg的播放器播放m3u8文件的ts视频,seek时,有的视频出现无法seek到0或者结尾,有的就是无法seek到任何地方。
总的来说,大概就是相关的几个变量的值可能有异常,包括:用户传进来的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);
上面修改后大部分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]
结合日志的确两者值不一样。所以在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 ;
这样大部分问题解决了。可是还是一些视频源无法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
好了,目前就发现这些问题,后面有新的再增加。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。