1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NativeDecoder"
19 
20 #include <jni.h>
21 #include <fstream>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 
26 #include <android/log.h>
27 
28 #include "Decoder.h"
29 
Java_com_android_media_benchmark_library_Native_Decode(JNIEnv * env,jobject thiz,jstring jFilePath,jstring jFileName,jstring jStatsFile,jstring jCodecName,jboolean asyncMode)30 extern "C" JNIEXPORT int JNICALL Java_com_android_media_benchmark_library_Native_Decode(
31         JNIEnv *env, jobject thiz, jstring jFilePath, jstring jFileName, jstring jStatsFile,
32         jstring jCodecName, jboolean asyncMode) {
33     const char *filePath = env->GetStringUTFChars(jFilePath, nullptr);
34     const char *fileName = env->GetStringUTFChars(jFileName, nullptr);
35     string sFilePath = string(filePath) + string(fileName);
36     UNUSED(thiz);
37     FILE *inputFp = fopen(sFilePath.c_str(), "rb");
38     env->ReleaseStringUTFChars(jFileName, fileName);
39     env->ReleaseStringUTFChars(jFilePath, filePath);
40     if (!inputFp) {
41         ALOGE("Unable to open input file for reading");
42         return -1;
43     }
44 
45     Decoder *decoder = new Decoder();
46     Extractor *extractor = decoder->getExtractor();
47     if (!extractor) {
48         ALOGE("Extractor creation failed");
49         return -1;
50     }
51 
52     // Read file properties
53     struct stat buf;
54     stat(sFilePath.c_str(), &buf);
55     size_t fileSize = buf.st_size;
56     if (fileSize > kMaxBufferSize) {
57         ALOGE("File size greater than maximum buffer size");
58         return -1;
59     }
60     int32_t fd = fileno(inputFp);
61     int32_t trackCount = extractor->initExtractor(fd, fileSize);
62     if (trackCount <= 0) {
63         ALOGE("initExtractor failed");
64         return -1;
65     }
66     for (int curTrack = 0; curTrack < trackCount; curTrack++) {
67         int32_t status = extractor->setupTrackFormat(curTrack);
68         if (status != 0) {
69             ALOGE("Track Format invalid");
70             return -1;
71         }
72 
73         uint8_t *inputBuffer = (uint8_t *) malloc(fileSize);
74         if (!inputBuffer) {
75             ALOGE("Insufficient memory");
76             return -1;
77         }
78 
79         vector<AMediaCodecBufferInfo> frameInfo;
80         AMediaCodecBufferInfo info;
81         uint32_t inputBufferOffset = 0;
82 
83         // Get frame data
84         while (1) {
85             status = extractor->getFrameSample(info);
86             if (status || !info.size) break;
87             // copy the meta data and buffer to be passed to decoder
88             if (inputBufferOffset + info.size > kMaxBufferSize) {
89                 ALOGE("Memory allocated not sufficient");
90                 free(inputBuffer);
91                 return -1;
92             }
93             memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
94             frameInfo.push_back(info);
95             inputBufferOffset += info.size;
96         }
97 
98         const char *codecName = env->GetStringUTFChars(jCodecName, nullptr);
99         string sCodecName = string(codecName);
100         decoder->setupDecoder();
101         status = decoder->decode(inputBuffer, frameInfo, sCodecName, asyncMode);
102         if (status != AMEDIA_OK) {
103             ALOGE("Decode returned error");
104             free(inputBuffer);
105             env->ReleaseStringUTFChars(jCodecName, codecName);
106             return -1;
107         }
108         decoder->deInitCodec();
109         const char *inputReference = env->GetStringUTFChars(jFileName, nullptr);
110         const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
111         string sInputReference = string(inputReference);
112         decoder->dumpStatistics(sInputReference, sCodecName, (asyncMode ? "async" : "sync"),
113                                 statsFile);
114         env->ReleaseStringUTFChars(jCodecName, codecName);
115         env->ReleaseStringUTFChars(jStatsFile, statsFile);
116         env->ReleaseStringUTFChars(jFileName, inputReference);
117         if (inputBuffer) {
118             free(inputBuffer);
119             inputBuffer = nullptr;
120         }
121         decoder->resetDecoder();
122     }
123     if (inputFp) {
124         fclose(inputFp);
125         inputFp = nullptr;
126     }
127     extractor->deInitExtractor();
128     delete decoder;
129     return 0;
130 }
131