You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:09:54