[FFmpeg-devel] avformat/hlsenc: enhanced %v handling with variant names

Submitted by Bodecs Bela on June 18, 2019, 9:09 p.m.

Details

Message ID e4fe8390-0533-c602-e469-3f766be366f0@vivanet.hu
State New
Headers show

Commit Message

Bodecs Bela June 18, 2019, 9:09 p.m.
Dear All,

When multiple variant streams are specified by var_stream_map option, %v
placeholder in various names ensures that each variant has its unique
names. Currently %v is substituted by its variant index value (0, 1, 2
etc.). In some use cases it would be handy to specify names for variants
instead of numerical indexes. This patch makes it possible to use names
instead of default indexes. In var_stream_map option each or some of the
variant streams may use an optional name attributum (e.g.
-var_stream_map "v:0,a:0,name:sd v:1,a:1,name:720p") If a name is
specified for a variant, then this name value will be used as
substitution value of %v instead of the default index value.


example:
ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
   -map 0:v:0 -map 0:a:0 -map 0:v:1 -map 0:a:1 -f hls -var_stream_map 
"v:0,a:0,name:my_hd v:1,a:1,name:mysd" \
   http://example.com/live/out_%v.m3u8

This example creates two hls variant streams, the two output media playlist
with file names out_my_hd.m3u8 and out_mysd.m3u8 will be created.

Please review this patch.

best regards,

Bela
From 690670d8c66fce71662292b44b9927a7f46917b5 Mon Sep 17 00:00:00 2001
From: Bela Bodecs <bodecsb@vivanet.hu>
Date: Tue, 18 Jun 2019 22:44:49 +0200
Subject: [PATCH] avformat/hlsenc: enhanced %v handling with variant names

When multiple variant streams are specified by var_stream_map option, %v
placeholder in various names ensures that each variant has its unique
names. Currently %v is substituted by its variant index value (0, 1, 2
etc.). In some use cases it would be handy to specify names for variants
instead of numerical indexes. This patch makes it possible to use names
instead of default indexes. In var_stream_map option each or some of the
variant streams may use an optional name attributum (e.g.
-var_stream_map "v:0,a:0,name:sd v:1,a:1,name:720p") If a name is
specified for a variant, then this name value will be used as
substitution value of %v instead of the default index value.


Signed-off-by: Bela Bodecs <bodecsb@vivanet.hu>
---
 doc/muxers.texi      | 16 +++++++-
 libavformat/hlsenc.c | 95 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 95 insertions(+), 16 deletions(-)

Comments

Bodecs Bela June 18, 2019, 9:16 p.m.
this patch assumes/requires my previous patch to be applied

2019 jun 17
[PATCH] av_format/hlsenc: fix %v handling by format_name function

best,

Bela
Michael Niedermayer June 19, 2019, 9:37 a.m.
On Tue, Jun 18, 2019 at 11:09:12PM +0200, Bodecs Bela wrote:
> Dear All,
> 
> When multiple variant streams are specified by var_stream_map option, %v
> placeholder in various names ensures that each variant has its unique
> names. Currently %v is substituted by its variant index value (0, 1, 2
> etc.). In some use cases it would be handy to specify names for variants
> instead of numerical indexes. This patch makes it possible to use names
> instead of default indexes. In var_stream_map option each or some of the
> variant streams may use an optional name attributum (e.g.
> -var_stream_map "v:0,a:0,name:sd v:1,a:1,name:720p") If a name is
> specified for a variant, then this name value will be used as
> substitution value of %v instead of the default index value.
> 
> 
> example:
> ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
>   -map 0:v:0 -map 0:a:0 -map 0:v:1 -map 0:a:1 -f hls -var_stream_map
> "v:0,a:0,name:my_hd v:1,a:1,name:mysd" \
>   http://example.com/live/out_%v.m3u8
> 
> This example creates two hls variant streams, the two output media playlist
> with file names out_my_hd.m3u8 and out_mysd.m3u8 will be created.
> 
> Please review this patch.
> 
> best regards,

maybe i made a mistake but this seems not to apply

Applying: avformat/hlsenc: enhanced %v handling with variant names
error: sha1 information is lacking or useless (libavformat/hlsenc.c).
error: could not build fake ancestor
Patch failed at 0001 avformat/hlsenc: enhanced %v handling with variant names
hint: Use 'git am --show-current-patch' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

[...]
Bodecs Bela June 19, 2019, 10 a.m.
2019.06.19. 11:37 keltezéssel, Michael Niedermayer írta:
> On Tue, Jun 18, 2019 at 11:09:12PM +0200, Bodecs Bela wrote:
>> Dear All,
>>
>> When multiple variant streams are specified by var_stream_map option, %v
>> placeholder in various names ensures that each variant has its unique
>> names. Currently %v is substituted by its variant index value (0, 1, 2
>> etc.). In some use cases it would be handy to specify names for variants
>> instead of numerical indexes. This patch makes it possible to use names
>> instead of default indexes. In var_stream_map option each or some of the
>> variant streams may use an optional name attributum (e.g.
>> -var_stream_map "v:0,a:0,name:sd v:1,a:1,name:720p") If a name is
>> specified for a variant, then this name value will be used as
>> substitution value of %v instead of the default index value.
>>
>>
>> example:
>> ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
>>    -map 0:v:0 -map 0:a:0 -map 0:v:1 -map 0:a:1 -f hls -var_stream_map
>> "v:0,a:0,name:my_hd v:1,a:1,name:mysd" \
>>    http://example.com/live/out_%v.m3u8
>>
>> This example creates two hls variant streams, the two output media playlist
>> with file names out_my_hd.m3u8 and out_mysd.m3u8 will be created.
>>
>> Please review this patch.
>>
>> best regards,
> maybe i made a mistake but this seems not to apply
>
> Applying: avformat/hlsenc: enhanced %v handling with variant names
> error: sha1 information is lacking or useless (libavformat/hlsenc.c).
> error: could not build fake ancestor
> Patch failed at 0001 avformat/hlsenc: enhanced %v handling with variant names
> hint: Use 'git am --show-current-patch' to see the failed patch
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
>
> [...]
>
>
I think it relates to the fact - as I mentioned my other post - that I 
created two related patches and I send them into the list as unrelated 
patches.

I will wait for my earlier patch to be applied and then I reissue this 
patch again.

best,

bb

> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Steven Liu June 19, 2019, 10:02 a.m.
> 在 2019年6月19日,下午6:00,Bodecs Bela <bodecsb@vivanet.hu> 写道:
> 
> 
> 2019.06.19. 11:37 keltezéssel, Michael Niedermayer írta:
>> On Tue, Jun 18, 2019 at 11:09:12PM +0200, Bodecs Bela wrote:
>>> Dear All,
>>> 
>>> When multiple variant streams are specified by var_stream_map option, %v
>>> placeholder in various names ensures that each variant has its unique
>>> names. Currently %v is substituted by its variant index value (0, 1, 2
>>> etc.). In some use cases it would be handy to specify names for variants
>>> instead of numerical indexes. This patch makes it possible to use names
>>> instead of default indexes. In var_stream_map option each or some of the
>>> variant streams may use an optional name attributum (e.g.
>>> -var_stream_map "v:0,a:0,name:sd v:1,a:1,name:720p") If a name is
>>> specified for a variant, then this name value will be used as
>>> substitution value of %v instead of the default index value.
>>> 
>>> 
>>> example:
>>> ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
>>>   -map 0:v:0 -map 0:a:0 -map 0:v:1 -map 0:a:1 -f hls -var_stream_map
>>> "v:0,a:0,name:my_hd v:1,a:1,name:mysd" \
>>>   http://example.com/live/out_%v.m3u8
>>> 
>>> This example creates two hls variant streams, the two output media playlist
>>> with file names out_my_hd.m3u8 and out_mysd.m3u8 will be created.
>>> 
>>> Please review this patch.
>>> 
>>> best regards,
>> maybe i made a mistake but this seems not to apply
>> 
>> Applying: avformat/hlsenc: enhanced %v handling with variant names
>> error: sha1 information is lacking or useless (libavformat/hlsenc.c).
>> error: could not build fake ancestor
>> Patch failed at 0001 avformat/hlsenc: enhanced %v handling with variant names
>> hint: Use 'git am --show-current-patch' to see the failed patch
>> When you have resolved this problem, run "git am --continue".
>> If you prefer to skip this patch, run "git am --skip" instead.
>> To restore the original branch and stop patching, run "git am --abort".
>> 
>> [...]
>> 
>> 
> I think it relates to the fact - as I mentioned my other post - that I created two related patches and I send them into the list as unrelated patches.
> 
> I will wait for my earlier patch to be applied and then I reissue this patch again.
Let me push it :D
> 
> best,
> 
> bb
> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> 
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@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-request@ffmpeg.org with subject "unsubscribe".
Steven Liu June 19, 2019, 10:17 a.m.
> 在 2019年6月19日,下午6:00,Bodecs Bela <bodecsb@vivanet.hu> 写道:
> 
> 
> 2019.06.19. 11:37 keltezéssel, Michael Niedermayer írta:
>> On Tue, Jun 18, 2019 at 11:09:12PM +0200, Bodecs Bela wrote:
>>> Dear All,
>>> 
>>> When multiple variant streams are specified by var_stream_map option, %v
>>> placeholder in various names ensures that each variant has its unique
>>> names. Currently %v is substituted by its variant index value (0, 1, 2
>>> etc.). In some use cases it would be handy to specify names for variants
>>> instead of numerical indexes. This patch makes it possible to use names
>>> instead of default indexes. In var_stream_map option each or some of the
>>> variant streams may use an optional name attributum (e.g.
>>> -var_stream_map "v:0,a:0,name:sd v:1,a:1,name:720p") If a name is
>>> specified for a variant, then this name value will be used as
>>> substitution value of %v instead of the default index value.
>>> 
>>> 
>>> example:
>>> ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
>>>   -map 0:v:0 -map 0:a:0 -map 0:v:1 -map 0:a:1 -f hls -var_stream_map
>>> "v:0,a:0,name:my_hd v:1,a:1,name:mysd" \
>>>   http://example.com/live/out_%v.m3u8
>>> 
>>> This example creates two hls variant streams, the two output media playlist
>>> with file names out_my_hd.m3u8 and out_mysd.m3u8 will be created.
>>> 
>>> Please review this patch.
>>> 
>>> best regards,
>> maybe i made a mistake but this seems not to apply
>> 
>> Applying: avformat/hlsenc: enhanced %v handling with variant names
>> error: sha1 information is lacking or useless (libavformat/hlsenc.c).
>> error: could not build fake ancestor
>> Patch failed at 0001 avformat/hlsenc: enhanced %v handling with variant names
>> hint: Use 'git am --show-current-patch' to see the failed patch
>> When you have resolved this problem, run "git am --continue".
>> If you prefer to skip this patch, run "git am --skip" instead.
>> To restore the original branch and stop patching, run "git am --abort".
>> 
>> [...]
>> 
>> 
> I think it relates to the fact - as I mentioned my other post - that I created two related patches and I send them into the list as unrelated patches.
> 
> I will wait for my earlier patch to be applied and then I reissue this patch again.

I have pushed the first patch, and this patch cannot be merged:

muhanmoeMacBook:ffmpeg StevenLiu$ git am ~/Downloads/0001-avformat-hlsenc-enhanced-v-handling-with-variant-nam.patch
fatal: previous rebase directory .git/rebase-apply still exists but mbox given.
muhanmoeMacBook:ffmpeg StevenLiu$ patch -p1 < ~/Downloads/0001-avformat-hlsenc-enhanced-v-handling-with-variant-nam.patch
(Stripping trailing CRs from patch.)
patching file doc/muxers.texi
(Stripping trailing CRs from patch.)
patching file libavformat/hlsenc.c
Hunk #8 FAILED at 2693.
Hunk #9 FAILED at 2754.
Hunk #10 FAILED at 2811.
Hunk #11 FAILED at 2876.
Hunk #12 succeeded at 2938 (offset 11 lines).
4 out of 12 hunks FAILED -- saving rejects to file libavformat/hlsenc.c.rej
muhanmoeMacBook:ffmpeg StevenLiu$


> 
> best,
> 
> bb
> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> 
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@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-request@ffmpeg.org with subject "unsubscribe".

Patch hide | download patch | download mbox

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 50147c4d20..8370b6dc2e 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -943,7 +943,21 @@  This example creates two hls variant streams. The first variant stream will
 contain video stream of bitrate 1000k and audio stream of bitrate 64k and the
 second variant stream will contain video stream of bitrate 256k and audio
 stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and
-out_1.m3u8 will be created.
+out_1.m3u8 will be created. If you want something meaningful text instead of indexes
+in result names, you may specify names for each or some of the variants
+as in the following example.
+
+
+@example
+ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0,name:my_hd v:1,a:1,name:mysd" \
+  http://example.com/live/out_%v.m3u8
+@end example
+
+This example creates two hls variant streams as in the previous one.
+But here, the two media playlist with file names out_my_hd.m3u8 and
+out_mysd.m3u8 will be created.
+
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \
   -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 6d00a70041..f88b8a9618 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -164,6 +164,7 @@  typedef struct VariantStream {
     char *agroup; /* audio group name */
     char *ccgroup; /* closed caption group name */
     char *baseurl;
+    char *varname; // variant name
 } VariantStream;
 
 typedef struct ClosedCaptionsStream {
@@ -340,6 +341,47 @@  fail:
     return;
 }
 
+static int replace_str_data_in_filename(char **s, const char *filename, char placeholder, const char *datastring)
+{
+    const char *p;
+    char *new_filename;
+    char c;
+    int addchar_count;
+    int found_count = 0;
+    AVBPrint buf;
+
+    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+    p = filename;
+    for (;;) {
+        c = *p;
+        if (c == '\0')
+            break;
+        if (c == '%' && *(p+1) == '%')  // %%
+            addchar_count = 2;
+        else if (c == '%' && *(p+1) == placeholder) {
+            av_bprintf(&buf, "%s", datastring);
+            p += 2;
+            addchar_count = 0;
+            found_count ++;
+        } else
+            addchar_count = 1;
+
+        if (addchar_count > 0) {
+            av_bprint_append_data(&buf, p, addchar_count);
+            p += addchar_count;
+        }
+    }
+    if (!av_bprint_is_complete(&buf)) {
+        av_bprint_finalize(&buf, NULL);
+        return -1;
+    }
+    if (av_bprint_finalize(&buf, &new_filename) < 0 || !new_filename)
+        return -1;
+    *s = new_filename;
+    return found_count;
+}
+
 static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number)
 {
     const char *p;
@@ -474,20 +516,27 @@  static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
 
     }
 
-    while (segment) {
+    /* if %v is present in the file's directory
+     * all segment belongs to the same variant, so do it only once before the loop*/
+    if (dirname && av_stristr(dirname, "%v")) {
         char * r_dirname = dirname;
-
-        /* if %v is present in the file's directory */
-        if (dirname && av_stristr(dirname, "%v")) {
-
+        if (!vs->varname) {
             if (replace_int_data_in_filename(&r_dirname, dirname, 'v', segment->var_stream_idx) < 1) {
                 ret = AVERROR(EINVAL);
                 goto fail;
             }
-            av_free(dirname);
-            dirname = r_dirname;
+        } else {
+            if (replace_str_data_in_filename(&r_dirname, dirname, 'v', vs->varname) < 1) {
+                ret = AVERROR(EINVAL);
+                goto fail;
+            }
         }
 
+        av_free(dirname);
+        dirname = r_dirname;
+    }
+
+    while (segment) {
         av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n",
                                   segment->filename);
         path_size =  (hls->use_localtime_mkdir ? 0 : strlen(dirname)) + strlen(segment->filename) + 1;
@@ -1761,7 +1810,7 @@  fail:
     return ret;
 }
 
-static int format_name(const char *buf, char **s, int index)
+static int format_name(const char *buf, char **s, int index, const char *varname)
 {
     const char *proto, *dir;
     char *orig_buf_dup = NULL, *mod_buf_dup = NULL;
@@ -1778,11 +1827,20 @@  static int format_name(const char *buf, char **s, int index)
         return ret;
     }
 
-    if (replace_int_data_in_filename(s, orig_buf_dup, 'v', index) < 1) {
-        ret = AVERROR(EINVAL);
-        goto fail;
+
+    if (!varname) {
+        if (replace_int_data_in_filename(s, orig_buf_dup, 'v', index) < 1) {
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
+    } else {
+        if (replace_str_data_in_filename(s, orig_buf_dup, 'v', varname) < 1) {
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
     }
 
+
     proto = avio_find_protocol_name(orig_buf_dup);
     dir = av_dirname(orig_buf_dup);
 
@@ -1898,6 +1956,11 @@  static int parse_variant_stream_mapstring(AVFormatContext *s)
                                   (!av_strncasecmp(val, "1", strlen("1"))));
                 hls->has_default_key = 1;
                 continue;
+            } else if (av_strstart(keyval, "name:", &val)) {
+                vs->varname = av_strdup(val);
+                if (!vs->varname)
+                    return AVERROR(ENOMEM);
+                continue;
             } else if (av_strstart(keyval, "agroup:", &val)) {
                 vs->agroup = av_strdup(val);
                 if (!vs->agroup)
@@ -2417,6 +2480,7 @@  static void hls_free_variant_streams(struct HLSContext *hls)
         av_freep(&vs->language);
         av_freep(&vs->ccgroup);
         av_freep(&vs->baseurl);
+        av_freep(&vs->varname);
     }
 }
 
@@ -2629,7 +2693,7 @@  static int hls_init(AVFormatContext *s)
     for (i = 0; i < hls->nb_varstreams; i++) {
         vs = &hls->var_streams[i];
 
-        ret = format_name(s->url, &vs->m3u8_name, i);
+        ret = format_name(s->url, &vs->m3u8_name, i, vs->varname);
         if (ret < 0)
             goto fail;
 
@@ -2690,7 +2754,7 @@  static int hls_init(AVFormatContext *s)
             }
         }
         if (hls->segment_filename) {
-            ret = format_name(hls->segment_filename, &vs->basename, i);
+            ret = format_name(hls->segment_filename, &vs->basename, i, vs->varname);
             if (ret < 0)
                 goto fail;
             basename_size = strlen(vs->basename) + 1;
@@ -2747,7 +2811,7 @@  static int hls_init(AVFormatContext *s)
                 if (hls->nb_varstreams > 1) {
                     if (av_stristr(vs->fmp4_init_filename, "%v")) {
                         av_freep(&vs->fmp4_init_filename);
-                        format_name(hls->fmp4_init_filename, &vs->fmp4_init_filename, i);
+                        format_name(hls->fmp4_init_filename, &vs->fmp4_init_filename, i, vs->varname);
                     } else {
                         ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i);
                     }
@@ -2812,7 +2876,7 @@  static int hls_init(AVFormatContext *s)
 
             if ( hls->subtitle_filename ) {
                 av_freep(&vs->vtt_m3u8_name);
-                ret = format_name(hls->subtitle_filename, &vs->vtt_m3u8_name, i);
+                ret = format_name(hls->subtitle_filename, &vs->vtt_m3u8_name, i, vs->varname);
                 if (ret < 0)
                     goto fail;
             } else {
@@ -2863,6 +2927,7 @@  fail:
             av_freep(&vs->agroup);
             av_freep(&vs->ccgroup);
             av_freep(&vs->baseurl);
+            av_freep(&vs->varname);
             if (vs->avf)
                 avformat_free_context(vs->avf);
             if (vs->vtt_avf)