fix(flv): stop recording on unsupported codec

This commit is contained in:
genteure 2022-11-23 23:33:42 +08:00
parent 07a203d46d
commit 1e8bab25d6
7 changed files with 55 additions and 59 deletions

View File

@ -12,6 +12,7 @@ using BililiveRecorder.Core.ProcessingRules;
using BililiveRecorder.Core.Scripting; using BililiveRecorder.Core.Scripting;
using BililiveRecorder.Flv; using BililiveRecorder.Flv;
using BililiveRecorder.Flv.Amf; using BililiveRecorder.Flv.Amf;
using BililiveRecorder.Flv.Parser;
using BililiveRecorder.Flv.Pipeline; using BililiveRecorder.Flv.Pipeline;
using BililiveRecorder.Flv.Pipeline.Actions; using BililiveRecorder.Flv.Pipeline.Actions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -134,7 +135,7 @@ namespace BililiveRecorder.Core.Recording
if (bytesRead == 0) if (bytesRead == 0)
break; break;
writer.Advance(bytesRead); writer.Advance(bytesRead);
Interlocked.Add(ref this.ioNetworkDownloadedBytes, bytesRead); _ = Interlocked.Add(ref this.ioNetworkDownloadedBytes, bytesRead);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -194,6 +195,12 @@ namespace BililiveRecorder.Core.Recording
} }
} }
} }
catch (UnsupportedCodecException ex)
{
// 直播流不是 H.264
this.logger.Warning(ex, "不支持此直播流的视频编码格式(只支持 H.264),本场直播不再自动启动录制。");
this.room.StopRecord(); // 停止自动重试
}
catch (OperationCanceledException ex) catch (OperationCanceledException ex)
{ {
this.logger.Debug(ex, "录制被取消"); this.logger.Debug(ex, "录制被取消");
@ -260,7 +267,7 @@ namespace BililiveRecorder.Core.Recording
switch (this.room.RoomConfig.CuttingMode) switch (this.room.RoomConfig.CuttingMode)
{ {
case CuttingMode.ByTime: case CuttingMode.ByTime:
if (e.FileMaxTimestamp > this.room.RoomConfig.CuttingNumber * (60u * 1000u)) if (e.FileMaxTimestamp > this.room.RoomConfig.CuttingNumber * 60u * 1000u)
this.splitFileRule.SetSplitBeforeFlag(); this.splitFileRule.SetSplitBeforeFlag();
break; break;
case CuttingMode.BySize: case CuttingMode.BySize:
@ -290,7 +297,7 @@ namespace BililiveRecorder.Core.Recording
var paths = this.task.CreateFileName(); var paths = this.task.CreateFileName();
try try
{ Directory.CreateDirectory(Path.GetDirectoryName(paths.fullPath)); } { _ = Directory.CreateDirectory(Path.GetDirectoryName(paths.fullPath)); }
catch (Exception) { } catch (Exception) { }
this.last_path = paths.fullPath; this.last_path = paths.fullPath;
@ -307,7 +314,7 @@ namespace BililiveRecorder.Core.Recording
: Path.ChangeExtension(this.last_path, "txt"); : Path.ChangeExtension(this.last_path, "txt");
try try
{ Directory.CreateDirectory(Path.GetDirectoryName(path)); } { _ = Directory.CreateDirectory(Path.GetDirectoryName(path)); }
catch (Exception) { } catch (Exception) { }
var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read); var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read);

View File

@ -317,7 +317,7 @@ namespace BililiveRecorder.Core
} }
finally finally
{ {
this.recordRetryDelaySemaphoreSlim.Release(); _ = this.recordRetryDelaySemaphoreSlim.Release();
} }
// 如果状态是非直播中,跳过重试尝试。当状态切换到直播中时会开始新的录制任务。 // 如果状态是非直播中,跳过重试尝试。当状态切换到直播中时会开始新的录制任务。
@ -451,7 +451,7 @@ namespace BililiveRecorder.Core
{ {
const int MAX_ATTEMPT = 3; const int MAX_ATTEMPT = 3;
var attempt = 0; var attempt = 0;
retry: retry:
try try
{ {
var coverUrl = this.RawBilibiliApiJsonData?["room_info"]?["cover"]?.ToObject<string>(); var coverUrl = this.RawBilibiliApiJsonData?["room_info"]?["cover"]?.ToObject<string>();

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Runtime.Serialization; using System.Runtime.Serialization;
namespace BililiveRecorder.Flv.Parser namespace BililiveRecorder.Flv.Parser
@ -14,4 +14,28 @@ namespace BililiveRecorder.Flv.Parser
/// <inheritdoc/> /// <inheritdoc/>
protected FlvException(SerializationInfo info, StreamingContext context) : base(info, context) { } protected FlvException(SerializationInfo info, StreamingContext context) : base(info, context) { }
} }
public class UnknownFlvTagTypeException : FlvException
{
public UnknownFlvTagTypeException() { }
public UnknownFlvTagTypeException(string message) : base(message) { }
public UnknownFlvTagTypeException(string message, Exception innerException) : base(message, innerException) { }
protected UnknownFlvTagTypeException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class NotFlvFileException : FlvException
{
public NotFlvFileException() { }
public NotFlvFileException(string message) : base(message) { }
public NotFlvFileException(string message, Exception innerException) : base(message, innerException) { }
protected NotFlvFileException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
public class UnsupportedCodecException : FlvException
{
public UnsupportedCodecException() { }
public UnsupportedCodecException(string message) : base(message) { }
public UnsupportedCodecException(string message, Exception innerException) : base(message, innerException) { }
protected UnsupportedCodecException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
} }

View File

@ -227,7 +227,7 @@ namespace BililiveRecorder.Flv.Parser
if (tagBodyStream.Length > 2) if (tagBodyStream.Length > 2)
{ {
tagBodyStream.Seek(0, SeekOrigin.Begin); _ = tagBodyStream.Seek(0, SeekOrigin.Begin);
switch (tagType) switch (tagType)
{ {
case TagType.Audio: case TagType.Audio:
@ -243,8 +243,10 @@ namespace BililiveRecorder.Flv.Parser
case TagType.Video: case TagType.Video:
{ {
var frame = tagBodyStream.ReadByte(); var frame = tagBodyStream.ReadByte();
if ((frame & 0x0F) != 7) // AVC if ((frame & 0x0F) != 7) // AVC
break; throw new UnsupportedCodecException(string.Format("Unsupported Video Codec: {0}.", frame & 0x0F));
if (frame == 0x17) if (frame == 0x17)
tagFlag |= TagFlag.Keyframe; tagFlag |= TagFlag.Keyframe;
var packet = tagBodyStream.ReadByte(); var packet = tagBodyStream.ReadByte();
@ -272,7 +274,7 @@ namespace BililiveRecorder.Flv.Parser
}; };
// Read Tag Type Specific Data // Read Tag Type Specific Data
tagBodyStream.Seek(0, SeekOrigin.Begin); _ = tagBodyStream.Seek(0, SeekOrigin.Begin);
if (tag.Type == TagType.Script) if (tag.Type == TagType.Script)
{ {
@ -320,7 +322,7 @@ namespace BililiveRecorder.Flv.Parser
} }
finally finally
{ {
this.peekSemaphoreSlim.Release(); _ = this.peekSemaphoreSlim.Release();
} }
} }
@ -344,7 +346,7 @@ namespace BililiveRecorder.Flv.Parser
} }
finally finally
{ {
this.peekSemaphoreSlim.Release(); _ = this.peekSemaphoreSlim.Release();
} }
} }
} }

View File

@ -1,16 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace BililiveRecorder.Flv.Parser
{
public class NotFlvFileException : FlvException
{
public NotFlvFileException() { }
public NotFlvFileException(string message) : base(message) { }
public NotFlvFileException(string message, Exception innerException) : base(message, innerException) { }
protected NotFlvFileException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}

View File

@ -1,16 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace BililiveRecorder.Flv.Parser
{
public class UnknownFlvTagTypeException : FlvException
{
public UnknownFlvTagTypeException() { }
public UnknownFlvTagTypeException(string message) : base(message) { }
public UnknownFlvTagTypeException(string message, Exception innerException) : base(message, innerException) { }
protected UnknownFlvTagTypeException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}

View File

@ -81,8 +81,8 @@ namespace BililiveRecorder.Flv
if (this.BinaryData != null) if (this.BinaryData != null)
{ {
binaryData = provider?.CreateMemoryStream(nameof(Tag) + ":" + nameof(Clone)) ?? new MemoryStream(); binaryData = provider?.CreateMemoryStream(nameof(Tag) + ":" + nameof(Clone)) ?? new MemoryStream();
this.BinaryData.Seek(0, SeekOrigin.Begin); _ = this.BinaryData.Seek(0, SeekOrigin.Begin);
this.BinaryData.CopyToAsync(binaryData); _ = this.BinaryData.CopyToAsync(binaryData);
} }
ScriptTagBody? scriptData = null; ScriptTagBody? scriptData = null;
@ -90,7 +90,7 @@ namespace BililiveRecorder.Flv
{ {
using var stream = provider?.CreateMemoryStream(nameof(Tag) + ":" + nameof(Clone) + ":Temp") ?? new MemoryStream(); using var stream = provider?.CreateMemoryStream(nameof(Tag) + ":" + nameof(Clone) + ":Temp") ?? new MemoryStream();
this.ScriptData.WriteTo(stream); this.ScriptData.WriteTo(stream);
stream.Seek(0, SeekOrigin.Begin); _ = stream.Seek(0, SeekOrigin.Begin);
scriptData = ScriptTagBody.Parse(stream); scriptData = ScriptTagBody.Parse(stream);
} }
@ -126,7 +126,7 @@ namespace BililiveRecorder.Flv
var buffer = ArrayPool<byte>.Shared.Rent(5); var buffer = ArrayPool<byte>.Shared.Rent(5);
try try
{ {
binaryData.Read(buffer, 0, 5); _ = binaryData.Read(buffer, 0, 5);
extra.FirstBytes = BinaryConvertUtilities.ByteArrayToHexString(buffer, 0, 2); extra.FirstBytes = BinaryConvertUtilities.ByteArrayToHexString(buffer, 0, 2);
if (this.Type == TagType.Video) if (this.Type == TagType.Video)
@ -176,14 +176,9 @@ namespace BililiveRecorder.Flv
{ {
var bytesLeft = buffer.Length - nalu.StartPosition; var bytesLeft = buffer.Length - nalu.StartPosition;
if (bytesLeft >= nalu.FullSize) nalu.NaluHash = bytesLeft >= nalu.FullSize
{ ? BinaryConvertUtilities.ByteArrayToHexString(farmHash64.ComputeHash(buffer, nalu.StartPosition, (int)nalu.FullSize))
nalu.NaluHash = BinaryConvertUtilities.ByteArrayToHexString(farmHash64.ComputeHash(buffer, nalu.StartPosition, (int)nalu.FullSize)); : BinaryConvertUtilities.ByteArrayToHexString(farmHash64.ComputeHash(buffer, nalu.StartPosition, Math.Min(buffer.Length - nalu.StartPosition, (int)nalu.FullSize))) + "-PARTIAL";
}
else
{
nalu.NaluHash = BinaryConvertUtilities.ByteArrayToHexString(farmHash64.ComputeHash(buffer, nalu.StartPosition, Math.Min(buffer.Length - nalu.StartPosition, (int)nalu.FullSize))) + "-PARTIAL";
}
} }
} }
} }
@ -229,7 +224,7 @@ namespace BililiveRecorder.Flv
{ {
var val = lookup32[bytes[i]]; var val = lookup32[bytes[i]];
result[2 * i] = (char)val; result[2 * i] = (char)val;
result[2 * i + 1] = (char)(val >> 16); result[(2 * i) + 1] = (char)(val >> 16);
} }
return new string(result); return new string(result);
} }
@ -245,13 +240,13 @@ namespace BililiveRecorder.Flv
internal static string StreamToHexString(Stream stream) internal static string StreamToHexString(Stream stream)
{ {
var lookup32 = _lookup32; var lookup32 = _lookup32;
stream.Seek(0, SeekOrigin.Begin); _ = stream.Seek(0, SeekOrigin.Begin);
var result = new char[stream.Length * 2]; var result = new char[stream.Length * 2];
for (var i = 0; i < stream.Length; i++) for (var i = 0; i < stream.Length; i++)
{ {
var val = lookup32[stream.ReadByte()]; var val = lookup32[stream.ReadByte()];
result[2 * i] = (char)val; result[2 * i] = (char)val;
result[2 * i + 1] = (char)(val >> 16); result[(2 * i) + 1] = (char)(val >> 16);
} }
return new string(result); return new string(result);
} }