blob: eb39ac3a13d42be29257647db49d0d7f0d41fc1a [file] [log] [blame]
James Dong1d7491b2010-01-19 17:45:38 -08001/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "MediaProfiles"
21
22#include <stdlib.h>
Lajos Molnar88e2e172022-01-14 16:03:05 -080023#include <utils/misc.h>
James Dong1d7491b2010-01-19 17:45:38 -080024#include <utils/Log.h>
25#include <utils/Vector.h>
26#include <cutils/properties.h>
Elliott Hughes242b4002015-07-10 11:09:23 -070027#include <expat.h>
James Dong1d7491b2010-01-19 17:45:38 -080028#include <media/MediaProfiles.h>
James Dongf1d5aa12012-02-06 23:46:37 -080029#include <media/stagefright/foundation/ADebug.h>
Lajos Molnar88e2e172022-01-14 16:03:05 -080030#include <media/stagefright/MediaCodecConstants.h>
James Dong6c6b4d02012-03-12 14:37:53 -070031#include <OMX_Video.h>
Pawin Vongmasad7db05b2017-05-03 04:19:20 -070032#include <sys/stat.h>
James Dong1d7491b2010-01-19 17:45:38 -080033
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -080034#include <array>
35#include <string>
36#include <vector>
37
James Dong1d7491b2010-01-19 17:45:38 -080038namespace android {
39
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -080040namespace /* unnamed */ {
41
42// Returns a list of possible paths for the media_profiles XML file.
43std::array<char const*, 5> const& getXmlPaths() {
44 static std::array<std::string const, 5> const paths =
45 []() -> decltype(paths) {
46 // Directories for XML file that will be searched (in this order).
47 constexpr std::array<char const*, 4> searchDirs = {
48 "product/etc/",
49 "odm/etc/",
50 "vendor/etc/",
51 "system/etc/",
52 };
53
54 // The file name may contain a variant if the vendor property
55 // ro.vendor.media_profiles_xml_variant is set.
56 char variant[PROPERTY_VALUE_MAX];
57 property_get("ro.media.xml_variant.profiles",
58 variant,
59 "_V1_0");
60
61 std::string fileName =
62 std::string("media_profiles") + variant + ".xml";
63
64 return { searchDirs[0] + fileName,
65 searchDirs[1] + fileName,
66 searchDirs[2] + fileName,
67 searchDirs[3] + fileName,
Matthias Springer0f44db02020-08-14 14:32:05 +090068 "system/etc/media_profiles.xml" // System fallback
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -080069 };
70 }();
71 static std::array<char const*, 5> const cPaths = {
72 paths[0].data(),
73 paths[1].data(),
74 paths[2].data(),
75 paths[3].data(),
76 paths[4].data()
77 };
78 return cPaths;
79}
80
81} // unnamed namespace
82
James Dong1d7491b2010-01-19 17:45:38 -080083Mutex MediaProfiles::sLock;
84bool MediaProfiles::sIsInitialized = false;
85MediaProfiles *MediaProfiles::sInstance = NULL;
86
87const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
88 {"h263", VIDEO_ENCODER_H263},
89 {"h264", VIDEO_ENCODER_H264},
Wonsik Kim9aa87d42015-12-07 13:52:02 +090090 {"m4v", VIDEO_ENCODER_MPEG_4_SP},
Lajos Molnar88e2e172022-01-14 16:03:05 -080091 {"vp8", VIDEO_ENCODER_VP8},
92 {"hevc", VIDEO_ENCODER_HEVC},
93 {"vp9", VIDEO_ENCODER_VP9},
94 {"dolbyvision", VIDEO_ENCODER_DOLBY_VISION},
95};
96
97const MediaProfiles::NameToTagMap MediaProfiles::sChromaSubsamplingNameMap[] = {
98 {"yuv 4:2:0", CHROMA_SUBSAMPLING_YUV_420},
99 {"yuv 4:2:2", CHROMA_SUBSAMPLING_YUV_422},
100 {"yuv 4:4:4", CHROMA_SUBSAMPLING_YUV_444},
101};
102
103const MediaProfiles::NameToTagMap MediaProfiles::sHdrFormatNameMap[] = {
104 {"sdr", HDR_FORMAT_NONE},
105 {"hlg", HDR_FORMAT_HLG},
106 {"hdr10", HDR_FORMAT_HDR10},
107 {"hdr10+", HDR_FORMAT_HDR10PLUS},
108 {"dolbyvision", HDR_FORMAT_DOLBY_VISION},
James Dong1d7491b2010-01-19 17:45:38 -0800109};
110
111const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
Dave Burkeaeb8fd42012-04-19 00:14:27 -0700112 {"amrnb", AUDIO_ENCODER_AMR_NB},
113 {"amrwb", AUDIO_ENCODER_AMR_WB},
114 {"aac", AUDIO_ENCODER_AAC},
Dave Burkef60c6602012-04-28 21:58:22 -0700115 {"heaac", AUDIO_ENCODER_HE_AAC},
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -0800116 {"aaceld", AUDIO_ENCODER_AAC_ELD},
Ray Essickdf27b042018-11-27 18:55:09 -0800117 {"opus", AUDIO_ENCODER_OPUS}
James Dong1d7491b2010-01-19 17:45:38 -0800118};
119
120const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
121 {"3gp", OUTPUT_FORMAT_THREE_GPP},
122 {"mp4", OUTPUT_FORMAT_MPEG_4}
123};
124
125const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
126 {"wmv", VIDEO_DECODER_WMV}
127};
128
129const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
130 {"wma", AUDIO_DECODER_WMA}
131};
132
133const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700134 {"low", CAMCORDER_QUALITY_LOW},
James Dong1d7491b2010-01-19 17:45:38 -0800135 {"high", CAMCORDER_QUALITY_HIGH},
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700136 {"qcif", CAMCORDER_QUALITY_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -0700137 {"cif", CAMCORDER_QUALITY_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700138 {"480p", CAMCORDER_QUALITY_480P},
139 {"720p", CAMCORDER_QUALITY_720P},
140 {"1080p", CAMCORDER_QUALITY_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -0700141 {"2160p", CAMCORDER_QUALITY_2160P},
James Dong669012d2011-09-19 16:27:31 -0700142 {"qvga", CAMCORDER_QUALITY_QVGA},
Lajos Molnar5e35f772021-02-06 00:33:07 -0800143 {"vga", CAMCORDER_QUALITY_VGA},
144 {"4kdci", CAMCORDER_QUALITY_4KDCI},
145 {"qhd", CAMCORDER_QUALITY_QHD},
146 {"2k", CAMCORDER_QUALITY_2K},
147 {"8kuhd", CAMCORDER_QUALITY_8KUHD},
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700148
149 {"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
150 {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
151 {"timelapseqcif", CAMCORDER_QUALITY_TIME_LAPSE_QCIF},
Nipun Kwatra9783ed82010-09-10 15:45:57 -0700152 {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
Nipun Kwatrac0a84782010-09-06 15:59:02 -0700153 {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
154 {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
James Dong669012d2011-09-19 16:27:31 -0700155 {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
Zhijun He5f6af1a2014-06-10 08:26:33 -0700156 {"timelapse2160p", CAMCORDER_QUALITY_TIME_LAPSE_2160P},
James Dong669012d2011-09-19 16:27:31 -0700157 {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
Lajos Molnar5e35f772021-02-06 00:33:07 -0800158 {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA},
159 {"timelapse4kdci", CAMCORDER_QUALITY_TIME_LAPSE_4KDCI},
160 {"timelapseqhd", CAMCORDER_QUALITY_TIME_LAPSE_QHD},
161 {"timelapse2k", CAMCORDER_QUALITY_TIME_LAPSE_2K},
Malathi Gottamd2bf2842021-05-05 15:16:07 +0530162 {"timelapse8kuhd", CAMCORDER_QUALITY_TIME_LAPSE_8KUHD},
Zhijun Hee0790972014-07-23 15:17:26 -0700163
164 {"highspeedlow", CAMCORDER_QUALITY_HIGH_SPEED_LOW},
165 {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH},
166 {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P},
167 {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
168 {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
Zhijun He9520aa62014-09-09 16:18:31 -0700169 {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
Praveen Chavanb5bfa0e2019-01-16 15:49:42 -0800170 {"highspeedcif", CAMCORDER_QUALITY_HIGH_SPEED_CIF},
171 {"highspeedvga", CAMCORDER_QUALITY_HIGH_SPEED_VGA},
172 {"highspeed4kdci", CAMCORDER_QUALITY_HIGH_SPEED_4KDCI},
Lajos Molnar5e35f772021-02-06 00:33:07 -0800173
174 // Vendor-specific profiles
James Dong1d7491b2010-01-19 17:45:38 -0800175};
176
Glenn Kasten80520382014-01-31 16:49:31 -0800177#if LOG_NDEBUG
178#define UNUSED __unused
179#else
180#define UNUSED
181#endif
182
James Dong1d7491b2010-01-19 17:45:38 -0800183/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800184MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800185{
Steve Block3856b092011-10-20 11:56:00 +0100186 ALOGV("video codec:");
Lajos Molnar88e2e172022-01-14 16:03:05 -0800187 ALOGV("codec = %d (%s)", codec.mCodec,
188 findNameForTag(sVideoEncoderNameMap, NELEM(sVideoEncoderNameMap), codec.mCodec));
Steve Block3856b092011-10-20 11:56:00 +0100189 ALOGV("bit rate: %d", codec.mBitRate);
190 ALOGV("frame width: %d", codec.mFrameWidth);
191 ALOGV("frame height: %d", codec.mFrameHeight);
192 ALOGV("frame rate: %d", codec.mFrameRate);
Lajos Molnar28091432021-05-03 20:42:32 -0700193 ALOGV("profile: %d", codec.mProfile);
Lajos Molnar88e2e172022-01-14 16:03:05 -0800194 ALOGV("chroma: %s", findNameForTag(sChromaSubsamplingNameMap, NELEM(sChromaSubsamplingNameMap),
195 codec.mChromaSubsampling));
196 ALOGV("bit depth: %d", codec.mBitDepth);
197 ALOGV("hdr format: %s", findNameForTag(sHdrFormatNameMap, NELEM(sHdrFormatNameMap),
198 codec.mHdrFormat));
James Dong1d7491b2010-01-19 17:45:38 -0800199}
200
201/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800202MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800203{
Steve Block3856b092011-10-20 11:56:00 +0100204 ALOGV("audio codec:");
205 ALOGV("codec = %d", codec.mCodec);
206 ALOGV("bit rate: %d", codec.mBitRate);
207 ALOGV("sample rate: %d", codec.mSampleRate);
208 ALOGV("number of channels: %d", codec.mChannels);
Lajos Molnar28091432021-05-03 20:42:32 -0700209 ALOGV("profile: %d", codec.mProfile);
James Dong1d7491b2010-01-19 17:45:38 -0800210}
211
212/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800213MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800214{
Steve Block3856b092011-10-20 11:56:00 +0100215 ALOGV("video encoder cap:");
216 ALOGV("codec = %d", cap.mCodec);
217 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
218 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
219 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
220 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800221}
222
223/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800224MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800225{
Steve Block3856b092011-10-20 11:56:00 +0100226 ALOGV("audio encoder cap:");
227 ALOGV("codec = %d", cap.mCodec);
228 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
229 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
230 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800231}
232
233/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800234MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800235{
Steve Block3856b092011-10-20 11:56:00 +0100236 ALOGV("video decoder cap:");
237 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800238}
239
240/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800241MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800242{
Steve Block3856b092011-10-20 11:56:00 +0100243 ALOGV("audio codec cap:");
244 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800245}
246
247/*static*/ int
Glenn Kastenb187de12014-12-30 08:18:15 -0800248MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings,
249 const char *name)
James Dong1d7491b2010-01-19 17:45:38 -0800250{
251 int tag = -1;
252 for (size_t i = 0; i < nMappings; ++i) {
253 if (!strcmp(map[i].name, name)) {
254 tag = map[i].tag;
255 break;
256 }
257 }
258 return tag;
259}
260
Lajos Molnar88e2e172022-01-14 16:03:05 -0800261/*static*/ const char *
262MediaProfiles::findNameForTag(
263 const MediaProfiles::NameToTagMap *map, size_t nMappings, int tag, const char *def_)
264{
265 for (size_t i = 0; i < nMappings; ++i) {
266 if (map[i].tag == tag) {
267 return map[i].name;
268 }
269 }
270 return def_;
271}
272
273/*static*/ bool
274MediaProfiles::detectAdvancedVideoProfile(
275 video_encoder codec, int profile,
276 chroma_subsampling *chroma, int *bitDepth, hdr_format *hdr)
277{
278 // default values
279 *chroma = CHROMA_SUBSAMPLING_YUV_420;
280 *bitDepth = 8;
281 *hdr = HDR_FORMAT_NONE;
282
283 switch (codec) {
284 case VIDEO_ENCODER_H263:
285 case VIDEO_ENCODER_MPEG_4_SP:
286 case VIDEO_ENCODER_VP8:
287 // these are always 4:2:0 SDR 8-bit
288 return true;
289
290 case VIDEO_ENCODER_H264:
291 switch (profile) {
292 case AVCProfileBaseline:
293 case AVCProfileConstrainedBaseline:
294 case AVCProfileMain:
295 case AVCProfileExtended:
296 case AVCProfileHigh:
297 case AVCProfileConstrainedHigh:
298 return true;
299 case AVCProfileHigh10:
300 // returning false here as this could be an HLG stream
301 *bitDepth = 10;
302 return false;
303 case AVCProfileHigh422:
304 *chroma = CHROMA_SUBSAMPLING_YUV_422;
305 // returning false here as bit-depth could be 8 or 10
306 return false;
307 case AVCProfileHigh444:
308 *chroma = CHROMA_SUBSAMPLING_YUV_444;
309 // returning false here as bit-depth could be 8 or 10
310 return false;
311 default:
312 return false;
313 }
314 // flow does not get here
315
316 case VIDEO_ENCODER_HEVC:
317 switch (profile) {
318 case HEVCProfileMain:
319 return true;
320 case HEVCProfileMain10:
321 *bitDepth = 10;
322 // returning false here as this could be an HLG stream
323 return false;
324 case HEVCProfileMain10HDR10:
325 *bitDepth = 10;
326 *hdr = HDR_FORMAT_HDR10;
327 return true;
328 case HEVCProfileMain10HDR10Plus:
329 *bitDepth = 10;
330 *hdr = HDR_FORMAT_HDR10PLUS;
331 return true;
332 default:
333 return false;
334 }
335 // flow does not get here
336
337 case VIDEO_ENCODER_VP9:
338 switch (profile) {
339 case VP9Profile0:
340 return true;
341 case VP9Profile2:
342 // this is always 10-bit on Android */
343 *bitDepth = 10;
344 // returning false here as this could be an HLG stream
345 return false;
346 case VP9Profile2HDR:
347 // this is always 10-bit on Android */
348 *bitDepth = 10;
349 *hdr = HDR_FORMAT_HDR10;
350 return true;
351 case VP9Profile2HDR10Plus:
352 *bitDepth = 10;
353 *hdr = HDR_FORMAT_HDR10PLUS;
354 return true;
355 default:
356 return false;
357 }
358 // flow does not get here
359
360 case VIDEO_ENCODER_DOLBY_VISION:
361 {
362 // for Dolby Vision codec we always assume 10-bit DV
363 *bitDepth = 10;
364 *hdr = HDR_FORMAT_DOLBY_VISION;
365
366 switch (profile) {
367 case DolbyVisionProfileDvheDer /* profile 2 deprecated */:
368 case DolbyVisionProfileDvheDen /* profile 3 deprecated */:
369 case DolbyVisionProfileDvavPer /* profile 0 deprecated */:
370 case DolbyVisionProfileDvavPen /* profile 1 deprecated */:
371 case DolbyVisionProfileDvheDtr /* dvhe.04 */:
372 case DolbyVisionProfileDvheStn /* dvhe.05 */:
373 case DolbyVisionProfileDvheDth /* profile 6 deprecated */:
374 case DolbyVisionProfileDvheDtb /* dvhe.07 */:
375 case DolbyVisionProfileDvheSt /* dvhe.08 */:
376 case DolbyVisionProfileDvavSe /* dvav.09 */:
377 case DolbyVisionProfileDvav110 /* dvav1.10 */:
378 return true;
379 default:
380 return false;
381 }
382 // flow does not get here
383 }
384
385 case VIDEO_ENCODER_AV1:
386 switch (profile) {
387 case AV1ProfileMain10:
388 *bitDepth = 10;
389 // returning false here as this could be an HLG stream
390 return false;
391 case AV1ProfileMain10HDR10:
392 *bitDepth = 10;
393 *hdr = HDR_FORMAT_HDR10;
394 return true;
395 case AV1ProfileMain10HDR10Plus:
396 *bitDepth = 10;
397 *hdr = HDR_FORMAT_HDR10PLUS;
398 return true;
399 default:
400 return false;
401 }
402 // flow does not get here
403
404 default:
405 return false;
406 }
407 // flow does not get here
408}
409
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700410/*static*/ void
Lajos Molnar28091432021-05-03 20:42:32 -0700411MediaProfiles::createVideoCodec(const char **atts, size_t natts, MediaProfiles *profiles)
James Dong1d7491b2010-01-19 17:45:38 -0800412{
Lajos Molnar28091432021-05-03 20:42:32 -0700413 CHECK(natts >= 10 &&
414 !strcmp("codec", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800415 !strcmp("bitRate", atts[2]) &&
416 !strcmp("width", atts[4]) &&
417 !strcmp("height", atts[6]) &&
418 !strcmp("frameRate", atts[8]));
419
420 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
421 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700422 if (codec == -1) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700423 ALOGE("MediaProfiles::createVideoCodec failed to locate codec %s", atts[1]);
424 return;
Alex Zhang032f7a12020-04-17 16:08:24 -0700425 }
James Dong1d7491b2010-01-19 17:45:38 -0800426
Lajos Molnar28091432021-05-03 20:42:32 -0700427 int profile = -1;
Lajos Molnar88e2e172022-01-14 16:03:05 -0800428 chroma_subsampling chroma = CHROMA_SUBSAMPLING_YUV_420;
429 int bitDepth = 8;
430 hdr_format hdr = HDR_FORMAT_NONE;
431 if (codec == VIDEO_ENCODER_DOLBY_VISION) {
432 bitDepth = 10;
433 hdr = HDR_FORMAT_DOLBY_VISION;
Lajos Molnar28091432021-05-03 20:42:32 -0700434 }
435
Lajos Molnar88e2e172022-01-14 16:03:05 -0800436 if (natts >= 12 && !strcmp("profile", atts[10])) {
437 profile = atoi(atts[11]);
438 if (!detectAdvancedVideoProfile(
439 (video_encoder)codec, profile, &chroma, &bitDepth, &hdr)) {
440 // if not detected read values from the attributes
441 for (size_t ix = 12; natts >= ix + 2; ix += 2) {
442 if (!strcmp("chroma", atts[ix])) {
443 int chromaTag = findTagForName(sChromaSubsamplingNameMap,
444 NELEM(sChromaSubsamplingNameMap), atts[ix + 1]);
445 if (chromaTag == -1) {
446 ALOGE("MediaProfiles::createVideoCodec invalid chroma %s", atts[ix + 1]);
447 return;
448 } else {
449 chroma = (chroma_subsampling)chromaTag;
450 }
451 } else if (!strcmp("bitDepth", atts[ix])) {
452 bitDepth = atoi(atts[ix + 1]);
453 if (bitDepth < 8 || bitDepth > 16) {
454 ALOGE("MediaProfiles::createVideoCodec invalid bidDepth %s", atts[ix + 1]);
455 return;
456 }
457 } else if (!strcmp("hdr", atts[ix])) {
458 int hdrTag = findTagForName(sHdrFormatNameMap,
459 NELEM(sHdrFormatNameMap), atts[ix + 1]);
460 if (hdrTag == -1) {
461 ALOGE("MediaProfiles::createVideoCodec invalid hdr %s", atts[ix + 1]);
462 return;
463 } else {
464 hdr = (hdr_format)hdrTag;
465 }
466 } else {
467 // ignoring here. TODO: rewrite this whole file to ignore invalid attrs
468 ALOGD("MediaProfiles::createVideoCodec ignoring invalid attr %s", atts[ix]);
469 }
470 }
471 }
472 }
473
474 VideoCodec videoCodec{
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700475 static_cast<video_encoder>(codec),
Lajos Molnar88e2e172022-01-14 16:03:05 -0800476 atoi(atts[3]) /* bitRate */, atoi(atts[5]) /* width */, atoi(atts[7]) /* height */,
477 atoi(atts[9]) /* frameRate */, profile, chroma, bitDepth, hdr };
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700478 logVideoCodec(videoCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800479
480 size_t nCamcorderProfiles;
481 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700482 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodecs.emplace_back(videoCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800483}
484
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700485/*static*/ void
Lajos Molnar28091432021-05-03 20:42:32 -0700486MediaProfiles::createAudioCodec(const char **atts, size_t natts, MediaProfiles *profiles)
James Dong1d7491b2010-01-19 17:45:38 -0800487{
Lajos Molnar28091432021-05-03 20:42:32 -0700488 CHECK(natts >= 8 &&
489 !strcmp("codec", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800490 !strcmp("bitRate", atts[2]) &&
491 !strcmp("sampleRate", atts[4]) &&
492 !strcmp("channels", atts[6]));
493 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
494 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700495 if (codec == -1) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700496 ALOGE("MediaProfiles::createAudioCodec failed to locate codec %s", atts[1]);
497 return;
Alex Zhang032f7a12020-04-17 16:08:24 -0700498 }
James Dong1d7491b2010-01-19 17:45:38 -0800499
Lajos Molnar28091432021-05-03 20:42:32 -0700500 int profile = -1;
501 if (natts >= 10 && !strcmp("profile", atts[8])) {
502 profile = atoi(atts[9]);
503 }
504
505 AudioCodec audioCodec{
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700506 static_cast<audio_encoder>(codec),
Lajos Molnar28091432021-05-03 20:42:32 -0700507 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), profile };
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700508 logAudioCodec(audioCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800509
510 size_t nCamcorderProfiles;
511 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700512 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodecs.emplace_back(audioCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800513}
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700514
James Dong1d7491b2010-01-19 17:45:38 -0800515/*static*/ MediaProfiles::AudioDecoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700516MediaProfiles::createAudioDecoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800517{
Lajos Molnar28091432021-05-03 20:42:32 -0700518 CHECK(natts >= 4 &&
519 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800520 !strcmp("enabled", atts[2]));
521
522 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
523 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700524 if (codec == -1) {
525 ALOGE("MediaProfiles::createAudioDecoderCap failed to locate codec %s", atts[1]);
526 return nullptr;
527 }
James Dong1d7491b2010-01-19 17:45:38 -0800528
529 MediaProfiles::AudioDecoderCap *cap =
530 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
531 logAudioDecoderCap(*cap);
532 return cap;
533}
534
535/*static*/ MediaProfiles::VideoDecoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700536MediaProfiles::createVideoDecoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800537{
Lajos Molnar28091432021-05-03 20:42:32 -0700538 CHECK(natts >= 4 &&
539 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800540 !strcmp("enabled", atts[2]));
541
542 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
543 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700544 if (codec == -1) {
545 ALOGE("MediaProfiles::createVideoDecoderCap failed to locate codec %s", atts[1]);
546 return nullptr;
547 }
James Dong1d7491b2010-01-19 17:45:38 -0800548
549 MediaProfiles::VideoDecoderCap *cap =
550 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
551 logVideoDecoderCap(*cap);
552 return cap;
553}
554
555/*static*/ MediaProfiles::VideoEncoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700556MediaProfiles::createVideoEncoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800557{
Lajos Molnar28091432021-05-03 20:42:32 -0700558 CHECK(natts >= 20 &&
559 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800560 !strcmp("enabled", atts[2]) &&
561 !strcmp("minBitRate", atts[4]) &&
562 !strcmp("maxBitRate", atts[6]) &&
563 !strcmp("minFrameWidth", atts[8]) &&
564 !strcmp("maxFrameWidth", atts[10]) &&
565 !strcmp("minFrameHeight", atts[12]) &&
566 !strcmp("maxFrameHeight", atts[14]) &&
567 !strcmp("minFrameRate", atts[16]) &&
568 !strcmp("maxFrameRate", atts[18]));
569
570 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
571 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700572 if (codec == -1) {
573 ALOGE("MediaProfiles::createVideoEncoderCap failed to locate codec %s", atts[1]);
574 return nullptr;
575 }
James Dong1d7491b2010-01-19 17:45:38 -0800576
577 MediaProfiles::VideoEncoderCap *cap =
578 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
579 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
580 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
581 logVideoEncoderCap(*cap);
582 return cap;
583}
584
585/*static*/ MediaProfiles::AudioEncoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700586MediaProfiles::createAudioEncoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800587{
Lajos Molnar28091432021-05-03 20:42:32 -0700588 CHECK(natts >= 16 &&
589 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800590 !strcmp("enabled", atts[2]) &&
591 !strcmp("minBitRate", atts[4]) &&
592 !strcmp("maxBitRate", atts[6]) &&
593 !strcmp("minSampleRate", atts[8]) &&
594 !strcmp("maxSampleRate", atts[10]) &&
595 !strcmp("minChannels", atts[12]) &&
596 !strcmp("maxChannels", atts[14]));
597
598 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
599 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700600 if (codec == -1) {
601 ALOGE("MediaProfiles::createAudioEncoderCap failed to locate codec %s", atts[1]);
602 return nullptr;
603 }
James Dong1d7491b2010-01-19 17:45:38 -0800604
605 MediaProfiles::AudioEncoderCap *cap =
Glenn Kastenb187de12014-12-30 08:18:15 -0800606 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]),
607 atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15]));
James Dong1d7491b2010-01-19 17:45:38 -0800608 logAudioEncoderCap(*cap);
609 return cap;
610}
611
612/*static*/ output_format
Lajos Molnar28091432021-05-03 20:42:32 -0700613MediaProfiles::createEncoderOutputFileFormat(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800614{
Lajos Molnar28091432021-05-03 20:42:32 -0700615 CHECK(natts >= 2 &&
616 !strcmp("name", atts[0]));
James Dong1d7491b2010-01-19 17:45:38 -0800617
618 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
619 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
620 CHECK(format != -1);
621
622 return static_cast<output_format>(format);
623}
624
James Dong2a7e0a12011-02-28 21:07:39 -0800625static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
626 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
627 if (cameraId == cameraIds[i]) {
628 return true;
629 }
630 }
631 return false;
632}
633
James Dong1d7491b2010-01-19 17:45:38 -0800634/*static*/ MediaProfiles::CamcorderProfile*
Lajos Molnar28091432021-05-03 20:42:32 -0700635MediaProfiles::createCamcorderProfile(
636 int cameraId, const char **atts, size_t natts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800637{
Lajos Molnar28091432021-05-03 20:42:32 -0700638 CHECK(natts >= 6 &&
639 !strcmp("quality", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800640 !strcmp("fileFormat", atts[2]) &&
641 !strcmp("duration", atts[4]));
642
Glenn Kastenb187de12014-12-30 08:18:15 -0800643 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/
644 sizeof(sCamcorderQualityNameMap[0]);
James Dong1d7491b2010-01-19 17:45:38 -0800645 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700646 if (quality == -1) {
647 ALOGE("MediaProfiles::createCamcorderProfile failed to locate quality %s", atts[1]);
648 return nullptr;
649 }
James Dong1d7491b2010-01-19 17:45:38 -0800650
651 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
652 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700653 if (fileFormat == -1) {
654 ALOGE("MediaProfiles::createCamcorderProfile failed to locate file format %s", atts[1]);
655 return nullptr;
656 }
James Dong1d7491b2010-01-19 17:45:38 -0800657
658 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800659 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800660 if (!isCameraIdFound(cameraId, cameraIds)) {
661 cameraIds.add(cameraId);
662 }
James Dong1d7491b2010-01-19 17:45:38 -0800663 profile->mFileFormat = static_cast<output_format>(fileFormat);
664 profile->mQuality = static_cast<camcorder_quality>(quality);
665 profile->mDuration = atoi(atts[5]);
666 return profile;
667}
668
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800669MediaProfiles::ImageEncodingQualityLevels*
670MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
671{
672 int n = mImageEncodingQualityLevels.size();
673 for (int i = 0; i < n; i++) {
674 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
675 if (levels->mCameraId == cameraId) {
676 return levels;
677 }
678 }
679 return NULL;
680}
681
Lajos Molnar28091432021-05-03 20:42:32 -0700682void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts, size_t natts)
James Dongf5a83852010-02-23 17:21:44 -0800683{
Lajos Molnar28091432021-05-03 20:42:32 -0700684 CHECK(natts >= 2 &&
685 !strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800686 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800687 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800688 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
689
690 if (levels == NULL) {
691 levels = new ImageEncodingQualityLevels();
692 levels->mCameraId = cameraId;
693 mImageEncodingQualityLevels.add(levels);
694 }
695
696 levels->mLevels.add(quality);
697}
698
699/*static*/ int
Lajos Molnar28091432021-05-03 20:42:32 -0700700MediaProfiles::getCameraId(const char** atts, size_t natts)
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800701{
702 if (!atts[0]) return 0; // default cameraId = 0
Lajos Molnar28091432021-05-03 20:42:32 -0700703 CHECK(natts >= 2 &&
704 !strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800705 return atoi(atts[1]);
706}
707
Lajos Molnar28091432021-05-03 20:42:32 -0700708void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts, size_t natts)
James Dong0f056292011-05-09 18:49:31 -0700709{
Eric Laurentb1eb1a02012-10-22 17:44:24 -0700710 int offsetTimeMs = 1000;
Lajos Molnar28091432021-05-03 20:42:32 -0700711 if (natts >= 3 && atts[2]) {
712 CHECK(natts >= 4 && !strcmp("startOffsetMs", atts[2]));
James Dong0f056292011-05-09 18:49:31 -0700713 offsetTimeMs = atoi(atts[3]);
714 }
715
Steve Block3856b092011-10-20 11:56:00 +0100716 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700717 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
718}
Hong Tengcabd5f82011-07-06 18:33:09 -0700719
James Dong1d7491b2010-01-19 17:45:38 -0800720/*static*/ void
721MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
722{
Lajos Molnar28091432021-05-03 20:42:32 -0700723 // determine number of attributes
724 size_t natts = 0;
725 while (atts[natts]) {
726 ++natts;
727 }
728
729 MediaProfiles *profiles = (MediaProfiles *)userData;
James Dong1d7491b2010-01-19 17:45:38 -0800730 if (strcmp("Video", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700731 createVideoCodec(atts, natts, profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800732 } else if (strcmp("Audio", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700733 createAudioCodec(atts, natts, profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800734 } else if (strcmp("VideoEncoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700735 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800736 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700737 MediaProfiles::VideoEncoderCap* cap = createVideoEncoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700738 if (cap != nullptr) {
739 profiles->mVideoEncoders.add(cap);
740 }
James Dong1d7491b2010-01-19 17:45:38 -0800741 } else if (strcmp("AudioEncoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700742 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800743 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700744 MediaProfiles::AudioEncoderCap* cap = createAudioEncoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700745 if (cap != nullptr) {
746 profiles->mAudioEncoders.add(cap);
747 }
James Dong1d7491b2010-01-19 17:45:38 -0800748 } else if (strcmp("VideoDecoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700749 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800750 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700751 MediaProfiles::VideoDecoderCap* cap = createVideoDecoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700752 if (cap != nullptr) {
753 profiles->mVideoDecoders.add(cap);
754 }
James Dong1d7491b2010-01-19 17:45:38 -0800755 } else if (strcmp("AudioDecoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700756 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800757 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700758 MediaProfiles::AudioDecoderCap* cap = createAudioDecoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700759 if (cap != nullptr) {
760 profiles->mAudioDecoders.add(cap);
761 }
James Dong1d7491b2010-01-19 17:45:38 -0800762 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700763 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts, natts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800764 } else if (strcmp("CamcorderProfiles", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700765 profiles->mCurrentCameraId = getCameraId(atts, natts);
766 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts, natts);
James Dong1d7491b2010-01-19 17:45:38 -0800767 } else if (strcmp("EncoderProfile", name) == 0) {
Alex Zhang032f7a12020-04-17 16:08:24 -0700768 MediaProfiles::CamcorderProfile* profile = createCamcorderProfile(
Lajos Molnar28091432021-05-03 20:42:32 -0700769 profiles->mCurrentCameraId, atts, natts, profiles->mCameraIds);
Alex Zhang032f7a12020-04-17 16:08:24 -0700770 if (profile != nullptr) {
771 profiles->mCamcorderProfiles.add(profile);
772 }
James Dongf5a83852010-02-23 17:21:44 -0800773 } else if (strcmp("ImageEncoding", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700774 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts, natts);
James Dong1d7491b2010-01-19 17:45:38 -0800775 }
776}
777
James Dong2a7e0a12011-02-28 21:07:39 -0800778static bool isCamcorderProfile(camcorder_quality quality) {
779 return quality >= CAMCORDER_QUALITY_LIST_START &&
780 quality <= CAMCORDER_QUALITY_LIST_END;
781}
782
783static bool isTimelapseProfile(camcorder_quality quality) {
784 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
785 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
786}
787
Zhijun Hee0790972014-07-23 15:17:26 -0700788static bool isHighSpeedProfile(camcorder_quality quality) {
789 return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
790 quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END;
791}
792
James Dong2a7e0a12011-02-28 21:07:39 -0800793void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700794 ALOGV("Number of camera ids: %zu", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800795 CHECK(cameraIds.size() > 0);
796 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
797 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
798 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
799 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
800 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
801 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
802 if ((j & 1) == 0) { // low resolution
803 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
804 } else { // high resolution
805 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
806 }
807 }
808 }
809}
810
811int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
812 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
813 if (mCameraIds[i] == cameraId) {
814 return i;
815 }
816 }
817 return -1;
818}
819
820void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
821 if (sIsInitialized) {
822 return;
823 }
824
825 initRequiredProfileRefs(mCameraIds);
826
827 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700828 // ensure at least one video and audio profile is added
Lajos Molnar28091432021-05-03 20:42:32 -0700829 if (mCamcorderProfiles[i]->mVideoCodecs.empty()) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700830 mCamcorderProfiles[i]->mVideoCodecs.emplace_back(
831 VIDEO_ENCODER_H263, 192000 /* bitrate */,
832 176 /* width */, 144 /* height */, 20 /* frameRate */);
833 }
Lajos Molnar28091432021-05-03 20:42:32 -0700834 if (mCamcorderProfiles[i]->mAudioCodecs.empty()) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700835 mCamcorderProfiles[i]->mAudioCodecs.emplace_back(
836 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
837 8000 /* sampleRate */, 1 /* channels */);
838 }
839
840 int product = mCamcorderProfiles[i]->mVideoCodecs[0].mFrameWidth *
841 mCamcorderProfiles[i]->mVideoCodecs[0].mFrameHeight;
James Dong2a7e0a12011-02-28 21:07:39 -0800842
843 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
844 int cameraId = mCamcorderProfiles[i]->mCameraId;
845 int index = -1;
846 int refIndex = getRequiredProfileRefIndex(cameraId);
847 CHECK(refIndex != -1);
848 RequiredProfileRefInfo *info;
849 camcorder_quality refQuality;
James Dong2a7e0a12011-02-28 21:07:39 -0800850
Zhijun Hee0790972014-07-23 15:17:26 -0700851 // Check high and low from either camcorder profile, timelapse profile
852 // or high speed profile, but not all of them. Default, check camcorder profile
James Dong2a7e0a12011-02-28 21:07:39 -0800853 size_t j = 0;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200854 size_t o = 2;
James Dong2a7e0a12011-02-28 21:07:39 -0800855 if (isTimelapseProfile(quality)) {
856 // Check timelapse profile instead.
857 j = 2;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200858 o = kNumRequiredProfiles;
Zhijun Hee0790972014-07-23 15:17:26 -0700859 } else if (isHighSpeedProfile(quality)) {
860 // Skip the check for high speed profile.
861 continue;
James Dong2a7e0a12011-02-28 21:07:39 -0800862 } else {
863 // Must be camcorder profile.
864 CHECK(isCamcorderProfile(quality));
865 }
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200866 for (; j < o; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800867 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
868 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
869 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
870 continue;
871 }
872 switch (j) {
873 case 0:
874 refQuality = CAMCORDER_QUALITY_LOW;
875 break;
876 case 1:
877 refQuality = CAMCORDER_QUALITY_HIGH;
878 break;
879 case 2:
880 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
881 break;
882 case 3:
883 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
884 break;
885 default:
886 CHECK(!"Should never reach here");
887 }
888
889 if (!info->mHasRefProfile) {
890 index = getCamcorderProfileIndex(cameraId, refQuality);
891 }
892 if (index == -1) {
893 // New high or low quality profile is found.
894 // Update its reference.
895 info->mHasRefProfile = true;
896 info->mRefProfileIndex = i;
897 info->mResolutionProduct = product;
898 }
899 }
900 }
901
Roman Kiryanovfb42ae82023-02-17 23:12:11 -0800902 for (size_t refIndex = 0; refIndex < mCameraIds.size(); ++refIndex) {
903 const int cameraId = mCameraIds[refIndex];
James Dong2a7e0a12011-02-28 21:07:39 -0800904 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800905 RequiredProfileRefInfo *info =
906 &mRequiredProfileRefs[refIndex].mRefs[j];
907
908 if (info->mHasRefProfile) {
909
George Burgess IV215545b2018-07-25 10:06:30 -0700910 std::unique_ptr<CamcorderProfile> profile =
911 std::make_unique<CamcorderProfile>(
James Dong2a7e0a12011-02-28 21:07:39 -0800912 *mCamcorderProfiles[info->mRefProfileIndex]);
913
914 // Overwrite the quality
915 switch (j % kNumRequiredProfiles) {
916 case 0:
917 profile->mQuality = CAMCORDER_QUALITY_LOW;
918 break;
919 case 1:
920 profile->mQuality = CAMCORDER_QUALITY_HIGH;
921 break;
922 case 2:
923 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
924 break;
925 case 3:
926 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
927 break;
928 default:
929 CHECK(!"Should never come here");
930 }
931
932 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
933 if (index != -1) {
Roman Kiryanovfb42ae82023-02-17 23:12:11 -0800934 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800935 profile->mQuality, cameraId);
936 CHECK(index == refIndex);
937 continue;
938 }
939
940 // Insert the new profile
Roman Kiryanovfb42ae82023-02-17 23:12:11 -0800941 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800942 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
943 profile->mQuality, cameraId);
944
George Burgess IV215545b2018-07-25 10:06:30 -0700945 mCamcorderProfiles.add(profile.release());
James Dong2a7e0a12011-02-28 21:07:39 -0800946 }
947 }
948 }
949}
950
James Dong1d7491b2010-01-19 17:45:38 -0800951/*static*/ MediaProfiles*
952MediaProfiles::getInstance()
953{
Steve Block3856b092011-10-20 11:56:00 +0100954 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800955 Mutex::Autolock lock(sLock);
956 if (!sIsInitialized) {
957 char value[PROPERTY_VALUE_MAX];
958 if (property_get("media.settings.xml", value, NULL) <= 0) {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700959 const char* xmlFile = nullptr;
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -0800960 for (auto const& f : getXmlPaths()) {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700961 if (checkXmlFile(f)) {
962 xmlFile = f;
963 break;
964 }
965 }
966 if (xmlFile == nullptr) {
967 ALOGW("Could not find a validated xml file. "
968 "Using the default instance instead.");
James Dong1d7491b2010-01-19 17:45:38 -0800969 sInstance = createDefaultInstance();
970 } else {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700971 sInstance = createInstanceFromXmlFile(xmlFile);
James Dong1d7491b2010-01-19 17:45:38 -0800972 }
973 } else {
974 sInstance = createInstanceFromXmlFile(value);
975 }
James Dong2a7e0a12011-02-28 21:07:39 -0800976 CHECK(sInstance != NULL);
977 sInstance->checkAndAddRequiredProfilesIfNecessary();
978 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800979 }
980
981 return sInstance;
982}
983
984/*static*/ MediaProfiles::VideoEncoderCap*
985MediaProfiles::createDefaultH263VideoEncoderCap()
986{
987 return new MediaProfiles::VideoEncoderCap(
988 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
989}
990
991/*static*/ MediaProfiles::VideoEncoderCap*
992MediaProfiles::createDefaultM4vVideoEncoderCap()
993{
994 return new MediaProfiles::VideoEncoderCap(
995 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
996}
997
998
999/*static*/ void
1000MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
1001{
1002 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
1003 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
1004}
1005
1006/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001007MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001008{
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001009 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
1010 profile->mCameraId = 0;
1011 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001012 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001013 profile->mDuration = 60;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001014 profile->mVideoCodecs.emplace_back(
1015 VIDEO_ENCODER_H263, 1000000 /* bitrate */,
1016 176 /* width */, 144 /* height */, 20 /* frameRate */);
1017 profile->mAudioCodecs.emplace_back(
1018 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1019 8000 /* sampleRate */, 1 /* channels */);
1020
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001021 return profile;
1022}
1023
1024/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001025MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -08001026{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001027 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
1028 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -08001029 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001030 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -08001031 profile->mDuration = 60;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001032 profile->mVideoCodecs.emplace_back(
1033 VIDEO_ENCODER_H263, 20000000 /* bitrate */,
1034 720 /* width */, 480 /* height */, 20 /* frameRate */);
1035 profile->mAudioCodecs.emplace_back(
1036 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1037 8000 /* sampleRate */, 1 /* channels */);
James Dong1d7491b2010-01-19 17:45:38 -08001038 return profile;
1039}
1040
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001041/*static*/ void
1042MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
1043 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
1044 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -08001045 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
1046 CAMCORDER_QUALITY_TIME_LAPSE_LOW);
1047 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
1048 CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001049}
1050
1051/*static*/ void
1052MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
1053 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
1054 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -08001055 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
1056 CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
1057 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
1058 CAMCORDER_QUALITY_TIME_LAPSE_480P);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001059}
1060
James Dong1d7491b2010-01-19 17:45:38 -08001061/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001062MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -08001063{
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001064 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001065 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -08001066 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001067 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -08001068 profile->mDuration = 30;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001069 profile->mVideoCodecs.emplace_back(
1070 VIDEO_ENCODER_H263, 192000 /* bitrate */,
1071 176 /* width */, 144 /* height */, 20 /* frameRate */);
1072 profile->mAudioCodecs.emplace_back(
1073 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1074 8000 /* sampleRate */, 1 /* channels */);
James Dong1d7491b2010-01-19 17:45:38 -08001075 return profile;
1076}
1077
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001078/*static*/ MediaProfiles::CamcorderProfile*
1079MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
1080{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001081 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
1082 profile->mCameraId = 0;
1083 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
1084 profile->mQuality = quality;
1085 profile->mDuration = 60;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001086 profile->mVideoCodecs.emplace_back(
1087 VIDEO_ENCODER_H263, 360000 /* bitrate */,
1088 352 /* width */, 288 /* height */, 20 /* frameRate */);
1089 profile->mAudioCodecs.emplace_back(
1090 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1091 8000 /* sampleRate */, 1 /* channels */);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001092 return profile;
1093}
1094
1095/*static*/ void
1096MediaProfiles::createDefaultCamcorderLowProfiles(
1097 MediaProfiles::CamcorderProfile **lowProfile,
1098 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
1099 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
1100 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
1101}
1102
1103/*static*/ void
1104MediaProfiles::createDefaultCamcorderHighProfiles(
1105 MediaProfiles::CamcorderProfile **highProfile,
1106 MediaProfiles::CamcorderProfile **highSpecificProfile) {
1107 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
1108 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
1109}
1110
James Dong1d7491b2010-01-19 17:45:38 -08001111/*static*/ void
1112MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
1113{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001114 // low camcorder profiles.
1115 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
1116 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
1117 profiles->mCamcorderProfiles.add(lowProfile);
1118 profiles->mCamcorderProfiles.add(lowSpecificProfile);
1119
1120 // high camcorder profiles.
1121 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
1122 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
1123 profiles->mCamcorderProfiles.add(highProfile);
1124 profiles->mCamcorderProfiles.add(highSpecificProfile);
1125
1126 // low camcorder time lapse profiles.
1127 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
1128 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
1129 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
1130 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
1131
1132 // high camcorder time lapse profiles.
1133 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
Glenn Kastenb187de12014-12-30 08:18:15 -08001134 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile,
1135 &highSpecificTimeLapseProfile);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001136 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
1137 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -07001138
1139 // For emulator and other legacy devices which does not have a
1140 // media_profiles.xml file, We assume that the default camera id
1141 // is 0 and that is the only camera available.
1142 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -08001143}
1144
1145/*static*/ void
1146MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
1147{
1148 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
1149}
1150
1151/*static*/ void
1152MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
1153{
1154 MediaProfiles::VideoDecoderCap *cap =
1155 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
1156
1157 profiles->mVideoDecoders.add(cap);
1158}
1159
1160/*static*/ void
1161MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
1162{
1163 MediaProfiles::AudioDecoderCap *cap =
1164 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
1165
1166 profiles->mAudioDecoders.add(cap);
1167}
1168
1169/*static*/ void
1170MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
1171{
1172 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
1173 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
1174}
1175
1176/*static*/ MediaProfiles::AudioEncoderCap*
1177MediaProfiles::createDefaultAmrNBEncoderCap()
1178{
1179 return new MediaProfiles::AudioEncoderCap(
1180 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
1181}
1182
James Dongf5a83852010-02-23 17:21:44 -08001183/*static*/ void
1184MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
1185{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001186 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
1187 levels->mCameraId = 0;
1188 levels->mLevels.add(70);
1189 levels->mLevels.add(80);
1190 levels->mLevels.add(90);
1191 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -08001192}
1193
James Dong1d7491b2010-01-19 17:45:38 -08001194/*static*/ MediaProfiles*
1195MediaProfiles::createDefaultInstance()
1196{
1197 MediaProfiles *profiles = new MediaProfiles;
1198 createDefaultCamcorderProfiles(profiles);
1199 createDefaultVideoEncoders(profiles);
1200 createDefaultAudioEncoders(profiles);
1201 createDefaultVideoDecoders(profiles);
1202 createDefaultAudioDecoders(profiles);
1203 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -08001204 createDefaultImageEncodingQualityLevels(profiles);
James Dong1d7491b2010-01-19 17:45:38 -08001205 return profiles;
1206}
1207
Pawin Vongmasad7db05b2017-05-03 04:19:20 -07001208bool MediaProfiles::checkXmlFile(const char* xmlFile) {
1209 struct stat fStat;
1210 return stat(xmlFile, &fStat) == 0 && S_ISREG(fStat.st_mode);
1211 // TODO: Add validation
1212}
1213
James Dong1d7491b2010-01-19 17:45:38 -08001214/*static*/ MediaProfiles*
1215MediaProfiles::createInstanceFromXmlFile(const char *xml)
1216{
1217 FILE *fp = NULL;
1218 CHECK((fp = fopen(xml, "r")));
1219
1220 XML_Parser parser = ::XML_ParserCreate(NULL);
1221 CHECK(parser != NULL);
1222
1223 MediaProfiles *profiles = new MediaProfiles();
1224 ::XML_SetUserData(parser, profiles);
1225 ::XML_SetElementHandler(parser, startElementHandler, NULL);
1226
1227 /*
1228 FIXME:
1229 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
1230
1231 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +00001232 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -08001233 return UNKNOWN_ERROR;
1234 }
1235
1236 */
1237
1238 const int BUFF_SIZE = 512;
1239 for (;;) {
1240 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
1241 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001242 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -08001243 delete profiles;
1244 profiles = NULL;
1245 goto exit;
1246 }
1247
1248 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
1249 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001250 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -08001251 delete profiles;
1252 profiles = NULL;
1253 goto exit;
1254 }
1255
1256 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
1257
1258 if (bytes_read == 0) break; // done parsing the xml file
1259 }
1260
1261exit:
1262 ::XML_ParserFree(parser);
1263 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -08001264 return profiles;
1265}
1266
1267Vector<output_format> MediaProfiles::getOutputFileFormats() const
1268{
1269 return mEncoderOutputFileFormats; // copy out
1270}
1271
1272Vector<video_encoder> MediaProfiles::getVideoEncoders() const
1273{
1274 Vector<video_encoder> encoders;
1275 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1276 encoders.add(mVideoEncoders[i]->mCodec);
1277 }
1278 return encoders; // copy out
1279}
1280
1281int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
1282{
Steve Block3856b092011-10-20 11:56:00 +01001283 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001284 int index = -1;
1285 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
1286 if (mVideoEncoders[i]->mCodec == codec) {
1287 index = i;
1288 break;
1289 }
1290 }
1291 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001292 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001293 return -1;
1294 }
1295
1296 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
1297 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
1298 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
1299 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
1300 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
1301 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
1302 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
1303 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
1304
Steve Block29357bc2012-01-06 19:20:56 +00001305 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001306 return -1;
1307}
Hong Tengcabd5f82011-07-06 18:33:09 -07001308
James Dong1d7491b2010-01-19 17:45:38 -08001309Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1310{
1311 Vector<audio_encoder> encoders;
1312 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1313 encoders.add(mAudioEncoders[i]->mCodec);
1314 }
1315 return encoders; // copy out
1316}
1317
1318int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1319{
Steve Block3856b092011-10-20 11:56:00 +01001320 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001321 int index = -1;
1322 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1323 if (mAudioEncoders[i]->mCodec == codec) {
1324 index = i;
1325 break;
1326 }
1327 }
1328 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001329 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001330 return -1;
1331 }
1332
1333 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1334 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1335 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1336 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1337 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1338 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1339
Steve Block29357bc2012-01-06 19:20:56 +00001340 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001341 return -1;
1342}
1343
1344Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1345{
1346 Vector<video_decoder> decoders;
1347 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1348 decoders.add(mVideoDecoders[i]->mCodec);
1349 }
1350 return decoders; // copy out
1351}
1352
1353Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1354{
1355 Vector<audio_decoder> decoders;
1356 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1357 decoders.add(mAudioDecoders[i]->mCodec);
1358 }
1359 return decoders; // copy out
1360}
1361
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001362int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001363{
James Dong1d7491b2010-01-19 17:45:38 -08001364 int index = -1;
1365 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001366 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1367 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001368 index = i;
1369 break;
1370 }
1371 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001372 return index;
1373}
1374
Lajos Molnard64df6d2021-04-29 23:20:57 -07001375const MediaProfiles::CamcorderProfile *MediaProfiles::getCamcorderProfile(
1376 int cameraId, camcorder_quality quality) const {
1377 int index = getCamcorderProfileIndex(cameraId, quality);
1378 if (index == -1) {
1379 ALOGE("The given camcorder profile camera %d quality %d is not found",
1380 cameraId, quality);
1381 return nullptr;
1382 }
1383
1384 return mCamcorderProfiles[index];
1385}
1386
1387std::vector<const MediaProfiles::AudioCodec *>
1388MediaProfiles::CamcorderProfile::getAudioCodecs() const {
1389 std::vector<const MediaProfiles::AudioCodec *> res;
1390 for (const MediaProfiles::AudioCodec &ac : mAudioCodecs) {
1391 res.push_back(&ac);
1392 }
1393 return res;
1394}
1395
1396std::vector<const MediaProfiles::VideoCodec *>
1397MediaProfiles::CamcorderProfile::getVideoCodecs() const {
1398 std::vector<const MediaProfiles::VideoCodec *> res;
1399 for (const MediaProfiles::VideoCodec &vc : mVideoCodecs) {
1400 res.push_back(&vc);
1401 }
1402 return res;
1403}
1404
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001405int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1406 int cameraId,
1407 camcorder_quality quality) const
1408{
Steve Block3856b092011-10-20 11:56:00 +01001409 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001410 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001411
1412 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001413 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001414 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001415 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001416 return -1;
1417 }
1418
James Dongf5a83852010-02-23 17:21:44 -08001419 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001420 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001421 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mCodec;
1422 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameWidth;
1423 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameHeight;
1424 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mBitRate;
1425 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameRate;
1426 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mCodec;
1427 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mBitRate;
1428 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mChannels;
1429 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mSampleRate;
James Dong1d7491b2010-01-19 17:45:38 -08001430
Steve Block29357bc2012-01-06 19:20:56 +00001431 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001432 return -1;
1433}
1434
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001435bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1436{
1437 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1438}
1439
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001440Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001441{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001442 Vector<int> result;
1443 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1444 if (levels != NULL) {
1445 result = levels->mLevels; // copy out
1446 }
1447 return result;
James Dongf5a83852010-02-23 17:21:44 -08001448}
1449
James Dong0f056292011-05-09 18:49:31 -07001450int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1451 int offsetTimeMs = -1;
1452 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1453 if (index >= 0) {
1454 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1455 }
Steve Block3856b092011-10-20 11:56:00 +01001456 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001457 return offsetTimeMs;
1458}
1459
James Dong1d7491b2010-01-19 17:45:38 -08001460MediaProfiles::~MediaProfiles()
1461{
1462 CHECK("destructor should never be called" == 0);
1463#if 0
1464 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1465 delete mAudioEncoders[i];
1466 }
1467 mAudioEncoders.clear();
1468
1469 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1470 delete mVideoEncoders[i];
1471 }
1472 mVideoEncoders.clear();
1473
1474 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1475 delete mVideoDecoders[i];
1476 }
1477 mVideoDecoders.clear();
1478
1479 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1480 delete mAudioDecoders[i];
1481 }
1482 mAudioDecoders.clear();
1483
1484 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1485 delete mCamcorderProfiles[i];
1486 }
1487 mCamcorderProfiles.clear();
1488#endif
1489}
1490} // namespace android