FFmpeg
smoothstreamingenc.c
Go to the documentation of this file.
1 /*
2  * Live smooth streaming fragmenter
3  * Copyright (c) 2012 Martin Storsjo
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include "config.h"
23 #include <float.h>
24 #if HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 
28 #include "avformat.h"
29 #include "avio_internal.h"
30 #include "internal.h"
31 #include "os_support.h"
32 #include "avc.h"
33 #include "url.h"
34 #include "isom.h"
35 
36 #include "libavutil/opt.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/file.h"
39 #include "libavutil/mathematics.h"
40 #include "libavutil/intreadwrite.h"
41 
42 typedef struct Fragment {
43  char file[1024];
44  char infofile[1024];
45  int64_t start_time, duration;
46  int n;
47  int64_t start_pos, size;
48 } Fragment;
49 
50 typedef struct OutputStream {
52  char dirname[1024];
53  uint8_t iobuf[32768];
54  URLContext *out; // Current output stream where all output is written
55  URLContext *out2; // Auxiliary output stream where all output is also written
56  URLContext *tail_out; // The actual main output stream, if we're currently seeked back to write elsewhere
57  int64_t tail_pos, cur_pos, cur_start_pos;
58  int packets_written;
59  const char *stream_type_tag;
60  int nb_fragments, fragments_size, fragment_index;
61  Fragment **fragments;
62 
63  const char *fourcc;
64  char *private_str;
66  int audio_tag;
67 } OutputStream;
68 
69 typedef struct SmoothStreamingContext {
70  const AVClass *class; /* Class for private options. */
77  int has_video, has_audio;
80 
81 static int ism_write(void *opaque, uint8_t *buf, int buf_size)
82 {
83  OutputStream *os = opaque;
84  if (os->out)
85  ffurl_write(os->out, buf, buf_size);
86  if (os->out2)
87  ffurl_write(os->out2, buf, buf_size);
88  os->cur_pos += buf_size;
89  if (os->cur_pos >= os->tail_pos)
90  os->tail_pos = os->cur_pos;
91  return buf_size;
92 }
93 
94 static int64_t ism_seek(void *opaque, int64_t offset, int whence)
95 {
96  OutputStream *os = opaque;
97  int i;
98  if (whence != SEEK_SET)
99  return AVERROR(ENOSYS);
100  if (os->tail_out) {
101  ffurl_closep(&os->out);
102  ffurl_closep(&os->out2);
103  os->out = os->tail_out;
104  os->tail_out = NULL;
105  }
106  if (offset >= os->cur_start_pos) {
107  if (os->out)
108  ffurl_seek(os->out, offset - os->cur_start_pos, SEEK_SET);
109  os->cur_pos = offset;
110  return offset;
111  }
112  for (i = os->nb_fragments - 1; i >= 0; i--) {
113  Fragment *frag = os->fragments[i];
114  if (offset >= frag->start_pos && offset < frag->start_pos + frag->size) {
115  int ret;
117  os->tail_out = os->out;
118  av_dict_set(&opts, "truncate", "0", 0);
119  ret = ffurl_open_whitelist(&os->out, frag->file, AVIO_FLAG_WRITE,
121  av_dict_free(&opts);
122  if (ret < 0) {
123  os->out = os->tail_out;
124  os->tail_out = NULL;
125  return ret;
126  }
127  av_dict_set(&opts, "truncate", "0", 0);
130  av_dict_free(&opts);
131  ffurl_seek(os->out, offset - frag->start_pos, SEEK_SET);
132  if (os->out2)
133  ffurl_seek(os->out2, offset - frag->start_pos, SEEK_SET);
134  os->cur_pos = offset;
135  return offset;
136  }
137  }
138  return AVERROR(EIO);
139 }
140 
142 {
143  AVCodecParameters *par = os->ctx->streams[0]->codecpar;
144  uint8_t *ptr = par->extradata;
145  int size = par->extradata_size;
146  int i;
147  if (par->codec_id == AV_CODEC_ID_H264) {
148  ff_avc_write_annexb_extradata(ptr, &ptr, &size);
149  if (!ptr)
150  ptr = par->extradata;
151  }
152  if (!ptr)
153  return;
154  os->private_str = av_mallocz(2*size + 1);
155  if (!os->private_str)
156  goto fail;
157  for (i = 0; i < size; i++)
158  snprintf(&os->private_str[2*i], 3, "%02x", ptr[i]);
159 fail:
160  if (ptr != par->extradata)
161  av_free(ptr);
162 }
163 
165 {
167  int i, j;
168  if (!c->streams)
169  return;
170  for (i = 0; i < s->nb_streams; i++) {
171  OutputStream *os = &c->streams[i];
172  ffurl_closep(&os->out);
173  ffurl_closep(&os->out2);
174  ffurl_closep(&os->tail_out);
175  if (os->ctx && os->ctx->pb)
176  avio_context_free(&os->ctx->pb);
178  av_freep(&os->private_str);
179  for (j = 0; j < os->nb_fragments; j++)
180  av_freep(&os->fragments[j]);
181  av_freep(&os->fragments);
182  }
183  av_freep(&c->streams);
184 }
185 
186 static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
187 {
188  int removed = 0, i, start = 0;
189  if (os->nb_fragments <= 0)
190  return;
191  if (os->fragments[0]->n > 0)
192  removed = 1;
193  if (final)
194  skip = 0;
195  if (window_size)
196  start = FFMAX(os->nb_fragments - skip - window_size, 0);
197  for (i = start; i < os->nb_fragments - skip; i++) {
198  Fragment *frag = os->fragments[i];
199  if (!final || removed)
200  avio_printf(out, "<c t=\"%"PRIu64"\" d=\"%"PRIu64"\" />\n", frag->start_time, frag->duration);
201  else
202  avio_printf(out, "<c n=\"%d\" d=\"%"PRIu64"\" />\n", frag->n, frag->duration);
203  }
204 }
205 
206 static int write_manifest(AVFormatContext *s, int final)
207 {
209  AVIOContext *out;
210  char filename[1024], temp_filename[1024];
211  int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0;
212  int64_t duration = 0;
213 
214  snprintf(filename, sizeof(filename), "%s/Manifest", s->url);
215  snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->url);
216  ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
217  if (ret < 0) {
218  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
219  return ret;
220  }
221  avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
222  for (i = 0; i < s->nb_streams; i++) {
223  OutputStream *os = &c->streams[i];
224  if (os->nb_fragments > 0) {
225  Fragment *last = os->fragments[os->nb_fragments - 1];
226  duration = last->start_time + last->duration;
227  }
229  video_chunks = os->nb_fragments;
230  video_streams++;
231  } else {
232  audio_chunks = os->nb_fragments;
233  audio_streams++;
234  }
235  }
236  if (!final) {
237  duration = 0;
238  video_chunks = audio_chunks = 0;
239  }
240  if (c->window_size) {
241  video_chunks = FFMIN(video_chunks, c->window_size);
242  audio_chunks = FFMIN(audio_chunks, c->window_size);
243  }
244  avio_printf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"%"PRIu64"\"", duration);
245  if (!final)
246  avio_printf(out, " IsLive=\"true\" LookAheadFragmentCount=\"%d\" DVRWindowLength=\"0\"", c->lookahead_count);
247  avio_printf(out, ">\n");
248  if (c->has_video) {
249  int last = -1, index = 0;
250  avio_printf(out, "<StreamIndex Type=\"video\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n", video_streams, video_chunks);
251  for (i = 0; i < s->nb_streams; i++) {
252  OutputStream *os = &c->streams[i];
254  continue;
255  last = i;
256  avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%"PRId64"\" FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height, os->private_str);
257  index++;
258  }
259  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
260  avio_printf(out, "</StreamIndex>\n");
261  }
262  if (c->has_audio) {
263  int last = -1, index = 0;
264  avio_printf(out, "<StreamIndex Type=\"audio\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n", audio_streams, audio_chunks);
265  for (i = 0; i < s->nb_streams; i++) {
266  OutputStream *os = &c->streams[i];
268  continue;
269  last = i;
270  avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%"PRId64"\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->sample_rate, s->streams[i]->codecpar->channels, os->packet_size, os->audio_tag, os->private_str);
271  index++;
272  }
273  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
274  avio_printf(out, "</StreamIndex>\n");
275  }
276  avio_printf(out, "</SmoothStreamingMedia>\n");
277  avio_flush(out);
278  ff_format_io_close(s, &out);
279  return ff_rename(temp_filename, filename, s);
280 }
281 
283 {
285  int ret = 0, i;
286  ff_const59 AVOutputFormat *oformat;
287 
288  if (mkdir(s->url, 0777) == -1 && errno != EEXIST) {
289  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
290  return AVERROR(errno);
291  }
292 
293  oformat = av_guess_format("ismv", NULL, NULL);
294  if (!oformat) {
296  }
297 
298  c->streams = av_mallocz_array(s->nb_streams, sizeof(*c->streams));
299  if (!c->streams) {
300  return AVERROR(ENOMEM);
301  }
302 
303  for (i = 0; i < s->nb_streams; i++) {
304  OutputStream *os = &c->streams[i];
306  AVStream *st;
308 
309  if (!s->streams[i]->codecpar->bit_rate) {
310  av_log(s, AV_LOG_WARNING, "No bit rate set for stream %d\n", i);
311  // create a tmp name for the directory of fragments
312  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(Tmp_%d)", s->url, i);
313  } else {
314  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate);
315  }
316 
317  if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) {
318  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
319  return AVERROR(errno);
320  }
321 
322  os->ctx = ctx = avformat_alloc_context();
323  if (!ctx) {
324  return AVERROR(ENOMEM);
325  }
326  if ((ret = ff_copy_whiteblacklists(ctx, s)) < 0)
327  return ret;
328  ctx->oformat = oformat;
330 
331  if (!(st = avformat_new_stream(ctx, NULL))) {
332  return AVERROR(ENOMEM);
333  }
336  st->time_base = s->streams[i]->time_base;
337 
338  ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), AVIO_FLAG_WRITE, os, NULL, ism_write, ism_seek);
339  if (!ctx->pb) {
340  return AVERROR(ENOMEM);
341  }
342 
343  av_dict_set_int(&opts, "ism_lookahead", c->lookahead_count, 0);
344  av_dict_set(&opts, "movflags", "frag_custom", 0);
345  ret = avformat_write_header(ctx, &opts);
346  av_dict_free(&opts);
347  if (ret < 0) {
348  return ret;
349  }
350  avio_flush(ctx->pb);
351  s->streams[i]->time_base = st->time_base;
352  if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
353  c->has_video = 1;
354  os->stream_type_tag = "video";
355  if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
356  os->fourcc = "H264";
357  } else if (st->codecpar->codec_id == AV_CODEC_ID_VC1) {
358  os->fourcc = "WVC1";
359  } else {
360  av_log(s, AV_LOG_ERROR, "Unsupported video codec\n");
361  return AVERROR(EINVAL);
362  }
363  } else {
364  c->has_audio = 1;
365  os->stream_type_tag = "audio";
366  if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
367  os->fourcc = "AACL";
368  os->audio_tag = 0xff;
369  } else if (st->codecpar->codec_id == AV_CODEC_ID_WMAPRO) {
370  os->fourcc = "WMAP";
371  os->audio_tag = 0x0162;
372  } else {
373  av_log(s, AV_LOG_ERROR, "Unsupported audio codec\n");
374  return AVERROR(EINVAL);
375  }
376  os->packet_size = st->codecpar->block_align ? st->codecpar->block_align : 4;
377  }
378  get_private_data(os);
379  }
380 
381  if (!c->has_video && c->min_frag_duration <= 0) {
382  av_log(s, AV_LOG_WARNING, "no video stream and no min frag duration set\n");
383  return AVERROR(EINVAL);
384  }
385  ret = write_manifest(s, 0);
386  if (ret < 0)
387  return ret;
388 
389  return 0;
390 }
391 
392 static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size)
393 {
394  AVIOContext *in;
395  int ret;
396  uint32_t len;
397  if ((ret = s->io_open(s, &in, filename, AVIO_FLAG_READ, NULL)) < 0)
398  return ret;
399  ret = AVERROR(EIO);
400  *moof_size = avio_rb32(in);
401  if (*moof_size < 8 || *moof_size > size)
402  goto fail;
403  if (avio_rl32(in) != MKTAG('m','o','o','f'))
404  goto fail;
405  len = avio_rb32(in);
406  if (len > *moof_size)
407  goto fail;
408  if (avio_rl32(in) != MKTAG('m','f','h','d'))
409  goto fail;
410  avio_seek(in, len - 8, SEEK_CUR);
411  avio_rb32(in); /* traf size */
412  if (avio_rl32(in) != MKTAG('t','r','a','f'))
413  goto fail;
414  while (avio_tell(in) < *moof_size) {
415  uint32_t len = avio_rb32(in);
416  uint32_t tag = avio_rl32(in);
417  int64_t end = avio_tell(in) + len - 8;
418  if (len < 8 || len >= *moof_size)
419  goto fail;
420  if (tag == MKTAG('u','u','i','d')) {
421  static const uint8_t tfxd[] = {
422  0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
423  0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
424  };
425  uint8_t uuid[16];
426  avio_read(in, uuid, 16);
427  if (!memcmp(uuid, tfxd, 16) && len >= 8 + 16 + 4 + 16) {
428  avio_seek(in, 4, SEEK_CUR);
429  *start_ts = avio_rb64(in);
430  *duration = avio_rb64(in);
431  ret = 0;
432  break;
433  }
434  }
435  avio_seek(in, end, SEEK_SET);
436  }
437 fail:
438  ff_format_io_close(s, &in);
439  return ret;
440 }
441 
442 static int add_fragment(OutputStream *os, const char *file, const char *infofile, int64_t start_time, int64_t duration, int64_t start_pos, int64_t size)
443 {
444  int err;
445  Fragment *frag;
446  if (os->nb_fragments >= os->fragments_size) {
447  os->fragments_size = (os->fragments_size + 1) * 2;
448  if ((err = av_reallocp_array(&os->fragments, sizeof(*os->fragments),
449  os->fragments_size)) < 0) {
450  os->fragments_size = 0;
451  os->nb_fragments = 0;
452  return err;
453  }
454  }
455  frag = av_mallocz(sizeof(*frag));
456  if (!frag)
457  return AVERROR(ENOMEM);
458  av_strlcpy(frag->file, file, sizeof(frag->file));
459  av_strlcpy(frag->infofile, infofile, sizeof(frag->infofile));
460  frag->start_time = start_time;
461  frag->duration = duration;
462  frag->start_pos = start_pos;
463  frag->size = size;
464  frag->n = os->fragment_index;
465  os->fragments[os->nb_fragments++] = frag;
466  os->fragment_index++;
467  return 0;
468 }
469 
470 static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile, int64_t size)
471 {
472  AVIOContext *in, *out;
473  int ret = 0;
474  if ((ret = s->io_open(s, &in, infile, AVIO_FLAG_READ, NULL)) < 0)
475  return ret;
476  if ((ret = s->io_open(s, &out, outfile, AVIO_FLAG_WRITE, NULL)) < 0) {
477  ff_format_io_close(s, &in);
478  return ret;
479  }
480  while (size > 0) {
481  uint8_t buf[8192];
482  int n = FFMIN(size, sizeof(buf));
483  n = avio_read(in, buf, n);
484  if (n <= 0) {
485  ret = AVERROR(EIO);
486  break;
487  }
488  avio_write(out, buf, n);
489  size -= n;
490  }
491  avio_flush(out);
492  ff_format_io_close(s, &out);
493  ff_format_io_close(s, &in);
494  return ret;
495 }
496 
497 static int ism_flush(AVFormatContext *s, int final)
498 {
500  int i, ret = 0;
501 
502  for (i = 0; i < s->nb_streams; i++) {
503  OutputStream *os = &c->streams[i];
504  char filename[1024], target_filename[1024], header_filename[1024], curr_dirname[1024];
505  int64_t size;
506  int64_t start_ts, duration, moof_size;
507  if (!os->packets_written)
508  continue;
509 
510  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
512  if (ret < 0)
513  break;
514  os->cur_start_pos = os->tail_pos;
515  av_write_frame(os->ctx, NULL);
516  avio_flush(os->ctx->pb);
517  os->packets_written = 0;
518  if (!os->out || os->tail_out)
519  return AVERROR(EIO);
520 
521  ffurl_closep(&os->out);
522  size = os->tail_pos - os->cur_start_pos;
523  if ((ret = parse_fragment(s, filename, &start_ts, &duration, &moof_size, size)) < 0)
524  break;
525 
526  if (!s->streams[i]->codecpar->bit_rate) {
527  int64_t bitrate = (int64_t) size * 8 * AV_TIME_BASE / av_rescale_q(duration, s->streams[i]->time_base, AV_TIME_BASE_Q);
528  if (!bitrate) {
529  av_log(s, AV_LOG_ERROR, "calculating bitrate got zero.\n");
530  ret = AVERROR(EINVAL);
531  return ret;
532  }
533 
534  av_log(s, AV_LOG_DEBUG, "calculated bitrate: %"PRId64"\n", bitrate);
536  memcpy(curr_dirname, os->dirname, sizeof(os->dirname));
537  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate);
538  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
539 
540  // rename the tmp folder back to the correct name since we now have the bitrate
541  if ((ret = ff_rename((const char*)curr_dirname, os->dirname, s)) < 0)
542  return ret;
543  }
544 
545  snprintf(header_filename, sizeof(header_filename), "%s/FragmentInfo(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
546  snprintf(target_filename, sizeof(target_filename), "%s/Fragments(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
547  copy_moof(s, filename, header_filename, moof_size);
548  ret = ff_rename(filename, target_filename, s);
549  if (ret < 0)
550  break;
551  add_fragment(os, target_filename, header_filename, start_ts, duration,
552  os->cur_start_pos, size);
553  }
554 
555  if (c->window_size || (final && c->remove_at_exit)) {
556  for (i = 0; i < s->nb_streams; i++) {
557  OutputStream *os = &c->streams[i];
558  int j;
559  int remove = os->nb_fragments - c->window_size - c->extra_window_size - c->lookahead_count;
560  if (final && c->remove_at_exit)
561  remove = os->nb_fragments;
562  if (remove > 0) {
563  for (j = 0; j < remove; j++) {
564  unlink(os->fragments[j]->file);
565  unlink(os->fragments[j]->infofile);
566  av_freep(&os->fragments[j]);
567  }
568  os->nb_fragments -= remove;
569  memmove(os->fragments, os->fragments + remove, os->nb_fragments * sizeof(*os->fragments));
570  }
571  if (final && c->remove_at_exit)
572  rmdir(os->dirname);
573  }
574  }
575 
576  if (ret >= 0)
577  ret = write_manifest(s, final);
578  return ret;
579 }
580 
582 {
584  AVStream *st = s->streams[pkt->stream_index];
585  OutputStream *os = &c->streams[pkt->stream_index];
586  int64_t end_dts = (c->nb_fragments + 1) * (int64_t) c->min_frag_duration;
587  int ret;
588 
589  if (st->first_dts == AV_NOPTS_VALUE)
590  st->first_dts = pkt->dts;
591 
592  if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
593  av_compare_ts(pkt->dts - st->first_dts, st->time_base,
594  end_dts, AV_TIME_BASE_Q) >= 0 &&
595  pkt->flags & AV_PKT_FLAG_KEY && os->packets_written) {
596 
597  if ((ret = ism_flush(s, 0)) < 0)
598  return ret;
599  c->nb_fragments++;
600  }
601 
602  os->packets_written++;
603  return ff_write_chained(os->ctx, 0, pkt, s, 0);
604 }
605 
607 {
609  ism_flush(s, 1);
610 
611  if (c->remove_at_exit) {
612  char filename[1024];
613  snprintf(filename, sizeof(filename), "%s/Manifest", s->url);
614  unlink(filename);
615  rmdir(s->url);
616  }
617 
618  return 0;
619 }
620 
621 #define OFFSET(x) offsetof(SmoothStreamingContext, x)
622 #define E AV_OPT_FLAG_ENCODING_PARAM
623 static const AVOption options[] = {
624  { "window_size", "number of fragments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
625  { "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 },
626  { "lookahead_count", "number of lookahead fragments", OFFSET(lookahead_count), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, E },
627  { "min_frag_duration", "minimum fragment duration (in microseconds)", OFFSET(min_frag_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E },
628  { "remove_at_exit", "remove all fragments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
629  { NULL },
630 };
631 
632 static const AVClass ism_class = {
633  .class_name = "smooth streaming muxer",
634  .item_name = av_default_item_name,
635  .option = options,
636  .version = LIBAVUTIL_VERSION_INT,
637 };
638 
639 
641  .name = "smoothstreaming",
642  .long_name = NULL_IF_CONFIG_SMALL("Smooth Streaming Muxer"),
643  .priv_data_size = sizeof(SmoothStreamingContext),
644  .audio_codec = AV_CODEC_ID_AAC,
645  .video_codec = AV_CODEC_ID_H264,
650  .deinit = ism_free,
651  .priv_class = &ism_class,
652 };
static int write_manifest(AVFormatContext *s, int final)
int nb_fragments
Definition: hdsenc.c:55
static int ism_flush(AVFormatContext *s, int final)
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:701
int(* io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
A callback for opening new IO streams.
Definition: avformat.h:1933
char infofile[1024]
int64_t first_dts
Timestamp corresponding to the last dts sync point.
Definition: avformat.h:1078
#define NULL
Definition: coverity.c:32
Bytestream IO Context.
Definition: avio.h:161
URLContext * tail_out
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:310
int64_t start_time
Definition: hdsenc.c:41
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1629
AVOption.
Definition: opt.h:248
static int ism_write(void *opaque, uint8_t *buf, int buf_size)
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:1190
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
#define OFFSET(x)
static int ism_write_header(AVFormatContext *s)
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: avio.c:423
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: utils.c:159
static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
int n
Definition: hdsenc.c:42
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src, int interleave)
Write a packet to another muxer than the one the user originally intended.
Definition: mux.c:1305
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:938
static int ism_write_packet(AVFormatContext *s, AVPacket *pkt)
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:253
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
#define AVIO_FLAG_READ
read-only
Definition: avio.h:674
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:675
URLContext * out
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
AVFormatContext * ctx
Definition: dashenc.c:100
static AVPacket pkt
static void ism_free(AVFormatContext *s)
uint64_t packets_written
Definition: ffmpeg.h:537
This struct describes the properties of an encoded stream.
Definition: codec_par.h:52
Format I/O context.
Definition: avformat.h:1351
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
uint8_t
int fragment_index
Definition: hdsenc.c:55
int width
Video only.
Definition: codec_par.h:126
AVOptions.
miscellaneous OS support macros and functions.
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:790
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
static int add_fragment(OutputStream *os, const char *file, const char *infofile, int64_t start_time, int64_t duration, int64_t start_pos, int64_t size)
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
char dirname[1024]
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: utils.c:5685
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4519
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1419
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:208
Misc file utilities.
uint8_t iobuf[32768]
Definition: hdsenc.c:50
int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
Definition: avc.c:221
char * protocol_whitelist
&#39;,&#39; separated list of allowed protocols.
Definition: avformat.h:1911
uint32_t tag
Definition: movenc.c:1532
ptrdiff_t size
Definition: opengl_enc.c:100
uint64_t avio_rb64(AVIOContext *s)
Definition: aviobuf.c:911
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:225
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:637
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: codec_par.h:89
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:388
#define E
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
uint8_t iobuf[32768]
Definition: movenc.c:49
#define ff_const59
The ff_const59 define is not part of the public API and will be removed without further warning...
Definition: avformat.h:544
AVIOContext * avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Allocate and initialize an AVIOContext for buffered I/O.
Definition: aviobuf.c:138
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:759
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
char * url
input or output URL.
Definition: avformat.h:1447
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
static const AVOption options[]
URLContext * out2
static const AVClass ism_class
static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size)
#define FFMAX(a, b)
Definition: common.h:94
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:83
#define fail()
Definition: checkasm.h:123
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:361
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare two timestamps each in its own time base.
Definition: mathematics.c:147
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:78
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate, or free an array through a pointer to a pointer.
Definition: mem.c:206
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1407
int ff_rename(const char *url_src, const char *url_dst, void *logctx)
Wrap avpriv_io_move and log if error happens.
Definition: avio.c:673
AVDictionary * opts
Definition: movenc.c:50
int block_align
Audio only.
Definition: codec_par.h:177
int64_t start_pos
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition: mux.c:505
#define FFMIN(a, b)
Definition: common.h:96
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:98
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:461
const char * name
Definition: avformat.h:500
AVFormatContext * ctx
Definition: movenc.c:48
#define s(width, name)
Definition: cbs_vp9.c:257
ff_const59 struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1370
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:446
Stream structure.
Definition: avformat.h:876
const char * fourcc
int fragments_size
Definition: hdsenc.c:55
const char * stream_type_tag
Fragment ** fragments
Definition: hdsenc.c:56
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
AVIOContext * pb
I/O context.
Definition: avformat.h:1393
static int64_t ism_seek(void *opaque, int64_t offset, int whence)
int64_t duration
Definition: hdsenc.c:41
Definition: url.h:38
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
Describe the class of an AVClass context structure.
Definition: log.h:67
int index
Definition: gxfenc.c:89
ff_const59 AVOutputFormat * av_guess_format(const char *short_name, const char *filename, const char *mime_type)
Return the output format in the list of registered output formats which best matches the provided par...
Definition: format.c:51
void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:245
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4448
static int ism_write_trailer(AVFormatContext *s)
AVOutputFormat ff_smoothstreaming_muxer
#define flags(name, subs,...)
Definition: cbs_av1.c:560
int sample_rate
Audio only.
Definition: codec_par.h:170
int64_t bitrate
Definition: h264_levels.c:131
static int copy_moof(AVFormatContext *s, const char *infile, const char *outfile, int64_t size)
Main libavformat public API header.
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:458
int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
Change the position that will be used by the next read/write operation on the resource accessed by h...
Definition: avio.c:436
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set that converts the value to a string and stores it...
Definition: dict.c:147
void avio_context_free(AVIOContext **s)
Free the supplied IO context and everything associated with it.
Definition: aviobuf.c:155
#define av_free(p)
int len
void * priv_data
Format private data.
Definition: avformat.h:1379
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:346
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:74
int channels
Audio only.
Definition: codec_par.h:166
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: packet.h:354
char * protocol_blacklist
&#39;,&#39; separated list of disallowed protocols.
Definition: avformat.h:1946
FILE * out
Definition: movenc.c:54
#define av_freep(p)
unbuffered private I/O API
#define AVERROR_MUXER_NOT_FOUND
Muxer not found.
Definition: error.h:60
static void get_private_data(OutputStream *os)
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1023
AVIOContext * out
Definition: dashenc.c:102
int stream_index
Definition: packet.h:357
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:905
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
#define MKTAG(a, b, c, d)
Definition: common.h:406
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: utils.c:2073
This structure stores compressed data.
Definition: packet.h:332
char file[1024]
Definition: hdsenc.c:40
FILE * outfile
Definition: audiogen.c:96
int i
Definition: input.c:406
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:190