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
29 #include "avio_internal.h"
31 #include "os_support.h"
33 #include "libavutil/avstring.h"
34 #include "libavutil/base64.h"
35 #include "libavutil/intreadwrite.h"
36 #include "libavutil/mathematics.h"
37 #include "libavutil/opt.h"
39 typedef struct Fragment
{
41 int64_t start_time
, duration
;
45 typedef struct OutputStream
{
51 char temp_filename
[1024];
52 int64_t frag_start_ts
, last_ts
;
55 int nb_fragments
, fragments_size
, fragment_index
;
58 int has_audio
, has_video
;
63 uint8_t *extra_packets
[2];
64 int extra_packet_sizes
[2];
68 typedef struct HDSContext
{
69 const AVClass
*class; /* Class for private options. */
71 int extra_window_size
;
72 int min_frag_duration
;
75 OutputStream
*streams
;
79 static int parse_header(OutputStream
*os
, const uint8_t *buf
, int buf_size
)
82 return AVERROR_INVALIDDATA
;
83 if (memcmp(buf
, "FLV", 3))
84 return AVERROR_INVALIDDATA
;
87 while (buf_size
>= 11 + 4) {
89 int size
= AV_RB24(&buf
[1]) + 11 + 4;
91 return AVERROR_INVALIDDATA
;
92 if (type
== 8 || type
== 9) {
93 if (os
->nb_extra_packets
>= FF_ARRAY_ELEMS(os
->extra_packets
))
94 return AVERROR_INVALIDDATA
;
95 os
->extra_packet_sizes
[os
->nb_extra_packets
] = size
;
96 os
->extra_packets
[os
->nb_extra_packets
] = av_malloc(size
);
97 if (!os
->extra_packets
[os
->nb_extra_packets
])
98 return AVERROR(ENOMEM
);
99 memcpy(os
->extra_packets
[os
->nb_extra_packets
], buf
, size
);
100 os
->nb_extra_packets
++;
101 } else if (type
== 0x12) {
103 return AVERROR_INVALIDDATA
;
104 os
->metadata_size
= size
- 11 - 4;
105 os
->metadata
= av_malloc(os
->metadata_size
);
107 return AVERROR(ENOMEM
);
108 memcpy(os
->metadata
, buf
+ 11, os
->metadata_size
);
114 return AVERROR_INVALIDDATA
;
118 static int hds_write(void *opaque
, uint8_t *buf
, int buf_size
)
120 OutputStream
*os
= opaque
;
122 avio_write(os
->out
, buf
, buf_size
);
124 if (!os
->metadata_size
) {
126 // Assuming the IO buffer is large enough to fit the
127 // FLV header and all metadata and extradata packets
128 if ((ret
= parse_header(os
, buf
, buf_size
)) < 0)
135 static void hds_free(AVFormatContext
*s
)
137 HDSContext
*c
= s
->priv_data
;
141 for (i
= 0; i
< s
->nb_streams
; i
++) {
142 OutputStream
*os
= &c
->streams
[i
];
144 ff_format_io_close(s
, &os
->out
);
145 if (os
->ctx
&& os
->ctx_inited
)
146 av_write_trailer(os
->ctx
);
148 avio_context_free(&os
->ctx
->pb
);
149 avformat_free_context(os
->ctx
);
150 av_freep(&os
->metadata
);
151 for (j
= 0; j
< os
->nb_extra_packets
; j
++)
152 av_freep(&os
->extra_packets
[j
]);
153 for (j
= 0; j
< os
->nb_fragments
; j
++)
154 av_freep(&os
->fragments
[j
]);
155 av_freep(&os
->fragments
);
157 av_freep(&c
->streams
);
160 static int write_manifest(AVFormatContext
*s
, int final
)
162 HDSContext
*c
= s
->priv_data
;
164 char filename
[1024], temp_filename
[1024];
168 if (c
->nb_streams
> 0)
169 duration
= c
->streams
[0].last_ts
* av_q2d(s
->streams
[0]->time_base
);
171 snprintf(filename
, sizeof(filename
), "%s/index.f4m", s
->url
);
172 snprintf(temp_filename
, sizeof(temp_filename
), "%s/index.f4m.tmp", s
->url
);
173 ret
= s
->io_open(s
, &out
, temp_filename
, AVIO_FLAG_WRITE
, NULL
);
175 av_log(s
, AV_LOG_ERROR
, "Unable to open %s for writing\n", temp_filename
);
178 avio_printf(out
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
179 avio_printf(out
, "<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n");
180 avio_printf(out
, "\t<id>%s</id>\n", av_basename(s
->url
));
181 avio_printf(out
, "\t<streamType>%s</streamType>\n",
182 final
? "recorded" : "live");
183 avio_printf(out
, "\t<deliveryType>streaming</deliveryType>\n");
185 avio_printf(out
, "\t<duration>%f</duration>\n", duration
);
186 for (i
= 0; i
< c
->nb_streams
; i
++) {
187 OutputStream
*os
= &c
->streams
[i
];
188 int b64_size
= AV_BASE64_SIZE(os
->metadata_size
);
189 char *base64
= av_malloc(b64_size
);
191 ff_format_io_close(s
, &out
);
192 return AVERROR(ENOMEM
);
194 av_base64_encode(base64
, b64_size
, os
->metadata
, os
->metadata_size
);
196 avio_printf(out
, "\t<bootstrapInfo profile=\"named\" url=\"stream%d.abst\" id=\"bootstrap%d\" />\n", i
, i
);
197 avio_printf(out
, "\t<media bitrate=\"%d\" url=\"stream%d\" bootstrapInfoId=\"bootstrap%d\">\n", os
->bitrate
/1000, i
, i
);
198 avio_printf(out
, "\t\t<metadata>%s</metadata>\n", base64
);
199 avio_printf(out
, "\t</media>\n");
202 avio_printf(out
, "</manifest>\n");
204 ff_format_io_close(s
, &out
);
205 return ff_rename(temp_filename
, filename
, s
);
208 static void update_size(AVIOContext
*out
, int64_t pos
)
210 int64_t end
= avio_tell(out
);
211 avio_seek(out
, pos
, SEEK_SET
);
212 avio_wb32(out
, end
- pos
);
213 avio_seek(out
, end
, SEEK_SET
);
216 /* Note, the .abst files need to be served with the "binary/octet"
217 * mime type, otherwise at least the OSMF player can easily fail
218 * with "stream not found" when polling for the next fragment. */
219 static int write_abst(AVFormatContext
*s
, OutputStream
*os
, int final
)
221 HDSContext
*c
= s
->priv_data
;
223 char filename
[1024], temp_filename
[1024];
225 int64_t asrt_pos
, afrt_pos
;
226 int start
= 0, fragments
;
227 int index
= s
->streams
[os
->first_stream
]->id
;
228 int64_t cur_media_time
= 0;
230 start
= FFMAX(os
->nb_fragments
- c
->window_size
, 0);
231 fragments
= os
->nb_fragments
- start
;
233 cur_media_time
= os
->last_ts
;
234 else if (os
->nb_fragments
)
235 cur_media_time
= os
->fragments
[os
->nb_fragments
- 1]->start_time
;
237 snprintf(filename
, sizeof(filename
),
238 "%s/stream%d.abst", s
->url
, index
);
239 snprintf(temp_filename
, sizeof(temp_filename
),
240 "%s/stream%d.abst.tmp", s
->url
, index
);
241 ret
= s
->io_open(s
, &out
, temp_filename
, AVIO_FLAG_WRITE
, NULL
);
243 av_log(s
, AV_LOG_ERROR
, "Unable to open %s for writing\n", temp_filename
);
246 avio_wb32(out
, 0); // abst size
247 avio_wl32(out
, MKTAG('a','b','s','t'));
248 avio_wb32(out
, 0); // version + flags
249 avio_wb32(out
, os
->fragment_index
- 1); // BootstrapinfoVersion
250 avio_w8(out
, final
? 0 : 0x20); // profile, live, update
251 avio_wb32(out
, 1000); // timescale
252 avio_wb64(out
, cur_media_time
);
253 avio_wb64(out
, 0); // SmpteTimeCodeOffset
254 avio_w8(out
, 0); // MovieIdentifer (null string)
255 avio_w8(out
, 0); // ServerEntryCount
256 avio_w8(out
, 0); // QualityEntryCount
257 avio_w8(out
, 0); // DrmData (null string)
258 avio_w8(out
, 0); // MetaData (null string)
259 avio_w8(out
, 1); // SegmentRunTableCount
260 asrt_pos
= avio_tell(out
);
261 avio_wb32(out
, 0); // asrt size
262 avio_wl32(out
, MKTAG('a','s','r','t'));
263 avio_wb32(out
, 0); // version + flags
264 avio_w8(out
, 0); // QualityEntryCount
265 avio_wb32(out
, 1); // SegmentRunEntryCount
266 avio_wb32(out
, 1); // FirstSegment
267 avio_wb32(out
, final
? (os
->fragment_index
- 1) : 0xffffffff); // FragmentsPerSegment
268 update_size(out
, asrt_pos
);
269 avio_w8(out
, 1); // FragmentRunTableCount
270 afrt_pos
= avio_tell(out
);
271 avio_wb32(out
, 0); // afrt size
272 avio_wl32(out
, MKTAG('a','f','r','t'));
273 avio_wb32(out
, 0); // version + flags
274 avio_wb32(out
, 1000); // timescale
275 avio_w8(out
, 0); // QualityEntryCount
276 avio_wb32(out
, fragments
); // FragmentRunEntryCount
277 for (i
= start
; i
< os
->nb_fragments
; i
++) {
278 avio_wb32(out
, os
->fragments
[i
]->n
);
279 avio_wb64(out
, os
->fragments
[i
]->start_time
);
280 avio_wb32(out
, os
->fragments
[i
]->duration
);
282 update_size(out
, afrt_pos
);
284 ff_format_io_close(s
, &out
);
285 return ff_rename(temp_filename
, filename
, s
);
288 static int init_file(AVFormatContext
*s
, OutputStream
*os
, int64_t start_ts
)
291 ret
= s
->io_open(s
, &os
->out
, os
->temp_filename
, AVIO_FLAG_WRITE
, NULL
);
294 avio_wb32(os
->out
, 0);
295 avio_wl32(os
->out
, MKTAG('m','d','a','t'));
296 for (i
= 0; i
< os
->nb_extra_packets
; i
++) {
297 AV_WB24(os
->extra_packets
[i
] + 4, start_ts
);
298 os
->extra_packets
[i
][7] = (start_ts
>> 24) & 0x7f;
299 avio_write(os
->out
, os
->extra_packets
[i
], os
->extra_packet_sizes
[i
]);
304 static void close_file(AVFormatContext
*s
, OutputStream
*os
)
306 int64_t pos
= avio_tell(os
->out
);
307 avio_seek(os
->out
, 0, SEEK_SET
);
308 avio_wb32(os
->out
, pos
);
310 ff_format_io_close(s
, &os
->out
);
313 static int hds_write_header(AVFormatContext
*s
)
315 HDSContext
*c
= s
->priv_data
;
317 ff_const59 AVOutputFormat
*oformat
;
319 if (mkdir(s
->url
, 0777) == -1 && errno
!= EEXIST
) {
320 av_log(s
, AV_LOG_ERROR
, "Failed to create directory %s\n", s
->url
);
321 return AVERROR(errno
);
324 oformat
= av_guess_format("flv", NULL
, NULL
);
326 return AVERROR_MUXER_NOT_FOUND
;
329 c
->streams
= av_mallocz_array(s
->nb_streams
, sizeof(*c
->streams
));
331 return AVERROR(ENOMEM
);
334 for (i
= 0; i
< s
->nb_streams
; i
++) {
335 OutputStream
*os
= &c
->streams
[c
->nb_streams
];
336 AVFormatContext
*ctx
;
337 AVStream
*st
= s
->streams
[i
];
339 if (!st
->codecpar
->bit_rate
) {
340 av_log(s
, AV_LOG_ERROR
, "No bit rate set for stream %d\n", i
);
341 return AVERROR(EINVAL
);
343 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
349 } else if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
356 av_log(s
, AV_LOG_ERROR
, "Unsupported stream type in stream %d\n", i
);
357 return AVERROR(EINVAL
);
359 os
->bitrate
+= s
->streams
[i
]->codecpar
->bit_rate
;
362 os
->first_stream
= i
;
363 ctx
= avformat_alloc_context();
365 return AVERROR(ENOMEM
);
368 ctx
->oformat
= oformat
;
369 ctx
->interrupt_callback
= s
->interrupt_callback
;
370 ctx
->flags
= s
->flags
;
372 ctx
->pb
= avio_alloc_context(os
->iobuf
, sizeof(os
->iobuf
),
374 NULL
, hds_write
, NULL
);
376 return AVERROR(ENOMEM
);
381 s
->streams
[i
]->id
= c
->nb_streams
;
383 if (!(st
= avformat_new_stream(ctx
, NULL
))) {
384 return AVERROR(ENOMEM
);
386 avcodec_parameters_copy(st
->codecpar
, s
->streams
[i
]->codecpar
);
387 st
->codecpar
->codec_tag
= 0;
388 st
->sample_aspect_ratio
= s
->streams
[i
]->sample_aspect_ratio
;
389 st
->time_base
= s
->streams
[i
]->time_base
;
391 if (c
->streams
[c
->nb_streams
].ctx
)
394 for (i
= 0; i
< c
->nb_streams
; i
++) {
395 OutputStream
*os
= &c
->streams
[i
];
397 if ((ret
= avformat_write_header(os
->ctx
, NULL
)) < 0) {
401 avio_flush(os
->ctx
->pb
);
402 for (j
= 0; j
< os
->ctx
->nb_streams
; j
++)
403 s
->streams
[os
->first_stream
+ j
]->time_base
= os
->ctx
->streams
[j
]->time_base
;
405 snprintf(os
->temp_filename
, sizeof(os
->temp_filename
),
406 "%s/stream%d_temp", s
->url
, i
);
407 ret
= init_file(s
, os
, 0);
411 if (!os
->has_video
&& c
->min_frag_duration
<= 0) {
412 av_log(s
, AV_LOG_WARNING
,
413 "No video stream in output stream %d and no min frag duration set\n", i
);
415 os
->fragment_index
= 1;
416 write_abst(s
, os
, 0);
418 ret
= write_manifest(s
, 0);
423 static int add_fragment(OutputStream
*os
, const char *file
,
424 int64_t start_time
, int64_t duration
)
429 if (os
->nb_fragments
>= os
->fragments_size
) {
431 os
->fragments_size
= (os
->fragments_size
+ 1) * 2;
432 if ((ret
= av_reallocp_array(&os
->fragments
, os
->fragments_size
,
433 sizeof(*os
->fragments
))) < 0) {
434 os
->fragments_size
= 0;
435 os
->nb_fragments
= 0;
439 frag
= av_mallocz(sizeof(*frag
));
441 return AVERROR(ENOMEM
);
442 av_strlcpy(frag
->file
, file
, sizeof(frag
->file
));
443 frag
->start_time
= start_time
;
444 frag
->duration
= duration
;
445 frag
->n
= os
->fragment_index
;
446 os
->fragments
[os
->nb_fragments
++] = frag
;
447 os
->fragment_index
++;
451 static int hds_flush(AVFormatContext
*s
, OutputStream
*os
, int final
,
454 HDSContext
*c
= s
->priv_data
;
456 char target_filename
[1024];
457 int index
= s
->streams
[os
->first_stream
]->id
;
459 if (!os
->packets_written
)
462 avio_flush(os
->ctx
->pb
);
463 os
->packets_written
= 0;
466 snprintf(target_filename
, sizeof(target_filename
),
467 "%s/stream%dSeg1-Frag%d", s
->url
, index
, os
->fragment_index
);
468 ret
= ff_rename(os
->temp_filename
, target_filename
, s
);
471 add_fragment(os
, target_filename
, os
->frag_start_ts
, end_ts
- os
->frag_start_ts
);
474 ret
= init_file(s
, os
, end_ts
);
479 if (c
->window_size
|| (final
&& c
->remove_at_exit
)) {
480 int remove
= os
->nb_fragments
- c
->window_size
- c
->extra_window_size
;
481 if (final
&& c
->remove_at_exit
)
482 remove
= os
->nb_fragments
;
484 for (i
= 0; i
< remove
; i
++) {
485 unlink(os
->fragments
[i
]->file
);
486 av_freep(&os
->fragments
[i
]);
488 os
->nb_fragments
-= remove
;
489 memmove(os
->fragments
, os
->fragments
+ remove
,
490 os
->nb_fragments
* sizeof(*os
->fragments
));
495 ret
= write_abst(s
, os
, final
);
499 static int hds_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
501 HDSContext
*c
= s
->priv_data
;
502 AVStream
*st
= s
->streams
[pkt
->stream_index
];
503 OutputStream
*os
= &c
->streams
[s
->streams
[pkt
->stream_index
]->id
];
504 int64_t end_dts
= os
->fragment_index
* (int64_t)c
->min_frag_duration
;
507 if (st
->first_dts
== AV_NOPTS_VALUE
)
508 st
->first_dts
= pkt
->dts
;
510 if ((!os
->has_video
|| st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) &&
511 av_compare_ts(pkt
->dts
- st
->first_dts
, st
->time_base
,
512 end_dts
, AV_TIME_BASE_Q
) >= 0 &&
513 pkt
->flags
& AV_PKT_FLAG_KEY
&& os
->packets_written
) {
515 if ((ret
= hds_flush(s
, os
, 0, pkt
->dts
)) < 0)
519 // Note, these fragment start timestamps, that represent a whole
520 // OutputStream, assume all streams in it have the same time base.
521 if (!os
->packets_written
)
522 os
->frag_start_ts
= pkt
->dts
;
523 os
->last_ts
= pkt
->dts
;
525 os
->packets_written
++;
526 return ff_write_chained(os
->ctx
, pkt
->stream_index
- os
->first_stream
, pkt
, s
, 0);
529 static int hds_write_trailer(AVFormatContext
*s
)
531 HDSContext
*c
= s
->priv_data
;
534 for (i
= 0; i
< c
->nb_streams
; i
++)
535 hds_flush(s
, &c
->streams
[i
], 1, c
->streams
[i
].last_ts
);
536 write_manifest(s
, 1);
538 if (c
->remove_at_exit
) {
540 snprintf(filename
, sizeof(filename
), "%s/index.f4m", s
->url
);
542 for (i
= 0; i
< c
->nb_streams
; i
++) {
543 snprintf(filename
, sizeof(filename
), "%s/stream%d.abst", s
->url
, i
);
552 #define OFFSET(x) offsetof(HDSContext, x)
553 #define E AV_OPT_FLAG_ENCODING_PARAM
554 static const AVOption options
[] = {
555 { "window_size", "number of fragments kept in the manifest", OFFSET(window_size
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, INT_MAX
, E
},
556 { "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
},
557 { "min_frag_duration", "minimum fragment duration (in microseconds)", OFFSET(min_frag_duration
), AV_OPT_TYPE_INT64
, { .i64
= 10000000 }, 0, INT_MAX
, E
},
558 { "remove_at_exit", "remove all fragments when finished", OFFSET(remove_at_exit
), AV_OPT_TYPE_BOOL
, { .i64
= 0 }, 0, 1, E
},
562 static const AVClass hds_class
= {
563 .class_name
= "HDS muxer",
564 .item_name
= av_default_item_name
,
566 .version
= LIBAVUTIL_VERSION_INT
,
569 AVOutputFormat ff_hds_muxer
= {
571 .long_name
= NULL_IF_CONFIG_SMALL("HDS Muxer"),
572 .priv_data_size
= sizeof(HDSContext
),
573 .audio_codec
= AV_CODEC_ID_AAC
,
574 .video_codec
= AV_CODEC_ID_H264
,
575 .flags
= AVFMT_GLOBALHEADER
| AVFMT_NOFILE
,
576 .write_header
= hds_write_header
,
577 .write_packet
= hds_write_packet
,
578 .write_trailer
= hds_write_trailer
,
580 .priv_class
= &hds_class
,