blob: 5aa9adce2338764329aa27d5f8a699aa2965ce26 [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},
Zhijun Hee0790972014-07-23 15:17:26 -0700162
163 {"highspeedlow", CAMCORDER_QUALITY_HIGH_SPEED_LOW},
164 {"highspeedhigh", CAMCORDER_QUALITY_HIGH_SPEED_HIGH},
165 {"highspeed480p", CAMCORDER_QUALITY_HIGH_SPEED_480P},
166 {"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
167 {"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
Zhijun He9520aa62014-09-09 16:18:31 -0700168 {"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
Praveen Chavanb5bfa0e2019-01-16 15:49:42 -0800169 {"highspeedcif", CAMCORDER_QUALITY_HIGH_SPEED_CIF},
170 {"highspeedvga", CAMCORDER_QUALITY_HIGH_SPEED_VGA},
171 {"highspeed4kdci", CAMCORDER_QUALITY_HIGH_SPEED_4KDCI},
Lajos Molnar5e35f772021-02-06 00:33:07 -0800172
173 // Vendor-specific profiles
James Dong1d7491b2010-01-19 17:45:38 -0800174};
175
Glenn Kasten80520382014-01-31 16:49:31 -0800176#if LOG_NDEBUG
177#define UNUSED __unused
178#else
179#define UNUSED
180#endif
181
James Dong1d7491b2010-01-19 17:45:38 -0800182/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800183MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800184{
Steve Block3856b092011-10-20 11:56:00 +0100185 ALOGV("video codec:");
Lajos Molnar88e2e172022-01-14 16:03:05 -0800186 ALOGV("codec = %d (%s)", codec.mCodec,
187 findNameForTag(sVideoEncoderNameMap, NELEM(sVideoEncoderNameMap), codec.mCodec));
Steve Block3856b092011-10-20 11:56:00 +0100188 ALOGV("bit rate: %d", codec.mBitRate);
189 ALOGV("frame width: %d", codec.mFrameWidth);
190 ALOGV("frame height: %d", codec.mFrameHeight);
191 ALOGV("frame rate: %d", codec.mFrameRate);
Lajos Molnar28091432021-05-03 20:42:32 -0700192 ALOGV("profile: %d", codec.mProfile);
Lajos Molnar88e2e172022-01-14 16:03:05 -0800193 ALOGV("chroma: %s", findNameForTag(sChromaSubsamplingNameMap, NELEM(sChromaSubsamplingNameMap),
194 codec.mChromaSubsampling));
195 ALOGV("bit depth: %d", codec.mBitDepth);
196 ALOGV("hdr format: %s", findNameForTag(sHdrFormatNameMap, NELEM(sHdrFormatNameMap),
197 codec.mHdrFormat));
James Dong1d7491b2010-01-19 17:45:38 -0800198}
199
200/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800201MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800202{
Steve Block3856b092011-10-20 11:56:00 +0100203 ALOGV("audio codec:");
204 ALOGV("codec = %d", codec.mCodec);
205 ALOGV("bit rate: %d", codec.mBitRate);
206 ALOGV("sample rate: %d", codec.mSampleRate);
207 ALOGV("number of channels: %d", codec.mChannels);
Lajos Molnar28091432021-05-03 20:42:32 -0700208 ALOGV("profile: %d", codec.mProfile);
James Dong1d7491b2010-01-19 17:45:38 -0800209}
210
211/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800212MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800213{
Steve Block3856b092011-10-20 11:56:00 +0100214 ALOGV("video encoder cap:");
215 ALOGV("codec = %d", cap.mCodec);
216 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
217 ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
218 ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
219 ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
James Dong1d7491b2010-01-19 17:45:38 -0800220}
221
222/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800223MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800224{
Steve Block3856b092011-10-20 11:56:00 +0100225 ALOGV("audio encoder cap:");
226 ALOGV("codec = %d", cap.mCodec);
227 ALOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
228 ALOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
229 ALOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
James Dong1d7491b2010-01-19 17:45:38 -0800230}
231
232/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800233MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800234{
Steve Block3856b092011-10-20 11:56:00 +0100235 ALOGV("video decoder cap:");
236 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800237}
238
239/*static*/ void
Glenn Kasten80520382014-01-31 16:49:31 -0800240MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
James Dong1d7491b2010-01-19 17:45:38 -0800241{
Steve Block3856b092011-10-20 11:56:00 +0100242 ALOGV("audio codec cap:");
243 ALOGV("codec = %d", cap.mCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800244}
245
246/*static*/ int
Glenn Kastenb187de12014-12-30 08:18:15 -0800247MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings,
248 const char *name)
James Dong1d7491b2010-01-19 17:45:38 -0800249{
250 int tag = -1;
251 for (size_t i = 0; i < nMappings; ++i) {
252 if (!strcmp(map[i].name, name)) {
253 tag = map[i].tag;
254 break;
255 }
256 }
257 return tag;
258}
259
Lajos Molnar88e2e172022-01-14 16:03:05 -0800260/*static*/ const char *
261MediaProfiles::findNameForTag(
262 const MediaProfiles::NameToTagMap *map, size_t nMappings, int tag, const char *def_)
263{
264 for (size_t i = 0; i < nMappings; ++i) {
265 if (map[i].tag == tag) {
266 return map[i].name;
267 }
268 }
269 return def_;
270}
271
272/*static*/ bool
273MediaProfiles::detectAdvancedVideoProfile(
274 video_encoder codec, int profile,
275 chroma_subsampling *chroma, int *bitDepth, hdr_format *hdr)
276{
277 // default values
278 *chroma = CHROMA_SUBSAMPLING_YUV_420;
279 *bitDepth = 8;
280 *hdr = HDR_FORMAT_NONE;
281
282 switch (codec) {
283 case VIDEO_ENCODER_H263:
284 case VIDEO_ENCODER_MPEG_4_SP:
285 case VIDEO_ENCODER_VP8:
286 // these are always 4:2:0 SDR 8-bit
287 return true;
288
289 case VIDEO_ENCODER_H264:
290 switch (profile) {
291 case AVCProfileBaseline:
292 case AVCProfileConstrainedBaseline:
293 case AVCProfileMain:
294 case AVCProfileExtended:
295 case AVCProfileHigh:
296 case AVCProfileConstrainedHigh:
297 return true;
298 case AVCProfileHigh10:
299 // returning false here as this could be an HLG stream
300 *bitDepth = 10;
301 return false;
302 case AVCProfileHigh422:
303 *chroma = CHROMA_SUBSAMPLING_YUV_422;
304 // returning false here as bit-depth could be 8 or 10
305 return false;
306 case AVCProfileHigh444:
307 *chroma = CHROMA_SUBSAMPLING_YUV_444;
308 // returning false here as bit-depth could be 8 or 10
309 return false;
310 default:
311 return false;
312 }
313 // flow does not get here
314
315 case VIDEO_ENCODER_HEVC:
316 switch (profile) {
317 case HEVCProfileMain:
318 return true;
319 case HEVCProfileMain10:
320 *bitDepth = 10;
321 // returning false here as this could be an HLG stream
322 return false;
323 case HEVCProfileMain10HDR10:
324 *bitDepth = 10;
325 *hdr = HDR_FORMAT_HDR10;
326 return true;
327 case HEVCProfileMain10HDR10Plus:
328 *bitDepth = 10;
329 *hdr = HDR_FORMAT_HDR10PLUS;
330 return true;
331 default:
332 return false;
333 }
334 // flow does not get here
335
336 case VIDEO_ENCODER_VP9:
337 switch (profile) {
338 case VP9Profile0:
339 return true;
340 case VP9Profile2:
341 // this is always 10-bit on Android */
342 *bitDepth = 10;
343 // returning false here as this could be an HLG stream
344 return false;
345 case VP9Profile2HDR:
346 // this is always 10-bit on Android */
347 *bitDepth = 10;
348 *hdr = HDR_FORMAT_HDR10;
349 return true;
350 case VP9Profile2HDR10Plus:
351 *bitDepth = 10;
352 *hdr = HDR_FORMAT_HDR10PLUS;
353 return true;
354 default:
355 return false;
356 }
357 // flow does not get here
358
359 case VIDEO_ENCODER_DOLBY_VISION:
360 {
361 // for Dolby Vision codec we always assume 10-bit DV
362 *bitDepth = 10;
363 *hdr = HDR_FORMAT_DOLBY_VISION;
364
365 switch (profile) {
366 case DolbyVisionProfileDvheDer /* profile 2 deprecated */:
367 case DolbyVisionProfileDvheDen /* profile 3 deprecated */:
368 case DolbyVisionProfileDvavPer /* profile 0 deprecated */:
369 case DolbyVisionProfileDvavPen /* profile 1 deprecated */:
370 case DolbyVisionProfileDvheDtr /* dvhe.04 */:
371 case DolbyVisionProfileDvheStn /* dvhe.05 */:
372 case DolbyVisionProfileDvheDth /* profile 6 deprecated */:
373 case DolbyVisionProfileDvheDtb /* dvhe.07 */:
374 case DolbyVisionProfileDvheSt /* dvhe.08 */:
375 case DolbyVisionProfileDvavSe /* dvav.09 */:
376 case DolbyVisionProfileDvav110 /* dvav1.10 */:
377 return true;
378 default:
379 return false;
380 }
381 // flow does not get here
382 }
383
384 case VIDEO_ENCODER_AV1:
385 switch (profile) {
386 case AV1ProfileMain10:
387 *bitDepth = 10;
388 // returning false here as this could be an HLG stream
389 return false;
390 case AV1ProfileMain10HDR10:
391 *bitDepth = 10;
392 *hdr = HDR_FORMAT_HDR10;
393 return true;
394 case AV1ProfileMain10HDR10Plus:
395 *bitDepth = 10;
396 *hdr = HDR_FORMAT_HDR10PLUS;
397 return true;
398 default:
399 return false;
400 }
401 // flow does not get here
402
403 default:
404 return false;
405 }
406 // flow does not get here
407}
408
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700409/*static*/ void
Lajos Molnar28091432021-05-03 20:42:32 -0700410MediaProfiles::createVideoCodec(const char **atts, size_t natts, MediaProfiles *profiles)
James Dong1d7491b2010-01-19 17:45:38 -0800411{
Lajos Molnar28091432021-05-03 20:42:32 -0700412 CHECK(natts >= 10 &&
413 !strcmp("codec", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800414 !strcmp("bitRate", atts[2]) &&
415 !strcmp("width", atts[4]) &&
416 !strcmp("height", atts[6]) &&
417 !strcmp("frameRate", atts[8]));
418
419 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
420 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700421 if (codec == -1) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700422 ALOGE("MediaProfiles::createVideoCodec failed to locate codec %s", atts[1]);
423 return;
Alex Zhang032f7a12020-04-17 16:08:24 -0700424 }
James Dong1d7491b2010-01-19 17:45:38 -0800425
Lajos Molnar28091432021-05-03 20:42:32 -0700426 int profile = -1;
Lajos Molnar88e2e172022-01-14 16:03:05 -0800427 chroma_subsampling chroma = CHROMA_SUBSAMPLING_YUV_420;
428 int bitDepth = 8;
429 hdr_format hdr = HDR_FORMAT_NONE;
430 if (codec == VIDEO_ENCODER_DOLBY_VISION) {
431 bitDepth = 10;
432 hdr = HDR_FORMAT_DOLBY_VISION;
Lajos Molnar28091432021-05-03 20:42:32 -0700433 }
434
Lajos Molnar88e2e172022-01-14 16:03:05 -0800435 if (natts >= 12 && !strcmp("profile", atts[10])) {
436 profile = atoi(atts[11]);
437 if (!detectAdvancedVideoProfile(
438 (video_encoder)codec, profile, &chroma, &bitDepth, &hdr)) {
439 // if not detected read values from the attributes
440 for (size_t ix = 12; natts >= ix + 2; ix += 2) {
441 if (!strcmp("chroma", atts[ix])) {
442 int chromaTag = findTagForName(sChromaSubsamplingNameMap,
443 NELEM(sChromaSubsamplingNameMap), atts[ix + 1]);
444 if (chromaTag == -1) {
445 ALOGE("MediaProfiles::createVideoCodec invalid chroma %s", atts[ix + 1]);
446 return;
447 } else {
448 chroma = (chroma_subsampling)chromaTag;
449 }
450 } else if (!strcmp("bitDepth", atts[ix])) {
451 bitDepth = atoi(atts[ix + 1]);
452 if (bitDepth < 8 || bitDepth > 16) {
453 ALOGE("MediaProfiles::createVideoCodec invalid bidDepth %s", atts[ix + 1]);
454 return;
455 }
456 } else if (!strcmp("hdr", atts[ix])) {
457 int hdrTag = findTagForName(sHdrFormatNameMap,
458 NELEM(sHdrFormatNameMap), atts[ix + 1]);
459 if (hdrTag == -1) {
460 ALOGE("MediaProfiles::createVideoCodec invalid hdr %s", atts[ix + 1]);
461 return;
462 } else {
463 hdr = (hdr_format)hdrTag;
464 }
465 } else {
466 // ignoring here. TODO: rewrite this whole file to ignore invalid attrs
467 ALOGD("MediaProfiles::createVideoCodec ignoring invalid attr %s", atts[ix]);
468 }
469 }
470 }
471 }
472
473 VideoCodec videoCodec{
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700474 static_cast<video_encoder>(codec),
Lajos Molnar88e2e172022-01-14 16:03:05 -0800475 atoi(atts[3]) /* bitRate */, atoi(atts[5]) /* width */, atoi(atts[7]) /* height */,
476 atoi(atts[9]) /* frameRate */, profile, chroma, bitDepth, hdr };
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700477 logVideoCodec(videoCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800478
479 size_t nCamcorderProfiles;
480 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700481 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodecs.emplace_back(videoCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800482}
483
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700484/*static*/ void
Lajos Molnar28091432021-05-03 20:42:32 -0700485MediaProfiles::createAudioCodec(const char **atts, size_t natts, MediaProfiles *profiles)
James Dong1d7491b2010-01-19 17:45:38 -0800486{
Lajos Molnar28091432021-05-03 20:42:32 -0700487 CHECK(natts >= 8 &&
488 !strcmp("codec", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800489 !strcmp("bitRate", atts[2]) &&
490 !strcmp("sampleRate", atts[4]) &&
491 !strcmp("channels", atts[6]));
492 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
493 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700494 if (codec == -1) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700495 ALOGE("MediaProfiles::createAudioCodec failed to locate codec %s", atts[1]);
496 return;
Alex Zhang032f7a12020-04-17 16:08:24 -0700497 }
James Dong1d7491b2010-01-19 17:45:38 -0800498
Lajos Molnar28091432021-05-03 20:42:32 -0700499 int profile = -1;
500 if (natts >= 10 && !strcmp("profile", atts[8])) {
501 profile = atoi(atts[9]);
502 }
503
504 AudioCodec audioCodec{
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700505 static_cast<audio_encoder>(codec),
Lajos Molnar28091432021-05-03 20:42:32 -0700506 atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), profile };
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700507 logAudioCodec(audioCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800508
509 size_t nCamcorderProfiles;
510 CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700511 profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodecs.emplace_back(audioCodec);
James Dong1d7491b2010-01-19 17:45:38 -0800512}
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700513
James Dong1d7491b2010-01-19 17:45:38 -0800514/*static*/ MediaProfiles::AudioDecoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700515MediaProfiles::createAudioDecoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800516{
Lajos Molnar28091432021-05-03 20:42:32 -0700517 CHECK(natts >= 4 &&
518 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800519 !strcmp("enabled", atts[2]));
520
521 const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
522 const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700523 if (codec == -1) {
524 ALOGE("MediaProfiles::createAudioDecoderCap failed to locate codec %s", atts[1]);
525 return nullptr;
526 }
James Dong1d7491b2010-01-19 17:45:38 -0800527
528 MediaProfiles::AudioDecoderCap *cap =
529 new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
530 logAudioDecoderCap(*cap);
531 return cap;
532}
533
534/*static*/ MediaProfiles::VideoDecoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700535MediaProfiles::createVideoDecoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800536{
Lajos Molnar28091432021-05-03 20:42:32 -0700537 CHECK(natts >= 4 &&
538 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800539 !strcmp("enabled", atts[2]));
540
541 const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
542 const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700543 if (codec == -1) {
544 ALOGE("MediaProfiles::createVideoDecoderCap failed to locate codec %s", atts[1]);
545 return nullptr;
546 }
James Dong1d7491b2010-01-19 17:45:38 -0800547
548 MediaProfiles::VideoDecoderCap *cap =
549 new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
550 logVideoDecoderCap(*cap);
551 return cap;
552}
553
554/*static*/ MediaProfiles::VideoEncoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700555MediaProfiles::createVideoEncoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800556{
Lajos Molnar28091432021-05-03 20:42:32 -0700557 CHECK(natts >= 20 &&
558 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800559 !strcmp("enabled", atts[2]) &&
560 !strcmp("minBitRate", atts[4]) &&
561 !strcmp("maxBitRate", atts[6]) &&
562 !strcmp("minFrameWidth", atts[8]) &&
563 !strcmp("maxFrameWidth", atts[10]) &&
564 !strcmp("minFrameHeight", atts[12]) &&
565 !strcmp("maxFrameHeight", atts[14]) &&
566 !strcmp("minFrameRate", atts[16]) &&
567 !strcmp("maxFrameRate", atts[18]));
568
569 const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
570 const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700571 if (codec == -1) {
572 ALOGE("MediaProfiles::createVideoEncoderCap failed to locate codec %s", atts[1]);
573 return nullptr;
574 }
James Dong1d7491b2010-01-19 17:45:38 -0800575
576 MediaProfiles::VideoEncoderCap *cap =
577 new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
578 atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
579 atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
580 logVideoEncoderCap(*cap);
581 return cap;
582}
583
584/*static*/ MediaProfiles::AudioEncoderCap*
Lajos Molnar28091432021-05-03 20:42:32 -0700585MediaProfiles::createAudioEncoderCap(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800586{
Lajos Molnar28091432021-05-03 20:42:32 -0700587 CHECK(natts >= 16 &&
588 !strcmp("name", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800589 !strcmp("enabled", atts[2]) &&
590 !strcmp("minBitRate", atts[4]) &&
591 !strcmp("maxBitRate", atts[6]) &&
592 !strcmp("minSampleRate", atts[8]) &&
593 !strcmp("maxSampleRate", atts[10]) &&
594 !strcmp("minChannels", atts[12]) &&
595 !strcmp("maxChannels", atts[14]));
596
597 const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
598 const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700599 if (codec == -1) {
600 ALOGE("MediaProfiles::createAudioEncoderCap failed to locate codec %s", atts[1]);
601 return nullptr;
602 }
James Dong1d7491b2010-01-19 17:45:38 -0800603
604 MediaProfiles::AudioEncoderCap *cap =
Glenn Kastenb187de12014-12-30 08:18:15 -0800605 new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]),
606 atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]), atoi(atts[15]));
James Dong1d7491b2010-01-19 17:45:38 -0800607 logAudioEncoderCap(*cap);
608 return cap;
609}
610
611/*static*/ output_format
Lajos Molnar28091432021-05-03 20:42:32 -0700612MediaProfiles::createEncoderOutputFileFormat(const char **atts, size_t natts)
James Dong1d7491b2010-01-19 17:45:38 -0800613{
Lajos Molnar28091432021-05-03 20:42:32 -0700614 CHECK(natts >= 2 &&
615 !strcmp("name", atts[0]));
James Dong1d7491b2010-01-19 17:45:38 -0800616
617 const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
618 const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
619 CHECK(format != -1);
620
621 return static_cast<output_format>(format);
622}
623
James Dong2a7e0a12011-02-28 21:07:39 -0800624static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
625 for (int i = 0, n = cameraIds.size(); i < n; ++i) {
626 if (cameraId == cameraIds[i]) {
627 return true;
628 }
629 }
630 return false;
631}
632
James Dong1d7491b2010-01-19 17:45:38 -0800633/*static*/ MediaProfiles::CamcorderProfile*
Lajos Molnar28091432021-05-03 20:42:32 -0700634MediaProfiles::createCamcorderProfile(
635 int cameraId, const char **atts, size_t natts, Vector<int>& cameraIds)
James Dong1d7491b2010-01-19 17:45:38 -0800636{
Lajos Molnar28091432021-05-03 20:42:32 -0700637 CHECK(natts >= 6 &&
638 !strcmp("quality", atts[0]) &&
James Dong1d7491b2010-01-19 17:45:38 -0800639 !strcmp("fileFormat", atts[2]) &&
640 !strcmp("duration", atts[4]));
641
Glenn Kastenb187de12014-12-30 08:18:15 -0800642 const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/
643 sizeof(sCamcorderQualityNameMap[0]);
James Dong1d7491b2010-01-19 17:45:38 -0800644 const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700645 if (quality == -1) {
646 ALOGE("MediaProfiles::createCamcorderProfile failed to locate quality %s", atts[1]);
647 return nullptr;
648 }
James Dong1d7491b2010-01-19 17:45:38 -0800649
650 const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
651 const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
Alex Zhang032f7a12020-04-17 16:08:24 -0700652 if (fileFormat == -1) {
653 ALOGE("MediaProfiles::createCamcorderProfile failed to locate file format %s", atts[1]);
654 return nullptr;
655 }
James Dong1d7491b2010-01-19 17:45:38 -0800656
657 MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800658 profile->mCameraId = cameraId;
James Dong2a7e0a12011-02-28 21:07:39 -0800659 if (!isCameraIdFound(cameraId, cameraIds)) {
660 cameraIds.add(cameraId);
661 }
James Dong1d7491b2010-01-19 17:45:38 -0800662 profile->mFileFormat = static_cast<output_format>(fileFormat);
663 profile->mQuality = static_cast<camcorder_quality>(quality);
664 profile->mDuration = atoi(atts[5]);
665 return profile;
666}
667
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800668MediaProfiles::ImageEncodingQualityLevels*
669MediaProfiles::findImageEncodingQualityLevels(int cameraId) const
670{
671 int n = mImageEncodingQualityLevels.size();
672 for (int i = 0; i < n; i++) {
673 ImageEncodingQualityLevels *levels = mImageEncodingQualityLevels[i];
674 if (levels->mCameraId == cameraId) {
675 return levels;
676 }
677 }
678 return NULL;
679}
680
Lajos Molnar28091432021-05-03 20:42:32 -0700681void MediaProfiles::addImageEncodingQualityLevel(int cameraId, const char** atts, size_t natts)
James Dongf5a83852010-02-23 17:21:44 -0800682{
Lajos Molnar28091432021-05-03 20:42:32 -0700683 CHECK(natts >= 2 &&
684 !strcmp("quality", atts[0]));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800685 int quality = atoi(atts[1]);
Glenn Kasten90bebef2012-01-27 15:24:38 -0800686 ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800687 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
688
689 if (levels == NULL) {
690 levels = new ImageEncodingQualityLevels();
691 levels->mCameraId = cameraId;
692 mImageEncodingQualityLevels.add(levels);
693 }
694
695 levels->mLevels.add(quality);
696}
697
698/*static*/ int
Lajos Molnar28091432021-05-03 20:42:32 -0700699MediaProfiles::getCameraId(const char** atts, size_t natts)
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800700{
701 if (!atts[0]) return 0; // default cameraId = 0
Lajos Molnar28091432021-05-03 20:42:32 -0700702 CHECK(natts >= 2 &&
703 !strcmp("cameraId", atts[0]));
James Dongf5a83852010-02-23 17:21:44 -0800704 return atoi(atts[1]);
705}
706
Lajos Molnar28091432021-05-03 20:42:32 -0700707void MediaProfiles::addStartTimeOffset(int cameraId, const char** atts, size_t natts)
James Dong0f056292011-05-09 18:49:31 -0700708{
Eric Laurentb1eb1a02012-10-22 17:44:24 -0700709 int offsetTimeMs = 1000;
Lajos Molnar28091432021-05-03 20:42:32 -0700710 if (natts >= 3 && atts[2]) {
711 CHECK(natts >= 4 && !strcmp("startOffsetMs", atts[2]));
James Dong0f056292011-05-09 18:49:31 -0700712 offsetTimeMs = atoi(atts[3]);
713 }
714
Steve Block3856b092011-10-20 11:56:00 +0100715 ALOGV("%s: cameraId=%d, offset=%d ms", __func__, cameraId, offsetTimeMs);
James Dong0f056292011-05-09 18:49:31 -0700716 mStartTimeOffsets.replaceValueFor(cameraId, offsetTimeMs);
717}
Hong Tengcabd5f82011-07-06 18:33:09 -0700718
James Dong1d7491b2010-01-19 17:45:38 -0800719/*static*/ void
720MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
721{
Lajos Molnar28091432021-05-03 20:42:32 -0700722 // determine number of attributes
723 size_t natts = 0;
724 while (atts[natts]) {
725 ++natts;
726 }
727
728 MediaProfiles *profiles = (MediaProfiles *)userData;
James Dong1d7491b2010-01-19 17:45:38 -0800729 if (strcmp("Video", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700730 createVideoCodec(atts, natts, profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800731 } else if (strcmp("Audio", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700732 createAudioCodec(atts, natts, profiles);
James Dong1d7491b2010-01-19 17:45:38 -0800733 } else if (strcmp("VideoEncoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700734 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800735 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700736 MediaProfiles::VideoEncoderCap* cap = createVideoEncoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700737 if (cap != nullptr) {
738 profiles->mVideoEncoders.add(cap);
739 }
James Dong1d7491b2010-01-19 17:45:38 -0800740 } else if (strcmp("AudioEncoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700741 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800742 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700743 MediaProfiles::AudioEncoderCap* cap = createAudioEncoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700744 if (cap != nullptr) {
745 profiles->mAudioEncoders.add(cap);
746 }
James Dong1d7491b2010-01-19 17:45:38 -0800747 } else if (strcmp("VideoDecoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700748 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800749 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700750 MediaProfiles::VideoDecoderCap* cap = createVideoDecoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700751 if (cap != nullptr) {
752 profiles->mVideoDecoders.add(cap);
753 }
James Dong1d7491b2010-01-19 17:45:38 -0800754 } else if (strcmp("AudioDecoderCap", name) == 0 &&
Lajos Molnar28091432021-05-03 20:42:32 -0700755 natts >= 4 &&
James Dong1d7491b2010-01-19 17:45:38 -0800756 strcmp("true", atts[3]) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700757 MediaProfiles::AudioDecoderCap* cap = createAudioDecoderCap(atts, natts);
Alex Zhang032f7a12020-04-17 16:08:24 -0700758 if (cap != nullptr) {
759 profiles->mAudioDecoders.add(cap);
760 }
James Dong1d7491b2010-01-19 17:45:38 -0800761 } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700762 profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts, natts));
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +0800763 } else if (strcmp("CamcorderProfiles", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700764 profiles->mCurrentCameraId = getCameraId(atts, natts);
765 profiles->addStartTimeOffset(profiles->mCurrentCameraId, atts, natts);
James Dong1d7491b2010-01-19 17:45:38 -0800766 } else if (strcmp("EncoderProfile", name) == 0) {
Alex Zhang032f7a12020-04-17 16:08:24 -0700767 MediaProfiles::CamcorderProfile* profile = createCamcorderProfile(
Lajos Molnar28091432021-05-03 20:42:32 -0700768 profiles->mCurrentCameraId, atts, natts, profiles->mCameraIds);
Alex Zhang032f7a12020-04-17 16:08:24 -0700769 if (profile != nullptr) {
770 profiles->mCamcorderProfiles.add(profile);
771 }
James Dongf5a83852010-02-23 17:21:44 -0800772 } else if (strcmp("ImageEncoding", name) == 0) {
Lajos Molnar28091432021-05-03 20:42:32 -0700773 profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts, natts);
James Dong1d7491b2010-01-19 17:45:38 -0800774 }
775}
776
James Dong2a7e0a12011-02-28 21:07:39 -0800777static bool isCamcorderProfile(camcorder_quality quality) {
778 return quality >= CAMCORDER_QUALITY_LIST_START &&
779 quality <= CAMCORDER_QUALITY_LIST_END;
780}
781
782static bool isTimelapseProfile(camcorder_quality quality) {
783 return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
784 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
785}
786
Zhijun Hee0790972014-07-23 15:17:26 -0700787static bool isHighSpeedProfile(camcorder_quality quality) {
788 return quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
789 quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END;
790}
791
James Dong2a7e0a12011-02-28 21:07:39 -0800792void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
Mark Salyzyn34fb2962014-06-18 16:30:56 -0700793 ALOGV("Number of camera ids: %zu", cameraIds.size());
James Dong2a7e0a12011-02-28 21:07:39 -0800794 CHECK(cameraIds.size() > 0);
795 mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
796 for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
797 mRequiredProfileRefs[i].mCameraId = cameraIds[i];
798 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
799 mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
800 mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
801 if ((j & 1) == 0) { // low resolution
802 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
803 } else { // high resolution
804 mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
805 }
806 }
807 }
808}
809
810int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
811 for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
812 if (mCameraIds[i] == cameraId) {
813 return i;
814 }
815 }
816 return -1;
817}
818
819void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
820 if (sIsInitialized) {
821 return;
822 }
823
824 initRequiredProfileRefs(mCameraIds);
825
826 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700827 // ensure at least one video and audio profile is added
Lajos Molnar28091432021-05-03 20:42:32 -0700828 if (mCamcorderProfiles[i]->mVideoCodecs.empty()) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700829 mCamcorderProfiles[i]->mVideoCodecs.emplace_back(
830 VIDEO_ENCODER_H263, 192000 /* bitrate */,
831 176 /* width */, 144 /* height */, 20 /* frameRate */);
832 }
Lajos Molnar28091432021-05-03 20:42:32 -0700833 if (mCamcorderProfiles[i]->mAudioCodecs.empty()) {
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -0700834 mCamcorderProfiles[i]->mAudioCodecs.emplace_back(
835 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
836 8000 /* sampleRate */, 1 /* channels */);
837 }
838
839 int product = mCamcorderProfiles[i]->mVideoCodecs[0].mFrameWidth *
840 mCamcorderProfiles[i]->mVideoCodecs[0].mFrameHeight;
James Dong2a7e0a12011-02-28 21:07:39 -0800841
842 camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
843 int cameraId = mCamcorderProfiles[i]->mCameraId;
844 int index = -1;
845 int refIndex = getRequiredProfileRefIndex(cameraId);
846 CHECK(refIndex != -1);
847 RequiredProfileRefInfo *info;
848 camcorder_quality refQuality;
James Dong2a7e0a12011-02-28 21:07:39 -0800849
Zhijun Hee0790972014-07-23 15:17:26 -0700850 // Check high and low from either camcorder profile, timelapse profile
851 // or high speed profile, but not all of them. Default, check camcorder profile
James Dong2a7e0a12011-02-28 21:07:39 -0800852 size_t j = 0;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200853 size_t o = 2;
James Dong2a7e0a12011-02-28 21:07:39 -0800854 if (isTimelapseProfile(quality)) {
855 // Check timelapse profile instead.
856 j = 2;
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200857 o = kNumRequiredProfiles;
Zhijun Hee0790972014-07-23 15:17:26 -0700858 } else if (isHighSpeedProfile(quality)) {
859 // Skip the check for high speed profile.
860 continue;
James Dong2a7e0a12011-02-28 21:07:39 -0800861 } else {
862 // Must be camcorder profile.
863 CHECK(isCamcorderProfile(quality));
864 }
Bernhard Rosenkraenzer3c8889e2012-03-29 11:38:59 +0200865 for (; j < o; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800866 info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
867 if ((j % 2 == 0 && product > info->mResolutionProduct) || // low
868 (j % 2 != 0 && product < info->mResolutionProduct)) { // high
869 continue;
870 }
871 switch (j) {
872 case 0:
873 refQuality = CAMCORDER_QUALITY_LOW;
874 break;
875 case 1:
876 refQuality = CAMCORDER_QUALITY_HIGH;
877 break;
878 case 2:
879 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
880 break;
881 case 3:
882 refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
883 break;
884 default:
885 CHECK(!"Should never reach here");
886 }
887
888 if (!info->mHasRefProfile) {
889 index = getCamcorderProfileIndex(cameraId, refQuality);
890 }
891 if (index == -1) {
892 // New high or low quality profile is found.
893 // Update its reference.
894 info->mHasRefProfile = true;
895 info->mRefProfileIndex = i;
896 info->mResolutionProduct = product;
897 }
898 }
899 }
900
Roman Kiryanovfb42ae82023-02-17 23:12:11 -0800901 for (size_t refIndex = 0; refIndex < mCameraIds.size(); ++refIndex) {
902 const int cameraId = mCameraIds[refIndex];
James Dong2a7e0a12011-02-28 21:07:39 -0800903 for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
James Dong2a7e0a12011-02-28 21:07:39 -0800904 RequiredProfileRefInfo *info =
905 &mRequiredProfileRefs[refIndex].mRefs[j];
906
907 if (info->mHasRefProfile) {
908
George Burgess IV215545b2018-07-25 10:06:30 -0700909 std::unique_ptr<CamcorderProfile> profile =
910 std::make_unique<CamcorderProfile>(
James Dong2a7e0a12011-02-28 21:07:39 -0800911 *mCamcorderProfiles[info->mRefProfileIndex]);
912
913 // Overwrite the quality
914 switch (j % kNumRequiredProfiles) {
915 case 0:
916 profile->mQuality = CAMCORDER_QUALITY_LOW;
917 break;
918 case 1:
919 profile->mQuality = CAMCORDER_QUALITY_HIGH;
920 break;
921 case 2:
922 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
923 break;
924 case 3:
925 profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
926 break;
927 default:
928 CHECK(!"Should never come here");
929 }
930
931 int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
932 if (index != -1) {
Roman Kiryanovfb42ae82023-02-17 23:12:11 -0800933 ALOGV("Profile quality %d for camera %d already exists",
James Dong2a7e0a12011-02-28 21:07:39 -0800934 profile->mQuality, cameraId);
935 CHECK(index == refIndex);
936 continue;
937 }
938
939 // Insert the new profile
Roman Kiryanovfb42ae82023-02-17 23:12:11 -0800940 ALOGV("Add a profile: quality %d=>%d for camera %d",
James Dong2a7e0a12011-02-28 21:07:39 -0800941 mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
942 profile->mQuality, cameraId);
943
George Burgess IV215545b2018-07-25 10:06:30 -0700944 mCamcorderProfiles.add(profile.release());
James Dong2a7e0a12011-02-28 21:07:39 -0800945 }
946 }
947 }
948}
949
James Dong1d7491b2010-01-19 17:45:38 -0800950/*static*/ MediaProfiles*
951MediaProfiles::getInstance()
952{
Steve Block3856b092011-10-20 11:56:00 +0100953 ALOGV("getInstance");
James Dong1d7491b2010-01-19 17:45:38 -0800954 Mutex::Autolock lock(sLock);
955 if (!sIsInitialized) {
956 char value[PROPERTY_VALUE_MAX];
957 if (property_get("media.settings.xml", value, NULL) <= 0) {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700958 const char* xmlFile = nullptr;
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -0800959 for (auto const& f : getXmlPaths()) {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700960 if (checkXmlFile(f)) {
961 xmlFile = f;
962 break;
963 }
964 }
965 if (xmlFile == nullptr) {
966 ALOGW("Could not find a validated xml file. "
967 "Using the default instance instead.");
James Dong1d7491b2010-01-19 17:45:38 -0800968 sInstance = createDefaultInstance();
969 } else {
Pawin Vongmasad7db05b2017-05-03 04:19:20 -0700970 sInstance = createInstanceFromXmlFile(xmlFile);
James Dong1d7491b2010-01-19 17:45:38 -0800971 }
972 } else {
973 sInstance = createInstanceFromXmlFile(value);
974 }
James Dong2a7e0a12011-02-28 21:07:39 -0800975 CHECK(sInstance != NULL);
976 sInstance->checkAndAddRequiredProfilesIfNecessary();
977 sIsInitialized = true;
James Dong1d7491b2010-01-19 17:45:38 -0800978 }
979
980 return sInstance;
981}
982
983/*static*/ MediaProfiles::VideoEncoderCap*
984MediaProfiles::createDefaultH263VideoEncoderCap()
985{
986 return new MediaProfiles::VideoEncoderCap(
987 VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
988}
989
990/*static*/ MediaProfiles::VideoEncoderCap*
991MediaProfiles::createDefaultM4vVideoEncoderCap()
992{
993 return new MediaProfiles::VideoEncoderCap(
994 VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
995}
996
997
998/*static*/ void
999MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
1000{
1001 profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
1002 profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
1003}
1004
1005/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001006MediaProfiles::createDefaultCamcorderTimeLapseQcifProfile(camcorder_quality quality)
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001007{
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001008 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
1009 profile->mCameraId = 0;
1010 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001011 profile->mQuality = quality;
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001012 profile->mDuration = 60;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001013 profile->mVideoCodecs.emplace_back(
1014 VIDEO_ENCODER_H263, 1000000 /* bitrate */,
1015 176 /* width */, 144 /* height */, 20 /* frameRate */);
1016 profile->mAudioCodecs.emplace_back(
1017 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1018 8000 /* sampleRate */, 1 /* channels */);
1019
Nipun Kwatrac0a84782010-09-06 15:59:02 -07001020 return profile;
1021}
1022
1023/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001024MediaProfiles::createDefaultCamcorderTimeLapse480pProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -08001025{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001026 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
1027 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -08001028 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001029 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -08001030 profile->mDuration = 60;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001031 profile->mVideoCodecs.emplace_back(
1032 VIDEO_ENCODER_H263, 20000000 /* bitrate */,
1033 720 /* width */, 480 /* height */, 20 /* frameRate */);
1034 profile->mAudioCodecs.emplace_back(
1035 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1036 8000 /* sampleRate */, 1 /* channels */);
James Dong1d7491b2010-01-19 17:45:38 -08001037 return profile;
1038}
1039
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001040/*static*/ void
1041MediaProfiles::createDefaultCamcorderTimeLapseLowProfiles(
1042 MediaProfiles::CamcorderProfile **lowTimeLapseProfile,
1043 MediaProfiles::CamcorderProfile **lowSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -08001044 *lowTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
1045 CAMCORDER_QUALITY_TIME_LAPSE_LOW);
1046 *lowSpecificTimeLapseProfile = createDefaultCamcorderTimeLapseQcifProfile(
1047 CAMCORDER_QUALITY_TIME_LAPSE_QCIF);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001048}
1049
1050/*static*/ void
1051MediaProfiles::createDefaultCamcorderTimeLapseHighProfiles(
1052 MediaProfiles::CamcorderProfile **highTimeLapseProfile,
1053 MediaProfiles::CamcorderProfile **highSpecificTimeLapseProfile) {
Glenn Kastenb187de12014-12-30 08:18:15 -08001054 *highTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
1055 CAMCORDER_QUALITY_TIME_LAPSE_HIGH);
1056 *highSpecificTimeLapseProfile = createDefaultCamcorderTimeLapse480pProfile(
1057 CAMCORDER_QUALITY_TIME_LAPSE_480P);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001058}
1059
James Dong1d7491b2010-01-19 17:45:38 -08001060/*static*/ MediaProfiles::CamcorderProfile*
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001061MediaProfiles::createDefaultCamcorderQcifProfile(camcorder_quality quality)
James Dong1d7491b2010-01-19 17:45:38 -08001062{
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001063 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001064 profile->mCameraId = 0;
James Dong1d7491b2010-01-19 17:45:38 -08001065 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001066 profile->mQuality = quality;
James Dong1d7491b2010-01-19 17:45:38 -08001067 profile->mDuration = 30;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001068 profile->mVideoCodecs.emplace_back(
1069 VIDEO_ENCODER_H263, 192000 /* bitrate */,
1070 176 /* width */, 144 /* height */, 20 /* frameRate */);
1071 profile->mAudioCodecs.emplace_back(
1072 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1073 8000 /* sampleRate */, 1 /* channels */);
James Dong1d7491b2010-01-19 17:45:38 -08001074 return profile;
1075}
1076
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001077/*static*/ MediaProfiles::CamcorderProfile*
1078MediaProfiles::createDefaultCamcorderCifProfile(camcorder_quality quality)
1079{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001080 CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
1081 profile->mCameraId = 0;
1082 profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
1083 profile->mQuality = quality;
1084 profile->mDuration = 60;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001085 profile->mVideoCodecs.emplace_back(
1086 VIDEO_ENCODER_H263, 360000 /* bitrate */,
1087 352 /* width */, 288 /* height */, 20 /* frameRate */);
1088 profile->mAudioCodecs.emplace_back(
1089 AUDIO_ENCODER_AMR_NB, 12200 /* bitrate */,
1090 8000 /* sampleRate */, 1 /* channels */);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001091 return profile;
1092}
1093
1094/*static*/ void
1095MediaProfiles::createDefaultCamcorderLowProfiles(
1096 MediaProfiles::CamcorderProfile **lowProfile,
1097 MediaProfiles::CamcorderProfile **lowSpecificProfile) {
1098 *lowProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_LOW);
1099 *lowSpecificProfile = createDefaultCamcorderQcifProfile(CAMCORDER_QUALITY_QCIF);
1100}
1101
1102/*static*/ void
1103MediaProfiles::createDefaultCamcorderHighProfiles(
1104 MediaProfiles::CamcorderProfile **highProfile,
1105 MediaProfiles::CamcorderProfile **highSpecificProfile) {
1106 *highProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_HIGH);
1107 *highSpecificProfile = createDefaultCamcorderCifProfile(CAMCORDER_QUALITY_CIF);
1108}
1109
James Dong1d7491b2010-01-19 17:45:38 -08001110/*static*/ void
1111MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
1112{
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001113 // low camcorder profiles.
1114 MediaProfiles::CamcorderProfile *lowProfile, *lowSpecificProfile;
1115 createDefaultCamcorderLowProfiles(&lowProfile, &lowSpecificProfile);
1116 profiles->mCamcorderProfiles.add(lowProfile);
1117 profiles->mCamcorderProfiles.add(lowSpecificProfile);
1118
1119 // high camcorder profiles.
1120 MediaProfiles::CamcorderProfile* highProfile, *highSpecificProfile;
1121 createDefaultCamcorderHighProfiles(&highProfile, &highSpecificProfile);
1122 profiles->mCamcorderProfiles.add(highProfile);
1123 profiles->mCamcorderProfiles.add(highSpecificProfile);
1124
1125 // low camcorder time lapse profiles.
1126 MediaProfiles::CamcorderProfile *lowTimeLapseProfile, *lowSpecificTimeLapseProfile;
1127 createDefaultCamcorderTimeLapseLowProfiles(&lowTimeLapseProfile, &lowSpecificTimeLapseProfile);
1128 profiles->mCamcorderProfiles.add(lowTimeLapseProfile);
1129 profiles->mCamcorderProfiles.add(lowSpecificTimeLapseProfile);
1130
1131 // high camcorder time lapse profiles.
1132 MediaProfiles::CamcorderProfile *highTimeLapseProfile, *highSpecificTimeLapseProfile;
Glenn Kastenb187de12014-12-30 08:18:15 -08001133 createDefaultCamcorderTimeLapseHighProfiles(&highTimeLapseProfile,
1134 &highSpecificTimeLapseProfile);
Nipun Kwatrad5672bc2010-09-16 22:25:23 -07001135 profiles->mCamcorderProfiles.add(highTimeLapseProfile);
1136 profiles->mCamcorderProfiles.add(highSpecificTimeLapseProfile);
James Dong8031ec72011-03-16 14:09:50 -07001137
1138 // For emulator and other legacy devices which does not have a
1139 // media_profiles.xml file, We assume that the default camera id
1140 // is 0 and that is the only camera available.
1141 profiles->mCameraIds.push(0);
James Dong1d7491b2010-01-19 17:45:38 -08001142}
1143
1144/*static*/ void
1145MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
1146{
1147 profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
1148}
1149
1150/*static*/ void
1151MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
1152{
1153 MediaProfiles::VideoDecoderCap *cap =
1154 new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
1155
1156 profiles->mVideoDecoders.add(cap);
1157}
1158
1159/*static*/ void
1160MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
1161{
1162 MediaProfiles::AudioDecoderCap *cap =
1163 new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
1164
1165 profiles->mAudioDecoders.add(cap);
1166}
1167
1168/*static*/ void
1169MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
1170{
1171 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
1172 profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
1173}
1174
1175/*static*/ MediaProfiles::AudioEncoderCap*
1176MediaProfiles::createDefaultAmrNBEncoderCap()
1177{
1178 return new MediaProfiles::AudioEncoderCap(
1179 AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
1180}
1181
James Dongf5a83852010-02-23 17:21:44 -08001182/*static*/ void
1183MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
1184{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001185 ImageEncodingQualityLevels *levels = new ImageEncodingQualityLevels();
1186 levels->mCameraId = 0;
1187 levels->mLevels.add(70);
1188 levels->mLevels.add(80);
1189 levels->mLevels.add(90);
1190 profiles->mImageEncodingQualityLevels.add(levels);
James Dongf5a83852010-02-23 17:21:44 -08001191}
1192
James Dong1d7491b2010-01-19 17:45:38 -08001193/*static*/ MediaProfiles*
1194MediaProfiles::createDefaultInstance()
1195{
1196 MediaProfiles *profiles = new MediaProfiles;
1197 createDefaultCamcorderProfiles(profiles);
1198 createDefaultVideoEncoders(profiles);
1199 createDefaultAudioEncoders(profiles);
1200 createDefaultVideoDecoders(profiles);
1201 createDefaultAudioDecoders(profiles);
1202 createDefaultEncoderOutputFileFormats(profiles);
James Dongf5a83852010-02-23 17:21:44 -08001203 createDefaultImageEncodingQualityLevels(profiles);
James Dong1d7491b2010-01-19 17:45:38 -08001204 return profiles;
1205}
1206
Pawin Vongmasad7db05b2017-05-03 04:19:20 -07001207bool MediaProfiles::checkXmlFile(const char* xmlFile) {
1208 struct stat fStat;
1209 return stat(xmlFile, &fStat) == 0 && S_ISREG(fStat.st_mode);
1210 // TODO: Add validation
1211}
1212
James Dong1d7491b2010-01-19 17:45:38 -08001213/*static*/ MediaProfiles*
1214MediaProfiles::createInstanceFromXmlFile(const char *xml)
1215{
1216 FILE *fp = NULL;
1217 CHECK((fp = fopen(xml, "r")));
1218
1219 XML_Parser parser = ::XML_ParserCreate(NULL);
1220 CHECK(parser != NULL);
1221
1222 MediaProfiles *profiles = new MediaProfiles();
1223 ::XML_SetUserData(parser, profiles);
1224 ::XML_SetElementHandler(parser, startElementHandler, NULL);
1225
1226 /*
1227 FIXME:
1228 expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
1229
1230 if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
Steve Block29357bc2012-01-06 19:20:56 +00001231 ALOGE("failed to enable DTD support in the xml file");
James Dong1d7491b2010-01-19 17:45:38 -08001232 return UNKNOWN_ERROR;
1233 }
1234
1235 */
1236
1237 const int BUFF_SIZE = 512;
1238 for (;;) {
1239 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
1240 if (buff == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001241 ALOGE("failed to in call to XML_GetBuffer()");
James Dong1d7491b2010-01-19 17:45:38 -08001242 delete profiles;
1243 profiles = NULL;
1244 goto exit;
1245 }
1246
1247 int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
1248 if (bytes_read < 0) {
Steve Block29357bc2012-01-06 19:20:56 +00001249 ALOGE("failed in call to read");
James Dong1d7491b2010-01-19 17:45:38 -08001250 delete profiles;
1251 profiles = NULL;
1252 goto exit;
1253 }
1254
1255 CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
1256
1257 if (bytes_read == 0) break; // done parsing the xml file
1258 }
1259
1260exit:
1261 ::XML_ParserFree(parser);
1262 ::fclose(fp);
James Dong1d7491b2010-01-19 17:45:38 -08001263 return profiles;
1264}
1265
1266Vector<output_format> MediaProfiles::getOutputFileFormats() const
1267{
1268 return mEncoderOutputFileFormats; // copy out
1269}
1270
1271Vector<video_encoder> MediaProfiles::getVideoEncoders() const
1272{
1273 Vector<video_encoder> encoders;
1274 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1275 encoders.add(mVideoEncoders[i]->mCodec);
1276 }
1277 return encoders; // copy out
1278}
1279
1280int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
1281{
Steve Block3856b092011-10-20 11:56:00 +01001282 ALOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001283 int index = -1;
1284 for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
1285 if (mVideoEncoders[i]->mCodec == codec) {
1286 index = i;
1287 break;
1288 }
1289 }
1290 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001291 ALOGE("The given video encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001292 return -1;
1293 }
1294
1295 if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
1296 if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
1297 if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
1298 if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
1299 if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
1300 if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
1301 if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
1302 if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
1303
Steve Block29357bc2012-01-06 19:20:56 +00001304 ALOGE("The given video encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001305 return -1;
1306}
Hong Tengcabd5f82011-07-06 18:33:09 -07001307
James Dong1d7491b2010-01-19 17:45:38 -08001308Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
1309{
1310 Vector<audio_encoder> encoders;
1311 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1312 encoders.add(mAudioEncoders[i]->mCodec);
1313 }
1314 return encoders; // copy out
1315}
1316
1317int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
1318{
Steve Block3856b092011-10-20 11:56:00 +01001319 ALOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
James Dong1d7491b2010-01-19 17:45:38 -08001320 int index = -1;
1321 for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
1322 if (mAudioEncoders[i]->mCodec == codec) {
1323 index = i;
1324 break;
1325 }
1326 }
1327 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001328 ALOGE("The given audio encoder %d is not found", codec);
James Dong1d7491b2010-01-19 17:45:38 -08001329 return -1;
1330 }
1331
1332 if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
1333 if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
1334 if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
1335 if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
1336 if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
1337 if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
1338
Steve Block29357bc2012-01-06 19:20:56 +00001339 ALOGE("The given audio encoder param name %s is not found", name);
James Dong1d7491b2010-01-19 17:45:38 -08001340 return -1;
1341}
1342
1343Vector<video_decoder> MediaProfiles::getVideoDecoders() const
1344{
1345 Vector<video_decoder> decoders;
1346 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1347 decoders.add(mVideoDecoders[i]->mCodec);
1348 }
1349 return decoders; // copy out
1350}
1351
1352Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
1353{
1354 Vector<audio_decoder> decoders;
1355 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1356 decoders.add(mAudioDecoders[i]->mCodec);
1357 }
1358 return decoders; // copy out
1359}
1360
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001361int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
James Dong1d7491b2010-01-19 17:45:38 -08001362{
James Dong1d7491b2010-01-19 17:45:38 -08001363 int index = -1;
1364 for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001365 if (mCamcorderProfiles[i]->mCameraId == cameraId &&
1366 mCamcorderProfiles[i]->mQuality == quality) {
James Dong1d7491b2010-01-19 17:45:38 -08001367 index = i;
1368 break;
1369 }
1370 }
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001371 return index;
1372}
1373
Lajos Molnard64df6d2021-04-29 23:20:57 -07001374const MediaProfiles::CamcorderProfile *MediaProfiles::getCamcorderProfile(
1375 int cameraId, camcorder_quality quality) const {
1376 int index = getCamcorderProfileIndex(cameraId, quality);
1377 if (index == -1) {
1378 ALOGE("The given camcorder profile camera %d quality %d is not found",
1379 cameraId, quality);
1380 return nullptr;
1381 }
1382
1383 return mCamcorderProfiles[index];
1384}
1385
1386std::vector<const MediaProfiles::AudioCodec *>
1387MediaProfiles::CamcorderProfile::getAudioCodecs() const {
1388 std::vector<const MediaProfiles::AudioCodec *> res;
1389 for (const MediaProfiles::AudioCodec &ac : mAudioCodecs) {
1390 res.push_back(&ac);
1391 }
1392 return res;
1393}
1394
1395std::vector<const MediaProfiles::VideoCodec *>
1396MediaProfiles::CamcorderProfile::getVideoCodecs() const {
1397 std::vector<const MediaProfiles::VideoCodec *> res;
1398 for (const MediaProfiles::VideoCodec &vc : mVideoCodecs) {
1399 res.push_back(&vc);
1400 }
1401 return res;
1402}
1403
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001404int MediaProfiles::getCamcorderProfileParamByName(const char *name,
1405 int cameraId,
1406 camcorder_quality quality) const
1407{
Steve Block3856b092011-10-20 11:56:00 +01001408 ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001409 name, cameraId, quality);
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001410
1411 int index = getCamcorderProfileIndex(cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001412 if (index == -1) {
Steve Block29357bc2012-01-06 19:20:56 +00001413 ALOGE("The given camcorder profile camera %d quality %d is not found",
Glenn Kastene53b9ea2012-03-12 16:29:55 -07001414 cameraId, quality);
James Dong1d7491b2010-01-19 17:45:38 -08001415 return -1;
1416 }
1417
James Dongf5a83852010-02-23 17:21:44 -08001418 if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
James Dong1d7491b2010-01-19 17:45:38 -08001419 if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
Lajos Molnarb0aeb8b2021-03-24 10:11:41 -07001420 if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mCodec;
1421 if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameWidth;
1422 if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameHeight;
1423 if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mBitRate;
1424 if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameRate;
1425 if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mCodec;
1426 if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mBitRate;
1427 if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mChannels;
1428 if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mSampleRate;
James Dong1d7491b2010-01-19 17:45:38 -08001429
Steve Block29357bc2012-01-06 19:20:56 +00001430 ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
James Dong1d7491b2010-01-19 17:45:38 -08001431 return -1;
1432}
1433
Nipun Kwatra8bb56032010-09-09 16:25:08 -07001434bool MediaProfiles::hasCamcorderProfile(int cameraId, camcorder_quality quality) const
1435{
1436 return (getCamcorderProfileIndex(cameraId, quality) != -1);
1437}
1438
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001439Vector<int> MediaProfiles::getImageEncodingQualityLevels(int cameraId) const
James Dongf5a83852010-02-23 17:21:44 -08001440{
Chih-Chung Chang3eaa4e92010-06-22 20:50:55 +08001441 Vector<int> result;
1442 ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
1443 if (levels != NULL) {
1444 result = levels->mLevels; // copy out
1445 }
1446 return result;
James Dongf5a83852010-02-23 17:21:44 -08001447}
1448
James Dong0f056292011-05-09 18:49:31 -07001449int MediaProfiles::getStartTimeOffsetMs(int cameraId) const {
1450 int offsetTimeMs = -1;
1451 ssize_t index = mStartTimeOffsets.indexOfKey(cameraId);
1452 if (index >= 0) {
1453 offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
1454 }
Steve Block3856b092011-10-20 11:56:00 +01001455 ALOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
James Dong0f056292011-05-09 18:49:31 -07001456 return offsetTimeMs;
1457}
1458
James Dong1d7491b2010-01-19 17:45:38 -08001459MediaProfiles::~MediaProfiles()
1460{
1461 CHECK("destructor should never be called" == 0);
1462#if 0
1463 for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
1464 delete mAudioEncoders[i];
1465 }
1466 mAudioEncoders.clear();
1467
1468 for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
1469 delete mVideoEncoders[i];
1470 }
1471 mVideoEncoders.clear();
1472
1473 for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
1474 delete mVideoDecoders[i];
1475 }
1476 mVideoDecoders.clear();
1477
1478 for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
1479 delete mAudioDecoders[i];
1480 }
1481 mAudioDecoders.clear();
1482
1483 for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
1484 delete mCamcorderProfiles[i];
1485 }
1486 mCamcorderProfiles.clear();
1487#endif
1488}
1489} // namespace android