mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-15 16:06:41 +03:00
6a775e29a4
When unboxing TKHD, the reader read int64 as trackId instead of int32. Thus unable to find matching timescale when doing TFHD unboxing. Therefore when parsing MDAT, the default timescale will be used which is 90000. All CC timestamps will then be incorrect. This also fixes "Shaka Error MEDIA.VIDEO_ERROR (3,,PIPELINE_ERROR_DECODE: Failed to parse H.264 stream)" error when playing DASH MP4 H.264 streams with CEA-608 CC embedded. It's likely that the VDA bundled in Chromium-based browsers have already included EPB detection & prevention. If we let the player to remove the byte, VDA will complain about stream conformance. Closes #3502
85 lines
2.3 KiB
JavaScript
85 lines
2.3 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.cea.SeiProcessor');
|
|
|
|
|
|
/**
|
|
* H.264 SEI NALU Parser used for extracting 708 closed caption packets.
|
|
*/
|
|
shaka.cea.SeiProcessor = class {
|
|
/**
|
|
* Processes supplemental enhancement information data.
|
|
* @param {!Uint8Array} naluData NALU from which SEI data is to be processed.
|
|
* @return {!Iterable.<!Uint8Array>}
|
|
*/
|
|
* process(naluData) {
|
|
const naluClone = this.removeEmu(naluData);
|
|
|
|
// The following is an implementation of section 7.3.2.3.1
|
|
// in Rec. ITU-T H.264 (06/2019), the H.264 spec.
|
|
let offset = 0;
|
|
|
|
while (offset < naluClone.length) {
|
|
let payloadType = 0; // SEI payload type as defined by H.264 spec
|
|
while (naluClone[offset] == 0xFF) {
|
|
payloadType += 255;
|
|
offset++;
|
|
}
|
|
payloadType += naluClone[offset++];
|
|
|
|
let payloadSize = 0; // SEI payload size as defined by H.264 spec
|
|
while (naluClone[offset] == 0xFF) {
|
|
payloadSize += 255;
|
|
offset++;
|
|
}
|
|
payloadSize += naluClone[offset++];
|
|
|
|
// Payload type 4 is user_data_registered_itu_t_t35, as per the H.264
|
|
// spec. This payload type contains caption data.
|
|
if (payloadType == 0x04) {
|
|
yield naluClone.subarray(offset, offset + payloadSize);
|
|
}
|
|
offset += payloadSize;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Removes H.264 emulation prevention bytes from the byte array.
|
|
*
|
|
* Note: Remove bytes by shifting will cause Chromium (VDA) to complain
|
|
* about conformance. Recreating a new array solves it.
|
|
*
|
|
* @param {!Uint8Array} naluData NALU from which EMUs should be removed.
|
|
* @return {!Uint8Array} The NALU with the emulation prevention byte removed.
|
|
*/
|
|
removeEmu(naluData) {
|
|
let naluClone = naluData;
|
|
let zeroCount = 0;
|
|
let src = 0;
|
|
while (src < naluClone.length) {
|
|
if (zeroCount == 2 && naluClone[src] == 0x03) {
|
|
// 0x00, 0x00, 0x03 pattern detected
|
|
zeroCount = 0;
|
|
|
|
// Splice the array and recreate a new one, instead of shifting bytes
|
|
const newArr = [...naluClone];
|
|
newArr.splice(src, 1);
|
|
naluClone = new Uint8Array(newArr);
|
|
} else {
|
|
if (naluClone[src] == 0x00) {
|
|
zeroCount++;
|
|
} else {
|
|
zeroCount = 0;
|
|
}
|
|
}
|
|
src++;
|
|
}
|
|
return naluClone;
|
|
}
|
|
};
|