blob: f69dbeabd85ec706a3f225bc0733aa30e6d2413a [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},
James Dong669012d2011-09-19 16:27:31 -070072 {"qvga", CAMCORDER_QUALITY_QVGA},
Ankit Premrajkabf3be122011-11-21 19:25:02 -080073 {"fwvga", CAMCORDER_QUALITY_FWVGA},
74 {"wvga", CAMCORDER_QUALITY_WVGA},
75 {"vga", CAMCORDER_QUALITY_VGA},
76 {"wqvga", CAMCORDER_QUALITY_WQVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070077
78 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
79 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
80 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070081 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070082 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
83 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070084 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
85 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
James Dong1d7491b2010-01-19 17:45:38 -080086};
87
88/*static*/ void
89MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
90{
Steve Block3856b092011-10-20 11:56:00 +010091 ALOGV("video codec:");
92 ALOGV("codec = %d", codec.mCodec);
93 ALOGV("bit rate: %d", codec.mBitRate);
94 ALOGV("frame width: %d", codec.mFrameWidth);
95 ALOGV("frame height: %d", codec.mFrameHeight);
96 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -080097}
98
99/*static*/ void
100MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
101{
Steve Block3856b092011-10-20 11:56:00 +0100102 ALOGV("audio codec:");
103 ALOGV("codec = %d", codec.mCodec);
104 ALOGV("bit rate: %d", codec.mBitRate);
105 ALOGV("sample rate: %d", codec.mSampleRate);
106 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800107}
108
109/*static*/ void
110MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
111{
Steve Block3856b092011-10-20 11:56:00 +0100112 ALOGV("video encoder cap:");
113 ALOGV("codec = %d", cap.mCodec);
114 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
115 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
116 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
117 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800118}
119
120/*static*/ void
121MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
122{
Steve Block3856b092011-10-20 11:56:00 +0100123 ALOGV("audio encoder cap:");
124 ALOGV("codec = %d", cap.mCodec);
125 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
126 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
127 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800128}
129
130/*static*/ void
131MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
132{
Steve Block3856b092011-10-20 11:56:00 +0100133 ALOGV("video decoder cap:");
134 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800135}
136
137/*static*/ void
138MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
139{
Steve Block3856b092011-10-20 11:56:00 +0100140 ALOGV("audio codec cap:");
141 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800142}
143
Hong Tengcabd5f82011-07-06 18:33:09 -0700144/*static*/ void
145MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
146{
Steve Block3856b092011-10-20 11:56:00 +0100147 ALOGV("videoeditor cap:");
148 ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
149 ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
150 ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
151 ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
Hong Tengcabd5f82011-07-06 18:33:09 -0700152}
153
James Dong1d7491b2010-01-19 17:45:38 -0800154/*static*/ int
155MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
156{
157 int tag = -1;
158 for (size_t i = 0; i < nMappings; ++i) {
159 if (!strcmp(map[i].name, name)) {
160 tag = map[i].tag;
161 break;
162 }
163 }
164 return tag;
165}
166
167/*static*/ MediaProfiles::VideoCodec*
168MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
169{
170 CHECK(!strcmp("codec", atts[0]) &&
171 !strcmp("bitRate", atts[2]) &&
172 !strcmp("width", atts[4]) &&
173 !strcmp("height", atts[6]) &&
174 !strcmp("frameRate", atts[8]));
175
176 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
177 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
178 CHECK(codec != -1);
179
180 MediaProfiles::VideoCodec *videoCodec =
181 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
182 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
183 logVideoCodec(*videoCodec);
184
185 size_t nCamcorderProfiles;
186 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
187 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
188 return videoCodec;
189}
190
191/*static*/ MediaProfiles::AudioCodec*
192MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
193{
194 CHECK(!strcmp("codec", atts[0]) &&
195 !strcmp("bitRate", atts[2]) &&
196 !strcmp("sampleRate", atts[4]) &&
197 !strcmp("channels", atts[6]));
198 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
199 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
200 CHECK(codec != -1);
201
202 MediaProfiles::AudioCodec *audioCodec =
203 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
204 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
205 logAudioCodec(*audioCodec);
206
207 size_t nCamcorderProfiles;
208 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
209 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
210 return audioCodec;
211}
212/*static*/ MediaProfiles::AudioDecoderCap*
213MediaProfiles::createAudioDecoderCap(const char **atts)
214{
215 CHECK(!strcmp("name", atts[0]) &&
216 !strcmp("enabled", atts[2]));
217
218 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
219 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
220 CHECK(codec != -1);
221
222 MediaProfiles::AudioDecoderCap *cap =
223 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
224 logAudioDecoderCap(*cap);
225 return cap;
226}
227
228/*static*/ MediaProfiles::VideoDecoderCap*
229MediaProfiles::createVideoDecoderCap(const char **atts)
230{
231 CHECK(!strcmp("name", atts[0]) &&
232 !strcmp("enabled", atts[2]));
233
234 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
235 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
236 CHECK(codec != -1);
237
238 MediaProfiles::VideoDecoderCap *cap =
239 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
240 logVideoDecoderCap(*cap);
241 return cap;
242}
243
244/*static*/ MediaProfiles::VideoEncoderCap*
245MediaProfiles::createVideoEncoderCap(const char **atts)
246{
247 CHECK(!strcmp("name", atts[0]) &&
248 !strcmp("enabled", atts[2]) &&
249 !strcmp("minBitRate", atts[4]) &&
250 !strcmp("maxBitRate", atts[6]) &&
251 !strcmp("minFrameWidth", atts[8]) &&
252 !strcmp("maxFrameWidth", atts[10]) &&
253 !strcmp("minFrameHeight", atts[12]) &&
254 !strcmp("maxFrameHeight", atts[14]) &&
255 !strcmp("minFrameRate", atts[16]) &&
256 !strcmp("maxFrameRate", atts[18]));
257
258 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
259 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
260 CHECK(codec != -1);
261
262 MediaProfiles::VideoEncoderCap *cap =
263 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
264 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
265 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
266 logVideoEncoderCap(*cap);
267 return cap;
268}
269
270/*static*/ MediaProfiles::AudioEncoderCap*
271MediaProfiles::createAudioEncoderCap(const char **atts)
272{
273 CHECK(!strcmp("name", atts[0]) &&
274 !strcmp("enabled", atts[2]) &&
275 !strcmp("minBitRate", atts[4]) &&
276 !strcmp("maxBitRate", atts[6]) &&
277 !strcmp("minSampleRate", atts[8]) &&
278 !strcmp("maxSampleRate", atts[10]) &&
279 !strcmp("minChannels", atts[12]) &&
280 !strcmp("maxChannels", atts[14]));
281
282 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
283 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
284 CHECK(codec != -1);
285
286 MediaProfiles::AudioEncoderCap *cap =
287 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
288 atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
289 atoi(atts[15]));
290 logAudioEncoderCap(*cap);
291 return cap;
292}
293
294/*static*/ output_format
295MediaProfiles::createEncoderOutputFileFormat(const char **atts)
296{
297 CHECK(!strcmp("name", atts[0]));
298
299 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
300 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
301 CHECK(format != -1);
302
303 return static_cast<output_format>(format);
304}
305
James Dong2a7e0a12011-02-28 21:07:39 -0800306static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
307 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
308 if (cameraId == cameraIds[i]) {
309 return true;
310 }
311 }
312 return false;
313}
314
James Dong1d7491b2010-01-19 17:45:38 -0800315/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800316MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800317{
318 CHECK(!strcmp("quality", atts[0]) &&
319 !strcmp("fileFormat", atts[2]) &&
320 !strcmp("duration", atts[4]));
321
322 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
323 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
324 CHECK(quality != -1);
325
326 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
327 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
328 CHECK(fileFormat != -1);
329
330 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800331 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800332 if (!isCameraIdFound(cameraId, cameraIds)) {
333 cameraIds.add(cameraId);
334 }
James Dong1d7491b2010-01-19 17:45:38 -0800335 profile->mFileFormat = static_cast<output_format>(fileFormat);
336 profile->mQuality = static_cast<camcorder_quality>(quality);
337 profile->mDuration = atoi(atts[5]);
338 return profile;
339}
340
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800341MediaProfiles::ImageEncodingQualityLevels*
342MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
343{
344 int n = mImageEncodingQualityLevels.size();
345 for (int i = 0; i < n; i++) {
346 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
347 if (levels->mCameraId == cameraId) {
348 return levels;
349 }
350 }
351 return NULL;
352}
353
354void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800355{
356 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800357 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800358 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800359 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
360
361 if (levels == NULL) {
362 levels = new ImageEncodingQualityLevels();
363 levels->mCameraId = cameraId;
364 mImageEncodingQualityLevels.add(levels);
365 }
366
367 levels->mLevels.add(quality);
368}
369
370/*static*/ int
371MediaProfiles::getCameraId(const char** atts)
372{
373 if (!atts[0]) return 0; // default cameraId = 0
374 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800375 return atoi(atts[1]);
376}
377
James Dong0f056292011-05-09 18:49:31 -0700378void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
379{
Eric Laurentb1eb1a02012-10-22 17:44:24 -0700380 int offsetTimeMs = 1000;
James Dong0f056292011-05-09 18:49:31 -0700381 if (atts[2]) {
382 CHECK(!strcmp("startOffsetMs", atts[2]));
383 offsetTimeMs = atoi(atts[3]);
384 }
385
Steve Block3856b092011-10-20 11:56:00 +0100386 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700387 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
388}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700389/*static*/ MediaProfiles::ExportVideoProfile*
390MediaProfiles::createExportVideoProfile(const char **atts)
391{
392 CHECK(!strcmp("name", atts[0]) &&
393 !strcmp("profile", atts[2]) &&
394 !strcmp("level", atts[4]));
James Dong0f056292011-05-09 18:49:31 -0700395
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700396 const size_t nMappings =
397 sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
398 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
399 CHECK(codec != -1);
400
401 MediaProfiles::ExportVideoProfile *profile =
402 new MediaProfiles::ExportVideoProfile(
403 codec, atoi(atts[3]), atoi(atts[5]));
404
405 return profile;
406}
Hong Tengcabd5f82011-07-06 18:33:09 -0700407/*static*/ MediaProfiles::VideoEditorCap*
408MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
409{
410 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
411 !strcmp("maxInputFrameHeight", atts[2]) &&
412 !strcmp("maxOutputFrameWidth", atts[4]) &&
Hong Teng3a9cefe2011-11-10 14:54:26 -0800413 !strcmp("maxOutputFrameHeight", atts[6]) &&
414 !strcmp("maxPrefetchYUVFrames", atts[8]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700415
416 MediaProfiles::VideoEditorCap *pVideoEditorCap =
417 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
Hong Teng3a9cefe2011-11-10 14:54:26 -0800418 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700419
420 logVideoEditorCap(*pVideoEditorCap);
421 profiles->mVideoEditorCap = pVideoEditorCap;
422
423 return pVideoEditorCap;
424}
425
James Dong1d7491b2010-01-19 17:45:38 -0800426/*static*/ void
427MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
428{
429 MediaProfiles *profiles = (MediaProfiles *) userData;
430 if (strcmp("Video", name) == 0) {
431 createVideoCodec(atts, profiles);
432 } else if (strcmp("Audio", name) == 0) {
433 createAudioCodec(atts, profiles);
434 } else if (strcmp("VideoEncoderCap", name) == 0 &&
435 strcmp("true", atts[3]) == 0) {
436 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
437 } else if (strcmp("AudioEncoderCap", name) == 0 &&
438 strcmp("true", atts[3]) == 0) {
439 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
440 } else if (strcmp("VideoDecoderCap", name) == 0 &&
441 strcmp("true", atts[3]) == 0) {
442 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
443 } else if (strcmp("AudioDecoderCap", name) == 0 &&
444 strcmp("true", atts[3]) == 0) {
445 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
446 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
447 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800448 } else if (strcmp("CamcorderProfiles", name) == 0) {
449 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700450 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800451 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800452 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800453 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800454 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800455 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700456 } else if (strcmp("VideoEditorCap", name) == 0) {
457 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700458 } else if (strcmp("ExportVideoProfile", name) == 0) {
459 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dong1d7491b2010-01-19 17:45:38 -0800460 }
461}
462
James Dong2a7e0a12011-02-28 21:07:39 -0800463static bool isCamcorderProfile(camcorder_quality quality) {
464 return quality >= CAMCORDER_QUALITY_LIST_START &&
465 quality <= CAMCORDER_QUALITY_LIST_END;
466}
467
468static bool isTimelapseProfile(camcorder_quality quality) {
469 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
470 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
471}
472
473void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Steve Block3856b092011-10-20 11:56:00 +0100474 ALOGV("Number of camera ids: %d", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800475 CHECK(cameraIds.size() > 0);
476 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
477 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
478 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
479 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
480 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
481 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
482 if ((j & 1) == 0) { // low resolution
483 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
484 } else { // high resolution
485 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
486 }
487 }
488 }
489}
490
491int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
492 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
493 if (mCameraIds[i] == cameraId) {
494 return i;
495 }
496 }
497 return -1;
498}
499
500void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
501 if (sIsInitialized) {
502 return;
503 }
504
505 initRequiredProfileRefs(mCameraIds);
506
507 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
508 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
509 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
510
511 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
512 int cameraId = mCamcorderProfiles[i]->mCameraId;
513 int index = -1;
514 int refIndex = getRequiredProfileRefIndex(cameraId);
515 CHECK(refIndex != -1);
516 RequiredProfileRefInfo *info;
517 camcorder_quality refQuality;
518 VideoCodec *codec = NULL;
519
520 // Check high and low from either camcorder profile or timelapse profile
521 // but not both. Default, check camcorder profile
522 size_t j = 0;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200523 size_t o = 2;
James Dong2a7e0a12011-02-28 21:07:39 -0800524 if (isTimelapseProfile(quality)) {
525 // Check timelapse profile instead.
526 j = 2;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200527 o = kNumRequiredProfiles;
James Dong2a7e0a12011-02-28 21:07:39 -0800528 } else {
529 // Must be camcorder profile.
530 CHECK(isCamcorderProfile(quality));
531 }
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200532 for (; j < o; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800533 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
534 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
535 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
536 continue;
537 }
538 switch (j) {
539 case 0:
540 refQuality = CAMCORDER_QUALITY_LOW;
541 break;
542 case 1:
543 refQuality = CAMCORDER_QUALITY_HIGH;
544 break;
545 case 2:
546 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
547 break;
548 case 3:
549 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
550 break;
551 default:
552 CHECK(!"Should never reach here");
553 }
554
555 if (!info->mHasRefProfile) {
556 index = getCamcorderProfileIndex(cameraId, refQuality);
557 }
558 if (index == -1) {
559 // New high or low quality profile is found.
560 // Update its reference.
561 info->mHasRefProfile = true;
562 info->mRefProfileIndex = i;
563 info->mResolutionProduct = product;
564 }
565 }
566 }
567
568 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
569 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
570 int refIndex = getRequiredProfileRefIndex(cameraId);
571 CHECK(refIndex != -1);
572 RequiredProfileRefInfo *info =
573 &mRequiredProfileRefs[refIndex].mRefs[j];
574
575 if (info->mHasRefProfile) {
576
577 CamcorderProfile *profile =
578 new CamcorderProfile(
579 *mCamcorderProfiles[info->mRefProfileIndex]);
580
581 // Overwrite the quality
582 switch (j % kNumRequiredProfiles) {
583 case 0:
584 profile->mQuality = CAMCORDER_QUALITY_LOW;
585 break;
586 case 1:
587 profile->mQuality = CAMCORDER_QUALITY_HIGH;
588 break;
589 case 2:
590 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
591 break;
592 case 3:
593 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
594 break;
595 default:
596 CHECK(!"Should never come here");
597 }
598
599 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
600 if (index != -1) {
Steve Block3856b092011-10-20 11:56:00 +0100601 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800602 profile->mQuality, cameraId);
603 CHECK(index == refIndex);
604 continue;
605 }
606
607 // Insert the new profile
Steve Block3856b092011-10-20 11:56:00 +0100608 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800609 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
610 profile->mQuality, cameraId);
611
612 mCamcorderProfiles.add(profile);
613 }
614 }
615 }
616}
617
James Dong1d7491b2010-01-19 17:45:38 -0800618/*static*/ MediaProfiles*
619MediaProfiles::getInstance()
620{
Steve Block3856b092011-10-20 11:56:00 +0100621 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800622 Mutex::Autolock lock(sLock);
623 if (!sIsInitialized) {
624 char value[PROPERTY_VALUE_MAX];
625 if (property_get("media.settings.xml", value, NULL) <= 0) {
626 const char *defaultXmlFile = "/etc/media_profiles.xml";
627 FILE *fp = fopen(defaultXmlFile, "r");
628 if (fp == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000629 ALOGW("could not find media config xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800630 sInstance = createDefaultInstance();
631 } else {
632 fclose(fp); // close the file first.
633 sInstance = createInstanceFromXmlFile(defaultXmlFile);
634 }
635 } else {
636 sInstance = createInstanceFromXmlFile(value);
637 }
James Dong2a7e0a12011-02-28 21:07:39 -0800638 CHECK(sInstance != NULL);
639 sInstance->checkAndAddRequiredProfilesIfNecessary();
640 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800641 }
642
643 return sInstance;
644}
645
646/*static*/ MediaProfiles::VideoEncoderCap*
647MediaProfiles::createDefaultH263VideoEncoderCap()
648{
649 return new MediaProfiles::VideoEncoderCap(
650 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
651}
652
653/*static*/ MediaProfiles::VideoEncoderCap*
654MediaProfiles::createDefaultM4vVideoEncoderCap()
655{
656 return new MediaProfiles::VideoEncoderCap(
657 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
658}
659
660
661/*static*/ void
662MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
663{
664 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
665 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
666}
667
668/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700669MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700670{
671 MediaProfiles::VideoCodec *videoCodec =
672 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
673
674 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
675 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
676 profile->mCameraId = 0;
677 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700678 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700679 profile->mDuration = 60;
680 profile->mVideoCodec = videoCodec;
681 profile->mAudioCodec = audioCodec;
682 return profile;
683}
684
685/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700686MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800687{
688 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700689 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800690
691 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800692 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
693 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800694 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700695 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800696 profile->mDuration = 60;
697 profile->mVideoCodec = videoCodec;
698 profile->mAudioCodec = audioCodec;
699 return profile;
700}
701
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700702/*static*/ void
703MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
704 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
705 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
706 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
707 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
708}
709
710/*static*/ void
711MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
712 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
713 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
714 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
715 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
716}
717
James Dong1d7491b2010-01-19 17:45:38 -0800718/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700719MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800720{
721 MediaProfiles::VideoCodec *videoCodec =
722 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
723
724 MediaProfiles::AudioCodec *audioCodec =
725 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
726
727 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800728 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800729 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700730 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800731 profile->mDuration = 30;
732 profile->mVideoCodec = videoCodec;
733 profile->mAudioCodec = audioCodec;
734 return profile;
735}
736
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700737/*static*/ MediaProfiles::CamcorderProfile*
738MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
739{
740 MediaProfiles::VideoCodec *videoCodec =
741 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
742
743 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
744 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
745 profile->mCameraId = 0;
746 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
747 profile->mQuality = quality;
748 profile->mDuration = 60;
749 profile->mVideoCodec = videoCodec;
750 profile->mAudioCodec = audioCodec;
751 return profile;
752}
753
754/*static*/ void
755MediaProfiles::createDefaultCamcorderLowProfiles(
756 MediaProfiles::CamcorderProfile **lowProfile,
757 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
758 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
759 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
760}
761
762/*static*/ void
763MediaProfiles::createDefaultCamcorderHighProfiles(
764 MediaProfiles::CamcorderProfile **highProfile,
765 MediaProfiles::CamcorderProfile **highSpecificProfile) {
766 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
767 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
768}
769
James Dong1d7491b2010-01-19 17:45:38 -0800770/*static*/ void
771MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
772{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700773 // low camcorder profiles.
774 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
775 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
776 profiles->mCamcorderProfiles.add(lowProfile);
777 profiles->mCamcorderProfiles.add(lowSpecificProfile);
778
779 // high camcorder profiles.
780 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
781 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
782 profiles->mCamcorderProfiles.add(highProfile);
783 profiles->mCamcorderProfiles.add(highSpecificProfile);
784
785 // low camcorder time lapse profiles.
786 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
787 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
788 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
789 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
790
791 // high camcorder time lapse profiles.
792 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
793 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
794 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
795 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700796
797 // For emulator and other legacy devices which does not have a
798 // media_profiles.xml file, We assume that the default camera id
799 // is 0 and that is the only camera available.
800 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800801}
802
803/*static*/ void
804MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
805{
806 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
807}
808
809/*static*/ void
810MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
811{
812 MediaProfiles::VideoDecoderCap *cap =
813 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
814
815 profiles->mVideoDecoders.add(cap);
816}
817
818/*static*/ void
819MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
820{
821 MediaProfiles::AudioDecoderCap *cap =
822 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
823
824 profiles->mAudioDecoders.add(cap);
825}
826
827/*static*/ void
828MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
829{
830 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
831 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
832}
833
834/*static*/ MediaProfiles::AudioEncoderCap*
835MediaProfiles::createDefaultAmrNBEncoderCap()
836{
837 return new MediaProfiles::AudioEncoderCap(
838 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
839}
840
James Dongf5a83852010-02-23 17:21:44 -0800841/*static*/ void
842MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
843{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800844 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
845 levels->mCameraId = 0;
846 levels->mLevels.add(70);
847 levels->mLevels.add(80);
848 levels->mLevels.add(90);
849 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800850}
851
Hong Tengcabd5f82011-07-06 18:33:09 -0700852/*static*/ void
853MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
854{
855 profiles->mVideoEditorCap =
856 new MediaProfiles::VideoEditorCap(
857 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
858 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
859 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
Hong Teng3a9cefe2011-11-10 14:54:26 -0800860 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
861 VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
Hong Tengcabd5f82011-07-06 18:33:09 -0700862}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700863/*static*/ void
864MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
865{
866 // Create default video export profiles
867 profiles->mVideoEditorExportProfiles.add(
868 new ExportVideoProfile(VIDEO_ENCODER_H263,
869 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
870 profiles->mVideoEditorExportProfiles.add(
871 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
872 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
873 profiles->mVideoEditorExportProfiles.add(
874 new ExportVideoProfile(VIDEO_ENCODER_H264,
875 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
876}
Hong Tengcabd5f82011-07-06 18:33:09 -0700877
James Dong1d7491b2010-01-19 17:45:38 -0800878/*static*/ MediaProfiles*
879MediaProfiles::createDefaultInstance()
880{
881 MediaProfiles *profiles = new MediaProfiles;
882 createDefaultCamcorderProfiles(profiles);
883 createDefaultVideoEncoders(profiles);
884 createDefaultAudioEncoders(profiles);
885 createDefaultVideoDecoders(profiles);
886 createDefaultAudioDecoders(profiles);
887 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800888 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700889 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700890 createDefaultExportVideoProfiles(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800891 return profiles;
892}
893
894/*static*/ MediaProfiles*
895MediaProfiles::createInstanceFromXmlFile(const char *xml)
896{
897 FILE *fp = NULL;
898 CHECK((fp = fopen(xml, "r")));
899
900 XML_Parser parser = ::XML_ParserCreate(NULL);
901 CHECK(parser != NULL);
902
903 MediaProfiles *profiles = new MediaProfiles();
904 ::XML_SetUserData(parser, profiles);
905 ::XML_SetElementHandler(parser, startElementHandler, NULL);
906
907 /*
908 FIXME:
909 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
910
911 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +0000912 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800913 return UNKNOWN_ERROR;
914 }
915
916 */
917
918 const int BUFF_SIZE = 512;
919 for (;;) {
920 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
921 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000922 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -0800923 delete profiles;
924 profiles = NULL;
925 goto exit;
926 }
927
928 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
929 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000930 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -0800931 delete profiles;
932 profiles = NULL;
933 goto exit;
934 }
935
936 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
937
938 if (bytes_read == 0) break; // done parsing the xml file
939 }
940
941exit:
942 ::XML_ParserFree(parser);
943 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800944 return profiles;
945}
946
947Vector<output_format> MediaProfiles::getOutputFileFormats() const
948{
949 return mEncoderOutputFileFormats; // copy out
950}
951
952Vector<video_encoder> MediaProfiles::getVideoEncoders() const
953{
954 Vector<video_encoder> encoders;
955 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
956 encoders.add(mVideoEncoders[i]->mCodec);
957 }
958 return encoders; // copy out
959}
960
961int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
962{
Steve Block3856b092011-10-20 11:56:00 +0100963 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800964 int index = -1;
965 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
966 if (mVideoEncoders[i]->mCodec == codec) {
967 index = i;
968 break;
969 }
970 }
971 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000972 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800973 return -1;
974 }
975
976 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
977 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
978 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
979 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
980 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
981 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
982 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
983 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
984
Steve Block29357bc2012-01-06 19:20:56 +0000985 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -0800986 return -1;
987}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700988int MediaProfiles::getVideoEditorExportParamByName(
989 const char *name, int codec) const
990{
Steve Block3856b092011-10-20 11:56:00 +0100991 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700992 ExportVideoProfile *exportProfile = NULL;
993 int index = -1;
994 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
995 exportProfile = mVideoEditorExportProfiles[i];
996 if (exportProfile->mCodec == codec) {
997 index = i;
998 break;
999 }
1000 }
1001 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001002 ALOGE("The given video decoder %d is not found", codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001003 return -1;
1004 }
1005 if (!strcmp("videoeditor.export.profile", name))
1006 return exportProfile->mProfile;
1007 if (!strcmp("videoeditor.export.level", name))
1008 return exportProfile->mLevel;
James Dong1d7491b2010-01-19 17:45:38 -08001009
Steve Block29357bc2012-01-06 19:20:56 +00001010 ALOGE("The given video editor export param name %s is not found", name);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001011 return -1;
1012}
Hong Tengcabd5f82011-07-06 18:33:09 -07001013int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1014{
Steve Block3856b092011-10-20 11:56:00 +01001015 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001016
1017 if (mVideoEditorCap == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001018 ALOGE("The mVideoEditorCap is not created, then create default cap.");
Hong Tengcabd5f82011-07-06 18:33:09 -07001019 createDefaultVideoEditorCap(sInstance);
1020 }
1021
1022 if (!strcmp("videoeditor.input.width.max", name))
1023 return mVideoEditorCap->mMaxInputFrameWidth;
1024 if (!strcmp("videoeditor.input.height.max", name))
1025 return mVideoEditorCap->mMaxInputFrameHeight;
1026 if (!strcmp("videoeditor.output.width.max", name))
1027 return mVideoEditorCap->mMaxOutputFrameWidth;
1028 if (!strcmp("videoeditor.output.height.max", name))
1029 return mVideoEditorCap->mMaxOutputFrameHeight;
Hong Teng3a9cefe2011-11-10 14:54:26 -08001030 if (!strcmp("maxPrefetchYUVFrames", name))
1031 return mVideoEditorCap->mMaxPrefetchYUVFrames;
Hong Tengcabd5f82011-07-06 18:33:09 -07001032
Steve Block29357bc2012-01-06 19:20:56 +00001033 ALOGE("The given video editor param name %s is not found", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001034 return -1;
1035}
1036
James Dong1d7491b2010-01-19 17:45:38 -08001037Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1038{
1039 Vector<audio_encoder> encoders;
1040 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1041 encoders.add(mAudioEncoders[i]->mCodec);
1042 }
1043 return encoders; // copy out
1044}
1045
1046int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1047{
Steve Block3856b092011-10-20 11:56:00 +01001048 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001049 int index = -1;
1050 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1051 if (mAudioEncoders[i]->mCodec == codec) {
1052 index = i;
1053 break;
1054 }
1055 }
1056 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001057 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001058 return -1;
1059 }
1060
1061 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1062 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1063 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1064 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1065 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1066 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1067
Steve Block29357bc2012-01-06 19:20:56 +00001068 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001069 return -1;
1070}
1071
1072Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1073{
1074 Vector<video_decoder> decoders;
1075 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1076 decoders.add(mVideoDecoders[i]->mCodec);
1077 }
1078 return decoders; // copy out
1079}
1080
1081Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1082{
1083 Vector<audio_decoder> decoders;
1084 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1085 decoders.add(mAudioDecoders[i]->mCodec);
1086 }
1087 return decoders; // copy out
1088}
1089
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001090int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001091{
James Dong1d7491b2010-01-19 17:45:38 -08001092 int index = -1;
1093 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001094 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1095 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001096 index = i;
1097 break;
1098 }
1099 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001100 return index;
1101}
1102
1103int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1104 int cameraId,
1105 camcorder_quality quality) const
1106{
Steve Block3856b092011-10-20 11:56:00 +01001107 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001108 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001109
1110 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001111 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001112 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001113 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001114 return -1;
1115 }
1116
James Dongf5a83852010-02-23 17:21:44 -08001117 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001118 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1119 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1120 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1121 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1122 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1123 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1124 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1125 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1126 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1127 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1128
Steve Block29357bc2012-01-06 19:20:56 +00001129 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001130 return -1;
1131}
1132
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001133bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1134{
1135 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1136}
1137
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001138Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001139{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001140 Vector<int> result;
1141 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1142 if (levels != NULL) {
1143 result = levels->mLevels; // copy out
1144 }
1145 return result;
James Dongf5a83852010-02-23 17:21:44 -08001146}
1147
James Dong0f056292011-05-09 18:49:31 -07001148int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1149 int offsetTimeMs = -1;
1150 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1151 if (index >= 0) {
1152 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1153 }
Steve Block3856b092011-10-20 11:56:00 +01001154 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001155 return offsetTimeMs;
1156}
1157
James Dong1d7491b2010-01-19 17:45:38 -08001158MediaProfiles::~MediaProfiles()
1159{
1160 CHECK("destructor should never be called" == 0);
1161#if 0
1162 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1163 delete mAudioEncoders[i];
1164 }
1165 mAudioEncoders.clear();
1166
1167 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1168 delete mVideoEncoders[i];
1169 }
1170 mVideoEncoders.clear();
1171
1172 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1173 delete mVideoDecoders[i];
1174 }
1175 mVideoDecoders.clear();
1176
1177 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1178 delete mAudioDecoders[i];
1179 }
1180 mAudioDecoders.clear();
1181
1182 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1183 delete mCamcorderProfiles[i];
1184 }
1185 mCamcorderProfiles.clear();
1186#endif
1187}
1188} // namespace android