On 10/10/2012 12:04 AM, Martin Storsjö wrote: > On Tue, 9 Oct 2012, Luca Barbato wrote: > >> --- >> >> Should be ok now, Martin, did I overlook something else? >> >> libavformat/segment.c | 49 >> +++++++++++++++++++++++++++++++++++++++++++++++-- >> 1 file changed, 47 insertions(+), 2 deletions(-) >> >> diff --git a/libavformat/segment.c b/libavformat/segment.c >> index 8ac04e2..9a53333 100644 >> --- a/libavformat/segment.c >> +++ b/libavformat/segment.c >> @@ -37,6 +37,7 @@ typedef struct { >> AVFormatContext *avf; >> char *format; /**< Set by a private option. */ >> char *list; /**< Set by a private option. */ >> + int list_type; /**< Set by a private option. */ >> float time; /**< Set by a private option. */ >> int size; /**< Set by a private option. */ >> int wrap; /**< Set by a private option. */ >> @@ -48,6 +49,11 @@ typedef struct { >> AVIOContext *pb; >> } SegmentContext; >> >> +enum { >> + LIST_FLAT, >> + LIST_HLS >> +}; >> + >> static int segment_mux_init(AVFormatContext *s) >> { >> SegmentContext *seg = s->priv_data; >> @@ -72,6 +78,34 @@ static int segment_mux_init(AVFormatContext *s) >> return 0; >> } >> >> +static void segment_hls_header(SegmentContext *seg) >> +{ >> + avio_printf(seg->pb, "#EXTM3U\n"); >> + >> + avio_printf(seg->pb, "#EXT-X-VERSION:3\n"); >> + >> + avio_printf(seg->pb, "#EXT-X-TARGETDURATION:%d\n", (int)seg->time); >> + >> + avio_printf(seg->pb, "#EXT-X-MEDIA-SEQUENCE:%d\n", >> + FFMAX(0, seg->number - seg->size)); >> +} > > The extra newlines just look weird here to me. > >> + >> +static void segment_hls_window(AVFormatContext *s) >> +{ >> + SegmentContext *seg = s->priv_data; >> + int i; >> + char buf[1024]; >> + >> + segment_hls_header(seg); >> + for (i = FFMAX(0, seg->number - seg->size); >> + i < seg->number; i++) { >> + avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time); >> + av_get_frame_filename(buf, sizeof(buf), s->filename, i); >> + avio_printf(seg->pb, "%s\n", buf); >> + } >> + avio_flush(seg->pb); >> +} >> + >> static int segment_start(AVFormatContext *s, int write_header) >> { >> SegmentContext *c = s->priv_data; >> @@ -211,6 +245,10 @@ static int seg_write_header(AVFormatContext *s) >> } >> >> if (seg->list) { >> + if (seg->list_type == LIST_HLS) { >> + segment_hls_header(seg); >> + avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time); >> + } >> avio_printf(seg->pb, "%s\n", oc->filename); >> avio_flush(seg->pb); >> } >> @@ -252,14 +290,18 @@ static int seg_write_packet(AVFormatContext *s, >> AVPacket *pkt) >> oc = seg->avf; >> >> if (seg->list) { >> - avio_printf(seg->pb, "%s\n", oc->filename); >> + if (seg->list_type != LIST_HLS) >> +// avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time); >> + avio_printf(seg->pb, "%s\n", oc->filename); >> avio_flush(seg->pb); >> - if (seg->size && !(seg->number % seg->size)) { >> + if (seg->list_type == LIST_HLS || >> + seg->size && !(seg->number % seg->size)) { >> avio_close(seg->pb); >> if ((ret = avio_open2(&seg->pb, seg->list, >> AVIO_FLAG_WRITE, >> &s->interrupt_callback, NULL)) < 0) >> goto fail; >> } >> + segment_hls_window(s); > > Hmm, I guess this works, although it keeps the file open for writing all > the time (instead of just opening, writing and closing each time you > want to update it). > >> } >> } >> >> @@ -301,6 +343,9 @@ static const AVOption options[] = { >> { "segment_time", "segment length in seconds", >> OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E }, >> { "segment_list", "output the segment list", >> OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, >> { "segment_list_size", "maximum number of playlist entries", >> OFFSET(size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E }, >> + { "segment_list_type", "segment list format", >> OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, E, >> "list_type" }, > > This could use LIST_FLAT instead of 0 as default here > >> + { "flat", "plain list (default)", >> 0, AV_OPT_TYPE_CONST, {.i64 = LIST_FLAT}, 0, 0, E, >> "list_type" }, >> + { "hls", "Apple HTTP Live Streaming compatible", >> 0, AV_OPT_TYPE_CONST, {.i64 = LIST_HLS}, 0, 0, E, >> "list_type" }, >> { "segment_wrap", "number after which the index wraps", >> OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, >> { "individual_header_trailer", "write header/trailer to each >> segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = >> 1}, 0, 1, E }, >> { "write_header_trailer", "write a header to the first segment and >> a trailer to the last one", OFFSET(write_header_trailer), >> AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, >> -- >> 1.7.12 > > You might want to write a list terminator to the file when the muxer is > closed, to indicate to players that no more segments will be added (that > is, the stream transitions from live to on-demand). > > Other than that, this looks acceptable to me. >
Ok. Let me address those comments. lu _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel