• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdlib.h>
21 
22 #include "NativeMediaCommon.h"
23 
24 /* TODO(b/153592281)
25  * Note: constants used by the native media tests but not available in media ndk api
26  */
27 const char* AMEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
28 const char* AMEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
29 const char* AMEDIA_MIMETYPE_VIDEO_AV1 = "video/av01";
30 const char* AMEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
31 const char* AMEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
32 const char* AMEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
33 const char* AMEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
34 
35 const char* AMEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
36 const char* AMEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
37 const char* AMEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
38 const char* AMEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac";
39 const char* AMEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
40 const char* AMEDIA_MIMETYPE_AUDIO_OPUS = "audio/opus";
41 const char* AMEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
42 
43 /* TODO(b/153592281) */
44 const char* TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
45 const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
46 const char* COMPATIBLE_AMEDIAFORMAT_KEY_MAX_B_FRAMES = "max-bframes";
47 const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE = "bitrate-mode";
48 
49 // NDK counterpart of RMS_ERROR_TOLERANCE of CodecDecoderTest class
50 const float kRmsErrorTolerance = 1.05f;
51 
52 // NDK counterpart of Q_DEQ_TIMEOUT_US and RETRY_LIMIT of CodecTestBase class
53 const long kQDeQTimeOutUs = 5000; // block at most 5ms while looking for io buffers
54 const int kRetryLimit = 100; // max poll counter before test aborts and returns error
55 
isCSDIdentical(AMediaFormat * refFormat,AMediaFormat * testFormat)56 bool isCSDIdentical(AMediaFormat* refFormat, AMediaFormat* testFormat) {
57     for (int i = 0;; i++) {
58         std::pair<void*, size_t> refCsd;
59         std::pair<void*, size_t> testCsd;
60         char name[16];
61         snprintf(name, sizeof(name), "csd-%d", i);
62         bool hasRefCSD = AMediaFormat_getBuffer(refFormat, name, &refCsd.first, &refCsd.second);
63         bool hasTestCSD = AMediaFormat_getBuffer(testFormat, name, &testCsd.first, &testCsd.second);
64         if (hasRefCSD != hasTestCSD) {
65             ALOGW("mismatch, ref fmt has CSD %d, test fmt has CSD %d", hasRefCSD, hasTestCSD);
66             return false;
67         }
68         if (hasRefCSD) {
69             if (refCsd.second != testCsd.second) {
70                 ALOGW("ref/test %s buffer sizes are not identical %zu/%zu", name, refCsd.second,
71                       testCsd.second);
72                 return false;
73             }
74             if (memcmp(refCsd.first, testCsd.first, refCsd.second)) {
75                 ALOGW("ref/test %s buffers are not identical", name);
76                 return false;
77             }
78         } else break;
79     }
80     return true;
81 }
82 
83 template <class T>
flattenField(uint8_t * buffer,int * pos,T value)84 void flattenField(uint8_t* buffer, int* pos, T value) {
85     uint8_t* ptr = (buffer + *pos);
86     for (int i = sizeof(T) - 1; i >= 0; i--) {
87         *ptr++ = (uint8_t)((value >> (i * 8)) & 0xff);
88     }
89     *pos += sizeof(T);
90 }
91 
92 template void flattenField<int32_t>(uint8_t* buffer, int* pos, int32_t value);
93 template void flattenField<int64_t>(uint8_t* buffer, int* pos, int64_t value);
94 
isFormatSimilar(AMediaFormat * refFormat,AMediaFormat * testFormat)95 bool isFormatSimilar(AMediaFormat* refFormat, AMediaFormat* testFormat) {
96     const char *refMediaType = nullptr, *testMediaType = nullptr;
97     int64_t refKeyDuration, testKeyDuration;
98     bool hasRefMediaType = AMediaFormat_getString(refFormat, AMEDIAFORMAT_KEY_MIME, &refMediaType);
99     if (!hasRefMediaType) return false;
100     bool hasTestMediaType =
101             AMediaFormat_getString(testFormat, AMEDIAFORMAT_KEY_MIME, &testMediaType);
102     if (!hasTestMediaType) return false;
103     if (strcmp(refMediaType, testMediaType) != 0) return false;
104     bool hasRefKeyDuration =
105             AMediaFormat_getInt64(refFormat, AMEDIAFORMAT_KEY_DURATION, &refKeyDuration);
106     if (!hasRefKeyDuration) return false;
107     bool hasTestKeyDuration =
108             AMediaFormat_getInt64(testFormat, AMEDIAFORMAT_KEY_DURATION, &testKeyDuration);
109     if (!hasTestKeyDuration) return false;
110     if (refKeyDuration != testKeyDuration) {
111         ALOGW("Duration mismatches ref / test = %lld / %lld", (long long)refKeyDuration,
112               (long long)testKeyDuration);
113         // TODO (b/163477410)(b/163478168)
114 //        return false;
115     }
116     if (!isCSDIdentical(refFormat, testFormat)) return false;
117     if (!strncmp(refMediaType, "audio/", strlen("audio/"))) {
118         int32_t refSampleRate, testSampleRate, refNumChannels, testNumChannels;
119         bool hasRefSampleRate =
120                 AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &refSampleRate);
121         if (!hasRefSampleRate) return false;
122         bool hasTestSampleRate =
123                 AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &testSampleRate);
124         if (!hasTestSampleRate) return false;
125         if (refSampleRate != testSampleRate) return false;
126         bool hasRefNumChannels =
127                 AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &refNumChannels);
128         if (!hasRefNumChannels) return false;
129         bool hasTestNumChannels =
130                 AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &testNumChannels);
131         if (!hasTestNumChannels) return false;
132         if (refNumChannels != testNumChannels) return false;
133     } else if (!strncmp(refMediaType, "video/", strlen("video/"))) {
134         int32_t refWidth, testWidth, refHeight, testHeight;
135         bool hasRefWidth = AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_WIDTH, &refWidth);
136         if (!hasRefWidth) return false;
137         bool hasTestWidth = AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_WIDTH, &testWidth);
138         if (!hasTestWidth) return false;
139         if (refWidth != testWidth) return false;
140         bool hasRefHeight = AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_HEIGHT, &refHeight);
141         if (!hasRefHeight) return false;
142         bool hasTestHeight =
143                 AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_HEIGHT, &testHeight);
144         if (!hasTestHeight) return false;
145         if (refHeight != testHeight) return false;
146     }
147     return true;
148 }
149 
isMediaTypeOutputUnAffectedBySeek(const char * mediaType)150 bool isMediaTypeOutputUnAffectedBySeek(const char* mediaType) {
151     if (strcmp(mediaType, AMEDIA_MIMETYPE_AUDIO_FLAC) == 0) return true;
152     if (strcmp(mediaType, AMEDIA_MIMETYPE_AUDIO_RAW) == 0) return true;
153     if (strncmp(mediaType, "video/", strlen("video/")) == 0) return true;
154     return false;
155 }
156 
deSerializeMediaFormat(const char * msg,const char * separator)157 AMediaFormat* deSerializeMediaFormat(const char* msg, const char* separator) {
158     if (msg == nullptr || separator == nullptr) return nullptr;
159     // constants to be kept in sync with definitions at MediaFormat.java
160     static const int TYPE_INTEGER = 1;
161     static const int TYPE_LONG = 2;
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 = atoi(valueTypeStr.c_str());
200         if (valueType == TYPE_INTEGER) {
201             AMediaFormat_setInt32(fmt, keyStr.c_str(), atoi(valueStr.c_str()));
202         } else if (valueType == TYPE_LONG) {
203             AMediaFormat_setInt64(fmt, keyStr.c_str(), atol(valueStr.c_str()));
204         } else if (valueType == TYPE_FLOAT) {
205             AMediaFormat_setFloat(fmt, keyStr.c_str(), atof(valueStr.c_str()));
206         } else if (valueType == TYPE_STRING) {
207             AMediaFormat_setString(fmt, keyStr.c_str(), valueStr.c_str());
208         } else {
209             ALOGE("unrecognized type for key %s", keyStr.c_str());
210             AMediaFormat_delete(fmt);
211             return nullptr;
212         }
213     }
214     return fmt;
215 }
216