stagefright: Updates to Opus unified CSD syntax

Added a marker and length field before OpusHead data as well.
This will prevent any potential truncation of OpusHead, when
data inside OpusHead matches one of the markers defined

Added checks to validate sizes parsed.
If the sizes are not as expected, then treat that as an error

OggWriter updated to not write codec config data as frame data

Test: With a local AMediaCodec api based application to decode
 opus encoder's output
Test: Test with mediamuxer api based application to mux encoders output
 to ogg file
Test: cts-tradefed run cts -m CtsMediaTestCases \
 -t android.media.cts.EncoderTest#testOpusEncoders

Bug: 123581317
Bug: 124053011
Change-Id: Ic3c7613ff47855e16be39dc60939e1e715522bc6
diff --git a/media/codec2/components/opus/C2SoftOpusDec.cpp b/media/codec2/components/opus/C2SoftOpusDec.cpp
index 680712e..13e3df5 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.cpp
+++ b/media/codec2/components/opus/C2SoftOpusDec.cpp
@@ -252,20 +252,25 @@
     const uint8_t *data = rView.data() + inOffset;
     if (mInputBufferCount < 3) {
         if (mInputBufferCount == 0) {
-            size_t opusHeadSize = inSize;
+            size_t opusHeadSize = 0;
             size_t codecDelayBufSize = 0;
             size_t seekPreRollBufSize = 0;
-            void *opusHeadBuf = (void *)data;
+            void *opusHeadBuf = NULL;
             void *codecDelayBuf = NULL;
             void *seekPreRollBuf = NULL;
 
-            GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
-                                &opusHeadSize, &codecDelayBuf,
-                                &codecDelayBufSize, &seekPreRollBuf,
-                                &seekPreRollBufSize);
+            if (!GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
+                                     &opusHeadSize, &codecDelayBuf,
+                                     &codecDelayBufSize, &seekPreRollBuf,
+                                     &seekPreRollBufSize)) {
+                ALOGE("%s encountered error in GetOpusHeaderBuffers", __func__);
+                mSignalledError = true;
+                work->result = C2_CORRUPTED;
+                return;
+            }
 
             if (!ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &mHeader)) {
-                ALOGE("Encountered error while Parsing Opus Header.");
+                ALOGE("%s Encountered error while Parsing Opus Header.", __func__);
                 mSignalledError = true;
                 work->result = C2_CORRUPTED;
                 return;
@@ -304,14 +309,14 @@
                 return;
             }
 
-            if (codecDelayBuf && codecDelayBufSize == 8) {
+            if (codecDelayBuf && codecDelayBufSize == sizeof(uint64_t)) {
                 uint64_t value;
                 memcpy(&value, codecDelayBuf, sizeof(uint64_t));
                 mCodecDelay = ns_to_samples(value, kRate);
                 mSamplesToDiscard = mCodecDelay;
                 ++mInputBufferCount;
             }
-            if (seekPreRollBuf && seekPreRollBufSize == 8) {
+            if (seekPreRollBuf && seekPreRollBufSize == sizeof(uint64_t)) {
                 uint64_t value;
                 memcpy(&value, codecDelayBuf, sizeof(uint64_t));
                 mSeekPreRoll = ns_to_samples(value, kRate);
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index 5c13983..cb87b55 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -295,6 +295,18 @@
                   mEstimatedSizeBytes, mMaxFileSizeLimitBytes);
             break;
         }
+
+        int32_t isCodecSpecific;
+        if ((buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecSpecific)
+             && isCodecSpecific)
+            || IsOpusHeader((uint8_t*)buffer->data() + buffer->range_offset(),
+                         buffer->range_length())) {
+            ALOGV("Drop codec specific info buffer");
+            buffer->release();
+            buffer = nullptr;
+            continue;
+        }
+
         int64_t timestampUs;
         CHECK(buffer->meta_data().findInt64(kKeyTime, &timestampUs));
         if (timestampUs > mEstimatedDurationUs) {
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 9faede1..acb9ccf 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -15,9 +15,9 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "SoftOpus"
-#include <algorithm>
+#define LOG_TAG "OpusHeader"
 #include <cstring>
+#include <inttypes.h>
 #include <stdint.h>
 
 #include <log/log.h>
@@ -91,6 +91,9 @@
 
 // Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
 bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header) {
+    if (data == NULL) {
+        return false;
+    }
     if (data_size < kOpusHeaderSize) {
         ALOGV("Header size is too small.");
         return false;
@@ -183,53 +186,88 @@
         ALOGD("Buffer not large enough to hold unified OPUS CSD");
         return -1;
     }
+    int headerLen = 0;
 
-    int headerLen = WriteOpusHeader(header, inputSampleRate, output,
+    // Add opus header
+    /*
+      Following is the CSD syntax for signalling OpusHeader
+      (http://wiki.xiph.org/OggOpus#ID_Header)
+
+      Marker (8 bytes) | Length (8 bytes) | OpusHeader
+
+      Markers supported:
+      AOPUS_CSD_OPUS_HEADER_MARKER - Signals Opus Header
+
+      Length should be a value within AOPUS_OPUSHEAD_MINSIZE and AOPUS_OPUSHEAD_MAXSIZE.
+    */
+
+    memcpy(output + headerLen, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
+    headerLen += AOPUS_MARKER_SIZE;
+
+    // Place holder for opusHeader Size
+    headerLen += AOPUS_LENGTH_SIZE;
+
+    int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
         outputSize);
-    if (headerLen < 0) {
-        ALOGD("WriteOpusHeader failed");
+    if (headerSize < 0) {
+        ALOGD("%s: WriteOpusHeader failed", __func__);
         return -1;
     }
-    if (headerLen >= (outputSize - 2 * AOPUS_TOTAL_CSD_SIZE)) {
-        ALOGD("Buffer not large enough to hold codec delay and seek pre roll");
-        return -1;
-    }
+    headerLen += headerSize;
 
-    uint64_t length = AOPUS_LENGTH;
+    // Update opus headerSize after AOPUS_CSD_OPUS_HEADER_MARKER
+    uint64_t length = headerSize;
+    memcpy(output + AOPUS_MARKER_SIZE, &length, AOPUS_LENGTH_SIZE);
 
     /*
       Following is the CSD syntax for signalling codec delay and
       seek pre-roll which is to be appended after OpusHeader
 
-      Marker (8 bytes) | Length (8 bytes) | Samples (8 bytes)
+      Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes)
 
       Markers supported:
-      AOPUSDLY - Signals Codec Delay
-      AOPUSPRL - Signals seek pre roll
+      AOPUS_CSD_CODEC_DELAY_MARKER - codec delay as samples in ns, represented in 8 bytes
+      AOPUS_CSD_SEEK_PREROLL_MARKER - preroll adjustment as samples in ns, represented in 8 bytes
 
-      Length should be 8.
     */
-
+    length = sizeof(codecDelay);
+    if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
+        ALOGD("Buffer not large enough to hold codec delay");
+        return -1;
+    }
     // Add codec delay
     memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
     headerLen += AOPUS_MARKER_SIZE;
     memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
     headerLen += AOPUS_LENGTH_SIZE;
-    memcpy(output + headerLen, &codecDelay, AOPUS_CSD_SIZE);
-    headerLen += AOPUS_CSD_SIZE;
+    memcpy(output + headerLen, &codecDelay, length);
+    headerLen += length;
 
+    length = sizeof(seekPreRoll);
+    if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
+        ALOGD("Buffer not large enough to hold seek pre roll");
+        return -1;
+    }
     // Add skip pre roll
     memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
     headerLen += AOPUS_MARKER_SIZE;
     memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
     headerLen += AOPUS_LENGTH_SIZE;
-    memcpy(output + headerLen, &seekPreRoll, AOPUS_CSD_SIZE);
-    headerLen += AOPUS_CSD_SIZE;
+    memcpy(output + headerLen, &seekPreRoll, length);
+    headerLen += length;
 
     return headerLen;
 }
 
-void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+bool IsOpusHeader(const uint8_t *data, size_t data_size) {
+    if (data_size < AOPUS_MARKER_SIZE) {
+        return false;
+    }
+
+    return !memcmp(data, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
+}
+
+bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
                           void **opusHeadBuf, size_t *opusHeadSize,
                           void **codecDelayBuf, size_t *codecDelaySize,
                           void **seekPreRollBuf, size_t *seekPreRollSize) {
@@ -237,26 +275,77 @@
     *codecDelaySize = 0;
     *seekPreRollBuf = NULL;
     *seekPreRollSize = 0;
-    *opusHeadBuf = (void *)data;
-    *opusHeadSize = data_size;
-    if (data_size >= AOPUS_UNIFIED_CSD_MINSIZE) {
+    *opusHeadBuf = NULL;
+    *opusHeadSize = 0;
+
+    // AOPUS_MARKER_SIZE is 8 "OpusHead" is of size 8
+    if (data_size < 8)
+        return false;
+
+    // Check if the CSD is in legacy format
+    if (!memcmp("OpusHead", data, 8)) {
+        if (data_size < AOPUS_OPUSHEAD_MINSIZE || data_size > AOPUS_OPUSHEAD_MAXSIZE) {
+            ALOGD("Unexpected size for opusHeadSize %zu", data_size);
+            return false;
+        }
+        *opusHeadBuf = (void *)data;
+        *opusHeadSize = data_size;
+        return true;
+    } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
         size_t i = 0;
-        while (i < data_size - AOPUS_TOTAL_CSD_SIZE) {
+        bool found = false;
+        while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
             uint8_t *csdBuf = (uint8_t *)data + i;
-            if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
-                *opusHeadSize = std::min(*opusHeadSize, i);
+            if (!memcmp(csdBuf, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE)) {
+                uint64_t value;
+                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+                if (value < AOPUS_OPUSHEAD_MINSIZE || value > AOPUS_OPUSHEAD_MAXSIZE) {
+                    ALOGD("Unexpected size for opusHeadSize %" PRIu64, value);
+                    return false;
+                }
+                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+                if (i > data_size) {
+                    ALOGD("Marker signals a header that is larger than input");
+                    return false;
+                }
+                *opusHeadBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
+                *opusHeadSize = value;
+                found = true;
+            } else if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
+                uint64_t value;
+                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+                if (value != sizeof(uint64_t)) {
+                    ALOGD("Unexpected size for codecDelay %" PRIu64, value);
+                    return false;
+                }
+                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+                if (i > data_size) {
+                    ALOGD("Marker signals a header that is larger than input");
+                    return false;
+                }
                 *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
-                *codecDelaySize = AOPUS_CSD_SIZE;
-                i += AOPUS_TOTAL_CSD_SIZE;
+                *codecDelaySize = value;
             } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
-                *opusHeadSize = std::min(*opusHeadSize, i);
+                uint64_t value;
+                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+                if (value != sizeof(uint64_t)) {
+                    ALOGD("Unexpected size for seekPreRollSize %" PRIu64, value);
+                    return false;
+                }
+                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+                if (i > data_size) {
+                    ALOGD("Marker signals a header that is larger than input");
+                    return false;
+                }
                 *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
-                *seekPreRollSize = AOPUS_CSD_SIZE;
-                i += AOPUS_TOTAL_CSD_SIZE;
+                *seekPreRollSize = value;
             } else {
                 i++;
             }
         }
+        return found;
+    } else {
+        return false;  // it isn't in either format
     }
 }
 
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
index 9bffccb..29037af 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
@@ -25,22 +25,37 @@
 namespace android {
 
 /* Constants used for delimiting Opus CSD */
-#define AOPUS_CSD_CODEC_DELAY_MARKER "AOPUSDLY"
-#define AOPUS_CSD_SEEK_PREROLL_MARKER "AOPUSPRL"
-#define AOPUS_CSD_SIZE 8
-#define AOPUS_LENGTH 8
+#define AOPUS_CSD_MARKER_PREFIX "AOPUS"
+#define AOPUS_CSD_MARKER_PREFIX_SIZE (sizeof(AOPUS_CSD_MARKER_PREFIX) - 1)
+#define AOPUS_CSD_OPUS_HEADER_MARKER AOPUS_CSD_MARKER_PREFIX "HDR"
+#define AOPUS_CSD_CODEC_DELAY_MARKER AOPUS_CSD_MARKER_PREFIX "DLY"
+#define AOPUS_CSD_SEEK_PREROLL_MARKER AOPUS_CSD_MARKER_PREFIX "PRL"
 #define AOPUS_MARKER_SIZE 8
-#define AOPUS_LENGTH_SIZE 8
-#define AOPUS_TOTAL_CSD_SIZE \
-    ((AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_CSD_SIZE))
-#define AOPUS_CSD0_MINSIZE 19
-#define AOPUS_UNIFIED_CSD_MINSIZE \
-    ((AOPUS_CSD0_MINSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+#define AOPUS_LENGTH_SIZE sizeof(uint64_t)
+#define AOPUS_CSD_CODEC_DELAY_SIZE \
+     (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
+#define AOPUS_CSD_SEEK_PREROLL_SIZE \
+     (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
 
-/* CSD0 at max can be 22 bytes + max number of channels (255) */
-#define AOPUS_CSD0_MAXSIZE 277
+/* OpusHead csd minimum size is 19 */
+#define AOPUS_OPUSHEAD_MINSIZE 19
+#define AOPUS_CSD_OPUSHEAD_MINSIZE \
+    (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MINSIZE)
+
+#define AOPUS_UNIFIED_CSD_MINSIZE \
+    ((AOPUS_CSD_OPUSHEAD_MINSIZE) + \
+     (AOPUS_CSD_CODEC_DELAY_SIZE) + \
+     (AOPUS_CSD_SEEK_PREROLL_SIZE))
+
+/* OpusHead csd at max can be AOPUS_CSD_OPUSHEAD_MINSIZE + 2 + max number of channels (255) */
+#define AOPUS_OPUSHEAD_MAXSIZE ((AOPUS_OPUSHEAD_MINSIZE) + 2 + 255)
+#define AOPUS_CSD_OPUSHEAD_MAXSIZE \
+    (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MAXSIZE)
+
 #define AOPUS_UNIFIED_CSD_MAXSIZE \
-    ((AOPUS_CSD0_MAXSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+    ((AOPUS_CSD_OPUSHEAD_MAXSIZE) + \
+     (AOPUS_CSD_CODEC_DELAY_SIZE) + \
+     (AOPUS_CSD_SEEK_PREROLL_SIZE))
 
 struct OpusHeader {
     int channels;
@@ -54,13 +69,14 @@
 
 bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header);
 int WriteOpusHeader(const OpusHeader &header, int input_sample_rate, uint8_t* output, size_t output_size);
-void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
                           void **opusHeadBuf, size_t *opusHeadSize,
                           void **codecDelayBuf, size_t *codecDelaySize,
                           void **seekPreRollBuf, size_t *seekPreRollSize);
 int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
                      uint8_t* output, size_t outputSize, uint64_t codecDelay,
                      uint64_t seekPreRoll);
+bool IsOpusHeader(const uint8_t *data, size_t data_size);
 }  // namespace android
 
 #endif  // OPUS_HEADER_H_