[FFmpeg-devel] [PATCH] [GSoC v3 5/7] ffplay: add an option to enable abr

Steven Liu lq at chinaffmpeg.org
Thu Sep 3 18:05:00 EEST 2020



> 在 2020年8月23日,20:23,Hongcheng Zhong <sj.hc_zhong at sjtu.edu.cn> 写道:
> 
> From: spartazhc <spartazhc at 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 <spartazhc at gmail.com>
> 
> v1 fixed:
> None.
> 
> v2 fixed:
> 1. check malloc result and return error message
> 
> Signed-off-by: spartazhc <spartazhc at gmail.com>
> ---
> doc/ffplay.texi  |   2 +
> fftools/ffplay.c | 151 ++++++++++++++++++++++++++++++++++++++++++++---
> 2 files changed, 144 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.
> + at 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 6c9c041e9a..30944ba4be 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 AVERROR(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,21 @@ 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));
> +        if (!is->abr_list) {
> +            ret = AVERROR(ENOMEM);
> +            goto fail;
> +        }
> +        ret = abr_init_list(is);
> +        if (ret < 0) {
> +            av_log(NULL, AV_LOG_FATAL, "Failed to initiate abr_list\n");
> +            ret = -1;
> +            goto fail;
> +        }
> +    }
> +
>     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 +3158,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 +3190,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 +3720,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.28.0
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe”.

I have no more comments for this, waiting enough time for more reviewers’ comments,

Thanks
Steven








More information about the ffmpeg-devel mailing list