FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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;
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;
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) {
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 *ptr;
123  struct Track *track;
124 
125  err = avformat_open_input(&ctx, file, NULL, NULL);
126  if (err < 0) {
127  fprintf(stderr, "Unable to open %s: %s\n", file, av_err2str(err));
128  return 1;
129  }
130 
132  if (err < 0) {
133  fprintf(stderr, "Unable to identify %s: %s\n", file, av_err2str(err));
134  goto fail;
135  }
136 
137  if (ctx->nb_streams < 1) {
138  fprintf(stderr, "No streams found in %s\n", file);
139  goto fail;
140  }
141  if (ctx->nb_streams > 1)
142  tracks->multiple_tracks_per_file = 1;
143 
144  for (i = 0; i < ctx->nb_streams; i++) {
145  struct Track **temp;
146  AVStream *st = ctx->streams[i];
147 
148  if (st->codecpar->bit_rate == 0) {
149  fprintf(stderr, "Skipping track %d in %s as it has zero bitrate\n",
150  st->id, file);
151  continue;
152  }
153 
154  track = av_mallocz(sizeof(*track));
155  if (!track) {
156  err = AVERROR(ENOMEM);
157  goto fail;
158  }
159  temp = av_realloc_array(tracks->tracks, tracks->nb_tracks + 1,
160  sizeof(*tracks->tracks));
161  if (!temp) {
162  av_free(track);
163  err = AVERROR(ENOMEM);
164  goto fail;
165  }
166  tracks->tracks = temp;
167  tracks->tracks[tracks->nb_tracks] = track;
168 
169  track->name = file;
170  if ((ptr = strrchr(file, '/')))
171  track->name = ptr + 1;
172 
173  track->bitrate = st->codecpar->bit_rate;
174  track->track_id = st->id;
175  track->timescale = st->time_base.den;
176  track->duration = st->duration;
179 
180  if (!track->is_audio && !track->is_video) {
181  fprintf(stderr,
182  "Track %d in %s is neither video nor audio, skipping\n",
183  track->track_id, file);
184  av_freep(&tracks->tracks[tracks->nb_tracks]);
185  continue;
186  }
187 
188  tracks->duration = FFMAX(tracks->duration,
190  track->timescale, AV_ROUND_UP));
191 
192  if (track->is_audio) {
193  track->channels = st->codecpar->ch_layout.nb_channels;
194  track->sample_rate = st->codecpar->sample_rate;
195  }
196  if (track->is_video) {
197  track->width = st->codecpar->width;
198  track->height = st->codecpar->height;
199  }
200  set_codec_str(st->codecpar, track->codec_str, sizeof(track->codec_str));
201 
202  tracks->nb_tracks++;
203  }
204 
206 
207  err = find_sidx(tracks, orig_tracks, file);
208 
209 fail:
210  if (ctx)
212  return err;
213 }
214 
215 static void write_time(FILE *out, int64_t time, int decimals, enum AVRounding round)
216 {
217  int seconds = time / AV_TIME_BASE;
218  int fractions = time % AV_TIME_BASE;
219  int minutes = seconds / 60;
220  int hours = minutes / 60;
221  fractions = av_rescale_rnd(fractions, pow(10, decimals), AV_TIME_BASE, round);
222  seconds %= 60;
223  minutes %= 60;
224  fprintf(out, "PT");
225  if (hours)
226  fprintf(out, "%dH", hours);
227  if (hours || minutes)
228  fprintf(out, "%dM", minutes);
229  fprintf(out, "%d.%0*dS", seconds, decimals, fractions);
230 }
231 
232 static int output_mpd(struct Tracks *tracks, const char *filename)
233 {
234  FILE *out;
235  int i, j, ret = 0;
236  struct Track **adaptation_sets_buf[2] = { NULL };
237  struct Track ***adaptation_sets;
238  int nb_tracks_buf[2] = { 0 };
239  int *nb_tracks;
240  int set, nb_sets;
241 
242  if (!tracks->multiple_tracks_per_file) {
243  adaptation_sets = adaptation_sets_buf;
244  nb_tracks = nb_tracks_buf;
245  nb_sets = 2;
246  for (i = 0; i < 2; i++) {
247  adaptation_sets[i] = av_malloc_array(tracks->nb_tracks, sizeof(*adaptation_sets[i]));
248  if (!adaptation_sets[i]) {
249  ret = AVERROR(ENOMEM);
250  goto err;
251  }
252  }
253  for (i = 0; i < tracks->nb_tracks; i++) {
254  int set_index = -1;
255  if (tracks->tracks[i]->is_video)
256  set_index = 0;
257  else if (tracks->tracks[i]->is_audio)
258  set_index = 1;
259  else
260  continue;
261  adaptation_sets[set_index][nb_tracks[set_index]++] = tracks->tracks[i];
262  }
263  } else {
264  adaptation_sets = &tracks->tracks;
265  nb_tracks = &tracks->nb_tracks;
266  nb_sets = 1;
267  }
268 
269  out = fopen(filename, "w");
270  if (!out) {
271  ret = AVERROR(errno);
272  perror(filename);
273  return ret;
274  }
275  fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
276  fprintf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
277  "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
278  "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
279  "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
280  "\tprofiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\"\n"
281  "\ttype=\"static\"\n");
282  fprintf(out, "\tmediaPresentationDuration=\"");
283  write_time(out, tracks->duration, 1, AV_ROUND_DOWN);
284  fprintf(out, "\"\n");
285  fprintf(out, "\tminBufferTime=\"PT5S\">\n");
286 
287  fprintf(out, "\t<Period start=\"PT0.0S\">\n");
288 
289  for (set = 0; set < nb_sets; set++) {
290  if (nb_tracks[set] == 0)
291  continue;
292  fprintf(out, "\t\t<AdaptationSet segmentAlignment=\"true\">\n");
293  if (nb_sets == 1) {
294  for (i = 0; i < nb_tracks[set]; i++) {
295  struct Track *track = adaptation_sets[set][i];
296  if (strcmp(track->name, adaptation_sets[set][0]->name))
297  break;
298  fprintf(out, "\t\t\t<ContentComponent id=\"%d\" contentType=\"%s\" />\n", track->track_id, track->is_audio ? "audio" : "video");
299  }
300  }
301 
302  for (i = 0; i < nb_tracks[set]; ) {
303  struct Track *first_track = adaptation_sets[set][i];
304  int width = 0, height = 0, sample_rate = 0, channels = 0, bitrate = 0;
305  fprintf(out, "\t\t\t<Representation id=\"%d\" codecs=\"", i);
306  for (j = i; j < nb_tracks[set]; j++) {
307  struct Track *track = adaptation_sets[set][j];
308  if (strcmp(track->name, first_track->name))
309  break;
310  if (track->is_audio) {
311  sample_rate = track->sample_rate;
312  channels = track->channels;
313  }
314  if (track->is_video) {
315  width = track->width;
316  height = track->height;
317  }
318  bitrate += track->bitrate;
319  if (j > i)
320  fprintf(out, ",");
321  fprintf(out, "%s", track->codec_str);
322  }
323  fprintf(out, "\" mimeType=\"%s/mp4\" bandwidth=\"%d\"",
324  width ? "video" : "audio", bitrate);
325  if (width > 0 && height > 0)
326  fprintf(out, " width=\"%d\" height=\"%d\"", width, height);
327  if (sample_rate > 0)
328  fprintf(out, " audioSamplingRate=\"%d\"", sample_rate);
329  fprintf(out, ">\n");
330  if (channels > 0)
331  fprintf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", channels);
332  fprintf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", first_track->name);
333  fprintf(out, "\t\t\t\t<SegmentBase indexRange=\"%"PRId64"-%"PRId64"\" />\n", first_track->sidx_start, first_track->sidx_start + first_track->sidx_length - 1);
334  fprintf(out, "\t\t\t</Representation>\n");
335  i = j;
336  }
337  fprintf(out, "\t\t</AdaptationSet>\n");
338  }
339  fprintf(out, "\t</Period>\n");
340  fprintf(out, "</MPD>\n");
341 
342  fclose(out);
343 err:
344  for (i = 0; i < 2; i++)
345  av_free(adaptation_sets_buf[i]);
346  return ret;
347 }
348 
349 static void clean_tracks(struct Tracks *tracks)
350 {
351  int i;
352  for (i = 0; i < tracks->nb_tracks; i++) {
353  av_freep(&tracks->tracks[i]);
354  }
355  av_freep(&tracks->tracks);
356  tracks->nb_tracks = 0;
357 }
358 
359 int main(int argc, char **argv)
360 {
361  const char *out = NULL;
362  struct Tracks tracks = { 0 };
363  int i;
364 
365  for (i = 1; i < argc; i++) {
366  if (!strcmp(argv[i], "-out")) {
367  out = argv[i + 1];
368  i++;
369  } else if (argv[i][0] == '-') {
370  return usage(argv[0], 1);
371  } else {
372  if (handle_file(&tracks, argv[i]))
373  return 1;
374  }
375  }
376  if (!tracks.nb_tracks || !out)
377  return usage(argv[0], 1);
378 
379  output_mpd(&tracks, out);
380 
382 
383  return 0;
384 }
set_codec_str
static void set_codec_str(AVCodecParameters *codecpar, char *str, int size)
Definition: sidxindex.c:56
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:134
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
int64_t
long long int64_t
Definition: coverity.c:34
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1333
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:329
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
avformat_close_input
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: demux.c:367
fail
#define fail()
Definition: checkasm.h:194
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
clean_tracks
static void clean_tracks(struct Tracks *tracks)
Definition: sidxindex.c:349
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:804
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:217
write_time
static void write_time(FILE *out, int64_t time, int decimals, enum AVRounding round)
Definition: sidxindex.c:215
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:1265
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:768
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:784
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:1321
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: codec_id.h:450
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:133
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:2507
Track::channels
int channels
Definition: ismindex.c:78
f
f
Definition: af_crystalizer.c:122
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
height
#define height
Definition: dsp.h:85
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
size
int size
Definition: twinvq_data.h:10344
MKBETAG
#define MKBETAG(a, b, c, d)
Definition: macros.h:56
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:446
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:32
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:1911
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:757
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:745
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:232
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:359
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:34
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:35
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
width
#define width
Definition: dsp.h:85
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