c - Gstreamer C 代码因流停止而失败,原因未协商 (-4)
问题描述
我正在学习 Gstreamer 以及我通过 Gstreamer 工具所取得的任何成就,我正在尝试使用 C 语言在 gstreamer 应用程序中实现相同的功能。
以下命令成功流式传输 mp4 视频文件: gst-launch-1.0.exe -v filesrc location=file.mp4 !qtdemux !h264解析!avdec_h264 !视频转换!自动视频接收器
我对 C 代码进行了同样的尝试,还使用“pad-added” Elements Signals 来创建 pad 并链接到下一个元素,即解析器(h264parser)。
因此,它因流媒体停止而失败,原因未协商。
完整输出:正在播放:file.mp4 正在运行...为 demux 元素创建了一个新的 pad video_0 demux 将链接到解析器错误:内部数据流错误。调试信息:../gst/isomp4/qtdemux.c(6607): gst_qtdemux_loop (): /GstPipeline:video-play/GstQTDemux:demux: 流停止,原因未协商 (-4) 返回,停止播放...释放管道...已完成。再见!
#include <gst/gst.h>
#include <stdlib.h>
#include <string.h>
#define INPUT_FILE "file.mp4"
static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
{
GMainLoop *loop = (GMainLoop *)data;
switch (GST_MESSAGE_TYPE(msg)) {
gchar *debug;
GError *error;
case GST_MESSAGE_EOS:
g_print("End of stream\n");
g_main_loop_quit(loop);
break;
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg, &error, &debug);
g_free(debug);
g_printerr("Error: %s\n", error->message);
g_printerr("Debug Information: %s\n", debug);
g_error_free(error);
g_main_loop_quit(loop);
break;
default:
break;
}
return TRUE;
}
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data)
{
gchar *name;
GstElement *parse = (GstElement *)data;
name = gst_pad_get_name(pad);
g_print("A new pad %s was created for %s\n", name, gst_element_get_name(element));
g_free(name);
g_print("element %s will be linked to %s\n",
gst_element_get_name(element),
gst_element_get_name(parse));
gst_element_link(element, parse);
}
int main(int argc, char *argv[])
{
GMainLoop *loop;
GstElement *pipeline, *source, *demux, *parser, *decoder, *sink, *fpssink;
GstBus *bus;
guint bus_watch_id;
const gchar *input_file = INPUT_FILE;
/* Initialization */
gst_init(&argc, &argv);
loop = g_main_loop_new(NULL, FALSE);
/* Create gstreamer elements */
pipeline = gst_pipeline_new("video-play");
source = gst_element_factory_make("filesrc", "file-source");
demux = gst_element_factory_make("qtdemux", "demux");
parser = gst_element_factory_make("h264parse", "h264-parser");
decoder = gst_element_factory_make("avdec_h264", "decoder");
sink = gst_element_factory_make("d3dvideosink", "video-output");
if (!pipeline || !source || !demux || !parser || !decoder || !sink) {
g_printerr("One element could not be created. Exiting.\n");
return -1;
}
/* Set input video file for source element */
g_object_set(G_OBJECT(source), "location", input_file, NULL);
/* we add a message handler */
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
bus_watch_id = gst_bus_add_watch(bus, bus_call, loop);
gst_object_unref(bus);
/* Add all elements into the pipeline */
/* pipeline---[ filesrc + qtdemux + h264parse + avdec_h264 + d3dvideosink ] */
gst_bin_add_many(GST_BIN(pipeline), source, demux, parser, decoder, sink, NULL);
/* Link the elements filesrc->demux together */
if (gst_element_link(source, demux) != TRUE) {
g_printerr("Element source->demux could not be linked.\n");
gst_object_unref(pipeline);
return -1;
}
/* h264parse -> avdec_h264 -> d3dvideosink */
if (gst_element_link_many(parser, decoder, sink, NULL) != TRUE) {
g_printerr("Many Elements could not be linked.\n");
gst_object_unref(pipeline);
return -1;
}
g_signal_connect(demux, "pad-added", G_CALLBACK(on_pad_added), parser);
/* Set the pipeline to "playing" state */
g_print("Now playing: %s\n", input_file);
if (gst_element_set_state(pipeline,
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
g_printerr("Unable to set the pipeline to the playing state.\n");
gst_object_unref(pipeline);
return -1;
}
g_print("Running...\n");
g_main_loop_run(loop);
/* Free resources and change state to NULL */
gst_object_unref(bus);
g_print("Returned, stopping playback...\n");
gst_element_set_state(pipeline, GST_STATE_NULL);
g_print("Freeing pipeline...\n");
gst_object_unref(GST_OBJECT(pipeline));
g_print("Completed. Goodbye!\n");
return 0;
}
你们能否让我知道如何将这些垫链接到 h264parser 元素以流式传输视频文件。如果可能,请解释这些垫如何在 Gstreamer 工具和应用程序中工作
解决方案
以下命令成功流式传输 mp4 视频文件: gst-launch-1.0.exe -v filesrc location=file.mp4 !qtdemux !h264解析!avdec_h264 !视频转换!自动视频接收器
理想情况下,您的管道应该是:
gst-launch-1.0.exe -v filesrc location=file.mp4 !qtdemux 名称=d d.video_0 !队列 !h264解析!avdec_h264 !视频转换!自动视频接收器
如果您检查 qtdemux (gst-inspect-1.0 qtdemux),您会注意到 SINK 焊盘具有以下上限:
功能:视频/快速视频/mj2 音频/x-m4a 应用程序/x-3gp
如果您检查 h264parse (gst-inspect-1.0 h264parse),您会注意到 SRC Pad 具有以下上限:
SRC 模板:'src' 可用性:始终 功能:视频/x-h264 解析:true 流格式:{ (string)avc, (string)avc3, (string)byte-stream } 对齐方式:{ (string)au, (字符串)最后 }
当您尝试将 Qtdemux 的 sink pad 链接到 h264parse 的 src pad 时,您可能需要收集视频 cap 才能与 h264parse 连接。
我已使用以下代码将 qtdemux 与 h264parse 链接到“pad-added”信号中:
static void pad_added_handler(GstElement *src, GstPad *new_pad, gpointer *data) {
GstPadLinkReturn ret;
GstCaps *new_pad_caps = NULL;
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
GstElement *h264parse = (GstElement *) data;
/* Check the new pad's type */
new_pad_caps = gst_pad_get_current_caps(new_pad);
new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);
new_pad_type = gst_structure_get_name(new_pad_struct);
if (g_str_has_prefix(new_pad_type, "video/x-h264")) {
GstPad *sink_pad_video = gst_element_get_static_pad (h264parse, "sink");
ret = gst_pad_link(new_pad, sink_pad_video);
}
}
注意:您可能需要链接 caps 过滤器来过滤视频源的所需视频功能,或者只是尝试以下条件: if (g_str_has_prefix(new_pad_type, " video ")) {}
但我不确定添加队列如何解决您的问题。
希望这可以帮助。
推荐阅读
- reactjs - 最佳实践:将 Twitter 访问令牌发送到服务器
- import - 在 PyCharm 中重构目录结构后修复项目中的所有导入路径
- kdb - 在某些条件下删除表重复项
- php - 如何避免 php mail() 函数将电子邮件发送到垃圾邮件文件夹?
- django - 用 django 中的信号更新
- reactjs - Google recaptcha 无法读取 null 的属性“样式”
- android - 在 Android 中以编程方式检测“显示虚拟键盘”设置
- c - 这是结构的正确用法吗?
- javascript - 根据 Javascript 中选中的复选框组合显示搜索结果
- c++ - 在调用针对不同特征矩阵类型重载的函数时避免 eval