1:前言
本文使用的是瑞芯微的RK3588开发板,编译我提供的程序需要使用SDK内置的交叉编译器。
更具官方文档若需要编译单个模块或者第三⽅应⽤,需对交叉编译环境进⾏配置。⽐如RK3588,其交叉编译⼯具位于
buildroot/output/rockchip_rk3588/host/usr ⽬录下,需要将⼯具的bin/⽬录和
aarch64-buildroot-linux-gnu/bin/ ⽬录设为环境变量,在顶层⽬录执⾏⾃动配置环境变量的脚本
source envsetup.sh
然后选择对应的交叉编译器。
配置完之后查看配置好了没:
cd buildroot/output/rockchip_rk3588/host/usr/bin
./aarch64-linux-gcc --version
我的打印信息为:
aarch64-linux-gcc.br_real (Buildroot linux-5.10-gen-rkr3.3) 11.3.0
2:程序实现:
#include <gst/gst.h>
/* 回调函数 */
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data);
int main(int argc, char *argv[]) {
GstElement *pipeline, *source, *depay, *parse, *decoder, *convert, *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
/* 初始化 GStreamer库 */
gst_init(&argc, &argv);
/* 创建各个元素 */
source = gst_element_factory_make("rtspsrc", "source");// RTSP 源
depay = gst_element_factory_make("rtph264depay", "depay");//H.264 RTP 解封装
parse = gst_element_factory_make("h264parse", "parse");// H.264 解析器
decoder = gst_element_factory_make("mppvideodec", "decoder");// MPP 视频解码器
convert = gst_element_factory_make("videoconvert", "convert");// 视频格式转换
sink = gst_element_factory_make("autovideosink", "sink");// 自动选择视频输出
if (!source || !depay || !parse || !decoder || !convert || !sink) {
g_printerr("Not all elements could be created.\n");
return -1;
}
/* Create the empty pipeline */
pipeline = gst_pipeline_new("test-pipeline");
if (!pipeline) {
g_printerr("无法创建管道\n");
gst_object_unref(source);
gst_object_unref(depay);
gst_object_unref(parse);
gst_object_unref(decoder);
gst_object_unref(convert);
gst_object_unref(sink);
return -1;
}
/* 设置源的属性 */
g_object_set(G_OBJECT(source), "location", "rtsp://192.168.220.10/stream/main", NULL);
/* 构建管道 */
gst_bin_add_many(GST_BIN(pipeline), source, depay, parse, decoder, convert, sink, NULL);
/* 手动连接元素 */
if (gst_element_link(depay, parse) != TRUE ||
gst_element_link(parse, decoder) != TRUE ||
gst_element_link(decoder, convert) != TRUE ||
gst_element_link(convert, sink) != TRUE) {
g_printerr("Elements could not be linked.\n");
gst_object_unref(pipeline);
return -1;
}
/* 动态连接 rtspsrc 到 rtph264depay */
g_signal_connect(source, "pad-added", G_CALLBACK(on_pad_added), depay);
/* 开始播放 */
ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("Unable to set the pipeline to the playing state.\n");
gst_object_unref(pipeline);
return -1;
}
/* 等待错误或 EOS(End-Of-Stream)消息 */
bus = gst_element_get_bus(pipeline);
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* 解析消息 */
if (msg != NULL) {
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ERROR:
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);
break;
case GST_MESSAGE_EOS:
g_print("达到流末尾.\n");
break;
default:
g_printerr("收到意外的消息.\n");
break;
}
gst_message_unref(msg);
}
/* Free resources */
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
/* 回调函数,用于动态链接 rtspsrc 到 rtph264depay */
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data) {
GstPad *sinkpad;
GstElement *depay = (GstElement *)data;
g_print("Received new pad '%s' from '%s':\n", GST_PAD_NAME(pad), GST_ELEMENT_NAME(element));
/* If our depay is already linked, we have nothing to do here */
sinkpad = gst_element_get_static_pad(depay, "sink");
if (sinkpad && gst_pad_is_linked(sinkpad)) {
g_print("We are already linked. Ignoring.\n");
gst_object_unref(sinkpad);
return;
}
/* 尝试链接 */
if (sinkpad && gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
g_print("Type of the pad does not match type of sink pad.\n");
} else {
g_print("Link succeeded.\n");
}
/* 释放 sink pad */
if (sinkpad) {
gst_object_unref(sinkpad);
}
}
使用SDK的交叉编译器编译,生成可执行文件,把可执行文件拖到开发板上面就可以实现使用GStreamer拉取RTSP流并通过MPP解码器解码并播放