update keyframe setting

pull/702/head
Luke Pulverenti 9 years ago
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 false;
//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…
Cancel
Save