Je capture des images vidéo avec OpenCV VideoCapture. La capture fonctionne très bien car je peux utiliser les images comme ceci:
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);
Je voudrais également envoyer le flux sur le réseau et voici où je suis bloqué. D'une manière ou d'une autre, j'échoue dans la partie du pipeline appsrc. Je veux encoder le flux en jpeg et l'envoyer en udp. Voici ce que j'ai obtenu:
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);
On dirait que la ligne ci-dessus ne fait rien. Le writer << frame
ne fait rien. De plus, cette commande gstreamer n'affiche rien:
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
Je ne sais pas où j'échoue dans le writer.open
partie. Si j'exécute les commandes gstreamer comme celle-ci, elles fonctionnent:
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
Avant d'utiliser l'API Gstreamer d'OpenCV, nous avons besoin d'un pipeline de travail utilisant l'outil de ligne de commande Gstreamer.
Sender: L'OP utilise le codage JPEG, donc ce pipeline utilisera le même codage.
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: Le récepteur caps
pour rtpjpegdepay
doit correspondre au src caps
du rtpjpegpay
du pipeline de l'expéditeur.
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
Maintenant que nous avons des pipelines qui fonctionnent pour l'expéditeur et le récepteur, nous pouvons les porter sur OpenCV.
Expéditeur:
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");
}
Récepteur:
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");
}