1 /*
2  * Copyright (C) 2017 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 
17 #define LOG_TAG "media_omx_hidl_video_enc_test"
18 #ifdef __LP64__
19 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
20 #endif
21 
22 #include <android-base/logging.h>
23 
24 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
25 #include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
26 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
27 #include <android/hardware/media/omx/1.0/IOmx.h>
28 #include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
29 #include <android/hardware/media/omx/1.0/IOmxNode.h>
30 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
31 #include <android/hardware/media/omx/1.0/types.h>
32 #include <android/hidl/allocator/1.0/IAllocator.h>
33 #include <android/hidl/memory/1.0/IMapper.h>
34 #include <android/hidl/memory/1.0/IMemory.h>
35 #include <gtest/gtest.h>
36 #include <hidl/GtestPrinter.h>
37 
38 using ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer;
39 using ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener;
40 using ::android::hardware::graphics::common::V1_0::BufferUsage;
41 using ::android::hardware::graphics::common::V1_0::PixelFormat;
42 using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
43 using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
44 using ::android::hardware::media::omx::V1_0::IOmx;
45 using ::android::hardware::media::omx::V1_0::IOmxObserver;
46 using ::android::hardware::media::omx::V1_0::IOmxNode;
47 using ::android::hardware::media::omx::V1_0::Message;
48 using ::android::hardware::media::omx::V1_0::CodecBuffer;
49 using ::android::hardware::media::omx::V1_0::PortMode;
50 using ::android::hidl::allocator::V1_0::IAllocator;
51 using ::android::hidl::memory::V1_0::IMemory;
52 using ::android::hidl::memory::V1_0::IMapper;
53 using ::android::hardware::Return;
54 using ::android::hardware::Void;
55 using ::android::hardware::hidl_vec;
56 using ::android::hardware::hidl_string;
57 using ::android::sp;
58 
59 #include <getopt.h>
60 #include <media/hardware/HardwareAPI.h>
61 #include <media_video_hidl_test_common.h>
62 #include <system/window.h>
63 #include <fstream>
64 #include <variant>
65 
66 // Resource directory
67 std::string sResourceDir = "";
68 
69 // video encoder test fixture class
70 class VideoEncHidlTest
71     : public ::testing::TestWithParam<std::tuple<std::string, std::string, std::string>> {
72   public:
getTestCaseInfo() const73     ::std::string getTestCaseInfo() const {
74         return ::std::string() + "Component: " + component_ + " | " + "Role: " + role_ + " | " +
75                "Instance: " + instance_ + " | " + "Res: " + sResourceDir;
76     }
77 
SetUp()78     virtual void SetUp() override {
79         instance_ = std::get<0>(GetParam());
80         component_ = std::get<1>(GetParam());
81         role_ = std::get<2>(GetParam());
82         ASSERT_NE(sResourceDir.empty(), true);
83 
84         disableTest = false;
85         android::hardware::media::omx::V1_0::Status status;
86         omx = IOmx::getService(instance_);
87         ASSERT_NE(omx, nullptr);
88         observer =
89             new CodecObserver([this](Message msg, const BufferInfo* buffer) {
90                 handleMessage(msg, buffer);
91             });
92         ASSERT_NE(observer, nullptr);
93         if (component_.find("OMX.") != 0) disableTest = true;
94         EXPECT_TRUE(omx->allocateNode(component_, observer,
95                                       [&](android::hardware::media::omx::V1_0::Status _s,
96                                           sp<IOmxNode> const& _nl) {
97                                           status = _s;
98                                           this->omxNode = _nl;
99                                       })
100                             .isOk());
101         if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
102             disableTest = true;
103             std::cout << "[   WARN   ] Test Disabled, component not present\n";
104             return;
105         }
106         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
107         ASSERT_NE(omxNode, nullptr);
108         ASSERT_NE(role_.empty(), true) << "Invalid Component Role";
109         struct StringToName {
110             const char* Name;
111             standardComp CompName;
112         };
113         const StringToName kStringToName[] = {
114             {"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4},
115             {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
116         };
117         const size_t kNumStringToName =
118             sizeof(kStringToName) / sizeof(kStringToName[0]);
119         const char* pch;
120         char substring[OMX_MAX_STRINGNAME_SIZE];
121         strcpy(substring, role_.c_str());
122         pch = strchr(substring, '.');
123         ASSERT_NE(pch, nullptr);
124         compName = unknown_comp;
125         for (size_t i = 0; i < kNumStringToName; ++i) {
126             if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
127                 compName = kStringToName[i].CompName;
128                 break;
129             }
130         }
131         if (compName == unknown_comp) disableTest = true;
132         struct CompToCompression {
133             standardComp CompName;
134             OMX_VIDEO_CODINGTYPE eCompressionFormat;
135         };
136         static const CompToCompression kCompToCompression[] = {
137             {h263, OMX_VIDEO_CodingH263},   {avc, OMX_VIDEO_CodingAVC},
138             {mpeg4, OMX_VIDEO_CodingMPEG4}, {hevc, OMX_VIDEO_CodingHEVC},
139             {vp8, OMX_VIDEO_CodingVP8},     {vp9, OMX_VIDEO_CodingVP9},
140         };
141         static const size_t kNumCompToCompression =
142             sizeof(kCompToCompression) / sizeof(kCompToCompression[0]);
143         size_t i;
144         for (i = 0; i < kNumCompToCompression; ++i) {
145             if (kCompToCompression[i].CompName == compName) {
146                 eCompressionFormat = kCompToCompression[i].eCompressionFormat;
147                 break;
148             }
149         }
150         if (i == kNumCompToCompression) disableTest = true;
151         eosFlag = false;
152         prependSPSPPS = false;
153         timestampDevTest = false;
154         producer = nullptr;
155         source = nullptr;
156         isSecure = false;
157         size_t suffixLen = strlen(".secure");
158         if (component_.rfind(".secure") == component_.length() - suffixLen) {
159             isSecure = true;
160         }
161         if (isSecure) disableTest = true;
162         if (disableTest) std::cout << "[   WARN   ] Test Disabled \n";
163     }
164 
TearDown()165     virtual void TearDown() override {
166         if (omxNode != nullptr) {
167             // If you have encountered a fatal failure, it is possible that
168             // freeNode() will not go through. Instead of hanging the app.
169             // let it pass through and report errors
170             if (::testing::Test::HasFatalFailure()) return;
171             EXPECT_TRUE((omxNode->freeNode()).isOk());
172             omxNode = nullptr;
173         }
174     }
175 
176     // callback function to process messages received by onMessages() from IL
177     // client.
handleMessage(Message msg,const BufferInfo * buffer)178     void handleMessage(Message msg, const BufferInfo* buffer) {
179         (void)buffer;
180 
181         if (msg.type == Message::Type::FILL_BUFFER_DONE) {
182             if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) {
183                 eosFlag = true;
184             }
185             if (msg.data.extendedBufferData.rangeLength != 0) {
186                 // Test if current timestamp is among the list of queued
187                 // timestamps
188                 if (timestampDevTest && ((msg.data.extendedBufferData.flags &
189                                           OMX_BUFFERFLAG_CODECCONFIG) == 0)) {
190                     bool tsHit = false;
191                     android::List<uint64_t>::iterator it =
192                         timestampUslist.begin();
193                     while (it != timestampUslist.end()) {
194                         if (*it == msg.data.extendedBufferData.timestampUs) {
195                             timestampUslist.erase(it);
196                             tsHit = true;
197                             break;
198                         }
199                         it++;
200                     }
201                     if (tsHit == false) {
202                         if (timestampUslist.empty() == false) {
203                             EXPECT_EQ(tsHit, true)
204                                 << "TimeStamp not recognized";
205                         } else {
206                             std::cout << "[   INFO   ] Received non-zero "
207                                          "output / TimeStamp not recognized \n";
208                         }
209                     }
210                 }
211 #define WRITE_OUTPUT 0
212 #if WRITE_OUTPUT
213                 static int count = 0;
214                 FILE* ofp = nullptr;
215                 if (count)
216                     ofp = fopen("out.bin", "ab");
217                 else
218                     ofp = fopen("out.bin", "wb");
219                 if (ofp != nullptr) {
220                     fwrite(static_cast<void*>(buffer->mMemory->getPointer()),
221                            sizeof(char),
222                            msg.data.extendedBufferData.rangeLength, ofp);
223                     fclose(ofp);
224                     count++;
225                 }
226 #endif
227             }
228         }
229     }
230 
231     enum standardComp {
232         h263,
233         avc,
234         mpeg4,
235         hevc,
236         vp8,
237         vp9,
238         unknown_comp,
239     };
240 
241     std::string component_;
242     std::string role_;
243     std::string instance_;
244 
245     sp<IOmx> omx;
246     sp<CodecObserver> observer;
247     sp<IOmxNode> omxNode;
248     standardComp compName;
249     OMX_VIDEO_CODINGTYPE eCompressionFormat;
250     bool disableTest;
251     bool eosFlag;
252     bool prependSPSPPS;
253     ::android::List<uint64_t> timestampUslist;
254     bool timestampDevTest;
255     bool isSecure;
256     sp<IGraphicBufferProducer> producer;
257     sp<IGraphicBufferSource> source;
258 
259    protected:
description(const std::string & description)260     static void description(const std::string& description) {
261         RecordProperty("description", description);
262     }
263 };
264 
265 // CodecProducerListener class
266 struct CodecProducerListener : public IProducerListener {
267    public:
CodecProducerListenerCodecProducerListener268     CodecProducerListener(int a, int b)
269         : freeBuffers(a), minUnDequeuedCount(b) {}
onBufferReleasedCodecProducerListener270     virtual ::android::hardware::Return<void> onBufferReleased() override {
271         android::Mutex::Autolock autoLock(bufferLock);
272         freeBuffers += 1;
273         return Void();
274     }
needsReleaseNotifyCodecProducerListener275     virtual ::android::hardware::Return<bool> needsReleaseNotify() override {
276         return true;
277     }
reduceCountCodecProducerListener278     void reduceCount() {
279         android::Mutex::Autolock autoLock(bufferLock);
280         freeBuffers -= 1;
281         EXPECT_GE(freeBuffers, minUnDequeuedCount);
282     }
283 
284     size_t freeBuffers;
285     size_t minUnDequeuedCount;
286     android::Mutex bufferLock;
287 };
288 
289 // Mock IOmxBufferSource class. GraphicBufferSource.cpp in libstagefright/omx/
290 // implements this class. Below class is introduced to test if callback
291 // functions are actually being called or not
292 struct MockBufferSource : public IOmxBufferSource {
293    public:
MockBufferSourceMockBufferSource294     MockBufferSource(sp<IOmxNode> node) {
295         callback = 0;
296         executing = false;
297         omxNode = node;
298     }
299     virtual Return<void> onOmxExecuting();
300     virtual Return<void> onOmxIdle();
301     virtual Return<void> onOmxLoaded();
302     virtual Return<void> onInputBufferAdded(uint32_t buffer);
303     virtual Return<void> onInputBufferEmptied(
304         uint32_t buffer, const ::android::hardware::hidl_handle& fence);
305 
306     int callback;
307     bool executing;
308     sp<IOmxNode> omxNode;
309     android::Vector<BufferInfo> iBuffer, oBuffer;
310 };
311 
onOmxExecuting()312 Return<void> MockBufferSource::onOmxExecuting() {
313     executing = true;
314     callback |= 0x1;
315     size_t index;
316     // Fetch a client owned input buffer and send an EOS
317     if ((index = getEmptyBufferID(&iBuffer)) < iBuffer.size()) {
318         android::hardware::media::omx::V1_0::Status status;
319         CodecBuffer t = iBuffer[index].omxBuffer;
320         t.type = CodecBuffer::Type::ANW_BUFFER;
321         native_handle_t* fenceNh = native_handle_create(0, 0);
322         EXPECT_NE(fenceNh, nullptr);
323         status = omxNode->emptyBuffer(iBuffer[index].id, t, OMX_BUFFERFLAG_EOS,
324                                       0, fenceNh);
325         native_handle_close(fenceNh);
326         native_handle_delete(fenceNh);
327         EXPECT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
328         iBuffer.editItemAt(index).owner = component;
329     }
330     return Void();
331 };
332 
onOmxIdle()333 Return<void> MockBufferSource::onOmxIdle() {
334     callback |= 0x2;
335     executing = false;
336     return Void();
337 };
338 
onOmxLoaded()339 Return<void> MockBufferSource::onOmxLoaded() {
340     callback |= 0x4;
341     return Void();
342 };
343 
onInputBufferAdded(uint32_t buffer)344 Return<void> MockBufferSource::onInputBufferAdded(uint32_t buffer) {
345     (void)buffer;
346     EXPECT_EQ(executing, false);
347     callback |= 0x8;
348     return Void();
349 };
350 
onInputBufferEmptied(uint32_t buffer,const::android::hardware::hidl_handle & fence)351 Return<void> MockBufferSource::onInputBufferEmptied(
352     uint32_t buffer, const ::android::hardware::hidl_handle& fence) {
353     (void)fence;
354     callback |= 0x10;
355     size_t i;
356     for (i = 0; i < iBuffer.size(); i++) {
357         if (iBuffer[i].id == buffer) {
358             iBuffer.editItemAt(i).owner = client;
359             break;
360         }
361     }
362     return Void();
363 };
364 
365 // request VOP refresh
requestIDR(sp<IOmxNode> omxNode,OMX_U32 portIndex)366 void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) {
367     android::hardware::media::omx::V1_0::Status status;
368     OMX_CONFIG_INTRAREFRESHVOPTYPE param;
369     param.IntraRefreshVOP = OMX_TRUE;
370     status = setPortConfig(omxNode, OMX_IndexConfigVideoIntraVOPRefresh,
371                            portIndex, &param);
372     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
373         std::cout << "[   INFO   ] unable to request IDR \n";
374 }
375 
376 // modify bitrate
changeBitrate(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t nBitrate)377 void changeBitrate(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t nBitrate) {
378     android::hardware::media::omx::V1_0::Status status;
379     OMX_VIDEO_CONFIG_BITRATETYPE param;
380     param.nEncodeBitrate = nBitrate;
381     status =
382         setPortConfig(omxNode, OMX_IndexConfigVideoBitrate, portIndex, &param);
383     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
384         std::cout << "[   INFO   ] unable to change Bitrate \n";
385 }
386 
387 // modify framerate
changeFrameRate(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t xFramerate)388 Return<android::hardware::media::omx::V1_0::Status> changeFrameRate(
389     sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t xFramerate) {
390     android::hardware::media::omx::V1_0::Status status;
391     OMX_CONFIG_FRAMERATETYPE param;
392     param.xEncodeFramerate = xFramerate;
393     status = setPortConfig(omxNode, OMX_IndexConfigVideoFramerate, portIndex,
394                            &param);
395     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
396         std::cout << "[   INFO   ] unable to change Framerate \n";
397     return status;
398 }
399 
400 // modify intra refresh interval
changeRefreshPeriod(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t nRefreshPeriod)401 void changeRefreshPeriod(sp<IOmxNode> omxNode, OMX_U32 portIndex,
402                          uint32_t nRefreshPeriod) {
403     android::hardware::media::omx::V1_0::Status status;
404     OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE param;
405     param.nRefreshPeriod = nRefreshPeriod;
406     status = setPortConfig(omxNode,
407                            (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
408                            portIndex, &param);
409     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
410         std::cout << "[   INFO   ] unable to change Refresh Period\n";
411 }
412 
413 // set intra refresh interval
setRefreshPeriod(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t nRefreshPeriod)414 void setRefreshPeriod(sp<IOmxNode> omxNode, OMX_U32 portIndex,
415                       uint32_t nRefreshPeriod) {
416     android::hardware::media::omx::V1_0::Status status;
417     OMX_VIDEO_PARAM_INTRAREFRESHTYPE param;
418     param.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
419     param.nCirMBs = 0;
420     if (nRefreshPeriod == 0)
421         param.nCirMBs = 0;
422     else {
423         OMX_PARAM_PORTDEFINITIONTYPE portDef;
424         status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
425                               &portDef);
426         if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
427             param.nCirMBs =
428                 ((portDef.format.video.nFrameWidth + 15) >>
429                  4 * (portDef.format.video.nFrameHeight + 15) >> 4) /
430                 nRefreshPeriod;
431         }
432     }
433     status = setPortParam(omxNode, OMX_IndexParamVideoIntraRefresh, portIndex,
434                           &param);
435     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
436         std::cout << "[   INFO   ] unable to set Refresh Period \n";
437 }
438 
setLatency(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t latency)439 void setLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t latency) {
440     android::hardware::media::omx::V1_0::Status status;
441     OMX_PARAM_U32TYPE param;
442     param.nU32 = (OMX_U32)latency;
443     status = setPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency,
444                            portIndex, &param);
445     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
446         std::cout << "[   INFO   ] unable to set latency\n";
447 }
448 
getLatency(sp<IOmxNode> omxNode,OMX_U32 portIndex,uint32_t * latency)449 void getLatency(sp<IOmxNode> omxNode, OMX_U32 portIndex, uint32_t* latency) {
450     android::hardware::media::omx::V1_0::Status status;
451     OMX_PARAM_U32TYPE param;
452     status = getPortConfig(omxNode, (OMX_INDEXTYPE)OMX_IndexConfigLatency,
453                            portIndex, &param);
454     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
455         std::cout << "[   INFO   ] unable to get latency\n";
456     else
457         *latency = param.nU32;
458 }
459 
460 // Set Default port param.
setDefaultPortParam(sp<IOmxNode> omxNode,OMX_U32 portIndex,OMX_VIDEO_CODINGTYPE eCompressionFormat,OMX_U32 nFrameWidth,OMX_U32 nFrameHeight,OMX_U32 nBitrate,OMX_U32 xFramerate)461 void setDefaultPortParam(sp<IOmxNode> omxNode, OMX_U32 portIndex,
462                          OMX_VIDEO_CODINGTYPE eCompressionFormat,
463                          OMX_U32 nFrameWidth, OMX_U32 nFrameHeight,
464                          OMX_U32 nBitrate, OMX_U32 xFramerate) {
465     android::hardware::media::omx::V1_0::Status status;
466     OMX_PARAM_PORTDEFINITIONTYPE portDef;
467     status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
468                           &portDef);
469     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
470     portDef.format.video.nFrameWidth = nFrameWidth;
471     portDef.format.video.nFrameHeight = nFrameHeight;
472     portDef.format.video.nBitrate = nBitrate;
473     portDef.format.video.xFramerate = xFramerate;
474     portDef.format.video.bFlagErrorConcealment = OMX_TRUE;
475     portDef.format.video.eCompressionFormat = eCompressionFormat;
476     portDef.format.video.eColorFormat = OMX_COLOR_FormatUnused;
477     status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
478                           &portDef);
479     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
480 
481     std::vector<int32_t> arrProfile;
482     std::vector<int32_t> arrLevel;
483     enumerateProfileAndLevel(omxNode, portIndex, &arrProfile, &arrLevel);
484     if (arrProfile.empty() == true || arrLevel.empty() == true)
485         ASSERT_TRUE(false);
486     int32_t profile = arrProfile[0];
487     int32_t level = arrLevel[0];
488 
489     switch ((int)eCompressionFormat) {
490         case OMX_VIDEO_CodingAVC:
491             setupAVCPort(omxNode, portIndex,
492                          static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile),
493                          static_cast<OMX_VIDEO_AVCLEVELTYPE>(level),
494                          xFramerate);
495             break;
496         case OMX_VIDEO_CodingHEVC:
497             setupHEVCPort(omxNode, portIndex,
498                           static_cast<OMX_VIDEO_HEVCPROFILETYPE>(profile),
499                           static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level));
500             break;
501         case OMX_VIDEO_CodingH263:
502             setupH263Port(omxNode, portIndex,
503                           static_cast<OMX_VIDEO_H263PROFILETYPE>(profile),
504                           static_cast<OMX_VIDEO_H263LEVELTYPE>(level),
505                           xFramerate);
506             break;
507         case OMX_VIDEO_CodingMPEG4:
508             setupMPEG4Port(omxNode, portIndex,
509                            static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profile),
510                            static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(level),
511                            xFramerate);
512             break;
513         case OMX_VIDEO_CodingVP8:
514             setupVPXPort(omxNode, portIndex, xFramerate);
515             setupVP8Port(omxNode, portIndex,
516                          static_cast<OMX_VIDEO_VP8PROFILETYPE>(profile),
517                          static_cast<OMX_VIDEO_VP8LEVELTYPE>(level));
518             break;
519         case OMX_VIDEO_CodingVP9:
520             setupVPXPort(omxNode, portIndex, xFramerate);
521             setupVP9Port(omxNode, portIndex,
522                          static_cast<OMX_VIDEO_VP9PROFILETYPE>(profile),
523                          static_cast<OMX_VIDEO_VP9LEVELTYPE>(level));
524             break;
525         default:
526             break;
527     }
528 }
529 
530 // LookUpTable of clips and metadata for component testing
GetURLForComponent(char * URL)531 void GetURLForComponent(char* URL) {
532     strcat(URL, "bbb_352x288_420p_30fps_32frames.yuv");
533 }
534 
535 // blocking call to ensures application to Wait till all the inputs are consumed
waitOnInputConsumption(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,bool inputDataIsMeta=false,sp<CodecProducerListener> listener=nullptr)536 void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
537                             android::Vector<BufferInfo>* iBuffer,
538                             android::Vector<BufferInfo>* oBuffer,
539                             bool inputDataIsMeta = false,
540                             sp<CodecProducerListener> listener = nullptr) {
541     android::hardware::media::omx::V1_0::Status status;
542     Message msg;
543     int timeOut = TIMEOUT_COUNTER_Q;
544 
545     while (timeOut--) {
546         size_t i = 0;
547         status =
548             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
549         ASSERT_EQ(status,
550                   android::hardware::media::omx::V1_0::Status::TIMED_OUT);
551         // status == TIMED_OUT, it could be due to process time being large
552         // than DEFAULT_TIMEOUT or component needs output buffers to start
553         // processing.
554         if (inputDataIsMeta) {
555             if (listener->freeBuffers == iBuffer->size()) break;
556         } else {
557             for (; i < iBuffer->size(); i++) {
558                 if ((*iBuffer)[i].owner != client) break;
559             }
560             if (i == iBuffer->size()) break;
561         }
562 
563         // Dispatch an output buffer assuming outQueue.empty() is true
564         size_t index;
565         if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
566             ASSERT_NO_FATAL_FAILURE(
567                 dispatchOutputBuffer(omxNode, oBuffer, index));
568             timeOut = TIMEOUT_COUNTER_Q;
569         }
570     }
571 }
572 
colorFormatConversion(BufferInfo * buffer,buffer_handle_t buff,PixelFormat format,std::ifstream & eleStream)573 int colorFormatConversion(BufferInfo* buffer, buffer_handle_t buff, PixelFormat format,
574                           std::ifstream& eleStream) {
575     android::GraphicBufferMapper& gbmapper = android::GraphicBufferMapper::get();
576 
577     android::Rect rect(0, 0, buffer->omxBuffer.attr.anwBuffer.width,
578                        buffer->omxBuffer.attr.anwBuffer.height);
579     android_ycbcr ycbcrLayout;
580     android::status_t error = android::NO_ERROR;
581 
582     if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
583         format == PixelFormat::YCBCR_420_888) {
584         error = gbmapper.lockYCbCr(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect,
585                                    &ycbcrLayout);
586         EXPECT_EQ(error, android::NO_ERROR);
587         if (error != android::NO_ERROR) return 1;
588 
589         int size = ((rect.getWidth() * rect.getHeight() * 3) >> 1);
590         char* img = new char[size];
591         if (img == nullptr) return 1;
592         eleStream.read(img, size);
593         if (eleStream.gcount() != size) {
594             delete[] img;
595             return 1;
596         }
597 
598         char* imgTmp = img;
599         char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
600         for (size_t y = rect.getHeight(); y > 0; --y) {
601             memcpy(ipBuffer, imgTmp, rect.getWidth());
602             ipBuffer += ycbcrLayout.ystride;
603             imgTmp += rect.getWidth();
604         }
605 
606         if (format == PixelFormat::YV12)
607             EXPECT_EQ(ycbcrLayout.chroma_step, 1U);
608         else if (format == PixelFormat::YCRCB_420_SP)
609             EXPECT_EQ(ycbcrLayout.chroma_step, 2U);
610 
611         ipBuffer = static_cast<char*>(ycbcrLayout.cb);
612         for (size_t y = rect.getHeight() >> 1; y > 0; --y) {
613             for (int32_t x = 0; x < (rect.getWidth() >> 1); ++x) {
614                 ipBuffer[ycbcrLayout.chroma_step * x] = *imgTmp++;
615             }
616             ipBuffer += ycbcrLayout.cstride;
617         }
618         ipBuffer = static_cast<char*>(ycbcrLayout.cr);
619         for (size_t y = rect.getHeight() >> 1; y > 0; --y) {
620             for (int32_t x = 0; x < (rect.getWidth() >> 1); ++x) {
621                 ipBuffer[ycbcrLayout.chroma_step * x] = *imgTmp++;
622             }
623             ipBuffer += ycbcrLayout.cstride;
624         }
625 
626         delete[] img;
627 
628         error = gbmapper.unlock(buff);
629         EXPECT_EQ(error, android::NO_ERROR);
630         if (error != android::NO_ERROR) return 1;
631     } else {
632         void* data;
633         int32_t outBytesPerPixel;
634         int32_t outBytesPerStride;
635         error = gbmapper.lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, &data,
636                               &outBytesPerPixel, &outBytesPerStride);
637         EXPECT_EQ(error, android::NO_ERROR);
638         if (error != android::NO_ERROR) return 1;
639 
640         if (format == PixelFormat::BGRA_8888) {
641             char* ipBuffer = static_cast<char*>(data);
642             for (size_t y = rect.getHeight(); y > 0; --y) {
643                 eleStream.read(ipBuffer, rect.getWidth() * 4);
644                 if (eleStream.gcount() != rect.getWidth() * 4) return 1;
645                 ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
646             }
647         } else {
648             EXPECT_TRUE(false) << "un expected pixel format";
649             return 1;
650         }
651 
652         error = gbmapper.unlock(buff);
653         EXPECT_EQ(error, android::NO_ERROR);
654         if (error != android::NO_ERROR) return 1;
655     }
656 
657     return 0;
658 }
659 
fillGraphicBuffer(BufferInfo * buffer,PixelFormat format,std::ifstream & eleStream)660 int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format,
661                       std::ifstream& eleStream) {
662     android::GraphicBufferMapper& gbmapper = android::GraphicBufferMapper::get();
663     buffer_handle_t buff;
664     android::status_t error = android::NO_ERROR;
665     gbmapper.importBuffer(
666             buffer->omxBuffer.nativeHandle, buffer->omxBuffer.attr.anwBuffer.width,
667             buffer->omxBuffer.attr.anwBuffer.height, buffer->omxBuffer.attr.anwBuffer.layerCount,
668             static_cast<android::PixelFormat>(format), buffer->omxBuffer.attr.anwBuffer.usage,
669             buffer->omxBuffer.attr.anwBuffer.stride, &buff);
670     EXPECT_EQ(error, android::NO_ERROR);
671     if (error != android::NO_ERROR) return 1;
672 
673     if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
674 
675     error = gbmapper.freeBuffer(buff);
676     EXPECT_EQ(error, android::NO_ERROR);
677     if (error != android::NO_ERROR) return 1;
678 
679     return 0;
680 }
681 
dispatchGraphicBuffer(sp<IOmxNode> omxNode,sp<IGraphicBufferProducer> producer,sp<CodecProducerListener> listener,android::Vector<BufferInfo> * buffArray,OMX_U32 portIndex,std::ifstream & eleStream,uint64_t timestamp)682 int dispatchGraphicBuffer(sp<IOmxNode> omxNode,
683                           sp<IGraphicBufferProducer> producer,
684                           sp<CodecProducerListener> listener,
685                           android::Vector<BufferInfo>* buffArray,
686                           OMX_U32 portIndex, std::ifstream& eleStream,
687                           uint64_t timestamp) {
688     android::hardware::media::omx::V1_0::Status status;
689     OMX_PARAM_PORTDEFINITIONTYPE portDef;
690 
691     status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
692                           &portDef);
693     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
694     if (status != ::android::hardware::media::omx::V1_0::Status::OK) return 1;
695 
696     enum {
697         // A flag returned by dequeueBuffer when the client needs to call
698         // requestBuffer immediately thereafter.
699         BUFFER_NEEDS_REALLOCATION = 0x1,
700         // A flag returned by dequeueBuffer when all mirrored slots should be
701         // released by the client. This flag should always be processed first.
702         RELEASE_ALL_BUFFERS = 0x2,
703     };
704 
705     int32_t slot;
706     int32_t result;
707     ::android::hardware::hidl_handle fence;
708     IGraphicBufferProducer::FrameEventHistoryDelta outTimestamps;
709     ::android::hardware::media::V1_0::AnwBuffer AnwBuffer;
710     PixelFormat format = PixelFormat::YCBCR_420_888;
711     producer->dequeueBuffer(
712         portDef.format.video.nFrameWidth, portDef.format.video.nFrameHeight,
713         format, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
714         true, [&](int32_t _s, int32_t const& _n1,
715                   ::android::hardware::hidl_handle const& _n2,
716                   IGraphicBufferProducer::FrameEventHistoryDelta const& _n3) {
717             result = _s;
718             slot = _n1;
719             fence = _n2;
720             outTimestamps = _n3;
721         });
722     if (result & BUFFER_NEEDS_REALLOCATION) {
723         producer->requestBuffer(
724             slot, [&](int32_t _s,
725                       ::android::hardware::media::V1_0::AnwBuffer const& _n1) {
726                 result = _s;
727                 AnwBuffer = _n1;
728             });
729         EXPECT_EQ(result, 0);
730         if (result != 0) return 1;
731         size_t i;
732         for (i = 0; i < buffArray->size(); i++) {
733             if ((*buffArray)[i].slot == -1) {
734                 buffArray->editItemAt(i).slot = slot;
735                 buffArray->editItemAt(i).omxBuffer.nativeHandle =
736                     AnwBuffer.nativeHandle;
737                 buffArray->editItemAt(i).omxBuffer.attr.anwBuffer =
738                     AnwBuffer.attr;
739                 break;
740             }
741         }
742         EXPECT_NE(i, buffArray->size());
743         if (i == buffArray->size()) return 1;
744     }
745     EXPECT_EQ(result, 0);
746     if (result != 0) return 1;
747 
748     // fill Buffer
749     BufferInfo buffer;
750     size_t i;
751     for (i = 0; i < buffArray->size(); i++) {
752         if ((*buffArray)[i].slot == slot) {
753             buffer = (*buffArray)[i];
754             break;
755         }
756     }
757     EXPECT_NE(i, buffArray->size());
758     if (i == buffArray->size()) return 1;
759     if (fillGraphicBuffer(&buffer, format, eleStream)) return 1;
760 
761     // queue Buffer
762     IGraphicBufferProducer::QueueBufferOutput output;
763     IGraphicBufferProducer::QueueBufferInput input;
764     android::hardware::media::V1_0::Rect rect;
765     rect.left = 0;
766     rect.top = 0;
767     rect.right = buffer.omxBuffer.attr.anwBuffer.width;
768     rect.bottom = buffer.omxBuffer.attr.anwBuffer.height;
769     input.timestamp = timestamp;
770     input.isAutoTimestamp = false;
771     input.dataSpace =
772         android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN;
773     input.crop = rect;
774     input.scalingMode = 0;
775     input.transform = 0;
776     input.stickyTransform = 0;
777     input.fence = android::hardware::hidl_handle();
778     input.surfaceDamage =
779         android::hardware::hidl_vec<android::hardware::media::V1_0::Rect>{rect};
780     input.getFrameTimestamps = false;
781     producer->queueBuffer(
782         buffer.slot, input,
783         [&](int32_t _s, const IGraphicBufferProducer::QueueBufferOutput& _n1) {
784             result = _s;
785             output = _n1;
786         });
787     EXPECT_EQ(result, 0);
788     if (result != 0) return 1;
789 
790     listener->reduceCount();
791 
792     return 0;
793 }
794 
fillByteBuffer(sp<IOmxNode> omxNode,char * ipBuffer,OMX_U32 portIndexInput,std::ifstream & eleStream)795 int fillByteBuffer(sp<IOmxNode> omxNode, char* ipBuffer, OMX_U32 portIndexInput,
796                    std::ifstream& eleStream) {
797     android::hardware::media::omx::V1_0::Status status;
798     OMX_PARAM_PORTDEFINITIONTYPE portDef;
799     uint32_t i, j;
800 
801     status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndexInput,
802                           &portDef);
803     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
804 
805     int size = ((portDef.format.video.nFrameWidth *
806                  portDef.format.video.nFrameHeight * 3) >>
807                 1);
808     char* img = new char[size];
809     if (img == nullptr) return 1;
810     eleStream.read(img, size);
811     if (eleStream.gcount() != size) {
812         delete[] img;
813         return 1;
814     }
815 
816     char* Y = ipBuffer;
817     char* imgTmp = img;
818     for (j = 0; j < portDef.format.video.nFrameHeight; ++j) {
819         memcpy(Y, imgTmp, portDef.format.video.nFrameWidth);
820         Y += portDef.format.video.nStride;
821         imgTmp += portDef.format.video.nFrameWidth;
822     }
823 
824     if (portDef.format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
825         char* Cb = ipBuffer + (portDef.format.video.nFrameHeight *
826                                portDef.format.video.nStride);
827         char* Cr = Cb + 1;
828         for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
829             for (i = 0; i < (portDef.format.video.nFrameWidth >> 1); ++i) {
830                 Cb[2 * i] = *imgTmp++;
831             }
832             Cb += portDef.format.video.nStride;
833         }
834         for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
835             for (i = 0; i < (portDef.format.video.nFrameWidth >> 1); ++i) {
836                 Cr[2 * i] = *imgTmp++;
837             }
838             Cr += portDef.format.video.nStride;
839         }
840     } else if (portDef.format.video.eColorFormat ==
841                OMX_COLOR_FormatYUV420Planar) {
842         char* Cb = ipBuffer + (portDef.format.video.nFrameHeight *
843                                portDef.format.video.nStride);
844         char* Cr = Cb + ((portDef.format.video.nFrameHeight *
845                           portDef.format.video.nStride) >>
846                          2);
847         for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
848             memcpy(Cb, imgTmp, (portDef.format.video.nFrameWidth >> 1));
849             Cb += (portDef.format.video.nStride >> 1);
850             imgTmp += (portDef.format.video.nFrameWidth >> 1);
851         }
852         for (j = 0; j<portDef.format.video.nFrameHeight>> 1; ++j) {
853             memcpy(Cr, imgTmp, (portDef.format.video.nFrameWidth >> 1));
854             Cr += (portDef.format.video.nStride >> 1);
855             imgTmp += (portDef.format.video.nFrameWidth >> 1);
856         }
857     }
858 
859     delete[] img;
860     return 0;
861 }
862 
863 // Encode N Frames
encodeNFrames(sp<IOmxNode> omxNode,sp<CodecObserver> observer,OMX_U32 portIndexInput,OMX_U32 portIndexOutput,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,uint32_t nFrames,uint32_t xFramerate,int bytesCount,std::ifstream & eleStream,::android::List<uint64_t> * timestampUslist=nullptr,bool signalEOS=true,bool inputDataIsMeta=false,sp<IGraphicBufferProducer> producer=nullptr,sp<CodecProducerListener> listener=nullptr)864 void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
865                    OMX_U32 portIndexInput, OMX_U32 portIndexOutput,
866                    android::Vector<BufferInfo>* iBuffer,
867                    android::Vector<BufferInfo>* oBuffer, uint32_t nFrames,
868                    uint32_t xFramerate, int bytesCount,
869                    std::ifstream& eleStream,
870                    ::android::List<uint64_t>* timestampUslist = nullptr,
871                    bool signalEOS = true, bool inputDataIsMeta = false,
872                    sp<IGraphicBufferProducer> producer = nullptr,
873                    sp<CodecProducerListener> listener = nullptr) {
874     android::hardware::media::omx::V1_0::Status status;
875     Message msg;
876     uint64_t timestamp = 0;
877     uint32_t flags = 0;
878     int timeOut = TIMEOUT_COUNTER_Q;
879     bool iQueued, oQueued;
880 
881     uint32_t ipCount = 0;
882     if (ipCount == 0) {
883         status = changeFrameRate(omxNode, portIndexOutput, (24U << 16));
884         if (status == ::android::hardware::media::omx::V1_0::Status::OK)
885             xFramerate = (24U << 16);
886     }
887     int32_t timestampIncr = (int)((float)1000000 / (xFramerate >> 16));
888     if (inputDataIsMeta) timestampIncr *= 1000;  // timestamp scale: Nano sec
889 
890     while (1) {
891         iQueued = oQueued = false;
892         status =
893             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
894         // Port Reconfiguration
895         if (status == android::hardware::media::omx::V1_0::Status::OK) {
896             ASSERT_EQ(msg.type, Message::Type::EVENT);
897             if (msg.data.eventData.event == OMX_EventPortSettingsChanged) {
898                 ASSERT_EQ(msg.data.eventData.data1, portIndexOutput);
899                 ASSERT_EQ(msg.data.eventData.data2,
900                           OMX_IndexConfigAndroidIntraRefresh);
901             } else if (msg.data.eventData.event == OMX_EventError) {
902                 ASSERT_TRUE(false) << "Received OMX_EventError, not sure why";
903             } else if (msg.data.eventData.event == OMX_EventDataSpaceChanged) {
904                 // TODO: how am i supposed to respond now?
905                 std::cout << "[   INFO   ] OMX_EventDataSpaceChanged \n";
906             } else {
907                 ASSERT_TRUE(false);
908             }
909         }
910 
911         if (nFrames == 0) break;
912 
913         // Dispatch input buffer
914         size_t index = 0;
915         if (inputDataIsMeta) {
916             if (listener->freeBuffers > listener->minUnDequeuedCount) {
917                 if (dispatchGraphicBuffer(omxNode, producer, listener, iBuffer,
918                                           portIndexInput, eleStream,
919                                           timestamp)) {
920                     if (::testing::Test::HasFailure())
921                         ASSERT_TRUE(false);
922                     else
923                         break;
924                 }
925                 timestamp += timestampIncr;
926                 nFrames--;
927                 ipCount++;
928                 iQueued = true;
929             }
930         } else {
931             if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
932                 char* ipBuffer = static_cast<char*>(static_cast<void*>(
933                     (*iBuffer)[index].mMemory->getPointer()));
934                 ASSERT_LE(
935                     bytesCount,
936                     static_cast<int>((*iBuffer)[index].mMemory->getSize()));
937                 if (fillByteBuffer(omxNode, ipBuffer, portIndexInput,
938                                    eleStream))
939                     break;
940                 flags = OMX_BUFFERFLAG_ENDOFFRAME;
941                 if (signalEOS && (nFrames == 1)) flags |= OMX_BUFFERFLAG_EOS;
942                 ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(
943                     omxNode, iBuffer, index, bytesCount, flags, timestamp));
944                 if (timestampUslist) timestampUslist->push_back(timestamp);
945                 timestamp += timestampIncr;
946                 nFrames--;
947                 ipCount++;
948                 iQueued = true;
949             }
950         }
951         // Dispatch output buffer
952         if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
953             ASSERT_NO_FATAL_FAILURE(
954                 dispatchOutputBuffer(omxNode, oBuffer, index));
955             oQueued = true;
956         }
957         // Reset Counters when either input or output buffer is dispatched
958         if (iQueued || oQueued)
959             timeOut = TIMEOUT_COUNTER_Q;
960         else
961             timeOut--;
962         if (timeOut == 0) {
963             ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite";
964         }
965         // Runtime Param Configuration
966         if (ipCount == 15) {
967             changeBitrate(omxNode, portIndexOutput, 768000);
968             requestIDR(omxNode, portIndexOutput);
969             changeRefreshPeriod(omxNode, portIndexOutput, 15);
970         }
971     }
972 }
973 
974 // set component role
TEST_P(VideoEncHidlTest,SetRole)975 TEST_P(VideoEncHidlTest, SetRole) {
976     description("Test Set Component Role");
977     if (disableTest) return;
978     android::hardware::media::omx::V1_0::Status status;
979     status = setRole(omxNode, role_);
980     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
981 }
982 
983 // port format enumeration
TEST_P(VideoEncHidlTest,EnumeratePortFormat)984 TEST_P(VideoEncHidlTest, EnumeratePortFormat) {
985     description("Test Component on Mandatory Port Parameters (Port Format)");
986     if (disableTest) return;
987     android::hardware::media::omx::V1_0::Status status;
988     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
989     OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar;
990     OMX_U32 xFramerate = (30U << 16);
991     status = setRole(omxNode, role_);
992     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
993     OMX_PORT_PARAM_TYPE params;
994     status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
995     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
996         ASSERT_EQ(params.nPorts, 2U);
997         kPortIndexInput = params.nStartPortNumber;
998         kPortIndexOutput = kPortIndexInput + 1;
999     }
1000     status =
1001         setVideoPortFormat(omxNode, kPortIndexInput, OMX_VIDEO_CodingUnused,
1002                            eColorFormat, xFramerate);
1003     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1004 
1005     status = setVideoPortFormat(omxNode, kPortIndexOutput, eCompressionFormat,
1006                                 OMX_COLOR_FormatUnused, 0U);
1007     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1008 }
1009 
1010 // Test IOmxBufferSource CallBacks
TEST_P(VideoEncHidlTest,BufferSourceCallBacks)1011 TEST_P(VideoEncHidlTest, BufferSourceCallBacks) {
1012     description("Test IOmxBufferSource CallBacks");
1013     if (disableTest) return;
1014     android::hardware::media::omx::V1_0::Status status;
1015     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1016     status = setRole(omxNode, role_);
1017     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1018     OMX_PORT_PARAM_TYPE params;
1019     status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1020     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1021         ASSERT_EQ(params.nPorts, 2U);
1022         kPortIndexInput = params.nStartPortNumber;
1023         kPortIndexOutput = kPortIndexInput + 1;
1024     }
1025 
1026     // Configure input port
1027     uint32_t nFrameWidth = 352;
1028     uint32_t nFrameHeight = 288;
1029     uint32_t xFramerate = (30U << 16);
1030     OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque;
1031     setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1032                  xFramerate, eColorFormat);
1033 
1034     sp<MockBufferSource> buffersource = new MockBufferSource(omxNode);
1035     ASSERT_NE(buffersource, nullptr);
1036     status = omxNode->setInputSurface(buffersource);
1037     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1038 
1039     // set port mode
1040     PortMode portMode[2];
1041     portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;
1042     portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1043     status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1044     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1045     status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1046     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1047 
1048     // set state to idle
1049     ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1050         omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer,
1051         kPortIndexInput, kPortIndexOutput, portMode));
1052     // set state to executing
1053     ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1054     ASSERT_NO_FATAL_FAILURE(testEOS(omxNode, observer, &buffersource->iBuffer,
1055                                     &buffersource->oBuffer, false, eosFlag));
1056     // set state to idle
1057     ASSERT_NO_FATAL_FAILURE(changeStateExecutetoIdle(
1058         omxNode, observer, &buffersource->iBuffer, &buffersource->oBuffer));
1059     // set state to executing
1060     ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &buffersource->iBuffer,
1061                                                     &buffersource->oBuffer, kPortIndexInput,
1062                                                     kPortIndexOutput, portMode));
1063     // test for callbacks
1064     EXPECT_EQ(buffersource->callback, 31);
1065 }
1066 
1067 // test raw stream encode (input is byte buffers)
TEST_P(VideoEncHidlTest,EncodeTest)1068 TEST_P(VideoEncHidlTest, EncodeTest) {
1069     description("Test Encode");
1070     if (disableTest) return;
1071     android::hardware::media::omx::V1_0::Status status;
1072     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1073     status = setRole(omxNode, role_);
1074     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1075     OMX_PORT_PARAM_TYPE params;
1076     status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1077     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1078         ASSERT_EQ(params.nPorts, 2U);
1079         kPortIndexInput = params.nStartPortNumber;
1080         kPortIndexOutput = kPortIndexInput + 1;
1081     }
1082     char mURL[512];
1083     strcpy(mURL, sResourceDir.c_str());
1084     GetURLForComponent(mURL);
1085 
1086     std::ifstream eleStream;
1087 
1088     timestampDevTest = true;
1089 
1090     // Configure input port
1091     uint32_t nFrameWidth = 352;
1092     uint32_t nFrameHeight = 288;
1093     uint32_t xFramerate = (30U << 16);
1094     OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
1095     OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
1096     portFormat.nIndex = 0;
1097     while (1) {
1098         status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat,
1099                               kPortIndexInput, &portFormat);
1100         if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
1101         EXPECT_EQ(portFormat.eCompressionFormat, OMX_VIDEO_CodingUnused);
1102         if (OMX_COLOR_FormatYUV420SemiPlanar == portFormat.eColorFormat ||
1103             OMX_COLOR_FormatYUV420Planar == portFormat.eColorFormat) {
1104             eColorFormat = portFormat.eColorFormat;
1105             break;
1106         }
1107         portFormat.nIndex++;
1108         if (portFormat.nIndex == 512) break;
1109     }
1110     ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
1111     setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1112                  xFramerate, eColorFormat);
1113 
1114     // Configure output port
1115     uint32_t nBitRate = 512000;
1116     ASSERT_NO_FATAL_FAILURE(
1117         setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat,
1118                             nFrameWidth, nFrameHeight, nBitRate, xFramerate));
1119     setRefreshPeriod(omxNode, kPortIndexOutput, 0);
1120 
1121     unsigned int index;
1122     omxNode->getExtensionIndex(
1123         "OMX.google.android.index.prependSPSPPSToIDRFrames",
1124         [&status, &index](android::hardware::media::omx::V1_0::Status _s,
1125                           unsigned int _nl) {
1126             status = _s;
1127             index = _nl;
1128         });
1129     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1130         android::PrependSPSPPSToIDRFramesParams param;
1131         param.bEnable = OMX_TRUE;
1132         status = setParam(omxNode, static_cast<OMX_INDEXTYPE>(index), &param);
1133     }
1134     if (status != ::android::hardware::media::omx::V1_0::Status::OK)
1135         std::cout << "[   INFO   ] unable to prependSPSPPSToIDRFrames\n";
1136     else
1137         prependSPSPPS = true;
1138 
1139     // set port mode
1140     PortMode portMode[2];
1141     portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1142     status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1143     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1144     status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1145     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1146 
1147     uint32_t latency = 0;
1148     setLatency(omxNode, kPortIndexInput, latency);
1149     getLatency(omxNode, kPortIndexInput, &latency);
1150 
1151     android::Vector<BufferInfo> iBuffer, oBuffer;
1152 
1153     // set state to idle
1154     ASSERT_NO_FATAL_FAILURE(
1155         changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer,
1156                                 kPortIndexInput, kPortIndexOutput, portMode));
1157     // set state to executing
1158     ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1159 
1160     eleStream.open(mURL, std::ifstream::binary);
1161     ASSERT_EQ(eleStream.is_open(), true);
1162     ASSERT_NO_FATAL_FAILURE(encodeNFrames(
1163         omxNode, observer, kPortIndexInput, kPortIndexOutput, &iBuffer,
1164         &oBuffer, 32, xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1,
1165         eleStream, &timestampUslist));
1166     eleStream.close();
1167     ASSERT_NO_FATAL_FAILURE(
1168         waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer));
1169     ASSERT_NO_FATAL_FAILURE(
1170         testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
1171     if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true);
1172 
1173     // set state to idle
1174     ASSERT_NO_FATAL_FAILURE(
1175         changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1176     // set state to executing
1177     ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer,
1178                                                     kPortIndexInput, kPortIndexOutput, portMode));
1179 }
1180 
1181 // test raw stream encode (input is ANW buffers)
TEST_P(VideoEncHidlTest,EncodeTestBufferMetaModes)1182 TEST_P(VideoEncHidlTest, EncodeTestBufferMetaModes) {
1183     description("Test Encode Input buffer metamodes");
1184     if (disableTest) return;
1185     android::hardware::media::omx::V1_0::Status status;
1186     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1187     status = setRole(omxNode, role_);
1188     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1189     OMX_PORT_PARAM_TYPE params;
1190     status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1191     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1192         ASSERT_EQ(params.nPorts, 2U);
1193         kPortIndexInput = params.nStartPortNumber;
1194         kPortIndexOutput = kPortIndexInput + 1;
1195     }
1196 
1197     // Configure input port
1198     uint32_t nFrameWidth = 352;
1199     uint32_t nFrameHeight = 288;
1200     uint32_t xFramerate = (30U << 16);
1201     OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque;
1202     setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1203                  xFramerate, eColorFormat);
1204 
1205     // Configure output port
1206     uint32_t nBitRate = 512000;
1207     ASSERT_NO_FATAL_FAILURE(
1208         setDefaultPortParam(omxNode, kPortIndexOutput, eCompressionFormat,
1209                             nFrameWidth, nFrameHeight, nBitRate, xFramerate));
1210     // CreateInputSurface
1211     EXPECT_TRUE(omx->createInputSurface(
1212                        [&](android::hardware::media::omx::V1_0::Status _s,
1213                            sp<IGraphicBufferProducer> const& _nl,
1214                            sp<IGraphicBufferSource> const& _n2) {
1215                            status = _s;
1216                            producer = _nl;
1217                            source = _n2;
1218                        })
1219                     .isOk());
1220     ASSERT_NE(producer, nullptr);
1221     ASSERT_NE(source, nullptr);
1222 
1223     // setMaxDequeuedBufferCount
1224     int32_t returnval;
1225     int32_t value;
1226     producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
1227                     [&returnval, &value](int32_t _s, int32_t _n1) {
1228                         returnval = _s;
1229                         value = _n1;
1230                     });
1231     ASSERT_EQ(returnval, 0);
1232     OMX_PARAM_PORTDEFINITIONTYPE portDef;
1233     status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
1234                           kPortIndexInput, &portDef);
1235     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1236     ASSERT_EQ(::android::OK,
1237               producer->setMaxDequeuedBufferCount(portDef.nBufferCountActual));
1238 
1239     // Connect :: Mock Producer Listener
1240     IGraphicBufferProducer::QueueBufferOutput qbo;
1241     sp<CodecProducerListener> listener =
1242         new CodecProducerListener(portDef.nBufferCountActual + value, value);
1243     producer->connect(
1244         listener, NATIVE_WINDOW_API_CPU, false,
1245         [&](int32_t _s, IGraphicBufferProducer::QueueBufferOutput const& _n1) {
1246             returnval = _s;
1247             qbo = _n1;
1248         });
1249     ASSERT_EQ(returnval, 0);
1250 
1251     portDef.nBufferCountActual = portDef.nBufferCountActual + value;
1252     status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
1253                           kPortIndexInput, &portDef);
1254     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1255 
1256     // Do setInputSurface()
1257     // enable MetaMode on input port
1258     status = source->configure(
1259         omxNode, android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN);
1260     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1261 
1262     // set port mode
1263     PortMode portMode[2];
1264     portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;
1265     portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1266     status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1267     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1268     status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1269     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1270 
1271     char mURL[512];
1272     strcpy(mURL, sResourceDir.c_str());
1273     GetURLForComponent(mURL);
1274 
1275     uint32_t latency = 0;
1276     setLatency(omxNode, kPortIndexInput, latency);
1277     getLatency(omxNode, kPortIndexInput, &latency);
1278 
1279     std::ifstream eleStream;
1280 
1281     status = source->setSuspend(false, 0);
1282     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1283     status = source->setRepeatPreviousFrameDelayUs(100000);
1284     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1285     status = source->setMaxFps(24.0f);
1286     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1287     status = source->setTimeLapseConfig(24.0, 24.0);
1288     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1289     status = source->setTimeOffsetUs(-100);
1290     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1291     status = source->setStartTimeUs(10);
1292     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1293     status = source->setStopTimeUs(1000000);
1294     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1295     ::android::hardware::media::omx::V1_0::ColorAspects aspects;
1296     aspects.range =
1297         ::android::hardware::media::omx::V1_0::ColorAspects::Range::UNSPECIFIED;
1298     aspects.primaries = ::android::hardware::media::omx::V1_0::ColorAspects::
1299         Primaries::UNSPECIFIED;
1300     aspects.transfer = ::android::hardware::media::omx::V1_0::ColorAspects::
1301         Transfer::UNSPECIFIED;
1302     aspects.matrixCoeffs = ::android::hardware::media::omx::V1_0::ColorAspects::
1303         MatrixCoeffs::UNSPECIFIED;
1304     status = source->setColorAspects(aspects);
1305     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1306     int64_t stopTimeOffsetUs;
1307     source->getStopTimeOffsetUs(
1308         [&](android::hardware::media::omx::V1_0::Status _s, int64_t _n1) {
1309             status = _s;
1310             stopTimeOffsetUs = _n1;
1311         });
1312     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1313 
1314     android::Vector<BufferInfo> iBuffer, oBuffer;
1315     // set state to idle
1316     ASSERT_NO_FATAL_FAILURE(
1317         changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer,
1318                                 kPortIndexInput, kPortIndexOutput, portMode));
1319     // set state to executing
1320     ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1321 
1322     eleStream.open(mURL, std::ifstream::binary);
1323     ASSERT_EQ(eleStream.is_open(), true);
1324     ASSERT_NO_FATAL_FAILURE(encodeNFrames(
1325         omxNode, observer, kPortIndexInput, kPortIndexOutput, &iBuffer,
1326         &oBuffer, 1024, xFramerate, (nFrameWidth * nFrameHeight * 3) >> 1,
1327         eleStream, nullptr, false, true, producer, listener));
1328     eleStream.close();
1329     ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(omxNode, observer, &iBuffer,
1330                                                    &oBuffer, true, listener));
1331     ASSERT_NO_FATAL_FAILURE(
1332         testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
1333 
1334     // set state to idle
1335     ASSERT_NO_FATAL_FAILURE(
1336         changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1337     EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers);
1338     // set state to executing
1339     ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer,
1340                                                     kPortIndexInput, kPortIndexOutput, portMode));
1341 
1342     returnval = producer->disconnect(
1343         NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API);
1344     ASSERT_EQ(returnval, 0);
1345 }
1346 
1347 // Test end of stream
TEST_P(VideoEncHidlTest,EncodeTestEOS)1348 TEST_P(VideoEncHidlTest, EncodeTestEOS) {
1349     description("Test EOS");
1350     if (disableTest) return;
1351     android::hardware::media::omx::V1_0::Status status;
1352     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1353     status = setRole(omxNode, role_);
1354     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1355     OMX_PORT_PARAM_TYPE params;
1356     status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1357     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1358         ASSERT_EQ(params.nPorts, 2U);
1359         kPortIndexInput = params.nStartPortNumber;
1360         kPortIndexOutput = kPortIndexInput + 1;
1361     }
1362 
1363     // Configure input port
1364     uint32_t nFrameWidth = 352;
1365     uint32_t nFrameHeight = 288;
1366     uint32_t xFramerate = (30U << 16);
1367     OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatAndroidOpaque;
1368     setupRAWPort(omxNode, kPortIndexInput, nFrameWidth, nFrameHeight, 0,
1369                  xFramerate, eColorFormat);
1370 
1371     // CreateInputSurface
1372     EXPECT_TRUE(omx->createInputSurface(
1373                        [&](android::hardware::media::omx::V1_0::Status _s,
1374                            sp<IGraphicBufferProducer> const& _nl,
1375                            sp<IGraphicBufferSource> const& _n2) {
1376                            status = _s;
1377                            producer = _nl;
1378                            source = _n2;
1379                        })
1380                     .isOk());
1381     ASSERT_NE(producer, nullptr);
1382     ASSERT_NE(source, nullptr);
1383 
1384     // setMaxDequeuedBufferCount
1385     int32_t returnval;
1386     int32_t value;
1387     producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
1388                     [&returnval, &value](int32_t _s, int32_t _n1) {
1389                         returnval = _s;
1390                         value = _n1;
1391                     });
1392     ASSERT_EQ(returnval, 0);
1393     OMX_PARAM_PORTDEFINITIONTYPE portDef;
1394     status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
1395                           kPortIndexInput, &portDef);
1396     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1397     ASSERT_EQ(::android::OK,
1398               producer->setMaxDequeuedBufferCount(portDef.nBufferCountActual));
1399 
1400     // Connect :: Mock Producer Listener
1401     IGraphicBufferProducer::QueueBufferOutput qbo;
1402     sp<CodecProducerListener> listener =
1403         new CodecProducerListener(portDef.nBufferCountActual + value, value);
1404     producer->connect(
1405         listener, NATIVE_WINDOW_API_CPU, false,
1406         [&](int32_t _s, IGraphicBufferProducer::QueueBufferOutput const& _n1) {
1407             returnval = _s;
1408             qbo = _n1;
1409         });
1410     ASSERT_EQ(returnval, 0);
1411 
1412     portDef.nBufferCountActual = portDef.nBufferCountActual + value;
1413     status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
1414                           kPortIndexInput, &portDef);
1415     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1416 
1417     // Do setInputSurface()
1418     // enable MetaMode on input port
1419     status = source->configure(
1420         omxNode, android::hardware::graphics::common::V1_0::Dataspace::UNKNOWN);
1421     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1422 
1423     // set port mode
1424     PortMode portMode[2];
1425     portMode[0] = PortMode::DYNAMIC_ANW_BUFFER;
1426     portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1427     status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1428     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1429     status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1430     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1431 
1432     android::Vector<BufferInfo> iBuffer, oBuffer;
1433     // set state to idle
1434     ASSERT_NO_FATAL_FAILURE(
1435         changeStateLoadedtoIdle(omxNode, observer, &iBuffer, &oBuffer,
1436                                 kPortIndexInput, kPortIndexOutput, portMode));
1437     // set state to executing
1438     ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1439 
1440     // send EOS
1441     status = source->signalEndOfInputStream();
1442     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1443     ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(omxNode, observer, &iBuffer,
1444                                                    &oBuffer, true, listener));
1445     ASSERT_NO_FATAL_FAILURE(
1446         testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
1447 
1448     // set state to idle
1449     ASSERT_NO_FATAL_FAILURE(
1450         changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1451     EXPECT_EQ(portDef.nBufferCountActual, listener->freeBuffers);
1452     // set state to executing
1453     ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer, &oBuffer,
1454                                                     kPortIndexInput, kPortIndexOutput, portMode));
1455 
1456     returnval = producer->disconnect(
1457         NATIVE_WINDOW_API_CPU, IGraphicBufferProducer::DisconnectMode::API);
1458     ASSERT_EQ(returnval, 0);
1459 }
1460 
1461 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VideoEncHidlTest);
1462 INSTANTIATE_TEST_SUITE_P(PerInstance, VideoEncHidlTest, testing::ValuesIn(kTestParameters),
1463                          android::hardware::PrintInstanceTupleNameToString<>);
1464 
main(int argc,char ** argv)1465 int main(int argc, char** argv) {
1466     kTestParameters = getTestParameters("video_encoder");
1467     ::testing::InitGoogleTest(&argc, argv);
1468 
1469     // Set the resource directory based on command line args.
1470     // Test will fail to set up if the argument is not set.
1471     for (int i = 1; i < argc; i++) {
1472         if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
1473             sResourceDir = argv[i + 1];
1474             break;
1475         }
1476     }
1477 
1478     return RUN_ALL_TESTS();
1479 }