|
|
|
@ -152,7 +152,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|
|
|
|
RedirectStandardError = true,
|
|
|
|
|
FileName = FFProbePath,
|
|
|
|
|
Arguments = string.Format(args,
|
|
|
|
|
probeSizeArgument, inputPath).Trim(),
|
|
|
|
|
probeSizeArgument, inputPath).Trim(),
|
|
|
|
|
|
|
|
|
|
WindowStyle = ProcessWindowStyle.Hidden,
|
|
|
|
|
ErrorDialog = false
|
|
|
|
@ -186,8 +186,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|
|
|
|
{
|
|
|
|
|
process.BeginErrorReadLine();
|
|
|
|
|
|
|
|
|
|
result =
|
|
|
|
|
_jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
|
|
|
|
|
result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
@ -292,7 +291,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|
|
|
|
// apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600.
|
|
|
|
|
// This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar
|
|
|
|
|
var vf = "scale=600:trunc(600/dar/2)*2";
|
|
|
|
|
//crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,scale=600:(600/dar),thumbnail" -f image2
|
|
|
|
|
|
|
|
|
|
if (threedFormat.HasValue)
|
|
|
|
|
{
|
|
|
|
@ -344,7 +342,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|
|
|
|
WindowStyle = ProcessWindowStyle.Hidden,
|
|
|
|
|
ErrorDialog = false,
|
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
|
RedirectStandardError = true
|
|
|
|
|
RedirectStandardError = true,
|
|
|
|
|
RedirectStandardInput = true
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -370,7 +369,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|
|
|
|
{
|
|
|
|
|
_logger.Info("Killing ffmpeg process");
|
|
|
|
|
|
|
|
|
|
process.Kill();
|
|
|
|
|
process.StandardInput.WriteLine("q");
|
|
|
|
|
|
|
|
|
|
process.WaitForExit(1000);
|
|
|
|
|
}
|
|
|
|
@ -437,5 +436,93 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|
|
|
|
{
|
|
|
|
|
return time.ToString(@"hh\:mm\:ss\.fff", UsCulture);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task ExtractVideoImagesOnInterval(string[] inputFiles,
|
|
|
|
|
MediaProtocol protocol,
|
|
|
|
|
Video3DFormat? threedFormat,
|
|
|
|
|
TimeSpan interval,
|
|
|
|
|
string targetDirectory,
|
|
|
|
|
string filenamePrefix,
|
|
|
|
|
int? maxWidth,
|
|
|
|
|
CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var resourcePool = _videoImageResourcePool;
|
|
|
|
|
|
|
|
|
|
var inputArgument = GetInputArgument(inputFiles, protocol);
|
|
|
|
|
|
|
|
|
|
var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture);
|
|
|
|
|
|
|
|
|
|
if (maxWidth.HasValue)
|
|
|
|
|
{
|
|
|
|
|
var maxWidthParam = maxWidth.Value.ToString(UsCulture);
|
|
|
|
|
|
|
|
|
|
vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Directory.CreateDirectory(targetDirectory);
|
|
|
|
|
var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
|
|
|
|
|
|
|
|
|
|
var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
|
|
|
|
|
|
|
|
|
|
var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol);
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(probeSize))
|
|
|
|
|
{
|
|
|
|
|
args = probeSize + " " + args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var process = new Process
|
|
|
|
|
{
|
|
|
|
|
StartInfo = new ProcessStartInfo
|
|
|
|
|
{
|
|
|
|
|
CreateNoWindow = true,
|
|
|
|
|
UseShellExecute = false,
|
|
|
|
|
FileName = FFMpegPath,
|
|
|
|
|
Arguments = args,
|
|
|
|
|
WindowStyle = ProcessWindowStyle.Hidden,
|
|
|
|
|
ErrorDialog = false,
|
|
|
|
|
RedirectStandardInput = true
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
|
|
|
|
|
|
|
|
|
|
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
process.Start();
|
|
|
|
|
|
|
|
|
|
var ranToCompletion = process.WaitForExit(120000);
|
|
|
|
|
|
|
|
|
|
if (!ranToCompletion)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_logger.Info("Killing ffmpeg process");
|
|
|
|
|
|
|
|
|
|
process.StandardInput.WriteLine("q");
|
|
|
|
|
|
|
|
|
|
process.WaitForExit(1000);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.ErrorException("Error killing process", ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resourcePool.Release();
|
|
|
|
|
|
|
|
|
|
var exitCode = ranToCompletion ? process.ExitCode : -1;
|
|
|
|
|
|
|
|
|
|
process.Dispose();
|
|
|
|
|
|
|
|
|
|
if (exitCode == -1)
|
|
|
|
|
{
|
|
|
|
|
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
|
|
|
|
|
|
|
|
|
_logger.Error(msg);
|
|
|
|
|
|
|
|
|
|
throw new ApplicationException(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|