Libav 0.7.1
|
00001 /* 00002 * Ogg bitstream support 00003 * Luca Barbato <lu_zero@gentoo.org> 00004 * Based on tcvp implementation 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 //FIXME We could avoid some structure duplication 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 = av_new_stream(s, idx); 00175 if (!st) 00176 return AVERROR(ENOMEM); 00177 00178 av_set_pts_info(st, 64, 1, 1000000); 00179 } 00180 00181 return idx; 00182 } 00183 00184 static int ogg_new_buf(struct ogg *ogg, int idx) 00185 { 00186 struct ogg_stream *os = ogg->streams + idx; 00187 uint8_t *nb = av_malloc(os->bufsize); 00188 int size = os->bufpos - os->pstart; 00189 if(os->buf){ 00190 memcpy(nb, os->buf + os->pstart, size); 00191 av_free(os->buf); 00192 } 00193 os->buf = nb; 00194 os->bufpos = size; 00195 os->pstart = 0; 00196 00197 return 0; 00198 } 00199 00200 static int ogg_read_page(AVFormatContext *s, int *str) 00201 { 00202 AVIOContext *bc = s->pb; 00203 struct ogg *ogg = s->priv_data; 00204 struct ogg_stream *os; 00205 int i = 0; 00206 int flags, nsegs; 00207 uint64_t gp; 00208 uint32_t serial; 00209 int size, idx; 00210 uint8_t sync[4]; 00211 int sp = 0; 00212 00213 if (avio_read (bc, sync, 4) < 4) 00214 return -1; 00215 00216 do{ 00217 int c; 00218 00219 if (sync[sp & 3] == 'O' && 00220 sync[(sp + 1) & 3] == 'g' && 00221 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S') 00222 break; 00223 00224 c = avio_r8(bc); 00225 if (bc->eof_reached) 00226 return -1; 00227 sync[sp++ & 3] = c; 00228 }while (i++ < MAX_PAGE_SIZE); 00229 00230 if (i >= MAX_PAGE_SIZE){ 00231 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n"); 00232 return -1; 00233 } 00234 00235 if (avio_r8(bc) != 0) /* version */ 00236 return -1; 00237 00238 flags = avio_r8(bc); 00239 gp = avio_rl64 (bc); 00240 serial = avio_rl32 (bc); 00241 avio_skip(bc, 8); /* seq, crc */ 00242 nsegs = avio_r8(bc); 00243 00244 idx = ogg_find_stream (ogg, serial); 00245 if (idx < 0){ 00246 if (ogg->headers) { 00247 int n; 00248 00249 for (n = 0; n < ogg->nstreams; n++) { 00250 av_freep(&ogg->streams[n].buf); 00251 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private) 00252 av_freep(&ogg->streams[n].private); 00253 } 00254 ogg->curidx = -1; 00255 ogg->nstreams = 0; 00256 idx = ogg_new_stream(s, serial, 0); 00257 } else { 00258 idx = ogg_new_stream(s, serial, 1); 00259 } 00260 if (idx < 0) 00261 return -1; 00262 } 00263 00264 os = ogg->streams + idx; 00265 os->page_pos = avio_tell(bc) - 27; 00266 00267 if(os->psize > 0) 00268 ogg_new_buf(ogg, idx); 00269 00270 if (avio_read (bc, os->segments, nsegs) < nsegs) 00271 return -1; 00272 00273 os->nsegs = nsegs; 00274 os->segp = 0; 00275 00276 size = 0; 00277 for (i = 0; i < nsegs; i++) 00278 size += os->segments[i]; 00279 00280 if (flags & OGG_FLAG_CONT || os->incomplete){ 00281 if (!os->psize){ 00282 while (os->segp < os->nsegs){ 00283 int seg = os->segments[os->segp++]; 00284 os->pstart += seg; 00285 if (seg < 255) 00286 break; 00287 } 00288 os->sync_pos = os->page_pos; 00289 } 00290 }else{ 00291 os->psize = 0; 00292 os->sync_pos = os->page_pos; 00293 } 00294 00295 if (os->bufsize - os->bufpos < size){ 00296 uint8_t *nb = av_malloc (os->bufsize *= 2); 00297 memcpy (nb, os->buf, os->bufpos); 00298 av_free (os->buf); 00299 os->buf = nb; 00300 } 00301 00302 if (avio_read (bc, os->buf + os->bufpos, size) < size) 00303 return -1; 00304 00305 os->bufpos += size; 00306 os->granule = gp; 00307 os->flags = flags; 00308 00309 if (str) 00310 *str = idx; 00311 00312 return 0; 00313 } 00314 00315 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize, 00316 int64_t *fpos) 00317 { 00318 struct ogg *ogg = s->priv_data; 00319 int idx, i; 00320 struct ogg_stream *os; 00321 int complete = 0; 00322 int segp = 0, psize = 0; 00323 00324 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx); 00325 00326 do{ 00327 idx = ogg->curidx; 00328 00329 while (idx < 0){ 00330 if (ogg_read_page (s, &idx) < 0) 00331 return -1; 00332 } 00333 00334 os = ogg->streams + idx; 00335 00336 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n", 00337 idx, os->pstart, os->psize, os->segp, os->nsegs); 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 av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n", 00370 idx, os->psize, os->pstart); 00371 00372 if (os->granule == -1) 00373 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos); 00374 00375 ogg->curidx = idx; 00376 os->incomplete = 0; 00377 00378 if (os->header) { 00379 os->header = os->codec->header (s, idx); 00380 if (!os->header){ 00381 os->segp = segp; 00382 os->psize = psize; 00383 00384 // We have reached the first non-header packet in this stream. 00385 // Unfortunately more header packets may still follow for others, 00386 // but if we continue with header parsing we may lose data packets. 00387 ogg->headers = 1; 00388 00389 // Update the header state for all streams and 00390 // compute the data_offset. 00391 if (!s->data_offset) 00392 s->data_offset = os->sync_pos; 00393 for (i = 0; i < ogg->nstreams; i++) { 00394 struct ogg_stream *cur_os = ogg->streams + i; 00395 00396 // if we have a partial non-header packet, its start is 00397 // obviously at or after the data start 00398 if (cur_os->incomplete) 00399 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos); 00400 } 00401 }else{ 00402 os->pstart += os->psize; 00403 os->psize = 0; 00404 } 00405 } else { 00406 os->pflags = 0; 00407 os->pduration = 0; 00408 if (os->codec && os->codec->packet) 00409 os->codec->packet (s, idx); 00410 if (str) 00411 *str = idx; 00412 if (dstart) 00413 *dstart = os->pstart; 00414 if (dsize) 00415 *dsize = os->psize; 00416 if (fpos) 00417 *fpos = os->sync_pos; 00418 os->pstart += os->psize; 00419 os->psize = 0; 00420 os->sync_pos = os->page_pos; 00421 } 00422 00423 // determine whether there are more complete packets in this page 00424 // if not, the page's granule will apply to this packet 00425 os->page_end = 1; 00426 for (i = os->segp; i < os->nsegs; i++) 00427 if (os->segments[i] < 255) { 00428 os->page_end = 0; 00429 break; 00430 } 00431 00432 if (os->segp == os->nsegs) 00433 ogg->curidx = -1; 00434 00435 return 0; 00436 } 00437 00438 static int ogg_get_headers(AVFormatContext *s) 00439 { 00440 struct ogg *ogg = s->priv_data; 00441 00442 do{ 00443 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0) 00444 return -1; 00445 }while (!ogg->headers); 00446 00447 av_dlog(s, "found headers\n"); 00448 00449 return 0; 00450 } 00451 00452 static int ogg_get_length(AVFormatContext *s) 00453 { 00454 struct ogg *ogg = s->priv_data; 00455 int i; 00456 int64_t size, end; 00457 00458 if(!s->pb->seekable) 00459 return 0; 00460 00461 // already set 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 static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap) 00489 { 00490 struct ogg *ogg = s->priv_data; 00491 int i; 00492 ogg->curidx = -1; 00493 //linear headers seek from start 00494 if (ogg_get_headers (s) < 0){ 00495 return -1; 00496 } 00497 00498 for (i = 0; i < ogg->nstreams; i++) 00499 if (ogg->streams[i].header < 0) 00500 ogg->streams[i].codec = NULL; 00501 00502 //linear granulepos seek from end 00503 ogg_get_length (s); 00504 00505 //fill the extradata in the per codec callbacks 00506 return 0; 00507 } 00508 00509 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts) 00510 { 00511 struct ogg *ogg = s->priv_data; 00512 struct ogg_stream *os = ogg->streams + idx; 00513 int64_t pts = AV_NOPTS_VALUE; 00514 00515 if (dts) 00516 *dts = AV_NOPTS_VALUE; 00517 00518 if (os->lastpts != AV_NOPTS_VALUE) { 00519 pts = os->lastpts; 00520 os->lastpts = AV_NOPTS_VALUE; 00521 } 00522 if (os->lastdts != AV_NOPTS_VALUE) { 00523 if (dts) 00524 *dts = os->lastdts; 00525 os->lastdts = AV_NOPTS_VALUE; 00526 } 00527 if (os->page_end) { 00528 if (os->granule != -1LL) { 00529 if (os->codec && os->codec->granule_is_start) 00530 pts = ogg_gptopts(s, idx, os->granule, dts); 00531 else 00532 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts); 00533 os->granule = -1LL; 00534 } 00535 } 00536 return pts; 00537 } 00538 00539 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt) 00540 { 00541 struct ogg *ogg; 00542 struct ogg_stream *os; 00543 int idx = -1; 00544 int pstart, psize; 00545 int64_t fpos, pts, dts; 00546 00547 //Get an ogg packet 00548 retry: 00549 do{ 00550 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0) 00551 return AVERROR(EIO); 00552 }while (idx < 0 || !s->streams[idx]); 00553 00554 ogg = s->priv_data; 00555 os = ogg->streams + idx; 00556 00557 // pflags might not be set until after this 00558 pts = ogg_calc_pts(s, idx, &dts); 00559 00560 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY)) 00561 goto retry; 00562 os->keyframe_seek = 0; 00563 00564 //Alloc a pkt 00565 if (av_new_packet (pkt, psize) < 0) 00566 return AVERROR(EIO); 00567 pkt->stream_index = idx; 00568 memcpy (pkt->data, os->buf + pstart, psize); 00569 00570 pkt->pts = pts; 00571 pkt->dts = dts; 00572 pkt->flags = os->pflags; 00573 pkt->duration = os->pduration; 00574 pkt->pos = fpos; 00575 00576 return psize; 00577 } 00578 00579 static int ogg_read_close(AVFormatContext *s) 00580 { 00581 struct ogg *ogg = s->priv_data; 00582 int i; 00583 00584 for (i = 0; i < ogg->nstreams; i++){ 00585 av_free (ogg->streams[i].buf); 00586 av_free (ogg->streams[i].private); 00587 } 00588 av_free (ogg->streams); 00589 return 0; 00590 } 00591 00592 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index, 00593 int64_t *pos_arg, int64_t pos_limit) 00594 { 00595 struct ogg *ogg = s->priv_data; 00596 AVIOContext *bc = s->pb; 00597 int64_t pts = AV_NOPTS_VALUE; 00598 int i = -1; 00599 avio_seek(bc, *pos_arg, SEEK_SET); 00600 ogg_reset(ogg); 00601 00602 while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) { 00603 if (i == stream_index) { 00604 struct ogg_stream *os = ogg->streams + stream_index; 00605 pts = ogg_calc_pts(s, i, NULL); 00606 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY)) 00607 pts = AV_NOPTS_VALUE; 00608 } 00609 if (pts != AV_NOPTS_VALUE) 00610 break; 00611 } 00612 ogg_reset(ogg); 00613 return pts; 00614 } 00615 00616 static int ogg_read_seek(AVFormatContext *s, int stream_index, 00617 int64_t timestamp, int flags) 00618 { 00619 struct ogg *ogg = s->priv_data; 00620 struct ogg_stream *os = ogg->streams + stream_index; 00621 int ret; 00622 00623 // Try seeking to a keyframe first. If this fails (very possible), 00624 // av_seek_frame will fall back to ignoring keyframes 00625 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO 00626 && !(flags & AVSEEK_FLAG_ANY)) 00627 os->keyframe_seek = 1; 00628 00629 ret = av_seek_frame_binary(s, stream_index, timestamp, flags); 00630 os = ogg->streams + stream_index; 00631 if (ret < 0) 00632 os->keyframe_seek = 0; 00633 return ret; 00634 } 00635 00636 static int ogg_probe(AVProbeData *p) 00637 { 00638 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7) 00639 return AVPROBE_SCORE_MAX; 00640 return 0; 00641 } 00642 00643 AVInputFormat ff_ogg_demuxer = { 00644 .name = "ogg", 00645 .long_name = NULL_IF_CONFIG_SMALL("Ogg"), 00646 .priv_data_size = sizeof(struct ogg), 00647 .read_probe = ogg_probe, 00648 .read_header = ogg_read_header, 00649 .read_packet = ogg_read_packet, 00650 .read_close = ogg_read_close, 00651 .read_seek = ogg_read_seek, 00652 .read_timestamp = ogg_read_timestamp, 00653 .extensions = "ogg", 00654 .flags = AVFMT_GENERIC_INDEX, 00655 };