blob: a7536b362a51c7329c9e374aab1efd82ebf019b7 [file] [log] [blame]
James Dongc3711942010-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>
James Dong8e9d67a2012-02-06 23:46:37 -080028#include <media/stagefright/foundation/ADebug.h>
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -070029#include <media/stagefright/openmax/OMX_Video.h>
James Dongc3711942010-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 Kwatra4af0dfd2010-09-06 15:59:02 -070063 {"low", CAMCORDER_QUALITY_LOW},
James Dongc3711942010-01-19 17:45:38 -080064 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatra4af0dfd2010-09-06 15:59:02 -070065 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra522632c2010-09-10 15:45:57 -070066 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatra4af0dfd2010-09-06 15:59:02 -070067 {"480p", CAMCORDER_QUALITY_480P},
68 {"720p", CAMCORDER_QUALITY_720P},
69 {"1080p", CAMCORDER_QUALITY_1080P},
James Dong07b9ae32011-09-19 16:27:31 -070070 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatra4af0dfd2010-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 Kwatra522632c2010-09-10 15:45:57 -070075 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatra4af0dfd2010-09-06 15:59:02 -070076 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
77 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong07b9ae32011-09-19 16:27:31 -070078 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
79 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
James Dongc3711942010-01-19 17:45:38 -080080};
81
82/*static*/ void
83MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
84{
Steve Block71f2cf12011-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 Dongc3711942010-01-19 17:45:38 -080091}
92
93/*static*/ void
94MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
95{
Steve Block71f2cf12011-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 Dongc3711942010-01-19 17:45:38 -0800101}
102
103/*static*/ void
104MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
105{
Steve Block71f2cf12011-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 Dongc3711942010-01-19 17:45:38 -0800112}
113
114/*static*/ void
115MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
116{
Steve Block71f2cf12011-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 Dongc3711942010-01-19 17:45:38 -0800122}
123
124/*static*/ void
125MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
126{
Steve Block71f2cf12011-10-20 11:56:00 +0100127 ALOGV("video decoder cap:");
128 ALOGV("codec = %d", cap.mCodec);
James Dongc3711942010-01-19 17:45:38 -0800129}
130
131/*static*/ void
132MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
133{
Steve Block71f2cf12011-10-20 11:56:00 +0100134 ALOGV("audio codec cap:");
135 ALOGV("codec = %d", cap.mCodec);
James Dongc3711942010-01-19 17:45:38 -0800136}
137
Hong Teng600acf12011-07-06 18:33:09 -0700138/*static*/ void
139MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
140{
Steve Block71f2cf12011-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 Teng600acf12011-07-06 18:33:09 -0700146}
147
James Dongc3711942010-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 Dong797e4f12011-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 Dongc3711942010-01-19 17:45:38 -0800309/*static*/ MediaProfiles::CamcorderProfile*
James Dong797e4f12011-02-28 21:07:39 -0800310MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dongc3711942010-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 Chang09b90052010-06-22 20:50:55 +0800325 profile->mCameraId = cameraId;
James Dong797e4f12011-02-28 21:07:39 -0800326 if (!isCameraIdFound(cameraId, cameraIds)) {
327 cameraIds.add(cameraId);
328 }
James Dongc3711942010-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 Chang09b90052010-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 Dong9b433f02010-02-23 17:21:44 -0800349{
350 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800351 int quality = atoi(atts[1]);
Glenn Kasten0765c442012-01-27 15:24:38 -0800352 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang09b90052010-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 Dong9b433f02010-02-23 17:21:44 -0800369 return atoi(atts[1]);
370}
371
James Donga403a932011-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 Block71f2cf12011-10-20 11:56:00 +0100380 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Donga403a932011-05-09 18:49:31 -0700381 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
382}
Rajneesh Chowdury3ced0442011-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 Donga403a932011-05-09 18:49:31 -0700389
Rajneesh Chowdury3ced0442011-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 Teng600acf12011-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]) &&
Hong Teng7eb53192011-11-10 14:54:26 -0800407 !strcmp("maxOutputFrameHeight", atts[6]) &&
408 !strcmp("maxPrefetchYUVFrames", atts[8]));
Hong Teng600acf12011-07-06 18:33:09 -0700409
410 MediaProfiles::VideoEditorCap *pVideoEditorCap =
411 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
Hong Teng7eb53192011-11-10 14:54:26 -0800412 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
Hong Teng600acf12011-07-06 18:33:09 -0700413
414 logVideoEditorCap(*pVideoEditorCap);
415 profiles->mVideoEditorCap = pVideoEditorCap;
416
417 return pVideoEditorCap;
418}
419
James Dongc3711942010-01-19 17:45:38 -0800420/*static*/ void
421MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
422{
423 MediaProfiles *profiles = (MediaProfiles *) userData;
424 if (strcmp("Video", name) == 0) {
425 createVideoCodec(atts, profiles);
426 } else if (strcmp("Audio", name) == 0) {
427 createAudioCodec(atts, profiles);
428 } else if (strcmp("VideoEncoderCap", name) == 0 &&
429 strcmp("true", atts[3]) == 0) {
430 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
431 } else if (strcmp("AudioEncoderCap", name) == 0 &&
432 strcmp("true", atts[3]) == 0) {
433 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
434 } else if (strcmp("VideoDecoderCap", name) == 0 &&
435 strcmp("true", atts[3]) == 0) {
436 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
437 } else if (strcmp("AudioDecoderCap", name) == 0 &&
438 strcmp("true", atts[3]) == 0) {
439 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
440 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
441 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800442 } else if (strcmp("CamcorderProfiles", name) == 0) {
443 profiles->mCurrentCameraId = getCameraId(atts);
James Donga403a932011-05-09 18:49:31 -0700444 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dongc3711942010-01-19 17:45:38 -0800445 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800446 profiles->mCamcorderProfiles.add(
James Dong797e4f12011-02-28 21:07:39 -0800447 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dong9b433f02010-02-23 17:21:44 -0800448 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800449 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Teng600acf12011-07-06 18:33:09 -0700450 } else if (strcmp("VideoEditorCap", name) == 0) {
451 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -0700452 } else if (strcmp("ExportVideoProfile", name) == 0) {
453 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dongc3711942010-01-19 17:45:38 -0800454 }
455}
456
James Dong797e4f12011-02-28 21:07:39 -0800457static bool isCamcorderProfile(camcorder_quality quality) {
458 return quality >= CAMCORDER_QUALITY_LIST_START &&
459 quality <= CAMCORDER_QUALITY_LIST_END;
460}
461
462static bool isTimelapseProfile(camcorder_quality quality) {
463 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
464 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
465}
466
467void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Steve Block71f2cf12011-10-20 11:56:00 +0100468 ALOGV("Number of camera ids: %d", cameraIds.size());
James Dong797e4f12011-02-28 21:07:39 -0800469 CHECK(cameraIds.size() > 0);
470 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
471 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
472 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
473 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
474 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
475 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
476 if ((j & 1) == 0) { // low resolution
477 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
478 } else { // high resolution
479 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
480 }
481 }
482 }
483}
484
485int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
486 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
487 if (mCameraIds[i] == cameraId) {
488 return i;
489 }
490 }
491 return -1;
492}
493
494void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
495 if (sIsInitialized) {
496 return;
497 }
498
499 initRequiredProfileRefs(mCameraIds);
500
501 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
502 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
503 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
504
505 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
506 int cameraId = mCamcorderProfiles[i]->mCameraId;
507 int index = -1;
508 int refIndex = getRequiredProfileRefIndex(cameraId);
509 CHECK(refIndex != -1);
510 RequiredProfileRefInfo *info;
511 camcorder_quality refQuality;
512 VideoCodec *codec = NULL;
513
514 // Check high and low from either camcorder profile or timelapse profile
515 // but not both. Default, check camcorder profile
516 size_t j = 0;
517 size_t n = 2;
518 if (isTimelapseProfile(quality)) {
519 // Check timelapse profile instead.
520 j = 2;
521 n = kNumRequiredProfiles;
522 } else {
523 // Must be camcorder profile.
524 CHECK(isCamcorderProfile(quality));
525 }
526 for (; j < n; ++j) {
527 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
528 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
529 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
530 continue;
531 }
532 switch (j) {
533 case 0:
534 refQuality = CAMCORDER_QUALITY_LOW;
535 break;
536 case 1:
537 refQuality = CAMCORDER_QUALITY_HIGH;
538 break;
539 case 2:
540 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
541 break;
542 case 3:
543 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
544 break;
545 default:
546 CHECK(!"Should never reach here");
547 }
548
549 if (!info->mHasRefProfile) {
550 index = getCamcorderProfileIndex(cameraId, refQuality);
551 }
552 if (index == -1) {
553 // New high or low quality profile is found.
554 // Update its reference.
555 info->mHasRefProfile = true;
556 info->mRefProfileIndex = i;
557 info->mResolutionProduct = product;
558 }
559 }
560 }
561
562 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
563 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
564 int refIndex = getRequiredProfileRefIndex(cameraId);
565 CHECK(refIndex != -1);
566 RequiredProfileRefInfo *info =
567 &mRequiredProfileRefs[refIndex].mRefs[j];
568
569 if (info->mHasRefProfile) {
570
571 CamcorderProfile *profile =
572 new CamcorderProfile(
573 *mCamcorderProfiles[info->mRefProfileIndex]);
574
575 // Overwrite the quality
576 switch (j % kNumRequiredProfiles) {
577 case 0:
578 profile->mQuality = CAMCORDER_QUALITY_LOW;
579 break;
580 case 1:
581 profile->mQuality = CAMCORDER_QUALITY_HIGH;
582 break;
583 case 2:
584 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
585 break;
586 case 3:
587 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
588 break;
589 default:
590 CHECK(!"Should never come here");
591 }
592
593 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
594 if (index != -1) {
Steve Block71f2cf12011-10-20 11:56:00 +0100595 ALOGV("Profile quality %d for camera %d already exists",
James Dong797e4f12011-02-28 21:07:39 -0800596 profile->mQuality, cameraId);
597 CHECK(index == refIndex);
598 continue;
599 }
600
601 // Insert the new profile
Steve Block71f2cf12011-10-20 11:56:00 +0100602 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong797e4f12011-02-28 21:07:39 -0800603 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
604 profile->mQuality, cameraId);
605
606 mCamcorderProfiles.add(profile);
607 }
608 }
609 }
610}
611
James Dongc3711942010-01-19 17:45:38 -0800612/*static*/ MediaProfiles*
613MediaProfiles::getInstance()
614{
Steve Block71f2cf12011-10-20 11:56:00 +0100615 ALOGV("getInstance");
James Dongc3711942010-01-19 17:45:38 -0800616 Mutex::Autolock lock(sLock);
617 if (!sIsInitialized) {
618 char value[PROPERTY_VALUE_MAX];
619 if (property_get("media.settings.xml", value, NULL) <= 0) {
620 const char *defaultXmlFile = "/etc/media_profiles.xml";
621 FILE *fp = fopen(defaultXmlFile, "r");
622 if (fp == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000623 ALOGW("could not find media config xml file");
James Dongc3711942010-01-19 17:45:38 -0800624 sInstance = createDefaultInstance();
625 } else {
626 fclose(fp); // close the file first.
627 sInstance = createInstanceFromXmlFile(defaultXmlFile);
628 }
629 } else {
630 sInstance = createInstanceFromXmlFile(value);
631 }
James Dong797e4f12011-02-28 21:07:39 -0800632 CHECK(sInstance != NULL);
633 sInstance->checkAndAddRequiredProfilesIfNecessary();
634 sIsInitialized = true;
James Dongc3711942010-01-19 17:45:38 -0800635 }
636
637 return sInstance;
638}
639
640/*static*/ MediaProfiles::VideoEncoderCap*
641MediaProfiles::createDefaultH263VideoEncoderCap()
642{
643 return new MediaProfiles::VideoEncoderCap(
644 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
645}
646
647/*static*/ MediaProfiles::VideoEncoderCap*
648MediaProfiles::createDefaultM4vVideoEncoderCap()
649{
650 return new MediaProfiles::VideoEncoderCap(
651 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
652}
653
654
655/*static*/ void
656MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
657{
658 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
659 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
660}
661
662/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700663MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatra4af0dfd2010-09-06 15:59:02 -0700664{
665 MediaProfiles::VideoCodec *videoCodec =
666 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
667
668 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
669 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
670 profile->mCameraId = 0;
671 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700672 profile->mQuality = quality;
Nipun Kwatra4af0dfd2010-09-06 15:59:02 -0700673 profile->mDuration = 60;
674 profile->mVideoCodec = videoCodec;
675 profile->mAudioCodec = audioCodec;
676 return profile;
677}
678
679/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700680MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dongc3711942010-01-19 17:45:38 -0800681{
682 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700683 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dongc3711942010-01-19 17:45:38 -0800684
685 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800686 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
687 profile->mCameraId = 0;
James Dongc3711942010-01-19 17:45:38 -0800688 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700689 profile->mQuality = quality;
James Dongc3711942010-01-19 17:45:38 -0800690 profile->mDuration = 60;
691 profile->mVideoCodec = videoCodec;
692 profile->mAudioCodec = audioCodec;
693 return profile;
694}
695
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700696/*static*/ void
697MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
698 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
699 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
700 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
701 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
702}
703
704/*static*/ void
705MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
706 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
707 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
708 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
709 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
710}
711
James Dongc3711942010-01-19 17:45:38 -0800712/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700713MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dongc3711942010-01-19 17:45:38 -0800714{
715 MediaProfiles::VideoCodec *videoCodec =
716 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
717
718 MediaProfiles::AudioCodec *audioCodec =
719 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
720
721 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800722 profile->mCameraId = 0;
James Dongc3711942010-01-19 17:45:38 -0800723 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700724 profile->mQuality = quality;
James Dongc3711942010-01-19 17:45:38 -0800725 profile->mDuration = 30;
726 profile->mVideoCodec = videoCodec;
727 profile->mAudioCodec = audioCodec;
728 return profile;
729}
730
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700731/*static*/ MediaProfiles::CamcorderProfile*
732MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
733{
734 MediaProfiles::VideoCodec *videoCodec =
735 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
736
737 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
738 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
739 profile->mCameraId = 0;
740 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
741 profile->mQuality = quality;
742 profile->mDuration = 60;
743 profile->mVideoCodec = videoCodec;
744 profile->mAudioCodec = audioCodec;
745 return profile;
746}
747
748/*static*/ void
749MediaProfiles::createDefaultCamcorderLowProfiles(
750 MediaProfiles::CamcorderProfile **lowProfile,
751 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
752 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
753 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
754}
755
756/*static*/ void
757MediaProfiles::createDefaultCamcorderHighProfiles(
758 MediaProfiles::CamcorderProfile **highProfile,
759 MediaProfiles::CamcorderProfile **highSpecificProfile) {
760 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
761 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
762}
763
James Dongc3711942010-01-19 17:45:38 -0800764/*static*/ void
765MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
766{
Nipun Kwatrad48a15c2010-09-16 22:25:23 -0700767 // low camcorder profiles.
768 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
769 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
770 profiles->mCamcorderProfiles.add(lowProfile);
771 profiles->mCamcorderProfiles.add(lowSpecificProfile);
772
773 // high camcorder profiles.
774 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
775 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
776 profiles->mCamcorderProfiles.add(highProfile);
777 profiles->mCamcorderProfiles.add(highSpecificProfile);
778
779 // low camcorder time lapse profiles.
780 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
781 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
782 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
783 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
784
785 // high camcorder time lapse profiles.
786 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
787 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
788 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
789 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong6ec0ca92011-03-16 14:09:50 -0700790
791 // For emulator and other legacy devices which does not have a
792 // media_profiles.xml file, We assume that the default camera id
793 // is 0 and that is the only camera available.
794 profiles->mCameraIds.push(0);
James Dongc3711942010-01-19 17:45:38 -0800795}
796
797/*static*/ void
798MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
799{
800 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
801}
802
803/*static*/ void
804MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
805{
806 MediaProfiles::VideoDecoderCap *cap =
807 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
808
809 profiles->mVideoDecoders.add(cap);
810}
811
812/*static*/ void
813MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
814{
815 MediaProfiles::AudioDecoderCap *cap =
816 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
817
818 profiles->mAudioDecoders.add(cap);
819}
820
821/*static*/ void
822MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
823{
824 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
825 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
826}
827
828/*static*/ MediaProfiles::AudioEncoderCap*
829MediaProfiles::createDefaultAmrNBEncoderCap()
830{
831 return new MediaProfiles::AudioEncoderCap(
832 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
833}
834
James Dong9b433f02010-02-23 17:21:44 -0800835/*static*/ void
836MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
837{
Chih-Chung Chang09b90052010-06-22 20:50:55 +0800838 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
839 levels->mCameraId = 0;
840 levels->mLevels.add(70);
841 levels->mLevels.add(80);
842 levels->mLevels.add(90);
843 profiles->mImageEncodingQualityLevels.add(levels);
James Dong9b433f02010-02-23 17:21:44 -0800844}
845
Hong Teng600acf12011-07-06 18:33:09 -0700846/*static*/ void
847MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
848{
849 profiles->mVideoEditorCap =
850 new MediaProfiles::VideoEditorCap(
851 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
852 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
853 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
Hong Teng7eb53192011-11-10 14:54:26 -0800854 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
855 VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
Hong Teng600acf12011-07-06 18:33:09 -0700856}
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -0700857/*static*/ void
858MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
859{
860 // Create default video export profiles
861 profiles->mVideoEditorExportProfiles.add(
862 new ExportVideoProfile(VIDEO_ENCODER_H263,
863 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
864 profiles->mVideoEditorExportProfiles.add(
865 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
866 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
867 profiles->mVideoEditorExportProfiles.add(
868 new ExportVideoProfile(VIDEO_ENCODER_H264,
869 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
870}
Hong Teng600acf12011-07-06 18:33:09 -0700871
James Dongc3711942010-01-19 17:45:38 -0800872/*static*/ MediaProfiles*
873MediaProfiles::createDefaultInstance()
874{
875 MediaProfiles *profiles = new MediaProfiles;
876 createDefaultCamcorderProfiles(profiles);
877 createDefaultVideoEncoders(profiles);
878 createDefaultAudioEncoders(profiles);
879 createDefaultVideoDecoders(profiles);
880 createDefaultAudioDecoders(profiles);
881 createDefaultEncoderOutputFileFormats(profiles);
James Dong9b433f02010-02-23 17:21:44 -0800882 createDefaultImageEncodingQualityLevels(profiles);
Hong Teng600acf12011-07-06 18:33:09 -0700883 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -0700884 createDefaultExportVideoProfiles(profiles);
James Dongc3711942010-01-19 17:45:38 -0800885 return profiles;
886}
887
888/*static*/ MediaProfiles*
889MediaProfiles::createInstanceFromXmlFile(const char *xml)
890{
891 FILE *fp = NULL;
892 CHECK((fp = fopen(xml, "r")));
893
894 XML_Parser parser = ::XML_ParserCreate(NULL);
895 CHECK(parser != NULL);
896
897 MediaProfiles *profiles = new MediaProfiles();
898 ::XML_SetUserData(parser, profiles);
899 ::XML_SetElementHandler(parser, startElementHandler, NULL);
900
901 /*
902 FIXME:
903 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
904
905 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block3762c312012-01-06 19:20:56 +0000906 ALOGE("failed to enable DTD support in the xml file");
James Dongc3711942010-01-19 17:45:38 -0800907 return UNKNOWN_ERROR;
908 }
909
910 */
911
912 const int BUFF_SIZE = 512;
913 for (;;) {
914 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
915 if (buff == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000916 ALOGE("failed to in call to XML_GetBuffer()");
James Dongc3711942010-01-19 17:45:38 -0800917 delete profiles;
918 profiles = NULL;
919 goto exit;
920 }
921
922 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
923 if (bytes_read < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000924 ALOGE("failed in call to read");
James Dongc3711942010-01-19 17:45:38 -0800925 delete profiles;
926 profiles = NULL;
927 goto exit;
928 }
929
930 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
931
932 if (bytes_read == 0) break; // done parsing the xml file
933 }
934
935exit:
936 ::XML_ParserFree(parser);
937 ::fclose(fp);
James Dongc3711942010-01-19 17:45:38 -0800938 return profiles;
939}
940
941Vector<output_format> MediaProfiles::getOutputFileFormats() const
942{
943 return mEncoderOutputFileFormats; // copy out
944}
945
946Vector<video_encoder> MediaProfiles::getVideoEncoders() const
947{
948 Vector<video_encoder> encoders;
949 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
950 encoders.add(mVideoEncoders[i]->mCodec);
951 }
952 return encoders; // copy out
953}
954
955int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
956{
Steve Block71f2cf12011-10-20 11:56:00 +0100957 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dongc3711942010-01-19 17:45:38 -0800958 int index = -1;
959 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
960 if (mVideoEncoders[i]->mCodec == codec) {
961 index = i;
962 break;
963 }
964 }
965 if (index == -1) {
Steve Block3762c312012-01-06 19:20:56 +0000966 ALOGE("The given video encoder %d is not found", codec);
James Dongc3711942010-01-19 17:45:38 -0800967 return -1;
968 }
969
970 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
971 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
972 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
973 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
974 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
975 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
976 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
977 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
978
Steve Block3762c312012-01-06 19:20:56 +0000979 ALOGE("The given video encoder param name %s is not found", name);
James Dongc3711942010-01-19 17:45:38 -0800980 return -1;
981}
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -0700982int MediaProfiles::getVideoEditorExportParamByName(
983 const char *name, int codec) const
984{
Steve Block71f2cf12011-10-20 11:56:00 +0100985 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -0700986 ExportVideoProfile *exportProfile = NULL;
987 int index = -1;
988 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
989 exportProfile = mVideoEditorExportProfiles[i];
990 if (exportProfile->mCodec == codec) {
991 index = i;
992 break;
993 }
994 }
995 if (index == -1) {
Steve Block3762c312012-01-06 19:20:56 +0000996 ALOGE("The given video decoder %d is not found", codec);
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -0700997 return -1;
998 }
999 if (!strcmp("videoeditor.export.profile", name))
1000 return exportProfile->mProfile;
1001 if (!strcmp("videoeditor.export.level", name))
1002 return exportProfile->mLevel;
James Dongc3711942010-01-19 17:45:38 -08001003
Steve Block3762c312012-01-06 19:20:56 +00001004 ALOGE("The given video editor export param name %s is not found", name);
Rajneesh Chowdury3ced0442011-08-12 16:43:37 -07001005 return -1;
1006}
Hong Teng600acf12011-07-06 18:33:09 -07001007int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1008{
Steve Block71f2cf12011-10-20 11:56:00 +01001009 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Teng600acf12011-07-06 18:33:09 -07001010
1011 if (mVideoEditorCap == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001012 ALOGE("The mVideoEditorCap is not created, then create default cap.");
Hong Teng600acf12011-07-06 18:33:09 -07001013 createDefaultVideoEditorCap(sInstance);
1014 }
1015
1016 if (!strcmp("videoeditor.input.width.max", name))
1017 return mVideoEditorCap->mMaxInputFrameWidth;
1018 if (!strcmp("videoeditor.input.height.max", name))
1019 return mVideoEditorCap->mMaxInputFrameHeight;
1020 if (!strcmp("videoeditor.output.width.max", name))
1021 return mVideoEditorCap->mMaxOutputFrameWidth;
1022 if (!strcmp("videoeditor.output.height.max", name))
1023 return mVideoEditorCap->mMaxOutputFrameHeight;
Hong Teng7eb53192011-11-10 14:54:26 -08001024 if (!strcmp("maxPrefetchYUVFrames", name))
1025 return mVideoEditorCap->mMaxPrefetchYUVFrames;
Hong Teng600acf12011-07-06 18:33:09 -07001026
Steve Block3762c312012-01-06 19:20:56 +00001027 ALOGE("The given video editor param name %s is not found", name);
Hong Teng600acf12011-07-06 18:33:09 -07001028 return -1;
1029}
1030
James Dongc3711942010-01-19 17:45:38 -08001031Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1032{
1033 Vector<audio_encoder> encoders;
1034 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1035 encoders.add(mAudioEncoders[i]->mCodec);
1036 }
1037 return encoders; // copy out
1038}
1039
1040int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1041{
Steve Block71f2cf12011-10-20 11:56:00 +01001042 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dongc3711942010-01-19 17:45:38 -08001043 int index = -1;
1044 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1045 if (mAudioEncoders[i]->mCodec == codec) {
1046 index = i;
1047 break;
1048 }
1049 }
1050 if (index == -1) {
Steve Block3762c312012-01-06 19:20:56 +00001051 ALOGE("The given audio encoder %d is not found", codec);
James Dongc3711942010-01-19 17:45:38 -08001052 return -1;
1053 }
1054
1055 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1056 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1057 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1058 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1059 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1060 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1061
Steve Block3762c312012-01-06 19:20:56 +00001062 ALOGE("The given audio encoder param name %s is not found", name);
James Dongc3711942010-01-19 17:45:38 -08001063 return -1;
1064}
1065
1066Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1067{
1068 Vector<video_decoder> decoders;
1069 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1070 decoders.add(mVideoDecoders[i]->mCodec);
1071 }
1072 return decoders; // copy out
1073}
1074
1075Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1076{
1077 Vector<audio_decoder> decoders;
1078 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1079 decoders.add(mAudioDecoders[i]->mCodec);
1080 }
1081 return decoders; // copy out
1082}
1083
Nipun Kwatra9d619542010-09-09 16:25:08 -07001084int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dongc3711942010-01-19 17:45:38 -08001085{
James Dongc3711942010-01-19 17:45:38 -08001086 int index = -1;
1087 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang09b90052010-06-22 20:50:55 +08001088 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1089 mCamcorderProfiles[i]->mQuality == quality) {
James Dongc3711942010-01-19 17:45:38 -08001090 index = i;
1091 break;
1092 }
1093 }
Nipun Kwatra9d619542010-09-09 16:25:08 -07001094 return index;
1095}
1096
1097int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1098 int cameraId,
1099 camcorder_quality quality) const
1100{
Steve Block71f2cf12011-10-20 11:56:00 +01001101 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kasten18db49a2012-03-12 16:29:55 -07001102 name, cameraId, quality);
Nipun Kwatra9d619542010-09-09 16:25:08 -07001103
1104 int index = getCamcorderProfileIndex(cameraId, quality);
James Dongc3711942010-01-19 17:45:38 -08001105 if (index == -1) {
Steve Block3762c312012-01-06 19:20:56 +00001106 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kasten18db49a2012-03-12 16:29:55 -07001107 cameraId, quality);
James Dongc3711942010-01-19 17:45:38 -08001108 return -1;
1109 }
1110
James Dong9b433f02010-02-23 17:21:44 -08001111 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dongc3711942010-01-19 17:45:38 -08001112 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1113 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1114 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1115 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1116 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1117 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1118 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1119 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1120 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1121 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1122
Steve Block3762c312012-01-06 19:20:56 +00001123 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dongc3711942010-01-19 17:45:38 -08001124 return -1;
1125}
1126
Nipun Kwatra9d619542010-09-09 16:25:08 -07001127bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1128{
1129 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1130}
1131
Chih-Chung Chang09b90052010-06-22 20:50:55 +08001132Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dong9b433f02010-02-23 17:21:44 -08001133{
Chih-Chung Chang09b90052010-06-22 20:50:55 +08001134 Vector<int> result;
1135 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1136 if (levels != NULL) {
1137 result = levels->mLevels; // copy out
1138 }
1139 return result;
James Dong9b433f02010-02-23 17:21:44 -08001140}
1141
James Donga403a932011-05-09 18:49:31 -07001142int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1143 int offsetTimeMs = -1;
1144 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1145 if (index >= 0) {
1146 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1147 }
Steve Block71f2cf12011-10-20 11:56:00 +01001148 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Donga403a932011-05-09 18:49:31 -07001149 return offsetTimeMs;
1150}
1151
James Dongc3711942010-01-19 17:45:38 -08001152MediaProfiles::~MediaProfiles()
1153{
1154 CHECK("destructor should never be called" == 0);
1155#if 0
1156 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1157 delete mAudioEncoders[i];
1158 }
1159 mAudioEncoders.clear();
1160
1161 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1162 delete mVideoEncoders[i];
1163 }
1164 mVideoEncoders.clear();
1165
1166 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1167 delete mVideoDecoders[i];
1168 }
1169 mVideoDecoders.clear();
1170
1171 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1172 delete mAudioDecoders[i];
1173 }
1174 mAudioDecoders.clear();
1175
1176 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1177 delete mCamcorderProfiles[i];
1178 }
1179 mCamcorderProfiles.clear();
1180#endif
1181}
1182} // namespace android