[FFmpeg-devel] avformat/hlsenc: add EXT-X-I-FRAMES-ONLY tag support

Submitted by Steven Liu on June 2, 2019, 12:33 p.m.

Details

Message ID 20190602123359.6776-1-lq@chinaffmpeg.org
State New
Headers show

Commit Message

Steven Liu June 2, 2019, 12:33 p.m.
Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
---
 doc/muxers.texi           |  4 ++++
 libavformat/dashenc.c     |  4 ++--
 libavformat/hlsenc.c      | 27 ++++++++++++++++++++++-----
 libavformat/hlsplaylist.c | 11 ++++++++---
 libavformat/hlsplaylist.h |  5 +++--
 5 files changed, 39 insertions(+), 12 deletions(-)

Comments

Gyan June 2, 2019, 1:32 p.m.
On 02-06-2019 06:03 PM, Steven Liu wrote:
> Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
> ---
>   doc/muxers.texi           |  4 ++++
>   libavformat/dashenc.c     |  4 ++--
>   libavformat/hlsenc.c      | 27 ++++++++++++++++++++++-----
>   libavformat/hlsplaylist.c | 11 ++++++++---
>   libavformat/hlsplaylist.h |  5 +++--
>   5 files changed, 39 insertions(+), 12 deletions(-)
>
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index 83ae017d6c..7f3758b117 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -852,6 +852,10 @@ including the file containing the AES encryption key.
>   Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} to playlists that has video segments
>   and when all the segments of that playlist are guaranteed to start with a Key frame.
>   
> +@item iframes_only
> +Add the @code{#EXT-X-I-FRAMES-ONLY} to playlists that has video segments
> +and only can play i frames in the @code{#EXT-X-BYTERANGE} mode.
"and can play only I-frames in ..."

> +
>   @item split_by_time
>   Allow segments to start on frames other than keyframes. This improves
>   behavior on some players when the time between keyframes is inconsistent,
> diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
> index 94b198ceb8..3fd7e78166 100644
> --- a/libavformat/dashenc.c
> +++ b/libavformat/dashenc.c
> @@ -471,7 +471,7 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s,
>       }
>   
>       ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration,
> -                                 start_number, PLAYLIST_TYPE_NONE);
> +                                 start_number, PLAYLIST_TYPE_NONE, 0);
>   
>       ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file,
>                              os->init_range_length, os->init_start_pos);
> @@ -491,7 +491,7 @@ static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s,
>                                   (double) seg->duration / timescale, 0,
>                                   seg->range_length, seg->start_pos, NULL,
>                                   c->single_file ? os->initfile : seg->file,
> -                                &prog_date_time);
> +                                &prog_date_time, 0, 0, 0);
>           if (ret < 0) {
>               av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
>           }
> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> index 6b913be31c..4ffc522803 100644
> --- a/libavformat/hlsenc.c
> +++ b/libavformat/hlsenc.c
> @@ -75,6 +75,8 @@ typedef struct HLSSegment {
>       int discont;
>       int64_t pos;
>       int64_t size;
> +    int64_t keyframe_pos;
> +    int64_t keyframe_size;
>       unsigned var_stream_idx;
>   
>       char key_uri[LINE_BUFFER_SIZE + 1];
> @@ -99,6 +101,7 @@ typedef enum HLSFlags {
>       HLS_TEMP_FILE = (1 << 11),
>       HLS_PERIODIC_REKEY = (1 << 12),
>       HLS_INDEPENDENT_SEGMENTS = (1 << 13),
> +    HLS_I_FRAMES_ONLY = (1 << 14),
>   } HLSFlags;
>   
>   typedef enum {
> @@ -125,6 +128,9 @@ typedef struct VariantStream {
>       double dpp;           // duration per packet
>       int64_t start_pts;
>       int64_t end_pts;
> +    int64_t video_lastpos;
> +    int64_t video_keyframe_pos;
> +    int64_t video_keyframe_size;
>       double duration;      // last segment duration computed so far, in seconds
>       int64_t start_pos;    // last segment starting position
>       int64_t size;         // last segment size
> @@ -994,6 +1000,8 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
>       en->duration = duration;
>       en->pos      = pos;
>       en->size     = size;
> +    en->keyframe_pos      = vs->video_keyframe_pos;
> +    en->keyframe_size     = vs->video_keyframe_size;
>       en->next     = NULL;
>       en->discont  = 0;
>   
> @@ -1411,7 +1419,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
>   
>       vs->discontinuity_set = 0;
>       ff_hls_write_playlist_header(hls->m3u8_out, hls->version, hls->allowcache,
> -                                 target_duration, sequence, hls->pl_type);
> +                                 target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY);
>   
>       if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){
>           avio_printf(hls->m3u8_out, "#EXT-X-DISCONTINUITY\n");
> @@ -1439,7 +1447,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
>           ret = ff_hls_write_file_entry(hls->m3u8_out, en->discont, byterange_mode,
>                                         en->duration, hls->flags & HLS_ROUND_DURATIONS,
>                                         en->size, en->pos, vs->baseurl,
> -                                      en->filename, prog_date_time_p);
> +                                      en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
>           if (ret < 0) {
>               av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
>           }
> @@ -1455,11 +1463,11 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
>               goto fail;
>           }
>           ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache,
> -                                     target_duration, sequence, PLAYLIST_TYPE_NONE);
> +                                     target_duration, sequence, PLAYLIST_TYPE_NONE, 0);
>           for (en = vs->segments; en; en = en->next) {
>               ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode,
>                                             en->duration, 0, en->size, en->pos,
> -                                          vs->baseurl, en->sub_filename, NULL);
> +                                          vs->baseurl, en->sub_filename, NULL, 0, 0, 0);
>               if (ret < 0) {
>                   av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
>               }
> @@ -2205,7 +2213,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>           vs->start_pts = pkt->pts;
>       }
>   
> -    if (vs->has_video) {
> +   if (vs->has_video) {
>           can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
>                       ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME));
>           is_ref_pkt = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->stream_index == vs->reference_stream_index);
> @@ -2240,6 +2248,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>           av_write_frame(vs->avf, NULL); /* Flush any buffered data */
>   
>           new_start_pos = avio_tell(vs->avf->pb);
> +
>           if (hls->segment_type != SEGMENT_TYPE_FMP4) {
>               avio_flush(oc->pb);
>               vs->size = new_start_pos - vs->start_pos;
> @@ -2368,6 +2377,13 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>       vs->packets_written++;
>       if (oc->pb) {
>           ret = ff_write_chained(oc, stream_index, pkt, s, 0);
> +        if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
> +            vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos;
> +            vs->video_keyframe_pos = vs->start_pos;
> +        } else {
> +            vs->video_lastpos = avio_tell(oc->pb);
> +        }
> +
>           if (hls->ignore_io_errors)
>               ret = 0;
>       }
> @@ -2919,6 +2935,7 @@ static const AVOption options[] = {
>       {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX,   E, "flags"},
>       {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX,   E, "flags"},
>       {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"},
> +    {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, "flags"},
>   #if FF_API_HLS_USE_LOCALTIME
>       {"use_localtime", "set filename expansion with strftime at segment creation(will be deprecated )", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
>   #endif
> diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c
> index 0537049a97..e8b566789c 100644
> --- a/libavformat/hlsplaylist.c
> +++ b/libavformat/hlsplaylist.c
> @@ -76,7 +76,7 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
>   
>   void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache,
>                                     int target_duration, int64_t sequence,
> -                                  uint32_t playlist_type) {
> +                                  uint32_t playlist_type, int iframe_mode) {
>       if (!out)
>           return;
>       ff_hls_write_playlist_version(out, version);
> @@ -92,6 +92,9 @@ void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache,
>       } else if (playlist_type == PLAYLIST_TYPE_VOD) {
>           avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n");
>       }
> +    if (iframe_mode) {
> +        avio_printf(out, "#EXT-X-I-FRAMES-ONLY\n");
> +    }
>   }
>   
>   void ff_hls_write_init_file(AVIOContext *out, char *filename,
> @@ -108,7 +111,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
>                                double duration, int round_duration,
>                                int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set
>                                char *baseurl, //Ignored if NULL
> -                             char *filename, double *prog_date_time) {
> +                             char *filename, double *prog_date_time,
> +                             int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode) {
>       if (!out || !filename)
>           return AVERROR(EINVAL);
>   
> @@ -120,7 +124,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
>       else
>           avio_printf(out, "#EXTINF:%f,\n", duration);
>       if (byterange_mode)
> -        avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", size, pos);
> +        avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", iframe_mode ? video_keyframe_size : size,
> +                    iframe_mode ? video_keyframe_pos : pos);
>   
>       if (prog_date_time) {
>           time_t tt, wrongsecs;
> diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h
> index 54c93a3963..8d2d83b661 100644
> --- a/libavformat/hlsplaylist.h
> +++ b/libavformat/hlsplaylist.h
> @@ -44,7 +44,7 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
>                                 char *codecs, char *ccgroup);
>   void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache,
>                                     int target_duration, int64_t sequence,
> -                                  uint32_t playlist_type);
> +                                  uint32_t playlist_type, int iframe_mode);
>   void ff_hls_write_init_file(AVIOContext *out, char *filename,
>                               int byterange_mode, int64_t size, int64_t pos);
>   int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
> @@ -52,7 +52,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
>                                double duration, int round_duration,
>                                int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set
>                                char *baseurl, //Ignored if NULL
> -                             char *filename, double *prog_date_time);
> +                             char *filename, double *prog_date_time,
> +                             int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode);
>   void ff_hls_write_end_list (AVIOContext *out);
>   
>   #endif /* AVFORMAT_HLSPLAYLIST_H_ */

Gyan

Patch hide | download patch | download mbox

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 83ae017d6c..7f3758b117 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -852,6 +852,10 @@  including the file containing the AES encryption key.
 Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} to playlists that has video segments
 and when all the segments of that playlist are guaranteed to start with a Key frame.
 
+@item iframes_only
+Add the @code{#EXT-X-I-FRAMES-ONLY} to playlists that has video segments
+and only can play i frames in the @code{#EXT-X-BYTERANGE} mode.
+
 @item split_by_time
 Allow segments to start on frames other than keyframes. This improves
 behavior on some players when the time between keyframes is inconsistent,
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 94b198ceb8..3fd7e78166 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -471,7 +471,7 @@  static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s,
     }
 
     ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration,
-                                 start_number, PLAYLIST_TYPE_NONE);
+                                 start_number, PLAYLIST_TYPE_NONE, 0);
 
     ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file,
                            os->init_range_length, os->init_start_pos);
@@ -491,7 +491,7 @@  static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s,
                                 (double) seg->duration / timescale, 0,
                                 seg->range_length, seg->start_pos, NULL,
                                 c->single_file ? os->initfile : seg->file,
-                                &prog_date_time);
+                                &prog_date_time, 0, 0, 0);
         if (ret < 0) {
             av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
         }
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 6b913be31c..4ffc522803 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -75,6 +75,8 @@  typedef struct HLSSegment {
     int discont;
     int64_t pos;
     int64_t size;
+    int64_t keyframe_pos;
+    int64_t keyframe_size;
     unsigned var_stream_idx;
 
     char key_uri[LINE_BUFFER_SIZE + 1];
@@ -99,6 +101,7 @@  typedef enum HLSFlags {
     HLS_TEMP_FILE = (1 << 11),
     HLS_PERIODIC_REKEY = (1 << 12),
     HLS_INDEPENDENT_SEGMENTS = (1 << 13),
+    HLS_I_FRAMES_ONLY = (1 << 14),
 } HLSFlags;
 
 typedef enum {
@@ -125,6 +128,9 @@  typedef struct VariantStream {
     double dpp;           // duration per packet
     int64_t start_pts;
     int64_t end_pts;
+    int64_t video_lastpos;
+    int64_t video_keyframe_pos;
+    int64_t video_keyframe_size;
     double duration;      // last segment duration computed so far, in seconds
     int64_t start_pos;    // last segment starting position
     int64_t size;         // last segment size
@@ -994,6 +1000,8 @@  static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
     en->duration = duration;
     en->pos      = pos;
     en->size     = size;
+    en->keyframe_pos      = vs->video_keyframe_pos;
+    en->keyframe_size     = vs->video_keyframe_size;
     en->next     = NULL;
     en->discont  = 0;
 
@@ -1411,7 +1419,7 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
 
     vs->discontinuity_set = 0;
     ff_hls_write_playlist_header(hls->m3u8_out, hls->version, hls->allowcache,
-                                 target_duration, sequence, hls->pl_type);
+                                 target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY);
 
     if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){
         avio_printf(hls->m3u8_out, "#EXT-X-DISCONTINUITY\n");
@@ -1439,7 +1447,7 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
         ret = ff_hls_write_file_entry(hls->m3u8_out, en->discont, byterange_mode,
                                       en->duration, hls->flags & HLS_ROUND_DURATIONS,
                                       en->size, en->pos, vs->baseurl,
-                                      en->filename, prog_date_time_p);
+                                      en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
         if (ret < 0) {
             av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
         }
@@ -1455,11 +1463,11 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
             goto fail;
         }
         ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache,
-                                     target_duration, sequence, PLAYLIST_TYPE_NONE);
+                                     target_duration, sequence, PLAYLIST_TYPE_NONE, 0);
         for (en = vs->segments; en; en = en->next) {
             ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode,
                                           en->duration, 0, en->size, en->pos,
-                                          vs->baseurl, en->sub_filename, NULL);
+                                          vs->baseurl, en->sub_filename, NULL, 0, 0, 0);
             if (ret < 0) {
                 av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
             }
@@ -2205,7 +2213,7 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
         vs->start_pts = pkt->pts;
     }
 
-    if (vs->has_video) {
+   if (vs->has_video) {
         can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
                     ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME));
         is_ref_pkt = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->stream_index == vs->reference_stream_index);
@@ -2240,6 +2248,7 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
         av_write_frame(vs->avf, NULL); /* Flush any buffered data */
 
         new_start_pos = avio_tell(vs->avf->pb);
+
         if (hls->segment_type != SEGMENT_TYPE_FMP4) {
             avio_flush(oc->pb);
             vs->size = new_start_pos - vs->start_pos;
@@ -2368,6 +2377,13 @@  static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
     vs->packets_written++;
     if (oc->pb) {
         ret = ff_write_chained(oc, stream_index, pkt, s, 0);
+        if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
+            vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos;
+            vs->video_keyframe_pos = vs->start_pos;
+        } else {
+            vs->video_lastpos = avio_tell(oc->pb);
+        }
+
         if (hls->ignore_io_errors)
             ret = 0;
     }
@@ -2919,6 +2935,7 @@  static const AVOption options[] = {
     {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX,   E, "flags"},
     {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX,   E, "flags"},
     {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"},
+    {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, "flags"},
 #if FF_API_HLS_USE_LOCALTIME
     {"use_localtime", "set filename expansion with strftime at segment creation(will be deprecated )", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
 #endif
diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c
index 0537049a97..e8b566789c 100644
--- a/libavformat/hlsplaylist.c
+++ b/libavformat/hlsplaylist.c
@@ -76,7 +76,7 @@  void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
 
 void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache,
                                   int target_duration, int64_t sequence,
-                                  uint32_t playlist_type) {
+                                  uint32_t playlist_type, int iframe_mode) {
     if (!out)
         return;
     ff_hls_write_playlist_version(out, version);
@@ -92,6 +92,9 @@  void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache,
     } else if (playlist_type == PLAYLIST_TYPE_VOD) {
         avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n");
     }
+    if (iframe_mode) {
+        avio_printf(out, "#EXT-X-I-FRAMES-ONLY\n");
+    }
 }
 
 void ff_hls_write_init_file(AVIOContext *out, char *filename,
@@ -108,7 +111,8 @@  int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
                              double duration, int round_duration,
                              int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set
                              char *baseurl, //Ignored if NULL
-                             char *filename, double *prog_date_time) {
+                             char *filename, double *prog_date_time,
+                             int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode) {
     if (!out || !filename)
         return AVERROR(EINVAL);
 
@@ -120,7 +124,8 @@  int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
     else
         avio_printf(out, "#EXTINF:%f,\n", duration);
     if (byterange_mode)
-        avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", size, pos);
+        avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", iframe_mode ? video_keyframe_size : size,
+                    iframe_mode ? video_keyframe_pos : pos);
 
     if (prog_date_time) {
         time_t tt, wrongsecs;
diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h
index 54c93a3963..8d2d83b661 100644
--- a/libavformat/hlsplaylist.h
+++ b/libavformat/hlsplaylist.h
@@ -44,7 +44,7 @@  void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
                               char *codecs, char *ccgroup);
 void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache,
                                   int target_duration, int64_t sequence,
-                                  uint32_t playlist_type);
+                                  uint32_t playlist_type, int iframe_mode);
 void ff_hls_write_init_file(AVIOContext *out, char *filename,
                             int byterange_mode, int64_t size, int64_t pos);
 int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
@@ -52,7 +52,8 @@  int ff_hls_write_file_entry(AVIOContext *out, int insert_discont,
                              double duration, int round_duration,
                              int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set
                              char *baseurl, //Ignored if NULL
-                             char *filename, double *prog_date_time);
+                             char *filename, double *prog_date_time,
+                             int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode);
 void ff_hls_write_end_list (AVIOContext *out);
 
 #endif /* AVFORMAT_HLSPLAYLIST_H_ */