Gsteamer播放MP4文件

news/2024/9/20 7:20:01/ 标签: gstreamer, 视频编解码, 音视频, c语言, c++

1.概述:

gstreamer提供了gst-launch工具,使用该工具我们可以很方便的搭建各种管道,比如gst-launc-1.0 videotestsrc ! autovideosink输入上述命令,我们就能测试视频通路是否OK,但有些场景需要我们提供代码形式。本篇文章将以mp4视频文件的播放为例子介绍基于gst-launc-1.0以及代码形式如何实现MP4视频文件播放.

2.使用gst-launch工具

终端输入如下命令即可播放MP4视频(封装格式是MP4,编码格式是H264的视频文件)

gst-launch-1.0 filesrc location = /path/to/your/file.mp4 ! qtdemux ! queue ! h264parse ! omxh264dec ! queue! v4l2sink device=/dev/video1

omxh264dec为h264硬解码器,不同平台所提供的h264硬解码器并不一样,需根据平台自行更换h264硬解码器,没有硬解码器可以使用avdec_h264替代进入软解码。

也可以使用playbin进行播放如下:

gst-launch-1.0 playbin uri=file:///path/to/your/file.mp4

3.代码形式实现MP4文件播放

在开发某个视频播放需求时,我们一般会使用gst-launch工具快速构建管道测试此管道是否满足这个需求,当验证通过后我们就会以此管道为参照以代码形式去实现此管道。

为什么一定要用代码去实现,不能直接调用系统命令执行管道这个问题?

1.命令行方式无法获取各元素的状态

2.无法精确控制pad的连接/断开,设置管道的各种状态以及错误信息判断等

3.1 快速构建管道代码

当我们实现的需求很简单,举个例子实现一个视频播放,如果不需要对每个元素精确设置属性,我们可以借助gst_parse_launch将gst-launch使用的管道快速转换成代码:

代码如下:

gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data)
{GstElement*    pipeline =(GstElement*    )data;switch (GST_MESSAGE_TYPE (message)){case GST_MESSAGE_ERROR:{GError *err;gchar *debug;gst_message_parse_error (message, &err, &debug);printf("####Error: %s\n", err->message);g_error_free (err);g_free (debug);break;}case GST_MESSAGE_ASYNC_DONE:{printf("######### logo play GST_MESSAGE_ASYNC_DONE #########");gst_element_set_state(pipeline, GST_STATE_PLAYING);}break;case GST_MESSAGE_EOS:{printf("######### logo play eos #########");}break;default:/* unhandled message */break;}return TRUE;
}
// play logo
void PlayLogo()
{char cmd[256];string file_path = "test.mp4"if (!gst_is_initialized()){if (!gst_init_check(nullptr, nullptr, nullptr)){return;}}sprintf(cmd,"filesrc location = %s ! qtdemux ! queue ! h264parse ! omxh264dec ! queue! v4l2sink \"device=/dev/video1\"",file_path.c_str())GstElement * logo_play_pipeline = gst_parse_launch(cmd,nullptr);bus = gst_pipeline_get_bus (GST_PIPELINE (logo_play_pipeline));gst_bus_add_watch (bus, my_bus_callback, logo_play_pipeline);gst_element_set_state(logo_play_pipeline, GST_STATE_PLAYING);g_main_loop_run(g_main_loop_new(NULL, FALSE));/* Free resources */gst_object_unref (bus);gst_element_set_state (logo_play_pipeline, GST_STATE_NULL);gst_object_unref (logo_play_pipeline);
}
3.2 构建管道代码

当我们需要对每个元素精确设置属性/操作时,或者在某些状态下控制pad的连接/断开等等,我们最好的方式是单独创建出每个element然后链接成管道,这样就能在有需要做逻辑的地方直接操作element.

代码举例如下:

/* This function will be called by the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *new_pad, GstElement *data){GstPad *sink_pad = gst_element_get_static_pad (data, "sink");GstPadTemplate* name_template = gst_pad_get_pad_template(new_pad);GstPadLinkReturn ret;/* If our converter is already linked, we have nothing to do here */if (gst_pad_is_linked (sink_pad)) {/* Unreference the sink pad */gst_object_unref (sink_pad);MWP_WARN("We are already linked. Ignoring:%s\n",name_template->name_template);return;}/* Check the new pad's type */if ((name_template != nullptr) && g_strcmp0(name_template->name_template, "video_%u") == 0){/* Attempt the link */ret = gst_pad_link (new_pad, sink_pad);if (GST_PAD_LINK_FAILED (ret)) {MWP_ERROR ("Type is '%s' but link failed.\n",name_template->name_template);} else {MWP_DEBUG ("Link succeeded (type '%s').\n",name_template->name_template);}}/* Unreference the sink pad */gst_object_unref (sink_pad);return;
}/* This function will be creat pipeline for mp4 video file to play.  */
GstElement * CreatLogoPlayPipeLine(std::string path)
{GstElement* logoPipeline = nullptr;GstElement* fileSrc = nullptr;GstElement* qtDemux = nullptr;GstElement* queue1 = nullptr;GstElement* h264parse = nullptr;GstElement* omxh264dec = nullptr;GstElement* queue2 = nullptr;GstElement* v4l2sink = nullptr;/* Create the empty pipeline */logoPipeline = gst_pipeline_new("logoPlayPipeLine");/* Create the elements */fileSrc = gst_element_factory_make ("filesrc", "filesrc");qtDemux = gst_element_factory_make ("qtdemux", "qtdemux");queue1 = gst_element_factory_make ("queue", "queue1");h264parse = gst_element_factory_make ("h264parse", "h264parse");omxh264dec = gst_element_factory_make ("omxh264dec", "omxh264dec");queue2 = gst_element_factory_make ("queue", "queue2");v4l2sink = gst_element_factory_make ("v4l2sink", "v4l2sink");if (!logoPipeline || !fileSrc || !qtDemux || !queue1 || !h264parse || !omxh264dec || !queue2 || !v4l2sink){MWP_ERROR("element creat fail!");return nullptr;}g_object_set(G_OBJECT(fileSrc),"location", path.c_str(),nullptr);g_object_set(G_OBJECT(v4l2sink),"sync", false,"device","/dev/video1","io-mode",2,"max-lateness",(gint64)10000000,nullptr);/* Connect to the pad-added signal */g_signal_connect(qtDemux,"pad-added",G_CALLBACK(pad_added_handler),queue1);gst_bin_add_many(GST_BIN(logoPipeline),fileSrc,qtDemux,queue1,h264parse,omxh264dec,queue2,v4l2sink,nullptr);/* Build the pipeline. Note that we are NOT linking the source at this* point. We will do it later. */if (!gst_element_link_many(fileSrc,qtDemux, nullptr)){MWP_ERROR("[CreatLogoPlayPipeLine] pipeline elements could not be linked");if(logoPipeline != nullptr){gst_object_unref(logoPipeline);}return nullptr;}if (!gst_element_link_many(queue1,h264parse,omxh264dec,queue2,v4l2sink, nullptr)){MWP_ERROR("[CreatLogoPlayPipeLine] pipeline elements could not be linked");if(logoPipeline != nullptr){gst_object_unref(logoPipeline);}return nullptr;}return logoPipeline;
}// play logo
void PlayLogo()
{char cmd[256];string file_path = "test.mp4"/* Initialize GStreamer */if (!gst_is_initialized()){if (!gst_init_check(nullptr, nullptr, nullptr)){return;}}GstElement * logo_play_pipeline = CreatLogoPlayPipeLine(file_path);bus = gst_pipeline_get_bus (GST_PIPELINE (logo_play_pipeline));gst_bus_add_watch (bus, my_bus_callback, logo_play_pipeline);gst_element_set_state(logo_play_pipeline, GST_STATE_PLAYING);g_main_loop_run(g_main_loop_new(NULL, FALSE));/* Free resources */gst_object_unref (bus);gst_element_set_state (logo_play_pipeline, GST_STATE_NULL);gst_object_unref (logo_play_pipeline);
}

Tips:由于它包含demuxer(qtdemux),它的源pad最初不可用,我们需要动态链接到它们。所以管道初始化时分为两部分,第一部分为fileSrc–>qtDemux,第二部分为queue1–>h264parse–>omxh264dec–>queue2–>v4l2sink,第一部分和第二部分管道的链接需要在运行时pad-added时进行两部分的最后的链接。


http://www.ppmy.cn/news/1460946.html

相关文章

博弈智能的特点

博弈智能是指通过算法和模型对博弈过程进行分析和决策的智能系统。在博弈中,各方参与者追求自身利益和目标,会采取各种策略来达到自己的目标。其中,包括了一些不正当手段,如诡计和欺骗(诡)(诈&a…

理解Oracle闪回级别【Oracle闪回技术】(一)

Oracle闪回技术是数据恢复技术,具有恢复时间快,不适用备份文件。可以使数据库回到某个状态。 可以满足用户的逻辑处理的快速恢复。 但是闪回技术只是逻辑数据恢复,如果是数据文件损坏,必须依赖介质才能恢复。 闪回技术的特性&…

对比学习笔记

这里写目录标题 什么是对比学习计算机视觉中的对比学习对比学习在NLP中的应用 什么是对比学习 对比学习是在没有标签的前提下学习样本之间的是否相似,其实和二分类比较相似,判断两个图像是不是属于同一个类别。换句话来说就是把相近的分布推得更近&…

【MySQL 数据宝典】【索引原理】- 008 数据库优化基本思路

一、影响性能的因素 1.1 商业需求影响性能 1.1.1 不合理需求 需求:一个论坛帖子总量的统计 附加要求:实时更新 初级阶段:SELECT COUNT(*)新建一个表,在这个表中更新这个汇总数据(频率问题)真正的问题在于…

大数据Scala教程从入门到精通第一篇:Scala基本介绍

一:Scala基本介绍 1:Scala相当于Java的增强版和拓展 Scala 基于 JVM和 Java 完全兼容。同样具有跨平台、可移植性好、方便的垃圾回收等特性 Scala 比 Java 更加面向对象,可以说完全面对对象。 Scala 是一门函数式编程语言,Java就…

外卖系统微信小程序支付

微信小程序支付时序图 其中第9.步骤就是微信小程序前端调用wx.requestPayment

【Web后端】实现文件上传

表单必须使用post提交 ,enctype 必须是multipart/form-data在Servlet上填加注解 MultipartConfiglocation :默认情况下将存储文件的目录,默认值为“”。maxFileSize :允许上传文件的最大大小,其值以字节为单位。 默认值为-1L表示无…

【408精华知识】提高外部排序速度的三种方式

文章目录 一、败者树二、置换-选择排序三、最佳归并树 一、败者树 还没写完… 二、置换-选择排序 三、最佳归并树 写在后面 这个专栏主要是我在学习408真题的过程中总结的一些笔记,因为我学的也很一般,如果有错误和不足之处,还望大家在评…

【k8s多集群管理平台开发实践】九、client-go实现nginx-ingress读取列表、创建ingress、读取更新yaml配置

文章目录 简介 一.k8s的ingress列表1.1.controllers控制器代码1.2.models模型代码 二.创建ingress2.1.controllers控制器代码2.2.models模分代码 三.读取和更新ingress的yaml配置3.1.controllers控制器代码3.2.models模型代码 四.路由设置4.1.路由设置 五.前端代码5.1.列表部分…

C++面向对象学习笔记三

本文学习大佬的文章,所摘录和整理的一些知识《C面向对象程序设计》✍千处细节、万字总结(建议收藏)_c面向对象程序设计千处细节-CSDN博客 文章目录 文章目录 前言 正文 const修饰符 void型指针 内联函数 带有默认参数值的函数 new和delete运…

如何提高自己的全局视野?

以下是一些可以帮助提高全局视野的方法: 1. 广泛学习不同领域知识:包括但不限于技术相关的各个领域、业务知识、行业动态等,拓宽知识面。 2. 参与大型项目:积极投身到复杂的、规模较大的项目中,在实践中感受和理解系…

蓝桥杯备战16.砝码称重

P2347 [NOIP1996 提高组] 砝码称重 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> using namespace std; #define endl \n #define int long long const int N 2e510; int a[N],f[N]; int w[] {0,1,2,3,5,10,20}; signed main() {std::ios::sy…

Sass:强大而灵活的CSS预处理器详解

Sass&#xff1a;强大而灵活的CSS预处理器详解 在前端开发的世界里&#xff0c;CSS&#xff08;层叠样式表&#xff09;作为样式描述语言&#xff0c;为我们提供了丰富的样式定义和布局方式。然而&#xff0c;随着项目规模的不断扩大和复杂度的提升&#xff0c;原生CSS的编写和…

【JVM】垃圾回收机制(Garbage Collection)

目录 一、什么是垃圾回收&#xff1f; 二、为什么要有垃圾回收机制&#xff08;GC&#xff09;&#xff1f; 三、垃圾回收主要回收的内存区域 四、死亡对象的判断算法 a&#xff09;引用计数算法 b&#xff09;可达性分析算法 五、垃圾回收算法 a&#xff09;标记-清除…

23种设计模式(软考中级 软件设计师)

设计模式 23个设计模式&#xff0c;23个意图 1. 设计模式概要 设计模式的核心在于提供了相关问题的解决方案&#xff0c;使得人们可以更加简单方便的复用成功的设计和体系结构 设计模式的类别 创建型结构型行为型类工厂方法模式适配器模式&#xff08;类&#xff09;解释器模…

HIVE调优-数据倾斜优化(详细版)

HIVE调优-数据倾斜优化 目录 HIVE调优-数据倾斜优化 1.排序优化 1&#xff09;order by 2&#xff09;distribute by sort by 3&#xff09;cluster by语句&#xff1a; 2.数据倾斜优化 1&#xff09;原因&#xff1a; 2&#xff09;表现&#xff1a; 3&#xff09…

蓝桥杯国赛每日一题:献给阿尔吉侬的花束(BFS)

题目描述&#xff1a; 阿尔吉侬是一只聪明又慵懒的小白鼠&#xff0c;它最擅长的就是走各种各样的迷宫。 今天它要挑战一个非常大的迷宫&#xff0c;研究员们为了鼓励阿尔吉侬尽快到达终点&#xff0c;就在终点放了一块阿尔吉侬最喜欢的奶酪。 现在研究员们想知道&#xff0…

python从零开始学习深度学习01——神经网络反向传播的链式求导

自我介绍 最懂保险的算法工程师&#xff0c;致力于保险理念的推广&#xff0c;让每个程序员在35岁时都能够免除后顾之忧。通过构建保险组合&#xff0c;避免中年因病致穷&#xff0c;苦攒多年积蓄全部花费在医疗上&#xff0c;因此返贫。有兴趣的朋友后台私信加V&#xff1a;A…

使用 GPT-4-turbo+Streamlit+wiki+calculator构建Math Agents应用【Step by Step】

&#x1f496; Brief&#xff1a;大家好&#xff0c;我是Zeeland。Tags: 大模型创业、LangChain Top Contributor、算法工程师、Promptulate founder、Python开发者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 个人说明书&#xff1a;Zeeland&…

Java入门基础学习笔记22——程序流程控制

程序流程控制&#xff1a;控制程序的执行顺序。 程序有哪些执行顺序&#xff1f; 顺序、分支和循环。 分支结构&#xff1a; if、switch 循环&#xff1a; for、while、do-while 顺序结构是程序中最简单最基本的流程控制&#xff0c;没有特定的语法结构&#xff0c;按照代码…