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