mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-02-06 23:04:54 +00:00
avformat/hlsenc: add EXT-X-I-FRAMES-ONLY tag support
Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
This commit is contained in:
parent
4208b428c4
commit
fa7a6dbd76
@ -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 can play only 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,
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user