|
|
@ -375,6 +375,78 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService |
|
|
|
graphicsElementContexts.AddRange(watermarks.Values); |
|
|
|
graphicsElementContexts.AddRange(watermarks.Values); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings, fillerKind); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string videoFormat = GetVideoFormat(playbackSettings); |
|
|
|
|
|
|
|
Option<string> maybeVideoProfile = GetVideoProfile(videoFormat, channel.FFmpegProfile.VideoProfile); |
|
|
|
|
|
|
|
Option<string> maybeVideoPreset = GetVideoPreset(hwAccel, videoFormat, channel.FFmpegProfile.VideoPreset); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<string> hlsPlaylistPath = outputFormat == OutputFormatKind.Hls |
|
|
|
|
|
|
|
? Path.Combine(FileSystemLayout.TranscodeFolder, channel.Number, "live.m3u8") |
|
|
|
|
|
|
|
: Option<string>.None; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<string> hlsSegmentTemplate = outputFormat == OutputFormatKind.Hls |
|
|
|
|
|
|
|
? Path.Combine(FileSystemLayout.TranscodeFolder, channel.Number, "live%06d.ts") |
|
|
|
|
|
|
|
: Option<string>.None; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FrameSize scaledSize = ffmpegVideoStream.SquarePixelFrameSize( |
|
|
|
|
|
|
|
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var paddedSize = new FrameSize( |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Width, |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Height); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<FrameSize> cropSize = Option<FrameSize>.None; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (channel.FFmpegProfile.ScalingBehavior is ScalingBehavior.Stretch) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
scaledSize = paddedSize; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (channel.FFmpegProfile.ScalingBehavior is ScalingBehavior.Crop) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bool isTooSmallToCrop = videoVersion.Height < channel.FFmpegProfile.Resolution.Height || |
|
|
|
|
|
|
|
videoVersion.Width < channel.FFmpegProfile.Resolution.Width; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if any dimension is smaller than the crop, scale beyond the crop (beyond the target resolution)
|
|
|
|
|
|
|
|
if (isTooSmallToCrop) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foreach (IDisplaySize size in playbackSettings.ScaledSize) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
scaledSize = new FrameSize(size.Width, size.Height); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paddedSize = scaledSize; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
paddedSize = ffmpegVideoStream.SquarePixelFrameSizeForCrop( |
|
|
|
|
|
|
|
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cropSize = new FrameSize( |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Width, |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Height); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var desiredState = new FrameState( |
|
|
|
|
|
|
|
playbackSettings.RealtimeOutput, |
|
|
|
|
|
|
|
fillerKind == FillerKind.Fallback, |
|
|
|
|
|
|
|
videoFormat, |
|
|
|
|
|
|
|
maybeVideoProfile, |
|
|
|
|
|
|
|
maybeVideoPreset, |
|
|
|
|
|
|
|
channel.FFmpegProfile.AllowBFrames, |
|
|
|
|
|
|
|
Optional(playbackSettings.PixelFormat), |
|
|
|
|
|
|
|
scaledSize, |
|
|
|
|
|
|
|
paddedSize, |
|
|
|
|
|
|
|
cropSize, |
|
|
|
|
|
|
|
false, |
|
|
|
|
|
|
|
playbackSettings.FrameRate, |
|
|
|
|
|
|
|
playbackSettings.VideoBitrate, |
|
|
|
|
|
|
|
playbackSettings.VideoBufferSize, |
|
|
|
|
|
|
|
playbackSettings.VideoTrackTimeScale, |
|
|
|
|
|
|
|
playbackSettings.Deinterlace); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var playoutItemGraphicsElement in graphicsElements) |
|
|
|
foreach (var playoutItemGraphicsElement in graphicsElements) |
|
|
|
{ |
|
|
|
{ |
|
|
|
switch (playoutItemGraphicsElement.GraphicsElement.Kind) |
|
|
|
switch (playoutItemGraphicsElement.GraphicsElement.Kind) |
|
|
@ -445,6 +517,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService |
|
|
|
graphicsEngineContext = new GraphicsEngineContext( |
|
|
|
graphicsEngineContext = new GraphicsEngineContext( |
|
|
|
audioVersion.MediaItem, |
|
|
|
audioVersion.MediaItem, |
|
|
|
graphicsElementContexts, |
|
|
|
graphicsElementContexts, |
|
|
|
|
|
|
|
new Resolution { Width = desiredState.ScaledSize.Width, Height = desiredState.ScaledSize.Height }, |
|
|
|
channel.FFmpegProfile.Resolution, |
|
|
|
channel.FFmpegProfile.Resolution, |
|
|
|
await playbackSettings.FrameRate.IfNoneAsync(24), |
|
|
|
await playbackSettings.FrameRate.IfNoneAsync(24), |
|
|
|
ChannelStartTime: channelStartTime, |
|
|
|
ChannelStartTime: channelStartTime, |
|
|
@ -453,78 +526,6 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService |
|
|
|
finish - now); |
|
|
|
finish - now); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings, fillerKind); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string videoFormat = GetVideoFormat(playbackSettings); |
|
|
|
|
|
|
|
Option<string> maybeVideoProfile = GetVideoProfile(videoFormat, channel.FFmpegProfile.VideoProfile); |
|
|
|
|
|
|
|
Option<string> maybeVideoPreset = GetVideoPreset(hwAccel, videoFormat, channel.FFmpegProfile.VideoPreset); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<string> hlsPlaylistPath = outputFormat == OutputFormatKind.Hls |
|
|
|
|
|
|
|
? Path.Combine(FileSystemLayout.TranscodeFolder, channel.Number, "live.m3u8") |
|
|
|
|
|
|
|
: Option<string>.None; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<string> hlsSegmentTemplate = outputFormat == OutputFormatKind.Hls |
|
|
|
|
|
|
|
? Path.Combine(FileSystemLayout.TranscodeFolder, channel.Number, "live%06d.ts") |
|
|
|
|
|
|
|
: Option<string>.None; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FrameSize scaledSize = ffmpegVideoStream.SquarePixelFrameSize( |
|
|
|
|
|
|
|
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var paddedSize = new FrameSize( |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Width, |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Height); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Option<FrameSize> cropSize = Option<FrameSize>.None; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (channel.FFmpegProfile.ScalingBehavior is ScalingBehavior.Stretch) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
scaledSize = paddedSize; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (channel.FFmpegProfile.ScalingBehavior is ScalingBehavior.Crop) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bool isTooSmallToCrop = videoVersion.Height < channel.FFmpegProfile.Resolution.Height || |
|
|
|
|
|
|
|
videoVersion.Width < channel.FFmpegProfile.Resolution.Width; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if any dimension is smaller than the crop, scale beyond the crop (beyond the target resolution)
|
|
|
|
|
|
|
|
if (isTooSmallToCrop) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foreach (IDisplaySize size in playbackSettings.ScaledSize) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
scaledSize = new FrameSize(size.Width, size.Height); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paddedSize = scaledSize; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
paddedSize = ffmpegVideoStream.SquarePixelFrameSizeForCrop( |
|
|
|
|
|
|
|
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cropSize = new FrameSize( |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Width, |
|
|
|
|
|
|
|
channel.FFmpegProfile.Resolution.Height); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var desiredState = new FrameState( |
|
|
|
|
|
|
|
playbackSettings.RealtimeOutput, |
|
|
|
|
|
|
|
fillerKind == FillerKind.Fallback, |
|
|
|
|
|
|
|
videoFormat, |
|
|
|
|
|
|
|
maybeVideoProfile, |
|
|
|
|
|
|
|
maybeVideoPreset, |
|
|
|
|
|
|
|
channel.FFmpegProfile.AllowBFrames, |
|
|
|
|
|
|
|
Optional(playbackSettings.PixelFormat), |
|
|
|
|
|
|
|
scaledSize, |
|
|
|
|
|
|
|
paddedSize, |
|
|
|
|
|
|
|
cropSize, |
|
|
|
|
|
|
|
false, |
|
|
|
|
|
|
|
playbackSettings.FrameRate, |
|
|
|
|
|
|
|
playbackSettings.VideoBitrate, |
|
|
|
|
|
|
|
playbackSettings.VideoBufferSize, |
|
|
|
|
|
|
|
playbackSettings.VideoTrackTimeScale, |
|
|
|
|
|
|
|
playbackSettings.Deinterlace); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ffmpegState = new FFmpegState( |
|
|
|
var ffmpegState = new FFmpegState( |
|
|
|
saveReports, |
|
|
|
saveReports, |
|
|
|
hwAccel, |
|
|
|
hwAccel, |
|
|
|