Skip to content

Commit

Permalink
fix(cea): Fix not rendering CEA-608 on encrypted mp4 segments (shaka-…
Browse files Browse the repository at this point in the history
…project#4756)

Fixes shaka-project#4605

Co-authored-by: Joey Parrish <joeyparrish@google.com>
  • Loading branch information
avelad and joeyparrish committed Dec 1, 2022
1 parent b46012d commit d600109
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 16 deletions.
3 changes: 3 additions & 0 deletions externs/shaka/mp4_parser.js
Expand Up @@ -11,6 +11,7 @@

/**
* @typedef {{
* name: string,
* parser: !shaka.util.Mp4Parser,
* partialOkay: boolean,
* start: number,
Expand All @@ -21,6 +22,8 @@
* has64BitSize: boolean
* }}
*
* @property {string} name
* The box name, a 4-character string (fourcc).
* @property {!shaka.util.Mp4Parser} parser
* The parser that parsed this box. The parser can be used to parse child
* boxes where the configuration of the current parser is needed to parsed
Expand Down
53 changes: 37 additions & 16 deletions lib/cea/mp4_cea_parser.js
Expand Up @@ -66,14 +66,7 @@ shaka.cea.Mp4CeaParser = class {
const trackIds = [];
const timescales = [];

// This generates a box-parser callback that simply sets a particular
// bitstream format. It makes the list of codec-signalling boxes below
// more compact and readable.
const bitstreamFormatSetter = (format) => {
return (box) => {
this.bitstreamFormat_ = format;
};
};
const codecBoxParser = (box) => this.setBitstreamFormat_(box.name);

new Mp4Parser()
.box('moov', Mp4Parser.children)
Expand Down Expand Up @@ -108,14 +101,21 @@ shaka.cea.Mp4CeaParser = class {
.fullBox('stsd', Mp4Parser.sampleDescription)

// These are the various boxes that signal a codec.
// Use these to set bistreamFormat_.
.box('avc1', bitstreamFormatSetter(BitstreamFormat.H264))
.box('avc3', bitstreamFormatSetter(BitstreamFormat.H264))
.box('hev1', bitstreamFormatSetter(BitstreamFormat.H265))
.box('hvc1', bitstreamFormatSetter(BitstreamFormat.H265))
// Dobly vision is also H265.
.box('dvh1', bitstreamFormatSetter(BitstreamFormat.H265))
.box('dvhe', bitstreamFormatSetter(BitstreamFormat.H265))
.box('avc1', codecBoxParser)
.box('avc3', codecBoxParser)
.box('hev1', codecBoxParser)
.box('hvc1', codecBoxParser)
.box('dvh1', codecBoxParser)
.box('dvhe', codecBoxParser)

// This signals an encrypted sample, which we can go inside of to find
// the codec used.
.box('encv', Mp4Parser.visualSampleEntry)
.box('sinf', Mp4Parser.children)
.box('frma', (box) => {
const {codec} = shaka.util.Mp4BoxParsers.parseFRMA(box.reader);
this.setBitstreamFormat_(codec);
})

.parse(initSegment, /* partialOkay= */ true);

Expand Down Expand Up @@ -338,6 +338,16 @@ shaka.cea.Mp4CeaParser = class {
}
}
}

/**
* @param {string} codec A fourcc for a codec.
* @private
*/
setBitstreamFormat_(codec) {
if (codec in shaka.cea.Mp4CeaParser.CodecBitstreamMap_) {
this.bitstreamFormat_ = shaka.cea.Mp4CeaParser.CodecBitstreamMap_[codec];
}
}
};

/** @enum {number} */
Expand All @@ -346,3 +356,14 @@ shaka.cea.Mp4CeaParser.BitstreamFormat = {
H264: 1,
H265: 2,
};

/** @private {Object.<string, shaka.cea.Mp4CeaParser.BitstreamFormat>} */
shaka.cea.Mp4CeaParser.CodecBitstreamMap_ = {
'avc1': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
'avc3': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
'hev1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
'hvc1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
// Dobly vision is also H265.
'dvh1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
'dvhe': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
};
24 changes: 24 additions & 0 deletions lib/util/mp4_box_parsers.js
Expand Up @@ -7,6 +7,7 @@
goog.provide('shaka.util.Mp4BoxParsers');

goog.require('shaka.util.DataViewReader');
goog.require('shaka.util.Mp4Parser');

shaka.util.Mp4BoxParsers = class {
/**
Expand Down Expand Up @@ -188,6 +189,17 @@ shaka.util.Mp4BoxParsers = class {
trackId,
};
}

/**
* Parses a FRMA box.
* @param {!shaka.util.DataViewReader} reader
* @return {!shaka.util.ParsedFRMABox}
*/
static parseFRMA(reader) {
const fourcc = reader.readUint32();
const codec = shaka.util.Mp4Parser.typeToString(fourcc);
return {codec};
}
};


Expand Down Expand Up @@ -306,3 +318,15 @@ shaka.util.ParsedTRUNSample;
* @exportDoc
*/
shaka.util.ParsedTKHDBox;

/**
* @typedef {{
* codec: string
* }}
*
* @property {string} codec
* A fourcc for a codec
*
* @exportDoc
*/
shaka.util.ParsedFRMABox;
35 changes: 35 additions & 0 deletions lib/util/mp4_parser.js
Expand Up @@ -172,6 +172,7 @@ shaka.util.Mp4Parser = class {

/** @type {shaka.extern.ParsedBox} */
const box = {
name,
parser: this,
partialOkay: partialOkay || false,
version,
Expand Down Expand Up @@ -236,6 +237,40 @@ shaka.util.Mp4Parser = class {
}


/**
* A callback that tells the Mp4 parser to treat the body of a box as a visual
* sample entry. A visual sample entry has some fixed-sized fields
* describing the video codec parameters, followed by an arbitrary number of
* appended children. Each child is a box.
*
* @param {!shaka.extern.ParsedBox} box
* @export
*/
static visualSampleEntry(box) {
// The "reader" starts at the payload, so we need to add the header to the
// start position. The header size varies.
const headerSize = shaka.util.Mp4Parser.headerSize(box);

// Skip 6 reserved bytes.
// Skip 2-byte data reference index.
// Skip 16 more reserved bytes.
// Skip 4 bytes for width/height.
// Skip 8 bytes for horizontal/vertical resolution.
// Skip 4 more reserved bytes (0)
// Skip 2-byte frame count.
// Skip 32-byte compressor name (length byte, then name, then 0-padding).
// Skip 2-byte depth.
// Skip 2 more reserved bytes (0xff)
// 78 bytes total.
// See also https://github.com/shaka-project/shaka-packager/blob/d5ca6e84/packager/media/formats/mp4/box_definitions.cc#L1544
box.reader.skip(78);

while (box.reader.hasMoreData() && !box.parser.done_) {
box.parser.parseNext(box.start + headerSize, box.reader, box.partialOkay);
}
}


/**
* Create a callback that tells the Mp4 parser to treat the body of a box as a
* binary blob and to parse the body's contents using the provided callback.
Expand Down

0 comments on commit d600109

Please sign in to comment.