Echtzeit-video-streaming in C#

Ich entwickle eine Anwendung für Echtzeit-streaming. Zwei Teile sind für das streaming.
Ich benutze eine capture-Karte zu erfassen einige der live-Quelle und müssen stream in Echtzeit.
und auch brauchen, um Strom eine lokale video-Datei.

Streamen Sie lokale video-Datei in Echtzeit nutze ich emgu cv zu erfassen den video-frame als Bitmap.
Um dies zu erreichen habe ich das erstellen der bitmap-Liste und ich speichern Sie die aufgezeichneten bitmap zu dieser Liste mit einem thread.
und auch ich, zeigen die Bilder in ein Bild-Feld. Bitmap-Liste speichern können, 1 Sekunde video. wenn die frame-rate ist
30 speichern 30 video-frames. Nach ausfüllen dieser Liste starte ich einen weiteren thread zu codieren, dass 1 Sekunde chunk
video.

Zur Kodierung Zweck benutze ich ffmpeg wrapper genannt nreco. Ich Schreibe, dass die video-frames, um ffmpeg
und starten Sie den ffmpeg zu codieren. Nach Beendigung dieser Aufgabe, die ich bekommen kann-codierte Daten als byte-array.

Dann bin ich mit dem senden von Daten über UDP-Protokoll, über LAN.

Diese funktioniert einwandfrei. Aber ich nicht erreichen kann, die smooth streaming. Ich erhielt stream über VLC-player gibt es einige Millisekunden Verzögerung zwischen Paketen und auch ich habe bemerkt, dass ein frame verloren.

private Capture _capture = null;
Image<Bgr, Byte> frame;

//Here I capture the frames and store them in a list
private void ProcessFrame(object sender, EventArgs arg)
{
     frame = _capture.QueryFrame();
     frameBmp = new Bitmap((int)frameWidth, (int)frameHeight, PixelFormat.Format24bppRgb);
     frameBmp = frame.ToBitmap(); 


 twoSecondVideoBitmapFramesForEncode.Add(frameBmp);
                        ////}
     if (twoSecondVideoBitmapFramesForEncode.Count == (int)FrameRate)
     {
         isInitiate = false;
         thread = new Thread(new ThreadStart(encodeTwoSecondVideo));
         thread.IsBackground = true;
         thread.Start();
     }  
 }

public void encodeTwoSecondVideo()
{
    List<Bitmap> copyOfTwoSecondVideo = new List<Bitmap>();
    copyOfTwoSecondVideo = twoSecondVideoBitmapFramesForEncode.ToList();
    twoSecondVideoBitmapFramesForEncode.Clear();

    int g = (int)FrameRate * 2;

    //create the ffmpeg task. these are the parameters i use for h264 encoding

        string outPutFrameSize = frameWidth.ToString() + "x" + frameHeight.ToString();
        //frame.ToBitmap().Save(msBit, frame.ToBitmap().RawFormat);
        ms = new MemoryStream();
        //Create video encoding task and set main parameters for the video encode

        ffMpegTask = ffmpegConverter.ConvertLiveMedia(
            Format.raw_video,
            ms,
            Format.h264,
            new ConvertSettings()
            {

                CustomInputArgs = " -pix_fmt bgr24 -video_size " + frameWidth + "x" + frameHeight + " -framerate " + FrameRate + " ", //windows bitmap pixel format
                CustomOutputArgs = " -threads 7 -preset ultrafast -profile:v baseline -level 3.0 -tune zerolatency -qp 0 -pix_fmt yuv420p -g " + g + " -keyint_min " + g + " -flags -global_header -sc_threshold 40 -qscale:v 1 -crf 25 -b:v 10000k -bufsize 20000k -s " + outPutFrameSize + " -r " + FrameRate + " -pass 1 -coder 1 -movflags frag_keyframe -movflags +faststart -c:a libfdk_aac -b:a 128k "
                //VideoFrameSize = FrameSize.hd1080,
                //VideoFrameRate = 30

            });

        ////////ffMpegTask.Start();
        ffMpegTask.Start();


      //I get the 2 second chunk video bitmap from the list and write to the ffmpeg 
  foreach (var item in copyOfTwoSecondVideo)
        {
            id++;
            byte[] buf = null;
            BitmapData bd = null;
            Bitmap frameBmp = null;

            Thread.Sleep((int)(1000.5 / FrameRate));

            bd = item.LockBits(new Rectangle(0, 0, item.Width, item.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            buf = new byte[bd.Stride * item.Height];
            Marshal.Copy(bd.Scan0, buf, 0, buf.Length);
            ffMpegTask.Write(buf, 0, buf.Length);
            item.UnlockBits(bd);
        }
   }

Dies ist der Prozess, den ich verwendet, um live-streaming. Aber der stream ist nicht glatt. Ich habe versucht, mit einer Warteschlange statt
der Liste zu reduzieren, die die Wartezeit zum füllen der Liste. Weil ich dachte, dass die Wartezeit passiert encoding-thread-Encodierung
und send 2-Sekunden-video sehr schnell. Aber wenn es fertig ist diese Codierung Prozess der bitmap-Liste nicht
komplett voll. Also encoding-thread zu stoppen, bis die nächsten 2-Sekunden-video ist fertig.

Wenn jemand mir helfen kann, dies herauszufinden, ist es sehr dankbar. Wenn der Weg, ich mache dies falsch ist, bitte korrigieren Sie mich.
Danke!!!

  • Ich bin mir nicht sicher, dass dies Ihr problem lösen, aber ich glaube nicht, dass es eine gute Idee, um eine neue zu erstellen Thread jedes mal in den code erfassen. Dies ist ein nicht benötigter Aufwand für die Erfassung routine. Es ist besser, erstellen Sie eine thread-sichere queue zwei-Sekunden-frames, Listen und verarbeiten Sie in einem separaten Arbeits-thread. Der Arbeits-thread ausgelöst werden kann, um die Bearbeitung zu starten, beispielsweise unter Verwendung von ManualResetEvent. Nach anfänglichen Frage ein Arbeits-thread genug sein. Ich würde auch erwägen, TPL, aber das ist nicht Gegenstand der Eingangsfrage.
InformationsquelleAutor Nuwan | 2014-07-19
Schreibe einen Kommentar