[FFmpeg-devel] [PATCH] avformat/hlsenc: creation of hls variant streams with master playlist in a single hlsenc instance

刘歧 lq at chinaffmpeg.org
Thu Nov 16 08:38:45 EET 2017


> 在 2017年11月15日,21:48,Dixit, Vishwanath <vdixit at akamai.com> 写道:
> 
> 
>> On 11/15/17, 9:56 AM, "刘歧" <lq at chinaffmpeg.org> wrote:    
>>   all test info bellow:
>> 
>>   1st, look at the ffmpeg.exe banner 
>>   2nd, test with fate-filter-hls-append
>>   3nd, test with filter-hls-vs-with-master
>> 
>> 
>> /home/liuqi/ffmpeg/tests/fate-run.sh: 1: eval: ffmpeg.exe: not found
>>   make: *** [fate-filter-hls-vs-with-master] Error 1
>>   liuqi at localhost:~/ffmpeg/windows$
> 
> I have fixed the issue. Please find the updated patches in the attachment. The following updates are made,
> 1. An additional FATE ‘run’ command was needed in the test to resolve ‘ffmpeg.exe: not found’ issue.
> 2. Line splitter ‘\’ in make file was creating some sort of un-certainty in test results between linux and windows. I have removed line splitter and have made it a single line command. 
> 3. There are minor updates to resolve the compile time warnings.
> 
> <0001-avformat-hlsenc-creation-of-hls-variant-streams-in-a.patch><0002-avformat-hlsenc-creation-of-hls-master-playlist-file.patch><0003-tests-fate-addition-of-test-case-for-hls-variant-str.patch>_______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

FATE test passed:  Ubuntu, OS X, qemu+MIPS Linux,  wine MingW, qemu+ARM Linux, Thanks.


> 0001-avformat-hlsenc-creation-of-hls-variant-streams-in-a.patch:

+static int format_name(char *name, int name_buf_len, int i)
+{
+    char *p;
+    char extension[10] = {'\0'};
+
+    p = strrchr(name, '.');
+    if (p) {
+        strcpy(extension, p);
What about use av_strlcpy ?


+        *p = '\0';
+    }
+
+    snprintf(name + strlen(name), name_buf_len - strlen(name), POSTFIX_PATTERN, i);
+
+    if (strlen(extension))
+        av_strlcat(name, extension, name_buf_len);
+
+    return 0;
+}
+
+static int get_nth_codec_stream_index(AVFormatContext *s,
+                                      enum AVMediaType codec_type,
+                                      int stream_id)
+{
+    unsigned int stream_index, cnt;
+    if (stream_id < 0 || stream_id > s->nb_streams - 1)
+        return -1;
+    cnt = 0;
+    for (stream_index = 0; stream_index < s->nb_streams; stream_index++) {
+        if (s->streams[stream_index]->codecpar->codec_type != codec_type)
+            continue;
+        if (cnt == stream_id)
+            return stream_index;
+        cnt++;
+    }
+    return -1;
+}
+
+static int parse_variant_stream_mapstring(AVFormatContext *s)
+{
+    HLSContext *hls = s->priv_data;
+    VariantStream *vs;
+    int stream_index;
+    enum AVMediaType codec_type;
+    int nb_varstreams, nb_streams;
+    char *p, *q, *saveptr1, *saveptr2, *varstr, *keyval;
+    const char *val;
+
+    /**
+     * Expected format for var_stream_map string is as below:
+     * "a:0,v:0 a:1,v:1"
+     * This string specifies how to group the audio, video and subtitle streams
+     * into different variant streams. The variant stream groups are separated
+     * by space.
+     *
+     * a:, v:, s: are keys to specify audio, video and subtitle streams
+     * respectively. Allowed values are 0 to 9 digits (limited just based on
+     * practical usage)
+     *
+     */
+    p = av_strdup(hls->var_stream_map);
+    q = p;
+    while(av_strtok(q, " \t", &saveptr1)) {
+        q = NULL;
+        hls->nb_varstreams++;
+    }
+    av_freep(&p);
+
+    hls->var_streams = av_mallocz(sizeof(*hls->var_streams) * hls->nb_varstreams);
+    if (!hls->var_streams)
+        return AVERROR(ENOMEM);
+
+    p = hls->var_stream_map;
+    nb_varstreams = 0;
+    while (varstr = av_strtok(p, " \t", &saveptr1)) {
+        p = NULL;
+
+        if (nb_varstreams < hls->nb_varstreams)
+            vs = &(hls->var_streams[nb_varstreams++]);
+        else
+            return -1;
+
+        q = varstr;
+        while (q < varstr + strlen(varstr)) {
+            if (!strncmp(q, "a:", 2) || !strncmp(q, "v:", 2) ||
+                !strncmp(q, "s:", 2))
What about use av_strcasecmp ?


+                vs->nb_streams++;
+            q++;
+        }
+        vs->streams = av_mallocz(sizeof(AVStream *) * vs->nb_streams);
+        if (!vs->streams)
+            return AVERROR(ENOMEM);
+
+        nb_streams = 0;
+        while (keyval = av_strtok(varstr, ",", &saveptr2)) {
+            varstr = NULL;
+
+            if (av_strstart(keyval, "v:", &val)) {
+                codec_type = AVMEDIA_TYPE_VIDEO;
+            } else if (av_strstart(keyval, "a:", &val)) {
+                codec_type = AVMEDIA_TYPE_AUDIO;
+            } else if (av_strstart(keyval, "s:", &val)) {
+                codec_type = AVMEDIA_TYPE_SUBTITLE;
+            } else {
+                av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval);
+                return -1;
What about use return AVERROR(EINVAL)?


+            }
+
+            stream_index = -1;
+            if (av_isdigit(*val))
+                stream_index = get_nth_codec_stream_index (s, codec_type,
+                                                           atoi(val));
+
+            if (stream_index >= 0 && nb_streams < vs->nb_streams) {
+                vs->streams[nb_streams++] = s->streams[stream_index];
+            } else {
+                av_log(s, AV_LOG_ERROR, "Unable to map stream at %s\n", keyval);
+                return -1;
same as above.


+            }
+        }
+    }
+    av_log(s, AV_LOG_DEBUG, "Number of variant streams %d\n",
+            hls->nb_varstreams);
+
+    return 0;
+}
+
+static int update_variant_stream_info(AVFormatContext *s) {
+    HLSContext *hls = s->priv_data;
+    unsigned int i;
+
+    if (hls->var_stream_map) {
+        return parse_variant_stream_mapstring(s);
+    } else {
+        //By default, a single variant stream with all the codec streams is created
+        hls->nb_varstreams = 1;
+        hls->var_streams = av_mallocz(sizeof(*hls->var_streams) *
+                                             hls->nb_varstreams);
+        if (!hls->var_streams)
+            return AVERROR(ENOMEM);
+
+        hls->var_streams[0].nb_streams = s->nb_streams;
+        hls->var_streams[0].streams = av_mallocz(sizeof(AVStream *) *
+                                            hls->var_streams[0].nb_streams);
+        if (!hls->var_streams[0].streams)
+            return AVERROR(ENOMEM);
+
+        for (i = 0; i < s->nb_streams; i++)
+            hls->var_streams[0].streams[i] = s->streams[i];
+    }
+    return 0;
+}
+





> 0002-avformat-hlsenc-creation-of-hls-master-playlist-file.patch:

+static int get_relative_url(const char *master_url, const char *media_url,
+                            char *rel_url, int rel_url_buf_size)
+{
+    char *p = NULL;
+    int base_len = -1;
+    p = strrchr(master_url, '/') ? strrchr(master_url, '/') :\
+            strrchr(master_url, '\\');
+    if (p) {
+        base_len = abs(p - master_url);
use FFABS


+        if (strncmp(master_url, media_url, base_len)) {
use av_strcasecmp

+            av_log(NULL, AV_LOG_WARNING, "Unable to find relative url\n");
+            return -1;
+        }
+    }
+    av_strlcpy(rel_url, &(media_url[base_len + 1]), rel_url_buf_size);
+    return 0;
+}






More information about the ffmpeg-devel mailing list