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