staticinthls_read_seek(AVFormatContext *s,int stream_index, int64_t timestamp,int flags){
HLSContext *c = s->priv_data;struct playlist *seek_pls =NULL;int i, seq_no;int j;int stream_subdemuxer_index;
int64_t first_timestamp, seek_timestamp, duration;// hls不支持byte方式的seek,並判斷是否支持seek,hls的seek狀態會動態改變的if((flags & AVSEEK_FLAG_BYTE)||(c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE))returnAVERROR(ENOSYS);
first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ?0: c->first_timestamp;// 計算以time_base爲倍數的時間戳
seek_timestamp =av_rescale_rnd(timestamp, AV_TIME_BASE,
s->streams[stream_index]->time_base.den,
flags & AVSEEK_FLAG_BACKWARD ?
AV_ROUND_DOWN : AV_ROUND_UP);
duration = s->duration == AV_NOPTS_VALUE ?0: s->duration;if(0< duration && duration < seek_timestamp - first_timestamp)returnAVERROR(EIO);/* find the playlist with the specified stream */for(i =0; i < c->n_playlists; i++){struct playlist *pls = c->playlists[i];for(j =0; j < pls->n_main_streams; j++){if(pls->main_streams[j]== s->streams[stream_index]){
seek_pls = pls;
stream_subdemuxer_index = j;break;}}}/* check if the timestamp is valid for the playlist with the specified stream index */if(!seek_pls ||!find_timestamp_in_playlist(c, seek_pls, seek_timestamp,&seq_no))returnAVERROR(EIO);/* set segment now so we do not need to search again below */
seek_pls->cur_seq_no = seq_no;
seek_pls->seek_stream_index = stream_subdemuxer_index;for(i =0; i < c->n_playlists; i++){/* Reset reading */struct playlist *pls = c->playlists[i];if(pls->input)ff_format_io_close(pls->parent,&pls->input);
pls->input_read_done =0;if(pls->input_next)ff_format_io_close(pls->parent,&pls->input_next);
pls->input_next_requested =0;av_packet_unref(&pls->pkt);reset_packet(&pls->pkt);
pls->pb.eof_reached =0;/* Clear any buffered data */
pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer;/* Reset the pos, to let the mpegts demuxer know we've seeked. */
pls->pb.pos =0;/* Flush the packet queue of the subdemuxer. */ff_read_frame_flush(pls->ctx);
pls->seek_timestamp = seek_timestamp;
pls->seek_flags = flags;if(pls != seek_pls){/* set closest segment seq_no for playlists not handled above */find_timestamp_in_playlist(c, pls, seek_timestamp,&pls->cur_seq_no);/* seek the playlist to the given position without taking
* keyframes into account since this playlist does not have the
* specified stream where we should look for the keyframes */
pls->seek_stream_index =-1;
pls->seek_flags |= AVSEEK_FLAG_ANY;}}
c->cur_timestamp = seek_timestamp;return0;}
hls_read_packet
當seek之後第一幀的時間戳一定是等於或者晚於我們要期望的seek時間的
staticinthls_read_packet(AVFormatContext *s, AVPacket *pkt){
HLSContext *c = s->priv_data;int ret, i, minplaylist =-1;recheck_discard_flags(s, c->first_packet);
c->first_packet =0;for(i =0; i < c->n_playlists; i++){struct playlist *pls = c->playlists[i];/* Make sure we've got one buffered packet from each open playlist
* stream */if(pls->needed &&!pls->pkt.data){while(1){
int64_t ts_diff;
AVRational tb;
ret =av_read_frame(pls->ctx,&pls->pkt);if(ret <0){if(!avio_feof(&pls->pb)&& ret != AVERROR_EOF)return ret;reset_packet(&pls->pkt);break;}else{/* stream_index check prevents matching picture attachments etc. */if(pls->is_id3_timestamped && pls->pkt.stream_index ==0){/* audio elementary streams are id3 timestamped */fill_timing_for_id3_timestamped_stream(pls);}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(pls->seek_timestamp == AV_NOPTS_VALUE)break;if(pls->seek_stream_index <0|| pls->seek_stream_index == pls->pkt.stream_index){if(pls->pkt.dts == AV_NOPTS_VALUE){
pls->seek_timestamp = AV_NOPTS_VALUE;break;}
tb =get_timebase(pls);// 得到當前幀的時間戳和要seek的時間戳的差值
ts_diff =av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE, tb.den, AV_ROUND_DOWN)- pls->seek_timestamp;// seek_flags就支持AVSEEK_FLAG_ANY和AV_PKT_FLAG_KEY,返回的幀一定是要晚於seek時間戳的if(ts_diff >=0&&(pls->seek_flags & AVSEEK_FLAG_ANY || pls->pkt.flags & AV_PKT_FLAG_KEY)){
pls->seek_timestamp = AV_NOPTS_VALUE;break;}}av_packet_unref(&pls->pkt);reset_packet(&pls->pkt);}}/* Check if this stream has the packet with the lowest dts */if(pls->pkt.data){struct playlist *minpls = minplaylist <0?NULL: c->playlists[minplaylist];if(minplaylist <0){
minplaylist = i;}else{
int64_t dts = pls->pkt.dts;
int64_t mindts = minpls->pkt.dts;if(dts == AV_NOPTS_VALUE ||(mindts != AV_NOPTS_VALUE &&compare_ts_with_wrapdetect(dts, pls, mindts, minpls)<0))
minplaylist = i;}}}.../* If we got a packet, return it */if(minplaylist >=0){...return0;}return AVERROR_EOF;}