我对 GStreamer 管道相对较新,目前正在开发一项相机服务,需要使用 OpenCV 和 GStreamer 读取 H.264 编码的相机流。
以下 GStreamer 管道工作正常:
const char *pipeline_str = "v4l2src device=/dev/video0 ! videoconvert ! video/x-raw, width=640, height=480, framerate=30/1 ! x264enc ! h264parse ! avdec_h264 ! videoconvert ! appsink";
cv::VideoCapture cap(pipeline_str, cv::CAP_GSTREAMER);
if (!cap.isOpened()) {
std::cerr << "Failed to open appsink as VideoCapture\n";
return;
}
但是,当我尝试不使用 H.264 解码部分的类似管道时:
const char *pipeline_str = "v4l2src device=/dev/video0 ! videoconvert ! video/x-raw, width=640, height=480, framerate=30/1 ! x264enc ! h264parse ! appsink";
cv::VideoCapture cap(pipeline_str, cv::CAP_GSTREAMER);
if (!cap.isOpened()) {
std::cerr << "Failed to open appsink as VideoCapture\n";
return;
}
无法以VideoCapture方式打开appsink。我不确定非工作场景中编码流的问题是什么。
有人可以帮我理解为什么没有 H.264 解码的管道无法按预期工作吗?任何见解或建议将不胜感激。
首先,让我区分原始视频和压缩视频(例如 h264)。描述很简单,但应该足以指出问题所在。 在原始视频中,每个视频帧都未经压缩地存储,以便每个像素存储一系列字节(RGB 或 BGR 帧每个像素 3 个字节,YUV 帧每个像素 2 个字节)。 对于压缩视频,视频帧被压缩到较低的内存,您需要一个编码器将其转换回原始视频。
让我们检查一下您的管道:
v4l2src device=/dev/video0 ! videoconvert ! video/x-raw, width=640, height=480, framerate=30/1
-->原始视频在这里
x264enc
--> h264 编码视频
h264parse ! avdec_h264
--> 再次原始视频
videoconvert ! appsink
--> 仍然原始视频
在第一个管道中,您将原始视频传递到 appsink,而在第二个管道中,您将压缩的 h264 视频数据。
VideoCapture
需要原始视频,这就是为什么它无法打开压缩视频帧。
我相信您正在尝试发送 h264 压缩数据并在 OpenCV 中读取它以进行进一步处理。如果是这样,您需要先使用
avdec_h264
进行解码。