annotate ffmpeg/libavformat/oggdec.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 * Ogg bitstream support
yading@11 3 * Luca Barbato <lu_zero@gentoo.org>
yading@11 4 * Based on tcvp implementation
yading@11 5 */
yading@11 6
yading@11 7 /*
yading@11 8 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
yading@11 9
yading@11 10 Permission is hereby granted, free of charge, to any person
yading@11 11 obtaining a copy of this software and associated documentation
yading@11 12 files (the "Software"), to deal in the Software without
yading@11 13 restriction, including without limitation the rights to use, copy,
yading@11 14 modify, merge, publish, distribute, sublicense, and/or sell copies
yading@11 15 of the Software, and to permit persons to whom the Software is
yading@11 16 furnished to do so, subject to the following conditions:
yading@11 17
yading@11 18 The above copyright notice and this permission notice shall be
yading@11 19 included in all copies or substantial portions of the Software.
yading@11 20
yading@11 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
yading@11 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
yading@11 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
yading@11 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
yading@11 25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
yading@11 26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
yading@11 27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
yading@11 28 DEALINGS IN THE SOFTWARE.
yading@11 29 */
yading@11 30
yading@11 31 #include <stdio.h>
yading@11 32 #include "libavutil/avassert.h"
yading@11 33 #include "oggdec.h"
yading@11 34 #include "avformat.h"
yading@11 35 #include "internal.h"
yading@11 36 #include "vorbiscomment.h"
yading@11 37
yading@11 38 #define MAX_PAGE_SIZE 65307
yading@11 39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
yading@11 40
yading@11 41 static const struct ogg_codec * const ogg_codecs[] = {
yading@11 42 &ff_skeleton_codec,
yading@11 43 &ff_dirac_codec,
yading@11 44 &ff_speex_codec,
yading@11 45 &ff_vorbis_codec,
yading@11 46 &ff_theora_codec,
yading@11 47 &ff_flac_codec,
yading@11 48 &ff_celt_codec,
yading@11 49 &ff_opus_codec,
yading@11 50 &ff_old_dirac_codec,
yading@11 51 &ff_old_flac_codec,
yading@11 52 &ff_ogm_video_codec,
yading@11 53 &ff_ogm_audio_codec,
yading@11 54 &ff_ogm_text_codec,
yading@11 55 &ff_ogm_old_codec,
yading@11 56 NULL
yading@11 57 };
yading@11 58
yading@11 59 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
yading@11 60 static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
yading@11 61
yading@11 62 //FIXME We could avoid some structure duplication
yading@11 63 static int ogg_save(AVFormatContext *s)
yading@11 64 {
yading@11 65 struct ogg *ogg = s->priv_data;
yading@11 66 struct ogg_state *ost =
yading@11 67 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
yading@11 68 int i;
yading@11 69 ost->pos = avio_tell(s->pb);
yading@11 70 ost->curidx = ogg->curidx;
yading@11 71 ost->next = ogg->state;
yading@11 72 ost->nstreams = ogg->nstreams;
yading@11 73 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
yading@11 74
yading@11 75 for (i = 0; i < ogg->nstreams; i++) {
yading@11 76 struct ogg_stream *os = ogg->streams + i;
yading@11 77 os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 78 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
yading@11 79 }
yading@11 80
yading@11 81 ogg->state = ost;
yading@11 82
yading@11 83 return 0;
yading@11 84 }
yading@11 85
yading@11 86 static int ogg_restore(AVFormatContext *s, int discard)
yading@11 87 {
yading@11 88 struct ogg *ogg = s->priv_data;
yading@11 89 AVIOContext *bc = s->pb;
yading@11 90 struct ogg_state *ost = ogg->state;
yading@11 91 int i;
yading@11 92
yading@11 93 if (!ost)
yading@11 94 return 0;
yading@11 95
yading@11 96 ogg->state = ost->next;
yading@11 97
yading@11 98 if (!discard) {
yading@11 99 struct ogg_stream *old_streams = ogg->streams;
yading@11 100
yading@11 101 for (i = 0; i < ogg->nstreams; i++)
yading@11 102 av_free(ogg->streams[i].buf);
yading@11 103
yading@11 104 avio_seek(bc, ost->pos, SEEK_SET);
yading@11 105 ogg->page_pos = -1;
yading@11 106 ogg->curidx = ost->curidx;
yading@11 107 ogg->nstreams = ost->nstreams;
yading@11 108 ogg->streams = av_realloc(ogg->streams,
yading@11 109 ogg->nstreams * sizeof(*ogg->streams));
yading@11 110
yading@11 111 if (ogg->streams) {
yading@11 112 memcpy(ogg->streams, ost->streams,
yading@11 113 ost->nstreams * sizeof(*ogg->streams));
yading@11 114 } else {
yading@11 115 av_free(old_streams);
yading@11 116 ogg->nstreams = 0;
yading@11 117 }
yading@11 118 }
yading@11 119
yading@11 120 av_free(ost);
yading@11 121
yading@11 122 return 0;
yading@11 123 }
yading@11 124
yading@11 125 static int ogg_reset(AVFormatContext *s)
yading@11 126 {
yading@11 127 struct ogg *ogg = s->priv_data;
yading@11 128 int i;
yading@11 129 int64_t start_pos = avio_tell(s->pb);
yading@11 130
yading@11 131 for (i = 0; i < ogg->nstreams; i++) {
yading@11 132 struct ogg_stream *os = ogg->streams + i;
yading@11 133 os->bufpos = 0;
yading@11 134 os->pstart = 0;
yading@11 135 os->psize = 0;
yading@11 136 os->granule = -1;
yading@11 137 os->lastpts = AV_NOPTS_VALUE;
yading@11 138 os->lastdts = AV_NOPTS_VALUE;
yading@11 139 os->sync_pos = -1;
yading@11 140 os->page_pos = 0;
yading@11 141 os->nsegs = 0;
yading@11 142 os->segp = 0;
yading@11 143 os->incomplete = 0;
yading@11 144 os->got_data = 0;
yading@11 145 if (start_pos <= s->data_offset) {
yading@11 146 os->lastpts = 0;
yading@11 147 }
yading@11 148 }
yading@11 149
yading@11 150 ogg->page_pos = -1;
yading@11 151 ogg->curidx = -1;
yading@11 152
yading@11 153 return 0;
yading@11 154 }
yading@11 155
yading@11 156 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
yading@11 157 {
yading@11 158 int i;
yading@11 159
yading@11 160 for (i = 0; ogg_codecs[i]; i++)
yading@11 161 if (size >= ogg_codecs[i]->magicsize &&
yading@11 162 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
yading@11 163 return ogg_codecs[i];
yading@11 164
yading@11 165 return NULL;
yading@11 166 }
yading@11 167
yading@11 168 /**
yading@11 169 * Replace the current stream with a new one. This is a typical webradio
yading@11 170 * situation where a new audio stream spawn (identified with a new serial) and
yading@11 171 * must replace the previous one (track switch).
yading@11 172 */
yading@11 173 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
yading@11 174 {
yading@11 175 struct ogg *ogg = s->priv_data;
yading@11 176 struct ogg_stream *os;
yading@11 177 const struct ogg_codec *codec;
yading@11 178 int i = 0;
yading@11 179
yading@11 180 if (s->pb->seekable) {
yading@11 181 uint8_t magic[8];
yading@11 182 int64_t pos = avio_tell(s->pb);
yading@11 183 avio_skip(s->pb, nsegs);
yading@11 184 avio_read(s->pb, magic, sizeof(magic));
yading@11 185 avio_seek(s->pb, pos, SEEK_SET);
yading@11 186 codec = ogg_find_codec(magic, sizeof(magic));
yading@11 187 if (!codec) {
yading@11 188 av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
yading@11 189 return AVERROR_INVALIDDATA;
yading@11 190 }
yading@11 191 for (i = 0; i < ogg->nstreams; i++) {
yading@11 192 if (ogg->streams[i].codec == codec)
yading@11 193 break;
yading@11 194 }
yading@11 195 if (i >= ogg->nstreams)
yading@11 196 return ogg_new_stream(s, serial);
yading@11 197 } else if (ogg->nstreams != 1) {
yading@11 198 avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
yading@11 199 return AVERROR_PATCHWELCOME;
yading@11 200 }
yading@11 201
yading@11 202 os = &ogg->streams[i];
yading@11 203
yading@11 204 os->serial = serial;
yading@11 205 return i;
yading@11 206
yading@11 207 #if 0
yading@11 208 buf = os->buf;
yading@11 209 bufsize = os->bufsize;
yading@11 210 codec = os->codec;
yading@11 211
yading@11 212 if (!ogg->state || ogg->state->streams[i].private != os->private)
yading@11 213 av_freep(&ogg->streams[i].private);
yading@11 214
yading@11 215 /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
yading@11 216 * also re-use the ogg_stream allocated buffer */
yading@11 217 memset(os, 0, sizeof(*os));
yading@11 218 os->serial = serial;
yading@11 219 os->bufsize = bufsize;
yading@11 220 os->buf = buf;
yading@11 221 os->header = -1;
yading@11 222 os->codec = codec;
yading@11 223
yading@11 224 return i;
yading@11 225 #endif
yading@11 226 }
yading@11 227
yading@11 228 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
yading@11 229 {
yading@11 230 struct ogg *ogg = s->priv_data;
yading@11 231 int idx = ogg->nstreams;
yading@11 232 AVStream *st;
yading@11 233 struct ogg_stream *os;
yading@11 234 size_t size;
yading@11 235
yading@11 236 if (ogg->state) {
yading@11 237 av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
yading@11 238 "in between Ogg context save/restore operations.\n");
yading@11 239 return AVERROR_BUG;
yading@11 240 }
yading@11 241
yading@11 242 /* Allocate and init a new Ogg Stream */
yading@11 243 if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
yading@11 244 !(os = av_realloc(ogg->streams, size)))
yading@11 245 return AVERROR(ENOMEM);
yading@11 246 ogg->streams = os;
yading@11 247 os = ogg->streams + idx;
yading@11 248 memset(os, 0, sizeof(*os));
yading@11 249 os->serial = serial;
yading@11 250 os->bufsize = DECODER_BUFFER_SIZE;
yading@11 251 os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 252 os->header = -1;
yading@11 253 os->start_granule = OGG_NOGRANULE_VALUE;
yading@11 254 if (!os->buf)
yading@11 255 return AVERROR(ENOMEM);
yading@11 256
yading@11 257 /* Create the associated AVStream */
yading@11 258 st = avformat_new_stream(s, NULL);
yading@11 259 if (!st) {
yading@11 260 av_freep(&os->buf);
yading@11 261 return AVERROR(ENOMEM);
yading@11 262 }
yading@11 263 st->id = idx;
yading@11 264 avpriv_set_pts_info(st, 64, 1, 1000000);
yading@11 265
yading@11 266 ogg->nstreams++;
yading@11 267 return idx;
yading@11 268 }
yading@11 269
yading@11 270 static int ogg_new_buf(struct ogg *ogg, int idx)
yading@11 271 {
yading@11 272 struct ogg_stream *os = ogg->streams + idx;
yading@11 273 uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 274 int size = os->bufpos - os->pstart;
yading@11 275
yading@11 276 if (os->buf) {
yading@11 277 memcpy(nb, os->buf + os->pstart, size);
yading@11 278 av_free(os->buf);
yading@11 279 }
yading@11 280
yading@11 281 os->buf = nb;
yading@11 282 os->bufpos = size;
yading@11 283 os->pstart = 0;
yading@11 284
yading@11 285 return 0;
yading@11 286 }
yading@11 287
yading@11 288 static int data_packets_seen(const struct ogg *ogg)
yading@11 289 {
yading@11 290 int i;
yading@11 291
yading@11 292 for (i = 0; i < ogg->nstreams; i++)
yading@11 293 if (ogg->streams[i].got_data)
yading@11 294 return 1;
yading@11 295 return 0;
yading@11 296 }
yading@11 297
yading@11 298 static int ogg_read_page(AVFormatContext *s, int *sid)
yading@11 299 {
yading@11 300 AVIOContext *bc = s->pb;
yading@11 301 struct ogg *ogg = s->priv_data;
yading@11 302 struct ogg_stream *os;
yading@11 303 int ret, i = 0;
yading@11 304 int flags, nsegs;
yading@11 305 uint64_t gp;
yading@11 306 uint32_t serial;
yading@11 307 int size, idx;
yading@11 308 uint8_t sync[4];
yading@11 309 int sp = 0;
yading@11 310
yading@11 311 ret = avio_read(bc, sync, 4);
yading@11 312 if (ret < 4)
yading@11 313 return ret < 0 ? ret : AVERROR_EOF;
yading@11 314
yading@11 315 do {
yading@11 316 int c;
yading@11 317
yading@11 318 if (sync[sp & 3] == 'O' &&
yading@11 319 sync[(sp + 1) & 3] == 'g' &&
yading@11 320 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
yading@11 321 break;
yading@11 322
yading@11 323 if(!i && bc->seekable && ogg->page_pos > 0) {
yading@11 324 memset(sync, 0, 4);
yading@11 325 avio_seek(bc, ogg->page_pos+4, SEEK_SET);
yading@11 326 ogg->page_pos = -1;
yading@11 327 }
yading@11 328
yading@11 329 c = avio_r8(bc);
yading@11 330
yading@11 331 if (url_feof(bc))
yading@11 332 return AVERROR_EOF;
yading@11 333
yading@11 334 sync[sp++ & 3] = c;
yading@11 335 } while (i++ < MAX_PAGE_SIZE);
yading@11 336
yading@11 337 if (i >= MAX_PAGE_SIZE) {
yading@11 338 av_log(s, AV_LOG_INFO, "cannot find sync word\n");
yading@11 339 return AVERROR_INVALIDDATA;
yading@11 340 }
yading@11 341
yading@11 342 if (avio_r8(bc) != 0) { /* version */
yading@11 343 av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
yading@11 344 return AVERROR_INVALIDDATA;
yading@11 345 }
yading@11 346
yading@11 347 flags = avio_r8(bc);
yading@11 348 gp = avio_rl64(bc);
yading@11 349 serial = avio_rl32(bc);
yading@11 350 avio_skip(bc, 8); /* seq, crc */
yading@11 351 nsegs = avio_r8(bc);
yading@11 352
yading@11 353 idx = ogg_find_stream(ogg, serial);
yading@11 354 if (idx < 0) {
yading@11 355 if (data_packets_seen(ogg))
yading@11 356 idx = ogg_replace_stream(s, serial, nsegs);
yading@11 357 else
yading@11 358 idx = ogg_new_stream(s, serial);
yading@11 359
yading@11 360 if (idx < 0) {
yading@11 361 av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
yading@11 362 return idx;
yading@11 363 }
yading@11 364 }
yading@11 365
yading@11 366 os = ogg->streams + idx;
yading@11 367 ogg->page_pos =
yading@11 368 os->page_pos = avio_tell(bc) - 27;
yading@11 369
yading@11 370 if (os->psize > 0)
yading@11 371 ogg_new_buf(ogg, idx);
yading@11 372
yading@11 373 ret = avio_read(bc, os->segments, nsegs);
yading@11 374 if (ret < nsegs)
yading@11 375 return ret < 0 ? ret : AVERROR_EOF;
yading@11 376
yading@11 377 os->nsegs = nsegs;
yading@11 378 os->segp = 0;
yading@11 379
yading@11 380 size = 0;
yading@11 381 for (i = 0; i < nsegs; i++)
yading@11 382 size += os->segments[i];
yading@11 383
yading@11 384 if (!(flags & OGG_FLAG_BOS))
yading@11 385 os->got_data = 1;
yading@11 386
yading@11 387 if (flags & OGG_FLAG_CONT || os->incomplete) {
yading@11 388 if (!os->psize) {
yading@11 389 // If this is the very first segment we started
yading@11 390 // playback in the middle of a continuation packet.
yading@11 391 // Discard it since we missed the start of it.
yading@11 392 while (os->segp < os->nsegs) {
yading@11 393 int seg = os->segments[os->segp++];
yading@11 394 os->pstart += seg;
yading@11 395 if (seg < 255)
yading@11 396 break;
yading@11 397 }
yading@11 398 os->sync_pos = os->page_pos;
yading@11 399 }
yading@11 400 } else {
yading@11 401 os->psize = 0;
yading@11 402 os->sync_pos = os->page_pos;
yading@11 403 }
yading@11 404
yading@11 405 if (os->bufsize - os->bufpos < size) {
yading@11 406 uint8_t *nb = av_malloc((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 407 if (!nb)
yading@11 408 return AVERROR(ENOMEM);
yading@11 409 memcpy(nb, os->buf, os->bufpos);
yading@11 410 av_free(os->buf);
yading@11 411 os->buf = nb;
yading@11 412 }
yading@11 413
yading@11 414 ret = avio_read(bc, os->buf + os->bufpos, size);
yading@11 415 if (ret < size)
yading@11 416 return ret < 0 ? ret : AVERROR_EOF;
yading@11 417
yading@11 418 os->bufpos += size;
yading@11 419 os->granule = gp;
yading@11 420 os->flags = flags;
yading@11 421
yading@11 422 memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 423 if (sid)
yading@11 424 *sid = idx;
yading@11 425
yading@11 426 return 0;
yading@11 427 }
yading@11 428
yading@11 429 /**
yading@11 430 * @brief find the next Ogg packet
yading@11 431 * @param *sid is set to the stream for the packet or -1 if there is
yading@11 432 * no matching stream, in that case assume all other return
yading@11 433 * values to be uninitialized.
yading@11 434 * @return negative value on error or EOF.
yading@11 435 */
yading@11 436 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
yading@11 437 int64_t *fpos)
yading@11 438 {
yading@11 439 struct ogg *ogg = s->priv_data;
yading@11 440 int idx, i, ret;
yading@11 441 struct ogg_stream *os;
yading@11 442 int complete = 0;
yading@11 443 int segp = 0, psize = 0;
yading@11 444
yading@11 445 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
yading@11 446 if (sid)
yading@11 447 *sid = -1;
yading@11 448
yading@11 449 do {
yading@11 450 idx = ogg->curidx;
yading@11 451
yading@11 452 while (idx < 0) {
yading@11 453 ret = ogg_read_page(s, &idx);
yading@11 454 if (ret < 0)
yading@11 455 return ret;
yading@11 456 }
yading@11 457
yading@11 458 os = ogg->streams + idx;
yading@11 459
yading@11 460 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
yading@11 461 idx, os->pstart, os->psize, os->segp, os->nsegs);
yading@11 462
yading@11 463 if (!os->codec) {
yading@11 464 if (os->header < 0) {
yading@11 465 os->codec = ogg_find_codec(os->buf, os->bufpos);
yading@11 466 if (!os->codec) {
yading@11 467 av_log(s, AV_LOG_WARNING, "Codec not found\n");
yading@11 468 os->header = 0;
yading@11 469 return 0;
yading@11 470 }
yading@11 471 } else {
yading@11 472 return 0;
yading@11 473 }
yading@11 474 }
yading@11 475
yading@11 476 segp = os->segp;
yading@11 477 psize = os->psize;
yading@11 478
yading@11 479 while (os->segp < os->nsegs) {
yading@11 480 int ss = os->segments[os->segp++];
yading@11 481 os->psize += ss;
yading@11 482 if (ss < 255) {
yading@11 483 complete = 1;
yading@11 484 break;
yading@11 485 }
yading@11 486 }
yading@11 487
yading@11 488 if (!complete && os->segp == os->nsegs) {
yading@11 489 ogg->curidx = -1;
yading@11 490 // Do not set incomplete for empty packets.
yading@11 491 // Together with the code in ogg_read_page
yading@11 492 // that discards all continuation of empty packets
yading@11 493 // we would get an infinite loop.
yading@11 494 os->incomplete = !!os->psize;
yading@11 495 }
yading@11 496 } while (!complete);
yading@11 497
yading@11 498
yading@11 499 if (os->granule == -1)
yading@11 500 av_log(s, AV_LOG_WARNING,
yading@11 501 "Page at %"PRId64" is missing granule\n",
yading@11 502 os->page_pos);
yading@11 503
yading@11 504 ogg->curidx = idx;
yading@11 505 os->incomplete = 0;
yading@11 506
yading@11 507 if (os->header) {
yading@11 508 os->header = os->codec->header(s, idx);
yading@11 509 if (!os->header) {
yading@11 510 os->segp = segp;
yading@11 511 os->psize = psize;
yading@11 512
yading@11 513 // We have reached the first non-header packet in this stream.
yading@11 514 // Unfortunately more header packets may still follow for others,
yading@11 515 // but if we continue with header parsing we may lose data packets.
yading@11 516 ogg->headers = 1;
yading@11 517
yading@11 518 // Update the header state for all streams and
yading@11 519 // compute the data_offset.
yading@11 520 if (!s->data_offset)
yading@11 521 s->data_offset = os->sync_pos;
yading@11 522
yading@11 523 for (i = 0; i < ogg->nstreams; i++) {
yading@11 524 struct ogg_stream *cur_os = ogg->streams + i;
yading@11 525
yading@11 526 // if we have a partial non-header packet, its start is
yading@11 527 // obviously at or after the data start
yading@11 528 if (cur_os->incomplete)
yading@11 529 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
yading@11 530 }
yading@11 531 } else {
yading@11 532 os->nb_header++;
yading@11 533 os->pstart += os->psize;
yading@11 534 os->psize = 0;
yading@11 535 }
yading@11 536 } else {
yading@11 537 os->pflags = 0;
yading@11 538 os->pduration = 0;
yading@11 539 if (os->codec && os->codec->packet)
yading@11 540 os->codec->packet(s, idx);
yading@11 541 if (sid)
yading@11 542 *sid = idx;
yading@11 543 if (dstart)
yading@11 544 *dstart = os->pstart;
yading@11 545 if (dsize)
yading@11 546 *dsize = os->psize;
yading@11 547 if (fpos)
yading@11 548 *fpos = os->sync_pos;
yading@11 549 os->pstart += os->psize;
yading@11 550 os->psize = 0;
yading@11 551 if(os->pstart == os->bufpos)
yading@11 552 os->bufpos = os->pstart = 0;
yading@11 553 os->sync_pos = os->page_pos;
yading@11 554 }
yading@11 555
yading@11 556 // determine whether there are more complete packets in this page
yading@11 557 // if not, the page's granule will apply to this packet
yading@11 558 os->page_end = 1;
yading@11 559 for (i = os->segp; i < os->nsegs; i++)
yading@11 560 if (os->segments[i] < 255) {
yading@11 561 os->page_end = 0;
yading@11 562 break;
yading@11 563 }
yading@11 564
yading@11 565 if (os->segp == os->nsegs)
yading@11 566 ogg->curidx = -1;
yading@11 567
yading@11 568 return 0;
yading@11 569 }
yading@11 570
yading@11 571 static int ogg_get_length(AVFormatContext *s)
yading@11 572 {
yading@11 573 struct ogg *ogg = s->priv_data;
yading@11 574 int i;
yading@11 575 int64_t size, end;
yading@11 576 int streams_left=0;
yading@11 577
yading@11 578 if (!s->pb->seekable)
yading@11 579 return 0;
yading@11 580
yading@11 581 // already set
yading@11 582 if (s->duration != AV_NOPTS_VALUE)
yading@11 583 return 0;
yading@11 584
yading@11 585 size = avio_size(s->pb);
yading@11 586 if (size < 0)
yading@11 587 return 0;
yading@11 588 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
yading@11 589
yading@11 590 ogg_save(s);
yading@11 591 avio_seek(s->pb, end, SEEK_SET);
yading@11 592 ogg->page_pos = -1;
yading@11 593
yading@11 594 while (!ogg_read_page(s, &i)) {
yading@11 595 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
yading@11 596 ogg->streams[i].codec) {
yading@11 597 s->streams[i]->duration =
yading@11 598 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
yading@11 599 if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
yading@11 600 s->streams[i]->duration -= s->streams[i]->start_time;
yading@11 601 streams_left-= (ogg->streams[i].got_start==-1);
yading@11 602 ogg->streams[i].got_start= 1;
yading@11 603 } else if(!ogg->streams[i].got_start) {
yading@11 604 ogg->streams[i].got_start= -1;
yading@11 605 streams_left++;
yading@11 606 }
yading@11 607 }
yading@11 608 }
yading@11 609
yading@11 610 ogg_restore(s, 0);
yading@11 611
yading@11 612 ogg_save (s);
yading@11 613 avio_seek (s->pb, s->data_offset, SEEK_SET);
yading@11 614 ogg_reset(s);
yading@11 615 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
yading@11 616 int64_t pts;
yading@11 617 if (i < 0) continue;
yading@11 618 pts = ogg_calc_pts(s, i, NULL);
yading@11 619 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
yading@11 620 s->streams[i]->duration -= pts;
yading@11 621 ogg->streams[i].got_start= 1;
yading@11 622 streams_left--;
yading@11 623 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
yading@11 624 ogg->streams[i].got_start= 1;
yading@11 625 streams_left--;
yading@11 626 }
yading@11 627 }
yading@11 628 ogg_restore (s, 0);
yading@11 629
yading@11 630 return 0;
yading@11 631 }
yading@11 632
yading@11 633 static int ogg_read_close(AVFormatContext *s)
yading@11 634 {
yading@11 635 struct ogg *ogg = s->priv_data;
yading@11 636 int i;
yading@11 637
yading@11 638 for (i = 0; i < ogg->nstreams; i++) {
yading@11 639 av_free(ogg->streams[i].buf);
yading@11 640 if (ogg->streams[i].codec &&
yading@11 641 ogg->streams[i].codec->cleanup) {
yading@11 642 ogg->streams[i].codec->cleanup(s, i);
yading@11 643 }
yading@11 644 av_free(ogg->streams[i].private);
yading@11 645 }
yading@11 646 av_free(ogg->streams);
yading@11 647 return 0;
yading@11 648 }
yading@11 649
yading@11 650 static int ogg_read_header(AVFormatContext *s)
yading@11 651 {
yading@11 652 struct ogg *ogg = s->priv_data;
yading@11 653 int ret, i;
yading@11 654
yading@11 655 ogg->curidx = -1;
yading@11 656
yading@11 657 //linear headers seek from start
yading@11 658 do {
yading@11 659 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
yading@11 660 if (ret < 0) {
yading@11 661 ogg_read_close(s);
yading@11 662 return ret;
yading@11 663 }
yading@11 664 } while (!ogg->headers);
yading@11 665 av_dlog(s, "found headers\n");
yading@11 666
yading@11 667 for (i = 0; i < ogg->nstreams; i++) {
yading@11 668 struct ogg_stream *os = ogg->streams + i;
yading@11 669
yading@11 670 if (ogg->streams[i].header < 0) {
yading@11 671 av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
yading@11 672 ogg->streams[i].codec = NULL;
yading@11 673 } else if (os->codec && os->nb_header < os->codec->nb_header) {
yading@11 674 av_log(s, AV_LOG_WARNING, "Number of headers (%d) mismatch for stream %d\n", os->nb_header, i);
yading@11 675 }
yading@11 676 if (os->start_granule != OGG_NOGRANULE_VALUE)
yading@11 677 os->lastpts = s->streams[i]->start_time =
yading@11 678 ogg_gptopts(s, i, os->start_granule, NULL);
yading@11 679 }
yading@11 680
yading@11 681 //linear granulepos seek from end
yading@11 682 ogg_get_length(s);
yading@11 683
yading@11 684 return 0;
yading@11 685 }
yading@11 686
yading@11 687 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
yading@11 688 {
yading@11 689 struct ogg *ogg = s->priv_data;
yading@11 690 struct ogg_stream *os = ogg->streams + idx;
yading@11 691 int64_t pts = AV_NOPTS_VALUE;
yading@11 692
yading@11 693 if (dts)
yading@11 694 *dts = AV_NOPTS_VALUE;
yading@11 695
yading@11 696 if (os->lastpts != AV_NOPTS_VALUE) {
yading@11 697 pts = os->lastpts;
yading@11 698 os->lastpts = AV_NOPTS_VALUE;
yading@11 699 }
yading@11 700 if (os->lastdts != AV_NOPTS_VALUE) {
yading@11 701 if (dts)
yading@11 702 *dts = os->lastdts;
yading@11 703 os->lastdts = AV_NOPTS_VALUE;
yading@11 704 }
yading@11 705 if (os->page_end) {
yading@11 706 if (os->granule != -1LL) {
yading@11 707 if (os->codec && os->codec->granule_is_start)
yading@11 708 pts = ogg_gptopts(s, idx, os->granule, dts);
yading@11 709 else
yading@11 710 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
yading@11 711 os->granule = -1LL;
yading@11 712 }
yading@11 713 }
yading@11 714 return pts;
yading@11 715 }
yading@11 716
yading@11 717 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
yading@11 718 {
yading@11 719 struct ogg *ogg = s->priv_data;
yading@11 720 struct ogg_stream *os = ogg->streams + idx;
yading@11 721 if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) {
yading@11 722 if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
yading@11 723 os->pflags ^= AV_PKT_FLAG_KEY;
yading@11 724 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
yading@11 725 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
yading@11 726 }
yading@11 727 }
yading@11 728 }
yading@11 729
yading@11 730 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 731 {
yading@11 732 struct ogg *ogg;
yading@11 733 struct ogg_stream *os;
yading@11 734 int idx, ret;
yading@11 735 int pstart, psize;
yading@11 736 int64_t fpos, pts, dts;
yading@11 737
yading@11 738 if (s->io_repositioned) {
yading@11 739 ogg_reset(s);
yading@11 740 s->io_repositioned = 0;
yading@11 741 }
yading@11 742
yading@11 743 //Get an ogg packet
yading@11 744 retry:
yading@11 745 do {
yading@11 746 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
yading@11 747 if (ret < 0)
yading@11 748 return ret;
yading@11 749 } while (idx < 0 || !s->streams[idx]);
yading@11 750
yading@11 751 ogg = s->priv_data;
yading@11 752 os = ogg->streams + idx;
yading@11 753
yading@11 754 // pflags might not be set until after this
yading@11 755 pts = ogg_calc_pts(s, idx, &dts);
yading@11 756 ogg_validate_keyframe(s, idx, pstart, psize);
yading@11 757
yading@11 758 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
yading@11 759 goto retry;
yading@11 760 os->keyframe_seek = 0;
yading@11 761
yading@11 762 //Alloc a pkt
yading@11 763 ret = av_new_packet(pkt, psize);
yading@11 764 if (ret < 0)
yading@11 765 return ret;
yading@11 766 pkt->stream_index = idx;
yading@11 767 memcpy(pkt->data, os->buf + pstart, psize);
yading@11 768
yading@11 769 pkt->pts = pts;
yading@11 770 pkt->dts = dts;
yading@11 771 pkt->flags = os->pflags;
yading@11 772 pkt->duration = os->pduration;
yading@11 773 pkt->pos = fpos;
yading@11 774
yading@11 775 return psize;
yading@11 776 }
yading@11 777
yading@11 778 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
yading@11 779 int64_t *pos_arg, int64_t pos_limit)
yading@11 780 {
yading@11 781 struct ogg *ogg = s->priv_data;
yading@11 782 AVIOContext *bc = s->pb;
yading@11 783 int64_t pts = AV_NOPTS_VALUE;
yading@11 784 int64_t keypos = -1;
yading@11 785 int i;
yading@11 786 int pstart, psize;
yading@11 787 avio_seek(bc, *pos_arg, SEEK_SET);
yading@11 788 ogg_reset(s);
yading@11 789
yading@11 790 while ( avio_tell(bc) <= pos_limit
yading@11 791 && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
yading@11 792 if (i == stream_index) {
yading@11 793 struct ogg_stream *os = ogg->streams + stream_index;
yading@11 794 pts = ogg_calc_pts(s, i, NULL);
yading@11 795 ogg_validate_keyframe(s, i, pstart, psize);
yading@11 796 if (os->pflags & AV_PKT_FLAG_KEY) {
yading@11 797 keypos = *pos_arg;
yading@11 798 } else if (os->keyframe_seek) {
yading@11 799 // if we had a previous keyframe but no pts for it,
yading@11 800 // return that keyframe with this pts value.
yading@11 801 if (keypos >= 0)
yading@11 802 *pos_arg = keypos;
yading@11 803 else
yading@11 804 pts = AV_NOPTS_VALUE;
yading@11 805 }
yading@11 806 }
yading@11 807 if (pts != AV_NOPTS_VALUE)
yading@11 808 break;
yading@11 809 }
yading@11 810 ogg_reset(s);
yading@11 811 return pts;
yading@11 812 }
yading@11 813
yading@11 814 static int ogg_read_seek(AVFormatContext *s, int stream_index,
yading@11 815 int64_t timestamp, int flags)
yading@11 816 {
yading@11 817 struct ogg *ogg = s->priv_data;
yading@11 818 struct ogg_stream *os = ogg->streams + stream_index;
yading@11 819 int ret;
yading@11 820
yading@11 821 av_assert0(stream_index < ogg->nstreams);
yading@11 822 // Ensure everything is reset even when seeking via
yading@11 823 // the generated index.
yading@11 824 ogg_reset(s);
yading@11 825
yading@11 826 // Try seeking to a keyframe first. If this fails (very possible),
yading@11 827 // av_seek_frame will fall back to ignoring keyframes
yading@11 828 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
yading@11 829 && !(flags & AVSEEK_FLAG_ANY))
yading@11 830 os->keyframe_seek = 1;
yading@11 831
yading@11 832 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
yading@11 833 os = ogg->streams + stream_index;
yading@11 834 if (ret < 0)
yading@11 835 os->keyframe_seek = 0;
yading@11 836 return ret;
yading@11 837 }
yading@11 838
yading@11 839 static int ogg_probe(AVProbeData *p)
yading@11 840 {
yading@11 841 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
yading@11 842 return AVPROBE_SCORE_MAX;
yading@11 843 return 0;
yading@11 844 }
yading@11 845
yading@11 846 AVInputFormat ff_ogg_demuxer = {
yading@11 847 .name = "ogg",
yading@11 848 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
yading@11 849 .priv_data_size = sizeof(struct ogg),
yading@11 850 .read_probe = ogg_probe,
yading@11 851 .read_header = ogg_read_header,
yading@11 852 .read_packet = ogg_read_packet,
yading@11 853 .read_close = ogg_read_close,
yading@11 854 .read_seek = ogg_read_seek,
yading@11 855 .read_timestamp = ogg_read_timestamp,
yading@11 856 .extensions = "ogg",
yading@11 857 .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT,
yading@11 858 };