Source: lib/transmuxer/h265.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.transmuxer.H265');
  7. goog.require('shaka.util.ExpGolomb');
  8. goog.require('shaka.util.Uint8ArrayUtils');
  9. /**
  10. * H.265 utils
  11. */
  12. shaka.transmuxer.H265 = class {
  13. /**
  14. * Read a sequence parameter set and return some interesting video
  15. * properties. A sequence parameter set is the H265 metadata that
  16. * describes the properties of upcoming video frames.
  17. *
  18. * @param {!Array<shaka.extern.VideoNalu>} nalus
  19. * @return {?{height: number, width: number, videoConfig: !Uint8Array,
  20. * hSpacing: number, vSpacing: number}}
  21. */
  22. static parseInfo(nalus) {
  23. const H265 = shaka.transmuxer.H265;
  24. if (!nalus.length) {
  25. return null;
  26. }
  27. const vpsNalu = nalus.find((nalu) => {
  28. return nalu.type == H265.NALU_TYPE_VPS_;
  29. });
  30. const spsNalu = nalus.find((nalu) => {
  31. return nalu.type == H265.NALU_TYPE_SPS_;
  32. });
  33. const ppsNalu = nalus.find((nalu) => {
  34. return nalu.type == H265.NALU_TYPE_PPS_;
  35. });
  36. if (!vpsNalu || !spsNalu || !ppsNalu) {
  37. return null;
  38. }
  39. const vpsConfiguration = H265.parseVPS_(vpsNalu.fullData);
  40. const spsConfiguration = H265.parseSPS_(spsNalu.fullData);
  41. const ppsConfiguration = H265.parsePPS_(ppsNalu.fullData);
  42. /** @type {shaka.transmuxer.H265.DecoderConfigurationRecordType} */
  43. const detail = {
  44. numTemporalLayers: vpsConfiguration.numTemporalLayers,
  45. temporalIdNested: vpsConfiguration.temporalIdNested,
  46. generalProfileSpace: spsConfiguration.generalProfileSpace,
  47. generalTierFlag: spsConfiguration.generalTierFlag,
  48. generalLevelIdc: spsConfiguration.generalLevelIdc,
  49. generalProfileIdc: spsConfiguration.generalProfileIdc,
  50. generalProfileCompatibilityFlags1:
  51. spsConfiguration.generalProfileCompatibilityFlags1,
  52. generalProfileCompatibilityFlags2:
  53. spsConfiguration.generalProfileCompatibilityFlags2,
  54. generalProfileCompatibilityFlags3:
  55. spsConfiguration.generalProfileCompatibilityFlags3,
  56. generalProfileCompatibilityFlags4:
  57. spsConfiguration.generalProfileCompatibilityFlags4,
  58. generalConstraintIndicatorFlags1:
  59. spsConfiguration.generalConstraintIndicatorFlags1,
  60. generalConstraintIndicatorFlags2:
  61. spsConfiguration.generalConstraintIndicatorFlags2,
  62. generalConstraintIndicatorFlags3:
  63. spsConfiguration.generalConstraintIndicatorFlags3,
  64. generalConstraintIndicatorFlags4:
  65. spsConfiguration.generalConstraintIndicatorFlags4,
  66. generalConstraintIndicatorFlags5:
  67. spsConfiguration.generalConstraintIndicatorFlags5,
  68. generalConstraintIndicatorFlags6:
  69. spsConfiguration.generalConstraintIndicatorFlags6,
  70. constantFrameRate: spsConfiguration.constantFrameRate,
  71. minSpatialSegmentationIdc: spsConfiguration.minSpatialSegmentationIdc,
  72. chromaFormatIdc: spsConfiguration.chromaFormatIdc,
  73. bitDepthLumaMinus8: spsConfiguration.bitDepthLumaMinus8,
  74. bitDepthChromaMinus8: spsConfiguration.bitDepthChromaMinus8,
  75. parallelismType: ppsConfiguration.parallelismType,
  76. };
  77. const videoConfig = H265.getVideoConfiguration_(
  78. vpsNalu.fullData, spsNalu.fullData, ppsNalu.fullData, detail);
  79. return {
  80. height: spsConfiguration.height,
  81. width: spsConfiguration.width,
  82. videoConfig,
  83. hSpacing: spsConfiguration.sarWidth,
  84. vSpacing: spsConfiguration.sarHeight,
  85. };
  86. }
  87. /**
  88. * @param {!Uint8Array} data
  89. * @return {shaka.transmuxer.H265.VPSConfiguration}
  90. * @private
  91. */
  92. static parseVPS_(data) {
  93. const gb = new shaka.util.ExpGolomb(data, /* convertEbsp2rbsp= */ true);
  94. // remove NALu Header
  95. gb.readUnsignedByte();
  96. gb.readUnsignedByte();
  97. // VPS
  98. gb.readBits(4); // video_parameter_set_id
  99. gb.readBits(2);
  100. gb.readBits(6); // max_layers_minus1
  101. const maxSubLayersMinus1 = gb.readBits(3);
  102. const temporalIdNestingFlag = gb.readBoolean();
  103. return {
  104. numTemporalLayers: maxSubLayersMinus1 + 1,
  105. temporalIdNested: temporalIdNestingFlag,
  106. };
  107. }
  108. /**
  109. * The code is based on mpegts.js
  110. * https://github.com/xqq/mpegts.js/blob/master/src/demux/h265-parser.js#L65
  111. *
  112. * @param {!Uint8Array} data
  113. * @return {shaka.transmuxer.H265.SPSConfiguration}
  114. * @private
  115. */
  116. static parseSPS_(data) {
  117. const gb = new shaka.util.ExpGolomb(data, /* convertEbsp2rbsp= */ true);
  118. // remove NALu Header
  119. gb.readUnsignedByte();
  120. gb.readUnsignedByte();
  121. let leftOffset = 0;
  122. let rightOffset = 0;
  123. let topOffset = 0;
  124. let bottomOffset = 0;
  125. // SPS
  126. gb.readBits(4); // video_parameter_set_id
  127. const maxSubLayersMinus1 = gb.readBits(3);
  128. gb.readBoolean(); // temporal_id_nesting_flag
  129. // profile_tier_level begin
  130. const generalProfileSpace = gb.readBits(2);
  131. const generalTierFlag = gb.readBits(1);
  132. const generalProfileIdc = gb.readBits(5);
  133. const generalProfileCompatibilityFlags1 = gb.readUnsignedByte();
  134. const generalProfileCompatibilityFlags2 = gb.readUnsignedByte();
  135. const generalProfileCompatibilityFlags3 = gb.readUnsignedByte();
  136. const generalProfileCompatibilityFlags4 = gb.readUnsignedByte();
  137. const generalConstraintIndicatorFlags1 = gb.readUnsignedByte();
  138. const generalConstraintIndicatorFlags2 = gb.readUnsignedByte();
  139. const generalConstraintIndicatorFlags3 = gb.readUnsignedByte();
  140. const generalConstraintIndicatorFlags4 = gb.readUnsignedByte();
  141. const generalConstraintIndicatorFlags5 = gb.readUnsignedByte();
  142. const generalConstraintIndicatorFlags6 = gb.readUnsignedByte();
  143. const generalLevelIdc = gb.readUnsignedByte();
  144. const subLayerProfilePresentFlag = [];
  145. const subLayerLevelPresentFlag = [];
  146. for (let i = 0; i < maxSubLayersMinus1; i++) {
  147. subLayerProfilePresentFlag.push(gb.readBoolean());
  148. subLayerLevelPresentFlag.push(gb.readBoolean());
  149. }
  150. if (maxSubLayersMinus1 > 0) {
  151. for (let i = maxSubLayersMinus1; i < 8; i++) {
  152. gb.readBits(2);
  153. }
  154. }
  155. for (let i = 0; i < maxSubLayersMinus1; i++) {
  156. if (subLayerProfilePresentFlag[i]) {
  157. gb.readBits(88);
  158. }
  159. if (subLayerLevelPresentFlag[i]) {
  160. gb.readUnsignedByte();
  161. }
  162. }
  163. // profile_tier_level end
  164. gb.readUnsignedExpGolomb(); // seq_parameter_set_id
  165. const chromaFormatIdc = gb.readUnsignedExpGolomb();
  166. if (chromaFormatIdc == 3) {
  167. gb.readBits(1); // separate_colour_plane_flag
  168. }
  169. const picWidthInLumaSamples = gb.readUnsignedExpGolomb();
  170. const picHeightInLumaSamples = gb.readUnsignedExpGolomb();
  171. const conformanceWindowFlag = gb.readBoolean();
  172. if (conformanceWindowFlag) {
  173. leftOffset += gb.readUnsignedExpGolomb();
  174. rightOffset += gb.readUnsignedExpGolomb();
  175. topOffset += gb.readUnsignedExpGolomb();
  176. bottomOffset += gb.readUnsignedExpGolomb();
  177. }
  178. const bitDepthLumaMinus8 = gb.readUnsignedExpGolomb();
  179. const bitDepthChromaMinus8 = gb.readUnsignedExpGolomb();
  180. const log2MaxPicOrderCntLsbMinus4 = gb.readUnsignedExpGolomb();
  181. const subLayerOrderingInfoPresentFlag = gb.readBoolean();
  182. if (subLayerOrderingInfoPresentFlag) {
  183. // Skip each layer
  184. for (let i = 0; i <= maxSubLayersMinus1; i++) {
  185. gb.readUnsignedExpGolomb(); // max_dec_pic_buffering_minus1[i]
  186. gb.readUnsignedExpGolomb(); // max_num_reorder_pics[i]
  187. gb.readUnsignedExpGolomb(); // max_latency_increase_plus1[i]
  188. }
  189. } else {
  190. // Skip one layer
  191. gb.readUnsignedExpGolomb(); // max_dec_pic_buffering_minus1[i]
  192. gb.readUnsignedExpGolomb(); // max_num_reorder_pics[i]
  193. gb.readUnsignedExpGolomb(); // max_latency_increase_plus1[i]
  194. }
  195. gb.readUnsignedExpGolomb(); // log2_min_luma_coding_block_size_minus3
  196. gb.readUnsignedExpGolomb(); // log2_diff_max_min_luma_coding_block_size
  197. gb.readUnsignedExpGolomb(); // log2_min_transform_block_size_minus2
  198. gb.readUnsignedExpGolomb(); // log2_diff_max_min_transform_block_size
  199. gb.readUnsignedExpGolomb(); // max_transform_hierarchy_depth_inter
  200. gb.readUnsignedExpGolomb(); // max_transform_hierarchy_depth_intra
  201. const scalingListEnabledFlag = gb.readBoolean();
  202. if (scalingListEnabledFlag) {
  203. const spsScalingListDataPresentFlag = gb.readBoolean();
  204. if (spsScalingListDataPresentFlag) {
  205. for (let sizeId = 0; sizeId < 4; sizeId++) {
  206. for (
  207. let matrixId = 0;
  208. matrixId < (sizeId === 3 ? 2 : 6);
  209. matrixId++
  210. ) {
  211. const scalingListPredModeFlag = gb.readBoolean();
  212. if (!scalingListPredModeFlag) {
  213. gb.readUnsignedExpGolomb(); // scaling_list_pred_matrix_id_delta
  214. } else {
  215. const coefNum = Math.min(64, 1 << (4 + (sizeId << 1)));
  216. if (sizeId > 1) {
  217. gb.readExpGolomb();
  218. }
  219. for (let i = 0; i < coefNum; i++) {
  220. gb.readExpGolomb();
  221. }
  222. }
  223. }
  224. }
  225. }
  226. }
  227. gb.readBoolean(); // amp_enabled_flag
  228. gb.readBoolean(); // sample_adaptive_offset_enabled_flag
  229. const pcmEnabledFlag = gb.readBoolean();
  230. if (pcmEnabledFlag) {
  231. gb.readUnsignedByte();
  232. gb.readUnsignedExpGolomb();
  233. gb.readUnsignedExpGolomb();
  234. gb.readBoolean();
  235. }
  236. const numShortTermRefPicSets = gb.readUnsignedExpGolomb();
  237. let numDeltaPocs = 0;
  238. for (let i = 0; i < numShortTermRefPicSets; i++) {
  239. let interRefPicSetPredictionFlag = false;
  240. if (i !== 0) {
  241. interRefPicSetPredictionFlag = gb.readBoolean();
  242. }
  243. if (interRefPicSetPredictionFlag) {
  244. if (i === numShortTermRefPicSets) {
  245. gb.readUnsignedExpGolomb();
  246. }
  247. gb.readBoolean();
  248. gb.readUnsignedExpGolomb();
  249. let nextNumDeltaPocs = 0;
  250. for (let j = 0; j <= numDeltaPocs; j++) {
  251. const usedByCurrPicFlag = gb.readBoolean();
  252. let useDeltaFlag = false;
  253. if (!usedByCurrPicFlag) {
  254. useDeltaFlag = gb.readBoolean();
  255. }
  256. if (usedByCurrPicFlag || useDeltaFlag) {
  257. nextNumDeltaPocs++;
  258. }
  259. }
  260. numDeltaPocs = nextNumDeltaPocs;
  261. } else {
  262. const numNegativePics = gb.readUnsignedExpGolomb();
  263. const numPositivePics = gb.readUnsignedExpGolomb();
  264. numDeltaPocs = numNegativePics + numPositivePics;
  265. for (let j = 0; j < numNegativePics; j++) {
  266. gb.readUnsignedExpGolomb();
  267. gb.readBoolean();
  268. }
  269. for (let j = 0; j < numPositivePics; j++) {
  270. gb.readUnsignedExpGolomb();
  271. gb.readBoolean();
  272. }
  273. }
  274. }
  275. const longTermRefPicsPresentFlag = gb.readBoolean();
  276. if (longTermRefPicsPresentFlag) {
  277. const numLongTermRefPicsSps = gb.readUnsignedExpGolomb();
  278. for (let i = 0; i < numLongTermRefPicsSps; i++) {
  279. for (let j = 0; j < log2MaxPicOrderCntLsbMinus4 + 4; j++) {
  280. gb.readBits(1);
  281. }
  282. gb.readBits(1);
  283. }
  284. }
  285. let defaultDisplayWindowFlag = false; // for calc offset
  286. let sarWidth = 1;
  287. let sarHeight = 1;
  288. let minSpatialSegmentationIdc = 0; // for hvcC
  289. gb.readBoolean(); // sps_temporal_mvp_enabled_flag
  290. gb.readBoolean(); // strong_intra_smoothing_enabled_flag
  291. const vuiParametersPresentFlag = gb.readBoolean();
  292. if (vuiParametersPresentFlag) {
  293. const aspectRatioInfoPresentFlag = gb.readBoolean();
  294. if (aspectRatioInfoPresentFlag) {
  295. const aspectRatioIdc = gb.readUnsignedByte();
  296. const sarWidthTable = [
  297. 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2,
  298. ];
  299. const sarHeightTable = [
  300. 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1,
  301. ];
  302. if (aspectRatioIdc > 0 && aspectRatioIdc <= 16) {
  303. sarWidth = sarWidthTable[aspectRatioIdc - 1];
  304. sarHeight = sarHeightTable[aspectRatioIdc - 1];
  305. } else if (aspectRatioIdc === 255) {
  306. sarWidth = gb.readBits(16);
  307. sarHeight = gb.readBits(16);
  308. }
  309. }
  310. const overscanInfoPresentFlag = gb.readBoolean();
  311. if (overscanInfoPresentFlag) {
  312. gb.readBoolean();
  313. }
  314. const videoSignalTypePresentFlag = gb.readBoolean();
  315. if (videoSignalTypePresentFlag) {
  316. gb.readBits(3);
  317. gb.readBoolean();
  318. const colourDescriptionPresentFlag = gb.readBoolean();
  319. if (colourDescriptionPresentFlag) {
  320. gb.readUnsignedByte();
  321. gb.readUnsignedByte();
  322. gb.readUnsignedByte();
  323. }
  324. }
  325. const chromaLocInfoPresentFlag = gb.readBoolean();
  326. if (chromaLocInfoPresentFlag) {
  327. gb.readUnsignedExpGolomb();
  328. gb.readUnsignedExpGolomb();
  329. }
  330. gb.readBoolean(); // neutral_chroma_indication_flag
  331. gb.readBoolean(); // field_seq_flag
  332. gb.readBoolean(); // frame_field_info_present_flag
  333. defaultDisplayWindowFlag = gb.readBoolean();
  334. if (defaultDisplayWindowFlag) {
  335. gb.readUnsignedExpGolomb();
  336. gb.readUnsignedExpGolomb();
  337. gb.readUnsignedExpGolomb();
  338. gb.readUnsignedExpGolomb();
  339. }
  340. const vuiTimingInfoPresentFlag = gb.readBoolean();
  341. if (vuiTimingInfoPresentFlag) {
  342. gb.readBits(32); // fps_den
  343. gb.readBits(32); // fps_num
  344. const vuiPocProportionalToTimingFlag = gb.readBoolean();
  345. if (vuiPocProportionalToTimingFlag) {
  346. gb.readUnsignedExpGolomb();
  347. }
  348. const vuiHrdParametersPresentFlag = gb.readBoolean();
  349. if (vuiHrdParametersPresentFlag) {
  350. const commonInfPresentFlag = 1;
  351. let nalHrdParametersPresentFlag = false;
  352. let vclHrdParametersPresentFlag = false;
  353. let subPicHrdParamsPresentFlag = false;
  354. if (commonInfPresentFlag) {
  355. nalHrdParametersPresentFlag = gb.readBoolean();
  356. vclHrdParametersPresentFlag = gb.readBoolean();
  357. if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) {
  358. subPicHrdParamsPresentFlag = gb.readBoolean();
  359. if (subPicHrdParamsPresentFlag) {
  360. gb.readUnsignedByte();
  361. gb.readBits(5);
  362. gb.readBoolean();
  363. gb.readBits(5);
  364. }
  365. gb.readBits(4); // bit_rate_scale
  366. gb.readBits(4); // cpb_size_scale
  367. if (subPicHrdParamsPresentFlag) {
  368. gb.readBits(4);
  369. }
  370. gb.readBits(5);
  371. gb.readBits(5);
  372. gb.readBits(5);
  373. }
  374. }
  375. for (let i = 0; i <= maxSubLayersMinus1; i++) {
  376. const fixedPicRateGeneralFlag = gb.readBoolean();
  377. let fixedPicRateWithinCvsFlag = true;
  378. let cpbCnt = 1;
  379. if (!fixedPicRateGeneralFlag) {
  380. fixedPicRateWithinCvsFlag = gb.readBoolean();
  381. }
  382. let lowDelayHrdFlag = false;
  383. if (fixedPicRateWithinCvsFlag) {
  384. gb.readUnsignedExpGolomb();
  385. } else {
  386. lowDelayHrdFlag = gb.readBoolean();
  387. }
  388. if (!lowDelayHrdFlag) {
  389. cpbCnt = gb.readUnsignedExpGolomb() + 1;
  390. }
  391. if (nalHrdParametersPresentFlag) {
  392. for (let j = 0; j < cpbCnt; j++) {
  393. gb.readUnsignedExpGolomb();
  394. gb.readUnsignedExpGolomb();
  395. if (subPicHrdParamsPresentFlag) {
  396. gb.readUnsignedExpGolomb();
  397. gb.readUnsignedExpGolomb();
  398. }
  399. }
  400. gb.readBoolean();
  401. }
  402. if (vclHrdParametersPresentFlag) {
  403. for (let j = 0; j < cpbCnt; j++) {
  404. gb.readUnsignedExpGolomb();
  405. gb.readUnsignedExpGolomb();
  406. if (subPicHrdParamsPresentFlag) {
  407. gb.readUnsignedExpGolomb();
  408. gb.readUnsignedExpGolomb();
  409. }
  410. }
  411. gb.readBoolean();
  412. }
  413. }
  414. }
  415. }
  416. const bitstreamRestrictionFlag = gb.readBoolean();
  417. if (bitstreamRestrictionFlag) {
  418. gb.readBoolean(); // tiles_fixed_structure_flag
  419. gb.readBoolean(); // motion_vectors_over_pic_boundaries_flag
  420. gb.readBoolean(); // restricted_ref_pic_lists_flag
  421. minSpatialSegmentationIdc = gb.readUnsignedExpGolomb();
  422. gb.readUnsignedExpGolomb(); // max_bytes_per_pic_denom
  423. gb.readUnsignedExpGolomb(); // max_bits_per_min_cu_denom
  424. gb.readUnsignedExpGolomb(); // log2_max_mv_length_horizontal
  425. gb.readUnsignedExpGolomb(); // log2_max_mv_length_vertical
  426. }
  427. }
  428. const subWc = chromaFormatIdc === 1 || chromaFormatIdc === 2 ? 2 : 1;
  429. const subHc = chromaFormatIdc === 1 ? 2 : 1;
  430. const codecWidth =
  431. picWidthInLumaSamples - (leftOffset + rightOffset) * subWc;
  432. const codecHeight =
  433. picHeightInLumaSamples - (topOffset + bottomOffset) * subHc;
  434. return {
  435. generalLevelIdc,
  436. generalProfileSpace,
  437. generalTierFlag,
  438. generalProfileIdc,
  439. generalProfileCompatibilityFlags1,
  440. generalProfileCompatibilityFlags2,
  441. generalProfileCompatibilityFlags3,
  442. generalProfileCompatibilityFlags4,
  443. generalConstraintIndicatorFlags1,
  444. generalConstraintIndicatorFlags2,
  445. generalConstraintIndicatorFlags3,
  446. generalConstraintIndicatorFlags4,
  447. generalConstraintIndicatorFlags5,
  448. generalConstraintIndicatorFlags6,
  449. minSpatialSegmentationIdc,
  450. constantFrameRate: 0, // FIXME!!!
  451. chromaFormatIdc,
  452. bitDepthLumaMinus8,
  453. bitDepthChromaMinus8,
  454. width: codecWidth,
  455. height: codecHeight,
  456. sarWidth: sarWidth,
  457. sarHeight: sarHeight,
  458. };
  459. }
  460. /**
  461. * @param {!Uint8Array} data
  462. * @return {shaka.transmuxer.H265.PPSConfiguration}
  463. * @private
  464. */
  465. static parsePPS_(data) {
  466. const gb = new shaka.util.ExpGolomb(data, /* convertEbsp2rbsp= */ true);
  467. // remove NALu Header
  468. gb.readUnsignedByte();
  469. gb.readUnsignedByte();
  470. // PPS
  471. gb.readUnsignedExpGolomb(); // pic_parameter_set_id
  472. gb.readUnsignedExpGolomb(); // seq_parameter_set_id
  473. gb.readBoolean(); // dependent_slice_segments_enabled_flag
  474. gb.readBoolean(); // output_flag_present_flag
  475. gb.readBits(3); // num_extra_slice_header_bits
  476. gb.readBoolean(); // sign_data_hiding_enabled_flag
  477. gb.readBoolean(); // cabac_init_present_flag
  478. gb.readUnsignedExpGolomb(); // num_ref_idx_l0_default_active_minus1
  479. gb.readUnsignedExpGolomb(); // num_ref_idx_l1_default_active_minus1
  480. gb.readExpGolomb(); // init_qp_minus26
  481. gb.readBoolean(); // constrained_intra_pred_flag
  482. gb.readBoolean(); // transform_skip_enabled_flag
  483. const cuQpDeltaEnabledFlag = gb.readBoolean();
  484. if (cuQpDeltaEnabledFlag) {
  485. gb.readUnsignedExpGolomb(); // diff_cu_qp_delta_depth
  486. }
  487. gb.readExpGolomb(); // cb_qp_offset
  488. gb.readExpGolomb(); // cr_qp_offset
  489. gb.readBoolean(); // pps_slice_chroma_qp_offsets_present_flag
  490. gb.readBoolean(); // weighted_pred_flag
  491. gb.readBoolean(); // weighted_bipred_flag
  492. gb.readBoolean(); // transquant_bypass_enabled_flag
  493. const tilesEnabledFlag = gb.readBoolean();
  494. const entropyCodingSyncEnabledFlag = gb.readBoolean();
  495. // needs hvcC
  496. let parallelismType = 1; // slice-based parallel decoding
  497. if (entropyCodingSyncEnabledFlag && tilesEnabledFlag) {
  498. parallelismType = 0; // mixed-type parallel decoding
  499. } else if (entropyCodingSyncEnabledFlag) {
  500. parallelismType = 3; // wavefront-based parallel decoding
  501. } else if (tilesEnabledFlag) {
  502. parallelismType = 2; // tile-based parallel decoding
  503. }
  504. return {
  505. parallelismType,
  506. };
  507. }
  508. /**
  509. * @param {!Uint8Array} vps
  510. * @param {!Uint8Array} sps
  511. * @param {!Uint8Array} pps
  512. * @param {shaka.transmuxer.H265.DecoderConfigurationRecordType} detail
  513. * @return {!Uint8Array}
  514. * @private
  515. */
  516. static getVideoConfiguration_(vps, sps, pps, detail) {
  517. const H265 = shaka.transmuxer.H265;
  518. const length = 23 + (3 + 2 + vps.byteLength) +
  519. (3 + 2 + sps.byteLength) + (3 + 2 + pps.byteLength);
  520. const data = new Uint8Array(length);
  521. data[0] = 0x01; // configurationVersion
  522. data[1] = ((detail.generalProfileSpace & 0x03) << 6) |
  523. ((detail.generalTierFlag ? 1 : 0) << 5) |
  524. ((detail.generalProfileIdc & 0x1F));
  525. data[2] = detail.generalProfileCompatibilityFlags1;
  526. data[3] = detail.generalProfileCompatibilityFlags2;
  527. data[4] = detail.generalProfileCompatibilityFlags3;
  528. data[5] = detail.generalProfileCompatibilityFlags4;
  529. data[6] = detail.generalConstraintIndicatorFlags1;
  530. data[7] = detail.generalConstraintIndicatorFlags2;
  531. data[8] = detail.generalConstraintIndicatorFlags3;
  532. data[9] = detail.generalConstraintIndicatorFlags4;
  533. data[10] = detail.generalConstraintIndicatorFlags5;
  534. data[11] = detail.generalConstraintIndicatorFlags6;
  535. data[12] = detail.generalLevelIdc;
  536. data[13] = 0xF0 |
  537. ((detail.minSpatialSegmentationIdc & 0x0F00) >> 8);
  538. data[14] = (detail.minSpatialSegmentationIdc & 0xFF);
  539. data[15] = 0xFC | (detail.parallelismType & 0x03);
  540. data[16] = 0xFC | (detail.chromaFormatIdc & 0x03);
  541. data[17] = 0xF8 | (detail.bitDepthLumaMinus8 & 0x07);
  542. data[18] = 0xF8 | (detail.bitDepthChromaMinus8 & 0x07);
  543. data[19] = 0;
  544. data[20] = 0;
  545. data[21] = ((detail.constantFrameRate & 0x03) << 6) |
  546. ((detail.numTemporalLayers & 0x07) << 3) |
  547. ((detail.temporalIdNested ? 1 : 0) << 2) | 3;
  548. data[22] = 3;
  549. data[23 + 0 + 0] = 0x80 | H265.NALU_TYPE_VPS_;
  550. data[23 + 0 + 1] = 0;
  551. data[23 + 0 + 2] = 1;
  552. data[23 + 0 + 3] = (vps.byteLength & 0xFF00) >> 8;
  553. data[23 + 0 + 4] = (vps.byteLength & 0x00FF) >> 0;
  554. data.set(vps, 23 + 0 + 5);
  555. data[23 + (5 + vps.byteLength) + 0] =
  556. 0x80 | H265.NALU_TYPE_SPS_;
  557. data[23 + (5 + vps.byteLength) + 1] = 0;
  558. data[23 + (5 + vps.byteLength) + 2] = 1;
  559. data[23 + (5 + vps.byteLength) + 3] = (sps.byteLength & 0xFF00) >> 8;
  560. data[23 + (5 + vps.byteLength) + 4] = (sps.byteLength & 0x00FF) >> 0;
  561. data.set(sps, 23 + (5 + vps.byteLength) + 5);
  562. data[23 + (5 + vps.byteLength + 5 + sps.byteLength) + 0] =
  563. 0x80 | H265.NALU_TYPE_PPS_;
  564. data[23 + (5 + vps.byteLength + 5 + sps.byteLength) + 1] = 0;
  565. data[23 + (5 + vps.byteLength + 5 + sps.byteLength) + 2] = 1;
  566. data[23 + (5 + vps.byteLength + 5 + sps.byteLength) + 3] =
  567. (pps.byteLength & 0xFF00) >> 8;
  568. data[23 + (5 + vps.byteLength + 5 + sps.byteLength) + 4] =
  569. (pps.byteLength & 0x00FF) >> 0;
  570. data.set(pps, 23 + (5 + vps.byteLength + 5 + sps.byteLength) + 5);
  571. return data;
  572. }
  573. /**
  574. * @param {!Array<shaka.extern.VideoNalu>} nalus
  575. * @return {?{data: !Uint8Array, isKeyframe: boolean}}
  576. */
  577. static parseFrame(nalus) {
  578. const H265 = shaka.transmuxer.H265;
  579. let isKeyframe = false;
  580. const nalusData = [];
  581. let hvcSample = false;
  582. for (const nalu of nalus) {
  583. let push = false;
  584. switch (nalu.type) {
  585. case H265.NALU_TYPE_TRAIL_N_:
  586. case H265.NALU_TYPE_TRAIL_R_: {
  587. hvcSample = true;
  588. push = true;
  589. break;
  590. }
  591. case H265.NALU_TYPE_IDR_W_RADL_:
  592. case H265.NALU_TYPE_IDR_N_LP_:
  593. case H265.NALU_TYPE_CRA_NUT_:
  594. hvcSample = true;
  595. push = true;
  596. isKeyframe = true;
  597. break;
  598. case H265.NALU_TYPE_VPS_:
  599. push = true;
  600. break;
  601. case H265.NALU_TYPE_SPS_:
  602. push = true;
  603. break;
  604. case H265.NALU_TYPE_PPS_:
  605. push = true;
  606. break;
  607. case H265.NALU_TYPE_AUD_:
  608. push = true;
  609. hvcSample = true;
  610. break;
  611. case H265.NALU_TYPE_SEI_PREFIX_:
  612. case H265.NALU_TYPE_SEI_SUFFIX_:
  613. push = true;
  614. break;
  615. default:
  616. push = false;
  617. break;
  618. }
  619. if (hvcSample && push) {
  620. const size = nalu.fullData.byteLength;
  621. const naluLength = new Uint8Array(4);
  622. naluLength[0] = (size >> 24) & 0xff;
  623. naluLength[1] = (size >> 16) & 0xff;
  624. naluLength[2] = (size >> 8) & 0xff;
  625. naluLength[3] = size & 0xff;
  626. nalusData.push(naluLength);
  627. nalusData.push(nalu.fullData);
  628. }
  629. }
  630. if (!nalusData.length) {
  631. return null;
  632. }
  633. const data = shaka.util.Uint8ArrayUtils.concat(...nalusData);
  634. return {
  635. data,
  636. isKeyframe,
  637. };
  638. }
  639. };
  640. /**
  641. * NALU type for non-reference trailing picture for H.265.
  642. * @const {number}
  643. * @private
  644. */
  645. shaka.transmuxer.H265.NALU_TYPE_TRAIL_N_ = 0x01;
  646. /**
  647. * NALU type for reference trailing picture for H.265.
  648. * @const {number}
  649. * @private
  650. */
  651. shaka.transmuxer.H265.NALU_TYPE_TRAIL_R_ = 0x00;
  652. /**
  653. * NALU type for Instantaneous Decoder Refresh (IDR) for H.265.
  654. * @const {number}
  655. * @private
  656. */
  657. shaka.transmuxer.H265.NALU_TYPE_IDR_W_RADL_ = 0x13;
  658. /**
  659. * NALU type for Instantaneous Decoder Refresh (IDR) for H.265.
  660. * @const {number}
  661. * @private
  662. */
  663. shaka.transmuxer.H265.NALU_TYPE_IDR_N_LP_ = 0x14;
  664. /**
  665. * NALU type for Clean Random Access (CRA) for H.265.
  666. * @const {number}
  667. * @private
  668. */
  669. shaka.transmuxer.H265.NALU_TYPE_CRA_NUT_ = 0x15;
  670. /**
  671. * NALU type for Video Parameter Set (VPS) for H.265.
  672. * @const {number}
  673. * @private
  674. */
  675. shaka.transmuxer.H265.NALU_TYPE_VPS_ = 0x20;
  676. /**
  677. * NALU type for Sequence Parameter Set (SPS) for H.265.
  678. * @const {number}
  679. * @private
  680. */
  681. shaka.transmuxer.H265.NALU_TYPE_SPS_ = 0x21;
  682. /**
  683. * NALU type for Picture Parameter Set (PPS) for H.265.
  684. * @const {number}
  685. * @private
  686. */
  687. shaka.transmuxer.H265.NALU_TYPE_PPS_ = 0x22;
  688. /**
  689. * NALU type for Access Unit Delimiter (AUD) for H.265.
  690. * @const {number}
  691. * @private
  692. */
  693. shaka.transmuxer.H265.NALU_TYPE_AUD_ = 0x23;
  694. /**
  695. * NALU type for Supplemental Enhancement Information (SEI) for H.265.
  696. * @const {number}
  697. * @private
  698. */
  699. shaka.transmuxer.H265.NALU_TYPE_SEI_PREFIX_ = 0x27;
  700. /**
  701. * NALU type for Supplemental Enhancement Information (SEI) for H.265.
  702. * @const {number}
  703. * @private
  704. */
  705. shaka.transmuxer.H265.NALU_TYPE_SEI_SUFFIX_ = 0x28;
  706. /**
  707. * @typedef {{
  708. * numTemporalLayers: number,
  709. * temporalIdNested: boolean
  710. * }}
  711. *
  712. * @property {number} numTemporalLayers
  713. * @property {boolean} temporalIdNested
  714. */
  715. shaka.transmuxer.H265.VPSConfiguration;
  716. /**
  717. * @typedef {{
  718. * generalProfileSpace: number,
  719. * generalTierFlag: number,
  720. * generalLevelIdc: number,
  721. * generalProfileIdc: number,
  722. * generalProfileCompatibilityFlags1: number,
  723. * generalProfileCompatibilityFlags2: number,
  724. * generalProfileCompatibilityFlags3: number,
  725. * generalProfileCompatibilityFlags4: number,
  726. * generalConstraintIndicatorFlags1: number,
  727. * generalConstraintIndicatorFlags2: number,
  728. * generalConstraintIndicatorFlags3: number,
  729. * generalConstraintIndicatorFlags4: number,
  730. * generalConstraintIndicatorFlags5: number,
  731. * generalConstraintIndicatorFlags6: number,
  732. * constantFrameRate: number,
  733. * minSpatialSegmentationIdc: number,
  734. * chromaFormatIdc: number,
  735. * bitDepthLumaMinus8: number,
  736. * bitDepthChromaMinus8: number,
  737. * width: number,
  738. * height: number,
  739. * sarWidth: number,
  740. * sarHeight: number
  741. * }}
  742. *
  743. * @property {number} generalProfileSpace
  744. * @property {number} generalTierFlag
  745. * @property {number} generalLevelIdc
  746. * @property {number} generalProfileIdc
  747. * @property {number} generalProfileCompatibilityFlags1
  748. * @property {number} generalProfileCompatibilityFlags2
  749. * @property {number} generalProfileCompatibilityFlags3
  750. * @property {number} generalProfileCompatibilityFlags4
  751. * @property {number} generalConstraintIndicatorFlags1
  752. * @property {number} generalConstraintIndicatorFlags2
  753. * @property {number} generalConstraintIndicatorFlags3
  754. * @property {number} generalConstraintIndicatorFlags4
  755. * @property {number} generalConstraintIndicatorFlags5
  756. * @property {number} generalConstraintIndicatorFlags6
  757. * @property {number} constantFrameRate
  758. * @property {number} minSpatialSegmentationIdc
  759. * @property {number} chromaFormatIdc
  760. * @property {number} bitDepthLumaMinus8
  761. * @property {number} bitDepthChromaMinus8
  762. * @property {number} width
  763. * @property {number} height
  764. * @property {number} sarWidth
  765. * @property {number} sarHeight
  766. */
  767. shaka.transmuxer.H265.SPSConfiguration;
  768. /**
  769. * @typedef {{
  770. * parallelismType: number
  771. * }}
  772. *
  773. * @property {number} parallelismType
  774. */
  775. shaka.transmuxer.H265.PPSConfiguration;
  776. /**
  777. * @typedef {{
  778. * numTemporalLayers: number,
  779. * temporalIdNested: boolean,
  780. * generalProfileSpace: number,
  781. * generalTierFlag: number,
  782. * generalLevelIdc: number,
  783. * generalProfileIdc: number,
  784. * generalProfileCompatibilityFlags1: number,
  785. * generalProfileCompatibilityFlags2: number,
  786. * generalProfileCompatibilityFlags3: number,
  787. * generalProfileCompatibilityFlags4: number,
  788. * generalConstraintIndicatorFlags1: number,
  789. * generalConstraintIndicatorFlags2: number,
  790. * generalConstraintIndicatorFlags3: number,
  791. * generalConstraintIndicatorFlags4: number,
  792. * generalConstraintIndicatorFlags5: number,
  793. * generalConstraintIndicatorFlags6: number,
  794. * constantFrameRate: number,
  795. * minSpatialSegmentationIdc: number,
  796. * chromaFormatIdc: number,
  797. * bitDepthLumaMinus8: number,
  798. * bitDepthChromaMinus8: number,
  799. * parallelismType: number
  800. * }}
  801. *
  802. * @property {number} numTemporalLayers
  803. * @property {boolean} temporalIdNested
  804. * @property {number} generalProfileSpace
  805. * @property {number} generalTierFlag
  806. * @property {number} generalLevelIdc
  807. * @property {number} generalProfileIdc
  808. * @property {number} generalProfileCompatibilityFlags1
  809. * @property {number} generalProfileCompatibilityFlags2
  810. * @property {number} generalProfileCompatibilityFlags3
  811. * @property {number} generalProfileCompatibilityFlags4
  812. * @property {number} generalConstraintIndicatorFlags1
  813. * @property {number} generalConstraintIndicatorFlags2
  814. * @property {number} generalConstraintIndicatorFlags3
  815. * @property {number} generalConstraintIndicatorFlags4
  816. * @property {number} generalConstraintIndicatorFlags5
  817. * @property {number} generalConstraintIndicatorFlags6
  818. * @property {number} constantFrameRate
  819. * @property {number} minSpatialSegmentationIdc
  820. * @property {number} chromaFormatIdc
  821. * @property {number} bitDepthLumaMinus8
  822. * @property {number} bitDepthChromaMinus8
  823. * @property {number} parallelismType
  824. */
  825. shaka.transmuxer.H265.DecoderConfigurationRecordType;