blob: 08c6a5000614cdd5e53cd53357b73cb6621ad334 [file] [log] [blame]
James Dong1d7491b2010-01-19 17:45:38 -08001/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "MediaProfiles"
21
22#include <stdlib.h>
23#include <utils/Log.h>
24#include <utils/Vector.h>
25#include <cutils/properties.h>
Elliott Hughes242b4002015-07-10 11:09:23 -070026#include <expat.h>
James Dong1d7491b2010-01-19 17:45:38 -080027#include <media/MediaProfiles.h>
James Dongf1d5aa12012-02-06 23:46:37 -080028#include <media/stagefright/foundation/ADebug.h>
James Dong6c6b4d02012-03-12 14:37:53 -070029#include <OMX_Video.h>
Pawin Vongmasad7db05b2017-05-03 04:19:20 -070030#include <sys/stat.h>
James Dong1d7491b2010-01-19 17:45:38 -080031
32namespace android {
33
Pawin Vongmasad7db05b2017-05-03 04:19:20 -070034constexpr char const * const MediaProfiles::xmlFiles[];
James Dong1d7491b2010-01-19 17:45:38 -080035Mutex MediaProfiles::sLock;
36bool MediaProfiles::sIsInitialized = false;
37MediaProfiles *MediaProfiles::sInstance = NULL;
38
39const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
40 {"h263", VIDEO_ENCODER_H263},
41 {"h264", VIDEO_ENCODER_H264},
Wonsik Kim9aa87d42015-12-07 13:52:02 +090042 {"m4v", VIDEO_ENCODER_MPEG_4_SP},
43 {"hevc", VIDEO_ENCODER_HEVC}
James Dong1d7491b2010-01-19 17:45:38 -080044};
45
46const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
Dave Burkeaeb8fd42012-04-19 00:14:27 -070047 {"amrnb", AUDIO_ENCODER_AMR_NB},
48 {"amrwb", AUDIO_ENCODER_AMR_WB},
49 {"aac", AUDIO_ENCODER_AAC},
Dave Burkef60c6602012-04-28 21:58:22 -070050 {"heaac", AUDIO_ENCODER_HE_AAC},
Ray Essickdf27b042018-11-27 18:55:09 -080051 {"aaceld", AUDIO_ENCODER_AAC_ELD},
52 {"opus", AUDIO_ENCODER_OPUS}
James Dong1d7491b2010-01-19 17:45:38 -080053};
54
55const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
56 {"3gp", OUTPUT_FORMAT_THREE_GPP},
57 {"mp4", OUTPUT_FORMAT_MPEG_4}
58};
59
60const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
61 {"wmv", VIDEO_DECODER_WMV}
62};
63
64const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
65 {"wma", AUDIO_DECODER_WMA}
66};
67
68const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -070069 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -080070 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070071 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070072 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070073 {"480p", CAMCORDER_QUALITY_480P},
74 {"720p", CAMCORDER_QUALITY_720P},
75 {"1080p", CAMCORDER_QUALITY_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -070076 {"2160p", CAMCORDER_QUALITY_2160P},
James Dong669012d2011-09-19 16:27:31 -070077 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070078
79 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
80 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
81 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070082 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070083 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
84 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070085 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -070086 {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P},
James Dong669012d2011-09-19 16:27:31 -070087 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
Zhijun Hee0790972014-07-23 15:17:26 -070088
89 {"highspeedlow", CAMCORDER_QUALITY_HIGH_SPEED_LOW},
90 {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH},
91 {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P},
92 {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
93 {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
Zhijun He9520aa62014-09-09 16:18:31 -070094 {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
James Dong1d7491b2010-01-19 17:45:38 -080095};
96
Glenn Kasten80520382014-01-31 16:49:31 -080097#if LOG_NDEBUG
98#define UNUSED __unused
99#else
100#define UNUSED
101#endif
102
James Dong1d7491b2010-01-19 17:45:38 -0800103/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800104MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800105{
Steve Block3856b092011-10-20 11:56:00 +0100106 ALOGV("video codec:");
107 ALOGV("codec = %d", codec.mCodec);
108 ALOGV("bit rate: %d", codec.mBitRate);
109 ALOGV("frame width: %d", codec.mFrameWidth);
110 ALOGV("frame height: %d", codec.mFrameHeight);
111 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800112}
113
114/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800115MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800116{
Steve Block3856b092011-10-20 11:56:00 +0100117 ALOGV("audio codec:");
118 ALOGV("codec = %d", codec.mCodec);
119 ALOGV("bit rate: %d", codec.mBitRate);
120 ALOGV("sample rate: %d", codec.mSampleRate);
121 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800122}
123
124/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800125MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800126{
Steve Block3856b092011-10-20 11:56:00 +0100127 ALOGV("video encoder cap:");
128 ALOGV("codec = %d", cap.mCodec);
129 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
130 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
131 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
132 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800133}
134
135/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800136MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800137{
Steve Block3856b092011-10-20 11:56:00 +0100138 ALOGV("audio encoder cap:");
139 ALOGV("codec = %d", cap.mCodec);
140 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
141 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
142 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800143}
144
145/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800146MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800147{
Steve Block3856b092011-10-20 11:56:00 +0100148 ALOGV("video decoder cap:");
149 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800150}
151
152/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800153MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800154{
Steve Block3856b092011-10-20 11:56:00 +0100155 ALOGV("audio codec cap:");
156 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800157}
158
159/*static*/ int
Glenn Kastenb187de12014-12-30 08:18:15 -0800160MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings,
161 const char *name)
James Dong1d7491b2010-01-19 17:45:38 -0800162{
163 int tag = -1;
164 for (size_t i = 0; i < nMappings; ++i) {
165 if (!strcmp(map[i].name, name)) {
166 tag = map[i].tag;
167 break;
168 }
169 }
170 return tag;
171}
172
173/*static*/ MediaProfiles::VideoCodec*
174MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
175{
176 CHECK(!strcmp("codec", atts[0]) &&
177 !strcmp("bitRate", atts[2]) &&
178 !strcmp("width", atts[4]) &&
179 !strcmp("height", atts[6]) &&
180 !strcmp("frameRate", atts[8]));
181
182 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
183 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
184 CHECK(codec != -1);
185
186 MediaProfiles::VideoCodec *videoCodec =
187 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
188 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
189 logVideoCodec(*videoCodec);
190
191 size_t nCamcorderProfiles;
192 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
193 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
194 return videoCodec;
195}
196
197/*static*/ MediaProfiles::AudioCodec*
198MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
199{
200 CHECK(!strcmp("codec", atts[0]) &&
201 !strcmp("bitRate", atts[2]) &&
202 !strcmp("sampleRate", atts[4]) &&
203 !strcmp("channels", atts[6]));
204 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
205 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
206 CHECK(codec != -1);
207
208 MediaProfiles::AudioCodec *audioCodec =
209 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
210 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
211 logAudioCodec(*audioCodec);
212
213 size_t nCamcorderProfiles;
214 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
215 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
216 return audioCodec;
217}
218/*static*/ MediaProfiles::AudioDecoderCap*
219MediaProfiles::createAudioDecoderCap(const char **atts)
220{
221 CHECK(!strcmp("name", atts[0]) &&
222 !strcmp("enabled", atts[2]));
223
224 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
225 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
226 CHECK(codec != -1);
227
228 MediaProfiles::AudioDecoderCap *cap =
229 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
230 logAudioDecoderCap(*cap);
231 return cap;
232}
233
234/*static*/ MediaProfiles::VideoDecoderCap*
235MediaProfiles::createVideoDecoderCap(const char **atts)
236{
237 CHECK(!strcmp("name", atts[0]) &&
238 !strcmp("enabled", atts[2]));
239
240 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
241 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
242 CHECK(codec != -1);
243
244 MediaProfiles::VideoDecoderCap *cap =
245 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
246 logVideoDecoderCap(*cap);
247 return cap;
248}
249
250/*static*/ MediaProfiles::VideoEncoderCap*
251MediaProfiles::createVideoEncoderCap(const char **atts)
252{
253 CHECK(!strcmp("name", atts[0]) &&
254 !strcmp("enabled", atts[2]) &&
255 !strcmp("minBitRate", atts[4]) &&
256 !strcmp("maxBitRate", atts[6]) &&
257 !strcmp("minFrameWidth", atts[8]) &&
258 !strcmp("maxFrameWidth", atts[10]) &&
259 !strcmp("minFrameHeight", atts[12]) &&
260 !strcmp("maxFrameHeight", atts[14]) &&
261 !strcmp("minFrameRate", atts[16]) &&
262 !strcmp("maxFrameRate", atts[18]));
263
264 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
265 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
266 CHECK(codec != -1);
267
268 MediaProfiles::VideoEncoderCap *cap =
269 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
270 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
271 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
272 logVideoEncoderCap(*cap);
273 return cap;
274}
275
276/*static*/ MediaProfiles::AudioEncoderCap*
277MediaProfiles::createAudioEncoderCap(const char **atts)
278{
279 CHECK(!strcmp("name", atts[0]) &&
280 !strcmp("enabled", atts[2]) &&
281 !strcmp("minBitRate", atts[4]) &&
282 !strcmp("maxBitRate", atts[6]) &&
283 !strcmp("minSampleRate", atts[8]) &&
284 !strcmp("maxSampleRate", atts[10]) &&
285 !strcmp("minChannels", atts[12]) &&
286 !strcmp("maxChannels", atts[14]));
287
288 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
289 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
290 CHECK(codec != -1);
291
292 MediaProfiles::AudioEncoderCap *cap =
Glenn Kastenb187de12014-12-30 08:18:15 -0800293 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]),
294 atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15]));
James Dong1d7491b2010-01-19 17:45:38 -0800295 logAudioEncoderCap(*cap);
296 return cap;
297}
298
299/*static*/ output_format
300MediaProfiles::createEncoderOutputFileFormat(const char **atts)
301{
302 CHECK(!strcmp("name", atts[0]));
303
304 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
305 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
306 CHECK(format != -1);
307
308 return static_cast<output_format>(format);
309}
310
James Dong2a7e0a12011-02-28 21:07:39 -0800311static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
312 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
313 if (cameraId == cameraIds[i]) {
314 return true;
315 }
316 }
317 return false;
318}
319
James Dong1d7491b2010-01-19 17:45:38 -0800320/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800321MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800322{
323 CHECK(!strcmp("quality", atts[0]) &&
324 !strcmp("fileFormat", atts[2]) &&
325 !strcmp("duration", atts[4]));
326
Glenn Kastenb187de12014-12-30 08:18:15 -0800327 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/
328 sizeof(sCamcorderQualityNameMap[0]);
James Dong1d7491b2010-01-19 17:45:38 -0800329 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
330 CHECK(quality != -1);
331
332 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
333 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
334 CHECK(fileFormat != -1);
335
336 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800337 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800338 if (!isCameraIdFound(cameraId, cameraIds)) {
339 cameraIds.add(cameraId);
340 }
James Dong1d7491b2010-01-19 17:45:38 -0800341 profile->mFileFormat = static_cast<output_format>(fileFormat);
342 profile->mQuality = static_cast<camcorder_quality>(quality);
343 profile->mDuration = atoi(atts[5]);
344 return profile;
345}
346
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800347MediaProfiles::ImageEncodingQualityLevels*
348MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
349{
350 int n = mImageEncodingQualityLevels.size();
351 for (int i = 0; i < n; i++) {
352 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
353 if (levels->mCameraId == cameraId) {
354 return levels;
355 }
356 }
357 return NULL;
358}
359
360void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800361{
362 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800363 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800364 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800365 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
366
367 if (levels == NULL) {
368 levels = new ImageEncodingQualityLevels();
369 levels->mCameraId = cameraId;
370 mImageEncodingQualityLevels.add(levels);
371 }
372
373 levels->mLevels.add(quality);
374}
375
376/*static*/ int
377MediaProfiles::getCameraId(const char** atts)
378{
379 if (!atts[0]) return 0; // default cameraId = 0
380 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800381 return atoi(atts[1]);
382}
383
James Dong0f056292011-05-09 18:49:31 -0700384void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
385{
Eric Laurentb1eb1a02012-10-22 17:44:24 -0700386 int offsetTimeMs = 1000;
James Dong0f056292011-05-09 18:49:31 -0700387 if (atts[2]) {
388 CHECK(!strcmp("startOffsetMs", atts[2]));
389 offsetTimeMs = atoi(atts[3]);
390 }
391
Steve Block3856b092011-10-20 11:56:00 +0100392 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700393 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
394}
Hong Tengcabd5f82011-07-06 18:33:09 -0700395
James Dong1d7491b2010-01-19 17:45:38 -0800396/*static*/ void
397MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
398{
399 MediaProfiles *profiles = (MediaProfiles *) userData;
400 if (strcmp("Video", name) == 0) {
401 createVideoCodec(atts, profiles);
402 } else if (strcmp("Audio", name) == 0) {
403 createAudioCodec(atts, profiles);
404 } else if (strcmp("VideoEncoderCap", name) == 0 &&
405 strcmp("true", atts[3]) == 0) {
406 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
407 } else if (strcmp("AudioEncoderCap", name) == 0 &&
408 strcmp("true", atts[3]) == 0) {
409 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
410 } else if (strcmp("VideoDecoderCap", name) == 0 &&
411 strcmp("true", atts[3]) == 0) {
412 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
413 } else if (strcmp("AudioDecoderCap", name) == 0 &&
414 strcmp("true", atts[3]) == 0) {
415 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
416 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
417 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800418 } else if (strcmp("CamcorderProfiles", name) == 0) {
419 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700420 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800421 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800422 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800423 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800424 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800425 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800426 }
427}
428
James Dong2a7e0a12011-02-28 21:07:39 -0800429static bool isCamcorderProfile(camcorder_quality quality) {
430 return quality >= CAMCORDER_QUALITY_LIST_START &&
431 quality <= CAMCORDER_QUALITY_LIST_END;
432}
433
434static bool isTimelapseProfile(camcorder_quality quality) {
435 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
436 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
437}
438
Zhijun Hee0790972014-07-23 15:17:26 -0700439static bool isHighSpeedProfile(camcorder_quality quality) {
440 return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
441 quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END;
442}
443
James Dong2a7e0a12011-02-28 21:07:39 -0800444void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700445 ALOGV("Number of camera ids: %zu", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800446 CHECK(cameraIds.size() > 0);
447 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
448 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
449 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
450 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
451 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
452 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
453 if ((j & 1) == 0) { // low resolution
454 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
455 } else { // high resolution
456 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
457 }
458 }
459 }
460}
461
462int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
463 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
464 if (mCameraIds[i] == cameraId) {
465 return i;
466 }
467 }
468 return -1;
469}
470
471void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
472 if (sIsInitialized) {
473 return;
474 }
475
476 initRequiredProfileRefs(mCameraIds);
477
478 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
479 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
480 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
481
482 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
483 int cameraId = mCamcorderProfiles[i]->mCameraId;
484 int index = -1;
485 int refIndex = getRequiredProfileRefIndex(cameraId);
486 CHECK(refIndex != -1);
487 RequiredProfileRefInfo *info;
488 camcorder_quality refQuality;
James Dong2a7e0a12011-02-28 21:07:39 -0800489
Zhijun Hee0790972014-07-23 15:17:26 -0700490 // Check high and low from either camcorder profile, timelapse profile
491 // or high speed profile, but not all of them. Default, check camcorder profile
James Dong2a7e0a12011-02-28 21:07:39 -0800492 size_t j = 0;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200493 size_t o = 2;
James Dong2a7e0a12011-02-28 21:07:39 -0800494 if (isTimelapseProfile(quality)) {
495 // Check timelapse profile instead.
496 j = 2;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200497 o = kNumRequiredProfiles;
Zhijun Hee0790972014-07-23 15:17:26 -0700498 } else if (isHighSpeedProfile(quality)) {
499 // Skip the check for high speed profile.
500 continue;
James Dong2a7e0a12011-02-28 21:07:39 -0800501 } else {
502 // Must be camcorder profile.
503 CHECK(isCamcorderProfile(quality));
504 }
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200505 for (; j < o; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800506 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
507 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
508 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
509 continue;
510 }
511 switch (j) {
512 case 0:
513 refQuality = CAMCORDER_QUALITY_LOW;
514 break;
515 case 1:
516 refQuality = CAMCORDER_QUALITY_HIGH;
517 break;
518 case 2:
519 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
520 break;
521 case 3:
522 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
523 break;
524 default:
525 CHECK(!"Should never reach here");
526 }
527
528 if (!info->mHasRefProfile) {
529 index = getCamcorderProfileIndex(cameraId, refQuality);
530 }
531 if (index == -1) {
532 // New high or low quality profile is found.
533 // Update its reference.
534 info->mHasRefProfile = true;
535 info->mRefProfileIndex = i;
536 info->mResolutionProduct = product;
537 }
538 }
539 }
540
541 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
542 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
543 int refIndex = getRequiredProfileRefIndex(cameraId);
544 CHECK(refIndex != -1);
545 RequiredProfileRefInfo *info =
546 &mRequiredProfileRefs[refIndex].mRefs[j];
547
548 if (info->mHasRefProfile) {
549
George Burgess IV215545b2018-07-25 10:06:30 -0700550 std::unique_ptr<CamcorderProfile> profile =
551 std::make_unique<CamcorderProfile>(
James Dong2a7e0a12011-02-28 21:07:39 -0800552 *mCamcorderProfiles[info->mRefProfileIndex]);
553
554 // Overwrite the quality
555 switch (j % kNumRequiredProfiles) {
556 case 0:
557 profile->mQuality = CAMCORDER_QUALITY_LOW;
558 break;
559 case 1:
560 profile->mQuality = CAMCORDER_QUALITY_HIGH;
561 break;
562 case 2:
563 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
564 break;
565 case 3:
566 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
567 break;
568 default:
569 CHECK(!"Should never come here");
570 }
571
572 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
573 if (index != -1) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700574 ALOGV("Profile quality %d for camera %zu already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800575 profile->mQuality, cameraId);
576 CHECK(index == refIndex);
577 continue;
578 }
579
580 // Insert the new profile
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700581 ALOGV("Add a profile: quality %d=>%d for camera %zu",
James Dong2a7e0a12011-02-28 21:07:39 -0800582 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
583 profile->mQuality, cameraId);
584
George Burgess IV215545b2018-07-25 10:06:30 -0700585 mCamcorderProfiles.add(profile.release());
James Dong2a7e0a12011-02-28 21:07:39 -0800586 }
587 }
588 }
589}
590
James Dong1d7491b2010-01-19 17:45:38 -0800591/*static*/ MediaProfiles*
592MediaProfiles::getInstance()
593{
Steve Block3856b092011-10-20 11:56:00 +0100594 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800595 Mutex::Autolock lock(sLock);
596 if (!sIsInitialized) {
597 char value[PROPERTY_VALUE_MAX];
598 if (property_get("media.settings.xml", value, NULL) <= 0) {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700599 const char* xmlFile = nullptr;
600 for (auto const& f : xmlFiles) {
601 if (checkXmlFile(f)) {
602 xmlFile = f;
603 break;
604 }
605 }
606 if (xmlFile == nullptr) {
607 ALOGW("Could not find a validated xml file. "
608 "Using the default instance instead.");
James Dong1d7491b2010-01-19 17:45:38 -0800609 sInstance = createDefaultInstance();
610 } else {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700611 sInstance = createInstanceFromXmlFile(xmlFile);
James Dong1d7491b2010-01-19 17:45:38 -0800612 }
613 } else {
614 sInstance = createInstanceFromXmlFile(value);
615 }
James Dong2a7e0a12011-02-28 21:07:39 -0800616 CHECK(sInstance != NULL);
617 sInstance->checkAndAddRequiredProfilesIfNecessary();
618 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800619 }
620
621 return sInstance;
622}
623
624/*static*/ MediaProfiles::VideoEncoderCap*
625MediaProfiles::createDefaultH263VideoEncoderCap()
626{
627 return new MediaProfiles::VideoEncoderCap(
628 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
629}
630
631/*static*/ MediaProfiles::VideoEncoderCap*
632MediaProfiles::createDefaultM4vVideoEncoderCap()
633{
634 return new MediaProfiles::VideoEncoderCap(
635 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
636}
637
638
639/*static*/ void
640MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
641{
642 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
643 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
644}
645
646/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700647MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700648{
649 MediaProfiles::VideoCodec *videoCodec =
650 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
651
652 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
653 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
654 profile->mCameraId = 0;
655 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700656 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700657 profile->mDuration = 60;
658 profile->mVideoCodec = videoCodec;
659 profile->mAudioCodec = audioCodec;
660 return profile;
661}
662
663/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700664MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800665{
666 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700667 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800668
669 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800670 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
671 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800672 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700673 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800674 profile->mDuration = 60;
675 profile->mVideoCodec = videoCodec;
676 profile->mAudioCodec = audioCodec;
677 return profile;
678}
679
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700680/*static*/ void
681MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
682 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
683 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -0800684 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
685 CAMCORDER_QUALITY_TIME_LAPSE_LOW);
686 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
687 CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700688}
689
690/*static*/ void
691MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
692 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
693 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -0800694 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
695 CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
696 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
697 CAMCORDER_QUALITY_TIME_LAPSE_480P);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700698}
699
James Dong1d7491b2010-01-19 17:45:38 -0800700/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700701MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800702{
703 MediaProfiles::VideoCodec *videoCodec =
704 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
705
706 MediaProfiles::AudioCodec *audioCodec =
707 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
708
709 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800710 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800711 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700712 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800713 profile->mDuration = 30;
714 profile->mVideoCodec = videoCodec;
715 profile->mAudioCodec = audioCodec;
716 return profile;
717}
718
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700719/*static*/ MediaProfiles::CamcorderProfile*
720MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
721{
722 MediaProfiles::VideoCodec *videoCodec =
723 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
724
725 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
726 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
727 profile->mCameraId = 0;
728 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
729 profile->mQuality = quality;
730 profile->mDuration = 60;
731 profile->mVideoCodec = videoCodec;
732 profile->mAudioCodec = audioCodec;
733 return profile;
734}
735
736/*static*/ void
737MediaProfiles::createDefaultCamcorderLowProfiles(
738 MediaProfiles::CamcorderProfile **lowProfile,
739 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
740 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
741 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
742}
743
744/*static*/ void
745MediaProfiles::createDefaultCamcorderHighProfiles(
746 MediaProfiles::CamcorderProfile **highProfile,
747 MediaProfiles::CamcorderProfile **highSpecificProfile) {
748 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
749 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
750}
751
James Dong1d7491b2010-01-19 17:45:38 -0800752/*static*/ void
753MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
754{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700755 // low camcorder profiles.
756 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
757 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
758 profiles->mCamcorderProfiles.add(lowProfile);
759 profiles->mCamcorderProfiles.add(lowSpecificProfile);
760
761 // high camcorder profiles.
762 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
763 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
764 profiles->mCamcorderProfiles.add(highProfile);
765 profiles->mCamcorderProfiles.add(highSpecificProfile);
766
767 // low camcorder time lapse profiles.
768 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
769 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
770 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
771 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
772
773 // high camcorder time lapse profiles.
774 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
Glenn Kastenb187de12014-12-30 08:18:15 -0800775 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile,
776 &highSpecificTimeLapseProfile);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700777 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
778 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700779
780 // For emulator and other legacy devices which does not have a
781 // media_profiles.xml file, We assume that the default camera id
782 // is 0 and that is the only camera available.
783 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800784}
785
786/*static*/ void
787MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
788{
789 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
790}
791
792/*static*/ void
793MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
794{
795 MediaProfiles::VideoDecoderCap *cap =
796 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
797
798 profiles->mVideoDecoders.add(cap);
799}
800
801/*static*/ void
802MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
803{
804 MediaProfiles::AudioDecoderCap *cap =
805 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
806
807 profiles->mAudioDecoders.add(cap);
808}
809
810/*static*/ void
811MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
812{
813 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
814 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
815}
816
817/*static*/ MediaProfiles::AudioEncoderCap*
818MediaProfiles::createDefaultAmrNBEncoderCap()
819{
820 return new MediaProfiles::AudioEncoderCap(
821 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
822}
823
James Dongf5a83852010-02-23 17:21:44 -0800824/*static*/ void
825MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
826{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800827 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
828 levels->mCameraId = 0;
829 levels->mLevels.add(70);
830 levels->mLevels.add(80);
831 levels->mLevels.add(90);
832 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800833}
834
James Dong1d7491b2010-01-19 17:45:38 -0800835/*static*/ MediaProfiles*
836MediaProfiles::createDefaultInstance()
837{
838 MediaProfiles *profiles = new MediaProfiles;
839 createDefaultCamcorderProfiles(profiles);
840 createDefaultVideoEncoders(profiles);
841 createDefaultAudioEncoders(profiles);
842 createDefaultVideoDecoders(profiles);
843 createDefaultAudioDecoders(profiles);
844 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800845 createDefaultImageEncodingQualityLevels(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800846 return profiles;
847}
848
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700849bool MediaProfiles::checkXmlFile(const char* xmlFile) {
850 struct stat fStat;
851 return stat(xmlFile, &fStat) == 0 && S_ISREG(fStat.st_mode);
852 // TODO: Add validation
853}
854
James Dong1d7491b2010-01-19 17:45:38 -0800855/*static*/ MediaProfiles*
856MediaProfiles::createInstanceFromXmlFile(const char *xml)
857{
858 FILE *fp = NULL;
859 CHECK((fp = fopen(xml, "r")));
860
861 XML_Parser parser = ::XML_ParserCreate(NULL);
862 CHECK(parser != NULL);
863
864 MediaProfiles *profiles = new MediaProfiles();
865 ::XML_SetUserData(parser, profiles);
866 ::XML_SetElementHandler(parser, startElementHandler, NULL);
867
868 /*
869 FIXME:
870 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
871
872 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +0000873 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800874 return UNKNOWN_ERROR;
875 }
876
877 */
878
879 const int BUFF_SIZE = 512;
880 for (;;) {
881 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
882 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000883 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -0800884 delete profiles;
885 profiles = NULL;
886 goto exit;
887 }
888
889 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
890 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000891 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -0800892 delete profiles;
893 profiles = NULL;
894 goto exit;
895 }
896
897 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
898
899 if (bytes_read == 0) break; // done parsing the xml file
900 }
901
902exit:
903 ::XML_ParserFree(parser);
904 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800905 return profiles;
906}
907
908Vector<output_format> MediaProfiles::getOutputFileFormats() const
909{
910 return mEncoderOutputFileFormats; // copy out
911}
912
913Vector<video_encoder> MediaProfiles::getVideoEncoders() const
914{
915 Vector<video_encoder> encoders;
916 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
917 encoders.add(mVideoEncoders[i]->mCodec);
918 }
919 return encoders; // copy out
920}
921
922int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
923{
Steve Block3856b092011-10-20 11:56:00 +0100924 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800925 int index = -1;
926 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
927 if (mVideoEncoders[i]->mCodec == codec) {
928 index = i;
929 break;
930 }
931 }
932 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000933 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800934 return -1;
935 }
936
937 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
938 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
939 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
940 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
941 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
942 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
943 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
944 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
945
Steve Block29357bc2012-01-06 19:20:56 +0000946 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -0800947 return -1;
948}
Hong Tengcabd5f82011-07-06 18:33:09 -0700949
James Dong1d7491b2010-01-19 17:45:38 -0800950Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
951{
952 Vector<audio_encoder> encoders;
953 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
954 encoders.add(mAudioEncoders[i]->mCodec);
955 }
956 return encoders; // copy out
957}
958
959int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
960{
Steve Block3856b092011-10-20 11:56:00 +0100961 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800962 int index = -1;
963 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
964 if (mAudioEncoders[i]->mCodec == codec) {
965 index = i;
966 break;
967 }
968 }
969 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000970 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800971 return -1;
972 }
973
974 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
975 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
976 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
977 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
978 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
979 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
980
Steve Block29357bc2012-01-06 19:20:56 +0000981 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -0800982 return -1;
983}
984
985Vector<video_decoder> MediaProfiles::getVideoDecoders() const
986{
987 Vector<video_decoder> decoders;
988 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
989 decoders.add(mVideoDecoders[i]->mCodec);
990 }
991 return decoders; // copy out
992}
993
994Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
995{
996 Vector<audio_decoder> decoders;
997 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
998 decoders.add(mAudioDecoders[i]->mCodec);
999 }
1000 return decoders; // copy out
1001}
1002
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001003int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001004{
James Dong1d7491b2010-01-19 17:45:38 -08001005 int index = -1;
1006 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001007 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1008 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001009 index = i;
1010 break;
1011 }
1012 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001013 return index;
1014}
1015
1016int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1017 int cameraId,
1018 camcorder_quality quality) const
1019{
Steve Block3856b092011-10-20 11:56:00 +01001020 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001021 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001022
1023 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001024 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001025 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001026 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001027 return -1;
1028 }
1029
James Dongf5a83852010-02-23 17:21:44 -08001030 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001031 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1032 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1033 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1034 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1035 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1036 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1037 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1038 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1039 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1040 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1041
Steve Block29357bc2012-01-06 19:20:56 +00001042 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001043 return -1;
1044}
1045
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001046bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1047{
1048 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1049}
1050
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001051Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001052{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001053 Vector<int> result;
1054 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1055 if (levels != NULL) {
1056 result = levels->mLevels; // copy out
1057 }
1058 return result;
James Dongf5a83852010-02-23 17:21:44 -08001059}
1060
James Dong0f056292011-05-09 18:49:31 -07001061int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1062 int offsetTimeMs = -1;
1063 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1064 if (index >= 0) {
1065 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1066 }
Steve Block3856b092011-10-20 11:56:00 +01001067 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001068 return offsetTimeMs;
1069}
1070
James Dong1d7491b2010-01-19 17:45:38 -08001071MediaProfiles::~MediaProfiles()
1072{
1073 CHECK("destructor should never be called" == 0);
1074#if 0
1075 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1076 delete mAudioEncoders[i];
1077 }
1078 mAudioEncoders.clear();
1079
1080 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1081 delete mVideoEncoders[i];
1082 }
1083 mVideoEncoders.clear();
1084
1085 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1086 delete mVideoDecoders[i];
1087 }
1088 mVideoDecoders.clear();
1089
1090 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1091 delete mAudioDecoders[i];
1092 }
1093 mAudioDecoders.clear();
1094
1095 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1096 delete mCamcorderProfiles[i];
1097 }
1098 mCamcorderProfiles.clear();
1099#endif
1100}
1101} // namespace android