aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding/Encoder
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs57
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs13
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs38
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs102
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs1
6 files changed, 152 insertions, 60 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index e9204ef5b..b488741d1 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 181f147b4..912110c04 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -19,6 +19,7 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -65,7 +66,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
.CreateJob(options, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);
encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
- Directory.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath));
encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate;
@@ -112,7 +113,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
Logger.Info(commandLineLogMessage);
var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath));
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
@@ -144,7 +145,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream);
// Wait for the file to exist before proceeeding
- while (!File.Exists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
+ while (!FileSystem.FileExists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
{
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
@@ -342,9 +343,55 @@ namespace MediaBrowser.MediaEncoding.Encoder
inputModifier += " -re";
}
+ var videoDecoder = GetVideoDecoder(job);
+ if (!string.IsNullOrWhiteSpace(videoDecoder))
+ {
+ inputModifier += " " + videoDecoder;
+ }
+
return inputModifier;
}
+ /// <summary>
+ /// Gets the name of the output video codec
+ /// </summary>
+ /// <param name="state">The state.</param>
+ /// <returns>System.String.</returns>
+ protected string GetVideoDecoder(EncodingJob state)
+ {
+ if (string.Equals(GetEncodingOptions().HardwareVideoDecoder, "qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
+ {
+ switch (state.MediaSource.VideoStream.Codec.ToLower())
+ {
+ case "avc":
+ case "h264":
+ if (MediaEncoder.SupportsDecoder("h264_qsv"))
+ {
+ return "-c:v h264_qsv ";
+ }
+ break;
+ case "mpeg2video":
+ if (MediaEncoder.SupportsDecoder("mpeg2_qsv"))
+ {
+ return "-c:v mpeg2_qsv ";
+ }
+ break;
+ case "vc1":
+ if (MediaEncoder.SupportsDecoder("vc1_qsv"))
+ {
+ return "-c:v vc1_qsv ";
+ }
+ break;
+ }
+ }
+ }
+
+ // leave blank so ffmpeg will decide
+ return null;
+ }
+
private string GetUserAgentParam(EncodingJob job)
{
string useragent = null;
@@ -422,7 +469,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
if (!(job.VideoType == VideoType.Iso && job.IsoMount == null))
{
- inputPath = MediaEncoderHelpers.GetInputArgument(job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames);
+ inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames);
}
}
@@ -436,7 +483,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false);
}
- if (state.MediaSource.RequiresOpening)
+ if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.LiveStreamId))
{
var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index 806910d89..07626db33 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public bool EnableMpegtsM2TsMode { get; set; }
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
public long? EncodingDurationTicks { get; set; }
- public string LiveTvStreamId { get; set; }
+ public string LiveStreamId { get; set; }
public long? RunTimeTicks;
public string ItemType { get; set; }
@@ -368,6 +368,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ public string TargetVideoCodecTag
+ {
+ get
+ {
+ var stream = VideoStream;
+ return !Options.Static
+ ? null
+ : stream == null ? null : stream.CodecTag;
+ }
+ }
+
public bool? IsTargetAnamorphic
{
get
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 476d9166b..692fe2b6a 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -326,26 +326,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns>System.Nullable{System.Int32}.</returns>
private int? GetNumAudioChannelsParam(EncodingJobOptions request, MediaStream audioStream, string outputAudioCodec)
{
- if (audioStream != null)
+ var inputChannels = audioStream == null
+ ? null
+ : audioStream.Channels;
+
+ if (inputChannels <= 0)
{
- var codec = outputAudioCodec ?? string.Empty;
+ inputChannels = null;
+ }
- if (audioStream.Channels > 2 && codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1)
- {
- // wmav2 currently only supports two channel output
- return 2;
- }
+ var codec = outputAudioCodec ?? string.Empty;
+
+ if (codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ // wmav2 currently only supports two channel output
+ return Math.Min(2, inputChannels ?? 2);
}
if (request.MaxAudioChannels.HasValue)
{
- if (audioStream != null && audioStream.Channels.HasValue)
+ if (inputChannels.HasValue)
{
- return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
+ return Math.Min(request.MaxAudioChannels.Value, inputChannels.Value);
}
+ var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1
+ ? 2
+ : 6;
+
// If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels
- return Math.Min(request.MaxAudioChannels.Value, 5);
+ return Math.Min(request.MaxAudioChannels.Value, channelLimit);
}
return request.AudioChannels;
@@ -519,6 +529,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
return false;
}
+ if (videoStream.IsAnamorphic ?? false)
+ {
+ return false;
+ }
+
// Can't stream copy if we're burning in subtitles
if (request.SubtitleStreamIndex.HasValue)
{
@@ -735,7 +750,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsTargetCabac,
state.TargetRefFrames,
state.TargetVideoStreamCount,
- state.TargetAudioStreamCount);
+ state.TargetAudioStreamCount,
+ state.TargetVideoCodecTag);
if (mediaProfile != null)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 4fcc71f97..c8361ea04 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -22,6 +22,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -97,6 +98,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
FFMpegPath = ffMpegPath;
}
+ public void SetAvailableEncoders(List<string> list)
+ {
+
+ }
+
+ private List<string> _decoders = new List<string>();
+ public void SetAvailableDecoders(List<string> list)
+ {
+ _decoders = list.ToList();
+ }
+
+ public bool SupportsDecoder(string decoder)
+ {
+ return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
+ }
+
/// <summary>
/// Gets the encoder path.
/// </summary>
@@ -116,7 +133,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
- var inputFiles = MediaEncoderHelpers.GetInputArgument(request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
+ var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
var extractKeyFrameInterval = request.ExtractKeyFrameInterval && request.Protocol == MediaProtocol.File && request.VideoType == VideoType.VideoFile;
@@ -199,10 +216,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
using (var processWrapper = new ProcessWrapper(process, this, _logger))
{
+ await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
try
{
StartProcess(processWrapper);
@@ -222,53 +239,55 @@ namespace MediaBrowser.MediaEncoding.Encoder
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
- if (result != null)
+ if (result.streams == null && result.format == null)
{
- if (result.streams != null)
+ throw new ApplicationException("ffprobe failed - streams and format are both null.");
+ }
+
+ if (result.streams != null)
+ {
+ // Normalize aspect ratio if invalid
+ foreach (var stream in result.streams)
{
- // Normalize aspect ratio if invalid
- foreach (var stream in result.streams)
+ if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.display_aspect_ratio = string.Empty;
- }
- if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.sample_aspect_ratio = string.Empty;
- }
+ stream.display_aspect_ratio = string.Empty;
+ }
+ if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.sample_aspect_ratio = string.Empty;
}
}
+ }
- var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
+ var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
- if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
+ if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
+ {
+ if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue)
{
- if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue)
+ foreach (var stream in mediaInfo.MediaStreams)
{
- foreach (var stream in mediaInfo.MediaStreams)
+ if (EnableKeyframeExtraction(mediaInfo, stream))
{
- if (EnableKeyframeExtraction(mediaInfo, stream))
+ try
{
- try
- {
- stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting key frame interval", ex);
- }
+ stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting key frame interval", ex);
}
}
}
}
-
- return mediaInfo;
}
+
+ return mediaInfo;
}
catch
{
@@ -330,7 +349,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
EnableRaisingEvents = true
};
- _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
using (process)
{
@@ -356,7 +375,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
process.WaitForExit();
- _logger.Debug("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds);
+ _logger.Info("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds);
//_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray()));
return lines;
}
@@ -483,9 +502,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- // TODO: Output in webp for smaller sizes
- // -f image2 -f webp
-
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
var args = useIFrame ? string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) :
string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
@@ -520,10 +536,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
using (var processWrapper = new ProcessWrapper(process, this, _logger))
{
+ await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
bool ranToCompletion;
var memoryStream = new MemoryStream();
@@ -605,7 +621,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
}
- Directory.CreateDirectory(targetDirectory);
+ FileSystem.CreateDirectory(targetDirectory);
var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
var args = string.Format("-i {0} -threads 1 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
@@ -879,4 +895,4 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index 49eed9ee5..127145aec 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using System;
using System.IO;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{