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.
258 lines
8.5 KiB
258 lines
8.5 KiB
import QUnit from 'qunit';
|
|
import { mimeTypesForPlaylist, mapLegacyAvcCodecs } from '../src/util/codecs';
|
|
|
|
const generateMedia = function(isMaat, isMuxed, hasVideoCodec, hasAudioCodec, isFMP4) {
|
|
const codec = (hasVideoCodec ? 'avc1.deadbeef' : '') +
|
|
(hasVideoCodec && hasAudioCodec ? ',' : '') +
|
|
(hasAudioCodec ? 'mp4a.40.E' : '');
|
|
const master = {
|
|
mediaGroups: {},
|
|
playlists: []
|
|
};
|
|
const media = {
|
|
attributes: {}
|
|
};
|
|
|
|
if (isMaat) {
|
|
master.mediaGroups.AUDIO = {
|
|
test: {
|
|
demuxed: {
|
|
uri: 'foo.bar'
|
|
}
|
|
}
|
|
};
|
|
|
|
if (isMuxed) {
|
|
master.mediaGroups.AUDIO.test.muxed = {};
|
|
}
|
|
media.attributes.AUDIO = 'test';
|
|
}
|
|
|
|
if (isFMP4) {
|
|
// This is not a great way to signal that the playlist is fmp4 but
|
|
// this is how we currently detect it in HLS so let's emulate it here
|
|
media.segments = [
|
|
{
|
|
map: 'test'
|
|
}
|
|
];
|
|
}
|
|
|
|
if (hasVideoCodec || hasAudioCodec) {
|
|
media.attributes.CODECS = codec;
|
|
}
|
|
|
|
return [master, media];
|
|
};
|
|
|
|
QUnit.module('Codec to MIME Type Conversion');
|
|
|
|
const testMimeTypes = function(assert, isFMP4) {
|
|
let container = isFMP4 ? 'mp4' : 'mp2t';
|
|
|
|
let videoMime = `video/${container}`;
|
|
let audioMime = `audio/${container}`;
|
|
|
|
// no MAAT
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(false, true, false, false, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.4d400d, mp4a.40.2"`],
|
|
`no MAAT, container: ${container}, codecs: none`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(false, true, true, false, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.deadbeef"`],
|
|
`no MAAT, container: ${container}, codecs: video`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(false, true, false, true, isFMP4)),
|
|
[`${audioMime}; codecs="mp4a.40.E"`],
|
|
`no MAAT, container: ${container}, codecs: audio`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(false, true, true, true, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.deadbeef, mp4a.40.E"`],
|
|
`no MAAT, container: ${container}, codecs: video, audio`);
|
|
|
|
// MAAT, not muxed
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, false, false, false, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.4d400d"`,
|
|
`${audioMime}; codecs="mp4a.40.2"`],
|
|
`MAAT, demuxed, container: ${container}, codecs: none`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, false, true, false, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.deadbeef"`,
|
|
`${audioMime}; codecs="mp4a.40.2"`],
|
|
`MAAT, demuxed, container: ${container}, codecs: video`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, false, false, true, isFMP4)),
|
|
[`${audioMime}; codecs="mp4a.40.E"`,
|
|
`${audioMime}; codecs="mp4a.40.E"`],
|
|
`MAAT, demuxed, container: ${container}, codecs: audio`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, false, true, true, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.deadbeef"`,
|
|
`${audioMime}; codecs="mp4a.40.E"`],
|
|
`MAAT, demuxed, container: ${container}, codecs: video, audio`);
|
|
|
|
// MAAT, muxed
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, true, false, false, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.4d400d, mp4a.40.2"`,
|
|
`${audioMime}; codecs="mp4a.40.2"`],
|
|
`MAAT, muxed, container: ${container}, codecs: none`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, true, true, false, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.deadbeef, mp4a.40.2"`,
|
|
`${audioMime}; codecs="mp4a.40.2"`],
|
|
`MAAT, muxed, container: ${container}, codecs: video`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, true, false, true, isFMP4)),
|
|
[`${videoMime}; codecs="mp4a.40.E"`,
|
|
`${audioMime}; codecs="mp4a.40.E"`],
|
|
`MAAT, muxed, container: ${container}, codecs: audio`);
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist.apply(null,
|
|
generateMedia(true, true, true, true, isFMP4)),
|
|
[`${videoMime}; codecs="avc1.deadbeef, mp4a.40.E"`,
|
|
`${audioMime}; codecs="mp4a.40.E"`],
|
|
`MAAT, muxed, container: ${container}, codecs: video, audio`);
|
|
};
|
|
|
|
QUnit.test('recognizes muxed codec configurations', function(assert) {
|
|
testMimeTypes(assert, false);
|
|
testMimeTypes(assert, true);
|
|
});
|
|
|
|
// dash audio playlist won't have a URI but will have resolved playlists
|
|
QUnit.test('content demuxed if alt audio URI not present but playlists present',
|
|
function(assert) {
|
|
const media = {
|
|
attributes: {
|
|
AUDIO: 'test',
|
|
CODECS: 'avc1.deadbeef, mp4a.40.E'
|
|
},
|
|
segments: [
|
|
// signal fmp4
|
|
{ map: 'test' }
|
|
]
|
|
};
|
|
const master = {
|
|
mediaGroups: {
|
|
AUDIO: {
|
|
test: {
|
|
demuxed: {
|
|
uri: 'foo.bar'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
playlists: [media]
|
|
};
|
|
|
|
assert.deepEqual(mimeTypesForPlaylist(master, media),
|
|
['video/mp4; codecs="avc1.deadbeef"', 'audio/mp4; codecs="mp4a.40.E"'],
|
|
'demuxed if URI');
|
|
|
|
delete master.mediaGroups.AUDIO.test.demuxed.uri;
|
|
assert.deepEqual(
|
|
mimeTypesForPlaylist(master, media),
|
|
['video/mp4; codecs="avc1.deadbeef, mp4a.40.E"', 'audio/mp4; codecs="mp4a.40.E"'],
|
|
'muxed if no URI and no playlists');
|
|
|
|
master.mediaGroups.AUDIO.test.demuxed.playlists = [{}];
|
|
assert.deepEqual(mimeTypesForPlaylist(master, media),
|
|
['video/mp4; codecs="avc1.deadbeef"', 'audio/mp4; codecs="mp4a.40.E"'],
|
|
'demuxed if no URI but playlists');
|
|
});
|
|
|
|
QUnit.test('uses audio codec from default group if not specified in media attributes',
|
|
function(assert) {
|
|
const media = {
|
|
attributes: {
|
|
AUDIO: 'test',
|
|
CODECS: 'avc1.deadbeef'
|
|
},
|
|
segments: [
|
|
// signal fmp4
|
|
{ map: 'test' }
|
|
]
|
|
};
|
|
// dash audio playlist won't have a URI but will have resolved playlists
|
|
const master = {
|
|
mediaGroups: {
|
|
AUDIO: {
|
|
test: {
|
|
demuxed: {
|
|
default: true,
|
|
playlists: [{
|
|
attributes: {
|
|
CODECS: 'mp4a.40.E'
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
playlists: [media]
|
|
};
|
|
|
|
assert.deepEqual(
|
|
mimeTypesForPlaylist(master, media),
|
|
['video/mp4; codecs="avc1.deadbeef"', 'audio/mp4; codecs="mp4a.40.E"'],
|
|
'uses audio codec from media group');
|
|
|
|
delete master.mediaGroups.AUDIO.test.demuxed.default;
|
|
assert.deepEqual(
|
|
mimeTypesForPlaylist(master, media),
|
|
['video/mp4; codecs="avc1.deadbeef"', 'audio/mp4; codecs="mp4a.40.2"'],
|
|
'uses default audio codec');
|
|
});
|
|
|
|
QUnit.module('Map Legacy AVC Codec');
|
|
|
|
QUnit.test('maps legacy AVC codecs', function(assert) {
|
|
assert.equal(mapLegacyAvcCodecs('avc1.deadbeef'),
|
|
'avc1.deadbeef',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('avc1.dead.beef, mp4a.something'),
|
|
'avc1.dead.beef, mp4a.something',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('avc1.dead.beef,mp4a.something'),
|
|
'avc1.dead.beef,mp4a.something',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('mp4a.something,avc1.dead.beef'),
|
|
'mp4a.something,avc1.dead.beef',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('mp4a.something, avc1.dead.beef'),
|
|
'mp4a.something, avc1.dead.beef',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('avc1.42001e'),
|
|
'avc1.42001e',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('avc1.4d0020,mp4a.40.2'),
|
|
'avc1.4d0020,mp4a.40.2',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('mp4a.40.2,avc1.4d0020'),
|
|
'mp4a.40.2,avc1.4d0020',
|
|
'does nothing for non legacy pattern');
|
|
assert.equal(mapLegacyAvcCodecs('mp4a.40.40'),
|
|
'mp4a.40.40',
|
|
'does nothing for non video codecs');
|
|
|
|
assert.equal(mapLegacyAvcCodecs('avc1.66.30'),
|
|
'avc1.42001e',
|
|
'translates legacy video codec alone');
|
|
assert.equal(mapLegacyAvcCodecs('avc1.66.30, mp4a.40.2'),
|
|
'avc1.42001e, mp4a.40.2',
|
|
'translates legacy video codec when paired with audio');
|
|
assert.equal(mapLegacyAvcCodecs('mp4a.40.2, avc1.66.30'),
|
|
'mp4a.40.2, avc1.42001e',
|
|
'translates video codec when specified second');
|
|
});
|