diff options
| author | Joshua M. Boniface <joshua@boniface.me> | 2023-10-19 01:45:42 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-19 01:45:42 -0400 |
| commit | 8859a3ac8ea44f1a53668e0a7522cf4c875c4be8 (patch) | |
| tree | edc6ad0f1f241c2c3c2cdba5359d4d3006636d33 /MediaBrowser.Controller | |
| parent | de08d38a6f2a6e773fa1000574e08322605b56d3 (diff) | |
| parent | 6b94d55e1ef7ca95e0ddc2a88b0ff0fd63d630a9 (diff) | |
Merge pull request #9554 from nicknsy/trickplay
Diffstat (limited to 'MediaBrowser.Controller')
4 files changed, 157 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index e5c8ebfaf..c7bfbdb53 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -81,5 +81,15 @@ namespace MediaBrowser.Controller.Drawing /// <param name="posters">The list of poster paths.</param> /// <param name="backdrops">The list of backdrop paths.</param> void CreateSplashscreen(IReadOnlyList<string> posters, IReadOnlyList<string> backdrops); + + /// <summary> + /// Creates a new trickplay tile image. + /// </summary> + /// <param name="options">The options to use when creating the image. Width and Height are a quantity of thumbnails in this case, not pixels.</param> + /// <param name="quality">The image encode quality.</param> + /// <param name="imgWidth">The width of a single trickplay thumbnail.</param> + /// <param name="imgHeight">Optional height of a single trickplay thumbnail, if it is known.</param> + /// <returns>Height of single decoded trickplay thumbnail.</returns> + int CreateTrickplayTile(ImageCollageOptions options, int quality, int imgWidth, int? imgHeight); } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 08ce19f69..c3a20cdb4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -100,6 +100,13 @@ namespace MediaBrowser.Controller.MediaEncoding { "truehd", 6 }, }; + private static readonly string _defaultMjpegEncoder = "mjpeg"; + private static readonly Dictionary<string, string> _mjpegCodecMap = new(StringComparer.OrdinalIgnoreCase) + { + { "vaapi", _defaultMjpegEncoder + "_vaapi" }, + { "qsv", _defaultMjpegEncoder + "_qsv" } + }; + public static readonly string[] LosslessAudioCodecs = new string[] { "alac", @@ -167,6 +174,24 @@ namespace MediaBrowser.Controller.MediaEncoding return defaultEncoder; } + private string GetMjpegEncoder(EncodingJobInfo state, EncodingOptions encodingOptions) + { + if (state.VideoType == VideoType.VideoFile) + { + var hwType = encodingOptions.HardwareAccelerationType; + + if (!string.IsNullOrEmpty(hwType) + && encodingOptions.EnableHardwareEncoding + && _mjpegCodecMap.TryGetValue(hwType, out var preferredEncoder) + && _mediaEncoder.SupportsEncoder(preferredEncoder)) + { + return preferredEncoder; + } + } + + return _defaultMjpegEncoder; + } + private bool IsVaapiSupported(EncodingJobInfo state) { // vaapi will throw an error with this input @@ -300,6 +325,11 @@ namespace MediaBrowser.Controller.MediaEncoding return GetH264Encoder(state, encodingOptions); } + if (string.Equals(codec, "mjpeg", StringComparison.OrdinalIgnoreCase)) + { + return GetMjpegEncoder(state, encodingOptions); + } + if (string.Equals(codec, "vp8", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) { @@ -4917,6 +4947,15 @@ namespace MediaBrowser.Controller.MediaEncoding subFilters?.RemoveAll(filter => string.IsNullOrEmpty(filter)); overlayFilters?.RemoveAll(filter => string.IsNullOrEmpty(filter)); + var framerate = GetFramerateParam(state); + if (framerate.HasValue) + { + mainFilters.Insert(0, string.Format( + CultureInfo.InvariantCulture, + "fps={0}", + framerate.Value)); + } + var mainStr = string.Empty; if (mainFilters?.Count > 0) { diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 4114dea4f..c2cef4978 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; @@ -138,6 +140,36 @@ namespace MediaBrowser.Controller.MediaEncoding Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, ImageFormat? targetFormat, CancellationToken cancellationToken); /// <summary> + /// Extracts the video images on interval. + /// </summary> + /// <param name="inputFile">Input file.</param> + /// <param name="container">Video container type.</param> + /// <param name="mediaSource">Media source information.</param> + /// <param name="imageStream">Media stream information.</param> + /// <param name="maxWidth">The maximum width.</param> + /// <param name="interval">The interval.</param> + /// <param name="allowHwAccel">Allow for hardware acceleration.</param> + /// <param name="threads">The input/output thread count for ffmpeg.</param> + /// <param name="qualityScale">The qscale value for ffmpeg.</param> + /// <param name="priority">The process priority for the ffmpeg process.</param> + /// <param name="encodingHelper">EncodingHelper instance.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Directory where images where extracted. A given image made before another will always be named with a lower number.</returns> + Task<string> ExtractVideoImagesOnIntervalAccelerated( + string inputFile, + string container, + MediaSourceInfo mediaSource, + MediaStream imageStream, + int maxWidth, + TimeSpan interval, + bool allowHwAccel, + int? threads, + int? qualityScale, + ProcessPriorityClass? priority, + EncodingHelper encodingHelper, + CancellationToken cancellationToken); + + /// <summary> /// Gets the media info. /// </summary> /// <param name="request">The request.</param> diff --git a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs new file mode 100644 index 000000000..0c41f3023 --- /dev/null +++ b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Configuration; + +namespace MediaBrowser.Controller.Trickplay; + +/// <summary> +/// Interface ITrickplayManager. +/// </summary> +public interface ITrickplayManager +{ + /// <summary> + /// Generates new trickplay images and metadata. + /// </summary> + /// <param name="video">The video.</param> + /// <param name="replace">Whether or not existing data should be replaced.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>Task.</returns> + Task RefreshTrickplayDataAsync(Video video, bool replace, CancellationToken cancellationToken); + + /// <summary> + /// Creates trickplay tiles out of individual thumbnails. + /// </summary> + /// <param name="images">Ordered file paths of the thumbnails to be used.</param> + /// <param name="width">The width of a single thumbnail.</param> + /// <param name="options">The trickplay options.</param> + /// <param name="outputDir">The output directory.</param> + /// <returns>The associated trickplay information.</returns> + /// <remarks> + /// The output directory will be DELETED and replaced if it already exists. + /// </remarks> + TrickplayInfo CreateTiles(List<string> images, int width, TrickplayOptions options, string outputDir); + + /// <summary> + /// Get available trickplay resolutions and corresponding info. + /// </summary> + /// <param name="itemId">The item.</param> + /// <returns>Map of width resolutions to trickplay tiles info.</returns> + Task<Dictionary<int, TrickplayInfo>> GetTrickplayResolutions(Guid itemId); + + /// <summary> + /// Saves trickplay info. + /// </summary> + /// <param name="info">The trickplay info.</param> + /// <returns>Task.</returns> + Task SaveTrickplayInfo(TrickplayInfo info); + + /// <summary> + /// Gets all trickplay infos for all media streams of an item. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>A map of media source id to a map of tile width to trickplay info.</returns> + Task<Dictionary<string, Dictionary<int, TrickplayInfo>>> GetTrickplayManifest(BaseItem item); + + /// <summary> + /// Gets the path to a trickplay tile image. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="width">The width of a single thumbnail.</param> + /// <param name="index">The tile's index.</param> + /// <returns>The absolute path.</returns> + string GetTrickplayTilePath(BaseItem item, int width, int index); + + /// <summary> + /// Gets the trickplay HLS playlist. + /// </summary> + /// <param name="itemId">The item.</param> + /// <param name="width">The width of a single thumbnail.</param> + /// <param name="apiKey">Optional api key of the requesting user.</param> + /// <returns>The text content of the .m3u8 playlist.</returns> + Task<string?> GetHlsPlaylist(Guid itemId, int width, string? apiKey); +} |
