You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.0 KiB
138 lines
4.0 KiB
/**
|
|
* Helper functions for creating 608/708 SEI NAL units
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var box = require('./mp4-helpers').box;
|
|
|
|
// Create SEI nal-units from Caption packets
|
|
var makeSeiFromCaptionPacket = function(caption) {
|
|
return {
|
|
pts: caption.pts,
|
|
dts: caption.dts,
|
|
nalUnitType: 'sei_rbsp',
|
|
escapedRBSP: new Uint8Array([
|
|
0x04, // payload_type === user_data_registered_itu_t_t35
|
|
|
|
0x0e, // payload_size
|
|
|
|
181, // itu_t_t35_country_code
|
|
0x00, 0x31, // itu_t_t35_provider_code
|
|
0x47, 0x41, 0x39, 0x34, // user_identifier, "GA94"
|
|
0x03, // user_data_type_code, 0x03 is cc_data
|
|
|
|
// 110 00001
|
|
0xc1, // process_cc_data, cc_count
|
|
0xff, // reserved
|
|
// 1111 1100
|
|
(0xfc | caption.type), // cc_valid, cc_type (608, field 1)
|
|
(caption.ccData & 0xff00) >> 8, // cc_data_1
|
|
caption.ccData & 0xff, // cc_data_2 without parity bit set
|
|
|
|
0xff // marker_bits
|
|
])
|
|
};
|
|
};
|
|
|
|
// Create SEI nal-units from Caption packets
|
|
var makeSeiFromMultipleCaptionPackets = function(captionHash) {
|
|
var pts = captionHash.pts,
|
|
dts = captionHash.dts,
|
|
captions = captionHash.captions;
|
|
|
|
var data = [];
|
|
captions.forEach(function(caption) {
|
|
data.push(0xfc | caption.type);
|
|
data.push((caption.ccData & 0xff00) >> 8);
|
|
data.push(caption.ccData & 0xff);
|
|
});
|
|
|
|
return {
|
|
pts: pts,
|
|
dts: dts,
|
|
nalUnitType: 'sei_rbsp',
|
|
escapedRBSP: new Uint8Array([
|
|
0x04, // payload_type === user_data_registered_itu_t_t35
|
|
|
|
(0x0b + (captions.length * 3)), // payload_size
|
|
|
|
181, // itu_t_t35_country_code
|
|
0x00, 0x31, // itu_t_t35_provider_code
|
|
0x47, 0x41, 0x39, 0x34, // user_identifier, "GA94"
|
|
0x03, // user_data_type_code, 0x03 is cc_data
|
|
|
|
// 110 00001
|
|
(0x6 << 5) | captions.length, // process_cc_data, cc_count
|
|
0xff // reserved
|
|
].concat(data).concat([0xff /* marker bits */])
|
|
)
|
|
};
|
|
};
|
|
|
|
var makeMdatFromCaptionPackets = function(packets) {
|
|
var mdat = ['mdat'];
|
|
var seis = packets.map(makeSeiFromCaptionPacket);
|
|
|
|
seis.forEach(function(sei) {
|
|
mdat.push(0x00);
|
|
mdat.push(0x00);
|
|
mdat.push(0x00);
|
|
mdat.push(sei.escapedRBSP.length + 1); // nal length
|
|
mdat.push(0x06); // declare nal type as SEI
|
|
// SEI message
|
|
for (var i = 0; i < sei.escapedRBSP.length; i++) {
|
|
var byte = sei.escapedRBSP[i];
|
|
|
|
mdat.push(byte);
|
|
}
|
|
});
|
|
|
|
return box.apply(null, mdat);
|
|
};
|
|
|
|
// Returns a ccData byte-pair for a two character string. That is,
|
|
// it converts a string like 'hi' into the two-byte number that
|
|
// would be parsed back as 'hi' when provided as ccData.
|
|
var characters = function(text) {
|
|
if (text.length !== 2) {
|
|
throw new Error('ccdata must be specified two characters at a time');
|
|
}
|
|
return (text.charCodeAt(0) << 8) | text.charCodeAt(1);
|
|
};
|
|
|
|
// Returns a ccData byte-pair including
|
|
// Header for 708 packet
|
|
// Header for the first service block
|
|
// seq should increment by 1 for each byte pair mod 3 (0,1,2,0,1,2,...)
|
|
// sizeCode is the number of byte pairs in the packet (including header)
|
|
// serviceNum is the service number of the first service block
|
|
// blockSize is the size of the first service block in bytes (no header)
|
|
// If there's only one service block, the blockSize should be (sizeCode-1)*2
|
|
var packetHeader708 = function(seq, sizeCode, serviceNum, blockSize) {
|
|
var b1 = (seq << 6) | sizeCode;
|
|
var b2 = (serviceNum << 5) | blockSize;
|
|
return (b1 << 8) | b2;
|
|
};
|
|
|
|
// Returns a ccData byte-pair to execute a 708 DSW command
|
|
// Takes an array of window indicies to display
|
|
var displayWindows708 = function(windows) {
|
|
var cmd = 0x8900;
|
|
|
|
windows.forEach(function(winIdx) {
|
|
cmd |= (0x01 << winIdx);
|
|
});
|
|
|
|
return cmd;
|
|
};
|
|
|
|
module.exports = {
|
|
makeSeiFromCaptionPacket: makeSeiFromCaptionPacket,
|
|
makeSeiFromMultipleCaptionPackets: makeSeiFromMultipleCaptionPackets,
|
|
makeMdatFromCaptionPackets: makeMdatFromCaptionPackets,
|
|
characters: characters,
|
|
packetHeader708: packetHeader708,
|
|
displayWindows708: displayWindows708
|
|
};
|