Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(DASH): Ensure variants are created for unique video codec bases #6835

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions lib/util/periods.js
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ shaka.util.PeriodCombiner = class {
periodsMissing) {
const ContentType = shaka.util.ManifestParserUtils.ContentType;
const LanguageUtils = shaka.util.LanguageUtils;
const MimeUtils = shaka.util.MimeUtils;
const matches = outputStream.matchedStreams;

// Assure the compiler that matches didn't become null during the async
Expand All @@ -733,6 +734,29 @@ shaka.util.PeriodCombiner = class {
if (relatedness == 0) {
used = false;
}
// If we have different audio codecs in matched representations,
// we don't want to delete the matched stream until
// an outputStream has been created for each audio representation.
if (used && outputStream.codecs != match.codecs) {
used = false;
}
}
// In cases where we have the same video codec but different
// codec bases in matched representations (e.g. HEVC as hev and hvc),
// we don't want to delete the matched stream until an
// outputStream has been created for each video representation.
if (outputStream.type == ContentType.VIDEO) {
avelad marked this conversation as resolved.
Show resolved Hide resolved
const outputStreamNormalizedCodec =
MimeUtils.getNormalizedCodec(outputStream.codecs);
const matchNormalizedCodec = MimeUtils.getNormalizedCodec(match.codecs);
const outputStreamCodecBase =
MimeUtils.getCodecBase(outputStream.codecs);
const matchCodecBase = MimeUtils.getCodecBase(match.codecs);

if (outputStreamNormalizedCodec == matchNormalizedCodec &&
outputStreamCodecBase != matchCodecBase) {
used = false;
}
}

if (used) {
Expand Down
72 changes: 70 additions & 2 deletions test/util/periods_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,59 @@ describe('PeriodCombiner', () => {
expect(audio2.originalId).toBe('2,4');
});

it('Matches streams with related codecs', async () => {
it('Creates an audio stream per unique codec ' +
'and matches streams with related codecs', async () => {
const stream1 = makeAudioStream('en', /* channels= */ 2);
stream1.originalId = '1';
stream1.bandwidth = 129597;
stream1.codecs = 'mp4a.40.2';

const stream2 = makeAudioStream('en', /* channels= */ 2);
stream2.originalId = '2';
stream2.bandwidth = 131033;
stream2.codecs = 'mp4a.40.29';

/** @type {!Array.<shaka.extern.Period>} */
const periods = [
{
id: '0',
videoStreams: [
makeVideoStream(1080),
],
audioStreams: [
stream1,
],
textStreams: [],
imageStreams: [],
},
{
id: '1',
videoStreams: [
makeVideoStream(1080),
],
audioStreams: [
stream2,
],
textStreams: [],
imageStreams: [],
},
];

await combiner.combinePeriods(periods, /* isDynamic= */ true);
const variants = combiner.getVariants();
expect(variants.length).toBe(2);
// We can use the originalId field to see what each track is composed of.
const audio1 = variants[0].audio;
expect(audio1.codecs).toBe(stream1.codecs);
expect(audio1.originalId).toBe('1,2');

const audio2 = variants[1].audio;
expect(audio2.codecs).toBe(stream2.codecs);
expect(audio2.originalId).toBe('1,2');
});

it('Creates a video stream per unique codec base ' +
'and matches streams with related codecs', async () => {
const stream1 = makeVideoStream(1080);
stream1.originalId = '1';
stream1.bandwidth = 120000;
Expand Down Expand Up @@ -1189,19 +1241,35 @@ describe('PeriodCombiner', () => {

await combiner.combinePeriods(periods, /* isDynamic= */ true);
const variants = combiner.getVariants();
expect(variants.length).toBe(4);
expect(variants.length).toBe(7);
// We can use the originalId field to see what each track is composed of.
const video1 = variants[0].video;
expect(video1.originalId).toBe('1,2');
expect(video1.codecs).toBe(stream1.codecs);

const video2 = variants[1].video;
expect(video2.originalId).toBe('3,4');
expect(video2.codecs).toBe(stream3.codecs);

const video3 = variants[2].video;
expect(video3.originalId).toBe('5,6');
expect(video3.codecs).toBe(stream5.codecs);

const video4 = variants[3].video;
expect(video4.originalId).toBe('7,8');
expect(video4.codecs).toBe(stream7.codecs);

const video5 = variants[4].video;
expect(video5.originalId).toBe('1,2');
expect(video5.codecs).toBe(stream2.codecs);

const video6 = variants[5].video;
expect(video6.originalId).toBe('3,4');
expect(video6.codecs).toBe(stream4.codecs);

const video7 = variants[6].video;
expect(video7.originalId).toBe('5,6');
expect(video7.codecs).toBe(stream6.codecs);
});

it('Matches streams with most roles in common', async () => {
Expand Down
Loading