3.0.5713.4

This commit is contained in:
Luke Pulverenti 2015-08-27 11:58:07 -04:00
parent 0e1b983ffc
commit 4ca526979d
10 changed files with 214 additions and 137 deletions

View File

@ -1634,11 +1634,6 @@ namespace MediaBrowser.Api.Playback
private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest) private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest)
{ {
if (!EnableStreamCopy)
{
return;
}
if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream)) if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
{ {
state.OutputVideoCodec = "copy"; state.OutputVideoCodec = "copy";
@ -1650,14 +1645,6 @@ namespace MediaBrowser.Api.Playback
} }
} }
protected virtual bool EnableStreamCopy
{
get
{
return true;
}
}
private void AttachMediaSourceInfo(StreamState state, private void AttachMediaSourceInfo(StreamState state,
MediaSourceInfo mediaSource, MediaSourceInfo mediaSource,
VideoStreamRequest videoRequest, VideoStreamRequest videoRequest,
@ -1741,7 +1728,7 @@ namespace MediaBrowser.Api.Playback
state.MediaSource = mediaSource; state.MediaSource = mediaSource;
} }
private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) protected virtual bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
{ {
if (videoStream.IsInterlaced) if (videoStream.IsInterlaced)
{ {
@ -1889,7 +1876,7 @@ namespace MediaBrowser.Api.Playback
return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase)); return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
} }
private bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs) protected virtual bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
{ {
// Source and target codecs must match // Source and target codecs must match
if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase))

View File

@ -1,9 +1,11 @@
using MediaBrowser.Common.IO; using System.Linq;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
@ -310,5 +312,33 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
return 0; return 0;
} }
protected override bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
{
if (videoStream.KeyFrames == null || videoStream.KeyFrames.Count == 0)
{
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)
{
return false;
}
previousSegment = frame;
}
return base.CanStreamCopyVideo(request, videoStream);
}
protected override bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
{
return false;
}
} }
} }

View File

@ -160,7 +160,6 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8"); var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex); var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex);
var segmentLength = state.SegmentLength;
var segmentExtension = GetSegmentFileExtension(state); var segmentExtension = GetSegmentFileExtension(state);
@ -169,7 +168,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (File.Exists(segmentPath)) if (File.Exists(segmentPath))
{ {
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
} }
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
@ -178,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (File.Exists(segmentPath)) if (File.Exists(segmentPath))
{ {
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
@ -214,7 +213,7 @@ namespace MediaBrowser.Api.Playback.Hls
DeleteLastFile(playlistPath, segmentExtension, 0); DeleteLastFile(playlistPath, segmentExtension, 0);
} }
request.StartTimeTicks = GetSeekPositionTicks(state, playlistPath, requestedIndex); request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false); job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
} }
@ -249,37 +248,76 @@ namespace MediaBrowser.Api.Playback.Hls
Logger.Info("returning {0}", segmentPath); Logger.Info("returning {0}", segmentPath);
job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
} }
// 256k // 256k
private const int BufferSize = 262144; private const int BufferSize = 262144;
private long GetSeekPositionTicks(StreamState state, string playlist, int requestedIndex) private long GetStartPositionTicks(StreamState state, int requestedIndex)
{ {
double startSeconds = 0; double startSeconds = 0;
var lengths = GetSegmentLengths(state);
for (var i = 0; i < requestedIndex; i++) for (var i = 0; i < requestedIndex; i++)
{ {
var segmentPath = GetSegmentPath(state, playlist, i); startSeconds += lengths[requestedIndex];
//double length;
//if (SegmentLengths.TryGetValue(Path.GetFileName(segmentPath), out length))
//{
// Logger.Debug("Found segment length of {0} for index {1}", length, i);
// startSeconds += length;
//}
//else
//{
// startSeconds += state.SegmentLength;
//}
startSeconds += state.SegmentLength;
} }
var position = TimeSpan.FromSeconds(startSeconds).Ticks; var position = TimeSpan.FromSeconds(startSeconds).Ticks;
return position; return position;
} }
private long GetEndPositionTicks(StreamState state, int requestedIndex)
{
double startSeconds = 0;
var lengths = GetSegmentLengths(state);
for (var i = 0; i <= requestedIndex; i++)
{
startSeconds += lengths[requestedIndex];
}
var position = TimeSpan.FromSeconds(startSeconds).Ticks;
return position;
}
private double[] GetSegmentLengths(StreamState state)
{
var result = new List<double>();
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;
var segmentLengthTicks = TimeSpan.FromSeconds(state.SegmentLength).Ticks;
while (ticks > 0)
{
var length = ticks >= segmentLengthTicks ? segmentLengthTicks : ticks;
result.Add(TimeSpan.FromTicks(length).TotalSeconds);
ticks -= length;
}
return result.ToArray();
}
public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension) public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
{ {
var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType); var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType);
@ -384,17 +422,16 @@ namespace MediaBrowser.Api.Playback.Hls
return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state)); return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state));
} }
private async Task<object> GetSegmentResult(string playlistPath, private async Task<object> GetSegmentResult(StreamState state, string playlistPath,
string segmentPath, string segmentPath,
int segmentIndex, int segmentIndex,
int segmentLength,
TranscodingJob transcodingJob, TranscodingJob transcodingJob,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
// If all transcoding has completed, just return immediately // If all transcoding has completed, just return immediately
if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath)) if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath))
{ {
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob); return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
} }
var segmentFilename = Path.GetFileName(segmentPath); var segmentFilename = Path.GetFileName(segmentPath);
@ -414,7 +451,7 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
if (File.Exists(segmentPath)) if (File.Exists(segmentPath))
{ {
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob); return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
} }
//break; //break;
} }
@ -465,13 +502,12 @@ namespace MediaBrowser.Api.Playback.Hls
//} //}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob); return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
} }
private object GetSegmentResult(string segmentPath, int index, int segmentLength, TranscodingJob transcodingJob) private object GetSegmentResult(StreamState state, string segmentPath, int index, TranscodingJob transcodingJob)
{ {
var segmentEndingSeconds = (1 + index) * segmentLength; var segmentEndingPositionTicks = GetEndPositionTicks(state, index);
var segmentEndingPositionTicks = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks;
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{ {
@ -698,26 +734,22 @@ namespace MediaBrowser.Api.Playback.Hls
{ {
var state = await GetState(request, CancellationToken.None).ConfigureAwait(false); var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
var segmentLengths = GetSegmentLengths(state);
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("#EXTM3U"); builder.AppendLine("#EXTM3U");
builder.AppendLine("#EXT-X-VERSION:3"); builder.AppendLine("#EXT-X-VERSION:3");
builder.AppendLine("#EXT-X-TARGETDURATION:" + (state.SegmentLength).ToString(UsCulture)); builder.AppendLine("#EXT-X-TARGETDURATION:" + Math.Ceiling((segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength)).ToString(UsCulture));
builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0"); builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
var queryStringIndex = Request.RawUrl.IndexOf('?'); var queryStringIndex = Request.RawUrl.IndexOf('?');
var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex); var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
var index = 0; var index = 0;
double segmentLength = state.SegmentLength; foreach (var length in segmentLengths)
while (seconds > 0)
{ {
var length = seconds >= state.SegmentLength ? segmentLength : seconds;
builder.AppendLine("#EXTINF:" + length.ToString("0.000000", UsCulture) + ","); builder.AppendLine("#EXTINF:" + length.ToString("0.000000", UsCulture) + ",");
builder.AppendLine(string.Format("hlsdynamic/{0}/{1}{2}{3}", builder.AppendLine(string.Format("hlsdynamic/{0}/{1}{2}{3}",
@ -727,7 +759,6 @@ namespace MediaBrowser.Api.Playback.Hls
GetSegmentFileExtension(isOutputVideo), GetSegmentFileExtension(isOutputVideo),
queryString)); queryString));
seconds -= length;
index++; index++;
} }
@ -850,11 +881,6 @@ namespace MediaBrowser.Api.Playback.Hls
args += " -flags +loop-global_header -sc_threshold 0"; args += " -flags +loop-global_header -sc_threshold 0";
} }
if (!EnableSplitTranscoding(state))
{
//args += " -copyts";
}
return args; return args;
} }
@ -870,21 +896,6 @@ namespace MediaBrowser.Api.Playback.Hls
var toTimeParam = string.Empty; var toTimeParam = string.Empty;
var timestampOffsetParam = string.Empty; var timestampOffsetParam = string.Empty;
if (EnableSplitTranscoding(state))
{
var startTime = state.Request.StartTimeTicks ?? 0;
var durationSeconds = ApiEntryPoint.Instance.GetEncodingOptions().ThrottleThresholdInSeconds;
var endTime = startTime + TimeSpan.FromSeconds(durationSeconds).Ticks;
endTime = Math.Min(endTime, state.RunTimeTicks.Value);
if (endTime < state.RunTimeTicks.Value)
{
//toTimeParam = " -to " + MediaEncoder.GetTimeParameter(endTime);
toTimeParam = " -t " + MediaEncoder.GetTimeParameter(TimeSpan.FromSeconds(durationSeconds).Ticks);
}
}
if (state.IsOutputVideo && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0) if (state.IsOutputVideo && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0)
{ {
timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture); timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture);
@ -927,36 +938,7 @@ namespace MediaBrowser.Api.Playback.Hls
protected override bool EnableThrottling(StreamState state) protected override bool EnableThrottling(StreamState state)
{ {
return !EnableSplitTranscoding(state); return true;
}
private bool EnableSplitTranscoding(StreamState state)
{
return false;
if (string.Equals(Request.QueryString["EnableSplitTranscoding"], "false", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return state.RunTimeTicks.HasValue && state.IsOutputVideo;
}
protected override bool EnableStreamCopy
{
get
{
return false;
}
} }
/// <summary> /// <summary>

View File

@ -226,7 +226,9 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Profiles\Xml\Sony Bravia %282014%29.xml" /> <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282014%29.xml">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -248,8 +248,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
try try
{ {
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken) //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false);
// .ConfigureAwait(false);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -283,7 +282,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private async Task<List<int>> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken) private async Task<List<int>> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken)
{ {
const string args = "-i {0} -select_streams v:{1} -show_frames -show_entries frame=pkt_dts,key_frame -print_format compact"; const string args = "-i {0} -select_streams v:{1} -show_packets -print_format compact -show_entries packet=flags -show_entries packet=pts_time";
var process = new Process var process = new Process
{ {
@ -318,7 +317,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
process.BeginErrorReadLine(); process.BeginErrorReadLine();
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false); await StartReadingOutput(process.StandardOutput.BaseStream, lines, cancellationToken).ConfigureAwait(false);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -336,7 +335,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
} }
private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken) private async Task StartReadingOutput(Stream source, List<int> lines, CancellationToken cancellationToken)
{ {
try try
{ {
@ -354,14 +353,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
.Where(i => i.Length == 2) .Where(i => i.Length == 2)
.ToDictionary(i => i[0], i => i[1]); .ToDictionary(i => i[0], i => i[1]);
string pktDts; string flags;
int frameMs; if (values.TryGetValue("flags", out flags) && string.Equals(flags, "k", StringComparison.OrdinalIgnoreCase))
if (values.TryGetValue("pkt_dts", out pktDts) && int.TryParse(pktDts, NumberStyles.Any, CultureInfo.InvariantCulture, out frameMs))
{ {
string keyFrame; string pts_time;
if (values.TryGetValue("key_frame", out keyFrame) && string.Equals(keyFrame, "1", StringComparison.OrdinalIgnoreCase)) double frameSeconds;
if (values.TryGetValue("pts_time", out pts_time) && double.TryParse(pts_time, NumberStyles.Any, CultureInfo.InvariantCulture, out frameSeconds))
{ {
lines.Add(frameMs); var ms = frameSeconds * 1000;
lines.Add(Convert.ToInt32(ms));
} }
} }
} }
@ -376,7 +376,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.ErrorException("Error reading ffprobe output", ex); _logger.ErrorException("Error reading ffprobe output", ex);
} }
} }
/// <summary> /// <summary>
/// The us culture /// The us culture
/// </summary> /// </summary>
@ -802,7 +801,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public ProcessWrapper(Process process, MediaEncoder mediaEncoder, ILogger logger) public ProcessWrapper(Process process, MediaEncoder mediaEncoder, ILogger logger)
{ {
Process = process; Process = process;
this._mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
_logger = logger; _logger = logger;
Process.Exited += Process_Exited; Process.Exited += Process_Exited;
} }
@ -819,7 +818,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.ErrorException("Error determing process exit code", ex);
} }
lock (_mediaEncoder._runningProcesses) lock (_mediaEncoder._runningProcesses)

View File

@ -1,4 +1,6 @@
using MediaBrowser.Model.Dlna; using System.Collections.Generic;
using System.Runtime.Serialization;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
using System.Diagnostics; using System.Diagnostics;
@ -225,5 +227,8 @@ namespace MediaBrowser.Model.Entities
/// </summary> /// </summary>
/// <value><c>null</c> if [is cabac] contains no value, <c>true</c> if [is cabac]; otherwise, <c>false</c>.</value> /// <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; } public bool? IsCabac { get; set; }
[IgnoreDataMember]
public List<int> KeyFrames { get; set; }
} }
} }

View File

@ -132,7 +132,7 @@ namespace MediaBrowser.Providers.MediaInfo
return ItemUpdateType.MetadataImport; return ItemUpdateType.MetadataImport;
} }
private const string SchemaVersion = "5"; private const string SchemaVersion = "6";
private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(Video item, private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(Video item,
IIsoMount isoMount, IIsoMount isoMount,
@ -140,14 +140,14 @@ namespace MediaBrowser.Providers.MediaInfo
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var idString = item.Id.ToString("N"); //var idString = item.Id.ToString("N");
var cachePath = Path.Combine(_appPaths.CachePath, //var cachePath = Path.Combine(_appPaths.CachePath,
"ffprobe-video", // "ffprobe-video",
idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); // idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
try try
{ {
return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath); //return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@ -174,8 +174,8 @@ namespace MediaBrowser.Providers.MediaInfo
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); //Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
_json.SerializeToFile(result, cachePath); //_json.SerializeToFile(result, cachePath);
return result; return result;
} }

View File

@ -187,6 +187,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary> /// </summary>
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
private string[] _retriveItemColumns =
{
"type",
"data",
"IsOffline"
};
/// <summary> /// <summary>
/// Prepares the statements. /// Prepares the statements.
/// </summary> /// </summary>
@ -455,7 +462,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand()) using (var cmd = _connection.CreateCommand())
{ {
cmd.CommandText = "select type,data from TypedBaseItems where guid = @guid"; cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid";
cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = id; cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = id;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
@ -482,11 +489,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
return null; return null;
} }
BaseItem item;
using (var stream = reader.GetMemoryStream(1)) using (var stream = reader.GetMemoryStream(1))
{ {
try try
{ {
return _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem; item = _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem;
if (item == null)
{
return null;
}
} }
catch (SerializationException ex) catch (SerializationException ex)
{ {
@ -494,6 +508,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
return null; return null;
} }
} }
if (!reader.IsDBNull(2))
{
item.IsOffline = reader.GetBoolean(2);
}
return item;
} }
/// <summary> /// <summary>
@ -685,7 +706,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand()) using (var cmd = _connection.CreateCommand())
{ {
cmd.CommandText = "select type,data from TypedBaseItems where guid in (select ItemId from ChildrenIds where ParentId = @ParentId)"; cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid in (select ItemId from ChildrenIds where ParentId = @ParentId)";
cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId; cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId;
@ -715,7 +736,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand()) using (var cmd = _connection.CreateCommand())
{ {
cmd.CommandText = "select type,data from TypedBaseItems where type = @type"; cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where type = @type";
cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName; cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName;
@ -745,7 +766,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand()) using (var cmd = _connection.CreateCommand())
{ {
cmd.CommandText = "select type,data from TypedBaseItems"; cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems";
var whereClauses = GetWhereClauses(query, cmd, false); var whereClauses = GetWhereClauses(query, cmd, false);

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Persistence; using System.Globalization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
@ -38,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
// Add PixelFormat column // Add PixelFormat column
createTableCommand += "(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, PRIMARY KEY (ItemId, StreamIndex))"; createTableCommand += "(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, PRIMARY KEY (ItemId, StreamIndex))";
string[] queries = { string[] queries = {
@ -58,6 +59,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
AddBitDepthCommand(); AddBitDepthCommand();
AddIsAnamorphicColumn(); AddIsAnamorphicColumn();
AddIsCabacColumn(); AddIsCabacColumn();
AddKeyFramesColumn();
AddRefFramesCommand(); AddRefFramesCommand();
PrepareStatements(); PrepareStatements();
@ -187,6 +189,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.RunQueries(new[] { builder.ToString() }, _logger); _connection.RunQueries(new[] { builder.ToString() }, _logger);
} }
private void AddKeyFramesColumn()
{
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "PRAGMA table_info(mediastreams)";
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
while (reader.Read())
{
if (!reader.IsDBNull(1))
{
var name = reader.GetString(1);
if (string.Equals(name, "KeyFrames", StringComparison.OrdinalIgnoreCase))
{
return;
}
}
}
}
}
var builder = new StringBuilder();
builder.AppendLine("alter table mediastreams");
builder.AppendLine("add column KeyFrames TEXT NULL");
_connection.RunQueries(new[] { builder.ToString() }, _logger);
}
private void AddIsAnamorphicColumn() private void AddIsAnamorphicColumn()
{ {
using (var cmd = _connection.CreateCommand()) using (var cmd = _connection.CreateCommand())
@ -245,7 +278,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"BitDepth", "BitDepth",
"IsAnamorphic", "IsAnamorphic",
"RefFrames", "RefFrames",
"IsCabac" "IsCabac",
"KeyFrames"
}; };
/// <summary> /// <summary>
@ -429,6 +463,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.IsCabac = reader.GetBoolean(25); item.IsCabac = reader.GetBoolean(25);
} }
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();
}
}
return item; return item;
} }
@ -498,6 +541,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveStreamCommand.GetParameter(index++).Value = stream.RefFrames; _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames;
_saveStreamCommand.GetParameter(index++).Value = stream.IsCabac; _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.Transaction = transaction; _saveStreamCommand.Transaction = transaction;
_saveStreamCommand.ExecuteNonQuery(); _saveStreamCommand.ExecuteNonQuery();
} }

View File

@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.0.*")] //[assembly: AssemblyVersion("3.0.*")]
//[assembly: AssemblyVersion("3.0.5713.3")] [assembly: AssemblyVersion("3.0.5713.4")]