FFmpeg
sidxindex.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Martin Storsjo
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include "libavformat/avformat.h"
25 #include "libavutil/avstring.h"
26 #include "libavutil/intreadwrite.h"
27 #include "libavutil/mathematics.h"
28 
29 static int usage(const char *argv0, int ret)
30 {
31  fprintf(stderr, "%s -out foo.mpd file1\n", argv0);
32  return ret;
33 }
34 
35 struct Track {
36  const char *name;
37  int64_t duration;
38  int bitrate;
39  int track_id;
40  int is_audio, is_video;
41  int width, height;
42  int sample_rate, channels;
43  int timescale;
44  char codec_str[30];
46 };
47 
48 struct Tracks {
49  int nb_tracks;
50  int64_t duration;
51  struct Track **tracks;
53 };
54 
55 static void set_codec_str(AVCodecParameters *codecpar, char *str, int size)
56 {
57  switch (codecpar->codec_id) {
58  case AV_CODEC_ID_H264:
59  snprintf(str, size, "avc1");
60  if (codecpar->extradata_size >= 4 && codecpar->extradata[0] == 1) {
61  av_strlcatf(str, size, ".%02x%02x%02x",
62  codecpar->extradata[1], codecpar->extradata[2],
63  codecpar->extradata[3]);
64  }
65  break;
66  case AV_CODEC_ID_AAC:
67  snprintf(str, size, "mp4a.40"); // 0x40 is the mp4 object type for AAC
68  if (codecpar->extradata_size >= 2) {
69  int aot = codecpar->extradata[0] >> 3;
70  if (aot == 31)
71  aot = ((AV_RB16(codecpar->extradata) >> 5) & 0x3f) + 32;
72  av_strlcatf(str, size, ".%d", aot);
73  }
74  break;
75  }
76 }
77 
78 static int find_sidx(struct Tracks *tracks, int start_index,
79  const char *file)
80 {
81  int err = 0;
82  AVIOContext *f = NULL;
83  int i;
84 
85  if ((err = avio_open2(&f, file, AVIO_FLAG_READ, NULL, NULL)) < 0)
86  goto fail;
87 
88  while (!f->eof_reached) {
89  int64_t pos = avio_tell(f);
90  int32_t size, tag;
91 
92  size = avio_rb32(f);
93  tag = avio_rb32(f);
94  if (size < 8)
95  break;
96  if (tag == MKBETAG('s', 'i', 'd', 'x')) {
97  for (i = start_index; i < tracks->nb_tracks; i++) {
98  struct Track *track = tracks->tracks[i];
99  if (!track->sidx_start) {
100  track->sidx_start = pos;
101  track->sidx_length = size;
102  } else if (pos == track->sidx_start + track->sidx_length) {
103  track->sidx_length = pos + size - track->sidx_start;
104  }
105  }
106  }
107  if (avio_seek(f, pos + size, SEEK_SET) != pos + size)
108  break;
109  }
110 
111 fail:
112  if (f)
113  avio_close(f);
114  return err;
115 }
116 
117 static int handle_file(struct Tracks *tracks, const char *file)
118 {
120  int err = 0, i, orig_tracks = tracks->nb_tracks;
121  char errbuf[50], *ptr;
122  struct Track *track;
123 
124  err = avformat_open_input(&ctx, file, NULL, NULL);
125  if (err < 0) {
126  av_strerror(err, errbuf, sizeof(errbuf));
127  fprintf(stderr, "Unable to open %s: %s\n", file, errbuf);
128  return 1;
129  }
130 
132  if (err < 0) {
133  av_strerror(err, errbuf, sizeof(errbuf));
134  fprintf(stderr, "Unable to identify %s: %s\n", file, errbuf);
135  goto fail;
136  }
137 
138  if (ctx->nb_streams < 1) {
139  fprintf(stderr, "No streams found in %s\n", file);
140  goto fail;
141  }
142  if (ctx->nb_streams > 1)
143  tracks->multiple_tracks_per_file = 1;
144 
145  for (i = 0; i < ctx->nb_streams; i++) {
146  struct Track **temp;
147  AVStream *st = ctx->streams[i];
148 
149  if (st->codecpar->bit_rate == 0) {
150  fprintf(stderr, "Skipping track %d in %s as it has zero bitrate\n",
151  st->id, file);
152  continue;
153  }
154 
155  track = av_mallocz(sizeof(*track));
156  if (!track) {
157  err = AVERROR(ENOMEM);
158  goto fail;
159  }
160  temp = av_realloc_array(tracks->tracks, tracks->nb_tracks + 1,
161  sizeof(*tracks->tracks));
162  if (!temp) {
163  av_free(track);
164  err = AVERROR(ENOMEM);
165  goto fail;
166  }
167  tracks->tracks = temp;
168  tracks->tracks[tracks->nb_tracks] = track;
169 
170  track->name = file;
171  if ((ptr = strrchr(file, '/')))
172  track->name = ptr + 1;
173 
174  track->bitrate = st->codecpar->bit_rate;
175  track->track_id = st->id;
176  track->timescale = st->time_base.den;
177  track->duration = st->duration;
180 
181  if (!track->is_audio && !track->is_video) {
182  fprintf(stderr,
183  "Track %d in %s is neither video nor audio, skipping\n",
184  track->track_id, file);
185  av_freep(&tracks->tracks[tracks->nb_tracks]);
186  continue;
187  }
188 
189  tracks->duration = FFMAX(tracks->duration,
191  track->timescale, AV_ROUND_UP));
192 
193  if (track->is_audio) {
194  track->channels = st->codecpar->channels;
195  track->sample_rate = st->codecpar->sample_rate;
196  }
197  if (track->is_video) {
198  track->width = st->codecpar->width;
199  track->height = st->codecpar->height;
200  }
201  set_codec_str(st->codecpar, track->codec_str, sizeof(track->codec_str));
202 
203  tracks->nb_tracks++;
204  }
205 
207 
208  err = find_sidx(tracks, orig_tracks, file);
209 
210 fail:
211  if (ctx)
213  return err;
214 }
215 
216 static void write_time(FILE *out, int64_t time, int decimals, enum AVRounding round)
217 {
218  int seconds = time / AV_TIME_BASE;
219  int fractions = time % AV_TIME_BASE;
220  int minutes = seconds / 60;
221  int hours = minutes / 60;
222  fractions = av_rescale_rnd(fractions, pow(10, decimals), AV_TIME_BASE, round);
223  seconds %= 60;
224  minutes %= 60;
225  fprintf(out, "PT");
226  if (hours)
227  fprintf(out, "%dH", hours);
228  if (hours || minutes)
229  fprintf(out, "%dM", minutes);
230  fprintf(out, "%d.%0*dS", seconds, decimals, fractions);
231 }
232 
233 static int output_mpd(struct Tracks *tracks, const char *filename)
234 {
235  FILE *out;
236  int i, j, ret = 0;
237  struct Track **adaptation_sets_buf[2] = { NULL };
238  struct Track ***adaptation_sets;
239  int nb_tracks_buf[2] = { 0 };
240  int *nb_tracks;
241  int set, nb_sets;
242 
243  if (!tracks->multiple_tracks_per_file) {
244  adaptation_sets = adaptation_sets_buf;
245  nb_tracks = nb_tracks_buf;
246  nb_sets = 2;
247  for (i = 0; i < 2; i++) {
248  adaptation_sets[i] = av_malloc_array(tracks->nb_tracks, sizeof(*adaptation_sets[i]));
249  if (!adaptation_sets[i]) {
250  ret = AVERROR(ENOMEM);
251  goto err;
252  }
253  }
254  for (i = 0; i < tracks->nb_tracks; i++) {
255  int set_index = -1;
256  if (tracks->tracks[i]->is_video)
257  set_index = 0;
258  else if (tracks->tracks[i]->is_audio)
259  set_index = 1;
260  else
261  continue;
262  adaptation_sets[set_index][nb_tracks[set_index]++] = tracks->tracks[i];
263  }
264  } else {
265  adaptation_sets = &tracks->tracks;
266  nb_tracks = &tracks->nb_tracks;
267  nb_sets = 1;
268  }
269 
270  out = fopen(filename, "w");
271  if (!out) {
272  ret = AVERROR(errno);
273  perror(filename);
274  return ret;
275  }
276  fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
277  fprintf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
278  "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
279  "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
280  "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
281  "\tprofiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\"\n"
282  "\ttype=\"static\"\n");
283  fprintf(out, "\tmediaPresentationDuration=\"");
284  write_time(out, tracks->duration, 1, AV_ROUND_DOWN);
285  fprintf(out, "\"\n");
286  fprintf(out, "\tminBufferTime=\"PT5S\">\n");
287 
288  fprintf(out, "\t<Period start=\"PT0.0S\">\n");
289 
290  for (set = 0; set < nb_sets; set++) {
291  if (nb_tracks[set] == 0)
292  continue;
293  fprintf(out, "\t\t<AdaptationSet segmentAlignment=\"true\">\n");
294  if (nb_sets == 1) {
295  for (i = 0; i < nb_tracks[set]; i++) {
296  struct Track *track = adaptation_sets[set][i];
297  if (strcmp(track->name, adaptation_sets[set][0]->name))
298  break;
299  fprintf(out, "\t\t\t<ContentComponent id=\"%d\" contentType=\"%s\" />\n", track->track_id, track->is_audio ? "audio" : "video");
300  }
301  }
302 
303  for (i = 0; i < nb_tracks[set]; ) {
304  struct Track *first_track = adaptation_sets[set][i];
305  int width = 0, height = 0, sample_rate = 0, channels = 0, bitrate = 0;
306  fprintf(out, "\t\t\t<Representation id=\"%d\" codecs=\"", i);
307  for (j = i; j < nb_tracks[set]; j++) {
308  struct Track *track = adaptation_sets[set][j];
309  if (strcmp(track->name, first_track->name))
310  break;
311  if (track->is_audio) {
312  sample_rate = track->sample_rate;
313  channels = track->channels;
314  }
315  if (track->is_video) {
316  width = track->width;
317  height = track->height;
318  }
319  bitrate += track->bitrate;
320  if (j > i)
321  fprintf(out, ",");
322  fprintf(out, "%s", track->codec_str);
323  }
324  fprintf(out, "\" mimeType=\"%s/mp4\" bandwidth=\"%d\"",
325  width ? "video" : "audio", bitrate);
326  if (width > 0 && height > 0)
327  fprintf(out, " width=\"%d\" height=\"%d\"", width, height);
328  if (sample_rate > 0)
329  fprintf(out, " audioSamplingRate=\"%d\"", sample_rate);
330  fprintf(out, ">\n");
331  if (channels > 0)
332  fprintf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", channels);
333  fprintf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", first_track->name);
334  fprintf(out, "\t\t\t\t<SegmentBase indexRange=\"%"PRId64"-%"PRId64"\" />\n", first_track->sidx_start, first_track->sidx_start + first_track->sidx_length - 1);
335  fprintf(out, "\t\t\t</Representation>\n");
336  i = j;
337  }
338  fprintf(out, "\t\t</AdaptationSet>\n");
339  }
340  fprintf(out, "\t</Period>\n");
341  fprintf(out, "</MPD>\n");
342 
343  fclose(out);
344 err:
345  for (i = 0; i < 2; i++)
346  av_free(adaptation_sets_buf[i]);
347  return ret;
348 }
349 
350 static void clean_tracks(struct Tracks *tracks)
351 {
352  int i;
353  for (i = 0; i < tracks->nb_tracks; i++) {
354  av_freep(&tracks->tracks[i]);
355  }
356  av_freep(&tracks->tracks);
357  tracks->nb_tracks = 0;
358 }
359 
360 int main(int argc, char **argv)
361 {
362  const char *out = NULL;
363  struct Tracks tracks = { 0 };
364  int i;
365 
366  for (i = 1; i < argc; i++) {
367  if (!strcmp(argv[i], "-out")) {
368  out = argv[i + 1];
369  i++;
370  } else if (argv[i][0] == '-') {
371  return usage(argv[0], 1);
372  } else {
373  if (handle_file(&tracks, argv[i]))
374  return 1;
375  }
376  }
377  if (!tracks.nb_tracks || !out)
378  return usage(argv[0], 1);
379 
380  output_mpd(&tracks, out);
381 
383 
384  return 0;
385 }
set_codec_str
static void set_codec_str(AVCodecParameters *codecpar, char *str, int size)
Definition: sidxindex.c:55
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3971
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
Track
Definition: ismindex.c:69
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3953
avio_close
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:1185
out
FILE * out
Definition: movenc.c:54
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3949
handle_file
static int handle_file(struct Tracks *tracks, const char *file)
Definition: sidxindex.c:117
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1410
AVRounding
AVRounding
Rounding methods.
Definition: mathematics.h:79
channels
channels
Definition: aptx.c:30
mathematics.h
Tracks::duration
int64_t duration
Definition: ismindex.c:89
av_strlcatf
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
sample_rate
sample_rate
Definition: ffmpeg_filter.c:191
avformat_close_input
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: utils.c:4452
AVCodecParameters::channels
int channels
Audio only.
Definition: avcodec.h:4063
avio_open2
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:1179
fail
#define fail()
Definition: checkasm.h:120
av_strerror
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
Put a description of the AVERROR code errnum in errbuf.
Definition: error.c:105
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
usage
static int usage(const char *argv0, int ret)
Definition: sidxindex.c:29
Track::bitrate
int bitrate
Definition: ismindex.c:72
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:83
clean_tracks
static void clean_tracks(struct Tracks *tracks)
Definition: sidxindex.c:350
find_sidx
static int find_sidx(struct Tracks *tracks, int start_index, const char *file)
Definition: sidxindex.c:78
AVStream::duration
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:919
Tracks::nb_tracks
int nb_tracks
Definition: ismindex.c:88
Track::name
const char * name
Definition: ismindex.c:70
avio_rb32
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:800
set
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v)
Definition: swresample.c:59
write_time
static void write_time(FILE *out, int64_t time, int decimals, enum AVRounding round)
Definition: sidxindex.c:216
width
#define width
intreadwrite.h
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:198
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVCodecParameters::width
int width
Video only.
Definition: avcodec.h:4023
ctx
AVFormatContext * ctx
Definition: movenc.c:48
Track::height
int height
Definition: ismindex.c:75
f
#define f(width, name)
Definition: cbs_vp9.c:255
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: avcodec.h:245
int32_t
int32_t
Definition: audio_convert.c:194
AVFormatContext
Format I/O context.
Definition: avformat.h:1342
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1017
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:899
NULL
#define NULL
Definition: coverity.c:32
Track::codec_str
char codec_str[30]
Definition: sidxindex.c:44
AVCodecParameters::sample_rate
int sample_rate
Audio only.
Definition: avcodec.h:4067
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:3975
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1398
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: avcodec.h:566
av_rescale_rnd
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
Rescale a 64-bit integer with specified rounding.
Definition: mathematics.c:58
Tracks::multiple_tracks_per_file
int multiple_tracks_per_file
Definition: sidxindex.c:52
avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
Read packets of a media file to get stream information.
Definition: utils.c:3588
Track::channels
int channels
Definition: ismindex.c:77
AVIOContext
Bytestream IO Context.
Definition: avio.h:161
FFMAX
#define FFMAX(a, b)
Definition: common.h:94
size
int size
Definition: twinvq_data.h:11134
MKBETAG
#define MKBETAG(a, b, c, d)
Definition: common.h:367
height
#define height
bitrate
int64_t bitrate
Definition: h264_levels.c:131
Tracks::tracks
struct Track ** tracks
Definition: ismindex.c:90
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
avformat_open_input
int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: utils.c:540
round
static av_always_inline av_const double round(double x)
Definition: libm.h:444
Track::sample_rate
int sample_rate
Definition: ismindex.c:77
AVCodecParameters::height
int height
Definition: avcodec.h:4024
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:82
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:236
Track::is_video
int is_video
Definition: ismindex.c:74
Tracks
Definition: ismindex.c:87
Track::duration
int64_t duration
Definition: ismindex.c:71
tag
uint32_t tag
Definition: movenc.c:1496
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:877
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:870
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
avformat.h
Track::sidx_start
int64_t sidx_start
Definition: sidxindex.c:45
Track::width
int width
Definition: ismindex.c:75
output_mpd
static int output_mpd(struct Tracks *tracks, const char *filename)
Definition: sidxindex.c:233
AVRational::den
int den
Denominator.
Definition: rational.h:60
temp
else temp
Definition: vf_mcdeint.c:256
main
int main(int argc, char **argv)
Definition: sidxindex.c:360
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:654
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
Track::is_audio
int is_audio
Definition: ismindex.c:74
Track::timescale
int timescale
Definition: ismindex.c:81
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3957
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
Track::track_id
int track_id
Definition: ismindex.c:73
AVCodecParameters::bit_rate
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: avcodec.h:3986
avstring.h
snprintf
#define snprintf
Definition: snprintf.h:34
Track::sidx_length
int64_t sidx_length
Definition: sidxindex.c:45
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:94