Merge "C2SoftAvcEnc: Allocate output buffer as per clip's dimensions"
diff --git a/media/libdatasource/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
index 7f5ae61..6d63ffb 100644
--- a/media/libdatasource/NuCachedSource2.cpp
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -689,10 +689,6 @@
restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
}
-sp<DecryptHandle> NuCachedSource2::DrmInitialization(const char* mime) {
- return mSource->DrmInitialization(mime);
-}
-
String8 NuCachedSource2::getUri() {
return mSource->getUri();
}
diff --git a/media/libdatasource/include/datasource/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
index 596efb8..4c253ad 100644
--- a/media/libdatasource/include/datasource/NuCachedSource2.h
+++ b/media/libdatasource/include/datasource/NuCachedSource2.h
@@ -44,7 +44,6 @@
virtual status_t getSize(off64_t *size);
virtual uint32_t flags();
- virtual sp<DecryptHandle> DrmInitialization(const char* mime);
virtual String8 getUri();
virtual String8 getMIMEType() const;
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index a977300..bbc14a9 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -66,9 +66,6 @@
void close() {}
uint32_t getFlags() override { return 0; }
String8 toString() override { return String8("HeifDataSource"); }
- sp<DecryptHandle> DrmInitialization(const char*) override {
- return nullptr;
- }
private:
enum {
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 31c85af..61f0a68 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -23,7 +23,6 @@
#include <binder/IMemory.h>
#include <binder/Parcel.h>
-#include <drm/drm_framework_common.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -35,7 +34,6 @@
CLOSE,
GET_FLAGS,
TO_STRING,
- DRM_INITIALIZATION,
};
struct BpDataSource : public BpInterface<IDataSource> {
@@ -95,47 +93,6 @@
remote()->transact(TO_STRING, data, &reply);
return reply.readString8();
}
-
- virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
- Parcel data, reply;
- data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
- if (mime == NULL) {
- data.writeInt32(0);
- } else {
- data.writeInt32(1);
- data.writeCString(mime);
- }
- remote()->transact(DRM_INITIALIZATION, data, &reply);
- sp<DecryptHandle> handle;
- if (reply.dataAvail() != 0) {
- handle = new DecryptHandle();
- handle->decryptId = reply.readInt32();
- handle->mimeType = reply.readString8();
- handle->decryptApiType = reply.readInt32();
- handle->status = reply.readInt32();
-
- const int bufferLength = data.readInt32();
- if (bufferLength != -1) {
- handle->decryptInfo = new DecryptInfo();
- handle->decryptInfo->decryptBufferLength = bufferLength;
- }
-
- size_t size = data.readInt32();
- for (size_t i = 0; i < size; ++i) {
- DrmCopyControl key = (DrmCopyControl)data.readInt32();
- int value = data.readInt32();
- handle->copyControlVector.add(key, value);
- }
-
- size = data.readInt32();
- for (size_t i = 0; i < size; ++i) {
- String8 key = data.readString8();
- String8 value = data.readString8();
- handle->extendedData.add(key, value);
- }
- }
- return handle;
- }
};
IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -178,42 +135,6 @@
reply->writeString8(toString());
return NO_ERROR;
} break;
- case DRM_INITIALIZATION: {
- CHECK_INTERFACE(IDataSource, data, reply);
- const char *mime = NULL;
- const int32_t flag = data.readInt32();
- if (flag != 0) {
- mime = data.readCString();
- }
- sp<DecryptHandle> handle = DrmInitialization(mime);
- if (handle != NULL) {
- reply->writeInt32(handle->decryptId);
- reply->writeString8(handle->mimeType);
- reply->writeInt32(handle->decryptApiType);
- reply->writeInt32(handle->status);
-
- if (handle->decryptInfo != NULL) {
- reply->writeInt32(handle->decryptInfo->decryptBufferLength);
- } else {
- reply->writeInt32(-1);
- }
-
- size_t size = handle->copyControlVector.size();
- reply->writeInt32(size);
- for (size_t i = 0; i < size; ++i) {
- reply->writeInt32(handle->copyControlVector.keyAt(i));
- reply->writeInt32(handle->copyControlVector.valueAt(i));
- }
-
- size = handle->extendedData.size();
- reply->writeInt32(size);
- for (size_t i = 0; i < size; ++i) {
- reply->writeString8(handle->extendedData.keyAt(i));
- reply->writeString8(handle->extendedData.valueAt(i));
- }
- }
- return NO_ERROR;
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/include/media/IDataSource.h b/media/libmedia/include/media/IDataSource.h
index 3858f78..43e2b50 100644
--- a/media/libmedia/include/media/IDataSource.h
+++ b/media/libmedia/include/media/IDataSource.h
@@ -50,8 +50,6 @@
virtual uint32_t getFlags() = 0;
// get a description of the source, e.g. the url or filename it is based on
virtual String8 toString() = 0;
- // Initialize DRM and return a DecryptHandle.
- virtual sp<DecryptHandle> DrmInitialization(const char *mime) = 0;
private:
DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
index 1580891..bb4ba75 100644
--- a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
@@ -31,6 +31,7 @@
mDrmBufOffset(0),
mDrmBufSize(0),
mDrmBuf(NULL){
+ (void) DrmInitialization(nullptr);
}
PlayerServiceFileSource::PlayerServiceFileSource(int fd, int64_t offset, int64_t length)
@@ -40,6 +41,7 @@
mDrmBufOffset(0),
mDrmBufSize(0),
mDrmBuf(NULL) {
+ (void) DrmInitialization(nullptr);
}
PlayerServiceFileSource::~PlayerServiceFileSource() {
@@ -87,7 +89,9 @@
}
sp<DecryptHandle> PlayerServiceFileSource::DrmInitialization(const char *mime) {
- if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
+ if (getuid() == AID_MEDIA_EX) {
+ return NULL; // no DRM in media extractor
+ }
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();
}
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
index 0124720..f99a861 100644
--- a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
@@ -32,6 +32,7 @@
PlayerServiceMediaHTTP::PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn)
: MediaHTTP(conn),
mDrmManagerClient(NULL) {
+ (void) DrmInitialization(nullptr);
}
PlayerServiceMediaHTTP::~PlayerServiceMediaHTTP() {
@@ -40,7 +41,7 @@
// DRM...
-sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char* mime) {
+sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char *mime) {
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();
}
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
index 08a013e..7ae8dda 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
@@ -37,8 +37,6 @@
virtual ssize_t readAt(off64_t offset, void *data, size_t size);
- virtual sp<DecryptHandle> DrmInitialization(const char *mime);
-
static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
protected:
@@ -52,6 +50,7 @@
ssize_t mDrmBufSize;
unsigned char *mDrmBuf;
+ sp<DecryptHandle> DrmInitialization(const char *mime);
ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
PlayerServiceFileSource(const PlayerServiceFileSource &);
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
index 0032cd7..b5124dc 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -33,12 +33,11 @@
protected:
virtual ~PlayerServiceMediaHTTP();
- virtual sp<DecryptHandle> DrmInitialization(const char* mime);
-
private:
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
+ sp<DecryptHandle> DrmInitialization(const char *mime);
void clearDRMState_l();
DISALLOW_EVIL_CONSTRUCTORS(PlayerServiceMediaHTTP);
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 92e6eb9..265f21b 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -113,10 +113,6 @@
}
}
-sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
- return mIDataSource->DrmInitialization(mime);
-}
-
sp<IDataSource> CallbackDataSource::getIDataSource() const {
return mIDataSource;
}
@@ -190,14 +186,6 @@
return mSource->flags();
}
-sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
- // flush cache when DrmInitialization occurs since decrypted
- // data may differ from what is in cache.
- mCachedOffset = 0;
- mCachedSize = 0;
- return mSource->DrmInitialization(mime);
-}
-
sp<IDataSource> TinyCacheSource::getIDataSource() const {
return mSource->getIDataSource();
}
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 4c8be1f..120f354 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -71,9 +71,6 @@
ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
- // initialize source decryption if needed
- source->DrmInitialization(nullptr /* mime */);
-
void *meta = nullptr;
void *creator = NULL;
FreeMetaFunc freeMeta = nullptr;
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 9f413cd..e428494 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -41,7 +41,6 @@
virtual String8 toString() {
return mName;
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
virtual sp<IDataSource> getIDataSource() const;
private:
@@ -70,7 +69,6 @@
virtual String8 toString() {
return mName;
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
virtual sp<IDataSource> getIDataSource() const;
private:
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 71e62f7..5ae0653 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -54,10 +54,6 @@
return mSource->reconnectAtOffset(offset);
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
- return mSource->DrmInitialization(mime);
- }
-
virtual String8 getMIMEType() const {
return mSource->getMIMEType();
}
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
index 1f7a473..83d3e5d 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libstagefright/include/media/stagefright/DataSource.h
@@ -52,11 +52,6 @@
////////////////////////////////////////////////////////////////////////////
- // for DRM
- virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
- return NULL;
- }
-
virtual String8 getUri() {
return String8();
}
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index e191e6a..5a69bd7 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -66,9 +66,6 @@
virtual String8 toString() {
return mName;
}
- virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
- return mSource->DrmInitialization(mime);
- }
private:
enum {
diff --git a/media/libstagefright/tests/writer/Android.bp b/media/libstagefright/tests/writer/Android.bp
new file mode 100644
index 0000000..7e169cb
--- /dev/null
+++ b/media/libstagefright/tests/writer/Android.bp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "writerTest",
+ gtest: true,
+
+ srcs: [
+ "WriterUtility.cpp",
+ "WriterTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libstagefright_webm",
+ "libdatasource",
+ "libstagefright",
+ "libstagefright_foundation",
+ "libstagefright_esds",
+ "libogg",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libstagefright/tests/writer/README.md b/media/libstagefright/tests/writer/README.md
new file mode 100644
index 0000000..52db6f0
--- /dev/null
+++ b/media/libstagefright/tests/writer/README.md
@@ -0,0 +1,30 @@
+## Media Testing ##
+---
+#### Writer :
+The Writer Test Suite validates the writers available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/libstagefright/tests/writer/
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+
+adb push ${OUT}/data/nativetest64/writerTest/writerTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+adb push ${OUT}/data/nativetest/writerTest/writerTest /data/local/tmp/
+
+The resource file for the tests is taken from Codec2 VTS resource folder. Push these files into device for testing.
+```
+adb push $ANDROID_BUILD_TOP/frameworks/av/media/codec2/hidl/1.0/vts/functional/res /sdcard/
+```
+
+usage: writerTest -P \<path_to_res_folder\>
+```
+adb shell /data/local/tmp/writerTest -P /sdcard/res/
+```
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
new file mode 100644
index 0000000..d68438c
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WriterTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <iostream>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/mediarecorder.h>
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/OggWriter.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <webm/WebmWriter.h>
+
+#include "WriterTestEnvironment.h"
+#include "WriterUtility.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/writer.out"
+
+static WriterTestEnvironment *gEnv = nullptr;
+
+struct configFormat {
+ char mime[128];
+ int32_t width;
+ int32_t height;
+ int32_t sampleRate;
+ int32_t channelCount;
+};
+
+// LookUpTable of clips and metadata for component testing
+static const struct InputData {
+ const char *mime;
+ string inputFile;
+ string info;
+ int32_t firstParam;
+ int32_t secondParam;
+ bool isAudio;
+} kInputData[] = {
+ {MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
+ "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
+ "bbb_aac_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
+ "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+ "sine_amrnb_1ch_12kbps_8000hz.info", 8000, 1, true},
+ {MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+ "bbb_amrwb_1ch_14kbps_16000hz.info", 16000, 1, true},
+ {MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
+ "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
+ "bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
+ {MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
+ "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
+ "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
+ "bbb_avc_176x144_300kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
+ "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144, false},
+ {MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
+ "bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
+ {MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
+ "bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
+};
+
+class WriterTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+ public:
+ virtual void SetUp() override {
+ mNumCsds = 0;
+ mInputFrameId = 0;
+ mWriterName = unknown_comp;
+ mDisableTest = false;
+
+ std::map<std::string, standardWriters> mapWriter = {
+ {"ogg", OGG}, {"aac", AAC}, {"aac_adts", AAC_ADTS}, {"webm", WEBM},
+ {"mpeg4", MPEG4}, {"amrnb", AMR_NB}, {"amrwb", AMR_WB}, {"mpeg2Ts", MPEG2TS}};
+ // Find the component type
+ string writerFormat = GetParam().first;
+ if (mapWriter.find(writerFormat) != mapWriter.end()) {
+ mWriterName = mapWriter[writerFormat];
+ }
+ if (mWriterName == standardWriters::unknown_comp) {
+ cout << "[ WARN ] Test Skipped. No specific writer mentioned\n";
+ mDisableTest = true;
+ }
+ }
+
+ virtual void TearDown() override {
+ mWriter.clear();
+ mFileMeta.clear();
+ mBufferInfo.clear();
+ if (mInputStream) mInputStream.close();
+ }
+
+ void getInputBufferInfo(string inputFileName, string inputInfo);
+
+ int32_t createWriter(int32_t fd);
+
+ int32_t addWriterSource(bool isAudio, configFormat params);
+
+ enum standardWriters {
+ OGG,
+ AAC,
+ AAC_ADTS,
+ WEBM,
+ MPEG4,
+ AMR_NB,
+ AMR_WB,
+ MPEG2TS,
+ unknown_comp,
+ };
+
+ standardWriters mWriterName;
+ sp<MediaWriter> mWriter;
+ sp<MetaData> mFileMeta;
+ sp<MediaAdapter> mCurrentTrack;
+
+ bool mDisableTest;
+ int32_t mNumCsds;
+ int32_t mInputFrameId;
+ ifstream mInputStream;
+ vector<BufferInfo> mBufferInfo;
+};
+
+void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
+ std::ifstream eleInfo;
+ eleInfo.open(inputInfo.c_str());
+ CHECK_EQ(eleInfo.is_open(), true);
+ int32_t bytesCount = 0;
+ uint32_t flags = 0;
+ int64_t timestamp = 0;
+ while (1) {
+ if (!(eleInfo >> bytesCount)) break;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ mBufferInfo.push_back({bytesCount, flags, timestamp});
+ if (flags == CODEC_CONFIG_FLAG) mNumCsds++;
+ }
+ eleInfo.close();
+ mInputStream.open(inputFileName.c_str(), std::ifstream::binary);
+ CHECK_EQ(mInputStream.is_open(), true);
+}
+
+int32_t WriterTest::createWriter(int32_t fd) {
+ mFileMeta = new MetaData;
+ switch (mWriterName) {
+ case OGG:
+ mWriter = new OggWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+ break;
+ case AAC:
+ mWriter = new AACWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+ break;
+ case AAC_ADTS:
+ mWriter = new AACWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+ break;
+ case WEBM:
+ mWriter = new WebmWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+ break;
+ case MPEG4:
+ mWriter = new MPEG4Writer(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+ break;
+ case AMR_NB:
+ mWriter = new AMRWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+ break;
+ case AMR_WB:
+ mWriter = new AMRWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+ break;
+ case MPEG2TS:
+ mWriter = new MPEG2TSWriter(fd);
+ mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+ break;
+ default:
+ return -1;
+ }
+ if (mWriter == nullptr) return -1;
+ mFileMeta->setInt32(kKeyRealTimeRecording, false);
+ return 0;
+}
+
+int32_t WriterTest::addWriterSource(bool isAudio, configFormat params) {
+ if (mInputFrameId) return -1;
+ sp<AMessage> format = new AMessage;
+ if (mInputStream.is_open()) {
+ format->setString("mime", params.mime);
+ if (isAudio) {
+ format->setInt32("channel-count", params.channelCount);
+ format->setInt32("sample-rate", params.sampleRate);
+ } else {
+ format->setInt32("width", params.width);
+ format->setInt32("height", params.height);
+ }
+
+ int32_t status =
+ writeHeaderBuffers(mInputStream, mBufferInfo, mInputFrameId, format, mNumCsds);
+ if (status != 0) return -1;
+ }
+ sp<MetaData> trackMeta = new MetaData;
+ convertMessageToMetaData(format, trackMeta);
+ mCurrentTrack = new MediaAdapter(trackMeta);
+ status_t result = mWriter->addSource(mCurrentTrack);
+ return result;
+}
+
+void getFileDetails(string &inputFilePath, string &info, configFormat ¶ms, bool &isAudio,
+ int32_t streamIndex = 0) {
+ if (streamIndex >= sizeof(kInputData) / sizeof(kInputData[0])) {
+ return;
+ }
+ inputFilePath += kInputData[streamIndex].inputFile;
+ info += kInputData[streamIndex].info;
+ strcpy(params.mime, kInputData[streamIndex].mime);
+ isAudio = kInputData[streamIndex].isAudio;
+ if (isAudio) {
+ params.sampleRate = kInputData[streamIndex].firstParam;
+ params.channelCount = kInputData[streamIndex].secondParam;
+ } else {
+ params.width = kInputData[streamIndex].firstParam;
+ params.height = kInputData[streamIndex].secondParam;
+ }
+ return;
+}
+
+TEST_P(WriterTest, CreateWriterTest) {
+ if (mDisableTest) return;
+ ALOGV("Tests the creation of writers");
+
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) return;
+
+ // Creating writer within a test scope. Destructor should be called when the test ends
+ int32_t status = createWriter(fd);
+ if (status) {
+ cout << "Failed to create writer for output format:" << GetParam().first << "\n";
+ ASSERT_TRUE(false);
+ }
+}
+
+TEST_P(WriterTest, WriterTest) {
+ if (mDisableTest) return;
+ ALOGV("Checks if for a given input, a valid muxed file has been created or not");
+
+ string writerFormat = GetParam().first;
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) return;
+ int32_t status = createWriter(fd);
+ if (status) {
+ cout << "Failed to create writer for output format:" << writerFormat << "\n";
+ ASSERT_TRUE(false);
+ }
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ int32_t inputFileIdx = GetParam().second;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ if (!inputFile.compare(gEnv->getRes())) {
+ ALOGV("No input file specified");
+ return;
+ }
+ getInputBufferInfo(inputFile, inputInfo);
+ status = addWriterSource(isAudio, param);
+ if (status) {
+ cout << "Failed to add source for " << writerFormat << "Writer \n";
+ ASSERT_TRUE(false);
+ }
+ CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+ mBufferInfo.size());
+ mCurrentTrack->stop();
+ if (status) {
+ cout << writerFormat << " writer failed \n";
+ mWriter->stop();
+ ASSERT_TRUE(false);
+ }
+ CHECK_EQ((status_t)OK, mWriter->stop());
+ close(fd);
+}
+
+TEST_P(WriterTest, PauseWriterTest) {
+ if (mDisableTest) return;
+ ALOGV("Validates the pause() api of writers");
+
+ string writerFormat = GetParam().first;
+ string outputFile = OUTPUT_FILE_NAME;
+ int32_t fd =
+ open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) return;
+ int32_t status = createWriter(fd);
+ if (status) {
+ cout << "Failed to create writer for output format:" << writerFormat << "\n";
+ ASSERT_TRUE(false);
+ }
+ string inputFile = gEnv->getRes();
+ string inputInfo = gEnv->getRes();
+ configFormat param;
+ bool isAudio;
+ int32_t inputFileIdx = GetParam().second;
+ getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+ if (!inputFile.compare(gEnv->getRes())) {
+ ALOGV("No input file specified");
+ return;
+ }
+ getInputBufferInfo(inputFile, inputInfo);
+ status = addWriterSource(isAudio, param);
+ if (status) {
+ cout << "Failed to add source for " << writerFormat << "Writer \n";
+ ASSERT_TRUE(false);
+ }
+ CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+ status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+ mBufferInfo.size() / 4);
+ if (status) {
+ cout << writerFormat << " writer failed \n";
+ mCurrentTrack->stop();
+ mWriter->stop();
+ ASSERT_TRUE(false);
+ }
+
+ bool isPaused = false;
+ if ((mWriterName != standardWriters::MPEG2TS) && (mWriterName != standardWriters::MPEG4)) {
+ CHECK_EQ((status_t)OK, mWriter->pause());
+ isPaused = true;
+ }
+ // In the pause state, writers shouldn't write anything. Testing the writers for the same
+ int32_t numFramesPaused = mBufferInfo.size() / 4;
+ status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+ mInputFrameId, numFramesPaused, isPaused);
+ if (isPaused) {
+ CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+ }
+ status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+ mInputFrameId, mBufferInfo.size());
+ mCurrentTrack->stop();
+ if (status) {
+ cout << writerFormat << " writer failed \n";
+ mWriter->stop();
+ ASSERT_TRUE(false);
+ }
+ CHECK_EQ((status_t)OK, mWriter->stop());
+ close(fd);
+}
+
+// TODO: (b/144476164)
+// Add AAC_ADTS, FLAC, AV1 input
+INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriterTest,
+ ::testing::Values(make_pair("ogg", 0), make_pair("webm", 0),
+ make_pair("aac", 1), make_pair("mpeg4", 1),
+ make_pair("amrnb", 3), make_pair("amrwb", 4),
+ make_pair("webm", 5), make_pair("webm", 7),
+ make_pair("webm", 8), make_pair("mpeg4", 9),
+ make_pair("mpeg4", 10), make_pair("mpeg4", 12),
+ make_pair("mpeg4", 13), make_pair("mpeg2Ts", 1),
+ make_pair("mpeg2Ts", 9)));
+
+int main(int argc, char **argv) {
+ gEnv = new WriterTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ }
+ return status;
+}
diff --git a/media/libstagefright/tests/writer/WriterTestEnvironment.h b/media/libstagefright/tests/writer/WriterTestEnvironment.h
new file mode 100644
index 0000000..34c2baa
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WRITER_TEST_ENVIRONMENT_H__
+#define __WRITER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class WriterTestEnvironment : public ::testing::Environment {
+ public:
+ WriterTestEnvironment() : res("/sdcard/media/") {}
+
+ // Parses the command line arguments
+ int initFromOptions(int argc, char **argv);
+
+ void setRes(const char *_res) { res = _res; }
+
+ const string getRes() const { return res; }
+
+ private:
+ string res;
+};
+
+int WriterTestEnvironment::initFromOptions(int argc, char **argv) {
+ static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "P:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'P':
+ setRes(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-P, --path: Resource files directory location\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+}
+
+#endif // __WRITER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/tests/writer/WriterUtility.cpp b/media/libstagefright/tests/writer/WriterUtility.cpp
new file mode 100644
index 0000000..2ba90a0
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WriterUtility"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+
+#include "WriterUtility.h"
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<MediaAdapter> ¤tTrack, int32_t offset,
+ int32_t range, bool isPaused) {
+ while (1) {
+ if (inputFrameId == (int)bufferInfo.size() || inputFrameId >= (offset + range)) break;
+ int32_t size = bufferInfo[inputFrameId].size;
+ char *data = (char *)malloc(size);
+ if (!data) {
+ ALOGE("Insufficient memeory to read input");
+ return -1;
+ }
+
+ inputStream.read(data, size);
+ CHECK_EQ(inputStream.gcount(), size);
+
+ sp<ABuffer> buffer = new ABuffer((void *)data, size);
+ if (buffer.get() == nullptr) {
+ ALOGE("sendBuffersToWriter() got a nullptr buffer.");
+ return -1;
+ }
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
+ // Released in MediaAdapter::signalBufferReturned().
+ mediaBuffer->add_ref();
+ mediaBuffer->set_range(buffer->offset(), buffer->size());
+
+ MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
+ sampleMetaData.setInt64(kKeyTime, bufferInfo[inputFrameId].timeUs);
+ // Just set the kKeyDecodingTime as the presentation time for now.
+ sampleMetaData.setInt64(kKeyDecodingTime, bufferInfo[inputFrameId].timeUs);
+
+ if (bufferInfo[inputFrameId].flags == 1) {
+ sampleMetaData.setInt32(kKeyIsSyncFrame, true);
+ }
+
+ // This pushBuffer will wait until the mediaBuffer is consumed.
+ int status = currentTrack->pushBuffer(mediaBuffer);
+ free(data);
+ inputFrameId++;
+
+ if (OK != status) {
+ if (!isPaused) return status;
+ else {
+ ALOGD("Writer is in paused state. Input buffers won't get consumed");
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds) {
+ char csdName[kMaxCSDStrlen];
+ for (int csdId = 0; csdId < numCsds; csdId++) {
+ int32_t flags = bufferInfo[inputFrameId].flags;
+ if (flags == CODEC_CONFIG_FLAG) {
+ int32_t size = bufferInfo[inputFrameId].size;
+ char *data = (char *)malloc(size);
+ if (!data) {
+ ALOGE("Insufficient memeory to read input");
+ return -1;
+ }
+ inputStream.read(data, size);
+ CHECK_EQ(inputStream.gcount(), size);
+
+ sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy((void *)data, size);
+ if (csdBuffer.get() == nullptr || csdBuffer->base() == nullptr) {
+ return -1;
+ }
+ snprintf(csdName, sizeof(csdName), "csd-%d", csdId);
+ format->setBuffer(csdName, csdBuffer);
+ inputFrameId++;
+ free(data);
+ }
+ }
+ return 0;
+}
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
new file mode 100644
index 0000000..d402798
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WRITER_UTILITY_H_
+#define WRITER_UTILITY_H_
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MediaAdapter.h>
+
+using namespace android;
+using namespace std;
+
+#define CODEC_CONFIG_FLAG 32
+
+constexpr uint32_t kMaxCSDStrlen = 16;
+
+struct BufferInfo {
+ int32_t size;
+ uint32_t flags;
+ int64_t timeUs;
+};
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<MediaAdapter> ¤tTrack, int32_t offset,
+ int32_t range, bool isPaused = false);
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+ int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds);
+
+#endif // WRITER_UTILITY_H_
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index 08ef2d1..babc329 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -24,6 +24,7 @@
srcs: [
"BenchmarkCommon.cpp",
"Stats.cpp",
+ "utils/Timers.cpp",
],
export_include_dirs: ["."],
@@ -49,7 +50,6 @@
shared_libs: [
"libmediandk",
"liblog",
- "libutils",
],
cflags: [
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
index 5bdb48a..ab74508 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
@@ -56,10 +56,10 @@
void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode,
const char *detail) {
- (void)codec;
- ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
+ ALOGE("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
CallBackHandle *self = (CallBackHandle *)userdata;
self->mSawError = true;
+ self->mIOQueue.push([self, codec, err]() { self->onError(codec, err); });
}
AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.h b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
index df16baf..8153a86 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.h
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
@@ -17,8 +17,6 @@
#ifndef __BENCHMARK_COMMON_H__
#define __BENCHMARK_COMMON_H__
-#include <utils/Log.h>
-
#include <inttypes.h>
#include <mutex>
#include <queue>
@@ -89,6 +87,10 @@
(void)codec;
(void)format;
}
+ virtual void onError(AMediaCodec *codec, media_status_t err) {
+ (void)codec;
+ (void)err;
+ }
virtual void onOutputAvailable(AMediaCodec *codec, int32_t index,
AMediaCodecBufferInfo *bufferInfo) {
(void)codec;
diff --git a/media/tests/benchmark/src/native/common/Stats.cpp b/media/tests/benchmark/src/native/common/Stats.cpp
index 6bcd3ce..2d9bb31 100644
--- a/media/tests/benchmark/src/native/common/Stats.cpp
+++ b/media/tests/benchmark/src/native/common/Stats.cpp
@@ -19,7 +19,6 @@
#include <iostream>
#include <stdint.h>
-#include <utils/Log.h>
#include "Stats.h"
diff --git a/media/tests/benchmark/src/native/common/Stats.h b/media/tests/benchmark/src/native/common/Stats.h
index 024319a..2f556ee 100644
--- a/media/tests/benchmark/src/native/common/Stats.h
+++ b/media/tests/benchmark/src/native/common/Stats.h
@@ -17,11 +17,28 @@
#ifndef __STATS_H__
#define __STATS_H__
+#include <android/log.h>
+
+#ifndef ALOG
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define ALOGD(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#if LOG_NDEBUG
+#define ALOGV(cond, ...) ((void)0)
+#else
+#define ALOGV(...) ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#endif
+#endif // ALOG
+
#include <sys/time.h>
#include <algorithm>
#include <numeric>
#include <vector>
-#include <utils/Timers.h>
+
+// Include local copy of Timers taken from system/core/libutils
+#include "utils/Timers.h"
using namespace std;
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.cpp b/media/tests/benchmark/src/native/common/utils/Timers.cpp
new file mode 100644
index 0000000..1acbdb3
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Timer functions.
+//
+
+#define LOG_TAG "Timers"
+
+#include <limits.h>
+#include <time.h>
+
+#include "Timers.h"
+
+#if defined(__ANDROID__)
+nsecs_t systemTime(int clock) {
+ static const clockid_t clocks[] = {CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+ CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME};
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(clocks[clock], &t);
+ return nsecs_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+#else
+nsecs_t systemTime(int /*clock*/) {
+ // Clock support varies widely across hosts. Mac OS doesn't support
+ // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
+ // is windows.
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ return nsecs_t(t.tv_sec) * 1000000000LL + nsecs_t(t.tv_usec) * 1000LL;
+}
+#endif
+
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) {
+ nsecs_t timeoutDelayMillis;
+ if (timeoutTime > referenceTime) {
+ uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+ if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+ timeoutDelayMillis = -1;
+ } else {
+ timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+ }
+ } else {
+ timeoutDelayMillis = 0;
+ }
+ return (int)timeoutDelayMillis;
+}
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.h b/media/tests/benchmark/src/native/common/utils/Timers.h
new file mode 100644
index 0000000..d643dcd
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Timer functions.
+//
+
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t; // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) {
+ return secs * 1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) {
+ return secs * 1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) {
+ return secs * 1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) {
+ return secs / 1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) {
+ return secs / 1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) {
+ return secs / 1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v) {
+ return seconds_to_nanoseconds(v);
+}
+static inline nsecs_t ms2ns(nsecs_t v) {
+ return milliseconds_to_nanoseconds(v);
+}
+static inline nsecs_t us2ns(nsecs_t v) {
+ return microseconds_to_nanoseconds(v);
+}
+static inline nsecs_t ns2s(nsecs_t v) {
+ return nanoseconds_to_seconds(v);
+}
+static inline nsecs_t ns2ms(nsecs_t v) {
+ return nanoseconds_to_milliseconds(v);
+}
+static inline nsecs_t ns2us(nsecs_t v) {
+ return nanoseconds_to_microseconds(v);
+}
+
+static inline nsecs_t seconds(nsecs_t v) {
+ return s2ns(v);
+}
+static inline nsecs_t milliseconds(nsecs_t v) {
+ return ms2ns(v);
+}
+static inline nsecs_t microseconds(nsecs_t v) {
+ return us2ns(v);
+}
+
+enum {
+ SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
+ SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
+ SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock
+ SYSTEM_TIME_THREAD = 3, // high-resolution per-thread clock
+ SYSTEM_TIME_BOOTTIME = 4 // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
+};
+
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif // def __cplusplus
+
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _LIBS_UTILS_TIMERS_H
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.cpp b/media/tests/benchmark/src/native/decoder/Decoder.cpp
index ef84537..ac0d525 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.cpp
+++ b/media/tests/benchmark/src/native/decoder/Decoder.cpp
@@ -32,8 +32,8 @@
int64_t timestamp = frameInfo[frameID].presentationTimeUs;
ssize_t bytesCount = frameInfo[frameID].size;
if (bufSize < bytesCount) {
- ALOGE("Error : insufficient resource");
- return make_tuple(0, AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE, 0);
+ ALOGE("Error : Buffer size is insufficient to read sample");
+ return make_tuple(0, AMEDIA_ERROR_MALFORMED, 0);
}
memcpy(buf, inputBuffer + offset, bytesCount);
@@ -54,6 +54,7 @@
size_t bufSize;
uint8_t *buf = AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
if (!buf) {
+ mErrorCode = AMEDIA_ERROR_IO;
mSignalledError = true;
mDecoderDoneCondition.notify_one();
return;
@@ -64,7 +65,8 @@
int64_t presentationTimeUs = 0;
tie(bytesRead, flag, presentationTimeUs) = readSampleData(
mInputBuffer, mOffset, mFrameMetaData, buf, mNumInputFrame, bufSize);
- if (flag == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE) {
+ if (flag == AMEDIA_ERROR_MALFORMED) {
+ mErrorCode = (media_status_t)flag;
mSignalledError = true;
mDecoderDoneCondition.notify_one();
return;
@@ -74,9 +76,10 @@
ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRId64 " mSawInputEOS : %s", __FUNCTION__,
bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
- int status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */, bytesRead,
- presentationTimeUs, flag);
+ media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+ bytesRead, presentationTimeUs, flag);
if (AMEDIA_OK != status) {
+ mErrorCode = status;
mSignalledError = true;
mDecoderDoneCondition.notify_one();
return;
@@ -127,6 +130,16 @@
}
}
+void Decoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ ALOGE("Received Error %d", err);
+ mErrorCode = err;
+ mSignalledError = true;
+ mDecoderDoneCondition.notify_one();
+ }
+}
+
void Decoder::setupDecoder() {
if (!mFormat) mFormat = mExtractor->getFormat();
}
@@ -168,7 +181,8 @@
ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
- return AMEDIA_ERROR_IO;
+ mErrorCode = (media_status_t)inIdx;
+ return mErrorCode;
} else if (inIdx >= 0) {
mStats->addInputTime();
onInputAvailable(mCodec, inIdx);
@@ -188,13 +202,18 @@
} else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
- return AMEDIA_ERROR_IO;
+ mErrorCode = (media_status_t)outIdx;
+ return mErrorCode;
}
}
} else {
unique_lock<mutex> lock(mMutex);
mDecoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
}
+ if (mSignalledError) {
+ ALOGE("Received Error while Decoding");
+ return mErrorCode;
+ }
if (codecName.empty()) {
char *decName;
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.h b/media/tests/benchmark/src/native/decoder/Decoder.h
index 7630e7b..aeda080 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.h
+++ b/media/tests/benchmark/src/native/decoder/Decoder.h
@@ -38,6 +38,7 @@
mSawInputEOS(false),
mSawOutputEOS(false),
mSignalledError(false),
+ mErrorCode(AMEDIA_OK),
mInputBuffer(nullptr),
mOutFp(nullptr) {
mExtractor = new Extractor();
@@ -61,6 +62,8 @@
void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
+ void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
void onOutputAvailable(AMediaCodec *codec, int32_t index,
AMediaCodecBufferInfo *bufferInfo) override;
@@ -82,6 +85,7 @@
bool mSawInputEOS;
bool mSawOutputEOS;
bool mSignalledError;
+ media_status_t mErrorCode;
int32_t mOffset;
uint8_t *mInputBuffer;
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.cpp b/media/tests/benchmark/src/native/encoder/Encoder.cpp
index 5fdf9e3..a5605de 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.cpp
+++ b/media/tests/benchmark/src/native/encoder/Encoder.cpp
@@ -34,6 +34,7 @@
size_t bufSize = 0;
char *buf = (char *)AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
if (!buf) {
+ mErrorCode = AMEDIA_ERROR_IO;
mSignalledError = true;
mEncoderDoneCondition.notify_one();
return;
@@ -41,6 +42,7 @@
if (mInputBufferSize < mOffset) {
ALOGE("Out of bound access of input buffer\n");
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
mSignalledError = true;
mEncoderDoneCondition.notify_one();
return;
@@ -51,6 +53,7 @@
}
if (bufSize < bytesRead) {
ALOGE("bytes to read %zu bufSize %zu \n", bytesRead, bufSize);
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
mSignalledError = true;
mEncoderDoneCondition.notify_one();
return;
@@ -58,6 +61,7 @@
if (bytesRead < mParams.frameSize && mNumInputFrame < mParams.numFrames - 1) {
ALOGE("Partial frame at frameID %d bytesRead %zu frameSize %d total numFrames %d\n",
mNumInputFrame, bytesRead, mParams.frameSize, mParams.numFrames);
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
mSignalledError = true;
mEncoderDoneCondition.notify_one();
return;
@@ -66,6 +70,7 @@
size_t bytesgcount = mEleStream->gcount();
if (bytesgcount != bytesRead) {
ALOGE("bytes to read %zu actual bytes read %zu \n", bytesRead, bytesgcount);
+ mErrorCode = AMEDIA_ERROR_MALFORMED;
mSignalledError = true;
mEncoderDoneCondition.notify_one();
return;
@@ -89,9 +94,10 @@
ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRIu64 " mSawInputEOS : %s", __FUNCTION__,
bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
- int status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */, bytesRead,
- presentationTimeUs, flag);
+ media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+ bytesRead, presentationTimeUs, flag);
if (AMEDIA_OK != status) {
+ mErrorCode = status;
mSignalledError = true;
mEncoderDoneCondition.notify_one();
return;
@@ -133,6 +139,16 @@
}
}
+void Encoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+ ALOGV("In %s", __func__);
+ if (mediaCodec == mCodec && mediaCodec) {
+ ALOGE("Received Error %d", err);
+ mErrorCode = err;
+ mSignalledError = true;
+ mEncoderDoneCondition.notify_one();
+ }
+}
+
void Encoder::setupEncoder() {
if (!mFormat) mFormat = AMediaFormat_new();
}
@@ -235,7 +251,8 @@
ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
- return AMEDIA_ERROR_IO;
+ mErrorCode = (media_status_t)inIdx;
+ return mErrorCode;
} else if (inIdx >= 0) {
mStats->addInputTime();
onInputAvailable(mCodec, inIdx);
@@ -255,13 +272,18 @@
} else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
- return AMEDIA_ERROR_IO;
+ mErrorCode = (media_status_t)outIdx;
+ return mErrorCode;
}
}
} else {
unique_lock<mutex> lock(mMutex);
mEncoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
}
+ if (mSignalledError) {
+ ALOGE("Received Error while Encoding");
+ return mErrorCode;
+ }
if (codecName.empty()) {
char *encName;
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.h b/media/tests/benchmark/src/native/encoder/Encoder.h
index 75d9941..6059c4a 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.h
+++ b/media/tests/benchmark/src/native/encoder/Encoder.h
@@ -49,7 +49,8 @@
mNumOutputFrame(0),
mSawInputEOS(false),
mSawOutputEOS(false),
- mSignalledError(false) {}
+ mSignalledError(false),
+ mErrorCode(AMEDIA_OK) {}
virtual ~Encoder() {}
@@ -65,6 +66,8 @@
void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
+ void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
void onOutputAvailable(AMediaCodec *codec, int32_t index,
AMediaCodecBufferInfo *bufferInfo) override;
@@ -83,6 +86,7 @@
bool mSawInputEOS;
bool mSawOutputEOS;
bool mSignalledError;
+ media_status_t mErrorCode;
char *mMime;
int32_t mOffset;
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 242178f..fa37435 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -93,7 +93,7 @@
decoder->setupDecoder();
status = decoder->decode(inputBuffer, frameInfo, codecName, asyncMode);
if (status != AMEDIA_OK) {
- cout << "[ WARN ] Test Skipped. Decode returned error \n";
+ cout << "[ WARN ] Test Failed. Decode returned error " << status << endl;
free(inputBuffer);
return;
}
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 9f42c64..c3963f8 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -143,7 +143,11 @@
string codecName = get<1>(params);
bool asyncMode = get<2>(params);
status = encoder->encode(codecName, eleStream, eleSize, asyncMode, encParams, (char *)mime);
- ASSERT_EQ(status, 0);
+ if (status != AMEDIA_OK) {
+ cout << "[ WARN ] Test Failed. Encode returned error " << status << endl;
+ free(inputBuffer);
+ return;
+ }
encoder->deInitCodec();
cout << "codec : " << codecName << endl;
string inputReference = get<0>(params);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 84c2ec7..3089181 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -139,7 +139,9 @@
mOutputSlots.clear();
mConsumerBufferCount.clear();
- mConsumer->consumerDisconnect();
+ if (mConsumer.get() != nullptr) {
+ mConsumer->consumerDisconnect();
+ }
if (mBuffers.size() > 0) {
SP_LOGW("%zu buffers still being tracked", mBuffers.size());