summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/oggparseopus.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavformat/oggparseopus.c')
-rw-r--r--ffmpeg/libavformat/oggparseopus.c132
1 files changed, 89 insertions, 43 deletions
diff --git a/ffmpeg/libavformat/oggparseopus.c b/ffmpeg/libavformat/oggparseopus.c
index 0e8f1ca..aafefbb 100644
--- a/ffmpeg/libavformat/oggparseopus.c
+++ b/ffmpeg/libavformat/oggparseopus.c
@@ -36,35 +36,34 @@ struct oggopus_private {
static int opus_header(AVFormatContext *avf, int idx)
{
- struct ogg *ogg = avf->priv_data;
- struct ogg_stream *os = &ogg->streams[idx];
- AVStream *st = avf->streams[idx];
+ struct ogg *ogg = avf->priv_data;
+ struct ogg_stream *os = &ogg->streams[idx];
+ AVStream *st = avf->streams[idx];
struct oggopus_private *priv = os->private;
- uint8_t *packet = os->buf + os->pstart;
- uint8_t *extradata;
+ uint8_t *packet = os->buf + os->pstart;
if (!priv) {
priv = os->private = av_mallocz(sizeof(*priv));
if (!priv)
return AVERROR(ENOMEM);
}
+
if (os->flags & OGG_FLAG_BOS) {
if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0)
return AVERROR_INVALIDDATA;
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = AV_CODEC_ID_OPUS;
- st->codec->channels = AV_RL8 (packet + 9);
- priv->pre_skip = AV_RL16(packet + 10);
- /*orig_sample_rate = AV_RL32(packet + 12);*/
- /*gain = AV_RL16(packet + 16);*/
- /*channel_map = AV_RL8 (packet + 18);*/
-
- extradata = av_malloc(os->psize + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!extradata)
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_OPUS;
+ st->codec->channels = AV_RL8 (packet + 9);
+ priv->pre_skip = AV_RL16(packet + 10);
+ st->codec->delay = priv->pre_skip;
+ /*orig_sample_rate = AV_RL32(packet + 12);*/
+ /*gain = AV_RL16(packet + 16);*/
+ /*channel_map = AV_RL8 (packet + 18);*/
+
+ if (ff_alloc_extradata(st->codec, os->psize))
return AVERROR(ENOMEM);
- memcpy(extradata, packet, os->psize);
- st->codec->extradata = extradata;
- st->codec->extradata_size = os->psize;
+
+ memcpy(st->codec->extradata, packet, os->psize);
st->codec->sample_rate = 48000;
avpriv_set_pts_info(st, 64, 1, 48000);
@@ -79,57 +78,104 @@ static int opus_header(AVFormatContext *avf, int idx)
priv->need_comments--;
return 1;
}
+
return 0;
}
+static int opus_duration(uint8_t *src, int size)
+{
+ unsigned nb_frames = 1;
+ unsigned toc = src[0];
+ unsigned toc_config = toc >> 3;
+ unsigned toc_count = toc & 3;
+ unsigned frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
+ toc_config < 16 ? 480 << (toc_config & 1) :
+ 120 << (toc_config & 3);
+ if (toc_count == 3) {
+ if (size<2)
+ return AVERROR_INVALIDDATA;
+ nb_frames = src[1] & 0x3F;
+ } else if (toc_count) {
+ nb_frames = 2;
+ }
+
+ return frame_size * nb_frames;
+}
+
static int opus_packet(AVFormatContext *avf, int idx)
{
- struct ogg *ogg = avf->priv_data;
- struct ogg_stream *os = &ogg->streams[idx];
- AVStream *st = avf->streams[idx];
+ struct ogg *ogg = avf->priv_data;
+ struct ogg_stream *os = &ogg->streams[idx];
+ AVStream *st = avf->streams[idx];
struct oggopus_private *priv = os->private;
- uint8_t *packet = os->buf + os->pstart;
- unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1;
+ uint8_t *packet = os->buf + os->pstart;
+ int ret;
if (!os->psize)
return AVERROR_INVALIDDATA;
- toc = *packet;
- toc_config = toc >> 3;
- toc_count = toc & 3;
- frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
- toc_config < 16 ? 480 << (toc_config & 1) :
- 120 << (toc_config & 3);
- if (toc_count == 3) {
- if (os->psize < 2)
- return AVERROR_INVALIDDATA;
- nb_frames = packet[1] & 0x3F;
- } else if (toc_count) {
- nb_frames = 2;
+
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ int seg, d;
+ int duration;
+ uint8_t *last_pkt = os->buf + os->pstart;
+ uint8_t *next_pkt = last_pkt;
+
+ duration = 0;
+ seg = os->segp;
+ d = opus_duration(last_pkt, os->psize);
+ if (d < 0) {
+ os->pflags |= AV_PKT_FLAG_CORRUPT;
+ return 0;
+ }
+ duration += d;
+ last_pkt = next_pkt = next_pkt + os->psize;
+ for (; seg < os->nsegs; seg++) {
+ if (os->segments[seg] < 255) {
+ int d = opus_duration(last_pkt, os->segments[seg]);
+ if (d < 0) {
+ duration = os->granule;
+ break;
+ }
+ duration += d;
+ last_pkt = next_pkt + os->segments[seg];
+ }
+ next_pkt += os->segments[seg];
+ }
+ os->lastpts =
+ os->lastdts = os->granule - duration;
}
- os->pduration = frame_size * nb_frames;
+
+ if ((ret = opus_duration(packet, os->psize)) < 0)
+ return ret;
+
+ os->pduration = ret;
if (os->lastpts != AV_NOPTS_VALUE) {
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = os->lastpts;
priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip;
}
+
priv->cur_dts += os->pduration;
if ((os->flags & OGG_FLAG_EOS)) {
int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
skip = FFMIN(skip, os->pduration);
if (skip > 0) {
os->pduration = skip < os->pduration ? os->pduration - skip : 1;
- av_log(avf, AV_LOG_WARNING,
- "Last packet must be truncated to %d (unimplemented).\n",
+ os->end_trimming = skip;
+ av_log(avf, AV_LOG_DEBUG,
+ "Last packet was truncated to %d due to end trimming.\n",
os->pduration);
}
}
+
return 0;
}
const struct ogg_codec ff_opus_codec = {
- .name = "Opus",
- .magic = "OpusHead",
- .magicsize = 8,
- .header = opus_header,
- .packet = opus_packet,
+ .name = "Opus",
+ .magic = "OpusHead",
+ .magicsize = 8,
+ .header = opus_header,
+ .packet = opus_packet,
+ .nb_header = 1,
};