00001
00002
00003
00004
00005
00006
00007
00033 #include <stdio.h>
00034 #include "oggdec.h"
00035 #include "avformat.h"
00036
00037 #define MAX_PAGE_SIZE 65307
00038 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
00039
00040 static ogg_codec_t *ogg_codecs[] = {
00041 &vorbis_codec,
00042 &theora_codec,
00043 &flac_codec,
00044 &old_flac_codec,
00045 &ogm_video_codec,
00046 &ogm_audio_codec,
00047 &ogm_old_codec,
00048 NULL
00049 };
00050
00051
00052 static int
00053 ogg_save (AVFormatContext * s)
00054 {
00055 ogg_t *ogg = s->priv_data;
00056 ogg_state_t *ost =
00057 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
00058 int i;
00059 ost->pos = url_ftell (&s->pb);;
00060 ost->curidx = ogg->curidx;
00061 ost->next = ogg->state;
00062 ost->nstreams = ogg->nstreams;
00063 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
00064
00065 for (i = 0; i < ogg->nstreams; i++){
00066 ogg_stream_t *os = ogg->streams + i;
00067 os->buf = av_malloc (os->bufsize);
00068 memset (os->buf, 0, os->bufsize);
00069 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
00070 }
00071
00072 ogg->state = ost;
00073
00074 return 0;
00075 }
00076
00077 static int
00078 ogg_restore (AVFormatContext * s, int discard)
00079 {
00080 ogg_t *ogg = s->priv_data;
00081 ByteIOContext *bc = &s->pb;
00082 ogg_state_t *ost = ogg->state;
00083 int i;
00084
00085 if (!ost)
00086 return 0;
00087
00088 ogg->state = ost->next;
00089
00090 if (!discard){
00091 for (i = 0; i < ogg->nstreams; i++)
00092 av_free (ogg->streams[i].buf);
00093
00094 url_fseek (bc, ost->pos, SEEK_SET);
00095 ogg->curidx = ost->curidx;
00096 ogg->nstreams = ost->nstreams;
00097 memcpy(ogg->streams, ost->streams,
00098 ost->nstreams * sizeof(*ogg->streams));
00099 }
00100
00101 av_free (ost);
00102
00103 return 0;
00104 }
00105
00106 static int
00107 ogg_reset (ogg_t * ogg)
00108 {
00109 int i;
00110
00111 for (i = 0; i < ogg->nstreams; i++){
00112 ogg_stream_t *os = ogg->streams + i;
00113 os->bufpos = 0;
00114 os->pstart = 0;
00115 os->psize = 0;
00116 os->granule = -1;
00117 os->lastgp = -1;
00118 os->nsegs = 0;
00119 os->segp = 0;
00120 }
00121
00122 ogg->curidx = -1;
00123
00124 return 0;
00125 }
00126
00127 static ogg_codec_t *
00128 ogg_find_codec (uint8_t * buf, int size)
00129 {
00130 int i;
00131
00132 for (i = 0; ogg_codecs[i]; i++)
00133 if (size >= ogg_codecs[i]->magicsize &&
00134 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
00135 return ogg_codecs[i];
00136
00137 return NULL;
00138 }
00139
00140 static int
00141 ogg_find_stream (ogg_t * ogg, int serial)
00142 {
00143 int i;
00144
00145 for (i = 0; i < ogg->nstreams; i++)
00146 if (ogg->streams[i].serial == serial)
00147 return i;
00148
00149 return -1;
00150 }
00151
00152 static int
00153 ogg_new_stream (AVFormatContext * s, uint32_t serial)
00154 {
00155
00156 ogg_t *ogg = s->priv_data;
00157 int idx = ogg->nstreams++;
00158 AVStream *st;
00159 ogg_stream_t *os;
00160
00161 ogg->streams = av_realloc (ogg->streams,
00162 ogg->nstreams * sizeof (*ogg->streams));
00163 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
00164 os = ogg->streams + idx;
00165 os->serial = serial;
00166 os->bufsize = DECODER_BUFFER_SIZE;
00167 os->buf = av_malloc(os->bufsize);
00168 os->header = -1;
00169
00170 st = av_new_stream (s, idx);
00171 if (!st)
00172 return AVERROR(ENOMEM);
00173
00174 av_set_pts_info(st, 64, 1, 1000000);
00175
00176 return idx;
00177 }
00178
00179 static int
00180 ogg_new_buf(ogg_t *ogg, int idx)
00181 {
00182 ogg_stream_t *os = ogg->streams + idx;
00183 uint8_t *nb = av_malloc(os->bufsize);
00184 int size = os->bufpos - os->pstart;
00185 if(os->buf){
00186 memcpy(nb, os->buf + os->pstart, size);
00187 av_free(os->buf);
00188 }
00189 os->buf = nb;
00190 os->bufpos = size;
00191 os->pstart = 0;
00192
00193 return 0;
00194 }
00195
00196 static int
00197 ogg_read_page (AVFormatContext * s, int *str)
00198 {
00199 ByteIOContext *bc = &s->pb;
00200 ogg_t *ogg = s->priv_data;
00201 ogg_stream_t *os;
00202 int i = 0;
00203 int flags, nsegs;
00204 uint64_t gp;
00205 uint32_t serial;
00206 uint32_t seq;
00207 uint32_t crc;
00208 int size, idx;
00209 uint8_t sync[4];
00210 int sp = 0;
00211
00212 if (get_buffer (bc, sync, 4) < 4)
00213 return -1;
00214
00215 do{
00216 int c;
00217
00218 if (sync[sp & 3] == 'O' &&
00219 sync[(sp + 1) & 3] == 'g' &&
00220 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
00221 break;
00222
00223 c = url_fgetc (bc);
00224 if (c < 0)
00225 return -1;
00226 sync[sp++ & 3] = c;
00227 }while (i++ < MAX_PAGE_SIZE);
00228
00229 if (i >= MAX_PAGE_SIZE){
00230 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
00231 return -1;
00232 }
00233
00234 if (url_fgetc (bc) != 0)
00235 return -1;
00236
00237 flags = url_fgetc (bc);
00238 gp = get_le64 (bc);
00239 serial = get_le32 (bc);
00240 seq = get_le32 (bc);
00241 crc = get_le32 (bc);
00242 nsegs = url_fgetc (bc);
00243
00244 idx = ogg_find_stream (ogg, serial);
00245 if (idx < 0){
00246 idx = ogg_new_stream (s, serial);
00247 if (idx < 0)
00248 return -1;
00249 }
00250
00251 os = ogg->streams + idx;
00252
00253 if(os->psize > 0)
00254 ogg_new_buf(ogg, idx);
00255
00256 if (get_buffer (bc, os->segments, nsegs) < nsegs)
00257 return -1;
00258
00259 os->nsegs = nsegs;
00260 os->segp = 0;
00261
00262 size = 0;
00263 for (i = 0; i < nsegs; i++)
00264 size += os->segments[i];
00265
00266 if (flags & OGG_FLAG_CONT){
00267 if (!os->psize){
00268 while (os->segp < os->nsegs){
00269 int seg = os->segments[os->segp++];
00270 os->pstart += seg;
00271 if (seg < 255)
00272 break;
00273 }
00274 }
00275 }else{
00276 os->psize = 0;
00277 }
00278
00279 if (os->bufsize - os->bufpos < size){
00280 uint8_t *nb = av_malloc (os->bufsize *= 2);
00281 memcpy (nb, os->buf, os->bufpos);
00282 av_free (os->buf);
00283 os->buf = nb;
00284 }
00285
00286 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
00287 return -1;
00288
00289 os->lastgp = os->granule;
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)
00302 {
00303 ogg_t *ogg = s->priv_data;
00304 int idx;
00305 ogg_stream_t *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 }
00356 }while (!complete);
00357
00358 #if 0
00359 av_log (s, AV_LOG_DEBUG,
00360 "ogg_packet: idx %i, frame size %i, start %i\n",
00361 idx, os->psize, os->pstart);
00362 #endif
00363
00364 ogg->curidx = idx;
00365
00366 if (os->header < 0){
00367 int hdr = os->codec->header (s, idx);
00368 if (!hdr){
00369 os->header = os->seq;
00370 os->segp = segp;
00371 os->psize = psize;
00372 ogg->headers = 1;
00373 }else{
00374 os->pstart += os->psize;
00375 os->psize = 0;
00376 }
00377 }
00378
00379 if (os->header > -1 && os->seq > os->header){
00380 os->pflags = 0;
00381 if (os->codec && os->codec->packet)
00382 os->codec->packet (s, idx);
00383 if (str)
00384 *str = idx;
00385 if (dstart)
00386 *dstart = os->pstart;
00387 if (dsize)
00388 *dsize = os->psize;
00389 os->pstart += os->psize;
00390 os->psize = 0;
00391 }
00392
00393 os->seq++;
00394 if (os->segp == os->nsegs)
00395 ogg->curidx = -1;
00396
00397 return 0;
00398 }
00399
00400 static int
00401 ogg_get_headers (AVFormatContext * s)
00402 {
00403 ogg_t *ogg = s->priv_data;
00404
00405 do{
00406 if (ogg_packet (s, NULL, NULL, NULL) < 0)
00407 return -1;
00408 }while (!ogg->headers);
00409
00410 #if 0
00411 av_log (s, AV_LOG_DEBUG, "found headers\n");
00412 #endif
00413
00414 return 0;
00415 }
00416
00417 static uint64_t
00418 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
00419 {
00420 ogg_t *ogg = s->priv_data;
00421 ogg_stream_t *os = ogg->streams + i;
00422 uint64_t pts = AV_NOPTS_VALUE;
00423
00424 if(os->codec->gptopts){
00425 pts = os->codec->gptopts(s, i, gp);
00426 } else {
00427 pts = gp;
00428 }
00429
00430 return pts;
00431 }
00432
00433
00434 static int
00435 ogg_get_length (AVFormatContext * s)
00436 {
00437 ogg_t *ogg = s->priv_data;
00438 int idx = -1, i;
00439 offset_t size, end;
00440
00441 if(s->pb.is_streamed)
00442 return 0;
00443
00444
00445 if (s->duration != AV_NOPTS_VALUE)
00446 return 0;
00447
00448 size = url_fsize(&s->pb);
00449 if(size < 0)
00450 return 0;
00451 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
00452
00453 ogg_save (s);
00454 url_fseek (&s->pb, end, SEEK_SET);
00455
00456 while (!ogg_read_page (s, &i)){
00457 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
00458 ogg->streams[i].codec)
00459 idx = i;
00460 }
00461
00462 if (idx != -1){
00463 s->streams[idx]->duration =
00464 ogg_gptopts (s, idx, ogg->streams[idx].granule);
00465 }
00466
00467 ogg->size = size;
00468 ogg_restore (s, 0);
00469 ogg_save (s);
00470 while (!ogg_read_page (s, &i)) {
00471 if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
00472 break;
00473 }
00474 if (i == idx) {
00475 s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
00476 s->streams[idx]->duration -= s->streams[idx]->start_time;
00477 }
00478 ogg_restore (s, 0);
00479
00480 return 0;
00481 }
00482
00483
00484 static int
00485 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
00486 {
00487 ogg_t *ogg = s->priv_data;
00488 ogg->curidx = -1;
00489
00490 if (ogg_get_headers (s) < 0){
00491 return -1;
00492 }
00493
00494
00495 ogg_get_length (s);
00496
00497
00498 return 0;
00499 }
00500
00501
00502 static int
00503 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
00504 {
00505 ogg_t *ogg;
00506 ogg_stream_t *os;
00507 int idx = -1;
00508 int pstart, psize;
00509
00510
00511 do{
00512 if (ogg_packet (s, &idx, &pstart, &psize) < 0)
00513 return AVERROR(EIO);
00514 }while (idx < 0 || !s->streams[idx]);
00515
00516 ogg = s->priv_data;
00517 os = ogg->streams + idx;
00518
00519
00520 if (av_new_packet (pkt, psize) < 0)
00521 return AVERROR(EIO);
00522 pkt->stream_index = idx;
00523 memcpy (pkt->data, os->buf + pstart, psize);
00524 if (os->lastgp != -1LL){
00525 pkt->pts = ogg_gptopts (s, idx, os->lastgp);
00526 os->lastgp = -1;
00527 }
00528
00529 pkt->flags = os->pflags;
00530
00531 return psize;
00532 }
00533
00534
00535 static int
00536 ogg_read_close (AVFormatContext * s)
00537 {
00538 ogg_t *ogg = s->priv_data;
00539 int i;
00540
00541 for (i = 0; i < ogg->nstreams; i++){
00542 av_free (ogg->streams[i].buf);
00543 av_free (ogg->streams[i].private);
00544 }
00545 av_free (ogg->streams);
00546 return 0;
00547 }
00548
00549
00550 static int64_t
00551 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
00552 int64_t pos_limit)
00553 {
00554 ogg_t *ogg = s->priv_data;
00555 ByteIOContext *bc = &s->pb;
00556 int64_t pts = AV_NOPTS_VALUE;
00557 int i;
00558 url_fseek(bc, *pos_arg, SEEK_SET);
00559 while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
00560 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
00561 ogg->streams[i].codec && i == stream_index) {
00562 pts = ogg_gptopts(s, i, ogg->streams[i].granule);
00563
00564
00565 *pos_arg = url_ftell(bc);
00566 break;
00567 }
00568 }
00569 ogg_reset(ogg);
00570 return pts;
00571 }
00572
00573 static int ogg_probe(AVProbeData *p)
00574 {
00575 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
00576 p->buf[2] == 'g' && p->buf[3] == 'S' &&
00577 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
00578 return AVPROBE_SCORE_MAX;
00579 else
00580 return 0;
00581 }
00582
00583 AVInputFormat ogg_demuxer = {
00584 "ogg",
00585 "Ogg",
00586 sizeof (ogg_t),
00587 ogg_probe,
00588 ogg_read_header,
00589 ogg_read_packet,
00590 ogg_read_close,
00591 NULL,
00592 ogg_read_timestamp,
00593 .extensions = "ogg",
00594 };