Skip to content

Commit 3194700

Browse files
authored
Calculate correct framerate when using MediaCapabilitiesAPI (Dash-Industry-Forum#4709)
* Calculate correct framerate when using MediaCapabilitiesAPI * Add missing Typescript definition * Add unit tests
1 parent a656ec7 commit 3194700

File tree

6 files changed

+94
-41
lines changed

6 files changed

+94
-41
lines changed

index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,8 @@ declare namespace dashjs {
437437

438438
getEventsForPeriod(period: Period): any[];
439439

440+
getFramerate(representation: object): number;
441+
440442
getId(manifest: object): string;
441443

442444
getIndexForAdaptation(realAdaptation: object, manifest: object, periodIndex: number): number;
@@ -1065,6 +1067,8 @@ declare namespace dashjs {
10651067

10661068
getEventsFor(info: object, voRepresentation: object): Array<Event>;
10671069

1070+
getFramerate(representation: object): number;
1071+
10681072
getIndexForRepresentation(representationId: string, periodIdx: number): number;
10691073

10701074
getIsDVB(manifest: object): boolean;

src/dash/DashAdapter.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,15 @@ function DashAdapter() {
764764
return dashManifestModel.getCodec(adaptation, representationIndex, addResolutionInfo);
765765
}
766766

767+
/**
768+
* Returns the framerate of a Representation as number
769+
* @param representation
770+
* @returns {number}
771+
*/
772+
function getFramerate(representation) {
773+
return dashManifestModel.getFramerate(representation);
774+
}
775+
767776
/**
768777
* Returns the bandwidth for a given representation id and the corresponding period index
769778
* @param {number} representationId
@@ -1225,6 +1234,7 @@ function DashAdapter() {
12251234
getEssentialPropertiesForRepresentation,
12261235
getEvent,
12271236
getEventsFor,
1237+
getFramerate,
12281238
getIndexForRepresentation,
12291239
getIsDVB,
12301240
getIsDynamic,

src/dash/models/DashManifestModel.js

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,26 @@ function DashManifestModel() {
537537
return representation && representation.bandwidth ? representation.bandwidth : NaN;
538538
}
539539

540+
function getFramerate(realRepresentation) {
541+
if (!realRepresentation) {
542+
return null
543+
}
544+
const frameRate = realRepresentation[DashConstants.FRAMERATE];
545+
if (!frameRate) {
546+
return null
547+
}
548+
549+
if (typeof frameRate === 'string' && frameRate.includes('/')) {
550+
const [numerator, denominator] = frameRate.split('/').map(value => parseInt(value, 10));
551+
552+
if (!isNaN(numerator) && !isNaN(denominator) && denominator !== 0) {
553+
return numerator / denominator;
554+
}
555+
}
556+
557+
return parseInt(frameRate);
558+
}
559+
540560
function getManifestUpdatePeriod(manifest, latencyOfLastUpdate = 0) {
541561
let delay = NaN;
542562
if (manifest && manifest.hasOwnProperty(DashConstants.MINIMUM_UPDATE_PERIOD)) {
@@ -595,7 +615,7 @@ function DashManifestModel() {
595615
if (!repr || !repr.length) {
596616
return [];
597617
}
598-
618+
599619
let propertiesOfFirstRepresentation = repr[0][propertyType] || [];
600620

601621
if (propertiesOfFirstRepresentation.length === 0) {
@@ -605,12 +625,12 @@ function DashManifestModel() {
605625
if (repr.length === 1) {
606626
return propertiesOfFirstRepresentation;
607627
}
608-
628+
609629
// now, only return properties present on all Representations
610630
// repr.legth is always >= 2
611-
return propertiesOfFirstRepresentation.filter( prop => {
612-
return repr.slice(1).every( currRep => {
613-
return currRep.hasOwnProperty(propertyType) && currRep[propertyType].some( e => {
631+
return propertiesOfFirstRepresentation.filter(prop => {
632+
return repr.slice(1).every(currRep => {
633+
return currRep.hasOwnProperty(propertyType) && currRep[propertyType].some(e => {
614634
return e.schemeIdUri === prop.schemeIdUri && e.value === prop.value;
615635
});
616636
});
@@ -638,7 +658,7 @@ function DashManifestModel() {
638658
function getEssentialPropertiesForAdaptationSet(adaptation) {
639659
return _getProperties(DashConstants.ESSENTIAL_PROPERTY, adaptation);
640660
}
641-
661+
642662
function getCombinedEssentialPropertiesForAdaptationSet(adaptation) {
643663
return _getCombinedPropertiesForAdaptationSet(DashConstants.ESSENTIAL_PROPERTY, adaptation);
644664
}
@@ -724,20 +744,7 @@ function DashManifestModel() {
724744
voRepresentation.scanType = realRepresentation.scanType;
725745
}
726746
if (realRepresentation.hasOwnProperty(DashConstants.FRAMERATE)) {
727-
const frameRate = realRepresentation[DashConstants.FRAMERATE];
728-
if (isNaN(frameRate) && frameRate.includes('/')) {
729-
const parts = frameRate.split('/');
730-
if (parts.length === 2) {
731-
const numerator = parseFloat(parts[0]);
732-
const denominator = parseFloat(parts[1]);
733-
734-
if (!isNaN(numerator) && !isNaN(denominator) && denominator !== 0) {
735-
voRepresentation.frameRate = numerator / denominator;
736-
}
737-
}
738-
} else {
739-
voRepresentation.frameRate = frameRate
740-
}
747+
voRepresentation.frameRate = getFramerate(realRepresentation);
741748
}
742749
if (realRepresentation.hasOwnProperty(DashConstants.QUALITY_RANKING)) {
743750
voRepresentation.qualityRanking = realRepresentation[DashConstants.QUALITY_RANKING];
@@ -1527,6 +1534,7 @@ function DashManifestModel() {
15271534
getEventStreamForAdaptationSet,
15281535
getEventStreamForRepresentation,
15291536
getEventsForPeriod,
1537+
getFramerate,
15301538
getId,
15311539
getIndexForAdaptation,
15321540
getIsDynamic,

src/streaming/utils/CapabilitiesFilter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ function CapabilitiesFilter() {
221221
codec: codec,
222222
width: rep.width || null,
223223
height: rep.height || null,
224-
framerate: rep.frameRate || null,
224+
framerate: adapter.getFramerate(rep) || null,
225225
bitrate: rep.bandwidth || null,
226226
isSupported: true
227227
}

test/unit/mocks/AdapterMock.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ function AdapterMock() {
1717
return null;
1818
};
1919

20+
this.getFramerate = function (rep) {
21+
if (rep && rep.frameRate) {
22+
return rep.frameRate
23+
}
24+
25+
return null
26+
}
27+
2028
this.getEventsFor = function () {
2129
return [];
2230
};

test/unit/test/dash/dash.models.DashManifestModel.js

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,8 +1513,8 @@ describe('DashManifestModel', function () {
15131513

15141514
it('should return client data reporting from manifest', () => {
15151515
const manifestData = {
1516-
ServiceDescription:[{
1517-
'ClientDataReporting':{
1516+
ServiceDescription: [{
1517+
'ClientDataReporting': {
15181518
'CMCDParameters': { schemeIdUri: 'urn:mpeg:dash:cta-5004:2023' },
15191519
'serviceLocations': 'cdn-a cdn-b',
15201520
'adaptationSets': 'test1 test2'
@@ -1541,8 +1541,8 @@ describe('DashManifestModel', function () {
15411541

15421542
it('should NOT return client data reporting if schemeIdUri is missed in manifest', () => {
15431543
const manifestData = {
1544-
ServiceDescription:[{
1545-
'ClientDataReporting':{
1544+
ServiceDescription: [{
1545+
'ClientDataReporting': {
15461546
'CMCDParameters': {},
15471547
'serviceLocations': 'cdn-a cdn-b',
15481548
'adaptationSets': 'test1 test2'
@@ -1567,8 +1567,8 @@ describe('DashManifestModel', function () {
15671567

15681568
it('should NOT return client data reporting if schemeIdUri is invalid in manifest', () => {
15691569
const manifestData = {
1570-
ServiceDescription:[{
1571-
'ClientDataReporting':{
1570+
ServiceDescription: [{
1571+
'ClientDataReporting': {
15721572
'CMCDParameters': { schemeIdUri: 'urn:mpeg:daaash:ctaa-5003:2003' },
15731573
'serviceLocations': 'cdn-a cdn-b',
15741574
'adaptationSets': 'test1 test2'
@@ -1598,14 +1598,14 @@ describe('DashManifestModel', function () {
15981598
const mode = 'query';
15991599
const sessionID = 2;
16001600
const manifestData = {
1601-
ServiceDescription:[{
1602-
'ClientDataReporting':{
1601+
ServiceDescription: [{
1602+
'ClientDataReporting': {
16031603
'CMCDParameters': {
1604-
'contentID':contentID,
1605-
'includeInRequests':includeInRequests,
1606-
'keys':keys,
1607-
'mode':mode,
1608-
'sessionID':sessionID,
1604+
'contentID': contentID,
1605+
'includeInRequests': includeInRequests,
1606+
'keys': keys,
1607+
'mode': mode,
1608+
'sessionID': sessionID,
16091609
'version': 1,
16101610
'schemeIdUri': 'urn:mpeg:dash:cta-5004:2023'
16111611
},
@@ -1633,14 +1633,14 @@ describe('DashManifestModel', function () {
16331633
const serviceLocations = 'cdn-a cdn-b';
16341634
const adaptationSets = 'test1 test2';
16351635
const manifestData = {
1636-
ServiceDescription:[{
1637-
'ClientDataReporting':{
1636+
ServiceDescription: [{
1637+
'ClientDataReporting': {
16381638
'CMCDParameters': {
1639-
'contentID':contentID,
1640-
'includeInRequests':includeInRequests,
1641-
'keys':keys,
1642-
'mode':mode,
1643-
'sessionID':sessionID,
1639+
'contentID': contentID,
1640+
'includeInRequests': includeInRequests,
1641+
'keys': keys,
1642+
'mode': mode,
1643+
'sessionID': sessionID,
16441644
'schemeIdUri': 'urn:mpeg:dash:cta-5004:2023'
16451645
},
16461646
'serviceLocations': serviceLocations,
@@ -1662,5 +1662,28 @@ describe('DashManifestModel', function () {
16621662
})
16631663

16641664
})
1665+
1666+
describe('getFramerate()', () => {
1667+
1668+
it('Should be null when no Representation is provided', () => {
1669+
const framerate = dashManifestModel.getFramerate();
1670+
expect(framerate).to.be.null;
1671+
})
1672+
1673+
it('Should be null when not defined', () => {
1674+
const framerate = dashManifestModel.getFramerate({});
1675+
expect(framerate).to.be.null;
1676+
})
1677+
1678+
it('Should parse single integer', () => {
1679+
const framerate = dashManifestModel.getFramerate({frameRate: '24'});
1680+
expect(framerate).to.be.equal(24);
1681+
})
1682+
1683+
it('Should parse two separated Integers', () => {
1684+
const framerate = dashManifestModel.getFramerate({frameRate: '48/2'});
1685+
expect(framerate).to.be.equal(24);
1686+
})
1687+
})
16651688
});
16661689
});

0 commit comments

Comments
 (0)