• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NativeEncoder"
19 
20 #include <jni.h>
21 #include <sys/stat.h>
22 #include <fstream>
23 #include <iostream>
24 
25 #include <android/log.h>
26 
27 #include "Decoder.h"
28 #include "Encoder.h"
29 
30 #include <stdio.h>
31 
32 constexpr int32_t ENCODE_DEFAULT_FRAME_RATE = 25;
33 constexpr int32_t ENCODE_DEFAULT_AUDIO_BIT_RATE = 128000 /* 128 Kbps */;
34 constexpr int32_t ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
35 constexpr int32_t ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
36 
Java_com_android_media_benchmark_library_Native_Encode(JNIEnv * env,jobject thiz,jstring jFilePath,jstring jFileName,jstring jOutFilePath,jstring jStatsFile,jstring jCodecName)37 extern "C" JNIEXPORT int JNICALL Java_com_android_media_benchmark_library_Native_Encode(
38         JNIEnv *env, jobject thiz, jstring jFilePath, jstring jFileName, jstring jOutFilePath,
39         jstring jStatsFile, jstring jCodecName) {
40     const char *filePath = env->GetStringUTFChars(jFilePath, nullptr);
41     const char *fileName = env->GetStringUTFChars(jFileName, nullptr);
42     string sFilePath = string(filePath) + string(fileName);
43     UNUSED(thiz);
44     FILE *inputFp = fopen(sFilePath.c_str(), "rb");
45     env->ReleaseStringUTFChars(jFileName, fileName);
46     env->ReleaseStringUTFChars(jFilePath, filePath);
47     if (!inputFp) {
48         ALOGE("Unable to open input file for reading");
49         return -1;
50     }
51 
52     Decoder *decoder = new Decoder();
53     Extractor *extractor = decoder->getExtractor();
54     if (!extractor) {
55         ALOGE("Extractor creation failed");
56         return -1;
57     }
58 
59     // Read file properties
60     struct stat buf;
61     stat(sFilePath.c_str(), &buf);
62     size_t fileSize = buf.st_size;
63     if (fileSize > kMaxBufferSize) {
64         ALOGE("File size greater than maximum buffer size");
65         return -1;
66     }
67     int32_t fd = fileno(inputFp);
68     int32_t trackCount = extractor->initExtractor(fd, fileSize);
69     if (trackCount <= 0) {
70         ALOGE("initExtractor failed");
71         return -1;
72     }
73 
74     for (int curTrack = 0; curTrack < trackCount; curTrack++) {
75         int32_t status = extractor->setupTrackFormat(curTrack);
76         if (status != 0) {
77             ALOGE("Track Format invalid");
78             return -1;
79         }
80         uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
81         if (!inputBuffer) {
82             ALOGE("Insufficient memory");
83             return -1;
84         }
85         vector<AMediaCodecBufferInfo> frameInfo;
86         AMediaCodecBufferInfo info;
87         uint32_t inputBufferOffset = 0;
88 
89         // Get frame data
90         while (1) {
91             status = extractor->getFrameSample(info);
92             if (status || !info.size) break;
93             // copy the meta data and buffer to be passed to decoder
94             if (inputBufferOffset + info.size > kMaxBufferSize) {
95                 ALOGE("Memory allocated not sufficient");
96                 free(inputBuffer);
97                 return -1;
98             }
99             memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
100             frameInfo.push_back(info);
101             inputBufferOffset += info.size;
102         }
103         string decName = "";
104         const char *outputFilePath = env->GetStringUTFChars(jOutFilePath, nullptr);
105         FILE *outFp = fopen(outputFilePath, "wb");
106         if (outFp == nullptr) {
107             ALOGE("%s - File failed to open for writing!", outputFilePath);
108             free(inputBuffer);
109             return -1;
110         }
111         decoder->setupDecoder();
112         status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
113         if (status != AMEDIA_OK) {
114             ALOGE("Decode returned error");
115             free(inputBuffer);
116             return -1;
117         }
118 
119         AMediaFormat *decoderFormat = decoder->getFormat();
120         AMediaFormat *format = extractor->getFormat();
121         if (inputBuffer) {
122             free(inputBuffer);
123             inputBuffer = nullptr;
124         }
125         const char *mime = nullptr;
126         AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
127         if (!mime) {
128             ALOGE("Error in AMediaFormat_getString");
129             return -1;
130         }
131         ifstream eleStream;
132         eleStream.open(outputFilePath, ifstream::binary | ifstream::ate);
133         if (!eleStream.is_open()) {
134             ALOGE("%s - File failed to open for reading!", outputFilePath);
135             env->ReleaseStringUTFChars(jOutFilePath, outputFilePath);
136             return -1;
137         }
138         const char *codecName = env->GetStringUTFChars(jCodecName, NULL);
139         const char *inputReference = env->GetStringUTFChars(jFileName, nullptr);
140         string sCodecName = string(codecName);
141         string sInputReference = string(inputReference);
142 
143         bool asyncMode[2] = {true, false};
144         for (int i = 0; i < 2; i++) {
145             size_t eleSize = eleStream.tellg();
146             eleStream.seekg(0, ifstream::beg);
147 
148             // Get encoder params
149             encParameter encParams;
150             if (!strncmp(mime, "video/", 6)) {
151                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &encParams.width);
152                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &encParams.height);
153                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &encParams.frameRate);
154                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &encParams.bitrate);
155                 if (encParams.bitrate <= 0 || encParams.frameRate <= 0) {
156                     encParams.frameRate = ENCODE_DEFAULT_FRAME_RATE;
157                     if (!strcmp(mime, "video/3gpp") || !strcmp(mime, "video/mp4v-es")) {
158                         encParams.bitrate = ENCODE_MIN_BIT_RATE /* 600 Kbps */;
159                     } else {
160                         encParams.bitrate = ENCODE_DEFAULT_BIT_RATE /* 8 Mbps */;
161                     }
162                 }
163                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_PROFILE, &encParams.profile);
164                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_LEVEL, &encParams.level);
165                 AMediaFormat_getInt32(decoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT,
166                                       &encParams.colorFormat);
167             } else {
168                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &encParams.sampleRate);
169                 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
170                                       &encParams.numChannels);
171                 encParams.bitrate = ENCODE_DEFAULT_AUDIO_BIT_RATE;
172             }
173             Encoder *encoder = new Encoder();
174             encoder->setupEncoder();
175             status = encoder->encode(sCodecName, eleStream, eleSize, asyncMode[i], encParams,
176                                      (char *)mime);
177             if (status != AMEDIA_OK) {
178                 ALOGE("Encoder returned error");
179                 return -1;
180             }
181             ALOGV("Encoding complete with codec %s for asyncMode = %d", sCodecName.c_str(),
182                   asyncMode[i]);
183             encoder->deInitCodec();
184             const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
185             encoder->dumpStatistics(sInputReference, extractor->getClipDuration(), sCodecName,
186                                     (asyncMode[i] ? "async" : "sync"), statsFile);
187             env->ReleaseStringUTFChars(jStatsFile, statsFile);
188             encoder->resetEncoder();
189             delete encoder;
190             encoder = nullptr;
191         }
192         eleStream.close();
193         if (outFp) {
194             fclose(outFp);
195             outFp = nullptr;
196         }
197         env->ReleaseStringUTFChars(jFileName, inputReference);
198         env->ReleaseStringUTFChars(jCodecName, codecName);
199         env->ReleaseStringUTFChars(jOutFilePath, outputFilePath);
200         if (format) {
201             AMediaFormat_delete(format);
202             format = nullptr;
203         }
204         if (decoderFormat) {
205             AMediaFormat_delete(decoderFormat);
206             decoderFormat = nullptr;
207         }
208         decoder->deInitCodec();
209         decoder->resetDecoder();
210     }
211     if (inputFp) {
212         fclose(inputFp);
213         inputFp = nullptr;
214     }
215     extractor->deInitExtractor();
216     delete decoder;
217     return 0;
218 }
219