#include "libavutil/parseutils.h"
#include "libavutil/mathematics.h"
+typedef enum {
+ LIST_TYPE_FLAT = 0,
+ LIST_TYPE_EXT,
+ LIST_TYPE_NB,
+} ListType;
+
typedef struct {
const AVClass *class; /**< Class for private options. */
int number;
char *format; ///< format to use for output segment files
char *list; ///< filename for the segment list file
int list_size; ///< number of entries for the segment list file
+ ListType list_type; ///< set the list type
+ AVIOContext *list_pb; ///< list file put-byte context
float time; ///< segment duration
int wrap; ///< number after which the index wraps
int64_t recording_time;
int has_video;
- AVIOContext *pb;
+ double start_time, end_time;
} SegmentContext;
static int segment_start(AVFormatContext *s)
if (seg->list) {
if (seg->list_size && !(seg->number % seg->list_size)) {
- avio_close(seg->pb);
- if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
+ avio_close(seg->list_pb);
+ if ((ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL)) < 0)
goto end;
}
- avio_printf(seg->pb, "%s\n", oc->filename);
- avio_flush(seg->pb);
+
+ if (seg->list_type == LIST_TYPE_FLAT) {
+ avio_printf(seg->list_pb, "%s\n", oc->filename);
+ } else if (seg->list_type == LIST_TYPE_EXT) {
+ avio_printf(seg->list_pb, "%s,%f,%f\n", oc->filename, seg->start_time, seg->end_time);
+ }
+ avio_flush(seg->list_pb);
}
end:
return AVERROR(ENOMEM);
if (seg->list)
- if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
+ if ((ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL)) < 0)
goto fail;
avformat_free_context(oc);
}
if (seg->list)
- avio_close(seg->pb);
+ avio_close(seg->list_pb);
}
return ret;
}
if ((ret = segment_end(s)) < 0 || (ret = segment_start(s)) < 0)
goto fail;
+ seg->start_time = (double)pkt->pts * av_q2d(st->time_base);
+ } else if (pkt->pts != AV_NOPTS_VALUE) {
+ seg->end_time = FFMAX(seg->end_time,
+ (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
}
ret = oc->oformat->write_packet(oc, pkt);
oc->streams = NULL;
oc->nb_streams = 0;
if (seg->list)
- avio_close(seg->pb);
+ avio_close(seg->list_pb);
avformat_free_context(oc);
}
AVFormatContext *oc = seg->avf;
int ret = segment_end(s);
if (seg->list)
- avio_close(seg->pb);
+ avio_close(seg->list_pb);
oc->streams = NULL;
oc->nb_streams = 0;
avformat_free_context(oc);
{ "segment_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E },
{ "segment_list", "set the segment list filename", OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
{ "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.dbl = 5}, 0, INT_MAX, E },
+ { "segment_list_type", "set the segment list type", OFFSET(list_type), AV_OPT_TYPE_INT, {.dbl = LIST_TYPE_FLAT}, 0, LIST_TYPE_NB-1, E, "list_type" },
+ { "flat", "flat format", 0, AV_OPT_TYPE_CONST, {.dbl=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, 0, "list_type" },
+ { "ext", "extended format", 0, AV_OPT_TYPE_CONST, {.dbl=LIST_TYPE_EXT }, INT_MIN, INT_MAX, 0, "list_type" },
{ "segment_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, E },
{ NULL },
};