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