00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/avstring.h"
00023 #include "libavutil/log.h"
00024 #include "libavutil/opt.h"
00025 #include "libavutil/mathematics.h"
00026 #include "libavutil/parseutils.h"
00027 #include "avformat.h"
00028 #include "internal.h"
00029 #include <strings.h>
00030 #include <float.h>
00031
00032 typedef struct {
00033 const AVClass *class;
00034 int number;
00035 AVFormatContext *avf;
00036 char *format;
00037 char *pattern;
00038 char *path;
00039 float time;
00040 int64_t offset_time;
00041 int64_t recording_time;
00042 } SegmentContext;
00043
00044 #if CONFIG_SEGMENT_MUXER
00045
00046 static int segment_header(SegmentContext *s)
00047 {
00048 AVFormatContext *oc = s->avf;
00049 int err = 0;
00050
00051 av_strlcpy(oc->filename, s->path, sizeof(oc->filename));
00052
00053 av_strlcatf(oc->filename, sizeof(oc->filename),
00054 s->pattern, s->number++);
00055
00056 if ((err = avio_open(&oc->pb, oc->filename, AVIO_FLAG_WRITE)) < 0) {
00057 return err;
00058 }
00059
00060 if (!oc->priv_data && oc->oformat->priv_data_size > 0) {
00061 oc->priv_data = av_mallocz(oc->oformat->priv_data_size);
00062 if (!oc->priv_data) {
00063 avio_close(oc->pb);
00064 return AVERROR(ENOMEM);
00065 }
00066 }
00067
00068 if ((err = oc->oformat->write_header(oc)) < 0) {
00069 avio_close(oc->pb);
00070 av_freep(&oc->priv_data);
00071 }
00072
00073 return err;
00074 }
00075
00076 static int segment_trailer(AVFormatContext *oc)
00077 {
00078 int ret = 0;
00079
00080 if(oc->oformat->write_trailer)
00081 ret = oc->oformat->write_trailer(oc);
00082
00083 avio_close(oc->pb);
00084 av_freep(&oc->priv_data);
00085
00086 return ret;
00087 }
00088
00089 static int seg_write_header(AVFormatContext *s)
00090 {
00091 SegmentContext *seg = s->priv_data;
00092 AVFormatContext *oc;
00093 int ret;
00094
00095 seg->number = 0;
00096 seg->recording_time = seg->time*1000000;
00097 seg->offset_time = 0;
00098
00099 if (!seg->path) {
00100 char *t;
00101 seg->path = av_strdup(s->filename);
00102 t = strrchr(seg->path, '.');
00103 if (t) *t = '\0';
00104 }
00105
00106 oc = avformat_alloc_context();
00107
00108 if (!oc) {
00109 return AVERROR(ENOMEM);
00110 }
00111
00112 oc->oformat = av_guess_format(seg->format, NULL, NULL);
00113
00114 if (!oc->oformat) {
00115 avformat_free_context(oc);
00116 return AVERROR_MUXER_NOT_FOUND;
00117 }
00118
00119 seg->avf = oc;
00120
00121 oc->streams = s->streams;
00122 oc->nb_streams = s->nb_streams;
00123
00124 av_strlcpy(oc->filename, seg->path, sizeof(oc->filename));
00125
00126 av_strlcatf(oc->filename, sizeof(oc->filename),
00127 seg->pattern, seg->number++);
00128
00129 if ((ret = avio_open(&oc->pb, oc->filename, AVIO_FLAG_WRITE)) < 0) {
00130 avformat_free_context(oc);
00131 return ret;
00132 }
00133
00134 if ((ret = avformat_write_header(oc, NULL)) < 0) {
00135 avio_close(oc->pb);
00136 }
00137
00138 if (ret)
00139 avformat_free_context(oc);
00140
00141 avio_printf(s->pb, "%s\n", oc->filename);
00142 avio_flush(s->pb);
00143
00144 return ret;
00145 }
00146
00147 static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
00148 {
00149 SegmentContext *seg = s->priv_data;
00150 AVFormatContext *oc = seg->avf;
00151 AVStream *st = oc->streams[pkt->stream_index];
00152 int ret;
00153
00154 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
00155 av_compare_ts(pkt->pts, st->time_base,
00156 seg->recording_time*seg->number,
00157 (AVRational){1, 1000000}) >= 0 &&
00158 pkt->flags & AV_PKT_FLAG_KEY) {
00159 av_log(s, AV_LOG_INFO, "I'd reset at %d %"PRId64"\n",
00160 pkt->stream_index, pkt->pts);
00161
00162 ret = segment_trailer(oc);
00163 if (!ret)
00164 ret = segment_header(seg);
00165
00166 if (ret) {
00167 avformat_free_context(oc);
00168 return ret;
00169 }
00170 avio_printf(s->pb, "%s\n", oc->filename);
00171 avio_flush(s->pb);
00172 }
00173
00174 ret = oc->oformat->write_packet(oc, pkt);
00175
00176 return ret;
00177 }
00178
00179 static int seg_write_trailer(struct AVFormatContext *s)
00180 {
00181 SegmentContext *seg = s->priv_data;
00182 AVFormatContext *oc = seg->avf;
00183
00184 return segment_trailer(oc);
00185 }
00186
00187 #endif
00188
00189 #define OFFSET(x) offsetof(SegmentContext, x)
00190 #define E AV_OPT_FLAG_ENCODING_PARAM
00191 static const AVOption options[] = {
00192 { "container_format", "container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = "nut"}, 0, 0, E },
00193 { "segment_time", "segment lenght in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E },
00194 { "segment_pattern", "pattern to use in segment files", OFFSET(pattern),AV_OPT_TYPE_STRING, {.str = "%03d"}, 0, 0, E },
00195 { "segment_basename", "basename to use in segment files", OFFSET(path ),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
00196 { NULL },
00197 };
00198
00199 static const AVClass seg_class = {
00200 .class_name = "segment muxer",
00201 .item_name = av_default_item_name,
00202 .option = options,
00203 .version = LIBAVUTIL_VERSION_INT,
00204 };
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 #if CONFIG_SEGMENT_MUXER
00223 AVOutputFormat ff_segment_muxer = {
00224 .name = "segment",
00225 .long_name = NULL_IF_CONFIG_SMALL("segment muxer"),
00226 .extensions = "m3u8",
00227 .priv_data_size = sizeof(SegmentContext),
00228 .flags = AVFMT_GLOBALHEADER,
00229 .write_header = seg_write_header,
00230 .write_packet = seg_write_packet,
00231 .write_trailer = seg_write_trailer,
00232 .priv_class = &seg_class,
00233 };
00234 #endif