update keyframe setting
This commit is contained in:
parent
3060b0c5e9
commit
02938e7bcb
|
@ -2178,6 +2178,8 @@ namespace MediaBrowser.Api.Playback
|
|||
inputModifier += " " + videoDecoder;
|
||||
}
|
||||
|
||||
//inputModifier += " -noaccurate_seek";
|
||||
|
||||
return inputModifier;
|
||||
}
|
||||
|
||||
|
|
|
@ -291,25 +291,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
private double[] GetSegmentLengths(StreamState state)
|
||||
{
|
||||
var result = new List<double>();
|
||||
if (state.VideoRequest != null)
|
||||
{
|
||||
var encoder = GetVideoEncoder(state);
|
||||
|
||||
if (string.Equals(encoder, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var videoStream = state.VideoStream;
|
||||
if (videoStream.KeyFrames != null && videoStream.KeyFrames.Count > 0)
|
||||
{
|
||||
foreach (var frame in videoStream.KeyFrames)
|
||||
{
|
||||
var seconds = TimeSpan.FromMilliseconds(frame).TotalSeconds;
|
||||
seconds -= result.Sum();
|
||||
result.Add(seconds);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ticks = state.RunTimeTicks ?? 0;
|
||||
|
||||
|
@ -936,27 +917,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
protected override bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
|
||||
{
|
||||
if (videoStream.KeyFrames == null || videoStream.KeyFrames.Count == 0)
|
||||
{
|
||||
Logger.Debug("Cannot stream copy video due to missing keyframe info");
|
||||
return false;
|
||||
}
|
||||
|
||||
var previousSegment = 0;
|
||||
foreach (var frame in videoStream.KeyFrames)
|
||||
{
|
||||
var length = frame - previousSegment;
|
||||
|
||||
// Don't allow really long segments because this could result in long download times
|
||||
if (length > 10000)
|
||||
{
|
||||
Logger.Debug("Cannot stream copy video due to long segment length of {0}ms", length);
|
||||
return false;
|
||||
}
|
||||
previousSegment = frame;
|
||||
}
|
||||
|
||||
return base.CanStreamCopyVideo(request, videoStream);
|
||||
//return base.CanStreamCopyVideo(request, videoStream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -100,6 +100,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
{
|
||||
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
||||
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
||||
//format = " -avoid_negative_ts disabled -start_at_zero -copyts -f mp4 -movflags frag_keyframe+empty_moov";
|
||||
}
|
||||
|
||||
var threads = GetNumberOfThreads(state, string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
public IIsoMount MountedIso { get; set; }
|
||||
public VideoType VideoType { get; set; }
|
||||
public List<string> PlayableStreamFileNames { get; set; }
|
||||
public bool ExtractKeyFrameInterval { get; set; }
|
||||
|
||||
public MediaInfoRequest()
|
||||
{
|
||||
|
|
|
@ -135,9 +135,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
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;
|
||||
|
||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, extractKeyFrameInterval,
|
||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
|
||||
GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
|
||||
}
|
||||
|
||||
|
@ -171,18 +169,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
/// <param name="primaryPath">The primary path.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <param name="extractChapters">if set to <c>true</c> [extract chapters].</param>
|
||||
/// <param name="extractKeyFrameInterval">if set to <c>true</c> [extract key frame interval].</param>
|
||||
/// <param name="probeSizeArgument">The probe size argument.</param>
|
||||
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
|
||||
/// <param name="videoType">Type of the video.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{MediaInfoResult}.</returns>
|
||||
/// <exception cref="System.ApplicationException"></exception>
|
||||
/// <exception cref="System.ApplicationException">ffprobe failed - streams and format are both null.</exception>
|
||||
private async Task<Model.MediaInfo.MediaInfo> GetMediaInfoInternal(string inputPath,
|
||||
string primaryPath,
|
||||
MediaProtocol protocol,
|
||||
bool extractChapters,
|
||||
bool extractKeyFrameInterval,
|
||||
string probeSizeArgument,
|
||||
bool isAudio,
|
||||
VideoType videoType,
|
||||
|
@ -262,31 +258,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
||||
|
||||
if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
|
||||
{
|
||||
if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue)
|
||||
{
|
||||
foreach (var stream in mediaInfo.MediaStreams)
|
||||
{
|
||||
if (EnableKeyframeExtraction(mediaInfo, stream))
|
||||
{
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
catch
|
||||
|
@ -300,132 +271,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
_ffProbeResourcePool.Release();
|
||||
}
|
||||
}
|
||||
|
||||
throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
|
||||
}
|
||||
|
||||
private bool EnableKeyframeExtraction(MediaSourceInfo mediaSource, MediaStream videoStream)
|
||||
{
|
||||
if (videoStream.Type == MediaStreamType.Video && string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) &&
|
||||
!videoStream.IsInterlaced &&
|
||||
!(videoStream.IsAnamorphic ?? false))
|
||||
{
|
||||
var audioStreams = mediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio).ToList();
|
||||
|
||||
// If it has aac audio then it will probably direct stream anyway, so don't bother with this
|
||||
if (audioStreams.Count == 1 && string.Equals(audioStreams[0].Codec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<List<int>> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken)
|
||||
{
|
||||
inputPath = inputPath.Split(new[] { ':' }, 2).Last().Trim('"');
|
||||
|
||||
const string args = "-show_packets -print_format compact -select_streams v:{1} -show_entries packet=flags -show_entries packet=pts_time \"{0}\"";
|
||||
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
|
||||
// Must consume both or ffmpeg may hang due to deadlocks. See comments below.
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
FileName = FFProbePath,
|
||||
Arguments = string.Format(args, inputPath, videoStreamIndex.ToString(CultureInfo.InvariantCulture)).Trim(),
|
||||
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
ErrorDialog = false
|
||||
},
|
||||
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
|
||||
_logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||
|
||||
using (process)
|
||||
{
|
||||
var start = DateTime.UtcNow;
|
||||
|
||||
process.Start();
|
||||
|
||||
var lines = new List<int>();
|
||||
|
||||
try
|
||||
{
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
await StartReadingOutput(process.StandardOutput.BaseStream, lines, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
_logger.Info("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds);
|
||||
//_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray()));
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartReadingOutput(Stream source, List<int> keyframes, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var reader = new StreamReader(source))
|
||||
{
|
||||
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
var lines = StringHelper.RegexSplit(text, "[\r\n]+");
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var values = line.Split('|')
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.Select(i => i.Split('='))
|
||||
.Where(i => i.Length == 2)
|
||||
.ToDictionary(i => i[0], i => i[1]);
|
||||
|
||||
string flags;
|
||||
if (values.TryGetValue("flags", out flags) && string.Equals(flags, "k", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string pts_time;
|
||||
double frameSeconds;
|
||||
if (values.TryGetValue("pts_time", out pts_time) && double.TryParse(pts_time, NumberStyles.Any, CultureInfo.InvariantCulture, out frameSeconds))
|
||||
{
|
||||
var ms = frameSeconds * 1000;
|
||||
keyframes.Add(Convert.ToInt32(ms));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error reading ffprobe output", ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The us culture
|
||||
/// </summary>
|
||||
|
|
|
@ -209,8 +209,6 @@ namespace MediaBrowser.Model.Configuration
|
|||
|
||||
public bool EnableWindowsShortcuts { get; set; }
|
||||
|
||||
public bool EnableVideoFrameByFrameAnalysis { get; set; }
|
||||
|
||||
public bool EnableDateLastRefresh { get; set; }
|
||||
|
||||
public string[] Migrations { get; set; }
|
||||
|
|
|
@ -233,8 +233,5 @@ namespace MediaBrowser.Model.Entities
|
|||
/// </summary>
|
||||
/// <value><c>null</c> if [is cabac] contains no value, <c>true</c> if [is cabac]; otherwise, <c>false</c>.</value>
|
||||
public bool? IsCabac { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<int> KeyFrames { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,8 +170,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
VideoType = item.VideoType,
|
||||
MediaType = DlnaProfileType.Video,
|
||||
InputPath = item.Path,
|
||||
Protocol = protocol,
|
||||
ExtractKeyFrameInterval = true
|
||||
Protocol = protocol
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
||||
|
||||
var createMediaStreamsTableCommand
|
||||
= "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, KeyFrames TEXT NULL, CodecTag TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
|
||||
= "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, CodecTag TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
|
||||
|
||||
string[] queries = {
|
||||
|
||||
|
@ -385,7 +385,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
"IsAnamorphic",
|
||||
"RefFrames",
|
||||
"IsCabac",
|
||||
"KeyFrames",
|
||||
"CodecTag"
|
||||
};
|
||||
|
||||
|
@ -2683,15 +2682,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
_saveStreamCommand.GetParameter(index++).Value = stream.RefFrames;
|
||||
_saveStreamCommand.GetParameter(index++).Value = stream.IsCabac;
|
||||
|
||||
if (stream.KeyFrames == null || stream.KeyFrames.Count == 0)
|
||||
{
|
||||
_saveStreamCommand.GetParameter(index++).Value = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_saveStreamCommand.GetParameter(index++).Value = string.Join(",", stream.KeyFrames.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray());
|
||||
}
|
||||
|
||||
_saveStreamCommand.GetParameter(index++).Value = stream.CodecTag;
|
||||
|
||||
_saveStreamCommand.Transaction = transaction;
|
||||
|
@ -2848,16 +2838,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
if (!reader.IsDBNull(26))
|
||||
{
|
||||
var frames = reader.GetString(26);
|
||||
if (!string.IsNullOrWhiteSpace(frames))
|
||||
{
|
||||
item.KeyFrames = frames.Split(',').Select(i => int.Parse(i, CultureInfo.InvariantCulture)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
if (!reader.IsDBNull(27))
|
||||
{
|
||||
item.CodecTag = reader.GetString(27);
|
||||
item.CodecTag = reader.GetString(26);
|
||||
}
|
||||
|
||||
return item;
|
||||
|
|
|
@ -303,6 +303,11 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
|
||||
var mode = request.Mode;
|
||||
|
||||
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_fileSystem.DeleteFile(Path.Combine(path, "scripts", "registrationservices.js"));
|
||||
}
|
||||
|
||||
// Try to trim the output size a bit
|
||||
var bowerPath = Path.Combine(path, "bower_components");
|
||||
DeleteFilesByExtension(bowerPath, ".log");
|
||||
|
|
Loading…
Reference in New Issue
Block a user