MediaProfiles.cpp revision 0d0da9b40469b847f9913dd97805b7bd99b1aeb9
1/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "MediaProfiles"
21
22#include <stdlib.h>
23#include <utils/Log.h>
24#include <utils/Vector.h>
25#include <cutils/properties.h>
26#include <expat.h>
27#include <media/MediaProfiles.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <OMX_Video.h>
30
31namespace android {
32
33Mutex MediaProfiles::sLock;
34bool MediaProfiles::sIsInitialized = false;
35MediaProfiles *MediaProfiles::sInstance = NULL;
36
37const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
38    {"h263", VIDEO_ENCODER_H263},
39    {"h264", VIDEO_ENCODER_H264},
40    {"m4v",  VIDEO_ENCODER_MPEG_4_SP}
41};
42
43const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
44    {"amrnb",  AUDIO_ENCODER_AMR_NB},
45    {"amrwb",  AUDIO_ENCODER_AMR_WB},
46    {"aac",    AUDIO_ENCODER_AAC},
47    {"heaac",  AUDIO_ENCODER_HE_AAC},
48    {"aaceld", AUDIO_ENCODER_AAC_ELD}
49};
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[] = {
65    {"low", CAMCORDER_QUALITY_LOW},
66    {"high", CAMCORDER_QUALITY_HIGH},
67    {"qcif", CAMCORDER_QUALITY_QCIF},
68    {"cif", CAMCORDER_QUALITY_CIF},
69    {"480p", CAMCORDER_QUALITY_480P},
70    {"720p", CAMCORDER_QUALITY_720P},
71    {"1080p", CAMCORDER_QUALITY_1080P},
72    {"2160p", CAMCORDER_QUALITY_2160P},
73    {"qvga", CAMCORDER_QUALITY_QVGA},
74
75    {"timelapselow",  CAMCORDER_QUALITY_TIME_LAPSE_LOW},
76    {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
77    {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
78    {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
79    {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
80    {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
81    {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
82    {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P},
83    {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
84
85    {"highspeedlow",  CAMCORDER_QUALITY_HIGH_SPEED_LOW},
86    {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH},
87    {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P},
88    {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
89    {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
90    {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
91};
92
93#if LOG_NDEBUG
94#define UNUSED __unused
95#else
96#define UNUSED
97#endif
98
99/*static*/ void
100MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
101{
102    ALOGV("video codec:");
103    ALOGV("codec = %d", codec.mCodec);
104    ALOGV("bit rate: %d", codec.mBitRate);
105    ALOGV("frame width: %d", codec.mFrameWidth);
106    ALOGV("frame height: %d", codec.mFrameHeight);
107    ALOGV("frame rate: %d", codec.mFrameRate);
108}
109
110/*static*/ void
111MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
112{
113    ALOGV("audio codec:");
114    ALOGV("codec = %d", codec.mCodec);
115    ALOGV("bit rate: %d", codec.mBitRate);
116    ALOGV("sample rate: %d", codec.mSampleRate);
117    ALOGV("number of channels: %d", codec.mChannels);
118}
119
120/*static*/ void
121MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
122{
123    ALOGV("video encoder cap:");
124    ALOGV("codec = %d", cap.mCodec);
125    ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
126    ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
127    ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
128    ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
129}
130
131/*static*/ void
132MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
133{
134    ALOGV("audio encoder cap:");
135    ALOGV("codec = %d", cap.mCodec);
136    ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
137    ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
138    ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
139}
140
141/*static*/ void
142MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
143{
144    ALOGV("video decoder cap:");
145    ALOGV("codec = %d", cap.mCodec);
146}
147
148/*static*/ void
149MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
150{
151    ALOGV("audio codec cap:");
152    ALOGV("codec = %d", cap.mCodec);
153}
154
155/*static*/ int
156MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings,
157        const char *name)
158{
159    int tag = -1;
160    for (size_t i = 0; i < nMappings; ++i) {
161        if (!strcmp(map[i].name, name)) {
162            tag = map[i].tag;
163            break;
164        }
165    }
166    return tag;
167}
168
169/*static*/ MediaProfiles::VideoCodec*
170MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
171{
172    CHECK(!strcmp("codec",     atts[0]) &&
173          !strcmp("bitRate",   atts[2]) &&
174          !strcmp("width",     atts[4]) &&
175          !strcmp("height",    atts[6]) &&
176          !strcmp("frameRate", atts[8]));
177
178    const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
179    const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
180    CHECK(codec != -1);
181
182    MediaProfiles::VideoCodec *videoCodec =
183        new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
184            atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
185    logVideoCodec(*videoCodec);
186
187    size_t nCamcorderProfiles;
188    CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
189    profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
190    return videoCodec;
191}
192
193/*static*/ MediaProfiles::AudioCodec*
194MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
195{
196    CHECK(!strcmp("codec",      atts[0]) &&
197          !strcmp("bitRate",    atts[2]) &&
198          !strcmp("sampleRate", atts[4]) &&
199          !strcmp("channels",   atts[6]));
200    const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
201    const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
202    CHECK(codec != -1);
203
204    MediaProfiles::AudioCodec *audioCodec =
205        new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
206            atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
207    logAudioCodec(*audioCodec);
208
209    size_t nCamcorderProfiles;
210    CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
211    profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
212    return audioCodec;
213}
214/*static*/ MediaProfiles::AudioDecoderCap*
215MediaProfiles::createAudioDecoderCap(const char **atts)
216{
217    CHECK(!strcmp("name",    atts[0]) &&
218          !strcmp("enabled", atts[2]));
219
220    const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
221    const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
222    CHECK(codec != -1);
223
224    MediaProfiles::AudioDecoderCap *cap =
225        new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
226    logAudioDecoderCap(*cap);
227    return cap;
228}
229
230/*static*/ MediaProfiles::VideoDecoderCap*
231MediaProfiles::createVideoDecoderCap(const char **atts)
232{
233    CHECK(!strcmp("name",    atts[0]) &&
234          !strcmp("enabled", atts[2]));
235
236    const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
237    const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
238    CHECK(codec != -1);
239
240    MediaProfiles::VideoDecoderCap *cap =
241        new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
242    logVideoDecoderCap(*cap);
243    return cap;
244}
245
246/*static*/ MediaProfiles::VideoEncoderCap*
247MediaProfiles::createVideoEncoderCap(const char **atts)
248{
249    CHECK(!strcmp("name",           atts[0])  &&
250          !strcmp("enabled",        atts[2])  &&
251          !strcmp("minBitRate",     atts[4])  &&
252          !strcmp("maxBitRate",     atts[6])  &&
253          !strcmp("minFrameWidth",  atts[8])  &&
254          !strcmp("maxFrameWidth",  atts[10]) &&
255          !strcmp("minFrameHeight", atts[12]) &&
256          !strcmp("maxFrameHeight", atts[14]) &&
257          !strcmp("minFrameRate",   atts[16]) &&
258          !strcmp("maxFrameRate",   atts[18]));
259
260    const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
261    const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
262    CHECK(codec != -1);
263
264    MediaProfiles::VideoEncoderCap *cap =
265        new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
266            atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
267            atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
268    logVideoEncoderCap(*cap);
269    return cap;
270}
271
272/*static*/ MediaProfiles::AudioEncoderCap*
273MediaProfiles::createAudioEncoderCap(const char **atts)
274{
275    CHECK(!strcmp("name",          atts[0])  &&
276          !strcmp("enabled",       atts[2])  &&
277          !strcmp("minBitRate",    atts[4])  &&
278          !strcmp("maxBitRate",    atts[6])  &&
279          !strcmp("minSampleRate", atts[8])  &&
280          !strcmp("maxSampleRate", atts[10]) &&
281          !strcmp("minChannels",   atts[12]) &&
282          !strcmp("maxChannels",   atts[14]));
283
284    const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
285    const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
286    CHECK(codec != -1);
287
288    MediaProfiles::AudioEncoderCap *cap =
289        new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]),
290            atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15]));
291    logAudioEncoderCap(*cap);
292    return cap;
293}
294
295/*static*/ output_format
296MediaProfiles::createEncoderOutputFileFormat(const char **atts)
297{
298    CHECK(!strcmp("name", atts[0]));
299
300    const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
301    const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
302    CHECK(format != -1);
303
304    return static_cast<output_format>(format);
305}
306
307static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
308    for (int i = 0, n = cameraIds.size(); i < n; ++i) {
309        if (cameraId == cameraIds[i]) {
310            return true;
311        }
312    }
313    return false;
314}
315
316/*static*/ MediaProfiles::CamcorderProfile*
317MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
318{
319    CHECK(!strcmp("quality",    atts[0]) &&
320          !strcmp("fileFormat", atts[2]) &&
321          !strcmp("duration",   atts[4]));
322
323    const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/
324            sizeof(sCamcorderQualityNameMap[0]);
325    const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
326    CHECK(quality != -1);
327
328    const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
329    const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
330    CHECK(fileFormat != -1);
331
332    MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
333    profile->mCameraId = cameraId;
334    if (!isCameraIdFound(cameraId, cameraIds)) {
335        cameraIds.add(cameraId);
336    }
337    profile->mFileFormat = static_cast<output_format>(fileFormat);
338    profile->mQuality = static_cast<camcorder_quality>(quality);
339    profile->mDuration = atoi(atts[5]);
340    return profile;
341}
342
343MediaProfiles::ImageEncodingQualityLevels*
344MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
345{
346    int n = mImageEncodingQualityLevels.size();
347    for (int i = 0; i < n; i++) {
348        ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
349        if (levels->mCameraId == cameraId) {
350            return levels;
351        }
352    }
353    return NULL;
354}
355
356void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts)
357{
358    CHECK(!strcmp("quality", atts[0]));
359    int quality = atoi(atts[1]);
360    ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
361    ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
362
363    if (levels == NULL) {
364        levels = new ImageEncodingQualityLevels();
365        levels->mCameraId = cameraId;
366        mImageEncodingQualityLevels.add(levels);
367    }
368
369    levels->mLevels.add(quality);
370}
371
372/*static*/ int
373MediaProfiles::getCameraId(const char** atts)
374{
375    if (!atts[0]) return 0;  // default cameraId = 0
376    CHECK(!strcmp("cameraId", atts[0]));
377    return atoi(atts[1]);
378}
379
380void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts)
381{
382    int offsetTimeMs = 1000;
383    if (atts[2]) {
384        CHECK(!strcmp("startOffsetMs", atts[2]));
385        offsetTimeMs = atoi(atts[3]);
386    }
387
388    ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
389    mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
390}
391
392/*static*/ void
393MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
394{
395    MediaProfiles *profiles = (MediaProfiles *) userData;
396    if (strcmp("Video", name) == 0) {
397        createVideoCodec(atts, profiles);
398    } else if (strcmp("Audio", name) == 0) {
399        createAudioCodec(atts, profiles);
400    } else if (strcmp("VideoEncoderCap", name) == 0 &&
401               strcmp("true", atts[3]) == 0) {
402        profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
403    } else if (strcmp("AudioEncoderCap", name) == 0 &&
404               strcmp("true", atts[3]) == 0) {
405        profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
406    } else if (strcmp("VideoDecoderCap", name) == 0 &&
407               strcmp("true", atts[3]) == 0) {
408        profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
409    } else if (strcmp("AudioDecoderCap", name) == 0 &&
410               strcmp("true", atts[3]) == 0) {
411        profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
412    } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
413        profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
414    } else if (strcmp("CamcorderProfiles", name) == 0) {
415        profiles->mCurrentCameraId = getCameraId(atts);
416        profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts);
417    } else if (strcmp("EncoderProfile", name) == 0) {
418        profiles->mCamcorderProfiles.add(
419            createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
420    } else if (strcmp("ImageEncoding", name) == 0) {
421        profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
422    }
423}
424
425static bool isCamcorderProfile(camcorder_quality quality) {
426    return quality >= CAMCORDER_QUALITY_LIST_START &&
427           quality <= CAMCORDER_QUALITY_LIST_END;
428}
429
430static bool isTimelapseProfile(camcorder_quality quality) {
431    return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
432           quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
433}
434
435static bool isHighSpeedProfile(camcorder_quality quality) {
436    return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
437           quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END;
438}
439
440void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
441    ALOGV("Number of camera ids: %zu", cameraIds.size());
442    CHECK(cameraIds.size() > 0);
443    mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
444    for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
445        mRequiredProfileRefs[i].mCameraId = cameraIds[i];
446        for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
447            mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
448            mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
449            if ((j & 1) == 0) {  // low resolution
450                mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
451            } else {             // high resolution
452                mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
453            }
454        }
455    }
456}
457
458int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
459    for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
460        if (mCameraIds[i] == cameraId) {
461            return i;
462        }
463    }
464    return -1;
465}
466
467void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
468    if (sIsInitialized) {
469        return;
470    }
471
472    initRequiredProfileRefs(mCameraIds);
473
474    for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
475        int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
476                      mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;
477
478        camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
479        int cameraId = mCamcorderProfiles[i]->mCameraId;
480        int index = -1;
481        int refIndex = getRequiredProfileRefIndex(cameraId);
482        CHECK(refIndex != -1);
483        RequiredProfileRefInfo *info;
484        camcorder_quality refQuality;
485
486        // Check high and low from either camcorder profile, timelapse profile
487        // or high speed profile, but not all of them. Default, check camcorder profile
488        size_t j = 0;
489        size_t o = 2;
490        if (isTimelapseProfile(quality)) {
491            // Check timelapse profile instead.
492            j = 2;
493            o = kNumRequiredProfiles;
494        } else if (isHighSpeedProfile(quality)) {
495            // Skip the check for high speed profile.
496            continue;
497        } else {
498            // Must be camcorder profile.
499            CHECK(isCamcorderProfile(quality));
500        }
501        for (; j < o; ++j) {
502            info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
503            if ((j % 2 == 0 && product > info->mResolutionProduct) ||  // low
504                (j % 2 != 0 && product < info->mResolutionProduct)) {  // high
505                continue;
506            }
507            switch (j) {
508                case 0:
509                   refQuality = CAMCORDER_QUALITY_LOW;
510                   break;
511                case 1:
512                   refQuality = CAMCORDER_QUALITY_HIGH;
513                   break;
514                case 2:
515                   refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
516                   break;
517                case 3:
518                   refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
519                   break;
520                default:
521                    CHECK(!"Should never reach here");
522            }
523
524            if (!info->mHasRefProfile) {
525                index = getCamcorderProfileIndex(cameraId, refQuality);
526            }
527            if (index == -1) {
528                // New high or low quality profile is found.
529                // Update its reference.
530                info->mHasRefProfile = true;
531                info->mRefProfileIndex = i;
532                info->mResolutionProduct = product;
533            }
534        }
535    }
536
537    for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
538        for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
539            int refIndex = getRequiredProfileRefIndex(cameraId);
540            CHECK(refIndex != -1);
541            RequiredProfileRefInfo *info =
542                    &mRequiredProfileRefs[refIndex].mRefs[j];
543
544            if (info->mHasRefProfile) {
545
546                CamcorderProfile *profile =
547                    new CamcorderProfile(
548                            *mCamcorderProfiles[info->mRefProfileIndex]);
549
550                // Overwrite the quality
551                switch (j % kNumRequiredProfiles) {
552                    case 0:
553                        profile->mQuality = CAMCORDER_QUALITY_LOW;
554                        break;
555                    case 1:
556                        profile->mQuality = CAMCORDER_QUALITY_HIGH;
557                        break;
558                    case 2:
559                        profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
560                        break;
561                    case 3:
562                        profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
563                        break;
564                    default:
565                        CHECK(!"Should never come here");
566                }
567
568                int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
569                if (index != -1) {
570                    ALOGV("Profile quality %d for camera %zu already exists",
571                        profile->mQuality, cameraId);
572                    CHECK(index == refIndex);
573                    continue;
574                }
575
576                // Insert the new profile
577                ALOGV("Add a profile: quality %d=>%d for camera %zu",
578                        mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
579                        profile->mQuality, cameraId);
580
581                mCamcorderProfiles.add(profile);
582            }
583        }
584    }
585}
586
587/*static*/ MediaProfiles*
588MediaProfiles::getInstance()
589{
590    ALOGV("getInstance");
591    Mutex::Autolock lock(sLock);
592    if (!sIsInitialized) {
593        char value[PROPERTY_VALUE_MAX];
594        if (property_get("media.settings.xml", value, NULL) <= 0) {
595            const char *defaultXmlFile = "/etc/media_profiles.xml";
596            FILE *fp = fopen(defaultXmlFile, "r");
597            if (fp == NULL) {
598                ALOGW("could not find media config xml file");
599                sInstance = createDefaultInstance();
600            } else {
601                fclose(fp);  // close the file first.
602                sInstance = createInstanceFromXmlFile(defaultXmlFile);
603            }
604        } else {
605            sInstance = createInstanceFromXmlFile(value);
606        }
607        CHECK(sInstance != NULL);
608        sInstance->checkAndAddRequiredProfilesIfNecessary();
609        sIsInitialized = true;
610    }
611
612    return sInstance;
613}
614
615/*static*/ MediaProfiles::VideoEncoderCap*
616MediaProfiles::createDefaultH263VideoEncoderCap()
617{
618    return new MediaProfiles::VideoEncoderCap(
619        VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
620}
621
622/*static*/ MediaProfiles::VideoEncoderCap*
623MediaProfiles::createDefaultM4vVideoEncoderCap()
624{
625    return new MediaProfiles::VideoEncoderCap(
626        VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
627}
628
629
630/*static*/ void
631MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
632{
633    profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
634    profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
635}
636
637/*static*/ MediaProfiles::CamcorderProfile*
638MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
639{
640    MediaProfiles::VideoCodec *videoCodec =
641        new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 1000000, 176, 144, 20);
642
643    AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
644    CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
645    profile->mCameraId = 0;
646    profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
647    profile->mQuality = quality;
648    profile->mDuration = 60;
649    profile->mVideoCodec = videoCodec;
650    profile->mAudioCodec = audioCodec;
651    return profile;
652}
653
654/*static*/ MediaProfiles::CamcorderProfile*
655MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
656{
657    MediaProfiles::VideoCodec *videoCodec =
658        new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 20000000, 720, 480, 20);
659
660    AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
661    CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
662    profile->mCameraId = 0;
663    profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
664    profile->mQuality = quality;
665    profile->mDuration = 60;
666    profile->mVideoCodec = videoCodec;
667    profile->mAudioCodec = audioCodec;
668    return profile;
669}
670
671/*static*/ void
672MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
673        MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
674        MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
675    *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
676            CAMCORDER_QUALITY_TIME_LAPSE_LOW);
677    *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
678            CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
679}
680
681/*static*/ void
682MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
683        MediaProfiles::CamcorderProfile **highTimeLapseProfile,
684        MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
685    *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
686            CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
687    *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
688            CAMCORDER_QUALITY_TIME_LAPSE_480P);
689}
690
691/*static*/ MediaProfiles::CamcorderProfile*
692MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
693{
694    MediaProfiles::VideoCodec *videoCodec =
695        new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
696
697    MediaProfiles::AudioCodec *audioCodec =
698        new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
699
700    MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
701    profile->mCameraId = 0;
702    profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
703    profile->mQuality = quality;
704    profile->mDuration = 30;
705    profile->mVideoCodec = videoCodec;
706    profile->mAudioCodec = audioCodec;
707    return profile;
708}
709
710/*static*/ MediaProfiles::CamcorderProfile*
711MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
712{
713    MediaProfiles::VideoCodec *videoCodec =
714        new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
715
716    AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
717    CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
718    profile->mCameraId = 0;
719    profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
720    profile->mQuality = quality;
721    profile->mDuration = 60;
722    profile->mVideoCodec = videoCodec;
723    profile->mAudioCodec = audioCodec;
724    return profile;
725}
726
727/*static*/ void
728MediaProfiles::createDefaultCamcorderLowProfiles(
729        MediaProfiles::CamcorderProfile **lowProfile,
730        MediaProfiles::CamcorderProfile **lowSpecificProfile) {
731    *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
732    *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
733}
734
735/*static*/ void
736MediaProfiles::createDefaultCamcorderHighProfiles(
737        MediaProfiles::CamcorderProfile **highProfile,
738        MediaProfiles::CamcorderProfile **highSpecificProfile) {
739    *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
740    *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
741}
742
743/*static*/ void
744MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
745{
746    // low camcorder profiles.
747    MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
748    createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
749    profiles->mCamcorderProfiles.add(lowProfile);
750    profiles->mCamcorderProfiles.add(lowSpecificProfile);
751
752    // high camcorder profiles.
753    MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
754    createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
755    profiles->mCamcorderProfiles.add(highProfile);
756    profiles->mCamcorderProfiles.add(highSpecificProfile);
757
758    // low camcorder time lapse profiles.
759    MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
760    createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
761    profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
762    profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
763
764    // high camcorder time lapse profiles.
765    MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
766    createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile,
767            &highSpecificTimeLapseProfile);
768    profiles->mCamcorderProfiles.add(highTimeLapseProfile);
769    profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
770
771    // For emulator and other legacy devices which does not have a
772    // media_profiles.xml file, We assume that the default camera id
773    // is 0 and that is the only camera available.
774    profiles->mCameraIds.push(0);
775}
776
777/*static*/ void
778MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
779{
780    profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
781}
782
783/*static*/ void
784MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
785{
786    MediaProfiles::VideoDecoderCap *cap =
787        new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
788
789    profiles->mVideoDecoders.add(cap);
790}
791
792/*static*/ void
793MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
794{
795    MediaProfiles::AudioDecoderCap *cap =
796        new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
797
798    profiles->mAudioDecoders.add(cap);
799}
800
801/*static*/ void
802MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
803{
804    profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
805    profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
806}
807
808/*static*/ MediaProfiles::AudioEncoderCap*
809MediaProfiles::createDefaultAmrNBEncoderCap()
810{
811    return new MediaProfiles::AudioEncoderCap(
812        AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
813}
814
815/*static*/ void
816MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
817{
818    ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
819    levels->mCameraId = 0;
820    levels->mLevels.add(70);
821    levels->mLevels.add(80);
822    levels->mLevels.add(90);
823    profiles->mImageEncodingQualityLevels.add(levels);
824}
825
826/*static*/ MediaProfiles*
827MediaProfiles::createDefaultInstance()
828{
829    MediaProfiles *profiles = new MediaProfiles;
830    createDefaultCamcorderProfiles(profiles);
831    createDefaultVideoEncoders(profiles);
832    createDefaultAudioEncoders(profiles);
833    createDefaultVideoDecoders(profiles);
834    createDefaultAudioDecoders(profiles);
835    createDefaultEncoderOutputFileFormats(profiles);
836    createDefaultImageEncodingQualityLevels(profiles);
837    return profiles;
838}
839
840/*static*/ MediaProfiles*
841MediaProfiles::createInstanceFromXmlFile(const char *xml)
842{
843    FILE *fp = NULL;
844    CHECK((fp = fopen(xml, "r")));
845
846    XML_Parser parser = ::XML_ParserCreate(NULL);
847    CHECK(parser != NULL);
848
849    MediaProfiles *profiles = new MediaProfiles();
850    ::XML_SetUserData(parser, profiles);
851    ::XML_SetElementHandler(parser, startElementHandler, NULL);
852
853    /*
854      FIXME:
855      expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
856
857      if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
858          ALOGE("failed to enable DTD support in the xml file");
859          return UNKNOWN_ERROR;
860      }
861
862    */
863
864    const int BUFF_SIZE = 512;
865    for (;;) {
866        void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
867        if (buff == NULL) {
868            ALOGE("failed to in call to XML_GetBuffer()");
869            delete profiles;
870            profiles = NULL;
871            goto exit;
872        }
873
874        int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
875        if (bytes_read < 0) {
876            ALOGE("failed in call to read");
877            delete profiles;
878            profiles = NULL;
879            goto exit;
880        }
881
882        CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
883
884        if (bytes_read == 0) break;  // done parsing the xml file
885    }
886
887exit:
888    ::XML_ParserFree(parser);
889    ::fclose(fp);
890    return profiles;
891}
892
893Vector<output_format> MediaProfiles::getOutputFileFormats() const
894{
895    return mEncoderOutputFileFormats;  // copy out
896}
897
898Vector<video_encoder> MediaProfiles::getVideoEncoders() const
899{
900    Vector<video_encoder> encoders;
901    for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
902        encoders.add(mVideoEncoders[i]->mCodec);
903    }
904    return encoders;  // copy out
905}
906
907int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
908{
909    ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
910    int index = -1;
911    for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
912        if (mVideoEncoders[i]->mCodec == codec) {
913            index = i;
914            break;
915        }
916    }
917    if (index == -1) {
918        ALOGE("The given video encoder %d is not found", codec);
919        return -1;
920    }
921
922    if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
923    if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
924    if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
925    if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
926    if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
927    if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
928    if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
929    if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
930
931    ALOGE("The given video encoder param name %s is not found", name);
932    return -1;
933}
934
935Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
936{
937    Vector<audio_encoder> encoders;
938    for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
939        encoders.add(mAudioEncoders[i]->mCodec);
940    }
941    return encoders;  // copy out
942}
943
944int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
945{
946    ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
947    int index = -1;
948    for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
949        if (mAudioEncoders[i]->mCodec == codec) {
950            index = i;
951            break;
952        }
953    }
954    if (index == -1) {
955        ALOGE("The given audio encoder %d is not found", codec);
956        return -1;
957    }
958
959    if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
960    if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
961    if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
962    if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
963    if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
964    if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
965
966    ALOGE("The given audio encoder param name %s is not found", name);
967    return -1;
968}
969
970Vector<video_decoder> MediaProfiles::getVideoDecoders() const
971{
972    Vector<video_decoder> decoders;
973    for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
974        decoders.add(mVideoDecoders[i]->mCodec);
975    }
976    return decoders;  // copy out
977}
978
979Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
980{
981    Vector<audio_decoder> decoders;
982    for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
983        decoders.add(mAudioDecoders[i]->mCodec);
984    }
985    return decoders;  // copy out
986}
987
988int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
989{
990    int index = -1;
991    for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
992        if (mCamcorderProfiles[i]->mCameraId == cameraId &&
993            mCamcorderProfiles[i]->mQuality == quality) {
994            index = i;
995            break;
996        }
997    }
998    return index;
999}
1000
1001int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1002                                                  int cameraId,
1003                                                  camcorder_quality quality) const
1004{
1005    ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
1006        name, cameraId, quality);
1007
1008    int index = getCamcorderProfileIndex(cameraId, quality);
1009    if (index == -1) {
1010        ALOGE("The given camcorder profile camera %d quality %d is not found",
1011            cameraId, quality);
1012        return -1;
1013    }
1014
1015    if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
1016    if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
1017    if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
1018    if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
1019    if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
1020    if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
1021    if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
1022    if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
1023    if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
1024    if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
1025    if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
1026
1027    ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
1028    return -1;
1029}
1030
1031bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1032{
1033    return (getCamcorderProfileIndex(cameraId, quality) != -1);
1034}
1035
1036Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
1037{
1038    Vector<int> result;
1039    ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1040    if (levels != NULL) {
1041        result = levels->mLevels;  // copy out
1042    }
1043    return result;
1044}
1045
1046int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1047    int offsetTimeMs = -1;
1048    ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1049    if (index >= 0) {
1050        offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1051    }
1052    ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
1053    return offsetTimeMs;
1054}
1055
1056MediaProfiles::~MediaProfiles()
1057{
1058    CHECK("destructor should never be called" == 0);
1059#if 0
1060    for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1061        delete mAudioEncoders[i];
1062    }
1063    mAudioEncoders.clear();
1064
1065    for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1066        delete mVideoEncoders[i];
1067    }
1068    mVideoEncoders.clear();
1069
1070    for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1071        delete mVideoDecoders[i];
1072    }
1073    mVideoDecoders.clear();
1074
1075    for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1076        delete mAudioDecoders[i];
1077    }
1078    mAudioDecoders.clear();
1079
1080    for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1081        delete mCamcorderProfiles[i];
1082    }
1083    mCamcorderProfiles.clear();
1084#endif
1085}
1086} // namespace android
1087