xref: /aosp_15_r20/frameworks/av/media/libstagefright/tests/writer/WriterTest.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "WriterTest"
19 #include <utils/Log.h>
20 
21 #include <binder/ProcessState.h>
22 
23 #include <inttypes.h>
24 #include <fstream>
25 #include <iostream>
26 
27 #include <media/NdkMediaExtractor.h>
28 #include <media/stagefright/MediaDefs.h>
29 #include <media/stagefright/MetaData.h>
30 #include <media/stagefright/Utils.h>
31 
32 #include <media/mediarecorder.h>
33 
34 #include <media/stagefright/AACWriter.h>
35 #include <media/stagefright/AMRWriter.h>
36 #include <media/stagefright/MPEG2TSWriter.h>
37 #include <media/stagefright/MPEG4Writer.h>
38 #include <media/stagefright/OggWriter.h>
39 #include <webm/WebmWriter.h>
40 
41 #include "WriterTestEnvironment.h"
42 #include "WriterUtility.h"
43 
44 #define OUTPUT_FILE_NAME "/data/local/tmp/writer.out"
45 
46 // Stts values within 0.1ms(100us) difference are fudged to save too
47 // many stts entries in MPEG4Writer.
48 constexpr int32_t kMpeg4MuxToleranceTimeUs = 100;
49 // Tolerance value for other writers
50 constexpr int32_t kMuxToleranceTimeUs = 1;
51 
52 static WriterTestEnvironment *gEnv = nullptr;
53 
54 enum inputId {
55     // audio streams
56     AAC_1,
57     AAC_ADTS_1,
58     AMR_NB_1,
59     AMR_WB_1,
60     FLAC_1,
61     OPUS_1,
62     VORBIS_1,
63     // video streams
64     AV1_1,
65     AVC_1,
66     H263_1,
67     HEVC_1,
68     MPEG4_1,
69     VP8_1,
70     VP9_1,
71     // heif stream
72     HEIC_1,
73     UNUSED_ID,
74     UNKNOWN_ID,
75 };
76 
77 // LookUpTable of clips and metadata for component testing
78 static const struct InputData {
79     inputId inpId;
80     const char *mime;
81     string inputFile;
82     string info;
83     int32_t firstParam;
84     int32_t secondParam;
85     bool isAudio;
86 } kInputData[] = {
87         {AAC_1, MEDIA_MIMETYPE_AUDIO_AAC, "audio_aac_stereo_8kbps_11025hz.aac",
88          "audio_aac_stereo_8kbps_11025hz.info", 11025, 2, true},
89         {AAC_ADTS_1, MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
90          "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
91         {AMR_NB_1, MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
92          "sine_amrnb_1ch_12kbps_8000hz.info", 8000, 1, true},
93         {AMR_WB_1, MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
94          "bbb_amrwb_1ch_14kbps_16000hz.info", 16000, 1, true},
95         {FLAC_1, MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
96          "bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
97         {OPUS_1, MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
98          "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
99         {VORBIS_1, MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_1ch_64kbps_16kHz.vorbis",
100          "bbb_vorbis_1ch_64kbps_16kHz.info", 16000, 1, true},
101 
102         {AV1_1, MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144,
103          false},
104         {AVC_1, MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_352x288_768kbps_30fps.avc",
105          "bbb_avc_352x288_768kbps_30fps.info", 352, 288, false},
106         {H263_1, MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
107          "bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
108         {HEVC_1, MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_340x280_768kbps_30fps.hevc",
109          "bbb_hevc_340x280_768kbps_30fps.info", 340, 280, false},
110         {MPEG4_1, MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
111          "bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
112         {VP8_1, MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
113          "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
114         {VP9_1, MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
115          "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
116 
117         {HEIC_1, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, "bbb_hevc_176x144_176kbps_60fps.hevc",
118          "bbb_heic_176x144_176kbps_60fps.info", 176, 144, false},
119 };
120 
121 class WriterTest {
122   public:
WriterTest()123     WriterTest() : mWriter(nullptr), mFileMeta(nullptr) {}
124 
~WriterTest()125     ~WriterTest() {
126         if (mFileMeta) {
127             mFileMeta.clear();
128             mFileMeta = nullptr;
129         }
130         if (mWriter) {
131             mWriter.clear();
132             mWriter = nullptr;
133         }
134         if (gEnv->cleanUp()) remove(OUTPUT_FILE_NAME);
135 
136         for (int32_t idx = 0; idx < kMaxTrackCount; idx++) {
137             mBufferInfo[idx].clear();
138             if (mCurrentTrack[idx]) {
139                 mCurrentTrack[idx]->stop();
140                 mCurrentTrack[idx].clear();
141                 mCurrentTrack[idx] = nullptr;
142             }
143             if (mInputStream[idx].is_open()) mInputStream[idx].close();
144         }
145     }
146 
setupWriterType(string writerFormat)147     void setupWriterType(string writerFormat) {
148         mWriterName = unknown_comp;
149         mDisableTest = false;
150         static const std::map<std::string, standardWriters> mapWriter = {
151                 {"ogg", OGG},     {"aac", AAC},      {"aac_adts", AAC_ADTS}, {"webm", WEBM},
152                 {"mpeg4", MPEG4}, {"amrnb", AMR_NB}, {"amrwb", AMR_WB},      {"mpeg2Ts", MPEG2TS}};
153         // Find the component type
154         if (mapWriter.find(writerFormat) != mapWriter.end()) {
155             mWriterName = mapWriter.at(writerFormat);
156         }
157         if (mWriterName == standardWriters::unknown_comp) {
158             cout << "[   WARN   ] Test Skipped. No specific writer mentioned\n";
159             mDisableTest = true;
160         }
161     }
162 
163     void getInputBufferInfo(string inputFileName, string inputInfo, int32_t idx = 0);
164 
165     int32_t createWriter(int32_t fd);
166 
167     int32_t addWriterSource(bool isAudio, configFormat params, int32_t idx = 0);
168 
169     void setupExtractor(AMediaExtractor *extractor, string inputFileName, int32_t &trackCount);
170 
171     void extract(AMediaExtractor *extractor, configFormat &params, vector<BufferInfo> &bufferInfo,
172                  uint8_t *buffer, size_t bufSize, size_t *bytesExtracted, int32_t idx);
173 
174     void compareParams(configFormat srcParam, configFormat dstParam, vector<BufferInfo> dstBufInfo,
175                        int32_t index);
176 
177     enum standardWriters {
178         OGG,
179         AAC,
180         AAC_ADTS,
181         WEBM,
182         MPEG4,
183         AMR_NB,
184         AMR_WB,
185         MPEG2TS,
186         unknown_comp,
187     };
188 
189     standardWriters mWriterName;
190     sp<MediaWriter> mWriter;
191     sp<MetaData> mFileMeta;
192     sp<MediaAdapter> mCurrentTrack[kMaxTrackCount]{};
193 
194     bool mDisableTest;
195     int32_t mNumCsds[kMaxTrackCount]{};
196     int32_t mInputFrameId[kMaxTrackCount]{};
197     ifstream mInputStream[kMaxTrackCount]{};
198     vector<BufferInfo> mBufferInfo[kMaxTrackCount];
199 };
200 
201 class WriteFunctionalityTest
202     : public WriterTest,
203       public ::testing::TestWithParam<tuple<string /* writerFormat*/, inputId /* inputId0*/,
204                                             inputId /* inputId1*/, float /* BufferInterval*/>> {
205   public:
SetUp()206     virtual void SetUp() override { setupWriterType(get<0>(GetParam())); }
207 };
208 
getInputBufferInfo(string inputFileName,string inputInfo,int32_t idx)209 void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo, int32_t idx) {
210     std::ifstream eleInfo;
211     eleInfo.open(inputInfo.c_str());
212     ASSERT_EQ(eleInfo.is_open(), true);
213     int32_t bytesCount = 0;
214     uint32_t flags = 0;
215     int64_t timestamp = 0;
216     int32_t numCsds = 0;
217     while (1) {
218         if (!(eleInfo >> bytesCount)) break;
219         eleInfo >> flags;
220         eleInfo >> timestamp;
221         mBufferInfo[idx].push_back({bytesCount, flags, timestamp});
222         if (flags == CODEC_CONFIG_FLAG) numCsds++;
223     }
224     eleInfo.close();
225     mNumCsds[idx] = numCsds;
226     mInputStream[idx].open(inputFileName.c_str(), std::ifstream::binary);
227     ASSERT_EQ(mInputStream[idx].is_open(), true);
228 }
229 
createWriter(int32_t fd)230 int32_t WriterTest::createWriter(int32_t fd) {
231     mFileMeta = new MetaData;
232     switch (mWriterName) {
233         case OGG:
234             mWriter = new OggWriter(fd);
235             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
236             break;
237         case AAC:
238             mWriter = new AACWriter(fd);
239             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
240             break;
241         case AAC_ADTS:
242             mWriter = new AACWriter(fd);
243             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
244             break;
245         case WEBM:
246             mWriter = new WebmWriter(fd);
247             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
248             break;
249         case MPEG4:
250             mWriter = new MPEG4Writer(fd);
251             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
252             break;
253         case AMR_NB:
254             mWriter = new AMRWriter(fd);
255             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
256             break;
257         case AMR_WB:
258             mWriter = new AMRWriter(fd);
259             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
260             break;
261         case MPEG2TS:
262             mWriter = new MPEG2TSWriter(fd);
263             mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
264             break;
265         default:
266             return -1;
267     }
268     if (mWriter == nullptr) return -1;
269     mFileMeta->setInt32(kKeyRealTimeRecording, false);
270     return 0;
271 }
272 
addWriterSource(bool isAudio,configFormat params,int32_t idx)273 int32_t WriterTest::addWriterSource(bool isAudio, configFormat params, int32_t idx) {
274     if (mInputFrameId[idx]) return -1;
275     sp<AMessage> format = new AMessage;
276     if (mInputStream[idx].is_open()) {
277         format->setString("mime", params.mime);
278         if (isAudio) {
279             format->setInt32("channel-count", params.channelCount);
280             format->setInt32("sample-rate", params.sampleRate);
281         } else {
282             format->setInt32("width", params.width);
283             format->setInt32("height", params.height);
284         }
285         if (mNumCsds[idx]) {
286             int32_t status = writeHeaderBuffers(mInputStream[idx], mBufferInfo[idx],
287                                                 mInputFrameId[idx], format, mNumCsds[idx]);
288             if (status != 0) return -1;
289         }
290     }
291 
292     sp<MetaData> trackMeta = new MetaData;
293     convertMessageToMetaData(format, trackMeta);
294     mCurrentTrack[idx] = new MediaAdapter(trackMeta);
295     if (mCurrentTrack[idx] == nullptr) {
296         ALOGE("MediaAdapter returned nullptr");
297         return -1;
298     }
299     status_t result = mWriter->addSource(mCurrentTrack[idx]);
300     return result;
301 }
302 
getFileDetails(string & inputFilePath,string & info,configFormat & params,bool & isAudio,inputId inpId)303 void getFileDetails(string &inputFilePath, string &info, configFormat &params, bool &isAudio,
304                     inputId inpId) {
305     int32_t inputDataSize = sizeof(kInputData) / sizeof(kInputData[0]);
306     int32_t streamIndex = 0;
307     for (; streamIndex < inputDataSize; streamIndex++) {
308         if (inpId == kInputData[streamIndex].inpId) {
309             break;
310         }
311     }
312     if (streamIndex == inputDataSize) {
313         return;
314     }
315     inputFilePath += kInputData[streamIndex].inputFile;
316     info += kInputData[streamIndex].info;
317     strcpy(params.mime, kInputData[streamIndex].mime);
318     isAudio = kInputData[streamIndex].isAudio;
319     if (isAudio) {
320         params.sampleRate = kInputData[streamIndex].firstParam;
321         params.channelCount = kInputData[streamIndex].secondParam;
322     } else {
323         params.width = kInputData[streamIndex].firstParam;
324         params.height = kInputData[streamIndex].secondParam;
325     }
326     return;
327 }
328 
setupExtractor(AMediaExtractor * extractor,string inputFileName,int32_t & trackCount)329 void WriterTest::setupExtractor(AMediaExtractor *extractor, string inputFileName,
330                                 int32_t &trackCount) {
331     ALOGV("Input file for extractor: %s", inputFileName.c_str());
332 
333     int32_t fd = open(inputFileName.c_str(), O_RDONLY);
334     ASSERT_GE(fd, 0) << "Failed to open writer's output file to validate";
335 
336     struct stat buf;
337     int32_t status = fstat(fd, &buf);
338     ASSERT_EQ(status, 0) << "Failed to get properties of input file for extractor";
339 
340     size_t fileSize = buf.st_size;
341     ALOGV("Size of input file to extractor: %zu", fileSize);
342 
343     status = AMediaExtractor_setDataSourceFd(extractor, fd, 0, fileSize);
344     ASSERT_EQ(status, AMEDIA_OK) << "Failed to set data source for extractor";
345 
346     trackCount = AMediaExtractor_getTrackCount(extractor);
347     ASSERT_GT(trackCount, 0) << "No tracks reported by extractor";
348     ALOGV("Number of tracks reported by extractor : %d", trackCount);
349     return;
350 }
351 
extract(AMediaExtractor * extractor,configFormat & params,vector<BufferInfo> & bufferInfo,uint8_t * buffer,size_t bufSize,size_t * bytesExtracted,int32_t idx)352 void WriterTest::extract(AMediaExtractor *extractor, configFormat &params,
353                          vector<BufferInfo> &bufferInfo, uint8_t *buffer, size_t bufSize,
354                          size_t *bytesExtracted, int32_t idx) {
355     AMediaExtractor_selectTrack(extractor, idx);
356     AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, idx);
357     ASSERT_NE(format, nullptr) << "Track format is NULL";
358     ALOGI("Track format = %s", AMediaFormat_toString(format));
359 
360     const char *mime = nullptr;
361     AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
362     ASSERT_NE(mime, nullptr) << "Track mime is NULL";
363     ALOGI("Track mime = %s", mime);
364     strlcpy(params.mime, mime, kMimeSize);
365 
366     if (!strncmp(mime, "audio/", 6)) {
367         ASSERT_TRUE(
368                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &params.channelCount))
369                 << "Extractor did not report channel count";
370         ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &params.sampleRate))
371                 << "Extractor did not report sample rate";
372     } else if (!strncmp(mime, "video/", 6) || !strncmp(mime, "image/", 6)) {
373         ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &params.width))
374                 << "Extractor did not report width";
375         ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &params.height))
376                 << "Extractor did not report height";
377     } else {
378         ASSERT_TRUE(false) << "Invalid mime " << mime;
379     }
380 
381     int32_t bufferOffset = 0;
382     // Get CSD data
383     int index = 0;
384     void *csdBuf;
385     while (1) {
386         csdBuf = nullptr;
387         char csdName[16];
388         snprintf(csdName, 16, "csd-%d", index);
389         size_t csdSize = 0;
390         bool csdFound = AMediaFormat_getBuffer(format, csdName, &csdBuf, &csdSize);
391         if (!csdFound || !csdBuf || !csdSize) break;
392 
393         bufferInfo.push_back({static_cast<int32_t>(csdSize), CODEC_CONFIG_FLAG, 0});
394         memcpy(buffer + bufferOffset, csdBuf, csdSize);
395         bufferOffset += csdSize;
396         index++;
397     }
398 
399     // Get frame data
400     while (1) {
401         ssize_t sampleSize = AMediaExtractor_getSampleSize(extractor);
402         if (sampleSize < 0) break;
403 
404         uint8_t *sampleBuffer = (uint8_t *)malloc(sampleSize);
405         ASSERT_NE(sampleBuffer, nullptr) << "Failed to allocate the buffer of size " << sampleSize;
406 
407         int bytesRead = AMediaExtractor_readSampleData(extractor, sampleBuffer, sampleSize);
408         ASSERT_EQ(bytesRead, sampleSize)
409                 << "Number of bytes extracted does not match with sample size";
410         int64_t pts = AMediaExtractor_getSampleTime(extractor);
411         uint32_t flag = AMediaExtractor_getSampleFlags(extractor);
412 
413         if (mime == MEDIA_MIMETYPE_AUDIO_VORBIS) {
414             // Removing 4 bytes of AMEDIAFORMAT_KEY_VALID_SAMPLES from sample size
415             bytesRead = bytesRead - 4;
416         }
417 
418         ASSERT_LE(bufferOffset + bytesRead, bufSize)
419                 << "Size of the buffer is insufficient to store the extracted data";
420         bufferInfo.push_back({bytesRead, flag, pts});
421         memcpy(buffer + bufferOffset, sampleBuffer, bytesRead);
422         bufferOffset += bytesRead;
423 
424         AMediaExtractor_advance(extractor);
425         free(sampleBuffer);
426     }
427     *bytesExtracted = bufferOffset;
428     return;
429 }
430 
compareParams(configFormat srcParam,configFormat dstParam,vector<BufferInfo> dstBufInfo,int32_t index)431 void WriterTest::compareParams(configFormat srcParam, configFormat dstParam,
432                                vector<BufferInfo> dstBufInfo, int32_t index) {
433     ASSERT_STREQ(srcParam.mime, dstParam.mime)
434             << "Extracted mime type does not match with input mime type";
435 
436     if (!strncmp(srcParam.mime, "audio/", 6)) {
437         ASSERT_EQ(srcParam.channelCount, dstParam.channelCount)
438                 << "Extracted channel count does not match with input channel count";
439         ASSERT_EQ(srcParam.sampleRate, dstParam.sampleRate)
440                 << "Extracted sample rate does not match with input sample rate";
441     } else if (!strncmp(srcParam.mime, "video/", 6) || !strncmp(srcParam.mime, "image/", 6)) {
442         ASSERT_EQ(srcParam.width, dstParam.width)
443                 << "Extracted width does not match with input width";
444         ASSERT_EQ(srcParam.height, dstParam.height)
445                 << "Extracted height does not match with input height";
446     } else {
447         ASSERT_TRUE(false) << "Invalid mime type" << srcParam.mime;
448     }
449 
450     int32_t toleranceValueUs = kMuxToleranceTimeUs;
451     if (mWriterName == MPEG4) {
452         toleranceValueUs = kMpeg4MuxToleranceTimeUs;
453     }
454     for (int32_t i = 0; i < dstBufInfo.size(); i++) {
455         ASSERT_EQ(mBufferInfo[index][i].size, dstBufInfo[i].size)
456                 << "Input size " << mBufferInfo[index][i].size << " mismatched with extracted size "
457                 << dstBufInfo[i].size;
458         ASSERT_EQ(mBufferInfo[index][i].flags, dstBufInfo[i].flags)
459                 << "Input flag " << mBufferInfo[index][i].flags
460                 << " mismatched with extracted size " << dstBufInfo[i].flags;
461         ASSERT_LE(abs(mBufferInfo[index][i].timeUs - dstBufInfo[i].timeUs), toleranceValueUs)
462                 << "Difference between original timestamp " << mBufferInfo[index][i].timeUs
463                 << " and extracted timestamp " << dstBufInfo[i].timeUs
464                 << "is greater than tolerance value = " << toleranceValueUs << " micro seconds";
465     }
466     return;
467 }
468 
TEST_P(WriteFunctionalityTest,CreateWriterTest)469 TEST_P(WriteFunctionalityTest, CreateWriterTest) {
470     if (mDisableTest) return;
471     ALOGV("Tests the creation of writers");
472 
473     string outputFile = OUTPUT_FILE_NAME;
474     int32_t fd =
475             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
476     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
477 
478     // Creating writer within a test scope. Destructor should be called when the test ends
479     ASSERT_EQ((status_t)OK, createWriter(fd))
480             << "Failed to create writer for output format:" << get<0>(GetParam());
481 }
482 
TEST_P(WriteFunctionalityTest,WriterTest)483 TEST_P(WriteFunctionalityTest, WriterTest) {
484     if (mDisableTest) return;
485     ALOGV("Checks if for a given input, a valid muxed file has been created or not");
486 
487     string writerFormat = get<0>(GetParam());
488     string outputFile = OUTPUT_FILE_NAME;
489     int32_t fd =
490             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
491     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
492 
493     int32_t status = createWriter(fd);
494     ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
495 
496     inputId inpId[] = {get<1>(GetParam()), get<2>(GetParam())};
497     ASSERT_NE(inpId[0], UNUSED_ID) << "Test expects first inputId to be a valid id";
498 
499     int32_t numTracks = 1;
500     if (inpId[1] != UNUSED_ID) {
501         numTracks++;
502     }
503 
504     size_t fileSize[numTracks];
505     configFormat param[numTracks];
506     for (int32_t idx = 0; idx < numTracks; idx++) {
507         string inputFile = gEnv->getRes();
508         string inputInfo = gEnv->getRes();
509         bool isAudio;
510         getFileDetails(inputFile, inputInfo, param[idx], isAudio, inpId[idx]);
511         ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
512 
513         struct stat buf;
514         status = stat(inputFile.c_str(), &buf);
515         ASSERT_EQ(status, 0) << "Failed to get properties of input file:" << inputFile;
516         fileSize[idx] = buf.st_size;
517 
518         ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo, idx));
519         status = addWriterSource(isAudio, param[idx], idx);
520         ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
521     }
522 
523     status = mWriter->start(mFileMeta.get());
524     ASSERT_EQ((status_t)OK, status);
525     float interval = get<3>(GetParam());
526     ASSERT_LE(interval, 1.0f) << "Buffer interval invalid. Should be less than or equal to 1.0";
527 
528     size_t range = 0;
529     int32_t loopCount = 0;
530     int32_t offset[kMaxTrackCount]{};
531     while (loopCount < ceil(1.0 / interval)) {
532         for (int32_t idx = 0; idx < numTracks; idx++) {
533             range = mBufferInfo[idx].size() * interval;
534             status = sendBuffersToWriter(mInputStream[idx], mBufferInfo[idx], mInputFrameId[idx],
535                                          mCurrentTrack[idx], offset[idx], range);
536             ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
537             offset[idx] += range;
538         }
539         loopCount++;
540     }
541     for (int32_t idx = 0; idx < kMaxTrackCount; idx++) {
542         if (mCurrentTrack[idx]) {
543             mCurrentTrack[idx]->stop();
544         }
545     }
546     status = mWriter->stop();
547     ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
548     close(fd);
549 
550     // Validate the output muxed file created by writer
551     // TODO(b/146423022): Skip validating output for webm writer
552     // TODO(b/146421018): Skip validating output for ogg writer
553     if (mWriterName != OGG && mWriterName != WEBM) {
554         configFormat extractorParams[numTracks];
555         vector<BufferInfo> extractorBufferInfo[numTracks];
556         int32_t trackCount = -1;
557 
558         AMediaExtractor *extractor = AMediaExtractor_new();
559         ASSERT_NE(extractor, nullptr) << "Failed to create extractor";
560         ASSERT_NO_FATAL_FAILURE(setupExtractor(extractor, outputFile, trackCount));
561         ASSERT_EQ(trackCount, numTracks)
562                 << "Tracks reported by extractor does not match with input number of tracks";
563 
564         for (int32_t idx = 0; idx < numTracks; idx++) {
565             char *inputBuffer = (char *)malloc(fileSize[idx]);
566             ASSERT_NE(inputBuffer, nullptr)
567                     << "Failed to allocate the buffer of size " << fileSize[idx];
568             mInputStream[idx].seekg(0, mInputStream[idx].beg);
569             mInputStream[idx].read(inputBuffer, fileSize[idx]);
570             ASSERT_EQ(mInputStream[idx].gcount(), fileSize[idx]);
571 
572             uint8_t *extractedBuffer = (uint8_t *)malloc(fileSize[idx]);
573             ASSERT_NE(extractedBuffer, nullptr)
574                     << "Failed to allocate the buffer of size " << fileSize[idx];
575             size_t bytesExtracted = 0;
576 
577             ASSERT_NO_FATAL_FAILURE(extract(extractor, extractorParams[idx],
578                                             extractorBufferInfo[idx], extractedBuffer,
579                                             fileSize[idx], &bytesExtracted, idx));
580             ASSERT_GT(bytesExtracted, 0) << "Total bytes extracted by extractor cannot be zero";
581 
582             ASSERT_NO_FATAL_FAILURE(
583                     compareParams(param[idx], extractorParams[idx], extractorBufferInfo[idx], idx));
584 
585             ASSERT_EQ(memcmp(extractedBuffer, (uint8_t *)inputBuffer, bytesExtracted), 0)
586                     << "Extracted bit stream does not match with input bit stream";
587 
588             free(inputBuffer);
589             free(extractedBuffer);
590         }
591         AMediaExtractor_delete(extractor);
592     }
593 }
594 
TEST_P(WriteFunctionalityTest,PauseWriterTest)595 TEST_P(WriteFunctionalityTest, PauseWriterTest) {
596     if (mDisableTest) return;
597     ALOGV("Validates the pause() api of writers");
598 
599     string writerFormat = get<0>(GetParam());
600     string outputFile = OUTPUT_FILE_NAME;
601     int32_t fd =
602             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
603     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
604 
605     int32_t status = createWriter(fd);
606     ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
607 
608     string inputFile = gEnv->getRes();
609     string inputInfo = gEnv->getRes();
610     configFormat param;
611     bool isAudio;
612     inputId inpId = get<1>(GetParam());
613     ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
614 
615     getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
616     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
617 
618     ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
619     status = addWriterSource(isAudio, param);
620     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
621 
622     status = mWriter->start(mFileMeta.get());
623     ASSERT_EQ((status_t)OK, status);
624     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
625                                  mCurrentTrack[0], 0, mBufferInfo[0].size() / 4);
626     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
627 
628     bool isPaused = false;
629     if ((mWriterName != standardWriters::MPEG2TS) && (mWriterName != standardWriters::MPEG4)) {
630         status = mWriter->pause();
631         ASSERT_EQ((status_t)OK, status);
632         isPaused = true;
633     }
634     // In the pause state, writers shouldn't write anything. Testing the writers for the same
635     int32_t numFramesPaused = mBufferInfo[0].size() / 4;
636     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
637                                  mCurrentTrack[0], mInputFrameId[0], numFramesPaused, isPaused);
638     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
639 
640     if (isPaused) {
641         status = mWriter->start(mFileMeta.get());
642         ASSERT_EQ((status_t)OK, status);
643     }
644     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
645                                  mCurrentTrack[0], mInputFrameId[0], mBufferInfo[0].size());
646     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
647     mCurrentTrack[0]->stop();
648 
649     status = mWriter->stop();
650     ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
651     close(fd);
652 }
653 
TEST_P(WriteFunctionalityTest,MultiStartStopPauseTest)654 TEST_P(WriteFunctionalityTest, MultiStartStopPauseTest) {
655     // TODO: (b/144821804)
656     // Enable the test for MPE2TS writer
657     if (mDisableTest || mWriterName == standardWriters::MPEG2TS) return;
658     ALOGV("Test writers for multiple start, stop and pause calls");
659 
660     string outputFile = OUTPUT_FILE_NAME;
661     int32_t fd =
662             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
663     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
664 
665     string writerFormat = get<0>(GetParam());
666     int32_t status = createWriter(fd);
667     ASSERT_EQ(status, (status_t)OK) << "Failed to create writer for output format:" << writerFormat;
668 
669     string inputFile = gEnv->getRes();
670     string inputInfo = gEnv->getRes();
671     configFormat param;
672     bool isAudio;
673     inputId inpId = get<1>(GetParam());
674     ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
675 
676     getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
677     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
678 
679     ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
680     status = addWriterSource(isAudio, param);
681     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
682 
683     // first start should succeed.
684     status = mWriter->start(mFileMeta.get());
685     ASSERT_EQ((status_t)OK, status) << "Could not start the writer";
686 
687     // Multiple start() may/may not succeed.
688     // Writers are expected to not crash on multiple start() calls.
689     for (int32_t count = 0; count < kMaxCount; count++) {
690         mWriter->start(mFileMeta.get());
691     }
692 
693     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
694                                  mCurrentTrack[0], 0, mBufferInfo[0].size() / 4);
695     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
696 
697     for (int32_t count = 0; count < kMaxCount; count++) {
698         mWriter->pause();
699         mWriter->start(mFileMeta.get());
700     }
701 
702     mWriter->pause();
703     int32_t numFramesPaused = mBufferInfo[0].size() / 4;
704     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
705                                  mCurrentTrack[0], mInputFrameId[0], numFramesPaused, true);
706     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
707 
708     for (int32_t count = 0; count < kMaxCount; count++) {
709         mWriter->start(mFileMeta.get());
710     }
711 
712     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
713                                  mCurrentTrack[0], mInputFrameId[0], mBufferInfo[0].size());
714     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
715 
716     mCurrentTrack[0]->stop();
717 
718     // first stop should succeed.
719     status = mWriter->stop();
720     ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
721     // Multiple stop() may/may not succeed.
722     // Writers are expected to not crash on multiple stop() calls.
723     for (int32_t count = 0; count < kMaxCount; count++) {
724         mWriter->stop();
725     }
726     close(fd);
727 }
728 
729 class WriterValidityTest
730     : public WriterTest,
731       public ::testing::TestWithParam<
732               tuple<string /* writerFormat*/, inputId /* inputId0*/, bool /* addSourceFail*/>> {
733   public:
SetUp()734     virtual void SetUp() override { setupWriterType(get<0>(GetParam())); }
735 };
736 
TEST_P(WriterValidityTest,InvalidInputTest)737 TEST_P(WriterValidityTest, InvalidInputTest) {
738     if (mDisableTest) return;
739     ALOGV("Validates writer's behavior for invalid inputs");
740 
741     string writerFormat = get<0>(GetParam());
742     inputId inpId = get<1>(GetParam());
743     bool addSourceFailExpected = get<2>(GetParam());
744 
745     // Test writers for invalid FD value
746     int32_t fd = -1;
747     int32_t status = createWriter(fd);
748     if (status != OK) {
749         ALOGV("createWriter failed for invalid FD, this is expected behavior");
750         return;
751     }
752 
753     // If writer was created for invalid fd, test it further.
754     string inputFile = gEnv->getRes();
755     string inputInfo = gEnv->getRes();
756     configFormat param;
757     bool isAudio;
758     ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
759 
760     getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
761     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
762 
763     ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
764     status = addWriterSource(isAudio, param);
765     if (status != OK) {
766         ASSERT_TRUE(addSourceFailExpected)
767                 << "Failed to add source for " << writerFormat << " writer";
768         ALOGV("addWriterSource failed for invalid FD, this is expected behavior");
769         return;
770     }
771 
772     // start the writer with valid argument but invalid FD
773     status = mWriter->start(mFileMeta.get());
774     ASSERT_NE((status_t)OK, status) << "Writer did not fail for invalid FD";
775 
776     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
777                                  mCurrentTrack[0], 0, mBufferInfo[0].size());
778     ASSERT_NE((status_t)OK, status) << "Writer did not report error for invalid FD";
779 
780     status = mCurrentTrack[0]->stop();
781     ASSERT_EQ((status_t)OK, status) << "Failed to stop the track";
782 
783     status = mWriter->stop();
784     ASSERT_EQ((status_t)OK, status) << "Failed to stop " << writerFormat << " writer";
785 }
786 
TEST_P(WriterValidityTest,MalFormedDataTest)787 TEST_P(WriterValidityTest, MalFormedDataTest) {
788     if (mDisableTest) return;
789     // Enable test for Ogg writer
790     ASSERT_NE(mWriterName, OGG) << "TODO(b/160105646)";
791     ALOGV("Test writer for malformed inputs");
792 
793     string writerFormat = get<0>(GetParam());
794     inputId inpId = get<1>(GetParam());
795     bool addSourceFailExpected = get<2>(GetParam());
796     int32_t fd =
797             open(OUTPUT_FILE_NAME, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
798     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
799 
800     int32_t status = createWriter(fd);
801     ASSERT_EQ(status, (status_t)OK)
802             << "Failed to create writer for " << writerFormat << " output format";
803 
804     string inputFile = gEnv->getRes();
805     string inputInfo = gEnv->getRes();
806     configFormat param;
807     bool isAudio;
808     ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
809 
810     getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
811     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
812 
813     ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
814     // Remove CSD data from input
815     mNumCsds[0] = 0;
816     status = addWriterSource(isAudio, param);
817     if (status != OK) {
818         ASSERT_TRUE(addSourceFailExpected)
819                 << "Failed to add source for " << writerFormat << " writer";
820         ALOGV("%s writer failed to addSource after removing CSD from input", writerFormat.c_str());
821         return;
822     }
823 
824     status = mWriter->start(mFileMeta.get());
825     ASSERT_EQ((status_t)OK, status) << "Could not start " << writerFormat << "writer";
826 
827     // Skip first few frames. These may contain sync frames also.
828     int32_t frameID = mInputFrameId[0] + mBufferInfo[0].size() / 4;
829     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], frameID, mCurrentTrack[0], 0,
830                                  mBufferInfo[0].size());
831     ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
832 
833     status = mCurrentTrack[0]->stop();
834     ASSERT_EQ((status_t)OK, status) << "Failed to stop the track";
835 
836     Vector<String16> args;
837     status = mWriter->dump(fd, args);
838     ASSERT_EQ((status_t)OK, status) << "Failed to dump statistics from writer";
839 
840     status = mWriter->stop();
841     ASSERT_EQ((status_t)OK, status) << "Failed to stop " << writerFormat << " writer";
842     close(fd);
843 }
844 
845 // This test is specific to MPEG4Writer to test more APIs
TEST_P(WriteFunctionalityTest,Mpeg4WriterTest)846 TEST_P(WriteFunctionalityTest, Mpeg4WriterTest) {
847     if (mDisableTest) return;
848     if (mWriterName != standardWriters::MPEG4) return;
849     ALOGV("Test MPEG4 writer specific APIs");
850 
851     inputId inpId = get<1>(GetParam());
852     int32_t fd =
853             open(OUTPUT_FILE_NAME, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
854     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
855 
856     int32_t status = createWriter(fd);
857     ASSERT_EQ(status, (status_t)OK) << "Failed to create writer for mpeg4 output format";
858 
859     string inputFile = gEnv->getRes();
860     string inputInfo = gEnv->getRes();
861     configFormat param;
862     bool isAudio;
863     ASSERT_NE(inpId, UNUSED_ID) << "Test expects first inputId to be a valid id";
864 
865     getFileDetails(inputFile, inputInfo, param, isAudio, inpId);
866     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
867 
868     ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
869     status = addWriterSource(isAudio, param);
870     ASSERT_EQ((status_t)OK, status) << "Failed to add source for mpeg4 Writer";
871 
872     // signal meta data for the writer
873     sp<MPEG4Writer> mp4writer = static_cast<MPEG4Writer *>(mWriter.get());
874     status = mp4writer->setInterleaveDuration(kDefaultInterleaveDuration);
875     ASSERT_EQ((status_t)OK, status) << "setInterleaveDuration failed";
876 
877     status = mp4writer->setGeoData(kDefaultLatitudex10000, kDefaultLongitudex10000);
878     ASSERT_EQ((status_t)OK, status) << "setGeoData failed";
879 
880     status = mp4writer->setCaptureRate(kDefaultFPS);
881     ASSERT_EQ((status_t)OK, status) << "setCaptureRate failed";
882 
883     status = mWriter->start(mFileMeta.get());
884     ASSERT_EQ((status_t)OK, status) << "Could not start the writer";
885 
886     status = sendBuffersToWriter(mInputStream[0], mBufferInfo[0], mInputFrameId[0],
887                                  mCurrentTrack[0], 0, mBufferInfo[0].size());
888     ASSERT_EQ((status_t)OK, status) << "mpeg4 writer failed";
889 
890     status = mCurrentTrack[0]->stop();
891     ASSERT_EQ((status_t)OK, status) << "Failed to stop the track";
892 
893     status = mWriter->stop();
894     ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
895     mp4writer.clear();
896     close(fd);
897 }
898 
899 class ListenerTest
900     : public WriterTest,
901       public ::testing::TestWithParam<tuple<
902               string /* writerFormat*/, inputId /* inputId0*/, inputId /* inputId1*/,
903               float /* FileSizeLimit*/, float /* FileDurationLimit*/, float /* BufferInterval*/>> {
904   public:
SetUp()905     virtual void SetUp() override { setupWriterType(get<0>(GetParam())); }
906 };
907 
TEST_P(ListenerTest,SetMaxFileLimitsTest)908 TEST_P(ListenerTest, SetMaxFileLimitsTest) {
909     // TODO(b/151892414): Enable test for other writers
910     if (mDisableTest || mWriterName != MPEG4) return;
911     ALOGV("Validates writer when max file limits are set");
912 
913     string writerFormat = get<0>(GetParam());
914     string outputFile = OUTPUT_FILE_NAME;
915     int32_t fd =
916             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
917     ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
918 
919     int32_t status = createWriter(fd);
920     ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
921 
922     inputId inpId[] = {get<1>(GetParam()), get<2>(GetParam())};
923     ASSERT_NE(inpId[0], UNUSED_ID) << "Test expects first inputId to be a valid id";
924 
925     size_t inputFileSize = 0;
926     int64_t lastFrameTimeStampUs = INT_MAX;
927     int32_t numTracks = 1;
928     if (inpId[1] != UNUSED_ID) {
929         numTracks++;
930     }
931     for (int32_t idx = 0; idx < numTracks; idx++) {
932         string inputFile = gEnv->getRes();
933         string inputInfo = gEnv->getRes();
934         configFormat param;
935         bool isAudio;
936         getFileDetails(inputFile, inputInfo, param, isAudio, inpId[idx]);
937         ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
938 
939         ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo, idx));
940         status = addWriterSource(isAudio, param, idx);
941         ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
942 
943         // Read file properties
944         struct stat buf;
945         status = stat(inputFile.c_str(), &buf);
946         ASSERT_EQ(0, status);
947 
948         inputFileSize += buf.st_size;
949         if (lastFrameTimeStampUs > mBufferInfo[idx][mBufferInfo[idx].size() - 1].timeUs) {
950             lastFrameTimeStampUs = mBufferInfo[idx][mBufferInfo[idx].size() - 1].timeUs;
951         }
952     }
953 
954     float fileSizeLimit = get<3>(GetParam());
955     float fileDurationLimit = get<4>(GetParam());
956     int64_t maxFileSize = 0;
957     int64_t maxFileDuration = 0;
958     if (fileSizeLimit > 0) {
959         maxFileSize = (int64_t)(fileSizeLimit * inputFileSize);
960         mWriter->setMaxFileSize(maxFileSize);
961     }
962     if (fileDurationLimit > 0) {
963         maxFileDuration = (int64_t)(fileDurationLimit * lastFrameTimeStampUs);
964         mWriter->setMaxFileDuration(maxFileDuration);
965     }
966 
967     sp<WriterListener> listener = new WriterListener();
968     ASSERT_NE(listener, nullptr) << "unable to allocate listener";
969 
970     mWriter->setListener(listener);
971     status = mWriter->start(mFileMeta.get());
972     ASSERT_EQ((status_t)OK, status);
973 
974     float interval = get<5>(GetParam());
975     ASSERT_LE(interval, 1.0f) << "Buffer interval invalid. Should be less than or equal to 1.0";
976 
977     size_t range = 0;
978     int32_t loopCount = 0;
979     int32_t offset[kMaxTrackCount]{};
980     while (loopCount < ceil(1.0 / interval)) {
981         for (int32_t idx = 0; idx < numTracks; idx++) {
982             range = mBufferInfo[idx].size() * interval;
983             status = sendBuffersToWriter(mInputStream[idx], mBufferInfo[idx], mInputFrameId[idx],
984                                          mCurrentTrack[idx], offset[idx], range, false, listener);
985             ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
986             offset[idx] += range;
987         }
988         loopCount++;
989     }
990 
991     ASSERT_TRUE(mWriter->reachedEOS()) << "EOS not signalled.";
992 
993     for (int32_t idx = 0; idx < kMaxTrackCount; idx++) {
994         if (mCurrentTrack[idx]) {
995             mCurrentTrack[idx]->stop();
996         }
997     }
998 
999     status = mWriter->stop();
1000     ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
1001     close(fd);
1002 
1003     if (maxFileSize <= 0) {
1004         ASSERT_FALSE(listener->mSignaledSize);
1005     } else if (maxFileDuration <= 0) {
1006         ASSERT_FALSE(listener->mSignaledDuration);
1007     } else if (maxFileSize > 0 && maxFileDuration <= 0) {
1008         ASSERT_TRUE(listener->mSignaledSize);
1009     } else if (maxFileDuration > 0 && maxFileSize <= 0) {
1010         ASSERT_TRUE(listener->mSignaledDuration);
1011     } else {
1012         ASSERT_TRUE(listener->mSignaledSize || listener->mSignaledDuration);
1013     }
1014 
1015     if (maxFileSize > 0) {
1016         struct stat buf;
1017         status = stat(outputFile.c_str(), &buf);
1018         ASSERT_EQ(0, status);
1019         ASSERT_LE(buf.st_size, maxFileSize);
1020     }
1021 }
1022 
1023 // TODO: (b/150923387)
1024 // Add WEBM input
1025 INSTANTIATE_TEST_SUITE_P(ListenerTestAll, ListenerTest,
1026                          ::testing::Values(make_tuple("aac", AAC_1, UNUSED_ID, 0.6, 0.7, 1),
1027                                            make_tuple("amrnb", AMR_NB_1, UNUSED_ID, 0.2, 0.6, 1),
1028                                            make_tuple("amrwb", AMR_WB_1, UNUSED_ID, 0.5, 0.5, 1),
1029                                            make_tuple("mpeg2Ts", AAC_1, UNUSED_ID, 0.2, 1, 1),
1030                                            make_tuple("mpeg4", AAC_1, UNUSED_ID, 0.4, 0.3, 0.25),
1031                                            make_tuple("mpeg4", AAC_1, UNUSED_ID, 0.3, 1, 0.5),
1032                                            make_tuple("ogg", OPUS_1, UNUSED_ID, 0.7, 0.3, 1)));
1033 
1034 // TODO: (b/144476164)
1035 // Add AAC_ADTS, FLAC, AV1 input
1036 INSTANTIATE_TEST_SUITE_P(
1037         WriterTestAll, WriteFunctionalityTest,
1038         ::testing::Values(
1039                 make_tuple("aac", AAC_1, UNUSED_ID, 1),
1040 
1041                 make_tuple("amrnb", AMR_NB_1, UNUSED_ID, 1),
1042                 make_tuple("amrwb", AMR_WB_1, UNUSED_ID, 1),
1043 
1044                 // TODO(b/144902018): Enable test for mpeg2ts
1045                 // make_tuple("mpeg2Ts", AAC_1, UNUSED_ID, 1),
1046                 // make_tuple("mpeg2Ts", AVC_1, UNUSED_ID, 1),
1047                 // TODO(b/156355857): Add multitrack for mpeg2ts
1048                 // make_tuple("mpeg2Ts", AAC_1, AVC_1, 0.50),
1049                 // make_tuple("mpeg2Ts", AVC_1, AAC_1, 0.25),
1050 
1051                 make_tuple("mpeg4", AAC_1, UNUSED_ID, 1),
1052                 make_tuple("mpeg4", AMR_NB_1, UNUSED_ID, 1),
1053                 make_tuple("mpeg4", AMR_WB_1, UNUSED_ID, 1),
1054                 make_tuple("mpeg4", AVC_1, UNUSED_ID, 1),
1055                 make_tuple("mpeg4", H263_1, UNUSED_ID, 1),
1056                 make_tuple("mpeg4", HEIC_1, UNUSED_ID, 1),
1057                 make_tuple("mpeg4", HEVC_1, UNUSED_ID, 1),
1058                 make_tuple("mpeg4", MPEG4_1, UNUSED_ID, 1),
1059                 make_tuple("mpeg4", AAC_1, AVC_1, 0.25),
1060                 make_tuple("mpeg4", AVC_1, AAC_1, 0.75),
1061                 make_tuple("mpeg4", AMR_WB_1, AAC_1, 0.75),
1062                 make_tuple("mpeg4", HEVC_1, AMR_WB_1, 0.25),
1063                 make_tuple("mpeg4", H263_1, AMR_NB_1, 0.50),
1064                 make_tuple("mpeg4", MPEG4_1, AAC_1, 0.75),
1065                 make_tuple("mpeg4", AMR_NB_1, AMR_WB_1, 0.25),
1066                 make_tuple("mpeg4", H263_1, AMR_NB_1, 0.50),
1067                 make_tuple("mpeg4", MPEG4_1, HEVC_1, 0.75),
1068 
1069                 make_tuple("ogg", OPUS_1, UNUSED_ID, 1),
1070 
1071                 make_tuple("webm", OPUS_1, UNUSED_ID, 1),
1072                 make_tuple("webm", VORBIS_1, UNUSED_ID, 1),
1073                 make_tuple("webm", VP8_1, UNUSED_ID, 1),
1074                 make_tuple("webm", VP9_1, UNUSED_ID, 1),
1075                 make_tuple("webm", VP8_1, OPUS_1, 0.50),
1076                 make_tuple("webm", VORBIS_1, VP8_1, 0.25)));
1077 
1078 INSTANTIATE_TEST_SUITE_P(
1079         WriterValidityTest, WriterValidityTest,
1080         ::testing::Values(
1081                 make_tuple("aac", AAC_1, true),
1082 
1083                 make_tuple("amrnb", AMR_NB_1, true),
1084                 make_tuple("amrwb", AMR_WB_1, true),
1085 
1086                 make_tuple("mpeg4", AAC_1, false),
1087                 make_tuple("mpeg4", AMR_NB_1, false),
1088                 make_tuple("mpeg4", AVC_1, false),
1089                 make_tuple("mpeg4", H263_1, false),
1090                 make_tuple("mpeg4", HEIC_1, false),
1091                 make_tuple("mpeg4", HEVC_1, false),
1092                 make_tuple("mpeg4", MPEG4_1, false),
1093 
1094                 make_tuple("ogg", OPUS_1, true),
1095 
1096                 make_tuple("webm", OPUS_1, false),
1097                 make_tuple("webm", VORBIS_1, true),
1098                 make_tuple("webm", VP8_1, false),
1099                 make_tuple("webm", VP9_1, false)));
1100 
main(int argc,char ** argv)1101 int main(int argc, char **argv) {
1102     ProcessState::self()->startThreadPool();
1103     gEnv = new WriterTestEnvironment();
1104     ::testing::AddGlobalTestEnvironment(gEnv);
1105     ::testing::InitGoogleTest(&argc, argv);
1106     int status = gEnv->initFromOptions(argc, argv);
1107     if (status == 0) {
1108         status = RUN_ALL_TESTS();
1109         ALOGV("Test result = %d\n", status);
1110     }
1111     return status;
1112 }
1113