3 * Copyright (c) 2013 Martin Storsjo
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "os_support.h"
32 #include "libavutil/avstring.h"
33 #include "libavutil/base64.h"
34 #include "libavutil/intreadwrite.h"
35 #include "libavutil/mathematics.h"
36 #include "libavutil/opt.h"
38 typedef struct Fragment
{
40 int64_t start_time
, duration
;
44 typedef struct OutputStream
{
50 char temp_filename
[1024];
51 int64_t frag_start_ts
, last_ts
;
54 int nb_fragments
, fragments_size
, fragment_index
;
57 int has_audio
, has_video
;
62 uint8_t *extra_packets
[2];
63 int extra_packet_sizes
[2];
67 typedef struct HDSContext
{
68 const AVClass
*class; /* Class for private options. */
70 int extra_window_size
;
71 int min_frag_duration
;
74 OutputStream
*streams
;
78 static int parse_header(OutputStream
*os
, const uint8_t *buf
, int buf_size
)
81 return AVERROR_INVALIDDATA
;
82 if (memcmp(buf
, "FLV", 3))
83 return AVERROR_INVALIDDATA
;
86 while (buf_size
>= 11 + 4) {
88 int size
= AV_RB24(&buf
[1]) + 11 + 4;
90 return AVERROR_INVALIDDATA
;
91 if (type
== 8 || type
== 9) {
92 if (os
->nb_extra_packets
>= FF_ARRAY_ELEMS(os
->extra_packets
))
93 return AVERROR_INVALIDDATA
;
94 os
->extra_packet_sizes
[os
->nb_extra_packets
] = size
;
95 os
->extra_packets
[os
->nb_extra_packets
] = av_malloc(size
);
96 if (!os
->extra_packets
[os
->nb_extra_packets
])
97 return AVERROR(ENOMEM
);
98 memcpy(os
->extra_packets
[os
->nb_extra_packets
], buf
, size
);
99 os
->nb_extra_packets
++;
100 } else if (type
== 0x12) {
102 return AVERROR_INVALIDDATA
;
103 os
->metadata_size
= size
- 11 - 4;
104 os
->metadata
= av_malloc(os
->metadata_size
);
106 return AVERROR(ENOMEM
);
107 memcpy(os
->metadata
, buf
+ 11, os
->metadata_size
);
113 return AVERROR_INVALIDDATA
;
117 static int hds_write(void *opaque
, uint8_t *buf
, int buf_size
)
119 OutputStream
*os
= opaque
;
121 avio_write(os
->out
, buf
, buf_size
);
123 if (!os
->metadata_size
) {
125 // Assuming the IO buffer is large enough to fit the
126 // FLV header and all metadata and extradata packets
127 if ((ret
= parse_header(os
, buf
, buf_size
)) < 0)
134 static void hds_free(AVFormatContext
*s
)
136 HDSContext
*c
= s
->priv_data
;
140 for (i
= 0; i
< s
->nb_streams
; i
++) {
141 OutputStream
*os
= &c
->streams
[i
];
145 if (os
->ctx
&& os
->ctx_inited
)
146 av_write_trailer(os
->ctx
);
147 if (os
->ctx
&& os
->ctx
->pb
)
148 av_free(os
->ctx
->pb
);
150 avformat_free_context(os
->ctx
);
151 av_free(os
->metadata
);
152 for (j
= 0; j
< os
->nb_extra_packets
; j
++)
153 av_free(os
->extra_packets
[j
]);
154 for (j
= 0; j
< os
->nb_fragments
; j
++)
155 av_free(os
->fragments
[j
]);
156 av_free(os
->fragments
);
158 av_freep(&c
->streams
);
161 static int write_manifest(AVFormatContext
*s
, int final
)
163 HDSContext
*c
= s
->priv_data
;
165 char filename
[1024], temp_filename
[1024];
169 if (c
->nb_streams
> 0)
170 duration
= c
->streams
[0].last_ts
* av_q2d(s
->streams
[0]->time_base
);
172 snprintf(filename
, sizeof(filename
), "%s/index.f4m", s
->filename
);
173 snprintf(temp_filename
, sizeof(temp_filename
), "%s/index.f4m.tmp", s
->filename
);
174 ret
= avio_open2(&out
, temp_filename
, AVIO_FLAG_WRITE
,
175 &s
->interrupt_callback
, NULL
);
177 av_log(s
, AV_LOG_ERROR
, "Unable to open %s for writing\n", temp_filename
);
180 avio_printf(out
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
181 avio_printf(out
, "<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n");
182 avio_printf(out
, "\t<id>%s</id>\n", av_basename(s
->filename
));
183 avio_printf(out
, "\t<streamType>%s</streamType>\n",
184 final
? "recorded" : "live");
185 avio_printf(out
, "\t<deliveryType>streaming</deliveryType>\n");
187 avio_printf(out
, "\t<duration>%f</duration>\n", duration
);
188 for (i
= 0; i
< c
->nb_streams
; i
++) {
189 OutputStream
*os
= &c
->streams
[i
];
190 int b64_size
= AV_BASE64_SIZE(os
->metadata_size
);
191 char *base64
= av_malloc(b64_size
);
194 return AVERROR(ENOMEM
);
196 av_base64_encode(base64
, b64_size
, os
->metadata
, os
->metadata_size
);
198 avio_printf(out
, "\t<bootstrapInfo profile=\"named\" url=\"stream%d.abst\" id=\"bootstrap%d\" />\n", i
, i
);
199 avio_printf(out
, "\t<media bitrate=\"%d\" url=\"stream%d\" bootstrapInfoId=\"bootstrap%d\">\n", os
->bitrate
/1000, i
, i
);
200 avio_printf(out
, "\t\t<metadata>%s</metadata>\n", base64
);
201 avio_printf(out
, "\t</media>\n");
204 avio_printf(out
, "</manifest>\n");
207 return ff_rename(temp_filename
, filename
, s
);
210 static void update_size(AVIOContext
*out
, int64_t pos
)
212 int64_t end
= avio_tell(out
);
213 avio_seek(out
, pos
, SEEK_SET
);
214 avio_wb32(out
, end
- pos
);
215 avio_seek(out
, end
, SEEK_SET
);
218 /* Note, the .abst files need to be served with the "binary/octet"
219 * mime type, otherwise at least the OSMF player can easily fail
220 * with "stream not found" when polling for the next fragment. */
221 static int write_abst(AVFormatContext
*s
, OutputStream
*os
, int final
)
223 HDSContext
*c
= s
->priv_data
;
225 char filename
[1024], temp_filename
[1024];
227 int64_t asrt_pos
, afrt_pos
;
228 int start
= 0, fragments
;
229 int index
= s
->streams
[os
->first_stream
]->id
;
230 int64_t cur_media_time
= 0;
232 start
= FFMAX(os
->nb_fragments
- c
->window_size
, 0);
233 fragments
= os
->nb_fragments
- start
;
235 cur_media_time
= os
->last_ts
;
236 else if (os
->nb_fragments
)
237 cur_media_time
= os
->fragments
[os
->nb_fragments
- 1]->start_time
;
239 snprintf(filename
, sizeof(filename
),
240 "%s/stream%d.abst", s
->filename
, index
);
241 snprintf(temp_filename
, sizeof(temp_filename
),
242 "%s/stream%d.abst.tmp", s
->filename
, index
);
243 ret
= avio_open2(&out
, temp_filename
, AVIO_FLAG_WRITE
,
244 &s
->interrupt_callback
, NULL
);
246 av_log(s
, AV_LOG_ERROR
, "Unable to open %s for writing\n", temp_filename
);
249 avio_wb32(out
, 0); // abst size
250 avio_wl32(out
, MKTAG('a','b','s','t'));
251 avio_wb32(out
, 0); // version + flags
252 avio_wb32(out
, os
->fragment_index
- 1); // BootstrapinfoVersion
253 avio_w8(out
, final
? 0 : 0x20); // profile, live, update
254 avio_wb32(out
, 1000); // timescale
255 avio_wb64(out
, cur_media_time
);
256 avio_wb64(out
, 0); // SmpteTimeCodeOffset
257 avio_w8(out
, 0); // MovieIdentifer (null string)
258 avio_w8(out
, 0); // ServerEntryCount
259 avio_w8(out
, 0); // QualityEntryCount
260 avio_w8(out
, 0); // DrmData (null string)
261 avio_w8(out
, 0); // MetaData (null string)
262 avio_w8(out
, 1); // SegmentRunTableCount
263 asrt_pos
= avio_tell(out
);
264 avio_wb32(out
, 0); // asrt size
265 avio_wl32(out
, MKTAG('a','s','r','t'));
266 avio_wb32(out
, 0); // version + flags
267 avio_w8(out
, 0); // QualityEntryCount
268 avio_wb32(out
, 1); // SegmentRunEntryCount
269 avio_wb32(out
, 1); // FirstSegment
270 avio_wb32(out
, final
? (os
->fragment_index
- 1) : 0xffffffff); // FragmentsPerSegment
271 update_size(out
, asrt_pos
);
272 avio_w8(out
, 1); // FragmentRunTableCount
273 afrt_pos
= avio_tell(out
);
274 avio_wb32(out
, 0); // afrt size
275 avio_wl32(out
, MKTAG('a','f','r','t'));
276 avio_wb32(out
, 0); // version + flags
277 avio_wb32(out
, 1000); // timescale
278 avio_w8(out
, 0); // QualityEntryCount
279 avio_wb32(out
, fragments
); // FragmentRunEntryCount
280 for (i
= start
; i
< os
->nb_fragments
; i
++) {
281 avio_wb32(out
, os
->fragments
[i
]->n
);
282 avio_wb64(out
, os
->fragments
[i
]->start_time
);
283 avio_wb32(out
, os
->fragments
[i
]->duration
);
285 update_size(out
, afrt_pos
);
288 return ff_rename(temp_filename
, filename
, s
);
291 static int init_file(AVFormatContext
*s
, OutputStream
*os
, int64_t start_ts
)
294 ret
= avio_open2(&os
->out
, os
->temp_filename
, AVIO_FLAG_WRITE
,
295 &s
->interrupt_callback
, NULL
);
298 avio_wb32(os
->out
, 0);
299 avio_wl32(os
->out
, MKTAG('m','d','a','t'));
300 for (i
= 0; i
< os
->nb_extra_packets
; i
++) {
301 AV_WB24(os
->extra_packets
[i
] + 4, start_ts
);
302 os
->extra_packets
[i
][7] = (start_ts
>> 24) & 0x7f;
303 avio_write(os
->out
, os
->extra_packets
[i
], os
->extra_packet_sizes
[i
]);
308 static void close_file(OutputStream
*os
)
310 int64_t pos
= avio_tell(os
->out
);
311 avio_seek(os
->out
, 0, SEEK_SET
);
312 avio_wb32(os
->out
, pos
);
318 static int hds_write_header(AVFormatContext
*s
)
320 HDSContext
*c
= s
->priv_data
;
322 AVOutputFormat
*oformat
;
324 if (mkdir(s
->filename
, 0777) == -1 && errno
!= EEXIST
) {
325 ret
= AVERROR(errno
);
326 av_log(s
, AV_LOG_ERROR
, "Failed to create directory %s\n", s
->filename
);
330 oformat
= av_guess_format("flv", NULL
, NULL
);
332 ret
= AVERROR_MUXER_NOT_FOUND
;
336 c
->streams
= av_mallocz_array(s
->nb_streams
, sizeof(*c
->streams
));
338 ret
= AVERROR(ENOMEM
);
342 for (i
= 0; i
< s
->nb_streams
; i
++) {
343 OutputStream
*os
= &c
->streams
[c
->nb_streams
];
344 AVFormatContext
*ctx
;
345 AVStream
*st
= s
->streams
[i
];
347 if (!st
->codec
->bit_rate
) {
348 av_log(s
, AV_LOG_ERROR
, "No bit rate set for stream %d\n", i
);
349 ret
= AVERROR(EINVAL
);
352 if (st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
358 } else if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
365 av_log(s
, AV_LOG_ERROR
, "Unsupported stream type in stream %d\n", i
);
366 ret
= AVERROR(EINVAL
);
369 os
->bitrate
+= s
->streams
[i
]->codec
->bit_rate
;
372 os
->first_stream
= i
;
373 ctx
= avformat_alloc_context();
375 ret
= AVERROR(ENOMEM
);
379 ctx
->oformat
= oformat
;
380 ctx
->interrupt_callback
= s
->interrupt_callback
;
382 ctx
->pb
= avio_alloc_context(os
->iobuf
, sizeof(os
->iobuf
),
384 NULL
, hds_write
, NULL
);
386 ret
= AVERROR(ENOMEM
);
392 s
->streams
[i
]->id
= c
->nb_streams
;
394 if (!(st
= avformat_new_stream(ctx
, NULL
))) {
395 ret
= AVERROR(ENOMEM
);
398 avcodec_copy_context(st
->codec
, s
->streams
[i
]->codec
);
399 st
->codec
->codec_tag
= 0;
400 st
->sample_aspect_ratio
= s
->streams
[i
]->sample_aspect_ratio
;
401 st
->time_base
= s
->streams
[i
]->time_base
;
403 if (c
->streams
[c
->nb_streams
].ctx
)
406 for (i
= 0; i
< c
->nb_streams
; i
++) {
407 OutputStream
*os
= &c
->streams
[i
];
409 if ((ret
= avformat_write_header(os
->ctx
, NULL
)) < 0) {
413 avio_flush(os
->ctx
->pb
);
414 for (j
= 0; j
< os
->ctx
->nb_streams
; j
++)
415 s
->streams
[os
->first_stream
+ j
]->time_base
= os
->ctx
->streams
[j
]->time_base
;
417 snprintf(os
->temp_filename
, sizeof(os
->temp_filename
),
418 "%s/stream%d_temp", s
->filename
, i
);
419 ret
= init_file(s
, os
, 0);
423 if (!os
->has_video
&& c
->min_frag_duration
<= 0) {
424 av_log(s
, AV_LOG_WARNING
,
425 "No video stream in output stream %d and no min frag duration set\n", i
);
426 ret
= AVERROR(EINVAL
);
428 os
->fragment_index
= 1;
429 write_abst(s
, os
, 0);
431 ret
= write_manifest(s
, 0);
439 static int add_fragment(OutputStream
*os
, const char *file
,
440 int64_t start_time
, int64_t duration
)
445 if (os
->nb_fragments
>= os
->fragments_size
) {
447 os
->fragments_size
= (os
->fragments_size
+ 1) * 2;
448 if ((ret
= av_reallocp_array(&os
->fragments
, os
->fragments_size
,
449 sizeof(*os
->fragments
))) < 0) {
450 os
->fragments_size
= 0;
451 os
->nb_fragments
= 0;
455 frag
= av_mallocz(sizeof(*frag
));
457 return AVERROR(ENOMEM
);
458 av_strlcpy(frag
->file
, file
, sizeof(frag
->file
));
459 frag
->start_time
= start_time
;
460 frag
->duration
= duration
;
461 frag
->n
= os
->fragment_index
;
462 os
->fragments
[os
->nb_fragments
++] = frag
;
463 os
->fragment_index
++;
467 static int hds_flush(AVFormatContext
*s
, OutputStream
*os
, int final
,
470 HDSContext
*c
= s
->priv_data
;
472 char target_filename
[1024];
473 int index
= s
->streams
[os
->first_stream
]->id
;
475 if (!os
->packets_written
)
478 avio_flush(os
->ctx
->pb
);
479 os
->packets_written
= 0;
482 snprintf(target_filename
, sizeof(target_filename
),
483 "%s/stream%dSeg1-Frag%d", s
->filename
, index
, os
->fragment_index
);
484 ret
= ff_rename(os
->temp_filename
, target_filename
, s
);
487 add_fragment(os
, target_filename
, os
->frag_start_ts
, end_ts
- os
->frag_start_ts
);
490 ret
= init_file(s
, os
, end_ts
);
495 if (c
->window_size
|| (final
&& c
->remove_at_exit
)) {
496 int remove
= os
->nb_fragments
- c
->window_size
- c
->extra_window_size
;
497 if (final
&& c
->remove_at_exit
)
498 remove
= os
->nb_fragments
;
500 for (i
= 0; i
< remove
; i
++) {
501 unlink(os
->fragments
[i
]->file
);
502 av_free(os
->fragments
[i
]);
504 os
->nb_fragments
-= remove
;
505 memmove(os
->fragments
, os
->fragments
+ remove
,
506 os
->nb_fragments
* sizeof(*os
->fragments
));
511 ret
= write_abst(s
, os
, final
);
515 static int hds_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
517 HDSContext
*c
= s
->priv_data
;
518 AVStream
*st
= s
->streams
[pkt
->stream_index
];
519 OutputStream
*os
= &c
->streams
[s
->streams
[pkt
->stream_index
]->id
];
520 int64_t end_dts
= os
->fragment_index
* (int64_t)c
->min_frag_duration
;
523 if (st
->first_dts
== AV_NOPTS_VALUE
)
524 st
->first_dts
= pkt
->dts
;
526 if ((!os
->has_video
|| st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) &&
527 av_compare_ts(pkt
->dts
- st
->first_dts
, st
->time_base
,
528 end_dts
, AV_TIME_BASE_Q
) >= 0 &&
529 pkt
->flags
& AV_PKT_FLAG_KEY
&& os
->packets_written
) {
531 if ((ret
= hds_flush(s
, os
, 0, pkt
->dts
)) < 0)
535 // Note, these fragment start timestamps, that represent a whole
536 // OutputStream, assume all streams in it have the same time base.
537 if (!os
->packets_written
)
538 os
->frag_start_ts
= pkt
->dts
;
539 os
->last_ts
= pkt
->dts
;
541 os
->packets_written
++;
542 return ff_write_chained(os
->ctx
, pkt
->stream_index
- os
->first_stream
, pkt
, s
, 0);
545 static int hds_write_trailer(AVFormatContext
*s
)
547 HDSContext
*c
= s
->priv_data
;
550 for (i
= 0; i
< c
->nb_streams
; i
++)
551 hds_flush(s
, &c
->streams
[i
], 1, c
->streams
[i
].last_ts
);
552 write_manifest(s
, 1);
554 if (c
->remove_at_exit
) {
556 snprintf(filename
, sizeof(filename
), "%s/index.f4m", s
->filename
);
558 for (i
= 0; i
< c
->nb_streams
; i
++) {
559 snprintf(filename
, sizeof(filename
), "%s/stream%d.abst", s
->filename
, i
);
569 #define OFFSET(x) offsetof(HDSContext, x)
570 #define E AV_OPT_FLAG_ENCODING_PARAM
571 static const AVOption options
[] = {
572 { "window_size", "number of fragments kept in the manifest", OFFSET(window_size
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, INT_MAX
, E
},
573 { "extra_window_size", "number of fragments kept outside of the manifest before removing from disk", OFFSET(extra_window_size
), AV_OPT_TYPE_INT
, { .i64
= 5 }, 0, INT_MAX
, E
},
574 { "min_frag_duration", "minimum fragment duration (in microseconds)", OFFSET(min_frag_duration
), AV_OPT_TYPE_INT64
, { .i64
= 10000000 }, 0, INT_MAX
, E
},
575 { "remove_at_exit", "remove all fragments when finished", OFFSET(remove_at_exit
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 1, E
},
579 static const AVClass hds_class
= {
580 .class_name
= "HDS muxer",
581 .item_name
= av_default_item_name
,
583 .version
= LIBAVUTIL_VERSION_INT
,
586 AVOutputFormat ff_hds_muxer
= {
588 .long_name
= NULL_IF_CONFIG_SMALL("HDS Muxer"),
589 .priv_data_size
= sizeof(HDSContext
),
590 .audio_codec
= AV_CODEC_ID_AAC
,
591 .video_codec
= AV_CODEC_ID_H264
,
592 .flags
= AVFMT_GLOBALHEADER
| AVFMT_NOFILE
,
593 .write_header
= hds_write_header
,
594 .write_packet
= hds_write_packet
,
595 .write_trailer
= hds_write_trailer
,
596 .priv_class
= &hds_class
,