基于ffmpeg实现多路rtsp拉流解码为yuv420p

一:前言

        FFmpeg 是一个非常强大的多媒体框架,它可以用来处理视频和音频数据。它包括了命令行工具 ffmpegffplayffprobe 等,以及一套可以用来开发多媒体应用的库(libavcodec、libavformat、libavutil、libswscale 等)。FFmpeg 支持多种音视频格式的转换、编码、解码、流处理等操作。

        RTSP(Real Time Streaming Protocol)是一种网络控制协议,用于建立和控制媒体流的会话。它常用于流媒体应用,比如视频监控系统。RTSP 允许客户端控制媒体流,如播放、暂停、快进等,并且可以支持多种流媒体传输协议,如 RTP(Real-time Transport Protocol)。

二:功能分析

        功能要求:支持多路流媒体信号同时进行解码和保存也就是录播功能。

        功能分析:要想实现多路流媒体信号同时进行解码功能的实现,首先会想到一个问题,那就是同步性,对于多路并非运行而言,其多路从事的其实是一个工作,那就是通过avformat_open_input()打开对应的流文件,然后再对这个流文件进行处理。

        功能实现:更具功能分析可以得到一个实现方案,那就是使用线程并发性的特点,利用多线程互不干扰同时进行的特点来实现多路的流媒体并发解码。下面的示例为两路流并发运行的例子,多路流同样的道理有多少路采用多少线程。思路清晰,条理清晰,直接上具体实现功能。

三:功能实现

单路拉流解码流程

1:打开输入流文件

使用ffmpeg的接口函数:

avformat_alloc_context()

创建一个存储多媒体容器格式信息的结构体。然后用:avformat_open_input()打开流文件。

int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);

其中的第一个参数就是上面函数的返回值,第二个参数就是流地址的RUL,第三个参数为NULL,第四个参数的作用为设置一些解复用器特定的选项,rtsp的默认传输是UDP,可以通过这个参数加上av_dict_set()函数来修改为 TCP协议。

2:寻找媒体信息

int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

第一个参数为上面的创建结构体的函数返回值,第二个为NULL。

然后访问里面的流媒体信息。

fctx->nb_streams;//有几个流媒体

fctx->streams[0];//一般为视频流媒体

fctx->streams[1];//音频

3:创建上下文

avcodec_alloc_context3(NULL)
int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *params);

拷贝流媒体中的数据。

fctx->streams[video_index]->codecpar

4:寻找解码器

AVCodec *avcodec_find_decoder(enum AVCodecID id);

通过ID来寻找对应的解码器。

5:绑定上下文

打开编码器;avcodec_open2();

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);

6:编码并保存

接口函数:

int av_read_frame(AVFormatContext *s, AVPacket *pkt);
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *pkt);
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);

分别的功能为:

向输入流中读取一个数据包

向解码器发送一个压缩数据包

从解码器中接收解码后的帧。

基本解码功能就结束了,要注意资源的回收和释放

av_frame_unref();

释放 AVFrame 结构体中的所有引用的资源

av_packet_unref();

用于释放 AVPacket 结构体中的所有资源。

两路拉流功能实现

两路是用俩线程分别实现俩路解码的过程,解码流程大体不变,不一样的点就是加入两个线程。具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavdevice/avdevice.h>
#include <pthread.h>// 定义视频流索引
int video_index1 = -1;
int video_index2 = -1;
AVFormatContext *fctx1 = NULL;
AVFormatContext *fctx2 = NULL;
// 线程处理函数
void *decode_stream(void *arg) 
{AVFormatContext *format_ctx = (AVFormatContext *)arg;AVCodecContext *codec_ctx = NULL;AVCodec *codec = NULL;AVPacket packet;AVFrame *frame = av_frame_alloc();int ret;FILE *file = NULL;// 寻找视频流int video_stream_index = video_index1;if (format_ctx == fctx2) {video_stream_index = video_index2;file = fopen("2.yuv", "w+");} else {file = fopen("1.yuv", "w+");}if (!file) {printf("创建YUV文件失败\n");return NULL;}// 获取解码器上下文codec_ctx = avcodec_alloc_context3(NULL);avcodec_parameters_to_context(codec_ctx, format_ctx->streams[video_stream_index]->codecpar);// 寻找解码器codec = avcodec_find_decoder(codec_ctx->codec_id);if (codec == NULL) {printf("未找到解码器\n");fclose(file);return NULL;}// 打开解码器if (avcodec_open2(codec_ctx, codec, NULL) < 0) {printf("无法打开解码器\n");fclose(file);return NULL;}// 读取数据并解码av_init_packet(&packet);packet.data = NULL;packet.size = 0;while (av_read_frame(format_ctx, &packet) >= 0) {if (packet.stream_index == video_stream_index) {ret = avcodec_send_packet(codec_ctx, &packet);if (ret < 0) {printf("发送数据到解码器失败\n");break;}while (ret >= 0) {ret = avcodec_receive_frame(codec_ctx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {break;} else if (ret < 0){printf("解码失败\n");break;}// 写入YUV数据fwrite(frame->data[0], 1, frame->linesize[0] * frame->height, file);fwrite(frame->data[1], 1, frame->linesize[1] * frame->height / 2, file);fwrite(frame->data[2], 1, frame->linesize[2] * frame->height / 2, file);av_frame_unref(frame);}av_packet_unref(&packet);}}// 释放资源if (frame) {av_frame_free(&frame);}if (codec_ctx) {avcodec_free_context(&codec_ctx);}if (file) {fclose(file);}return NULL;
}int main() 
{avformat_network_init();AVDictionary *options1 = NULL;AVDictionary *options2 = NULL;//定义两路流媒体URLchar filepath1[] = "rtsp://192.168.xx.xx/xx/xx";//根据自己的URL设置char filepath2[] = "rtsp://xxx.xxx.xx.xx.";av_dict_set(&options1, "buffer_size", "1080000", 0);av_dict_set(&options1, "rtsp_transport", "tcp", 0);av_dict_set(&options1, "stimeout", "5000000", 0);av_dict_set(&options1, "max_delay", "500000", 0);av_dict_set(&options2, "buffer_size", "720000", 0);av_dict_set(&options2, "rtsp_transport", "tcp", 0);av_dict_set(&options2, "stimeout", "5000000", 0);av_dict_set(&options2, "max_delay", "500000", 0);//1:打开输入流文件fctx1 = avformat_alloc_context();fctx2 = avformat_alloc_context();if (avformat_open_input(&fctx1, filepath1, NULL, &options1) < 0) {printf("第一路流文件打开失败\n");return -1;}if (avformat_open_input(&fctx2, filepath2, NULL, &options2) < 0) {printf("第二路流文件打开失败\n");avformat_close_input(&fctx1);avformat_free_context(fctx1);return -1;}if (avformat_find_stream_info(fctx1, NULL) < 0) {printf("第一路流文件非流媒体文件\n");avformat_close_input(&fctx1);avformat_close_input(&fctx2);avformat_free_context(fctx1);avformat_free_context(fctx2);return -1;}if (avformat_find_stream_info(fctx2, NULL) < 0) {printf("第二路流文件非流媒体文件\n");avformat_close_input(&fctx1);avformat_close_input(&fctx2);avformat_free_context(fctx1);avformat_free_context(fctx2);return -1;}//寻找对应的视频流索引for (int i = 0; i < fctx1->nb_streams; i++) {if (fctx1->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_index1 = i;break;}}for (int i = 0; i < fctx2->nb_streams; i++) {if (fctx2->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_index2 = i;break;}}//创建线程pthread_t tid1, tid2;pthread_create(&tid1, NULL, decode_stream, fctx1);pthread_create(&tid2, NULL, decode_stream, fctx2);pthread_join(tid1, NULL);pthread_join(tid2, NULL);avformat_close_input(&fctx1);avformat_close_input(&fctx2);avformat_free_context(fctx1);avformat_free_context(fctx2);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在线深度学习:爱奇艺效果广告分钟级模型优化

01# 背景 在效果广告投放场景中&#xff0c;媒体侧需要准确衡量每次请求的价值&#xff0c;模型预估值在广告竞价中扮演着核心角色。模型预估精度的提升&#xff0c;是改善媒体侧变现效率、提升广告收益的核心技术驱动力。 此前&#xff0c;爱奇艺效果广告预估模型为小时级模型…

构建流媒体管道:利用 Docker 部署 Nginx-RTMP 从 FFmpeg RTMP 推流到 HLS 播放的完整流程

最近要实现一个类似导播台的功能&#xff0c;于是我先用 FFmpeg 实现一个参考对照的 Demo&#xff0c;我将其整理为一篇文章&#xff0c;方便后续大家或者和自己参考&#xff01; 1、软件工具介绍 本次部署相关软件 / 工具如下&#xff1a; FFmpeg&#xff1a;全称是 Fast Fo…

软件确认测试内容和方法分享,CMA、CNAS第三方软件检测机构推荐

在现代软件开发中&#xff0c;软件确认测试扮演着至关重要的角色。它不仅帮助开发团队识别系统中的缺陷&#xff0c;还确保软件产品符合用户需求和期望。 软件确认测试旨在验证软件系统的性能和功能是否符合设计规格和用户需求。它通常在软件开发的后期进行&#xff0c;以确保…

火语言RPA流程组件介绍--浏览器上传文件

&#x1f6a9;【组件功能】&#xff1a;在浏览器内自动点击上传功能按钮&#xff0c;选择本地文件完成文件网页上传 配置预览 配置说明 目标元素 支持T或# 通过捕获网页元素或填写css,xpath获取网页元素作为操作目标 上传文件路径 支持T或# 默认FLOW输入项 需要上传的文件…

从零开始构建:Python自定义脚本自动化你的日常任务

从零开始构建&#xff1a;Python自定义脚本自动化你的日常任务 Python 作为一种简洁且功能强大的编程语言&#xff0c;被广泛应用于各种自动化任务中。通过编写 Python 脚本&#xff0c;你可以轻松地将日常重复性工作自动化&#xff0c;例如文件操作、数据处理、网络爬虫、系统…

vue3--通用 button 组件实现

背景 在日常开发中,我们一般都是利用一些诸如:element-ui、element-plus、ant-design等组件库去做我们的页面或者系统 这些对于一些后台管理系统来说是最好的选择,因为后台管理系统其实都是大同小异的,包括功能、布局结构等 但是对于前台项目,比如官网、门户网站这些 …

【Linux驱动开发】嵌入式Linux驱动开发基本步骤,字符驱动和新字符驱动开发入门,点亮LED

【Linux驱动开发】嵌入式Linux驱动开发基本步骤&#xff0c;字符驱动和新字符驱动开发入门&#xff0c;点亮LED 文章目录 开发环境驱动文件编译驱动安装驱动自动创建设备节点文件 驱动开发驱动设备号地址映射&#xff0c;虚拟内存和硬件内存地址字符驱动旧字符驱动新字符驱动 …

live2d 实时虚拟数字人形象页面显示,对接大模型

live2dSpeek 测试不用gpu可以正常运行 https://github.com/lyz1810/live2dSpeek 运行的话还需要额外下载https://github.com/lyz1810/edge-tts支持语音 ## 运行live2dSpeek >npm install -g http-server >http-server . ## 运行edge-tts python edge-tts.py

使用 Helsinki-NLP 中英文翻译本地部署 - python 实现

通过 Helsinki-NLP 本地部署中英文翻译功能。该开源模型性价比相对高&#xff0c;资源占用少&#xff0c;对于翻译要求不高的应用场景可以使用&#xff0c;比如单词&#xff0c;简单句式的中英文翻译。 该示例使用的模型下载地址&#xff1a;【免费】Helsinki-NLP中英文翻译本…

心觉:激活潜意识财富密码:每天一练,财富自动来

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作200/1000天 为什么有些人总是轻而易举地吸引到财富 而你却努力多年仍然徘徊在财务的困境中&#xff1f; 你每天都在辛苦工作&…

MambaVision原理和源码调测

Hatamizadeh, Ali and Jan Kautz. “MambaVision: A Hybrid Mamba-Transformer Vision Backbone.” ArXiv abs/2407.08083 (2024): n. pag. 1.模型原理 关键思路&#xff1a; 通过重新设计Mamba的架构和在最终层增加自注意力块&#xff0c;提高了Mamba模型对视觉特征的建模能力…

C语言练习

题目&#xff1a; 1.运用switch选择语句&#xff0c;编写一段C语言&#xff0c;请根据输入的数字&#xff0c;显示相应的星期日&#xff0c;如果数字所对应的星期日并不存在请显示“抱歉&#xff0c;您输入的内容并不存在。” 分析&#xff1a;1.在本题中&#xff0c;要运用到…

C语言之扫雷小游戏(完整代码版)

说起扫雷游戏&#xff0c;这应该是很多人童年的回忆吧&#xff0c;中小学电脑课最常玩的必有扫雷游戏&#xff0c;那么大家知道它是如何开发出来的吗&#xff0c;扫雷游戏背后的原理是什么呢&#xff1f;今天就让我们一探究竟&#xff01; 扫雷游戏介绍 如下图&#xff0c;简…

【网络安全】漏洞案例:提升 Self-XSS 危害

未经许可,不得转载。 文章目录 Self-XSS-1Self-XSS-2Self-XSS-1 目标应用程序为某在线商店,在其注册页面的First Name字段中注入XSS Payload: 注册成功,但当我尝试登录我的帐户时,我得到了403 Forbidden,即无法登录我的帐户。 我很好奇为什么我无法登录我的帐户,所以我…

如何破解 AI 聊天机器人让它们吐露秘密!窥探 AI 系统指令的 10 种技巧

​ 有时&#xff0c;为了确保 AI 的安全性和透明性&#xff0c;用户需要自己动手&#xff0c;揭开系统指令的面纱。 如果人工智能现在已经成为生活中的事实&#xff0c;并影响着我们的福祉&#xff0c;人们理应知道它的运作原理。 对一些人来说&#xff0c;科幻电影中的经典…

新装ubuntu22.04必做两件事,不然可能没法用

一、换服务源 在全部里面找到软件和安装&#xff1b;打开后 在更多里面匹配一下最适合自己的软件源&#xff1b;这个过程比较漫长&#xff1b;要耐心等待 二、换软件安装中心 先执行&#xff1a; sudo apt upgrade 后执行&#xff1a; sudo apt install plasma-discover…

初级网络工程师之从入门到入狱(四)

本文是我在学习过程中记录学习的点点滴滴&#xff0c;目的是为了学完之后巩固一下顺便也和大家分享一下&#xff0c;日后忘记了也可以方便快速的复习。 网络工程师从入门到入狱 前言一、Wlan应用实战1.1、拓扑图详解1.2、LSW11.3、AC11.4、抓包1.5、Tunnel隧道模式解析1.6、AP、…

【AIF-C01认证】亚马逊云科技生成式 AI 认证正式上线啦

文章目录 一、AIF-C01简介二、考试概览三、考试知识点3.1 AI 和 ML 基础知识3.2 生成式人工智能基础3.3 基础模型的应用3.4 负责任 AI 准则3.5 AI 解决方案的安全性、合规性和监管 四、备考课程4.1 「备考训练营」 在线直播课4.2 「SkillBuilder」学习课程 五、常见问题六、参考…

Flutter技术学习

以下内容更适用于 不拘泥于教程学习&#xff0c;而是从简单项目入手的初学者。 在开始第一个项目之前&#xff0c;我们先要了解 两个概念。 Widget 和 属性 Widget 是用户界面的基本构建块&#xff0c;可以是任何 UI 元素。属性 是 widget 类中定义的变量&#xff0c;用于配…

【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024)

【IEEE独立出版 | 厦门大学主办】 第四届人工智能、机器人和通信国际会议&#xff08;ICAIRC 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 2024年12月27-29日 | 中国厦门 >>往届均已成功见刊检索…