1/* 2 * Ogg bitstream support 3 * Luca Barbato <lu_zero@gentoo.org> 4 * Based on tcvp implementation 5 * 6 */ 7 8/** 9 Copyright (C) 2005 Michael Ahlberg, M��ns Rullg��rd 10 11 Permission is hereby granted, free of charge, to any person 12 obtaining a copy of this software and associated documentation 13 files (the "Software"), to deal in the Software without 14 restriction, including without limitation the rights to use, copy, 15 modify, merge, publish, distribute, sublicense, and/or sell copies 16 of the Software, and to permit persons to whom the Software is 17 furnished to do so, subject to the following conditions: 18 19 The above copyright notice and this permission notice shall be 20 included in all copies or substantial portions of the Software. 21 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 DEALINGS IN THE SOFTWARE. 30**/ 31 32 33#include <stdio.h> 34#include "oggdec.h" 35#include "avformat.h" 36 37#define MAX_PAGE_SIZE 65307 38#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE 39 40static const struct ogg_codec * const ogg_codecs[] = { 41 &ff_speex_codec, 42 &ff_vorbis_codec, 43 &ff_theora_codec, 44 &ff_flac_codec, 45 &ff_old_flac_codec, 46 &ff_ogm_video_codec, 47 &ff_ogm_audio_codec, 48 &ff_ogm_text_codec, 49 &ff_ogm_old_codec, 50 NULL 51}; 52 53//FIXME We could avoid some structure duplication 54static int 55ogg_save (AVFormatContext * s) 56{ 57 struct ogg *ogg = s->priv_data; 58 struct ogg_state *ost = 59 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams)); 60 int i; 61 ost->pos = url_ftell (s->pb); 62 ost->curidx = ogg->curidx; 63 ost->next = ogg->state; 64 ost->nstreams = ogg->nstreams; 65 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams)); 66 67 for (i = 0; i < ogg->nstreams; i++){ 68 struct ogg_stream *os = ogg->streams + i; 69 os->buf = av_malloc (os->bufsize); 70 memset (os->buf, 0, os->bufsize); 71 memcpy (os->buf, ost->streams[i].buf, os->bufpos); 72 } 73 74 ogg->state = ost; 75 76 return 0; 77} 78 79static int 80ogg_restore (AVFormatContext * s, int discard) 81{ 82 struct ogg *ogg = s->priv_data; 83 ByteIOContext *bc = s->pb; 84 struct ogg_state *ost = ogg->state; 85 int i; 86 87 if (!ost) 88 return 0; 89 90 ogg->state = ost->next; 91 92 if (!discard){ 93 for (i = 0; i < ogg->nstreams; i++) 94 av_free (ogg->streams[i].buf); 95 96 url_fseek (bc, ost->pos, SEEK_SET); 97 ogg->curidx = ost->curidx; 98 ogg->nstreams = ost->nstreams; 99 memcpy(ogg->streams, ost->streams, 100 ost->nstreams * sizeof(*ogg->streams)); 101 } 102 103 av_free (ost); 104 105 return 0; 106} 107 108static int 109ogg_reset (struct ogg * ogg) 110{ 111 int i; 112 113 for (i = 0; i < ogg->nstreams; i++){ 114 struct ogg_stream *os = ogg->streams + i; 115 os->bufpos = 0; 116 os->pstart = 0; 117 os->psize = 0; 118 os->granule = -1; 119 os->lastgp = -1; 120 os->nsegs = 0; 121 os->segp = 0; 122 } 123 124 ogg->curidx = -1; 125 126 return 0; 127} 128 129static const struct ogg_codec * 130ogg_find_codec (uint8_t * buf, int size) 131{ 132 int i; 133 134 for (i = 0; ogg_codecs[i]; i++) 135 if (size >= ogg_codecs[i]->magicsize && 136 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize)) 137 return ogg_codecs[i]; 138 139 return NULL; 140} 141 142static int 143ogg_find_stream (struct ogg * ogg, int serial) 144{ 145 int i; 146 147 for (i = 0; i < ogg->nstreams; i++) 148 if (ogg->streams[i].serial == serial) 149 return i; 150 151 return -1; 152} 153 154static int 155ogg_new_stream (AVFormatContext * s, uint32_t serial) 156{ 157 158 struct ogg *ogg = s->priv_data; 159 int idx = ogg->nstreams++; 160 AVStream *st; 161 struct ogg_stream *os; 162 163 ogg->streams = av_realloc (ogg->streams, 164 ogg->nstreams * sizeof (*ogg->streams)); 165 memset (ogg->streams + idx, 0, sizeof (*ogg->streams)); 166 os = ogg->streams + idx; 167 os->serial = serial; 168 os->bufsize = DECODER_BUFFER_SIZE; 169 os->buf = av_malloc(os->bufsize); 170 os->header = -1; 171 172 st = av_new_stream (s, idx); 173 if (!st) 174 return AVERROR(ENOMEM); 175 176 av_set_pts_info(st, 64, 1, 1000000); 177 178 return idx; 179} 180 181static int 182ogg_new_buf(struct ogg *ogg, int idx) 183{ 184 struct ogg_stream *os = ogg->streams + idx; 185 uint8_t *nb = av_malloc(os->bufsize); 186 int size = os->bufpos - os->pstart; 187 if(os->buf){ 188 memcpy(nb, os->buf + os->pstart, size); 189 av_free(os->buf); 190 } 191 os->buf = nb; 192 os->bufpos = size; 193 os->pstart = 0; 194 195 return 0; 196} 197 198static int 199ogg_read_page (AVFormatContext * s, int *str) 200{ 201 ByteIOContext *bc = s->pb; 202 struct ogg *ogg = s->priv_data; 203 struct ogg_stream *os; 204 int i = 0; 205 int flags, nsegs; 206 uint64_t gp; 207 uint32_t serial; 208 uint32_t seq; 209 uint32_t crc; 210 int size, idx; 211 uint8_t sync[4]; 212 int sp = 0; 213 214 if (get_buffer (bc, sync, 4) < 4) 215 return -1; 216 217 do{ 218 int c; 219 220 if (sync[sp & 3] == 'O' && 221 sync[(sp + 1) & 3] == 'g' && 222 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S') 223 break; 224 225 c = url_fgetc (bc); 226 if (c < 0) 227 return -1; 228 sync[sp++ & 3] = c; 229 }while (i++ < MAX_PAGE_SIZE); 230 231 if (i >= MAX_PAGE_SIZE){ 232 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n"); 233 return -1; 234 } 235 236 if (url_fgetc (bc) != 0) /* version */ 237 return -1; 238 239 flags = url_fgetc (bc); 240 gp = get_le64 (bc); 241 serial = get_le32 (bc); 242 seq = get_le32 (bc); 243 crc = get_le32 (bc); 244 nsegs = url_fgetc (bc); 245 246 idx = ogg_find_stream (ogg, serial); 247 if (idx < 0){ 248 idx = ogg_new_stream (s, serial); 249 if (idx < 0) 250 return -1; 251 } 252 253 os = ogg->streams + idx; 254 255 if(os->psize > 0) 256 ogg_new_buf(ogg, idx); 257 258 if (get_buffer (bc, os->segments, nsegs) < nsegs) 259 return -1; 260 261 os->nsegs = nsegs; 262 os->segp = 0; 263 264 size = 0; 265 for (i = 0; i < nsegs; i++) 266 size += os->segments[i]; 267 268 if (flags & OGG_FLAG_CONT){ 269 if (!os->psize){ 270 while (os->segp < os->nsegs){ 271 int seg = os->segments[os->segp++]; 272 os->pstart += seg; 273 if (seg < 255) 274 break; 275 } 276 } 277 }else{ 278 os->psize = 0; 279 } 280 281 if (os->bufsize - os->bufpos < size){ 282 uint8_t *nb = av_malloc (os->bufsize *= 2); 283 memcpy (nb, os->buf, os->bufpos); 284 av_free (os->buf); 285 os->buf = nb; 286 } 287 288 if (get_buffer (bc, os->buf + os->bufpos, size) < size) 289 return -1; 290 291 os->lastgp = os->granule; 292 os->bufpos += size; 293 os->granule = gp; 294 os->flags = flags; 295 296 if (str) 297 *str = idx; 298 299 return 0; 300} 301 302static int 303ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize) 304{ 305 struct ogg *ogg = s->priv_data; 306 int idx; 307 struct ogg_stream *os; 308 int complete = 0; 309 int segp = 0, psize = 0; 310 311#if 0 312 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx); 313#endif 314 315 do{ 316 idx = ogg->curidx; 317 318 while (idx < 0){ 319 if (ogg_read_page (s, &idx) < 0) 320 return -1; 321 } 322 323 os = ogg->streams + idx; 324 325#if 0 326 av_log (s, AV_LOG_DEBUG, 327 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n", 328 idx, os->pstart, os->psize, os->segp, os->nsegs); 329#endif 330 331 if (!os->codec){ 332 if (os->header < 0){ 333 os->codec = ogg_find_codec (os->buf, os->bufpos); 334 if (!os->codec){ 335 os->header = 0; 336 return 0; 337 } 338 }else{ 339 return 0; 340 } 341 } 342 343 segp = os->segp; 344 psize = os->psize; 345 346 while (os->segp < os->nsegs){ 347 int ss = os->segments[os->segp++]; 348 os->psize += ss; 349 if (ss < 255){ 350 complete = 1; 351 break; 352 } 353 } 354 355 if (!complete && os->segp == os->nsegs){ 356 ogg->curidx = -1; 357 } 358 }while (!complete); 359 360#if 0 361 av_log (s, AV_LOG_DEBUG, 362 "ogg_packet: idx %i, frame size %i, start %i\n", 363 idx, os->psize, os->pstart); 364#endif 365 366 ogg->curidx = idx; 367 368 if (os->header < 0){ 369 int hdr = os->codec->header (s, idx); 370 if (!hdr){ 371 os->header = os->seq; 372 os->segp = segp; 373 os->psize = psize; 374 ogg->headers = 1; 375 }else{ 376 os->pstart += os->psize; 377 os->psize = 0; 378 } 379 } 380 381 if (os->header > -1 && os->seq > os->header){ 382 os->pflags = 0; 383 if (os->codec && os->codec->packet) 384 os->codec->packet (s, idx); 385 if (str) 386 *str = idx; 387 if (dstart) 388 *dstart = os->pstart; 389 if (dsize) 390 *dsize = os->psize; 391 os->pstart += os->psize; 392 os->psize = 0; 393 } 394 395 os->seq++; 396 if (os->segp == os->nsegs) 397 ogg->curidx = -1; 398 399 return 0; 400} 401 402static int 403ogg_get_headers (AVFormatContext * s) 404{ 405 struct ogg *ogg = s->priv_data; 406 407 do{ 408 if (ogg_packet (s, NULL, NULL, NULL) < 0) 409 return -1; 410 }while (!ogg->headers); 411 412#if 0 413 av_log (s, AV_LOG_DEBUG, "found headers\n"); 414#endif 415 416 return 0; 417} 418 419static uint64_t 420ogg_gptopts (AVFormatContext * s, int i, uint64_t gp) 421{ 422 struct ogg *ogg = s->priv_data; 423 struct ogg_stream *os = ogg->streams + i; 424 uint64_t pts = AV_NOPTS_VALUE; 425 426 if(os->codec->gptopts){ 427 pts = os->codec->gptopts(s, i, gp); 428 } else { 429 pts = gp; 430 } 431 432 return pts; 433} 434 435 436static int 437ogg_get_length (AVFormatContext * s) 438{ 439 struct ogg *ogg = s->priv_data; 440 int idx = -1, i; 441 int64_t size, end; 442 443 if(url_is_streamed(s->pb)) 444 return 0; 445 446// already set 447 if (s->duration != AV_NOPTS_VALUE) 448 return 0; 449 450 size = url_fsize(s->pb); 451 if(size < 0) 452 return 0; 453 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size; 454 455 ogg_save (s); 456 url_fseek (s->pb, end, SEEK_SET); 457 458 while (!ogg_read_page (s, &i)){ 459 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && 460 ogg->streams[i].codec) 461 idx = i; 462 } 463 464 if (idx != -1){ 465 s->streams[idx]->duration = 466 ogg_gptopts (s, idx, ogg->streams[idx].granule); 467 } 468 469 ogg->size = size; 470 ogg_restore (s, 0); 471 472 return 0; 473} 474 475 476static int 477ogg_read_header (AVFormatContext * s, AVFormatParameters * ap) 478{ 479 struct ogg *ogg = s->priv_data; 480 int i; 481 ogg->curidx = -1; 482 //linear headers seek from start 483 if (ogg_get_headers (s) < 0){ 484 return -1; 485 } 486 487 for (i = 0; i < ogg->nstreams; i++) 488 if (ogg->streams[i].header < 0) 489 ogg->streams[i].codec = NULL; 490 491 //linear granulepos seek from end 492 ogg_get_length (s); 493 494 //fill the extradata in the per codec callbacks 495 return 0; 496} 497 498 499static int 500ogg_read_packet (AVFormatContext * s, AVPacket * pkt) 501{ 502 struct ogg *ogg; 503 struct ogg_stream *os; 504 int idx = -1; 505 int pstart, psize; 506 507 //Get an ogg packet 508 do{ 509 if (ogg_packet (s, &idx, &pstart, &psize) < 0) 510 return AVERROR(EIO); 511 }while (idx < 0 || !s->streams[idx]); 512 513 ogg = s->priv_data; 514 os = ogg->streams + idx; 515 516 //Alloc a pkt 517 if (av_new_packet (pkt, psize) < 0) 518 return AVERROR(EIO); 519 pkt->stream_index = idx; 520 memcpy (pkt->data, os->buf + pstart, psize); 521 if (os->lastgp != -1LL){ 522 pkt->pts = ogg_gptopts (s, idx, os->lastgp); 523 os->lastgp = -1; 524 } 525 526 pkt->flags = os->pflags; 527 528 return psize; 529} 530 531 532static int 533ogg_read_close (AVFormatContext * s) 534{ 535 struct ogg *ogg = s->priv_data; 536 int i; 537 538 for (i = 0; i < ogg->nstreams; i++){ 539 av_free (ogg->streams[i].buf); 540 av_free (ogg->streams[i].private); 541 } 542 av_free (ogg->streams); 543 return 0; 544} 545 546 547static int64_t 548ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, 549 int64_t pos_limit) 550{ 551 struct ogg *ogg = s->priv_data; 552 ByteIOContext *bc = s->pb; 553 int64_t pts = AV_NOPTS_VALUE; 554 int i; 555 url_fseek(bc, *pos_arg, SEEK_SET); 556 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) { 557 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && 558 ogg->streams[i].codec && i == stream_index) { 559 pts = ogg_gptopts(s, i, ogg->streams[i].granule); 560 // FIXME: this is the position of the packet after the one with above 561 // pts. 562 *pos_arg = url_ftell(bc); 563 break; 564 } 565 } 566 ogg_reset(ogg); 567 return pts; 568} 569 570static int ogg_probe(AVProbeData *p) 571{ 572 if (p->buf[0] == 'O' && p->buf[1] == 'g' && 573 p->buf[2] == 'g' && p->buf[3] == 'S' && 574 p->buf[4] == 0x0 && p->buf[5] <= 0x7 ) 575 return AVPROBE_SCORE_MAX; 576 else 577 return 0; 578} 579 580AVInputFormat ogg_demuxer = { 581 "ogg", 582 NULL_IF_CONFIG_SMALL("Ogg"), 583 sizeof (struct ogg), 584 ogg_probe, 585 ogg_read_header, 586 ogg_read_packet, 587 ogg_read_close, 588 NULL, 589 ogg_read_timestamp, 590 .extensions = "ogg", 591}; 592