xref: /aosp_15_r20/frameworks/av/media/module/metadatautils/MetaDataUtils.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright 2018 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "MetaDataUtils"
19*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
20*ec779b8eSAndroid Build Coastguard Worker 
21*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/avc_utils.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/base64.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ABitReader.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ABuffer.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ByteUtils.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaDefs.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MetaDataUtils.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <media/NdkMediaFormat.h>
29*ec779b8eSAndroid Build Coastguard Worker 
30*ec779b8eSAndroid Build Coastguard Worker namespace android {
31*ec779b8eSAndroid Build Coastguard Worker 
MakeAVCCodecSpecificData(MetaDataBase & meta,const uint8_t * data,size_t size)32*ec779b8eSAndroid Build Coastguard Worker bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
33*ec779b8eSAndroid Build Coastguard Worker     if (data == nullptr || size == 0) {
34*ec779b8eSAndroid Build Coastguard Worker         return false;
35*ec779b8eSAndroid Build Coastguard Worker     }
36*ec779b8eSAndroid Build Coastguard Worker 
37*ec779b8eSAndroid Build Coastguard Worker     int32_t width;
38*ec779b8eSAndroid Build Coastguard Worker     int32_t height;
39*ec779b8eSAndroid Build Coastguard Worker     int32_t sarWidth;
40*ec779b8eSAndroid Build Coastguard Worker     int32_t sarHeight;
41*ec779b8eSAndroid Build Coastguard Worker     sp<ABuffer> accessUnit = new ABuffer((void*)data,  size);
42*ec779b8eSAndroid Build Coastguard Worker     sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
43*ec779b8eSAndroid Build Coastguard Worker     if (csd == nullptr) {
44*ec779b8eSAndroid Build Coastguard Worker         return false;
45*ec779b8eSAndroid Build Coastguard Worker     }
46*ec779b8eSAndroid Build Coastguard Worker     meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
47*ec779b8eSAndroid Build Coastguard Worker 
48*ec779b8eSAndroid Build Coastguard Worker     meta.setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
49*ec779b8eSAndroid Build Coastguard Worker     meta.setInt32(kKeyWidth, width);
50*ec779b8eSAndroid Build Coastguard Worker     meta.setInt32(kKeyHeight, height);
51*ec779b8eSAndroid Build Coastguard Worker     if (sarWidth > 0 && sarHeight > 0) {
52*ec779b8eSAndroid Build Coastguard Worker         meta.setInt32(kKeySARWidth, sarWidth);
53*ec779b8eSAndroid Build Coastguard Worker         meta.setInt32(kKeySARHeight, sarHeight);
54*ec779b8eSAndroid Build Coastguard Worker     }
55*ec779b8eSAndroid Build Coastguard Worker     return true;
56*ec779b8eSAndroid Build Coastguard Worker }
57*ec779b8eSAndroid Build Coastguard Worker 
MakeAVCCodecSpecificData(AMediaFormat * meta,const uint8_t * data,size_t size)58*ec779b8eSAndroid Build Coastguard Worker bool MakeAVCCodecSpecificData(AMediaFormat *meta, const uint8_t *data, size_t size) {
59*ec779b8eSAndroid Build Coastguard Worker     if (meta == nullptr || data == nullptr || size == 0) {
60*ec779b8eSAndroid Build Coastguard Worker         return false;
61*ec779b8eSAndroid Build Coastguard Worker     }
62*ec779b8eSAndroid Build Coastguard Worker 
63*ec779b8eSAndroid Build Coastguard Worker     int32_t width;
64*ec779b8eSAndroid Build Coastguard Worker     int32_t height;
65*ec779b8eSAndroid Build Coastguard Worker     int32_t sarWidth;
66*ec779b8eSAndroid Build Coastguard Worker     int32_t sarHeight;
67*ec779b8eSAndroid Build Coastguard Worker     sp<ABuffer> accessUnit = new ABuffer((void*)data,  size);
68*ec779b8eSAndroid Build Coastguard Worker     sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
69*ec779b8eSAndroid Build Coastguard Worker     if (csd == nullptr) {
70*ec779b8eSAndroid Build Coastguard Worker         return false;
71*ec779b8eSAndroid Build Coastguard Worker     }
72*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
73*ec779b8eSAndroid Build Coastguard Worker 
74*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_AVC, csd->data(), csd->size());
75*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_WIDTH, width);
76*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_HEIGHT, height);
77*ec779b8eSAndroid Build Coastguard Worker     if (sarWidth > 0 && sarHeight > 0) {
78*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
79*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
80*ec779b8eSAndroid Build Coastguard Worker     }
81*ec779b8eSAndroid Build Coastguard Worker     return true;
82*ec779b8eSAndroid Build Coastguard Worker }
83*ec779b8eSAndroid Build Coastguard Worker 
84*ec779b8eSAndroid Build Coastguard Worker // Check if the next 24 bits are VP9 SYNC_CODE
isVp9SyncCode(ABitReader & bits)85*ec779b8eSAndroid Build Coastguard Worker static bool isVp9SyncCode(ABitReader &bits) {
86*ec779b8eSAndroid Build Coastguard Worker     if (bits.numBitsLeft() < 24) {
87*ec779b8eSAndroid Build Coastguard Worker         return false;
88*ec779b8eSAndroid Build Coastguard Worker     }
89*ec779b8eSAndroid Build Coastguard Worker     return bits.getBits(24) == 0x498342;
90*ec779b8eSAndroid Build Coastguard Worker }
91*ec779b8eSAndroid Build Coastguard Worker 
92*ec779b8eSAndroid Build Coastguard Worker // This parses bitdepth and subsampling in a VP9 uncompressed header
93*ec779b8eSAndroid Build Coastguard Worker // (refer section bitdepth_colorspace_sampling in 6.2 of the VP9 bitstream spec)
getVp9BitdepthChromaSubSampling(ABitReader & bits,int32_t profile,int32_t * bitDepth,int32_t * chromaSubsampling)94*ec779b8eSAndroid Build Coastguard Worker static bool getVp9BitdepthChromaSubSampling(ABitReader &bits,
95*ec779b8eSAndroid Build Coastguard Worker         int32_t profile,
96*ec779b8eSAndroid Build Coastguard Worker         int32_t *bitDepth,
97*ec779b8eSAndroid Build Coastguard Worker         int32_t *chromaSubsampling) {
98*ec779b8eSAndroid Build Coastguard Worker     if (profile >= 2) {
99*ec779b8eSAndroid Build Coastguard Worker         if (bits.numBitsLeft() < 1) {
100*ec779b8eSAndroid Build Coastguard Worker             return false;
101*ec779b8eSAndroid Build Coastguard Worker         }
102*ec779b8eSAndroid Build Coastguard Worker         *bitDepth = bits.getBits(1) ? 12 : 10;
103*ec779b8eSAndroid Build Coastguard Worker     } else {
104*ec779b8eSAndroid Build Coastguard Worker         *bitDepth = 8;
105*ec779b8eSAndroid Build Coastguard Worker     }
106*ec779b8eSAndroid Build Coastguard Worker 
107*ec779b8eSAndroid Build Coastguard Worker     uint32_t colorspace;
108*ec779b8eSAndroid Build Coastguard Worker     if (!bits.getBitsGraceful(3, &colorspace)) {
109*ec779b8eSAndroid Build Coastguard Worker         return false;
110*ec779b8eSAndroid Build Coastguard Worker     }
111*ec779b8eSAndroid Build Coastguard Worker 
112*ec779b8eSAndroid Build Coastguard Worker     *chromaSubsampling = -1;
113*ec779b8eSAndroid Build Coastguard Worker     if (colorspace != 7 /*SRGB*/) {
114*ec779b8eSAndroid Build Coastguard Worker         // Skip yuv_range_flag
115*ec779b8eSAndroid Build Coastguard Worker         if (!bits.skipBits(1)) {
116*ec779b8eSAndroid Build Coastguard Worker             return false;
117*ec779b8eSAndroid Build Coastguard Worker         }
118*ec779b8eSAndroid Build Coastguard Worker         // Check for subsampling only for profiles 1 and 3.
119*ec779b8eSAndroid Build Coastguard Worker         if (profile == 1 || profile == 3) {
120*ec779b8eSAndroid Build Coastguard Worker             uint32_t ss_x;
121*ec779b8eSAndroid Build Coastguard Worker             uint32_t ss_y;
122*ec779b8eSAndroid Build Coastguard Worker             if (bits.getBitsGraceful(1, &ss_x) && bits.getBitsGraceful(1, &ss_y)) {
123*ec779b8eSAndroid Build Coastguard Worker                 *chromaSubsampling = ss_x << 1 & ss_y;
124*ec779b8eSAndroid Build Coastguard Worker             } else {
125*ec779b8eSAndroid Build Coastguard Worker                 return false;
126*ec779b8eSAndroid Build Coastguard Worker             }
127*ec779b8eSAndroid Build Coastguard Worker         } else {
128*ec779b8eSAndroid Build Coastguard Worker             *chromaSubsampling = 3;
129*ec779b8eSAndroid Build Coastguard Worker         }
130*ec779b8eSAndroid Build Coastguard Worker     } else {
131*ec779b8eSAndroid Build Coastguard Worker         if (profile == 1 || profile == 3) {
132*ec779b8eSAndroid Build Coastguard Worker             *chromaSubsampling = 0;
133*ec779b8eSAndroid Build Coastguard Worker         }
134*ec779b8eSAndroid Build Coastguard Worker     }
135*ec779b8eSAndroid Build Coastguard Worker     return true;
136*ec779b8eSAndroid Build Coastguard Worker }
137*ec779b8eSAndroid Build Coastguard Worker 
138*ec779b8eSAndroid Build Coastguard Worker /**
139*ec779b8eSAndroid Build Coastguard Worker  * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec.
140*ec779b8eSAndroid Build Coastguard Worker  * For reference:
141*ec779b8eSAndroid Build Coastguard Worker  * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
142*ec779b8eSAndroid Build Coastguard Worker  *
143*ec779b8eSAndroid Build Coastguard Worker  * @param meta          A pointer to AMediaFormat object.
144*ec779b8eSAndroid Build Coastguard Worker  * @param profile       The profile value of the VP9 stream.
145*ec779b8eSAndroid Build Coastguard Worker  * @param level         The VP9 codec level. If the level is unknown, pass -1 to this parameter.
146*ec779b8eSAndroid Build Coastguard Worker  * @param bitDepth      The bit depth of the luma and color components of the VP9 stream.
147*ec779b8eSAndroid Build Coastguard Worker  * @param chromaSubsampling  The chroma subsampling of the VP9 stream. If chromaSubsampling is
148*ec779b8eSAndroid Build Coastguard Worker  *                           unknown, pass -1 to this parameter.
149*ec779b8eSAndroid Build Coastguard Worker  * @return true if CodecPrivate is set as CSD of AMediaFormat object.
150*ec779b8eSAndroid Build Coastguard Worker  *
151*ec779b8eSAndroid Build Coastguard Worker  */
MakeVP9CodecPrivate(AMediaFormat * meta,int32_t profile,int32_t level,int32_t bitDepth,int32_t chromaSubsampling)152*ec779b8eSAndroid Build Coastguard Worker static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level,
153*ec779b8eSAndroid Build Coastguard Worker                                 int32_t bitDepth, int32_t chromaSubsampling) {
154*ec779b8eSAndroid Build Coastguard Worker     if (meta == nullptr) {
155*ec779b8eSAndroid Build Coastguard Worker         return false;
156*ec779b8eSAndroid Build Coastguard Worker     }
157*ec779b8eSAndroid Build Coastguard Worker 
158*ec779b8eSAndroid Build Coastguard Worker     std::vector<uint8_t> codecPrivate;
159*ec779b8eSAndroid Build Coastguard Worker     // Construct CodecPrivate in WebM format (ID | Length | Data).
160*ec779b8eSAndroid Build Coastguard Worker     // Helper lambda to add a field to the codec private data
161*ec779b8eSAndroid Build Coastguard Worker     auto addField = [&codecPrivate](uint8_t id, uint8_t value) {
162*ec779b8eSAndroid Build Coastguard Worker         codecPrivate.push_back(id);
163*ec779b8eSAndroid Build Coastguard Worker         codecPrivate.push_back(0x01);  // Length is always 1
164*ec779b8eSAndroid Build Coastguard Worker         codecPrivate.push_back(value);
165*ec779b8eSAndroid Build Coastguard Worker     };
166*ec779b8eSAndroid Build Coastguard Worker 
167*ec779b8eSAndroid Build Coastguard Worker     // Add fields
168*ec779b8eSAndroid Build Coastguard Worker     addField(0x01, static_cast<uint8_t>(profile));
169*ec779b8eSAndroid Build Coastguard Worker     if (level >= 0) {
170*ec779b8eSAndroid Build Coastguard Worker         addField(0x02, static_cast<uint8_t>(level));
171*ec779b8eSAndroid Build Coastguard Worker     }
172*ec779b8eSAndroid Build Coastguard Worker     addField(0x03, static_cast<uint8_t>(bitDepth));
173*ec779b8eSAndroid Build Coastguard Worker     if (chromaSubsampling >= 0) {
174*ec779b8eSAndroid Build Coastguard Worker         addField(0x04, static_cast<uint8_t>(chromaSubsampling));
175*ec779b8eSAndroid Build Coastguard Worker     }
176*ec779b8eSAndroid Build Coastguard Worker     // Set CSD in the meta format
177*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size());
178*ec779b8eSAndroid Build Coastguard Worker     return true;
179*ec779b8eSAndroid Build Coastguard Worker }
180*ec779b8eSAndroid Build Coastguard Worker 
181*ec779b8eSAndroid Build Coastguard Worker // The param data contains the first frame data, starting with the uncompressed frame
182*ec779b8eSAndroid Build Coastguard Worker // header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
183*ec779b8eSAndroid Build Coastguard Worker // used to parse profile, bitdepth and subsampling.
MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat * meta,const uint8_t * data,size_t size)184*ec779b8eSAndroid Build Coastguard Worker bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) {
185*ec779b8eSAndroid Build Coastguard Worker     if (meta == nullptr || data == nullptr || size == 0) {
186*ec779b8eSAndroid Build Coastguard Worker         return false;
187*ec779b8eSAndroid Build Coastguard Worker     }
188*ec779b8eSAndroid Build Coastguard Worker 
189*ec779b8eSAndroid Build Coastguard Worker     ABitReader bits(data, size);
190*ec779b8eSAndroid Build Coastguard Worker 
191*ec779b8eSAndroid Build Coastguard Worker     // First 2 bits of the uncompressed header should be the frame_marker.
192*ec779b8eSAndroid Build Coastguard Worker     if (bits.getBits(2) != 0b10) {
193*ec779b8eSAndroid Build Coastguard Worker         return false;
194*ec779b8eSAndroid Build Coastguard Worker     }
195*ec779b8eSAndroid Build Coastguard Worker 
196*ec779b8eSAndroid Build Coastguard Worker     int32_t profileLowBit = bits.getBits(1);
197*ec779b8eSAndroid Build Coastguard Worker     int32_t profileHighBit = bits.getBits(1);
198*ec779b8eSAndroid Build Coastguard Worker     int32_t profile = profileHighBit * 2 + profileLowBit;
199*ec779b8eSAndroid Build Coastguard Worker 
200*ec779b8eSAndroid Build Coastguard Worker     // One reserved '0' bit if profile is 3.
201*ec779b8eSAndroid Build Coastguard Worker     if (profile == 3 && bits.getBits(1) != 0) {
202*ec779b8eSAndroid Build Coastguard Worker         return false;
203*ec779b8eSAndroid Build Coastguard Worker     }
204*ec779b8eSAndroid Build Coastguard Worker 
205*ec779b8eSAndroid Build Coastguard Worker     // If show_existing_frame is set, we get no more data. Since this is
206*ec779b8eSAndroid Build Coastguard Worker     // expected to be the first frame, we can return false which will cascade
207*ec779b8eSAndroid Build Coastguard Worker     // into ERROR_MALFORMED.
208*ec779b8eSAndroid Build Coastguard Worker     if (bits.getBits(1)) {
209*ec779b8eSAndroid Build Coastguard Worker         return false;
210*ec779b8eSAndroid Build Coastguard Worker     }
211*ec779b8eSAndroid Build Coastguard Worker 
212*ec779b8eSAndroid Build Coastguard Worker     int32_t frame_type = bits.getBits(1);
213*ec779b8eSAndroid Build Coastguard Worker 
214*ec779b8eSAndroid Build Coastguard Worker     // Upto 7 bits could be read till now, which were guaranteed to be available
215*ec779b8eSAndroid Build Coastguard Worker     // since size > 0. Check for bits available before reading them from now on.
216*ec779b8eSAndroid Build Coastguard Worker     if (bits.numBitsLeft() < 2) {
217*ec779b8eSAndroid Build Coastguard Worker         return false;
218*ec779b8eSAndroid Build Coastguard Worker     }
219*ec779b8eSAndroid Build Coastguard Worker 
220*ec779b8eSAndroid Build Coastguard Worker     int32_t show_frame = bits.getBits(1);
221*ec779b8eSAndroid Build Coastguard Worker     int32_t error_resilient_mode = bits.getBits(1);
222*ec779b8eSAndroid Build Coastguard Worker     int32_t bitDepth = 8;
223*ec779b8eSAndroid Build Coastguard Worker     int32_t chromaSubsampling = -1;
224*ec779b8eSAndroid Build Coastguard Worker 
225*ec779b8eSAndroid Build Coastguard Worker     if (frame_type == 0 /* KEY_FRAME */) {
226*ec779b8eSAndroid Build Coastguard Worker         // Check for sync code.
227*ec779b8eSAndroid Build Coastguard Worker         if (!isVp9SyncCode(bits)) {
228*ec779b8eSAndroid Build Coastguard Worker             return false;
229*ec779b8eSAndroid Build Coastguard Worker         }
230*ec779b8eSAndroid Build Coastguard Worker 
231*ec779b8eSAndroid Build Coastguard Worker         if (!getVp9BitdepthChromaSubSampling(bits, profile, &bitDepth, &chromaSubsampling)) {
232*ec779b8eSAndroid Build Coastguard Worker             return false;
233*ec779b8eSAndroid Build Coastguard Worker         }
234*ec779b8eSAndroid Build Coastguard Worker     } else {
235*ec779b8eSAndroid Build Coastguard Worker         int32_t intra_only = 0;
236*ec779b8eSAndroid Build Coastguard Worker         if (!show_frame) {
237*ec779b8eSAndroid Build Coastguard Worker             if (bits.numBitsLeft() < 1) {
238*ec779b8eSAndroid Build Coastguard Worker                 return false;
239*ec779b8eSAndroid Build Coastguard Worker             }
240*ec779b8eSAndroid Build Coastguard Worker             intra_only = bits.getBits(1);
241*ec779b8eSAndroid Build Coastguard Worker         }
242*ec779b8eSAndroid Build Coastguard Worker 
243*ec779b8eSAndroid Build Coastguard Worker         if (!error_resilient_mode) {
244*ec779b8eSAndroid Build Coastguard Worker             if (bits.numBitsLeft() < 2) {
245*ec779b8eSAndroid Build Coastguard Worker                 return false;
246*ec779b8eSAndroid Build Coastguard Worker             }
247*ec779b8eSAndroid Build Coastguard Worker             // ignore reset_frame_context
248*ec779b8eSAndroid Build Coastguard Worker             bits.skipBits(2);
249*ec779b8eSAndroid Build Coastguard Worker         }
250*ec779b8eSAndroid Build Coastguard Worker 
251*ec779b8eSAndroid Build Coastguard Worker         if (!intra_only) {
252*ec779b8eSAndroid Build Coastguard Worker             // Require first frame to be either KEY_FRAME or INTER_FRAME with intra_only set to true
253*ec779b8eSAndroid Build Coastguard Worker             return false;
254*ec779b8eSAndroid Build Coastguard Worker         }
255*ec779b8eSAndroid Build Coastguard Worker 
256*ec779b8eSAndroid Build Coastguard Worker         // Check for sync code.
257*ec779b8eSAndroid Build Coastguard Worker         if (!isVp9SyncCode(bits)) {
258*ec779b8eSAndroid Build Coastguard Worker             return false;
259*ec779b8eSAndroid Build Coastguard Worker         }
260*ec779b8eSAndroid Build Coastguard Worker 
261*ec779b8eSAndroid Build Coastguard Worker         if (profile > 0) {
262*ec779b8eSAndroid Build Coastguard Worker             if (!getVp9BitdepthChromaSubSampling(bits, profile, &bitDepth, &chromaSubsampling)) {
263*ec779b8eSAndroid Build Coastguard Worker                 return false;
264*ec779b8eSAndroid Build Coastguard Worker             }
265*ec779b8eSAndroid Build Coastguard Worker         } else {
266*ec779b8eSAndroid Build Coastguard Worker             bitDepth = 8;
267*ec779b8eSAndroid Build Coastguard Worker             chromaSubsampling = 3;
268*ec779b8eSAndroid Build Coastguard Worker         }
269*ec779b8eSAndroid Build Coastguard Worker     }
270*ec779b8eSAndroid Build Coastguard Worker     int32_t csdSize = 6;
271*ec779b8eSAndroid Build Coastguard Worker     if (chromaSubsampling != -1) {
272*ec779b8eSAndroid Build Coastguard Worker         csdSize += 3;
273*ec779b8eSAndroid Build Coastguard Worker     }
274*ec779b8eSAndroid Build Coastguard Worker     // As level is not present in first frame build CodecPrivate without it.
275*ec779b8eSAndroid Build Coastguard Worker     return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling);
276*ec779b8eSAndroid Build Coastguard Worker }
277*ec779b8eSAndroid Build Coastguard Worker 
MakeVP9CodecPrivateFromVpcC(AMediaFormat * meta,const uint8_t * csdData,size_t size)278*ec779b8eSAndroid Build Coastguard Worker bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) {
279*ec779b8eSAndroid Build Coastguard Worker     if (meta == nullptr || csdData == nullptr || size < 12) {
280*ec779b8eSAndroid Build Coastguard Worker         return false;
281*ec779b8eSAndroid Build Coastguard Worker     }
282*ec779b8eSAndroid Build Coastguard Worker 
283*ec779b8eSAndroid Build Coastguard Worker     // Check the first 4 bytes (VersionAndFlags) if they match the required value.
284*ec779b8eSAndroid Build Coastguard Worker     if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) {
285*ec779b8eSAndroid Build Coastguard Worker         return false;
286*ec779b8eSAndroid Build Coastguard Worker     }
287*ec779b8eSAndroid Build Coastguard Worker 
288*ec779b8eSAndroid Build Coastguard Worker     // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed.
289*ec779b8eSAndroid Build Coastguard Worker     // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
290*ec779b8eSAndroid Build Coastguard Worker     const uint8_t* vpcCData = csdData + 4;  // Skip the first 4 bytes (VersionAndFlags)
291*ec779b8eSAndroid Build Coastguard Worker 
292*ec779b8eSAndroid Build Coastguard Worker     int32_t profile = vpcCData[0];
293*ec779b8eSAndroid Build Coastguard Worker     int32_t level = vpcCData[1];
294*ec779b8eSAndroid Build Coastguard Worker     int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F;           // Bit Depth (4 bits).
295*ec779b8eSAndroid Build Coastguard Worker     int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07;  // Chroma Subsampling (3 bits).
296*ec779b8eSAndroid Build Coastguard Worker     return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling);
297*ec779b8eSAndroid Build Coastguard Worker }
298*ec779b8eSAndroid Build Coastguard Worker 
MakeAACCodecSpecificData(MetaDataBase & meta,const uint8_t * data,size_t size)299*ec779b8eSAndroid Build Coastguard Worker bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
300*ec779b8eSAndroid Build Coastguard Worker     if (data == nullptr || size < 7) {
301*ec779b8eSAndroid Build Coastguard Worker         return false;
302*ec779b8eSAndroid Build Coastguard Worker     }
303*ec779b8eSAndroid Build Coastguard Worker 
304*ec779b8eSAndroid Build Coastguard Worker     ABitReader bits(data, size);
305*ec779b8eSAndroid Build Coastguard Worker 
306*ec779b8eSAndroid Build Coastguard Worker     // adts_fixed_header
307*ec779b8eSAndroid Build Coastguard Worker 
308*ec779b8eSAndroid Build Coastguard Worker     if (bits.getBits(12) != 0xfffu) {
309*ec779b8eSAndroid Build Coastguard Worker         ALOGE("Wrong atds_fixed_header");
310*ec779b8eSAndroid Build Coastguard Worker         return false;
311*ec779b8eSAndroid Build Coastguard Worker     }
312*ec779b8eSAndroid Build Coastguard Worker 
313*ec779b8eSAndroid Build Coastguard Worker     bits.skipBits(4);  // ID, layer, protection_absent
314*ec779b8eSAndroid Build Coastguard Worker 
315*ec779b8eSAndroid Build Coastguard Worker     unsigned profile = bits.getBits(2);
316*ec779b8eSAndroid Build Coastguard Worker     if (profile == 3u) {
317*ec779b8eSAndroid Build Coastguard Worker         ALOGE("profile should not be 3");
318*ec779b8eSAndroid Build Coastguard Worker         return false;
319*ec779b8eSAndroid Build Coastguard Worker     }
320*ec779b8eSAndroid Build Coastguard Worker     unsigned sampling_freq_index = bits.getBits(4);
321*ec779b8eSAndroid Build Coastguard Worker     bits.getBits(1);  // private_bit
322*ec779b8eSAndroid Build Coastguard Worker     unsigned channel_configuration = bits.getBits(3);
323*ec779b8eSAndroid Build Coastguard Worker     if (channel_configuration == 0u) {
324*ec779b8eSAndroid Build Coastguard Worker         ALOGE("channel_config should not be 0");
325*ec779b8eSAndroid Build Coastguard Worker         return false;
326*ec779b8eSAndroid Build Coastguard Worker     }
327*ec779b8eSAndroid Build Coastguard Worker 
328*ec779b8eSAndroid Build Coastguard Worker     if (!MakeAACCodecSpecificData(
329*ec779b8eSAndroid Build Coastguard Worker             meta, profile, sampling_freq_index, channel_configuration)) {
330*ec779b8eSAndroid Build Coastguard Worker         return false;
331*ec779b8eSAndroid Build Coastguard Worker     }
332*ec779b8eSAndroid Build Coastguard Worker 
333*ec779b8eSAndroid Build Coastguard Worker     meta.setInt32(kKeyIsADTS, true);
334*ec779b8eSAndroid Build Coastguard Worker     return true;
335*ec779b8eSAndroid Build Coastguard Worker }
336*ec779b8eSAndroid Build Coastguard Worker 
MakeAACCodecSpecificData(uint8_t * csd,size_t * esds_size,unsigned profile,unsigned sampling_freq_index,unsigned channel_configuration,int32_t * sampling_rate)337*ec779b8eSAndroid Build Coastguard Worker bool MakeAACCodecSpecificData(
338*ec779b8eSAndroid Build Coastguard Worker         uint8_t *csd, /* out */
339*ec779b8eSAndroid Build Coastguard Worker         size_t *esds_size, /* in/out */
340*ec779b8eSAndroid Build Coastguard Worker         unsigned profile, /* in */
341*ec779b8eSAndroid Build Coastguard Worker         unsigned sampling_freq_index, /* in */
342*ec779b8eSAndroid Build Coastguard Worker         unsigned channel_configuration, /* in */
343*ec779b8eSAndroid Build Coastguard Worker         int32_t *sampling_rate /* out */
344*ec779b8eSAndroid Build Coastguard Worker ) {
345*ec779b8eSAndroid Build Coastguard Worker     if(sampling_freq_index > 11u) {
346*ec779b8eSAndroid Build Coastguard Worker         return false;
347*ec779b8eSAndroid Build Coastguard Worker     }
348*ec779b8eSAndroid Build Coastguard Worker     static const int32_t kSamplingFreq[] = {
349*ec779b8eSAndroid Build Coastguard Worker         96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
350*ec779b8eSAndroid Build Coastguard Worker         16000, 12000, 11025, 8000
351*ec779b8eSAndroid Build Coastguard Worker     };
352*ec779b8eSAndroid Build Coastguard Worker     *sampling_rate = kSamplingFreq[sampling_freq_index];
353*ec779b8eSAndroid Build Coastguard Worker 
354*ec779b8eSAndroid Build Coastguard Worker     static const uint8_t kStaticESDS[] = {
355*ec779b8eSAndroid Build Coastguard Worker         0x03, 22,
356*ec779b8eSAndroid Build Coastguard Worker         0x00, 0x00,     // ES_ID
357*ec779b8eSAndroid Build Coastguard Worker         0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
358*ec779b8eSAndroid Build Coastguard Worker 
359*ec779b8eSAndroid Build Coastguard Worker         0x04, 17,
360*ec779b8eSAndroid Build Coastguard Worker         0x40,                       // Audio ISO/IEC 14496-3
361*ec779b8eSAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00,
362*ec779b8eSAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00,
363*ec779b8eSAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00,
364*ec779b8eSAndroid Build Coastguard Worker 
365*ec779b8eSAndroid Build Coastguard Worker         0x05, 2,
366*ec779b8eSAndroid Build Coastguard Worker         // AudioSpecificInfo follows
367*ec779b8eSAndroid Build Coastguard Worker 
368*ec779b8eSAndroid Build Coastguard Worker         // oooo offf fccc c000
369*ec779b8eSAndroid Build Coastguard Worker         // o - audioObjectType
370*ec779b8eSAndroid Build Coastguard Worker         // f - samplingFreqIndex
371*ec779b8eSAndroid Build Coastguard Worker         // c - channelConfig
372*ec779b8eSAndroid Build Coastguard Worker     };
373*ec779b8eSAndroid Build Coastguard Worker 
374*ec779b8eSAndroid Build Coastguard Worker     size_t csdSize = sizeof(kStaticESDS) + 2;
375*ec779b8eSAndroid Build Coastguard Worker     if (csdSize > *esds_size) {
376*ec779b8eSAndroid Build Coastguard Worker         return false;
377*ec779b8eSAndroid Build Coastguard Worker     }
378*ec779b8eSAndroid Build Coastguard Worker     memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
379*ec779b8eSAndroid Build Coastguard Worker 
380*ec779b8eSAndroid Build Coastguard Worker     csd[sizeof(kStaticESDS)] =
381*ec779b8eSAndroid Build Coastguard Worker         ((profile + 1) << 3) | (sampling_freq_index >> 1);
382*ec779b8eSAndroid Build Coastguard Worker 
383*ec779b8eSAndroid Build Coastguard Worker     csd[sizeof(kStaticESDS) + 1] =
384*ec779b8eSAndroid Build Coastguard Worker         ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
385*ec779b8eSAndroid Build Coastguard Worker 
386*ec779b8eSAndroid Build Coastguard Worker     *esds_size = csdSize;
387*ec779b8eSAndroid Build Coastguard Worker     return true;
388*ec779b8eSAndroid Build Coastguard Worker }
389*ec779b8eSAndroid Build Coastguard Worker 
MakeAACCodecSpecificData(AMediaFormat * meta,unsigned profile,unsigned sampling_freq_index,unsigned channel_configuration)390*ec779b8eSAndroid Build Coastguard Worker bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
391*ec779b8eSAndroid Build Coastguard Worker         unsigned channel_configuration) {
392*ec779b8eSAndroid Build Coastguard Worker 
393*ec779b8eSAndroid Build Coastguard Worker     if(sampling_freq_index > 11u) {
394*ec779b8eSAndroid Build Coastguard Worker         return false;
395*ec779b8eSAndroid Build Coastguard Worker     }
396*ec779b8eSAndroid Build Coastguard Worker 
397*ec779b8eSAndroid Build Coastguard Worker     uint8_t csd[2];
398*ec779b8eSAndroid Build Coastguard Worker     csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
399*ec779b8eSAndroid Build Coastguard Worker     csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
400*ec779b8eSAndroid Build Coastguard Worker 
401*ec779b8eSAndroid Build Coastguard Worker     static const int32_t kSamplingFreq[] = {
402*ec779b8eSAndroid Build Coastguard Worker         96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
403*ec779b8eSAndroid Build Coastguard Worker         16000, 12000, 11025, 8000
404*ec779b8eSAndroid Build Coastguard Worker     };
405*ec779b8eSAndroid Build Coastguard Worker     int32_t sampleRate = kSamplingFreq[sampling_freq_index];
406*ec779b8eSAndroid Build Coastguard Worker 
407*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
408*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
409*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
410*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
411*ec779b8eSAndroid Build Coastguard Worker 
412*ec779b8eSAndroid Build Coastguard Worker     return true;
413*ec779b8eSAndroid Build Coastguard Worker }
414*ec779b8eSAndroid Build Coastguard Worker 
MakeAACCodecSpecificData(MetaDataBase & meta,unsigned profile,unsigned sampling_freq_index,unsigned channel_configuration)415*ec779b8eSAndroid Build Coastguard Worker bool MakeAACCodecSpecificData(
416*ec779b8eSAndroid Build Coastguard Worker         MetaDataBase &meta,
417*ec779b8eSAndroid Build Coastguard Worker         unsigned profile, unsigned sampling_freq_index,
418*ec779b8eSAndroid Build Coastguard Worker         unsigned channel_configuration) {
419*ec779b8eSAndroid Build Coastguard Worker 
420*ec779b8eSAndroid Build Coastguard Worker     uint8_t csd[24];
421*ec779b8eSAndroid Build Coastguard Worker     size_t csdSize = sizeof(csd);
422*ec779b8eSAndroid Build Coastguard Worker     int32_t sampleRate;
423*ec779b8eSAndroid Build Coastguard Worker 
424*ec779b8eSAndroid Build Coastguard Worker     if (!MakeAACCodecSpecificData(csd, &csdSize, profile, sampling_freq_index,
425*ec779b8eSAndroid Build Coastguard Worker             channel_configuration, &sampleRate)) {
426*ec779b8eSAndroid Build Coastguard Worker         return false;
427*ec779b8eSAndroid Build Coastguard Worker     }
428*ec779b8eSAndroid Build Coastguard Worker 
429*ec779b8eSAndroid Build Coastguard Worker     meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
430*ec779b8eSAndroid Build Coastguard Worker 
431*ec779b8eSAndroid Build Coastguard Worker     meta.setInt32(kKeySampleRate, sampleRate);
432*ec779b8eSAndroid Build Coastguard Worker     meta.setInt32(kKeyChannelCount, channel_configuration);
433*ec779b8eSAndroid Build Coastguard Worker     meta.setData(kKeyESDS, 0, csd, csdSize);
434*ec779b8eSAndroid Build Coastguard Worker     return true;
435*ec779b8eSAndroid Build Coastguard Worker }
436*ec779b8eSAndroid Build Coastguard Worker 
437*ec779b8eSAndroid Build Coastguard Worker 
extractAlbumArt(AMediaFormat * fileMeta,const void * data,size_t size)438*ec779b8eSAndroid Build Coastguard Worker static void extractAlbumArt(
439*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat *fileMeta, const void *data, size_t size) {
440*ec779b8eSAndroid Build Coastguard Worker     ALOGV("extractAlbumArt from '%s'", (const char *)data);
441*ec779b8eSAndroid Build Coastguard Worker 
442*ec779b8eSAndroid Build Coastguard Worker     size_t inLen = strnlen((const char *)data, size);
443*ec779b8eSAndroid Build Coastguard Worker     size_t flacSize = inLen / 4 * 3;
444*ec779b8eSAndroid Build Coastguard Worker     uint8_t *flac = new uint8_t[flacSize];
445*ec779b8eSAndroid Build Coastguard Worker     if (!decodeBase64(flac, &flacSize, (const char*)data)) {
446*ec779b8eSAndroid Build Coastguard Worker         ALOGE("malformed base64 encoded data.");
447*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
448*ec779b8eSAndroid Build Coastguard Worker         return;
449*ec779b8eSAndroid Build Coastguard Worker     }
450*ec779b8eSAndroid Build Coastguard Worker 
451*ec779b8eSAndroid Build Coastguard Worker     ALOGV("got flac of size %zu", flacSize);
452*ec779b8eSAndroid Build Coastguard Worker 
453*ec779b8eSAndroid Build Coastguard Worker     uint32_t picType;
454*ec779b8eSAndroid Build Coastguard Worker     uint32_t typeLen;
455*ec779b8eSAndroid Build Coastguard Worker     uint32_t descLen;
456*ec779b8eSAndroid Build Coastguard Worker     uint32_t dataLen;
457*ec779b8eSAndroid Build Coastguard Worker     char type[128];
458*ec779b8eSAndroid Build Coastguard Worker 
459*ec779b8eSAndroid Build Coastguard Worker     if (flacSize < 8) {
460*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
461*ec779b8eSAndroid Build Coastguard Worker         return;
462*ec779b8eSAndroid Build Coastguard Worker     }
463*ec779b8eSAndroid Build Coastguard Worker 
464*ec779b8eSAndroid Build Coastguard Worker     picType = U32_AT(flac);
465*ec779b8eSAndroid Build Coastguard Worker 
466*ec779b8eSAndroid Build Coastguard Worker     if (picType != 3) {
467*ec779b8eSAndroid Build Coastguard Worker         // This is not a front cover.
468*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
469*ec779b8eSAndroid Build Coastguard Worker         return;
470*ec779b8eSAndroid Build Coastguard Worker     }
471*ec779b8eSAndroid Build Coastguard Worker 
472*ec779b8eSAndroid Build Coastguard Worker     typeLen = U32_AT(&flac[4]);
473*ec779b8eSAndroid Build Coastguard Worker     if (typeLen > sizeof(type) - 1) {
474*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
475*ec779b8eSAndroid Build Coastguard Worker         return;
476*ec779b8eSAndroid Build Coastguard Worker     }
477*ec779b8eSAndroid Build Coastguard Worker 
478*ec779b8eSAndroid Build Coastguard Worker     // we've already checked above that flacSize >= 8
479*ec779b8eSAndroid Build Coastguard Worker     if (flacSize - 8 < typeLen) {
480*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
481*ec779b8eSAndroid Build Coastguard Worker         return;
482*ec779b8eSAndroid Build Coastguard Worker     }
483*ec779b8eSAndroid Build Coastguard Worker 
484*ec779b8eSAndroid Build Coastguard Worker     memcpy(type, &flac[8], typeLen);
485*ec779b8eSAndroid Build Coastguard Worker     type[typeLen] = '\0';
486*ec779b8eSAndroid Build Coastguard Worker 
487*ec779b8eSAndroid Build Coastguard Worker     ALOGV("picType = %d, type = '%s'", picType, type);
488*ec779b8eSAndroid Build Coastguard Worker 
489*ec779b8eSAndroid Build Coastguard Worker     if (!strcmp(type, "-->")) {
490*ec779b8eSAndroid Build Coastguard Worker         // This is not inline cover art, but an external url instead.
491*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
492*ec779b8eSAndroid Build Coastguard Worker         return;
493*ec779b8eSAndroid Build Coastguard Worker     }
494*ec779b8eSAndroid Build Coastguard Worker 
495*ec779b8eSAndroid Build Coastguard Worker     if (flacSize < 32 || flacSize - 32 < typeLen) {
496*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
497*ec779b8eSAndroid Build Coastguard Worker         return;
498*ec779b8eSAndroid Build Coastguard Worker     }
499*ec779b8eSAndroid Build Coastguard Worker 
500*ec779b8eSAndroid Build Coastguard Worker     descLen = U32_AT(&flac[8 + typeLen]);
501*ec779b8eSAndroid Build Coastguard Worker     if (flacSize - 32 - typeLen < descLen) {
502*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
503*ec779b8eSAndroid Build Coastguard Worker         return;
504*ec779b8eSAndroid Build Coastguard Worker     }
505*ec779b8eSAndroid Build Coastguard Worker 
506*ec779b8eSAndroid Build Coastguard Worker     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
507*ec779b8eSAndroid Build Coastguard Worker 
508*ec779b8eSAndroid Build Coastguard Worker     // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
509*ec779b8eSAndroid Build Coastguard Worker     if (flacSize - 32 - typeLen - descLen < dataLen) {
510*ec779b8eSAndroid Build Coastguard Worker         delete[] flac;
511*ec779b8eSAndroid Build Coastguard Worker         return;
512*ec779b8eSAndroid Build Coastguard Worker     }
513*ec779b8eSAndroid Build Coastguard Worker 
514*ec779b8eSAndroid Build Coastguard Worker     ALOGV("got image data, %zu trailing bytes",
515*ec779b8eSAndroid Build Coastguard Worker          flacSize - 32 - typeLen - descLen - dataLen);
516*ec779b8eSAndroid Build Coastguard Worker 
517*ec779b8eSAndroid Build Coastguard Worker     AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
518*ec779b8eSAndroid Build Coastguard Worker             &flac[8 + typeLen + 4 + descLen + 20], dataLen);
519*ec779b8eSAndroid Build Coastguard Worker 
520*ec779b8eSAndroid Build Coastguard Worker     delete[] flac;
521*ec779b8eSAndroid Build Coastguard Worker }
522*ec779b8eSAndroid Build Coastguard Worker 
parseVorbisComment(AMediaFormat * fileMeta,const char * comment,size_t commentLength)523*ec779b8eSAndroid Build Coastguard Worker void parseVorbisComment(
524*ec779b8eSAndroid Build Coastguard Worker         AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
525*ec779b8eSAndroid Build Coastguard Worker     // Haptic tag is only kept here as it will only be used in extractor to generate channel mask.
526*ec779b8eSAndroid Build Coastguard Worker     struct {
527*ec779b8eSAndroid Build Coastguard Worker         const char *const mTag;
528*ec779b8eSAndroid Build Coastguard Worker         const char *mKey;
529*ec779b8eSAndroid Build Coastguard Worker     } kMap[] = {
530*ec779b8eSAndroid Build Coastguard Worker         { "TITLE", AMEDIAFORMAT_KEY_TITLE },
531*ec779b8eSAndroid Build Coastguard Worker         { "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
532*ec779b8eSAndroid Build Coastguard Worker         { "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
533*ec779b8eSAndroid Build Coastguard Worker         { "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
534*ec779b8eSAndroid Build Coastguard Worker         { "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
535*ec779b8eSAndroid Build Coastguard Worker         { "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
536*ec779b8eSAndroid Build Coastguard Worker         { "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
537*ec779b8eSAndroid Build Coastguard Worker         { "GENRE", AMEDIAFORMAT_KEY_GENRE },
538*ec779b8eSAndroid Build Coastguard Worker         { "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
539*ec779b8eSAndroid Build Coastguard Worker         { "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
540*ec779b8eSAndroid Build Coastguard Worker         { "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
541*ec779b8eSAndroid Build Coastguard Worker         { "DATE", AMEDIAFORMAT_KEY_DATE },
542*ec779b8eSAndroid Build Coastguard Worker         { "YEAR", AMEDIAFORMAT_KEY_YEAR },
543*ec779b8eSAndroid Build Coastguard Worker         { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
544*ec779b8eSAndroid Build Coastguard Worker         { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
545*ec779b8eSAndroid Build Coastguard Worker         { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
546*ec779b8eSAndroid Build Coastguard Worker         { "ANDROID_HAPTIC", AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT },
547*ec779b8eSAndroid Build Coastguard Worker     };
548*ec779b8eSAndroid Build Coastguard Worker 
549*ec779b8eSAndroid Build Coastguard Worker         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
550*ec779b8eSAndroid Build Coastguard Worker             size_t tagLen = strlen(kMap[j].mTag);
551*ec779b8eSAndroid Build Coastguard Worker             if (!strncasecmp(kMap[j].mTag, comment, tagLen)
552*ec779b8eSAndroid Build Coastguard Worker                     && comment[tagLen] == '=') {
553*ec779b8eSAndroid Build Coastguard Worker                 if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
554*ec779b8eSAndroid Build Coastguard Worker                     extractAlbumArt(
555*ec779b8eSAndroid Build Coastguard Worker                             fileMeta,
556*ec779b8eSAndroid Build Coastguard Worker                             &comment[tagLen + 1],
557*ec779b8eSAndroid Build Coastguard Worker                             commentLength - tagLen - 1);
558*ec779b8eSAndroid Build Coastguard Worker                 } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
559*ec779b8eSAndroid Build Coastguard Worker                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
560*ec779b8eSAndroid Build Coastguard Worker                         AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
561*ec779b8eSAndroid Build Coastguard Worker                     }
562*ec779b8eSAndroid Build Coastguard Worker                 } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT) {
563*ec779b8eSAndroid Build Coastguard Worker                     char *end;
564*ec779b8eSAndroid Build Coastguard Worker                     errno = 0;
565*ec779b8eSAndroid Build Coastguard Worker                     const int hapticChannelCount = strtol(&comment[tagLen + 1], &end, 10);
566*ec779b8eSAndroid Build Coastguard Worker                     if (errno == 0) {
567*ec779b8eSAndroid Build Coastguard Worker                         AMediaFormat_setInt32(fileMeta, kMap[j].mKey, hapticChannelCount);
568*ec779b8eSAndroid Build Coastguard Worker                     } else {
569*ec779b8eSAndroid Build Coastguard Worker                         ALOGE("Error(%d) when parsing haptic channel count", errno);
570*ec779b8eSAndroid Build Coastguard Worker                     }
571*ec779b8eSAndroid Build Coastguard Worker                 } else {
572*ec779b8eSAndroid Build Coastguard Worker                     AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
573*ec779b8eSAndroid Build Coastguard Worker                 }
574*ec779b8eSAndroid Build Coastguard Worker             }
575*ec779b8eSAndroid Build Coastguard Worker         }
576*ec779b8eSAndroid Build Coastguard Worker 
577*ec779b8eSAndroid Build Coastguard Worker }
578*ec779b8eSAndroid Build Coastguard Worker 
579*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
580