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
00346 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
00347 int64_t *fpos)
00348 {
00349 struct ogg *ogg = s->priv_data;
00350 int idx, i, ret;
00351 struct ogg_stream *os;
00352 int complete = 0;
00353 int segp = 0, psize = 0;
00354
00355 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
00356 if (str)
00357 *str = -1;
00358
00359 do{
00360 idx = ogg->curidx;
00361
00362 while (idx < 0){
00363 ret = ogg_read_page(s, &idx);
00364 if (ret < 0)
00365 return ret;
00366 }
00367
00368 os = ogg->streams + idx;
00369
00370 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
00371 idx, os->pstart, os->psize, os->segp, os->nsegs);
00372
00373 if (!os->codec){
00374 if (os->header < 0){
00375 os->codec = ogg_find_codec (os->buf, os->bufpos);
00376 if (!os->codec){
00377 av_log(s, AV_LOG_WARNING, "Codec not found\n");
00378 os->header = 0;
00379 return 0;
00380 }
00381 }else{
00382 return 0;
00383 }
00384 }
00385
00386 segp = os->segp;
00387 psize = os->psize;
00388
00389 while (os->segp < os->nsegs){
00390 int ss = os->segments[os->segp++];
00391 os->psize += ss;
00392 if (ss < 255){
00393 complete = 1;
00394 break;
00395 }
00396 }
00397
00398 if (!complete && os->segp == os->nsegs){
00399 ogg->curidx = -1;
00400
00401
00402
00403
00404 os->incomplete = !!os->psize;
00405 }
00406 }while (!complete);
00407
00408
00409 if (os->granule == -1)
00410 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
00411
00412 ogg->curidx = idx;
00413 os->incomplete = 0;
00414
00415 if (os->header) {
00416 os->header = os->codec->header (s, idx);
00417 if (!os->header){
00418 os->segp = segp;
00419 os->psize = psize;
00420
00421
00422
00423
00424 ogg->headers = 1;
00425
00426
00427
00428 if (!s->data_offset)
00429 s->data_offset = os->sync_pos;
00430 for (i = 0; i < ogg->nstreams; i++) {
00431 struct ogg_stream *cur_os = ogg->streams + i;
00432
00433
00434
00435 if (cur_os->incomplete)
00436 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
00437 }
00438 }else{
00439 os->pstart += os->psize;
00440 os->psize = 0;
00441 }
00442 } else {
00443 os->pflags = 0;
00444 os->pduration = 0;
00445 if (os->codec && os->codec->packet)
00446 os->codec->packet (s, idx);
00447 if (str)
00448 *str = idx;
00449 if (dstart)
00450 *dstart = os->pstart;
00451 if (dsize)
00452 *dsize = os->psize;
00453 if (fpos)
00454 *fpos = os->sync_pos;
00455 os->pstart += os->psize;
00456 os->psize = 0;
00457 if(os->pstart == os->bufpos)
00458 os->bufpos = os->pstart = 0;
00459 os->sync_pos = os->page_pos;
00460 }
00461
00462
00463
00464 os->page_end = 1;
00465 for (i = os->segp; i < os->nsegs; i++)
00466 if (os->segments[i] < 255) {
00467 os->page_end = 0;
00468 break;
00469 }
00470
00471 if (os->segp == os->nsegs)
00472 ogg->curidx = -1;
00473
00474 return 0;
00475 }
00476
00477 static int ogg_get_headers(AVFormatContext *s)
00478 {
00479 struct ogg *ogg = s->priv_data;
00480 int ret;
00481
00482 do{
00483 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
00484 if (ret < 0)
00485 return ret;
00486 }while (!ogg->headers);
00487
00488 av_dlog(s, "found headers\n");
00489
00490 return 0;
00491 }
00492
00493 static int ogg_get_length(AVFormatContext *s)
00494 {
00495 struct ogg *ogg = s->priv_data;
00496 int i;
00497 int64_t size, end;
00498 int streams_left=0;
00499
00500 if(!s->pb->seekable)
00501 return 0;
00502
00503
00504 if (s->duration != AV_NOPTS_VALUE)
00505 return 0;
00506
00507 size = avio_size(s->pb);
00508 if(size < 0)
00509 return 0;
00510 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
00511
00512 ogg_save (s);
00513 avio_seek (s->pb, end, SEEK_SET);
00514
00515 while (!ogg_read_page (s, &i)){
00516 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
00517 ogg->streams[i].codec) {
00518 s->streams[i]->duration =
00519 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
00520 if (s->streams[i]->start_time != AV_NOPTS_VALUE){
00521 s->streams[i]->duration -= s->streams[i]->start_time;
00522 streams_left-= (ogg->streams[i].got_start==-1);
00523 ogg->streams[i].got_start= 1;
00524 }else if(!ogg->streams[i].got_start){
00525 ogg->streams[i].got_start= -1;
00526 streams_left++;
00527 }
00528 }
00529 }
00530
00531 ogg_restore (s, 0);
00532
00533 ogg_save (s);
00534 avio_seek (s->pb, s->data_offset, SEEK_SET);
00535 ogg_reset(s);
00536 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
00537 int64_t pts;
00538 if (i < 0) continue;
00539 pts = ogg_calc_pts(s, i, NULL);
00540 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
00541 s->streams[i]->duration -= pts;
00542 ogg->streams[i].got_start= 1;
00543 streams_left--;
00544 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start){
00545 ogg->streams[i].got_start= 1;
00546 streams_left--;
00547 }
00548 }
00549 ogg_restore (s, 0);
00550
00551 return 0;
00552 }
00553
00554 static int ogg_read_header(AVFormatContext *s)
00555 {
00556 struct ogg *ogg = s->priv_data;
00557 int ret, i;
00558 ogg->curidx = -1;
00559
00560 ret = ogg_get_headers(s);
00561 if (ret < 0)
00562 return ret;
00563
00564 for (i = 0; i < ogg->nstreams; i++)
00565 if (ogg->streams[i].header < 0)
00566 ogg->streams[i].codec = NULL;
00567
00568
00569 ogg_get_length (s);
00570
00571
00572 return 0;
00573 }
00574
00575 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
00576 {
00577 struct ogg *ogg = s->priv_data;
00578 struct ogg_stream *os = ogg->streams + idx;
00579 int64_t pts = AV_NOPTS_VALUE;
00580
00581 if (dts)
00582 *dts = AV_NOPTS_VALUE;
00583
00584 if (os->lastpts != AV_NOPTS_VALUE) {
00585 pts = os->lastpts;
00586 os->lastpts = AV_NOPTS_VALUE;
00587 }
00588 if (os->lastdts != AV_NOPTS_VALUE) {
00589 if (dts)
00590 *dts = os->lastdts;
00591 os->lastdts = AV_NOPTS_VALUE;
00592 }
00593 if (os->page_end) {
00594 if (os->granule != -1LL) {
00595 if (os->codec && os->codec->granule_is_start)
00596 pts = ogg_gptopts(s, idx, os->granule, dts);
00597 else
00598 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
00599 os->granule = -1LL;
00600 }
00601 }
00602 return pts;
00603 }
00604
00605 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
00606 {
00607 struct ogg *ogg = s->priv_data;
00608 struct ogg_stream *os = ogg->streams + idx;
00609 if (psize && s->streams[idx]->codec->codec_id == CODEC_ID_THEORA) {
00610 if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
00611 os->pflags ^= AV_PKT_FLAG_KEY;
00612 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
00613 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
00614 }
00615 }
00616 }
00617
00618 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
00619 {
00620 struct ogg *ogg;
00621 struct ogg_stream *os;
00622 int idx, ret;
00623 int pstart, psize;
00624 int64_t fpos, pts, dts;
00625
00626
00627 retry:
00628 do{
00629 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
00630 if (ret < 0)
00631 return ret;
00632 }while (idx < 0 || !s->streams[idx]);
00633
00634 ogg = s->priv_data;
00635 os = ogg->streams + idx;
00636
00637
00638 pts = ogg_calc_pts(s, idx, &dts);
00639 ogg_validate_keyframe(s, idx, pstart, psize);
00640
00641 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
00642 goto retry;
00643 os->keyframe_seek = 0;
00644
00645
00646 ret = av_new_packet(pkt, psize);
00647 if (ret < 0)
00648 return ret;
00649 pkt->stream_index = idx;
00650 memcpy (pkt->data, os->buf + pstart, psize);
00651
00652 pkt->pts = pts;
00653 pkt->dts = dts;
00654 pkt->flags = os->pflags;
00655 pkt->duration = os->pduration;
00656 pkt->pos = fpos;
00657
00658 return psize;
00659 }
00660
00661 static int ogg_read_close(AVFormatContext *s)
00662 {
00663 struct ogg *ogg = s->priv_data;
00664 int i;
00665
00666 for (i = 0; i < ogg->nstreams; i++){
00667 av_free (ogg->streams[i].buf);
00668 av_free (ogg->streams[i].private);
00669 }
00670 av_free (ogg->streams);
00671 return 0;
00672 }
00673
00674 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
00675 int64_t *pos_arg, int64_t pos_limit)
00676 {
00677 struct ogg *ogg = s->priv_data;
00678 AVIOContext *bc = s->pb;
00679 int64_t pts = AV_NOPTS_VALUE;
00680 int64_t keypos = -1;
00681 int i;
00682 int pstart, psize;
00683 avio_seek(bc, *pos_arg, SEEK_SET);
00684 ogg_reset(s);
00685
00686 while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
00687 if (i == stream_index) {
00688 struct ogg_stream *os = ogg->streams + stream_index;
00689 pts = ogg_calc_pts(s, i, NULL);
00690 ogg_validate_keyframe(s, i, pstart, psize);
00691 if (os->pflags & AV_PKT_FLAG_KEY) {
00692 keypos = *pos_arg;
00693 } else if (os->keyframe_seek) {
00694
00695
00696 if (keypos >= 0)
00697 *pos_arg = keypos;
00698 else
00699 pts = AV_NOPTS_VALUE;
00700 }
00701 }
00702 if (pts != AV_NOPTS_VALUE)
00703 break;
00704 }
00705 ogg_reset(s);
00706 return pts;
00707 }
00708
00709 static int ogg_read_seek(AVFormatContext *s, int stream_index,
00710 int64_t timestamp, int flags)
00711 {
00712 struct ogg *ogg = s->priv_data;
00713 struct ogg_stream *os = ogg->streams + stream_index;
00714 int ret;
00715
00716 av_assert0(stream_index < ogg->nstreams);
00717
00718
00719 ogg_reset(s);
00720
00721
00722
00723 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
00724 && !(flags & AVSEEK_FLAG_ANY))
00725 os->keyframe_seek = 1;
00726
00727 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
00728 os = ogg->streams + stream_index;
00729 if (ret < 0)
00730 os->keyframe_seek = 0;
00731 return ret;
00732 }
00733
00734 static int ogg_probe(AVProbeData *p)
00735 {
00736 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
00737 return AVPROBE_SCORE_MAX;
00738 return 0;
00739 }
00740
00741 AVInputFormat ff_ogg_demuxer = {
00742 .name = "ogg",
00743 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
00744 .priv_data_size = sizeof(struct ogg),
00745 .read_probe = ogg_probe,
00746 .read_header = ogg_read_header,
00747 .read_packet = ogg_read_packet,
00748 .read_close = ogg_read_close,
00749 .read_seek = ogg_read_seek,
00750 .read_timestamp = ogg_read_timestamp,
00751 .extensions = "ogg",
00752 .flags = AVFMT_GENERIC_INDEX,
00753 };