• Home
  • History
  • Annotate
  • 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 <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