私は先週、エンコーダとして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に送るのではないかと思います。私はビデオにはかなり新しいですし、ここで欠けている重要なことがあるように感じます。何かヒント?
これは問題です。わかりません。必要な情報を見つけるのが難しいです。私が言うことから、libavformatはあなたのためにRTPストリームに物を詰め込みます(そして、無効なパケットを送信しません - 私は試しました)。 RTSPネゴシエーションは行われません。最終的には、Fengなどの外部アプリケーションがクライアントへのRTSPストリーミングを処理するように指示されます。ただし、libavformatが生成しているRTPストリームの頭や尾を作ることができない理由は説明していません。 –
何とかそれを交渉する必要があります。ストリーム用のSDPファイルを作成しようとしないでください。 –
私はそれを行ったし、緑の画面を表示するVLCを得ることができます - それが正しいかどうかはわかりませんが、それはスタートです。今日はそれに取り組んでいるので、実際に問題があるかどうかを確認します。 –