AMediaDataSource: add getAvailableSize callback

Bug: 109928575
Test: android.media.cts.NativeDecoderTest#testExtractorCachedDurationNative
Change-Id: I77af46e58bd81bc24a8682d6d2a48646c5f13e8f
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 75477b4..43c89bb 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -48,6 +48,7 @@
     AMediaDataSourceReadAt readAt;
     AMediaDataSourceGetSize getSize;
     AMediaDataSourceClose close;
+    AMediaDataSourceGetAvailableSize getAvailableSize;
     sp<DataSource> mImpl;
     uint32_t mFlags;
 };
@@ -107,6 +108,17 @@
     }
 }
 
+status_t NdkDataSource::getAvailableSize(off64_t offset, off64_t *sizeptr) {
+    off64_t size = -1;
+    if (mDataSource->getAvailableSize != NULL
+            && mDataSource->userdata != NULL
+            && sizeptr != NULL) {
+        size = mDataSource->getAvailableSize(mDataSource->userdata, offset);
+        *sizeptr = size;
+    }
+    return size >= 0 ? OK : UNKNOWN_ERROR;
+}
+
 static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
     if (obj == NULL) {
         return NULL;
@@ -251,5 +263,11 @@
     return mSource->close(mSource->userdata);
 }
 
+EXPORT
+void AMediaDataSource_setGetAvailableSize(AMediaDataSource *mSource,
+        AMediaDataSourceGetAvailableSize getAvailableSize) {
+    mSource->getAvailableSize = getAvailableSize;
+}
+
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaDataSourceCallbacks.cpp b/media/ndk/NdkMediaDataSourceCallbacks.cpp
index 1efcaa0..796c11b 100644
--- a/media/ndk/NdkMediaDataSourceCallbacks.cpp
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -40,4 +40,11 @@
     source->close();
 }
 
+ssize_t DataSource_getAvailableSize(void *userdata, off64_t offset) {
+    off64_t size = -1;
+    DataSource *source = static_cast<DataSource *>(userdata);
+    status_t err = source->getAvailableSize(offset, &size);
+    return  err == OK ? size : -1;
+}
+
 }  // namespace android
diff --git a/media/ndk/NdkMediaDataSourceCallbacksPriv.h b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
index 65fb0aa..6503305 100644
--- a/media/ndk/NdkMediaDataSourceCallbacksPriv.h
+++ b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
@@ -31,6 +31,8 @@
 
 void DataSource_close(void *userdata);
 
+ssize_t DataSource_getAvailableSize(void *userdata, off64_t offset);
+
 static inline AMediaDataSource* convertDataSourceToAMediaDataSource(const sp<DataSource> &source) {
     if (source == NULL) {
         return NULL;
@@ -40,6 +42,7 @@
     AMediaDataSource_setReadAt(mSource, DataSource_readAt);
     AMediaDataSource_setGetSize(mSource, DataSource_getSize);
     AMediaDataSource_setClose(mSource, DataSource_close);
+    AMediaDataSource_setGetAvailableSize(mSource, DataSource_getAvailableSize);
     return mSource;
 }
 
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 8a5423c..16ff974 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -50,6 +50,7 @@
     virtual String8 toString();
     virtual String8 getMIMEType() const;
     virtual void close();
+    virtual status_t getAvailableSize(off64_t offset, off64_t *size);
 
 protected:
     virtual ~NdkDataSource();
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 297d4bc..16b1eb3 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -94,6 +94,14 @@
 #if __ANDROID_API__ >= 29
 
 /**
+ * Called to get an estimate of the number of bytes that can be read from this data source
+ * starting at |offset| without blocking for I/O.
+ *
+ * Return -1 when such an estimate is not possible.
+ */
+typedef ssize_t (*AMediaDataSourceGetAvailableSize)(void *userdata, off64_t offset);
+
+/**
  * Create new media data source. Returns NULL if memory allocation
  * for the new data source object fails.
  *
@@ -176,6 +184,18 @@
  */
 void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
 
+/**
+ * Set a custom callback for supplying the estimated number of bytes
+ * that can be read from this data source starting at an offset without
+ * blocking for I/O.
+ *
+ * Please refer to the definition of AMediaDataSourceGetAvailableSize
+ * for additional details.
+ */
+void AMediaDataSource_setGetAvailableSize(
+        AMediaDataSource*,
+        AMediaDataSourceGetAvailableSize) __INTRODUCED_IN(29);
+
 #endif  /*__ANDROID_API__ >= 29 */
 
 __END_DECLS
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index e933376..224329a 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -143,6 +143,7 @@
     AMediaDataSource_setUserdata; # introduced=28
     AMediaDataSource_newUri;      # introduced=29
     AMediaDataSource_close;       # introduced=29
+    AMediaDataSource_setGetAvailableSize; # introduced=29
     AMediaDrm_closeSession;
     AMediaDrm_createByUUID;
     AMediaDrm_decrypt;