1.命令行实现h264文件推流到RTMP服务器
# 将yuv文件先编码再传输
GST_DEBUG=3 gst-launch-1.0 filesrc location=test.yuv ! queue ! "video/x-raw,format=I420,width=832,height=480,framerate=25/1" ! rawvideoparse use-sink-caps=true ! x264enc bitrate=5000 qp-min=18 qp-max=35 ! flxmux ! rtmpsink location='rtmp://127.0.0.1:1935/live/test'
# 直接传输h264文件
GST_DEBUG=3 gst-launch-1.0 filesrc location=test.h264 ! h264parse ! flvmux ! rtmpsink location='rtmp://127.0.0.1:1935/live/test'
# 直接传输h264文件(循环推流)
GST_DEBUG=3 gst-launch-1.0 multifilesrc location=test.h264 loop=true ! h264parse ! flvmux ! rtmpsink location='rtmp://127.0.0.1:1935/live/test'
2.基于gstreamer的h264推流器
下面代码中直接传输本地已经编码的h264码流文件
#include <gst/gst.h>
typedef struct _Data
{
GstElement* pipeline;
GstElement* filesrc;
GstElement* h264parse;
GstElement* flvmux;
GstElement* rtmpsink;
} Data;
int main(int argc, char* argv[])
{
Data data;
GstBus* bus;
GstMessage* msg;
GstStateChangeReturn ret;
gboolean terminate= FALSE;
// 设置日志级别
gst_debug_set_default_threshold(3);
// 初始化gst
gst_init(&argc, &argv);
// 创建模块
data.filesrc = gst_element_factory_make("filesrc", "filesrc");
data.h264parse = gst_element_factory_make("h264parse", "h264parse");
data.flvmux = gst_element_factory_make("flvmux", "flvmux");
data.rtmpsink = gst_element_factory_make("rtmpsink", "rtmpsink");
data.pipeline = gst_pipeline_new("pipeline");
if(!data.filesrc || !data.h264parse || !data.flvmux || !data.rtmpsink || !data.pipeline)
{
g_printerr("some elements created failed\n");
return -1;
}
// 设置输入输出
// 这里输出的地址是rtmp://127.0.0.1:1935/live/test,输入是本地的h264文件
g_object_set(G_OBJECT(data.filesrc), "location", "test.h264", NULL);
g_object_set(G_OBJECT(data.rtmpsink), "location", "rtmp://127.0.0.1:1935/live/test", NULL);
// 将不同元素添加到同一个pipeline中
gst_bin_add_many(GST_BIN(data.pipeline), data.filesrc, data.h264parse, data.flvmux, data.rtmpsink, NULL);
// 链接不同的元素
if(!gst_element_link_many(data.filesrc, data.h264parse, data.flvmux, data.rtmpsink, NULL))
{
g_printerr("link elements failed\n");
return -1;
}
// 设置pipeline为playing状态
ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING);
if(ret == GST_STATE_CHANGE_FAILURE)
{
g_printerr("failed to start playing\n");
return -1;
}
// 获取pipeline总线
bus = gst_element_get_bus(data.pipeline);
do {
// 监测总线上面的消息
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_STATE_CHANGED | 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_clear_error(&err);
g_free(debug_info);
gst_message_unref(msg);
terminate = TRUE;
break;
case GST_MESSAGE_EOS:
g_print("end of stream\n");
terminate = TRUE;
break;
case GST_MESSAGE_STATE_CHANGED:
if(GST_MESSAGE_SRC(msg) == GST_OBJECT(data.pipeline))
{
GstState old_state, new_state, pending_state;
gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
g_print("pipeline")
}
break;
default:
g_printerr("unexpected message received, type:%d\n", GST_MESSAGE_TYPE(msg));
break;
}
gst_message_unref(msg);
}
} while(!terminate);
gst_object_unref(bus);
gst_element_set_state(data.pipeline, GST_STATE_NULL);
gst_object_unref(data.pipeline);
return 0;
}
如果要播放测试,可以使用vlc或者ffplay
ffplay rtmp://127.0.0.1:1935/live/test