pull/702/head
Luke Pulverenti 9 years ago
parent 0e1b983ffc
commit 4ca526979d

@ -1634,11 +1634,6 @@ namespace MediaBrowser.Api.Playback
private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest)
{
if (!EnableStreamCopy)
{
return;
}
if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
{
state.OutputVideoCodec = "copy";
@ -1650,14 +1645,6 @@ namespace MediaBrowser.Api.Playback
}
}
protected virtual bool EnableStreamCopy
{
get
{
return true;
}
}
private void AttachMediaSourceInfo(StreamState state,
MediaSourceInfo mediaSource,
VideoStreamRequest videoRequest,
@ -1741,7 +1728,7 @@ namespace MediaBrowser.Api.Playback
state.MediaSource = mediaSource;
}
private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
protected virtual bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
{
if (videoStream.IsInterlaced)
{
@ -1889,7 +1876,7 @@ namespace MediaBrowser.Api.Playback
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
if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase))

@ -1,9 +1,11 @@
using MediaBrowser.Common.IO;
using System.Linq;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
@ -310,5 +312,33 @@ namespace MediaBrowser.Api.Playback.Hls
{
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;
}
}
}

@ -160,7 +160,6 @@ namespace MediaBrowser.Api.Playback.Hls
var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex);
var segmentLength = state.SegmentLength;
var segmentExtension = GetSegmentFileExtension(state);
@ -169,7 +168,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (File.Exists(segmentPath))
{
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);
@ -178,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (File.Exists(segmentPath))
{
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
{
@ -214,7 +213,7 @@ namespace MediaBrowser.Api.Playback.Hls
DeleteLastFile(playlistPath, segmentExtension, 0);
}
request.StartTimeTicks = GetSeekPositionTicks(state, playlistPath, requestedIndex);
request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
}
@ -249,37 +248,76 @@ namespace MediaBrowser.Api.Playback.Hls
Logger.Info("returning {0}", segmentPath);
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
private const int BufferSize = 262144;
private long GetSeekPositionTicks(StreamState state, string playlist, int requestedIndex)
private long GetStartPositionTicks(StreamState state, int requestedIndex)
{
double startSeconds = 0;
var lengths = GetSegmentLengths(state);
for (var i = 0; i < requestedIndex; i++)
{
var segmentPath = GetSegmentPath(state, playlist, i);
startSeconds += lengths[requestedIndex];
}
var position = TimeSpan.FromSeconds(startSeconds).Ticks;
return position;
}
//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;
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)
{
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));
}
private async Task<object> GetSegmentResult(string playlistPath,
private async Task<object> GetSegmentResult(StreamState state, string playlistPath,
string segmentPath,
int segmentIndex,
int segmentLength,
TranscodingJob transcodingJob,
CancellationToken cancellationToken)
{
// If all transcoding has completed, just return immediately
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);
@ -414,7 +451,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
if (File.Exists(segmentPath))
{
return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
}
//break;
}
@ -465,13 +502,12 @@ namespace MediaBrowser.Api.Playback.Hls
//}
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 = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks;
var segmentEndingPositionTicks = GetEndPositionTicks(state, index);
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 segmentLengths = GetSegmentLengths(state);
var builder = new StringBuilder();
builder.AppendLine("#EXTM3U");
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");
var queryStringIndex = Request.RawUrl.IndexOf('?');
var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
var index = 0;
double segmentLength = state.SegmentLength;
while (seconds > 0)
foreach (var length in segmentLengths)
{
var length = seconds >= state.SegmentLength ? segmentLength : seconds;
builder.AppendLine("#EXTINF:" + length.ToString("0.000000", UsCulture) + ",");
builder.AppendLine(string.Format("hlsdynamic/{0}/{1}{2}{3}",
@ -727,7 +759,6 @@ namespace MediaBrowser.Api.Playback.Hls
GetSegmentFileExtension(isOutputVideo),
queryString));
seconds -= length;
index++;
}
@ -850,11 +881,6 @@ namespace MediaBrowser.Api.Playback.Hls
args += " -flags +loop-global_header -sc_threshold 0";
}
if (!EnableSplitTranscoding(state))
{
//args += " -copyts";
}
return args;
}
@ -870,21 +896,6 @@ namespace MediaBrowser.Api.Playback.Hls
var toTimeParam = 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)
{
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)
{
return !EnableSplitTranscoding(state);
}
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;
}
return true;
}
/// <summary>

@ -226,7 +226,9 @@
</EmbeddedResource>
</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>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

@ -248,8 +248,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
try
{
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
// .ConfigureAwait(false);
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@ -283,7 +282,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
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
{
@ -318,7 +317,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
process.BeginErrorReadLine();
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
await StartReadingOutput(process.StandardOutput.BaseStream, lines, cancellationToken).ConfigureAwait(false);
}
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
{
@ -354,14 +353,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
.Where(i => i.Length == 2)
.ToDictionary(i => i[0], i => i[1]);
string pktDts;
int frameMs;
if (values.TryGetValue("pkt_dts", out pktDts) && int.TryParse(pktDts, NumberStyles.Any, CultureInfo.InvariantCulture, out frameMs))
string flags;
if (values.TryGetValue("flags", out flags) && string.Equals(flags, "k", StringComparison.OrdinalIgnoreCase))
{
string keyFrame;
if (values.TryGetValue("key_frame", out keyFrame) && string.Equals(keyFrame, "1", 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))
{
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);
}
}
/// <summary>
/// The us culture
/// </summary>
@ -802,7 +801,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public ProcessWrapper(Process process, MediaEncoder mediaEncoder, ILogger logger)
{
Process = process;
this._mediaEncoder = mediaEncoder;
_mediaEncoder = mediaEncoder;
_logger = logger;
Process.Exited += Process_Exited;
}
@ -819,7 +818,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
catch (Exception ex)
{
_logger.ErrorException("Error determing process exit code", ex);
}
lock (_mediaEncoder._runningProcesses)

@ -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 System.Diagnostics;
@ -225,5 +227,8 @@ 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; }
}
}

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

@ -187,6 +187,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
private string[] _retriveItemColumns =
{
"type",
"data",
"IsOffline"
};
/// <summary>
/// Prepares the statements.
/// </summary>
@ -398,7 +405,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.ForcedSortName;
_saveItemCommand.GetParameter(index++).Value = item.IsOffline;
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@ -455,7 +462,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
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;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
@ -482,11 +489,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
return null;
}
BaseItem item;
using (var stream = reader.GetMemoryStream(1))
{
try
{
return _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem;
item = _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem;
if (item == null)
{
return null;
}
}
catch (SerializationException ex)
{
@ -494,6 +508,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
return null;
}
}
if (!reader.IsDBNull(2))
{
item.IsOffline = reader.GetBoolean(2);
}
return item;
}
/// <summary>
@ -685,7 +706,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
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;
@ -715,7 +736,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
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;
@ -745,7 +766,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
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);

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Persistence;
using System.Globalization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
@ -38,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
// 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 = {
@ -58,6 +59,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
AddBitDepthCommand();
AddIsAnamorphicColumn();
AddIsCabacColumn();
AddKeyFramesColumn();
AddRefFramesCommand();
PrepareStatements();
@ -187,6 +189,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
_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()
{
using (var cmd = _connection.CreateCommand())
@ -245,7 +278,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"BitDepth",
"IsAnamorphic",
"RefFrames",
"IsCabac"
"IsCabac",
"KeyFrames"
};
/// <summary>
@ -429,6 +463,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
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;
}
@ -498,6 +541,15 @@ 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.Transaction = transaction;
_saveStreamCommand.ExecuteNonQuery();
}

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

Loading…
Cancel
Save