Hongcheng Zhong <sj.hc_zh...@sjtu.edu.cn> 于2020年7月15日周三 下午4:38写道: > > From: spartazhc <sparta...@gmail.com> > > Add abr option, ffplay can play hls using abr by: > ffplay -i http://xxx/master.m3u8 -abr > > Structure ABRList is added to save stream type and index, it is > used to allow packet_queue_put function to put pkt which from same > type(for example: video pkt) but different stream index to queue. > > Signed-off-by: spartazhc <sparta...@gmail.com> > --- > doc/ffplay.texi | 2 + > fftools/ffplay.c | 145 ++++++++++++++++++++++++++++++++++++++++++++--- > 2 files changed, 138 insertions(+), 9 deletions(-) > > diff --git a/doc/ffplay.texi b/doc/ffplay.texi > index f3761bb12e..6a24542cda 100644 > --- a/doc/ffplay.texi > +++ b/doc/ffplay.texi > @@ -46,6 +46,8 @@ Disable audio. > Disable video. > @item -sn > Disable subtitles. > +@item -abr > +Enable adaptive bitrate for hls/dash. > @item -ss @var{pos} > Seek to @var{pos}. Note that in most formats it is not possible to seek > exactly, so @command{ffplay} will seek to the nearest seek point to > diff --git a/fftools/ffplay.c b/fftools/ffplay.c > index d673b8049a..b17b75fa8f 100644 > --- a/fftools/ffplay.c > +++ b/fftools/ffplay.c > @@ -201,6 +201,15 @@ typedef struct Decoder { > SDL_Thread *decoder_tid; > } Decoder; > > +typedef struct ABRList { > + int **audio_list; > + int audios; > + int **video_list; > + int videos; > + int **sub_list; > + int subs; > +} ABRList; > + > typedef struct VideoState { > SDL_Thread *read_tid; > AVInputFormat *iformat; > @@ -305,6 +314,8 @@ typedef struct VideoState { > int last_video_stream, last_audio_stream, last_subtitle_stream; > > SDL_cond *continue_read_thread; > + > + ABRList *abr_list; > } VideoState; > > /* options specified by the user */ > @@ -356,6 +367,7 @@ static char *afilters = NULL; > static int autorotate = 1; > static int find_stream_info = 1; > static int filter_nbthreads = 0; > +static int abr = 0; > > /* current context */ > static int is_full_screen; > @@ -1262,6 +1274,29 @@ static void stream_component_close(VideoState *is, int > stream_index) > } > } > > +static void free_abr_dynarray(int **list, int num) > +{ > + for (int i = 0; i < num; i++) { > + av_free(list[i]); > + } > +} > + > +static void free_abr_list(ABRList *abrlist) > +{ > + if (abrlist->audios) { > + free_abr_dynarray(abrlist->audio_list, abrlist->audios); > + av_freep(&abrlist->audio_list); > + } > + if (abrlist->videos) { > + free_abr_dynarray(abrlist->video_list, abrlist->videos); > + av_freep(&abrlist->video_list); > + } > + if (abrlist->subs) { > + free_abr_dynarray(abrlist->sub_list, abrlist->subs); > + av_freep(&abrlist->sub_list); > + } > +} > + > static void stream_close(VideoState *is) > { > /* XXX: use a special url_shutdown call to abort parse cleanly */ > @@ -2753,6 +2788,67 @@ static int is_realtime(AVFormatContext *s) > return 0; > } > > +static av_cold int abr_init_list(VideoState *is) > +{ > + int stream_index, *tmp; > + AVStream *st; > + int nb_streams = is->ic->nb_streams; > + ABRList *abrlist = is->abr_list; > + > + for (stream_index = 0; stream_index < nb_streams; stream_index++) { > + st = is->ic->streams[stream_index]; > + tmp = av_memdup(&stream_index, sizeof(int)); > + if (!tmp) > + return -1; ENOMEM? > + switch (st->codecpar->codec_type) { > + case AVMEDIA_TYPE_AUDIO: > + av_dynarray_add(&abrlist->audio_list, &abrlist->audios, tmp); > + break; > + case AVMEDIA_TYPE_VIDEO: > + av_dynarray_add(&abrlist->video_list, &abrlist->videos, tmp); > + break; > + case AVMEDIA_TYPE_SUBTITLE: > + av_dynarray_add(&abrlist->sub_list, &abrlist->subs, tmp); > + break; > + default: > + av_free(tmp); > + break; > + } > + } > + return 0; > +} > + > +static int abr_check_list(ABRList *abr_list, enum AVMediaType type, int st) > +{ > + int **st_list; > + int n_st; > + switch (type) { > + case AVMEDIA_TYPE_AUDIO: > + st_list = abr_list->audio_list; > + n_st = abr_list->audios; > + break; > + case AVMEDIA_TYPE_VIDEO: > + st_list = abr_list->video_list; > + n_st = abr_list->videos; > + break; > + case AVMEDIA_TYPE_SUBTITLE: > + st_list = abr_list->sub_list; > + n_st = abr_list->subs; > + break; > + default: > + break; > + } > + if (!st_list) > + return 0; > + for (int i = 0; i < n_st; i++) { > + if (*st_list[i] == st) > + return 1; > + } > + return 0; > +} > + > + > + > /* this thread gets the stream from the disk or the network */ > static int read_thread(void *arg) > { > @@ -2789,6 +2885,8 @@ static int read_thread(void *arg) > av_dict_set(&format_opts, "scan_all_pmts", "1", > AV_DICT_DONT_OVERWRITE); > scan_all_pmts_set = 1; > } > + if (abr) > + av_dict_set(&format_opts, "abr", "1", 0); > err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts); > if (err < 0) { > print_error(is->filename, err); > @@ -2918,6 +3016,15 @@ static int read_thread(void *arg) > stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]); > } > > + /* clean packet list filled in hls_read_header if abr is enabled */ > + if (abr) { > + is->abr_list = av_mallocz(sizeof(ABRList)); check NULL? > + ret = abr_init_list(is); > + if (ret < 0) { > + av_log(NULL, AV_LOG_WARNING, "Failed to initiate abr_list\n"); > + } > + } > + > if (is->video_stream < 0 && is->audio_stream < 0) { > av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure > filtergraph\n", > is->filename); > @@ -3045,15 +3152,31 @@ static int read_thread(void *arg) > av_q2d(ic->streams[pkt->stream_index]->time_base) - > (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / > 1000000 > <= ((double)duration / 1000000); > - if (pkt->stream_index == is->audio_stream && pkt_in_play_range) { > - packet_queue_put(&is->audioq, pkt); > - } else if (pkt->stream_index == is->video_stream && pkt_in_play_range > - && !(is->video_st->disposition & > AV_DISPOSITION_ATTACHED_PIC)) { > - packet_queue_put(&is->videoq, pkt); > - } else if (pkt->stream_index == is->subtitle_stream && > pkt_in_play_range) { > - packet_queue_put(&is->subtitleq, pkt); > + if (abr) { > + if ((pkt->stream_index == is->audio_stream > + || abr_check_list(is->abr_list, AVMEDIA_TYPE_AUDIO, > pkt->stream_index)) && pkt_in_play_range) { > + packet_queue_put(&is->audioq, pkt); > + } else if ((pkt->stream_index == is->video_stream > + || abr_check_list(is->abr_list, AVMEDIA_TYPE_VIDEO, > pkt->stream_index)) && pkt_in_play_range > + && !(is->video_st->disposition & > AV_DISPOSITION_ATTACHED_PIC)) { > + packet_queue_put(&is->videoq, pkt); > + } else if ((pkt->stream_index == is->subtitle_stream > + || abr_check_list(is->abr_list, AVMEDIA_TYPE_SUBTITLE, > pkt->stream_index)) && pkt_in_play_range) { > + packet_queue_put(&is->subtitleq, pkt); > + } else { > + av_packet_unref(pkt); > + } > } else { > - av_packet_unref(pkt); > + if (pkt->stream_index == is->audio_stream && pkt_in_play_range) { > + packet_queue_put(&is->audioq, pkt); > + } else if (pkt->stream_index == is->video_stream && > pkt_in_play_range > + && !(is->video_st->disposition & > AV_DISPOSITION_ATTACHED_PIC)) { > + packet_queue_put(&is->videoq, pkt); > + } else if (pkt->stream_index == is->subtitle_stream && > pkt_in_play_range) { > + packet_queue_put(&is->subtitleq, pkt); > + } else { > + av_packet_unref(pkt); > + } > } > } > > @@ -3061,7 +3184,10 @@ static int read_thread(void *arg) > fail: > if (ic && !is->ic) > avformat_close_input(&ic); > - > + if (abr && is->abr_list) { > + free_abr_list(is->abr_list); > + av_freep(&is->abr_list); > + } > if (ret != 0) { > SDL_Event event; > > @@ -3588,6 +3714,7 @@ static const OptionDef options[] = { > { "an", OPT_BOOL, { &audio_disable }, "disable audio" }, > { "vn", OPT_BOOL, { &video_disable }, "disable video" }, > { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" }, > + { "abr", OPT_BOOL, { &abr }, "enable adaptive bitrate for hls/dash" }, > { "ast", OPT_STRING | HAS_ARG | OPT_EXPERT, { > &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", > "stream_specifier" }, > { "vst", OPT_STRING | HAS_ARG | OPT_EXPERT, { > &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", > "stream_specifier" }, > { "sst", OPT_STRING | HAS_ARG | OPT_EXPERT, { > &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle > stream", "stream_specifier" }, > -- > 2.27.0 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".