Libav
|
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 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 for (i = 0; i < ogg->nstreams; i++) 00098 av_free (ogg->streams[i].buf); 00099 00100 url_fseek (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 ByteIOContext *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 (get_buffer (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 = url_fgetc (bc); 00222 if (c < 0) 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 (url_fgetc (bc) != 0) /* version */ 00233 return -1; 00234 00235 flags = url_fgetc (bc); 00236 gp = get_le64 (bc); 00237 serial = get_le32 (bc); 00238 seq = get_le32 (bc); 00239 crc = get_le32 (bc); 00240 nsegs = url_fgetc (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 = url_ftell(bc) - 27; 00251 00252 if(os->psize > 0) 00253 ogg_new_buf(ogg, idx); 00254 00255 if (get_buffer (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 (get_buffer (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 %lld 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 if (!ogg->headers) 00377 s->data_offset = os->sync_pos; 00378 ogg->headers = 1; 00379 }else{ 00380 os->pstart += os->psize; 00381 os->psize = 0; 00382 } 00383 } else { 00384 os->pflags = 0; 00385 os->pduration = 0; 00386 if (os->codec && os->codec->packet) 00387 os->codec->packet (s, idx); 00388 if (str) 00389 *str = idx; 00390 if (dstart) 00391 *dstart = os->pstart; 00392 if (dsize) 00393 *dsize = os->psize; 00394 if (fpos) 00395 *fpos = os->sync_pos; 00396 os->pstart += os->psize; 00397 os->psize = 0; 00398 os->sync_pos = os->page_pos; 00399 } 00400 00401 // determine whether there are more complete packets in this page 00402 // if not, the page's granule will apply to this packet 00403 os->page_end = 1; 00404 for (i = os->segp; i < os->nsegs; i++) 00405 if (os->segments[i] < 255) { 00406 os->page_end = 0; 00407 break; 00408 } 00409 00410 if (os->segp == os->nsegs) 00411 ogg->curidx = -1; 00412 00413 return 0; 00414 } 00415 00416 static int 00417 ogg_get_headers (AVFormatContext * s) 00418 { 00419 struct ogg *ogg = s->priv_data; 00420 00421 do{ 00422 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0) 00423 return -1; 00424 }while (!ogg->headers); 00425 00426 #if 0 00427 av_log (s, AV_LOG_DEBUG, "found headers\n"); 00428 #endif 00429 00430 return 0; 00431 } 00432 00433 static int 00434 ogg_get_length (AVFormatContext * s) 00435 { 00436 struct ogg *ogg = s->priv_data; 00437 int i; 00438 int64_t size, end; 00439 00440 if(url_is_streamed(s->pb)) 00441 return 0; 00442 00443 // already set 00444 if (s->duration != AV_NOPTS_VALUE) 00445 return 0; 00446 00447 size = url_fsize(s->pb); 00448 if(size < 0) 00449 return 0; 00450 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0; 00451 00452 ogg_save (s); 00453 url_fseek (s->pb, end, SEEK_SET); 00454 00455 while (!ogg_read_page (s, &i)){ 00456 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && 00457 ogg->streams[i].codec) { 00458 s->streams[i]->duration = 00459 ogg_gptopts (s, i, ogg->streams[i].granule, NULL); 00460 if (s->streams[i]->start_time != AV_NOPTS_VALUE) 00461 s->streams[i]->duration -= s->streams[i]->start_time; 00462 } 00463 } 00464 00465 ogg_restore (s, 0); 00466 00467 return 0; 00468 } 00469 00470 00471 static int 00472 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap) 00473 { 00474 struct ogg *ogg = s->priv_data; 00475 int i; 00476 ogg->curidx = -1; 00477 //linear headers seek from start 00478 if (ogg_get_headers (s) < 0){ 00479 return -1; 00480 } 00481 00482 for (i = 0; i < ogg->nstreams; i++) 00483 if (ogg->streams[i].header < 0) 00484 ogg->streams[i].codec = NULL; 00485 00486 //linear granulepos seek from end 00487 ogg_get_length (s); 00488 00489 //fill the extradata in the per codec callbacks 00490 return 0; 00491 } 00492 00493 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts) 00494 { 00495 struct ogg *ogg = s->priv_data; 00496 struct ogg_stream *os = ogg->streams + idx; 00497 int64_t pts = AV_NOPTS_VALUE; 00498 00499 if (dts) 00500 *dts = AV_NOPTS_VALUE; 00501 00502 if (os->lastpts != AV_NOPTS_VALUE) { 00503 pts = os->lastpts; 00504 os->lastpts = AV_NOPTS_VALUE; 00505 } 00506 if (os->lastdts != AV_NOPTS_VALUE) { 00507 if (dts) 00508 *dts = os->lastdts; 00509 os->lastdts = AV_NOPTS_VALUE; 00510 } 00511 if (os->page_end) { 00512 if (os->granule != -1LL) { 00513 if (os->codec && os->codec->granule_is_start) 00514 pts = ogg_gptopts(s, idx, os->granule, dts); 00515 else 00516 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts); 00517 os->granule = -1LL; 00518 } 00519 } 00520 return pts; 00521 } 00522 00523 static int 00524 ogg_read_packet (AVFormatContext * s, AVPacket * pkt) 00525 { 00526 struct ogg *ogg; 00527 struct ogg_stream *os; 00528 int idx = -1; 00529 int pstart, psize; 00530 int64_t fpos, pts, dts; 00531 00532 //Get an ogg packet 00533 retry: 00534 do{ 00535 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0) 00536 return AVERROR(EIO); 00537 }while (idx < 0 || !s->streams[idx]); 00538 00539 ogg = s->priv_data; 00540 os = ogg->streams + idx; 00541 00542 // pflags might not be set until after this 00543 pts = ogg_calc_pts(s, idx, &dts); 00544 00545 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY)) 00546 goto retry; 00547 os->keyframe_seek = 0; 00548 00549 //Alloc a pkt 00550 if (av_new_packet (pkt, psize) < 0) 00551 return AVERROR(EIO); 00552 pkt->stream_index = idx; 00553 memcpy (pkt->data, os->buf + pstart, psize); 00554 00555 pkt->pts = pts; 00556 pkt->dts = dts; 00557 pkt->flags = os->pflags; 00558 pkt->duration = os->pduration; 00559 pkt->pos = fpos; 00560 00561 return psize; 00562 } 00563 00564 00565 static int 00566 ogg_read_close (AVFormatContext * s) 00567 { 00568 struct ogg *ogg = s->priv_data; 00569 int i; 00570 00571 for (i = 0; i < ogg->nstreams; i++){ 00572 av_free (ogg->streams[i].buf); 00573 av_free (ogg->streams[i].private); 00574 } 00575 av_free (ogg->streams); 00576 return 0; 00577 } 00578 00579 00580 static int64_t 00581 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, 00582 int64_t pos_limit) 00583 { 00584 struct ogg *ogg = s->priv_data; 00585 ByteIOContext *bc = s->pb; 00586 int64_t pts = AV_NOPTS_VALUE; 00587 int i = -1; 00588 url_fseek(bc, *pos_arg, SEEK_SET); 00589 ogg_reset(ogg); 00590 00591 while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) { 00592 if (i == stream_index) { 00593 struct ogg_stream *os = ogg->streams + stream_index; 00594 pts = ogg_calc_pts(s, i, NULL); 00595 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY)) 00596 pts = AV_NOPTS_VALUE; 00597 } 00598 if (pts != AV_NOPTS_VALUE) 00599 break; 00600 } 00601 ogg_reset(ogg); 00602 return pts; 00603 } 00604 00605 static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 00606 { 00607 struct ogg *ogg = s->priv_data; 00608 struct ogg_stream *os = ogg->streams + stream_index; 00609 int ret; 00610 00611 // Try seeking to a keyframe first. If this fails (very possible), 00612 // av_seek_frame will fall back to ignoring keyframes 00613 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO 00614 && !(flags & AVSEEK_FLAG_ANY)) 00615 os->keyframe_seek = 1; 00616 00617 ret = av_seek_frame_binary(s, stream_index, timestamp, flags); 00618 os = ogg->streams + stream_index; 00619 if (ret < 0) 00620 os->keyframe_seek = 0; 00621 return ret; 00622 } 00623 00624 static int ogg_probe(AVProbeData *p) 00625 { 00626 if (p->buf[0] == 'O' && p->buf[1] == 'g' && 00627 p->buf[2] == 'g' && p->buf[3] == 'S' && 00628 p->buf[4] == 0x0 && p->buf[5] <= 0x7 ) 00629 return AVPROBE_SCORE_MAX; 00630 else 00631 return 0; 00632 } 00633 00634 AVInputFormat ogg_demuxer = { 00635 "ogg", 00636 NULL_IF_CONFIG_SMALL("Ogg"), 00637 sizeof (struct ogg), 00638 ogg_probe, 00639 ogg_read_header, 00640 ogg_read_packet, 00641 ogg_read_close, 00642 ogg_read_seek, 00643 ogg_read_timestamp, 00644 .extensions = "ogg", 00645 .metadata_conv = ff_vorbiscomment_metadata_conv, 00646 .flags = AVFMT_GENERIC_INDEX, 00647 };