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