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 #include "libavutil/mem.h"
29 
30 static int usage(const char *argv0, int ret)
31 {
32  fprintf(stderr, "%s -out foo.mpd file1\n", argv0);
33  return ret;
34 }
35 
36 struct Track {
37  const char *name;
38  int64_t duration;
39  int bitrate;
40  int track_id;
41  int is_audio, is_video;
42  int width, height;
43  int sample_rate, channels;
44  int timescale;
45  char codec_str[30];
47 };
48 
49 struct Tracks {
50  int nb_tracks;
51  int64_t duration;
52  struct Track **tracks;
54 };
55 
56 static void set_codec_str(AVCodecParameters *codecpar, char *str, int size)
57 {
58  switch (codecpar->codec_id) {
59  case AV_CODEC_ID_H264:
60  snprintf(str, size, "avc1");
61  if (codecpar->extradata_size >= 4 && codecpar->extradata[0] == 1) {
62  av_strlcatf(str, size, ".%02x%02x%02x",
63  codecpar->extradata[1], codecpar->extradata[2],
64  codecpar->extradata[3]);
65  }
66  break;
67  case AV_CODEC_ID_AAC:
68  snprintf(str, size, "mp4a.40"); // 0x40 is the mp4 object type for AAC
69  if (codecpar->extradata_size >= 2) {
70  int aot = codecpar->extradata[0] >> 3;
71  if (aot == 31)
72  aot = ((AV_RB16(codecpar->extradata) >> 5) & 0x3f) + 32;
73  av_strlcatf(str, size, ".%d", aot);
74  }
75  break;
76  }
77 }
78 
79 static int find_sidx(struct Tracks *tracks, int start_index,
80  const char *file)
81 {
82  int err = 0;
83  AVIOContext *f = NULL;
84  int i;
85 
86  if ((err = avio_open2(&f, file, AVIO_FLAG_READ, NULL, NULL)) < 0)
87  goto fail;
88 
89  while (!f->eof_reached) {
90  int64_t pos = avio_tell(f);
91  int32_t size, tag;
92 
93  size = avio_rb32(f);
94  tag = avio_rb32(f);
95  if (size < 8)
96  break;
97  if (tag == MKBETAG('s', 'i', 'd', 'x')) {
98  for (i = start_index; i < tracks->nb_tracks; i++) {
99  struct Track *track = tracks->tracks[i];
100  if (!track->sidx_start) {
101  track->sidx_start = pos;
102  track->sidx_length = size;
103  } else if (pos == track->sidx_start + track->sidx_length) {
104  track->sidx_length = pos + size - track->sidx_start;
105  }
106  }
107  }
108  if (avio_seek(f, pos + size, SEEK_SET) != pos + size)
109  break;
110  }
111 
112 fail:
113  if (f)
114  avio_close(f);
115  return err;
116 }
117 
118 static int handle_file(struct Tracks *tracks, const char *file)
119 {
121  int err = 0, i, orig_tracks = tracks->nb_tracks;
122  char errbuf[50], *ptr;
123  struct Track *track;
124 
125  err = avformat_open_input(&ctx, file, NULL, NULL);
126  if (err < 0) {
127  av_strerror(err, errbuf, sizeof(errbuf));
128  fprintf(stderr, "Unable to open %s: %s\n", file, errbuf);
129  return 1;
130  }
131 
133  if (err < 0) {
134  av_strerror(err, errbuf, sizeof(errbuf));
135  fprintf(stderr, "Unable to identify %s: %s\n", file, errbuf);
136  goto fail;
137  }
138 
139  if (ctx->nb_streams < 1) {
140  fprintf(stderr, "No streams found in %s\n", file);
141  goto fail;
142  }
143  if (ctx->nb_streams > 1)
144  tracks->multiple_tracks_per_file = 1;
145 
146  for (i = 0; i < ctx->nb_streams; i++) {
147  struct Track **temp;
148  AVStream *st = ctx->streams[i];
149 
150  if (st->codecpar->bit_rate == 0) {
151  fprintf(stderr, "Skipping track %d in %s as it has zero bitrate\n",
152  st->id, file);
153  continue;
154  }
155 
156  track = av_mallocz(sizeof(*track));
157  if (!track) {
158  err = AVERROR(ENOMEM);
159  goto fail;
160  }
161  temp = av_realloc_array(tracks->tracks, tracks->nb_tracks + 1,
162  sizeof(*tracks->tracks));
163  if (!temp) {
164  av_free(track);
165  err = AVERROR(ENOMEM);
166  goto fail;
167  }
168  tracks->tracks = temp;
169  tracks->tracks[tracks->nb_tracks] = track;
170 
171  track->name = file;
172  if ((ptr = strrchr(file, '/')))
173  track->name = ptr + 1;
174 
175  track->bitrate = st->codecpar->bit_rate;
176  track->track_id = st->id;
177  track->timescale = st->time_base.den;
178  track->duration = st->duration;
181 
182  if (!track->is_audio && !track->is_video) {
183  fprintf(stderr,
184  "Track %d in %s is neither video nor audio, skipping\n",
185  track->track_id, file);
186  av_freep(&tracks->tracks[tracks->nb_tracks]);
187  continue;
188  }
189 
190  tracks->duration = FFMAX(tracks->duration,
192  track->timescale, AV_ROUND_UP));
193 
194  if (track->is_audio) {
195  track->channels = st->codecpar->ch_layout.nb_channels;
196  track->sample_rate = st->codecpar->sample_rate;
197  }
198  if (track->is_video) {
199  track->width = st->codecpar->width;
200  track->height = st->codecpar->height;
201  }
202  set_codec_str(st->codecpar, track->codec_str, sizeof(track->codec_str));
203 
204  tracks->nb_tracks++;
205  }
206 
208 
209  err = find_sidx(tracks, orig_tracks, file);
210 
211 fail:
212  if (ctx)
214  return err;
215 }
216 
217 static void write_time(FILE *out, int64_t time, int decimals, enum AVRounding round)
218 {
219  int seconds = time / AV_TIME_BASE;
220  int fractions = time % AV_TIME_BASE;
221  int minutes = seconds / 60;
222  int hours = minutes / 60;
223  fractions = av_rescale_rnd(fractions, pow(10, decimals), AV_TIME_BASE, round);
224  seconds %= 60;
225  minutes %= 60;
226  fprintf(out, "PT");
227  if (hours)
228  fprintf(out, "%dH", hours);
229  if (hours || minutes)
230  fprintf(out, "%dM", minutes);
231  fprintf(out, "%d.%0*dS", seconds, decimals, fractions);
232 }
233 
234 static int output_mpd(struct Tracks *tracks, const char *filename)
235 {
236  FILE *out;
237  int i, j, ret = 0;
238  struct Track **adaptation_sets_buf[2] = { NULL };
239  struct Track ***adaptation_sets;
240  int nb_tracks_buf[2] = { 0 };
241  int *nb_tracks;
242  int set, nb_sets;
243 
244  if (!tracks->multiple_tracks_per_file) {
245  adaptation_sets = adaptation_sets_buf;
246  nb_tracks = nb_tracks_buf;
247  nb_sets = 2;
248  for (i = 0; i < 2; i++) {
249  adaptation_sets[i] = av_malloc_array(tracks->nb_tracks, sizeof(*adaptation_sets[i]));
250  if (!adaptation_sets[i]) {
251  ret = AVERROR(ENOMEM);
252  goto err;
253  }
254  }
255  for (i = 0; i < tracks->nb_tracks; i++) {
256  int set_index = -1;
257  if (tracks->tracks[i]->is_video)
258  set_index = 0;
259  else if (tracks->tracks[i]->is_audio)
260  set_index = 1;
261  else
262  continue;
263  adaptation_sets[set_index][nb_tracks[set_index]++] = tracks->tracks[i];
264  }
265  } else {
266  adaptation_sets = &tracks->tracks;
267  nb_tracks = &tracks->nb_tracks;
268  nb_sets = 1;
269  }
270 
271  out = fopen(filename, "w");
272  if (!out) {
273  ret = AVERROR(errno);
274  perror(filename);
275  return ret;
276  }
277  fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
278  fprintf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
279  "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
280  "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
281  "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
282  "\tprofiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\"\n"
283  "\ttype=\"static\"\n");
284  fprintf(out, "\tmediaPresentationDuration=\"");
285  write_time(out, tracks->duration, 1, AV_ROUND_DOWN);
286  fprintf(out, "\"\n");
287  fprintf(out, "\tminBufferTime=\"PT5S\">\n");
288 
289  fprintf(out, "\t<Period start=\"PT0.0S\">\n");
290 
291  for (set = 0; set < nb_sets; set++) {
292  if (nb_tracks[set] == 0)
293  continue;
294  fprintf(out, "\t\t<AdaptationSet segmentAlignment=\"true\">\n");
295  if (nb_sets == 1) {
296  for (i = 0; i < nb_tracks[set]; i++) {
297  struct Track *track = adaptation_sets[set][i];
298  if (strcmp(track->name, adaptation_sets[set][0]->name))
299  break;
300  fprintf(out, "\t\t\t<ContentComponent id=\"%d\" contentType=\"%s\" />\n", track->track_id, track->is_audio ? "audio" : "video");
301  }
302  }
303 
304  for (i = 0; i < nb_tracks[set]; ) {
305  struct Track *first_track = adaptation_sets[set][i];
306  int width = 0, height = 0, sample_rate = 0, channels = 0, bitrate = 0;
307  fprintf(out, "\t\t\t<Representation id=\"%d\" codecs=\"", i);
308  for (j = i; j < nb_tracks[set]; j++) {
309  struct Track *track = adaptation_sets[set][j];
310  if (strcmp(track->name, first_track->name))
311  break;
312  if (track->is_audio) {
313  sample_rate = track->sample_rate;
314  channels = track->channels;
315  }
316  if (track->is_video) {
317  width = track->width;
318  height = track->height;
319  }
320  bitrate += track->bitrate;
321  if (j > i)
322  fprintf(out, ",");
323  fprintf(out, "%s", track->codec_str);
324  }
325  fprintf(out, "\" mimeType=\"%s/mp4\" bandwidth=\"%d\"",
326  width ? "video" : "audio", bitrate);
327  if (width > 0 && height > 0)
328  fprintf(out, " width=\"%d\" height=\"%d\"", width, height);
329  if (sample_rate > 0)
330  fprintf(out, " audioSamplingRate=\"%d\"", sample_rate);
331  fprintf(out, ">\n");
332  if (channels > 0)
333  fprintf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", channels);
334  fprintf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", first_track->name);
335  fprintf(out, "\t\t\t\t<SegmentBase indexRange=\"%"PRId64"-%"PRId64"\" />\n", first_track->sidx_start, first_track->sidx_start + first_track->sidx_length - 1);
336  fprintf(out, "\t\t\t</Representation>\n");
337  i = j;
338  }
339  fprintf(out, "\t\t</AdaptationSet>\n");
340  }
341  fprintf(out, "\t</Period>\n");
342  fprintf(out, "</MPD>\n");
343 
344  fclose(out);
345 err:
346  for (i = 0; i < 2; i++)
347  av_free(adaptation_sets_buf[i]);
348  return ret;
349 }
350 
351 static void clean_tracks(struct Tracks *tracks)
352 {
353  int i;
354  for (i = 0; i < tracks->nb_tracks; i++) {
355  av_freep(&tracks->tracks[i]);
356  }
357  av_freep(&tracks->tracks);
358  tracks->nb_tracks = 0;
359 }
360 
361 int main(int argc, char **argv)
362 {
363  const char *out = NULL;
364  struct Tracks tracks = { 0 };
365  int i;
366 
367  for (i = 1; i < argc; i++) {
368  if (!strcmp(argv[i], "-out")) {
369  out = argv[i + 1];
370  i++;
371  } else if (argv[i][0] == '-') {
372  return usage(argv[0], 1);
373  } else {
374  if (handle_file(&tracks, argv[i]))
375  return 1;
376  }
377  }
378  if (!tracks.nb_tracks || !out)
379  return usage(argv[0], 1);
380 
381  output_mpd(&tracks, out);
382 
384 
385  return 0;
386 }
set_codec_str
static void set_codec_str(AVCodecParameters *codecpar, char *str, int size)
Definition: sidxindex.c:56
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
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:70
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:51
out
FILE * out
Definition: movenc.c:55
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: codec_par.h:47
handle_file
static int handle_file(struct Tracks *tracks, const char *file)
Definition: sidxindex.c:118
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1323
AVRounding
AVRounding
Rounding methods.
Definition: mathematics.h:130
mathematics.h
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:321
Tracks::duration
int64_t duration
Definition: ismindex.c:90
av_strlcatf
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:103
sample_rate
sample_rate
Definition: ffmpeg_filter.c:424
avformat_close_input
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: demux.c:363
fail
#define fail()
Definition: checkasm.h:184
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:109
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
usage
static int usage(const char *argv0, int ret)
Definition: sidxindex.c:30
Track::bitrate
int bitrate
Definition: ismindex.c:73
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:134
clean_tracks
static void clean_tracks(struct Tracks *tracks)
Definition: sidxindex.c:351
find_sidx
static int find_sidx(struct Tracks *tracks, int start_index, const char *file)
Definition: sidxindex.c:79
AVStream::duration
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:802
Tracks::nb_tracks
int nb_tracks
Definition: ismindex.c:89
Track::name
const char * name
Definition: ismindex.c:71
avio_rb32
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:761
set
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v)
Definition: swresample.c:59
avformat_open_input
int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: demux.c:215
write_time
static void write_time(FILE *out, int64_t time, int decimals, enum AVRounding round)
Definition: sidxindex.c:217
width
#define width
intreadwrite.h
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:217
bitrate
int64_t bitrate
Definition: av1_levels.c:47
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVCodecParameters::width
int width
Video only.
Definition: codec_par.h:134
ctx
AVFormatContext * ctx
Definition: movenc.c:49
channels
channels
Definition: aptx.h:31
Track::height
int height
Definition: ismindex.c:76
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:766
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:782
NULL
#define NULL
Definition: coverity.c:32
Track::codec_str
char codec_str[30]
Definition: sidxindex.c:45
AVCodecParameters::ch_layout
AVChannelLayout ch_layout
Audio only.
Definition: codec_par.h:180
AVCodecParameters::sample_rate
int sample_rate
Audio only.
Definition: codec_par.h:184
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:73
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1311
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: codec_id.h:442
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:53
avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
Read packets of a media file to get stream information.
Definition: demux.c:2516
Track::channels
int channels
Definition: ismindex.c:78
f
f
Definition: af_crystalizer.c:121
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
size
int size
Definition: twinvq_data.h:10344
MKBETAG
#define MKBETAG(a, b, c, d)
Definition: macros.h:56
height
#define height
Tracks::tracks
struct Track ** tracks
Definition: ismindex.c:91
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
round
static av_always_inline av_const double round(double x)
Definition: libm.h:444
Track::sample_rate
int sample_rate
Definition: ismindex.c:78
AVCodecParameters::height
int height
Definition: codec_par.h:135
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:31
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:133
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:256
Track::is_video
int is_video
Definition: ismindex.c:75
Tracks
Definition: ismindex.c:88
Track::duration
int64_t duration
Definition: ismindex.c:72
tag
uint32_t tag
Definition: movenc.c:1851
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:755
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:743
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:231
pos
unsigned int pos
Definition: spdifenc.c:414
avformat.h
Track::sidx_start
int64_t sidx_start
Definition: sidxindex.c:46
Track::width
int width
Definition: ismindex.c:76
output_mpd
static int output_mpd(struct Tracks *tracks, const char *filename)
Definition: sidxindex.c:234
AVRational::den
int den
Denominator.
Definition: rational.h:60
temp
else temp
Definition: vf_mcdeint.c:263
main
int main(int argc, char **argv)
Definition: sidxindex.c:361
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
avio_open2
int avio_open2(AVIOContext **s, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: avio.c:491
Track::is_audio
int is_audio
Definition: ismindex.c:75
Track::timescale
int timescale
Definition: ismindex.c:82
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
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
Track::track_id
int track_id
Definition: ismindex.c:74
int32_t
int32_t
Definition: audioconvert.c:56
avio_close
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: avio.c:616
AVCodecParameters::bit_rate
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: codec_par.h:97
avstring.h
snprintf
#define snprintf
Definition: snprintf.h:34
Track::sidx_length
int64_t sidx_length
Definition: sidxindex.c:46
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:98