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 #if HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 
27 #include "avformat.h"
28 #include "internal.h"
29 #include "mux.h"
30 #include "os_support.h"
31 #include "avc.h"
32 #include "url.h"
33 
34 #include "libavutil/opt.h"
35 #include "libavutil/avstring.h"
36 #include "libavutil/mathematics.h"
37 
38 typedef struct Fragment {
39  int64_t start_time, duration;
40  int n;
41  int64_t start_pos, size;
42  char file[1024];
43  char infofile[1024];
44 } Fragment;
45 
46 typedef struct OutputStream {
48  URLContext *out; // Current output stream where all output is written
49  URLContext *out2; // Auxiliary output stream where all output is also written
50  URLContext *tail_out; // The actual main output stream, if we're currently seeked back to write elsewhere
52  int packets_written;
53  const char *stream_type_tag;
56 
57  const char *fourcc;
58  char *private_str;
60  int audio_tag;
61  char dirname[1024];
62  uint8_t iobuf[32768];
63 } OutputStream;
64 
65 typedef struct SmoothStreamingContext {
66  const AVClass *class; /* Class for private options. */
76 
77 static int ism_write(void *opaque, uint8_t *buf, int buf_size)
78 {
79  OutputStream *os = opaque;
80  if (os->out)
81  ffurl_write(os->out, buf, buf_size);
82  if (os->out2)
83  ffurl_write(os->out2, buf, buf_size);
84  os->cur_pos += buf_size;
85  if (os->cur_pos >= os->tail_pos)
86  os->tail_pos = os->cur_pos;
87  return buf_size;
88 }
89 
90 static int64_t ism_seek(void *opaque, int64_t offset, int whence)
91 {
92  OutputStream *os = opaque;
93  int i;
94  if (whence != SEEK_SET)
95  return AVERROR(ENOSYS);
96  if (os->tail_out) {
97  ffurl_closep(&os->out);
98  ffurl_closep(&os->out2);
99  os->out = os->tail_out;
100  os->tail_out = NULL;
101  }
102  if (offset >= os->cur_start_pos) {
103  if (os->out)
104  ffurl_seek(os->out, offset - os->cur_start_pos, SEEK_SET);
105  os->cur_pos = offset;
106  return offset;
107  }
108  for (i = os->nb_fragments - 1; i >= 0; i--) {
109  Fragment *frag = os->fragments[i];
110  if (offset >= frag->start_pos && offset < frag->start_pos + frag->size) {
111  int ret;
113  os->tail_out = os->out;
114  av_dict_set(&opts, "truncate", "0", 0);
117  av_dict_free(&opts);
118  if (ret < 0) {
119  os->out = os->tail_out;
120  os->tail_out = NULL;
121  return ret;
122  }
123  av_dict_set(&opts, "truncate", "0", 0);
126  av_dict_free(&opts);
127  ffurl_seek(os->out, offset - frag->start_pos, SEEK_SET);
128  if (os->out2)
129  ffurl_seek(os->out2, offset - frag->start_pos, SEEK_SET);
130  os->cur_pos = offset;
131  return offset;
132  }
133  }
134  return AVERROR(EIO);
135 }
136 
138 {
139  AVCodecParameters *par = os->ctx->streams[0]->codecpar;
140  uint8_t *ptr = par->extradata;
141  int size = par->extradata_size;
142  int i;
143  if (par->codec_id == AV_CODEC_ID_H264) {
144  ff_avc_write_annexb_extradata(ptr, &ptr, &size);
145  if (!ptr)
146  ptr = par->extradata;
147  }
148  if (!ptr)
149  return;
150  os->private_str = av_mallocz(2*size + 1);
151  if (!os->private_str)
152  goto fail;
153  for (i = 0; i < size; i++)
154  snprintf(&os->private_str[2*i], 3, "%02x", ptr[i]);
155 fail:
156  if (ptr != par->extradata)
157  av_free(ptr);
158 }
159 
161 {
162  SmoothStreamingContext *c = s->priv_data;
163  int i, j;
164  if (!c->streams)
165  return;
166  for (i = 0; i < s->nb_streams; i++) {
167  OutputStream *os = &c->streams[i];
168  ffurl_closep(&os->out);
169  ffurl_closep(&os->out2);
170  ffurl_closep(&os->tail_out);
171  if (os->ctx && os->ctx->pb)
172  avio_context_free(&os->ctx->pb);
174  av_freep(&os->private_str);
175  for (j = 0; j < os->nb_fragments; j++)
176  av_freep(&os->fragments[j]);
177  av_freep(&os->fragments);
178  }
179  av_freep(&c->streams);
180 }
181 
182 static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
183 {
184  int removed = 0, i, start = 0;
185  if (os->nb_fragments <= 0)
186  return;
187  if (os->fragments[0]->n > 0)
188  removed = 1;
189  if (final)
190  skip = 0;
191  if (window_size)
192  start = FFMAX(os->nb_fragments - skip - window_size, 0);
193  for (i = start; i < os->nb_fragments - skip; i++) {
194  Fragment *frag = os->fragments[i];
195  if (!final || removed)
196  avio_printf(out, "<c t=\"%"PRIu64"\" d=\"%"PRIu64"\" />\n", frag->start_time, frag->duration);
197  else
198  avio_printf(out, "<c n=\"%d\" d=\"%"PRIu64"\" />\n", frag->n, frag->duration);
199  }
200 }
201 
202 static int write_manifest(AVFormatContext *s, int final)
203 {
204  SmoothStreamingContext *c = s->priv_data;
205  AVIOContext *out;
206  char filename[1024], temp_filename[1024];
207  int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0;
208  int64_t duration = 0;
209 
210  snprintf(filename, sizeof(filename), "%s/Manifest", s->url);
211  snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->url);
212  ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
213  if (ret < 0) {
214  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
215  return ret;
216  }
217  avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
218  for (i = 0; i < s->nb_streams; i++) {
219  OutputStream *os = &c->streams[i];
220  if (os->nb_fragments > 0) {
221  Fragment *last = os->fragments[os->nb_fragments - 1];
222  duration = last->start_time + last->duration;
223  }
224  if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
225  video_chunks = os->nb_fragments;
226  video_streams++;
227  } else {
228  audio_chunks = os->nb_fragments;
229  audio_streams++;
230  }
231  }
232  if (!final) {
233  duration = 0;
234  video_chunks = audio_chunks = 0;
235  }
236  if (c->window_size) {
237  video_chunks = FFMIN(video_chunks, c->window_size);
238  audio_chunks = FFMIN(audio_chunks, c->window_size);
239  }
240  avio_printf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"%"PRIu64"\"", duration);
241  if (!final)
242  avio_printf(out, " IsLive=\"true\" LookAheadFragmentCount=\"%d\" DVRWindowLength=\"0\"", c->lookahead_count);
243  avio_printf(out, ">\n");
244  if (c->has_video) {
245  int last = -1, index = 0;
246  avio_printf(out, "<StreamIndex Type=\"video\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n", video_streams, video_chunks);
247  for (i = 0; i < s->nb_streams; i++) {
248  OutputStream *os = &c->streams[i];
249  if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
250  continue;
251  last = i;
252  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);
253  index++;
254  }
255  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
256  avio_printf(out, "</StreamIndex>\n");
257  }
258  if (c->has_audio) {
259  int last = -1, index = 0;
260  avio_printf(out, "<StreamIndex Type=\"audio\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n", audio_streams, audio_chunks);
261  for (i = 0; i < s->nb_streams; i++) {
262  OutputStream *os = &c->streams[i];
263  if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
264  continue;
265  last = i;
266  avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%"PRId64"\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n",
267  index, s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->sample_rate,
268  s->streams[i]->codecpar->ch_layout.nb_channels, os->packet_size, os->audio_tag, os->private_str);
269  index++;
270  }
271  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
272  avio_printf(out, "</StreamIndex>\n");
273  }
274  avio_printf(out, "</SmoothStreamingMedia>\n");
275  avio_flush(out);
277  return ff_rename(temp_filename, filename, s);
278 }
279 
281 {
282  SmoothStreamingContext *c = s->priv_data;
283  int ret = 0, i;
284  const AVOutputFormat *oformat;
285 
286  if (mkdir(s->url, 0777) == -1 && errno != EEXIST) {
287  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
288  return AVERROR(errno);
289  }
290 
291  oformat = av_guess_format("ismv", NULL, NULL);
292  if (!oformat) {
294  }
295 
296  c->streams = av_calloc(s->nb_streams, sizeof(*c->streams));
297  if (!c->streams) {
298  return AVERROR(ENOMEM);
299  }
300 
301  for (i = 0; i < s->nb_streams; i++) {
302  OutputStream *os = &c->streams[i];
304  AVStream *st;
306 
307  if (!s->streams[i]->codecpar->bit_rate) {
308  av_log(s, AV_LOG_WARNING, "No bit rate set for stream %d\n", i);
309  // create a tmp name for the directory of fragments
310  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(Tmp_%d)", s->url, i);
311  } else {
312  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate);
313  }
314 
315  if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) {
316  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
317  return AVERROR(errno);
318  }
319 
320  os->ctx = ctx = avformat_alloc_context();
321  if (!ctx) {
322  return AVERROR(ENOMEM);
323  }
324  if ((ret = ff_copy_whiteblacklists(ctx, s)) < 0)
325  return ret;
326  ctx->oformat = oformat;
327  ctx->interrupt_callback = s->interrupt_callback;
328 
329  if (!(st = avformat_new_stream(ctx, NULL))) {
330  return AVERROR(ENOMEM);
331  }
332  avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar);
333  st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
334  st->time_base = s->streams[i]->time_base;
335 
336  ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), 1, os, NULL, ism_write, ism_seek);
337  if (!ctx->pb) {
338  return AVERROR(ENOMEM);
339  }
340 
341  av_dict_set_int(&opts, "ism_lookahead", c->lookahead_count, 0);
342  av_dict_set(&opts, "movflags", "frag_custom", 0);
344  av_dict_free(&opts);
345  if (ret < 0) {
346  return ret;
347  }
348  avio_flush(ctx->pb);
349  s->streams[i]->time_base = st->time_base;
350  if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
351  c->has_video = 1;
352  os->stream_type_tag = "video";
353  if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
354  os->fourcc = "H264";
355  } else if (st->codecpar->codec_id == AV_CODEC_ID_VC1) {
356  os->fourcc = "WVC1";
357  } else {
358  av_log(s, AV_LOG_ERROR, "Unsupported video codec\n");
359  return AVERROR(EINVAL);
360  }
361  } else {
362  c->has_audio = 1;
363  os->stream_type_tag = "audio";
364  if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
365  os->fourcc = "AACL";
366  os->audio_tag = 0xff;
367  } else if (st->codecpar->codec_id == AV_CODEC_ID_WMAPRO) {
368  os->fourcc = "WMAP";
369  os->audio_tag = 0x0162;
370  } else {
371  av_log(s, AV_LOG_ERROR, "Unsupported audio codec\n");
372  return AVERROR(EINVAL);
373  }
374  os->packet_size = st->codecpar->block_align ? st->codecpar->block_align : 4;
375  }
376  get_private_data(os);
377  }
378 
379  if (!c->has_video && c->min_frag_duration <= 0) {
380  av_log(s, AV_LOG_WARNING, "no video stream and no min frag duration set\n");
381  return AVERROR(EINVAL);
382  }
383  ret = write_manifest(s, 0);
384  if (ret < 0)
385  return ret;
386 
387  return 0;
388 }
389 
390 static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size)
391 {
392  AVIOContext *in;
393  int ret;
394  uint32_t len;
395  if ((ret = s->io_open(s, &in, filename, AVIO_FLAG_READ, NULL)) < 0)
396  return ret;
397  ret = AVERROR(EIO);
398  *moof_size = avio_rb32(in);
399  if (*moof_size < 8 || *moof_size > size)
400  goto fail;
401  if (avio_rl32(in) != MKTAG('m','o','o','f'))
402  goto fail;
403  len = avio_rb32(in);
404  if (len > *moof_size)
405  goto fail;
406  if (avio_rl32(in) != MKTAG('m','f','h','d'))
407  goto fail;
408  avio_seek(in, len - 8, SEEK_CUR);
409  avio_rb32(in); /* traf size */
410  if (avio_rl32(in) != MKTAG('t','r','a','f'))
411  goto fail;
412  while (avio_tell(in) < *moof_size) {
413  uint32_t len = avio_rb32(in);
414  uint32_t tag = avio_rl32(in);
415  int64_t end = avio_tell(in) + len - 8;
416  if (len < 8 || len >= *moof_size)
417  goto fail;
418  if (tag == MKTAG('u','u','i','d')) {
419  static const uint8_t tfxd[] = {
420  0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
421  0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
422  };
423  uint8_t uuid[16];
424  avio_read(in, uuid, 16);
425  if (!memcmp(uuid, tfxd, 16) && len >= 8 + 16 + 4 + 16) {
426  avio_seek(in, 4, SEEK_CUR);
427  *start_ts = avio_rb64(in);
428  *duration = avio_rb64(in);
429  ret = 0;
430  break;
431  }
432  }
433  avio_seek(in, end, SEEK_SET);
434  }
435 fail:
436  ff_format_io_close(s, &in);
437  return ret;
438 }
439 
440 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)
441 {
442  int err;
443  Fragment *frag;
444  if (os->nb_fragments >= os->fragments_size) {
445  os->fragments_size = (os->fragments_size + 1) * 2;
446  if ((err = av_reallocp_array(&os->fragments, sizeof(*os->fragments),
447  os->fragments_size)) < 0) {
448  os->fragments_size = 0;
449  os->nb_fragments = 0;
450  return err;
451  }
452  }
453  frag = av_mallocz(sizeof(*frag));
454  if (!frag)
455  return AVERROR(ENOMEM);
456  av_strlcpy(frag->file, file, sizeof(frag->file));
457  av_strlcpy(frag->infofile, infofile, sizeof(frag->infofile));
458  frag->start_time = start_time;
459  frag->duration = duration;
460  frag->start_pos = start_pos;
461  frag->size = size;
462  frag->n = os->fragment_index;
463  os->fragments[os->nb_fragments++] = frag;
464  os->fragment_index++;
465  return 0;
466 }
467 
468 static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile, int64_t size)
469 {
470  AVIOContext *in, *out;
471  int ret = 0;
472  if ((ret = s->io_open(s, &in, infile, AVIO_FLAG_READ, NULL)) < 0)
473  return ret;
474  if ((ret = s->io_open(s, &out, outfile, AVIO_FLAG_WRITE, NULL)) < 0) {
475  ff_format_io_close(s, &in);
476  return ret;
477  }
478  while (size > 0) {
479  uint8_t buf[8192];
480  int n = FFMIN(size, sizeof(buf));
481  n = avio_read(in, buf, n);
482  if (n <= 0) {
483  ret = AVERROR(EIO);
484  break;
485  }
486  avio_write(out, buf, n);
487  size -= n;
488  }
489  avio_flush(out);
491  ff_format_io_close(s, &in);
492  return ret;
493 }
494 
495 static int ism_flush(AVFormatContext *s, int final)
496 {
497  SmoothStreamingContext *c = s->priv_data;
498  int i, ret = 0;
499 
500  for (i = 0; i < s->nb_streams; i++) {
501  OutputStream *os = &c->streams[i];
502  char filename[1024], target_filename[1024], header_filename[1024], curr_dirname[1024];
503  int64_t size;
504  int64_t start_ts, duration, moof_size;
505  if (!os->packets_written)
506  continue;
507 
508  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
509  ret = ffurl_open_whitelist(&os->out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL);
510  if (ret < 0)
511  break;
512  os->cur_start_pos = os->tail_pos;
513  av_write_frame(os->ctx, NULL);
514  avio_flush(os->ctx->pb);
515  os->packets_written = 0;
516  if (!os->out || os->tail_out)
517  return AVERROR(EIO);
518 
519  ffurl_closep(&os->out);
520  size = os->tail_pos - os->cur_start_pos;
521  if ((ret = parse_fragment(s, filename, &start_ts, &duration, &moof_size, size)) < 0)
522  break;
523 
524  if (!s->streams[i]->codecpar->bit_rate) {
525  int64_t bitrate = (int64_t) size * 8 * AV_TIME_BASE / av_rescale_q(duration, s->streams[i]->time_base, AV_TIME_BASE_Q);
526  if (!bitrate) {
527  av_log(s, AV_LOG_ERROR, "calculating bitrate got zero.\n");
528  ret = AVERROR(EINVAL);
529  return ret;
530  }
531 
532  av_log(s, AV_LOG_DEBUG, "calculated bitrate: %"PRId64"\n", bitrate);
533  s->streams[i]->codecpar->bit_rate = bitrate;
534  memcpy(curr_dirname, os->dirname, sizeof(os->dirname));
535  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate);
536  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
537 
538  // rename the tmp folder back to the correct name since we now have the bitrate
539  if ((ret = ff_rename((const char*)curr_dirname, os->dirname, s)) < 0)
540  return ret;
541  }
542 
543  snprintf(header_filename, sizeof(header_filename), "%s/FragmentInfo(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
544  snprintf(target_filename, sizeof(target_filename), "%s/Fragments(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
545  copy_moof(s, filename, header_filename, moof_size);
546  ret = ff_rename(filename, target_filename, s);
547  if (ret < 0)
548  break;
549  add_fragment(os, target_filename, header_filename, start_ts, duration,
550  os->cur_start_pos, size);
551  }
552 
553  if (c->window_size || (final && c->remove_at_exit)) {
554  for (i = 0; i < s->nb_streams; i++) {
555  OutputStream *os = &c->streams[i];
556  int j;
557  int remove = os->nb_fragments - c->window_size - c->extra_window_size - c->lookahead_count;
558  if (final && c->remove_at_exit)
559  remove = os->nb_fragments;
560  if (remove > 0) {
561  for (j = 0; j < remove; j++) {
562  unlink(os->fragments[j]->file);
563  unlink(os->fragments[j]->infofile);
564  av_freep(&os->fragments[j]);
565  }
566  os->nb_fragments -= remove;
567  memmove(os->fragments, os->fragments + remove, os->nb_fragments * sizeof(*os->fragments));
568  }
569  if (final && c->remove_at_exit)
570  rmdir(os->dirname);
571  }
572  }
573 
574  if (ret >= 0)
575  ret = write_manifest(s, final);
576  return ret;
577 }
578 
580 {
581  SmoothStreamingContext *c = s->priv_data;
582  AVStream *st = s->streams[pkt->stream_index];
583  FFStream *const sti = ffstream(st);
584  OutputStream *os = &c->streams[pkt->stream_index];
585  int64_t end_dts = (c->nb_fragments + 1) * (int64_t) c->min_frag_duration;
586  int ret;
587 
588  if (sti->first_dts == AV_NOPTS_VALUE)
589  sti->first_dts = pkt->dts;
590 
591  if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
592  av_compare_ts(pkt->dts - sti->first_dts, st->time_base,
593  end_dts, AV_TIME_BASE_Q) >= 0 &&
595 
596  if ((ret = ism_flush(s, 0)) < 0)
597  return ret;
598  c->nb_fragments++;
599  }
600 
601  os->packets_written++;
602  return ff_write_chained(os->ctx, 0, pkt, s, 0);
603 }
604 
606 {
607  SmoothStreamingContext *c = s->priv_data;
608  ism_flush(s, 1);
609 
610  if (c->remove_at_exit) {
611  char filename[1024];
612  snprintf(filename, sizeof(filename), "%s/Manifest", s->url);
613  unlink(filename);
614  rmdir(s->url);
615  }
616 
617  return 0;
618 }
619 
620 #define OFFSET(x) offsetof(SmoothStreamingContext, x)
621 #define E AV_OPT_FLAG_ENCODING_PARAM
622 static const AVOption options[] = {
623  { "window_size", "number of fragments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
624  { "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 },
625  { "lookahead_count", "number of lookahead fragments", OFFSET(lookahead_count), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, E },
626  { "min_frag_duration", "minimum fragment duration (in microseconds)", OFFSET(min_frag_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E },
627  { "remove_at_exit", "remove all fragments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
628  { NULL },
629 };
630 
631 static const AVClass ism_class = {
632  .class_name = "smooth streaming muxer",
633  .item_name = av_default_item_name,
634  .option = options,
635  .version = LIBAVUTIL_VERSION_INT,
636 };
637 
638 
640  .name = "smoothstreaming",
641  .long_name = NULL_IF_CONFIG_SMALL("Smooth Streaming Muxer"),
642  .priv_data_size = sizeof(SmoothStreamingContext),
643  .audio_codec = AV_CODEC_ID_AAC,
644  .video_codec = AV_CODEC_ID_H264,
649  .deinit = ism_free,
650  .priv_class = &ism_class,
651 };
SmoothStreamingContext::remove_at_exit
int remove_at_exit
Definition: smoothstreamingenc.c:71
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:75
OutputStream::cur_start_pos
int64_t cur_start_pos
Definition: smoothstreamingenc.c:51
AVOutputFormat::name
const char * name
Definition: avformat.h:510
AVERROR
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
opt.h
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: options.c:237
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:57
av_compare_ts
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
out
FILE * out
Definition: movenc.c:54
FFStream::first_dts
int64_t first_dts
Timestamp corresponding to the last dts sync point.
Definition: internal.h:403
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: codec_par.h:53
ffurl_seek
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:428
OutputStream::fragment_index
int fragment_index
Definition: hdsenc.c:54
avio_context_free
void avio_context_free(AVIOContext **s)
Free the supplied IO context and everything associated with it.
Definition: aviobuf.c:152
AVFormatContext::protocol_blacklist
char * protocol_blacklist
',' separated list of disallowed protocols.
Definition: avformat.h:1786
AV_TIME_BASE_Q
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
OutputStream::packets_written
uint64_t packets_written
Definition: ffmpeg.h:550
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1281
deinit
static void deinit(AVFormatContext *s)
Definition: chromaprint.c:49
SmoothStreamingContext
Definition: smoothstreamingenc.c:65
AVOption
AVOption.
Definition: opt.h:251
outfile
FILE * outfile
Definition: audiogen.c:96
Fragment::start_time
int64_t start_time
Definition: hdsenc.c:40
copy_moof
static int copy_moof(AVFormatContext *s, const char *infile, const char *outfile, int64_t size)
Definition: smoothstreamingenc.c:468
mathematics.h
AVDictionary
Definition: dict.c:30
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
SmoothStreamingContext::extra_window_size
int extra_window_size
Definition: smoothstreamingenc.c:68
OutputStream::nb_fragments
int nb_fragments
Definition: hdsenc.c:54
OutputStream::audio_tag
int audio_tag
Definition: smoothstreamingenc.c:60
SmoothStreamingContext::nb_fragments
int nb_fragments
Definition: smoothstreamingenc.c:74
os_support.h
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:429
get_private_data
static void get_private_data(OutputStream *os)
Definition: smoothstreamingenc.c:137
Fragment
Definition: hdsenc.c:38
AVFormatContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1480
OutputStream::stream_type_tag
const char * stream_type_tag
Definition: smoothstreamingenc.c:53
ffstream
static av_always_inline FFStream * ffstream(AVStream *st)
Definition: internal.h:407
fail
#define fail()
Definition: checkasm.h:130
Fragment::file
char file[1024]
Definition: hdsenc.c:39
SmoothStreamingContext::has_audio
int has_audio
Definition: smoothstreamingenc.c:73
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:505
ff_rename
int ff_rename(const char *url_src, const char *url_dst, void *logctx)
Wrap ffurl_move() and log if error happens.
Definition: avio.c:665
OutputStream::tail_out
URLContext * tail_out
Definition: smoothstreamingenc.c:50
avio_rb32
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:790
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
SmoothStreamingContext::window_size
int window_size
Definition: smoothstreamingenc.c:67
duration
int64_t duration
Definition: movenc.c:64
ffurl_open_whitelist
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
OFFSET
#define OFFSET(x)
Definition: smoothstreamingenc.c:620
Fragment::start_pos
int64_t start_pos
Definition: smoothstreamingenc.c:41
s
#define s(width, name)
Definition: cbs_vp9.c:256
AV_CODEC_ID_WMAPRO
@ AV_CODEC_ID_WMAPRO
Definition: codec_id.h:462
ism_flush
static int ism_flush(AVFormatContext *s, int final)
Definition: smoothstreamingenc.c:495
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Definition: opt.h:226
ism_write_trailer
static int ism_write_trailer(AVFormatContext *s)
Definition: smoothstreamingenc.c:605
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:623
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
av_rescale_q
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
ff_smoothstreaming_muxer
const AVOutputFormat ff_smoothstreaming_muxer
Definition: smoothstreamingenc.c:639
ism_seek
static int64_t ism_seek(void *opaque, int64_t offset, int whence)
Definition: smoothstreamingenc.c:90
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:77
avformat_write_header
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:449
ism_write
static int ism_write(void *opaque, uint8_t *buf, int buf_size)
Definition: smoothstreamingenc.c:77
avio_flush
void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:252
AVFormatContext
Format I/O context.
Definition: avformat.h:1213
internal.h
opts
AVDictionary * opts
Definition: movenc.c:50
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1108
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:978
NULL
#define NULL
Definition: coverity.c:32
OutputStream::dirname
char dirname[1024]
Definition: smoothstreamingenc.c:61
write_trailer
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:100
AVFormatContext::protocol_whitelist
char * protocol_whitelist
',' separated list of allowed protocols.
Definition: avformat.h:1751
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:741
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
avio_rb64
uint64_t avio_rb64(AVIOContext *s)
Definition: aviobuf.c:937
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1255
avc.h
av_write_frame
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:1188
Fragment::duration
int64_t duration
Definition: hdsenc.c:40
index
int index
Definition: gxfenc.c:89
c
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
ff_write_chained
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:1350
ism_free
static void ism_free(AVFormatContext *s)
Definition: smoothstreamingenc.c:160
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:79
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: codec_id.h:427
avio_rl32
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:759
AVIOContext
Bytestream IO Context.
Definition: avio.h:162
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:116
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:164
FFStream
Definition: internal.h:197
start_time
static int64_t start_time
Definition: ffplay.c:331
Fragment::size
int64_t size
Definition: smoothstreamingenc.c:41
size
int size
Definition: twinvq_data.h:10344
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
AVFMT_NOFILE
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:470
ff_format_io_close
int ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: avformat.c:779
AVStream::sample_aspect_ratio
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:1017
SmoothStreamingContext::min_frag_duration
int min_frag_duration
Definition: smoothstreamingenc.c:70
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:373
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:232
av_reallocp_array
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:233
offset
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
Definition: writing_filters.txt:86
OutputStream::fourcc
const char * fourcc
Definition: smoothstreamingenc.c:57
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:380
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:203
bitrate
int64_t bitrate
Definition: h264_levels.c:131
write_manifest
static int write_manifest(AVFormatContext *s, int final)
Definition: smoothstreamingenc.c:202
OutputStream::private_str
char * private_str
Definition: smoothstreamingenc.c:58
SmoothStreamingContext::lookahead_count
int lookahead_count
Definition: smoothstreamingenc.c:69
avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: codec_par.c:74
URLContext
Definition: url.h:37
AVFMT_GLOBALHEADER
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:480
AVOutputFormat
Definition: avformat.h:509
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
AVERROR_MUXER_NOT_FOUND
#define AVERROR_MUXER_NOT_FOUND
Muxer not found.
Definition: error.h:62
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
AVCodecParameters::block_align
int block_align
Audio only.
Definition: codec_par.h:184
OutputStream::tail_pos
int64_t tail_pos
Definition: smoothstreamingenc.c:51
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
avio_alloc_context
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:135
url.h
OutputStream::ctx
AVFormatContext * ctx
Definition: dashenc.c:103
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:264
AV_CODEC_ID_VC1
@ AV_CODEC_ID_VC1
Definition: codec_id.h:120
len
int len
Definition: vorbis_enc_data.h:426
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:272
ism_write_packet
static int ism_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: smoothstreamingenc.c:579
ffurl_closep
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:438
tag
uint32_t tag
Definition: movenc.c:1630
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:948
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:260
AVClass::class_name
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:71
AVFormatContext::oformat
const struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1232
SmoothStreamingContext::streams
OutputStream * streams
Definition: smoothstreamingenc.c:72
ism_class
static const AVClass ism_class
Definition: smoothstreamingenc.c:631
options
static const AVOption options[]
Definition: smoothstreamingenc.c:622
avformat.h
parse_fragment
static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size)
Definition: smoothstreamingenc.c:390
OutputStream::fragments_size
int fragments_size
Definition: hdsenc.c:54
OutputStream::fragments
Fragment ** fragments
Definition: hdsenc.c:55
avio_printf
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.
OutputStream::out
URLContext * out
Definition: smoothstreamingenc.c:48
ff_avc_write_annexb_extradata
int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
Definition: avc.c:255
OutputStream::iobuf
uint8_t iobuf[32768]
Definition: hdsenc.c:49
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
ism_write_header
static int ism_write_header(AVFormatContext *s)
Definition: smoothstreamingenc.c:280
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: avformat.c:95
avio_read
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:641
ffurl_write
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:415
output_chunk_list
static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
Definition: smoothstreamingenc.c:182
AVPacket::stream_index
int stream_index
Definition: packet.h:376
OutputStream::out
AVIOContext * out
Definition: dashenc.c:105
av_dict_set_int
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
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:622
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
av_guess_format
const 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:53
OutputStream::out2
URLContext * out2
Definition: smoothstreamingenc.c:49
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:61
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:244
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
av_dict_set
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
OutputStream::cur_pos
int64_t cur_pos
Definition: smoothstreamingenc.c:51
OutputStream
Definition: muxing.c:54
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
av_strlcpy
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:86
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
MKTAG
#define MKTAG(a, b, c, d)
Definition: macros.h:55
OutputStream::packet_size
int packet_size
Definition: smoothstreamingenc.c:59
write_packet
static int write_packet(AVFormatContext *s1, AVPacket *pkt)
Definition: v4l2enc.c:92
avstring.h
write_header
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:347
snprintf
#define snprintf
Definition: snprintf.h:34
Fragment::n
int n
Definition: hdsenc.c:41
SmoothStreamingContext::has_video
int has_video
Definition: smoothstreamingenc.c:73
Fragment::infofile
char infofile[1024]
Definition: smoothstreamingenc.c:43
E
#define E
Definition: smoothstreamingenc.c:621
add_fragment
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)
Definition: smoothstreamingenc.c:440
mux.h