Skip to content

Commit

Permalink
fix(Offline): Fix download of some HLS manifests (#5861)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad authored Nov 6, 2023
1 parent 51edeae commit c2c8320
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 95 deletions.
62 changes: 61 additions & 1 deletion lib/net/networking_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

goog.provide('shaka.net.NetworkingUtils');

goog.require('goog.Uri');
goog.require('shaka.net.NetworkingEngine');


Expand All @@ -20,6 +21,12 @@ shaka.net.NetworkingUtils = class {
* @return {!Promise.<string>}
*/
static async getMimeType(uri, netEngine, retryParams) {
const extension = shaka.net.NetworkingUtils.getExtension_(uri);
let mimeType =
shaka.net.NetworkingUtils.EXTENSIONS_TO_MIME_TYPES_[extension];
if (mimeType) {
return mimeType;
}
const type = shaka.net.NetworkingEngine.RequestType.MANIFEST;

const request = shaka.net.NetworkingEngine.makeRequest([uri], retryParams);
Expand All @@ -29,7 +36,60 @@ shaka.net.NetworkingUtils = class {

// https://bit.ly/2K9s9kf says this header should always be available,
// but just to be safe:
const mimeType = response.headers['content-type'];
mimeType = response.headers['content-type'];
return mimeType ? mimeType.toLowerCase().split(';').shift() : '';
}


/**
* @param {string} uri
* @return {string}
* @private
*/
static getExtension_(uri) {
const uriObj = new goog.Uri(uri);
const uriPieces = uriObj.getPath().split('/');
const uriFilename = uriPieces.pop();
const filenamePieces = uriFilename.split('.');

// Only one piece means there is no extension.
if (filenamePieces.length == 1) {
return '';
}

return filenamePieces.pop().toLowerCase();
}
};

/**
* @const {!Object.<string, string>}
* @private
*/
shaka.net.NetworkingUtils.EXTENSIONS_TO_MIME_TYPES_ = {
'mp4': 'video/mp4',
'm4v': 'video/mp4',
'm4a': 'audio/mp4',
'webm': 'video/webm',
'weba': 'audio/webm',
'mkv': 'video/webm', // Chromium browsers supports it.
'ts': 'video/mp2t',
'ogv': 'video/ogg',
'ogg': 'audio/ogg',
'mpg': 'video/mpeg',
'mpeg': 'video/mpeg',
'm3u8': 'application/x-mpegurl',
'mpd': 'application/dash+xml',
'ism': 'application/vnd.ms-sstr+xml',
'mp3': 'audio/mpeg',
'aac': 'audio/aac',
'flac': 'audio/flac',
'wav': 'audio/wav',
'sbv': 'text/x-subviewer',
'srt': 'text/srt',
'vtt': 'text/vtt',
'webvtt': 'text/vtt',
'ttml': 'application/ttml+xml',
'lrc': 'application/x-subtitle-lrc',
'ssa': 'text/x-ssa',
'ass': 'text/x-ssa',
};
87 changes: 4 additions & 83 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
goog.provide('shaka.Player');

goog.require('goog.asserts');
goog.require('goog.Uri');
goog.require('shaka.config.AutoShowText');
goog.require('shaka.Deprecate');
goog.require('shaka.log');
Expand Down Expand Up @@ -719,9 +718,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
setupLcevc_(config) {
if (config.lcevc.enabled) {
const tracks = this.getVariantTracks();
if (tracks && tracks[0] &&
tracks[0].videoMimeType ==
shaka.Player.EXTENSIONS_TO_MIME_TYPES_['ts']) {
if (tracks && tracks[0] && tracks[0].videoMimeType == 'video/mp2t') {
const edge = shaka.util.Platform.isEdge() ||
shaka.util.Platform.isLegacyEdge();
if (edge) {
Expand Down Expand Up @@ -1372,13 +1369,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
async guessMimeType_() {
goog.asserts.assert(this.assetUri_, 'should have a uri by now.');

// If we don't have a MIME type, try to guess based on the file extension.
// Try using the uri extension.
const extension = this.getExtension_(this.assetUri_);
if (shaka.Player.EXTENSIONS_TO_MIME_TYPES_[extension]) {
return shaka.Player.EXTENSIONS_TO_MIME_TYPES_[extension];
}

// If no MIME type is provided, and we can't base it on extension, make a
// HEAD request to determine it.
goog.asserts.assert(this.networkingEngine_, 'Should have a net engine!');
Expand All @@ -1391,26 +1381,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
return mimeType;
}


/**
* @param {string} uri
* @return {string}
* @private
*/
getExtension_(uri) {
const uriObj = new goog.Uri(uri);
const uriPieces = uriObj.getPath().split('/');
const uriFilename = uriPieces.pop();
const filenamePieces = uriFilename.split('.');

// Only one piece means there is no extension.
if (filenamePieces.length == 1) {
return '';
}

return filenamePieces.pop().toLowerCase();
}

/**
* Determines if we should use src equals, based on the the mimeType (if
* known), the URI, and platform information.
Expand Down Expand Up @@ -4852,14 +4822,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
* @private
*/
async getTextMimetype_(uri) {
// Try using the uri extension.
const extension = this.getExtension_(uri);
let mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];

if (mimeType) {
return mimeType;
}

let mimeType;
try {
goog.asserts.assert(
this.networkingEngine_, 'Need networking engine.');
Expand All @@ -4875,12 +4838,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {

shaka.log.error(
'The mimeType has not been provided and it could not be deduced ' +
'from its extension.');
'from its uri.');
throw new shaka.util.Error(
shaka.util.Error.Severity.RECOVERABLE,
shaka.util.Error.Category.TEXT,
shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
extension);
uri);
}

/**
Expand Down Expand Up @@ -6711,48 +6674,6 @@ shaka.Player.supportPlugins_ = {};
shaka.Player.adManagerFactory_ = null;


/**
* @const {!Object.<string, string>}
* @private
*/
shaka.Player.EXTENSIONS_TO_MIME_TYPES_ = {
'mp4': 'video/mp4',
'm4v': 'video/mp4',
'm4a': 'audio/mp4',
'webm': 'video/webm',
'weba': 'audio/webm',
'mkv': 'video/webm', // Chromium browsers supports it.
'ts': 'video/mp2t',
'ogv': 'video/ogg',
'ogg': 'audio/ogg',
'mpg': 'video/mpeg',
'mpeg': 'video/mpeg',
'm3u8': 'application/x-mpegurl',
'mpd': 'application/dash+xml',
'ism': 'application/vnd.ms-sstr+xml',
'mp3': 'audio/mpeg',
'aac': 'audio/aac',
'flac': 'audio/flac',
'wav': 'audio/wav',
};


/**
* @const {!Object.<string, string>}
* @private
*/
shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_ = {
'sbv': 'text/x-subviewer',
'srt': 'text/srt',
'vtt': 'text/vtt',
'webvtt': 'text/vtt',
'ttml': 'application/ttml+xml',
'lrc': 'application/x-subtitle-lrc',
'ssa': 'text/x-ssa',
'ass': 'text/x-ssa',
};


/**
* @const {string}
*/
Expand Down
2 changes: 1 addition & 1 deletion lib/util/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ shaka.util.Error.Code = {

/**
* Unable to guess mime type of the text.
* <br> error.data[0] is the text file's extension.
* <br> error.data[0] is the text file's uri.
*/
'TEXT_COULD_NOT_GUESS_MIME_TYPE': 2011,

Expand Down
27 changes: 24 additions & 3 deletions lib/util/player_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,8 @@ shaka.util.PlayerConfiguration = class {
// eslint-disable-next-line require-await
offline.trackSelectionCallback = async (tracks) => {
return shaka.util.PlayerConfiguration.defaultTrackSelect(
tracks, config.preferredAudioLanguage);
tracks, config.preferredAudioLanguage,
config.preferredVideoHdrLevel);
};

return config;
Expand Down Expand Up @@ -422,14 +423,34 @@ shaka.util.PlayerConfiguration = class {
/**
* @param {!Array.<shaka.extern.Track>} tracks
* @param {string} preferredAudioLanguage
* @param {string} preferredVideoHdrLevel
* @return {!Array.<shaka.extern.Track>}
*/
static defaultTrackSelect(tracks, preferredAudioLanguage) {
static defaultTrackSelect(
tracks, preferredAudioLanguage, preferredVideoHdrLevel) {
const ContentType = shaka.util.ManifestParserUtils.ContentType;
const LanguageUtils = shaka.util.LanguageUtils;

let hdrLevel = preferredVideoHdrLevel;
if (hdrLevel == 'AUTO') {
// Auto detect the ideal HDR level.
if (window.matchMedia('(color-gamut: p3)').matches) {
hdrLevel = 'PQ';
} else {
hdrLevel = 'SDR';
}
}

/** @type {!Array.<shaka.extern.Track>} */
const allVariants = tracks.filter((track) => track.type == 'variant');
const allVariants = tracks.filter((track) => {
if (track.type != 'variant') {
return false;
}
if (track.hdr && track.hdr != hdrLevel) {
return false;
}
return true;
});

/** @type {!Array.<shaka.extern.Track>} */
let selectedVariants = [];
Expand Down
17 changes: 10 additions & 7 deletions test/offline/storage_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ filterDescribe('Storage', storageSupport, () => {
];

const selected =
PlayerConfiguration.defaultTrackSelect(tracks, englishUS);
PlayerConfiguration.defaultTrackSelect(tracks, englishUS, 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(1);
expect(selected[0]).toBeTruthy();
Expand All @@ -285,7 +285,7 @@ filterDescribe('Storage', storageSupport, () => {
];

const selected =
PlayerConfiguration.defaultTrackSelect(tracks, englishUS);
PlayerConfiguration.defaultTrackSelect(tracks, englishUS, 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(2);
for (const track of tracks) {
Expand All @@ -302,7 +302,7 @@ filterDescribe('Storage', storageSupport, () => {
];

const selected =
PlayerConfiguration.defaultTrackSelect(tracks, 'eng-us');
PlayerConfiguration.defaultTrackSelect(tracks, 'eng-us', 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(1);
expect(selected[0]).toBeTruthy();
Expand All @@ -317,7 +317,8 @@ filterDescribe('Storage', storageSupport, () => {
variantTrack(3, 480, 'eng', kbps(1)),
];

const selected = PlayerConfiguration.defaultTrackSelect(tracks, 'eng');
const selected =
PlayerConfiguration.defaultTrackSelect(tracks, 'eng', 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(1);
expect(selected[0]).toBeTruthy();
Expand All @@ -331,7 +332,8 @@ filterDescribe('Storage', storageSupport, () => {
variantTrack(2, 480, 'eng-ca', kbps(1)),
];

const selected = PlayerConfiguration.defaultTrackSelect(tracks, 'fr');
const selected =
PlayerConfiguration.defaultTrackSelect(tracks, 'fr', 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(1);
expect(selected[0]).toBeTruthy();
Expand All @@ -346,7 +348,7 @@ filterDescribe('Storage', storageSupport, () => {
];

const selected =
PlayerConfiguration.defaultTrackSelect(tracks, 'fr-uk');
PlayerConfiguration.defaultTrackSelect(tracks, 'fr-uk', 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(1);
expect(selected[0]).toBeTruthy();
Expand All @@ -362,7 +364,8 @@ filterDescribe('Storage', storageSupport, () => {

tracks[0].primary = true;

const selected = PlayerConfiguration.defaultTrackSelect(tracks, 'de');
const selected =
PlayerConfiguration.defaultTrackSelect(tracks, 'de', 'SDR');
expect(selected).toBeTruthy();
expect(selected.length).toBe(1);
expect(selected[0]).toBeTruthy();
Expand Down

0 comments on commit c2c8320

Please sign in to comment.