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#include "vorbiscomment.h" 37 38#define MAX_PAGE_SIZE 65307 39#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE 40 41static const struct ogg_codec * const ogg_codecs[] = { 42 &ff_skeleton_codec, 43 &ff_dirac_codec, 44 &ff_speex_codec, 45 &ff_vorbis_codec, 46 &ff_theora_codec, 47 &ff_flac_codec, 48 &ff_old_dirac_codec, 49 &ff_old_flac_codec, 50 &ff_ogm_video_codec, 51 &ff_ogm_audio_codec, 52 &ff_ogm_text_codec, 53 &ff_ogm_old_codec, 54 NULL 55}; 56 57//FIXME We could avoid some structure duplication 58static int 59ogg_save (AVFormatContext * s) 60{ 61 struct ogg *ogg = s->priv_data; 62 struct ogg_state *ost = 63 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams)); 64 int i; 65 ost->pos = url_ftell (s->pb); 66 ost->curidx = ogg->curidx; 67 ost->next = ogg->state; 68 ost->nstreams = ogg->nstreams; 69 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams)); 70 71 for (i = 0; i < ogg->nstreams; i++){ 72 struct ogg_stream *os = ogg->streams + i; 73 os->buf = av_malloc (os->bufsize); 74 memset (os->buf, 0, os->bufsize); 75 memcpy (os->buf, ost->streams[i].buf, os->bufpos); 76 } 77 78 ogg->state = ost; 79 80 return 0; 81} 82 83static int 84ogg_restore (AVFormatContext * s, int discard) 85{ 86 struct ogg *ogg = s->priv_data; 87 ByteIOContext *bc = s->pb; 88 struct ogg_state *ost = ogg->state; 89 int i; 90 91 if (!ost) 92 return 0; 93 94 ogg->state = ost->next; 95 96 if (!discard){ 97 for (i = 0; i < ogg->nstreams; i++) 98 av_free (ogg->streams[i].buf); 99 100 url_fseek (bc, ost->pos, SEEK_SET); 101 ogg->curidx = ost->curidx; 102 ogg->nstreams = ost->nstreams; 103 memcpy(ogg->streams, ost->streams, 104 ost->nstreams * sizeof(*ogg->streams)); 105 } 106 107 av_free (ost); 108 109 return 0; 110} 111 112static int 113ogg_reset (struct ogg * ogg) 114{ 115 int i; 116 117 for (i = 0; i < ogg->nstreams; i++){ 118 struct ogg_stream *os = ogg->streams + i; 119 os->bufpos = 0; 120 os->pstart = 0; 121 os->psize = 0; 122 os->granule = -1; 123 os->lastpts = AV_NOPTS_VALUE; 124 os->lastdts = AV_NOPTS_VALUE; 125 os->sync_pos = -1; 126 os->page_pos = 0; 127 os->nsegs = 0; 128 os->segp = 0; 129 os->incomplete = 0; 130 } 131 132 ogg->curidx = -1; 133 134 return 0; 135} 136 137static const struct ogg_codec * 138ogg_find_codec (uint8_t * buf, int size) 139{ 140 int i; 141 142 for (i = 0; ogg_codecs[i]; i++) 143 if (size >= ogg_codecs[i]->magicsize && 144 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize)) 145 return ogg_codecs[i]; 146 147 return NULL; 148} 149 150static int 151ogg_new_stream (AVFormatContext * s, uint32_t serial) 152{ 153 154 struct ogg *ogg = s->priv_data; 155 int idx = ogg->nstreams++; 156 AVStream *st; 157 struct ogg_stream *os; 158 159 ogg->streams = av_realloc (ogg->streams, 160 ogg->nstreams * sizeof (*ogg->streams)); 161 memset (ogg->streams + idx, 0, sizeof (*ogg->streams)); 162 os = ogg->streams + idx; 163 os->serial = serial; 164 os->bufsize = DECODER_BUFFER_SIZE; 165 os->buf = av_malloc(os->bufsize); 166 os->header = -1; 167 168 st = av_new_stream (s, idx); 169 if (!st) 170 return AVERROR(ENOMEM); 171 172 av_set_pts_info(st, 64, 1, 1000000); 173 174 return idx; 175} 176 177static int 178ogg_new_buf(struct ogg *ogg, int idx) 179{ 180 struct ogg_stream *os = ogg->streams + idx; 181 uint8_t *nb = av_malloc(os->bufsize); 182 int size = os->bufpos - os->pstart; 183 if(os->buf){ 184 memcpy(nb, os->buf + os->pstart, size); 185 av_free(os->buf); 186 } 187 os->buf = nb; 188 os->bufpos = size; 189 os->pstart = 0; 190 191 return 0; 192} 193 194static int 195ogg_read_page (AVFormatContext * s, int *str) 196{ 197 ByteIOContext *bc = s->pb; 198 struct ogg *ogg = s->priv_data; 199 struct ogg_stream *os; 200 int i = 0; 201 int flags, nsegs; 202 uint64_t gp; 203 uint32_t serial; 204 uint32_t seq; 205 uint32_t crc; 206 int size, idx; 207 uint8_t sync[4]; 208 int sp = 0; 209 210 if (get_buffer (bc, sync, 4) < 4) 211 return -1; 212 213 do{ 214 int c; 215 216 if (sync[sp & 3] == 'O' && 217 sync[(sp + 1) & 3] == 'g' && 218 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S') 219 break; 220 221 c = url_fgetc (bc); 222 if (c < 0) 223 return -1; 224 sync[sp++ & 3] = c; 225 }while (i++ < MAX_PAGE_SIZE); 226 227 if (i >= MAX_PAGE_SIZE){ 228 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n"); 229 return -1; 230 } 231 232 if (url_fgetc (bc) != 0) /* version */ 233 return -1; 234 235 flags = url_fgetc (bc); 236 gp = get_le64 (bc); 237 serial = get_le32 (bc); 238 seq = get_le32 (bc); 239 crc = get_le32 (bc); 240 nsegs = url_fgetc (bc); 241 242 idx = ogg_find_stream (ogg, serial); 243 if (idx < 0){ 244 idx = ogg_new_stream (s, serial); 245 if (idx < 0) 246 return -1; 247 } 248 249 os = ogg->streams + idx; 250 os->page_pos = url_ftell(bc) - 27; 251 252 if(os->psize > 0) 253 ogg_new_buf(ogg, idx); 254 255 if (get_buffer (bc, os->segments, nsegs) < nsegs) 256 return -1; 257 258 os->nsegs = nsegs; 259 os->segp = 0; 260 261 size = 0; 262 for (i = 0; i < nsegs; i++) 263 size += os->segments[i]; 264 265 if (flags & OGG_FLAG_CONT || os->incomplete){ 266 if (!os->psize){ 267 while (os->segp < os->nsegs){ 268 int seg = os->segments[os->segp++]; 269 os->pstart += seg; 270 if (seg < 255) 271 break; 272 } 273 os->sync_pos = os->page_pos; 274 } 275 }else{ 276 os->psize = 0; 277 os->sync_pos = os->page_pos; 278 } 279 280 if (os->bufsize - os->bufpos < size){ 281 uint8_t *nb = av_malloc (os->bufsize *= 2); 282 memcpy (nb, os->buf, os->bufpos); 283 av_free (os->buf); 284 os->buf = nb; 285 } 286 287 if (get_buffer (bc, os->buf + os->bufpos, size) < size) 288 return -1; 289 290 os->bufpos += size; 291 os->granule = gp; 292 os->flags = flags; 293 294 if (str) 295 *str = idx; 296 297 return 0; 298} 299 300static int 301ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos) 302{ 303 struct ogg *ogg = s->priv_data; 304 int idx, i; 305 struct ogg_stream *os; 306 int complete = 0; 307 int segp = 0, psize = 0; 308 309#if 0 310 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx); 311#endif 312 313 do{ 314 idx = ogg->curidx; 315 316 while (idx < 0){ 317 if (ogg_read_page (s, &idx) < 0) 318 return -1; 319 } 320 321 os = ogg->streams + idx; 322 323#if 0 324 av_log (s, AV_LOG_DEBUG, 325 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n", 326 idx, os->pstart, os->psize, os->segp, os->nsegs); 327#endif 328 329 if (!os->codec){ 330 if (os->header < 0){ 331 os->codec = ogg_find_codec (os->buf, os->bufpos); 332 if (!os->codec){ 333 os->header = 0; 334 return 0; 335 } 336 }else{ 337 return 0; 338 } 339 } 340 341 segp = os->segp; 342 psize = os->psize; 343 344 while (os->segp < os->nsegs){ 345 int ss = os->segments[os->segp++]; 346 os->psize += ss; 347 if (ss < 255){ 348 complete = 1; 349 break; 350 } 351 } 352 353 if (!complete && os->segp == os->nsegs){ 354 ogg->curidx = -1; 355 os->incomplete = 1; 356 } 357 }while (!complete); 358 359#if 0 360 av_log (s, AV_LOG_DEBUG, 361 "ogg_packet: idx %i, frame size %i, start %i\n", 362 idx, os->psize, os->pstart); 363#endif 364 365 if (os->granule == -1) 366 av_log(s, AV_LOG_WARNING, "Page at %lld is missing granule\n", os->page_pos); 367 368 ogg->curidx = idx; 369 os->incomplete = 0; 370 371 if (os->header) { 372 os->header = os->codec->header (s, idx); 373 if (!os->header){ 374 os->segp = segp; 375 os->psize = psize; 376 if (!ogg->headers) 377 s->data_offset = os->sync_pos; 378 ogg->headers = 1; 379 }else{ 380 os->pstart += os->psize; 381 os->psize = 0; 382 } 383 } else { 384 os->pflags = 0; 385 os->pduration = 0; 386 if (os->codec && os->codec->packet) 387 os->codec->packet (s, idx); 388 if (str) 389 *str = idx; 390 if (dstart) 391 *dstart = os->pstart; 392 if (dsize) 393 *dsize = os->psize; 394 if (fpos) 395 *fpos = os->sync_pos; 396 os->pstart += os->psize; 397 os->psize = 0; 398 os->sync_pos = os->page_pos; 399 } 400 401 // determine whether there are more complete packets in this page 402 // if not, the page's granule will apply to this packet 403 os->page_end = 1; 404 for (i = os->segp; i < os->nsegs; i++) 405 if (os->segments[i] < 255) { 406 os->page_end = 0; 407 break; 408 } 409 410 if (os->segp == os->nsegs) 411 ogg->curidx = -1; 412 413 return 0; 414} 415 416static int 417ogg_get_headers (AVFormatContext * s) 418{ 419 struct ogg *ogg = s->priv_data; 420 421 do{ 422 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0) 423 return -1; 424 }while (!ogg->headers); 425 426#if 0 427 av_log (s, AV_LOG_DEBUG, "found headers\n"); 428#endif 429 430 return 0; 431} 432 433static int 434ogg_get_length (AVFormatContext * s) 435{ 436 struct ogg *ogg = s->priv_data; 437 int i; 438 int64_t size, end; 439 440 if(url_is_streamed(s->pb)) 441 return 0; 442 443// already set 444 if (s->duration != AV_NOPTS_VALUE) 445 return 0; 446 447 size = url_fsize(s->pb); 448 if(size < 0) 449 return 0; 450 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0; 451 452 ogg_save (s); 453 url_fseek (s->pb, end, SEEK_SET); 454 455 while (!ogg_read_page (s, &i)){ 456 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && 457 ogg->streams[i].codec) { 458 s->streams[i]->duration = 459 ogg_gptopts (s, i, ogg->streams[i].granule, NULL); 460 if (s->streams[i]->start_time != AV_NOPTS_VALUE) 461 s->streams[i]->duration -= s->streams[i]->start_time; 462 } 463 } 464 465 ogg_restore (s, 0); 466 467 return 0; 468} 469 470 471static int 472ogg_read_header (AVFormatContext * s, AVFormatParameters * ap) 473{ 474 struct ogg *ogg = s->priv_data; 475 int i; 476 ogg->curidx = -1; 477 //linear headers seek from start 478 if (ogg_get_headers (s) < 0){ 479 return -1; 480 } 481 482 for (i = 0; i < ogg->nstreams; i++) 483 if (ogg->streams[i].header < 0) 484 ogg->streams[i].codec = NULL; 485 486 //linear granulepos seek from end 487 ogg_get_length (s); 488 489 //fill the extradata in the per codec callbacks 490 return 0; 491} 492 493static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts) 494{ 495 struct ogg *ogg = s->priv_data; 496 struct ogg_stream *os = ogg->streams + idx; 497 int64_t pts = AV_NOPTS_VALUE; 498 499 if (dts) 500 *dts = AV_NOPTS_VALUE; 501 502 if (os->lastpts != AV_NOPTS_VALUE) { 503 pts = os->lastpts; 504 os->lastpts = AV_NOPTS_VALUE; 505 } 506 if (os->lastdts != AV_NOPTS_VALUE) { 507 if (dts) 508 *dts = os->lastdts; 509 os->lastdts = AV_NOPTS_VALUE; 510 } 511 if (os->page_end) { 512 if (os->granule != -1LL) { 513 if (os->codec && os->codec->granule_is_start) 514 pts = ogg_gptopts(s, idx, os->granule, dts); 515 else 516 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts); 517 os->granule = -1LL; 518 } 519 } 520 return pts; 521} 522 523static int 524ogg_read_packet (AVFormatContext * s, AVPacket * pkt) 525{ 526 struct ogg *ogg; 527 struct ogg_stream *os; 528 int idx = -1; 529 int pstart, psize; 530 int64_t fpos, pts, dts; 531 532 //Get an ogg packet 533retry: 534 do{ 535 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0) 536 return AVERROR(EIO); 537 }while (idx < 0 || !s->streams[idx]); 538 539 ogg = s->priv_data; 540 os = ogg->streams + idx; 541 542 // pflags might not be set until after this 543 pts = ogg_calc_pts(s, idx, &dts); 544 545 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY)) 546 goto retry; 547 os->keyframe_seek = 0; 548 549 //Alloc a pkt 550 if (av_new_packet (pkt, psize) < 0) 551 return AVERROR(EIO); 552 pkt->stream_index = idx; 553 memcpy (pkt->data, os->buf + pstart, psize); 554 555 pkt->pts = pts; 556 pkt->dts = dts; 557 pkt->flags = os->pflags; 558 pkt->duration = os->pduration; 559 pkt->pos = fpos; 560 561 return psize; 562} 563 564 565static int 566ogg_read_close (AVFormatContext * s) 567{ 568 struct ogg *ogg = s->priv_data; 569 int i; 570 571 for (i = 0; i < ogg->nstreams; i++){ 572 av_free (ogg->streams[i].buf); 573 av_free (ogg->streams[i].private); 574 } 575 av_free (ogg->streams); 576 return 0; 577} 578 579 580static int64_t 581ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, 582 int64_t pos_limit) 583{ 584 struct ogg *ogg = s->priv_data; 585 struct ogg_stream *os = ogg->streams + stream_index; 586 ByteIOContext *bc = s->pb; 587 int64_t pts = AV_NOPTS_VALUE; 588 int i; 589 url_fseek(bc, *pos_arg, SEEK_SET); 590 ogg_reset(ogg); 591 592 while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) { 593 if (i == stream_index) { 594 pts = ogg_calc_pts(s, i, NULL); 595 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY)) 596 pts = AV_NOPTS_VALUE; 597 } 598 if (pts != AV_NOPTS_VALUE) 599 break; 600 } 601 ogg_reset(ogg); 602 return pts; 603} 604 605static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 606{ 607 struct ogg *ogg = s->priv_data; 608 struct ogg_stream *os = ogg->streams + stream_index; 609 int ret; 610 611 // Try seeking to a keyframe first. If this fails (very possible), 612 // av_seek_frame will fall back to ignoring keyframes 613 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO 614 && !(flags & AVSEEK_FLAG_ANY)) 615 os->keyframe_seek = 1; 616 617 ret = av_seek_frame_binary(s, stream_index, timestamp, flags); 618 if (ret < 0) 619 os->keyframe_seek = 0; 620 return ret; 621} 622 623static int ogg_probe(AVProbeData *p) 624{ 625 if (p->buf[0] == 'O' && p->buf[1] == 'g' && 626 p->buf[2] == 'g' && p->buf[3] == 'S' && 627 p->buf[4] == 0x0 && p->buf[5] <= 0x7 ) 628 return AVPROBE_SCORE_MAX; 629 else 630 return 0; 631} 632 633AVInputFormat ogg_demuxer = { 634 "ogg", 635 NULL_IF_CONFIG_SMALL("Ogg"), 636 sizeof (struct ogg), 637 ogg_probe, 638 ogg_read_header, 639 ogg_read_packet, 640 ogg_read_close, 641 ogg_read_seek, 642 ogg_read_timestamp, 643 .extensions = "ogg", 644 .metadata_conv = ff_vorbiscomment_metadata_conv, 645 .flags = AVFMT_GENERIC_INDEX, 646}; 647