summaryrefslogtreecommitdiff
path: root/libavformat/oggparsevorbis.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/oggparsevorbis.c')
-rw-r--r--libavformat/oggparsevorbis.c77
1 files changed, 58 insertions, 19 deletions
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index adf8f0360a..7d525f43dc 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -24,12 +24,14 @@
#include <stdlib.h>
#include "libavutil/avstring.h"
+#include "libavutil/base64.h"
#include "libavutil/bswap.h"
#include "libavutil/dict.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/vorbis_parser.h"
#include "avformat.h"
+#include "flacdec.h"
#include "internal.h"
#include "oggdec.h"
#include "vorbiscomment.h"
@@ -39,10 +41,10 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
int i, cnum, h, m, s, ms, keylen = strlen(key);
AVChapter *chapter = NULL;
- if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1)
+ if (keylen < 9 || sscanf(key, "CHAPTER%03d", &cnum) != 1)
return 0;
- if (keylen == 9) {
+ if (keylen <= 10) {
if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
return 0;
@@ -50,7 +52,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
ms + 1000*(s + 60*(m + 60*h)),
AV_NOPTS_VALUE, NULL);
av_free(val);
- } else if (!strcmp(key+9, "NAME")) {
+ } else if (!strcmp(key+(keylen-4), "NAME")) {
for(i = 0; i < as->nb_chapters; i++)
if (as->chapters[i]->id == cnum) {
chapter = as->chapters[i];
@@ -128,7 +130,26 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in
memcpy(ct, v, vl);
ct[vl] = 0;
- if (!ogm_chapter(as, tt, ct))
+ if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) {
+ int ret;
+ char *pict = av_malloc(vl);
+
+ if (!pict) {
+ av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n");
+ av_freep(&tt);
+ av_freep(&ct);
+ continue;
+ }
+ if ((ret = av_base64_decode(pict, ct, vl)) > 0)
+ ret = ff_flac_parse_picture(as, pict, ret);
+ av_freep(&pict);
+ av_freep(&tt);
+ av_freep(&ct);
+ if (ret < 0) {
+ av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n");
+ continue;
+ }
+ } else if (!ogm_chapter(as, tt, ct))
av_dict_set(m, tt, ct,
AV_DICT_DONT_STRDUP_KEY |
AV_DICT_DONT_STRDUP_VAL);
@@ -173,11 +194,15 @@ static unsigned int
fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
uint8_t **buf)
{
- int i,offset, len;
+ int i,offset, len, buf_len;
unsigned char *ptr;
len = priv->len[0] + priv->len[1] + priv->len[2];
- ptr = *buf = av_mallocz(len + len/255 + 64);
+ buf_len = len + len/255 + 64;
+ ptr = *buf = av_realloc(NULL, buf_len);
+ if (!*buf)
+ return 0;
+ memset(*buf, '\0', buf_len);
ptr[0] = 2;
offset = 1;
@@ -215,7 +240,7 @@ vorbis_header (AVFormatContext * s, int idx)
if (!os->private) {
os->private = av_mallocz(sizeof(struct oggvorbis_private));
if (!os->private)
- return 0;
+ return -1;
}
if (!(pkt_type & 1))
@@ -233,11 +258,14 @@ vorbis_header (AVFormatContext * s, int idx)
priv->len[pkt_type >> 1] = os->psize;
priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
+ if (!priv->packet[pkt_type >> 1])
+ return AVERROR(ENOMEM);
memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize);
if (os->buf[os->pstart] == 1) {
const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
unsigned blocksize, bs0, bs1;
int srate;
+ int channels;
if (os->psize != 30)
return -1;
@@ -245,7 +273,12 @@ vorbis_header (AVFormatContext * s, int idx)
if (bytestream_get_le32(&p) != 0) /* vorbis_version */
return -1;
- st->codec->channels = bytestream_get_byte(&p);
+ channels= bytestream_get_byte(&p);
+ if (st->codec->channels && channels != st->codec->channels) {
+ av_log(s, AV_LOG_ERROR, "Channel change is not supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ st->codec->channels = channels;
srate = bytestream_get_le32(&p);
p += 4; // skip maximum bitrate
st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
@@ -306,33 +339,39 @@ static int vorbis_packet(AVFormatContext *s, int idx)
here we parse the duration of each packet in the first page and compare
the total duration to the page granule to find the encoder delay and
set the first timestamp */
- if (!os->lastpts) {
- int seg;
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ int seg, d;
uint8_t *last_pkt = os->buf + os->pstart;
uint8_t *next_pkt = last_pkt;
- int first_duration = 0;
avpriv_vorbis_parse_reset(&priv->vp);
duration = 0;
- for (seg = 0; seg < os->nsegs; seg++) {
+ seg = os->segp;
+ d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1);
+ 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 = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1);
if (d < 0) {
duration = os->granule;
break;
}
- if (!duration)
- first_duration = d;
duration += d;
last_pkt = next_pkt + os->segments[seg];
}
next_pkt += os->segments[seg];
}
os->lastpts = os->lastdts = os->granule - duration;
- s->streams[idx]->start_time = os->lastpts + first_duration;
- if (s->streams[idx]->duration)
- s->streams[idx]->duration -= s->streams[idx]->start_time;
- s->streams[idx]->cur_dts = AV_NOPTS_VALUE;
+ if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
+ s->streams[idx]->start_time = FFMAX(os->lastpts, 0);
+ if (s->streams[idx]->duration)
+ s->streams[idx]->duration -= s->streams[idx]->start_time;
+ }
priv->final_pts = AV_NOPTS_VALUE;
avpriv_vorbis_parse_reset(&priv->vp);
}
@@ -340,7 +379,7 @@ static int vorbis_packet(AVFormatContext *s, int idx)
/* parse packet duration */
if (os->psize > 0) {
duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1);
- if (duration <= 0) {
+ if (duration < 0) {
os->pflags |= AV_PKT_FLAG_CORRUPT;
return 0;
}