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 "internal.h"
30 #include "os_support.h"
31 #include "avc.h"
32 #include "url.h"
33 #include "isom.h"
34 
35 #include "libavutil/opt.h"
36 #include "libavutil/avstring.h"
37 #include "libavutil/mathematics.h"
38 #include "libavutil/intreadwrite.h"
39 
40 typedef struct {
41  char file[1024];
42  char infofile[1024];
43  int64_t start_time, duration;
44  int n;
45  int64_t start_pos, size;
46 } Fragment;
47 
48 typedef struct {
51  char dirname[1024];
52  uint8_t iobuf[32768];
53  URLContext *out; // Current output stream where all output is written
54  URLContext *out2; // Auxiliary output stream where all output is also written
55  URLContext *tail_out; // The actual main output stream, if we're currently seeked back to write elsewhere
56  int64_t tail_pos, cur_pos, cur_start_pos;
58  const char *stream_type_tag;
59  int nb_fragments, fragments_size, fragment_index;
61 
62  const char *fourcc;
63  char *private_str;
65  int audio_tag;
66 } OutputStream;
67 
68 typedef struct {
69  const AVClass *class; /* Class for private options. */
76  int has_video, has_audio;
79 
80 static int ism_write(void *opaque, uint8_t *buf, int buf_size)
81 {
82  OutputStream *os = opaque;
83  if (os->out)
84  ffurl_write(os->out, buf, buf_size);
85  if (os->out2)
86  ffurl_write(os->out2, buf, buf_size);
87  os->cur_pos += buf_size;
88  if (os->cur_pos >= os->tail_pos)
89  os->tail_pos = os->cur_pos;
90  return buf_size;
91 }
92 
93 static int64_t ism_seek(void *opaque, int64_t offset, int whence)
94 {
95  OutputStream *os = opaque;
96  int i;
97  if (whence != SEEK_SET)
98  return AVERROR(ENOSYS);
99  if (os->tail_out) {
100  if (os->out) {
101  ffurl_close(os->out);
102  }
103  if (os->out2) {
104  ffurl_close(os->out2);
105  }
106  os->out = os->tail_out;
107  os->out2 = NULL;
108  os->tail_out = NULL;
109  }
110  if (offset >= os->cur_start_pos) {
111  if (os->out)
112  ffurl_seek(os->out, offset - os->cur_start_pos, SEEK_SET);
113  os->cur_pos = offset;
114  return offset;
115  }
116  for (i = os->nb_fragments - 1; i >= 0; i--) {
117  Fragment *frag = os->fragments[i];
118  if (offset >= frag->start_pos && offset < frag->start_pos + frag->size) {
119  int ret;
120  AVDictionary *opts = NULL;
121  os->tail_out = os->out;
122  av_dict_set(&opts, "truncate", "0", 0);
123  ret = ffurl_open(&os->out, frag->file, AVIO_FLAG_READ_WRITE, &os->ctx->interrupt_callback, &opts);
124  av_dict_free(&opts);
125  if (ret < 0) {
126  os->out = os->tail_out;
127  os->tail_out = NULL;
128  return ret;
129  }
130  av_dict_set(&opts, "truncate", "0", 0);
132  av_dict_free(&opts);
133  ffurl_seek(os->out, offset - frag->start_pos, SEEK_SET);
134  if (os->out2)
135  ffurl_seek(os->out2, offset - frag->start_pos, SEEK_SET);
136  os->cur_pos = offset;
137  return offset;
138  }
139  }
140  return AVERROR(EIO);
141 }
142 
144 {
145  AVCodecContext *codec = os->ctx->streams[0]->codec;
146  uint8_t *ptr = codec->extradata;
147  int size = codec->extradata_size;
148  int i;
149  if (codec->codec_id == AV_CODEC_ID_H264) {
150  ff_avc_write_annexb_extradata(ptr, &ptr, &size);
151  if (!ptr)
152  ptr = codec->extradata;
153  }
154  if (!ptr)
155  return;
156  os->private_str = av_mallocz(2*size + 1);
157  for (i = 0; i < size; i++)
158  snprintf(&os->private_str[2*i], 3, "%02x", ptr[i]);
159  if (ptr != codec->extradata)
160  av_free(ptr);
161 }
162 
164 {
166  int i, j;
167  if (!c->streams)
168  return;
169  for (i = 0; i < s->nb_streams; i++) {
170  OutputStream *os = &c->streams[i];
171  ffurl_close(os->out);
172  ffurl_close(os->out2);
173  ffurl_close(os->tail_out);
174  os->out = os->out2 = os->tail_out = NULL;
175  if (os->ctx && os->ctx_inited)
176  av_write_trailer(os->ctx);
177  if (os->ctx && os->ctx->pb)
178  av_free(os->ctx->pb);
179  if (os->ctx)
181  av_free(os->private_str);
182  for (j = 0; j < os->nb_fragments; j++)
183  av_free(os->fragments[j]);
184  av_free(os->fragments);
185  }
186  av_freep(&c->streams);
187 }
188 
189 static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
190 {
191  int removed = 0, i, start = 0;
192  if (os->nb_fragments <= 0)
193  return;
194  if (os->fragments[0]->n > 0)
195  removed = 1;
196  if (final)
197  skip = 0;
198  if (window_size)
199  start = FFMAX(os->nb_fragments - skip - window_size, 0);
200  for (i = start; i < os->nb_fragments - skip; i++) {
201  Fragment *frag = os->fragments[i];
202  if (!final || removed)
203  avio_printf(out, "<c t=\"%"PRIu64"\" d=\"%"PRIu64"\" />\n", frag->start_time, frag->duration);
204  else
205  avio_printf(out, "<c n=\"%d\" d=\"%"PRIu64"\" />\n", frag->n, frag->duration);
206  }
207 }
208 
209 static int write_manifest(AVFormatContext *s, int final)
210 {
212  AVIOContext *out;
213  char filename[1024];
214  int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0;
215  int64_t duration = 0;
216 
217  snprintf(filename, sizeof(filename), "%s/Manifest", s->filename);
218  ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
219  if (ret < 0) {
220  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", filename);
221  return ret;
222  }
223  avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
224  for (i = 0; i < s->nb_streams; i++) {
225  OutputStream *os = &c->streams[i];
226  if (os->nb_fragments > 0) {
227  Fragment *last = os->fragments[os->nb_fragments - 1];
228  duration = last->start_time + last->duration;
229  }
230  if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
231  video_chunks = os->nb_fragments;
232  video_streams++;
233  } else {
234  audio_chunks = os->nb_fragments;
235  audio_streams++;
236  }
237  }
238  if (!final) {
239  duration = 0;
240  video_chunks = audio_chunks = 0;
241  }
242  if (c->window_size) {
243  video_chunks = FFMIN(video_chunks, c->window_size);
244  audio_chunks = FFMIN(audio_chunks, c->window_size);
245  }
246  avio_printf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"%"PRIu64"\"", duration);
247  if (!final)
248  avio_printf(out, " IsLive=\"true\" LookAheadFragmentCount=\"%d\" DVRWindowLength=\"0\"", c->lookahead_count);
249  avio_printf(out, ">\n");
250  if (c->has_video) {
251  int last = -1, index = 0;
252  avio_printf(out, "<StreamIndex Type=\"video\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n", video_streams, video_chunks);
253  for (i = 0; i < s->nb_streams; i++) {
254  OutputStream *os = &c->streams[i];
256  continue;
257  last = i;
258  avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codec->bit_rate, os->fourcc, s->streams[i]->codec->width, s->streams[i]->codec->height, os->private_str);
259  index++;
260  }
261  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
262  avio_printf(out, "</StreamIndex>\n");
263  }
264  if (c->has_audio) {
265  int last = -1, index = 0;
266  avio_printf(out, "<StreamIndex Type=\"audio\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n", audio_streams, audio_chunks);
267  for (i = 0; i < s->nb_streams; i++) {
268  OutputStream *os = &c->streams[i];
270  continue;
271  last = i;
272  avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codec->bit_rate, os->fourcc, s->streams[i]->codec->sample_rate, s->streams[i]->codec->channels, os->packet_size, os->audio_tag, os->private_str);
273  index++;
274  }
275  output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
276  avio_printf(out, "</StreamIndex>\n");
277  }
278  avio_printf(out, "</SmoothStreamingMedia>\n");
279  avio_flush(out);
280  avio_close(out);
281  return 0;
282 }
283 
285 {
287  int ret = 0, i;
288  AVOutputFormat *oformat;
289 
290  if (mkdir(s->filename, 0777) < 0) {
291  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
292  ret = AVERROR(errno);
293  goto fail;
294  }
295 
296  oformat = av_guess_format("ismv", NULL, NULL);
297  if (!oformat) {
299  goto fail;
300  }
301 
302  c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
303  if (!c->streams) {
304  ret = AVERROR(ENOMEM);
305  goto fail;
306  }
307 
308  for (i = 0; i < s->nb_streams; i++) {
309  OutputStream *os = &c->streams[i];
310  AVFormatContext *ctx;
311  AVStream *st;
312  AVDictionary *opts = NULL;
313  char buf[10];
314 
315  if (!s->streams[i]->codec->bit_rate) {
316  av_log(s, AV_LOG_ERROR, "No bit rate set for stream %d\n", i);
317  ret = AVERROR(EINVAL);
318  goto fail;
319  }
320  snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%d)", s->filename, s->streams[i]->codec->bit_rate);
321  if (mkdir(os->dirname, 0777) < 0) {
322  ret = AVERROR(errno);
323  av_log(s, AV_LOG_ERROR, "mkdir failed\n");
324  goto fail;
325  }
326 
327  ctx = avformat_alloc_context();
328  if (!ctx) {
329  ret = AVERROR(ENOMEM);
330  goto fail;
331  }
332  os->ctx = ctx;
333  ctx->oformat = oformat;
335 
336  if (!(st = avformat_new_stream(ctx, NULL))) {
337  ret = AVERROR(ENOMEM);
338  goto fail;
339  }
342 
343  ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), AVIO_FLAG_WRITE, os, NULL, ism_write, ism_seek);
344  if (!ctx->pb) {
345  ret = AVERROR(ENOMEM);
346  goto fail;
347  }
348 
349  snprintf(buf, sizeof(buf), "%d", c->lookahead_count);
350  av_dict_set(&opts, "ism_lookahead", buf, 0);
351  av_dict_set(&opts, "movflags", "frag_custom", 0);
352  if ((ret = avformat_write_header(ctx, &opts)) < 0) {
353  goto fail;
354  }
355  os->ctx_inited = 1;
356  avio_flush(ctx->pb);
357  av_dict_free(&opts);
358  s->streams[i]->time_base = st->time_base;
359  if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
360  c->has_video = 1;
361  os->stream_type_tag = "video";
362  if (st->codec->codec_id == AV_CODEC_ID_H264) {
363  os->fourcc = "H264";
364  } else if (st->codec->codec_id == AV_CODEC_ID_VC1) {
365  os->fourcc = "WVC1";
366  } else {
367  av_log(s, AV_LOG_ERROR, "Unsupported video codec\n");
368  ret = AVERROR(EINVAL);
369  goto fail;
370  }
371  } else {
372  c->has_audio = 1;
373  os->stream_type_tag = "audio";
374  if (st->codec->codec_id == AV_CODEC_ID_AAC) {
375  os->fourcc = "AACL";
376  os->audio_tag = 0xff;
377  } else if (st->codec->codec_id == AV_CODEC_ID_WMAPRO) {
378  os->fourcc = "WMAP";
379  os->audio_tag = 0x0162;
380  } else {
381  av_log(s, AV_LOG_ERROR, "Unsupported audio codec\n");
382  ret = AVERROR(EINVAL);
383  goto fail;
384  }
385  os->packet_size = st->codec->block_align ? st->codec->block_align : 4;
386  }
387  get_private_data(os);
388  }
389 
390  if (!c->has_video && c->min_frag_duration <= 0) {
391  av_log(s, AV_LOG_WARNING, "no video stream and no min frag duration set\n");
392  ret = AVERROR(EINVAL);
393  }
394  ret = write_manifest(s, 0);
395 
396 fail:
397  if (ret)
398  ism_free(s);
399  return ret;
400 }
401 
402 static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *start_ts, int64_t *duration, int64_t *moof_size, int64_t size)
403 {
404  AVIOContext *in;
405  int ret;
406  uint32_t len;
407  if ((ret = avio_open2(&in, filename, AVIO_FLAG_READ, &s->interrupt_callback, NULL)) < 0)
408  return ret;
409  ret = AVERROR(EIO);
410  *moof_size = avio_rb32(in);
411  if (*moof_size < 8 || *moof_size > size)
412  goto fail;
413  if (avio_rl32(in) != MKTAG('m','o','o','f'))
414  goto fail;
415  len = avio_rb32(in);
416  if (len > *moof_size)
417  goto fail;
418  if (avio_rl32(in) != MKTAG('m','f','h','d'))
419  goto fail;
420  avio_seek(in, len - 8, SEEK_CUR);
421  avio_rb32(in); /* traf size */
422  if (avio_rl32(in) != MKTAG('t','r','a','f'))
423  goto fail;
424  while (avio_tell(in) < *moof_size) {
425  uint32_t len = avio_rb32(in);
426  uint32_t tag = avio_rl32(in);
427  int64_t end = avio_tell(in) + len - 8;
428  if (len < 8 || len >= *moof_size)
429  goto fail;
430  if (tag == MKTAG('u','u','i','d')) {
431  const uint8_t tfxd[] = {
432  0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
433  0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
434  };
435  uint8_t uuid[16];
436  avio_read(in, uuid, 16);
437  if (!memcmp(uuid, tfxd, 16) && len >= 8 + 16 + 4 + 16) {
438  avio_seek(in, 4, SEEK_CUR);
439  *start_ts = avio_rb64(in);
440  *duration = avio_rb64(in);
441  ret = 0;
442  break;
443  }
444  }
445  avio_seek(in, end, SEEK_SET);
446  }
447 fail:
448  avio_close(in);
449  return ret;
450 }
451 
452 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)
453 {
454  Fragment *frag;
455  if (os->nb_fragments >= os->fragments_size) {
456  os->fragments_size = (os->fragments_size + 1) * 2;
457  os->fragments = av_realloc(os->fragments, sizeof(*os->fragments)*os->fragments_size);
458  if (!os->fragments)
459  return AVERROR(ENOMEM);
460  }
461  frag = av_mallocz(sizeof(*frag));
462  if (!frag)
463  return AVERROR(ENOMEM);
464  av_strlcpy(frag->file, file, sizeof(frag->file));
465  av_strlcpy(frag->infofile, infofile, sizeof(frag->infofile));
466  frag->start_time = start_time;
467  frag->duration = duration;
468  frag->start_pos = start_pos;
469  frag->size = size;
470  frag->n = os->fragment_index;
471  os->fragments[os->nb_fragments++] = frag;
472  os->fragment_index++;
473  return 0;
474 }
475 
476 static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile, int64_t size)
477 {
478  AVIOContext *in, *out;
479  int ret = 0;
480  if ((ret = avio_open2(&in, infile, AVIO_FLAG_READ, &s->interrupt_callback, NULL)) < 0)
481  return ret;
482  if ((ret = avio_open2(&out, outfile, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) {
483  avio_close(in);
484  return ret;
485  }
486  while (size > 0) {
487  uint8_t buf[8192];
488  int n = FFMIN(size, sizeof(buf));
489  n = avio_read(in, buf, n);
490  if (n <= 0) {
491  ret = AVERROR(EIO);
492  break;
493  }
494  avio_write(out, buf, n);
495  size -= n;
496  }
497  avio_flush(out);
498  avio_close(out);
499  avio_close(in);
500  return ret;
501 }
502 
503 static int ism_flush(AVFormatContext *s, int final)
504 {
506  int i, ret = 0;
507 
508  for (i = 0; i < s->nb_streams; i++) {
509  OutputStream *os = &c->streams[i];
510  char filename[1024], target_filename[1024], header_filename[1024];
511  int64_t start_pos = os->tail_pos, size;
512  int64_t start_ts, duration, moof_size;
513  if (!os->packets_written)
514  continue;
515 
516  snprintf(filename, sizeof(filename), "%s/temp", os->dirname);
517  ret = ffurl_open(&os->out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
518  if (ret < 0)
519  break;
520  os->cur_start_pos = os->tail_pos;
521  av_write_frame(os->ctx, NULL);
522  avio_flush(os->ctx->pb);
523  os->packets_written = 0;
524  if (!os->out || os->tail_out)
525  return AVERROR(EIO);
526 
527  ffurl_close(os->out);
528  os->out = NULL;
529  size = os->tail_pos - start_pos;
530  if ((ret = parse_fragment(s, filename, &start_ts, &duration, &moof_size, size)) < 0)
531  break;
532  snprintf(header_filename, sizeof(header_filename), "%s/FragmentInfo(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
533  snprintf(target_filename, sizeof(target_filename), "%s/Fragments(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
534  copy_moof(s, filename, header_filename, moof_size);
535  rename(filename, target_filename);
536  add_fragment(os, target_filename, header_filename, start_ts, duration, start_pos, size);
537  }
538 
539  if (c->window_size || (final && c->remove_at_exit)) {
540  for (i = 0; i < s->nb_streams; i++) {
541  OutputStream *os = &c->streams[i];
542  int j;
543  int remove = os->nb_fragments - c->window_size - c->extra_window_size - c->lookahead_count;
544  if (final && c->remove_at_exit)
545  remove = os->nb_fragments;
546  if (remove > 0) {
547  for (j = 0; j < remove; j++) {
548  unlink(os->fragments[j]->file);
549  unlink(os->fragments[j]->infofile);
550  av_free(os->fragments[j]);
551  }
552  os->nb_fragments -= remove;
553  memmove(os->fragments, os->fragments + remove, os->nb_fragments * sizeof(*os->fragments));
554  }
555  if (final && c->remove_at_exit)
556  rmdir(os->dirname);
557  }
558  }
559 
560  if (ret >= 0)
561  ret = write_manifest(s, final);
562  return ret;
563 }
564 
566 {
568  AVStream *st = s->streams[pkt->stream_index];
569  OutputStream *os = &c->streams[pkt->stream_index];
570  int64_t end_dts = (c->nb_fragments + 1LL) * c->min_frag_duration;
571  int ret;
572 
573  if (st->first_dts == AV_NOPTS_VALUE)
574  st->first_dts = pkt->dts;
575 
576  if ((!c->has_video || st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
577  av_compare_ts(pkt->dts - st->first_dts, st->time_base,
578  end_dts, AV_TIME_BASE_Q) >= 0 &&
579  pkt->flags & AV_PKT_FLAG_KEY && os->packets_written) {
580 
581  if ((ret = ism_flush(s, 0)) < 0)
582  return ret;
583  c->nb_fragments++;
584  }
585 
586  os->packets_written++;
587  return ff_write_chained(os->ctx, 0, pkt, s);
588 }
589 
591 {
593  ism_flush(s, 1);
594 
595  if (c->remove_at_exit) {
596  char filename[1024];
597  snprintf(filename, sizeof(filename), "%s/Manifest", s->filename);
598  unlink(filename);
599  rmdir(s->filename);
600  }
601 
602  ism_free(s);
603  return 0;
604 }
605 
606 #define OFFSET(x) offsetof(SmoothStreamingContext, x)
607 #define E AV_OPT_FLAG_ENCODING_PARAM
608 static const AVOption options[] = {
609  { "window_size", "number of fragments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
610  { "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 },
611  { "lookahead_count", "number of lookahead fragments", OFFSET(lookahead_count), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, E },
612  { "min_frag_duration", "minimum fragment duration (in microseconds)", OFFSET(min_frag_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E },
613  { "remove_at_exit", "remove all fragments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
614  { NULL },
615 };
616 
617 static const AVClass ism_class = {
618  .class_name = "smooth streaming muxer",
619  .item_name = av_default_item_name,
620  .option = options,
621  .version = LIBAVUTIL_VERSION_INT,
622 };
623 
624 
626  .name = "smoothstreaming",
627  .long_name = NULL_IF_CONFIG_SMALL("Smooth Streaming Muxer"),
628  .priv_data_size = sizeof(SmoothStreamingContext),
629  .audio_codec = AV_CODEC_ID_AAC,
630  .video_codec = AV_CODEC_ID_H264,
635  .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
636  .priv_class = &ism_class,
637 };
static int write_manifest(AVFormatContext *s, int final)
static int ism_flush(AVFormatContext *s, int final)
Definition: start.py:1
char infofile[1024]
int64_t first_dts
Definition: avformat.h:784
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
URLContext * tail_out
int64_t start_time
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1125
AVOption.
Definition: opt.h:251
static int ism_write(void *opaque, uint8_t *buf, int buf_size)
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:383
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:504
av_default_item_name
#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:317
static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size)
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
static int write_packet(AVFormatContext *s, AVPacket *pkt)
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:709
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:199
#define AVIO_FLAG_READ
read-only
Definition: avio.h:332
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference visit they are quite exhaustive You do not need a special username or password All you need is to provide a ssh public key to the Git server admin What follows now is a basic introduction to Git and some FFmpeg specific guidelines Read it at least if you are granted commit privileges to the FFmpeg project you are expected to be familiar with these rules I if not You can get git from etc no matter how small Every one of them has been saved from looking like a fool by this many times It s very easy for stray debug output or cosmetic modifications to slip in
Definition: git-howto.txt:5
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
URLContext * out
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:141
char file[1024]
static void ism_free(AVFormatContext *s)
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
Copy the settings of the source AVCodecContext into the destination AVCodecContext.
int block_align
number of bytes per packet if constant and known or 0 Used by some WAV based audio codecs...
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
initialize output if(nPeaks >3)%at least 3 peaks in spectrum for trying to find f0 nf0peaks
Format I/O context.
Definition: avformat.h:944
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:55
static int64_t start_time
Definition: ffplay.c:293
uint8_t
AVOptions.
miscellaneous OS support macros and functions.
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:610
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 AVPacket pkt
Definition: demuxing.c:56
char dirname[1024]
end end
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
AVStream ** streams
Definition: avformat.h:992
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
Definition: avc.c:164
uint32_t tag
Definition: movenc.c:894
uint64_t avio_rb64(AVIOContext *s)
Definition: aviobuf.c:675
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:248
static int64_t duration
Definition: ffplay.c:294
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:173
static int write_trailer(AVFormatContext *s)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:478
struct AVOutputFormat * oformat
Definition: avformat.h:958
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
#define E
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:109
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:579
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:821
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
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)
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
static const uint8_t offset[127][2]
Definition: vf_spp.c:70
#define FFMAX(a, b)
Definition: common.h:56
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:82
const AVCodecTag ff_mp4_obj_type[]
Definition: isom.c:34
struct OutputStream OutputStream
int size
int flags
A combination of AV_PKT_FLAG values.
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare 2 timestamps each in its own timebases.
Definition: mathematics.c:135
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:991
int bit_rate
the average bitrate
int void avio_flush(AVIOContext *s)
Force flushing of buffered data to the output s.
Definition: aviobuf.c:193
int64_t start_pos
char filename[1024]
input or output filename
Definition: avformat.h:994
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
int width
picture width / height.
FFmpeg Automated Testing Environment ************************************Table of Contents *****************FFmpeg Automated Testing Environment Introduction Using FATE from your FFmpeg source directory Submitting the results to the FFmpeg result aggregation server FATE makefile targets and variables Makefile targets Makefile variables Examples Introduction **************FATE is an extended regression suite on the client side and a means for results aggregation and presentation on the server side The first part of this document explains how you can use FATE from your FFmpeg source directory to test your ffmpeg binary The second part describes how you can run FATE to submit the results to FFmpeg s FATE server In any way you can have a look at the publicly viewable FATE results by visiting this as it can be seen if some test on some platform broke with their recent contribution This usually happens on the platforms the developers could not test on The second part of this document describes how you can run FATE to submit your results to FFmpeg s FATE server If you want to submit your results be sure to check that your combination of OS and compiler is not already listed on the above mentioned website In the third part you can find a comprehensive listing of FATE makefile targets and variables Using FATE from your FFmpeg source directory **********************************************If you want to run FATE on your machine you need to have the samples in place You can get the samples via the build target fate rsync Use this command from the top level source this will cause FATE to fail NOTE To use a custom wrapper to run the pass target exec to configure or set the TARGET_EXEC Make variable Submitting the results to the FFmpeg result aggregation server ****************************************************************To submit your results to the server you should run fate through the shell script tests fate sh from the FFmpeg sources This script needs to be invoked with a configuration file as its first argument tests fate sh path to fate_config A configuration file template with comments describing the individual configuration variables can be found at doc fate_config sh template Create a configuration that suits your based on the configuration template The slot configuration variable can be any string that is not yet but it is suggested that you name it adhering to the following pattern< arch >< os >< compiler >< compiler version > The configuration file itself will be sourced in a shell therefore all shell features may be used This enables you to setup the environment as you need it for your build For your first test runs the fate_recv variable should be empty or commented out This will run everything as normal except that it will omit the submission of the results to the server The following files should be present in $workdir as specified in the configuration file
Definition: fate.txt:34
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:351
const char * name
Definition: avformat.h:378
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...
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
Stream structure.
Definition: avformat.h:643
const char * fourcc
NULL
Definition: eval.c:55
const char * stream_type_tag
enum AVMediaType codec_type
enum AVCodecID codec_id
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:202
int sample_rate
samples per second
AVIOContext * pb
I/O context.
Definition: avformat.h:977
main external API structure.
static int64_t ism_seek(void *opaque, int64_t offset, int whence)
int64_t duration
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
Definition: url.h:41
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:334
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:62
Describe the class of an AVClass context structure.
Definition: log.h:50
int index
Definition: gxfenc.c:89
synthesis window for stochastic i
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:804
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
static int ism_write_trailer(AVFormatContext *s)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
AVOutputFormat ff_smoothstreaming_muxer
static int flags
Definition: cpu.c:23
int ffurl_close(URLContext *h)
Definition: avio.c:359
Fragment ** fragments
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:345
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:328
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:247
static double c[64]
uint8_t iobuf[32768]
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src)
Write a packet to another muxer than the one the user originally intended.
int len
int channels
number of audio channels
void * priv_data
Format private data.
Definition: avformat.h:964
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:470
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:769
unbuffered private I/O API
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=av_sample_fmt_is_planar(in_fmt);out_planar=av_sample_fmt_is_planar(out_fmt);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_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_dlog(ac->avr,"%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-> out
#define AVERROR_MUXER_NOT_FOUND
Muxer not found.
Definition: error.h:60
static void get_private_data(OutputStream *os)
AVFormatContext * ctx
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:679
#define MKTAG(a, b, c, d)
Definition: common.h:282
This structure stores compressed data.
FILE * outfile
Definition: audiogen.c:96
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:190
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2