X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fhlsenc.c;h=a9fa5d8aef164c5168aa4c28705f4070ac24b690;hb=6372c9dc9972318e75a5889ad6c52500b8294099;hp=8c61b6dfc66a0d04cc1e3ccd3b8ba6090b25061f;hpb=18d8398caf91ac585ae162a26ebddc0da756408f;p=ffmpeg diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 8c61b6dfc66..a9fa5d8aef1 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -64,6 +64,13 @@ typedef enum HLSFlags { HLS_OMIT_ENDLIST = (1 << 4), } HLSFlags; +typedef enum { + PLAYLIST_TYPE_NONE, + PLAYLIST_TYPE_EVENT, + PLAYLIST_TYPE_VOD, + PLAYLIST_TYPE_NB, +} PlaylistType; + typedef struct HLSContext { const AVClass *class; // Class for private options. unsigned number; @@ -79,6 +86,7 @@ typedef struct HLSContext { int max_nb_segments; // Set by a private option. int wrap; // Set by a private option. uint32_t flags; // enum HLSFlags + uint32_t pl_type; // enum PlaylistType char *segment_filename; int use_localtime; ///< flag to expand filename with localtime @@ -288,14 +296,14 @@ static int hls_mux_init(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st; AVFormatContext *loc; - if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) + if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) loc = vtt_oc; else loc = oc; if (!(st = avformat_new_stream(loc, NULL))) return AVERROR(ENOMEM); - avcodec_copy_context(st->codec, s->streams[i]->codec); + avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; st->time_base = s->streams[i]->time_base; } @@ -357,6 +365,10 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double hls->last_segment = en; + // EVENT or VOD playlists imply sliding window cannot be used + if (hls->pl_type != PLAYLIST_TYPE_NONE) + hls->max_nb_segments = 0; + if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { en = hls->segments; hls->segments = en->next; @@ -416,7 +428,7 @@ static int hls_window(AVFormatContext *s, int last) set_http_options(&options, hls); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename); - if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL)) < 0) + if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, &options)) < 0) goto fail; for (en = hls->segments; en; en = en->next) { @@ -432,6 +444,11 @@ static int hls_window(AVFormatContext *s, int last) } avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + if (hls->pl_type == PLAYLIST_TYPE_EVENT) { + avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); + } else if (hls->pl_type == PLAYLIST_TYPE_VOD) { + avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); + } av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); @@ -642,9 +659,9 @@ static int hls_write_header(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { hls->has_video += - s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO; + s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; hls->has_subtitle += - s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE; + s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE; } if (hls->has_video > 1) @@ -746,7 +763,7 @@ static int hls_write_header(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *inner_st; AVStream *outer_st = s->streams[i]; - if (outer_st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) + if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) inner_st = hls->avf->streams[i]; else if (hls->vtt_avf) inner_st = hls->vtt_avf->streams[0]; @@ -782,7 +799,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) int ret, can_split = 1; int stream_index = 0; - if( st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE ) { + if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) { oc = hls->vtt_avf; stream_index = 0; } else { @@ -795,9 +812,9 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } if (hls->has_video) { - can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && pkt->flags & AV_PKT_FLAG_KEY; - is_ref_pkt = st->codec->codec_type == AVMEDIA_TYPE_VIDEO; + is_ref_pkt = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; } if (pkt->pts == AV_NOPTS_VALUE) is_ref_pkt = can_split = 0; @@ -836,7 +853,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (ret < 0) return ret; - if( st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE ) + if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) oc = hls->vtt_avf; else oc = hls->avf; @@ -908,6 +925,9 @@ static const AVOption options[] = { {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"}, {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" }, + {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" }, + {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" }, {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, { NULL },