mirror of https://github.com/FFmpeg/FFmpeg.git
fixups by me. Originally committed as revision 4113 to svn://svn.ffmpeg.org/ffmpeg/trunkpull/126/head
parent
a18ba90880
commit
9146ca3700
8 changed files with 918 additions and 18 deletions
@ -0,0 +1,643 @@ |
||||
/*
|
||||
* Ogg bitstream support |
||||
* Luca Barbato <lu_zero@gentoo.org> |
||||
* Based on tcvp implementation |
||||
*
|
||||
*/ |
||||
|
||||
/**
|
||||
Copyright (C) 2005 Michael Ahlberg, Måns Rullgård |
||||
|
||||
Permission is hereby granted, free of charge, to any person |
||||
obtaining a copy of this software and associated documentation |
||||
files (the "Software"), to deal in the Software without |
||||
restriction, including without limitation the rights to use, copy, |
||||
modify, merge, publish, distribute, sublicense, and/or sell copies |
||||
of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
**/ |
||||
|
||||
|
||||
#include <stdio.h> |
||||
#include "ogg2.h" |
||||
#include "avformat.h" |
||||
|
||||
#define MAX_PAGE_SIZE 65307 |
||||
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE |
||||
|
||||
static ogg_codec_t *ogg_codecs[] = { |
||||
&vorbis_codec, |
||||
NULL |
||||
}; |
||||
|
||||
#if 0 // CONFIG_ENCODERS
|
||||
static int |
||||
ogg_write_header (AVFormatContext * avfcontext) |
||||
{ |
||||
} |
||||
|
||||
static int |
||||
ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt) |
||||
{ |
||||
} |
||||
|
||||
|
||||
static int |
||||
ogg_write_trailer (AVFormatContext * avfcontext) |
||||
{ |
||||
} |
||||
|
||||
|
||||
static AVOutputFormat ogg_oformat = { |
||||
"ogg", |
||||
"Ogg Vorbis", |
||||
"audio/x-vorbis", |
||||
"ogg", |
||||
sizeof (OggContext), |
||||
CODEC_ID_VORBIS, |
||||
0, |
||||
ogg_write_header, |
||||
ogg_write_packet, |
||||
ogg_write_trailer, |
||||
}; |
||||
#endif //CONFIG_ENCODERS
|
||||
|
||||
//FIXME We could avoid some structure duplication
|
||||
static int |
||||
ogg_save (AVFormatContext * s) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
ogg_state_t *ost = |
||||
av_malloc(sizeof (*ost) + ogg->nstreams * sizeof (*ogg->streams)); |
||||
int i; |
||||
ost->pos = url_ftell (&s->pb);; |
||||
ost->curidx = ogg->curidx; |
||||
ost->next = ogg->state; |
||||
memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams)); |
||||
|
||||
for (i = 0; i < ogg->nstreams; i++){ |
||||
ogg_stream_t *os = ogg->streams + i; |
||||
os->buf = av_malloc (os->bufsize); |
||||
memset (os->buf, 0, os->bufsize); |
||||
memcpy (os->buf, ost->streams[i].buf, os->bufpos); |
||||
} |
||||
|
||||
ogg->state = ost; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
ogg_restore (AVFormatContext * s, int discard) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
ByteIOContext *bc = &s->pb; |
||||
ogg_state_t *ost = ogg->state; |
||||
int i; |
||||
|
||||
if (!ost) |
||||
return 0; |
||||
|
||||
ogg->state = ost->next; |
||||
|
||||
if (!discard){ |
||||
for (i = 0; i < ogg->nstreams; i++) |
||||
av_free (ogg->streams[i].buf); |
||||
|
||||
url_fseek (bc, ost->pos, SEEK_SET); |
||||
ogg->curidx = ost->curidx; |
||||
memcpy (ogg->streams, ost->streams, |
||||
ogg->nstreams * sizeof (*ogg->streams)); |
||||
} |
||||
|
||||
av_free (ost); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
ogg_reset (ogg_t * ogg) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < ogg->nstreams; i++){ |
||||
ogg_stream_t *os = ogg->streams + i; |
||||
os->bufpos = 0; |
||||
os->pstart = 0; |
||||
os->psize = 0; |
||||
os->granule = -1; |
||||
os->lastgp = -1; |
||||
os->nsegs = 0; |
||||
os->segp = 0; |
||||
} |
||||
|
||||
ogg->curidx = -1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static ogg_codec_t * |
||||
ogg_find_codec (u_char * buf, int size) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; ogg_codecs[i]; i++) |
||||
if (size >= ogg_codecs[i]->magicsize && |
||||
!memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize)) |
||||
return ogg_codecs[i]; |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static int |
||||
ogg_find_stream (ogg_t * ogg, int serial) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < ogg->nstreams; i++) |
||||
if (ogg->streams[i].serial == serial) |
||||
return i; |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
static int |
||||
ogg_new_stream (AVFormatContext * s, uint32_t serial) |
||||
{ |
||||
|
||||
ogg_t *ogg = s->priv_data; |
||||
int idx = ogg->nstreams++; |
||||
AVStream *st; |
||||
ogg_stream_t *os; |
||||
|
||||
ogg->streams = av_realloc (ogg->streams, |
||||
ogg->nstreams * sizeof (*ogg->streams)); |
||||
memset (ogg->streams + idx, 0, sizeof (*ogg->streams)); |
||||
os = ogg->streams + idx; |
||||
os->serial = serial; |
||||
os->bufsize = DECODER_BUFFER_SIZE; |
||||
os->buf = av_malloc (os->bufsize); |
||||
memset (os->buf, 0, os->bufsize); |
||||
os->header = -1; |
||||
|
||||
st = av_new_stream (s, idx); |
||||
if (!st) |
||||
return AVERROR_NOMEM; |
||||
|
||||
av_set_pts_info(st, 64, 1, 1000000); |
||||
st->start_time = 0; |
||||
|
||||
return idx; |
||||
} |
||||
|
||||
static int |
||||
ogg_read_page (AVFormatContext * s, int *str) |
||||
{ |
||||
ByteIOContext *bc = &s->pb; |
||||
ogg_t *ogg = s->priv_data; |
||||
ogg_stream_t *os; |
||||
int i = 0; |
||||
int flags, nsegs; |
||||
uint64_t gp; |
||||
uint32_t serial; |
||||
uint32_t seq; |
||||
uint32_t crc; |
||||
int size, idx; |
||||
char sync[4]; |
||||
int sp = 0; |
||||
|
||||
if (get_buffer (bc, sync, 4) < 4) |
||||
return -1; |
||||
|
||||
do{ |
||||
int c; |
||||
|
||||
if (sync[sp & 3] == 'O' && |
||||
sync[(sp + 1) & 3] == 'g' && |
||||
sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S') |
||||
break; |
||||
|
||||
c = url_fgetc (bc); |
||||
if (c < 0) |
||||
return -1; |
||||
sync[sp++ & 3] = c; |
||||
}while (i++ < MAX_PAGE_SIZE); |
||||
|
||||
if (i >= MAX_PAGE_SIZE){ |
||||
av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n"); |
||||
return -1; |
||||
} |
||||
|
||||
if (url_fgetc (bc) != 0) /* version */ |
||||
return -1; |
||||
|
||||
flags = url_fgetc (bc); |
||||
gp = get_le64 (bc); |
||||
serial = get_le32 (bc); |
||||
seq = get_le32 (bc); |
||||
crc = get_le32 (bc); |
||||
nsegs = url_fgetc (bc); |
||||
|
||||
idx = ogg_find_stream (ogg, serial); |
||||
if (idx < 0){ |
||||
idx = ogg_new_stream (s, serial); |
||||
if (idx < 0) |
||||
return -1; |
||||
} |
||||
|
||||
os = ogg->streams + idx; |
||||
|
||||
if (get_buffer (bc, os->segments, nsegs) < nsegs) |
||||
return -1; |
||||
|
||||
os->nsegs = nsegs; |
||||
os->segp = 0; |
||||
|
||||
size = 0; |
||||
for (i = 0; i < nsegs; i++) |
||||
size += os->segments[i]; |
||||
|
||||
if (flags & OGG_FLAG_CONT){ |
||||
if (!os->psize){ |
||||
while (os->segp < os->nsegs){ |
||||
int seg = os->segments[os->segp++]; |
||||
os->pstart += seg; |
||||
if (seg < 255) |
||||
break; |
||||
} |
||||
} |
||||
}else{ |
||||
os->psize = 0; |
||||
} |
||||
|
||||
if (os->bufsize - os->bufpos < size){ |
||||
u_char *nb = av_malloc (os->bufsize *= 2); |
||||
memset (nb, 0, os->bufsize); |
||||
memcpy (nb, os->buf, os->bufpos); |
||||
av_free (os->buf); |
||||
os->buf = nb; |
||||
} |
||||
|
||||
if (get_buffer (bc, os->buf + os->bufpos, size) < size) |
||||
return -1; |
||||
|
||||
os->lastgp = os->granule; |
||||
os->bufpos += size; |
||||
os->granule = gp; |
||||
os->flags = flags; |
||||
|
||||
if (str) |
||||
*str = idx; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
ogg_packet (AVFormatContext * s, int *str) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
int idx; |
||||
ogg_stream_t *os; |
||||
int complete = 0; |
||||
int segp = 0, psize = 0; |
||||
|
||||
#if 0 |
||||
av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx); |
||||
#endif |
||||
|
||||
do{ |
||||
idx = ogg->curidx; |
||||
|
||||
while (idx < 0){ |
||||
if (ogg_read_page (s, &idx) < 0) |
||||
return -1; |
||||
} |
||||
|
||||
os = ogg->streams + idx; |
||||
|
||||
#if 0 |
||||
av_log (s, AV_LOG_DEBUG, |
||||
"ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n", |
||||
idx, os->pstart, os->psize, os->segp, os->nsegs); |
||||
#endif |
||||
|
||||
if (!os->codec){ |
||||
if (os->header < 0){ |
||||
os->codec = ogg_find_codec (os->buf, os->bufpos); |
||||
if (!os->codec){ |
||||
os->header = 0; |
||||
return 0; |
||||
} |
||||
}else{ |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
segp = os->segp; |
||||
psize = os->psize; |
||||
|
||||
while (os->segp < os->nsegs){ |
||||
int ss = os->segments[os->segp++]; |
||||
os->psize += ss; |
||||
if (ss < 255){ |
||||
complete = 1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!complete && os->segp == os->nsegs){ |
||||
u_char *nb = av_malloc (os->bufsize); |
||||
int size = os->bufpos - os->pstart; |
||||
memset (nb, 0, os->bufsize); |
||||
memcpy (nb, os->buf + os->pstart, size); |
||||
av_free (os->buf); |
||||
os->buf = nb; |
||||
os->bufpos = size; |
||||
os->pstart = 0; |
||||
ogg->curidx = -1; |
||||
} |
||||
}while (!complete); |
||||
|
||||
#if 0 |
||||
av_log (s, AV_LOG_DEBUG, |
||||
"ogg_packet: idx %i, frame size %i, start %i\n", |
||||
idx, os->psize, os->pstart); |
||||
#endif |
||||
|
||||
ogg->curidx = idx; |
||||
|
||||
if (os->header < 0){ |
||||
int hdr = os->codec->header (s, idx); |
||||
if (!hdr){ |
||||
os->header = os->seq; |
||||
os->segp = segp; |
||||
os->psize = psize; |
||||
ogg->headers = 1; |
||||
}else{ |
||||
os->pstart += os->psize; |
||||
os->psize = 0; |
||||
} |
||||
} |
||||
|
||||
if (os->header > -1 && os->seq > os->header){ |
||||
if (os->codec && os->codec->packet) |
||||
os->codec->packet (s, idx); |
||||
if (str) |
||||
*str = idx; |
||||
} |
||||
|
||||
os->seq++; |
||||
if (os->segp == os->nsegs) |
||||
ogg->curidx = -1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
ogg_get_headers (AVFormatContext * s) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
|
||||
do{ |
||||
if (ogg_packet (s, NULL) < 0) |
||||
return -1; |
||||
}while (!ogg->headers); |
||||
|
||||
#if 0 |
||||
av_log (s, AV_LOG_DEBUG, "found headers\n"); |
||||
#endif |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static uint64_t |
||||
ogg_gptopts (AVFormatContext * s, int i, uint64_t gp) |
||||
{ |
||||
AVStream *st = s->streams[i]; |
||||
AVCodecContext *codec = &st->codec; |
||||
uint64_t pts = AV_NOPTS_VALUE; |
||||
|
||||
if (codec->codec_type == CODEC_TYPE_AUDIO){ |
||||
pts = gp * 1000000LL / codec->sample_rate; |
||||
}else if (codec->codec_type == CODEC_TYPE_VIDEO){ |
||||
//FIXME
|
||||
pts = gp * 1000000LL / codec->sample_rate; |
||||
// pts = gp * st->video.frame_rate.den * 27000000LL /
|
||||
// st->video.frame_rate.num;
|
||||
} |
||||
|
||||
return pts; |
||||
} |
||||
|
||||
|
||||
static int |
||||
ogg_get_length (AVFormatContext * s) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
URLContext *h = url_fileno (&s->pb); |
||||
int idx = -1, i; |
||||
//FIXME: get the right ctx flag to know if is seekable or not
|
||||
// if(ogg->f->flags & URL_FLAG_STREAMED)
|
||||
// return 0;
|
||||
|
||||
// already set
|
||||
if (s->duration != AV_NOPTS_VALUE) |
||||
return 0; |
||||
|
||||
ogg_save (s); |
||||
url_seek (h, -MAX_PAGE_SIZE, SEEK_END); |
||||
|
||||
while (!ogg_read_page (s, &i)){ |
||||
if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0) |
||||
idx = i; |
||||
} |
||||
|
||||
if (idx != -1){ |
||||
s->streams[idx]->duration = |
||||
ogg_gptopts (s, idx, ogg->streams[idx].granule); |
||||
} |
||||
|
||||
ogg->size = url_filesize(h); |
||||
ogg_restore (s, 0); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int |
||||
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
ogg->curidx = -1; |
||||
//linear headers seek from start
|
||||
if (ogg_get_headers (s) < 0){ |
||||
return -1; |
||||
} |
||||
|
||||
//linear granulepos seek from end
|
||||
ogg_get_length (s); |
||||
|
||||
//fill the extradata in the per codec callbacks
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int |
||||
ogg_read_packet (AVFormatContext * s, AVPacket * pkt) |
||||
{ |
||||
ogg_t *ogg; |
||||
ogg_stream_t *os; |
||||
int idx = -1; |
||||
|
||||
//Get an ogg packet
|
||||
do{ |
||||
if (ogg_packet (s, &idx) < 0) |
||||
return AVERROR_IO; |
||||
}while (idx < 0 || !s->streams[idx]); |
||||
|
||||
ogg = s->priv_data; |
||||
os = ogg->streams + idx; |
||||
|
||||
//Alloc a pkt
|
||||
if (av_new_packet (pkt, os->psize) < 0) |
||||
return AVERROR_IO; |
||||
pkt->stream_index = idx; |
||||
memcpy (pkt->data, os->buf + os->pstart, os->psize); |
||||
if (os->lastgp != -1LL){ |
||||
pkt->pts = ogg_gptopts (s, idx, os->lastgp); |
||||
os->lastgp = -1; |
||||
} |
||||
//next
|
||||
os->pstart += os->psize; |
||||
os->psize = 0; |
||||
return os->psize; |
||||
} |
||||
|
||||
|
||||
static int |
||||
ogg_read_close (AVFormatContext * s) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
int i; |
||||
|
||||
for (i = 0; i < ogg->nstreams; i++){ |
||||
av_free (ogg->streams[i].buf); |
||||
av_freep (&s->streams[i]->codec.extradata); |
||||
} |
||||
av_free (ogg->streams); |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
static int |
||||
ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts, |
||||
int flags) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
ByteIOContext *bc = &s->pb; |
||||
uint64_t min = 0, max = ogg->size; |
||||
uint64_t tmin = 0, tmax = s->duration; |
||||
int64_t pts = AV_NOPTS_VALUE; |
||||
|
||||
ogg_save (s); |
||||
|
||||
while (min <= max){ |
||||
uint64_t p = min + (max - min) * target_ts / (tmax - tmin); |
||||
int i = -1; |
||||
|
||||
url_fseek (bc, p, SEEK_SET); |
||||
|
||||
while (!ogg_read_page (s, &i)){ |
||||
if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1) |
||||
break; |
||||
} |
||||
|
||||
if (i == -1) |
||||
break; |
||||
|
||||
pts = ogg_gptopts (s, i, ogg->streams[i].granule); |
||||
p = url_ftell (bc); |
||||
|
||||
if (ABS (pts - target_ts) < 1000000LL) |
||||
break; |
||||
|
||||
if (pts > target_ts){ |
||||
max = p; |
||||
tmax = pts; |
||||
}else{ |
||||
min = p; |
||||
tmin = pts; |
||||
} |
||||
} |
||||
|
||||
if (ABS (pts - target_ts) < 1000000LL){ |
||||
ogg_restore (s, 1); |
||||
ogg_reset (ogg); |
||||
}else{ |
||||
ogg_restore (s, 0); |
||||
pts = AV_NOPTS_VALUE; |
||||
} |
||||
|
||||
return pts; |
||||
|
||||
#if 0 |
||||
//later...
|
||||
int64_t pos; |
||||
if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0) |
||||
return -1; |
||||
pos = url_ftell (&s->pb); |
||||
ogg_read_timestamp (s, stream_index, &pos, pos - 1); |
||||
#endif |
||||
|
||||
} |
||||
|
||||
#if 0 |
||||
static int64_t |
||||
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, |
||||
int64_t pos_limit) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
ByteIOContext *bc = &s->pb; |
||||
int64_t pos, pts; |
||||
|
||||
if (*pos_arg < 0) |
||||
return AV_NOPTS_VALUE; |
||||
|
||||
pos = *pos_arg; |
||||
} |
||||
#endif |
||||
|
||||
static AVInputFormat ogg_iformat = { |
||||
"ogg", |
||||
"Ogg", |
||||
sizeof (ogg_t), |
||||
NULL, |
||||
ogg_read_header, |
||||
ogg_read_packet, |
||||
ogg_read_close, |
||||
ogg_read_seek, |
||||
// ogg_read_timestamp,
|
||||
.extensions = "ogg", |
||||
}; |
||||
|
||||
int |
||||
ogg_init (void) |
||||
{ |
||||
#if 0 // CONFIG_ENCODERS
|
||||
av_register_output_format (&ogg_oformat); |
||||
#endif |
||||
av_register_input_format (&ogg_iformat); |
||||
return 0; |
||||
} |
@ -0,0 +1,84 @@ |
||||
/**
|
||||
Copyright (C) 2005 Michael Ahlberg, Måns Rullgård |
||||
|
||||
Permission is hereby granted, free of charge, to any person |
||||
obtaining a copy of this software and associated documentation |
||||
files (the "Software"), to deal in the Software without |
||||
restriction, including without limitation the rights to use, copy, |
||||
modify, merge, publish, distribute, sublicense, and/or sell copies |
||||
of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
**/ |
||||
|
||||
#ifndef OGG_H |
||||
#define OGG_H |
||||
|
||||
#include "avformat.h" |
||||
|
||||
typedef struct ogg_codec { |
||||
uint8_t *magic; |
||||
uint8_t magicsize; |
||||
int8_t *name; |
||||
int (*header)(AVFormatContext *, int); |
||||
int (*packet)(AVFormatContext *, int); |
||||
} ogg_codec_t; |
||||
|
||||
typedef struct ogg_stream { |
||||
uint8_t *buf; |
||||
unsigned int bufsize; |
||||
unsigned int bufpos; |
||||
unsigned int pstart; |
||||
unsigned int psize; |
||||
uint32_t serial; |
||||
uint32_t seq; |
||||
uint64_t granule, lastgp; |
||||
int flags; |
||||
ogg_codec_t *codec; |
||||
int header; |
||||
int nsegs, segp; |
||||
uint8_t segments[255]; |
||||
} ogg_stream_t; |
||||
|
||||
typedef struct ogg_state { |
||||
uint64_t pos; |
||||
int curidx; |
||||
struct ogg_state *next; |
||||
ogg_stream_t streams[]; |
||||
} ogg_state_t; |
||||
|
||||
typedef struct ogg { |
||||
ogg_stream_t *streams; |
||||
int nstreams; |
||||
int headers; |
||||
int curidx; |
||||
uint64_t size; |
||||
ogg_state_t *state; |
||||
} ogg_t; |
||||
|
||||
#define OGG_FLAG_CONT 1 |
||||
#define OGG_FLAG_BOS 2 |
||||
#define OGG_FLAG_EOS 4 |
||||
|
||||
extern ogg_codec_t vorbis_codec; |
||||
#if 0 |
||||
extern ogg_codec_t ogm_video_codec; |
||||
extern ogg_codec_t ogm_audio_codec; |
||||
extern ogg_codec_t ogm_old_codec; |
||||
extern ogg_codec_t flac_codec; |
||||
#endif |
||||
|
||||
extern int vorbis_comment(AVFormatContext *ms, char *buf, int size); |
||||
|
||||
#endif |
@ -0,0 +1,169 @@ |
||||
/**
|
||||
Copyright (C) 2005 Michael Ahlberg, Måns Rullgård |
||||
|
||||
Permission is hereby granted, free of charge, to any person |
||||
obtaining a copy of this software and associated documentation |
||||
files (the "Software"), to deal in the Software without |
||||
restriction, including without limitation the rights to use, copy, |
||||
modify, merge, publish, distribute, sublicense, and/or sell copies |
||||
of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
**/ |
||||
|
||||
#include <stdlib.h> |
||||
#include "avformat.h" |
||||
#include "bitstream.h" |
||||
#include "bswap.h" |
||||
#include "ogg2.h" |
||||
|
||||
extern int |
||||
vorbis_comment (AVFormatContext * as, char *buf, int size) |
||||
{ |
||||
char *p = buf; |
||||
int s, n, j; |
||||
|
||||
if (size < 4) |
||||
return -1; |
||||
|
||||
s = le2me_32 (unaligned32 (p)); |
||||
p += 4; |
||||
size -= 4; |
||||
|
||||
if (size < s + 4) |
||||
return -1; |
||||
|
||||
p += s; |
||||
size -= s; |
||||
|
||||
n = le2me_32 (unaligned32 (p)); |
||||
p += 4; |
||||
size -= 4; |
||||
|
||||
while (size >= 4){ |
||||
char *t, *v; |
||||
int tl, vl; |
||||
|
||||
s = le2me_32 (unaligned32 (p)); |
||||
p += 4; |
||||
size -= 4; |
||||
|
||||
if (size < s) |
||||
break; |
||||
|
||||
t = p; |
||||
p += s; |
||||
size -= s; |
||||
n--; |
||||
|
||||
v = memchr (t, '=', s); |
||||
if (!v) |
||||
continue; |
||||
|
||||
tl = v - t; |
||||
vl = s - tl - 1; |
||||
v++; |
||||
|
||||
if (tl && vl){ |
||||
char tt[tl + 1]; |
||||
char ct[vl + 1]; |
||||
|
||||
for (j = 0; j < tl; j++) |
||||
tt[j] = toupper (t[j]); |
||||
tt[tl] = 0; |
||||
|
||||
memcpy (ct, v, vl); |
||||
ct[vl] = 0; |
||||
|
||||
// took from Vorbis_I_spec
|
||||
if (!strcmp (tt, "AUTHOR")) |
||||
strncpy (as->author, ct, FFMIN(sizeof (as->author), vl)); |
||||
else if (!strcmp (tt, "TITLE")) |
||||
strncpy (as->title, ct, FFMIN(sizeof (as->title), vl)); |
||||
else if (!strcmp (tt, "COPYRIGHT")) |
||||
strncpy (as->copyright, ct, FFMIN(sizeof (as->copyright), vl)); |
||||
else if (!strcmp (tt, "DESCRIPTION")) |
||||
strncpy (as->comment, ct, FFMIN(sizeof (as->comment), vl)); |
||||
else if (!strcmp (tt, "GENRE")) |
||||
strncpy (as->genre, ct, FFMIN(sizeof (as->genre), vl)); |
||||
else if (!strcmp (tt, "TRACKNUMBER")) |
||||
as->track = atoi (ct); |
||||
//Too bored to add others for today
|
||||
} |
||||
} |
||||
|
||||
if (size > 0) |
||||
av_log (as, AV_LOG_INFO, "%i bytes of comment header remain\n", size); |
||||
if (n > 0) |
||||
av_log (as, AV_LOG_INFO, |
||||
"truncated comment header, %i comments not found\n", n); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/** Parse the vorbis header
|
||||
* Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec |
||||
* [vorbis_version] = read 32 bits as unsigned integer | Not used |
||||
* [audio_channels] = read 8 bit integer as unsigned | Used |
||||
* [audio_sample_rate] = read 32 bits as unsigned integer | Used
|
||||
* [bitrate_maximum] = read 32 bits as signed integer | Not used yet |
||||
* [bitrate_nominal] = read 32 bits as signed integer | Not used yet |
||||
* [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate |
||||
* [blocksize_0] = read 4 bits as unsigned integer | Not Used |
||||
* [blocksize_1] = read 4 bits as unsigned integer | Not Used |
||||
* [framing_flag] = read one bit | Not Used |
||||
* */ |
||||
|
||||
static int |
||||
vorbis_header (AVFormatContext * s, int idx) |
||||
{ |
||||
ogg_t *ogg = s->priv_data; |
||||
ogg_stream_t *os = ogg->streams + idx; |
||||
AVStream *st = s->streams[idx]; |
||||
int cds = st->codec.extradata_size + os->psize + 2; |
||||
u_char *cdp; |
||||
|
||||
if (os->seq > 2) |
||||
return 0; |
||||
|
||||
st->codec.extradata = av_realloc (st->codec.extradata, cds); |
||||
cdp = st->codec.extradata + st->codec.extradata_size; |
||||
*cdp++ = os->psize >> 8; |
||||
*cdp++ = os->psize & 0xff; |
||||
memcpy (cdp, os->buf + os->pstart, os->psize); |
||||
st->codec.extradata_size = cds; |
||||
|
||||
if (os->buf[os->pstart] == 1) { |
||||
u_char *p = os->buf + os->pstart + 11; //skip up to the audio channels
|
||||
st->codec.channels = *p++; |
||||
st->codec.sample_rate = le2me_32 (unaligned32 (p)); |
||||
p += 8; //skip maximum and and nominal bitrate
|
||||
st->codec.bit_rate = le2me_32 (unaligned32 (p)); //Minimum bitrate
|
||||
|
||||
st->codec.codec_type = CODEC_TYPE_AUDIO; |
||||
st->codec.codec_id = CODEC_ID_VORBIS; |
||||
|
||||
} else if (os->buf[os->pstart] == 3) { |
||||
vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8); |
||||
} |
||||
|
||||
return os->seq < 3; |
||||
} |
||||
|
||||
ogg_codec_t vorbis_codec = { |
||||
.magic = "\001vorbis", |
||||
.magicsize = 7, |
||||
.header = vorbis_header |
||||
}; |
Loading…
Reference in new issue