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

Update thumbnails API #3297

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 14 additions & 5 deletions contrib/akamai/controlbar/ControlBar.js
Expand Up @@ -278,7 +278,7 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
}

// Get thumbnail information
player.getThumbnail(mouseTime, function (thumbnail) {
player.provideThumbnail(mouseTime, function (thumbnail) {
if (!thumbnail) return;

// Adjust left variable for positioning thumbnail with regards to its viewport
Expand Down Expand Up @@ -505,7 +505,8 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
var availableBitrates = { menuType: 'bitrate' };
availableBitrates.audio = player.getBitrateInfoListFor('audio') || [];
availableBitrates.video = player.getBitrateInfoListFor('video') || [];
if (availableBitrates.audio.length > 1 || availableBitrates.video.length > 1) {
availableBitrates.images = player.getBitrateInfoListFor('image') || [];
if (availableBitrates.audio.length > 1 || availableBitrates.video.length > 1 || availableBitrates.images.length > 1) {
contentFunc = function (element, index) {
var result = isNaN(index) ? ' Auto Switch' : Math.floor(element.bitrate / 1000) + ' kbps';
result += element && element.width && element.height ? ' (' + element.width + 'x' + element.height + ')' : '';
Expand Down Expand Up @@ -578,6 +579,11 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
el = createMenuContent(el, getMenuContent(menuType, info.audio, contentFunc), 'audio', 'audio-' + menuType + '-list');
setMenuItemsState(getMenuInitialIndex(info.audio, menuType, 'audio'), 'audio-' + menuType + '-list');
}
if (info.images.length > 1) {
el.appendChild(createMediaTypeMenu('image'));
el = createMenuContent(el, getMenuContent(menuType, info.images, contentFunc, false), 'image', 'image-' + menuType + '-list');
setMenuItemsState(getMenuInitialIndex(info.images, menuType, 'image'), 'image-' + menuType + '-list');
}
break;
}

Expand Down Expand Up @@ -619,12 +625,12 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
return (sameId && sameViewpoint && sameLang && sameRoles && sameAccessibility && sameAudioChannelConfiguration);
};

var getMenuContent = function (type, arr, contentFunc) {
var getMenuContent = function (type, arr, contentFunc, autoswitch = true) {
dsilhavy marked this conversation as resolved.
Show resolved Hide resolved
var content = [];
arr.forEach(function (element, index) {
content.push(contentFunc(element, index));
});
if (type !== 'track') {
if (type !== 'track' && autoswitch) {
content.unshift(contentFunc(null, NaN));
}
return content;
Expand Down Expand Up @@ -655,7 +661,7 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {

div.id = type;

title.textContent = type === 'video' ? 'Video' : 'Audio';
title.textContent = type.charAt(0).toUpperCase() + type.slice(1);
title.classList.add('menu-sub-menu-title');

content.id = type + 'Content';
Expand Down Expand Up @@ -749,6 +755,9 @@ var ControlBar = function (dashjsMediaPlayer, displayUTCTimeCodes) {
player.updateSettings(cfg);
}
break;
case 'image-bitrate-list':
player.setQualityFor(self.mediaType, self.index);
break;
case 'caption-list':
player.setTextTrack(self.index - 1);
break;
Expand Down
4 changes: 2 additions & 2 deletions index.d.ts
Expand Up @@ -283,7 +283,7 @@ declare namespace dashjs {
setTextDefaultLanguage(lang: string): void;
getTextDefaultEnabled(): boolean | undefined;
setTextDefaultEnabled(enable: boolean): void;
getThumbnail(time: number): Thumbnail;
provideThumbnail(time: number, callback: (thumbnail: Thumbnail | null) => void): void;
getBitrateInfoListFor(type: MediaType): BitrateInfo[];
getStreamsFromManifest(manifest: object): StreamInfo[];
getTracksFor(type: MediaType): MediaInfo[];
Expand Down Expand Up @@ -803,7 +803,7 @@ declare namespace dashjs {
}

export class BitrateInfo {
mediaType: 'video' | 'audio';
mediaType: 'video' | 'audio' | 'image';
bitrate: number;
width: number;
height: number;
Expand Down
22 changes: 12 additions & 10 deletions src/streaming/MediaPlayer.js
Expand Up @@ -1652,31 +1652,33 @@ function MediaPlayer() {
*/

/**
* Return the thumbnail at time position.
* @returns {Thumbnail|null} - Thumbnail for the given time position. It returns null in case there are is not a thumbnails representation or
* if it doesn't contain a thumbnail for the given time position.
* Provide the thumbnail at time position. This can be asynchronous, so you must provide a callback ro retrieve thumbnails informations
* @param {number} time - A relative time, in seconds, based on the return value of the {@link module:MediaPlayer#duration duration()} method is expected
* @param {function} callback - A Callback function provided when retrieving thumbnail
* @param {function} callback - A Callback function provided when retrieving thumbnail the given time position. Thumbnail object is null in case there are is not a thumbnails representation or
* if it doesn't contain a thumbnail for the given time position.
* @memberof module:MediaPlayer
* @instance
*/
function getThumbnail(time, callback) {
function provideThumbnail(time, callback) {
if (!callback) {
dsilhavy marked this conversation as resolved.
Show resolved Hide resolved
return;
}
if (time < 0) {
return null;
callback(null);
}
const s = playbackController.getIsDynamic() ? getDVRSeekOffset(time) : time;
const stream = streamController.getStreamForTime(s);
if (stream === null) {
return null;
callback(null);
}

const thumbnailController = stream.getThumbnailController();
if (!thumbnailController) {
return null;
callback(null);
}

const timeInPeriod = streamController.getTimeRelativeToStreamId(s, stream.getId());
return thumbnailController.get(timeInPeriod, callback);
return thumbnailController.provide(timeInPeriod, callback);
}

/*
Expand Down Expand Up @@ -2271,7 +2273,7 @@ function MediaPlayer() {
displayCaptionsOnTop: displayCaptionsOnTop,
attachTTMLRenderingDiv: attachTTMLRenderingDiv,
getCurrentTextTrackIndex: getCurrentTextTrackIndex,
getThumbnail: getThumbnail,
provideThumbnail: provideThumbnail,
getDashAdapter: getDashAdapter,
getOfflineController: getOfflineController,
getSettings: getSettings,
Expand Down
19 changes: 11 additions & 8 deletions src/streaming/thumbnail/ThumbnailController.js
Expand Up @@ -57,12 +57,18 @@ function ThumbnailController(config) {
});
}

function getThumbnail(time, callback) {
function provideThumbnail(time, callback) {

if (!callback) {
//callback is not defined, no need to continue
return;
}
const track = thumbnailTracks.getCurrentTrack();
let offset,
request;
if (!track || track.segmentDuration <= 0 || time === undefined || time === null) {
return null;
callback(null);
return;
}

// Calculate index of the sprite given a time
Expand All @@ -87,8 +93,7 @@ function ThumbnailController(config) {
if ('readThumbnail' in track) {
return track.readThumbnail(time, (url) => {
thumbnail.url = url;
if (callback)
callback(thumbnail);
callback(thumbnail);
});
} else {
if (!request) {
Expand All @@ -98,9 +103,7 @@ function ThumbnailController(config) {
thumbnail.url = request.url;
track.segmentDuration = NaN;
}
if (callback)
callback(thumbnail);
return thumbnail;
callback(thumbnail);
}
}

Expand Down Expand Up @@ -142,7 +145,7 @@ function ThumbnailController(config) {
}

instance = {
get: getThumbnail,
provide: provideThumbnail,
setTrackByIndex: setTrackByIndex,
getCurrentTrackIndex: getCurrentTrackIndex,
getBitrateList: getBitrateList,
Expand Down
24 changes: 13 additions & 11 deletions test/unit/streaming.thumbnail.ThumbnailController.js
Expand Up @@ -86,8 +86,9 @@ describe('Thumbnails', function () {
});

it('should return null if not initialized', function () {
const thumbnail = thumbnailController.get(0);
expect(thumbnail).to.be.null; // jshint ignore:line
thumbnailController.provide(0, (thumbnail) => {
expect(thumbnail).to.be.null; // jshint ignore:line
});

expect(thumbnailController.getBitrateList()).to.be.empty; // jshint ignore:line
});
Expand Down Expand Up @@ -116,10 +117,11 @@ describe('Thumbnails', function () {
});

it('should return a thumbnail', function () {
let thumbnail = thumbnailController.get();
expect(thumbnail).to.be.null; // jshint ignore:line
thumbnailController.provide(undefined, thumbnail => {
expect(thumbnail).to.be.null; // jshint ignore:line
});

thumbnailController.get(0, thumbnail => {
thumbnailController.provide(0, thumbnail => {
expect(thumbnail).to.be.not.null; // jshint ignore:line
expect(thumbnail.x).to.equal(0);
expect(thumbnail.y).to.equal(0);
Expand All @@ -128,7 +130,7 @@ describe('Thumbnails', function () {
expect(thumbnail.url).to.equal('http://media/rep_id/1.jpg');
});

thumbnailController.get(11, thumbnail => {
thumbnailController.provide(11, thumbnail => {
expect(thumbnail).to.be.not.null; // jshint ignore:line
expect(thumbnail.x).to.equal(320);
expect(thumbnail.y).to.equal(0);
Expand All @@ -137,7 +139,7 @@ describe('Thumbnails', function () {
expect(thumbnail.url).to.equal('http://media/rep_id/1.jpg');
});

thumbnailController.get(101, thumbnail => {
thumbnailController.provide(101, thumbnail => {
expect(thumbnail).to.be.not.null; // jshint ignore:line
expect(thumbnail.x).to.equal(0);
expect(thumbnail.y).to.equal(0);
Expand All @@ -149,7 +151,7 @@ describe('Thumbnails', function () {

it('shouldn\'t return any thumbnail after reset', function () {
thumbnailController.reset();
thumbnailController.get(0, thumbnail => {
thumbnailController.provide(0, thumbnail => {
expect(thumbnail).to.be.null; // jshint ignore:line
});
});
Expand Down Expand Up @@ -191,7 +193,7 @@ describe('Thumbnails', function () {
});

it('should return a thumbnail when using multiple rows sprites ', function () {
thumbnailController.get(0, thumbnail => {
thumbnailController.provide(0, thumbnail => {
expect(thumbnail).to.be.not.null; // jshint ignore:line
expect(thumbnail.x).to.equal(0);
expect(thumbnail.y).to.equal(0);
Expand All @@ -201,7 +203,7 @@ describe('Thumbnails', function () {
});


thumbnailController.get(15, thumbnail => {
thumbnailController.provide(15, thumbnail => {
expect(thumbnail).to.be.not.null; // jshint ignore:line
expect(thumbnail.x).to.equal(409.6);
expect(thumbnail.y).to.equal(0);
Expand All @@ -210,7 +212,7 @@ describe('Thumbnails', function () {
expect(thumbnail.url).to.equal('http://media/rep_id/1.jpg');
});

thumbnailController.get(40, thumbnail => {
thumbnailController.provide(40, thumbnail => {
expect(thumbnail).to.be.not.null; // jshint ignore:line
expect(thumbnail.x).to.equal(204.8);
expect(thumbnail.y).to.equal(57.6);
Expand Down