blob: ae0061ffb92bf65066c573ba500b8bb98eaf333c [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 Hughese8057dd2012-09-09 14:58:14 -070026#include <libexpat/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>
James Dong1d7491b2010-01-19 17:45:38 -080030
31namespace android {
32
33Mutex MediaProfiles::sLock;
34bool MediaProfiles::sIsInitialized = false;
35MediaProfiles *MediaProfiles::sInstance = NULL;
36
37const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
38 {"h263", VIDEO_ENCODER_H263},
39 {"h264", VIDEO_ENCODER_H264},
40 {"m4v", VIDEO_ENCODER_MPEG_4_SP}
41};
42
43const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
Dave Burkeaeb8fd42012-04-19 00:14:27 -070044 {"amrnb", AUDIO_ENCODER_AMR_NB},
45 {"amrwb", AUDIO_ENCODER_AMR_WB},
46 {"aac", AUDIO_ENCODER_AAC},
Dave Burkef60c6602012-04-28 21:58:22 -070047 {"heaac", AUDIO_ENCODER_HE_AAC},
48 {"aaceld", AUDIO_ENCODER_AAC_ELD}
James Dong1d7491b2010-01-19 17:45:38 -080049};
50
51const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
52 {"3gp", OUTPUT_FORMAT_THREE_GPP},
53 {"mp4", OUTPUT_FORMAT_MPEG_4}
54};
55
56const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
57 {"wmv", VIDEO_DECODER_WMV}
58};
59
60const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
61 {"wma", AUDIO_DECODER_WMA}
62};
63
64const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -070065 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -080066 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070067 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070068 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070069 {"480p", CAMCORDER_QUALITY_480P},
70 {"720p", CAMCORDER_QUALITY_720P},
71 {"1080p", CAMCORDER_QUALITY_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -070072 {"2160p", CAMCORDER_QUALITY_2160P},
James Dong669012d2011-09-19 16:27:31 -070073 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070074
75 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
76 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
77 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070078 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070079 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
80 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070081 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -070082 {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P},
James Dong669012d2011-09-19 16:27:31 -070083 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
Zhijun Hee0790972014-07-23 15:17:26 -070084
85 {"highspeedlow", CAMCORDER_QUALITY_HIGH_SPEED_LOW},
86 {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH},
87 {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P},
88 {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
89 {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
Zhijun He9520aa62014-09-09 16:18:31 -070090 {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
James Dong1d7491b2010-01-19 17:45:38 -080091};
92
Glenn Kasten80520382014-01-31 16:49:31 -080093#if LOG_NDEBUG
94#define UNUSED __unused
95#else
96#define UNUSED
97#endif
98
James Dong1d7491b2010-01-19 17:45:38 -080099/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800100MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800101{
Steve Block3856b092011-10-20 11:56:00 +0100102 ALOGV("video codec:");
103 ALOGV("codec = %d", codec.mCodec);
104 ALOGV("bit rate: %d", codec.mBitRate);
105 ALOGV("frame width: %d", codec.mFrameWidth);
106 ALOGV("frame height: %d", codec.mFrameHeight);
107 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800108}
109
110/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800111MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800112{
Steve Block3856b092011-10-20 11:56:00 +0100113 ALOGV("audio codec:");
114 ALOGV("codec = %d", codec.mCodec);
115 ALOGV("bit rate: %d", codec.mBitRate);
116 ALOGV("sample rate: %d", codec.mSampleRate);
117 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800118}
119
120/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800121MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800122{
Steve Block3856b092011-10-20 11:56:00 +0100123 ALOGV("video encoder cap:");
124 ALOGV("codec = %d", cap.mCodec);
125 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
126 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
127 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
128 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800129}
130
131/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800132MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800133{
Steve Block3856b092011-10-20 11:56:00 +0100134 ALOGV("audio encoder cap:");
135 ALOGV("codec = %d", cap.mCodec);
136 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
137 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
138 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800139}
140
141/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800142MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800143{
Steve Block3856b092011-10-20 11:56:00 +0100144 ALOGV("video decoder cap:");
145 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800146}
147
148/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800149MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800150{
Steve Block3856b092011-10-20 11:56:00 +0100151 ALOGV("audio codec cap:");
152 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800153}
154
Hong Tengcabd5f82011-07-06 18:33:09 -0700155/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800156MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED)
Hong Tengcabd5f82011-07-06 18:33:09 -0700157{
Steve Block3856b092011-10-20 11:56:00 +0100158 ALOGV("videoeditor cap:");
159 ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
160 ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
161 ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
162 ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
Hong Tengcabd5f82011-07-06 18:33:09 -0700163}
164
James Dong1d7491b2010-01-19 17:45:38 -0800165/*static*/ int
Glenn Kastenb187de12014-12-30 08:18:15 -0800166MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings,
167 const char *name)
James Dong1d7491b2010-01-19 17:45:38 -0800168{
169 int tag = -1;
170 for (size_t i = 0; i < nMappings; ++i) {
171 if (!strcmp(map[i].name, name)) {
172 tag = map[i].tag;
173 break;
174 }
175 }
176 return tag;
177}
178
179/*static*/ MediaProfiles::VideoCodec*
180MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
181{
182 CHECK(!strcmp("codec", atts[0]) &&
183 !strcmp("bitRate", atts[2]) &&
184 !strcmp("width", atts[4]) &&
185 !strcmp("height", atts[6]) &&
186 !strcmp("frameRate", atts[8]));
187
188 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
189 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
190 CHECK(codec != -1);
191
192 MediaProfiles::VideoCodec *videoCodec =
193 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
194 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
195 logVideoCodec(*videoCodec);
196
197 size_t nCamcorderProfiles;
198 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
199 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
200 return videoCodec;
201}
202
203/*static*/ MediaProfiles::AudioCodec*
204MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
205{
206 CHECK(!strcmp("codec", atts[0]) &&
207 !strcmp("bitRate", atts[2]) &&
208 !strcmp("sampleRate", atts[4]) &&
209 !strcmp("channels", atts[6]));
210 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
211 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
212 CHECK(codec != -1);
213
214 MediaProfiles::AudioCodec *audioCodec =
215 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
216 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
217 logAudioCodec(*audioCodec);
218
219 size_t nCamcorderProfiles;
220 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
221 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
222 return audioCodec;
223}
224/*static*/ MediaProfiles::AudioDecoderCap*
225MediaProfiles::createAudioDecoderCap(const char **atts)
226{
227 CHECK(!strcmp("name", atts[0]) &&
228 !strcmp("enabled", atts[2]));
229
230 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
231 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
232 CHECK(codec != -1);
233
234 MediaProfiles::AudioDecoderCap *cap =
235 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
236 logAudioDecoderCap(*cap);
237 return cap;
238}
239
240/*static*/ MediaProfiles::VideoDecoderCap*
241MediaProfiles::createVideoDecoderCap(const char **atts)
242{
243 CHECK(!strcmp("name", atts[0]) &&
244 !strcmp("enabled", atts[2]));
245
246 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
247 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
248 CHECK(codec != -1);
249
250 MediaProfiles::VideoDecoderCap *cap =
251 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
252 logVideoDecoderCap(*cap);
253 return cap;
254}
255
256/*static*/ MediaProfiles::VideoEncoderCap*
257MediaProfiles::createVideoEncoderCap(const char **atts)
258{
259 CHECK(!strcmp("name", atts[0]) &&
260 !strcmp("enabled", atts[2]) &&
261 !strcmp("minBitRate", atts[4]) &&
262 !strcmp("maxBitRate", atts[6]) &&
263 !strcmp("minFrameWidth", atts[8]) &&
264 !strcmp("maxFrameWidth", atts[10]) &&
265 !strcmp("minFrameHeight", atts[12]) &&
266 !strcmp("maxFrameHeight", atts[14]) &&
267 !strcmp("minFrameRate", atts[16]) &&
268 !strcmp("maxFrameRate", atts[18]));
269
270 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
271 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
272 CHECK(codec != -1);
273
274 MediaProfiles::VideoEncoderCap *cap =
275 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
276 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
277 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
278 logVideoEncoderCap(*cap);
279 return cap;
280}
281
282/*static*/ MediaProfiles::AudioEncoderCap*
283MediaProfiles::createAudioEncoderCap(const char **atts)
284{
285 CHECK(!strcmp("name", atts[0]) &&
286 !strcmp("enabled", atts[2]) &&
287 !strcmp("minBitRate", atts[4]) &&
288 !strcmp("maxBitRate", atts[6]) &&
289 !strcmp("minSampleRate", atts[8]) &&
290 !strcmp("maxSampleRate", atts[10]) &&
291 !strcmp("minChannels", atts[12]) &&
292 !strcmp("maxChannels", atts[14]));
293
294 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
295 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
296 CHECK(codec != -1);
297
298 MediaProfiles::AudioEncoderCap *cap =
Glenn Kastenb187de12014-12-30 08:18:15 -0800299 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]),
300 atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15]));
James Dong1d7491b2010-01-19 17:45:38 -0800301 logAudioEncoderCap(*cap);
302 return cap;
303}
304
305/*static*/ output_format
306MediaProfiles::createEncoderOutputFileFormat(const char **atts)
307{
308 CHECK(!strcmp("name", atts[0]));
309
310 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
311 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
312 CHECK(format != -1);
313
314 return static_cast<output_format>(format);
315}
316
James Dong2a7e0a12011-02-28 21:07:39 -0800317static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
318 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
319 if (cameraId == cameraIds[i]) {
320 return true;
321 }
322 }
323 return false;
324}
325
James Dong1d7491b2010-01-19 17:45:38 -0800326/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800327MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800328{
329 CHECK(!strcmp("quality", atts[0]) &&
330 !strcmp("fileFormat", atts[2]) &&
331 !strcmp("duration", atts[4]));
332
Glenn Kastenb187de12014-12-30 08:18:15 -0800333 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/
334 sizeof(sCamcorderQualityNameMap[0]);
James Dong1d7491b2010-01-19 17:45:38 -0800335 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
336 CHECK(quality != -1);
337
338 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
339 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
340 CHECK(fileFormat != -1);
341
342 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800343 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800344 if (!isCameraIdFound(cameraId, cameraIds)) {
345 cameraIds.add(cameraId);
346 }
James Dong1d7491b2010-01-19 17:45:38 -0800347 profile->mFileFormat = static_cast<output_format>(fileFormat);
348 profile->mQuality = static_cast<camcorder_quality>(quality);
349 profile->mDuration = atoi(atts[5]);
350 return profile;
351}
352
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800353MediaProfiles::ImageEncodingQualityLevels*
354MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
355{
356 int n = mImageEncodingQualityLevels.size();
357 for (int i = 0; i < n; i++) {
358 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
359 if (levels->mCameraId == cameraId) {
360 return levels;
361 }
362 }
363 return NULL;
364}
365
366void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800367{
368 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800369 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800370 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800371 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
372
373 if (levels == NULL) {
374 levels = new ImageEncodingQualityLevels();
375 levels->mCameraId = cameraId;
376 mImageEncodingQualityLevels.add(levels);
377 }
378
379 levels->mLevels.add(quality);
380}
381
382/*static*/ int
383MediaProfiles::getCameraId(const char** atts)
384{
385 if (!atts[0]) return 0; // default cameraId = 0
386 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800387 return atoi(atts[1]);
388}
389
James Dong0f056292011-05-09 18:49:31 -0700390void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
391{
Eric Laurentb1eb1a02012-10-22 17:44:24 -0700392 int offsetTimeMs = 1000;
James Dong0f056292011-05-09 18:49:31 -0700393 if (atts[2]) {
394 CHECK(!strcmp("startOffsetMs", atts[2]));
395 offsetTimeMs = atoi(atts[3]);
396 }
397
Steve Block3856b092011-10-20 11:56:00 +0100398 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700399 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
400}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700401/*static*/ MediaProfiles::ExportVideoProfile*
402MediaProfiles::createExportVideoProfile(const char **atts)
403{
404 CHECK(!strcmp("name", atts[0]) &&
405 !strcmp("profile", atts[2]) &&
406 !strcmp("level", atts[4]));
James Dong0f056292011-05-09 18:49:31 -0700407
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700408 const size_t nMappings =
409 sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
410 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
411 CHECK(codec != -1);
412
413 MediaProfiles::ExportVideoProfile *profile =
414 new MediaProfiles::ExportVideoProfile(
415 codec, atoi(atts[3]), atoi(atts[5]));
416
417 return profile;
418}
Hong Tengcabd5f82011-07-06 18:33:09 -0700419/*static*/ MediaProfiles::VideoEditorCap*
420MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
421{
422 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
423 !strcmp("maxInputFrameHeight", atts[2]) &&
424 !strcmp("maxOutputFrameWidth", atts[4]) &&
Hong Teng3a9cefe2011-11-10 14:54:26 -0800425 !strcmp("maxOutputFrameHeight", atts[6]) &&
426 !strcmp("maxPrefetchYUVFrames", atts[8]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700427
428 MediaProfiles::VideoEditorCap *pVideoEditorCap =
429 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
Hong Teng3a9cefe2011-11-10 14:54:26 -0800430 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700431
432 logVideoEditorCap(*pVideoEditorCap);
433 profiles->mVideoEditorCap = pVideoEditorCap;
434
435 return pVideoEditorCap;
436}
437
James Dong1d7491b2010-01-19 17:45:38 -0800438/*static*/ void
439MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
440{
441 MediaProfiles *profiles = (MediaProfiles *) userData;
442 if (strcmp("Video", name) == 0) {
443 createVideoCodec(atts, profiles);
444 } else if (strcmp("Audio", name) == 0) {
445 createAudioCodec(atts, profiles);
446 } else if (strcmp("VideoEncoderCap", name) == 0 &&
447 strcmp("true", atts[3]) == 0) {
448 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
449 } else if (strcmp("AudioEncoderCap", name) == 0 &&
450 strcmp("true", atts[3]) == 0) {
451 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
452 } else if (strcmp("VideoDecoderCap", name) == 0 &&
453 strcmp("true", atts[3]) == 0) {
454 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
455 } else if (strcmp("AudioDecoderCap", name) == 0 &&
456 strcmp("true", atts[3]) == 0) {
457 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
458 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
459 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800460 } else if (strcmp("CamcorderProfiles", name) == 0) {
461 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700462 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800463 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800464 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800465 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800466 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800467 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700468 } else if (strcmp("VideoEditorCap", name) == 0) {
469 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700470 } else if (strcmp("ExportVideoProfile", name) == 0) {
471 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dong1d7491b2010-01-19 17:45:38 -0800472 }
473}
474
James Dong2a7e0a12011-02-28 21:07:39 -0800475static bool isCamcorderProfile(camcorder_quality quality) {
476 return quality >= CAMCORDER_QUALITY_LIST_START &&
477 quality <= CAMCORDER_QUALITY_LIST_END;
478}
479
480static bool isTimelapseProfile(camcorder_quality quality) {
481 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
482 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
483}
484
Zhijun Hee0790972014-07-23 15:17:26 -0700485static bool isHighSpeedProfile(camcorder_quality quality) {
486 return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
487 quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END;
488}
489
James Dong2a7e0a12011-02-28 21:07:39 -0800490void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700491 ALOGV("Number of camera ids: %zu", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800492 CHECK(cameraIds.size() > 0);
493 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
494 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
495 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
496 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
497 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
498 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
499 if ((j & 1) == 0) { // low resolution
500 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
501 } else { // high resolution
502 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
503 }
504 }
505 }
506}
507
508int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
509 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
510 if (mCameraIds[i] == cameraId) {
511 return i;
512 }
513 }
514 return -1;
515}
516
517void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
518 if (sIsInitialized) {
519 return;
520 }
521
522 initRequiredProfileRefs(mCameraIds);
523
524 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
525 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
526 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
527
528 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
529 int cameraId = mCamcorderProfiles[i]->mCameraId;
530 int index = -1;
531 int refIndex = getRequiredProfileRefIndex(cameraId);
532 CHECK(refIndex != -1);
533 RequiredProfileRefInfo *info;
534 camcorder_quality refQuality;
James Dong2a7e0a12011-02-28 21:07:39 -0800535
Zhijun Hee0790972014-07-23 15:17:26 -0700536 // Check high and low from either camcorder profile, timelapse profile
537 // or high speed profile, but not all of them. Default, check camcorder profile
James Dong2a7e0a12011-02-28 21:07:39 -0800538 size_t j = 0;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200539 size_t o = 2;
James Dong2a7e0a12011-02-28 21:07:39 -0800540 if (isTimelapseProfile(quality)) {
541 // Check timelapse profile instead.
542 j = 2;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200543 o = kNumRequiredProfiles;
Zhijun Hee0790972014-07-23 15:17:26 -0700544 } else if (isHighSpeedProfile(quality)) {
545 // Skip the check for high speed profile.
546 continue;
James Dong2a7e0a12011-02-28 21:07:39 -0800547 } else {
548 // Must be camcorder profile.
549 CHECK(isCamcorderProfile(quality));
550 }
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200551 for (; j < o; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800552 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
553 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
554 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
555 continue;
556 }
557 switch (j) {
558 case 0:
559 refQuality = CAMCORDER_QUALITY_LOW;
560 break;
561 case 1:
562 refQuality = CAMCORDER_QUALITY_HIGH;
563 break;
564 case 2:
565 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
566 break;
567 case 3:
568 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
569 break;
570 default:
571 CHECK(!"Should never reach here");
572 }
573
574 if (!info->mHasRefProfile) {
575 index = getCamcorderProfileIndex(cameraId, refQuality);
576 }
577 if (index == -1) {
578 // New high or low quality profile is found.
579 // Update its reference.
580 info->mHasRefProfile = true;
581 info->mRefProfileIndex = i;
582 info->mResolutionProduct = product;
583 }
584 }
585 }
586
587 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
588 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
589 int refIndex = getRequiredProfileRefIndex(cameraId);
590 CHECK(refIndex != -1);
591 RequiredProfileRefInfo *info =
592 &mRequiredProfileRefs[refIndex].mRefs[j];
593
594 if (info->mHasRefProfile) {
595
596 CamcorderProfile *profile =
597 new CamcorderProfile(
598 *mCamcorderProfiles[info->mRefProfileIndex]);
599
600 // Overwrite the quality
601 switch (j % kNumRequiredProfiles) {
602 case 0:
603 profile->mQuality = CAMCORDER_QUALITY_LOW;
604 break;
605 case 1:
606 profile->mQuality = CAMCORDER_QUALITY_HIGH;
607 break;
608 case 2:
609 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
610 break;
611 case 3:
612 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
613 break;
614 default:
615 CHECK(!"Should never come here");
616 }
617
618 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
619 if (index != -1) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700620 ALOGV("Profile quality %d for camera %zu already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800621 profile->mQuality, cameraId);
622 CHECK(index == refIndex);
623 continue;
624 }
625
626 // Insert the new profile
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700627 ALOGV("Add a profile: quality %d=>%d for camera %zu",
James Dong2a7e0a12011-02-28 21:07:39 -0800628 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
629 profile->mQuality, cameraId);
630
631 mCamcorderProfiles.add(profile);
632 }
633 }
634 }
635}
636
James Dong1d7491b2010-01-19 17:45:38 -0800637/*static*/ MediaProfiles*
638MediaProfiles::getInstance()
639{
Steve Block3856b092011-10-20 11:56:00 +0100640 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800641 Mutex::Autolock lock(sLock);
642 if (!sIsInitialized) {
643 char value[PROPERTY_VALUE_MAX];
644 if (property_get("media.settings.xml", value, NULL) <= 0) {
645 const char *defaultXmlFile = "/etc/media_profiles.xml";
646 FILE *fp = fopen(defaultXmlFile, "r");
647 if (fp == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000648 ALOGW("could not find media config xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800649 sInstance = createDefaultInstance();
650 } else {
651 fclose(fp); // close the file first.
652 sInstance = createInstanceFromXmlFile(defaultXmlFile);
653 }
654 } else {
655 sInstance = createInstanceFromXmlFile(value);
656 }
James Dong2a7e0a12011-02-28 21:07:39 -0800657 CHECK(sInstance != NULL);
658 sInstance->checkAndAddRequiredProfilesIfNecessary();
659 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800660 }
661
662 return sInstance;
663}
664
665/*static*/ MediaProfiles::VideoEncoderCap*
666MediaProfiles::createDefaultH263VideoEncoderCap()
667{
668 return new MediaProfiles::VideoEncoderCap(
669 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
670}
671
672/*static*/ MediaProfiles::VideoEncoderCap*
673MediaProfiles::createDefaultM4vVideoEncoderCap()
674{
675 return new MediaProfiles::VideoEncoderCap(
676 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
677}
678
679
680/*static*/ void
681MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
682{
683 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
684 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
685}
686
687/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700688MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700689{
690 MediaProfiles::VideoCodec *videoCodec =
691 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
692
693 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
694 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
695 profile->mCameraId = 0;
696 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700697 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700698 profile->mDuration = 60;
699 profile->mVideoCodec = videoCodec;
700 profile->mAudioCodec = audioCodec;
701 return profile;
702}
703
704/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700705MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800706{
707 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700708 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800709
710 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800711 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
712 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800713 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700714 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800715 profile->mDuration = 60;
716 profile->mVideoCodec = videoCodec;
717 profile->mAudioCodec = audioCodec;
718 return profile;
719}
720
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700721/*static*/ void
722MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
723 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
724 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -0800725 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
726 CAMCORDER_QUALITY_TIME_LAPSE_LOW);
727 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
728 CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700729}
730
731/*static*/ void
732MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
733 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
734 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -0800735 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
736 CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
737 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
738 CAMCORDER_QUALITY_TIME_LAPSE_480P);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700739}
740
James Dong1d7491b2010-01-19 17:45:38 -0800741/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700742MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800743{
744 MediaProfiles::VideoCodec *videoCodec =
745 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
746
747 MediaProfiles::AudioCodec *audioCodec =
748 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
749
750 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800751 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800752 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700753 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800754 profile->mDuration = 30;
755 profile->mVideoCodec = videoCodec;
756 profile->mAudioCodec = audioCodec;
757 return profile;
758}
759
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700760/*static*/ MediaProfiles::CamcorderProfile*
761MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
762{
763 MediaProfiles::VideoCodec *videoCodec =
764 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
765
766 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
767 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
768 profile->mCameraId = 0;
769 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
770 profile->mQuality = quality;
771 profile->mDuration = 60;
772 profile->mVideoCodec = videoCodec;
773 profile->mAudioCodec = audioCodec;
774 return profile;
775}
776
777/*static*/ void
778MediaProfiles::createDefaultCamcorderLowProfiles(
779 MediaProfiles::CamcorderProfile **lowProfile,
780 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
781 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
782 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
783}
784
785/*static*/ void
786MediaProfiles::createDefaultCamcorderHighProfiles(
787 MediaProfiles::CamcorderProfile **highProfile,
788 MediaProfiles::CamcorderProfile **highSpecificProfile) {
789 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
790 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
791}
792
James Dong1d7491b2010-01-19 17:45:38 -0800793/*static*/ void
794MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
795{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700796 // low camcorder profiles.
797 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
798 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
799 profiles->mCamcorderProfiles.add(lowProfile);
800 profiles->mCamcorderProfiles.add(lowSpecificProfile);
801
802 // high camcorder profiles.
803 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
804 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
805 profiles->mCamcorderProfiles.add(highProfile);
806 profiles->mCamcorderProfiles.add(highSpecificProfile);
807
808 // low camcorder time lapse profiles.
809 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
810 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
811 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
812 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
813
814 // high camcorder time lapse profiles.
815 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
Glenn Kastenb187de12014-12-30 08:18:15 -0800816 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile,
817 &highSpecificTimeLapseProfile);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700818 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
819 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700820
821 // For emulator and other legacy devices which does not have a
822 // media_profiles.xml file, We assume that the default camera id
823 // is 0 and that is the only camera available.
824 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800825}
826
827/*static*/ void
828MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
829{
830 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
831}
832
833/*static*/ void
834MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
835{
836 MediaProfiles::VideoDecoderCap *cap =
837 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
838
839 profiles->mVideoDecoders.add(cap);
840}
841
842/*static*/ void
843MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
844{
845 MediaProfiles::AudioDecoderCap *cap =
846 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
847
848 profiles->mAudioDecoders.add(cap);
849}
850
851/*static*/ void
852MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
853{
854 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
855 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
856}
857
858/*static*/ MediaProfiles::AudioEncoderCap*
859MediaProfiles::createDefaultAmrNBEncoderCap()
860{
861 return new MediaProfiles::AudioEncoderCap(
862 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
863}
864
James Dongf5a83852010-02-23 17:21:44 -0800865/*static*/ void
866MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
867{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800868 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
869 levels->mCameraId = 0;
870 levels->mLevels.add(70);
871 levels->mLevels.add(80);
872 levels->mLevels.add(90);
873 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800874}
875
Hong Tengcabd5f82011-07-06 18:33:09 -0700876/*static*/ void
877MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
878{
879 profiles->mVideoEditorCap =
880 new MediaProfiles::VideoEditorCap(
881 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
882 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
883 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
Hong Teng3a9cefe2011-11-10 14:54:26 -0800884 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
885 VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
Hong Tengcabd5f82011-07-06 18:33:09 -0700886}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700887/*static*/ void
888MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
889{
890 // Create default video export profiles
891 profiles->mVideoEditorExportProfiles.add(
892 new ExportVideoProfile(VIDEO_ENCODER_H263,
893 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
894 profiles->mVideoEditorExportProfiles.add(
895 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
896 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
897 profiles->mVideoEditorExportProfiles.add(
898 new ExportVideoProfile(VIDEO_ENCODER_H264,
899 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
900}
Hong Tengcabd5f82011-07-06 18:33:09 -0700901
James Dong1d7491b2010-01-19 17:45:38 -0800902/*static*/ MediaProfiles*
903MediaProfiles::createDefaultInstance()
904{
905 MediaProfiles *profiles = new MediaProfiles;
906 createDefaultCamcorderProfiles(profiles);
907 createDefaultVideoEncoders(profiles);
908 createDefaultAudioEncoders(profiles);
909 createDefaultVideoDecoders(profiles);
910 createDefaultAudioDecoders(profiles);
911 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800912 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700913 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700914 createDefaultExportVideoProfiles(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800915 return profiles;
916}
917
918/*static*/ MediaProfiles*
919MediaProfiles::createInstanceFromXmlFile(const char *xml)
920{
921 FILE *fp = NULL;
922 CHECK((fp = fopen(xml, "r")));
923
924 XML_Parser parser = ::XML_ParserCreate(NULL);
925 CHECK(parser != NULL);
926
927 MediaProfiles *profiles = new MediaProfiles();
928 ::XML_SetUserData(parser, profiles);
929 ::XML_SetElementHandler(parser, startElementHandler, NULL);
930
931 /*
932 FIXME:
933 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
934
935 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +0000936 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800937 return UNKNOWN_ERROR;
938 }
939
940 */
941
942 const int BUFF_SIZE = 512;
943 for (;;) {
944 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
945 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000946 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -0800947 delete profiles;
948 profiles = NULL;
949 goto exit;
950 }
951
952 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
953 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000954 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -0800955 delete profiles;
956 profiles = NULL;
957 goto exit;
958 }
959
960 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
961
962 if (bytes_read == 0) break; // done parsing the xml file
963 }
964
965exit:
966 ::XML_ParserFree(parser);
967 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800968 return profiles;
969}
970
971Vector<output_format> MediaProfiles::getOutputFileFormats() const
972{
973 return mEncoderOutputFileFormats; // copy out
974}
975
976Vector<video_encoder> MediaProfiles::getVideoEncoders() const
977{
978 Vector<video_encoder> encoders;
979 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
980 encoders.add(mVideoEncoders[i]->mCodec);
981 }
982 return encoders; // copy out
983}
984
985int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
986{
Steve Block3856b092011-10-20 11:56:00 +0100987 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800988 int index = -1;
989 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
990 if (mVideoEncoders[i]->mCodec == codec) {
991 index = i;
992 break;
993 }
994 }
995 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000996 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800997 return -1;
998 }
999
1000 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
1001 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
1002 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
1003 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
1004 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
1005 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
1006 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
1007 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
1008
Steve Block29357bc2012-01-06 19:20:56 +00001009 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001010 return -1;
1011}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001012int MediaProfiles::getVideoEditorExportParamByName(
1013 const char *name, int codec) const
1014{
Steve Block3856b092011-10-20 11:56:00 +01001015 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001016 ExportVideoProfile *exportProfile = NULL;
1017 int index = -1;
1018 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
1019 exportProfile = mVideoEditorExportProfiles[i];
1020 if (exportProfile->mCodec == codec) {
1021 index = i;
1022 break;
1023 }
1024 }
1025 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001026 ALOGE("The given video decoder %d is not found", codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001027 return -1;
1028 }
1029 if (!strcmp("videoeditor.export.profile", name))
1030 return exportProfile->mProfile;
1031 if (!strcmp("videoeditor.export.level", name))
1032 return exportProfile->mLevel;
James Dong1d7491b2010-01-19 17:45:38 -08001033
Steve Block29357bc2012-01-06 19:20:56 +00001034 ALOGE("The given video editor export param name %s is not found", name);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001035 return -1;
1036}
Hong Tengcabd5f82011-07-06 18:33:09 -07001037int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1038{
Steve Block3856b092011-10-20 11:56:00 +01001039 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001040
1041 if (mVideoEditorCap == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001042 ALOGE("The mVideoEditorCap is not created, then create default cap.");
Hong Tengcabd5f82011-07-06 18:33:09 -07001043 createDefaultVideoEditorCap(sInstance);
1044 }
1045
1046 if (!strcmp("videoeditor.input.width.max", name))
1047 return mVideoEditorCap->mMaxInputFrameWidth;
1048 if (!strcmp("videoeditor.input.height.max", name))
1049 return mVideoEditorCap->mMaxInputFrameHeight;
1050 if (!strcmp("videoeditor.output.width.max", name))
1051 return mVideoEditorCap->mMaxOutputFrameWidth;
1052 if (!strcmp("videoeditor.output.height.max", name))
1053 return mVideoEditorCap->mMaxOutputFrameHeight;
Hong Teng3a9cefe2011-11-10 14:54:26 -08001054 if (!strcmp("maxPrefetchYUVFrames", name))
1055 return mVideoEditorCap->mMaxPrefetchYUVFrames;
Hong Tengcabd5f82011-07-06 18:33:09 -07001056
Steve Block29357bc2012-01-06 19:20:56 +00001057 ALOGE("The given video editor param name %s is not found", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001058 return -1;
1059}
1060
James Dong1d7491b2010-01-19 17:45:38 -08001061Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1062{
1063 Vector<audio_encoder> encoders;
1064 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1065 encoders.add(mAudioEncoders[i]->mCodec);
1066 }
1067 return encoders; // copy out
1068}
1069
1070int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1071{
Steve Block3856b092011-10-20 11:56:00 +01001072 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001073 int index = -1;
1074 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1075 if (mAudioEncoders[i]->mCodec == codec) {
1076 index = i;
1077 break;
1078 }
1079 }
1080 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001081 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001082 return -1;
1083 }
1084
1085 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1086 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1087 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1088 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1089 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1090 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1091
Steve Block29357bc2012-01-06 19:20:56 +00001092 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001093 return -1;
1094}
1095
1096Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1097{
1098 Vector<video_decoder> decoders;
1099 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1100 decoders.add(mVideoDecoders[i]->mCodec);
1101 }
1102 return decoders; // copy out
1103}
1104
1105Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1106{
1107 Vector<audio_decoder> decoders;
1108 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1109 decoders.add(mAudioDecoders[i]->mCodec);
1110 }
1111 return decoders; // copy out
1112}
1113
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001114int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001115{
James Dong1d7491b2010-01-19 17:45:38 -08001116 int index = -1;
1117 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001118 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1119 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001120 index = i;
1121 break;
1122 }
1123 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001124 return index;
1125}
1126
1127int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1128 int cameraId,
1129 camcorder_quality quality) const
1130{
Steve Block3856b092011-10-20 11:56:00 +01001131 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001132 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001133
1134 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001135 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001136 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001137 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001138 return -1;
1139 }
1140
James Dongf5a83852010-02-23 17:21:44 -08001141 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001142 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1143 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1144 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1145 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1146 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1147 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1148 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1149 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1150 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1151 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1152
Steve Block29357bc2012-01-06 19:20:56 +00001153 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001154 return -1;
1155}
1156
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001157bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1158{
1159 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1160}
1161
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001162Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001163{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001164 Vector<int> result;
1165 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1166 if (levels != NULL) {
1167 result = levels->mLevels; // copy out
1168 }
1169 return result;
James Dongf5a83852010-02-23 17:21:44 -08001170}
1171
James Dong0f056292011-05-09 18:49:31 -07001172int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1173 int offsetTimeMs = -1;
1174 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1175 if (index >= 0) {
1176 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1177 }
Steve Block3856b092011-10-20 11:56:00 +01001178 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001179 return offsetTimeMs;
1180}
1181
James Dong1d7491b2010-01-19 17:45:38 -08001182MediaProfiles::~MediaProfiles()
1183{
1184 CHECK("destructor should never be called" == 0);
1185#if 0
1186 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1187 delete mAudioEncoders[i];
1188 }
1189 mAudioEncoders.clear();
1190
1191 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1192 delete mVideoEncoders[i];
1193 }
1194 mVideoEncoders.clear();
1195
1196 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1197 delete mVideoDecoders[i];
1198 }
1199 mVideoDecoders.clear();
1200
1201 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1202 delete mAudioDecoders[i];
1203 }
1204 mAudioDecoders.clear();
1205
1206 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1207 delete mCamcorderProfiles[i];
1208 }
1209 mCamcorderProfiles.clear();
1210#endif
1211}
1212} // namespace android