00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <stdio.h>
00032 #include "libavutil/avassert.h"
00033 #include "oggdec.h"
00034 #include "avformat.h"
00035 #include "internal.h"
00036 #include "vorbiscomment.h"
00037
00038 #define MAX_PAGE_SIZE 65307
00039 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
00040
00041 static const struct ogg_codec * const ogg_codecs[] = {
00042 &ff_skeleton_codec,
00043 &ff_dirac_codec,
00044 &ff_speex_codec,
00045 &ff_vorbis_codec,
00046 &ff_theora_codec,
00047 &ff_flac_codec,
00048 &ff_celt_codec,
00049 &ff_old_dirac_codec,
00050 &ff_old_flac_codec,
00051 &ff_ogm_video_codec,
00052 &ff_ogm_audio_codec,
00053 &ff_ogm_text_codec,
00054 &ff_ogm_old_codec,
00055 NULL
00056 };
00057
00058 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
00059
00060
00061 static int ogg_save(AVFormatContext *s)
00062 {
00063 struct ogg *ogg = s->priv_data;
00064 struct ogg_state *ost =
00065 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
00066 int i;
00067 ost->pos = avio_tell (s->pb);
00068 ost->curidx = ogg->curidx;
00069 ost->next = ogg->state;
00070 ost->nstreams = ogg->nstreams;
00071 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
00072
00073 for (i = 0; i < ogg->nstreams; i++){
00074 struct ogg_stream *os = ogg->streams + i;
00075 os->buf = av_mallocz (os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
00076 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
00077 }
00078
00079 ogg->state = ost;
00080
00081 return 0;
00082 }
00083
00084 static int ogg_restore(AVFormatContext *s, int discard)
00085 {
00086 struct ogg *ogg = s->priv_data;
00087 AVIOContext *bc = s->pb;
00088 struct ogg_state *ost = ogg->state;
00089 int i;
00090
00091 if (!ost)
00092 return 0;
00093
00094 ogg->state = ost->next;
00095
00096 if (!discard){
00097 struct ogg_stream *old_streams = ogg->streams;
00098
00099 for (i = 0; i < ogg->nstreams; i++)
00100 av_free (ogg->streams[i].buf);
00101
00102 avio_seek (bc, ost->pos, SEEK_SET);
00103 ogg->curidx = ost->curidx;
00104 ogg->nstreams = ost->nstreams;
00105 ogg->streams = av_realloc (ogg->streams,
00106 ogg->nstreams * sizeof (*ogg->streams));
00107
00108 if (ogg->streams) {
00109 memcpy(ogg->streams, ost->streams,
00110 ost->nstreams * sizeof(*ogg->streams));
00111 } else {
00112 av_free(old_streams);
00113 ogg->nstreams = 0;
00114 }
00115 }
00116
00117 av_free (ost);
00118
00119 return 0;
00120 }
00121
00122 static int ogg_reset(AVFormatContext *s)
00123 {
00124 struct ogg *ogg = s->priv_data;
00125 int i;
00126 int64_t start_pos = avio_tell(s->pb);
00127
00128 for (i = 0; i < ogg->nstreams; i++){
00129 struct ogg_stream *os = ogg->streams + i;
00130 os->bufpos = 0;
00131 os->pstart = 0;
00132 os->psize = 0;
00133 os->granule = -1;
00134 os->lastpts = AV_NOPTS_VALUE;
00135 os->lastdts = AV_NOPTS_VALUE;
00136 os->sync_pos = -1;
00137 os->page_pos = 0;
00138 os->nsegs = 0;
00139 os->segp = 0;
00140 os->incomplete = 0;
00141 if (start_pos <= s->data_offset) {
00142 os->lastpts = 0;
00143 }
00144 }
00145
00146 ogg->curidx = -1;
00147
00148 return 0;
00149 }
00150
00151 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
00152 {
00153 int i;
00154
00155 for (i = 0; ogg_codecs[i]; i++)
00156 if (size >= ogg_codecs[i]->magicsize &&
00157 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
00158 return ogg_codecs[i];
00159
00160 return NULL;
00161 }
00162
00163 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
00164 {
00165
00166 struct ogg *ogg = s->priv_data;
00167 int idx = ogg->nstreams++;
00168 AVStream *st;
00169 struct ogg_stream *os;
00170
00171 ogg->streams = av_realloc (ogg->streams,
00172 ogg->nstreams * sizeof (*ogg->streams));
00173 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
00174 os = ogg->streams + idx;
00175 os->serial = serial;
00176 os->bufsize = DECODER_BUFFER_SIZE;
00177 os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
00178 os->header = -1;
00179
00180 if (new_avstream) {
00181 st = avformat_new_stream(s, NULL);
00182 if (!st)
00183 return AVERROR(ENOMEM);
00184
00185 st->id = idx;
00186 avpriv_set_pts_info(st, 64, 1, 1000000);
00187 }
00188
00189 return idx;
00190 }
00191
00192 static int ogg_new_buf(struct ogg *ogg, int idx)
00193 {
00194 struct ogg_stream *os = ogg->streams + idx;
00195 uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
00196 int size = os->bufpos - os->pstart;
00197 if(os->buf){
00198 memcpy(nb, os->buf + os->pstart, size);
00199 av_free(os->buf);
00200 }
00201 os->buf = nb;
00202 os->bufpos = size;
00203 os->pstart = 0;
00204
00205 return 0;
00206 }
00207
00208 static int ogg_read_page(AVFormatContext *s, int *str)
00209 {
00210 AVIOContext *bc = s->pb;
00211 struct ogg *ogg = s->priv_data;
00212 struct ogg_stream *os;
00213 int ret, i = 0;
00214 int flags, nsegs;
00215 uint64_t gp;
00216 uint32_t serial;
00217 int size, idx;
00218 uint8_t sync[4];
00219 int sp = 0;
00220
00221 ret = avio_read(bc, sync, 4);
00222 if (ret < 4)
00223 return ret < 0 ? ret : AVERROR_EOF;
00224
00225 do{
00226 int c;
00227
00228 if (sync[sp & 3] == 'O' &&
00229 sync[(sp + 1) & 3] == 'g' &&
00230 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
00231 break;
00232
00233 c = avio_r8(bc);
00234 if (url_feof(bc))
00235 return AVERROR_EOF;
00236 sync[sp++ & 3] = c;
00237 }while (i++ < MAX_PAGE_SIZE);
00238
00239 if (i >= MAX_PAGE_SIZE){
00240 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
00241 return AVERROR_INVALIDDATA;
00242 }
00243
00244 if (avio_r8(bc) != 0){
00245 av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
00246 return AVERROR_INVALIDDATA;
00247 }
00248
00249 flags = avio_r8(bc);
00250 gp = avio_rl64 (bc);
00251 serial = avio_rl32 (bc);
00252 avio_skip(bc, 8);
00253 nsegs = avio_r8(bc);
00254
00255 idx = ogg_find_stream (ogg, serial);
00256 if (idx < 0){
00257 if (ogg->headers) {
00258 int n;
00259
00260 if (ogg->nstreams != 1) {
00261 av_log_missing_feature(s, "Changing stream parameters in multistream ogg is", 0);
00262 return idx;
00263 }
00264
00265 for (n = 0; n < ogg->nstreams; n++) {
00266 av_freep(&ogg->streams[n].buf);
00267 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
00268 av_freep(&ogg->streams[n].private);
00269 }
00270 ogg->curidx = -1;
00271 ogg->nstreams = 0;
00272 idx = ogg_new_stream(s, serial, 0);
00273 } else {
00274 idx = ogg_new_stream(s, serial, 1);
00275 }
00276 if (idx < 0) {
00277 av_log (s, AV_LOG_ERROR, "failed to create stream (OOM?)\n");
00278 return idx;
00279 }
00280 }
00281
00282 os = ogg->streams + idx;
00283 os->page_pos = avio_tell(bc) - 27;
00284
00285 if(os->psize > 0)
00286 ogg_new_buf(ogg, idx);
00287
00288 ret = avio_read(bc, os->segments, nsegs);
00289 if (ret < nsegs)
00290 return ret < 0 ? ret : AVERROR_EOF;
00291
00292 os->nsegs = nsegs;
00293 os->segp = 0;
00294
00295 size = 0;
00296 for (i = 0; i < nsegs; i++)
00297 size += os->segments[i];
00298
00299 if (flags & OGG_FLAG_CONT || os->incomplete){
00300 if (!os->psize){
00301
00302
00303
00304 while (os->segp < os->nsegs){
00305 int seg = os->segments[os->segp++];
00306 os->pstart += seg;
00307 if (seg < 255)
00308 break;
00309 }
00310 os->sync_pos = os->page_pos;
00311 }
00312 }else{
00313 os->psize = 0;
00314 os->sync_pos = os->page_pos;
00315 }
00316
00317 if (os->bufsize - os->bufpos < size){
00318 uint8_t *nb = av_malloc ((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
00319 memcpy (nb, os->buf, os->bufpos);
00320 av_free (os->buf);
00321 os->buf = nb;
00322 }
00323
00324 ret = avio_read(bc, os->buf + os->bufpos, size);
00325 if (ret < size)
00326 return ret < 0 ? ret : AVERROR_EOF;
00327
00328 os->bufpos += size;
00329 os->granule = gp;
00330 os->flags = flags;
00331
00332 memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00333 if (str)
00334 *str = idx;
00335
00336 return 0;
00337 }
00338
00339 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
00340 int64_t *fpos)
00341 {
00342 struct ogg *ogg = s->priv_data;
00343 int idx, i, ret;
00344 struct ogg_stream *os;
00345 int complete = 0;
00346 int segp = 0, psize = 0;
00347
00348 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
00349
00350 do{
00351 idx = ogg->curidx;
00352
00353 while (idx < 0){
00354 ret = ogg_read_page(s, &idx);
00355 if (ret < 0)
00356 return ret;
00357 }
00358
00359 os = ogg->streams + idx;
00360
00361 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
00362 idx, os->pstart, os->psize, os->segp, os->nsegs);
00363
00364 if (!os->codec){
00365 if (os->header < 0){
00366 os->codec = ogg_find_codec (os->buf, os->bufpos);
00367 if (!os->codec){
00368 av_log(s, AV_LOG_WARNING, "Codec not found\n");
00369 os->header = 0;
00370 return 0;
00371 }
00372 }else{
00373 return 0;
00374 }
00375 }
00376
00377 segp = os->segp;
00378 psize = os->psize;
00379
00380 while (os->segp < os->nsegs){
00381 int ss = os->segments[os->segp++];
00382 os->psize += ss;
00383 if (ss < 255){
00384 complete = 1;
00385 break;
00386 }
00387 }
00388
00389 if (!complete && os->segp == os->nsegs){
00390 ogg->curidx = -1;
00391
00392
00393
00394
00395 os->incomplete = !!os->psize;
00396 }
00397 }while (!complete);
00398
00399
00400 if (os->granule == -1)
00401 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
00402
00403 ogg->curidx = idx;
00404 os->incomplete = 0;
00405
00406 if (os->header) {
00407 os->header = os->codec->header (s, idx);
00408 if (!os->header){
00409 os->segp = segp;
00410 os->psize = psize;
00411
00412
00413
00414
00415 ogg->headers = 1;
00416
00417
00418
00419 if (!s->data_offset)
00420 s->data_offset = os->sync_pos;
00421 for (i = 0; i < ogg->nstreams; i++) {
00422 struct ogg_stream *cur_os = ogg->streams + i;
00423
00424
00425
00426 if (cur_os->incomplete)
00427 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
00428 }
00429 }else{
00430 os->pstart += os->psize;
00431 os->psize = 0;
00432 }
00433 } else {
00434 os->pflags = 0;
00435 os->pduration = 0;
00436 if (os->codec && os->codec->packet)
00437 os->codec->packet (s, idx);
00438 if (str)
00439 *str = idx;
00440 if (dstart)
00441 *dstart = os->pstart;
00442 if (dsize)
00443 *dsize = os->psize;
00444 if (fpos)
00445 *fpos = os->sync_pos;
00446 os->pstart += os->psize;
00447 os->psize = 0;
00448 if(os->pstart == os->bufpos)
00449 os->bufpos = os->pstart = 0;
00450 os->sync_pos = os->page_pos;
00451 }
00452
00453
00454
00455 os->page_end = 1;
00456 for (i = os->segp; i < os->nsegs; i++)
00457 if (os->segments[i] < 255) {
00458 os->page_end = 0;
00459 break;
00460 }
00461
00462 if (os->segp == os->nsegs)
00463 ogg->curidx = -1;
00464
00465 return 0;
00466 }
00467
00468 static int ogg_get_headers(AVFormatContext *s)
00469 {
00470 struct ogg *ogg = s->priv_data;
00471 int ret;
00472
00473 do{
00474 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
00475 if (ret < 0)
00476 return ret;
00477 }while (!ogg->headers);
00478
00479 av_dlog(s, "found headers\n");
00480
00481 return 0;
00482 }
00483
00484 static int ogg_get_length(AVFormatContext *s)
00485 {
00486 struct ogg *ogg = s->priv_data;
00487 int i;
00488 int64_t size, end;
00489 int streams_left=0;
00490
00491 if(!s->pb->seekable)
00492 return 0;
00493
00494
00495 if (s->duration != AV_NOPTS_VALUE)
00496 return 0;
00497
00498 size = avio_size(s->pb);
00499 if(size < 0)
00500 return 0;
00501 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
00502
00503 ogg_save (s);
00504 avio_seek (s->pb, end, SEEK_SET);
00505
00506 while (!ogg_read_page (s, &i)){
00507 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
00508 ogg->streams[i].codec) {
00509 s->streams[i]->duration =
00510 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
00511 if (s->streams[i]->start_time != AV_NOPTS_VALUE){
00512 s->streams[i]->duration -= s->streams[i]->start_time;
00513 streams_left-= (ogg->streams[i].got_start==-1);
00514 ogg->streams[i].got_start= 1;
00515 }else if(!ogg->streams[i].got_start){
00516 ogg->streams[i].got_start= -1;
00517 streams_left++;
00518 }
00519 }
00520 }
00521
00522 ogg_restore (s, 0);
00523
00524 ogg_save (s);
00525 avio_seek (s->pb, s->data_offset, SEEK_SET);
00526 ogg_reset(s);
00527 while (!ogg_packet(s, &i, NULL, NULL, NULL)) {
00528 int64_t pts = ogg_calc_pts(s, i, NULL);
00529 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
00530 s->streams[i]->duration -= pts;
00531 ogg->streams[i].got_start= 1;
00532 streams_left--;
00533 }
00534 if(streams_left<=0)
00535 break;
00536 }
00537 ogg_restore (s, 0);
00538
00539 return 0;
00540 }
00541
00542 static int ogg_read_header(AVFormatContext *s)
00543 {
00544 struct ogg *ogg = s->priv_data;
00545 int ret, i;
00546 ogg->curidx = -1;
00547
00548 ret = ogg_get_headers(s);
00549 if (ret < 0)
00550 return ret;
00551
00552 for (i = 0; i < ogg->nstreams; i++)
00553 if (ogg->streams[i].header < 0)
00554 ogg->streams[i].codec = NULL;
00555
00556
00557 ogg_get_length (s);
00558
00559
00560 return 0;
00561 }
00562
00563 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
00564 {
00565 struct ogg *ogg = s->priv_data;
00566 struct ogg_stream *os = ogg->streams + idx;
00567 int64_t pts = AV_NOPTS_VALUE;
00568
00569 if (dts)
00570 *dts = AV_NOPTS_VALUE;
00571
00572 if (os->lastpts != AV_NOPTS_VALUE) {
00573 pts = os->lastpts;
00574 os->lastpts = AV_NOPTS_VALUE;
00575 }
00576 if (os->lastdts != AV_NOPTS_VALUE) {
00577 if (dts)
00578 *dts = os->lastdts;
00579 os->lastdts = AV_NOPTS_VALUE;
00580 }
00581 if (os->page_end) {
00582 if (os->granule != -1LL) {
00583 if (os->codec && os->codec->granule_is_start)
00584 pts = ogg_gptopts(s, idx, os->granule, dts);
00585 else
00586 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
00587 os->granule = -1LL;
00588 }
00589 }
00590 return pts;
00591 }
00592
00593 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
00594 {
00595 struct ogg *ogg = s->priv_data;
00596 struct ogg_stream *os = ogg->streams + idx;
00597 if (psize && s->streams[idx]->codec->codec_id == CODEC_ID_THEORA) {
00598 if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
00599 os->pflags ^= AV_PKT_FLAG_KEY;
00600 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
00601 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
00602 }
00603 }
00604 }
00605
00606 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
00607 {
00608 struct ogg *ogg;
00609 struct ogg_stream *os;
00610 int idx = -1, ret;
00611 int pstart, psize;
00612 int64_t fpos, pts, dts;
00613
00614
00615 retry:
00616 do{
00617 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
00618 if (ret < 0)
00619 return ret;
00620 }while (idx < 0 || !s->streams[idx]);
00621
00622 ogg = s->priv_data;
00623 os = ogg->streams + idx;
00624
00625
00626 pts = ogg_calc_pts(s, idx, &dts);
00627 ogg_validate_keyframe(s, idx, pstart, psize);
00628
00629 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
00630 goto retry;
00631 os->keyframe_seek = 0;
00632
00633
00634 ret = av_new_packet(pkt, psize);
00635 if (ret < 0)
00636 return ret;
00637 pkt->stream_index = idx;
00638 memcpy (pkt->data, os->buf + pstart, psize);
00639
00640 pkt->pts = pts;
00641 pkt->dts = dts;
00642 pkt->flags = os->pflags;
00643 pkt->duration = os->pduration;
00644 pkt->pos = fpos;
00645
00646 return psize;
00647 }
00648
00649 static int ogg_read_close(AVFormatContext *s)
00650 {
00651 struct ogg *ogg = s->priv_data;
00652 int i;
00653
00654 for (i = 0; i < ogg->nstreams; i++){
00655 av_free (ogg->streams[i].buf);
00656 av_free (ogg->streams[i].private);
00657 }
00658 av_free (ogg->streams);
00659 return 0;
00660 }
00661
00662 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
00663 int64_t *pos_arg, int64_t pos_limit)
00664 {
00665 struct ogg *ogg = s->priv_data;
00666 AVIOContext *bc = s->pb;
00667 int64_t pts = AV_NOPTS_VALUE;
00668 int64_t keypos = -1;
00669 int i = -1;
00670 int pstart, psize;
00671 avio_seek(bc, *pos_arg, SEEK_SET);
00672 ogg_reset(s);
00673
00674 while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
00675 if (i == stream_index) {
00676 struct ogg_stream *os = ogg->streams + stream_index;
00677 pts = ogg_calc_pts(s, i, NULL);
00678 ogg_validate_keyframe(s, i, pstart, psize);
00679 if (os->pflags & AV_PKT_FLAG_KEY) {
00680 keypos = *pos_arg;
00681 } else if (os->keyframe_seek) {
00682
00683
00684 if (keypos >= 0)
00685 *pos_arg = keypos;
00686 else
00687 pts = AV_NOPTS_VALUE;
00688 }
00689 }
00690 if (pts != AV_NOPTS_VALUE)
00691 break;
00692 }
00693 ogg_reset(s);
00694 return pts;
00695 }
00696
00697 static int ogg_read_seek(AVFormatContext *s, int stream_index,
00698 int64_t timestamp, int flags)
00699 {
00700 struct ogg *ogg = s->priv_data;
00701 struct ogg_stream *os = ogg->streams + stream_index;
00702 int ret;
00703
00704 av_assert0(stream_index < ogg->nstreams);
00705
00706
00707 ogg_reset(s);
00708
00709
00710
00711 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
00712 && !(flags & AVSEEK_FLAG_ANY))
00713 os->keyframe_seek = 1;
00714
00715 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
00716 os = ogg->streams + stream_index;
00717 if (ret < 0)
00718 os->keyframe_seek = 0;
00719 return ret;
00720 }
00721
00722 static int ogg_probe(AVProbeData *p)
00723 {
00724 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
00725 return AVPROBE_SCORE_MAX;
00726 return 0;
00727 }
00728
00729 AVInputFormat ff_ogg_demuxer = {
00730 .name = "ogg",
00731 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
00732 .priv_data_size = sizeof(struct ogg),
00733 .read_probe = ogg_probe,
00734 .read_header = ogg_read_header,
00735 .read_packet = ogg_read_packet,
00736 .read_close = ogg_read_close,
00737 .read_seek = ogg_read_seek,
00738 .read_timestamp = ogg_read_timestamp,
00739 .extensions = "ogg",
00740 .flags = AVFMT_GENERIC_INDEX,
00741 };