我正在设计一个管道,用于将视频帧从opencv应用程序(从网络摄像头获取)编码为video / x-h264格式,通过网络发送并在另一台不同类型的设备上解码(可能是覆盆子pi )为我的项目提供合适的RGB流。
为此,我应该使用硬件加速的编码器和解码器。 由于整个场景非常庞大,目前的开发是在使用gstreamer VAAPI插件(vaapiencode_h264& vaapidecode)的Intel机器上进行的。此外,我们不需要使用任何网络插件,如TCPServer或UDPServer
为此,我将以下管道用于我的目的: 在编码器端:
appsrc name=applicationSource ! videoconvert ! video/x-raw, format=I420, width=640, height=480,framerate=30/1, pixel-aspect-ratio=1/1,interlace-mode=progressive ! vaapiencode_h264 bitrate=600 tune=high-compression ! h264parse config-interval=1 ! appsink name=applicationSink sync=false
Appsrc部分非常有效,而appsink部分则存在一些问题。
此管道的appsink部分已使用以下上限设置:
“video / x-h264,format =(string){avc,avc3,byte-stream},alignment =(string){au,nal}; video / mpeg,mpegversion =(int)2,轮廓=(字符串)简单的“
我的appsink的数据提取代码是
bool HWEncoder::grabData()
{
// initial checks..
if (!cameraPipeline)
{
GST_ERROR("ERROR AS TO NO PIPE FOUND ... Stopping FRAME GRAB HERE !! ");
return false;
}
if (gst_app_sink_is_eos (GST_APP_SINK(applicationSink)))
{
GST_WARNING("APP SINK GAVE US AN EOS! BAILING OUT ");
return false;
}
if (sample)
{
cout << "sample available ... unrefing it ! "<< endl;
gst_sample_unref(sample);
}
sample = gst_app_sink_pull_sample (GST_APP_SINK(applicationSink));
if (!sample)
{
GST_WARNING("No valid sample");
return false; // no valid sample pulled !
}
sink_buffer = gst_sample_get_buffer(sample);
if (!sink_buffer)
{
GST_ERROR("No Valid Buffer ");return false;
}
return true;
}
启动管道并检查我的appsink中的缓冲区填满后,我无限期地陷入了下面所说的代码行:
sample = gst_app_sink_pull_sample (GST_APP_SINK(applicationSink));
我有以下问题: 1)我的申请上限是否正确?如果不是,我如何确定它们的上限? 2)我的管道上面有什么问题吗?
如何使用Appsink修复此问题?
任何形式的帮助都会有用!
谢谢!
答案 0 :(得分:1)
只是一个猜测(我有类似的问题)appink和appsrc在同一个管道中的问题可能是当你填充/清空其中一个时它会阻塞另一个(更多关于下面)。
appink和appsrc会在它们满/空时阻塞 - 这是正常的期望行为。对于appsink或者对于appsrc,有选项drop
,有选项block
- 但使用这些选项可能只是解决方法,您将在流中遇到问题。正确的解决方案是以更好的方式处理appsrc和appsink之间的同步。
您可以对appsrc信号enough-data
和need-data
做出反应 - 这是我们的方式。我们还摆弄了appsrc的属性:is-live
,do-timestamp
和缓冲区大小(这可能会对您有所帮助):
g_object_set(src->appsrc,
"stream-type", GST_APP_STREAM_TYPE_STREAM,
"format", GST_FORMAT_TIME,
"do-timestamp", TRUE,
"is-live", TRUE,
"block", TRUE,
NULL);
为什么他们互相阻挡? 因为(我猜)你在主应用程序线程中处理appsink并同时处理appsrc。当其中一个appsink / appsrc阻塞线程时,没有人会处理另一个线程的处理。因此,当appsink被阻止,因为它没有任何数据时,没有人可以用新数据提供appsrc - 因此无休止的死锁。
我们还实现了ninklock版本的appsink * pull_sample方法,但它只是一种解决方法,导致了比解决方案更多的问题。
如果你想调试正在发生的事情你可以为appsrc / appsink添加GST_DEBUG条目(我不记得它们是什么),你可以在提到的enough-data
和need-data
信号上添加回调或者你可以添加队列并启用GST_DEBUG = queue_dataflow:5以查看首先填充哪个队列等。这在调试“数据死锁”时总是有用。