Compare commits

...

No commits in common. "6f8d9b5fa66b6a7bec2df43031d808d73159b677" and "6e555569c0d91183b19402f28bdcbfc5ae25a5b2" have entirely different histories.

5 changed files with 116 additions and 35 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
/*.rar
/**.rar
/Build/client-push
/Logs
/obj

View File

@ -1,4 +1,7 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
@ -17,6 +20,7 @@ namespace ZC
public class RTMPPublisher : MonoBehaviour
{
Thread _thread;
private Timer _timer;
Process _process;
private RectInt _rectInt;
private RTMPConfig _config;
@ -30,12 +34,16 @@ namespace ZC
private volatile int _sendData;
private NativeArray<byte> _textureData;
private AsyncGPUReadbackRequest _asyncGPUReadbackRequest;
private bool _isRequesting;
private byte[] _bitmapArray;
private ConcurrentQueue<NativeArray<byte>> _textureDataPool;
private Queue<(AsyncGPUReadbackRequest, NativeArray<byte>)> _textureDatas;
private ConcurrentQueue<(AsyncGPUReadbackRequest, NativeArray<byte>)> _doneTextureDatas;
private int _targetTextureWidth;
private int _targetTextureHeight;
public void SetCamera(Camera camera)
{
@ -52,10 +60,40 @@ namespace ZC
return;
}
_textureDataPool = new ConcurrentQueue<NativeArray<byte>>();
_textureDatas = new Queue<(AsyncGPUReadbackRequest, NativeArray<byte>)>();
_doneTextureDatas = new ConcurrentQueue<(AsyncGPUReadbackRequest, NativeArray<byte>)>();
_config.Load();
_timer = new Timer(Tick, null, TimeSpan.FromMilliseconds(0), TimeSpan.FromMilliseconds(16));
Setup(Camera.main);
}
/// <summary>
/// 其他线程tick
/// </summary>
/// <param name="state"></param>
private void Tick(object state)
{
try
{
if (this._doneTextureDatas.TryDequeue(out var result))
{
var textureData = result.Item2;
Profiler.BeginSample("Conversion");
Bitmap.EncodeToBitmap(textureData, _bitmapArray, 0, textureData.Length, _targetTextureWidth, this._targetTextureHeight);
Profiler.EndSample();
Profiler.BeginSample("WriteBuffer");
_process.StandardInput.BaseStream.Write(_bitmapArray, 0, _bitmapArray.Length);
Profiler.EndSample();
_textureDataPool.Enqueue(result.Item2);
}
}
catch (Exception e)
{
UnityEngine.Debug.LogError(e.ToString());
}
}
private void CreateCaptureThread()
{
this._thread = new Thread(this.CreateThread);
@ -72,37 +110,59 @@ namespace ZC
{
if (_sendData != 0)
{
if (_camera)
if (_camera && !_isRequesting)
{
if (!_isRequesting || _asyncGPUReadbackRequest.done)
var cameraActiveTexture = _camera.targetTexture;
RenderTexture.active = cameraActiveTexture;
if (!_textureDataPool.TryDequeue(out var nativeArray))
{
var cameraActiveTexture = _camera.targetTexture;
RenderTexture.active = cameraActiveTexture;
_asyncGPUReadbackRequest = AsyncGPUReadback.RequestIntoNativeArray(ref _textureData, cameraActiveTexture, 0,
GraphicsFormat.B8G8R8_SRGB, ReadTextureCallback);
_isRequesting = true;
var targetTextureByteCount = this._camera.targetTexture.width * _camera.targetTexture.height * 3;
nativeArray = new NativeArray<byte>(targetTextureByteCount, Allocator.Persistent);
}
var asyncGPUReadbackRequest = AsyncGPUReadback.RequestIntoNativeArray(ref nativeArray, cameraActiveTexture, 0, GraphicsFormat.B8G8R8_SRGB, null);
_textureDatas.Enqueue((asyncGPUReadbackRequest, nativeArray));
}
if (_textureDatas.TryPeek(out var result))
{
if (result.Item1.done)
{
this._textureDatas.Dequeue();
if (result.Item1.hasError)
{
Debug.LogError("Request GPU DATA has error");
}
else
{
//放入多线程计算
this._doneTextureDatas.Enqueue(result);
}
}
}
}
}
private void ReadTextureCallback(AsyncGPUReadbackRequest obj)
{
if (obj is { done: true, hasError: false } && this._isRequesting)
{
Profiler.BeginSample("Conversion");
Bitmap.EncodeToBitmap(_textureData, _bitmapArray, 0, _textureData.Length, _output.width, _output.height);
// var encodeNativeArrayToJPG = ImageConversion.EncodeNativeArrayToJPG(this._textureData, GraphicsFormat.R8G8B8_UNorm, (uint)this._output.width, (uint)this._output.height);
Profiler.EndSample();
Profiler.BeginSample("WriteBuffer");
_process.StandardInput.BaseStream.Write(_bitmapArray, 0, _bitmapArray.Length);
Profiler.EndSample();
// encodeNativeArrayToJPG.Dispose();/
}
}
private void DisposeCaptureThread()
{
foreach (var textureData in this._textureDatas)
{
textureData.Item2.Dispose();
}
_textureDatas.Clear();
foreach (var doneTextureData in this._doneTextureDatas)
{
doneTextureData.Item2.Dispose();
}
_doneTextureDatas.Clear();
foreach (var nativeArray in this._textureDataPool)
{
nativeArray.Dispose();
}
if (_process != null && !this._process.HasExited)
{
GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, 0);
@ -130,11 +190,11 @@ namespace ZC
processStartInfo.Arguments =
$" -probesize 32 -thread_queue_size 5096 -fflags discardcorrupt -flags low_delay -analyzeduration 0 " +
$" -rtbufsize 100M -f dshow -i audio=\"virtual-audio-capturer\" " +
$" -f image2pipe -use_wallclock_as_timestamps 1 -i - " +
$" -f image2pipe -use_wallclock_as_timestamps 1 -r 60 -i - " +
$" -loglevel info " +
$" -map 0:a:0 -map 1:v:0 " +
$" -c:a aac -b:a 128k " +
$" -c:v:0 libx264 -g 1 -max_delay 0 -vf scale={this._config.resolution} -preset:v ultrafast -tune:v zerolatency -crf 10 -pix_fmt yuv420p -strict -2 " +
$" -c:a aac " +
$" -c:v:0 libx264 -g 1 -bf 0 -max_delay 0 -vf scale={this._config.resolution} -preset:v ultrafast -tune:v zerolatency -crf 10 -pix_fmt yuv420p -strict -2 " +
$" -f flv {this._config.server}{this._config.appName} -bf 0 ";
Debug.Log(processStartInfo.Arguments);
@ -166,28 +226,38 @@ namespace ZC
throw new NullReferenceException("camera is null");
if (!camera.targetTexture)
throw new Exception($"The camera[{camera}]'s targetTexture is null;");
_isRequesting = false;
_isRequesting = true;
SetCamera(camera);
_sendData = 0;
Object.Destroy(_output);
var targetTextureByteCount = camera.targetTexture.width * camera.targetTexture.height * 3;
this._targetTextureWidth = camera.targetTexture.width;
this._targetTextureHeight = camera.targetTexture.height;
var targetTextureByteCount = this._targetTextureWidth * this._targetTextureHeight * 3;
if (_bitmapArray == null || _bitmapArray.Length <
Bitmap.FileHeaderSize + Bitmap.ImageHeaderSize + targetTextureByteCount)
{
_bitmapArray = new byte[Bitmap.FileHeaderSize + Bitmap.ImageHeaderSize + targetTextureByteCount];
}
_output = new Texture2D(camera.targetTexture.width, camera.targetTexture.height);
_textureData.Dispose();
_textureData = new NativeArray<byte>(targetTextureByteCount, Allocator.Persistent);
_output = new Texture2D(this._targetTextureWidth, this._targetTextureHeight);
CreateCaptureThread();
StartCoroutine(this.Test());
}
IEnumerator Test()
{
yield return new WaitForSeconds(0.3f);
_isRequesting = false;
}
public void Dispose()
{
try
{
this._isRequesting = false;
this._isRequesting = true;
_sendData = 0;
_camera = null;
Object.Destroy(_output);

Binary file not shown.

View File

@ -102,3 +102,14 @@
2024/11/18 14:13:55 [notice] 27524#13420: sockinit() attempting to access sockapi
2024/11/18 14:13:55 [notice] 27524#13420: Access to sockapi succeded!
2024/11/18 14:13:55 [notice] 27524#13420: using sockapi from "4;80;"
2024/11/18 14:30:25 [notice] 12968#16444: Fatal: wait for sockapi failed
2024/11/18 14:30:28 [error] 27524#15664: *8 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 14:30:39 [notice] 30504#8424: Fatal: wait for sockapi failed
2024/11/18 14:31:04 [notice] 1792#18588: Fatal: wait for sockapi failed
2024/11/18 16:17:32 [error] 27524#15664: *42 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 16:19:00 [error] 27524#15664: *43 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 16:21:20 [error] 27524#15664: *44 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 16:24:23 [error] 27524#15664: *45 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 16:25:49 [error] 27524#15664: *46 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 16:27:59 [error] 27524#15664: *47 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935
2024/11/18 16:30:06 [error] 27524#15664: *48 live: already publishing, client: 127.0.0.1, server: 0.0.0.0:1935

View File

@ -1,2 +1,2 @@
cd client-pull
ffplay.exe rtmp://127.0.0.1:1935/live/test1 -fflags nobuffer -probesize 512 -analyzeduration 0 -flags low_delay -flags2 fast -fflags discardcorrupt
ffplay.exe rtmp://127.0.0.1:1935/live/test1 -fflags nobuffer -probesize 2048 -analyzeduration 0 -flags low_delay -flags2 fast -fflags discardcorrupt