blob: f0f07a2151f038e7ac4733b8bfd4d56ae20366da [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>
29
30namespace android {
31
32Mutex MediaProfiles::sLock;
33bool MediaProfiles::sIsInitialized = false;
34MediaProfiles *MediaProfiles::sInstance = NULL;
35
36const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
37 {"h263", VIDEO_ENCODER_H263},
38 {"h264", VIDEO_ENCODER_H264},
39 {"m4v", VIDEO_ENCODER_MPEG_4_SP}
40};
41
42const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
43 {"amrnb", AUDIO_ENCODER_AMR_NB},
44 {"amrwb", AUDIO_ENCODER_AMR_WB},
45 {"aac", AUDIO_ENCODER_AAC},
46};
47
48const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
49 {"3gp", OUTPUT_FORMAT_THREE_GPP},
50 {"mp4", OUTPUT_FORMAT_MPEG_4}
51};
52
53const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
54 {"wmv", VIDEO_DECODER_WMV}
55};
56
57const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
58 {"wma", AUDIO_DECODER_WMA}
59};
60
61const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -070062 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -080063 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070064 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070065 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070066 {"480p", CAMCORDER_QUALITY_480P},
67 {"720p", CAMCORDER_QUALITY_720P},
68 {"1080p", CAMCORDER_QUALITY_1080P},
69
70 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
71 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
72 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070073 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070074 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
75 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
76 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P}
James Dong1d7491b2010-01-19 17:45:38 -080077};
78
79/*static*/ void
80MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
81{
82 LOGV("video codec:");
83 LOGV("codec = %d", codec.mCodec);
84 LOGV("bit rate: %d", codec.mBitRate);
85 LOGV("frame width: %d", codec.mFrameWidth);
86 LOGV("frame height: %d", codec.mFrameHeight);
87 LOGV("frame rate: %d", codec.mFrameRate);
88}
89
90/*static*/ void
91MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
92{
93 LOGV("audio codec:");
94 LOGV("codec = %d", codec.mCodec);
95 LOGV("bit rate: %d", codec.mBitRate);
96 LOGV("sample rate: %d", codec.mSampleRate);
97 LOGV("number of channels: %d", codec.mChannels);
98}
99
100/*static*/ void
101MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
102{
103 LOGV("video encoder cap:");
104 LOGV("codec = %d", cap.mCodec);
105 LOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
106 LOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
107 LOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
108 LOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
109}
110
111/*static*/ void
112MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
113{
114 LOGV("audio encoder cap:");
115 LOGV("codec = %d", cap.mCodec);
116 LOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
117 LOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
118 LOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
119}
120
121/*static*/ void
122MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
123{
124 LOGV("video decoder cap:");
125 LOGV("codec = %d", cap.mCodec);
126}
127
128/*static*/ void
129MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
130{
131 LOGV("audio codec cap:");
132 LOGV("codec = %d", cap.mCodec);
133}
134
Hong Tengcabd5f82011-07-06 18:33:09 -0700135/*static*/ void
136MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
137{
138 LOGV("videoeditor cap:");
139 LOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
140 LOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
141 LOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
142 LOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
143}
144
James Dong1d7491b2010-01-19 17:45:38 -0800145/*static*/ int
146MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
147{
148 int tag = -1;
149 for (size_t i = 0; i < nMappings; ++i) {
150 if (!strcmp(map[i].name, name)) {
151 tag = map[i].tag;
152 break;
153 }
154 }
155 return tag;
156}
157
158/*static*/ MediaProfiles::VideoCodec*
159MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
160{
161 CHECK(!strcmp("codec", atts[0]) &&
162 !strcmp("bitRate", atts[2]) &&
163 !strcmp("width", atts[4]) &&
164 !strcmp("height", atts[6]) &&
165 !strcmp("frameRate", atts[8]));
166
167 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
168 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
169 CHECK(codec != -1);
170
171 MediaProfiles::VideoCodec *videoCodec =
172 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
173 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
174 logVideoCodec(*videoCodec);
175
176 size_t nCamcorderProfiles;
177 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
178 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
179 return videoCodec;
180}
181
182/*static*/ MediaProfiles::AudioCodec*
183MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
184{
185 CHECK(!strcmp("codec", atts[0]) &&
186 !strcmp("bitRate", atts[2]) &&
187 !strcmp("sampleRate", atts[4]) &&
188 !strcmp("channels", atts[6]));
189 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
190 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
191 CHECK(codec != -1);
192
193 MediaProfiles::AudioCodec *audioCodec =
194 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
195 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
196 logAudioCodec(*audioCodec);
197
198 size_t nCamcorderProfiles;
199 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
200 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
201 return audioCodec;
202}
203/*static*/ MediaProfiles::AudioDecoderCap*
204MediaProfiles::createAudioDecoderCap(const char **atts)
205{
206 CHECK(!strcmp("name", atts[0]) &&
207 !strcmp("enabled", atts[2]));
208
209 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
210 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
211 CHECK(codec != -1);
212
213 MediaProfiles::AudioDecoderCap *cap =
214 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
215 logAudioDecoderCap(*cap);
216 return cap;
217}
218
219/*static*/ MediaProfiles::VideoDecoderCap*
220MediaProfiles::createVideoDecoderCap(const char **atts)
221{
222 CHECK(!strcmp("name", atts[0]) &&
223 !strcmp("enabled", atts[2]));
224
225 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
226 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
227 CHECK(codec != -1);
228
229 MediaProfiles::VideoDecoderCap *cap =
230 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
231 logVideoDecoderCap(*cap);
232 return cap;
233}
234
235/*static*/ MediaProfiles::VideoEncoderCap*
236MediaProfiles::createVideoEncoderCap(const char **atts)
237{
238 CHECK(!strcmp("name", atts[0]) &&
239 !strcmp("enabled", atts[2]) &&
240 !strcmp("minBitRate", atts[4]) &&
241 !strcmp("maxBitRate", atts[6]) &&
242 !strcmp("minFrameWidth", atts[8]) &&
243 !strcmp("maxFrameWidth", atts[10]) &&
244 !strcmp("minFrameHeight", atts[12]) &&
245 !strcmp("maxFrameHeight", atts[14]) &&
246 !strcmp("minFrameRate", atts[16]) &&
247 !strcmp("maxFrameRate", atts[18]));
248
249 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
250 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
251 CHECK(codec != -1);
252
253 MediaProfiles::VideoEncoderCap *cap =
254 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
255 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
256 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
257 logVideoEncoderCap(*cap);
258 return cap;
259}
260
261/*static*/ MediaProfiles::AudioEncoderCap*
262MediaProfiles::createAudioEncoderCap(const char **atts)
263{
264 CHECK(!strcmp("name", atts[0]) &&
265 !strcmp("enabled", atts[2]) &&
266 !strcmp("minBitRate", atts[4]) &&
267 !strcmp("maxBitRate", atts[6]) &&
268 !strcmp("minSampleRate", atts[8]) &&
269 !strcmp("maxSampleRate", atts[10]) &&
270 !strcmp("minChannels", atts[12]) &&
271 !strcmp("maxChannels", atts[14]));
272
273 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
274 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
275 CHECK(codec != -1);
276
277 MediaProfiles::AudioEncoderCap *cap =
278 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
279 atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
280 atoi(atts[15]));
281 logAudioEncoderCap(*cap);
282 return cap;
283}
284
285/*static*/ output_format
286MediaProfiles::createEncoderOutputFileFormat(const char **atts)
287{
288 CHECK(!strcmp("name", atts[0]));
289
290 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
291 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
292 CHECK(format != -1);
293
294 return static_cast<output_format>(format);
295}
296
James Dong2a7e0a12011-02-28 21:07:39 -0800297static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
298 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
299 if (cameraId == cameraIds[i]) {
300 return true;
301 }
302 }
303 return false;
304}
305
James Dong1d7491b2010-01-19 17:45:38 -0800306/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800307MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800308{
309 CHECK(!strcmp("quality", atts[0]) &&
310 !strcmp("fileFormat", atts[2]) &&
311 !strcmp("duration", atts[4]));
312
313 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
314 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
315 CHECK(quality != -1);
316
317 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
318 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
319 CHECK(fileFormat != -1);
320
321 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800322 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800323 if (!isCameraIdFound(cameraId, cameraIds)) {
324 cameraIds.add(cameraId);
325 }
James Dong1d7491b2010-01-19 17:45:38 -0800326 profile->mFileFormat = static_cast<output_format>(fileFormat);
327 profile->mQuality = static_cast<camcorder_quality>(quality);
328 profile->mDuration = atoi(atts[5]);
329 return profile;
330}
331
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800332MediaProfiles::ImageEncodingQualityLevels*
333MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
334{
335 int n = mImageEncodingQualityLevels.size();
336 for (int i = 0; i < n; i++) {
337 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
338 if (levels->mCameraId == cameraId) {
339 return levels;
340 }
341 }
342 return NULL;
343}
344
345void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800346{
347 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800348 int quality = atoi(atts[1]);
349 LOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality);
350 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
351
352 if (levels == NULL) {
353 levels = new ImageEncodingQualityLevels();
354 levels->mCameraId = cameraId;
355 mImageEncodingQualityLevels.add(levels);
356 }
357
358 levels->mLevels.add(quality);
359}
360
361/*static*/ int
362MediaProfiles::getCameraId(const char** atts)
363{
364 if (!atts[0]) return 0; // default cameraId = 0
365 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800366 return atoi(atts[1]);
367}
368
James Dong0f056292011-05-09 18:49:31 -0700369void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
370{
371 int offsetTimeMs = 700;
372 if (atts[2]) {
373 CHECK(!strcmp("startOffsetMs", atts[2]));
374 offsetTimeMs = atoi(atts[3]);
375 }
376
377 LOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
378 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
379}
380
Hong Tengcabd5f82011-07-06 18:33:09 -0700381/*static*/ MediaProfiles::VideoEditorCap*
382MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
383{
384 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
385 !strcmp("maxInputFrameHeight", atts[2]) &&
386 !strcmp("maxOutputFrameWidth", atts[4]) &&
387 !strcmp("maxOutputFrameHeight", atts[6]));
388
389 MediaProfiles::VideoEditorCap *pVideoEditorCap =
390 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
391 atoi(atts[5]), atoi(atts[7]));
392
393 logVideoEditorCap(*pVideoEditorCap);
394 profiles->mVideoEditorCap = pVideoEditorCap;
395
396 return pVideoEditorCap;
397}
398
James Dong1d7491b2010-01-19 17:45:38 -0800399/*static*/ void
400MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
401{
402 MediaProfiles *profiles = (MediaProfiles *) userData;
403 if (strcmp("Video", name) == 0) {
404 createVideoCodec(atts, profiles);
405 } else if (strcmp("Audio", name) == 0) {
406 createAudioCodec(atts, profiles);
407 } else if (strcmp("VideoEncoderCap", name) == 0 &&
408 strcmp("true", atts[3]) == 0) {
409 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
410 } else if (strcmp("AudioEncoderCap", name) == 0 &&
411 strcmp("true", atts[3]) == 0) {
412 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
413 } else if (strcmp("VideoDecoderCap", name) == 0 &&
414 strcmp("true", atts[3]) == 0) {
415 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
416 } else if (strcmp("AudioDecoderCap", name) == 0 &&
417 strcmp("true", atts[3]) == 0) {
418 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
419 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
420 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800421 } else if (strcmp("CamcorderProfiles", name) == 0) {
422 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700423 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800424 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800425 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800426 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800427 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800428 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700429 } else if (strcmp("VideoEditorCap", name) == 0) {
430 createVideoEditorCap(atts, profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800431 }
432}
433
James Dong2a7e0a12011-02-28 21:07:39 -0800434static bool isCamcorderProfile(camcorder_quality quality) {
435 return quality >= CAMCORDER_QUALITY_LIST_START &&
436 quality <= CAMCORDER_QUALITY_LIST_END;
437}
438
439static bool isTimelapseProfile(camcorder_quality quality) {
440 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
441 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
442}
443
444void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
445 LOGV("Number of camera ids: %d", cameraIds.size());
446 CHECK(cameraIds.size() > 0);
447 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
448 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
449 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
450 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
451 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
452 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
453 if ((j & 1) == 0) { // low resolution
454 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
455 } else { // high resolution
456 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
457 }
458 }
459 }
460}
461
462int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
463 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
464 if (mCameraIds[i] == cameraId) {
465 return i;
466 }
467 }
468 return -1;
469}
470
471void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
472 if (sIsInitialized) {
473 return;
474 }
475
476 initRequiredProfileRefs(mCameraIds);
477
478 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
479 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
480 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
481
482 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
483 int cameraId = mCamcorderProfiles[i]->mCameraId;
484 int index = -1;
485 int refIndex = getRequiredProfileRefIndex(cameraId);
486 CHECK(refIndex != -1);
487 RequiredProfileRefInfo *info;
488 camcorder_quality refQuality;
489 VideoCodec *codec = NULL;
490
491 // Check high and low from either camcorder profile or timelapse profile
492 // but not both. Default, check camcorder profile
493 size_t j = 0;
494 size_t n = 2;
495 if (isTimelapseProfile(quality)) {
496 // Check timelapse profile instead.
497 j = 2;
498 n = kNumRequiredProfiles;
499 } else {
500 // Must be camcorder profile.
501 CHECK(isCamcorderProfile(quality));
502 }
503 for (; j < n; ++j) {
504 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
505 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
506 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
507 continue;
508 }
509 switch (j) {
510 case 0:
511 refQuality = CAMCORDER_QUALITY_LOW;
512 break;
513 case 1:
514 refQuality = CAMCORDER_QUALITY_HIGH;
515 break;
516 case 2:
517 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
518 break;
519 case 3:
520 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
521 break;
522 default:
523 CHECK(!"Should never reach here");
524 }
525
526 if (!info->mHasRefProfile) {
527 index = getCamcorderProfileIndex(cameraId, refQuality);
528 }
529 if (index == -1) {
530 // New high or low quality profile is found.
531 // Update its reference.
532 info->mHasRefProfile = true;
533 info->mRefProfileIndex = i;
534 info->mResolutionProduct = product;
535 }
536 }
537 }
538
539 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
540 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
541 int refIndex = getRequiredProfileRefIndex(cameraId);
542 CHECK(refIndex != -1);
543 RequiredProfileRefInfo *info =
544 &mRequiredProfileRefs[refIndex].mRefs[j];
545
546 if (info->mHasRefProfile) {
547
548 CamcorderProfile *profile =
549 new CamcorderProfile(
550 *mCamcorderProfiles[info->mRefProfileIndex]);
551
552 // Overwrite the quality
553 switch (j % kNumRequiredProfiles) {
554 case 0:
555 profile->mQuality = CAMCORDER_QUALITY_LOW;
556 break;
557 case 1:
558 profile->mQuality = CAMCORDER_QUALITY_HIGH;
559 break;
560 case 2:
561 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
562 break;
563 case 3:
564 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
565 break;
566 default:
567 CHECK(!"Should never come here");
568 }
569
570 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
571 if (index != -1) {
572 LOGV("Profile quality %d for camera %d already exists",
573 profile->mQuality, cameraId);
574 CHECK(index == refIndex);
575 continue;
576 }
577
578 // Insert the new profile
579 LOGV("Add a profile: quality %d=>%d for camera %d",
580 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
581 profile->mQuality, cameraId);
582
583 mCamcorderProfiles.add(profile);
584 }
585 }
586 }
587}
588
James Dong1d7491b2010-01-19 17:45:38 -0800589/*static*/ MediaProfiles*
590MediaProfiles::getInstance()
591{
592 LOGV("getInstance");
593 Mutex::Autolock lock(sLock);
594 if (!sIsInitialized) {
595 char value[PROPERTY_VALUE_MAX];
596 if (property_get("media.settings.xml", value, NULL) <= 0) {
597 const char *defaultXmlFile = "/etc/media_profiles.xml";
598 FILE *fp = fopen(defaultXmlFile, "r");
599 if (fp == NULL) {
600 LOGW("could not find media config xml file");
601 sInstance = createDefaultInstance();
602 } else {
603 fclose(fp); // close the file first.
604 sInstance = createInstanceFromXmlFile(defaultXmlFile);
605 }
606 } else {
607 sInstance = createInstanceFromXmlFile(value);
608 }
James Dong2a7e0a12011-02-28 21:07:39 -0800609 CHECK(sInstance != NULL);
610 sInstance->checkAndAddRequiredProfilesIfNecessary();
611 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800612 }
613
614 return sInstance;
615}
616
617/*static*/ MediaProfiles::VideoEncoderCap*
618MediaProfiles::createDefaultH263VideoEncoderCap()
619{
620 return new MediaProfiles::VideoEncoderCap(
621 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
622}
623
624/*static*/ MediaProfiles::VideoEncoderCap*
625MediaProfiles::createDefaultM4vVideoEncoderCap()
626{
627 return new MediaProfiles::VideoEncoderCap(
628 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
629}
630
631
632/*static*/ void
633MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
634{
635 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
636 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
637}
638
639/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700640MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700641{
642 MediaProfiles::VideoCodec *videoCodec =
643 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
644
645 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
646 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
647 profile->mCameraId = 0;
648 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700649 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700650 profile->mDuration = 60;
651 profile->mVideoCodec = videoCodec;
652 profile->mAudioCodec = audioCodec;
653 return profile;
654}
655
656/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700657MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800658{
659 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700660 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800661
662 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800663 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
664 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800665 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700666 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800667 profile->mDuration = 60;
668 profile->mVideoCodec = videoCodec;
669 profile->mAudioCodec = audioCodec;
670 return profile;
671}
672
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700673/*static*/ void
674MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
675 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
676 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
677 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
678 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
679}
680
681/*static*/ void
682MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
683 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
684 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
685 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
686 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
687}
688
James Dong1d7491b2010-01-19 17:45:38 -0800689/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700690MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800691{
692 MediaProfiles::VideoCodec *videoCodec =
693 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
694
695 MediaProfiles::AudioCodec *audioCodec =
696 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
697
698 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800699 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800700 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700701 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800702 profile->mDuration = 30;
703 profile->mVideoCodec = videoCodec;
704 profile->mAudioCodec = audioCodec;
705 return profile;
706}
707
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700708/*static*/ MediaProfiles::CamcorderProfile*
709MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
710{
711 MediaProfiles::VideoCodec *videoCodec =
712 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
713
714 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
715 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
716 profile->mCameraId = 0;
717 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
718 profile->mQuality = quality;
719 profile->mDuration = 60;
720 profile->mVideoCodec = videoCodec;
721 profile->mAudioCodec = audioCodec;
722 return profile;
723}
724
725/*static*/ void
726MediaProfiles::createDefaultCamcorderLowProfiles(
727 MediaProfiles::CamcorderProfile **lowProfile,
728 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
729 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
730 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
731}
732
733/*static*/ void
734MediaProfiles::createDefaultCamcorderHighProfiles(
735 MediaProfiles::CamcorderProfile **highProfile,
736 MediaProfiles::CamcorderProfile **highSpecificProfile) {
737 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
738 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
739}
740
James Dong1d7491b2010-01-19 17:45:38 -0800741/*static*/ void
742MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
743{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700744 // low camcorder profiles.
745 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
746 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
747 profiles->mCamcorderProfiles.add(lowProfile);
748 profiles->mCamcorderProfiles.add(lowSpecificProfile);
749
750 // high camcorder profiles.
751 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
752 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
753 profiles->mCamcorderProfiles.add(highProfile);
754 profiles->mCamcorderProfiles.add(highSpecificProfile);
755
756 // low camcorder time lapse profiles.
757 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
758 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
759 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
760 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
761
762 // high camcorder time lapse profiles.
763 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
764 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
765 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
766 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700767
768 // For emulator and other legacy devices which does not have a
769 // media_profiles.xml file, We assume that the default camera id
770 // is 0 and that is the only camera available.
771 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800772}
773
774/*static*/ void
775MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
776{
777 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
778}
779
780/*static*/ void
781MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
782{
783 MediaProfiles::VideoDecoderCap *cap =
784 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
785
786 profiles->mVideoDecoders.add(cap);
787}
788
789/*static*/ void
790MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
791{
792 MediaProfiles::AudioDecoderCap *cap =
793 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
794
795 profiles->mAudioDecoders.add(cap);
796}
797
798/*static*/ void
799MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
800{
801 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
802 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
803}
804
805/*static*/ MediaProfiles::AudioEncoderCap*
806MediaProfiles::createDefaultAmrNBEncoderCap()
807{
808 return new MediaProfiles::AudioEncoderCap(
809 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
810}
811
James Dongf5a83852010-02-23 17:21:44 -0800812/*static*/ void
813MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
814{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800815 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
816 levels->mCameraId = 0;
817 levels->mLevels.add(70);
818 levels->mLevels.add(80);
819 levels->mLevels.add(90);
820 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800821}
822
Hong Tengcabd5f82011-07-06 18:33:09 -0700823/*static*/ void
824MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
825{
826 profiles->mVideoEditorCap =
827 new MediaProfiles::VideoEditorCap(
828 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
829 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
830 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
831 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT);
832}
833
James Dong1d7491b2010-01-19 17:45:38 -0800834/*static*/ MediaProfiles*
835MediaProfiles::createDefaultInstance()
836{
837 MediaProfiles *profiles = new MediaProfiles;
838 createDefaultCamcorderProfiles(profiles);
839 createDefaultVideoEncoders(profiles);
840 createDefaultAudioEncoders(profiles);
841 createDefaultVideoDecoders(profiles);
842 createDefaultAudioDecoders(profiles);
843 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800844 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700845 createDefaultVideoEditorCap(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800846 return profiles;
847}
848
849/*static*/ MediaProfiles*
850MediaProfiles::createInstanceFromXmlFile(const char *xml)
851{
852 FILE *fp = NULL;
853 CHECK((fp = fopen(xml, "r")));
854
855 XML_Parser parser = ::XML_ParserCreate(NULL);
856 CHECK(parser != NULL);
857
858 MediaProfiles *profiles = new MediaProfiles();
859 ::XML_SetUserData(parser, profiles);
860 ::XML_SetElementHandler(parser, startElementHandler, NULL);
861
862 /*
863 FIXME:
864 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
865
866 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
867 LOGE("failed to enable DTD support in the xml file");
868 return UNKNOWN_ERROR;
869 }
870
871 */
872
873 const int BUFF_SIZE = 512;
874 for (;;) {
875 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
876 if (buff == NULL) {
877 LOGE("failed to in call to XML_GetBuffer()");
878 delete profiles;
879 profiles = NULL;
880 goto exit;
881 }
882
883 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
884 if (bytes_read < 0) {
885 LOGE("failed in call to read");
886 delete profiles;
887 profiles = NULL;
888 goto exit;
889 }
890
891 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
892
893 if (bytes_read == 0) break; // done parsing the xml file
894 }
895
896exit:
897 ::XML_ParserFree(parser);
898 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800899 return profiles;
900}
901
902Vector<output_format> MediaProfiles::getOutputFileFormats() const
903{
904 return mEncoderOutputFileFormats; // copy out
905}
906
907Vector<video_encoder> MediaProfiles::getVideoEncoders() const
908{
909 Vector<video_encoder> encoders;
910 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
911 encoders.add(mVideoEncoders[i]->mCodec);
912 }
913 return encoders; // copy out
914}
915
916int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
917{
918 LOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
919 int index = -1;
920 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
921 if (mVideoEncoders[i]->mCodec == codec) {
922 index = i;
923 break;
924 }
925 }
926 if (index == -1) {
927 LOGE("The given video encoder %d is not found", codec);
928 return -1;
929 }
930
931 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
932 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
933 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
934 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
935 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
936 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
937 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
938 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
939
940 LOGE("The given video encoder param name %s is not found", name);
941 return -1;
942}
943
Hong Tengcabd5f82011-07-06 18:33:09 -0700944int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
945{
946 LOGV("getVideoEditorCapParamByName: %s", name);
947
948 if (mVideoEditorCap == NULL) {
949 LOGE("The mVideoEditorCap is not created, then create default cap.");
950 createDefaultVideoEditorCap(sInstance);
951 }
952
953 if (!strcmp("videoeditor.input.width.max", name))
954 return mVideoEditorCap->mMaxInputFrameWidth;
955 if (!strcmp("videoeditor.input.height.max", name))
956 return mVideoEditorCap->mMaxInputFrameHeight;
957 if (!strcmp("videoeditor.output.width.max", name))
958 return mVideoEditorCap->mMaxOutputFrameWidth;
959 if (!strcmp("videoeditor.output.height.max", name))
960 return mVideoEditorCap->mMaxOutputFrameHeight;
961
962 LOGE("The given video editor param name %s is not found", name);
963 return -1;
964}
965
James Dong1d7491b2010-01-19 17:45:38 -0800966Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
967{
968 Vector<audio_encoder> encoders;
969 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
970 encoders.add(mAudioEncoders[i]->mCodec);
971 }
972 return encoders; // copy out
973}
974
975int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
976{
977 LOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
978 int index = -1;
979 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
980 if (mAudioEncoders[i]->mCodec == codec) {
981 index = i;
982 break;
983 }
984 }
985 if (index == -1) {
986 LOGE("The given audio encoder %d is not found", codec);
987 return -1;
988 }
989
990 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
991 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
992 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
993 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
994 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
995 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
996
997 LOGE("The given audio encoder param name %s is not found", name);
998 return -1;
999}
1000
1001Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1002{
1003 Vector<video_decoder> decoders;
1004 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1005 decoders.add(mVideoDecoders[i]->mCodec);
1006 }
1007 return decoders; // copy out
1008}
1009
1010Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1011{
1012 Vector<audio_decoder> decoders;
1013 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1014 decoders.add(mAudioDecoders[i]->mCodec);
1015 }
1016 return decoders; // copy out
1017}
1018
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001019int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001020{
James Dong1d7491b2010-01-19 17:45:38 -08001021 int index = -1;
1022 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001023 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1024 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001025 index = i;
1026 break;
1027 }
1028 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001029 return index;
1030}
1031
1032int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1033 int cameraId,
1034 camcorder_quality quality) const
1035{
1036 LOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
1037 name, cameraId, quality);
1038
1039 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001040 if (index == -1) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001041 LOGE("The given camcorder profile camera %d quality %d is not found",
1042 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001043 return -1;
1044 }
1045
James Dongf5a83852010-02-23 17:21:44 -08001046 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001047 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1048 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1049 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1050 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1051 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1052 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1053 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1054 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1055 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1056 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1057
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001058 LOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001059 return -1;
1060}
1061
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001062bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1063{
1064 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1065}
1066
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001067Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001068{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001069 Vector<int> result;
1070 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1071 if (levels != NULL) {
1072 result = levels->mLevels; // copy out
1073 }
1074 return result;
James Dongf5a83852010-02-23 17:21:44 -08001075}
1076
James Dong0f056292011-05-09 18:49:31 -07001077int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1078 int offsetTimeMs = -1;
1079 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1080 if (index >= 0) {
1081 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1082 }
1083 LOGV("%s: offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
1084 return offsetTimeMs;
1085}
1086
James Dong1d7491b2010-01-19 17:45:38 -08001087MediaProfiles::~MediaProfiles()
1088{
1089 CHECK("destructor should never be called" == 0);
1090#if 0
1091 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1092 delete mAudioEncoders[i];
1093 }
1094 mAudioEncoders.clear();
1095
1096 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1097 delete mVideoEncoders[i];
1098 }
1099 mVideoEncoders.clear();
1100
1101 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1102 delete mVideoDecoders[i];
1103 }
1104 mVideoDecoders.clear();
1105
1106 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1107 delete mAudioDecoders[i];
1108 }
1109 mAudioDecoders.clear();
1110
1111 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1112 delete mCamcorderProfiles[i];
1113 }
1114 mCamcorderProfiles.clear();
1115#endif
1116}
1117} // namespace android