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