blob: 28238c4572ca8066a12f934d2898b2b61596259c [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>
Elliott Hughese8057dd2012-09-09 14:58:14 -070026#include <libexpat/expat.h>
James Dong1d7491b2010-01-19 17:45:38 -080027#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},
Zhijun He5f6af1a2014-06-10 08:26:33 -070072 {"2160p", CAMCORDER_QUALITY_2160P},
James Dong669012d2011-09-19 16:27:31 -070073 {"qvga", CAMCORDER_QUALITY_QVGA},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070074
75 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
76 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
77 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -070078 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -070079 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
80 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -070081 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -070082 {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P},
James Dong669012d2011-09-19 16:27:31 -070083 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
James Dong1d7491b2010-01-19 17:45:38 -080084};
85
Glenn Kasten80520382014-01-31 16:49:31 -080086#if LOG_NDEBUG
87#define UNUSED __unused
88#else
89#define UNUSED
90#endif
91
James Dong1d7491b2010-01-19 17:45:38 -080092/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -080093MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -080094{
Steve Block3856b092011-10-20 11:56:00 +010095 ALOGV("video codec:");
96 ALOGV("codec = %d", codec.mCodec);
97 ALOGV("bit rate: %d", codec.mBitRate);
98 ALOGV("frame width: %d", codec.mFrameWidth);
99 ALOGV("frame height: %d", codec.mFrameHeight);
100 ALOGV("frame rate: %d", codec.mFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800101}
102
103/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800104MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800105{
Steve Block3856b092011-10-20 11:56:00 +0100106 ALOGV("audio codec:");
107 ALOGV("codec = %d", codec.mCodec);
108 ALOGV("bit rate: %d", codec.mBitRate);
109 ALOGV("sample rate: %d", codec.mSampleRate);
110 ALOGV("number of channels: %d", codec.mChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800111}
112
113/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800114MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800115{
Steve Block3856b092011-10-20 11:56:00 +0100116 ALOGV("video encoder cap:");
117 ALOGV("codec = %d", cap.mCodec);
118 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
119 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
120 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
121 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800122}
123
124/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800125MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800126{
Steve Block3856b092011-10-20 11:56:00 +0100127 ALOGV("audio encoder cap:");
128 ALOGV("codec = %d", cap.mCodec);
129 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
130 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
131 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800132}
133
134/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800135MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800136{
Steve Block3856b092011-10-20 11:56:00 +0100137 ALOGV("video decoder cap:");
138 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800139}
140
141/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800142MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800143{
Steve Block3856b092011-10-20 11:56:00 +0100144 ALOGV("audio codec cap:");
145 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800146}
147
Hong Tengcabd5f82011-07-06 18:33:09 -0700148/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800149MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED)
Hong Tengcabd5f82011-07-06 18:33:09 -0700150{
Steve Block3856b092011-10-20 11:56:00 +0100151 ALOGV("videoeditor cap:");
152 ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
153 ALOGV("mMaxInputFrameHeight = %d", cap.mMaxInputFrameHeight);
154 ALOGV("mMaxOutputFrameWidth = %d", cap.mMaxOutputFrameWidth);
155 ALOGV("mMaxOutputFrameHeight = %d", cap.mMaxOutputFrameHeight);
Hong Tengcabd5f82011-07-06 18:33:09 -0700156}
157
James Dong1d7491b2010-01-19 17:45:38 -0800158/*static*/ int
159MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
160{
161 int tag = -1;
162 for (size_t i = 0; i < nMappings; ++i) {
163 if (!strcmp(map[i].name, name)) {
164 tag = map[i].tag;
165 break;
166 }
167 }
168 return tag;
169}
170
171/*static*/ MediaProfiles::VideoCodec*
172MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
173{
174 CHECK(!strcmp("codec", atts[0]) &&
175 !strcmp("bitRate", atts[2]) &&
176 !strcmp("width", atts[4]) &&
177 !strcmp("height", atts[6]) &&
178 !strcmp("frameRate", atts[8]));
179
180 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
181 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
182 CHECK(codec != -1);
183
184 MediaProfiles::VideoCodec *videoCodec =
185 new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
186 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
187 logVideoCodec(*videoCodec);
188
189 size_t nCamcorderProfiles;
190 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
191 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
192 return videoCodec;
193}
194
195/*static*/ MediaProfiles::AudioCodec*
196MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
197{
198 CHECK(!strcmp("codec", atts[0]) &&
199 !strcmp("bitRate", atts[2]) &&
200 !strcmp("sampleRate", atts[4]) &&
201 !strcmp("channels", atts[6]));
202 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
203 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
204 CHECK(codec != -1);
205
206 MediaProfiles::AudioCodec *audioCodec =
207 new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
208 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
209 logAudioCodec(*audioCodec);
210
211 size_t nCamcorderProfiles;
212 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
213 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
214 return audioCodec;
215}
216/*static*/ MediaProfiles::AudioDecoderCap*
217MediaProfiles::createAudioDecoderCap(const char **atts)
218{
219 CHECK(!strcmp("name", atts[0]) &&
220 !strcmp("enabled", atts[2]));
221
222 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
223 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
224 CHECK(codec != -1);
225
226 MediaProfiles::AudioDecoderCap *cap =
227 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
228 logAudioDecoderCap(*cap);
229 return cap;
230}
231
232/*static*/ MediaProfiles::VideoDecoderCap*
233MediaProfiles::createVideoDecoderCap(const char **atts)
234{
235 CHECK(!strcmp("name", atts[0]) &&
236 !strcmp("enabled", atts[2]));
237
238 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
239 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
240 CHECK(codec != -1);
241
242 MediaProfiles::VideoDecoderCap *cap =
243 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
244 logVideoDecoderCap(*cap);
245 return cap;
246}
247
248/*static*/ MediaProfiles::VideoEncoderCap*
249MediaProfiles::createVideoEncoderCap(const char **atts)
250{
251 CHECK(!strcmp("name", atts[0]) &&
252 !strcmp("enabled", atts[2]) &&
253 !strcmp("minBitRate", atts[4]) &&
254 !strcmp("maxBitRate", atts[6]) &&
255 !strcmp("minFrameWidth", atts[8]) &&
256 !strcmp("maxFrameWidth", atts[10]) &&
257 !strcmp("minFrameHeight", atts[12]) &&
258 !strcmp("maxFrameHeight", atts[14]) &&
259 !strcmp("minFrameRate", atts[16]) &&
260 !strcmp("maxFrameRate", atts[18]));
261
262 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
263 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
264 CHECK(codec != -1);
265
266 MediaProfiles::VideoEncoderCap *cap =
267 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
268 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
269 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
270 logVideoEncoderCap(*cap);
271 return cap;
272}
273
274/*static*/ MediaProfiles::AudioEncoderCap*
275MediaProfiles::createAudioEncoderCap(const char **atts)
276{
277 CHECK(!strcmp("name", atts[0]) &&
278 !strcmp("enabled", atts[2]) &&
279 !strcmp("minBitRate", atts[4]) &&
280 !strcmp("maxBitRate", atts[6]) &&
281 !strcmp("minSampleRate", atts[8]) &&
282 !strcmp("maxSampleRate", atts[10]) &&
283 !strcmp("minChannels", atts[12]) &&
284 !strcmp("maxChannels", atts[14]));
285
286 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
287 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
288 CHECK(codec != -1);
289
290 MediaProfiles::AudioEncoderCap *cap =
291 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
292 atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
293 atoi(atts[15]));
294 logAudioEncoderCap(*cap);
295 return cap;
296}
297
298/*static*/ output_format
299MediaProfiles::createEncoderOutputFileFormat(const char **atts)
300{
301 CHECK(!strcmp("name", atts[0]));
302
303 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
304 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
305 CHECK(format != -1);
306
307 return static_cast<output_format>(format);
308}
309
James Dong2a7e0a12011-02-28 21:07:39 -0800310static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
311 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
312 if (cameraId == cameraIds[i]) {
313 return true;
314 }
315 }
316 return false;
317}
318
James Dong1d7491b2010-01-19 17:45:38 -0800319/*static*/ MediaProfiles::CamcorderProfile*
James Dong2a7e0a12011-02-28 21:07:39 -0800320MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800321{
322 CHECK(!strcmp("quality", atts[0]) &&
323 !strcmp("fileFormat", atts[2]) &&
324 !strcmp("duration", atts[4]));
325
326 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
327 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
328 CHECK(quality != -1);
329
330 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
331 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
332 CHECK(fileFormat != -1);
333
334 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800335 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800336 if (!isCameraIdFound(cameraId, cameraIds)) {
337 cameraIds.add(cameraId);
338 }
James Dong1d7491b2010-01-19 17:45:38 -0800339 profile->mFileFormat = static_cast<output_format>(fileFormat);
340 profile->mQuality = static_cast<camcorder_quality>(quality);
341 profile->mDuration = atoi(atts[5]);
342 return profile;
343}
344
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800345MediaProfiles::ImageEncodingQualityLevels*
346MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
347{
348 int n = mImageEncodingQualityLevels.size();
349 for (int i = 0; i < n; i++) {
350 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
351 if (levels->mCameraId == cameraId) {
352 return levels;
353 }
354 }
355 return NULL;
356}
357
358void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
James Dongf5a83852010-02-23 17:21:44 -0800359{
360 CHECK(!strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800361 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800362 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800363 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
364
365 if (levels == NULL) {
366 levels = new ImageEncodingQualityLevels();
367 levels->mCameraId = cameraId;
368 mImageEncodingQualityLevels.add(levels);
369 }
370
371 levels->mLevels.add(quality);
372}
373
374/*static*/ int
375MediaProfiles::getCameraId(const char** atts)
376{
377 if (!atts[0]) return 0; // default cameraId = 0
378 CHECK(!strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800379 return atoi(atts[1]);
380}
381
James Dong0f056292011-05-09 18:49:31 -0700382void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
383{
Eric Laurentb1eb1a02012-10-22 17:44:24 -0700384 int offsetTimeMs = 1000;
James Dong0f056292011-05-09 18:49:31 -0700385 if (atts[2]) {
386 CHECK(!strcmp("startOffsetMs", atts[2]));
387 offsetTimeMs = atoi(atts[3]);
388 }
389
Steve Block3856b092011-10-20 11:56:00 +0100390 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700391 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
392}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700393/*static*/ MediaProfiles::ExportVideoProfile*
394MediaProfiles::createExportVideoProfile(const char **atts)
395{
396 CHECK(!strcmp("name", atts[0]) &&
397 !strcmp("profile", atts[2]) &&
398 !strcmp("level", atts[4]));
James Dong0f056292011-05-09 18:49:31 -0700399
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700400 const size_t nMappings =
401 sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
402 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
403 CHECK(codec != -1);
404
405 MediaProfiles::ExportVideoProfile *profile =
406 new MediaProfiles::ExportVideoProfile(
407 codec, atoi(atts[3]), atoi(atts[5]));
408
409 return profile;
410}
Hong Tengcabd5f82011-07-06 18:33:09 -0700411/*static*/ MediaProfiles::VideoEditorCap*
412MediaProfiles::createVideoEditorCap(const char **atts, MediaProfiles *profiles)
413{
414 CHECK(!strcmp("maxInputFrameWidth", atts[0]) &&
415 !strcmp("maxInputFrameHeight", atts[2]) &&
416 !strcmp("maxOutputFrameWidth", atts[4]) &&
Hong Teng3a9cefe2011-11-10 14:54:26 -0800417 !strcmp("maxOutputFrameHeight", atts[6]) &&
418 !strcmp("maxPrefetchYUVFrames", atts[8]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700419
420 MediaProfiles::VideoEditorCap *pVideoEditorCap =
421 new MediaProfiles::VideoEditorCap(atoi(atts[1]), atoi(atts[3]),
Hong Teng3a9cefe2011-11-10 14:54:26 -0800422 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
Hong Tengcabd5f82011-07-06 18:33:09 -0700423
424 logVideoEditorCap(*pVideoEditorCap);
425 profiles->mVideoEditorCap = pVideoEditorCap;
426
427 return pVideoEditorCap;
428}
429
James Dong1d7491b2010-01-19 17:45:38 -0800430/*static*/ void
431MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
432{
433 MediaProfiles *profiles = (MediaProfiles *) userData;
434 if (strcmp("Video", name) == 0) {
435 createVideoCodec(atts, profiles);
436 } else if (strcmp("Audio", name) == 0) {
437 createAudioCodec(atts, profiles);
438 } else if (strcmp("VideoEncoderCap", name) == 0 &&
439 strcmp("true", atts[3]) == 0) {
440 profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
441 } else if (strcmp("AudioEncoderCap", name) == 0 &&
442 strcmp("true", atts[3]) == 0) {
443 profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
444 } else if (strcmp("VideoDecoderCap", name) == 0 &&
445 strcmp("true", atts[3]) == 0) {
446 profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
447 } else if (strcmp("AudioDecoderCap", name) == 0 &&
448 strcmp("true", atts[3]) == 0) {
449 profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
450 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
451 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800452 } else if (strcmp("CamcorderProfiles", name) == 0) {
453 profiles->mCurrentCameraId = getCameraId(atts);
James Dong0f056292011-05-09 18:49:31 -0700454 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
James Dong1d7491b2010-01-19 17:45:38 -0800455 } else if (strcmp("EncoderProfile", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800456 profiles->mCamcorderProfiles.add(
James Dong2a7e0a12011-02-28 21:07:39 -0800457 createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
James Dongf5a83852010-02-23 17:21:44 -0800458 } else if (strcmp("ImageEncoding", name) == 0) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800459 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
Hong Tengcabd5f82011-07-06 18:33:09 -0700460 } else if (strcmp("VideoEditorCap", name) == 0) {
461 createVideoEditorCap(atts, profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700462 } else if (strcmp("ExportVideoProfile", name) == 0) {
463 profiles->mVideoEditorExportProfiles.add(createExportVideoProfile(atts));
James Dong1d7491b2010-01-19 17:45:38 -0800464 }
465}
466
James Dong2a7e0a12011-02-28 21:07:39 -0800467static bool isCamcorderProfile(camcorder_quality quality) {
468 return quality >= CAMCORDER_QUALITY_LIST_START &&
469 quality <= CAMCORDER_QUALITY_LIST_END;
470}
471
472static bool isTimelapseProfile(camcorder_quality quality) {
473 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
474 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
475}
476
477void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Steve Block3856b092011-10-20 11:56:00 +0100478 ALOGV("Number of camera ids: %d", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800479 CHECK(cameraIds.size() > 0);
480 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
481 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
482 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
483 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
484 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
485 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
486 if ((j & 1) == 0) { // low resolution
487 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
488 } else { // high resolution
489 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
490 }
491 }
492 }
493}
494
495int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
496 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
497 if (mCameraIds[i] == cameraId) {
498 return i;
499 }
500 }
501 return -1;
502}
503
504void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
505 if (sIsInitialized) {
506 return;
507 }
508
509 initRequiredProfileRefs(mCameraIds);
510
511 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
512 int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
513 mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
514
515 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
516 int cameraId = mCamcorderProfiles[i]->mCameraId;
517 int index = -1;
518 int refIndex = getRequiredProfileRefIndex(cameraId);
519 CHECK(refIndex != -1);
520 RequiredProfileRefInfo *info;
521 camcorder_quality refQuality;
522 VideoCodec *codec = NULL;
523
524 // Check high and low from either camcorder profile or timelapse profile
525 // but not both. Default, check camcorder profile
526 size_t j = 0;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200527 size_t o = 2;
James Dong2a7e0a12011-02-28 21:07:39 -0800528 if (isTimelapseProfile(quality)) {
529 // Check timelapse profile instead.
530 j = 2;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200531 o = kNumRequiredProfiles;
James Dong2a7e0a12011-02-28 21:07:39 -0800532 } else {
533 // Must be camcorder profile.
534 CHECK(isCamcorderProfile(quality));
535 }
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200536 for (; j < o; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800537 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
538 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
539 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
540 continue;
541 }
542 switch (j) {
543 case 0:
544 refQuality = CAMCORDER_QUALITY_LOW;
545 break;
546 case 1:
547 refQuality = CAMCORDER_QUALITY_HIGH;
548 break;
549 case 2:
550 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
551 break;
552 case 3:
553 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
554 break;
555 default:
556 CHECK(!"Should never reach here");
557 }
558
559 if (!info->mHasRefProfile) {
560 index = getCamcorderProfileIndex(cameraId, refQuality);
561 }
562 if (index == -1) {
563 // New high or low quality profile is found.
564 // Update its reference.
565 info->mHasRefProfile = true;
566 info->mRefProfileIndex = i;
567 info->mResolutionProduct = product;
568 }
569 }
570 }
571
572 for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
573 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
574 int refIndex = getRequiredProfileRefIndex(cameraId);
575 CHECK(refIndex != -1);
576 RequiredProfileRefInfo *info =
577 &mRequiredProfileRefs[refIndex].mRefs[j];
578
579 if (info->mHasRefProfile) {
580
581 CamcorderProfile *profile =
582 new CamcorderProfile(
583 *mCamcorderProfiles[info->mRefProfileIndex]);
584
585 // Overwrite the quality
586 switch (j % kNumRequiredProfiles) {
587 case 0:
588 profile->mQuality = CAMCORDER_QUALITY_LOW;
589 break;
590 case 1:
591 profile->mQuality = CAMCORDER_QUALITY_HIGH;
592 break;
593 case 2:
594 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
595 break;
596 case 3:
597 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
598 break;
599 default:
600 CHECK(!"Should never come here");
601 }
602
603 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
604 if (index != -1) {
Steve Block3856b092011-10-20 11:56:00 +0100605 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800606 profile->mQuality, cameraId);
607 CHECK(index == refIndex);
608 continue;
609 }
610
611 // Insert the new profile
Steve Block3856b092011-10-20 11:56:00 +0100612 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800613 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
614 profile->mQuality, cameraId);
615
616 mCamcorderProfiles.add(profile);
617 }
618 }
619 }
620}
621
James Dong1d7491b2010-01-19 17:45:38 -0800622/*static*/ MediaProfiles*
623MediaProfiles::getInstance()
624{
Steve Block3856b092011-10-20 11:56:00 +0100625 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800626 Mutex::Autolock lock(sLock);
627 if (!sIsInitialized) {
628 char value[PROPERTY_VALUE_MAX];
629 if (property_get("media.settings.xml", value, NULL) <= 0) {
630 const char *defaultXmlFile = "/etc/media_profiles.xml";
631 FILE *fp = fopen(defaultXmlFile, "r");
632 if (fp == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000633 ALOGW("could not find media config xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800634 sInstance = createDefaultInstance();
635 } else {
636 fclose(fp); // close the file first.
637 sInstance = createInstanceFromXmlFile(defaultXmlFile);
638 }
639 } else {
640 sInstance = createInstanceFromXmlFile(value);
641 }
James Dong2a7e0a12011-02-28 21:07:39 -0800642 CHECK(sInstance != NULL);
643 sInstance->checkAndAddRequiredProfilesIfNecessary();
644 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800645 }
646
647 return sInstance;
648}
649
650/*static*/ MediaProfiles::VideoEncoderCap*
651MediaProfiles::createDefaultH263VideoEncoderCap()
652{
653 return new MediaProfiles::VideoEncoderCap(
654 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
655}
656
657/*static*/ MediaProfiles::VideoEncoderCap*
658MediaProfiles::createDefaultM4vVideoEncoderCap()
659{
660 return new MediaProfiles::VideoEncoderCap(
661 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
662}
663
664
665/*static*/ void
666MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
667{
668 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
669 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
670}
671
672/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700673MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700674{
675 MediaProfiles::VideoCodec *videoCodec =
676 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
677
678 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
679 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
680 profile->mCameraId = 0;
681 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700682 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700683 profile->mDuration = 60;
684 profile->mVideoCodec = videoCodec;
685 profile->mAudioCodec = audioCodec;
686 return profile;
687}
688
689/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700690MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800691{
692 MediaProfiles::VideoCodec *videoCodec =
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700693 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
James Dong1d7491b2010-01-19 17:45:38 -0800694
695 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800696 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
697 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800698 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700699 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800700 profile->mDuration = 60;
701 profile->mVideoCodec = videoCodec;
702 profile->mAudioCodec = audioCodec;
703 return profile;
704}
705
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700706/*static*/ void
707MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
708 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
709 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
710 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_LOW);
711 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
712}
713
714/*static*/ void
715MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
716 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
717 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
718 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
719 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(CAMCORDER_QUALITY_TIME_LAPSE_480P);
720}
721
James Dong1d7491b2010-01-19 17:45:38 -0800722/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700723MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -0800724{
725 MediaProfiles::VideoCodec *videoCodec =
726 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
727
728 MediaProfiles::AudioCodec *audioCodec =
729 new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
730
731 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800732 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -0800733 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700734 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -0800735 profile->mDuration = 30;
736 profile->mVideoCodec = videoCodec;
737 profile->mAudioCodec = audioCodec;
738 return profile;
739}
740
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700741/*static*/ MediaProfiles::CamcorderProfile*
742MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
743{
744 MediaProfiles::VideoCodec *videoCodec =
745 new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
746
747 AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
748 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
749 profile->mCameraId = 0;
750 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
751 profile->mQuality = quality;
752 profile->mDuration = 60;
753 profile->mVideoCodec = videoCodec;
754 profile->mAudioCodec = audioCodec;
755 return profile;
756}
757
758/*static*/ void
759MediaProfiles::createDefaultCamcorderLowProfiles(
760 MediaProfiles::CamcorderProfile **lowProfile,
761 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
762 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
763 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
764}
765
766/*static*/ void
767MediaProfiles::createDefaultCamcorderHighProfiles(
768 MediaProfiles::CamcorderProfile **highProfile,
769 MediaProfiles::CamcorderProfile **highSpecificProfile) {
770 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
771 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
772}
773
James Dong1d7491b2010-01-19 17:45:38 -0800774/*static*/ void
775MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
776{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -0700777 // low camcorder profiles.
778 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
779 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
780 profiles->mCamcorderProfiles.add(lowProfile);
781 profiles->mCamcorderProfiles.add(lowSpecificProfile);
782
783 // high camcorder profiles.
784 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
785 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
786 profiles->mCamcorderProfiles.add(highProfile);
787 profiles->mCamcorderProfiles.add(highSpecificProfile);
788
789 // low camcorder time lapse profiles.
790 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
791 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
792 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
793 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
794
795 // high camcorder time lapse profiles.
796 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
797 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile, &highSpecificTimeLapseProfile);
798 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
799 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -0700800
801 // For emulator and other legacy devices which does not have a
802 // media_profiles.xml file, We assume that the default camera id
803 // is 0 and that is the only camera available.
804 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -0800805}
806
807/*static*/ void
808MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
809{
810 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
811}
812
813/*static*/ void
814MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
815{
816 MediaProfiles::VideoDecoderCap *cap =
817 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
818
819 profiles->mVideoDecoders.add(cap);
820}
821
822/*static*/ void
823MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
824{
825 MediaProfiles::AudioDecoderCap *cap =
826 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
827
828 profiles->mAudioDecoders.add(cap);
829}
830
831/*static*/ void
832MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
833{
834 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
835 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
836}
837
838/*static*/ MediaProfiles::AudioEncoderCap*
839MediaProfiles::createDefaultAmrNBEncoderCap()
840{
841 return new MediaProfiles::AudioEncoderCap(
842 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
843}
844
James Dongf5a83852010-02-23 17:21:44 -0800845/*static*/ void
846MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
847{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800848 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
849 levels->mCameraId = 0;
850 levels->mLevels.add(70);
851 levels->mLevels.add(80);
852 levels->mLevels.add(90);
853 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -0800854}
855
Hong Tengcabd5f82011-07-06 18:33:09 -0700856/*static*/ void
857MediaProfiles::createDefaultVideoEditorCap(MediaProfiles *profiles)
858{
859 profiles->mVideoEditorCap =
860 new MediaProfiles::VideoEditorCap(
861 VIDEOEDITOR_DEFAULT_MAX_INPUT_FRAME_WIDTH,
862 VIDEOEDITOR_DEFUALT_MAX_INPUT_FRAME_HEIGHT,
863 VIDEOEDITOR_DEFAULT_MAX_OUTPUT_FRAME_WIDTH,
Hong Teng3a9cefe2011-11-10 14:54:26 -0800864 VIDEOEDITOR_DEFUALT_MAX_OUTPUT_FRAME_HEIGHT,
865 VIDEOEDITOR_DEFAULT_MAX_PREFETCH_YUV_FRAMES);
Hong Tengcabd5f82011-07-06 18:33:09 -0700866}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700867/*static*/ void
868MediaProfiles::createDefaultExportVideoProfiles(MediaProfiles *profiles)
869{
870 // Create default video export profiles
871 profiles->mVideoEditorExportProfiles.add(
872 new ExportVideoProfile(VIDEO_ENCODER_H263,
873 OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10));
874 profiles->mVideoEditorExportProfiles.add(
875 new ExportVideoProfile(VIDEO_ENCODER_MPEG_4_SP,
876 OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1));
877 profiles->mVideoEditorExportProfiles.add(
878 new ExportVideoProfile(VIDEO_ENCODER_H264,
879 OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13));
880}
Hong Tengcabd5f82011-07-06 18:33:09 -0700881
James Dong1d7491b2010-01-19 17:45:38 -0800882/*static*/ MediaProfiles*
883MediaProfiles::createDefaultInstance()
884{
885 MediaProfiles *profiles = new MediaProfiles;
886 createDefaultCamcorderProfiles(profiles);
887 createDefaultVideoEncoders(profiles);
888 createDefaultAudioEncoders(profiles);
889 createDefaultVideoDecoders(profiles);
890 createDefaultAudioDecoders(profiles);
891 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -0800892 createDefaultImageEncodingQualityLevels(profiles);
Hong Tengcabd5f82011-07-06 18:33:09 -0700893 createDefaultVideoEditorCap(profiles);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700894 createDefaultExportVideoProfiles(profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800895 return profiles;
896}
897
898/*static*/ MediaProfiles*
899MediaProfiles::createInstanceFromXmlFile(const char *xml)
900{
901 FILE *fp = NULL;
902 CHECK((fp = fopen(xml, "r")));
903
904 XML_Parser parser = ::XML_ParserCreate(NULL);
905 CHECK(parser != NULL);
906
907 MediaProfiles *profiles = new MediaProfiles();
908 ::XML_SetUserData(parser, profiles);
909 ::XML_SetElementHandler(parser, startElementHandler, NULL);
910
911 /*
912 FIXME:
913 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
914
915 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +0000916 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -0800917 return UNKNOWN_ERROR;
918 }
919
920 */
921
922 const int BUFF_SIZE = 512;
923 for (;;) {
924 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
925 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000926 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -0800927 delete profiles;
928 profiles = NULL;
929 goto exit;
930 }
931
932 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
933 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000934 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -0800935 delete profiles;
936 profiles = NULL;
937 goto exit;
938 }
939
940 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
941
942 if (bytes_read == 0) break; // done parsing the xml file
943 }
944
945exit:
946 ::XML_ParserFree(parser);
947 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -0800948 return profiles;
949}
950
951Vector<output_format> MediaProfiles::getOutputFileFormats() const
952{
953 return mEncoderOutputFileFormats; // copy out
954}
955
956Vector<video_encoder> MediaProfiles::getVideoEncoders() const
957{
958 Vector<video_encoder> encoders;
959 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
960 encoders.add(mVideoEncoders[i]->mCodec);
961 }
962 return encoders; // copy out
963}
964
965int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
966{
Steve Block3856b092011-10-20 11:56:00 +0100967 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -0800968 int index = -1;
969 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
970 if (mVideoEncoders[i]->mCodec == codec) {
971 index = i;
972 break;
973 }
974 }
975 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +0000976 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -0800977 return -1;
978 }
979
980 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
981 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
982 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
983 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
984 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
985 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
986 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
987 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
988
Steve Block29357bc2012-01-06 19:20:56 +0000989 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -0800990 return -1;
991}
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700992int MediaProfiles::getVideoEditorExportParamByName(
993 const char *name, int codec) const
994{
Steve Block3856b092011-10-20 11:56:00 +0100995 ALOGV("getVideoEditorExportParamByName: name %s codec %d", name, codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -0700996 ExportVideoProfile *exportProfile = NULL;
997 int index = -1;
998 for (size_t i =0; i < mVideoEditorExportProfiles.size(); i++) {
999 exportProfile = mVideoEditorExportProfiles[i];
1000 if (exportProfile->mCodec == codec) {
1001 index = i;
1002 break;
1003 }
1004 }
1005 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001006 ALOGE("The given video decoder %d is not found", codec);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001007 return -1;
1008 }
1009 if (!strcmp("videoeditor.export.profile", name))
1010 return exportProfile->mProfile;
1011 if (!strcmp("videoeditor.export.level", name))
1012 return exportProfile->mLevel;
James Dong1d7491b2010-01-19 17:45:38 -08001013
Steve Block29357bc2012-01-06 19:20:56 +00001014 ALOGE("The given video editor export param name %s is not found", name);
Rajneesh Chowdury8f74b712011-08-12 16:43:37 -07001015 return -1;
1016}
Hong Tengcabd5f82011-07-06 18:33:09 -07001017int MediaProfiles::getVideoEditorCapParamByName(const char *name) const
1018{
Steve Block3856b092011-10-20 11:56:00 +01001019 ALOGV("getVideoEditorCapParamByName: %s", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001020
1021 if (mVideoEditorCap == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001022 ALOGE("The mVideoEditorCap is not created, then create default cap.");
Hong Tengcabd5f82011-07-06 18:33:09 -07001023 createDefaultVideoEditorCap(sInstance);
1024 }
1025
1026 if (!strcmp("videoeditor.input.width.max", name))
1027 return mVideoEditorCap->mMaxInputFrameWidth;
1028 if (!strcmp("videoeditor.input.height.max", name))
1029 return mVideoEditorCap->mMaxInputFrameHeight;
1030 if (!strcmp("videoeditor.output.width.max", name))
1031 return mVideoEditorCap->mMaxOutputFrameWidth;
1032 if (!strcmp("videoeditor.output.height.max", name))
1033 return mVideoEditorCap->mMaxOutputFrameHeight;
Hong Teng3a9cefe2011-11-10 14:54:26 -08001034 if (!strcmp("maxPrefetchYUVFrames", name))
1035 return mVideoEditorCap->mMaxPrefetchYUVFrames;
Hong Tengcabd5f82011-07-06 18:33:09 -07001036
Steve Block29357bc2012-01-06 19:20:56 +00001037 ALOGE("The given video editor param name %s is not found", name);
Hong Tengcabd5f82011-07-06 18:33:09 -07001038 return -1;
1039}
1040
James Dong1d7491b2010-01-19 17:45:38 -08001041Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1042{
1043 Vector<audio_encoder> encoders;
1044 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1045 encoders.add(mAudioEncoders[i]->mCodec);
1046 }
1047 return encoders; // copy out
1048}
1049
1050int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1051{
Steve Block3856b092011-10-20 11:56:00 +01001052 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001053 int index = -1;
1054 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1055 if (mAudioEncoders[i]->mCodec == codec) {
1056 index = i;
1057 break;
1058 }
1059 }
1060 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001061 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001062 return -1;
1063 }
1064
1065 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1066 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1067 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1068 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1069 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1070 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1071
Steve Block29357bc2012-01-06 19:20:56 +00001072 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001073 return -1;
1074}
1075
1076Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1077{
1078 Vector<video_decoder> decoders;
1079 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1080 decoders.add(mVideoDecoders[i]->mCodec);
1081 }
1082 return decoders; // copy out
1083}
1084
1085Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1086{
1087 Vector<audio_decoder> decoders;
1088 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1089 decoders.add(mAudioDecoders[i]->mCodec);
1090 }
1091 return decoders; // copy out
1092}
1093
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001094int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001095{
James Dong1d7491b2010-01-19 17:45:38 -08001096 int index = -1;
1097 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001098 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1099 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001100 index = i;
1101 break;
1102 }
1103 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001104 return index;
1105}
1106
1107int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1108 int cameraId,
1109 camcorder_quality quality) const
1110{
Steve Block3856b092011-10-20 11:56:00 +01001111 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001112 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001113
1114 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001115 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001116 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001117 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001118 return -1;
1119 }
1120
James Dongf5a83852010-02-23 17:21:44 -08001121 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001122 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1123 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1124 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1125 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1126 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1127 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1128 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1129 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1130 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1131 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1132
Steve Block29357bc2012-01-06 19:20:56 +00001133 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001134 return -1;
1135}
1136
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001137bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1138{
1139 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1140}
1141
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001142Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001143{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001144 Vector<int> result;
1145 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1146 if (levels != NULL) {
1147 result = levels->mLevels; // copy out
1148 }
1149 return result;
James Dongf5a83852010-02-23 17:21:44 -08001150}
1151
James Dong0f056292011-05-09 18:49:31 -07001152int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1153 int offsetTimeMs = -1;
1154 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1155 if (index >= 0) {
1156 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1157 }
Steve Block3856b092011-10-20 11:56:00 +01001158 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001159 return offsetTimeMs;
1160}
1161
James Dong1d7491b2010-01-19 17:45:38 -08001162MediaProfiles::~MediaProfiles()
1163{
1164 CHECK("destructor should never be called" == 0);
1165#if 0
1166 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1167 delete mAudioEncoders[i];
1168 }
1169 mAudioEncoders.clear();
1170
1171 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1172 delete mVideoEncoders[i];
1173 }
1174 mVideoEncoders.clear();
1175
1176 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1177 delete mVideoDecoders[i];
1178 }
1179 mVideoDecoders.clear();
1180
1181 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1182 delete mAudioDecoders[i];
1183 }
1184 mAudioDecoders.clear();
1185
1186 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1187 delete mCamcorderProfiles[i];
1188 }
1189 mCamcorderProfiles.clear();
1190#endif
1191}
1192} // namespace android