1 /**
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <media/NdkMediaCodec.h>
18 #include <media/NdkMediaFormat.h>
19 #include <ImsMediaVideoUtil.h>
20 #include <ImsMediaBitReader.h>
21 #include <ImsMediaBinaryFormat.h>
22 #include <ImsMediaTrace.h>
23 #include <VideoConfig.h>
24 #include <memory>
25 #include <string.h>
26
27 #define START_CODE_PREFIX_LEN 4
28 #define MAX_OUTPUT_BUFFER_READ_ATTEMPTS 5
29 #define FRAME_TYPE_SPS 7
30 #define FRAME_TYPE_PPS 8
31
ImsMediaVideoUtil()32 ImsMediaVideoUtil::ImsMediaVideoUtil() {}
33
~ImsMediaVideoUtil()34 ImsMediaVideoUtil::~ImsMediaVideoUtil() {}
35
ConvertCodecType(int32_t type)36 int32_t ImsMediaVideoUtil::ConvertCodecType(int32_t type)
37 {
38 switch (type)
39 {
40 default:
41 case VideoConfig::CODEC_AVC:
42 return kVideoCodecAvc;
43 case VideoConfig::CODEC_HEVC:
44 return kVideoCodecHevc;
45 }
46 }
47
GetResolutionFromSize(uint32_t nWidth,uint32_t nHeight)48 uint32_t ImsMediaVideoUtil::GetResolutionFromSize(uint32_t nWidth, uint32_t nHeight)
49 {
50 if (nWidth == 128 && nHeight == 96)
51 return kVideoResolutionSqcifLandscape;
52 else if (nWidth == 96 && nHeight == 128)
53 return kVideoResolutionSqcifPortrait;
54 else if (nWidth == 480 && nHeight == 640)
55 return kVideoResolutionVgaPortrait;
56 else if (nWidth == 640 && nHeight == 480)
57 return kVideoResolutionVgaLandscape;
58 else if (nWidth == 240 && nHeight == 320)
59 return kVideoResolutionQvgaPortrait;
60 else if (nWidth == 320 && nHeight == 240)
61 return kVideoResolutionQvgaLandscape;
62 else if (nWidth == 144 && nHeight == 176)
63 return kVideoResolutionQcifPortrait;
64 else if (nWidth == 176 && nHeight == 144)
65 return kVideoResolutionQcifLandscape;
66 else if (nWidth == 352 && nHeight == 288)
67 return kVideoResolutionCifLandscape;
68 else if (nWidth == 288 && nHeight == 352)
69 return kVideoResolutionCifPortrait;
70 else if (nWidth == 240 && nHeight == 352)
71 return kVideoResolutionSifPortrait;
72 else if (nWidth == 352 && nHeight == 240)
73 return kVideoResolutionSifLandscape;
74 else if (nWidth == 1280 && nHeight == 720)
75 return kVideoResolutionHdLandscape;
76 else if (nWidth == 720 && nHeight == 1280)
77 return kVideoResolutionHdPortrait;
78 else
79 return kVideoResolutionInvalid;
80 }
81
ParseAvcSpropParam(const char * szSpropparam,tCodecConfig * pInfo)82 ImsMediaResult ImsMediaVideoUtil::ParseAvcSpropParam(const char* szSpropparam, tCodecConfig* pInfo)
83 {
84 ImsMediaBitReader bitreader;
85 bool ret = false;
86 uint8_t pbSPSConfig[MAX_CONFIG_LEN] = {'\0'};
87 char pSPSConfig[MAX_CONFIG_LEN] = {'\0'};
88 uint32_t nSPSConfigSize = 0;
89 uint32_t chroma_format_idc = 0;
90
91 memset(pSPSConfig, 0x00, MAX_CONFIG_LEN);
92
93 for (int32_t i = 0; i < MAX_CONFIG_LEN; i++)
94 {
95 uint8_t Comma = ',';
96 char cmpConfig = *(szSpropparam + i);
97 if (Comma == cmpConfig)
98 {
99 memset(pSPSConfig, 0x00, MAX_CONFIG_LEN);
100 memcpy(pSPSConfig, szSpropparam, i);
101 }
102 }
103
104 ret = ImsMediaBinaryFormat::Base00ToBinary(
105 pbSPSConfig, &nSPSConfigSize, MAX_CONFIG_LEN, pSPSConfig, BINARY_FORMAT_BASE64);
106
107 if (ret == false)
108 {
109 IMLOGW0("[ParseAvcSpropParam] sps convert fail");
110 return RESULT_INVALID_PARAM;
111 }
112
113 uint8_t* pszSpropparam = reinterpret_cast<uint8_t*>(malloc(nSPSConfigSize));
114
115 if (pszSpropparam == nullptr)
116 {
117 pInfo->nProfile = 0;
118 pInfo->nLevel = 0;
119 pInfo->nHeight = 0;
120 pInfo->nWidth = 0;
121
122 return RESULT_NO_MEMORY;
123 }
124
125 memcpy(pszSpropparam, pbSPSConfig, nSPSConfigSize);
126
127 bitreader.SetBuffer(pszSpropparam, nSPSConfigSize);
128 bitreader.Read(8);
129
130 uint32_t Profile_idc = bitreader.Read(8); // Read profile_idc
131
132 // Read constraint
133 bitreader.Read(1); // Constraint_set0
134 bitreader.Read(1); // Constraint_set1
135 bitreader.Read(1); // Constraint_set2
136 bitreader.Read(1); // Constraint_set3
137 bitreader.Read(1); // Constraint_set4
138 bitreader.Read(3); // Read reserved_zeor_3bits
139
140 uint32_t Level_idc = bitreader.Read(8); // Read level_idc
141 bitreader.ReadByUEMode(); // Read Seq_parameter_set_id
142
143 if (Profile_idc == 100 || Profile_idc == 11 || Profile_idc == 122 || Profile_idc == 244 ||
144 Profile_idc == 44 || Profile_idc == 83 || Profile_idc == 86 || Profile_idc == 118)
145 {
146 chroma_format_idc = bitreader.ReadByUEMode();
147
148 if (chroma_format_idc == 3)
149 {
150 bitreader.Read(1); // Separate_colour_plane
151 }
152
153 bitreader.ReadByUEMode(); // Read bit_depth_luma_minus8
154 bitreader.ReadByUEMode(); // Read bit_depth_chroma_minus8
155 bitreader.Read(1); // Read qpprime_y_zero_transformypass
156
157 // Read seq_scaling_matrix_present
158 if (bitreader.Read(1))
159 {
160 uint32_t i = ((chroma_format_idc != 3) ? 8 : 12);
161 // Set scaling_list... not implement
162 bitreader.Read(i);
163 }
164 }
165
166 pInfo->nProfile = Profile_idc;
167 pInfo->nLevel = Level_idc;
168
169 bitreader.ReadByUEMode(); // Read log2_max_frame_num_minus4
170 uint32_t pic_order_cnt_type = bitreader.ReadByUEMode(); // Read pic_order_cnt_type
171
172 if (pic_order_cnt_type == 0)
173 {
174 bitreader.ReadByUEMode(); // Read log2_max_pic_order_cnt_lsb_minus4
175 }
176 else if (pic_order_cnt_type == 1)
177 {
178 bitreader.Read(1); // Read delta_pic_order_always_zero_flag
179 bitreader.ReadByUEMode(); // Reda offset_for_non_ref_pic...
180 bitreader.ReadByUEMode(); // Read offset_for_top_to_bottom_field
181 uint32_t num_ref_frames_in_pic_order_cnt_cycle =
182 bitreader.ReadByUEMode(); // Read num_ref_frames_in_pic_order_cnt_cycle
183 for (int32_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
184 {
185 bitreader.ReadByUEMode(); // Read offset_for_ref_frame[i];
186 }
187 }
188
189 bitreader.ReadByUEMode(); // Read max_num_ref_frames
190 bitreader.Read(1); // Read gaps_in_frame_num_value_allowed
191
192 uint32_t pic_width_in_mbs_minus1 = bitreader.ReadByUEMode(); // Read pic_width_in_mbs_minus1
193 uint32_t pic_height_in_map_units_minus1 =
194 bitreader.ReadByUEMode(); // Read pic_height_in_map_units_minus1
195 uint32_t frame_mbs_only = bitreader.Read(1);
196
197 pInfo->nWidth = pic_width_in_mbs_minus1 * 16 + 16;
198 pInfo->nHeight = (2 - frame_mbs_only) * (pic_height_in_map_units_minus1 * 16 + 16);
199
200 if (!frame_mbs_only)
201 {
202 bitreader.Read(1); // Read mb_adaptive_frame_field
203 }
204
205 bitreader.Read(1); // Read direct_8x8_inferencce_flag
206 uint32_t frame_cropping = bitreader.Read(1); // Read frame_cropping_flag
207
208 if (frame_cropping)
209 {
210 uint32_t frame_crop_left_offset = bitreader.ReadByUEMode(); // Read frame_crop_left_offset
211 uint32_t frame_crop_right_offset = bitreader.ReadByUEMode(); // Read
212 // frame_crop_right_offset
213 uint32_t frame_crop_top_offset = bitreader.ReadByUEMode(); // Read frame_crop_top_offset
214 uint32_t frame_crop_bottom_offset =
215 bitreader.ReadByUEMode(); // Read frame_crop_bottom_offset
216 uint32_t cropX, cropY = 0;
217
218 if (chroma_format_idc == 0 /* Monochrome */)
219 {
220 cropX = 1;
221 cropY = 2 - frame_mbs_only;
222 }
223 else
224 {
225 uint32_t subWidthC = (chroma_format_idc == 3) ? 1 : 2;
226 uint32_t subHeightC = (chroma_format_idc == 1) ? 2 : 1;
227 cropX = subWidthC;
228 cropY = subHeightC * (2 - frame_mbs_only);
229 }
230
231 pInfo->nWidth -= (frame_crop_left_offset + frame_crop_right_offset) * cropX;
232 pInfo->nHeight -= (frame_crop_top_offset + frame_crop_bottom_offset) * cropY;
233 }
234
235 free(pszSpropparam);
236
237 IMLOGD4("[ParseAvcSpropParam] width[%d],height[%d],nProfile[%d],nLevel[%d]", pInfo->nWidth,
238 pInfo->nHeight, pInfo->nProfile, pInfo->nLevel);
239
240 return RESULT_SUCCESS;
241 }
242
ParseHevcSpropParam(const char * szSpropparam,tCodecConfig * pInfo)243 ImsMediaResult ImsMediaVideoUtil::ParseHevcSpropParam(const char* szSpropparam, tCodecConfig* pInfo)
244 {
245 uint32_t nSize = strlen(szSpropparam);
246
247 if (nSize == 0)
248 {
249 return RESULT_INVALID_PARAM;
250 }
251
252 IMLOGD1("[ParseHevcSpropParam] szSpropparam[%s]", szSpropparam);
253
254 uint8_t pbSPSConfig[MAX_CONFIG_LEN] = {'\0'};
255 char pSPSConfig[MAX_CONFIG_LEN] = {'\0'};
256 uint32_t nSPSConfigSize = 0;
257
258 memset(pSPSConfig, 0x00, MAX_CONFIG_LEN);
259 strlcpy(pSPSConfig, szSpropparam, MAX_CONFIG_LEN);
260
261 uint8_t* pszSpropparam = nullptr;
262
263 if (ImsMediaBinaryFormat::Base00ToBinary(pbSPSConfig, &nSPSConfigSize, MAX_CONFIG_LEN,
264 pSPSConfig, BINARY_FORMAT_BASE64) == false)
265 {
266 IMLOGW0("[ParseAvcSpropParam] sps convert fail");
267 return RESULT_INVALID_PARAM;
268 }
269
270 if (nSPSConfigSize == 0)
271 return RESULT_INVALID_PARAM;
272
273 pszSpropparam = reinterpret_cast<uint8_t*>(malloc(nSPSConfigSize));
274
275 if (pszSpropparam == nullptr)
276 {
277 pInfo->nProfile = 0;
278 pInfo->nLevel = 0;
279 pInfo->nHeight = 0;
280 pInfo->nWidth = 0;
281
282 return RESULT_INVALID_PARAM;
283 }
284
285 memcpy(pszSpropparam, pbSPSConfig, nSPSConfigSize);
286
287 // Check binary
288 ImsMediaTrace::IMLOGD_BINARY("[ParseHevcSpropParam] sps=",
289 reinterpret_cast<const char*>(pszSpropparam), nSPSConfigSize);
290
291 uint32_t nOffset = 0;
292
293 for (int32_t i = 0; i < nSPSConfigSize - 6; i++)
294 {
295 // NAL unit header offset
296 if (pszSpropparam[i] == 0x00 && pszSpropparam[i + 1] == 0x00 &&
297 pszSpropparam[i + 2] == 0x00 && pszSpropparam[i + 3] == 0x01 &&
298 pszSpropparam[i + 4] == 0x42 && pszSpropparam[i + 5] == 0x01)
299 {
300 nOffset = i + 6;
301 break;
302 }
303 }
304
305 IMLOGD2("[ParseHevcSpropParam] nSPSConfigSize[%d], offset[%d]", nSPSConfigSize, nOffset);
306
307 ImsMediaBitReader objBitReader;
308 objBitReader.SetBuffer(pszSpropparam + nOffset, nSPSConfigSize - nOffset);
309
310 objBitReader.Read(4); // sps_video_parameter_set_id;
311 uint32_t sps_max_sub_layers_minus1 = objBitReader.Read(3);
312
313 IMLOGD1("[ParseHevcSpropParam] sps_max_sub_layers_minus1[%d]", sps_max_sub_layers_minus1);
314
315 objBitReader.Read(1); // sps_temporal_id_nesting_flag;
316
317 /*-----------profile_tier_level start-----------------------*/
318 objBitReader.Read(3); // general_profile_spac, general_tier_flag
319 uint32_t general_profile_idc = objBitReader.Read(5);
320
321 IMLOGD1("[ParseHevcSpropParam] general_profile_idc[%d]", general_profile_idc);
322
323 // skip 13byte - flags, not handle
324 objBitReader.Read(24);
325 objBitReader.Read(24);
326 objBitReader.Read(24);
327 objBitReader.Read(24);
328 objBitReader.Read(8);
329
330 uint32_t general_level_idc = objBitReader.Read(8);
331
332 IMLOGD1("[ParseHevcSpropParam] general_level_idc[%d]", general_level_idc);
333
334 uint8_t sub_layer_profile_present_flag[sps_max_sub_layers_minus1];
335 uint8_t sub_layer_level_present_flag[sps_max_sub_layers_minus1];
336
337 for (int32_t i = 0; i < sps_max_sub_layers_minus1; i++)
338 {
339 sub_layer_profile_present_flag[i] = objBitReader.Read(1);
340 sub_layer_level_present_flag[i] = objBitReader.Read(1);
341 }
342
343 if (sps_max_sub_layers_minus1 > 0)
344 {
345 for (int32_t j = sps_max_sub_layers_minus1; j < 8; j++)
346 {
347 objBitReader.Read(2);
348 }
349 }
350
351 for (int32_t i = 0; i < sps_max_sub_layers_minus1; i++)
352 {
353 if (sub_layer_profile_present_flag[i])
354 {
355 objBitReader.Read(2); // sub_layer_profile_space
356 objBitReader.Read(1); // sub_layer_tier_flag
357 objBitReader.Read(5); // sub_layer_profile_idc
358 objBitReader.Read(24); // sub_layer_profile_compatibility_flag
359 objBitReader.Read(8); // sub_layer_profile_compatibility_flag
360 objBitReader.Read(24); // sub_layer_constraint_indicator_flags
361 objBitReader.Read(24); // sub_layer_constraint_indicator_flags
362 }
363
364 if (sub_layer_level_present_flag[i])
365 {
366 objBitReader.Read(8); // sub_layer_level_idc
367 }
368 }
369
370 /*-----------profile_tier_level done-----------------------*/
371 objBitReader.ReadByUEMode(); // sps_seq_parameter_set_id
372
373 uint32_t chroma_format_idc;
374 chroma_format_idc = objBitReader.ReadByUEMode();
375
376 IMLOGD1("[ParseHevcSpropParam] chroma_format_idc[%d]", chroma_format_idc);
377
378 if (chroma_format_idc == 3)
379 {
380 objBitReader.Read(1); // separate_colour_plane_flag
381 }
382
383 int32_t pic_width_in_luma_samples = objBitReader.ReadByUEMode();
384 int32_t pic_height_in_luma_samples = objBitReader.ReadByUEMode();
385
386 IMLOGD1("[ParseHevcSpropParam] pic_width_in_luma_samples[%d]", pic_width_in_luma_samples);
387
388 IMLOGD1("[ParseHevcSpropParam] pic_height_in_luma_samples[%d]", pic_height_in_luma_samples);
389
390 pInfo->nWidth = pic_width_in_luma_samples;
391 pInfo->nHeight = pic_height_in_luma_samples;
392
393 uint8_t conformance_window_flag = objBitReader.Read(1);
394
395 IMLOGD1("[ParseHevcSpropParam] conformance_window_flag[%d]", conformance_window_flag);
396
397 if (conformance_window_flag)
398 {
399 uint32_t conf_win_left_offset = objBitReader.ReadByUEMode();
400 uint32_t conf_win_right_offset = objBitReader.ReadByUEMode();
401 uint32_t conf_win_top_offset = objBitReader.ReadByUEMode();
402 uint32_t conf_win_bottom_offset = objBitReader.ReadByUEMode();
403
404 pInfo->nWidth -= conf_win_left_offset + conf_win_right_offset;
405 pInfo->nHeight -= conf_win_top_offset + conf_win_bottom_offset;
406
407 IMLOGD4("[ParseHevcSpropParam] frame_crop = [%u, %u, %u, %u]", conf_win_left_offset,
408 conf_win_right_offset, conf_win_top_offset, conf_win_bottom_offset);
409 }
410
411 // Round down by 16 unit
412 uint32_t nRoundDownWidth = (pInfo->nWidth) / 16 * 16;
413 uint32_t nRoundDownHeight = (pInfo->nHeight) / 16 * 16;
414
415 pInfo->nWidth = nRoundDownWidth;
416 pInfo->nHeight = nRoundDownHeight;
417 free(pszSpropparam);
418 return RESULT_SUCCESS;
419 }
420
ParseAvcSps(uint8_t * pbBuffer,uint32_t nBufferSize,tCodecConfig * pInfo)421 bool ImsMediaVideoUtil::ParseAvcSps(uint8_t* pbBuffer, uint32_t nBufferSize, tCodecConfig* pInfo)
422 {
423 ImsMediaBitReader bitreader;
424 uint32_t chroma_format_idc = 0;
425 uint8_t* pszSPS = reinterpret_cast<uint8_t*>(malloc(nBufferSize));
426
427 if (pszSPS == nullptr)
428 {
429 pInfo->nProfile = 0;
430 pInfo->nLevel = 0;
431 pInfo->nHeight = 0;
432 pInfo->nWidth = 0;
433 return false;
434 }
435
436 memcpy(pszSPS, pbBuffer, nBufferSize);
437
438 IMLOGD_PACKET1(IM_PACKET_LOG_VIDEO, "[ParseAvcSps] pszSPS[%02X]", pszSPS[0]);
439
440 bitreader.SetBuffer(pszSPS, nBufferSize);
441 bitreader.Read(8);
442 bitreader.Read(8);
443 bitreader.Read(8);
444 bitreader.Read(8);
445 bitreader.Read(8);
446
447 uint32_t Profile_idc = bitreader.Read(8); // Read profile_idc
448 // Read constraint
449 uint32_t constraint_set0 = bitreader.Read(1);
450 uint32_t constraint_set1 = bitreader.Read(1);
451 uint32_t constraint_set2 = bitreader.Read(1);
452 uint32_t constraint_set3 = bitreader.Read(1);
453 uint32_t constraint_set4 = bitreader.Read(1);
454 bitreader.Read(3); // Read reserved_zeor_3bits
455 uint32_t Level_idc = bitreader.Read(8); // Read level_idc
456 bitreader.ReadByUEMode(); // Read Seq_parameter_set_id
457
458 if (Profile_idc == 100 || Profile_idc == 110 || Profile_idc == 122 || Profile_idc == 244 ||
459 Profile_idc == 44 || Profile_idc == 83 || Profile_idc == 86 || Profile_idc == 118)
460 {
461 chroma_format_idc = bitreader.ReadByUEMode();
462
463 if (chroma_format_idc == 3)
464 {
465 bitreader.Read(1); // separate_colour_plane
466 }
467
468 bitreader.ReadByUEMode(); // Read bit_depth_luma_minus8
469 bitreader.ReadByUEMode(); // Read bit_depth_chroma_minus8
470 bitreader.Read(1); // Read qpprime_y_zero_transform_bypass
471
472 // Read seq_scaling_matrix_present
473 if (bitreader.Read(1))
474 {
475 uint32_t i = ((chroma_format_idc != 3) ? 8 : 12);
476 // set scaling_list... not implement
477 bitreader.Read(i);
478 }
479 }
480 else if (Profile_idc == 183)
481 {
482 chroma_format_idc = 0;
483 }
484 else
485 {
486 chroma_format_idc = 1; // if chroma_format_idc not present in SPS it should be set to 1;
487 }
488 pInfo->nProfile = Profile_idc;
489 pInfo->nLevel = Level_idc;
490
491 IMLOGD_PACKET5(IM_PACKET_LOG_VIDEO, "[ParseAvcSps] constraint_set[%d][%d][%d][%d][%d]",
492 constraint_set0, constraint_set1, constraint_set2, constraint_set3, constraint_set4);
493 IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[ParseAvcSps] Profile_idc[%d], Level_idc[%d]", Profile_idc,
494 Level_idc);
495
496 bitreader.ReadByUEMode(); // Read log2_max_frame_num_minus4
497 uint32_t pic_order_cnt_type = bitreader.ReadByUEMode(); // Read pic_order_cnt_type
498
499 if (pic_order_cnt_type == 0)
500 {
501 bitreader.ReadByUEMode(); // Read log2_max_pic_order_cnt_lsb_minus4
502 }
503 else if (pic_order_cnt_type == 1)
504 {
505 bitreader.Read(1); // Read delta_pic_order_always_zero_flag
506 bitreader.ReadByUEMode(); // Reda offset_for_non_ref_pic...
507 bitreader.ReadByUEMode(); // Read offset_for_top_to_bottom_field
508 uint32_t num_ref_frames_in_pic_order_cnt_cycle = bitreader.ReadByUEMode();
509
510 for (int32_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
511 {
512 bitreader.ReadByUEMode(); // Read offset_for_ref_frame[i];
513 }
514 }
515
516 bitreader.ReadByUEMode(); // Read max_num_ref_frames
517 bitreader.Read(1); // Read gaps_in_frame_num_value_allowed
518
519 uint32_t pic_width_in_mbs_minus1 = bitreader.ReadByUEMode();
520 uint32_t pic_height_in_map_units_minus1 = bitreader.ReadByUEMode();
521 uint32_t frame_mbs_only = bitreader.Read(1);
522
523 pInfo->nWidth = pic_width_in_mbs_minus1 * 16 + 16;
524 pInfo->nHeight = (2 - frame_mbs_only) * (pic_height_in_map_units_minus1 * 16 + 16);
525
526 if (!frame_mbs_only)
527 {
528 bitreader.Read(1); // Read mb_adaptive_frame_field
529 }
530
531 bitreader.Read(1); // Read direct_8x8_inferencce_flag
532 uint32_t frame_cropping = bitreader.Read(1); // Read frame_cropping_flag
533
534 if (frame_cropping)
535 {
536 uint32_t frame_crop_left_offset = bitreader.ReadByUEMode();
537 uint32_t frame_crop_right_offset = bitreader.ReadByUEMode();
538 uint32_t frame_crop_top_offset = bitreader.ReadByUEMode();
539 uint32_t frame_crop_bottom_offset = bitreader.ReadByUEMode();
540 uint32_t cropX, cropY = 0;
541 if (chroma_format_idc == 0 /* monochrome */)
542 {
543 cropX = 1;
544 cropY = 2 - frame_mbs_only;
545 }
546 else
547 {
548 uint32_t subWidthC = (chroma_format_idc == 3) ? 1 : 2;
549 uint32_t subHeightC = (chroma_format_idc == 1) ? 2 : 1;
550 cropX = subWidthC;
551 cropY = subHeightC * (2 - frame_mbs_only);
552 }
553
554 pInfo->nWidth -= (frame_crop_left_offset + frame_crop_right_offset) * cropX;
555 pInfo->nHeight -= (frame_crop_top_offset + frame_crop_bottom_offset) * cropY;
556 }
557
558 free(pszSPS);
559
560 IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[ParseAvcSps] width[%d],height[%d]", pInfo->nWidth,
561 pInfo->nHeight);
562 IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[ParseAvcSps] nProfile[%d],nLevel[%d]", pInfo->nProfile,
563 pInfo->nLevel);
564 return true;
565 }
566
ParseHevcSps(uint8_t * pbBuffer,uint32_t nBufferSize,tCodecConfig * pInfo)567 bool ImsMediaVideoUtil::ParseHevcSps(uint8_t* pbBuffer, uint32_t nBufferSize, tCodecConfig* pInfo)
568 {
569 if (pbBuffer == nullptr || nBufferSize == 0)
570 {
571 pInfo->nProfile = 0;
572 pInfo->nLevel = 0;
573 pInfo->nHeight = 0;
574 pInfo->nWidth = 0;
575 return false;
576 }
577
578 uint32_t nOffset = 0;
579
580 for (int32_t i = 0; i < nBufferSize - 6; i++)
581 {
582 // NAL unit header offset
583 if (pbBuffer[i] == 0x00 && pbBuffer[i + 1] == 0x00 && pbBuffer[i + 2] == 0x00 &&
584 pbBuffer[i + 3] == 0x01 && pbBuffer[i + 4] == 0x42 && pbBuffer[i + 5] == 0x01)
585 {
586 nOffset = i + 6;
587 break;
588 }
589 }
590
591 ImsMediaBitReader objBitReader;
592 objBitReader.SetBuffer(pbBuffer + nOffset, nBufferSize - nOffset);
593 objBitReader.Read(4); // sps_video_parameter_set_id;
594 uint32_t sps_max_sub_layers_minus1 = objBitReader.Read(3); // 0
595 objBitReader.Read(1); // sps_temporal_id_nesting_flag;
596
597 objBitReader.Read(3); // general_profile_spac, general_tier_flag
598 pInfo->nProfile = objBitReader.Read(5); // general_profile_idc
599
600 // skip 10byte - flags, not handle
601 objBitReader.Read(24);
602 objBitReader.Read(24);
603 objBitReader.Read(24);
604 objBitReader.Read(8);
605
606 pInfo->nLevel = objBitReader.Read(8); // general_level_idc
607
608 uint8_t sub_layer_profile_present_flag[sps_max_sub_layers_minus1];
609 uint8_t sub_layer_level_present_flag[sps_max_sub_layers_minus1];
610
611 for (int32_t i = 0; i < sps_max_sub_layers_minus1; i++)
612 {
613 sub_layer_profile_present_flag[i] = objBitReader.Read(1);
614 sub_layer_level_present_flag[i] = objBitReader.Read(1);
615 }
616
617 if (sps_max_sub_layers_minus1 > 0)
618 {
619 for (int32_t j = sps_max_sub_layers_minus1; j < 8; j++)
620 {
621 objBitReader.Read(2);
622 }
623 }
624
625 for (int32_t i = 0; i < sps_max_sub_layers_minus1; i++)
626 {
627 if (sub_layer_profile_present_flag[i])
628 {
629 objBitReader.Read(2); // sub_layer_profile_space
630 objBitReader.Read(1); // sub_layer_tier_flag
631 objBitReader.Read(5); // sub_layer_profile_idc
632 objBitReader.Read(24); // sub_layer_profile_compatibility_flag
633 objBitReader.Read(8); // sub_layer_profile_compatibility_flag
634 objBitReader.Read(24); // sub_layer_constraint_indicator_flags
635 objBitReader.Read(24); // sub_layer_constraint_indicator_flags
636 }
637
638 if (sub_layer_level_present_flag[i])
639 {
640 objBitReader.Read(8); // sub_layer_level_idc
641 }
642 }
643
644 objBitReader.ReadByUEMode(); // sps_seq_parameter_set_id
645
646 uint32_t chroma_format_idc = objBitReader.ReadByUEMode();
647
648 if (chroma_format_idc == 3)
649 {
650 objBitReader.Read(1); // separate_colour_plane_flag
651 }
652
653 pInfo->nWidth = objBitReader.ReadByUEMode();
654 pInfo->nHeight = objBitReader.ReadByUEMode();
655
656 uint8_t conformance_window_flag = objBitReader.Read(1);
657
658 if (conformance_window_flag)
659 {
660 uint32_t conf_win_left_offset = objBitReader.ReadByUEMode();
661 uint32_t conf_win_right_offset = objBitReader.ReadByUEMode();
662 uint32_t conf_win_top_offset = objBitReader.ReadByUEMode();
663 uint32_t conf_win_bottom_offset = objBitReader.ReadByUEMode();
664
665 pInfo->nWidth -= conf_win_left_offset + conf_win_right_offset;
666 pInfo->nHeight -= conf_win_top_offset + conf_win_bottom_offset;
667 }
668
669 // Round down by 16 unit
670 uint32_t nRoundDownWidth = (pInfo->nWidth) / 16 * 16;
671 uint32_t nRoundDownHeight = (pInfo->nHeight) / 16 * 16;
672
673 pInfo->nWidth = nRoundDownWidth;
674 pInfo->nHeight = nRoundDownHeight;
675
676 return true;
677 }
678
FindAvcStartCode(uint8_t * pData,uint32_t nDataSize,uint32_t * pnSkipSize)679 uint8_t* FindAvcStartCode(uint8_t* pData, uint32_t nDataSize, uint32_t* pnSkipSize)
680 {
681 uint8_t* pCurDataPos = pData;
682 uint32_t nSkipSize = 0;
683
684 // Remove leading zero bytes and start code prefix
685 while (nDataSize >= START_CODE_PREFIX_LEN)
686 {
687 // Start Code 00 00 00 01 case.
688 if (pCurDataPos[0] == 0x00 && pCurDataPos[1] == 0x00 && pCurDataPos[2] == 0x00 &&
689 pCurDataPos[3] == 0x01)
690 {
691 if (pnSkipSize)
692 *pnSkipSize = nSkipSize;
693 return pCurDataPos;
694 }
695 else
696 {
697 pCurDataPos += 1;
698 nDataSize -= 1;
699 nSkipSize += 1;
700 }
701 }
702
703 if (pnSkipSize)
704 *pnSkipSize = nSkipSize;
705 return nullptr;
706 }
707
GenerateVideoSprop(VideoConfig * pVideoConfig)708 char* ImsMediaVideoUtil::GenerateVideoSprop(VideoConfig* pVideoConfig)
709 {
710 if (pVideoConfig == nullptr)
711 {
712 IMLOGE0("[GenerateVideoSprop] pVideoConfig is null");
713 return nullptr;
714 }
715
716 // Configure Encoder
717 AMediaFormat* pFormat = AMediaFormat_new();
718 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_WIDTH, pVideoConfig->getResolutionWidth());
719 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_HEIGHT, pVideoConfig->getResolutionHeight());
720
721 char kMimeType[128] = {'\0'};
722 sprintf(kMimeType, "video/avc");
723 if (pVideoConfig->getCodecType() == VideoConfig::CODEC_HEVC)
724 {
725 sprintf(kMimeType, "video/hevc");
726 }
727
728 IMLOGD1("[GenerateVideoSprop] MimeType[%s]", kMimeType);
729 IMLOGD2("[GenerateVideoSprop] Resolution[%dx%d].", pVideoConfig->getResolutionWidth(),
730 pVideoConfig->getResolutionHeight());
731 IMLOGD2("[GenerateVideoSprop] Profile[%d] level[%d]", pVideoConfig->getCodecProfile(),
732 pVideoConfig->getCodecLevel());
733 IMLOGD2("[GenerateVideoSprop] Bitrate[%d], FrameRate[%d]", pVideoConfig->getBitrate(),
734 pVideoConfig->getFramerate());
735
736 AMediaFormat_setString(pFormat, AMEDIAFORMAT_KEY_MIME, kMimeType);
737 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT,
738 0x00000015); // COLOR_FormatYUV420SemiPlanar
739
740 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_BIT_RATE, pVideoConfig->getBitrate() * 1000);
741 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_PROFILE, pVideoConfig->getCodecProfile());
742 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_LEVEL, pVideoConfig->getCodecLevel());
743 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_BITRATE_MODE, 2); // #2 : BITRATE_MODE_CBR
744 AMediaFormat_setFloat(pFormat, AMEDIAFORMAT_KEY_FRAME_RATE, pVideoConfig->getFramerate());
745 AMediaFormat_setInt32(
746 pFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, pVideoConfig->getIntraFrameInterval());
747 AMediaFormat_setInt32(pFormat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE,
748 pVideoConfig->getResolutionWidth() * pVideoConfig->getResolutionHeight() * 10);
749
750 AMediaCodec* pCodec = AMediaCodec_createEncoderByType(kMimeType);
751 if (pCodec == nullptr)
752 {
753 IMLOGE1("[GenerateVideoSprop] Unable to create encoder. MimeType[%s]", kMimeType);
754 return nullptr;
755 }
756
757 media_status_t err = AMediaCodec_configure(
758 pCodec, pFormat, nullptr, nullptr, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
759 if (err != AMEDIA_OK)
760 {
761 IMLOGE1("[GenerateVideoSprop] Encoder configure error[%d]", err);
762 AMediaCodec_delete(pCodec);
763 pCodec = nullptr;
764 AMediaFormat_delete(pFormat);
765 pFormat = nullptr;
766 return nullptr;
767 }
768
769 err = AMediaCodec_start(pCodec);
770 if (err != AMEDIA_OK)
771 {
772 IMLOGE1("[GenerateVideoSprop] Encoder start Err[%d]", err);
773 AMediaCodec_delete(pCodec);
774 pCodec = nullptr;
775 AMediaFormat_delete(pFormat);
776 pFormat = nullptr;
777 return nullptr;
778 }
779
780 bool bSpsRead = false, bPpsRead = false;
781 int8_t nMaxBufferReads = MAX_OUTPUT_BUFFER_READ_ATTEMPTS;
782 char* pSpropStr = reinterpret_cast<char*>(malloc(MAX_CONFIG_LEN));
783 pSpropStr[0] = '\0';
784
785 while (!bSpsRead || !bPpsRead)
786 {
787 // Get output buffer
788 AMediaCodecBufferInfo info;
789 auto index = AMediaCodec_dequeueOutputBuffer(pCodec, &info, 100000);
790 IMLOGD2("[GenerateVideoSprop] dequeueOutputBuffer returned index[%d] frameSize[%d]", index,
791 info.size);
792 if (index >= 0 && info.size > 0)
793 {
794 size_t buffCapacity = 0;
795 uint8_t* buf = AMediaCodec_getOutputBuffer(pCodec, index, &buffCapacity);
796 IMLOGD1("[GenerateVideoSprop] getOutputBuffer returned buffCapacity[%d]", buffCapacity);
797
798 buf += info.offset;
799 buffCapacity = info.size;
800
801 while (buf != nullptr && buffCapacity > 0)
802 {
803 uint32_t skipLen = 0;
804 uint8_t* tempBufPtr = FindAvcStartCode(buf, buffCapacity, &skipLen);
805 if (tempBufPtr != nullptr)
806 {
807 buf = tempBufPtr;
808 buffCapacity -= skipLen;
809 }
810
811 if (buf == nullptr || buffCapacity < START_CODE_PREFIX_LEN)
812 continue;
813
814 // Remove start sequence
815 buf += START_CODE_PREFIX_LEN;
816 buffCapacity -= START_CODE_PREFIX_LEN;
817
818 uint8_t frameType = buf[0] & 0x1F;
819
820 // Extract frame
821 int frameLen = buffCapacity;
822 tempBufPtr = FindAvcStartCode(buf, buffCapacity, &skipLen);
823 if (tempBufPtr != nullptr)
824 {
825 frameLen = tempBufPtr - buf;
826 }
827
828 int16_t SpropStrlen = strlen(pSpropStr);
829 bool ret = ImsMediaBinaryFormat::BinaryToBase00(pSpropStr + SpropStrlen,
830 MAX_CONFIG_LEN, buf, frameLen, BINARY_FORMAT_BASE64);
831 if (ret == false)
832 {
833 IMLOGE0("[GenerateVideoSprop] BinaryToBase64 failed");
834 free(pSpropStr);
835 pSpropStr = nullptr;
836 AMediaCodec_releaseOutputBuffer(pCodec, index, false);
837 goto JP_Exit_GenerateSprop;
838 }
839
840 if (frameType == FRAME_TYPE_SPS) // Check if SPS
841 {
842 strlcat(pSpropStr, ",", MAX_CONFIG_LEN);
843 bSpsRead = true;
844 }
845 else if (frameType == FRAME_TYPE_PPS) // Check if PPS
846 {
847 bPpsRead = true;
848 }
849
850 buffCapacity -= frameLen;
851 buf += frameLen;
852 }
853
854 AMediaCodec_releaseOutputBuffer(pCodec, index, false);
855 }
856 else
857 {
858 IMLOGE2("[GenerateVideoSprop] dequeueOutputBuffer returned invalid index[%d] "
859 "info.size[%d]",
860 index, info.size);
861 }
862
863 if (--nMaxBufferReads <= 0)
864 {
865 free(pSpropStr);
866 pSpropStr = nullptr;
867 goto JP_Exit_GenerateSprop;
868 }
869 }
870
871 JP_Exit_GenerateSprop:
872 // Stop Encoder
873 if (pCodec != nullptr)
874 {
875 IMLOGD0("[GenerateVideoSprop] Stop encoder");
876 AMediaCodec_signalEndOfInputStream(pCodec);
877 AMediaCodec_stop(pCodec);
878 AMediaCodec_delete(pCodec);
879 }
880
881 if (pFormat != nullptr)
882 {
883 AMediaFormat_delete(pFormat);
884 }
885
886 IMLOGD1("[GenerateVideoSprop] Returning sprop[%s]", pSpropStr);
887 return pSpropStr;
888 }
889
ConvertBitrateToPower(const uint32_t nInputBitrate,uint32_t & nOutExp,uint32_t & nOutMantissa)890 void ImsMediaVideoUtil::ConvertBitrateToPower(
891 const uint32_t nInputBitrate, uint32_t& nOutExp, uint32_t& nOutMantissa)
892 {
893 if (nInputBitrate == 0)
894 {
895 return;
896 }
897
898 nOutExp = 0;
899 nOutMantissa = (nInputBitrate % 2 == 0) ? (nInputBitrate) : (nInputBitrate + 1);
900
901 while (nOutMantissa % 2 == 0)
902 {
903 nOutExp++;
904 nOutMantissa = nOutMantissa >> 1;
905
906 if (nOutMantissa >= 0x1ffff)
907 {
908 nOutMantissa = (nOutMantissa % 2 == 0) ? (nOutMantissa) : (nOutMantissa + 1);
909 }
910 }
911 }
912