2024年8月13日 星期二

C# 利用ffmpeg將WebCAM影像Streaming to RTSP server

Purpose:
利用C#架構一個RTSP 影像streaming的環境.包含WebCAM控制, FFMpeg使用 and Emgu.CV的應用 
Fundamental:
RTSP
即時串流協定(Real Time Streaming Protocol,RTSP)是一種網路應用協定,專為娛樂和通訊系統的使用,以控制串流媒體伺服器。該協定用於建立和控制終端之間的媒體對談。媒體伺服器的客戶端發布VCR命令,例如播放,錄製和暫停,以便於即時控制從伺服器到客戶端(影片點播)或從客戶端到伺服器(語音錄音)的媒體流。
FFmpeg
FFmpeg 是一個開放原始碼的自由軟體,它包含了音訊和視訊多種格式的錄影、轉檔、串流功能,同時也是一個音訊與視訊格式轉換函式庫(Library),許多開源的工具都是基於 FFmpeg 打造的。

Reference:
感謝分享:包含 RTSP windows server 和一些相關軟體介紹與下載!!
public void StartRTSP(string path)
    {
       
        if (_RTSPPara._process != null && !_RTSPPara._process.HasExited)
            return;

        _RTSPPara._process = new Process();
        _RTSPPara._process.StartInfo.UseShellExecute = false;
        _RTSPPara._process.StartInfo.FileName = @path;
        _RTSPPara._process.StartInfo.Arguments = "";
        _RTSPPara._process.StartInfo.RedirectStandardInput = true;
        _RTSPPara._process.StartInfo.RedirectStandardOutput = true;
        _RTSPPara._process.StartInfo.RedirectStandardError = true;
        _RTSPPara._process.EnableRaisingEvents = true;
        _RTSPPara._process.StartInfo.CreateNoWindow = true;
        try
        {
            var started = _RTSPPara._process.Start();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
        }

        _RTSPPara._process.BeginErrorReadLine();
        _RTSPPara._process.BeginOutputReadLine();
    }


public void StartFFmpeg(string path, string webname)
    {
        string rtspServer = "rtsp://localhost:8554/test";
        string ffmpegCommand =
                $"-f dshow -i video=\"{webname}\" -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -rtsp_transport tcp -f rtsp {rtspServer}";
        if (_FFmpegPara._process != null && !_FFmpegPara._process.HasExited)
            return;

        _FFmpegPara._process = new Process();
        _FFmpegPara._process.StartInfo.UseShellExecute = false;
        _FFmpegPara._process.StartInfo.FileName = @path;
        _FFmpegPara._process.StartInfo.Arguments = ffmpegCommand;
        _FFmpegPara._process.StartInfo.RedirectStandardInput = true;
        _FFmpegPara._process.StartInfo.RedirectStandardOutput = true;
        _FFmpegPara._process.StartInfo.RedirectStandardError = true;
        _FFmpegPara._process.EnableRaisingEvents = true;
        _FFmpegPara._process.StartInfo.CreateNoWindow = true;
        _FFmpegPara._process.StartInfo.Verb = "RunAs";
        try
        {
            var started = _FFmpegPara._process.Start();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
        }

        _FFmpegPara._process.BeginErrorReadLine();
        _FFmpegPara._process.BeginOutputReadLine();
    }

        private void button7_Click(object sender, EventArgs e)
        {

            if (FFmpeg._FFmpegPara.RunisFinish == true)
            {
                //button5.BackColor = Color.AliceBlue;
                button7.BackColor = Color.Green;
                WebCAM[0].show_screen = true;
                myVideoCapture = new VideoCapture("rtsp://127.0.0.1:8554/test");
                myVideoCapture.ImageGrabbed += imageGrabbedEvent;
                myVideoCapture.Start();
            }
            else if (WebCAM[0].run == true)
            {
                //button5.BackColor = Color.Green;
                button7.BackColor = Color.AliceBlue;
                if (myVideoCapture != null)
                {
                    myVideoCapture.ImageGrabbed -= imageGrabbedEvent;
                    Thread.Sleep(500);
                    myVideoCapture.Dispose();
                }

            }
        }

        public void imageGrabbedEvent(object sender, EventArgs arg)
        {
            try
            {
                TEmgu._EmguPara.ImageSource = myVideoCapture.QueryFrame().ToImage<Bgr, byte>();
            }
            catch (Exception Ex)
            {

            }
            if (TEmgu._EmguPara.ImageSource != null)
            {

                imageBox1.Image = TEmgu._EmguPara.ImageSource.Resize(imageBox1.Width, imageBox1.Height, Emgu.CV.CvEnum.Inter.Linear);

            } //----if (TEmgu._EmguPara.ImageSource != null)
           

        }

2024年7月10日 星期三

c# 如何檢測目錄檔案有變動

Purpose:
在一個測試系統中, 有時候會在特定的目錄中存放測試中的測試資料. 所以便可以在測試時去偵測特定目錄中是否有資料檔案產再去做資料的分析!
Method:

        DirectoryInfo dirInfo;
        FileSystemWatcher watcher = new FileSystemWatcher();
        private void button24_Click(object sender, EventArgs e)
        {
            button24.BackColor = Color.Green;
            button24.Enabled = false;

            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            folderDialog.SelectedPath = FileCtrl.CANFilePath;
            folderDialog.Description = "Select an listen Folder";

            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                string selectedPath = folderDialog.SelectedPath;
                dirInfo = new DirectoryInfo(selectedPath);
                string[] files = Directory.GetFiles(selectedPath);
                //設定所要監控的資料夾
                watcher.Path = selectedPath;
                CommonData.WriteMessage(DateTime.Now.ToString("yyyyMMdd_hhmmss_ffff") + " -- ", "選擇監聽目錄檔案於:" + watcher.Path, Color.Blue, Color.Green);
            }

            //FileSystemWatcher watcher = new FileSystemWatcher(@"C:\path\to\folder");

            watcher.NotifyFilter = NotifyFilters.Attributes
                                 | NotifyFilters.CreationTime
                                 | NotifyFilters.DirectoryName
                                 | NotifyFilters.FileName
                                 | NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.Security
                                 | NotifyFilters.Size;

            //watcher.Changed += OnChanged;
            watcher.Created += OnCreated;
            //watcher.Deleted += OnDeleted;
            //watcher.Renamed += OnRenamed;
            //watcher.Error += OnError;

            if (comboBox_carmodel.Text == "PeakCAN_csv")
            {
                CommonData.Auto_Detect_Mode = 0;
                watcher.Filter = "*.csv";
            }
            else if (comboBox_carmodel.Text == "CANoe_asc")
            {
                CommonData.Auto_Detect_Mode = 1;
                watcher.Filter = "*.asc";
            }
           
            watcher.IncludeSubdirectories = true;
            watcher.EnableRaisingEvents = true;
            button24.BackColor = Color.PeachPuff;
            button24.Enabled = true;
        }

private void OnCreated(object sender, FileSystemEventArgs e)
        {
            dirInfo = new DirectoryInfo(e.FullPath.ToString());
            CommonData.FilterFlag = true;
            Thread.Sleep(100);
            CommonData.WriteMessage(DateTime.Now.ToString("yyyyMMdd_hhmmss_ffff") + " -- ", "新建檔案於:" + dirInfo.FullName.Replace(dirInfo.Name, ""), Color.Blue, Color.Green);
            CommonData.WriteMessage(DateTime.Now.ToString("yyyyMMdd_hhmmss_ffff") + " -- ", "新建檔案名稱:" + dirInfo.Name, Color.Blue, Color.Green);
            CommonData.WriteMessage(DateTime.Now.ToString("yyyyMMdd_hhmmss_ffff") + " -- ", "建立時間:" + dirInfo.CreationTime.ToString(), Color.Blue, Color.Green);
            CommonData.WriteMessage(DateTime.Now.ToString("yyyyMMdd_hhmmss_ffff") + " -- ", "目錄下共有:" + dirInfo.Parent.GetFiles().Count() + " 檔案", Color.Blue, Color.Green);
            CommonData.WriteMessage(DateTime.Now.ToString("yyyyMMdd_hhmmss_ffff") + " -- ", "目錄下共有:" + dirInfo.Parent.GetDirectories().Count() + " 資料夾", Color.Blue, Color.Green);

        }

2024年7月9日 星期二

C# 讀取超大檔案方式

Purpose:
在專案中, 有一需求是去搜尋一些500MB個別檔案重複資料, 嘗試了很多讀取檔案的方式. 最後試出來最快的方法.
Method:
using System.IO;

string strLine;
const int MAX_BUFFER = 33554432; //32MB 
using (FileStream fs = File.Open(csvFile, FileMode.Open, FileAccess.Read))
using (BufferedStream bs = new BufferedStream(fs, MAX_BUFFER)
using (StreamReader sr = new StreamReader(bs))
{  
    while (!sr.EndOfStream)
   {
        while ((strLine = sr.ReadLine()) != null)
       {
               //---處理資料
        }

    }
    sr.Close();
    sr.Dispose();
}

希望對你們有幫助!!

2024年7月1日 星期一

CAN Bus Sniffer by PeakCAN windows software GUI

Purpose:
經由這篇文章PeakCAN windows software for CAN Bus message後, 再次利用PeakCAN的 PCANBasic API for C#的sample修改為自己的CAN Bus Sniffer擷取在CAN BUS介面上的資料!
特點
1. 增加monitor功能 
所有的CAN Bus上的資料 Tx and Rx 都可以即時監控.
2. 增加可同時多個Tx 傳送的CAN Bus資料依據個別定義的時序傳送
After reading this article PeakCAN windows software for CAN Bus message, I once again used the sample of PeakCAN's PCANBasic API for C# to modify it into my own CAN Bus Sniffer to capture the data on the CAN BUS interface!
Features
1. Add monitor function
All data Tx and Rx on the CAN Bus can be monitored in real time.
2. Added CAN Bus data that can be transmitted by multiple Tx at the same time according to individually defined timings.
利用自己製作的ESP32 CAN module搭配CAN Hacker software去做驗證!

YouTubeDemo: