4. 硬件解码与软件解码性能对比

任务目标

在嵌入式或桌面平台上,分别使用 GStreamer 的硬件解码插件(如 vaapidecode、nvdec)与软件解码插件(avdec_h264)解码同一 H.264 视频文件,通过统计解码耗时与丢帧率,量化两种方式的性能差异。本案例以 Intel VAAPI 硬件解码为例,软件解码使用通用 avdec_h264。

环境依赖

  • GStreamer 1.18+(含 gst-plugins-base、gst-plugins-good、gst-plugins-bad、gst-plugins-ugly)
  • Intel 平台需安装 gstreamer-vaapi 插件包(Ubuntu: sudo apt install gstreamer-vaapi)
  • 验证硬件解码是否可用:gst-inspect-1.0 vaapidecode 应返回插件信息

实现方案

通过 GStreamer 的 appsink 拉取解码后的原始帧,在回调中统计帧数并记录系统时间。解码结束后计算总耗时与平均帧率。使用 identity 插件的 drop-probability 属性模拟处理能力不足时的丢帧场景,对比两种解码器在相同负载下的表现。

关键完整代码

// decode_benchmark.c
#include <gst/gst.h>
#include <stdio.h>
#include <time.h>

static guint frame_count = 0;
static struct timespec start_time, end_time;
static gboolean first_frame = TRUE;

static GstFlowReturn on_new_sample(GstAppSink *appsink, gpointer user_data) {
    GstSample *sample = gst_app_sink_pull_sample(appsink);
    if (!sample) return GST_FLOW_ERROR;

    if (first_frame) {
        clock_gettime(CLOCK_MONOTONIC, &start_time);
        first_frame = FALSE;
    }
    frame_count++;
    gst_sample_unref(sample);
    return GST_FLOW_OK;
}

static void run_decode(const gchar *pipeline_str, const gchar *label) {
    GstElement *pipeline = gst_parse_launch(pipeline_str, NULL);
    if (!pipeline) {
        g_printerr("Failed to create pipeline: %s\n", label);
        return;
    }

    GstAppSink *appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(pipeline), "sink"));
    GstAppSinkCallbacks callbacks = { NULL, NULL, on_new_sample };
    gst_app_sink_set_callbacks(appsink, &callbacks, NULL, NULL);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    GstBus *bus = gst_element_get_bus(pipeline);
    GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
        GST_MESSAGE_EOS | GST_MESSAGE_ERROR);

    if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
        GError *err = NULL;
        gchar *debug = NULL;
        gst_message_parse_error(msg, &err, &debug);
        g_printerr("Error: %s\n", err->message);
        g_error_free(err);
        g_free(debug);
    }

    clock_gettime(CLOCK_MONOTONIC, &end_time);
    gdouble elapsed = (end_time.tv_sec - start_time.tv_sec) +
                      (end_time.tv_nsec - start_time.tv_nsec) / 1e9;
    gdouble fps = frame_count / elapsed;

    g_print("%s: %u frames in %.2f sec, avg %.1f fps\n",
            label, frame_count, elapsed, fps);

    gst_message_unref(msg);
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);

    frame_count = 0;
    first_frame = TRUE;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        g_printerr("Usage: %s <input.h264>\n", argv[0]);
        return 1;
    }

    gst_init(&argc, &argv);

    gchar *hw_pipeline = g_strdup_printf(
        "filesrc location=%s ! h264parse ! vaapidecode ! "
        "identity drop-probability=0.2 ! video/x-raw,format=I420 ! appsink name=sink",
        argv[1]);
    gchar *sw_pipeline = g_strdup_printf(
        "filesrc location=%s ! h264parse ! avdec_h264 ! "
        "identity drop-probability=0.2 ! video/x-raw,format=I420 ! appsink name=sink",
        argv[1]);

    g_print("=== Hardware decode (VAAPI) ===\n");
    run_decode(hw_pipeline, "HW");

    g_print("=== Software decode (avdec_h264) ===\n");
    run_decode(sw_pipeline, "SW");

    g_free(hw_pipeline);
    g_free(sw_pipeline);
    return 0;
}

编译与运行

# 编译(需安装 libgstreamer1.0-dev 和 libgstreamer-plugins-base1.0-dev)
gcc decode_benchmark.c -o decode_benchmark $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0)

# 运行(准备一个 H.264 视频文件 test.h264)
./decode_benchmark test.h264

验证方法与判定标准

  1. 程序依次输出 HW 和 SW 两行统计结果,包含帧数、耗时与平均帧率。
  2. 在相同输入文件与 drop-probability=0.2 条件下,硬件解码(HW)的平均帧率应显著高于软件解码(SW),通常差距在 2~5 倍以上(具体取决于 CPU/GPU 性能)。
  3. 若 vaapidecode 初始化失败,程序会打印 Error 信息,此时应检查 VAAPI 驱动是否安装(sudo apt install intel-media-va-driver)或改用其他硬件插件(如 nvdec)。
  4. 可通过修改 drop-probability 值(0.0~1.0)观察两种解码器在不同负载下的帧率变化趋势,验证硬件解码在高负载下更稳定。

预期输出示例

=== Hardware decode (VAAPI) ===
HW: 2450 frames in 8.32 sec, avg 294.5 fps
=== Software decode (avdec_h264) ===
SW: 2450 frames in 21.78 sec, avg 112.5 fps

以上数值仅为示意,实际帧率取决于视频分辨率、码率与平台性能。判定通过的标准是 HW 行帧率明显高于 SW 行,且无解码错误。