blob: d9cdb373b1149cc97090793325156d5f19f5b6e3 [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>
26#include <expat.h>
27#include <media/MediaProfiles.h>
28#include <media/stagefright/MediaDebug.h>
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -070029#include <media/stagefright/openmax/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[] = {
44 {"amrnb", AUDIO_ENCODER_AMR_NB},
45 {"amrwb", AUDIO_ENCODER_AMR_WB},
46 {"aac", AUDIO_ENCODER_AAC},
47};
48
49const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
50 {"3gp", OUTPUT_FORMAT_THREE_GPP},
51 {"mp4", OUTPUT_FORMAT_MPEG_4}
52};
53
54const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
55 {"wmv", VIDEO_DECODER_WMV}
56};
57
58const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
59 {"wma", AUDIO_DECODER_WMA}
60};
61
62const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -070063 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -080064 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070065 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070066 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070067 {"480p", CAMCORDER_QUALITY_480P},
68 {"720p", CAMCORDER_QUALITY_720P},
69 {"1080p", CAMCORDER_QUALITY_1080P},
James Dong669012d2011-09-19 16:27:31 -070070 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070071
72 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
73 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
74 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070075 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070076 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
77 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070078 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
79 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
James Dong1d7491b2010-01-19 17:45:38 -080080};
81
82/*static*/ void
83MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
84{
Steve Block3856b092011-10-20 11:56:00 +010085 ALOGV("video codec:");
86 ALOGV("codec = %d", codec.mCodec);
87 ALOGV("bit rate: %d", codec.mBitRate);
88 ALOGV("frame width: %d", codec.mFrameWidth);
89 ALOGV("frame height: %d", codec.mFrameHeight);
90 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -080091}
92
93/*static*/ void
94MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
95{
Steve Block3856b092011-10-20 11:56:00 +010096 ALOGV("audio codec:");
97 ALOGV("codec = %d", codec.mCodec);
98 ALOGV("bit rate: %d", codec.mBitRate);
99 ALOGV("sample rate: %d", codec.mSampleRate);
100 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800101}
102
103/*static*/ void
104MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
105{
Steve Block3856b092011-10-20 11:56:00 +0100106 ALOGV("video encoder cap:");
107 ALOGV("codec = %d", cap.mCodec);
108 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
109 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
110 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
111 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800112}
113
114/*static*/ void
115MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
116{
Steve Block3856b092011-10-20 11:56:00 +0100117 ALOGV("audio encoder cap:");
118 ALOGV("codec = %d", cap.mCodec);
119 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
120 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
121 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800122}
123
124/*static*/ void
125MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
126{
Steve Block3856b092011-10-20 11:56:00 +0100127 ALOGV("video decoder cap:");
128 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800129}
130
131/*static*/ void
132MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
133{
Steve Block3856b092011-10-20 11:56:00 +0100134 ALOGV("audio codec cap:");
135 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800136}
137
Hong Tengcabd5f82011-07-06 18:33:09 -0700138/*static*/ void
139MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
140{
Steve Block3856b092011-10-20 11:56:00 +0100141 ALOGV("videoeditor cap:");
142 ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
143 ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
144 ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
145 ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
Hong Tengcabd5f82011-07-06 18:33:09 -0700146}
147
James Dong1d7491b2010-01-19 17:45:38 -0800148/*static*/ int
149MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
150{
151 int tag = -1;
152 for (size_t i = 0; i < nMappings; ++i) {
153 if (!strcmp(map[i].name, name)) {
154 tag = map[i].tag;
155 break;
156 }
157 }
158 return tag;
159}
160
161/*static*/ MediaProfiles::VideoCodec*
162MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
163{
164 CHECK(!strcmp("codec", atts[0]) &&
165 !strcmp("bitRate", atts[2]) &&
166 !strcmp("width", atts[4]) &&
167 !strcmp("height", atts[6]) &&
168 !strcmp("frameRate", atts[8]));
169
170 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
171 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
172 CHECK(codec != -1);
173
174 MediaProfiles::VideoCodec *videoCodec =
175 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
176 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
177 logVideoCodec(*videoCodec);
178
179 size_t nCamcorderProfiles;
180 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
181 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
182 return videoCodec;
183}
184
185/*static*/ MediaProfiles::AudioCodec*
186MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
187{
188 CHECK(!strcmp("codec", atts[0]) &&
189 !strcmp("bitRate", atts[2]) &&
190 !strcmp("sampleRate", atts[4]) &&
191 !strcmp("channels", atts[6]));
192 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
193 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
194 CHECK(codec != -1);
195
196 MediaProfiles::AudioCodec *audioCodec =
197 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
198 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
199 logAudioCodec(*audioCodec);
200
201 size_t nCamcorderProfiles;
202 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
203 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
204 return audioCodec;
205}
206/*static*/ MediaProfiles::AudioDecoderCap*
207MediaProfiles::createAudioDecoderCap(const char **atts)
208{
209 CHECK(!strcmp("name", atts[0]) &&
210 !strcmp("enabled", atts[2]));
211
212 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
213 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
214 CHECK(codec != -1);
215
216 MediaProfiles::AudioDecoderCap *cap =
217 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
218 logAudioDecoderCap(*cap);
219 return cap;
220}
221
222/*static*/ MediaProfiles::VideoDecoderCap*
223MediaProfiles::createVideoDecoderCap(const char **atts)
224{
225 CHECK(!strcmp("name", atts[0]) &&
226 !strcmp("enabled", atts[2]));
227
228 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
229 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
230 CHECK(codec != -1);
231
232 MediaProfiles::VideoDecoderCap *cap =
233 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
234 logVideoDecoderCap(*cap);
235 return cap;
236}
237
238/*static*/ MediaProfiles::VideoEncoderCap*
239MediaProfiles::createVideoEncoderCap(const char **atts)
240{
241 CHECK(!strcmp("name", atts[0]) &&
242 !strcmp("enabled", atts[2]) &&
243 !strcmp("minBitRate", atts[4]) &&
244 !strcmp("maxBitRate", atts[6]) &&
245 !strcmp("minFrameWidth", atts[8]) &&
246 !strcmp("maxFrameWidth", atts[10]) &&
247 !strcmp("minFrameHeight", atts[12]) &&
248 !strcmp("maxFrameHeight", atts[14]) &&
249 !strcmp("minFrameRate", atts[16]) &&
250 !strcmp("maxFrameRate", atts[18]));
251
252 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
253 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
254 CHECK(codec != -1);
255
256 MediaProfiles::VideoEncoderCap *cap =
257 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
258 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
259 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
260 logVideoEncoderCap(*cap);
261 return cap;
262}
263
264/*static*/ MediaProfiles::AudioEncoderCap*
265MediaProfiles::createAudioEncoderCap(const char **atts)
266{
267 CHECK(!strcmp("name", atts[0]) &&
268 !strcmp("enabled", atts[2]) &&
269 !strcmp("minBitRate", atts[4]) &&
270 !strcmp("maxBitRate", atts[6]) &&
271 !strcmp("minSampleRate", atts[8]) &&
272 !strcmp("maxSampleRate", atts[10]) &&
273 !strcmp("minChannels", atts[12]) &&
274 !strcmp("maxChannels", atts[14]));
275
276 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
277 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
278 CHECK(codec != -1);
279
280 MediaProfiles::AudioEncoderCap *cap =
281 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
282 atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
283 atoi(atts[15]));
284 logAudioEncoderCap(*cap);
285 return cap;
286}
287
288/*static*/ output_format
289MediaProfiles::createEncoderOutputFileFormat(const char **atts)
290{
291 CHECK(!strcmp("name", atts[0]));
292
293 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
294 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
295 CHECK(format != -1);
296
297 return static_cast<output_format>(format);
298}
299
James Dong2a7e0a12011-02-28 21:07:39 -0800300static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
301 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
302 if (cameraId == cameraIds[i]) {
303 return true;
304 }
305 }
306 return false;
307}
308
James Dong1d7491b2010-01-19 17:45:38 -0800309/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800310MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800311{
312 CHECK(!strcmp("quality", atts[0]) &&
313 !strcmp("fileFormat", atts[2]) &&
314 !strcmp("duration", atts[4]));
315
316 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
317 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
318 CHECK(quality != -1);
319
320 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
321 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
322 CHECK(fileFormat != -1);
323
324 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800325 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800326 if (!isCameraIdFound(cameraId, cameraIds)) {
327 cameraIds.add(cameraId);
328 }
James Dong1d7491b2010-01-19 17:45:38 -0800329 profile->mFileFormat = static_cast<output_format>(fileFormat);
330 profile->mQuality = static_cast<camcorder_quality>(quality);
331 profile->mDuration = atoi(atts[5]);
332 return profile;
333}
334
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800335MediaProfiles::ImageEncodingQualityLevels*
336MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
337{
338 int n = mImageEncodingQualityLevels.size();
339 for (int i = 0; i < n; i++) {
340 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
341 if (levels->mCameraId == cameraId) {
342 return levels;
343 }
344 }
345 return NULL;
346}
347
348void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800349{
350 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800351 int quality = atoi(atts[1]);
Steve Block3856b092011-10-20 11:56:00 +0100352 ALOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800353 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
354
355 if (levels == NULL) {
356 levels = new ImageEncodingQualityLevels();
357 levels->mCameraId = cameraId;
358 mImageEncodingQualityLevels.add(levels);
359 }
360
361 levels->mLevels.add(quality);
362}
363
364/*static*/ int
365MediaProfiles::getCameraId(const char** atts)
366{
367 if (!atts[0]) return 0; // default cameraId = 0
368 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800369 return atoi(atts[1]);
370}
371
James Dong0f056292011-05-09 18:49:31 -0700372void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
373{
374 int offsetTimeMs = 700;
375 if (atts[2]) {
376 CHECK(!strcmp("startOffsetMs", atts[2]));
377 offsetTimeMs = atoi(atts[3]);
378 }
379
Steve Block3856b092011-10-20 11:56:00 +0100380 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700381 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
382}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700383/*static*/ MediaProfiles::ExportVideoProfile*
384MediaProfiles::createExportVideoProfile(const char **atts)
385{
386 CHECK(!strcmp("name", atts[0]) &&
387 !strcmp("profile", atts[2]) &&
388 !strcmp("level", atts[4]));
James Dong0f056292011-05-09 18:49:31 -0700389
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700390 const size_t nMappings =
391 sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
392 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
393 CHECK(codec != -1);
394
395 MediaProfiles::ExportVideoProfile *profile =
396 new MediaProfiles::ExportVideoProfile(
397 codec, atoi(atts[3]), atoi(atts[5]));
398
399 return profile;
400}
Hong Tengcabd5f82011-07-06 18:33:09 -0700401/*static*/ MediaProfiles::VideoEditorCap*
402MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
403{
404 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
405 !strcmp("maxInputFrameHeight", atts[2]) &&
406 !strcmp("maxOutputFrameWidth", atts[4]) &&
407 !strcmp("maxOutputFrameHeight", atts[6]));
408
409 MediaProfiles::VideoEditorCap *pVideoEditorCap =
410 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
411 atoi(atts[5]), atoi(atts[7]));
412
413 logVideoEditorCap(*pVideoEditorCap);
414 profiles->mVideoEditorCap = pVideoEditorCap;
415
416 return pVideoEditorCap;
417}
418
James Dong1d7491b2010-01-19 17:45:38 -0800419/*static*/ void
420MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
421{
422 MediaProfiles *profiles = (MediaProfiles *) userData;
423 if (strcmp("Video", name) == 0) {
424 createVideoCodec(atts, profiles);
425 } else if (strcmp("Audio", name) == 0) {
426 createAudioCodec(atts, profiles);
427 } else if (strcmp("VideoEncoderCap", name) == 0 &&
428 strcmp("true", atts[3]) == 0) {
429 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
430 } else if (strcmp("AudioEncoderCap", name) == 0 &&
431 strcmp("true", atts[3]) == 0) {
432 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
433 } else if (strcmp("VideoDecoderCap", name) == 0 &&
434 strcmp("true", atts[3]) == 0) {
435 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
436 } else if (strcmp("AudioDecoderCap", name) == 0 &&
437 strcmp("true", atts[3]) == 0) {
438 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
439 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
440 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800441 } else if (strcmp("CamcorderProfiles", name) == 0) {
442 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700443 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800444 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800445 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800446 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800447 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800448 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700449 } else if (strcmp("VideoEditorCap", name) == 0) {
450 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700451 } else if (strcmp("ExportVideoProfile", name) == 0) {
452 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dong1d7491b2010-01-19 17:45:38 -0800453 }
454}
455
James Dong2a7e0a12011-02-28 21:07:39 -0800456static bool isCamcorderProfile(camcorder_quality quality) {
457 return quality >= CAMCORDER_QUALITY_LIST_START &&
458 quality <= CAMCORDER_QUALITY_LIST_END;
459}
460
461static bool isTimelapseProfile(camcorder_quality quality) {
462 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
463 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
464}
465
466void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Steve Block3856b092011-10-20 11:56:00 +0100467 ALOGV("Number of camera ids: %d", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800468 CHECK(cameraIds.size() > 0);
469 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
470 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
471 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
472 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
473 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
474 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
475 if ((j & 1) == 0) { // low resolution
476 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
477 } else { // high resolution
478 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
479 }
480 }
481 }
482}
483
484int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
485 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
486 if (mCameraIds[i] == cameraId) {
487 return i;
488 }
489 }
490 return -1;
491}
492
493void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
494 if (sIsInitialized) {
495 return;
496 }
497
498 initRequiredProfileRefs(mCameraIds);
499
500 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
501 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
502 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
503
504 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
505 int cameraId = mCamcorderProfiles[i]->mCameraId;
506 int index = -1;
507 int refIndex = getRequiredProfileRefIndex(cameraId);
508 CHECK(refIndex != -1);
509 RequiredProfileRefInfo *info;
510 camcorder_quality refQuality;
511 VideoCodec *codec = NULL;
512
513 // Check high and low from either camcorder profile or timelapse profile
514 // but not both. Default, check camcorder profile
515 size_t j = 0;
516 size_t n = 2;
517 if (isTimelapseProfile(quality)) {
518 // Check timelapse profile instead.
519 j = 2;
520 n = kNumRequiredProfiles;
521 } else {
522 // Must be camcorder profile.
523 CHECK(isCamcorderProfile(quality));
524 }
525 for (; j < n; ++j) {
526 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
527 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
528 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
529 continue;
530 }
531 switch (j) {
532 case 0:
533 refQuality = CAMCORDER_QUALITY_LOW;
534 break;
535 case 1:
536 refQuality = CAMCORDER_QUALITY_HIGH;
537 break;
538 case 2:
539 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
540 break;
541 case 3:
542 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
543 break;
544 default:
545 CHECK(!"Should never reach here");
546 }
547
548 if (!info->mHasRefProfile) {
549 index = getCamcorderProfileIndex(cameraId, refQuality);
550 }
551 if (index == -1) {
552 // New high or low quality profile is found.
553 // Update its reference.
554 info->mHasRefProfile = true;
555 info->mRefProfileIndex = i;
556 info->mResolutionProduct = product;
557 }
558 }
559 }
560
561 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
562 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
563 int refIndex = getRequiredProfileRefIndex(cameraId);
564 CHECK(refIndex != -1);
565 RequiredProfileRefInfo *info =
566 &mRequiredProfileRefs[refIndex].mRefs[j];
567
568 if (info->mHasRefProfile) {
569
570 CamcorderProfile *profile =
571 new CamcorderProfile(
572 *mCamcorderProfiles[info->mRefProfileIndex]);
573
574 // Overwrite the quality
575 switch (j % kNumRequiredProfiles) {
576 case 0:
577 profile->mQuality = CAMCORDER_QUALITY_LOW;
578 break;
579 case 1:
580 profile->mQuality = CAMCORDER_QUALITY_HIGH;
581 break;
582 case 2:
583 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
584 break;
585 case 3:
586 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
587 break;
588 default:
589 CHECK(!"Should never come here");
590 }
591
592 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
593 if (index != -1) {
Steve Block3856b092011-10-20 11:56:00 +0100594 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800595 profile->mQuality, cameraId);
596 CHECK(index == refIndex);
597 continue;
598 }
599
600 // Insert the new profile
Steve Block3856b092011-10-20 11:56:00 +0100601 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800602 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
603 profile->mQuality, cameraId);
604
605 mCamcorderProfiles.add(profile);
606 }
607 }
608 }
609}
610
James Dong1d7491b2010-01-19 17:45:38 -0800611/*static*/ MediaProfiles*
612MediaProfiles::getInstance()
613{
Steve Block3856b092011-10-20 11:56:00 +0100614 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800615 Mutex::Autolock lock(sLock);
616 if (!sIsInitialized) {
617 char value[PROPERTY_VALUE_MAX];
618 if (property_get("media.settings.xml", value, NULL) <= 0) {
619 const char *defaultXmlFile = "/etc/media_profiles.xml";
620 FILE *fp = fopen(defaultXmlFile, "r");
621 if (fp == NULL) {
622 LOGW("could not find media config xml file");
623 sInstance = createDefaultInstance();
624 } else {
625 fclose(fp); // close the file first.
626 sInstance = createInstanceFromXmlFile(defaultXmlFile);
627 }
628 } else {
629 sInstance = createInstanceFromXmlFile(value);
630 }
James Dong2a7e0a12011-02-28 21:07:39 -0800631 CHECK(sInstance != NULL);
632 sInstance->checkAndAddRequiredProfilesIfNecessary();
633 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800634 }
635
636 return sInstance;
637}
638
639/*static*/ MediaProfiles::VideoEncoderCap*
640MediaProfiles::createDefaultH263VideoEncoderCap()
641{
642 return new MediaProfiles::VideoEncoderCap(
643 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
644}
645
646/*static*/ MediaProfiles::VideoEncoderCap*
647MediaProfiles::createDefaultM4vVideoEncoderCap()
648{
649 return new MediaProfiles::VideoEncoderCap(
650 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
651}
652
653
654/*static*/ void
655MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
656{
657 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
658 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
659}
660
661/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700662MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700663{
664 MediaProfiles::VideoCodec *videoCodec =
665 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
666
667 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
668 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
669 profile->mCameraId = 0;
670 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700671 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700672 profile->mDuration = 60;
673 profile->mVideoCodec = videoCodec;
674 profile->mAudioCodec = audioCodec;
675 return profile;
676}
677
678/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700679MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800680{
681 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700682 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800683
684 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800685 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
686 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800687 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700688 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800689 profile->mDuration = 60;
690 profile->mVideoCodec = videoCodec;
691 profile->mAudioCodec = audioCodec;
692 return profile;
693}
694
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700695/*static*/ void
696MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
697 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
698 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
699 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
700 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
701}
702
703/*static*/ void
704MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
705 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
706 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
707 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
708 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
709}
710
James Dong1d7491b2010-01-19 17:45:38 -0800711/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700712MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800713{
714 MediaProfiles::VideoCodec *videoCodec =
715 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
716
717 MediaProfiles::AudioCodec *audioCodec =
718 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
719
720 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800721 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800722 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700723 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800724 profile->mDuration = 30;
725 profile->mVideoCodec = videoCodec;
726 profile->mAudioCodec = audioCodec;
727 return profile;
728}
729
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700730/*static*/ MediaProfiles::CamcorderProfile*
731MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
732{
733 MediaProfiles::VideoCodec *videoCodec =
734 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
735
736 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
737 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
738 profile->mCameraId = 0;
739 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
740 profile->mQuality = quality;
741 profile->mDuration = 60;
742 profile->mVideoCodec = videoCodec;
743 profile->mAudioCodec = audioCodec;
744 return profile;
745}
746
747/*static*/ void
748MediaProfiles::createDefaultCamcorderLowProfiles(
749 MediaProfiles::CamcorderProfile **lowProfile,
750 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
751 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
752 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
753}
754
755/*static*/ void
756MediaProfiles::createDefaultCamcorderHighProfiles(
757 MediaProfiles::CamcorderProfile **highProfile,
758 MediaProfiles::CamcorderProfile **highSpecificProfile) {
759 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
760 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
761}
762
James Dong1d7491b2010-01-19 17:45:38 -0800763/*static*/ void
764MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
765{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700766 // low camcorder profiles.
767 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
768 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
769 profiles->mCamcorderProfiles.add(lowProfile);
770 profiles->mCamcorderProfiles.add(lowSpecificProfile);
771
772 // high camcorder profiles.
773 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
774 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
775 profiles->mCamcorderProfiles.add(highProfile);
776 profiles->mCamcorderProfiles.add(highSpecificProfile);
777
778 // low camcorder time lapse profiles.
779 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
780 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
781 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
782 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
783
784 // high camcorder time lapse profiles.
785 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
786 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
787 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
788 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700789
790 // For emulator and other legacy devices which does not have a
791 // media_profiles.xml file, We assume that the default camera id
792 // is 0 and that is the only camera available.
793 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800794}
795
796/*static*/ void
797MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
798{
799 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
800}
801
802/*static*/ void
803MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
804{
805 MediaProfiles::VideoDecoderCap *cap =
806 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
807
808 profiles->mVideoDecoders.add(cap);
809}
810
811/*static*/ void
812MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
813{
814 MediaProfiles::AudioDecoderCap *cap =
815 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
816
817 profiles->mAudioDecoders.add(cap);
818}
819
820/*static*/ void
821MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
822{
823 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
824 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
825}
826
827/*static*/ MediaProfiles::AudioEncoderCap*
828MediaProfiles::createDefaultAmrNBEncoderCap()
829{
830 return new MediaProfiles::AudioEncoderCap(
831 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
832}
833
James Dongf5a83852010-02-23 17:21:44 -0800834/*static*/ void
835MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
836{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800837 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
838 levels->mCameraId = 0;
839 levels->mLevels.add(70);
840 levels->mLevels.add(80);
841 levels->mLevels.add(90);
842 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800843}
844
Hong Tengcabd5f82011-07-06 18:33:09 -0700845/*static*/ void
846MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
847{
848 profiles->mVideoEditorCap =
849 new MediaProfiles::VideoEditorCap(
850 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
851 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
852 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
853 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT);
854}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700855/*static*/ void
856MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
857{
858 // Create default video export profiles
859 profiles->mVideoEditorExportProfiles.add(
860 new ExportVideoProfile(VIDEO_ENCODER_H263,
861 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
862 profiles->mVideoEditorExportProfiles.add(
863 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
864 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
865 profiles->mVideoEditorExportProfiles.add(
866 new ExportVideoProfile(VIDEO_ENCODER_H264,
867 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
868}
Hong Tengcabd5f82011-07-06 18:33:09 -0700869
James Dong1d7491b2010-01-19 17:45:38 -0800870/*static*/ MediaProfiles*
871MediaProfiles::createDefaultInstance()
872{
873 MediaProfiles *profiles = new MediaProfiles;
874 createDefaultCamcorderProfiles(profiles);
875 createDefaultVideoEncoders(profiles);
876 createDefaultAudioEncoders(profiles);
877 createDefaultVideoDecoders(profiles);
878 createDefaultAudioDecoders(profiles);
879 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800880 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700881 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700882 createDefaultExportVideoProfiles(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800883 return profiles;
884}
885
886/*static*/ MediaProfiles*
887MediaProfiles::createInstanceFromXmlFile(const char *xml)
888{
889 FILE *fp = NULL;
890 CHECK((fp = fopen(xml, "r")));
891
892 XML_Parser parser = ::XML_ParserCreate(NULL);
893 CHECK(parser != NULL);
894
895 MediaProfiles *profiles = new MediaProfiles();
896 ::XML_SetUserData(parser, profiles);
897 ::XML_SetElementHandler(parser, startElementHandler, NULL);
898
899 /*
900 FIXME:
901 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
902
903 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
904 LOGE("failed to enable DTD support in the xml file");
905 return UNKNOWN_ERROR;
906 }
907
908 */
909
910 const int BUFF_SIZE = 512;
911 for (;;) {
912 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
913 if (buff == NULL) {
914 LOGE("failed to in call to XML_GetBuffer()");
915 delete profiles;
916 profiles = NULL;
917 goto exit;
918 }
919
920 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
921 if (bytes_read < 0) {
922 LOGE("failed in call to read");
923 delete profiles;
924 profiles = NULL;
925 goto exit;
926 }
927
928 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
929
930 if (bytes_read == 0) break; // done parsing the xml file
931 }
932
933exit:
934 ::XML_ParserFree(parser);
935 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800936 return profiles;
937}
938
939Vector<output_format> MediaProfiles::getOutputFileFormats() const
940{
941 return mEncoderOutputFileFormats; // copy out
942}
943
944Vector<video_encoder> MediaProfiles::getVideoEncoders() const
945{
946 Vector<video_encoder> encoders;
947 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
948 encoders.add(mVideoEncoders[i]->mCodec);
949 }
950 return encoders; // copy out
951}
952
953int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
954{
Steve Block3856b092011-10-20 11:56:00 +0100955 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800956 int index = -1;
957 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
958 if (mVideoEncoders[i]->mCodec == codec) {
959 index = i;
960 break;
961 }
962 }
963 if (index == -1) {
964 LOGE("The given video encoder %d is not found", codec);
965 return -1;
966 }
967
968 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
969 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
970 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
971 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
972 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
973 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
974 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
975 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
976
977 LOGE("The given video encoder param name %s is not found", name);
978 return -1;
979}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700980int MediaProfiles::getVideoEditorExportParamByName(
981 const char *name, int codec) const
982{
Steve Block3856b092011-10-20 11:56:00 +0100983 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700984 ExportVideoProfile *exportProfile = NULL;
985 int index = -1;
986 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
987 exportProfile = mVideoEditorExportProfiles[i];
988 if (exportProfile->mCodec == codec) {
989 index = i;
990 break;
991 }
992 }
993 if (index == -1) {
994 LOGE("The given video decoder %d is not found", codec);
995 return -1;
996 }
997 if (!strcmp("videoeditor.export.profile", name))
998 return exportProfile->mProfile;
999 if (!strcmp("videoeditor.export.level", name))
1000 return exportProfile->mLevel;
James Dong1d7491b2010-01-19 17:45:38 -08001001
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001002 LOGE("The given video editor export param name %s is not found", name);
1003 return -1;
1004}
Hong Tengcabd5f82011-07-06 18:33:09 -07001005int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1006{
Steve Block3856b092011-10-20 11:56:00 +01001007 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001008
1009 if (mVideoEditorCap == NULL) {
1010 LOGE("The mVideoEditorCap is not created, then create default cap.");
1011 createDefaultVideoEditorCap(sInstance);
1012 }
1013
1014 if (!strcmp("videoeditor.input.width.max", name))
1015 return mVideoEditorCap->mMaxInputFrameWidth;
1016 if (!strcmp("videoeditor.input.height.max", name))
1017 return mVideoEditorCap->mMaxInputFrameHeight;
1018 if (!strcmp("videoeditor.output.width.max", name))
1019 return mVideoEditorCap->mMaxOutputFrameWidth;
1020 if (!strcmp("videoeditor.output.height.max", name))
1021 return mVideoEditorCap->mMaxOutputFrameHeight;
1022
1023 LOGE("The given video editor param name %s is not found", name);
1024 return -1;
1025}
1026
James Dong1d7491b2010-01-19 17:45:38 -08001027Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1028{
1029 Vector<audio_encoder> encoders;
1030 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1031 encoders.add(mAudioEncoders[i]->mCodec);
1032 }
1033 return encoders; // copy out
1034}
1035
1036int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1037{
Steve Block3856b092011-10-20 11:56:00 +01001038 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001039 int index = -1;
1040 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1041 if (mAudioEncoders[i]->mCodec == codec) {
1042 index = i;
1043 break;
1044 }
1045 }
1046 if (index == -1) {
1047 LOGE("The given audio encoder %d is not found", codec);
1048 return -1;
1049 }
1050
1051 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1052 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1053 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1054 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1055 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1056 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1057
1058 LOGE("The given audio encoder param name %s is not found", name);
1059 return -1;
1060}
1061
1062Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1063{
1064 Vector<video_decoder> decoders;
1065 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1066 decoders.add(mVideoDecoders[i]->mCodec);
1067 }
1068 return decoders; // copy out
1069}
1070
1071Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1072{
1073 Vector<audio_decoder> decoders;
1074 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1075 decoders.add(mAudioDecoders[i]->mCodec);
1076 }
1077 return decoders; // copy out
1078}
1079
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001080int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001081{
James Dong1d7491b2010-01-19 17:45:38 -08001082 int index = -1;
1083 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001084 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1085 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001086 index = i;
1087 break;
1088 }
1089 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001090 return index;
1091}
1092
1093int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1094 int cameraId,
1095 camcorder_quality quality) const
1096{
Steve Block3856b092011-10-20 11:56:00 +01001097 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001098 name, cameraId, quality);
1099
1100 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001101 if (index == -1) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001102 LOGE("The given camcorder profile camera %d quality %d is not found",
1103 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001104 return -1;
1105 }
1106
James Dongf5a83852010-02-23 17:21:44 -08001107 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001108 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1109 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1110 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1111 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1112 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1113 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1114 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1115 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1116 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1117 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1118
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001119 LOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001120 return -1;
1121}
1122
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001123bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1124{
1125 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1126}
1127
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001128Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001129{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001130 Vector<int> result;
1131 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1132 if (levels != NULL) {
1133 result = levels->mLevels; // copy out
1134 }
1135 return result;
James Dongf5a83852010-02-23 17:21:44 -08001136}
1137
James Dong0f056292011-05-09 18:49:31 -07001138int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1139 int offsetTimeMs = -1;
1140 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1141 if (index >= 0) {
1142 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1143 }
Steve Block3856b092011-10-20 11:56:00 +01001144 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001145 return offsetTimeMs;
1146}
1147
James Dong1d7491b2010-01-19 17:45:38 -08001148MediaProfiles::~MediaProfiles()
1149{
1150 CHECK("destructor should never be called" == 0);
1151#if 0
1152 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1153 delete mAudioEncoders[i];
1154 }
1155 mAudioEncoders.clear();
1156
1157 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1158 delete mVideoEncoders[i];
1159 }
1160 mVideoEncoders.clear();
1161
1162 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1163 delete mVideoDecoders[i];
1164 }
1165 mVideoDecoders.clear();
1166
1167 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1168 delete mAudioDecoders[i];
1169 }
1170 mAudioDecoders.clear();
1171
1172 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1173 delete mCamcorderProfiles[i];
1174 }
1175 mCamcorderProfiles.clear();
1176#endif
1177}
1178} // namespace android