我正在使用Xilinx Petalinux和Vivado 2018.2工具,这些工具针对具有(视频编解码器)VCU的Zynqmp设备。
我正在Vivado SDK中开发基于gstreamer的应用程序,目标是构建下一个管道:
目前,我可以连接相机,获取帧并将它们包装为GstBuffer类型。
问题是生成的“ output.h264”文件为空。
代码的相关部分是:
/* Create pipeline */
pipeline = gst_parse_launch("appsrc is-live=TRUE name=xsource caps= video/x-raw,format=Y800,width=1280,height=1024 ! omxh264enc ! filesink location= media/test/output.h264", NULL);
if(!pipeline)
goto finish;
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, NULL);
gst_object_unref (bus);
appsrc=gst_bin_get_by_name(GST_BIN(pipeline), "xsource");
gst_element_set_state(pipeline, GST_STATE_PLAYING);
if(xiGetImage(xiH, 5000, &image) == XI_OK) //Get just one frame
{
unsigned long buffer_size = image.width*image.height;
buffer = gst_buffer_new();
gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, (guint8*)image.bp, buffer_size, 0, buffer_size, NULL, NULL));
ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
if(ret != GST_FLOW_OK){
break;
}
}
gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline));
我检查(在SDK调试模式下)内存和缓冲区不为空,因此将相机接口和缓冲区推入 appsrc 的方法似乎运行良好。我怀疑问题可能出在管道链定义中,但是我尝试了许多配置,但没有成功...
任何想法/线索将不胜感激。
编辑:
按照建议,我尝试等待EOS确认以及代码末尾的错误消息检查:
gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
/* Wait until error or EOS */
bus = gst_element_get_bus (pipeline);
msg =
gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline));
我也尝试加载更多帧以查看是否有帮助,我尝试这样加载500个:
while(xiGetImage(xiH, 5000, &image) == XI_OK)
{
unsigned long buffer_size = image.width*image.height;
buffer = gst_buffer_new();
gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, (guint8*)image.bp, buffer_size, 0, buffer_size, NULL, NULL));
ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
if(ret != GST_FLOW_OK){
break;
}
if(frames > 500)
{
break;
}else{
frames++;
}
}
但不幸的是,它没有帮助,仍然有空文件且没有错误。
还有其他想法/线索吗?
谢谢。
答案 0 :(得分:0)
大多数视频编码器仅给它们一帧就不会产生任何缓冲区。他们想向前看..或在内部管道中有一些延迟。
因此也许在其中添加更多缓冲区会有帮助。
否则,当您正确地告诉视频帧不再有视频帧时,视频编码器可能会为您提供帧。这意味着:将EOS发送到管道,并等待EOS事件到达总线。到那时编码器有望将这一帧推到文件接收器中。
编辑:我注意到您已经发送了EOS。您可能想要在将管道的状态设置为NULL之前等待总线上的EOS。
答案 1 :(得分:0)
我有类似的问题。我看到的每个示例都以拉动方式使用需求数据回调,而不是像代码中那样推框架。
g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
gst_element_set_state (pipeline, GST_STATE_NULL);
完整来源:
// based on https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c
// and https://gist.github.com/floe/e35100f091315b86a5bf
// compile with:
// g++ -Wall $(pkg-config --cflags gstreamer-1.0) -o gst gst.cpp $(pkg-config --libs gstreamer-1.0) -lgstapp-1.0
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <stdint.h>
#include <iostream>
using namespace std;
bool run = true;
const int WIDTH = 1280;
const int HEIGHT = 720;
const int FRAME_RATE = 10;
uint16_t b_white[WIDTH*HEIGHT];
uint16_t b_black[WIDTH*HEIGHT];
static void prepare_buffer(GstAppSrc* appsrc) {
static gboolean white = FALSE;
static GstClockTime timestamp = 0;
GstBuffer *buffer;
guint size;
GstFlowReturn ret;
double now = ((double)timestamp / (double)GST_SECOND);
cout << now << endl;
if(now > 3.0)
{
/* we are EOS, send end-of-stream and remove the source */
g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
return;
}
size = WIDTH * HEIGHT * 2;
for (int i = 0; i < WIDTH*HEIGHT; i++) { b_white[i] = 0xFFFF; }
buffer = gst_buffer_new_wrapped_full( (GstMemoryFlags)0, (gpointer)(white?b_white:b_black), size, 0, size, NULL, NULL );
white = !white;
GST_BUFFER_PTS (buffer) = timestamp;
GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, FRAME_RATE);
timestamp += GST_BUFFER_DURATION (buffer);
//This can also trigger callbacks including cb_need_data!
ret = gst_app_src_push_buffer(appsrc, buffer);
if (ret != GST_FLOW_OK) {
run = false;
}
}
static void cb_need_data (GstElement *appsrc, guint unused_size, gpointer user_data) {
prepare_buffer((GstAppSrc*)appsrc);
}
static gboolean on_pipeline_message (GstBus * bus, GstMessage * message, GMainLoop *loop)
{
cout << GST_MESSAGE_TYPE_NAME(message) << endl;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
g_print ("Received End of Stream message\n");
//g_main_loop_quit (loop);
run = false;
break;
}
return TRUE;
}
gint main (gint argc, gchar *argv[]) {
GstElement *pipeline, *appsrc, *conv;
for (int i = 0; i < WIDTH*HEIGHT; i++) { b_black[i] = 0; b_white[i] = 0xFFFF; }
/* init GStreamer */
gst_init (&argc, &argv);
/* setup pipeline */
pipeline = gst_pipeline_new ("pipeline");
appsrc = gst_element_factory_make ("appsrc", "source");
conv = gst_element_factory_make ("videoconvert", "conv");
GstElement *enc = gst_element_factory_make ("x264enc", "enc");
GstElement *mux = gst_element_factory_make ("matroskamux", "mux");
GstElement *outFile = gst_element_factory_make ("filesink", "outFile");
/* setup */
g_object_set (G_OBJECT (appsrc), "caps",
gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, "RGB16",
"width", G_TYPE_INT, WIDTH,
"height", G_TYPE_INT, HEIGHT,
"framerate", GST_TYPE_FRACTION, FRAME_RATE, 1,
NULL), NULL);
gst_bin_add_many (GST_BIN (pipeline), appsrc, conv, enc, mux, outFile, NULL);
gst_element_link_many (appsrc, conv, enc, mux, outFile, NULL);
/* setup appsrc */
g_object_set (G_OBJECT (appsrc),
"stream-type", 0, // GST_APP_STREAM_TYPE_STREAM
"format", GST_FORMAT_TIME,
"is-live", false,
NULL);
g_signal_connect (appsrc, "need-data", G_CALLBACK (cb_need_data), NULL);
g_object_set (G_OBJECT (enc),
"qp-min", 18,
NULL);
g_object_set (G_OBJECT (outFile),
"location", "test.mkv",
NULL);
// play
gst_element_set_state (pipeline, GST_STATE_PLAYING);
auto bus = gst_element_get_bus (pipeline);
//Wait for bus events
while (run) {
//This can trigger callbacks including cb_need_data
GstClockTime timeout = 0 * GST_MSECOND;
GstMessage *msg = gst_bus_timed_pop_filtered (bus, timeout, (GstMessageType)
(GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
if(msg == nullptr) continue;
on_pipeline_message (bus, msg, nullptr);
}
gst_object_unref (bus);
/* clean up */
gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
return 0;
}