annotate ffmpeg/tools/ismindex.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Copyright (c) 2012 Martin Storsjo
yading@11 3 *
yading@11 4 * This file is part of Libav.
yading@11 5 *
yading@11 6 * Libav is free software; you can redistribute it and/or
yading@11 7 * modify it under the terms of the GNU Lesser General Public
yading@11 8 * License as published by the Free Software Foundation; either
yading@11 9 * version 2.1 of the License, or (at your option) any later version.
yading@11 10 *
yading@11 11 * Libav is distributed in the hope that it will be useful,
yading@11 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 14 * Lesser General Public License for more details.
yading@11 15 *
yading@11 16 * You should have received a copy of the GNU Lesser General Public
yading@11 17 * License along with Libav; if not, write to the Free Software
yading@11 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 19 */
yading@11 20
yading@11 21 /*
yading@11 22 * To create a simple file for smooth streaming:
yading@11 23 * ffmpeg <normal input/transcoding options> -movflags frag_keyframe foo.ismv
yading@11 24 * ismindex -n foo foo.ismv
yading@11 25 * This step creates foo.ism and foo.ismc that is required by IIS for
yading@11 26 * serving it.
yading@11 27 *
yading@11 28 * To pre-split files for serving as static files by a web server without
yading@11 29 * any extra server support, create the ismv file as above, and split it:
yading@11 30 * ismindex -split foo.ismv
yading@11 31 * This step creates a file Manifest and directories QualityLevel(...),
yading@11 32 * that can be read directly by a smooth streaming player.
yading@11 33 */
yading@11 34
yading@11 35 #include <stdio.h>
yading@11 36 #include <string.h>
yading@11 37 #include <sys/stat.h>
yading@11 38 #ifdef _WIN32
yading@11 39 #include <direct.h>
yading@11 40 #define mkdir(a, b) _mkdir(a)
yading@11 41 #endif
yading@11 42
yading@11 43 #include "cmdutils.h"
yading@11 44
yading@11 45 #include "libavformat/avformat.h"
yading@11 46 #include "libavutil/intreadwrite.h"
yading@11 47 #include "libavutil/mathematics.h"
yading@11 48
yading@11 49 static int usage(const char *argv0, int ret)
yading@11 50 {
yading@11 51 fprintf(stderr, "%s [-split] [-n basename] file1 [file2] ...\n", argv0);
yading@11 52 return ret;
yading@11 53 }
yading@11 54
yading@11 55 struct MoofOffset {
yading@11 56 int64_t time;
yading@11 57 int64_t offset;
yading@11 58 int duration;
yading@11 59 };
yading@11 60
yading@11 61 struct Track {
yading@11 62 const char *name;
yading@11 63 int64_t duration;
yading@11 64 int bitrate;
yading@11 65 int track_id;
yading@11 66 int is_audio, is_video;
yading@11 67 int width, height;
yading@11 68 int chunks;
yading@11 69 int sample_rate, channels;
yading@11 70 uint8_t *codec_private;
yading@11 71 int codec_private_size;
yading@11 72 struct MoofOffset *offsets;
yading@11 73 int timescale;
yading@11 74 const char *fourcc;
yading@11 75 int blocksize;
yading@11 76 int tag;
yading@11 77 };
yading@11 78
yading@11 79 struct Tracks {
yading@11 80 int nb_tracks;
yading@11 81 int64_t duration;
yading@11 82 struct Track **tracks;
yading@11 83 int video_track, audio_track;
yading@11 84 int nb_video_tracks, nb_audio_tracks;
yading@11 85 };
yading@11 86
yading@11 87 static int copy_tag(AVIOContext *in, AVIOContext *out, int32_t tag_name)
yading@11 88 {
yading@11 89 int32_t size, tag;
yading@11 90
yading@11 91 size = avio_rb32(in);
yading@11 92 tag = avio_rb32(in);
yading@11 93 avio_wb32(out, size);
yading@11 94 avio_wb32(out, tag);
yading@11 95 if (tag != tag_name)
yading@11 96 return -1;
yading@11 97 size -= 8;
yading@11 98 while (size > 0) {
yading@11 99 char buf[1024];
yading@11 100 int len = FFMIN(sizeof(buf), size);
yading@11 101 if (avio_read(in, buf, len) != len)
yading@11 102 break;
yading@11 103 avio_write(out, buf, len);
yading@11 104 size -= len;
yading@11 105 }
yading@11 106 return 0;
yading@11 107 }
yading@11 108
yading@11 109 static int write_fragment(const char *filename, AVIOContext *in)
yading@11 110 {
yading@11 111 AVIOContext *out = NULL;
yading@11 112 int ret;
yading@11 113
yading@11 114 if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, NULL, NULL)) < 0)
yading@11 115 return ret;
yading@11 116 copy_tag(in, out, MKBETAG('m', 'o', 'o', 'f'));
yading@11 117 copy_tag(in, out, MKBETAG('m', 'd', 'a', 't'));
yading@11 118
yading@11 119 avio_flush(out);
yading@11 120 avio_close(out);
yading@11 121
yading@11 122 return ret;
yading@11 123 }
yading@11 124
yading@11 125 static int write_fragments(struct Tracks *tracks, int start_index,
yading@11 126 AVIOContext *in)
yading@11 127 {
yading@11 128 char dirname[100], filename[500];
yading@11 129 int i, j;
yading@11 130
yading@11 131 for (i = start_index; i < tracks->nb_tracks; i++) {
yading@11 132 struct Track *track = tracks->tracks[i];
yading@11 133 const char *type = track->is_video ? "video" : "audio";
yading@11 134 snprintf(dirname, sizeof(dirname), "QualityLevels(%d)", track->bitrate);
yading@11 135 mkdir(dirname, 0777);
yading@11 136 for (j = 0; j < track->chunks; j++) {
yading@11 137 snprintf(filename, sizeof(filename), "%s/Fragments(%s=%"PRId64")",
yading@11 138 dirname, type, track->offsets[j].time);
yading@11 139 avio_seek(in, track->offsets[j].offset, SEEK_SET);
yading@11 140 write_fragment(filename, in);
yading@11 141 }
yading@11 142 }
yading@11 143 return 0;
yading@11 144 }
yading@11 145
yading@11 146 static int read_tfra(struct Tracks *tracks, int start_index, AVIOContext *f)
yading@11 147 {
yading@11 148 int ret = AVERROR_EOF, track_id;
yading@11 149 int version, fieldlength, i, j;
yading@11 150 int64_t pos = avio_tell(f);
yading@11 151 uint32_t size = avio_rb32(f);
yading@11 152 struct Track *track = NULL;
yading@11 153
yading@11 154 if (avio_rb32(f) != MKBETAG('t', 'f', 'r', 'a'))
yading@11 155 goto fail;
yading@11 156 version = avio_r8(f);
yading@11 157 avio_rb24(f);
yading@11 158 track_id = avio_rb32(f); /* track id */
yading@11 159 for (i = start_index; i < tracks->nb_tracks && !track; i++)
yading@11 160 if (tracks->tracks[i]->track_id == track_id)
yading@11 161 track = tracks->tracks[i];
yading@11 162 if (!track) {
yading@11 163 /* Ok, continue parsing the next atom */
yading@11 164 ret = 0;
yading@11 165 goto fail;
yading@11 166 }
yading@11 167 fieldlength = avio_rb32(f);
yading@11 168 track->chunks = avio_rb32(f);
yading@11 169 track->offsets = av_mallocz(sizeof(*track->offsets) * track->chunks);
yading@11 170 if (!track->offsets) {
yading@11 171 ret = AVERROR(ENOMEM);
yading@11 172 goto fail;
yading@11 173 }
yading@11 174 for (i = 0; i < track->chunks; i++) {
yading@11 175 if (version == 1) {
yading@11 176 track->offsets[i].time = avio_rb64(f);
yading@11 177 track->offsets[i].offset = avio_rb64(f);
yading@11 178 } else {
yading@11 179 track->offsets[i].time = avio_rb32(f);
yading@11 180 track->offsets[i].offset = avio_rb32(f);
yading@11 181 }
yading@11 182 for (j = 0; j < ((fieldlength >> 4) & 3) + 1; j++)
yading@11 183 avio_r8(f);
yading@11 184 for (j = 0; j < ((fieldlength >> 2) & 3) + 1; j++)
yading@11 185 avio_r8(f);
yading@11 186 for (j = 0; j < ((fieldlength >> 0) & 3) + 1; j++)
yading@11 187 avio_r8(f);
yading@11 188 if (i > 0)
yading@11 189 track->offsets[i - 1].duration = track->offsets[i].time -
yading@11 190 track->offsets[i - 1].time;
yading@11 191 }
yading@11 192 if (track->chunks > 0)
yading@11 193 track->offsets[track->chunks - 1].duration = track->duration -
yading@11 194 track->offsets[track->chunks - 1].time;
yading@11 195 ret = 0;
yading@11 196
yading@11 197 fail:
yading@11 198 avio_seek(f, pos + size, SEEK_SET);
yading@11 199 return ret;
yading@11 200 }
yading@11 201
yading@11 202 static int read_mfra(struct Tracks *tracks, int start_index,
yading@11 203 const char *file, int split)
yading@11 204 {
yading@11 205 int err = 0;
yading@11 206 AVIOContext *f = NULL;
yading@11 207 int32_t mfra_size;
yading@11 208
yading@11 209 if ((err = avio_open2(&f, file, AVIO_FLAG_READ, NULL, NULL)) < 0)
yading@11 210 goto fail;
yading@11 211 avio_seek(f, avio_size(f) - 4, SEEK_SET);
yading@11 212 mfra_size = avio_rb32(f);
yading@11 213 avio_seek(f, -mfra_size, SEEK_CUR);
yading@11 214 if (avio_rb32(f) != mfra_size) {
yading@11 215 err = AVERROR_INVALIDDATA;
yading@11 216 goto fail;
yading@11 217 }
yading@11 218 if (avio_rb32(f) != MKBETAG('m', 'f', 'r', 'a')) {
yading@11 219 err = AVERROR_INVALIDDATA;
yading@11 220 goto fail;
yading@11 221 }
yading@11 222 while (!read_tfra(tracks, start_index, f)) {
yading@11 223 /* Empty */
yading@11 224 }
yading@11 225
yading@11 226 if (split)
yading@11 227 write_fragments(tracks, start_index, f);
yading@11 228
yading@11 229 fail:
yading@11 230 if (f)
yading@11 231 avio_close(f);
yading@11 232 if (err)
yading@11 233 fprintf(stderr, "Unable to read the MFRA atom in %s\n", file);
yading@11 234 return err;
yading@11 235 }
yading@11 236
yading@11 237 static int get_private_data(struct Track *track, AVCodecContext *codec)
yading@11 238 {
yading@11 239 track->codec_private_size = codec->extradata_size;
yading@11 240 track->codec_private = av_mallocz(codec->extradata_size);
yading@11 241 if (!track->codec_private)
yading@11 242 return AVERROR(ENOMEM);
yading@11 243 memcpy(track->codec_private, codec->extradata, codec->extradata_size);
yading@11 244 return 0;
yading@11 245 }
yading@11 246
yading@11 247 static int get_video_private_data(struct Track *track, AVCodecContext *codec)
yading@11 248 {
yading@11 249 AVIOContext *io = NULL;
yading@11 250 uint16_t sps_size, pps_size;
yading@11 251 int err = AVERROR(EINVAL);
yading@11 252
yading@11 253 if (codec->codec_id == AV_CODEC_ID_VC1)
yading@11 254 return get_private_data(track, codec);
yading@11 255
yading@11 256 if (avio_open_dyn_buf(&io) < 0) {
yading@11 257 err = AVERROR(ENOMEM);
yading@11 258 goto fail;
yading@11 259 }
yading@11 260 if (codec->extradata_size < 11 || codec->extradata[0] != 1)
yading@11 261 goto fail;
yading@11 262 sps_size = AV_RB16(&codec->extradata[6]);
yading@11 263 if (11 + sps_size > codec->extradata_size)
yading@11 264 goto fail;
yading@11 265 avio_wb32(io, 0x00000001);
yading@11 266 avio_write(io, &codec->extradata[8], sps_size);
yading@11 267 pps_size = AV_RB16(&codec->extradata[9 + sps_size]);
yading@11 268 if (11 + sps_size + pps_size > codec->extradata_size)
yading@11 269 goto fail;
yading@11 270 avio_wb32(io, 0x00000001);
yading@11 271 avio_write(io, &codec->extradata[11 + sps_size], pps_size);
yading@11 272 err = 0;
yading@11 273
yading@11 274 fail:
yading@11 275 track->codec_private_size = avio_close_dyn_buf(io, &track->codec_private);
yading@11 276 return err;
yading@11 277 }
yading@11 278
yading@11 279 static int handle_file(struct Tracks *tracks, const char *file, int split)
yading@11 280 {
yading@11 281 AVFormatContext *ctx = NULL;
yading@11 282 int err = 0, i, orig_tracks = tracks->nb_tracks;
yading@11 283 char errbuf[50], *ptr;
yading@11 284 struct Track *track;
yading@11 285
yading@11 286 err = avformat_open_input(&ctx, file, NULL, NULL);
yading@11 287 if (err < 0) {
yading@11 288 av_strerror(err, errbuf, sizeof(errbuf));
yading@11 289 fprintf(stderr, "Unable to open %s: %s\n", file, errbuf);
yading@11 290 return 1;
yading@11 291 }
yading@11 292
yading@11 293 err = avformat_find_stream_info(ctx, NULL);
yading@11 294 if (err < 0) {
yading@11 295 av_strerror(err, errbuf, sizeof(errbuf));
yading@11 296 fprintf(stderr, "Unable to identify %s: %s\n", file, errbuf);
yading@11 297 goto fail;
yading@11 298 }
yading@11 299
yading@11 300 if (ctx->nb_streams < 1) {
yading@11 301 fprintf(stderr, "No streams found in %s\n", file);
yading@11 302 goto fail;
yading@11 303 }
yading@11 304 if (!tracks->duration)
yading@11 305 tracks->duration = ctx->duration;
yading@11 306
yading@11 307 for (i = 0; i < ctx->nb_streams; i++) {
yading@11 308 struct Track **temp;
yading@11 309 AVStream *st = ctx->streams[i];
yading@11 310 track = av_mallocz(sizeof(*track));
yading@11 311 if (!track) {
yading@11 312 err = AVERROR(ENOMEM);
yading@11 313 goto fail;
yading@11 314 }
yading@11 315 temp = av_realloc(tracks->tracks,
yading@11 316 sizeof(*tracks->tracks) * (tracks->nb_tracks + 1));
yading@11 317 if (!temp) {
yading@11 318 av_free(track);
yading@11 319 err = AVERROR(ENOMEM);
yading@11 320 goto fail;
yading@11 321 }
yading@11 322 tracks->tracks = temp;
yading@11 323 tracks->tracks[tracks->nb_tracks] = track;
yading@11 324
yading@11 325 track->name = file;
yading@11 326 if ((ptr = strrchr(file, '/')) != NULL)
yading@11 327 track->name = ptr + 1;
yading@11 328
yading@11 329 track->bitrate = st->codec->bit_rate;
yading@11 330 track->track_id = st->id;
yading@11 331 track->timescale = st->time_base.den;
yading@11 332 track->duration = av_rescale_rnd(ctx->duration, track->timescale,
yading@11 333 AV_TIME_BASE, AV_ROUND_UP);
yading@11 334 track->is_audio = st->codec->codec_type == AVMEDIA_TYPE_AUDIO;
yading@11 335 track->is_video = st->codec->codec_type == AVMEDIA_TYPE_VIDEO;
yading@11 336
yading@11 337 if (!track->is_audio && !track->is_video) {
yading@11 338 fprintf(stderr,
yading@11 339 "Track %d in %s is neither video nor audio, skipping\n",
yading@11 340 track->track_id, file);
yading@11 341 av_freep(&tracks->tracks[tracks->nb_tracks]);
yading@11 342 continue;
yading@11 343 }
yading@11 344
yading@11 345 if (track->is_audio) {
yading@11 346 if (tracks->audio_track < 0)
yading@11 347 tracks->audio_track = tracks->nb_tracks;
yading@11 348 tracks->nb_audio_tracks++;
yading@11 349 track->channels = st->codec->channels;
yading@11 350 track->sample_rate = st->codec->sample_rate;
yading@11 351 if (st->codec->codec_id == AV_CODEC_ID_AAC) {
yading@11 352 track->fourcc = "AACL";
yading@11 353 track->tag = 255;
yading@11 354 track->blocksize = 4;
yading@11 355 } else if (st->codec->codec_id == AV_CODEC_ID_WMAPRO) {
yading@11 356 track->fourcc = "WMAP";
yading@11 357 track->tag = st->codec->codec_tag;
yading@11 358 track->blocksize = st->codec->block_align;
yading@11 359 }
yading@11 360 get_private_data(track, st->codec);
yading@11 361 }
yading@11 362 if (track->is_video) {
yading@11 363 if (tracks->video_track < 0)
yading@11 364 tracks->video_track = tracks->nb_tracks;
yading@11 365 tracks->nb_video_tracks++;
yading@11 366 track->width = st->codec->width;
yading@11 367 track->height = st->codec->height;
yading@11 368 if (st->codec->codec_id == AV_CODEC_ID_H264)
yading@11 369 track->fourcc = "H264";
yading@11 370 else if (st->codec->codec_id == AV_CODEC_ID_VC1)
yading@11 371 track->fourcc = "WVC1";
yading@11 372 get_video_private_data(track, st->codec);
yading@11 373 }
yading@11 374
yading@11 375 tracks->nb_tracks++;
yading@11 376 }
yading@11 377
yading@11 378 avformat_close_input(&ctx);
yading@11 379
yading@11 380 err = read_mfra(tracks, orig_tracks, file, split);
yading@11 381
yading@11 382 fail:
yading@11 383 if (ctx)
yading@11 384 avformat_close_input(&ctx);
yading@11 385 return err;
yading@11 386 }
yading@11 387
yading@11 388 static void output_server_manifest(struct Tracks *tracks,
yading@11 389 const char *basename)
yading@11 390 {
yading@11 391 char filename[1000];
yading@11 392 FILE *out;
yading@11 393 int i;
yading@11 394
yading@11 395 snprintf(filename, sizeof(filename), "%s.ism", basename);
yading@11 396 out = fopen(filename, "w");
yading@11 397 if (!out) {
yading@11 398 perror(filename);
yading@11 399 return;
yading@11 400 }
yading@11 401 fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
yading@11 402 fprintf(out, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
yading@11 403 fprintf(out, "\t<head>\n");
yading@11 404 fprintf(out, "\t\t<meta name=\"clientManifestRelativePath\" "
yading@11 405 "content=\"%s.ismc\" />\n", basename);
yading@11 406 fprintf(out, "\t</head>\n");
yading@11 407 fprintf(out, "\t<body>\n");
yading@11 408 fprintf(out, "\t\t<switch>\n");
yading@11 409 for (i = 0; i < tracks->nb_tracks; i++) {
yading@11 410 struct Track *track = tracks->tracks[i];
yading@11 411 const char *type = track->is_video ? "video" : "audio";
yading@11 412 fprintf(out, "\t\t\t<%s src=\"%s\" systemBitrate=\"%d\">\n",
yading@11 413 type, track->name, track->bitrate);
yading@11 414 fprintf(out, "\t\t\t\t<param name=\"trackID\" value=\"%d\" "
yading@11 415 "valueType=\"data\" />\n", track->track_id);
yading@11 416 fprintf(out, "\t\t\t</%s>\n", type);
yading@11 417 }
yading@11 418 fprintf(out, "\t\t</switch>\n");
yading@11 419 fprintf(out, "\t</body>\n");
yading@11 420 fprintf(out, "</smil>\n");
yading@11 421 fclose(out);
yading@11 422 }
yading@11 423
yading@11 424 static void print_track_chunks(FILE *out, struct Tracks *tracks, int main,
yading@11 425 const char *type)
yading@11 426 {
yading@11 427 int i, j;
yading@11 428 struct Track *track = tracks->tracks[main];
yading@11 429 for (i = 0; i < track->chunks; i++) {
yading@11 430 for (j = main + 1; j < tracks->nb_tracks; j++) {
yading@11 431 if (tracks->tracks[j]->is_audio == track->is_audio &&
yading@11 432 track->offsets[i].duration != tracks->tracks[j]->offsets[i].duration)
yading@11 433 fprintf(stderr, "Mismatched duration of %s chunk %d in %s and %s\n",
yading@11 434 type, i, track->name, tracks->tracks[j]->name);
yading@11 435 }
yading@11 436 fprintf(out, "\t\t<c n=\"%d\" d=\"%d\" />\n",
yading@11 437 i, track->offsets[i].duration);
yading@11 438 }
yading@11 439 }
yading@11 440
yading@11 441 static void output_client_manifest(struct Tracks *tracks,
yading@11 442 const char *basename, int split)
yading@11 443 {
yading@11 444 char filename[1000];
yading@11 445 FILE *out;
yading@11 446 int i, j;
yading@11 447
yading@11 448 if (split)
yading@11 449 snprintf(filename, sizeof(filename), "Manifest");
yading@11 450 else
yading@11 451 snprintf(filename, sizeof(filename), "%s.ismc", basename);
yading@11 452 out = fopen(filename, "w");
yading@11 453 if (!out) {
yading@11 454 perror(filename);
yading@11 455 return;
yading@11 456 }
yading@11 457 fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
yading@11 458 fprintf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" "
yading@11 459 "Duration=\"%"PRId64 "\">\n", tracks->duration * 10);
yading@11 460 if (tracks->video_track >= 0) {
yading@11 461 struct Track *track = tracks->tracks[tracks->video_track];
yading@11 462 struct Track *first_track = track;
yading@11 463 int index = 0;
yading@11 464 fprintf(out,
yading@11 465 "\t<StreamIndex Type=\"video\" QualityLevels=\"%d\" "
yading@11 466 "Chunks=\"%d\" "
yading@11 467 "Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n",
yading@11 468 tracks->nb_video_tracks, track->chunks);
yading@11 469 for (i = 0; i < tracks->nb_tracks; i++) {
yading@11 470 track = tracks->tracks[i];
yading@11 471 if (!track->is_video)
yading@11 472 continue;
yading@11 473 fprintf(out,
yading@11 474 "\t\t<QualityLevel Index=\"%d\" Bitrate=\"%d\" "
yading@11 475 "FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" "
yading@11 476 "CodecPrivateData=\"",
yading@11 477 index, track->bitrate, track->fourcc, track->width, track->height);
yading@11 478 for (j = 0; j < track->codec_private_size; j++)
yading@11 479 fprintf(out, "%02X", track->codec_private[j]);
yading@11 480 fprintf(out, "\" />\n");
yading@11 481 index++;
yading@11 482 if (track->chunks != first_track->chunks)
yading@11 483 fprintf(stderr, "Mismatched number of video chunks in %s and %s\n",
yading@11 484 track->name, first_track->name);
yading@11 485 }
yading@11 486 print_track_chunks(out, tracks, tracks->video_track, "video");
yading@11 487 fprintf(out, "\t</StreamIndex>\n");
yading@11 488 }
yading@11 489 if (tracks->audio_track >= 0) {
yading@11 490 struct Track *track = tracks->tracks[tracks->audio_track];
yading@11 491 struct Track *first_track = track;
yading@11 492 int index = 0;
yading@11 493 fprintf(out,
yading@11 494 "\t<StreamIndex Type=\"audio\" QualityLevels=\"%d\" "
yading@11 495 "Chunks=\"%d\" "
yading@11 496 "Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n",
yading@11 497 tracks->nb_audio_tracks, track->chunks);
yading@11 498 for (i = 0; i < tracks->nb_tracks; i++) {
yading@11 499 track = tracks->tracks[i];
yading@11 500 if (!track->is_audio)
yading@11 501 continue;
yading@11 502 fprintf(out,
yading@11 503 "\t\t<QualityLevel Index=\"%d\" Bitrate=\"%d\" "
yading@11 504 "FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" "
yading@11 505 "BitsPerSample=\"16\" PacketSize=\"%d\" "
yading@11 506 "AudioTag=\"%d\" CodecPrivateData=\"",
yading@11 507 index, track->bitrate, track->fourcc, track->sample_rate,
yading@11 508 track->channels, track->blocksize, track->tag);
yading@11 509 for (j = 0; j < track->codec_private_size; j++)
yading@11 510 fprintf(out, "%02X", track->codec_private[j]);
yading@11 511 fprintf(out, "\" />\n");
yading@11 512 index++;
yading@11 513 if (track->chunks != first_track->chunks)
yading@11 514 fprintf(stderr, "Mismatched number of audio chunks in %s and %s\n",
yading@11 515 track->name, first_track->name);
yading@11 516 }
yading@11 517 print_track_chunks(out, tracks, tracks->audio_track, "audio");
yading@11 518 fprintf(out, "\t</StreamIndex>\n");
yading@11 519 }
yading@11 520 fprintf(out, "</SmoothStreamingMedia>\n");
yading@11 521 fclose(out);
yading@11 522 }
yading@11 523
yading@11 524 static void clean_tracks(struct Tracks *tracks)
yading@11 525 {
yading@11 526 int i;
yading@11 527 for (i = 0; i < tracks->nb_tracks; i++) {
yading@11 528 av_freep(&tracks->tracks[i]->codec_private);
yading@11 529 av_freep(&tracks->tracks[i]->offsets);
yading@11 530 av_freep(&tracks->tracks[i]);
yading@11 531 }
yading@11 532 av_freep(&tracks->tracks);
yading@11 533 tracks->nb_tracks = 0;
yading@11 534 }
yading@11 535
yading@11 536 int main(int argc, char **argv)
yading@11 537 {
yading@11 538 const char *basename = NULL;
yading@11 539 int split = 0, i;
yading@11 540 struct Tracks tracks = { 0, .video_track = -1, .audio_track = -1 };
yading@11 541
yading@11 542 av_register_all();
yading@11 543
yading@11 544 for (i = 1; i < argc; i++) {
yading@11 545 if (!strcmp(argv[i], "-n")) {
yading@11 546 basename = argv[i + 1];
yading@11 547 i++;
yading@11 548 } else if (!strcmp(argv[i], "-split")) {
yading@11 549 split = 1;
yading@11 550 } else if (argv[i][0] == '-') {
yading@11 551 return usage(argv[0], 1);
yading@11 552 } else {
yading@11 553 if (handle_file(&tracks, argv[i], split))
yading@11 554 return 1;
yading@11 555 }
yading@11 556 }
yading@11 557 if (!tracks.nb_tracks || (!basename && !split))
yading@11 558 return usage(argv[0], 1);
yading@11 559
yading@11 560 if (!split)
yading@11 561 output_server_manifest(&tracks, basename);
yading@11 562 output_client_manifest(&tracks, basename, split);
yading@11 563
yading@11 564 clean_tracks(&tracks);
yading@11 565
yading@11 566 return 0;
yading@11 567 }