OpenCV VideoCaptureでビデオフレームをキャプチャしています。このようなフレームを使用できるため、キャプチャは正常に機能します。
cv::VideoCapture cap("v4l2src device=/dev/video1 ! videoscale ! videorate ! video/x-raw, width=640, height=360, framerate=30/1 ! videoconvert ! appsink");
cv::imshow("feed", frame);
また、ネットワークを介してストリームを送信したいのですが、ここで行き詰まっています。どういうわけか、私はappsrcパイプライン部分で失敗しています。ストリームをjpegにエンコードし、それをvie udpで送信したい。これは私が得たものです:
cv::VideoWriter writer
writer.open("appsrc ! videoconvert ! jpegenc ! jpegparse ! rtpjpegpay pt=96 ! udpsink Host=192.168.1.25 port=5000", 0, (double)30, cv::Size(640, 360), true);
上記の行は何もしないようです。 writer << frame
は何もしません。また、このgstreamerコマンドは何も表示しません。
gst-launch-1.0 udpsrc port=5000 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG, payload=(int)96" ! rtpjpegdepay ! jpegdec ! decodebin ! videoconvert ! autovideosink
writer.open
部分のどこで失敗しているかわかりません。以下のようなgstreamerコマンドを実行すると、それらは機能します。
gst-launch-1.0 v4l2src device=/dev/video1 ! videoscale ! videorate ! video/x-raw, width=640, height=360, framerate=30/1 ! jpegenc ! jpegparse ! rtpjpegpay pt=96 ! udpsink Host=192.168.1.25 port=5000
gst-launch-1.0 udpsrc port=5000 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG, payload=(int)96" ! rtpjpegdepay ! jpegdec ! decodebin ! videoconvert ! autovideosink
OpenCVのGstreamer APIを使用する前に、Gstreamerコマンドラインツールを使用した作業パイプラインが必要です。
Sender: OPはJPEGエンコーディングを使用しているため、このパイプラインは同じエンコーディングを使用します。
gst-launch-1.0 -v v4l2src \
! video/x-raw,format=YUY2,width=640,height=480 \
! jpegenc \
! rtpjpegpay \
! udpsink Host=127.0.0.1 port=5000
Receiver:caps
のシンクrtpjpegdepay
は、送信側パイプラインのcaps
のsrc rtpjpegpay
と一致する必要があります。
gst-launch-1.0 -v udpsrc port=5000 \
! application/x-rtp, media=video, clock-rate=90000, encoding-name=JPEG, payload=26 \
! rtpjpegdepay \
! jpegdec \
! xvimagesink sync=0
送信者と受信者用の作業パイプラインができたので、それらをOpenCVに移植できます。
送信者:
void sender()
{
// VideoCapture: Getting frames using 'v4l2src' plugin, format is 'BGR' because
// the VideoWriter class expects a 3 channel image since we are sending colored images.
// Both 'YUY2' and 'I420' are single channel images.
VideoCapture cap("v4l2src ! video/x-raw,format=BGR,width=640,height=480,framerate=30/1 ! appsink",CAP_GSTREAMER);
// VideoWriter: 'videoconvert' converts the 'BGR' images into 'YUY2' raw frames to be fed to
// 'jpegenc' encoder since 'jpegenc' does not accept 'BGR' images. The 'videoconvert' is not
// in the original pipeline, because in there we are reading frames in 'YUY2' format from 'v4l2src'
VideoWriter out("appsrc ! videoconvert ! video/x-raw,format=YUY2,width=640,height=480,framerate=30/1 ! jpegenc ! rtpjpegpay ! udpsink Host=127.0.0.1 port=5000",CAP_GSTREAMER,0,30,Size(640,480),true);
if(!cap.isOpened() || !out.isOpened())
{
cout<<"VideoCapture or VideoWriter not opened"<<endl;
exit(-1);
}
Mat frame;
while(true) {
cap.read(frame);
if(frame.empty())
break;
out.write(frame);
imshow("Sender", frame);
if(waitKey(1) == 's')
break;
}
destroyWindow("Sender");
}
受信者:
void receiver()
{
// The sink caps for the 'rtpjpegdepay' need to match the src caps of the 'rtpjpegpay' of the sender pipeline
// Added 'videoconvert' at the end to convert the images into proper format for appsink, without
// 'videoconvert' the receiver will not read the frames, even though 'videoconvert' is not present
// in the original working pipeline
VideoCapture cap("udpsrc port=5000 ! application/x-rtp,media=video,payload=26,clock-rate=90000,encoding-name=JPEG,framerate=30/1 ! rtpjpegdepay ! jpegdec ! videoconvert ! appsink",CAP_GSTREAMER);
if(!cap.isOpened())
{
cout<<"VideoCapture not opened"<<endl;
exit(-1);
}
Mat frame;
while(true) {
cap.read(frame);
if(frame.empty())
break;
imshow("Receiver", frame);
if(waitKey(1) == 'r')
break;
}
destroyWindow("Receiver");
}