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