Merge commit '36ef5369ee9b336febc2c270f8718cec4476cb85'
[ffmpeg.git] / libavformat / oggparsevorbis.c
index f762c94..38eb4b0 100644 (file)
@@ -203,12 +203,12 @@ vorbis_header (AVFormatContext * s, int idx)
     int pkt_type = os->buf[os->pstart];
 
     if (!(pkt_type & 1))
-        return 0;
+        return os->private ? 0 : -1;
 
     if (!os->private) {
         os->private = av_mallocz(sizeof(struct oggvorbis_private));
         if (!os->private)
-            return 0;
+            return -1;
     }
 
     if (os->psize < 1 || pkt_type > 5)
@@ -223,6 +223,8 @@ 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 */
@@ -296,33 +298,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);
     }
@@ -330,7 +338,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;
         }