1*b7c941bbSAndroid Build Coastguard Worker /*
2*b7c941bbSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*b7c941bbSAndroid Build Coastguard Worker *
4*b7c941bbSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b7c941bbSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b7c941bbSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b7c941bbSAndroid Build Coastguard Worker *
8*b7c941bbSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b7c941bbSAndroid Build Coastguard Worker *
10*b7c941bbSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b7c941bbSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b7c941bbSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b7c941bbSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b7c941bbSAndroid Build Coastguard Worker * limitations under the License.
15*b7c941bbSAndroid Build Coastguard Worker */
16*b7c941bbSAndroid Build Coastguard Worker
17*b7c941bbSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*b7c941bbSAndroid Build Coastguard Worker #define LOG_TAG "NativeMuxerTest"
19*b7c941bbSAndroid Build Coastguard Worker #include <log/log.h>
20*b7c941bbSAndroid Build Coastguard Worker
21*b7c941bbSAndroid Build Coastguard Worker #include <dlfcn.h>
22*b7c941bbSAndroid Build Coastguard Worker #include <fcntl.h>
23*b7c941bbSAndroid Build Coastguard Worker #include <jni.h>
24*b7c941bbSAndroid Build Coastguard Worker #include <media/NdkMediaExtractor.h>
25*b7c941bbSAndroid Build Coastguard Worker #include <media/NdkMediaFormat.h>
26*b7c941bbSAndroid Build Coastguard Worker #include <media/NdkMediaMuxer.h>
27*b7c941bbSAndroid Build Coastguard Worker #include <sys/stat.h>
28*b7c941bbSAndroid Build Coastguard Worker #include <unistd.h>
29*b7c941bbSAndroid Build Coastguard Worker
30*b7c941bbSAndroid Build Coastguard Worker #include <cmath>
31*b7c941bbSAndroid Build Coastguard Worker #include <cstring>
32*b7c941bbSAndroid Build Coastguard Worker #include <fstream>
33*b7c941bbSAndroid Build Coastguard Worker #include <map>
34*b7c941bbSAndroid Build Coastguard Worker #include <vector>
35*b7c941bbSAndroid Build Coastguard Worker
36*b7c941bbSAndroid Build Coastguard Worker #include "NativeMediaCommon.h"
37*b7c941bbSAndroid Build Coastguard Worker
38*b7c941bbSAndroid Build Coastguard Worker // Transcoding arrived in Android 12/S, which is api 31.
39*b7c941bbSAndroid Build Coastguard Worker #define __TRANSCODING_MIN_API__ 31
40*b7c941bbSAndroid Build Coastguard Worker
41*b7c941bbSAndroid Build Coastguard Worker /**
42*b7c941bbSAndroid Build Coastguard Worker * MuxerNativeTestHelper breaks a media file to elements that a muxer can use to rebuild its clone.
43*b7c941bbSAndroid Build Coastguard Worker * While testing muxer, if the test doesn't use MediaCodecs class to generate elementary stream,
44*b7c941bbSAndroid Build Coastguard Worker * but uses MediaExtractor, this class will be handy
45*b7c941bbSAndroid Build Coastguard Worker */
46*b7c941bbSAndroid Build Coastguard Worker class MuxerNativeTestHelper {
47*b7c941bbSAndroid Build Coastguard Worker public:
MuxerNativeTestHelper(const char * srcPath,const char * mediaType=nullptr,int frameLimit=-1)48*b7c941bbSAndroid Build Coastguard Worker explicit MuxerNativeTestHelper(const char* srcPath, const char* mediaType = nullptr,
49*b7c941bbSAndroid Build Coastguard Worker int frameLimit = -1)
50*b7c941bbSAndroid Build Coastguard Worker : mSrcPath(srcPath), mMediaType(mediaType), mTrackCount(0), mBuffer(nullptr) {
51*b7c941bbSAndroid Build Coastguard Worker mFrameLimit = frameLimit < 0 ? INT_MAX : frameLimit;
52*b7c941bbSAndroid Build Coastguard Worker splitMediaToMuxerParameters();
53*b7c941bbSAndroid Build Coastguard Worker }
54*b7c941bbSAndroid Build Coastguard Worker
~MuxerNativeTestHelper()55*b7c941bbSAndroid Build Coastguard Worker ~MuxerNativeTestHelper() {
56*b7c941bbSAndroid Build Coastguard Worker for (auto format : mFormat) AMediaFormat_delete(format);
57*b7c941bbSAndroid Build Coastguard Worker delete[] mBuffer;
58*b7c941bbSAndroid Build Coastguard Worker for (const auto& buffInfoTrack : mBufferInfo) {
59*b7c941bbSAndroid Build Coastguard Worker for (auto info : buffInfoTrack) delete info;
60*b7c941bbSAndroid Build Coastguard Worker }
61*b7c941bbSAndroid Build Coastguard Worker }
62*b7c941bbSAndroid Build Coastguard Worker
getTrackCount()63*b7c941bbSAndroid Build Coastguard Worker int getTrackCount() { return mTrackCount; }
64*b7c941bbSAndroid Build Coastguard Worker
getSampleCount(size_t trackId)65*b7c941bbSAndroid Build Coastguard Worker size_t getSampleCount(size_t trackId) {
66*b7c941bbSAndroid Build Coastguard Worker if (trackId >= mTrackCount) {
67*b7c941bbSAndroid Build Coastguard Worker return 0;
68*b7c941bbSAndroid Build Coastguard Worker }
69*b7c941bbSAndroid Build Coastguard Worker return mBufferInfo[(mInpIndexMap.at(trackId))].size();
70*b7c941bbSAndroid Build Coastguard Worker }
71*b7c941bbSAndroid Build Coastguard Worker
getTrackFormat(size_t trackId)72*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* getTrackFormat(size_t trackId) {
73*b7c941bbSAndroid Build Coastguard Worker if (trackId >= mTrackCount) {
74*b7c941bbSAndroid Build Coastguard Worker return nullptr;
75*b7c941bbSAndroid Build Coastguard Worker }
76*b7c941bbSAndroid Build Coastguard Worker return mFormat[trackId];
77*b7c941bbSAndroid Build Coastguard Worker }
78*b7c941bbSAndroid Build Coastguard Worker
79*b7c941bbSAndroid Build Coastguard Worker bool registerTrack(AMediaMuxer* muxer);
80*b7c941bbSAndroid Build Coastguard Worker
81*b7c941bbSAndroid Build Coastguard Worker bool insertSampleData(AMediaMuxer* muxer);
82*b7c941bbSAndroid Build Coastguard Worker
83*b7c941bbSAndroid Build Coastguard Worker bool writeAFewSamplesData(AMediaMuxer* muxer, uint32_t fromIndex, uint32_t toIndex);
84*b7c941bbSAndroid Build Coastguard Worker
85*b7c941bbSAndroid Build Coastguard Worker bool writeAFewSamplesDataFromTime(AMediaMuxer* muxer, int64_t* fromTime, uint32_t numSamples,
86*b7c941bbSAndroid Build Coastguard Worker bool lastSplit);
87*b7c941bbSAndroid Build Coastguard Worker
88*b7c941bbSAndroid Build Coastguard Worker bool muxMedia(AMediaMuxer* muxer);
89*b7c941bbSAndroid Build Coastguard Worker
90*b7c941bbSAndroid Build Coastguard Worker bool appendMedia(AMediaMuxer *muxer, uint32_t fromIndex, uint32_t toIndex);
91*b7c941bbSAndroid Build Coastguard Worker
92*b7c941bbSAndroid Build Coastguard Worker bool appendMediaFromTime(AMediaMuxer *muxer, int64_t *appendFromTime,
93*b7c941bbSAndroid Build Coastguard Worker uint32_t numSamples, bool lastSplit);
94*b7c941bbSAndroid Build Coastguard Worker
95*b7c941bbSAndroid Build Coastguard Worker bool combineMedias(AMediaMuxer* muxer, MuxerNativeTestHelper* that, const int* repeater);
96*b7c941bbSAndroid Build Coastguard Worker
97*b7c941bbSAndroid Build Coastguard Worker bool isSubsetOf(MuxerNativeTestHelper* that);
98*b7c941bbSAndroid Build Coastguard Worker
99*b7c941bbSAndroid Build Coastguard Worker void offsetTimeStamp(int64_t tsAudioOffsetUs, int64_t tsVideoOffsetUs, int sampleOffset);
100*b7c941bbSAndroid Build Coastguard Worker
101*b7c941bbSAndroid Build Coastguard Worker private:
102*b7c941bbSAndroid Build Coastguard Worker void splitMediaToMuxerParameters();
103*b7c941bbSAndroid Build Coastguard Worker
104*b7c941bbSAndroid Build Coastguard Worker static const int STTS_TOLERANCE_US = 100;
105*b7c941bbSAndroid Build Coastguard Worker const char* mSrcPath;
106*b7c941bbSAndroid Build Coastguard Worker const char* mMediaType;
107*b7c941bbSAndroid Build Coastguard Worker int mTrackCount;
108*b7c941bbSAndroid Build Coastguard Worker std::vector<AMediaFormat*> mFormat;
109*b7c941bbSAndroid Build Coastguard Worker uint8_t* mBuffer;
110*b7c941bbSAndroid Build Coastguard Worker std::vector<std::vector<AMediaCodecBufferInfo*>> mBufferInfo;
111*b7c941bbSAndroid Build Coastguard Worker std::map<int, int> mInpIndexMap;
112*b7c941bbSAndroid Build Coastguard Worker std::vector<int> mTrackIdxOrder;
113*b7c941bbSAndroid Build Coastguard Worker int mFrameLimit;
114*b7c941bbSAndroid Build Coastguard Worker // combineMedias() uses local version of this variable
115*b7c941bbSAndroid Build Coastguard Worker std::map<int, int> mOutIndexMap;
116*b7c941bbSAndroid Build Coastguard Worker };
117*b7c941bbSAndroid Build Coastguard Worker
splitMediaToMuxerParameters()118*b7c941bbSAndroid Build Coastguard Worker void MuxerNativeTestHelper::splitMediaToMuxerParameters() {
119*b7c941bbSAndroid Build Coastguard Worker FILE* ifp = fopen(mSrcPath, "rbe");
120*b7c941bbSAndroid Build Coastguard Worker int fd;
121*b7c941bbSAndroid Build Coastguard Worker int fileSize;
122*b7c941bbSAndroid Build Coastguard Worker if (ifp) {
123*b7c941bbSAndroid Build Coastguard Worker struct stat buf {};
124*b7c941bbSAndroid Build Coastguard Worker stat(mSrcPath, &buf);
125*b7c941bbSAndroid Build Coastguard Worker fileSize = buf.st_size;
126*b7c941bbSAndroid Build Coastguard Worker fd = fileno(ifp);
127*b7c941bbSAndroid Build Coastguard Worker } else {
128*b7c941bbSAndroid Build Coastguard Worker return;
129*b7c941bbSAndroid Build Coastguard Worker }
130*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor* extractor = AMediaExtractor_new();
131*b7c941bbSAndroid Build Coastguard Worker if (extractor == nullptr) {
132*b7c941bbSAndroid Build Coastguard Worker fclose(ifp);
133*b7c941bbSAndroid Build Coastguard Worker return;
134*b7c941bbSAndroid Build Coastguard Worker }
135*b7c941bbSAndroid Build Coastguard Worker // Set up MediaExtractor to read from the source.
136*b7c941bbSAndroid Build Coastguard Worker media_status_t status = AMediaExtractor_setDataSourceFd(extractor, fd, 0, fileSize);
137*b7c941bbSAndroid Build Coastguard Worker if (AMEDIA_OK != status) {
138*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_delete(extractor);
139*b7c941bbSAndroid Build Coastguard Worker fclose(ifp);
140*b7c941bbSAndroid Build Coastguard Worker return;
141*b7c941bbSAndroid Build Coastguard Worker }
142*b7c941bbSAndroid Build Coastguard Worker
143*b7c941bbSAndroid Build Coastguard Worker // Set up MediaFormat
144*b7c941bbSAndroid Build Coastguard Worker int index = 0;
145*b7c941bbSAndroid Build Coastguard Worker for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
146*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_selectTrack(extractor, trackID);
147*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackID);
148*b7c941bbSAndroid Build Coastguard Worker if (mMediaType == nullptr) {
149*b7c941bbSAndroid Build Coastguard Worker mTrackCount++;
150*b7c941bbSAndroid Build Coastguard Worker mFormat.push_back(format);
151*b7c941bbSAndroid Build Coastguard Worker mInpIndexMap[trackID] = index++;
152*b7c941bbSAndroid Build Coastguard Worker } else {
153*b7c941bbSAndroid Build Coastguard Worker const char* mediaType;
154*b7c941bbSAndroid Build Coastguard Worker bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mediaType);
155*b7c941bbSAndroid Build Coastguard Worker if (hasKey && !strcmp(mediaType, mMediaType)) {
156*b7c941bbSAndroid Build Coastguard Worker mTrackCount++;
157*b7c941bbSAndroid Build Coastguard Worker mFormat.push_back(format);
158*b7c941bbSAndroid Build Coastguard Worker mInpIndexMap[trackID] = index;
159*b7c941bbSAndroid Build Coastguard Worker break;
160*b7c941bbSAndroid Build Coastguard Worker } else {
161*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_delete(format);
162*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_unselectTrack(extractor, trackID);
163*b7c941bbSAndroid Build Coastguard Worker }
164*b7c941bbSAndroid Build Coastguard Worker }
165*b7c941bbSAndroid Build Coastguard Worker }
166*b7c941bbSAndroid Build Coastguard Worker
167*b7c941bbSAndroid Build Coastguard Worker if (mTrackCount <= 0) {
168*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_delete(extractor);
169*b7c941bbSAndroid Build Coastguard Worker fclose(ifp);
170*b7c941bbSAndroid Build Coastguard Worker return;
171*b7c941bbSAndroid Build Coastguard Worker }
172*b7c941bbSAndroid Build Coastguard Worker
173*b7c941bbSAndroid Build Coastguard Worker // Set up location for elementary stream
174*b7c941bbSAndroid Build Coastguard Worker int bufferSize = ((fileSize + 127) >> 7) << 7;
175*b7c941bbSAndroid Build Coastguard Worker // Ideally, Sum of return values of extractor.readSampleData(...) should not exceed
176*b7c941bbSAndroid Build Coastguard Worker // source file size. But in case of Vorbis, aosp extractor appends an additional 4 bytes to
177*b7c941bbSAndroid Build Coastguard Worker // the data at every readSampleData() call. bufferSize <<= 1 empirically large enough to
178*b7c941bbSAndroid Build Coastguard Worker // hold the excess 4 bytes per read call
179*b7c941bbSAndroid Build Coastguard Worker bufferSize <<= 1;
180*b7c941bbSAndroid Build Coastguard Worker mBuffer = new uint8_t[bufferSize];
181*b7c941bbSAndroid Build Coastguard Worker if (mBuffer == nullptr) {
182*b7c941bbSAndroid Build Coastguard Worker mTrackCount = 0;
183*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_delete(extractor);
184*b7c941bbSAndroid Build Coastguard Worker fclose(ifp);
185*b7c941bbSAndroid Build Coastguard Worker return;
186*b7c941bbSAndroid Build Coastguard Worker }
187*b7c941bbSAndroid Build Coastguard Worker
188*b7c941bbSAndroid Build Coastguard Worker // Let MediaExtractor do its thing
189*b7c941bbSAndroid Build Coastguard Worker bool sawEOS = false;
190*b7c941bbSAndroid Build Coastguard Worker int frameCount = 0;
191*b7c941bbSAndroid Build Coastguard Worker int offset = 0;
192*b7c941bbSAndroid Build Coastguard Worker mBufferInfo.resize(mTrackCount);
193*b7c941bbSAndroid Build Coastguard Worker while (!sawEOS && frameCount < mFrameLimit) {
194*b7c941bbSAndroid Build Coastguard Worker auto* bufferInfo = new AMediaCodecBufferInfo();
195*b7c941bbSAndroid Build Coastguard Worker bufferInfo->offset = offset;
196*b7c941bbSAndroid Build Coastguard Worker bufferInfo->size =
197*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_readSampleData(extractor, mBuffer + offset, (bufferSize - offset));
198*b7c941bbSAndroid Build Coastguard Worker if (bufferInfo->size < 0) {
199*b7c941bbSAndroid Build Coastguard Worker sawEOS = true;
200*b7c941bbSAndroid Build Coastguard Worker } else {
201*b7c941bbSAndroid Build Coastguard Worker bufferInfo->presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
202*b7c941bbSAndroid Build Coastguard Worker bufferInfo->flags = AMediaExtractor_getSampleFlags(extractor);
203*b7c941bbSAndroid Build Coastguard Worker int trackID = AMediaExtractor_getSampleTrackIndex(extractor);
204*b7c941bbSAndroid Build Coastguard Worker mTrackIdxOrder.push_back(trackID);
205*b7c941bbSAndroid Build Coastguard Worker mBufferInfo[(mInpIndexMap.at(trackID))].push_back(bufferInfo);
206*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_advance(extractor);
207*b7c941bbSAndroid Build Coastguard Worker frameCount++;
208*b7c941bbSAndroid Build Coastguard Worker }
209*b7c941bbSAndroid Build Coastguard Worker offset += bufferInfo->size;
210*b7c941bbSAndroid Build Coastguard Worker }
211*b7c941bbSAndroid Build Coastguard Worker ALOGV("frameCount:%d", frameCount);
212*b7c941bbSAndroid Build Coastguard Worker AMediaExtractor_delete(extractor);
213*b7c941bbSAndroid Build Coastguard Worker fclose(ifp);
214*b7c941bbSAndroid Build Coastguard Worker }
215*b7c941bbSAndroid Build Coastguard Worker
registerTrack(AMediaMuxer * muxer)216*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::registerTrack(AMediaMuxer* muxer) {
217*b7c941bbSAndroid Build Coastguard Worker for (int trackID = 0; trackID < mTrackCount; trackID++) {
218*b7c941bbSAndroid Build Coastguard Worker int dstIndex = AMediaMuxer_addTrack(muxer, mFormat[trackID]);
219*b7c941bbSAndroid Build Coastguard Worker if (dstIndex < 0) return false;
220*b7c941bbSAndroid Build Coastguard Worker mOutIndexMap[trackID] = dstIndex;
221*b7c941bbSAndroid Build Coastguard Worker }
222*b7c941bbSAndroid Build Coastguard Worker return true;
223*b7c941bbSAndroid Build Coastguard Worker }
224*b7c941bbSAndroid Build Coastguard Worker
insertSampleData(AMediaMuxer * muxer)225*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::insertSampleData(AMediaMuxer* muxer) {
226*b7c941bbSAndroid Build Coastguard Worker // write all registered tracks in interleaved order
227*b7c941bbSAndroid Build Coastguard Worker int* frameCount = new int[mTrackCount]{0};
228*b7c941bbSAndroid Build Coastguard Worker for (int trackID : mTrackIdxOrder) {
229*b7c941bbSAndroid Build Coastguard Worker int index = mInpIndexMap.at(trackID);
230*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* info = mBufferInfo[index][frameCount[index]];
231*b7c941bbSAndroid Build Coastguard Worker if (AMediaMuxer_writeSampleData(muxer, mOutIndexMap.at(index), mBuffer, info) !=
232*b7c941bbSAndroid Build Coastguard Worker AMEDIA_OK) {
233*b7c941bbSAndroid Build Coastguard Worker delete[] frameCount;
234*b7c941bbSAndroid Build Coastguard Worker return false;
235*b7c941bbSAndroid Build Coastguard Worker }
236*b7c941bbSAndroid Build Coastguard Worker ALOGV("Track: %d Timestamp: %" PRId64 "", trackID, info->presentationTimeUs);
237*b7c941bbSAndroid Build Coastguard Worker frameCount[index]++;
238*b7c941bbSAndroid Build Coastguard Worker }
239*b7c941bbSAndroid Build Coastguard Worker delete[] frameCount;
240*b7c941bbSAndroid Build Coastguard Worker ALOGV("Total track samples %zu", mTrackIdxOrder.size());
241*b7c941bbSAndroid Build Coastguard Worker return true;
242*b7c941bbSAndroid Build Coastguard Worker }
243*b7c941bbSAndroid Build Coastguard Worker
writeAFewSamplesData(AMediaMuxer * muxer,uint32_t fromIndex,uint32_t toIndex)244*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::writeAFewSamplesData(AMediaMuxer* muxer, uint32_t fromIndex,
245*b7c941bbSAndroid Build Coastguard Worker uint32_t toIndex) {
246*b7c941bbSAndroid Build Coastguard Worker ALOGV("fromIndex:%u, toIndex:%u", fromIndex, toIndex);
247*b7c941bbSAndroid Build Coastguard Worker // write all registered tracks in interleaved order
248*b7c941bbSAndroid Build Coastguard Worker ALOGV("mTrackIdxOrder.size:%zu", mTrackIdxOrder.size());
249*b7c941bbSAndroid Build Coastguard Worker if (fromIndex > toIndex || toIndex >= mTrackIdxOrder.size()) {
250*b7c941bbSAndroid Build Coastguard Worker ALOGE("wrong index");
251*b7c941bbSAndroid Build Coastguard Worker return false;
252*b7c941bbSAndroid Build Coastguard Worker }
253*b7c941bbSAndroid Build Coastguard Worker int* frameCount = new int[mTrackCount]{0};
254*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < fromIndex; ++i) {
255*b7c941bbSAndroid Build Coastguard Worker ++frameCount[mInpIndexMap.at(mTrackIdxOrder[i])];
256*b7c941bbSAndroid Build Coastguard Worker }
257*b7c941bbSAndroid Build Coastguard Worker ALOGV("Initial samples skipped:");
258*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < mTrackCount; ++i) {
259*b7c941bbSAndroid Build Coastguard Worker ALOGV("i:%d:%d", i, frameCount[i]);
260*b7c941bbSAndroid Build Coastguard Worker }
261*b7c941bbSAndroid Build Coastguard Worker for (int i = fromIndex; i <= toIndex; ++i) {
262*b7c941bbSAndroid Build Coastguard Worker int trackID = mTrackIdxOrder[i];
263*b7c941bbSAndroid Build Coastguard Worker int trackIndex = mInpIndexMap.at(trackID);
264*b7c941bbSAndroid Build Coastguard Worker ALOGV("trackID:%d, trackIndex:%d, frameCount:%d", trackID, trackIndex,
265*b7c941bbSAndroid Build Coastguard Worker frameCount[trackIndex]);
266*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* info = mBufferInfo[trackIndex][frameCount[trackIndex]];
267*b7c941bbSAndroid Build Coastguard Worker ALOGV("Got info offset:%d, size:%d", info->offset, info->size);
268*b7c941bbSAndroid Build Coastguard Worker if (AMediaMuxer_writeSampleData(muxer, mOutIndexMap.at(trackIndex), mBuffer, info) !=
269*b7c941bbSAndroid Build Coastguard Worker AMEDIA_OK) {
270*b7c941bbSAndroid Build Coastguard Worker delete[] frameCount;
271*b7c941bbSAndroid Build Coastguard Worker return false;
272*b7c941bbSAndroid Build Coastguard Worker }
273*b7c941bbSAndroid Build Coastguard Worker ALOGV("Track: %d Timestamp: %" PRId64 "", trackID, info->presentationTimeUs);
274*b7c941bbSAndroid Build Coastguard Worker ++frameCount[trackIndex];
275*b7c941bbSAndroid Build Coastguard Worker }
276*b7c941bbSAndroid Build Coastguard Worker ALOGV("Last sample counts:");
277*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < mTrackCount; ++i) {
278*b7c941bbSAndroid Build Coastguard Worker ALOGV("i:%d", frameCount[i]);
279*b7c941bbSAndroid Build Coastguard Worker }
280*b7c941bbSAndroid Build Coastguard Worker delete[] frameCount;
281*b7c941bbSAndroid Build Coastguard Worker return true;
282*b7c941bbSAndroid Build Coastguard Worker }
283*b7c941bbSAndroid Build Coastguard Worker
writeAFewSamplesDataFromTime(AMediaMuxer * muxer,int64_t * fromTime,uint32_t numSamples,bool lastSplit)284*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::writeAFewSamplesDataFromTime(AMediaMuxer* muxer, int64_t* fromTime,
285*b7c941bbSAndroid Build Coastguard Worker uint32_t numSamples, bool lastSplit) {
286*b7c941bbSAndroid Build Coastguard Worker for (int tc = 0; tc < mTrackCount; ++tc) {
287*b7c941bbSAndroid Build Coastguard Worker ALOGV("fromTime[%d]:%lld", tc, (long long)fromTime[tc]);
288*b7c941bbSAndroid Build Coastguard Worker }
289*b7c941bbSAndroid Build Coastguard Worker ALOGV("numSamples:%u", numSamples);
290*b7c941bbSAndroid Build Coastguard Worker uint32_t samplesWritten = 0;
291*b7c941bbSAndroid Build Coastguard Worker uint32_t i = 0;
292*b7c941bbSAndroid Build Coastguard Worker int* frameCount = new int[mTrackCount]{0};
293*b7c941bbSAndroid Build Coastguard Worker do {
294*b7c941bbSAndroid Build Coastguard Worker int trackID = mTrackIdxOrder[i++];
295*b7c941bbSAndroid Build Coastguard Worker int trackIndex = mInpIndexMap.at(trackID);
296*b7c941bbSAndroid Build Coastguard Worker ALOGV("trackID:%d, trackIndex:%d, frameCount:%d", trackID, trackIndex,
297*b7c941bbSAndroid Build Coastguard Worker frameCount[trackIndex]);
298*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* info = mBufferInfo[trackIndex][frameCount[trackIndex]];
299*b7c941bbSAndroid Build Coastguard Worker ++frameCount[trackIndex];
300*b7c941bbSAndroid Build Coastguard Worker ALOGV("Got info offset:%d, size:%d, PTS:%" PRId64 "", info->offset, info->size,
301*b7c941bbSAndroid Build Coastguard Worker info->presentationTimeUs);
302*b7c941bbSAndroid Build Coastguard Worker if (info->presentationTimeUs < fromTime[trackID]) {
303*b7c941bbSAndroid Build Coastguard Worker ALOGV("skipped");
304*b7c941bbSAndroid Build Coastguard Worker continue;
305*b7c941bbSAndroid Build Coastguard Worker }
306*b7c941bbSAndroid Build Coastguard Worker if (AMediaMuxer_writeSampleData(muxer, mOutIndexMap.at(trackIndex), mBuffer, info) !=
307*b7c941bbSAndroid Build Coastguard Worker AMEDIA_OK) {
308*b7c941bbSAndroid Build Coastguard Worker delete[] frameCount;
309*b7c941bbSAndroid Build Coastguard Worker return false;
310*b7c941bbSAndroid Build Coastguard Worker } else {
311*b7c941bbSAndroid Build Coastguard Worker ++samplesWritten;
312*b7c941bbSAndroid Build Coastguard Worker }
313*b7c941bbSAndroid Build Coastguard Worker } while ((lastSplit) ? (i < mTrackIdxOrder.size())
314*b7c941bbSAndroid Build Coastguard Worker : ((samplesWritten < numSamples) && (i < mTrackIdxOrder.size())));
315*b7c941bbSAndroid Build Coastguard Worker ALOGV("samplesWritten:%u", samplesWritten);
316*b7c941bbSAndroid Build Coastguard Worker
317*b7c941bbSAndroid Build Coastguard Worker delete[] frameCount;
318*b7c941bbSAndroid Build Coastguard Worker return true;
319*b7c941bbSAndroid Build Coastguard Worker }
320*b7c941bbSAndroid Build Coastguard Worker
muxMedia(AMediaMuxer * muxer)321*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::muxMedia(AMediaMuxer* muxer) {
322*b7c941bbSAndroid Build Coastguard Worker return (registerTrack(muxer) && (AMediaMuxer_start(muxer) == AMEDIA_OK) &&
323*b7c941bbSAndroid Build Coastguard Worker insertSampleData(muxer) && (AMediaMuxer_stop(muxer) == AMEDIA_OK));
324*b7c941bbSAndroid Build Coastguard Worker }
325*b7c941bbSAndroid Build Coastguard Worker
appendMedia(AMediaMuxer * muxer,uint32_t fromIndex,uint32_t toIndex)326*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::appendMedia(AMediaMuxer *muxer, uint32_t fromIndex, uint32_t toIndex) {
327*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
328*b7c941bbSAndroid Build Coastguard Worker ALOGV("fromIndex:%u, toIndex:%u", fromIndex, toIndex);
329*b7c941bbSAndroid Build Coastguard Worker if (fromIndex == 0) {
330*b7c941bbSAndroid Build Coastguard Worker registerTrack(muxer);
331*b7c941bbSAndroid Build Coastguard Worker } else {
332*b7c941bbSAndroid Build Coastguard Worker size_t trackCount = AMediaMuxer_getTrackCount(muxer);
333*b7c941bbSAndroid Build Coastguard Worker ALOGV("appendMedia:trackCount:%zu", trackCount);
334*b7c941bbSAndroid Build Coastguard Worker for(size_t i = 0; i < trackCount; ++i) {
335*b7c941bbSAndroid Build Coastguard Worker ALOGV("track i:%zu", i);
336*b7c941bbSAndroid Build Coastguard Worker ALOGV("%s", AMediaFormat_toString(AMediaMuxer_getTrackFormat(muxer, i)));
337*b7c941bbSAndroid Build Coastguard Worker ALOGV("%s", AMediaFormat_toString(mFormat[i]));
338*b7c941bbSAndroid Build Coastguard Worker for(size_t j = 0; j < mFormat.size(); ++j) {
339*b7c941bbSAndroid Build Coastguard Worker const char* thatMediaType = nullptr;
340*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(AMediaMuxer_getTrackFormat(muxer, i),
341*b7c941bbSAndroid Build Coastguard Worker AMEDIAFORMAT_KEY_MIME, &thatMediaType);
342*b7c941bbSAndroid Build Coastguard Worker const char* thisMediaType = nullptr;
343*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(mFormat[j], AMEDIAFORMAT_KEY_MIME, &thisMediaType);
344*b7c941bbSAndroid Build Coastguard Worker ALOGV("strlen(thisMediaType)%zu", strlen(thisMediaType));
345*b7c941bbSAndroid Build Coastguard Worker if (strcmp(thatMediaType, thisMediaType) == 0) {
346*b7c941bbSAndroid Build Coastguard Worker ALOGV("appendMedia:i:%zu, j:%zu", i, j);
347*b7c941bbSAndroid Build Coastguard Worker mOutIndexMap[j]=i;
348*b7c941bbSAndroid Build Coastguard Worker }
349*b7c941bbSAndroid Build Coastguard Worker }
350*b7c941bbSAndroid Build Coastguard Worker }
351*b7c941bbSAndroid Build Coastguard Worker }
352*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_start(muxer);
353*b7c941bbSAndroid Build Coastguard Worker bool res = writeAFewSamplesData(muxer, fromIndex, toIndex);
354*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_stop(muxer);
355*b7c941bbSAndroid Build Coastguard Worker return res;
356*b7c941bbSAndroid Build Coastguard Worker } else {
357*b7c941bbSAndroid Build Coastguard Worker return false;
358*b7c941bbSAndroid Build Coastguard Worker }
359*b7c941bbSAndroid Build Coastguard Worker }
360*b7c941bbSAndroid Build Coastguard Worker
appendMediaFromTime(AMediaMuxer * muxer,int64_t * appendFromTime,uint32_t numSamples,bool lastSplit)361*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::appendMediaFromTime(AMediaMuxer *muxer, int64_t *appendFromTime,
362*b7c941bbSAndroid Build Coastguard Worker uint32_t numSamples, bool lastSplit) {
363*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
364*b7c941bbSAndroid Build Coastguard Worker size_t trackCount = AMediaMuxer_getTrackCount(muxer);
365*b7c941bbSAndroid Build Coastguard Worker ALOGV("appendMediaFromTime:trackCount:%zu", trackCount);
366*b7c941bbSAndroid Build Coastguard Worker for(size_t i = 0; i < trackCount; ++i) {
367*b7c941bbSAndroid Build Coastguard Worker ALOGV("track i:%zu", i);
368*b7c941bbSAndroid Build Coastguard Worker ALOGV("%s", AMediaFormat_toString(AMediaMuxer_getTrackFormat(muxer, i)));
369*b7c941bbSAndroid Build Coastguard Worker ALOGV("%s", AMediaFormat_toString(mFormat[i]));
370*b7c941bbSAndroid Build Coastguard Worker for(size_t j = 0; j < mFormat.size(); ++j) {
371*b7c941bbSAndroid Build Coastguard Worker const char* thatMediaType = nullptr;
372*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(AMediaMuxer_getTrackFormat(muxer, i),
373*b7c941bbSAndroid Build Coastguard Worker AMEDIAFORMAT_KEY_MIME, &thatMediaType);
374*b7c941bbSAndroid Build Coastguard Worker const char* thisMediaType = nullptr;
375*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(mFormat[j], AMEDIAFORMAT_KEY_MIME, &thisMediaType);
376*b7c941bbSAndroid Build Coastguard Worker ALOGV("strlen(thisMediaType)%zu", strlen(thisMediaType));
377*b7c941bbSAndroid Build Coastguard Worker if (strcmp(thatMediaType, thisMediaType) == 0) {
378*b7c941bbSAndroid Build Coastguard Worker ALOGV("appendMediaFromTime:i:%zu, j:%zu", i, j);
379*b7c941bbSAndroid Build Coastguard Worker mOutIndexMap[j]=i;
380*b7c941bbSAndroid Build Coastguard Worker }
381*b7c941bbSAndroid Build Coastguard Worker }
382*b7c941bbSAndroid Build Coastguard Worker }
383*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_start(muxer);
384*b7c941bbSAndroid Build Coastguard Worker bool res = writeAFewSamplesDataFromTime(muxer, appendFromTime, numSamples, lastSplit);
385*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_stop(muxer);
386*b7c941bbSAndroid Build Coastguard Worker return res;
387*b7c941bbSAndroid Build Coastguard Worker } else {
388*b7c941bbSAndroid Build Coastguard Worker return false;
389*b7c941bbSAndroid Build Coastguard Worker }
390*b7c941bbSAndroid Build Coastguard Worker }
combineMedias(AMediaMuxer * muxer,MuxerNativeTestHelper * that,const int * repeater)391*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::combineMedias(AMediaMuxer* muxer, MuxerNativeTestHelper* that,
392*b7c941bbSAndroid Build Coastguard Worker const int* repeater) {
393*b7c941bbSAndroid Build Coastguard Worker if (that == nullptr) return false;
394*b7c941bbSAndroid Build Coastguard Worker if (repeater == nullptr) return false;
395*b7c941bbSAndroid Build Coastguard Worker
396*b7c941bbSAndroid Build Coastguard Worker // register tracks
397*b7c941bbSAndroid Build Coastguard Worker int totalTracksToAdd = repeater[0] * this->mTrackCount + repeater[1] * that->mTrackCount;
398*b7c941bbSAndroid Build Coastguard Worker int outIndexMap[totalTracksToAdd];
399*b7c941bbSAndroid Build Coastguard Worker MuxerNativeTestHelper* group[2]{this, that};
400*b7c941bbSAndroid Build Coastguard Worker for (int k = 0, idx = 0; k < 2; k++) {
401*b7c941bbSAndroid Build Coastguard Worker for (int j = 0; j < repeater[k]; j++) {
402*b7c941bbSAndroid Build Coastguard Worker for (AMediaFormat* format : group[k]->mFormat) {
403*b7c941bbSAndroid Build Coastguard Worker int dstIndex = AMediaMuxer_addTrack(muxer, format);
404*b7c941bbSAndroid Build Coastguard Worker if (dstIndex < 0) return false;
405*b7c941bbSAndroid Build Coastguard Worker outIndexMap[idx++] = dstIndex;
406*b7c941bbSAndroid Build Coastguard Worker }
407*b7c941bbSAndroid Build Coastguard Worker }
408*b7c941bbSAndroid Build Coastguard Worker }
409*b7c941bbSAndroid Build Coastguard Worker // start
410*b7c941bbSAndroid Build Coastguard Worker if (AMediaMuxer_start(muxer) != AMEDIA_OK) return false;
411*b7c941bbSAndroid Build Coastguard Worker // write sample data
412*b7c941bbSAndroid Build Coastguard Worker // write all registered tracks in planar order viz all samples of a track A then all
413*b7c941bbSAndroid Build Coastguard Worker // samples of track B, ...
414*b7c941bbSAndroid Build Coastguard Worker for (int k = 0, idx = 0; k < 2; k++) {
415*b7c941bbSAndroid Build Coastguard Worker for (int j = 0; j < repeater[k]; j++) {
416*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < group[k]->mTrackCount; i++) {
417*b7c941bbSAndroid Build Coastguard Worker for (int p = 0; p < group[k]->mBufferInfo[i].size(); p++) {
418*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* info = group[k]->mBufferInfo[i][p];
419*b7c941bbSAndroid Build Coastguard Worker if (AMediaMuxer_writeSampleData(muxer, outIndexMap[idx], group[k]->mBuffer,
420*b7c941bbSAndroid Build Coastguard Worker info) != AMEDIA_OK) {
421*b7c941bbSAndroid Build Coastguard Worker return false;
422*b7c941bbSAndroid Build Coastguard Worker }
423*b7c941bbSAndroid Build Coastguard Worker ALOGV("Track: %d Timestamp: %" PRId64 "", outIndexMap[idx],
424*b7c941bbSAndroid Build Coastguard Worker info->presentationTimeUs);
425*b7c941bbSAndroid Build Coastguard Worker }
426*b7c941bbSAndroid Build Coastguard Worker idx++;
427*b7c941bbSAndroid Build Coastguard Worker }
428*b7c941bbSAndroid Build Coastguard Worker }
429*b7c941bbSAndroid Build Coastguard Worker }
430*b7c941bbSAndroid Build Coastguard Worker // stop
431*b7c941bbSAndroid Build Coastguard Worker return (AMediaMuxer_stop(muxer) == AMEDIA_OK);
432*b7c941bbSAndroid Build Coastguard Worker }
433*b7c941bbSAndroid Build Coastguard Worker
434*b7c941bbSAndroid Build Coastguard Worker // returns true if 'this' stream is a subset of 'that'. That is all tracks in current media
435*b7c941bbSAndroid Build Coastguard Worker // stream are present in ref media stream
isSubsetOf(MuxerNativeTestHelper * that)436*b7c941bbSAndroid Build Coastguard Worker bool MuxerNativeTestHelper::isSubsetOf(MuxerNativeTestHelper* that) {
437*b7c941bbSAndroid Build Coastguard Worker if (this == that) return true;
438*b7c941bbSAndroid Build Coastguard Worker if (that == nullptr) return false;
439*b7c941bbSAndroid Build Coastguard Worker
440*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < mTrackCount; i++) {
441*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* thisFormat = mFormat[i];
442*b7c941bbSAndroid Build Coastguard Worker const char* thisMediaType = nullptr;
443*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(thisFormat, AMEDIAFORMAT_KEY_MIME, &thisMediaType);
444*b7c941bbSAndroid Build Coastguard Worker int tolerance = !strncmp(thisMediaType, "video/", strlen("video/")) ? STTS_TOLERANCE_US : 0;
445*b7c941bbSAndroid Build Coastguard Worker tolerance += 1; // rounding error
446*b7c941bbSAndroid Build Coastguard Worker int j = 0;
447*b7c941bbSAndroid Build Coastguard Worker for (; j < that->mTrackCount; j++) {
448*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* thatFormat = that->mFormat[j];
449*b7c941bbSAndroid Build Coastguard Worker const char* thatMediaType = nullptr;
450*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(thatFormat, AMEDIAFORMAT_KEY_MIME, &thatMediaType);
451*b7c941bbSAndroid Build Coastguard Worker if (thisMediaType != nullptr && thatMediaType != nullptr &&
452*b7c941bbSAndroid Build Coastguard Worker !strcmp(thisMediaType, thatMediaType)) {
453*b7c941bbSAndroid Build Coastguard Worker if (!isFormatSimilar(thisFormat, thatFormat)) continue;
454*b7c941bbSAndroid Build Coastguard Worker if (mBufferInfo[i].size() <= that->mBufferInfo[j].size()) {
455*b7c941bbSAndroid Build Coastguard Worker int tolerance = !strncmp(thisMediaType, "video/", strlen("video/"))
456*b7c941bbSAndroid Build Coastguard Worker ? STTS_TOLERANCE_US
457*b7c941bbSAndroid Build Coastguard Worker : 0;
458*b7c941bbSAndroid Build Coastguard Worker tolerance += 1; // rounding error
459*b7c941bbSAndroid Build Coastguard Worker int k = 0;
460*b7c941bbSAndroid Build Coastguard Worker for (; k < mBufferInfo[i].size(); k++) {
461*b7c941bbSAndroid Build Coastguard Worker ALOGV("k:%d", k);
462*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* thisInfo = mBufferInfo[i][k];
463*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* thatInfo = that->mBufferInfo[j][k];
464*b7c941bbSAndroid Build Coastguard Worker if (thisInfo->flags != thatInfo->flags) {
465*b7c941bbSAndroid Build Coastguard Worker ALOGD("flags this:%u, that:%u", thisInfo->flags, thatInfo->flags);
466*b7c941bbSAndroid Build Coastguard Worker break;
467*b7c941bbSAndroid Build Coastguard Worker }
468*b7c941bbSAndroid Build Coastguard Worker if (thisInfo->size != thatInfo->size) {
469*b7c941bbSAndroid Build Coastguard Worker ALOGD("size this:%d, that:%d", thisInfo->size, thatInfo->size);
470*b7c941bbSAndroid Build Coastguard Worker break;
471*b7c941bbSAndroid Build Coastguard Worker } else if (memcmp(mBuffer + thisInfo->offset,
472*b7c941bbSAndroid Build Coastguard Worker that->mBuffer + thatInfo->offset, thisInfo->size)) {
473*b7c941bbSAndroid Build Coastguard Worker ALOGD("memcmp failed");
474*b7c941bbSAndroid Build Coastguard Worker break;
475*b7c941bbSAndroid Build Coastguard Worker }
476*b7c941bbSAndroid Build Coastguard Worker if (abs(thisInfo->presentationTimeUs - thatInfo->presentationTimeUs) >
477*b7c941bbSAndroid Build Coastguard Worker tolerance) {
478*b7c941bbSAndroid Build Coastguard Worker ALOGD("time this:%lld, that:%lld",
479*b7c941bbSAndroid Build Coastguard Worker (long long)thisInfo->presentationTimeUs,
480*b7c941bbSAndroid Build Coastguard Worker (long long)thatInfo->presentationTimeUs);
481*b7c941bbSAndroid Build Coastguard Worker break;
482*b7c941bbSAndroid Build Coastguard Worker }
483*b7c941bbSAndroid Build Coastguard Worker }
484*b7c941bbSAndroid Build Coastguard Worker if (k == mBufferInfo[i].size()) break;
485*b7c941bbSAndroid Build Coastguard Worker }
486*b7c941bbSAndroid Build Coastguard Worker }
487*b7c941bbSAndroid Build Coastguard Worker }
488*b7c941bbSAndroid Build Coastguard Worker if (j == that->mTrackCount) {
489*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(thisFormat, AMEDIAFORMAT_KEY_MIME, &thisMediaType);
490*b7c941bbSAndroid Build Coastguard Worker ALOGV("For media type %s, Couldn't find a match", thisMediaType);
491*b7c941bbSAndroid Build Coastguard Worker return false;
492*b7c941bbSAndroid Build Coastguard Worker }
493*b7c941bbSAndroid Build Coastguard Worker }
494*b7c941bbSAndroid Build Coastguard Worker return true;
495*b7c941bbSAndroid Build Coastguard Worker }
496*b7c941bbSAndroid Build Coastguard Worker
offsetTimeStamp(int64_t tsAudioOffsetUs,int64_t tsVideoOffsetUs,int sampleOffset)497*b7c941bbSAndroid Build Coastguard Worker void MuxerNativeTestHelper::offsetTimeStamp(int64_t tsAudioOffsetUs, int64_t tsVideoOffsetUs,
498*b7c941bbSAndroid Build Coastguard Worker int sampleOffset) {
499*b7c941bbSAndroid Build Coastguard Worker // offset pts of samples from index sampleOffset till the end by tsOffset for each audio and
500*b7c941bbSAndroid Build Coastguard Worker // video track
501*b7c941bbSAndroid Build Coastguard Worker for (int trackID = 0; trackID < mTrackCount; trackID++) {
502*b7c941bbSAndroid Build Coastguard Worker int64_t tsOffsetUs = 0;
503*b7c941bbSAndroid Build Coastguard Worker const char* thisMediaType = nullptr;
504*b7c941bbSAndroid Build Coastguard Worker AMediaFormat_getString(mFormat[trackID], AMEDIAFORMAT_KEY_MIME, &thisMediaType);
505*b7c941bbSAndroid Build Coastguard Worker if (thisMediaType != nullptr) {
506*b7c941bbSAndroid Build Coastguard Worker if (strncmp(thisMediaType, "video/", strlen("video/")) == 0) {
507*b7c941bbSAndroid Build Coastguard Worker tsOffsetUs = tsVideoOffsetUs;
508*b7c941bbSAndroid Build Coastguard Worker } else if (strncmp(thisMediaType, "audio/", strlen("audio/")) == 0) {
509*b7c941bbSAndroid Build Coastguard Worker tsOffsetUs = tsAudioOffsetUs;
510*b7c941bbSAndroid Build Coastguard Worker }
511*b7c941bbSAndroid Build Coastguard Worker for (int i = sampleOffset; i < mBufferInfo[trackID].size(); i++) {
512*b7c941bbSAndroid Build Coastguard Worker AMediaCodecBufferInfo* info = mBufferInfo[trackID][i];
513*b7c941bbSAndroid Build Coastguard Worker info->presentationTimeUs += tsOffsetUs;
514*b7c941bbSAndroid Build Coastguard Worker }
515*b7c941bbSAndroid Build Coastguard Worker }
516*b7c941bbSAndroid Build Coastguard Worker }
517*b7c941bbSAndroid Build Coastguard Worker }
518*b7c941bbSAndroid Build Coastguard Worker
isCodecContainerPairValid(OutputFormat format,const char * mediaType)519*b7c941bbSAndroid Build Coastguard Worker static bool isCodecContainerPairValid(OutputFormat format, const char* mediaType) {
520*b7c941bbSAndroid Build Coastguard Worker static const std::map<OutputFormat, std::vector<const char*>> codecListforType = {
521*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4,
522*b7c941bbSAndroid Build Coastguard Worker {AMEDIA_MIMETYPE_VIDEO_MPEG4, AMEDIA_MIMETYPE_VIDEO_H263, AMEDIA_MIMETYPE_VIDEO_AVC,
523*b7c941bbSAndroid Build Coastguard Worker AMEDIA_MIMETYPE_VIDEO_HEVC, AMEDIA_MIMETYPE_AUDIO_AAC}},
524*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_WEBM,
525*b7c941bbSAndroid Build Coastguard Worker {AMEDIA_MIMETYPE_VIDEO_VP8, AMEDIA_MIMETYPE_VIDEO_VP9, AMEDIA_MIMETYPE_AUDIO_VORBIS,
526*b7c941bbSAndroid Build Coastguard Worker AMEDIA_MIMETYPE_AUDIO_OPUS}},
527*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP,
528*b7c941bbSAndroid Build Coastguard Worker {AMEDIA_MIMETYPE_VIDEO_MPEG4, AMEDIA_MIMETYPE_VIDEO_H263, AMEDIA_MIMETYPE_VIDEO_AVC,
529*b7c941bbSAndroid Build Coastguard Worker AMEDIA_MIMETYPE_AUDIO_AAC, AMEDIA_MIMETYPE_AUDIO_AMR_NB,
530*b7c941bbSAndroid Build Coastguard Worker AMEDIA_MIMETYPE_AUDIO_AMR_WB}},
531*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_OGG, {AMEDIA_MIMETYPE_AUDIO_OPUS}},
532*b7c941bbSAndroid Build Coastguard Worker };
533*b7c941bbSAndroid Build Coastguard Worker
534*b7c941bbSAndroid Build Coastguard Worker if (format == AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4 &&
535*b7c941bbSAndroid Build Coastguard Worker strncmp(mediaType, "application/", strlen("application/")) == 0)
536*b7c941bbSAndroid Build Coastguard Worker return true;
537*b7c941bbSAndroid Build Coastguard Worker
538*b7c941bbSAndroid Build Coastguard Worker auto it = codecListforType.find(format);
539*b7c941bbSAndroid Build Coastguard Worker if (it != codecListforType.end())
540*b7c941bbSAndroid Build Coastguard Worker for (auto it2 : it->second)
541*b7c941bbSAndroid Build Coastguard Worker if (strcmp(it2, mediaType) == 0) return true;
542*b7c941bbSAndroid Build Coastguard Worker
543*b7c941bbSAndroid Build Coastguard Worker return false;
544*b7c941bbSAndroid Build Coastguard Worker }
545*b7c941bbSAndroid Build Coastguard Worker
nativeTestSetLocation(JNIEnv * env,jobject,jint jformat,jstring jsrcPath,jstring jdstPath)546*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSetLocation(JNIEnv* env, jobject, jint jformat, jstring jsrcPath,
547*b7c941bbSAndroid Build Coastguard Worker jstring jdstPath) {
548*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
549*b7c941bbSAndroid Build Coastguard Worker bool isGeoDataSupported;
550*b7c941bbSAndroid Build Coastguard Worker const float atlanticLat = 14.59f;
551*b7c941bbSAndroid Build Coastguard Worker const float atlanticLong = 28.67f;
552*b7c941bbSAndroid Build Coastguard Worker const float tooFarNorth = 90.5f;
553*b7c941bbSAndroid Build Coastguard Worker const float tooFarWest = -180.5f;
554*b7c941bbSAndroid Build Coastguard Worker const float tooFarSouth = -90.5f;
555*b7c941bbSAndroid Build Coastguard Worker const float tooFarEast = 180.5f;
556*b7c941bbSAndroid Build Coastguard Worker const float annapurnaLat = 28.59f;
557*b7c941bbSAndroid Build Coastguard Worker const float annapurnaLong = 83.82f;
558*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
559*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "wbe+");
560*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
561*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
562*b7c941bbSAndroid Build Coastguard Worker media_status_t status = AMediaMuxer_setLocation(muxer, tooFarNorth, atlanticLong);
563*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
564*b7c941bbSAndroid Build Coastguard Worker isPass = false;
565*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds on bad args: (%f, %f)", tooFarNorth, atlanticLong);
566*b7c941bbSAndroid Build Coastguard Worker }
567*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, tooFarSouth, atlanticLong);
568*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
569*b7c941bbSAndroid Build Coastguard Worker isPass = false;
570*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds on bad args: (%f, %f)", tooFarSouth, atlanticLong);
571*b7c941bbSAndroid Build Coastguard Worker }
572*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, atlanticLat, tooFarWest);
573*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
574*b7c941bbSAndroid Build Coastguard Worker isPass = false;
575*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds on bad args: (%f, %f)", atlanticLat, tooFarWest);
576*b7c941bbSAndroid Build Coastguard Worker }
577*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, atlanticLat, tooFarEast);
578*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
579*b7c941bbSAndroid Build Coastguard Worker isPass = false;
580*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds on bad args: (%f, %f)", atlanticLat, tooFarEast);
581*b7c941bbSAndroid Build Coastguard Worker }
582*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, tooFarNorth, tooFarWest);
583*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
584*b7c941bbSAndroid Build Coastguard Worker isPass = false;
585*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds on bad args: (%f, %f)", tooFarNorth, tooFarWest);
586*b7c941bbSAndroid Build Coastguard Worker }
587*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, atlanticLat, atlanticLong);
588*b7c941bbSAndroid Build Coastguard Worker isGeoDataSupported = (status == AMEDIA_OK);
589*b7c941bbSAndroid Build Coastguard Worker if (isGeoDataSupported) {
590*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, annapurnaLat, annapurnaLong);
591*b7c941bbSAndroid Build Coastguard Worker if (status != AMEDIA_OK) {
592*b7c941bbSAndroid Build Coastguard Worker isPass = false;
593*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation fails on args: (%f, %f)", annapurnaLat, annapurnaLong);
594*b7c941bbSAndroid Build Coastguard Worker }
595*b7c941bbSAndroid Build Coastguard Worker } else {
596*b7c941bbSAndroid Build Coastguard Worker isPass &= ((OutputFormat)jformat != AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4 &&
597*b7c941bbSAndroid Build Coastguard Worker (OutputFormat)jformat != AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
598*b7c941bbSAndroid Build Coastguard Worker }
599*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
600*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
601*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->registerTrack(muxer) && AMediaMuxer_start(muxer) == AMEDIA_OK) {
602*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, atlanticLat, atlanticLong);
603*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
604*b7c941bbSAndroid Build Coastguard Worker isPass = false;
605*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds after starting the muxer");
606*b7c941bbSAndroid Build Coastguard Worker }
607*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->insertSampleData(muxer) && AMediaMuxer_stop(muxer) == AMEDIA_OK) {
608*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setLocation(muxer, atlanticLat, atlanticLong);
609*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
610*b7c941bbSAndroid Build Coastguard Worker isPass = false;
611*b7c941bbSAndroid Build Coastguard Worker ALOGE("setLocation succeeds after stopping the muxer");
612*b7c941bbSAndroid Build Coastguard Worker }
613*b7c941bbSAndroid Build Coastguard Worker } else {
614*b7c941bbSAndroid Build Coastguard Worker isPass = false;
615*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to writeSampleData or stop muxer");
616*b7c941bbSAndroid Build Coastguard Worker }
617*b7c941bbSAndroid Build Coastguard Worker } else {
618*b7c941bbSAndroid Build Coastguard Worker isPass = false;
619*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to addTrack or start muxer");
620*b7c941bbSAndroid Build Coastguard Worker }
621*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
622*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
623*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
624*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
625*b7c941bbSAndroid Build Coastguard Worker } else {
626*b7c941bbSAndroid Build Coastguard Worker isPass = false;
627*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
628*b7c941bbSAndroid Build Coastguard Worker }
629*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
630*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
631*b7c941bbSAndroid Build Coastguard Worker }
632*b7c941bbSAndroid Build Coastguard Worker
633*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4
634*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP
635*b7c941bbSAndroid Build Coastguard Worker //
nativeTestSetOrientationHint(JNIEnv * env,jobject,jint jformat,jstring jsrcPath,jstring jdstPath)636*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSetOrientationHint(JNIEnv* env, jobject, jint jformat, jstring jsrcPath,
637*b7c941bbSAndroid Build Coastguard Worker jstring jdstPath) {
638*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
639*b7c941bbSAndroid Build Coastguard Worker bool isOrientationSupported;
640*b7c941bbSAndroid Build Coastguard Worker const int badRotation[] = {360, 45, -90};
641*b7c941bbSAndroid Build Coastguard Worker const int oldRotation = 90;
642*b7c941bbSAndroid Build Coastguard Worker const int currRotation = 180;
643*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
644*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "wbe+");
645*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
646*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
647*b7c941bbSAndroid Build Coastguard Worker media_status_t status;
648*b7c941bbSAndroid Build Coastguard Worker for (int degrees : badRotation) {
649*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setOrientationHint(muxer, degrees);
650*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
651*b7c941bbSAndroid Build Coastguard Worker isPass = false;
652*b7c941bbSAndroid Build Coastguard Worker ALOGE("setOrientationHint succeeds on bad args: %d", degrees);
653*b7c941bbSAndroid Build Coastguard Worker }
654*b7c941bbSAndroid Build Coastguard Worker }
655*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setOrientationHint(muxer, oldRotation);
656*b7c941bbSAndroid Build Coastguard Worker isOrientationSupported = (status == AMEDIA_OK);
657*b7c941bbSAndroid Build Coastguard Worker if (isOrientationSupported) {
658*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setOrientationHint(muxer, currRotation);
659*b7c941bbSAndroid Build Coastguard Worker if (status != AMEDIA_OK) {
660*b7c941bbSAndroid Build Coastguard Worker isPass = false;
661*b7c941bbSAndroid Build Coastguard Worker ALOGE("setOrientationHint fails on args: %d", currRotation);
662*b7c941bbSAndroid Build Coastguard Worker }
663*b7c941bbSAndroid Build Coastguard Worker } else {
664*b7c941bbSAndroid Build Coastguard Worker isPass &= ((OutputFormat)jformat != AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4 &&
665*b7c941bbSAndroid Build Coastguard Worker (OutputFormat)jformat != AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
666*b7c941bbSAndroid Build Coastguard Worker }
667*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
668*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
669*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->registerTrack(muxer) && AMediaMuxer_start(muxer) == AMEDIA_OK) {
670*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setOrientationHint(muxer, currRotation);
671*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
672*b7c941bbSAndroid Build Coastguard Worker isPass = false;
673*b7c941bbSAndroid Build Coastguard Worker ALOGE("setOrientationHint succeeds after starting the muxer");
674*b7c941bbSAndroid Build Coastguard Worker }
675*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->insertSampleData(muxer) && AMediaMuxer_stop(muxer) == AMEDIA_OK) {
676*b7c941bbSAndroid Build Coastguard Worker status = AMediaMuxer_setOrientationHint(muxer, currRotation);
677*b7c941bbSAndroid Build Coastguard Worker if (status == AMEDIA_OK) {
678*b7c941bbSAndroid Build Coastguard Worker isPass = false;
679*b7c941bbSAndroid Build Coastguard Worker ALOGE("setOrientationHint succeeds after stopping the muxer");
680*b7c941bbSAndroid Build Coastguard Worker }
681*b7c941bbSAndroid Build Coastguard Worker } else {
682*b7c941bbSAndroid Build Coastguard Worker isPass = false;
683*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to writeSampleData or stop muxer");
684*b7c941bbSAndroid Build Coastguard Worker }
685*b7c941bbSAndroid Build Coastguard Worker } else {
686*b7c941bbSAndroid Build Coastguard Worker isPass = false;
687*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to addTrack or start muxer");
688*b7c941bbSAndroid Build Coastguard Worker }
689*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
690*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
691*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
692*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
693*b7c941bbSAndroid Build Coastguard Worker } else {
694*b7c941bbSAndroid Build Coastguard Worker isPass = false;
695*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
696*b7c941bbSAndroid Build Coastguard Worker }
697*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
698*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
699*b7c941bbSAndroid Build Coastguard Worker }
700*b7c941bbSAndroid Build Coastguard Worker
nativeTestMultiTrack(JNIEnv * env,jobject,jint jformat,jstring jsrcPathA,jstring jsrcPathB,jstring jrefPath,jstring jdstPath)701*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestMultiTrack(JNIEnv* env, jobject, jint jformat, jstring jsrcPathA,
702*b7c941bbSAndroid Build Coastguard Worker jstring jsrcPathB, jstring jrefPath, jstring jdstPath) {
703*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
704*b7c941bbSAndroid Build Coastguard Worker const char* csrcPathA = env->GetStringUTFChars(jsrcPathA, nullptr);
705*b7c941bbSAndroid Build Coastguard Worker const char* csrcPathB = env->GetStringUTFChars(jsrcPathB, nullptr);
706*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoA = new MuxerNativeTestHelper(csrcPathA);
707*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoB = new MuxerNativeTestHelper(csrcPathB);
708*b7c941bbSAndroid Build Coastguard Worker if (mediaInfoA->getTrackCount() == 1 && mediaInfoB->getTrackCount() == 1) {
709*b7c941bbSAndroid Build Coastguard Worker const char* crefPath = env->GetStringUTFChars(jrefPath, nullptr);
710*b7c941bbSAndroid Build Coastguard Worker // number of times to repeat {mSrcFileA, mSrcFileB} in Output
711*b7c941bbSAndroid Build Coastguard Worker // values should be in sync with testMultiTrack
712*b7c941bbSAndroid Build Coastguard Worker static const int numTracks[][2] = {{1, 1}, {2, 0}, {0, 2}, {1, 2}, {2, 1}, {2, 2}};
713*b7c941bbSAndroid Build Coastguard Worker // prepare reference
714*b7c941bbSAndroid Build Coastguard Worker FILE* rfp = fopen(crefPath, "wbe+");
715*b7c941bbSAndroid Build Coastguard Worker if (rfp) {
716*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer* muxer = AMediaMuxer_new(fileno(rfp), (OutputFormat)jformat);
717*b7c941bbSAndroid Build Coastguard Worker bool muxStatus = mediaInfoA->combineMedias(muxer, mediaInfoB, numTracks[0]);
718*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
719*b7c941bbSAndroid Build Coastguard Worker fclose(rfp);
720*b7c941bbSAndroid Build Coastguard Worker if (muxStatus) {
721*b7c941bbSAndroid Build Coastguard Worker auto* refInfo = new MuxerNativeTestHelper(crefPath);
722*b7c941bbSAndroid Build Coastguard Worker if (!mediaInfoA->isSubsetOf(refInfo) || !mediaInfoB->isSubsetOf(refInfo)) {
723*b7c941bbSAndroid Build Coastguard Worker isPass = false;
724*b7c941bbSAndroid Build Coastguard Worker ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing src A and src B "
725*b7c941bbSAndroid Build Coastguard Worker "failed", csrcPathA, csrcPathB, jformat);
726*b7c941bbSAndroid Build Coastguard Worker } else {
727*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
728*b7c941bbSAndroid Build Coastguard Worker for (int i = 1; i < sizeof(numTracks) / sizeof(numTracks[0]) && isPass; i++) {
729*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "wbe+");
730*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
731*b7c941bbSAndroid Build Coastguard Worker muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
732*b7c941bbSAndroid Build Coastguard Worker bool status =
733*b7c941bbSAndroid Build Coastguard Worker mediaInfoA->combineMedias(muxer, mediaInfoB, numTracks[i]);
734*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
735*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
736*b7c941bbSAndroid Build Coastguard Worker if (status) {
737*b7c941bbSAndroid Build Coastguard Worker auto* dstInfo = new MuxerNativeTestHelper(cdstPath);
738*b7c941bbSAndroid Build Coastguard Worker if (!dstInfo->isSubsetOf(refInfo)) {
739*b7c941bbSAndroid Build Coastguard Worker isPass = false;
740*b7c941bbSAndroid Build Coastguard Worker ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing "
741*b7c941bbSAndroid Build Coastguard Worker "src A: %d, src B: %d failed", csrcPathA, csrcPathB,
742*b7c941bbSAndroid Build Coastguard Worker jformat, numTracks[i][0], numTracks[i][1]);
743*b7c941bbSAndroid Build Coastguard Worker }
744*b7c941bbSAndroid Build Coastguard Worker delete dstInfo;
745*b7c941bbSAndroid Build Coastguard Worker } else {
746*b7c941bbSAndroid Build Coastguard Worker if ((OutputFormat)jformat != AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4) {
747*b7c941bbSAndroid Build Coastguard Worker isPass = false;
748*b7c941bbSAndroid Build Coastguard Worker ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing "
749*b7c941bbSAndroid Build Coastguard Worker "src A: %d, src B: %d failed", csrcPathA, csrcPathB,
750*b7c941bbSAndroid Build Coastguard Worker jformat, numTracks[i][0], numTracks[i][1]);
751*b7c941bbSAndroid Build Coastguard Worker }
752*b7c941bbSAndroid Build Coastguard Worker }
753*b7c941bbSAndroid Build Coastguard Worker } else {
754*b7c941bbSAndroid Build Coastguard Worker isPass = false;
755*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
756*b7c941bbSAndroid Build Coastguard Worker }
757*b7c941bbSAndroid Build Coastguard Worker }
758*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
759*b7c941bbSAndroid Build Coastguard Worker }
760*b7c941bbSAndroid Build Coastguard Worker delete refInfo;
761*b7c941bbSAndroid Build Coastguard Worker } else {
762*b7c941bbSAndroid Build Coastguard Worker if ((OutputFormat)jformat != AMEDIAMUXER_OUTPUT_FORMAT_OGG) {
763*b7c941bbSAndroid Build Coastguard Worker isPass = false;
764*b7c941bbSAndroid Build Coastguard Worker ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing src A and src B "
765*b7c941bbSAndroid Build Coastguard Worker "failed", csrcPathA, csrcPathB, jformat);
766*b7c941bbSAndroid Build Coastguard Worker }
767*b7c941bbSAndroid Build Coastguard Worker }
768*b7c941bbSAndroid Build Coastguard Worker } else {
769*b7c941bbSAndroid Build Coastguard Worker isPass = false;
770*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open reference output file %s", crefPath);
771*b7c941bbSAndroid Build Coastguard Worker }
772*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jrefPath, crefPath);
773*b7c941bbSAndroid Build Coastguard Worker } else {
774*b7c941bbSAndroid Build Coastguard Worker isPass = false;
775*b7c941bbSAndroid Build Coastguard Worker if (mediaInfoA->getTrackCount() != 1) {
776*b7c941bbSAndroid Build Coastguard Worker ALOGE("error: file %s, track count exp/rec - %d/%d", csrcPathA, 1,
777*b7c941bbSAndroid Build Coastguard Worker mediaInfoA->getTrackCount());
778*b7c941bbSAndroid Build Coastguard Worker }
779*b7c941bbSAndroid Build Coastguard Worker if (mediaInfoB->getTrackCount() != 1) {
780*b7c941bbSAndroid Build Coastguard Worker ALOGE("error: file %s, track count exp/rec - %d/%d", csrcPathB, 1,
781*b7c941bbSAndroid Build Coastguard Worker mediaInfoB->getTrackCount());
782*b7c941bbSAndroid Build Coastguard Worker }
783*b7c941bbSAndroid Build Coastguard Worker }
784*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPathA, csrcPathA);
785*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPathB, csrcPathB);
786*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoA;
787*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoB;
788*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
789*b7c941bbSAndroid Build Coastguard Worker }
790*b7c941bbSAndroid Build Coastguard Worker
nativeTestOffsetPts(JNIEnv * env,jobject,jint format,jstring jsrcPath,jstring jdstPath,jintArray joffsetIndices)791*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestOffsetPts(JNIEnv* env, jobject, jint format, jstring jsrcPath,
792*b7c941bbSAndroid Build Coastguard Worker jstring jdstPath, jintArray joffsetIndices) {
793*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
794*b7c941bbSAndroid Build Coastguard Worker // values should be in sync with testOffsetPresentationTime
795*b7c941bbSAndroid Build Coastguard Worker static const int64_t OFFSET_TS_AUDIO_US[4] = {-23220LL, 0LL, 200000LL, 400000LL};
796*b7c941bbSAndroid Build Coastguard Worker static const int64_t OFFSET_TS_VIDEO_US[3] = {0LL, 200000LL, 400000LL};
797*b7c941bbSAndroid Build Coastguard Worker jsize len = env->GetArrayLength(joffsetIndices);
798*b7c941bbSAndroid Build Coastguard Worker jint* coffsetIndices = env->GetIntArrayElements(joffsetIndices, nullptr);
799*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
800*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
801*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
802*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->getTrackCount() != 0) {
803*b7c941bbSAndroid Build Coastguard Worker for (int64_t audioOffsetUs : OFFSET_TS_AUDIO_US) {
804*b7c941bbSAndroid Build Coastguard Worker for (int64_t videoOffsetUs : OFFSET_TS_VIDEO_US) {
805*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < len; i++) {
806*b7c941bbSAndroid Build Coastguard Worker mediaInfo->offsetTimeStamp(audioOffsetUs, videoOffsetUs, coffsetIndices[i]);
807*b7c941bbSAndroid Build Coastguard Worker }
808*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "wbe+");
809*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
810*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)format);
811*b7c941bbSAndroid Build Coastguard Worker mediaInfo->muxMedia(muxer);
812*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
813*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
814*b7c941bbSAndroid Build Coastguard Worker auto* outInfo = new MuxerNativeTestHelper(cdstPath);
815*b7c941bbSAndroid Build Coastguard Worker isPass = mediaInfo->isSubsetOf(outInfo);
816*b7c941bbSAndroid Build Coastguard Worker if (!isPass) {
817*b7c941bbSAndroid Build Coastguard Worker ALOGE("Validation failed after adding timestamp offsets audio: %lld,"
818*b7c941bbSAndroid Build Coastguard Worker " video: %lld", (long long) audioOffsetUs, (long long) videoOffsetUs);
819*b7c941bbSAndroid Build Coastguard Worker }
820*b7c941bbSAndroid Build Coastguard Worker delete outInfo;
821*b7c941bbSAndroid Build Coastguard Worker } else {
822*b7c941bbSAndroid Build Coastguard Worker isPass = false;
823*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
824*b7c941bbSAndroid Build Coastguard Worker }
825*b7c941bbSAndroid Build Coastguard Worker for (int i = len - 1; i >= 0; i--) {
826*b7c941bbSAndroid Build Coastguard Worker mediaInfo->offsetTimeStamp(-audioOffsetUs, -videoOffsetUs, coffsetIndices[i]);
827*b7c941bbSAndroid Build Coastguard Worker }
828*b7c941bbSAndroid Build Coastguard Worker }
829*b7c941bbSAndroid Build Coastguard Worker }
830*b7c941bbSAndroid Build Coastguard Worker } else {
831*b7c941bbSAndroid Build Coastguard Worker isPass = false;
832*b7c941bbSAndroid Build Coastguard Worker ALOGE("no valid track found in input file %s", csrcPath);
833*b7c941bbSAndroid Build Coastguard Worker }
834*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
835*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
836*b7c941bbSAndroid Build Coastguard Worker env->ReleaseIntArrayElements(joffsetIndices, coffsetIndices, 0);
837*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
838*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
839*b7c941bbSAndroid Build Coastguard Worker }
840*b7c941bbSAndroid Build Coastguard Worker
841*b7c941bbSAndroid Build Coastguard Worker // simple muxer tests, including varying the output container format.
842*b7c941bbSAndroid Build Coastguard Worker //
843*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_HEIF
844*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4
845*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_OGG
846*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP
847*b7c941bbSAndroid Build Coastguard Worker // @ApiTest = AMEDIAMUXER_OUTPUT_FORMAT_WEBM
848*b7c941bbSAndroid Build Coastguard Worker //
nativeTestSimpleMux(JNIEnv * env,jobject,jstring jsrcPath,jstring jdstPath,jstring jMediaType,jstring jselector)849*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSimpleMux(JNIEnv* env, jobject, jstring jsrcPath, jstring jdstPath,
850*b7c941bbSAndroid Build Coastguard Worker jstring jMediaType, jstring jselector) {
851*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
852*b7c941bbSAndroid Build Coastguard Worker const char* cMediaType = env->GetStringUTFChars(jMediaType, nullptr);
853*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
854*b7c941bbSAndroid Build Coastguard Worker const char* cselector = env->GetStringUTFChars(jselector, nullptr);
855*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath, cMediaType);
856*b7c941bbSAndroid Build Coastguard Worker static const std::map<OutputFormat, const char*> formatStringPair = {
857*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, "mp4"},
858*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_WEBM, "webm"},
859*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP, "3gp"},
860*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_HEIF, "heif"},
861*b7c941bbSAndroid Build Coastguard Worker {AMEDIAMUXER_OUTPUT_FORMAT_OGG, "ogg"}};
862*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->getTrackCount() == 1) {
863*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
864*b7c941bbSAndroid Build Coastguard Worker for (int fmt = LOCAL_AMEDIAMUXER_OUTPUT_FORMAT_FIRST;
865*b7c941bbSAndroid Build Coastguard Worker fmt <= LOCAL_AMEDIAMUXER_OUTPUT_FORMAT_LAST && isPass; fmt++) {
866*b7c941bbSAndroid Build Coastguard Worker auto it = formatStringPair.find((OutputFormat)fmt);
867*b7c941bbSAndroid Build Coastguard Worker if (it == formatStringPair.end() || strstr(cselector, it->second) == nullptr) {
868*b7c941bbSAndroid Build Coastguard Worker continue;
869*b7c941bbSAndroid Build Coastguard Worker }
870*b7c941bbSAndroid Build Coastguard Worker if (fmt == AMEDIAMUXER_OUTPUT_FORMAT_WEBM) continue; // TODO(b/146923551)
871*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "wbe+");
872*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
873*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)fmt);
874*b7c941bbSAndroid Build Coastguard Worker bool muxStatus = mediaInfo->muxMedia(muxer);
875*b7c941bbSAndroid Build Coastguard Worker bool result = true;
876*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
877*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
878*b7c941bbSAndroid Build Coastguard Worker if (muxStatus) {
879*b7c941bbSAndroid Build Coastguard Worker auto* outInfo = new MuxerNativeTestHelper(cdstPath, cMediaType);
880*b7c941bbSAndroid Build Coastguard Worker result = mediaInfo->isSubsetOf(outInfo);
881*b7c941bbSAndroid Build Coastguard Worker delete outInfo;
882*b7c941bbSAndroid Build Coastguard Worker }
883*b7c941bbSAndroid Build Coastguard Worker if ((muxStatus && !result) ||
884*b7c941bbSAndroid Build Coastguard Worker (!muxStatus && isCodecContainerPairValid((OutputFormat)fmt, cMediaType))) {
885*b7c941bbSAndroid Build Coastguard Worker isPass = false;
886*b7c941bbSAndroid Build Coastguard Worker ALOGE("error: file %s, mediaType %s, output != clone(input) for format %d",
887*b7c941bbSAndroid Build Coastguard Worker csrcPath, cMediaType, fmt);
888*b7c941bbSAndroid Build Coastguard Worker }
889*b7c941bbSAndroid Build Coastguard Worker } else {
890*b7c941bbSAndroid Build Coastguard Worker isPass = false;
891*b7c941bbSAndroid Build Coastguard Worker ALOGE("error: file %s, mediaType %s, failed to open output file %s", csrcPath,
892*b7c941bbSAndroid Build Coastguard Worker cMediaType, cdstPath);
893*b7c941bbSAndroid Build Coastguard Worker }
894*b7c941bbSAndroid Build Coastguard Worker }
895*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
896*b7c941bbSAndroid Build Coastguard Worker } else {
897*b7c941bbSAndroid Build Coastguard Worker isPass = false;
898*b7c941bbSAndroid Build Coastguard Worker ALOGE("error: file %s, mediaType %s, track count exp/rec - %d/%d", csrcPath, cMediaType, 1,
899*b7c941bbSAndroid Build Coastguard Worker mediaInfo->getTrackCount());
900*b7c941bbSAndroid Build Coastguard Worker }
901*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jselector, cselector);
902*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
903*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jMediaType, cMediaType);
904*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
905*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
906*b7c941bbSAndroid Build Coastguard Worker }
907*b7c941bbSAndroid Build Coastguard Worker
908*b7c941bbSAndroid Build Coastguard Worker /* Check whether AMediaMuxer_getTrackCount works as expected.
909*b7c941bbSAndroid Build Coastguard Worker */
nativeTestGetTrackCount(JNIEnv * env,jobject,jstring jsrcPath,jstring jdstPath,jint jformat,jint jtrackCount)910*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestGetTrackCount(JNIEnv* env, jobject, jstring jsrcPath, jstring jdstPath,
911*b7c941bbSAndroid Build Coastguard Worker jint jformat, jint jtrackCount) {
912*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
913*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
914*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
915*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
916*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "w+");
917*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
918*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)jformat);
919*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
920*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
921*b7c941bbSAndroid Build Coastguard Worker if (!mediaInfo->registerTrack(muxer)) {
922*b7c941bbSAndroid Build Coastguard Worker isPass = false;
923*b7c941bbSAndroid Build Coastguard Worker ALOGE("register track failed");
924*b7c941bbSAndroid Build Coastguard Worker }
925*b7c941bbSAndroid Build Coastguard Worker if (AMediaMuxer_getTrackCount(muxer) != jtrackCount) {
926*b7c941bbSAndroid Build Coastguard Worker isPass = false;
927*b7c941bbSAndroid Build Coastguard Worker ALOGE("track counts are not equal");
928*b7c941bbSAndroid Build Coastguard Worker }
929*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
930*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
931*b7c941bbSAndroid Build Coastguard Worker } else {
932*b7c941bbSAndroid Build Coastguard Worker isPass = false;
933*b7c941bbSAndroid Build Coastguard Worker ALOGE("Failed to create muxer");
934*b7c941bbSAndroid Build Coastguard Worker }
935*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
936*b7c941bbSAndroid Build Coastguard Worker } else {
937*b7c941bbSAndroid Build Coastguard Worker isPass = false;
938*b7c941bbSAndroid Build Coastguard Worker ALOGE("file open error: file %s", csrcPath);
939*b7c941bbSAndroid Build Coastguard Worker }
940*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
941*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
942*b7c941bbSAndroid Build Coastguard Worker } else {
943*b7c941bbSAndroid Build Coastguard Worker isPass = false;
944*b7c941bbSAndroid Build Coastguard Worker }
945*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
946*b7c941bbSAndroid Build Coastguard Worker }
947*b7c941bbSAndroid Build Coastguard Worker
948*b7c941bbSAndroid Build Coastguard Worker /* Check whether AMediaMuxer_getTrackCount works as expected when the file is opened in
949*b7c941bbSAndroid Build Coastguard Worker * append mode.
950*b7c941bbSAndroid Build Coastguard Worker */
nativeTestAppendGetTrackCount(JNIEnv * env,jobject,jstring jsrcPath,jint jtrackCount)951*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestAppendGetTrackCount(JNIEnv* env, jobject, jstring jsrcPath,
952*b7c941bbSAndroid Build Coastguard Worker jint jtrackCount) {
953*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
954*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
955*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
956*b7c941bbSAndroid Build Coastguard Worker for (unsigned int mode = AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP;
957*b7c941bbSAndroid Build Coastguard Worker mode <= AMEDIAMUXER_APPEND_TO_EXISTING_DATA; ++mode) {
958*b7c941bbSAndroid Build Coastguard Worker ALOGV("mode:%u", mode);
959*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(csrcPath, "r");
960*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
961*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = AMediaMuxer_append(fileno(ofp), (AppendMode)mode);
962*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
963*b7c941bbSAndroid Build Coastguard Worker ssize_t trackCount = AMediaMuxer_getTrackCount(muxer);
964*b7c941bbSAndroid Build Coastguard Worker if ( trackCount != jtrackCount) {
965*b7c941bbSAndroid Build Coastguard Worker isPass = false;
966*b7c941bbSAndroid Build Coastguard Worker ALOGE("trackcounts are not equal, trackCount:%ld vs jtrackCount:%d",
967*b7c941bbSAndroid Build Coastguard Worker (long)trackCount, jtrackCount);
968*b7c941bbSAndroid Build Coastguard Worker }
969*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
970*b7c941bbSAndroid Build Coastguard Worker } else {
971*b7c941bbSAndroid Build Coastguard Worker isPass = false;
972*b7c941bbSAndroid Build Coastguard Worker ALOGE("Failed to create muxer");
973*b7c941bbSAndroid Build Coastguard Worker }
974*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
975*b7c941bbSAndroid Build Coastguard Worker ofp = nullptr;
976*b7c941bbSAndroid Build Coastguard Worker } else {
977*b7c941bbSAndroid Build Coastguard Worker isPass = false;
978*b7c941bbSAndroid Build Coastguard Worker ALOGE("file open error: file %s", csrcPath);
979*b7c941bbSAndroid Build Coastguard Worker }
980*b7c941bbSAndroid Build Coastguard Worker }
981*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
982*b7c941bbSAndroid Build Coastguard Worker } else {
983*b7c941bbSAndroid Build Coastguard Worker isPass = false;
984*b7c941bbSAndroid Build Coastguard Worker }
985*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
986*b7c941bbSAndroid Build Coastguard Worker }
987*b7c941bbSAndroid Build Coastguard Worker
988*b7c941bbSAndroid Build Coastguard Worker /* Checks whether AMediaMuxer_getTrackFormat works as expected in muxer mode.
989*b7c941bbSAndroid Build Coastguard Worker */
nativeTestGetTrackFormat(JNIEnv * env,jobject,jstring jsrcPath,jstring jdstPath,jint joutFormat)990*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestGetTrackFormat(JNIEnv* env, jobject, jstring jsrcPath, jstring jdstPath,
991*b7c941bbSAndroid Build Coastguard Worker jint joutFormat) {
992*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
993*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
994*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
995*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
996*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "w+");
997*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
998*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)joutFormat);
999*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1000*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
1001*b7c941bbSAndroid Build Coastguard Worker if (!mediaInfo->registerTrack(muxer)) {
1002*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1003*b7c941bbSAndroid Build Coastguard Worker ALOGE("register track failed");
1004*b7c941bbSAndroid Build Coastguard Worker }
1005*b7c941bbSAndroid Build Coastguard Worker for(int i = 0 ; i < mediaInfo->getTrackCount(); ++i ) {
1006*b7c941bbSAndroid Build Coastguard Worker if (!isFormatSimilar(mediaInfo->getTrackFormat(i),
1007*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_getTrackFormat(muxer, i))) {
1008*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1009*b7c941bbSAndroid Build Coastguard Worker ALOGE("track formats are not similar");
1010*b7c941bbSAndroid Build Coastguard Worker }
1011*b7c941bbSAndroid Build Coastguard Worker }
1012*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
1013*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1014*b7c941bbSAndroid Build Coastguard Worker } else {
1015*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1016*b7c941bbSAndroid Build Coastguard Worker ALOGE("Failed to create muxer");
1017*b7c941bbSAndroid Build Coastguard Worker }
1018*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1019*b7c941bbSAndroid Build Coastguard Worker } else {
1020*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1021*b7c941bbSAndroid Build Coastguard Worker ALOGE("file open error: file %s", csrcPath);
1022*b7c941bbSAndroid Build Coastguard Worker }
1023*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
1024*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
1025*b7c941bbSAndroid Build Coastguard Worker } else {
1026*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1027*b7c941bbSAndroid Build Coastguard Worker }
1028*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
1029*b7c941bbSAndroid Build Coastguard Worker }
1030*b7c941bbSAndroid Build Coastguard Worker
1031*b7c941bbSAndroid Build Coastguard Worker /* Checks whether AMediaMuxer_getTrackFormat works as expected when the file is opened in
1032*b7c941bbSAndroid Build Coastguard Worker * append mode.
1033*b7c941bbSAndroid Build Coastguard Worker */
nativeTestAppendGetTrackFormat(JNIEnv * env,jobject,jstring jsrcPath)1034*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestAppendGetTrackFormat(JNIEnv* env, jobject, jstring jsrcPath) {
1035*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
1036*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
1037*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
1038*b7c941bbSAndroid Build Coastguard Worker for (unsigned int mode = AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP;
1039*b7c941bbSAndroid Build Coastguard Worker mode <= AMEDIAMUXER_APPEND_TO_EXISTING_DATA; ++mode) {
1040*b7c941bbSAndroid Build Coastguard Worker ALOGV("mode:%u", mode);
1041*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(csrcPath, "r");
1042*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1043*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = AMediaMuxer_append(fileno(ofp), (AppendMode)mode);
1044*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1045*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
1046*b7c941bbSAndroid Build Coastguard Worker for(int i = 0 ; i < mediaInfo->getTrackCount(); ++i ) {
1047*b7c941bbSAndroid Build Coastguard Worker if (!isFormatSimilar(mediaInfo->getTrackFormat(i),
1048*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_getTrackFormat(muxer, i))) {
1049*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1050*b7c941bbSAndroid Build Coastguard Worker ALOGE("track formats are not similar");
1051*b7c941bbSAndroid Build Coastguard Worker }
1052*b7c941bbSAndroid Build Coastguard Worker }
1053*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
1054*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1055*b7c941bbSAndroid Build Coastguard Worker } else {
1056*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1057*b7c941bbSAndroid Build Coastguard Worker ALOGE("Failed to create muxer");
1058*b7c941bbSAndroid Build Coastguard Worker }
1059*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1060*b7c941bbSAndroid Build Coastguard Worker } else {
1061*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1062*b7c941bbSAndroid Build Coastguard Worker ALOGE("file open error: file %s", csrcPath);
1063*b7c941bbSAndroid Build Coastguard Worker }
1064*b7c941bbSAndroid Build Coastguard Worker }
1065*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
1066*b7c941bbSAndroid Build Coastguard Worker }
1067*b7c941bbSAndroid Build Coastguard Worker else {
1068*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1069*b7c941bbSAndroid Build Coastguard Worker }
1070*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
1071*b7c941bbSAndroid Build Coastguard Worker }
1072*b7c941bbSAndroid Build Coastguard Worker
1073*b7c941bbSAndroid Build Coastguard Worker /*
1074*b7c941bbSAndroid Build Coastguard Worker * Checks if appending media data to the end of existing media data in a file works good.
1075*b7c941bbSAndroid Build Coastguard Worker * Mode : AMEDIAMUXER_APPEND_TO_EXISTING_DATA. Splits the contents of source file equally
1076*b7c941bbSAndroid Build Coastguard Worker * starting from one and increasing the number of splits by one for every iteration. Starts
1077*b7c941bbSAndroid Build Coastguard Worker * with writing first split into a new file and appends the rest of the contents split by split.
1078*b7c941bbSAndroid Build Coastguard Worker */
nativeTestSimpleAppend(JNIEnv * env,jobject,jint joutFormat,jstring jsrcPath,jstring jdstPath)1079*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestSimpleAppend(JNIEnv* env, jobject, jint joutFormat, jstring jsrcPath,
1080*b7c941bbSAndroid Build Coastguard Worker jstring jdstPath) {
1081*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
1082*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
1083*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
1084*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
1085*b7c941bbSAndroid Build Coastguard Worker ALOGV("csrcPath:%s", csrcPath);
1086*b7c941bbSAndroid Build Coastguard Worker ALOGV("cdstPath:%s", cdstPath);
1087*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
1088*b7c941bbSAndroid Build Coastguard Worker for (int numSplits = 1; numSplits <= 5; ++numSplits) {
1089*b7c941bbSAndroid Build Coastguard Worker ALOGV("numSplits:%d", numSplits);
1090*b7c941bbSAndroid Build Coastguard Worker size_t totalSampleCount = 0;
1091*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = nullptr;
1092*b7c941bbSAndroid Build Coastguard Worker // Start by writing first split into a new file.
1093*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "w+");
1094*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1095*b7c941bbSAndroid Build Coastguard Worker muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)joutFormat);
1096*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1097*b7c941bbSAndroid Build Coastguard Worker for(int i = 0 ; i < mediaInfo->getTrackCount(); ++i ) {
1098*b7c941bbSAndroid Build Coastguard Worker ALOGV("getSampleCount:%d:%zu", i, mediaInfo->getSampleCount(i));
1099*b7c941bbSAndroid Build Coastguard Worker totalSampleCount += mediaInfo->getSampleCount(i);
1100*b7c941bbSAndroid Build Coastguard Worker }
1101*b7c941bbSAndroid Build Coastguard Worker mediaInfo->appendMedia(muxer, 0, (totalSampleCount/numSplits)-1);
1102*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1103*b7c941bbSAndroid Build Coastguard Worker } else {
1104*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1105*b7c941bbSAndroid Build Coastguard Worker ALOGE("Failed to create muxer");
1106*b7c941bbSAndroid Build Coastguard Worker }
1107*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1108*b7c941bbSAndroid Build Coastguard Worker ofp = nullptr;
1109*b7c941bbSAndroid Build Coastguard Worker // Check if the contents in the new file is as same as in the source file.
1110*b7c941bbSAndroid Build Coastguard Worker if (isPass) {
1111*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoDest = new MuxerNativeTestHelper(cdstPath, nullptr);
1112*b7c941bbSAndroid Build Coastguard Worker isPass = mediaInfoDest->isSubsetOf(mediaInfo);
1113*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoDest;
1114*b7c941bbSAndroid Build Coastguard Worker }
1115*b7c941bbSAndroid Build Coastguard Worker } else {
1116*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1117*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
1118*b7c941bbSAndroid Build Coastguard Worker }
1119*b7c941bbSAndroid Build Coastguard Worker
1120*b7c941bbSAndroid Build Coastguard Worker // Append rest of the contents from the source file to the new file split by split.
1121*b7c941bbSAndroid Build Coastguard Worker int curSplit = 1;
1122*b7c941bbSAndroid Build Coastguard Worker while (curSplit < numSplits && isPass) {
1123*b7c941bbSAndroid Build Coastguard Worker ofp = fopen(cdstPath, "r+");
1124*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1125*b7c941bbSAndroid Build Coastguard Worker muxer = AMediaMuxer_append(fileno(ofp), AMEDIAMUXER_APPEND_TO_EXISTING_DATA);
1126*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1127*b7c941bbSAndroid Build Coastguard Worker ssize_t trackCount = AMediaMuxer_getTrackCount(muxer);
1128*b7c941bbSAndroid Build Coastguard Worker if (trackCount > 0) {
1129*b7c941bbSAndroid Build Coastguard Worker decltype(trackCount) tc = 0;
1130*b7c941bbSAndroid Build Coastguard Worker while(tc < trackCount) {
1131*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format = AMediaMuxer_getTrackFormat(muxer, tc);
1132*b7c941bbSAndroid Build Coastguard Worker int64_t val = 0;
1133*b7c941bbSAndroid Build Coastguard Worker if (AMediaFormat_getInt64(format,
1134*b7c941bbSAndroid Build Coastguard Worker AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND, &val)) {
1135*b7c941bbSAndroid Build Coastguard Worker ALOGV("sample-time-before-append:%lld", (long long)val);
1136*b7c941bbSAndroid Build Coastguard Worker }
1137*b7c941bbSAndroid Build Coastguard Worker ++tc;
1138*b7c941bbSAndroid Build Coastguard Worker }
1139*b7c941bbSAndroid Build Coastguard Worker mediaInfo->appendMedia(muxer, totalSampleCount*curSplit/numSplits,
1140*b7c941bbSAndroid Build Coastguard Worker totalSampleCount*(curSplit+1)/numSplits-1);
1141*b7c941bbSAndroid Build Coastguard Worker } else {
1142*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1143*b7c941bbSAndroid Build Coastguard Worker ALOGE("no tracks in the file");
1144*b7c941bbSAndroid Build Coastguard Worker }
1145*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1146*b7c941bbSAndroid Build Coastguard Worker } else {
1147*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1148*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to create muxer");
1149*b7c941bbSAndroid Build Coastguard Worker }
1150*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1151*b7c941bbSAndroid Build Coastguard Worker ofp = nullptr;
1152*b7c941bbSAndroid Build Coastguard Worker if (isPass) {
1153*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoDest = new MuxerNativeTestHelper(cdstPath, nullptr);
1154*b7c941bbSAndroid Build Coastguard Worker isPass = mediaInfoDest->isSubsetOf(mediaInfo);
1155*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoDest;
1156*b7c941bbSAndroid Build Coastguard Worker }
1157*b7c941bbSAndroid Build Coastguard Worker } else {
1158*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1159*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
1160*b7c941bbSAndroid Build Coastguard Worker }
1161*b7c941bbSAndroid Build Coastguard Worker ++curSplit;
1162*b7c941bbSAndroid Build Coastguard Worker }
1163*b7c941bbSAndroid Build Coastguard Worker }
1164*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
1165*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
1166*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
1167*b7c941bbSAndroid Build Coastguard Worker } else {
1168*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1169*b7c941bbSAndroid Build Coastguard Worker }
1170*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
1171*b7c941bbSAndroid Build Coastguard Worker }
1172*b7c941bbSAndroid Build Coastguard Worker
1173*b7c941bbSAndroid Build Coastguard Worker /* Checks if opening a file to append data and closing it without actually appending data
1174*b7c941bbSAndroid Build Coastguard Worker * works good in all append modes.
1175*b7c941bbSAndroid Build Coastguard Worker */
nativeTestNoSamples(JNIEnv * env,jobject,jint joutFormat,jstring jinPath,jstring joutPath)1176*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestNoSamples(JNIEnv* env, jobject, jint joutFormat, jstring jinPath,
1177*b7c941bbSAndroid Build Coastguard Worker jstring joutPath) {
1178*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
1179*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
1180*b7c941bbSAndroid Build Coastguard Worker const char* cinPath = env->GetStringUTFChars(jinPath, nullptr);
1181*b7c941bbSAndroid Build Coastguard Worker const char* coutPath = env->GetStringUTFChars(joutPath, nullptr);
1182*b7c941bbSAndroid Build Coastguard Worker ALOGV("cinPath:%s", cinPath);
1183*b7c941bbSAndroid Build Coastguard Worker ALOGV("coutPath:%s", coutPath);
1184*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(cinPath);
1185*b7c941bbSAndroid Build Coastguard Worker for (unsigned int mode = AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP;
1186*b7c941bbSAndroid Build Coastguard Worker mode <= AMEDIAMUXER_APPEND_TO_EXISTING_DATA; ++mode) {
1187*b7c941bbSAndroid Build Coastguard Worker if (mediaInfo->getTrackCount() != 0) {
1188*b7c941bbSAndroid Build Coastguard Worker // Create a new file and write media data to it.
1189*b7c941bbSAndroid Build Coastguard Worker FILE *ofp = fopen(coutPath, "wbe+");
1190*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1191*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat) joutFormat);
1192*b7c941bbSAndroid Build Coastguard Worker mediaInfo->muxMedia(muxer);
1193*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1194*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1195*b7c941bbSAndroid Build Coastguard Worker } else {
1196*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1197*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", coutPath);
1198*b7c941bbSAndroid Build Coastguard Worker }
1199*b7c941bbSAndroid Build Coastguard Worker } else {
1200*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1201*b7c941bbSAndroid Build Coastguard Worker ALOGE("no tracks in input file");
1202*b7c941bbSAndroid Build Coastguard Worker }
1203*b7c941bbSAndroid Build Coastguard Worker ALOGV("after file close");
1204*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(coutPath, "r+");
1205*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1206*b7c941bbSAndroid Build Coastguard Worker ALOGV("create append muxer");
1207*b7c941bbSAndroid Build Coastguard Worker // Open the new file in one of the append modes and close it without writing data.
1208*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = AMediaMuxer_append(fileno(ofp), (AppendMode)mode);
1209*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1210*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_start(muxer);
1211*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_stop(muxer);
1212*b7c941bbSAndroid Build Coastguard Worker ALOGV("delete append muxer");
1213*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1214*b7c941bbSAndroid Build Coastguard Worker } else {
1215*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1216*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to create muxer");
1217*b7c941bbSAndroid Build Coastguard Worker }
1218*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1219*b7c941bbSAndroid Build Coastguard Worker ofp = nullptr;
1220*b7c941bbSAndroid Build Coastguard Worker } else {
1221*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1222*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file to append %s", coutPath);
1223*b7c941bbSAndroid Build Coastguard Worker }
1224*b7c941bbSAndroid Build Coastguard Worker // Check if contents written in the new file match with contents in the original file.
1225*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoOut = new MuxerNativeTestHelper(coutPath, nullptr);
1226*b7c941bbSAndroid Build Coastguard Worker isPass = mediaInfoOut->isSubsetOf(mediaInfo);
1227*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoOut;
1228*b7c941bbSAndroid Build Coastguard Worker }
1229*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
1230*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jinPath, cinPath);
1231*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(joutPath, coutPath);
1232*b7c941bbSAndroid Build Coastguard Worker } else {
1233*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1234*b7c941bbSAndroid Build Coastguard Worker }
1235*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
1236*b7c941bbSAndroid Build Coastguard Worker }
1237*b7c941bbSAndroid Build Coastguard Worker
1238*b7c941bbSAndroid Build Coastguard Worker /*
1239*b7c941bbSAndroid Build Coastguard Worker * Checks if appending media data in AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP mode works good.
1240*b7c941bbSAndroid Build Coastguard Worker * Splits the contents of source file equally starting from one and increasing the number of
1241*b7c941bbSAndroid Build Coastguard Worker * splits by one for every iteration. Starts with writing first split into a new file and
1242*b7c941bbSAndroid Build Coastguard Worker * appends the rest of the contents split by split.
1243*b7c941bbSAndroid Build Coastguard Worker */
nativeTestIgnoreLastGOPAppend(JNIEnv * env,jobject,jint joutFormat,jstring jsrcPath,jstring jdstPath)1244*b7c941bbSAndroid Build Coastguard Worker static jboolean nativeTestIgnoreLastGOPAppend(JNIEnv* env, jobject, jint joutFormat,
1245*b7c941bbSAndroid Build Coastguard Worker jstring jsrcPath, jstring jdstPath) {
1246*b7c941bbSAndroid Build Coastguard Worker bool isPass = true;
1247*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
1248*b7c941bbSAndroid Build Coastguard Worker const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
1249*b7c941bbSAndroid Build Coastguard Worker const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
1250*b7c941bbSAndroid Build Coastguard Worker ALOGV("csrcPath:%s", csrcPath);
1251*b7c941bbSAndroid Build Coastguard Worker ALOGV("cdstPath:%s", cdstPath);
1252*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfo = new MuxerNativeTestHelper(csrcPath);
1253*b7c941bbSAndroid Build Coastguard Worker for (int numSplits = 1; numSplits <= 5 && isPass; ++numSplits) {
1254*b7c941bbSAndroid Build Coastguard Worker ALOGV("numSplits:%d", numSplits);
1255*b7c941bbSAndroid Build Coastguard Worker size_t totalSampleCount = 0;
1256*b7c941bbSAndroid Build Coastguard Worker size_t totalSamplesWritten = 0;
1257*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer *muxer = nullptr;
1258*b7c941bbSAndroid Build Coastguard Worker FILE* ofp = fopen(cdstPath, "w+");
1259*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1260*b7c941bbSAndroid Build Coastguard Worker // Start by writing first split into a new file.
1261*b7c941bbSAndroid Build Coastguard Worker muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)joutFormat);
1262*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1263*b7c941bbSAndroid Build Coastguard Worker for(int i = 0 ; i < mediaInfo->getTrackCount(); ++i ) {
1264*b7c941bbSAndroid Build Coastguard Worker ALOGV("getSampleCount:%d:%zu", i, mediaInfo->getSampleCount(i));
1265*b7c941bbSAndroid Build Coastguard Worker totalSampleCount += mediaInfo->getSampleCount(i);
1266*b7c941bbSAndroid Build Coastguard Worker }
1267*b7c941bbSAndroid Build Coastguard Worker mediaInfo->appendMedia(muxer, 0, (totalSampleCount/numSplits)-1);
1268*b7c941bbSAndroid Build Coastguard Worker totalSamplesWritten += (totalSampleCount/numSplits);
1269*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1270*b7c941bbSAndroid Build Coastguard Worker } else {
1271*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1272*b7c941bbSAndroid Build Coastguard Worker ALOGE("Failed to create muxer");
1273*b7c941bbSAndroid Build Coastguard Worker }
1274*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1275*b7c941bbSAndroid Build Coastguard Worker ofp = nullptr;
1276*b7c941bbSAndroid Build Coastguard Worker if (isPass) {
1277*b7c941bbSAndroid Build Coastguard Worker // Check if the contents in the new file is as same as in the source file.
1278*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoDest = new MuxerNativeTestHelper(cdstPath, nullptr);
1279*b7c941bbSAndroid Build Coastguard Worker isPass = mediaInfoDest->isSubsetOf(mediaInfo);
1280*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoDest;
1281*b7c941bbSAndroid Build Coastguard Worker }
1282*b7c941bbSAndroid Build Coastguard Worker } else {
1283*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1284*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
1285*b7c941bbSAndroid Build Coastguard Worker }
1286*b7c941bbSAndroid Build Coastguard Worker
1287*b7c941bbSAndroid Build Coastguard Worker // Append rest of the contents from the source file to the new file split by split.
1288*b7c941bbSAndroid Build Coastguard Worker int curSplit = 1;
1289*b7c941bbSAndroid Build Coastguard Worker while (curSplit < numSplits && isPass) {
1290*b7c941bbSAndroid Build Coastguard Worker ofp = fopen(cdstPath, "r+");
1291*b7c941bbSAndroid Build Coastguard Worker if (ofp) {
1292*b7c941bbSAndroid Build Coastguard Worker muxer = AMediaMuxer_append(fileno(ofp),
1293*b7c941bbSAndroid Build Coastguard Worker AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP);
1294*b7c941bbSAndroid Build Coastguard Worker if (muxer) {
1295*b7c941bbSAndroid Build Coastguard Worker auto trackCount = AMediaMuxer_getTrackCount(muxer);
1296*b7c941bbSAndroid Build Coastguard Worker if (trackCount > 0) {
1297*b7c941bbSAndroid Build Coastguard Worker decltype(trackCount) tc = 0;
1298*b7c941bbSAndroid Build Coastguard Worker int64_t* appendFromTime = new int64_t[trackCount]{0};
1299*b7c941bbSAndroid Build Coastguard Worker while(tc < trackCount) {
1300*b7c941bbSAndroid Build Coastguard Worker AMediaFormat* format = AMediaMuxer_getTrackFormat(muxer, tc);
1301*b7c941bbSAndroid Build Coastguard Worker int64_t val = 0;
1302*b7c941bbSAndroid Build Coastguard Worker if (AMediaFormat_getInt64(format,
1303*b7c941bbSAndroid Build Coastguard Worker AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND, &val)) {
1304*b7c941bbSAndroid Build Coastguard Worker ALOGV("sample-time-before-append:%lld", (long long)val);
1305*b7c941bbSAndroid Build Coastguard Worker appendFromTime[tc] = val;
1306*b7c941bbSAndroid Build Coastguard Worker }
1307*b7c941bbSAndroid Build Coastguard Worker ++tc;
1308*b7c941bbSAndroid Build Coastguard Worker }
1309*b7c941bbSAndroid Build Coastguard Worker bool lastSplit = (curSplit == numSplits-1) ? true : false;
1310*b7c941bbSAndroid Build Coastguard Worker mediaInfo->appendMediaFromTime(muxer, appendFromTime,
1311*b7c941bbSAndroid Build Coastguard Worker totalSampleCount/numSplits + ((curSplit-1) * 30), lastSplit);
1312*b7c941bbSAndroid Build Coastguard Worker delete[] appendFromTime;
1313*b7c941bbSAndroid Build Coastguard Worker } else {
1314*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1315*b7c941bbSAndroid Build Coastguard Worker ALOGE("no tracks in the file");
1316*b7c941bbSAndroid Build Coastguard Worker }
1317*b7c941bbSAndroid Build Coastguard Worker AMediaMuxer_delete(muxer);
1318*b7c941bbSAndroid Build Coastguard Worker } else {
1319*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1320*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to create muxer");
1321*b7c941bbSAndroid Build Coastguard Worker }
1322*b7c941bbSAndroid Build Coastguard Worker fclose(ofp);
1323*b7c941bbSAndroid Build Coastguard Worker ofp = nullptr;
1324*b7c941bbSAndroid Build Coastguard Worker if (isPass) {
1325*b7c941bbSAndroid Build Coastguard Worker auto* mediaInfoDest = new MuxerNativeTestHelper(cdstPath, nullptr);
1326*b7c941bbSAndroid Build Coastguard Worker isPass = mediaInfoDest->isSubsetOf(mediaInfo);
1327*b7c941bbSAndroid Build Coastguard Worker delete mediaInfoDest;
1328*b7c941bbSAndroid Build Coastguard Worker }
1329*b7c941bbSAndroid Build Coastguard Worker } else {
1330*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1331*b7c941bbSAndroid Build Coastguard Worker ALOGE("failed to open output file %s", cdstPath);
1332*b7c941bbSAndroid Build Coastguard Worker }
1333*b7c941bbSAndroid Build Coastguard Worker ++curSplit;
1334*b7c941bbSAndroid Build Coastguard Worker }
1335*b7c941bbSAndroid Build Coastguard Worker }
1336*b7c941bbSAndroid Build Coastguard Worker delete mediaInfo;
1337*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jdstPath, cdstPath);
1338*b7c941bbSAndroid Build Coastguard Worker env->ReleaseStringUTFChars(jsrcPath, csrcPath);
1339*b7c941bbSAndroid Build Coastguard Worker } else {
1340*b7c941bbSAndroid Build Coastguard Worker isPass = false;
1341*b7c941bbSAndroid Build Coastguard Worker }
1342*b7c941bbSAndroid Build Coastguard Worker return static_cast<jboolean>(isPass);
1343*b7c941bbSAndroid Build Coastguard Worker }
1344*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsMuxerTestApi(JNIEnv * env)1345*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsMuxerTestApi(JNIEnv* env) {
1346*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
1347*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSetOrientationHint", "(ILjava/lang/String;Ljava/lang/String;)Z",
1348*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSetOrientationHint},
1349*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSetLocation", "(ILjava/lang/String;Ljava/lang/String;)Z",
1350*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSetLocation},
1351*b7c941bbSAndroid Build Coastguard Worker {"nativeTestGetTrackCount", "(Ljava/lang/String;Ljava/lang/String;II)Z",
1352*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestGetTrackCount},
1353*b7c941bbSAndroid Build Coastguard Worker {"nativeTestGetTrackFormat", "(Ljava/lang/String;Ljava/lang/String;I)Z",
1354*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestGetTrackFormat},
1355*b7c941bbSAndroid Build Coastguard Worker };
1356*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestApi");
1357*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
1358*b7c941bbSAndroid Build Coastguard Worker }
1359*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsMuxerTestMultiTrack(JNIEnv * env)1360*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsMuxerTestMultiTrack(JNIEnv* env) {
1361*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
1362*b7c941bbSAndroid Build Coastguard Worker {"nativeTestMultiTrack",
1363*b7c941bbSAndroid Build Coastguard Worker "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
1364*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestMultiTrack},
1365*b7c941bbSAndroid Build Coastguard Worker };
1366*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestMultiTrack");
1367*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
1368*b7c941bbSAndroid Build Coastguard Worker }
1369*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsMuxerTestOffsetPts(JNIEnv * env)1370*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsMuxerTestOffsetPts(JNIEnv* env) {
1371*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
1372*b7c941bbSAndroid Build Coastguard Worker {"nativeTestOffsetPts", "(ILjava/lang/String;Ljava/lang/String;[I)Z",
1373*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestOffsetPts},
1374*b7c941bbSAndroid Build Coastguard Worker };
1375*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestOffsetPts");
1376*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
1377*b7c941bbSAndroid Build Coastguard Worker }
1378*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsMuxerTestSimpleMux(JNIEnv * env)1379*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsMuxerTestSimpleMux(JNIEnv* env) {
1380*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
1381*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSimpleMux",
1382*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
1383*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSimpleMux},
1384*b7c941bbSAndroid Build Coastguard Worker };
1385*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestSimpleMux");
1386*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
1387*b7c941bbSAndroid Build Coastguard Worker }
1388*b7c941bbSAndroid Build Coastguard Worker
registerAndroidMediaV2CtsMuxerTestSimpleAppend(JNIEnv * env)1389*b7c941bbSAndroid Build Coastguard Worker int registerAndroidMediaV2CtsMuxerTestSimpleAppend(JNIEnv* env) {
1390*b7c941bbSAndroid Build Coastguard Worker const JNINativeMethod methodTable[] = {
1391*b7c941bbSAndroid Build Coastguard Worker {"nativeTestSimpleAppend",
1392*b7c941bbSAndroid Build Coastguard Worker "(ILjava/lang/String;Ljava/lang/String;)Z",
1393*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestSimpleAppend},
1394*b7c941bbSAndroid Build Coastguard Worker {"nativeTestAppendGetTrackCount",
1395*b7c941bbSAndroid Build Coastguard Worker "(Ljava/lang/String;I)Z",
1396*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestAppendGetTrackCount},
1397*b7c941bbSAndroid Build Coastguard Worker {"nativeTestAppendGetTrackFormat", "(Ljava/lang/String;)Z",
1398*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestAppendGetTrackFormat},
1399*b7c941bbSAndroid Build Coastguard Worker {"nativeTestNoSamples",
1400*b7c941bbSAndroid Build Coastguard Worker "(ILjava/lang/String;Ljava/lang/String;)Z",
1401*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestNoSamples},
1402*b7c941bbSAndroid Build Coastguard Worker {"nativeTestIgnoreLastGOPAppend",
1403*b7c941bbSAndroid Build Coastguard Worker "(ILjava/lang/String;Ljava/lang/String;)Z",
1404*b7c941bbSAndroid Build Coastguard Worker (void*)nativeTestIgnoreLastGOPAppend},
1405*b7c941bbSAndroid Build Coastguard Worker };
1406*b7c941bbSAndroid Build Coastguard Worker jclass c = env->FindClass("android/mediav2/cts/MuxerTest$TestSimpleAppend");
1407*b7c941bbSAndroid Build Coastguard Worker return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
1408*b7c941bbSAndroid Build Coastguard Worker }
1409*b7c941bbSAndroid Build Coastguard Worker
1410*b7c941bbSAndroid Build Coastguard Worker extern int registerAndroidMediaV2CtsMuxerUnitTestApi(JNIEnv* env);
1411*b7c941bbSAndroid Build Coastguard Worker
JNI_OnLoad(JavaVM * vm,void *)1412*b7c941bbSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
1413*b7c941bbSAndroid Build Coastguard Worker JNIEnv* env;
1414*b7c941bbSAndroid Build Coastguard Worker if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
1415*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsMuxerTestApi(env) != JNI_OK) return JNI_ERR;
1416*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsMuxerTestMultiTrack(env) != JNI_OK) return JNI_ERR;
1417*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsMuxerTestOffsetPts(env) != JNI_OK) return JNI_ERR;
1418*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsMuxerTestSimpleMux(env) != JNI_OK) return JNI_ERR;
1419*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsMuxerTestSimpleAppend(env) != JNI_OK) return JNI_ERR;
1420*b7c941bbSAndroid Build Coastguard Worker if (registerAndroidMediaV2CtsMuxerUnitTestApi(env) != JNI_OK) return JNI_ERR;
1421*b7c941bbSAndroid Build Coastguard Worker return JNI_VERSION_1_6;
1422*b7c941bbSAndroid Build Coastguard Worker }
1423