2016-01-11 13 views
16

現在、私はwebapiを使用してライブストリーミングを行っています。 ffmpegから直接flvストリームを受信し、それをPushStreamContentを使用してクライアントに直接送信することにより、ストリームが開始されたときにWebページがすでに開いている場合、これは完全にうまく動作します。問題は、別のページを開いたり、このページを更新したときにストリームが表示されなくなったことです(ストリームはまだクライアントに送信されています)。私はそれがストリームの開始から何かが欠けていることによると思うが、私は何をすべきか分からない。どんな指針も大変ありがとうございます。C#WebApiでのライブFLVストリーミング

コードストリームを受信し、クライアント

while (true) 
{ 
    bytes = new byte[8024000]; 
    int bytesRec = handler.Receive(bytes); 

    foreach (var subscriber in Startup.Subscribers.ToList()) 
    { 
     var theSubscriber = subscriber; 
     try 
     { 
      await theSubscriber.WriteAsync(bytes, 0, bytesRec); 
     } 
     catch 
     { 
      Startup.Subscribers.Remove(theSubscriber); 
     } 
    } 
} 

答えて

2

に行われた後、whileループを継続するタスクを使用する必要があるのawaitキーワード

theSubscriber.WriteAsync 

なしで実行を取得する必要があります密接

ほとんどのファイル形式は、特にビデオ形式、構造化されています。彼らは、フレーム(圧縮形式に応じて、すなわち、完全なまたは部分的なスクリーンショット)を含有します。

あなたが新しい加入者にストリーミングを開始するとき、特定のフレームを打つために管理する場合は、本当に幸運でなければなりません。したがって、ストリームの受信を開始すると、フレームが部分的であるため、フォーマットを識別できません。

あなたはwikipedia articleでより多くのFLVフレームを読み取ることができます。これはおそらくあなたの問題です。

簡単な試みは、第1の加入者が接続しているときに、ストリーミングサーバから受信した最初のヘッダを保存しようとするだろう。あなたは次の接続加入者にヘッダを送信することができます

static byte _header = new byte[9]; //signature, version, flags, headerSize 

public void YourStreamMethod() 
{ 
    int bytesRec = handler.Receive(bytes); 
    if (!_headerIsStored) 
    { 
     //store header 
     Buffer.BlockCopy(bytes, 0, _header, 0, 9); 
     _headerIsStored = true; 
    } 
} 

..::のような

何か一度行わ

private async Task WriteToStream(Stream arg1, HttpContent arg2, TransportContext arg3) 
{ 
    // send the FLV header 
    arg1.Write(_header, 0, 9); 

    Startup.AddSubscriber(arg1); 
    await Task.Yield(); 
} 

、受信機は部分的フレームを無視することを祈ります。そうでない場合は、ストリームを分析して次のフレームの場所を特定する必要があります。

  1. BytesLeftToNextFrame変数を作成します:あなたはこのような何かをする必要があることを行うには

  2. ストアバッファ
  3. で受信したパケットのヘッダint型
  4. に「ペイロードサイズ」ビットの変換では、ヘッダーを読み取る必要があり、次回までBytesLeftToNextFrame
  5. 解析された値へのカウントダウンをリセットします。

最後に、新しいクライアントが接続すると、次のフレームが到着することを知るまでストリーミングを開始しないでください。

擬似コード:

var bytesLeftToNextFrame = 0; 
while (true) 
{ 
    bytes = new byte[8024000]; 
    int bytesRec = handler.Receive(bytes); 

    foreach (var subscriber in Startup.Subscribers.ToList()) 
    { 
     var theSubscriber = subscriber; 
     try 
     { 
      if (subscriber.IsNew && bytesLeftToNextFrame < bytesRec) 
      { 
       //start from the index where the new frame starts 
       await theSubscriber.WriteAsync(bytes, bytesLeftToNextFrame, bytesRec - bytesLeftToNextFrame); 
       subscriber.IsNew = false; 
      } 
      else 
      { 
       //send everything, since we've already in streaming mode 
       await theSubscriber.WriteAsync(bytes, 0, bytesRec); 
      } 
     } 
     catch 
     { 
      Startup.Subscribers.Remove(theSubscriber); 
     } 
    } 

    //TODO: check if the current frame is done 
    // then parse the next header and reset the counter. 
} 
+0

は、シンプルなFLVメタデータリーダーを発見しました – jgauffin

1

に送信するためのストリーム

public class VideosController : ApiController 
{ 
    public HttpResponseMessage Get() 
    { 
     var response = Request.CreateResponse(); 
     response.Content = new PushStreamContent(WriteToStream, new MediaTypeHeaderValue("video/x-flv")); 

     return response; 
    } 

    private async Task WriteToStream(Stream arg1, HttpContent arg2, TransportContext arg3) 
    { 
     //I think metadata needs to be written here but not sure how 
     Startup.AddSubscriber(arg1); 
     await Task.Yield(); 
    } 
} 

コードを読んで、クライアントのために、私はストリーミングの専門家でないんだけど、あなたは、すべてのストリームを閉じる必要がありますように見えますデータは記録されます

await theSubscriber.WriteAsync(bytes, 0, bytesRec); 
{ 
    // After save we close the stream to signal that we are done writing. 
    xDoc.Save(stream); 
    stream.Close(); 
} 
+0

問題は、これがライブストリームであると私は新しい人々が –

-2

ITは、非同期プログラミングで

while (true) 
{ 

} 

を扱うとき、これはできるだけ速く自体をループ同期ループ、あるFUNDAMENTAL ERRORを示していますので、私は毎秒それが何千もを実行することができます。これCODEをLIKE回(空くのソフトウェアとハ​​ードウェアリソースに依存する)

await theSubscriber.WriteAsync(bytes, 0, bytesRec); 

のこれは別のスレッドで実行する非同期コマンド(それが十分明確ではなかった場合)(中ですループはメインスレッドの実行を表します)

今すぐ... whileループを非同期コマンドを使用して待機させるにはを待ちます ...いいですね(そうでなければwhileループは何千回も実行されますが、 )

を無数の非同期コマンドを実行しかし、加入者のループは()全ての加入者ためにストリームを送信する必要があるためsimulatanlyそれはRELOAD/NEW加入者が全体のことを凍結する理由であるのawaitキーワード

でstucked取得(新規接続=新規加入者)

結論:forループ全体がタスク内にある必要があります。タスクは、サーバがすべての加入者にストリームを送信するまで待つ必要があります。それだけでは、ContinueWithでwhileループを続ける必要があります(つまり、そのように呼び出されたのはなぜですか?)

so ...書き込みコマンドforeachループは、私はFLVや勉強のビデオフォーマットを使ったことがない、それが

+0

同期ループを接続したときのライブそれを維持したいのですか?あなたは何について話していますか?それはループです。期間。あなたがそれでやることは重要です。彼はループで 'await'を使うので、完全に有効です。 http://johndyer.name/flash-flv-meta-reader-in-net-c/: – jgauffin

関連する問題