< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.VideosController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/VideosController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 91
Coverable lines: 91
Total lines: 658
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/10/2025 - 12:11:16 AM Line coverage: 0% (0/93) Branch coverage: 0% (0/10) Total lines: 66512/1/2025 - 12:11:46 AM Line coverage: 0% (0/92) Branch coverage: 0% (0/10) Total lines: 6641/19/2026 - 12:13:54 AM Line coverage: 0% (0/91) Branch coverage: 0% (0/10) Total lines: 658 10/10/2025 - 12:11:16 AM Line coverage: 0% (0/93) Branch coverage: 0% (0/10) Total lines: 66512/1/2025 - 12:11:46 AM Line coverage: 0% (0/92) Branch coverage: 0% (0/10) Total lines: 6641/19/2026 - 12:13:54 AM Line coverage: 0% (0/91) Branch coverage: 0% (0/10) Total lines: 658

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
GetAdditionalPart(...)0%110100%
GetVideoStreamByContainer(...)100%210%

File(s)

/srv/git/jellyfin/Jellyfin.Api/Controllers/VideosController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel.DataAnnotations;
 4using System.Globalization;
 5using System.Linq;
 6using System.Net.Http;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using Jellyfin.Api.Attributes;
 10using Jellyfin.Api.Extensions;
 11using Jellyfin.Api.Helpers;
 12using Jellyfin.Api.ModelBinders;
 13using Jellyfin.Extensions;
 14using MediaBrowser.Common.Api;
 15using MediaBrowser.Common.Configuration;
 16using MediaBrowser.Common.Net;
 17using MediaBrowser.Controller.Configuration;
 18using MediaBrowser.Controller.Dto;
 19using MediaBrowser.Controller.Entities;
 20using MediaBrowser.Controller.Library;
 21using MediaBrowser.Controller.MediaEncoding;
 22using MediaBrowser.Controller.Streaming;
 23using MediaBrowser.Model.Dlna;
 24using MediaBrowser.Model.Dto;
 25using MediaBrowser.Model.Entities;
 26using MediaBrowser.Model.MediaInfo;
 27using MediaBrowser.Model.Net;
 28using MediaBrowser.Model.Querying;
 29using Microsoft.AspNetCore.Authorization;
 30using Microsoft.AspNetCore.Http;
 31using Microsoft.AspNetCore.Mvc;
 32
 33namespace Jellyfin.Api.Controllers;
 34
 35/// <summary>
 36/// The videos controller.
 37/// </summary>
 38public class VideosController : BaseJellyfinApiController
 39{
 40    private readonly ILibraryManager _libraryManager;
 41    private readonly IUserManager _userManager;
 42    private readonly IDtoService _dtoService;
 43    private readonly IMediaSourceManager _mediaSourceManager;
 44    private readonly IServerConfigurationManager _serverConfigurationManager;
 45    private readonly IMediaEncoder _mediaEncoder;
 46    private readonly ITranscodeManager _transcodeManager;
 47    private readonly IHttpClientFactory _httpClientFactory;
 48    private readonly EncodingHelper _encodingHelper;
 49
 50    private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive;
 51
 52    /// <summary>
 53    /// Initializes a new instance of the <see cref="VideosController"/> class.
 54    /// </summary>
 55    /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
 56    /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
 57    /// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
 58    /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
 59    /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</p
 60    /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
 61    /// <param name="transcodeManager">Instance of the <see cref="ITranscodeManager"/> interface.</param>
 62    /// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param>
 63    /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
 064    public VideosController(
 065        ILibraryManager libraryManager,
 066        IUserManager userManager,
 067        IDtoService dtoService,
 068        IMediaSourceManager mediaSourceManager,
 069        IServerConfigurationManager serverConfigurationManager,
 070        IMediaEncoder mediaEncoder,
 071        ITranscodeManager transcodeManager,
 072        IHttpClientFactory httpClientFactory,
 073        EncodingHelper encodingHelper)
 74    {
 075        _libraryManager = libraryManager;
 076        _userManager = userManager;
 077        _dtoService = dtoService;
 078        _mediaSourceManager = mediaSourceManager;
 079        _serverConfigurationManager = serverConfigurationManager;
 080        _mediaEncoder = mediaEncoder;
 081        _transcodeManager = transcodeManager;
 082        _httpClientFactory = httpClientFactory;
 083        _encodingHelper = encodingHelper;
 084    }
 85
 86    /// <summary>
 87    /// Gets additional parts for a video.
 88    /// </summary>
 89    /// <param name="itemId">The item id.</param>
 90    /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
 91    /// <response code="200">Additional parts returned.</response>
 92    /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the parts.</returns>
 93    [HttpGet("{itemId}/AdditionalParts")]
 94    [Authorize]
 95    [ProducesResponseType(StatusCodes.Status200OK)]
 96    public ActionResult<QueryResult<BaseItemDto>> GetAdditionalPart([FromRoute, Required] Guid itemId, [FromQuery] Guid?
 97    {
 098        userId = RequestHelpers.GetUserId(User, userId);
 099        var user = userId.IsNullOrEmpty()
 0100            ? null
 0101            : _userManager.GetUserById(userId.Value);
 102
 0103        var item = itemId.IsEmpty()
 0104            ? (userId.IsNullOrEmpty()
 0105                ? _libraryManager.RootFolder
 0106                : _libraryManager.GetUserRootFolder())
 0107            : _libraryManager.GetItemById<BaseItem>(itemId, user);
 0108        if (item is null)
 109        {
 0110            return NotFound();
 111        }
 112
 0113        var dtoOptions = new DtoOptions();
 114
 115        BaseItemDto[] items;
 0116        if (item is Video video)
 117        {
 0118            items = video.GetAdditionalParts()
 0119                .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
 0120                .ToArray();
 121        }
 122        else
 123        {
 0124            items = Array.Empty<BaseItemDto>();
 125        }
 126
 0127        var result = new QueryResult<BaseItemDto>(items);
 0128        return result;
 129    }
 130
 131    /// <summary>
 132    /// Removes alternate video sources.
 133    /// </summary>
 134    /// <param name="itemId">The item id.</param>
 135    /// <response code="204">Alternate sources deleted.</response>
 136    /// <response code="404">Video not found.</response>
 137    /// <returns>A <see cref="NoContentResult"/> indicating success, or a <see cref="NotFoundResult"/> if the video does
 138    [HttpDelete("{itemId}/AlternateSources")]
 139    [Authorize(Policy = Policies.RequiresElevation)]
 140    [ProducesResponseType(StatusCodes.Status204NoContent)]
 141    [ProducesResponseType(StatusCodes.Status404NotFound)]
 142    public async Task<ActionResult> DeleteAlternateSources([FromRoute, Required] Guid itemId)
 143    {
 144        var item = _libraryManager.GetItemById<Video>(itemId, User.GetUserId());
 145        if (item is null)
 146        {
 147            return NotFound();
 148        }
 149
 150        if (item.LinkedAlternateVersions.Length == 0)
 151        {
 152            item = _libraryManager.GetItemById<Video>(Guid.Parse(item.PrimaryVersionId));
 153        }
 154
 155        if (item is null)
 156        {
 157            return NotFound();
 158        }
 159
 160        foreach (var link in item.GetLinkedAlternateVersions())
 161        {
 162            link.SetPrimaryVersionId(null);
 163            link.LinkedAlternateVersions = Array.Empty<LinkedChild>();
 164
 165            await link.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false
 166        }
 167
 168        item.LinkedAlternateVersions = Array.Empty<LinkedChild>();
 169        item.SetPrimaryVersionId(null);
 170        await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
 171
 172        return NoContent();
 173    }
 174
 175    /// <summary>
 176    /// Merges videos into a single record.
 177    /// </summary>
 178    /// <param name="ids">Item id list. This allows multiple, comma delimited.</param>
 179    /// <response code="204">Videos merged.</response>
 180    /// <response code="400">Supply at least 2 video ids.</response>
 181    /// <returns>A <see cref="NoContentResult"/> indicating success, or a <see cref="BadRequestResult"/> if less than tw
 182    [HttpPost("MergeVersions")]
 183    [Authorize(Policy = Policies.RequiresElevation)]
 184    [ProducesResponseType(StatusCodes.Status204NoContent)]
 185    [ProducesResponseType(StatusCodes.Status400BadRequest)]
 186    public async Task<ActionResult> MergeVersions([FromQuery, Required, ModelBinder(typeof(CommaDelimitedCollectionModel
 187    {
 188        var userId = User.GetUserId();
 189        var items = ids
 190            .Select(i => _libraryManager.GetItemById<BaseItem>(i, userId))
 191            .OfType<Video>()
 192            .OrderBy(i => i.Id)
 193            .ToList();
 194
 195        if (items.Count < 2)
 196        {
 197            return BadRequest("Please supply at least two videos to merge.");
 198        }
 199
 200        var primaryVersion = items.FirstOrDefault(i => i.MediaSourceCount > 1 && string.IsNullOrEmpty(i.PrimaryVersionId
 201        if (primaryVersion is null)
 202        {
 203            primaryVersion = items
 204                .OrderBy(i =>
 205                {
 206                    if (i.Video3DFormat.HasValue || i.VideoType != VideoType.VideoFile)
 207                    {
 208                        return 1;
 209                    }
 210
 211                    return 0;
 212                })
 213                .ThenByDescending(i => i.GetDefaultVideoStream()?.Width ?? 0)
 214                .First();
 215        }
 216
 217        var alternateVersionsOfPrimary = primaryVersion.LinkedAlternateVersions.ToList();
 218
 219        foreach (var item in items.Where(i => !i.Id.Equals(primaryVersion.Id)))
 220        {
 221            item.SetPrimaryVersionId(primaryVersion.Id.ToString("N", CultureInfo.InvariantCulture));
 222
 223            await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false
 224
 225            if (!alternateVersionsOfPrimary.Any(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase
 226            {
 227                alternateVersionsOfPrimary.Add(new LinkedChild
 228                {
 229                    Path = item.Path,
 230                    ItemId = item.Id
 231                });
 232            }
 233
 234            foreach (var linkedItem in item.LinkedAlternateVersions)
 235            {
 236                if (!alternateVersionsOfPrimary.Any(i => string.Equals(i.Path, linkedItem.Path, StringComparison.Ordinal
 237                {
 238                    alternateVersionsOfPrimary.Add(linkedItem);
 239                }
 240            }
 241
 242            if (item.LinkedAlternateVersions.Length > 0)
 243            {
 244                item.LinkedAlternateVersions = Array.Empty<LinkedChild>();
 245                await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(f
 246            }
 247        }
 248
 249        primaryVersion.LinkedAlternateVersions = alternateVersionsOfPrimary.ToArray();
 250        await primaryVersion.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait
 251        return NoContent();
 252    }
 253
 254    /// <summary>
 255    /// Gets a video stream.
 256    /// </summary>
 257    /// <param name="itemId">The item id.</param>
 258    /// <param name="container">The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, 
 259    /// <param name="static">Optional. If true, the original file will be streamed statically without any encoding. Use 
 260    /// <param name="params">The streaming parameters.</param>
 261    /// <param name="tag">The tag.</param>
 262    /// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param>
 263    /// <param name="playSessionId">The play session id.</param>
 264    /// <param name="segmentContainer">The segment container.</param>
 265    /// <param name="segmentLength">The segment length.</param>
 266    /// <param name="minSegments">The minimum number of segments.</param>
 267    /// <param name="mediaSourceId">The media version id, if playing an alternate version.</param>
 268    /// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</par
 269    /// <param name="audioCodec">Optional. Specify an audio codec to encode to, e.g. mp3. If omitted the server will aut
 270    /// <param name="enableAutoStreamCopy">Whether or not to allow automatic stream copy if requested values match the o
 271    /// <param name="allowVideoStreamCopy">Whether or not to allow copying of the video stream url.</param>
 272    /// <param name="allowAudioStreamCopy">Whether or not to allow copying of the audio stream url.</param>
 273    /// <param name="audioSampleRate">Optional. Specify a specific audio sample rate, e.g. 44100.</param>
 274    /// <param name="maxAudioBitDepth">Optional. The maximum audio bit depth.</param>
 275    /// <param name="audioBitRate">Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be
 276    /// <param name="audioChannels">Optional. Specify a specific number of audio channels to encode to, e.g. 2.</param>
 277    /// <param name="maxAudioChannels">Optional. Specify a maximum number of audio channels to encode to, e.g. 2.</param
 278    /// <param name="profile">Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, 
 279    /// <param name="level">Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.</param>
 280    /// <param name="framerate">Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be
 281    /// <param name="maxFramerate">Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally thi
 282    /// <param name="copyTimestamps">Whether or not to copy timestamps when transcoding with an offset. Defaults to fals
 283    /// <param name="startTimeTicks">Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.</param>
 284    /// <param name="width">Optional. The fixed horizontal resolution of the encoded video.</param>
 285    /// <param name="height">Optional. The fixed vertical resolution of the encoded video.</param>
 286    /// <param name="maxWidth">Optional. The maximum horizontal resolution of the encoded video.</param>
 287    /// <param name="maxHeight">Optional. The maximum vertical resolution of the encoded video.</param>
 288    /// <param name="videoBitRate">Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be 
 289    /// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to use. If omitted no subtitles wil
 290    /// <param name="subtitleMethod">Optional. Specify the subtitle delivery method.</param>
 291    /// <param name="maxRefFrames">Optional.</param>
 292    /// <param name="maxVideoBitDepth">Optional. The maximum video bit depth.</param>
 293    /// <param name="requireAvc">Optional. Whether to require avc.</param>
 294    /// <param name="deInterlace">Optional. Whether to deinterlace the video.</param>
 295    /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamorphic stream.</param>
 296    /// <param name="transcodingMaxAudioChannels">Optional. The maximum number of audio channels to transcode.</param>
 297    /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param>
 298    /// <param name="liveStreamId">The live stream id.</param>
 299    /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param>
 300    /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will aut
 301    /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param>
 302    /// <param name="transcodeReasons">Optional. The transcoding reason.</param>
 303    /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream
 304    /// <param name="videoStreamIndex">Optional. The index of the video stream to use. If omitted the first video stream
 305    /// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
 306    /// <param name="streamOptions">Optional. The streaming options.</param>
 307    /// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
 308    /// <response code="200">Video stream returned.</response>
 309    /// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
 310    [HttpGet("{itemId}/stream")]
 311    [HttpHead("{itemId}/stream", Name = "HeadVideoStream")]
 312    [ProducesResponseType(StatusCodes.Status200OK)]
 313    [ProducesVideoFile]
 314    public async Task<ActionResult> GetVideoStream(
 315        [FromRoute, Required] Guid itemId,
 316        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? container,
 317        [FromQuery] bool? @static,
 318        [FromQuery] string? @params,
 319        [FromQuery] string? tag,
 320        [FromQuery, ParameterObsolete] string? deviceProfileId,
 321        [FromQuery] string? playSessionId,
 322        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
 323        [FromQuery] int? segmentLength,
 324        [FromQuery] int? minSegments,
 325        [FromQuery] string? mediaSourceId,
 326        [FromQuery] string? deviceId,
 327        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
 328        [FromQuery] bool? enableAutoStreamCopy,
 329        [FromQuery] bool? allowVideoStreamCopy,
 330        [FromQuery] bool? allowAudioStreamCopy,
 331        [FromQuery] int? audioSampleRate,
 332        [FromQuery] int? maxAudioBitDepth,
 333        [FromQuery] int? audioBitRate,
 334        [FromQuery] int? audioChannels,
 335        [FromQuery] int? maxAudioChannels,
 336        [FromQuery] string? profile,
 337        [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
 338        [FromQuery] float? framerate,
 339        [FromQuery] float? maxFramerate,
 340        [FromQuery] bool? copyTimestamps,
 341        [FromQuery] long? startTimeTicks,
 342        [FromQuery] int? width,
 343        [FromQuery] int? height,
 344        [FromQuery] int? maxWidth,
 345        [FromQuery] int? maxHeight,
 346        [FromQuery] int? videoBitRate,
 347        [FromQuery] int? subtitleStreamIndex,
 348        [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
 349        [FromQuery] int? maxRefFrames,
 350        [FromQuery] int? maxVideoBitDepth,
 351        [FromQuery] bool? requireAvc,
 352        [FromQuery] bool? deInterlace,
 353        [FromQuery] bool? requireNonAnamorphic,
 354        [FromQuery] int? transcodingMaxAudioChannels,
 355        [FromQuery] int? cpuCoreLimit,
 356        [FromQuery] string? liveStreamId,
 357        [FromQuery] bool? enableMpegtsM2TsMode,
 358        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
 359        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
 360        [FromQuery] string? transcodeReasons,
 361        [FromQuery] int? audioStreamIndex,
 362        [FromQuery] int? videoStreamIndex,
 363        [FromQuery] EncodingContext? context,
 364        [FromQuery] Dictionary<string, string> streamOptions,
 365        [FromQuery] bool enableAudioVbrEncoding = true)
 366    {
 367        var isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head;
 368        // CTS lifecycle is managed internally.
 369        var cancellationTokenSource = new CancellationTokenSource();
 370        var streamingRequest = new VideoRequestDto
 371        {
 372            Id = itemId,
 373            Container = container,
 374            Static = @static ?? false,
 375            Params = @params,
 376            Tag = tag,
 377            PlaySessionId = playSessionId,
 378            SegmentContainer = segmentContainer,
 379            SegmentLength = segmentLength,
 380            MinSegments = minSegments,
 381            MediaSourceId = mediaSourceId,
 382            DeviceId = deviceId,
 383            AudioCodec = audioCodec,
 384            EnableAutoStreamCopy = enableAutoStreamCopy ?? true,
 385            AllowAudioStreamCopy = allowAudioStreamCopy ?? true,
 386            AllowVideoStreamCopy = allowVideoStreamCopy ?? true,
 387            AudioSampleRate = audioSampleRate,
 388            MaxAudioChannels = maxAudioChannels,
 389            AudioBitRate = audioBitRate,
 390            MaxAudioBitDepth = maxAudioBitDepth,
 391            AudioChannels = audioChannels,
 392            Profile = profile,
 393            Level = level,
 394            Framerate = framerate,
 395            MaxFramerate = maxFramerate,
 396            CopyTimestamps = copyTimestamps ?? false,
 397            StartTimeTicks = startTimeTicks,
 398            Width = width,
 399            Height = height,
 400            MaxWidth = maxWidth,
 401            MaxHeight = maxHeight,
 402            VideoBitRate = videoBitRate,
 403            SubtitleStreamIndex = subtitleStreamIndex,
 404            SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
 405            MaxRefFrames = maxRefFrames,
 406            MaxVideoBitDepth = maxVideoBitDepth,
 407            RequireAvc = requireAvc ?? false,
 408            DeInterlace = deInterlace ?? false,
 409            RequireNonAnamorphic = requireNonAnamorphic ?? false,
 410            TranscodingMaxAudioChannels = transcodingMaxAudioChannels,
 411            CpuCoreLimit = cpuCoreLimit,
 412            LiveStreamId = liveStreamId,
 413            EnableMpegtsM2TsMode = enableMpegtsM2TsMode ?? false,
 414            VideoCodec = videoCodec,
 415            SubtitleCodec = subtitleCodec,
 416            TranscodeReasons = transcodeReasons,
 417            AudioStreamIndex = audioStreamIndex,
 418            VideoStreamIndex = videoStreamIndex,
 419            Context = context ?? EncodingContext.Streaming,
 420            StreamOptions = streamOptions,
 421            EnableAudioVbrEncoding = enableAudioVbrEncoding
 422        };
 423
 424        var state = await StreamingHelpers.GetStreamingState(
 425                streamingRequest,
 426                HttpContext,
 427                _mediaSourceManager,
 428                _userManager,
 429                _libraryManager,
 430                _serverConfigurationManager,
 431                _mediaEncoder,
 432                _encodingHelper,
 433                _transcodeManager,
 434                _transcodingJobType,
 435                cancellationTokenSource.Token)
 436            .ConfigureAwait(false);
 437
 438        if (@static.HasValue && @static.Value && state.DirectStreamProvider is not null)
 439        {
 440            var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId);
 441            if (liveStreamInfo is null)
 442            {
 443                return NotFound();
 444            }
 445
 446            var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream());
 447            // TODO (moved from MediaBrowser.Api): Don't hardcode contentType
 448            return File(liveStream, MimeTypes.GetMimeType("file.ts"));
 449        }
 450
 451        // Static remote stream
 452        if (@static.HasValue && @static.Value && state.InputProtocol == MediaProtocol.Http)
 453        {
 454            var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
 455            return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, HttpContext).Configure
 456        }
 457
 458        if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
 459        {
 460            return BadRequest($"Input protocol {state.InputProtocol} cannot be streamed statically");
 461        }
 462
 463        // Static stream
 464        if (@static.HasValue && @static.Value && !(state.MediaSource.VideoType == VideoType.BluRay || state.MediaSource.
 465        {
 466            var contentType = state.GetMimeType("." + state.OutputContainer, false) ?? state.GetMimeType(state.MediaPath
 467
 468            if (state.MediaSource.IsInfiniteStream)
 469            {
 470                var liveStream = new ProgressiveFileStream(state.MediaPath, null, _transcodeManager);
 471                return File(liveStream, contentType);
 472            }
 473
 474            return FileStreamResponseHelpers.GetStaticFileResult(
 475                state.MediaPath,
 476                contentType);
 477        }
 478
 479        // Need to start ffmpeg (because media can't be returned directly)
 480        var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
 481        var ffmpegCommandLineArguments = _encodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, Enco
 482        return await FileStreamResponseHelpers.GetTranscodedFile(
 483            state,
 484            isHeadRequest,
 485            HttpContext,
 486            _transcodeManager,
 487            ffmpegCommandLineArguments,
 488            _transcodingJobType,
 489            cancellationTokenSource).ConfigureAwait(false);
 490    }
 491
 492    /// <summary>
 493    /// Gets a video stream.
 494    /// </summary>
 495    /// <param name="itemId">The item id.</param>
 496    /// <param name="container">The video container. Possible values are: ts, webm, asf, wmv, ogv, mp4, m4v, mkv, mpeg, 
 497    /// <param name="static">Optional. If true, the original file will be streamed statically without any encoding. Use 
 498    /// <param name="params">The streaming parameters.</param>
 499    /// <param name="tag">The tag.</param>
 500    /// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param>
 501    /// <param name="playSessionId">The play session id.</param>
 502    /// <param name="segmentContainer">The segment container.</param>
 503    /// <param name="segmentLength">The segment length.</param>
 504    /// <param name="minSegments">The minimum number of segments.</param>
 505    /// <param name="mediaSourceId">The media version id, if playing an alternate version.</param>
 506    /// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</par
 507    /// <param name="audioCodec">Optional. Specify an audio codec to encode to, e.g. mp3. If omitted the server will aut
 508    /// <param name="enableAutoStreamCopy">Whether or not to allow automatic stream copy if requested values match the o
 509    /// <param name="allowVideoStreamCopy">Whether or not to allow copying of the video stream url.</param>
 510    /// <param name="allowAudioStreamCopy">Whether or not to allow copying of the audio stream url.</param>
 511    /// <param name="audioSampleRate">Optional. Specify a specific audio sample rate, e.g. 44100.</param>
 512    /// <param name="maxAudioBitDepth">Optional. The maximum audio bit depth.</param>
 513    /// <param name="audioBitRate">Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be
 514    /// <param name="audioChannels">Optional. Specify a specific number of audio channels to encode to, e.g. 2.</param>
 515    /// <param name="maxAudioChannels">Optional. Specify a maximum number of audio channels to encode to, e.g. 2.</param
 516    /// <param name="profile">Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, 
 517    /// <param name="level">Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.</param>
 518    /// <param name="framerate">Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be
 519    /// <param name="maxFramerate">Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally thi
 520    /// <param name="copyTimestamps">Whether or not to copy timestamps when transcoding with an offset. Defaults to fals
 521    /// <param name="startTimeTicks">Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.</param>
 522    /// <param name="width">Optional. The fixed horizontal resolution of the encoded video.</param>
 523    /// <param name="height">Optional. The fixed vertical resolution of the encoded video.</param>
 524    /// <param name="maxWidth">Optional. The maximum horizontal resolution of the encoded video.</param>
 525    /// <param name="maxHeight">Optional. The maximum vertical resolution of the encoded video.</param>
 526    /// <param name="videoBitRate">Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be 
 527    /// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to use. If omitted no subtitles wil
 528    /// <param name="subtitleMethod">Optional. Specify the subtitle delivery method.</param>
 529    /// <param name="maxRefFrames">Optional.</param>
 530    /// <param name="maxVideoBitDepth">Optional. The maximum video bit depth.</param>
 531    /// <param name="requireAvc">Optional. Whether to require avc.</param>
 532    /// <param name="deInterlace">Optional. Whether to deinterlace the video.</param>
 533    /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamorphic stream.</param>
 534    /// <param name="transcodingMaxAudioChannels">Optional. The maximum number of audio channels to transcode.</param>
 535    /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param>
 536    /// <param name="liveStreamId">The live stream id.</param>
 537    /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param>
 538    /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will aut
 539    /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param>
 540    /// <param name="transcodeReasons">Optional. The transcoding reason.</param>
 541    /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream
 542    /// <param name="videoStreamIndex">Optional. The index of the video stream to use. If omitted the first video stream
 543    /// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
 544    /// <param name="streamOptions">Optional. The streaming options.</param>
 545    /// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
 546    /// <response code="200">Video stream returned.</response>
 547    /// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
 548    [HttpGet("{itemId}/stream.{container}")]
 549    [HttpHead("{itemId}/stream.{container}", Name = "HeadVideoStreamByContainer")]
 550    [ProducesResponseType(StatusCodes.Status200OK)]
 551    [ProducesVideoFile]
 552    public Task<ActionResult> GetVideoStreamByContainer(
 553        [FromRoute, Required] Guid itemId,
 554        [FromRoute, Required] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string container,
 555        [FromQuery] bool? @static,
 556        [FromQuery] string? @params,
 557        [FromQuery] string? tag,
 558        [FromQuery] string? deviceProfileId,
 559        [FromQuery] string? playSessionId,
 560        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? segmentContainer,
 561        [FromQuery] int? segmentLength,
 562        [FromQuery] int? minSegments,
 563        [FromQuery] string? mediaSourceId,
 564        [FromQuery] string? deviceId,
 565        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? audioCodec,
 566        [FromQuery] bool? enableAutoStreamCopy,
 567        [FromQuery] bool? allowVideoStreamCopy,
 568        [FromQuery] bool? allowAudioStreamCopy,
 569        [FromQuery] int? audioSampleRate,
 570        [FromQuery] int? maxAudioBitDepth,
 571        [FromQuery] int? audioBitRate,
 572        [FromQuery] int? audioChannels,
 573        [FromQuery] int? maxAudioChannels,
 574        [FromQuery] string? profile,
 575        [FromQuery] [RegularExpression(EncodingHelper.LevelValidationRegex)] string? level,
 576        [FromQuery] float? framerate,
 577        [FromQuery] float? maxFramerate,
 578        [FromQuery] bool? copyTimestamps,
 579        [FromQuery] long? startTimeTicks,
 580        [FromQuery] int? width,
 581        [FromQuery] int? height,
 582        [FromQuery] int? maxWidth,
 583        [FromQuery] int? maxHeight,
 584        [FromQuery] int? videoBitRate,
 585        [FromQuery] int? subtitleStreamIndex,
 586        [FromQuery] SubtitleDeliveryMethod? subtitleMethod,
 587        [FromQuery] int? maxRefFrames,
 588        [FromQuery] int? maxVideoBitDepth,
 589        [FromQuery] bool? requireAvc,
 590        [FromQuery] bool? deInterlace,
 591        [FromQuery] bool? requireNonAnamorphic,
 592        [FromQuery] int? transcodingMaxAudioChannels,
 593        [FromQuery] int? cpuCoreLimit,
 594        [FromQuery] string? liveStreamId,
 595        [FromQuery] bool? enableMpegtsM2TsMode,
 596        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? videoCodec,
 597        [FromQuery] [RegularExpression(EncodingHelper.ContainerValidationRegex)] string? subtitleCodec,
 598        [FromQuery] string? transcodeReasons,
 599        [FromQuery] int? audioStreamIndex,
 600        [FromQuery] int? videoStreamIndex,
 601        [FromQuery] EncodingContext? context,
 602        [FromQuery] Dictionary<string, string> streamOptions,
 603        [FromQuery] bool enableAudioVbrEncoding = true)
 604    {
 0605        return GetVideoStream(
 0606            itemId,
 0607            container,
 0608            @static,
 0609            @params,
 0610            tag,
 0611            deviceProfileId,
 0612            playSessionId,
 0613            segmentContainer,
 0614            segmentLength,
 0615            minSegments,
 0616            mediaSourceId,
 0617            deviceId,
 0618            audioCodec,
 0619            enableAutoStreamCopy,
 0620            allowVideoStreamCopy,
 0621            allowAudioStreamCopy,
 0622            audioSampleRate,
 0623            maxAudioBitDepth,
 0624            audioBitRate,
 0625            audioChannels,
 0626            maxAudioChannels,
 0627            profile,
 0628            level,
 0629            framerate,
 0630            maxFramerate,
 0631            copyTimestamps,
 0632            startTimeTicks,
 0633            width,
 0634            height,
 0635            maxWidth,
 0636            maxHeight,
 0637            videoBitRate,
 0638            subtitleStreamIndex,
 0639            subtitleMethod,
 0640            maxRefFrames,
 0641            maxVideoBitDepth,
 0642            requireAvc,
 0643            deInterlace,
 0644            requireNonAnamorphic,
 0645            transcodingMaxAudioChannels,
 0646            cpuCoreLimit,
 0647            liveStreamId,
 0648            enableMpegtsM2TsMode,
 0649            videoCodec,
 0650            subtitleCodec,
 0651            transcodeReasons,
 0652            audioStreamIndex,
 0653            videoStreamIndex,
 0654            context,
 0655            streamOptions,
 0656            enableAudioVbrEncoding);
 657    }
 658}

Methods/Properties

.ctor(MediaBrowser.Controller.Library.ILibraryManager,MediaBrowser.Controller.Library.IUserManager,MediaBrowser.Controller.Dto.IDtoService,MediaBrowser.Controller.Library.IMediaSourceManager,MediaBrowser.Controller.Configuration.IServerConfigurationManager,MediaBrowser.Controller.MediaEncoding.IMediaEncoder,MediaBrowser.Controller.MediaEncoding.ITranscodeManager,System.Net.Http.IHttpClientFactory,MediaBrowser.Controller.MediaEncoding.EncodingHelper)
GetAdditionalPart(System.Guid,System.Nullable`1<System.Guid>)
GetVideoStreamByContainer(System.Guid,System.String,System.Nullable`1<System.Boolean>,System.String,System.String,System.String,System.String,System.String,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.String,System.String,System.String,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.String,System.String,System.Nullable`1<System.Single>,System.Nullable`1<System.Single>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Int64>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<MediaBrowser.Model.Dlna.SubtitleDeliveryMethod>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.String,System.Nullable`1<System.Boolean>,System.String,System.String,System.String,System.Nullable`1<System.Int32>,System.Nullable`1<System.Int32>,System.Nullable`1<MediaBrowser.Model.Dlna.EncodingContext>,System.Collections.Generic.Dictionary`2<System.String,System.String>,System.Boolean)