blob: c08f033e5ebbf28591e565bdbff61bbd771dc675 [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>
James Dongf1d5aa12012-02-06 23:46:37 -080028#include <media/stagefright/foundation/ADebug.h>
James Dong6c6b4d02012-03-12 14:37:53 -070029#include <OMX_Video.h>
James Dong1d7491b2010-01-19 17:45:38 -080030
31namespace android {
32
33Mutex MediaProfiles::sLock;
34bool MediaProfiles::sIsInitialized = false;
35MediaProfiles *MediaProfiles::sInstance = NULL;
36
37const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
38 {"h263", VIDEO_ENCODER_H263},
39 {"h264", VIDEO_ENCODER_H264},
40 {"m4v", VIDEO_ENCODER_MPEG_4_SP}
41};
42
43const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
Dave Burkeaeb8fd42012-04-19 00:14:27 -070044 {"amrnb", AUDIO_ENCODER_AMR_NB},
45 {"amrwb", AUDIO_ENCODER_AMR_WB},
46 {"aac", AUDIO_ENCODER_AAC},
47 {"aaceld", AUDIO_ENCODER_AAC_ELD},
James Dong1d7491b2010-01-19 17:45:38 -080048};
49
50const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
51 {"3gp", OUTPUT_FORMAT_THREE_GPP},
52 {"mp4", OUTPUT_FORMAT_MPEG_4}
53};
54
55const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
56 {"wmv", VIDEO_DECODER_WMV}
57};
58
59const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
60 {"wma", AUDIO_DECODER_WMA}
61};
62
63const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -070064 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -080065 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070066 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070067 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070068 {"480p", CAMCORDER_QUALITY_480P},
69 {"720p", CAMCORDER_QUALITY_720P},
70 {"1080p", CAMCORDER_QUALITY_1080P},
James Dong669012d2011-09-19 16:27:31 -070071 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070072
73 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
74 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
75 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070076 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070077 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
78 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070079 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
80 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
James Dong1d7491b2010-01-19 17:45:38 -080081};
82
83/*static*/ void
84MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
85{
Steve Block3856b092011-10-20 11:56:00 +010086 ALOGV("video codec:");
87 ALOGV("codec = %d", codec.mCodec);
88 ALOGV("bit rate: %d", codec.mBitRate);
89 ALOGV("frame width: %d", codec.mFrameWidth);
90 ALOGV("frame height: %d", codec.mFrameHeight);
91 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -080092}
93
94/*static*/ void
95MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
96{
Steve Block3856b092011-10-20 11:56:00 +010097 ALOGV("audio codec:");
98 ALOGV("codec = %d", codec.mCodec);
99 ALOGV("bit rate: %d", codec.mBitRate);
100 ALOGV("sample rate: %d", codec.mSampleRate);
101 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800102}
103
104/*static*/ void
105MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
106{
Steve Block3856b092011-10-20 11:56:00 +0100107 ALOGV("video encoder cap:");
108 ALOGV("codec = %d", cap.mCodec);
109 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
110 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
111 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
112 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800113}
114
115/*static*/ void
116MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
117{
Steve Block3856b092011-10-20 11:56:00 +0100118 ALOGV("audio encoder cap:");
119 ALOGV("codec = %d", cap.mCodec);
120 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
121 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
122 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800123}
124
125/*static*/ void
126MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
127{
Steve Block3856b092011-10-20 11:56:00 +0100128 ALOGV("video decoder cap:");
129 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800130}
131
132/*static*/ void
133MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
134{
Steve Block3856b092011-10-20 11:56:00 +0100135 ALOGV("audio codec cap:");
136 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800137}
138
Hong Tengcabd5f82011-07-06 18:33:09 -0700139/*static*/ void
140MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
141{
Steve Block3856b092011-10-20 11:56:00 +0100142 ALOGV("videoeditor cap:");
143 ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
144 ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
145 ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
146 ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
Hong Tengcabd5f82011-07-06 18:33:09 -0700147}
148
James Dong1d7491b2010-01-19 17:45:38 -0800149/*static*/ int
150MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
151{
152 int tag = -1;
153 for (size_t i = 0; i < nMappings; ++i) {
154 if (!strcmp(map[i].name, name)) {
155 tag = map[i].tag;
156 break;
157 }
158 }
159 return tag;
160}
161
162/*static*/ MediaProfiles::VideoCodec*
163MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
164{
165 CHECK(!strcmp("codec", atts[0]) &&
166 !strcmp("bitRate", atts[2]) &&
167 !strcmp("width", atts[4]) &&
168 !strcmp("height", atts[6]) &&
169 !strcmp("frameRate", atts[8]));
170
171 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
172 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
173 CHECK(codec != -1);
174
175 MediaProfiles::VideoCodec *videoCodec =
176 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
177 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
178 logVideoCodec(*videoCodec);
179
180 size_t nCamcorderProfiles;
181 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
182 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
183 return videoCodec;
184}
185
186/*static*/ MediaProfiles::AudioCodec*
187MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
188{
189 CHECK(!strcmp("codec", atts[0]) &&
190 !strcmp("bitRate", atts[2]) &&
191 !strcmp("sampleRate", atts[4]) &&
192 !strcmp("channels", atts[6]));
193 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
194 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
195 CHECK(codec != -1);
196
197 MediaProfiles::AudioCodec *audioCodec =
198 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
199 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
200 logAudioCodec(*audioCodec);
201
202 size_t nCamcorderProfiles;
203 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
204 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
205 return audioCodec;
206}
207/*static*/ MediaProfiles::AudioDecoderCap*
208MediaProfiles::createAudioDecoderCap(const char **atts)
209{
210 CHECK(!strcmp("name", atts[0]) &&
211 !strcmp("enabled", atts[2]));
212
213 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
214 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
215 CHECK(codec != -1);
216
217 MediaProfiles::AudioDecoderCap *cap =
218 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
219 logAudioDecoderCap(*cap);
220 return cap;
221}
222
223/*static*/ MediaProfiles::VideoDecoderCap*
224MediaProfiles::createVideoDecoderCap(const char **atts)
225{
226 CHECK(!strcmp("name", atts[0]) &&
227 !strcmp("enabled", atts[2]));
228
229 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
230 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
231 CHECK(codec != -1);
232
233 MediaProfiles::VideoDecoderCap *cap =
234 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
235 logVideoDecoderCap(*cap);
236 return cap;
237}
238
239/*static*/ MediaProfiles::VideoEncoderCap*
240MediaProfiles::createVideoEncoderCap(const char **atts)
241{
242 CHECK(!strcmp("name", atts[0]) &&
243 !strcmp("enabled", atts[2]) &&
244 !strcmp("minBitRate", atts[4]) &&
245 !strcmp("maxBitRate", atts[6]) &&
246 !strcmp("minFrameWidth", atts[8]) &&
247 !strcmp("maxFrameWidth", atts[10]) &&
248 !strcmp("minFrameHeight", atts[12]) &&
249 !strcmp("maxFrameHeight", atts[14]) &&
250 !strcmp("minFrameRate", atts[16]) &&
251 !strcmp("maxFrameRate", atts[18]));
252
253 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
254 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
255 CHECK(codec != -1);
256
257 MediaProfiles::VideoEncoderCap *cap =
258 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
259 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
260 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
261 logVideoEncoderCap(*cap);
262 return cap;
263}
264
265/*static*/ MediaProfiles::AudioEncoderCap*
266MediaProfiles::createAudioEncoderCap(const char **atts)
267{
268 CHECK(!strcmp("name", atts[0]) &&
269 !strcmp("enabled", atts[2]) &&
270 !strcmp("minBitRate", atts[4]) &&
271 !strcmp("maxBitRate", atts[6]) &&
272 !strcmp("minSampleRate", atts[8]) &&
273 !strcmp("maxSampleRate", atts[10]) &&
274 !strcmp("minChannels", atts[12]) &&
275 !strcmp("maxChannels", atts[14]));
276
277 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
278 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
279 CHECK(codec != -1);
280
281 MediaProfiles::AudioEncoderCap *cap =
282 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
283 atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
284 atoi(atts[15]));
285 logAudioEncoderCap(*cap);
286 return cap;
287}
288
289/*static*/ output_format
290MediaProfiles::createEncoderOutputFileFormat(const char **atts)
291{
292 CHECK(!strcmp("name", atts[0]));
293
294 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
295 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
296 CHECK(format != -1);
297
298 return static_cast<output_format>(format);
299}
300
James Dong2a7e0a12011-02-28 21:07:39 -0800301static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
302 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
303 if (cameraId == cameraIds[i]) {
304 return true;
305 }
306 }
307 return false;
308}
309
James Dong1d7491b2010-01-19 17:45:38 -0800310/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800311MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800312{
313 CHECK(!strcmp("quality", atts[0]) &&
314 !strcmp("fileFormat", atts[2]) &&
315 !strcmp("duration", atts[4]));
316
317 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
318 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
319 CHECK(quality != -1);
320
321 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
322 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
323 CHECK(fileFormat != -1);
324
325 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800326 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800327 if (!isCameraIdFound(cameraId, cameraIds)) {
328 cameraIds.add(cameraId);
329 }
James Dong1d7491b2010-01-19 17:45:38 -0800330 profile->mFileFormat = static_cast<output_format>(fileFormat);
331 profile->mQuality = static_cast<camcorder_quality>(quality);
332 profile->mDuration = atoi(atts[5]);
333 return profile;
334}
335
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800336MediaProfiles::ImageEncodingQualityLevels*
337MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
338{
339 int n = mImageEncodingQualityLevels.size();
340 for (int i = 0; i < n; i++) {
341 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
342 if (levels->mCameraId == cameraId) {
343 return levels;
344 }
345 }
346 return NULL;
347}
348
349void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800350{
351 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800352 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800353 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800354 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
355
356 if (levels == NULL) {
357 levels = new ImageEncodingQualityLevels();
358 levels->mCameraId = cameraId;
359 mImageEncodingQualityLevels.add(levels);
360 }
361
362 levels->mLevels.add(quality);
363}
364
365/*static*/ int
366MediaProfiles::getCameraId(const char** atts)
367{
368 if (!atts[0]) return 0; // default cameraId = 0
369 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800370 return atoi(atts[1]);
371}
372
James Dong0f056292011-05-09 18:49:31 -0700373void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
374{
375 int offsetTimeMs = 700;
376 if (atts[2]) {
377 CHECK(!strcmp("startOffsetMs", atts[2]));
378 offsetTimeMs = atoi(atts[3]);
379 }
380
Steve Block3856b092011-10-20 11:56:00 +0100381 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700382 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
383}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700384/*static*/ MediaProfiles::ExportVideoProfile*
385MediaProfiles::createExportVideoProfile(const char **atts)
386{
387 CHECK(!strcmp("name", atts[0]) &&
388 !strcmp("profile", atts[2]) &&
389 !strcmp("level", atts[4]));
James Dong0f056292011-05-09 18:49:31 -0700390
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700391 const size_t nMappings =
392 sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
393 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
394 CHECK(codec != -1);
395
396 MediaProfiles::ExportVideoProfile *profile =
397 new MediaProfiles::ExportVideoProfile(
398 codec, atoi(atts[3]), atoi(atts[5]));
399
400 return profile;
401}
Hong Tengcabd5f82011-07-06 18:33:09 -0700402/*static*/ MediaProfiles::VideoEditorCap*
403MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
404{
405 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
406 !strcmp("maxInputFrameHeight", atts[2]) &&
407 !strcmp("maxOutputFrameWidth", atts[4]) &&
Hong Teng3a9cefe2011-11-10 14:54:26 -0800408 !strcmp("maxOutputFrameHeight", atts[6]) &&
409 !strcmp("maxPrefetchYUVFrames", atts[8]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700410
411 MediaProfiles::VideoEditorCap *pVideoEditorCap =
412 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
Hong Teng3a9cefe2011-11-10 14:54:26 -0800413 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700414
415 logVideoEditorCap(*pVideoEditorCap);
416 profiles->mVideoEditorCap = pVideoEditorCap;
417
418 return pVideoEditorCap;
419}
420
James Dong1d7491b2010-01-19 17:45:38 -0800421/*static*/ void
422MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
423{
424 MediaProfiles *profiles = (MediaProfiles *) userData;
425 if (strcmp("Video", name) == 0) {
426 createVideoCodec(atts, profiles);
427 } else if (strcmp("Audio", name) == 0) {
428 createAudioCodec(atts, profiles);
429 } else if (strcmp("VideoEncoderCap", name) == 0 &&
430 strcmp("true", atts[3]) == 0) {
431 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
432 } else if (strcmp("AudioEncoderCap", name) == 0 &&
433 strcmp("true", atts[3]) == 0) {
434 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
435 } else if (strcmp("VideoDecoderCap", name) == 0 &&
436 strcmp("true", atts[3]) == 0) {
437 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
438 } else if (strcmp("AudioDecoderCap", name) == 0 &&
439 strcmp("true", atts[3]) == 0) {
440 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
441 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
442 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800443 } else if (strcmp("CamcorderProfiles", name) == 0) {
444 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700445 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800446 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800447 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800448 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800449 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800450 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700451 } else if (strcmp("VideoEditorCap", name) == 0) {
452 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700453 } else if (strcmp("ExportVideoProfile", name) == 0) {
454 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dong1d7491b2010-01-19 17:45:38 -0800455 }
456}
457
James Dong2a7e0a12011-02-28 21:07:39 -0800458static bool isCamcorderProfile(camcorder_quality quality) {
459 return quality >= CAMCORDER_QUALITY_LIST_START &&
460 quality <= CAMCORDER_QUALITY_LIST_END;
461}
462
463static bool isTimelapseProfile(camcorder_quality quality) {
464 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
465 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
466}
467
468void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Steve Block3856b092011-10-20 11:56:00 +0100469 ALOGV("Number of camera ids: %d", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800470 CHECK(cameraIds.size() > 0);
471 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
472 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
473 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
474 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
475 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
476 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
477 if ((j & 1) == 0) { // low resolution
478 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
479 } else { // high resolution
480 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
481 }
482 }
483 }
484}
485
486int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
487 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
488 if (mCameraIds[i] == cameraId) {
489 return i;
490 }
491 }
492 return -1;
493}
494
495void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
496 if (sIsInitialized) {
497 return;
498 }
499
500 initRequiredProfileRefs(mCameraIds);
501
502 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
503 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
504 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
505
506 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
507 int cameraId = mCamcorderProfiles[i]->mCameraId;
508 int index = -1;
509 int refIndex = getRequiredProfileRefIndex(cameraId);
510 CHECK(refIndex != -1);
511 RequiredProfileRefInfo *info;
512 camcorder_quality refQuality;
513 VideoCodec *codec = NULL;
514
515 // Check high and low from either camcorder profile or timelapse profile
516 // but not both. Default, check camcorder profile
517 size_t j = 0;
518 size_t n = 2;
519 if (isTimelapseProfile(quality)) {
520 // Check timelapse profile instead.
521 j = 2;
522 n = kNumRequiredProfiles;
523 } else {
524 // Must be camcorder profile.
525 CHECK(isCamcorderProfile(quality));
526 }
527 for (; j < n; ++j) {
528 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
529 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
530 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
531 continue;
532 }
533 switch (j) {
534 case 0:
535 refQuality = CAMCORDER_QUALITY_LOW;
536 break;
537 case 1:
538 refQuality = CAMCORDER_QUALITY_HIGH;
539 break;
540 case 2:
541 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
542 break;
543 case 3:
544 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
545 break;
546 default:
547 CHECK(!"Should never reach here");
548 }
549
550 if (!info->mHasRefProfile) {
551 index = getCamcorderProfileIndex(cameraId, refQuality);
552 }
553 if (index == -1) {
554 // New high or low quality profile is found.
555 // Update its reference.
556 info->mHasRefProfile = true;
557 info->mRefProfileIndex = i;
558 info->mResolutionProduct = product;
559 }
560 }
561 }
562
563 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
564 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
565 int refIndex = getRequiredProfileRefIndex(cameraId);
566 CHECK(refIndex != -1);
567 RequiredProfileRefInfo *info =
568 &mRequiredProfileRefs[refIndex].mRefs[j];
569
570 if (info->mHasRefProfile) {
571
572 CamcorderProfile *profile =
573 new CamcorderProfile(
574 *mCamcorderProfiles[info->mRefProfileIndex]);
575
576 // Overwrite the quality
577 switch (j % kNumRequiredProfiles) {
578 case 0:
579 profile->mQuality = CAMCORDER_QUALITY_LOW;
580 break;
581 case 1:
582 profile->mQuality = CAMCORDER_QUALITY_HIGH;
583 break;
584 case 2:
585 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
586 break;
587 case 3:
588 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
589 break;
590 default:
591 CHECK(!"Should never come here");
592 }
593
594 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
595 if (index != -1) {
Steve Block3856b092011-10-20 11:56:00 +0100596 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800597 profile->mQuality, cameraId);
598 CHECK(index == refIndex);
599 continue;
600 }
601
602 // Insert the new profile
Steve Block3856b092011-10-20 11:56:00 +0100603 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800604 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
605 profile->mQuality, cameraId);
606
607 mCamcorderProfiles.add(profile);
608 }
609 }
610 }
611}
612
James Dong1d7491b2010-01-19 17:45:38 -0800613/*static*/ MediaProfiles*
614MediaProfiles::getInstance()
615{
Steve Block3856b092011-10-20 11:56:00 +0100616 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800617 Mutex::Autolock lock(sLock);
618 if (!sIsInitialized) {
619 char value[PROPERTY_VALUE_MAX];
620 if (property_get("media.settings.xml", value, NULL) <= 0) {
621 const char *defaultXmlFile = "/etc/media_profiles.xml";
622 FILE *fp = fopen(defaultXmlFile, "r");
623 if (fp == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000624 ALOGW("could not find media config xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800625 sInstance = createDefaultInstance();
626 } else {
627 fclose(fp); // close the file first.
628 sInstance = createInstanceFromXmlFile(defaultXmlFile);
629 }
630 } else {
631 sInstance = createInstanceFromXmlFile(value);
632 }
James Dong2a7e0a12011-02-28 21:07:39 -0800633 CHECK(sInstance != NULL);
634 sInstance->checkAndAddRequiredProfilesIfNecessary();
635 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800636 }
637
638 return sInstance;
639}
640
641/*static*/ MediaProfiles::VideoEncoderCap*
642MediaProfiles::createDefaultH263VideoEncoderCap()
643{
644 return new MediaProfiles::VideoEncoderCap(
645 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
646}
647
648/*static*/ MediaProfiles::VideoEncoderCap*
649MediaProfiles::createDefaultM4vVideoEncoderCap()
650{
651 return new MediaProfiles::VideoEncoderCap(
652 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
653}
654
655
656/*static*/ void
657MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
658{
659 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
660 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
661}
662
663/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700664MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700665{
666 MediaProfiles::VideoCodec *videoCodec =
667 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
668
669 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
670 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
671 profile->mCameraId = 0;
672 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700673 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700674 profile->mDuration = 60;
675 profile->mVideoCodec = videoCodec;
676 profile->mAudioCodec = audioCodec;
677 return profile;
678}
679
680/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700681MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800682{
683 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700684 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800685
686 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800687 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
688 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800689 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700690 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800691 profile->mDuration = 60;
692 profile->mVideoCodec = videoCodec;
693 profile->mAudioCodec = audioCodec;
694 return profile;
695}
696
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700697/*static*/ void
698MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
699 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
700 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
701 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
702 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
703}
704
705/*static*/ void
706MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
707 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
708 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
709 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
710 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
711}
712
James Dong1d7491b2010-01-19 17:45:38 -0800713/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700714MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800715{
716 MediaProfiles::VideoCodec *videoCodec =
717 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
718
719 MediaProfiles::AudioCodec *audioCodec =
720 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
721
722 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800723 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800724 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700725 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800726 profile->mDuration = 30;
727 profile->mVideoCodec = videoCodec;
728 profile->mAudioCodec = audioCodec;
729 return profile;
730}
731
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700732/*static*/ MediaProfiles::CamcorderProfile*
733MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
734{
735 MediaProfiles::VideoCodec *videoCodec =
736 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
737
738 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
739 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
740 profile->mCameraId = 0;
741 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
742 profile->mQuality = quality;
743 profile->mDuration = 60;
744 profile->mVideoCodec = videoCodec;
745 profile->mAudioCodec = audioCodec;
746 return profile;
747}
748
749/*static*/ void
750MediaProfiles::createDefaultCamcorderLowProfiles(
751 MediaProfiles::CamcorderProfile **lowProfile,
752 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
753 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
754 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
755}
756
757/*static*/ void
758MediaProfiles::createDefaultCamcorderHighProfiles(
759 MediaProfiles::CamcorderProfile **highProfile,
760 MediaProfiles::CamcorderProfile **highSpecificProfile) {
761 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
762 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
763}
764
James Dong1d7491b2010-01-19 17:45:38 -0800765/*static*/ void
766MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
767{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700768 // low camcorder profiles.
769 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
770 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
771 profiles->mCamcorderProfiles.add(lowProfile);
772 profiles->mCamcorderProfiles.add(lowSpecificProfile);
773
774 // high camcorder profiles.
775 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
776 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
777 profiles->mCamcorderProfiles.add(highProfile);
778 profiles->mCamcorderProfiles.add(highSpecificProfile);
779
780 // low camcorder time lapse profiles.
781 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
782 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
783 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
784 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
785
786 // high camcorder time lapse profiles.
787 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
788 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
789 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
790 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700791
792 // For emulator and other legacy devices which does not have a
793 // media_profiles.xml file, We assume that the default camera id
794 // is 0 and that is the only camera available.
795 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800796}
797
798/*static*/ void
799MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
800{
801 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
802}
803
804/*static*/ void
805MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
806{
807 MediaProfiles::VideoDecoderCap *cap =
808 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
809
810 profiles->mVideoDecoders.add(cap);
811}
812
813/*static*/ void
814MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
815{
816 MediaProfiles::AudioDecoderCap *cap =
817 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
818
819 profiles->mAudioDecoders.add(cap);
820}
821
822/*static*/ void
823MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
824{
825 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
826 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
827}
828
829/*static*/ MediaProfiles::AudioEncoderCap*
830MediaProfiles::createDefaultAmrNBEncoderCap()
831{
832 return new MediaProfiles::AudioEncoderCap(
833 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
834}
835
James Dongf5a83852010-02-23 17:21:44 -0800836/*static*/ void
837MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
838{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800839 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
840 levels->mCameraId = 0;
841 levels->mLevels.add(70);
842 levels->mLevels.add(80);
843 levels->mLevels.add(90);
844 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800845}
846
Hong Tengcabd5f82011-07-06 18:33:09 -0700847/*static*/ void
848MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
849{
850 profiles->mVideoEditorCap =
851 new MediaProfiles::VideoEditorCap(
852 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
853 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
854 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
Hong Teng3a9cefe2011-11-10 14:54:26 -0800855 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
856 VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
Hong Tengcabd5f82011-07-06 18:33:09 -0700857}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700858/*static*/ void
859MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
860{
861 // Create default video export profiles
862 profiles->mVideoEditorExportProfiles.add(
863 new ExportVideoProfile(VIDEO_ENCODER_H263,
864 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
865 profiles->mVideoEditorExportProfiles.add(
866 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
867 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
868 profiles->mVideoEditorExportProfiles.add(
869 new ExportVideoProfile(VIDEO_ENCODER_H264,
870 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
871}
Hong Tengcabd5f82011-07-06 18:33:09 -0700872
James Dong1d7491b2010-01-19 17:45:38 -0800873/*static*/ MediaProfiles*
874MediaProfiles::createDefaultInstance()
875{
876 MediaProfiles *profiles = new MediaProfiles;
877 createDefaultCamcorderProfiles(profiles);
878 createDefaultVideoEncoders(profiles);
879 createDefaultAudioEncoders(profiles);
880 createDefaultVideoDecoders(profiles);
881 createDefaultAudioDecoders(profiles);
882 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800883 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700884 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700885 createDefaultExportVideoProfiles(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800886 return profiles;
887}
888
889/*static*/ MediaProfiles*
890MediaProfiles::createInstanceFromXmlFile(const char *xml)
891{
892 FILE *fp = NULL;
893 CHECK((fp = fopen(xml, "r")));
894
895 XML_Parser parser = ::XML_ParserCreate(NULL);
896 CHECK(parser != NULL);
897
898 MediaProfiles *profiles = new MediaProfiles();
899 ::XML_SetUserData(parser, profiles);
900 ::XML_SetElementHandler(parser, startElementHandler, NULL);
901
902 /*
903 FIXME:
904 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
905
906 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +0000907 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800908 return UNKNOWN_ERROR;
909 }
910
911 */
912
913 const int BUFF_SIZE = 512;
914 for (;;) {
915 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
916 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000917 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -0800918 delete profiles;
919 profiles = NULL;
920 goto exit;
921 }
922
923 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
924 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000925 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -0800926 delete profiles;
927 profiles = NULL;
928 goto exit;
929 }
930
931 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
932
933 if (bytes_read == 0) break; // done parsing the xml file
934 }
935
936exit:
937 ::XML_ParserFree(parser);
938 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800939 return profiles;
940}
941
942Vector<output_format> MediaProfiles::getOutputFileFormats() const
943{
944 return mEncoderOutputFileFormats; // copy out
945}
946
947Vector<video_encoder> MediaProfiles::getVideoEncoders() const
948{
949 Vector<video_encoder> encoders;
950 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
951 encoders.add(mVideoEncoders[i]->mCodec);
952 }
953 return encoders; // copy out
954}
955
956int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
957{
Steve Block3856b092011-10-20 11:56:00 +0100958 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800959 int index = -1;
960 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
961 if (mVideoEncoders[i]->mCodec == codec) {
962 index = i;
963 break;
964 }
965 }
966 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000967 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800968 return -1;
969 }
970
971 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
972 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
973 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
974 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
975 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
976 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
977 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
978 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
979
Steve Block29357bc2012-01-06 19:20:56 +0000980 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -0800981 return -1;
982}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700983int MediaProfiles::getVideoEditorExportParamByName(
984 const char *name, int codec) const
985{
Steve Block3856b092011-10-20 11:56:00 +0100986 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700987 ExportVideoProfile *exportProfile = NULL;
988 int index = -1;
989 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
990 exportProfile = mVideoEditorExportProfiles[i];
991 if (exportProfile->mCodec == codec) {
992 index = i;
993 break;
994 }
995 }
996 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000997 ALOGE("The given video decoder %d is not found", codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700998 return -1;
999 }
1000 if (!strcmp("videoeditor.export.profile", name))
1001 return exportProfile->mProfile;
1002 if (!strcmp("videoeditor.export.level", name))
1003 return exportProfile->mLevel;
James Dong1d7491b2010-01-19 17:45:38 -08001004
Steve Block29357bc2012-01-06 19:20:56 +00001005 ALOGE("The given video editor export param name %s is not found", name);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001006 return -1;
1007}
Hong Tengcabd5f82011-07-06 18:33:09 -07001008int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1009{
Steve Block3856b092011-10-20 11:56:00 +01001010 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001011
1012 if (mVideoEditorCap == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001013 ALOGE("The mVideoEditorCap is not created, then create default cap.");
Hong Tengcabd5f82011-07-06 18:33:09 -07001014 createDefaultVideoEditorCap(sInstance);
1015 }
1016
1017 if (!strcmp("videoeditor.input.width.max", name))
1018 return mVideoEditorCap->mMaxInputFrameWidth;
1019 if (!strcmp("videoeditor.input.height.max", name))
1020 return mVideoEditorCap->mMaxInputFrameHeight;
1021 if (!strcmp("videoeditor.output.width.max", name))
1022 return mVideoEditorCap->mMaxOutputFrameWidth;
1023 if (!strcmp("videoeditor.output.height.max", name))
1024 return mVideoEditorCap->mMaxOutputFrameHeight;
Hong Teng3a9cefe2011-11-10 14:54:26 -08001025 if (!strcmp("maxPrefetchYUVFrames", name))
1026 return mVideoEditorCap->mMaxPrefetchYUVFrames;
Hong Tengcabd5f82011-07-06 18:33:09 -07001027
Steve Block29357bc2012-01-06 19:20:56 +00001028 ALOGE("The given video editor param name %s is not found", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001029 return -1;
1030}
1031
James Dong1d7491b2010-01-19 17:45:38 -08001032Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1033{
1034 Vector<audio_encoder> encoders;
1035 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1036 encoders.add(mAudioEncoders[i]->mCodec);
1037 }
1038 return encoders; // copy out
1039}
1040
1041int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1042{
Steve Block3856b092011-10-20 11:56:00 +01001043 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001044 int index = -1;
1045 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1046 if (mAudioEncoders[i]->mCodec == codec) {
1047 index = i;
1048 break;
1049 }
1050 }
1051 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001052 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001053 return -1;
1054 }
1055
1056 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1057 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1058 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1059 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1060 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1061 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1062
Steve Block29357bc2012-01-06 19:20:56 +00001063 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001064 return -1;
1065}
1066
1067Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1068{
1069 Vector<video_decoder> decoders;
1070 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1071 decoders.add(mVideoDecoders[i]->mCodec);
1072 }
1073 return decoders; // copy out
1074}
1075
1076Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1077{
1078 Vector<audio_decoder> decoders;
1079 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1080 decoders.add(mAudioDecoders[i]->mCodec);
1081 }
1082 return decoders; // copy out
1083}
1084
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001085int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001086{
James Dong1d7491b2010-01-19 17:45:38 -08001087 int index = -1;
1088 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001089 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1090 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001091 index = i;
1092 break;
1093 }
1094 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001095 return index;
1096}
1097
1098int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1099 int cameraId,
1100 camcorder_quality quality) const
1101{
Steve Block3856b092011-10-20 11:56:00 +01001102 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001103 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001104
1105 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001106 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001107 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001108 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001109 return -1;
1110 }
1111
James Dongf5a83852010-02-23 17:21:44 -08001112 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001113 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1114 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1115 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1116 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1117 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1118 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1119 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1120 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1121 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1122 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1123
Steve Block29357bc2012-01-06 19:20:56 +00001124 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001125 return -1;
1126}
1127
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001128bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1129{
1130 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1131}
1132
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001133Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001134{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001135 Vector<int> result;
1136 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1137 if (levels != NULL) {
1138 result = levels->mLevels; // copy out
1139 }
1140 return result;
James Dongf5a83852010-02-23 17:21:44 -08001141}
1142
James Dong0f056292011-05-09 18:49:31 -07001143int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1144 int offsetTimeMs = -1;
1145 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1146 if (index >= 0) {
1147 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1148 }
Steve Block3856b092011-10-20 11:56:00 +01001149 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001150 return offsetTimeMs;
1151}
1152
James Dong1d7491b2010-01-19 17:45:38 -08001153MediaProfiles::~MediaProfiles()
1154{
1155 CHECK("destructor should never be called" == 0);
1156#if 0
1157 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1158 delete mAudioEncoders[i];
1159 }
1160 mAudioEncoders.clear();
1161
1162 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1163 delete mVideoEncoders[i];
1164 }
1165 mVideoEncoders.clear();
1166
1167 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1168 delete mVideoDecoders[i];
1169 }
1170 mVideoDecoders.clear();
1171
1172 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1173 delete mAudioDecoders[i];
1174 }
1175 mAudioDecoders.clear();
1176
1177 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1178 delete mCamcorderProfiles[i];
1179 }
1180 mCamcorderProfiles.clear();
1181#endif
1182}
1183} // namespace android