123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- using FFmpeg.AutoGen;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using Vinno.FIS.TRTCClient.Common.Enum;
- using Vinno.vCloud.FIS.CrossPlatform.Common;
- using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
- using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
- using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface;
- using Vinno.vCloud.FIS.CrossPlatform.Windows.LiveVideo.RTC;
- namespace Vinno.vCloud.FIS.CrossPlatform.Windows.LiveVideo
- {
- public abstract unsafe class MergePusherBaseV2 : PusherBase, ILiveVideoPusherV2
- {
- private readonly ManualResetEvent _handlingImageEvent = new ManualResetEvent(true);
- private readonly Dictionary<EnumLiveChannelCategory, ICapturer> _captures;
- private readonly IMergeUtil _mergeUtil;
- private readonly FormatConvertUtil _convertUtil;
- private AVFrame* _srcFrame;
- private AVFrame* _destFrame;
- private CancellationTokenSource _tokenSource;
- protected bool IsTRTCMode;
- protected const int MergeWidth = 1920;
- protected const int MergeHeight = 1080;
- protected const int MergeFrameRate = 20;
- public event EventHandler<ChannelStateEventArgsV2> ChannelStateChanged;
- public MergePusherBaseV2()
- {
- _captures = new Dictionary<EnumLiveChannelCategory, ICapturer>();
- _mergeUtil = new RGBMergeUtilV2(MergeWidth, MergeHeight);
- _convertUtil = new FormatConvertUtil();
- }
- public virtual bool StartPusher(IExtendedData pushParams, IEnumerable<CPVideoDeviceOutputInfo> deviceInfos)
- {
- InitPushersAndMergeOffsets(pushParams, deviceInfos);
- StartCaptures();
- StartPostMergeImageDataThread();
- return true;
- }
- public virtual bool StopPusher()
- {
- StopPostMergeImageDataThread();
- StopCaptures();
- return true;
- }
- public abstract void SetMute(bool isMute);
- public abstract void SwitchMic(string micId);
- protected void InitCacheImage(AVPixelFormat destFormat)
- {
- _srcFrame = AvFrameOperateUtil.Create(MergeWidth, MergeHeight, AVPixelFormat.AV_PIX_FMT_BGRA);
- _destFrame = AvFrameOperateUtil.Create(MergeWidth, MergeHeight, destFormat);
- }
- protected virtual void DealWithFullBuffer(AVFrame* frame)
- {
- }
- protected void PushLiveStateChanged()
- {
- ChannelStateChanged?.Invoke(this, new ChannelStateEventArgsV2(EnumLiveChannelCategory.Main, EnumDeviceLiveState.Pushing));
- }
- private void InitPushersAndMergeOffsets(IExtendedData pushParams, IEnumerable<CPVideoDeviceOutputInfo> deviceInfos)
- {
- var areaImageInfos = new List<AreaImageInfo>();
- if (pushParams is RtcExtendedData rtcExtendedData)
- {
- foreach (var user in rtcExtendedData.UserInfos)
- {
- var deviceInfo = deviceInfos.FirstOrDefault(c => c.Category == user.Category);
- if (deviceInfo != null)
- {
- ICapturer capturer;
- if (!CommonParameter.Instance.IsSonopost && user.Category == EnumLiveChannelCategory.Main)
- {
- capturer = new TerminalImageCapturerV2(deviceInfo.VideoDeviceId, user.Width, user.Height, EnumImageType.ImageFrameData);
- }
- else if (!CommonParameter.Instance.IsSonopost && user.Category != EnumLiveChannelCategory.Main)
- {
- capturer = new Capturer(deviceInfo.VideoDeviceId, user.Width, user.Height, 15, user.Category, deviceInfo.OutputWidth, deviceInfo.OutputHeight, true);
- }
- else
- {
- capturer = new Capturer(deviceInfo.VideoDeviceId, user.Width, user.Height, 20, user.Category, deviceInfo.OutputWidth, deviceInfo.OutputHeight, false);
- }
- areaImageInfos.Add(new AreaImageInfo { Width = user.Width, Height = user.Height, Category = user.Category });
- _captures.Add(user.Category, capturer);
- }
- else
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"MergePusherBaseV2 Can not find {user.Category} Device Info!");
- }
- }
- }
- else if (pushParams is RtmpExtendedData rtmpExtendedData)
- {
- foreach (var user in rtmpExtendedData.UserInfos)
- {
- var deviceInfo = deviceInfos.FirstOrDefault(c => c.Category == user.Category);
- if (deviceInfo != null)
- {
- ICapturer capturer;
- if (!CommonParameter.Instance.IsSonopost && user.Category == EnumLiveChannelCategory.Main)
- {
- capturer = new TerminalImageCapturerV2(deviceInfo.VideoDeviceId, user.Width, user.Height, EnumImageType.ImageFrameData);
- }
- else if (!CommonParameter.Instance.IsSonopost && user.Category != EnumLiveChannelCategory.Main)
- {
- capturer = new Capturer(deviceInfo.VideoDeviceId, user.Width, user.Height, 15, user.Category, deviceInfo.OutputWidth, deviceInfo.OutputHeight, true);
- }
- else
- {
- capturer = new Capturer(deviceInfo.VideoDeviceId, user.Width, user.Height, 20, user.Category, deviceInfo.OutputWidth, deviceInfo.OutputHeight, false);
- }
- areaImageInfos.Add(new AreaImageInfo { Width = user.Width, Height = user.Height, Category = user.Category });
- _captures.Add(user.Category, capturer);
- }
- else
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"MergePusherBaseV2 Can not find {user.Category} Device Info!");
- }
- }
- }
- _mergeUtil.InitAreaOffset(areaImageInfos);
- }
- private void StartCaptures()
- {
- foreach (var capturer in _captures.Values)
- {
- capturer.ImageFrameReceived += OnImageReceived;
- capturer.StartCapture();
- }
- }
- private void StopCaptures()
- {
- foreach (var capture in _captures.Values)
- {
- capture.ImageFrameReceived -= OnImageReceived;
- capture.StopCapture();
- capture.Dispose();
- }
- _captures.Clear();
- }
- private unsafe void StartPostMergeImageDataThread()
- {
- if (_tokenSource != null && !_tokenSource.IsCancellationRequested)
- {
- _tokenSource.Cancel();
- }
- _tokenSource = new CancellationTokenSource();
- Task.Run(() =>
- {
- while (!_tokenSource.IsCancellationRequested)
- {
- try
- {
- _handlingImageEvent.Reset();
- _mergeUtil.GetFullBuffer(new IntPtr(_srcFrame->data[0]));
- _convertUtil.Convert(_srcFrame, _destFrame);
- DealWithFullBuffer(_destFrame);
- }
- catch (Exception e)
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"Get Full Buffer Error:{e}");
- }
- finally
- {
- _handlingImageEvent.Set();
- Thread.Sleep(35);
- }
- }
- _convertUtil.Dispose();
- }, _tokenSource.Token);
- }
- private void StopPostMergeImageDataThread()
- {
- _tokenSource?.Cancel();
- }
- private void OnImageReceived(object sender, ImageFrameData e)
- {
- try
- {
- if (sender is ICapturer capture)
- {
- var area = GetAreaAndCategory(capture.Id, out var category);
- _mergeUtil.CopyToArea(area, e);
- CopyPreviewData(category, e);
- }
- }
- catch (Exception ex)
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"OnImageReceived Error:{ex}");
- }
- }
- private EnumArea GetAreaAndCategory(string id, out EnumLiveChannelCategory category)
- {
- foreach (var item in _captures)
- {
- if (item.Value.Id == id)
- {
- category = item.Key;
- return GetArea(category);
- }
- }
- throw new Exception("Can not get correct area");
- }
- protected abstract EnumArea GetArea(EnumLiveChannelCategory category);
- public bool StartSpeedTest(uint appId, string userId, string userSign)
- {
- if (!IsTRTCMode)
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartSpeedTest Fail,it only support TRTC Modes");
- return false;
- }
- TRTCPusher pusher = null;
- try
- {
- pusher = new TRTCPusher();
- return pusher.StartSpeedTest(appId, userId, userSign);
- }
- catch (Exception ex)
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"Rtc Single PusherV2 StartSpeedTest Error:{ex}");
- return false;
- }
- finally
- {
- if (pusher != null)
- {
- pusher.StopSpeedTest();
- pusher = null;
- }
- }
- }
- public override void DoDispose()
- {
- _handlingImageEvent.WaitOne();
- AvFrameOperateUtil.Destory(_srcFrame);
- AvFrameOperateUtil.Destory(_destFrame);
- _mergeUtil?.Dispose();
- base.DoDispose();
- }
- }
- }
|