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  int ctx_inited;
53  char dirname[1024];
54  uint8_t iobuf[32768];
55  URLContext *out; // Current output stream where all output is written
56  URLContext *out2; // Auxiliary output stream where all output is also written
57  URLContext *tail_out; // The actual main output stream, if we're currently seeked back to write elsewhere
58  int64_t tail_pos, cur_pos, cur_start_pos;
59  int packets_written;
60  const char *stream_type_tag;
61  int nb_fragments, fragments_size, fragment_index;
62  Fragment **fragments;
63 
64  const char *fourcc;
65  char *private_str;
67  int audio_tag;
68 } OutputStream;
69 
70 typedef struct SmoothStreamingContext {
71  const AVClass *class; /* Class for private options. */
78  int has_video, has_audio;
81 
82 static int ism_write(void *opaque, uint8_t *buf, int buf_size)
83 {
84  OutputStream *os = opaque;
85  if (os->out)
86  ffurl_write(os->out, buf, buf_size);
87  if (os->out2)
88  ffurl_write(os->out2, buf, buf_size);
89  os->cur_pos += buf_size;
90  if (os->cur_pos >= os->tail_pos)
91  os->tail_pos = os->cur_pos;
92  return buf_size;
93 }
94 
95 static int64_t ism_seek(void *opaque, int64_t offset, int whence)
96 {
97  OutputStream *os = opaque;
98  int i;
99  if (whence != SEEK_SET)
100  return AVERROR(ENOSYS);
101  if (os->tail_out) {
102  if (os->out) {
103  ffurl_close(os->out);
104  }
105  if (os->out2) {
106  ffurl_close(os->out2);
107  }
108  os->out = os->tail_out;
109  os->out2 = NULL;
110  os->tail_out = NULL;
111  }
112  if (offset >= os->cur_start_pos) {
113  if (os->out)
114  ffurl_seek(os->out, offset - os->cur_start_pos, SEEK_SET);
115  os->cur_pos = offset;
116  return offset;
117  }
118  for (i = os->nb_fragments - 1; i >= 0; i--) {
119  Fragment *frag = os->fragments[i];
120  if (offset >= frag->start_pos && offset < frag->start_pos + frag->size) {
121  int ret;
123  os->tail_out = os->out;
124  av_dict_set(&opts, "truncate", "0", 0);
125  ret = ffurl_open_whitelist(&os->out, frag->file, AVIO_FLAG_WRITE,
127  av_dict_free(&opts);
128  if (ret < 0) {
129  os->out = os->tail_out;
130  os->tail_out = NULL;
131  return ret;
132  }
133  av_dict_set(&opts, "truncate", "0", 0);
136  av_dict_free(&opts);
137  ffurl_seek(os->out, offset - frag->start_pos, SEEK_SET);
138  if (os->out2)
139  ffurl_seek(os->out2, offset - frag->start_pos, SEEK_SET);
140  os->cur_pos = offset;
141  return offset;
142  }
143  }
144  return AVERROR(EIO);
145 }
146 
148 {
149  AVCodecParameters *par = os->ctx->streams[0]->codecpar;
150  uint8_t *ptr = par->extradata;
151  int size = par->extradata_size;
152  int i;
153  if (par->codec_id == AV_CODEC_ID_H264) {
154  ff_avc_write_annexb_extradata(ptr, &ptr, &size);
155  if (!ptr)
156  ptr = par->extradata;
157  }
158  if (!ptr)
159  return;
160  os->private_str = av_mallocz(2*size + 1);
161  if (!os->private_str)
162  goto fail;
163  for (i = 0; i < size; i++)
164  snprintf(&os->private_str[2*i], 3, "%02x", ptr[i]);
165 fail:
166  if (ptr != par->extradata)
167  av_free(ptr);
168 }
169 
171 {
173  int i, j;
174  if (!c->streams)
175  return;
176  for (i = 0; i < s->nb_streams; i++) {
177  OutputStream *os = &c->streams[i];
178  ffurl_close(os->out);
179  ffurl_close(os->out2);
180  ffurl_close(os->tail_out);
181  os->out = os->out2 = os->tail_out = NULL;
182  if (os->ctx && os->ctx_inited)
183  av_write_trailer(os->ctx);
184  if (os->ctx && os->ctx->pb)
185  avio_context_free(&os->ctx->pb);
187  av_freep(&os->private_str);
188  for (j = 0; j < os->nb_fragments; j++)
189  av_freep(&os->fragments[j]);
190  av_freep(&os->fragments);
191  }
192  av_freep(&c->streams);
193 }
194 
195 static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
196 {
197  int removed = 0, i, start = 0;
198  if (os->nb_fragments <= 0)
199  return;
200  if (os->fragments[0]->n > 0)
201  removed = 1;
202  if (final)
203  skip = 0;
204  if (window_size)
205  start = FFMAX(os->nb_fragments - skip - window_size, 0);
206  for (i = start; i < os->nb_fragments - skip; i++) {
207  Fragment *frag = os->fragments[i];
208  if (!final || removed)
209  avio_printf(out, "<c t=\"%"PRIu64"\" d=\"%"PRIu64"\" />\n", frag->start_time, frag->duration);
210  else
211  avio_printf(out, "<c n=\"%d\" d=\"%"PRIu64"\" />\n", frag->n, frag->duration);
212  }
213 }
214 
215 static int write_manifest(AVFormatContext *s, int final)
216 {
218  AVIOContext *out;
219  char filename[1024], temp_filename[1024];
220  int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0;
221  int64_t duration = 0;
222 
223  snprintf(filename, sizeof(filename), "%s/Manifest", s->url);
224  snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->url);
225  ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
226  if (ret < 0) {
227  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
228  return ret;
229  }
230  avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
231  for (i = 0; i < s->nb_streams; i++) {
232  OutputStream *os = &c->streams[i];
233  if (os->nb_fragments > 0) {
234  Fragment *last = os->fragments[os->nb_fragments - 1];
235  duration = last->start_time + last->duration;
236  }
238  video_chunks = os->nb_fragments;
239  video_streams++;
240  } else {
241  audio_chunks = os->nb_fragments;
242  audio_streams++;
243  }
244  }
245  if (!final) {
246  duration = 0;
247  video_chunks = audio_chunks = 0;
248  }
249  if (c->window_size) {
250  video_chunks = FFMIN(video_chunks, c->window_size);
251  audio_chunks = FFMIN(audio_chunks, c->window_size);
252  }
253  avio_printf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"%"PRIu64"\"", duration);
254  if (!final)
255  avio_printf(out, " IsLive=\"true\" LookAheadFragmentCount=\"%d\" DVRWindowLength=\"0\"", c->lookahead_count);
256  avio_printf(out, ">\n");
257  if (c->has_video) {
258  int last = -1, index = 0;
259  avio_printf(out, "<StreamIndex Type=\"video\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n", video_streams, video_chunks);
260  for (i = 0; i < s->nb_streams; i++) {
261  OutputStream *os = &c->streams[i];
263  continue;
264  last = i;
265  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);
266  index++;
267  }
268  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
269  avio_printf(out, "</StreamIndex>\n");
270  }
271  if (c->has_audio) {
272  int last = -1, index = 0;
273  avio_printf(out, "<StreamIndex Type=\"audio\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n", audio_streams, audio_chunks);
274  for (i = 0; i < s->nb_streams; i++) {
275  OutputStream *os = &c->streams[i];
277  continue;
278  last = i;
279  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);
280  index++;
281  }
282  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
283  avio_printf(out, "</StreamIndex>\n");
284  }
285  avio_printf(out, "</SmoothStreamingMedia>\n");
286  avio_flush(out);
287  ff_format_io_close(s, &out);
288  return ff_rename(temp_filename, filename, s);
289 }
290 
292 {
294  int ret = 0, i;
295  ff_const59 AVOutputFormat *oformat;
296 
297  if (mkdir(s->url, 0777) == -1 && errno != EEXIST) {
298  ret = AVERROR(errno);
299  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
300  goto fail;
301  }
302 
303  oformat = av_guess_format("ismv", NULL, NULL);
304  if (!oformat) {
306  goto fail;
307  }
308 
309  c->streams = av_mallocz_array(s->nb_streams, sizeof(*c->streams));
310  if (!c->streams) {
311  ret = AVERROR(ENOMEM);
312  goto fail;
313  }
314 
315  for (i = 0; i < s->nb_streams; i++) {
316  OutputStream *os = &c->streams[i];
318  AVStream *st;
320 
321  if (!s->streams[i]->codecpar->bit_rate) {
322  av_log(s, AV_LOG_WARNING, "No bit rate set for stream %d\n", i);
323  // create a tmp name for the directory of fragments
324  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(Tmp_%d)", s->url, i);
325  } else {
326  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate);
327  }
328 
329  if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) {
330  ret = AVERROR(errno);
331  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
332  goto fail;
333  }
334 
335  ctx = avformat_alloc_context();
336  if (!ctx || ff_copy_whiteblacklists(ctx, s) < 0) {
337  ret = AVERROR(ENOMEM);
338  goto fail;
339  }
340  os->ctx = ctx;
341  ctx->oformat = oformat;
343 
344  if (!(st = avformat_new_stream(ctx, NULL))) {
345  ret = AVERROR(ENOMEM);
346  goto fail;
347  }
350  st->time_base = s->streams[i]->time_base;
351 
352  ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), AVIO_FLAG_WRITE, os, NULL, ism_write, ism_seek);
353  if (!ctx->pb) {
354  ret = AVERROR(ENOMEM);
355  goto fail;
356  }
357 
358  av_dict_set_int(&opts, "ism_lookahead", c->lookahead_count, 0);
359  av_dict_set(&opts, "movflags", "frag_custom", 0);
360  if ((ret = avformat_write_header(ctx, &opts)) < 0) {
361  goto fail;
362  }
363  os->ctx_inited = 1;
364  avio_flush(ctx->pb);
365  av_dict_free(&opts);
366  s->streams[i]->time_base = st->time_base;
367  if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
368  c->has_video = 1;
369  os->stream_type_tag = "video";
370  if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
371  os->fourcc = "H264";
372  } else if (st->codecpar->codec_id == AV_CODEC_ID_VC1) {
373  os->fourcc = "WVC1";
374  } else {
375  av_log(s, AV_LOG_ERROR, "Unsupported video codec\n");
376  ret = AVERROR(EINVAL);
377  goto fail;
378  }
379  } else {
380  c->has_audio = 1;
381  os->stream_type_tag = "audio";
382  if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
383  os->fourcc = "AACL";
384  os->audio_tag = 0xff;
385  } else if (st->codecpar->codec_id == AV_CODEC_ID_WMAPRO) {
386  os->fourcc = "WMAP";
387  os->audio_tag = 0x0162;
388  } else {
389  av_log(s, AV_LOG_ERROR, "Unsupported audio codec\n");
390  ret = AVERROR(EINVAL);
391  goto fail;
392  }
393  os->packet_size = st->codecpar->block_align ? st->codecpar->block_align : 4;
394  }
395  get_private_data(os);
396  }
397 
398  if (!c->has_video && c->min_frag_duration <= 0) {
399  av_log(s, AV_LOG_WARNING, "no video stream and no min frag duration set\n");
400  ret = AVERROR(EINVAL);
401  goto fail;
402  }
403  ret = write_manifest(s, 0);
404 
405 fail:
406  if (ret)
407  ism_free(s);
408  return ret;
409 }
410 
411 static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size)
412 {
413  AVIOContext *in;
414  int ret;
415  uint32_t len;
416  if ((ret = s->io_open(s, &in, filename, AVIO_FLAG_READ, NULL)) < 0)
417  return ret;
418  ret = AVERROR(EIO);
419  *moof_size = avio_rb32(in);
420  if (*moof_size < 8 || *moof_size > size)
421  goto fail;
422  if (avio_rl32(in) != MKTAG('m','o','o','f'))
423  goto fail;
424  len = avio_rb32(in);
425  if (len > *moof_size)
426  goto fail;
427  if (avio_rl32(in) != MKTAG('m','f','h','d'))
428  goto fail;
429  avio_seek(in, len - 8, SEEK_CUR);
430  avio_rb32(in); /* traf size */
431  if (avio_rl32(in) != MKTAG('t','r','a','f'))
432  goto fail;
433  while (avio_tell(in) < *moof_size) {
434  uint32_t len = avio_rb32(in);
435  uint32_t tag = avio_rl32(in);
436  int64_t end = avio_tell(in) + len - 8;
437  if (len < 8 || len >= *moof_size)
438  goto fail;
439  if (tag == MKTAG('u','u','i','d')) {
440  static const uint8_t tfxd[] = {
441  0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
442  0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
443  };
444  uint8_t uuid[16];
445  avio_read(in, uuid, 16);
446  if (!memcmp(uuid, tfxd, 16) && len >= 8 + 16 + 4 + 16) {
447  avio_seek(in, 4, SEEK_CUR);
448  *start_ts = avio_rb64(in);
449  *duration = avio_rb64(in);
450  ret = 0;
451  break;
452  }
453  }
454  avio_seek(in, end, SEEK_SET);
455  }
456 fail:
457  ff_format_io_close(s, &in);
458  return ret;
459 }
460 
461 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)
462 {
463  int err;
464  Fragment *frag;
465  if (os->nb_fragments >= os->fragments_size) {
466  os->fragments_size = (os->fragments_size + 1) * 2;
467  if ((err = av_reallocp(&os->fragments, sizeof(*os->fragments) *
468  os->fragments_size)) < 0) {
469  os->fragments_size = 0;
470  os->nb_fragments = 0;
471  return err;
472  }
473  }
474  frag = av_mallocz(sizeof(*frag));
475  if (!frag)
476  return AVERROR(ENOMEM);
477  av_strlcpy(frag->file, file, sizeof(frag->file));
478  av_strlcpy(frag->infofile, infofile, sizeof(frag->infofile));
479  frag->start_time = start_time;
480  frag->duration = duration;
481  frag->start_pos = start_pos;
482  frag->size = size;
483  frag->n = os->fragment_index;
484  os->fragments[os->nb_fragments++] = frag;
485  os->fragment_index++;
486  return 0;
487 }
488 
489 static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile, int64_t size)
490 {
491  AVIOContext *in, *out;
492  int ret = 0;
493  if ((ret = s->io_open(s, &in, infile, AVIO_FLAG_READ, NULL)) < 0)
494  return ret;
495  if ((ret = s->io_open(s, &out, outfile, AVIO_FLAG_WRITE, NULL)) < 0) {
496  ff_format_io_close(s, &in);
497  return ret;
498  }
499  while (size > 0) {
500  uint8_t buf[8192];
501  int n = FFMIN(size, sizeof(buf));
502  n = avio_read(in, buf, n);
503  if (n <= 0) {
504  ret = AVERROR(EIO);
505  break;
506  }
507  avio_write(out, buf, n);
508  size -= n;
509  }
510  avio_flush(out);
511  ff_format_io_close(s, &out);
512  ff_format_io_close(s, &in);
513  return ret;
514 }
515 
516 static int ism_flush(AVFormatContext *s, int final)
517 {
519  int i, ret = 0;
520 
521  for (i = 0; i < s->nb_streams; i++) {
522  OutputStream *os = &c->streams[i];
523  char filename[1024], target_filename[1024], header_filename[1024], curr_dirname[1024];
524  int64_t size;
525  int64_t start_ts, duration, moof_size;
526  if (!os->packets_written)
527  continue;
528 
529  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
531  if (ret < 0)
532  break;
533  os->cur_start_pos = os->tail_pos;
534  av_write_frame(os->ctx, NULL);
535  avio_flush(os->ctx->pb);
536  os->packets_written = 0;
537  if (!os->out || os->tail_out)
538  return AVERROR(EIO);
539 
540  ffurl_close(os->out);
541  os->out = NULL;
542  size = os->tail_pos - os->cur_start_pos;
543  if ((ret = parse_fragment(s, filename, &start_ts, &duration, &moof_size, size)) < 0)
544  break;
545 
546  if (!s->streams[i]->codecpar->bit_rate) {
547  int64_t bitrate = (int64_t) size * 8 * AV_TIME_BASE / av_rescale_q(duration, s->streams[i]->time_base, AV_TIME_BASE_Q);
548  if (!bitrate) {
549  av_log(s, AV_LOG_ERROR, "calculating bitrate got zero.\n");
550  ret = AVERROR(EINVAL);
551  return ret;
552  }
553 
554  av_log(s, AV_LOG_DEBUG, "calculated bitrate: %"PRId64"\n", bitrate);
556  memcpy(curr_dirname, os->dirname, sizeof(os->dirname));
557  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate);
558  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
559 
560  // rename the tmp folder back to the correct name since we now have the bitrate
561  if ((ret = ff_rename((const char*)curr_dirname, os->dirname, s)) < 0)
562  return ret;
563  }
564 
565  snprintf(header_filename, sizeof(header_filename), "%s/FragmentInfo(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
566  snprintf(target_filename, sizeof(target_filename), "%s/Fragments(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
567  copy_moof(s, filename, header_filename, moof_size);
568  ret = ff_rename(filename, target_filename, s);
569  if (ret < 0)
570  break;
571  add_fragment(os, target_filename, header_filename, start_ts, duration,
572  os->cur_start_pos, size);
573  }
574 
575  if (c->window_size || (final && c->remove_at_exit)) {
576  for (i = 0; i < s->nb_streams; i++) {
577  OutputStream *os = &c->streams[i];
578  int j;
579  int remove = os->nb_fragments - c->window_size - c->extra_window_size - c->lookahead_count;
580  if (final && c->remove_at_exit)
581  remove = os->nb_fragments;
582  if (remove > 0) {
583  for (j = 0; j < remove; j++) {
584  unlink(os->fragments[j]->file);
585  unlink(os->fragments[j]->infofile);
586  av_freep(&os->fragments[j]);
587  }
588  os->nb_fragments -= remove;
589  memmove(os->fragments, os->fragments + remove, os->nb_fragments * sizeof(*os->fragments));
590  }
591  if (final && c->remove_at_exit)
592  rmdir(os->dirname);
593  }
594  }
595 
596  if (ret >= 0)
597  ret = write_manifest(s, final);
598  return ret;
599 }
600 
602 {
604  AVStream *st = s->streams[pkt->stream_index];
605  OutputStream *os = &c->streams[pkt->stream_index];
606  int64_t end_dts = (c->nb_fragments + 1) * (int64_t) c->min_frag_duration;
607  int ret;
608 
609  if (st->first_dts == AV_NOPTS_VALUE)
610  st->first_dts = pkt->dts;
611 
612  if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
613  av_compare_ts(pkt->dts - st->first_dts, st->time_base,
614  end_dts, AV_TIME_BASE_Q) >= 0 &&
615  pkt->flags & AV_PKT_FLAG_KEY && os->packets_written) {
616 
617  if ((ret = ism_flush(s, 0)) < 0)
618  return ret;
619  c->nb_fragments++;
620  }
621 
622  os->packets_written++;
623  return ff_write_chained(os->ctx, 0, pkt, s, 0);
624 }
625 
627 {
629  ism_flush(s, 1);
630 
631  if (c->remove_at_exit) {
632  char filename[1024];
633  snprintf(filename, sizeof(filename), "%s/Manifest", s->url);
634  unlink(filename);
635  rmdir(s->url);
636  }
637 
638  ism_free(s);
639  return 0;
640 }
641 
642 #define OFFSET(x) offsetof(SmoothStreamingContext, x)
643 #define E AV_OPT_FLAG_ENCODING_PARAM
644 static const AVOption options[] = {
645  { "window_size", "number of fragments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
646  { "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 },
647  { "lookahead_count", "number of lookahead fragments", OFFSET(lookahead_count), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, E },
648  { "min_frag_duration", "minimum fragment duration (in microseconds)", OFFSET(min_frag_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E },
649  { "remove_at_exit", "remove all fragments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
650  { NULL },
651 };
652 
653 static const AVClass ism_class = {
654  .class_name = "smooth streaming muxer",
655  .item_name = av_default_item_name,
656  .option = options,
657  .version = LIBAVUTIL_VERSION_INT,
658 };
659 
660 
662  .name = "smoothstreaming",
663  .long_name = NULL_IF_CONFIG_SMALL("Smooth Streaming Muxer"),
664  .priv_data_size = sizeof(SmoothStreamingContext),
665  .audio_codec = AV_CODEC_ID_AAC,
666  .video_codec = AV_CODEC_ID_H264,
671  .priv_class = &ism_class,
672 };
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:690
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:1940
char infofile[1024]
int64_t first_dts
Timestamp corresponding to the last dts sync point.
Definition: avformat.h:1083
#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:306
int64_t start_time
Definition: hdsenc.c:41
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1636
AVOption.
Definition: opt.h:246
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:885
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#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:419
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: utils.c:164
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:1321
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3971
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:943
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:246
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
#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:236
AVFormatContext * ctx
Definition: dashenc.c:80
static AVPacket pkt
static void ism_free(AVFormatContext *s)
uint64_t packets_written
Definition: ffmpeg.h:534
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3963
Format I/O context.
Definition: avformat.h:1358
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: avcodec.h:4037
AVOptions.
miscellaneous OS support macros and functions.
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:803
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
int ctx_inited
Definition: dashenc.c:81
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4503
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1426
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:144
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:223
char * protocol_whitelist
&#39;,&#39; separated list of allowed protocols.
Definition: avformat.h:1918
uint32_t tag
Definition: movenc.c:1531
ptrdiff_t size
Definition: opengl_enc.c:100
uint64_t avio_rb64(AVIOContext *s)
Definition: aviobuf.c:924
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:218
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:650
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: avcodec.h:4000
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1515
#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:549
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:131
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: utils.c:2040
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:772
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
char * url
input or output URL.
Definition: avformat.h:1454
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
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: avcodec.h:3967
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:122
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1489
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: avcodec.h:3989
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1414
AVDictionary * opts
Definition: movenc.c:50
int block_align
Audio only.
Definition: avcodec.h:4088
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:516
#define FFMIN(a, b)
Definition: common.h:96
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:466
const char * name
Definition: avformat.h:505
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:1377
Stream structure.
Definition: avformat.h:881
const char * fourcc
int fragments_size
Definition: hdsenc.c:55
const char * stream_type_tag
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:163
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:1400
static int64_t ism_seek(void *opaque, int64_t offset, int whence)
int64_t duration
Definition: hdsenc.c:41
void * buf
Definition: avisynth_c.h:766
Definition: url.h:38
static int ff_rename(const char *oldpath, const char *newpath, void *logctx)
Wrap errno on rename() error.
Definition: internal.h:589
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:238
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4434
static int ism_write_trailer(AVFormatContext *s)
AVOutputFormat ff_smoothstreaming_muxer
#define flags(name, subs,...)
Definition: cbs_av1.c:561
int ffurl_close(URLContext *h)
Definition: avio.c:465
int sample_rate
Audio only.
Definition: avcodec.h:4081
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:463
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:432
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:148
#define av_free(p)
int len
void * priv_data
Format private data.
Definition: avformat.h:1386
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:349
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3985
int channels
Audio only.
Definition: avcodec.h:4077
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1482
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1261
char * protocol_blacklist
&#39;,&#39; separated list of disallowed protocols.
Definition: avformat.h:1953
FILE * out
Definition: movenc.c:54
#define av_freep(p)
void INT64 start
Definition: avisynth_c.h:766
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:1028
AVIOContext * out
Definition: dashenc.c:82
int stream_index
Definition: avcodec.h:1485
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:910
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:366
This structure stores compressed data.
Definition: avcodec.h:1460
char file[1024]
Definition: hdsenc.c:40
FILE * outfile
Definition: audiogen.c:96
#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:191