blob: 6929efa2ebfe8b44ff490bf4f3b27e9a65b47739 [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},
Dave Burkef60c6602012-04-28 21:58:22 -070047 {"heaac", AUDIO_ENCODER_HE_AAC},
48 {"aaceld", AUDIO_ENCODER_AAC_ELD}
James Dong1d7491b2010-01-19 17:45:38 -080049};
50
51const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
52 {"3gp", OUTPUT_FORMAT_THREE_GPP},
53 {"mp4", OUTPUT_FORMAT_MPEG_4}
54};
55
56const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
57 {"wmv", VIDEO_DECODER_WMV}
58};
59
60const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
61 {"wma", AUDIO_DECODER_WMA}
62};
63
64const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -070065 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -080066 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070067 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070068 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070069 {"480p", CAMCORDER_QUALITY_480P},
70 {"720p", CAMCORDER_QUALITY_720P},
71 {"1080p", CAMCORDER_QUALITY_1080P},
James Dong669012d2011-09-19 16:27:31 -070072 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070073
74 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
75 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
76 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070077 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070078 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
79 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070080 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
81 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
James Dong1d7491b2010-01-19 17:45:38 -080082};
83
84/*static*/ void
85MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
86{
Steve Block3856b092011-10-20 11:56:00 +010087 ALOGV("video codec:");
88 ALOGV("codec = %d", codec.mCodec);
89 ALOGV("bit rate: %d", codec.mBitRate);
90 ALOGV("frame width: %d", codec.mFrameWidth);
91 ALOGV("frame height: %d", codec.mFrameHeight);
92 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -080093}
94
95/*static*/ void
96MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
97{
Steve Block3856b092011-10-20 11:56:00 +010098 ALOGV("audio codec:");
99 ALOGV("codec = %d", codec.mCodec);
100 ALOGV("bit rate: %d", codec.mBitRate);
101 ALOGV("sample rate: %d", codec.mSampleRate);
102 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800103}
104
105/*static*/ void
106MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
107{
Steve Block3856b092011-10-20 11:56:00 +0100108 ALOGV("video encoder cap:");
109 ALOGV("codec = %d", cap.mCodec);
110 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
111 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
112 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
113 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800114}
115
116/*static*/ void
117MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
118{
Steve Block3856b092011-10-20 11:56:00 +0100119 ALOGV("audio encoder cap:");
120 ALOGV("codec = %d", cap.mCodec);
121 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
122 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
123 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800124}
125
126/*static*/ void
127MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
128{
Steve Block3856b092011-10-20 11:56:00 +0100129 ALOGV("video decoder cap:");
130 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800131}
132
133/*static*/ void
134MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
135{
Steve Block3856b092011-10-20 11:56:00 +0100136 ALOGV("audio codec cap:");
137 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800138}
139
Hong Tengcabd5f82011-07-06 18:33:09 -0700140/*static*/ void
141MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
142{
Steve Block3856b092011-10-20 11:56:00 +0100143 ALOGV("videoeditor cap:");
144 ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
145 ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
146 ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
147 ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
Hong Tengcabd5f82011-07-06 18:33:09 -0700148}
149
James Dong1d7491b2010-01-19 17:45:38 -0800150/*static*/ int
151MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
152{
153 int tag = -1;
154 for (size_t i = 0; i < nMappings; ++i) {
155 if (!strcmp(map[i].name, name)) {
156 tag = map[i].tag;
157 break;
158 }
159 }
160 return tag;
161}
162
163/*static*/ MediaProfiles::VideoCodec*
164MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
165{
166 CHECK(!strcmp("codec", atts[0]) &&
167 !strcmp("bitRate", atts[2]) &&
168 !strcmp("width", atts[4]) &&
169 !strcmp("height", atts[6]) &&
170 !strcmp("frameRate", atts[8]));
171
172 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
173 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
174 CHECK(codec != -1);
175
176 MediaProfiles::VideoCodec *videoCodec =
177 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
178 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
179 logVideoCodec(*videoCodec);
180
181 size_t nCamcorderProfiles;
182 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
183 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
184 return videoCodec;
185}
186
187/*static*/ MediaProfiles::AudioCodec*
188MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
189{
190 CHECK(!strcmp("codec", atts[0]) &&
191 !strcmp("bitRate", atts[2]) &&
192 !strcmp("sampleRate", atts[4]) &&
193 !strcmp("channels", atts[6]));
194 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
195 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
196 CHECK(codec != -1);
197
198 MediaProfiles::AudioCodec *audioCodec =
199 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
200 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
201 logAudioCodec(*audioCodec);
202
203 size_t nCamcorderProfiles;
204 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
205 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
206 return audioCodec;
207}
208/*static*/ MediaProfiles::AudioDecoderCap*
209MediaProfiles::createAudioDecoderCap(const char **atts)
210{
211 CHECK(!strcmp("name", atts[0]) &&
212 !strcmp("enabled", atts[2]));
213
214 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
215 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
216 CHECK(codec != -1);
217
218 MediaProfiles::AudioDecoderCap *cap =
219 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
220 logAudioDecoderCap(*cap);
221 return cap;
222}
223
224/*static*/ MediaProfiles::VideoDecoderCap*
225MediaProfiles::createVideoDecoderCap(const char **atts)
226{
227 CHECK(!strcmp("name", atts[0]) &&
228 !strcmp("enabled", atts[2]));
229
230 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
231 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
232 CHECK(codec != -1);
233
234 MediaProfiles::VideoDecoderCap *cap =
235 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
236 logVideoDecoderCap(*cap);
237 return cap;
238}
239
240/*static*/ MediaProfiles::VideoEncoderCap*
241MediaProfiles::createVideoEncoderCap(const char **atts)
242{
243 CHECK(!strcmp("name", atts[0]) &&
244 !strcmp("enabled", atts[2]) &&
245 !strcmp("minBitRate", atts[4]) &&
246 !strcmp("maxBitRate", atts[6]) &&
247 !strcmp("minFrameWidth", atts[8]) &&
248 !strcmp("maxFrameWidth", atts[10]) &&
249 !strcmp("minFrameHeight", atts[12]) &&
250 !strcmp("maxFrameHeight", atts[14]) &&
251 !strcmp("minFrameRate", atts[16]) &&
252 !strcmp("maxFrameRate", atts[18]));
253
254 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
255 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
256 CHECK(codec != -1);
257
258 MediaProfiles::VideoEncoderCap *cap =
259 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
260 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
261 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
262 logVideoEncoderCap(*cap);
263 return cap;
264}
265
266/*static*/ MediaProfiles::AudioEncoderCap*
267MediaProfiles::createAudioEncoderCap(const char **atts)
268{
269 CHECK(!strcmp("name", atts[0]) &&
270 !strcmp("enabled", atts[2]) &&
271 !strcmp("minBitRate", atts[4]) &&
272 !strcmp("maxBitRate", atts[6]) &&
273 !strcmp("minSampleRate", atts[8]) &&
274 !strcmp("maxSampleRate", atts[10]) &&
275 !strcmp("minChannels", atts[12]) &&
276 !strcmp("maxChannels", atts[14]));
277
278 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
279 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
280 CHECK(codec != -1);
281
282 MediaProfiles::AudioEncoderCap *cap =
283 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
284 atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
285 atoi(atts[15]));
286 logAudioEncoderCap(*cap);
287 return cap;
288}
289
290/*static*/ output_format
291MediaProfiles::createEncoderOutputFileFormat(const char **atts)
292{
293 CHECK(!strcmp("name", atts[0]));
294
295 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
296 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
297 CHECK(format != -1);
298
299 return static_cast<output_format>(format);
300}
301
James Dong2a7e0a12011-02-28 21:07:39 -0800302static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
303 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
304 if (cameraId == cameraIds[i]) {
305 return true;
306 }
307 }
308 return false;
309}
310
James Dong1d7491b2010-01-19 17:45:38 -0800311/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800312MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800313{
314 CHECK(!strcmp("quality", atts[0]) &&
315 !strcmp("fileFormat", atts[2]) &&
316 !strcmp("duration", atts[4]));
317
318 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
319 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
320 CHECK(quality != -1);
321
322 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
323 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
324 CHECK(fileFormat != -1);
325
326 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800327 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800328 if (!isCameraIdFound(cameraId, cameraIds)) {
329 cameraIds.add(cameraId);
330 }
James Dong1d7491b2010-01-19 17:45:38 -0800331 profile->mFileFormat = static_cast<output_format>(fileFormat);
332 profile->mQuality = static_cast<camcorder_quality>(quality);
333 profile->mDuration = atoi(atts[5]);
334 return profile;
335}
336
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800337MediaProfiles::ImageEncodingQualityLevels*
338MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
339{
340 int n = mImageEncodingQualityLevels.size();
341 for (int i = 0; i < n; i++) {
342 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
343 if (levels->mCameraId == cameraId) {
344 return levels;
345 }
346 }
347 return NULL;
348}
349
350void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800351{
352 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800353 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800354 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800355 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
356
357 if (levels == NULL) {
358 levels = new ImageEncodingQualityLevels();
359 levels->mCameraId = cameraId;
360 mImageEncodingQualityLevels.add(levels);
361 }
362
363 levels->mLevels.add(quality);
364}
365
366/*static*/ int
367MediaProfiles::getCameraId(const char** atts)
368{
369 if (!atts[0]) return 0; // default cameraId = 0
370 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800371 return atoi(atts[1]);
372}
373
James Dong0f056292011-05-09 18:49:31 -0700374void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
375{
376 int offsetTimeMs = 700;
377 if (atts[2]) {
378 CHECK(!strcmp("startOffsetMs", atts[2]));
379 offsetTimeMs = atoi(atts[3]);
380 }
381
Steve Block3856b092011-10-20 11:56:00 +0100382 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700383 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
384}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700385/*static*/ MediaProfiles::ExportVideoProfile*
386MediaProfiles::createExportVideoProfile(const char **atts)
387{
388 CHECK(!strcmp("name", atts[0]) &&
389 !strcmp("profile", atts[2]) &&
390 !strcmp("level", atts[4]));
James Dong0f056292011-05-09 18:49:31 -0700391
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700392 const size_t nMappings =
393 sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
394 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
395 CHECK(codec != -1);
396
397 MediaProfiles::ExportVideoProfile *profile =
398 new MediaProfiles::ExportVideoProfile(
399 codec, atoi(atts[3]), atoi(atts[5]));
400
401 return profile;
402}
Hong Tengcabd5f82011-07-06 18:33:09 -0700403/*static*/ MediaProfiles::VideoEditorCap*
404MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
405{
406 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
407 !strcmp("maxInputFrameHeight", atts[2]) &&
408 !strcmp("maxOutputFrameWidth", atts[4]) &&
Hong Teng3a9cefe2011-11-10 14:54:26 -0800409 !strcmp("maxOutputFrameHeight", atts[6]) &&
410 !strcmp("maxPrefetchYUVFrames", atts[8]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700411
412 MediaProfiles::VideoEditorCap *pVideoEditorCap =
413 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
Hong Teng3a9cefe2011-11-10 14:54:26 -0800414 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700415
416 logVideoEditorCap(*pVideoEditorCap);
417 profiles->mVideoEditorCap = pVideoEditorCap;
418
419 return pVideoEditorCap;
420}
421
James Dong1d7491b2010-01-19 17:45:38 -0800422/*static*/ void
423MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
424{
425 MediaProfiles *profiles = (MediaProfiles *) userData;
426 if (strcmp("Video", name) == 0) {
427 createVideoCodec(atts, profiles);
428 } else if (strcmp("Audio", name) == 0) {
429 createAudioCodec(atts, profiles);
430 } else if (strcmp("VideoEncoderCap", name) == 0 &&
431 strcmp("true", atts[3]) == 0) {
432 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
433 } else if (strcmp("AudioEncoderCap", name) == 0 &&
434 strcmp("true", atts[3]) == 0) {
435 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
436 } else if (strcmp("VideoDecoderCap", name) == 0 &&
437 strcmp("true", atts[3]) == 0) {
438 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
439 } else if (strcmp("AudioDecoderCap", name) == 0 &&
440 strcmp("true", atts[3]) == 0) {
441 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
442 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
443 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800444 } else if (strcmp("CamcorderProfiles", name) == 0) {
445 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700446 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800447 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800448 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800449 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800450 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800451 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700452 } else if (strcmp("VideoEditorCap", name) == 0) {
453 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700454 } else if (strcmp("ExportVideoProfile", name) == 0) {
455 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dong1d7491b2010-01-19 17:45:38 -0800456 }
457}
458
James Dong2a7e0a12011-02-28 21:07:39 -0800459static bool isCamcorderProfile(camcorder_quality quality) {
460 return quality >= CAMCORDER_QUALITY_LIST_START &&
461 quality <= CAMCORDER_QUALITY_LIST_END;
462}
463
464static bool isTimelapseProfile(camcorder_quality quality) {
465 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
466 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
467}
468
469void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Steve Block3856b092011-10-20 11:56:00 +0100470 ALOGV("Number of camera ids: %d", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800471 CHECK(cameraIds.size() > 0);
472 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
473 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
474 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
475 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
476 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
477 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
478 if ((j & 1) == 0) { // low resolution
479 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
480 } else { // high resolution
481 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
482 }
483 }
484 }
485}
486
487int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
488 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
489 if (mCameraIds[i] == cameraId) {
490 return i;
491 }
492 }
493 return -1;
494}
495
496void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
497 if (sIsInitialized) {
498 return;
499 }
500
501 initRequiredProfileRefs(mCameraIds);
502
503 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
504 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
505 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
506
507 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
508 int cameraId = mCamcorderProfiles[i]->mCameraId;
509 int index = -1;
510 int refIndex = getRequiredProfileRefIndex(cameraId);
511 CHECK(refIndex != -1);
512 RequiredProfileRefInfo *info;
513 camcorder_quality refQuality;
514 VideoCodec *codec = NULL;
515
516 // Check high and low from either camcorder profile or timelapse profile
517 // but not both. Default, check camcorder profile
518 size_t j = 0;
519 size_t n = 2;
520 if (isTimelapseProfile(quality)) {
521 // Check timelapse profile instead.
522 j = 2;
523 n = kNumRequiredProfiles;
524 } else {
525 // Must be camcorder profile.
526 CHECK(isCamcorderProfile(quality));
527 }
528 for (; j < n; ++j) {
529 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
530 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
531 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
532 continue;
533 }
534 switch (j) {
535 case 0:
536 refQuality = CAMCORDER_QUALITY_LOW;
537 break;
538 case 1:
539 refQuality = CAMCORDER_QUALITY_HIGH;
540 break;
541 case 2:
542 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
543 break;
544 case 3:
545 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
546 break;
547 default:
548 CHECK(!"Should never reach here");
549 }
550
551 if (!info->mHasRefProfile) {
552 index = getCamcorderProfileIndex(cameraId, refQuality);
553 }
554 if (index == -1) {
555 // New high or low quality profile is found.
556 // Update its reference.
557 info->mHasRefProfile = true;
558 info->mRefProfileIndex = i;
559 info->mResolutionProduct = product;
560 }
561 }
562 }
563
564 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
565 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
566 int refIndex = getRequiredProfileRefIndex(cameraId);
567 CHECK(refIndex != -1);
568 RequiredProfileRefInfo *info =
569 &mRequiredProfileRefs[refIndex].mRefs[j];
570
571 if (info->mHasRefProfile) {
572
573 CamcorderProfile *profile =
574 new CamcorderProfile(
575 *mCamcorderProfiles[info->mRefProfileIndex]);
576
577 // Overwrite the quality
578 switch (j % kNumRequiredProfiles) {
579 case 0:
580 profile->mQuality = CAMCORDER_QUALITY_LOW;
581 break;
582 case 1:
583 profile->mQuality = CAMCORDER_QUALITY_HIGH;
584 break;
585 case 2:
586 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
587 break;
588 case 3:
589 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
590 break;
591 default:
592 CHECK(!"Should never come here");
593 }
594
595 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
596 if (index != -1) {
Steve Block3856b092011-10-20 11:56:00 +0100597 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800598 profile->mQuality, cameraId);
599 CHECK(index == refIndex);
600 continue;
601 }
602
603 // Insert the new profile
Steve Block3856b092011-10-20 11:56:00 +0100604 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800605 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
606 profile->mQuality, cameraId);
607
608 mCamcorderProfiles.add(profile);
609 }
610 }
611 }
612}
613
James Dong1d7491b2010-01-19 17:45:38 -0800614/*static*/ MediaProfiles*
615MediaProfiles::getInstance()
616{
Steve Block3856b092011-10-20 11:56:00 +0100617 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800618 Mutex::Autolock lock(sLock);
619 if (!sIsInitialized) {
620 char value[PROPERTY_VALUE_MAX];
621 if (property_get("media.settings.xml", value, NULL) <= 0) {
622 const char *defaultXmlFile = "/etc/media_profiles.xml";
623 FILE *fp = fopen(defaultXmlFile, "r");
624 if (fp == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000625 ALOGW("could not find media config xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800626 sInstance = createDefaultInstance();
627 } else {
628 fclose(fp); // close the file first.
629 sInstance = createInstanceFromXmlFile(defaultXmlFile);
630 }
631 } else {
632 sInstance = createInstanceFromXmlFile(value);
633 }
James Dong2a7e0a12011-02-28 21:07:39 -0800634 CHECK(sInstance != NULL);
635 sInstance->checkAndAddRequiredProfilesIfNecessary();
636 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800637 }
638
639 return sInstance;
640}
641
642/*static*/ MediaProfiles::VideoEncoderCap*
643MediaProfiles::createDefaultH263VideoEncoderCap()
644{
645 return new MediaProfiles::VideoEncoderCap(
646 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
647}
648
649/*static*/ MediaProfiles::VideoEncoderCap*
650MediaProfiles::createDefaultM4vVideoEncoderCap()
651{
652 return new MediaProfiles::VideoEncoderCap(
653 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
654}
655
656
657/*static*/ void
658MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
659{
660 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
661 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
662}
663
664/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700665MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700666{
667 MediaProfiles::VideoCodec *videoCodec =
668 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
669
670 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
671 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
672 profile->mCameraId = 0;
673 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700674 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700675 profile->mDuration = 60;
676 profile->mVideoCodec = videoCodec;
677 profile->mAudioCodec = audioCodec;
678 return profile;
679}
680
681/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700682MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800683{
684 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700685 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800686
687 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800688 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
689 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800690 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700691 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800692 profile->mDuration = 60;
693 profile->mVideoCodec = videoCodec;
694 profile->mAudioCodec = audioCodec;
695 return profile;
696}
697
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700698/*static*/ void
699MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
700 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
701 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
702 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
703 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
704}
705
706/*static*/ void
707MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
708 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
709 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
710 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
711 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
712}
713
James Dong1d7491b2010-01-19 17:45:38 -0800714/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700715MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800716{
717 MediaProfiles::VideoCodec *videoCodec =
718 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
719
720 MediaProfiles::AudioCodec *audioCodec =
721 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
722
723 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800724 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800725 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700726 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800727 profile->mDuration = 30;
728 profile->mVideoCodec = videoCodec;
729 profile->mAudioCodec = audioCodec;
730 return profile;
731}
732
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700733/*static*/ MediaProfiles::CamcorderProfile*
734MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
735{
736 MediaProfiles::VideoCodec *videoCodec =
737 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
738
739 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
740 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
741 profile->mCameraId = 0;
742 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
743 profile->mQuality = quality;
744 profile->mDuration = 60;
745 profile->mVideoCodec = videoCodec;
746 profile->mAudioCodec = audioCodec;
747 return profile;
748}
749
750/*static*/ void
751MediaProfiles::createDefaultCamcorderLowProfiles(
752 MediaProfiles::CamcorderProfile **lowProfile,
753 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
754 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
755 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
756}
757
758/*static*/ void
759MediaProfiles::createDefaultCamcorderHighProfiles(
760 MediaProfiles::CamcorderProfile **highProfile,
761 MediaProfiles::CamcorderProfile **highSpecificProfile) {
762 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
763 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
764}
765
James Dong1d7491b2010-01-19 17:45:38 -0800766/*static*/ void
767MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
768{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700769 // low camcorder profiles.
770 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
771 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
772 profiles->mCamcorderProfiles.add(lowProfile);
773 profiles->mCamcorderProfiles.add(lowSpecificProfile);
774
775 // high camcorder profiles.
776 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
777 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
778 profiles->mCamcorderProfiles.add(highProfile);
779 profiles->mCamcorderProfiles.add(highSpecificProfile);
780
781 // low camcorder time lapse profiles.
782 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
783 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
784 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
785 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
786
787 // high camcorder time lapse profiles.
788 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
789 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
790 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
791 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700792
793 // For emulator and other legacy devices which does not have a
794 // media_profiles.xml file, We assume that the default camera id
795 // is 0 and that is the only camera available.
796 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800797}
798
799/*static*/ void
800MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
801{
802 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
803}
804
805/*static*/ void
806MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
807{
808 MediaProfiles::VideoDecoderCap *cap =
809 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
810
811 profiles->mVideoDecoders.add(cap);
812}
813
814/*static*/ void
815MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
816{
817 MediaProfiles::AudioDecoderCap *cap =
818 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
819
820 profiles->mAudioDecoders.add(cap);
821}
822
823/*static*/ void
824MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
825{
826 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
827 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
828}
829
830/*static*/ MediaProfiles::AudioEncoderCap*
831MediaProfiles::createDefaultAmrNBEncoderCap()
832{
833 return new MediaProfiles::AudioEncoderCap(
834 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
835}
836
James Dongf5a83852010-02-23 17:21:44 -0800837/*static*/ void
838MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
839{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800840 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
841 levels->mCameraId = 0;
842 levels->mLevels.add(70);
843 levels->mLevels.add(80);
844 levels->mLevels.add(90);
845 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800846}
847
Hong Tengcabd5f82011-07-06 18:33:09 -0700848/*static*/ void
849MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
850{
851 profiles->mVideoEditorCap =
852 new MediaProfiles::VideoEditorCap(
853 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
854 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
855 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
Hong Teng3a9cefe2011-11-10 14:54:26 -0800856 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
857 VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
Hong Tengcabd5f82011-07-06 18:33:09 -0700858}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700859/*static*/ void
860MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
861{
862 // Create default video export profiles
863 profiles->mVideoEditorExportProfiles.add(
864 new ExportVideoProfile(VIDEO_ENCODER_H263,
865 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
866 profiles->mVideoEditorExportProfiles.add(
867 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
868 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
869 profiles->mVideoEditorExportProfiles.add(
870 new ExportVideoProfile(VIDEO_ENCODER_H264,
871 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
872}
Hong Tengcabd5f82011-07-06 18:33:09 -0700873
James Dong1d7491b2010-01-19 17:45:38 -0800874/*static*/ MediaProfiles*
875MediaProfiles::createDefaultInstance()
876{
877 MediaProfiles *profiles = new MediaProfiles;
878 createDefaultCamcorderProfiles(profiles);
879 createDefaultVideoEncoders(profiles);
880 createDefaultAudioEncoders(profiles);
881 createDefaultVideoDecoders(profiles);
882 createDefaultAudioDecoders(profiles);
883 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800884 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700885 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700886 createDefaultExportVideoProfiles(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800887 return profiles;
888}
889
890/*static*/ MediaProfiles*
891MediaProfiles::createInstanceFromXmlFile(const char *xml)
892{
893 FILE *fp = NULL;
894 CHECK((fp = fopen(xml, "r")));
895
896 XML_Parser parser = ::XML_ParserCreate(NULL);
897 CHECK(parser != NULL);
898
899 MediaProfiles *profiles = new MediaProfiles();
900 ::XML_SetUserData(parser, profiles);
901 ::XML_SetElementHandler(parser, startElementHandler, NULL);
902
903 /*
904 FIXME:
905 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
906
907 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +0000908 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800909 return UNKNOWN_ERROR;
910 }
911
912 */
913
914 const int BUFF_SIZE = 512;
915 for (;;) {
916 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
917 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000918 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -0800919 delete profiles;
920 profiles = NULL;
921 goto exit;
922 }
923
924 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
925 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000926 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -0800927 delete profiles;
928 profiles = NULL;
929 goto exit;
930 }
931
932 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
933
934 if (bytes_read == 0) break; // done parsing the xml file
935 }
936
937exit:
938 ::XML_ParserFree(parser);
939 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800940 return profiles;
941}
942
943Vector<output_format> MediaProfiles::getOutputFileFormats() const
944{
945 return mEncoderOutputFileFormats; // copy out
946}
947
948Vector<video_encoder> MediaProfiles::getVideoEncoders() const
949{
950 Vector<video_encoder> encoders;
951 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
952 encoders.add(mVideoEncoders[i]->mCodec);
953 }
954 return encoders; // copy out
955}
956
957int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
958{
Steve Block3856b092011-10-20 11:56:00 +0100959 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800960 int index = -1;
961 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
962 if (mVideoEncoders[i]->mCodec == codec) {
963 index = i;
964 break;
965 }
966 }
967 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000968 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800969 return -1;
970 }
971
972 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
973 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
974 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
975 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
976 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
977 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
978 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
979 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
980
Steve Block29357bc2012-01-06 19:20:56 +0000981 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -0800982 return -1;
983}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700984int MediaProfiles::getVideoEditorExportParamByName(
985 const char *name, int codec) const
986{
Steve Block3856b092011-10-20 11:56:00 +0100987 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700988 ExportVideoProfile *exportProfile = NULL;
989 int index = -1;
990 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
991 exportProfile = mVideoEditorExportProfiles[i];
992 if (exportProfile->mCodec == codec) {
993 index = i;
994 break;
995 }
996 }
997 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000998 ALOGE("The given video decoder %d is not found", codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700999 return -1;
1000 }
1001 if (!strcmp("videoeditor.export.profile", name))
1002 return exportProfile->mProfile;
1003 if (!strcmp("videoeditor.export.level", name))
1004 return exportProfile->mLevel;
James Dong1d7491b2010-01-19 17:45:38 -08001005
Steve Block29357bc2012-01-06 19:20:56 +00001006 ALOGE("The given video editor export param name %s is not found", name);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001007 return -1;
1008}
Hong Tengcabd5f82011-07-06 18:33:09 -07001009int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1010{
Steve Block3856b092011-10-20 11:56:00 +01001011 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001012
1013 if (mVideoEditorCap == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001014 ALOGE("The mVideoEditorCap is not created, then create default cap.");
Hong Tengcabd5f82011-07-06 18:33:09 -07001015 createDefaultVideoEditorCap(sInstance);
1016 }
1017
1018 if (!strcmp("videoeditor.input.width.max", name))
1019 return mVideoEditorCap->mMaxInputFrameWidth;
1020 if (!strcmp("videoeditor.input.height.max", name))
1021 return mVideoEditorCap->mMaxInputFrameHeight;
1022 if (!strcmp("videoeditor.output.width.max", name))
1023 return mVideoEditorCap->mMaxOutputFrameWidth;
1024 if (!strcmp("videoeditor.output.height.max", name))
1025 return mVideoEditorCap->mMaxOutputFrameHeight;
Hong Teng3a9cefe2011-11-10 14:54:26 -08001026 if (!strcmp("maxPrefetchYUVFrames", name))
1027 return mVideoEditorCap->mMaxPrefetchYUVFrames;
Hong Tengcabd5f82011-07-06 18:33:09 -07001028
Steve Block29357bc2012-01-06 19:20:56 +00001029 ALOGE("The given video editor param name %s is not found", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001030 return -1;
1031}
1032
James Dong1d7491b2010-01-19 17:45:38 -08001033Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1034{
1035 Vector<audio_encoder> encoders;
1036 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1037 encoders.add(mAudioEncoders[i]->mCodec);
1038 }
1039 return encoders; // copy out
1040}
1041
1042int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1043{
Steve Block3856b092011-10-20 11:56:00 +01001044 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001045 int index = -1;
1046 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1047 if (mAudioEncoders[i]->mCodec == codec) {
1048 index = i;
1049 break;
1050 }
1051 }
1052 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001053 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001054 return -1;
1055 }
1056
1057 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1058 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1059 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1060 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1061 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1062 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1063
Steve Block29357bc2012-01-06 19:20:56 +00001064 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001065 return -1;
1066}
1067
1068Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1069{
1070 Vector<video_decoder> decoders;
1071 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1072 decoders.add(mVideoDecoders[i]->mCodec);
1073 }
1074 return decoders; // copy out
1075}
1076
1077Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1078{
1079 Vector<audio_decoder> decoders;
1080 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1081 decoders.add(mAudioDecoders[i]->mCodec);
1082 }
1083 return decoders; // copy out
1084}
1085
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001086int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001087{
James Dong1d7491b2010-01-19 17:45:38 -08001088 int index = -1;
1089 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001090 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1091 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001092 index = i;
1093 break;
1094 }
1095 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001096 return index;
1097}
1098
1099int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1100 int cameraId,
1101 camcorder_quality quality) const
1102{
Steve Block3856b092011-10-20 11:56:00 +01001103 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001104 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001105
1106 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001107 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001108 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001109 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001110 return -1;
1111 }
1112
James Dongf5a83852010-02-23 17:21:44 -08001113 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001114 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1115 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1116 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1117 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1118 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1119 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1120 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1121 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1122 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1123 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1124
Steve Block29357bc2012-01-06 19:20:56 +00001125 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001126 return -1;
1127}
1128
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001129bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1130{
1131 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1132}
1133
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001134Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001135{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001136 Vector<int> result;
1137 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1138 if (levels != NULL) {
1139 result = levels->mLevels; // copy out
1140 }
1141 return result;
James Dongf5a83852010-02-23 17:21:44 -08001142}
1143
James Dong0f056292011-05-09 18:49:31 -07001144int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1145 int offsetTimeMs = -1;
1146 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1147 if (index >= 0) {
1148 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1149 }
Steve Block3856b092011-10-20 11:56:00 +01001150 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001151 return offsetTimeMs;
1152}
1153
James Dong1d7491b2010-01-19 17:45:38 -08001154MediaProfiles::~MediaProfiles()
1155{
1156 CHECK("destructor should never be called" == 0);
1157#if 0
1158 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1159 delete mAudioEncoders[i];
1160 }
1161 mAudioEncoders.clear();
1162
1163 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1164 delete mVideoEncoders[i];
1165 }
1166 mVideoEncoders.clear();
1167
1168 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1169 delete mVideoDecoders[i];
1170 }
1171 mVideoDecoders.clear();
1172
1173 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1174 delete mAudioDecoders[i];
1175 }
1176 mAudioDecoders.clear();
1177
1178 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1179 delete mCamcorderProfiles[i];
1180 }
1181 mCamcorderProfiles.clear();
1182#endif
1183}
1184} // namespace android