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