c++ - Cómo abrir una tubería GStreamer desde OpenCV con VideoWriter
(1)
Estoy capturando cuadros de video con OpenCV VideoCapture. La captura funciona bien, ya que puedo usar los marcos de esta manera:
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);
También me gustaría enviar la transmisión a través de la red y aquí es donde estoy atascado. De alguna manera estoy fallando en la parte de la tubería de appsrc. Quiero codificar el flujo a jpeg y enviarlo vie udp. Esto es lo que conseguí:
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);
Parece que la línea anterior no hace nada.
El
writer << frame
no hace nada.
Además, este comando gstreamer no muestra nada:
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
No sé dónde estoy fallando en el
writer.open
. Parte
writer.open
.
Si ejecuto los comandos de gstreamer como este a continuación, funcionan:
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
Antes de usar la API de Gstreamer de OpenCV, necesitamos una tubería de trabajo que use la herramienta de línea de comando Gstreamer.
Remitente: El OP utiliza la codificación JPEG, por lo que esta canalización utilizará la misma codificación.
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
Receptor: las
caps
sumidero para
rtpjpegdepay
deben coincidir con las
caps
de src de la
rtpjpegpay
del remitente.
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
Ahora que tenemos canales de trabajo para el remitente y el receptor, podemos portarlos a OpenCV.
Remitente:
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");
}
Receptor:
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");
}