1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 //#define LOG_NDEBUG 0 17 #define LOG_TAG "NativeMediaCommon" 18 #include <log/log.h> 19 20 #include <cstdio> 21 #include <cstring> 22 #include <utility> 23 24 #include "NativeMediaCommon.h" 25 26 /* TODO(b/153592281) 27 * Note: constants used by the native media tests but not available in media ndk api 28 */ 29 const char* AMEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"; 30 const char* AMEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"; 31 const char* AMEDIA_MIMETYPE_VIDEO_AV1 = "video/av01"; 32 const char* AMEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; 33 const char* AMEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc"; 34 const char* AMEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; 35 const char* AMEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp"; 36 37 const char* AMEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp"; 38 const char* AMEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb"; 39 const char* AMEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"; 40 const char* AMEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac"; 41 const char* AMEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis"; 42 const char* AMEDIA_MIMETYPE_AUDIO_OPUS = "audio/opus"; 43 const char* AMEDIA_MIMETYPE_AUDIO_RAW = "audio/raw"; 44 45 /* TODO(b/153592281) */ 46 const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync"; 47 const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate"; 48 const char* COMPATIBLE_AMEDIAFORMAT_KEY_MAX_B_FRAMES = "max-bframes"; 49 const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE = "bitrate-mode"; 50 51 // NDK counterpart of RMS_ERROR_TOLERANCE of CodecDecoderTest class 52 const float kRmsErrorTolerance = 1.05f; 53 54 // NDK counterpart of Q_DEQ_TIMEOUT_US and RETRY_LIMIT of CodecTestBase class 55 const long kQDeQTimeOutUs = 5000; // block at most 5ms while looking for io buffers 56 const int kRetryLimit = 100; // max poll counter before test aborts and returns error 57 isCSDIdentical(AMediaFormat * refFormat,AMediaFormat * testFormat)58 bool isCSDIdentical(AMediaFormat* refFormat, AMediaFormat* testFormat) { 59 for (int i = 0;; i++) { 60 std::pair<void*, size_t> refCsd; 61 std::pair<void*, size_t> testCsd; 62 char name[16]; 63 snprintf(name, sizeof(name), "csd-%d", i); 64 bool hasRefCSD = AMediaFormat_getBuffer(refFormat, name, &refCsd.first, &refCsd.second); 65 bool hasTestCSD = AMediaFormat_getBuffer(testFormat, name, &testCsd.first, &testCsd.second); 66 if (hasRefCSD != hasTestCSD) { 67 ALOGW("mismatch, ref fmt has CSD %d, test fmt has CSD %d", hasRefCSD, hasTestCSD); 68 return false; 69 } 70 if (hasRefCSD) { 71 if (refCsd.second != testCsd.second) { 72 ALOGW("ref/test %s buffer sizes are not identical %zu/%zu", name, refCsd.second, 73 testCsd.second); 74 return false; 75 } 76 if (memcmp(refCsd.first, testCsd.first, refCsd.second)) { 77 ALOGW("ref/test %s buffers are not identical", name); 78 return false; 79 } 80 } else break; 81 } 82 return true; 83 } 84 85 template <class T> flattenField(uint8_t * buffer,int * pos,T value)86 void flattenField(uint8_t* buffer, int* pos, T value) { 87 uint8_t* ptr = (buffer + *pos); 88 for (int i = sizeof(T) - 1; i >= 0; i--) { 89 *ptr++ = (uint8_t)((value >> (i * 8)) & 0xff); 90 } 91 *pos += sizeof(T); 92 } 93 94 template void flattenField<int32_t>(uint8_t* buffer, int* pos, int32_t value); 95 template void flattenField<int64_t>(uint8_t* buffer, int* pos, int64_t value); 96 isFormatSimilar(AMediaFormat * refFormat,AMediaFormat * testFormat)97 bool isFormatSimilar(AMediaFormat* refFormat, AMediaFormat* testFormat) { 98 const char *refMediaType = nullptr, *testMediaType = nullptr; 99 int64_t refKeyDuration, testKeyDuration; 100 bool hasRefMediaType = AMediaFormat_getString(refFormat, AMEDIAFORMAT_KEY_MIME, &refMediaType); 101 if (!hasRefMediaType) return false; 102 bool hasTestMediaType = 103 AMediaFormat_getString(testFormat, AMEDIAFORMAT_KEY_MIME, &testMediaType); 104 if (!hasTestMediaType) return false; 105 if (strcmp(refMediaType, testMediaType) != 0) return false; 106 bool hasRefKeyDuration = 107 AMediaFormat_getInt64(refFormat, AMEDIAFORMAT_KEY_DURATION, &refKeyDuration); 108 if (!hasRefKeyDuration) return false; 109 bool hasTestKeyDuration = 110 AMediaFormat_getInt64(testFormat, AMEDIAFORMAT_KEY_DURATION, &testKeyDuration); 111 if (!hasTestKeyDuration) return false; 112 if (refKeyDuration != testKeyDuration) { 113 ALOGW("Duration mismatches ref / test = %lld / %lld", (long long)refKeyDuration, 114 (long long)testKeyDuration); 115 // TODO (b/163477410)(b/163478168) 116 // return false; 117 } 118 if (!isCSDIdentical(refFormat, testFormat)) return false; 119 if (!strncmp(refMediaType, "audio/", strlen("audio/"))) { 120 int32_t refSampleRate, testSampleRate, refNumChannels, testNumChannels; 121 bool hasRefSampleRate = 122 AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &refSampleRate); 123 if (!hasRefSampleRate) return false; 124 bool hasTestSampleRate = 125 AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &testSampleRate); 126 if (!hasTestSampleRate) return false; 127 if (refSampleRate != testSampleRate) return false; 128 bool hasRefNumChannels = 129 AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &refNumChannels); 130 if (!hasRefNumChannels) return false; 131 bool hasTestNumChannels = 132 AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &testNumChannels); 133 if (!hasTestNumChannels) return false; 134 if (refNumChannels != testNumChannels) return false; 135 } else if (!strncmp(refMediaType, "video/", strlen("video/"))) { 136 int32_t refWidth, testWidth, refHeight, testHeight; 137 bool hasRefWidth = AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_WIDTH, &refWidth); 138 if (!hasRefWidth) return false; 139 bool hasTestWidth = AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_WIDTH, &testWidth); 140 if (!hasTestWidth) return false; 141 if (refWidth != testWidth) return false; 142 bool hasRefHeight = AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_HEIGHT, &refHeight); 143 if (!hasRefHeight) return false; 144 bool hasTestHeight = 145 AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_HEIGHT, &testHeight); 146 if (!hasTestHeight) return false; 147 if (refHeight != testHeight) return false; 148 } 149 return true; 150 } 151 isMediaTypeOutputUnAffectedBySeek(const char * mediaType)152 bool isMediaTypeOutputUnAffectedBySeek(const char* mediaType) { 153 if (strcmp(mediaType, AMEDIA_MIMETYPE_AUDIO_FLAC) == 0) return true; 154 if (strcmp(mediaType, AMEDIA_MIMETYPE_AUDIO_RAW) == 0) return true; 155 if (strncmp(mediaType, "video/", strlen("video/")) == 0) return true; 156 return false; 157 } 158 deSerializeMediaFormat(const char * msg,const char * separator)159 AMediaFormat* deSerializeMediaFormat(const char* msg, const char* separator) { 160 // constants to be kept in sync with definitions at MediaFormat.java 161 static const int TYPE_INTEGER = 1; 162 static const int TYPE_FLOAT = 3; 163 static const int TYPE_STRING = 4; 164 std::string limiter{separator}; 165 std::string fmtMsg{msg}; 166 AMediaFormat* fmt = AMediaFormat_new(); 167 if (fmt == nullptr) { 168 ALOGE("no format received"); 169 return nullptr; 170 } 171 auto start = 0u; 172 auto end = fmtMsg.find(limiter); 173 std::string keyStr, valueTypeStr, valueStr; 174 for (; end != std::string::npos;) { 175 // key 176 keyStr = fmtMsg.substr(start, end - start); 177 start = end + limiter.length(); 178 end = fmtMsg.find(limiter, start); 179 if (end == std::string::npos) { 180 ALOGE("incomplete media format received %s", msg); 181 AMediaFormat_delete(fmt); 182 return nullptr; 183 } 184 // value type 185 valueTypeStr = fmtMsg.substr(start, end - start); 186 start = end + limiter.length(); 187 end = fmtMsg.find(limiter, start); 188 if (end == std::string::npos) { 189 ALOGE("incomplete media format received %s", msg); 190 AMediaFormat_delete(fmt); 191 return nullptr; 192 } 193 194 // value 195 valueStr = fmtMsg.substr(start, end - start); 196 start = end + limiter.length(); 197 end = fmtMsg.find(limiter, start); 198 199 auto valueType = std::stoi(valueTypeStr); 200 if (valueType == TYPE_INTEGER) { 201 AMediaFormat_setInt32(fmt, keyStr.c_str(), std::stoi(valueStr)); 202 } else if (valueType == TYPE_FLOAT) { 203 AMediaFormat_setFloat(fmt, keyStr.c_str(), std::stof(valueStr)); 204 } else if (valueType == TYPE_STRING) { 205 AMediaFormat_setString(fmt, keyStr.c_str(), valueStr.c_str()); 206 } else { 207 ALOGE("unrecognized type for key %s", keyStr.c_str()); 208 AMediaFormat_delete(fmt); 209 return nullptr; 210 } 211 } 212 return fmt; 213 } 214