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