]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/oggparseopus.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavformat / oggparseopus.c
index 94267b26f314b25b0eb120e18efff83b779ba668..aafefbbe65bac6ce31df70599bd4cde7c077d084 100644 (file)
@@ -82,6 +82,26 @@ static int opus_header(AVFormatContext *avf, int idx)
     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;
@@ -89,26 +109,46 @@ static int opus_packet(AVFormatContext *avf, int 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;
+    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;