GStreamer appsrc对接自定义图像传感器的分辨率限制问题排查
问题排查:GStreamer appsrc大分辨率崩溃问题
运行环境:Ubuntu22系统,GStreamer 1.20.3,g++ 11.3.0
尝试将4800x2400分辨率的自定义图像传感器接入GStreamer的appsrc管道,通过驱动获取unsigned char*格式的图像缓冲区,再通过push-buffer信号传递给appsrc。
测试发现:
- 使用
gst-launch-1.0运行以下命令设置4800x2400分辨率时,可正常显示缩放后的测试画面:gst-launch-1.0 -v -e videotestsrc name=video_input do-timestamp=true ! video/x-raw, width=4800, height=2400, format=I420, framerate=25/1 ! xvimagesink - 自行编写的C++代码中,当分辨率设置为4800x2400时,程序调用
video_push_data函数后立即崩溃,目前能正常运行的最大分辨率为2560x2100。怀疑是appsrc存在未明确说明的分辨率限制,或是代码存在问题,请求协助排查。
测试代码如下:
const gint mWidth = 640; // 4800; 640 1280 1920 2560 3840 // max working: 2560 const gint mHeight = 480; // 2400; 480 720 1080 1440 2160 // max working: 2100 const unsigned int mFps = 25; const int mSize = mWidth * mHeight * 1.5; const int frame_count = mFps * 10; const char* mFilename = "./output_file.mp4"; typedef struct _CustomData { GstElement *video_appsrc; GMainLoop *main_loop; GstElement *pipeline; bool _need_video_; unsigned int video_frame; } CustomData; gboolean video_push_data (CustomData *data) { GstFlowReturn ret; GstBuffer *buffer; static int video_timestamp = 0; GstMapInfo info; buffer = gst_buffer_new_and_alloc(mSize); char buf[mSize]; for(int i = 0; i < mSize; i++) buf[i] = rand()%255; gst_buffer_map(buffer, &info, GST_MAP_WRITE); memmove(info.data, buf, mSize); info.size = mSize; GST_BUFFER_PTS (buffer) = video_timestamp; GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, mFps); GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (data->video_frame, GST_SECOND, mFps); GST_BUFFER_DTS(buffer) = data->video_frame; video_timestamp += GST_BUFFER_DURATION (buffer); gst_buffer_unmap(buffer, &info); data->video_frame++; g_signal_emit_by_name (data->video_appsrc, "push-buffer", buffer, &ret); gst_buffer_unref (buffer); if (ret != GST_FLOW_OK) { return FALSE; } return TRUE; } static void video_start_feed (GstElement *source, guint size, CustomData *data) { printf("video need data %d times\n", data->video_quant); data->_need_video_ = 1; } static void video_stop_feed (GstElement *source, CustomData *data) { printf("video already got data \n"); data->_need_video_ = 0; } void* GstreamerThread(void* pThreadParam) { gst_debug_set_active(TRUE); gst_debug_set_default_threshold(GST_LEVEL_LOG); memset (&data, 0, sizeof (data)); data.b = 1; data.d = 1; GstBus *bus; guint bus_watch_id; char *strPipeline = g_strdup_printf ("appsrc name=video_input do-timestamp=true ! video/x-raw, width=(int)%d, height=(int)%d, format=(string)I420, framerate=(fraction)%d/1 ! xvimagesink sync=true window-height=480 window-width=640 ", mWidth, mHeight, mFps); // NV12 data.pipeline = gst_parse_launch(strPipeline, NULL); data.video_appsrc = gst_bin_get_by_name((GstBin *)(data.pipeline), "video_input"); if( !data.video_appsrc) exit(-2); g_object_set(G_OBJECT(data.video_appsrc), "is-live", 1, NULL); g_object_set(G_OBJECT(data.video_appsrc), "leaky-type", GST_APP_LEAKY_TYPE_DOWNSTREAM, NULL); g_object_set(G_OBJECT(data.video_appsrc), "block", 1, NULL); g_object_set(G_OBJECT(data.video_appsrc), "blocksize", mSize, NULL); g_object_set(G_OBJECT(data.video_appsrc), "max-bytes", mSize, NULL); g_object_set(G_OBJECT(data.video_appsrc), "format", GST_FORMAT_TIME, NULL); g_object_set(G_OBJECT(data.video_appsrc), "stream-type", 0, NULL); // stream g_object_set(G_OBJECT(data.video_appsrc), "duration", GST_CLOCK_TIME_NONE, NULL); g_object_set(G_OBJECT (data.video_appsrc), "max-time", -1, NULL); g_object_set(G_OBJECT (data.video_appsrc), "max-latency", -1, NULL); g_signal_connect (data.video_appsrc, "need-data", G_CALLBACK (video_start_feed), &data); g_signal_connect (data.video_appsrc, "enough-data", G_CALLBACK (video_stop_feed), &data); gst_element_set_base_time( data.video_appsrc, GstClockTime(0)); gst_element_set_start_time(data.video_appsrc, GstClockTime(0)); data.main_loop = g_main_loop_new(NULL, FALSE); bus = gst_pipeline_get_bus(GST_PIPELINE(data.pipeline)); bus_watch_id = gst_bus_add_watch(bus, reinterpret_cast<GstBusFunc>(bus_call), &data); g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, &data); fprintf(stderr, "Setting g_main_loop_run to GST_STATE_PLAYING\n"); gst_element_set_state(data.pipeline, GST_STATE_PLAYING); g_main_loop_run(data.main_loop); fprintf(stderr, "g_main_loop_run returned, stopping playback\n"); gst_element_set_state(data.pipeline, GST_STATE_NULL); fprintf(stderr, "Deleting pipeline\n"); gst_object_unref(GST_OBJECT(data.pipeline)); g_source_remove (bus_watch_id); g_main_loop_unref (data.main_loop); return NULL; } bool StartGstreamer() { unsigned long GtkThreadId; pthread_attr_t GtkAttr; int result = pthread_attr_init(&GtkAttr); if (result != 0) { fprintf(stderr, "pthread_attr_init returned error %d\n", result); return false; } void* pParam = NULL; result = pthread_create(&GtkThreadId, &GtkAttr, GstreamerThread, pParam); if (result != 0) { fprintf(stderr, "pthread_create returned error %d\n", result); return false; } return true; } gboolean bus_call(GstBus *bus, GstMessage *msg, CustomData *data) { GMainLoop *loop = (GMainLoop *) data; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: fprintf(stderr, "End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg, &error, &debug); g_free(debug); g_printerr("Error: %s\n", error->message); g_error_free(error); gst_element_set_state (data->pipeline, GST_STATE_READY); g_main_loop_quit(loop); } break; default: break; } return TRUE; } static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) { GError *err; gchar *debug_info; gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); g_main_loop_quit (data->main_loop); } int main(int argc, char *argv[]) { data.video_frame = 0; data._need_video_ = 0; gst_init(NULL, NULL); StartGstreamer(); while(1){ if(data._need_video_){ usleep(10); video_push_data(&data); printf("processing %d frame \n", data.video_frame); } else usleep(100); if(data.video_frame == frame_count) break; } return 0; }
内容的提问来源于stack exchange,提问作者Serhii
相关产品推荐
相关产品推荐

