mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
fixes #1003 - [Transcoding] VP8 + OGG to VP8 + OGG
This commit is contained in:
parent
1fc390dc50
commit
640b6df867
2 changed files with 192 additions and 180 deletions
|
@ -933,69 +933,18 @@
|
||||||
|
|
||||||
self.playVideo = function (deviceProfile, playbackInfo, item, mediaSource, startPosition) {
|
self.playVideo = function (deviceProfile, playbackInfo, item, mediaSource, startPosition) {
|
||||||
|
|
||||||
var videoUrl;
|
var streamInfo = self.createStreamInfo('video', item, mediaSource, startPosition);
|
||||||
var contentType;
|
|
||||||
|
var videoUrl = streamInfo.url;
|
||||||
|
var contentType = streamInfo.contentType;
|
||||||
|
var startPositionInSeekParam = streamInfo.startPositionInSeekParam;
|
||||||
|
self.startTimeTicksOffset = streamInfo.startTimeTicksOffset;
|
||||||
|
|
||||||
var mediaStreams = mediaSource.MediaStreams || [];
|
var mediaStreams = mediaSource.MediaStreams || [];
|
||||||
var subtitleStreams = mediaStreams.filter(function (s) {
|
var subtitleStreams = mediaStreams.filter(function (s) {
|
||||||
return s.Type == 'Subtitle';
|
return s.Type == 'Subtitle';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mediaSource.enableDirectPlay) {
|
|
||||||
videoUrl = mediaSource.Path;
|
|
||||||
self.startTimeTicksOffset = 0;
|
|
||||||
contentType = 'video/' + mediaSource.Container;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
var selectedSubtitleStream = subtitleStreams.filter(function (s) {
|
|
||||||
return s.Index == mediaSource.DefaultSubtitleStreamIndex;
|
|
||||||
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
var transcodingParams = {
|
|
||||||
audioChannels: 2,
|
|
||||||
StartTimeTicks: startPosition,
|
|
||||||
AudioStreamIndex: mediaSource.DefaultAudioStreamIndex,
|
|
||||||
deviceId: ApiClient.deviceId(),
|
|
||||||
mediaSourceId: mediaSource.Id,
|
|
||||||
api_key: ApiClient.accessToken(),
|
|
||||||
StreamId: playbackInfo.StreamId,
|
|
||||||
ClientTime: new Date().getTime()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (selectedSubtitleStream && (!self.supportsSubtitleStreamExternally(selectedSubtitleStream) || !self.supportsTextTracks())) {
|
|
||||||
transcodingParams.SubtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.startTimeTicksOffset = mediaSource.SupportsDirectStream ? 0 : startPosition || 0;
|
|
||||||
var startPositionInSeekParam = startPosition ? (startPosition / 10000000) : 0;
|
|
||||||
var seekParam = startPositionInSeekParam ? '#t=' + startPositionInSeekParam : '';
|
|
||||||
|
|
||||||
if (mediaSource.SupportsDirectStream) {
|
|
||||||
|
|
||||||
videoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.' + mediaSource.Container, {
|
|
||||||
Static: true,
|
|
||||||
mediaSourceId: mediaSource.Id,
|
|
||||||
api_key: ApiClient.accessToken()
|
|
||||||
});
|
|
||||||
videoUrl += seekParam;
|
|
||||||
contentType = 'video/' + mediaSource.Container;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
videoUrl = ApiClient.getUrl(mediaSource.TranscodingUrl);
|
|
||||||
|
|
||||||
if (mediaSource.TranscodingSubProtocol == 'hls') {
|
|
||||||
|
|
||||||
videoUrl += seekParam;
|
|
||||||
contentType = 'application/x-mpegURL';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
contentType = 'video/' + mediaSource.TranscodingContainer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//======================================================================================>
|
//======================================================================================>
|
||||||
|
|
||||||
// Create video player
|
// Create video player
|
||||||
|
|
|
@ -378,71 +378,73 @@
|
||||||
if (canClientSeek && params == null) {
|
if (canClientSeek && params == null) {
|
||||||
|
|
||||||
element.currentTime = ticks / (1000 * 10000);
|
element.currentTime = ticks / (1000 * 10000);
|
||||||
|
return;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
params = params || {};
|
params = params || {};
|
||||||
|
|
||||||
var currentSrc = element.currentSrc;
|
var currentSrc = element.currentSrc;
|
||||||
|
|
||||||
var transcodingExtension;
|
|
||||||
var isStatic;
|
|
||||||
var currentStreamId = getParameterByName('StreamId', currentSrc);
|
var currentStreamId = getParameterByName('StreamId', currentSrc);
|
||||||
|
|
||||||
if (self.currentItem.MediaType == "Video") {
|
//if (self.currentItem.MediaType == "Video") {
|
||||||
|
|
||||||
transcodingExtension = self.getVideoTranscodingExtension(currentSrc);
|
// transcodingExtension = self.getVideoTranscodingExtension(currentSrc);
|
||||||
|
|
||||||
if (params.AudioStreamIndex != null) {
|
// if (params.AudioStreamIndex != null) {
|
||||||
currentSrc = replaceQueryString(currentSrc, 'AudioStreamIndex', params.AudioStreamIndex);
|
// currentSrc = replaceQueryString(currentSrc, 'AudioStreamIndex', params.AudioStreamIndex);
|
||||||
}
|
// }
|
||||||
if (params.SubtitleStreamIndex != null) {
|
// if (params.SubtitleStreamIndex != null) {
|
||||||
currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', (params.SubtitleStreamIndex == -1 ? '' : params.SubtitleStreamIndex));
|
// currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', (params.SubtitleStreamIndex == -1 ? '' : params.SubtitleStreamIndex));
|
||||||
}
|
// }
|
||||||
|
|
||||||
var audioStreamIndex = params.AudioStreamIndex == null ? getParameterByName('AudioStreamIndex', currentSrc) : params.AudioStreamIndex;
|
// var audioStreamIndex = params.AudioStreamIndex == null ? getParameterByName('AudioStreamIndex', currentSrc) : params.AudioStreamIndex;
|
||||||
if (typeof (audioStreamIndex) == 'string') {
|
// if (typeof (audioStreamIndex) == 'string') {
|
||||||
audioStreamIndex = parseInt(audioStreamIndex);
|
// audioStreamIndex = parseInt(audioStreamIndex);
|
||||||
}
|
// }
|
||||||
var subtitleStreamIndex = self.currentSubtitleStreamIndex;
|
// var subtitleStreamIndex = self.currentSubtitleStreamIndex;
|
||||||
var videoBitrate = parseInt(getParameterByName('VideoBitrate', currentSrc) || '0');
|
// var videoBitrate = parseInt(getParameterByName('VideoBitrate', currentSrc) || '0');
|
||||||
var audioBitrate = parseInt(getParameterByName('AudioBitrate', currentSrc) || '0');
|
// var audioBitrate = parseInt(getParameterByName('AudioBitrate', currentSrc) || '0');
|
||||||
var bitrate = params.Bitrate || (videoBitrate + audioBitrate);
|
// var bitrate = params.Bitrate || (videoBitrate + audioBitrate);
|
||||||
|
|
||||||
var finalParams = self.getFinalVideoParams(self.currentMediaSource, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
|
// var finalParams = self.getFinalVideoParams(self.currentMediaSource, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
|
||||||
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate);
|
// currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate);
|
||||||
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'VideoCodec', finalParams.videoCodec);
|
// currentSrc = replaceQueryString(currentSrc, 'VideoCodec', finalParams.videoCodec);
|
||||||
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'profile', finalParams.profile || '');
|
// currentSrc = replaceQueryString(currentSrc, 'profile', finalParams.profile || '');
|
||||||
currentSrc = replaceQueryString(currentSrc, 'level', finalParams.level || '');
|
// currentSrc = replaceQueryString(currentSrc, 'level', finalParams.level || '');
|
||||||
|
|
||||||
|
// if (finalParams.isStatic) {
|
||||||
|
// currentSrc = currentSrc.replace('.webm', '.mp4').replace('.m3u8', '.mp4');
|
||||||
|
// currentSrc = replaceQueryString(currentSrc, 'ClientTime', '');
|
||||||
|
// } else {
|
||||||
|
// currentSrc = currentSrc.replace('.mp4', transcodingExtension).replace('.m4v', transcodingExtension).replace('.mkv', transcodingExtension).replace('.webm', transcodingExtension);
|
||||||
|
// currentSrc = replaceQueryString(currentSrc, 'ClientTime', new Date().getTime());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate);
|
||||||
|
// currentSrc = replaceQueryString(currentSrc, 'Static', finalParams.isStatic);
|
||||||
|
// currentSrc = replaceQueryString(currentSrc, 'AudioCodec', finalParams.audioCodec);
|
||||||
|
// isStatic = finalParams.isStatic;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (params.AudioStreamIndex == null && params.SubtitleStreamIndex == null && params.Bitrate == null) {
|
||||||
|
|
||||||
|
var transcodingProfile = self.getDeviceProfile().TranscodingProfiles.filter(function (t) {
|
||||||
|
|
||||||
|
return t.Type == self.currentItem.MediaType;
|
||||||
|
})[0];
|
||||||
|
|
||||||
if (finalParams.isStatic) {
|
|
||||||
currentSrc = currentSrc.replace('.webm', '.mp4').replace('.m3u8', '.mp4');
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'ClientTime', '');
|
|
||||||
} else {
|
} else {
|
||||||
currentSrc = currentSrc.replace('.mp4', transcodingExtension).replace('.m4v', transcodingExtension).replace('.mkv', transcodingExtension).replace('.webm', transcodingExtension);
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'ClientTime', new Date().getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate);
|
currentSrc = replaceQueryString(currentSrc, 'starttimeticks', ticks || 0);
|
||||||
currentSrc = replaceQueryString(currentSrc, 'Static', finalParams.isStatic);
|
changeStreamToUrl(currentStreamId, currentSrc, ticks);
|
||||||
currentSrc = replaceQueryString(currentSrc, 'AudioCodec', finalParams.audioCodec);
|
|
||||||
isStatic = finalParams.isStatic;
|
|
||||||
} else {
|
|
||||||
transcodingExtension = '.mp3';
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var isSeekableMedia = self.currentMediaSource.RunTimeTicks;
|
function changeStreamToUrl(currentStreamId, url, newPositionTicks) {
|
||||||
var isClientSeekable = isStatic || (isSeekableMedia && transcodingExtension == '.m3u8');
|
|
||||||
|
|
||||||
if (isClientSeekable || !ticks || !isSeekableMedia) {
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'starttimeticks', '');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentSrc = replaceQueryString(currentSrc, 'starttimeticks', ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearProgressInterval();
|
clearProgressInterval();
|
||||||
|
|
||||||
|
@ -460,19 +462,18 @@
|
||||||
if (self.currentItem.MediaType == "Video") {
|
if (self.currentItem.MediaType == "Video") {
|
||||||
ApiClient.stopActiveEncodings(currentStreamId).done(function () {
|
ApiClient.stopActiveEncodings(currentStreamId).done(function () {
|
||||||
|
|
||||||
self.startTimeTicksOffset = ticks;
|
self.startTimeTicksOffset = newPositionTicks;
|
||||||
element.src = currentSrc;
|
element.src = url;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.updateTextStreamUrls(ticks || 0);
|
self.updateTextStreamUrls(newPositionTicks || 0);
|
||||||
} else {
|
} else {
|
||||||
self.startTimeTicksOffset = ticks;
|
self.startTimeTicksOffset = newPositionTicks;
|
||||||
element.src = currentSrc;
|
element.src = url;
|
||||||
element.play();
|
element.play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
self.setCurrentTime = function (ticks, positionSlider, currentTimeElement) {
|
self.setCurrentTime = function (ticks, positionSlider, currentTimeElement) {
|
||||||
|
|
||||||
|
@ -791,6 +792,106 @@
|
||||||
})[0];
|
})[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPlaybackInfo(itemId, deviceProfile, startPosition) {
|
||||||
|
|
||||||
|
return ApiClient.ajax({
|
||||||
|
url: ApiClient.getUrl('Items/' + itemId + '/PlaybackInfo', {
|
||||||
|
UserId: Dashboard.getCurrentUserId(),
|
||||||
|
StartPositionTicks: startPosition || 0
|
||||||
|
}),
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify({
|
||||||
|
DeviceProfile: deviceProfile
|
||||||
|
}),
|
||||||
|
contentType: "application/json",
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.createStreamInfo = function (type, item, mediaSource, startPosition) {
|
||||||
|
|
||||||
|
var mediaUrl;
|
||||||
|
var contentType;
|
||||||
|
var startTimeTicksOffset = 0;
|
||||||
|
|
||||||
|
var startPositionInSeekParam = startPosition ? (startPosition / 10000000) : 0;
|
||||||
|
var seekParam = startPositionInSeekParam ? '#t=' + startPositionInSeekParam : '';
|
||||||
|
|
||||||
|
if (type == 'video') {
|
||||||
|
|
||||||
|
contentType = 'video/' + mediaSource.Container;
|
||||||
|
|
||||||
|
if (mediaSource.enableDirectPlay) {
|
||||||
|
mediaUrl = mediaSource.Path;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (mediaSource.SupportsDirectStream) {
|
||||||
|
|
||||||
|
mediaUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.' + mediaSource.Container, {
|
||||||
|
Static: true,
|
||||||
|
mediaSourceId: mediaSource.Id,
|
||||||
|
api_key: ApiClient.accessToken()
|
||||||
|
});
|
||||||
|
mediaUrl += seekParam;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
startTimeTicksOffset = startPosition || 0;
|
||||||
|
mediaUrl = ApiClient.getUrl(mediaSource.TranscodingUrl);
|
||||||
|
|
||||||
|
if (mediaSource.TranscodingSubProtocol == 'hls') {
|
||||||
|
|
||||||
|
mediaUrl += seekParam;
|
||||||
|
contentType = 'application/x-mpegURL';
|
||||||
|
} else {
|
||||||
|
|
||||||
|
contentType = 'video/' + mediaSource.TranscodingContainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
contentType = 'audio/' + mediaSource.Container;
|
||||||
|
|
||||||
|
if (mediaSource.enableDirectPlay) {
|
||||||
|
|
||||||
|
mediaUrl = mediaSource.Path;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var isDirectStream = mediaSource.SupportsDirectStream;
|
||||||
|
|
||||||
|
if (isDirectStream) {
|
||||||
|
|
||||||
|
var outputContainer = (mediaSource.Container || '').toLowerCase();
|
||||||
|
|
||||||
|
mediaUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.' + outputContainer, {
|
||||||
|
mediaSourceId: mediaSource.Id,
|
||||||
|
deviceId: ApiClient.deviceId(),
|
||||||
|
api_key: ApiClient.accessToken()
|
||||||
|
});
|
||||||
|
mediaUrl += "&static=true" + seekParam;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
contentType = 'audio/' + mediaSource.TranscodingContainer;
|
||||||
|
|
||||||
|
mediaUrl = ApiClient.getUrl(mediaSource.TranscodingUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
startTimeTicksOffset = startPosition || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: mediaUrl,
|
||||||
|
contentType: contentType,
|
||||||
|
startTimeTicksOffset: startTimeTicksOffset,
|
||||||
|
startPositionInSeekParam: startPositionInSeekParam
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
self.playInternal = function (item, startPosition, callback) {
|
self.playInternal = function (item, startPosition, callback) {
|
||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
|
@ -813,20 +914,7 @@
|
||||||
var mediaSource;
|
var mediaSource;
|
||||||
var deviceProfile = self.getDeviceProfile();
|
var deviceProfile = self.getDeviceProfile();
|
||||||
|
|
||||||
ApiClient.ajax({
|
getPlaybackInfo(item.Id, deviceProfile, startPosition).done(function (result) {
|
||||||
|
|
||||||
url: ApiClient.getUrl('Items/' + item.Id + '/PlaybackInfo', {
|
|
||||||
userId: Dashboard.getCurrentUserId()
|
|
||||||
|
|
||||||
}),
|
|
||||||
type: 'POST',
|
|
||||||
data: JSON.stringify({
|
|
||||||
DeviceProfile: deviceProfile
|
|
||||||
}),
|
|
||||||
contentType: "application/json",
|
|
||||||
dataType: "json"
|
|
||||||
|
|
||||||
}).done(function (result) {
|
|
||||||
|
|
||||||
if (validatePlaybackInfoResult(result)) {
|
if (validatePlaybackInfoResult(result)) {
|
||||||
|
|
||||||
|
@ -846,7 +934,7 @@
|
||||||
|
|
||||||
} else if (item.MediaType === "Audio") {
|
} else if (item.MediaType === "Audio") {
|
||||||
|
|
||||||
self.currentMediaElement = playAudio(result, item, self.currentMediaSource, startPosition);
|
self.currentMediaElement = playAudio(item, self.currentMediaSource, startPosition);
|
||||||
self.currentDurationTicks = self.currentMediaSource.RunTimeTicks;
|
self.currentDurationTicks = self.currentMediaSource.RunTimeTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1607,36 +1695,11 @@
|
||||||
return $('.mediaPlayerAudio');
|
return $('.mediaPlayerAudio');
|
||||||
}
|
}
|
||||||
|
|
||||||
function playAudio(playbackInfo, item, mediaSource, startPositionTicks) {
|
function playAudio(item, mediaSource, startPositionTicks) {
|
||||||
|
|
||||||
var audioUrl;
|
var streamInfo = self.createStreamInfo('audio', item, mediaSource, startPositionTicks);
|
||||||
if (mediaSource.enableDirectPlay) {
|
var audioUrl = streamInfo.url;
|
||||||
|
self.startTimeTicksOffset = streamInfo.startTimeTicksOffset;
|
||||||
audioUrl = mediaSource.Path;
|
|
||||||
self.startTimeTicksOffset = 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
var isDirectStream = mediaSource.SupportsDirectStream;
|
|
||||||
startPositionTicks = startPositionTicks || 0;
|
|
||||||
|
|
||||||
if (isDirectStream) {
|
|
||||||
|
|
||||||
var outputContainer = (mediaSource.Container || '').toLowerCase();
|
|
||||||
|
|
||||||
var seekParam = startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : '';
|
|
||||||
audioUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.' + outputContainer, {
|
|
||||||
mediaSourceId: mediaSource.Id,
|
|
||||||
deviceId: ApiClient.deviceId(),
|
|
||||||
api_key: ApiClient.accessToken()
|
|
||||||
});
|
|
||||||
audioUrl += "&static=true" + seekParam;
|
|
||||||
} else {
|
|
||||||
audioUrl = ApiClient.getUrl(mediaSource.TranscodingUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.startTimeTicksOffset = isDirectStream ? 0 : startPositionTicks;
|
|
||||||
}
|
|
||||||
|
|
||||||
var initialVolume = self.getSavedVolume();
|
var initialVolume = self.getSavedVolume();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue