2012-04-13 8 views
10

私は先週、エンコーダとしてx264、ストリームをパックして送信するためにlibavformatを使用して、RTP上でH.264ストリーミングを実装しようと試みました。問題は、それが正しく動作していないと私が言うことができる限りです。libavformatを使用したRTP over H.264のストリーミング

今はランダムなデータ(x264_picture_alloc)をエンコードし、libx264からNALフレームを抽出しています。これは非常に簡単です:

x264_picture_t pic_out; 
x264_nal_t* nals; 
int num_nals; 
int frame_size = x264_encoder_encode(this->encoder, &nals, &num_nals, this->pic_in, &pic_out); 

if (frame_size <= 0) 
{ 
    return frame_size; 
} 

// push NALs into the queue 
for (int i = 0; i < num_nals; i++) 
{ 
    // create a NAL storage unit 
    NAL nal; 
    nal.size = nals[i].i_payload; 
    nal.payload = new uint8_t[nal.size]; 
    memcpy(nal.payload, nals[i].p_payload, nal.size); 

    // push the storage into the NAL queue 
    { 
     // lock and push the NAL to the queue 
     boost::mutex::scoped_lock lock(this->nal_lock); 
     this->nal_queue.push(nal); 
    } 
} 

nal_queueが安全に、その後のフレームを送信しますストリーマークラスにフレームにわたって渡すために使用されます。今はスレッド化されていません。これを動作させるために試してみるだけです。個々のフレームをエンコードする前に、エンコーダの初期化を確実にしました。

しかし、戻ってくるNALのフレームデータを見ることができるので、x264は問題ではないと思います。データをストリーミング は最初ストリーマークラスで初期化されてはlibavformat、で達成される:

Streamer::Streamer(Encoder* encoder, string rtp_address, int rtp_port, int width, int height, int fps, int bitrate) 
{ 
    this->encoder = encoder; 

    // initalize the AV context 
    this->ctx = avformat_alloc_context(); 
    if (!this->ctx) 
    { 
     throw runtime_error("Couldn't initalize AVFormat output context"); 
    } 

    // get the output format 
    this->fmt = av_guess_format("rtp", NULL, NULL); 
    if (!this->fmt) 
    { 
     throw runtime_error("Unsuitable output format"); 
    } 
    this->ctx->oformat = this->fmt; 

    // try to open the RTP stream 
    snprintf(this->ctx->filename, sizeof(this->ctx->filename), "rtp://%s:%d", rtp_address.c_str(), rtp_port); 
    if (url_fopen(&(this->ctx->pb), this->ctx->filename, URL_WRONLY) < 0) 
    { 
     throw runtime_error("Couldn't open RTP output stream"); 
    } 

    // add an H.264 stream 
    this->stream = av_new_stream(this->ctx, 1); 
    if (!this->stream) 
    { 
     throw runtime_error("Couldn't allocate H.264 stream"); 
    } 

    // initalize codec 
    AVCodecContext* c = this->stream->codec; 
    c->codec_id = CODEC_ID_H264; 
    c->codec_type = AVMEDIA_TYPE_VIDEO; 
    c->bit_rate = bitrate; 
    c->width = width; 
    c->height = height; 
    c->time_base.den = fps; 
    c->time_base.num = 1; 

    // write the header 
    av_write_header(this->ctx); 
} 

物事がうまくいかないように見える場所です。上記のav_write_headerは絶対に何もしていないようです。私はwiresharkを使ってこれを確認しました。参考までに、私はが以前にx264を扱うために使用されたEncoderオブジェクトへの参照であり、Streamerインスタンスを初期化するためにStreamer streamer(&enc, "10.89.6.3", 49990, 800, 600, 30, 40000);を使用します。 、私は、RTPデータがネットワーク上で表示されて見ることができます。この時点で

// grab a NAL 
NAL nal = this->encoder->nal_pop(); 
cout << "NAL popped with size " << nal.size << endl; 

// initalize a packet 
AVPacket p; 
av_init_packet(&p); 
p.data = nal.payload; 
p.size = nal.size; 
p.stream_index = this->stream->index; 

// send it out 
av_write_frame(this->ctx, &p); 

、それは私が送信されてきたフレームのようになります。私はNALをストリーミングするとき

は今、私はこれを使用しますたとえx264の著作権ブロブが少しでも含まれています。 しかし、、私が使ったプレイヤーはデータを理解できませんでした。 VLCはSDP記述を望んでいません(apparently isn't required)。

私はその後gst-launchを通してそれを再生しようとした:

gst-launch udpsrc port=49990 ! rtph264depay ! decodebin ! xvimagesink

これは、UDPデータを待って座っているだろうが、それを受信したときに、私が取得:

ERROR: element /GstPipeline:pipeline0/GstRtpH264Depay:rtph264depay0: No RTP format was negotiated. Additional debug info: gstbasertpdepayload.c(372): gst_base_rtp_depayload_chain(): /GstPipeline:pipeline0/GstRtpH264Depay:rtph264depay0: Input buffers need to have RTP caps set on them. This is usually achieved by setting the 'caps' property of the upstream source element (often udpsrc or appsrc), or by putting a capsfilter element before the depayloader and setting the 'caps' property on that. Also see http://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/gst/rtp/README

私は通りGStreamerを使用してストリームを作成するのではなく、RTPの大文字と小文字が何であるかはわかりません。しかし、それは私がストリームを記述するのに十分な情報をRTPに送るのではないかと思います。私はビデオにはかなり新しいですし、ここで欠けている重要なことがあるように感じます。何かヒント?

答えて

4

h264は、符号化規格です。ビデオデータが圧縮され、後でビデオストリームに解凍される形式で保存される方法を指定します。

RTPは伝送プロトコルです。これは、任意のエンコーダでエンコードされたオーディオビデオデータを伝送できるパケットの形式と順序を指定します。

GStreamerは、RTP procotolに準拠するデータを受信することを想定しています。 libaformatはGStreamerがすぐに読めるRTPパケットを生成すると期待していますか?たぶん、GStreamersは、適切なデコーダを使用してストリーミングされたパケットを受け取り、デコードできるようにする追加のストリーム記述を期待しているでしょうか?たぶん追加のRTSP交換またはSDPストリーム記述子ファイルが必要でしょうか?

エラーメッセージは、RTPフォーマットがネゴシエートされていないことを明確に示しています。 capsは、機能のための短い手です。受信機は、受信機/復号機を正しく設定する送信機の能力を知る必要がある。

RTPストリーム用のSDPファイルを少なくとも作成することを強くお勧めします。 libavformat should be able to do it for you

+0

これは問題です。わかりません。必要な情報を見つけるのが難しいです。私が言うことから、libavformatはあなたのためにRTPストリームに物を詰め込みます(そして、無効なパケットを送信しません - 私は試しました)。 RTSPネゴシエーションは行われません。最終的には、Fengなどの外部アプリケーションがクライアントへのRTSPストリーミングを処理するように指示されます。ただし、libavformatが生成しているRTPストリームの頭や尾を作ることができない理由は説明していません。 –

+0

何とかそれを交渉する必要があります。ストリーム用のSDPファイルを作成しようとしないでください。 –

+0

私はそれを行ったし、緑の画面を表示するVLCを得ることができます - それが正しいかどうかはわかりませんが、それはスタートです。今日はそれに取り組んでいるので、実際に問題があるかどうかを確認します。 –

関連する問題