NdkMediaExtractor: per-sample format metadata API

Bug: 63934228
Test: MediaPlayer2Test
Change-Id: I8ac081ba91152b1bb2e7bb61bf6977f90bcb8e3c
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index ea43d2e..ac837a3 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -43,7 +43,12 @@
 static media_status_t translate_error(status_t err) {
     if (err == OK) {
         return AMEDIA_OK;
+    } else if (err == ERROR_END_OF_STREAM) {
+        return AMEDIA_ERROR_END_OF_STREAM;
+    } else if (err == ERROR_IO) {
+        return AMEDIA_ERROR_IO;
     }
+
     ALOGE("sf error code: %d", err);
     return AMEDIA_ERROR_UNKNOWN;
 }
@@ -411,5 +416,64 @@
     return -1;
 }
 
+EXPORT
+media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex, AMediaFormat *fmt) {
+    if (fmt == NULL) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    sp<MetaData> sampleMeta;
+    status_t err = ex->mImpl->getSampleMeta(&sampleMeta);
+    if (err != OK) {
+        return translate_error(err);
+    }
+
+    sp<AMessage> meta;
+    AMediaFormat_getFormat(fmt, &meta);
+    meta->clear();
+
+    int32_t layerId;
+    if (sampleMeta->findInt32(kKeyTemporalLayerId, &layerId)) {
+        meta->setInt32(AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID, layerId);
+    }
+
+    size_t trackIndex;
+    err = ex->mImpl->getSampleTrackIndex(&trackIndex);
+    if (err == OK) {
+        meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, trackIndex);
+        sp<AMessage> trackFormat;
+        AString mime;
+        err = ex->mImpl->getTrackFormat(trackIndex, &trackFormat);
+        if (err == OK
+                && trackFormat != NULL
+                && trackFormat->findString(AMEDIAFORMAT_KEY_MIME, &mime)) {
+            meta->setString(AMEDIAFORMAT_KEY_MIME, mime);
+        }
+    }
+
+    int64_t durationUs;
+    if (sampleMeta->findInt64(kKeyDuration, &durationUs)) {
+        meta->setInt64(AMEDIAFORMAT_KEY_DURATION, durationUs);
+    }
+
+    uint32_t dataType; // unused
+    const void *seiData;
+    size_t seiLength;
+    if (sampleMeta->findData(kKeySEI, &dataType, &seiData, &seiLength)) {
+        sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
+        meta->setBuffer(AMEDIAFORMAT_KEY_SEI, sei);
+    }
+
+    const void *mpegUserDataPointer;
+    size_t mpegUserDataLength;
+    if (sampleMeta->findData(
+            kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
+        sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
+        meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData);
+    }
+
+    return AMEDIA_OK;
+}
+
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index b86876b..abcaa0a 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -309,6 +309,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
 EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
+EXPORT const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA = "mpeg-user-data";
 EXPORT const char* AMEDIAFORMAT_KEY_OPERATING_RATE = "operating-rate";
 EXPORT const char* AMEDIAFORMAT_KEY_PCM_ENCODING = "pcm-encoding";
 EXPORT const char* AMEDIAFORMAT_KEY_PRIORITY = "priority";
@@ -317,10 +318,13 @@
 EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
 EXPORT const char* AMEDIAFORMAT_KEY_ROTATION = "rotation-degrees";
 EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_SEI = "sei";
 EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height";
 EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
+EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
+EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
 EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
 
 
diff --git a/media/ndk/include/media/NdkMediaError.h b/media/ndk/include/media/NdkMediaError.h
index e48fcbe..13aacc9 100644
--- a/media/ndk/include/media/NdkMediaError.h
+++ b/media/ndk/include/media/NdkMediaError.h
@@ -53,6 +53,8 @@
     AMEDIA_ERROR_INVALID_OBJECT        = AMEDIA_ERROR_BASE - 3,
     AMEDIA_ERROR_INVALID_PARAMETER     = AMEDIA_ERROR_BASE - 4,
     AMEDIA_ERROR_INVALID_OPERATION     = AMEDIA_ERROR_BASE - 5,
+    AMEDIA_ERROR_END_OF_STREAM         = AMEDIA_ERROR_BASE - 6,
+    AMEDIA_ERROR_IO                    = AMEDIA_ERROR_BASE - 7,
 
     AMEDIA_DRM_ERROR_BASE              = -20000,
     AMEDIA_DRM_NOT_PROVISIONED         = AMEDIA_DRM_ERROR_BASE - 1,
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index 3c9e23d..f7b9cfd 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -203,6 +203,17 @@
  */
 int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *);
 
+/**
+ * Read the current sample's metadata format into |fmt|. Examples of sample metadata are
+ * SEI (supplemental enhancement information) and MPEG user data, both of which can embed
+ * closed-caption data.
+ *
+ * Returns AMEDIA_OK on success or AMEDIA_ERROR_* to indicate failure reason.
+ * Existing key-value pairs in |fmt| would be removed if this API returns AMEDIA_OK.
+ * The contents of |fmt| is undefined if this API returns AMEDIA_ERROR_*.
+ */
+media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex, AMediaFormat *fmt);
+
 #endif /* __ANDROID_API__ >= 28 */
 
 #endif /* __ANDROID_API__ >= 21 */
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index b6489c7..464c127 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -123,6 +123,7 @@
 extern const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE;
 extern const char* AMEDIAFORMAT_KEY_MAX_WIDTH;
 extern const char* AMEDIAFORMAT_KEY_MIME;
+extern const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA;
 extern const char* AMEDIAFORMAT_KEY_OPERATING_RATE;
 extern const char* AMEDIAFORMAT_KEY_PCM_ENCODING;
 extern const char* AMEDIAFORMAT_KEY_PRIORITY;
@@ -131,10 +132,13 @@
 extern const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER;
 extern const char* AMEDIAFORMAT_KEY_ROTATION;
 extern const char* AMEDIAFORMAT_KEY_SAMPLE_RATE;
+extern const char* AMEDIAFORMAT_KEY_SEI;
 extern const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT;
 extern const char* AMEDIAFORMAT_KEY_STRIDE;
+extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID;
 extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING;
 extern const char* AMEDIAFORMAT_KEY_TRACK_ID;
+extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX;
 extern const char* AMEDIAFORMAT_KEY_WIDTH;
 
 #endif /* __ANDROID_API__ >= 21 */
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 17c1a0d..d8c41d2 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -159,6 +159,7 @@
     AMediaExtractor_getPsshInfo;
     AMediaExtractor_getSampleCryptoInfo;
     AMediaExtractor_getSampleFlags;
+    AMediaExtractor_getSampleFormat;   # introduced=28
     AMediaExtractor_getSampleSize;     # introduced=28
     AMediaExtractor_getSampleTime;
     AMediaExtractor_getSampleTrackIndex;