123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- 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;
- namespace Vinno.vCloud.FIS.CrossPlatform.Windows.LiveVideo
- {
- public abstract unsafe class MergePusherBase : PusherBase, ILiveVideoPusherForSonopost
- {
- private readonly Dictionary<EnumLiveChannelCategory, ICapturer> _captures;
- private readonly IMergeUtil _mergeUtil;
- private readonly FormatConvertUtil _convertUtil;
- private readonly ManualResetEvent _handlingImageEvent = new ManualResetEvent(true);
- private CancellationTokenSource _tokenSource;
- private AVFrame* _srcFrame;
- private AVFrame* _destFrame;
- protected const int MergeWidth = 1920;
- protected const int MergeHeight = 1080;
- protected const int MergeFrameRate = 20;
- public event EventHandler<ChannelStateEventArgs> ChannelStateChanged;
- public MergePusherBase()
- {
- _captures = new Dictionary<EnumLiveChannelCategory, ICapturer>();
- _mergeUtil = new RGBMergeUtil(MergeWidth, MergeHeight);
- _convertUtil = new FormatConvertUtil();
- }
- public virtual bool StartPusher(IExtendedData pushParams, IEnumerable<CPVideoDeviceInfo> deviceInfos)
- {
- InitPushersAndMergeOffsets(pushParams, deviceInfos);
- StartCaptures();
- StartPostMergeImageDataThread();
- return true;
- }
- public abstract void SetMute(bool isMute);
- public virtual bool StopPusher()
- {
- StopPostMergeImageDataThread();
- StopCaptures();
- return true;
- }
- 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 ChannelStateEventArgs(EnumLiveChannelCategory.Main, EnumLiveStates.TerminalIsPushing));
- }
- private void InitPushersAndMergeOffsets(IExtendedData pushParams, IEnumerable<CPVideoDeviceInfo> 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)
- {
- var capturer = new Capturer(deviceInfo.Id, user.Width, user.Height, user.Category == EnumLiveChannelCategory.Main ? 20 : 15, user.Category, deviceInfo.Width, deviceInfo.Height, false);
- areaImageInfos.Add(new AreaImageInfo { Width = user.Width, Height = user.Height, Category = user.Category });
- _captures.Add(user.Category, capturer);
- }
- else
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"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)
- {
- var capturer = new Capturer(deviceInfo.Id, user.Width, user.Height, user.Category == EnumLiveChannelCategory.Main ? 20 : 15, user.Category, deviceInfo.Width, deviceInfo.Height, false);
- areaImageInfos.Add(new AreaImageInfo { Width = user.Width, Height = user.Height, Category = user.Category });
- _captures.Add(user.Category, capturer);
- }
- else
- {
- CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"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 override void DoDispose()
- {
- _handlingImageEvent.WaitOne();
- AvFrameOperateUtil.Destory(_srcFrame);
- AvFrameOperateUtil.Destory(_destFrame);
- _mergeUtil?.Dispose();
- base.DoDispose();
- }
- }
- }
|