Skip to content

Commit

Permalink
refactor: try get content type via codecs, add bitmovin parsing test …
Browse files Browse the repository at this point in the history
…with audio protection
  • Loading branch information
vitalygashkov committed Nov 27, 2024
1 parent df94521 commit 8ae7982
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 27 deletions.
9 changes: 4 additions & 5 deletions lib/audio.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,11 @@ const parseAudioCodec = (codecs) => {
);
};

const isAudioCodec = (codecs) => {
const tryParseAudioCodec = (codecs) => {
try {
parseAudioCodec(codecs);
return true;
return parseAudioCodec(codecs);
} catch (e) {
return false;
return null;
}
};

Expand Down Expand Up @@ -142,7 +141,7 @@ const createAudioTrack = ({
module.exports = {
AUDIO_CODECS,
parseAudioCodec,
isAudioCodec,
tryParseAudioCodec,
createAudioTrack,
getDolbyDigitalPlusComplexityIndex,
checkIsDescriptive,
Expand Down
25 changes: 13 additions & 12 deletions lib/dash.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ const xml = require('./xml');
const { parseDuration, isLanguageTagValid } = require('./util');
const {
parseVideoCodec,
isVideoCodec,
tryParseVideoCodec,
parseDynamicRange,
createVideoTrack,
} = require('./video');
const {
parseAudioCodec,
isAudioCodec,
tryParseAudioCodec,
createAudioTrack,
getDolbyDigitalPlusComplexityIndex,
checkIsDescriptive,
} = require('./audio');
const {
parseSubtitleCodec,
isSubtitleCodec,
tryParseSubtitleCodec,
checkIsClosedCaption,
checkIsSdh,
checkIsForced,
Expand Down Expand Up @@ -79,23 +79,24 @@ const parseBaseUrl = (manifestUrl, mpd, period, representation) => {
return baseUrl;
};

const getTrackTypeByCodecs = (codecs) => {
if (tryParseVideoCodec(codecs)) return 'video';
else if (tryParseAudioCodec(codecs)) return 'audio';
else if (tryParseSubtitleCodec(codecs)) return 'text';
return null;
};

const parseContentTypes = (representation) => {
const codecs = representation.get('codecs');
const codecsType = isVideoCodec(codecs)
? 'video'
: isAudioCodec(codecs)
? 'audio'
: isSubtitleCodec(codecs)
? 'text'
: null;
const mimeType = representation.get('mimeType');
const contentTypeByCodecs = getTrackTypeByCodecs(codecs);
const contentType =
codecsType || representation.get('contentType') || mimeType?.split('/')[0];
representation.get('contentType') || mimeType?.split('/')[0];
if (!contentType && !mimeType)
throw new Error(
'Unable to determine the format of a Representation, cannot continue...',
);
return { contentType, mimeType };
return { contentType: contentTypeByCodecs || contentType, mimeType };
};

const parseCodecs = (representation, contentType, mimeType) => {
Expand Down
9 changes: 4 additions & 5 deletions lib/subtitle.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,11 @@ const parseSubtitleCodec = (codecs) => {
);
};

const isSubtitleCodec = (codecs) => {
const tryParseSubtitleCodec = (codecs) => {
try {
parseSubtitleCodec(codecs);
return true;
return parseSubtitleCodec(codecs);
} catch (e) {
return false;
return null;
}
};

Expand Down Expand Up @@ -129,7 +128,7 @@ const createSubtitleTrack = ({

module.exports = {
parseSubtitleCodec,
isSubtitleCodec,
tryParseSubtitleCodec,
checkIsClosedCaption,
checkIsSdh,
checkIsForced,
Expand Down
9 changes: 4 additions & 5 deletions lib/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,11 @@ const parseVideoCodec = (codecs) => {
);
};

const isVideoCodec = (codecs) => {
const tryParseVideoCodec = (codecs) => {
try {
parseVideoCodec(codecs);
return true;
return parseVideoCodec(codecs);
} catch (e) {
return false;
return null;
}
};

Expand Down Expand Up @@ -194,7 +193,7 @@ const parseDynamicRange = (

module.exports = {
parseVideoCodec,
isVideoCodec,
tryParseVideoCodec,
parseDynamicRange,
createVideoTrack,
VIDEO_CODECS,
Expand Down
4 changes: 4 additions & 0 deletions test/axinom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ test('axinom manifest parsing', async () => {
'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/5/1.m4s',
);

const firstSubtitleTrack = manifest.tracks.subtitles[0];
strictEqual(firstSubtitleTrack.codec, 'WVTT');
strictEqual(firstSubtitleTrack.language, 'en');

strictEqual(manifest.tracks.all.length, 23);
});
54 changes: 54 additions & 0 deletions test/bitmovin.mpd
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<MPD id="505916a3-fc9b-4088-be98-d90796861a3a" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="static" availabilityStartTime="2015-09-17T09:32:38.000Z" publishTime="2015-09-17T09:32:46.000Z" mediaPresentationDuration="P0Y0M0DT0H3M30.000S" minBufferTime="P0Y0M0DT0H0M1.000S" bitmovin:version="1.6.0" xmlns:ns2="http://www.w3.org/1999/xlink" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:bitmovin="http://www.bitmovin.net/mpd/2015">
<Period>
<AdaptationSet mimeType="video/mp4" codecs="avc1.42c00d">
<SegmentTemplate media="../video/$RepresentationID$/cenc_dash/segment_$Number$.m4s" initialization="../video/$RepresentationID$/cenc_dash/init.mp4" duration="4000" startNumber="0" timescale="1000"/>
<Representation id="180_250000" bandwidth="250000" width="320" height="180" frameRate="25">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation id="270_400000" bandwidth="400000" width="480" height="270" frameRate="25">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation id="360_800000" bandwidth="800000" width="640" height="360" frameRate="25">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation id="540_1200000" bandwidth="1200000" width="960" height="540" frameRate="25">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation id="720_2400000" bandwidth="2400000" width="1280" height="720" frameRate="25">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation id="1080_4800000" bandwidth="4800000" width="1920" height="1080" frameRate="25">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
<AdaptationSet lang="en" mimeType="audio/mp4" codecs="mp4a.40.2" bitmovin:label="english stereo">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<SegmentTemplate media="../audio/$RepresentationID$/cenc_dash/segment_$Number$.m4s" initialization="../audio/$RepresentationID$/cenc_dash/init.mp4" duration="3999" startNumber="0" timescale="1000"/>
<Representation id="1_stereo_192000" bandwidth="192000" audioSamplingRate="48000">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="eb676abb-cb34-5e96-bbcf-616630f1a3da" xmlns:cenc="urn:mpeg:cenc:2013"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh xmlns:cenc="urn:mpeg:cenc:2013">AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
</Period>
</MPD>
19 changes: 19 additions & 0 deletions test/bitmovin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { test } = require('node:test');
const { strictEqual } = require('node:assert');
const { parse } = require('../dasha');
const { load } = require('./utils');

test('bitmovin manifest parsing', async () => {
const url =
'https://cdn.bitmovin.com/content/assets/art-of-motion_drm/mpds/11331.mpd';
const text = load('bitmovin.mpd');
const manifest = await parse(text, url);

const firstAudioTrack = manifest.tracks.audios[0];
strictEqual(
firstAudioTrack.protection.widevine.pssh,
'AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==',
);

strictEqual(manifest.tracks.all.length, 7);
});

0 comments on commit 8ae7982

Please sign in to comment.