Browse Source

修改flv的包装(目前已经可以正常播放视频)

tags/v1.1.0
smallchi 5 years ago
parent
commit
6c00fe7ef1
10 changed files with 138 additions and 44 deletions
  1. +1
    -0
      .gitignore
  2. +3
    -1
      doc/ffmpeginfo.txt
  3. +59
    -3
      src/JT1078.Flv.Test/FlvEncoderTest.cs
  4. BIN
      src/JT1078.Flv.Test/H264/JT1078_4.rar
  5. +2
    -2
      src/JT1078.Flv.Test/H264/index.html
  6. +4
    -0
      src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
  7. +50
    -35
      src/JT1078.Flv/FlvEncoder.cs
  8. +16
    -2
      src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs
  9. +2
    -0
      src/JT1078.Flv/Metadata/AvcVideoPacke.cs
  10. +1
    -1
      src/JT808.Protocol.Extensions.WebApiTest/Program.cs

+ 1
- 0
.gitignore View File

@@ -329,3 +329,4 @@ ASALocalRun/
# MFractors (Xamarin productivity tool) working folder # MFractors (Xamarin productivity tool) working folder
.mfractor/ .mfractor/
/src/JT1078.Flv.Test/H264/JT1078_3.txt /src/JT1078.Flv.Test/H264/JT1078_3.txt
/src/JT1078.Flv.Test/H264/JT1078_4.txt

+ 3
- 1
doc/ffmpeginfo.txt View File

@@ -1,3 +1,5 @@
ffmpeg -i demo.mp4 -c copy -f flv -vcodec h264 -acodec aac demo_flv.flv ffmpeg -i demo.mp4 -c copy -f flv -vcodec h264 -acodec aac demo_flv.flv


./ffmpeg -i JT1078_3.h264 -r 25 -c copy -f flv "D:\JT1078_3.flv"
./ffmpeg -i JT1078_3.h264 -r 25 -c copy -f flv "D:\JT1078_3.flv"

ffmpeg -f dshow -i video="USB2.0 PC CAMERA" -t 60 -c copy -f h264 -vcodec h264 jt1078.264

+ 59
- 3
src/JT1078.Flv.Test/FlvEncoderTest.cs View File

@@ -112,9 +112,9 @@ namespace JT1078.Flv.Test
{ {
File.Delete(filepath); File.Delete(filepath);
} }
JT1078Package Package = null; JT1078Package Package = null;
foreach (var line in lines) foreach (var line in lines)
{ {
var data = line.Split(','); var data = line.Split(',');
@@ -124,7 +124,7 @@ namespace JT1078.Flv.Test
if (Package != null) if (Package != null)
{ {
var tmp = decoder.ParseNALU(Package); var tmp = decoder.ParseNALU(Package);
if(tmp!=null && tmp.Count > 0)
if (tmp != null && tmp.Count > 0)
{ {
h264NALULs = h264NALULs.Concat(tmp).ToList(); h264NALULs = h264NALULs.Concat(tmp).ToList();
} }
@@ -144,7 +144,63 @@ namespace JT1078.Flv.Test
} }
catch (Exception ex) catch (Exception ex)
{ {
Assert.Throws<Exception>(()=> { });
}
finally
{
fileStream?.Close();
fileStream?.Dispose();
}
}

[Fact]
public void FlvEncoder_Test_4()
{
FileStream fileStream = null;
Flv.H264.H264Decoder decoder = new Flv.H264.H264Decoder();
List<H264NALU> h264NALULs = new List<H264NALU>();
FlvEncoder encoder = new FlvEncoder();
try
{
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_4.flv");
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_4.txt"));
if (File.Exists(filepath))
{
File.Delete(filepath);
}

JT1078Package Package = null;

foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
Package = JT1078Serializer.Merge(package);
if (Package != null)
{
var tmp = decoder.ParseNALU(Package);
if (tmp != null && tmp.Count > 0)
{
h264NALULs = h264NALULs.Concat(tmp).ToList();
}
}
}


fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
var totalPage = (h264NALULs.Count + 10 - 1) / 10;
for (var i = 0; i < totalPage; i++)
{
var flv2 = encoder.CreateFlvFrame(h264NALULs.Skip(i * 10).Take(10).ToList());
if (flv2.Length != 0)
{
fileStream.Write(flv2);
}
}
}
catch (Exception ex)
{
Assert.Throws<Exception>(() => { });
} }
finally finally
{ {


BIN
src/JT1078.Flv.Test/H264/JT1078_4.rar View File


+ 2
- 2
src/JT1078.Flv.Test/H264/index.html View File

@@ -15,7 +15,7 @@
var player = document.getElementById('player'); var player = document.getElementById('player');
var flvPlayer = flvjs.createPlayer({ var flvPlayer = flvjs.createPlayer({
type: 'flv', type: 'flv',
url: "jt1078_1.flv"
url: "jt1078_3.flv"
}); });
flvPlayer.attachMediaElement(player); flvPlayer.attachMediaElement(player);
flvPlayer.load(); flvPlayer.load();
@@ -24,7 +24,7 @@
var player2 = document.getElementById('player2'); var player2 = document.getElementById('player2');
var flvPlayer2 = flvjs.createPlayer({ var flvPlayer2 = flvjs.createPlayer({
type: 'flv', type: 'flv',
url: "jt1078_3.flv"
url: "jt1078_4.flv"
}); });
flvPlayer2.attachMediaElement(player2); flvPlayer2.attachMediaElement(player2);
flvPlayer2.load(); flvPlayer2.load();


+ 4
- 0
src/JT1078.Flv.Test/JT1078.Flv.Test.csproj View File

@@ -6,6 +6,7 @@


<ItemGroup> <ItemGroup>
<None Remove="H264\JT1078_3.rar" /> <None Remove="H264\JT1078_3.rar" />
<None Remove="H264\JT1078_4.rar" />
</ItemGroup> </ItemGroup>


<ItemGroup> <ItemGroup>
@@ -35,6 +36,9 @@
<None Update="H264\JT1078_3.txt"> <None Update="H264\JT1078_3.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="H264\JT1078_4.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>


</Project> </Project>

+ 50
- 35
src/JT1078.Flv/FlvEncoder.cs View File

@@ -13,7 +13,7 @@ namespace JT1078.Flv
{ {
public class FlvEncoder public class FlvEncoder
{ {
private static readonly byte[] VideoFlvHeaderBuffer;
private static readonly byte[] VideoFlvHeaderBuffer;
private const uint PreviousTagSizeFixedLength = 4; private const uint PreviousTagSizeFixedLength = 4;
private static readonly ConcurrentDictionary<string, uint> PreviousTagSizeDict; private static readonly ConcurrentDictionary<string, uint> PreviousTagSizeDict;
private static readonly ConcurrentDictionary<string, bool> FrameInitDict; private static readonly ConcurrentDictionary<string, bool> FrameInitDict;
@@ -78,7 +78,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer); FlvArrayPool.Return(buffer);
} }
} }
private void CreateScriptTagFrame(ref FlvMessagePackWriter flvMessagePackWriter,int width,int height)
private void CreateScriptTagFrame(ref FlvMessagePackWriter flvMessagePackWriter, int width, int height,double frameRate = 25d)
{ {
//flv body PreviousTagSize awalys 0 //flv body PreviousTagSize awalys 0
flvMessagePackWriter.WriteUInt32(0); flvMessagePackWriter.WriteUInt32(0);
@@ -106,7 +106,7 @@ namespace JT1078.Flv
}); });
flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_FrameRate flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_FrameRate
{ {
Value = 25d
Value = frameRate
}); });
flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Width flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Width
{ {
@@ -118,7 +118,7 @@ namespace JT1078.Flv
}); });
flvMessagePackWriter.WriteFlvTag(flvTags); flvMessagePackWriter.WriteFlvTag(flvTags);
} }
private void CreateVideoTag0Frame(ref FlvMessagePackWriter flvMessagePackWriter, uint previousTagSize,AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord)
private void CreateVideoTag0Frame(ref FlvMessagePackWriter flvMessagePackWriter, uint previousTagSize, AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord)
{ {
//flv body PreviousTagSize ScriptTag //flv body PreviousTagSize ScriptTag
flvMessagePackWriter.WriteUInt32(previousTagSize); flvMessagePackWriter.WriteUInt32(previousTagSize);
@@ -138,7 +138,10 @@ namespace JT1078.Flv
flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord; flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord;
flvMessagePackWriter.WriteFlvTag(flvTags); flvMessagePackWriter.WriteFlvTag(flvTags);
} }
private void CreateVideoTagOtherFrame(ref FlvMessagePackWriter flvMessagePackWriter, uint previousTagSize, H264NALU nALU)

public static uint LastFrameInterval = 0;

private void CreateVideoTagOtherFrame(ref FlvMessagePackWriter flvMessagePackWriter, uint previousTagSize, H264NALU nALU, H264NALU sps, H264NALU pps,H264NALU sei)
{ {
//flv body PreviousTagSize //flv body PreviousTagSize
flvMessagePackWriter.WriteUInt32(previousTagSize); flvMessagePackWriter.WriteUInt32(previousTagSize);
@@ -146,26 +149,48 @@ namespace JT1078.Flv
//flv body tag header //flv body tag header
FlvTags flvTags = new FlvTags(); FlvTags flvTags = new FlvTags();
flvTags.Type = TagType.Video; flvTags.Type = TagType.Video;
flvTags.Timestamp = nALU.LastIFrameInterval;
flvTags.TimestampExt = 0; flvTags.TimestampExt = 0;
flvTags.StreamId = 0; flvTags.StreamId = 0;
//flv body tag body //flv body tag body
flvTags.VideoTagsData = new VideoTags(); flvTags.VideoTagsData = new VideoTags();
flvTags.VideoTagsData.VideoData = new AvcVideoPacke();
flvTags.VideoTagsData.VideoData.CompositionTime = 0;
flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw;
flvTags.VideoTagsData.VideoData.MultiData = new List<byte[]>();
LastFrameInterval += nALU.LastFrameInterval;
flvTags.Timestamp = LastFrameInterval;

if (nALU.NALUHeader.NalUnitType == 5) if (nALU.NALUHeader.NalUnitType == 5)
{ {
flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; flvTags.VideoTagsData.FrameType = FrameType.KeyFrame;
if (sps!=null && pps != null)
{
//flvTags.VideoTagsData.VideoData.MultiData.Add(sps.RawData);
//flvTags.VideoTagsData.VideoData.MultiData.Add(pps.RawData);
flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData);
}
else
{
//if (sei != null)
//{
// flvTags.VideoTagsData.VideoData.MultiData.Add(sei.RawData);
//}
flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData);
}
} }
else else
{ {
flvTags.VideoTagsData.FrameType = FrameType.InterFrame; flvTags.VideoTagsData.FrameType = FrameType.InterFrame;
//if (sei != null)
//{
// flvTags.VideoTagsData.VideoData.MultiData.Add(sei.RawData);
//}
flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData);
} }
flvTags.VideoTagsData.VideoData = new AvcVideoPacke();
flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw;
flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastIFrameInterval;
flvTags.VideoTagsData.VideoData.Data = nALU.RawData;
flvMessagePackWriter.WriteFlvTag(flvTags); flvMessagePackWriter.WriteFlvTag(flvTags);
} }
public byte[] CreateFlvFrame(List<H264NALU> nALUs, int minimumLength = 10240)
public byte[] CreateFlvFrame(List<H264NALU> nALUs, int minimumLength = 65535)
{ {
byte[] buffer = FlvArrayPool.Rent(minimumLength); byte[] buffer = FlvArrayPool.Rent(minimumLength);
try try
@@ -173,39 +198,29 @@ namespace JT1078.Flv
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
int currentMarkPosition = 0; int currentMarkPosition = 0;
int nextMarkPosition = 0; int nextMarkPosition = 0;
H264NALU? sps=null, pps=null;
foreach (var naln in nALUs)
H264NALU sps = nALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 7);
H264NALU pps = nALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 8);
H264NALU sei = nALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 6);
if (sps!=null && pps != null)
{ {
string key = naln.GetKey();
if(!FrameInitDict.ContainsKey(key))
string key = sps.GetKey();
if (!FrameInitDict.ContainsKey(key))
{ {
if (naln.NALUHeader.NalUnitType == 7)
{
naln.RawData = H264Decoder.DiscardEmulationPreventionBytes(naln.RawData);
sps = naln;
}
else if (naln.NALUHeader.NalUnitType == 8)
{
pps = naln;
}
if (sps != null && pps != null)
{
flvMessagePackWriter.WriteArray(CreateFlvFirstFrame(sps, pps));
FrameInitDict.TryAdd(key, true);
}
else
{
continue;
}
flvMessagePackWriter.WriteArray(CreateFlvFirstFrame(sps, pps));
FrameInitDict.TryAdd(key, true);
} }
}
foreach (var naln in nALUs.Where(w=> w.NALUHeader.NalUnitType != 7 && w.NALUHeader.NalUnitType != 8 && w.NALUHeader.NalUnitType != 6))
{
string key = naln.GetKey();
if (PreviousTagSizeDict.TryGetValue(key, out uint previousTagSize)) if (PreviousTagSizeDict.TryGetValue(key, out uint previousTagSize))
{ {
currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); currentMarkPosition = flvMessagePackWriter.GetCurrentPosition();
CreateVideoTagOtherFrame(ref flvMessagePackWriter, previousTagSize, naln);
CreateVideoTagOtherFrame(ref flvMessagePackWriter, previousTagSize, naln,sps, pps, sei);
nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); nextMarkPosition = flvMessagePackWriter.GetCurrentPosition();
uint tmpPreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); uint tmpPreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength);
PreviousTagSizeDict.TryUpdate(key, tmpPreviousTagSize, previousTagSize); PreviousTagSizeDict.TryUpdate(key, tmpPreviousTagSize, previousTagSize);
}
}
} }
return flvMessagePackWriter.FlushAndGetArray(); return flvMessagePackWriter.FlushAndGetArray();
} }


+ 16
- 2
src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs View File

@@ -87,8 +87,22 @@ namespace JT1078.Flv.MessagePack
WriteUInt24(videoPacke.CompositionTime); WriteUInt24(videoPacke.CompositionTime);
//One or more NALUs //One or more NALUs
//WriteArray(new byte[] {0,0,0,1}); //WriteArray(new byte[] {0,0,0,1});
WriteInt32(videoPacke.Data.Length);
WriteArray(videoPacke.Data);
if (videoPacke.MultiData != null)
{
foreach(var item in videoPacke.MultiData)
{
if (item != null && item.Length > 0)
{
WriteInt32(item.Length);
WriteArray(item);
}
}
}
if (videoPacke.Data != null && videoPacke.Data.Length>0)
{
WriteInt32(videoPacke.Data.Length);
WriteArray(videoPacke.Data);
}
} }
else else
{ {


+ 2
- 0
src/JT1078.Flv/Metadata/AvcVideoPacke.cs View File

@@ -14,5 +14,7 @@ namespace JT1078.Flv.Metadata
public AVCDecoderConfigurationRecord AVCDecoderConfiguration { get; set; } public AVCDecoderConfigurationRecord AVCDecoderConfiguration { get; set; }


public byte[] Data { get; set; } public byte[] Data { get; set; }

public List<byte[]> MultiData { get; set; }
} }
} }

+ 1
- 1
src/JT808.Protocol.Extensions.WebApiTest/Program.cs View File

@@ -25,7 +25,7 @@ namespace JT808.Protocol.Extensions.WebApiTest
{ {
c.HttpHost = new Uri("http://localhost:12828/jt808api/"); c.HttpHost = new Uri("http://localhost:12828/jt808api/");
c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff"; c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
//c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
}); });


IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider(); IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();


Loading…
Cancel
Save