当前位置: 首页 > news >正文

T31开发笔记:librtmp拉流测试

若该文为原创文章,转载请注明原文出处。

T31使用librtmp拉流并保存成FLV文件或H264和AAC文件。

librtmp编译在前面有教程,自行编译。

实现的目的是想要获取获取rtmp的AAC流并播放,实时双向对讲功能。

一、硬件和开发环境
1、硬件:T31X+SC5235 

2、开发环境: ubuntu16.04-64bit

3、编译器:mips-gcc540-glibc222-32bit-r3.3.0.tar.gz

注:板子和和WIFI模块是某淘上淘的,使用的是RTL8188,使用的是USB接口,uboot和内核是自己裁剪移植的,内核默认自带WIFI驱动,所以不用移植可以直接使用。
 

二、使用librtmp拉流流程

  1. 初使化RTMP上下文
  2. 设置拉流地址
  3. 连接服务器
  4. 连接流地址
  5. 循环拉流,提取媒体数据,保存为文件或者交给解码模块
  6. 拉流完毕,释放资源

三、代码解析

编译代码需要用到的库,本人在T31上使用的是静态库,可以自行改成动态库,以减少编译文件的大小 。

编译所需的库有:librtmp.a、libssl.a、libcrypto.a、libz.a

下面这个例子演示了使用librtmp库从服务器拉流到本地保存为flv文件或是h264和aac文件,代码如下:

/*!*******************************************************************************  Copyright ? 2017-2018 yifeng. All Rights Reserved.** \file      main.c* \author    yifeng* \version   1.0* \date      2022年3月3日* \brief     rtmp测试代码**----------------------------------------------------------------------------* \attention********************************************************************************//*****************************************************************************change history: 1.date  : 2022年3月3日author: yifengchange: create file*****************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>/* 环形队列头文件 */
#include "xiecc_rtmp.h"
#include "rtmp.h"typedef unsigned long   ULONG;
typedef unsigned int    UINT;
typedef unsigned char   BYTE;
typedef char            _TCHAR;uint8_t nalu_header[4] = { 0x00, 0x00, 0x00, 0x01 };/*!* \fn     main* \brief  主函数*          * \param  [in] int argc       #* \param  [in] char *argv[]   #* * \retval int*/
int main(int argc, char *argv[])
{ uint16_t object_type = 0;uint16_t sample_frequency_index = 0;uint8_t  channels = 0;uint8_t  frame_length_flag = 0;uint8_t  depend_on_core_coder = 0;uint8_t  extension_flag = 0;// 初使化RTMP上下文RTMP* pRTMP = RTMP_Alloc();RTMP_Init(pRTMP);// 设置拉流地址RTMP_SetupURL(pRTMP, (char*)"rtmp://192.168.0.109/live/stream");// 连接服务器pRTMP->Link.timeout = 10;pRTMP->Link.lFlags |= RTMP_LF_LIVE;bool b = RTMP_Connect(pRTMP, NULL);if (!b){printf("connect failed! \n");return -1;}// 连接流地址b = RTMP_ConnectStream(pRTMP, 0);if (!b){printf("connect stream failed! \n");return -1;}bool bSaveFlv = false;  // 保存成FLV格式FILE *pFile = fopen("testrtmp.flv", "wb");FILE *h264_file_ptr = fopen("testrtmp.h264", "wb");FILE *aac_file_ptr = fopen("testrtmp.aac", "wb");while (RTMP_IsConnected(pRTMP)){if (bSaveFlv == true){char sBuf[4096] = {0};int bytes = RTMP_Read(pRTMP, sBuf, sizeof(sBuf));printf("RTMP_Read() ret:[%d] \n", bytes);if (bytes <= 0)break;fwrite(sBuf, 1, bytes, pFile);}else{RTMPPacket packet;RTMPPacket_Reset(&packet);packet.m_body = NULL;packet.m_chunk = NULL;b = RTMP_ReadPacket(pRTMP, &packet);if (b < 0)break;if (0 == b )continue;if (RTMPPacket_IsReady(&packet)){RTMP_ClientPacket(pRTMP, &packet);if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO){bool keyframe = 0x17 == packet.m_body[0] ? true : false;bool sequence = 0x00 == packet.m_body[1];printf("keyframe=%s, sequence=%s\n", keyframe ? "true" : "false", sequence ? "true" : "false");// SPS/PPS sequenceif (sequence){uint32_t offset = 10;uint32_t sps_num = packet.m_body[offset++] & 0x1f;for (int i = 0; i < sps_num; i++) {uint8_t ch0 = packet.m_body[offset];uint8_t ch1 = packet.m_body[offset + 1];uint32_t sps_len = ((ch0 << 8) | ch1);offset += 2;// Write sps dataprintf("Write sps data len: %d\n", sps_len);fwrite(nalu_header, sizeof(uint8_t), 4, h264_file_ptr);fwrite(packet.m_body + offset, sizeof(uint8_t), sps_len, h264_file_ptr);offset += sps_len;}uint32_t pps_num = packet.m_body[offset++] & 0x1f;for (int i = 0; i < pps_num; i++) {uint8_t ch0 = packet.m_body[offset];uint8_t ch1 = packet.m_body[offset + 1];uint32_t pps_len = ((ch0 << 8) | ch1);offset += 2;// Write pps dataprintf("Write pps data len: %d\n", pps_len);fwrite(nalu_header, sizeof(uint8_t), 4, h264_file_ptr);fwrite(packet.m_body + offset, sizeof(uint8_t), pps_len, h264_file_ptr);offset += pps_len;}}// Nalu frameselse{uint32_t offset = 5;uint8_t ch0 = packet.m_body[offset];uint8_t ch1 = packet.m_body[offset + 1];uint8_t ch2 = packet.m_body[offset + 2];uint8_t ch3 = packet.m_body[offset + 3];uint32_t data_len = ((ch0 << 24) | (ch1 << 16) | (ch2 << 8) | ch3);offset += 4;// Write nalu data(already started with '0x00,0x00,0x00,0x01')printf("Write nalu data len: %d\n", data_len);fwrite(nalu_header, sizeof(uint8_t), 4, h264_file_ptr);fwrite(packet.m_body + offset, sizeof(uint8_t), data_len, h264_file_ptr);offset += data_len;}}else if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO){bool sequence = 0x00 == packet.m_body[1];printf("sequence=%s\n", sequence ? "true" : "false");// AAC sequenceif (sequence) {uint8_t format = (packet.m_body[0] & 0xf0) >> 4;uint8_t samplerate = (packet.m_body[0] & 0x0c) >> 2;uint8_t sampledepth = (packet.m_body[0] & 0x02) >> 1;uint8_t type = packet.m_body[0] & 0x01;// sequence = packet.m_body[1];// AAC(AudioSpecificConfig)if (format == 10){uint8_t ch0 = packet.m_body[2];uint8_t ch1 = packet.m_body[3];uint16_t config = ((ch0 << 8) | ch1);object_type = (config & 0xF800) >> 11;sample_frequency_index = (config & 0x0780) >> 7;channels = (config & 0x78) >> 3;frame_length_flag = (config & 0x04) >> 2;depend_on_core_coder = (config & 0x02) >> 1;extension_flag = config & 0x01;}// Speex(Fix data here, so no need to parse...)else if (format == 11) {// 16 KHz, mono, 16bit/sampletype = 0;sampledepth = 1;samplerate = 4;}}// Audio frameselse {// ADTS(7 bytes) + AAC datauint32_t data_len = packet.m_nBodySize - 2 + 7;uint8_t adts[7];adts[0] = 0xff;adts[1] = 0xf1;adts[2] = ((object_type - 1) << 6) | (sample_frequency_index << 2) | (channels >> 2);adts[3] = ((channels & 3) << 6) + (data_len >> 11);adts[4] = (data_len & 0x7FF) >> 3;adts[5] = ((data_len & 7) << 5) + 0x1F;adts[6] = 0xfc;// Write audio framesprintf("Write audio frames len: %d\n", packet.m_nBodySize - 2);fwrite(adts, sizeof(uint8_t), 7, aac_file_ptr);fwrite(packet.m_body + 2, sizeof(uint8_t), packet.m_nBodySize - 2, aac_file_ptr);}}else if (packet.m_packetType == RTMP_PACKET_TYPE_INFO) {// TODO:// ...printf("RTMP_PACKET_TYPE_INFO1\n");}else {// TODO:// ...printf("RTMP_PACKET_TYPE_INFO2\n");}}RTMPPacket_Free(&packet);}}fclose(pFile);RTMP_Close(pRTMP);RTMP_Free(pRTMP);return 0;
}

定义了bSaveFlv标记,是否保存成flv文件,true保存成flv文件,否则保存成aac和h264,

rtmp的Url需要根据自己的服务器修改。

四、测试结果

执行后,在当前目录下生成264和aac文件

把文件复制到pc端用vlc播放

 使用librtmp拉流网友説会有问题,目前测试是正常,有遇到的网友麻烦告知一下。谢谢。

如有侵权,或需要完整代码,请及时联系博主。

相关文章:

T31开发笔记:librtmp拉流测试

若该文为原创文章&#xff0c;转载请注明原文出处。 T31使用librtmp拉流并保存成FLV文件或H264和AAC文件。 librtmp编译在前面有教程&#xff0c;自行编译。 实现的目的是想要获取获取rtmp的AAC流并播放&#xff0c;实时双向对讲功能。 一、硬件和开发环境 1、硬件&#xff1…...

2308C++概念化

原文 库 //概念化(需要C20) struct 可画 {void 画(小出流 &out) const {te::call([](auto const &s, auto &out)-> decltype(s.画(out)) { s.画(out); }, *this, out);} }; struct 方形 {void 画(小出流 &out) const { out << "方形"; } }…...

flutter开发实战-实现自定义按钮类似UIButton效果

flutter开发实战-实现自定义按钮类似UIButton效果 最近开发过程中需要实现一下UIButton效果的flutter按钮&#xff0c;这里使用的是监听手势点击事件。 一、GestureDetector GestureDetector属性定义 GestureDetector({super.key,this.child,this.onTapDown,this.onTapUp,t…...

深度优先搜索|1034, 1020, 1254

深度优先搜索|1034. 边界着色&#xff0c; 机器人的运动范围&#xff0c;529. 扫雷游戏 边界着色机器人的运动范围扫雷问题 边界着色 把这个题分段了&#xff0c;先找到包括 (row, col) 的连通分量&#xff0c;然后再去找符合条件的边界&#xff0c;找到以后涂上颜色就行。 c…...

都市信息供求网servlet+jsp新闻广告出售java源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 都市信息供求网servletjsp 系统1权限&#xff1a;管理…...

kubeadm init:failed to pull image registry.k8s.io/pause:3.6

错误信息&#xff1a; Unfortunately, an error has occurred: timed out waiting for the condition This error is likely caused by: - The kubelet is not running - The kubelet is unhealthy due to a misconfiguration of the node in some way…...

设计模式之简单工厂模式、工厂模式、抽象工厂模式

参考&#xff1a; 设计模式笔记 简单工厂模式 ● 将类的创建过程交给工厂类实现&#xff0c;如果需要一个类对象&#xff0c;则直接通过工厂创建一个类。 ● 简单工厂模式不符合开闭原则 ● 适用场景&#xff1a;工厂类负责创建的对象比较少&#xff1b;客户端只知道传入工厂…...

C# 控制台彩色深度打印 工具类

文章目录 前言Nuget 环境安装代码使用打印结果 总结 前言 有时候我们想要靠打印获得程序信息&#xff0c;因为Dubeg模式需要一点一点断点进入进出&#xff0c;但是我们觉得断点运行实在是太慢了&#xff0c;还是直接打印后找结果会好一点。 Nuget 环境安装 想自己写的话可以看…...

Pytorch Tensor维度变换方法

1.torch.reshape()、torch.view()可以调整Tensor的shape 2.torch.unsqueeze(index)可以为Tensor增加一个维度 3.squeeze()可以删减维度 4.expand&#xff08;&#xff09;扩展维度 5.repeat()维度重复&#xff0c;不常用 6.transpose(dim1, dim2)交换dim1与dim2&#xff0…...

微信小程序之点击文字文字自动转语音进行播放,微信小程序文字识别转语音播放

需求 一堆题目&#xff0c;题干需要在点击的时候进行语音朗读&#xff0c;不做音频上传&#xff0c;不然不便于维护 解决方案 点击查看微信官方文档&#xff1a;微信同声传译 使用流程 后台配置 mp.weixin.qq.com 设置 > 第三方设置 > 插件管理 小程序插件使用流…...

主动学习、半监督学习、它们之间的区别?

1、主动学习&#xff08;Active Learning&#xff09;&#xff1a; 含义&#xff1a; 有的时候&#xff0c;有类标的数据比较稀少而没有类标的数据是相当丰富的&#xff0c;但是对数据进行人工标注又非常昂贵&#xff0c;这时候&#xff0c;学习算法可以主动地提出一些标注请…...

linux快速安装Rabbitmq

linux快速安装Rabbitmq 准备yum仓库 # root执行rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.ascrpm --import https://packagecloud.io/rabbitmq/erlang/gpgkeyrpm --import https://packagecloud.io/ra…...

spconv1.2.1库的编译与安装

SpConv是一个稀疏卷积库&#xff0c;在点云相关的深度学习算法中用的比较多。由于目前官方升级到了2.0&#xff0c;然而有些算法&#xff08;比如审稿人要我复现的Cylinder3D&#xff09;仍需要用到1.2.1版本&#xff0c;因此本人花了亿点点时间折腾了一下。。。 本机安装cuda…...

java+springboot+mysql企业邮件管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的企业邮件管理系统&#xff0c;系统包含超级管理员、管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;员工管理&#xff1b;反馈管理&#xff1b;系统公告&#xff1b;个人…...

[CKA]考试之一个 Pod 封装多个容器

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 创建一个Pod&#xff0c;名字为kucc1&#xff0c;这个Pod包含4容器&#xff…...

iphone备份用什么软件?好用的苹果数据备份工具推荐!

众所周知&#xff0c;如果要将iPhone的数据跟电脑进行传输备份的话&#xff0c;我们需要用到iTunes这个pc工具。但是对于iTunes&#xff0c;不少人都反映这个软件比较难用&#xff0c;用不习惯。于是&#xff0c;顺应时代命运的iPhone备份同步工具就出现了。那iphone备份用什么…...

一语道破 python 迭代器和生成器

简而言之&#xff1a;迭代器是一个抽象化的概念&#xff0c;在python中表示访问数据集合中元素的一种方式&#xff1b;生成器也是一个抽象化的概念&#xff0c;在python 中&#xff0c;边循环边生成所需数据&#xff0c;是一种时间换空间的方法。从访问数据方式上来看&#xff…...

有哪些开源和非开源的项目管理工具?

开源和非开源项目管理工具各有其特点和优势。下面是一些常见的开源和非开源项目管理工具以及它们的简要介绍。 开源项目管理工具&#xff1a; OpenProject&#xff1a;OpenProject 是一个功能强大、易于使用的开源项目管理工具。它提供了项目计划、任务管理、团队协作、文档管…...

实战 01|「编写互动式界面」

前言 实践是最好的学习方式&#xff0c;技术也如此。 文章目录 前言一、功能需求&#xff08;一&#xff09;1、功能需求描述2、知识点3、布局与程序设计 二、功能需求&#xff08;二&#xff09;1、功能需求描述2、知识点1&#xff09;LinearLayout2&#xff09;RelativeLayou…...

开源社区寻找八月创作之星!你准备好了吗~

活动页面&#xff1a;https://openlab.cosmoplat.com/createStarCampaign-202308​​​​​​卡奥斯开源社区定位打造工业互联网行业顶级开源社区生态平台&#xff0c;为开发者、企业等用户提供代码托管、技术交流/共享、硬件认证/接入、培训认证、大赛活动等服务&#xff0c;目…...

springboot 微信小程序的红色导览之烈士陵园烈士纪念app

目录同行可拿货,招校园代理 ,本人源头供货商功能模块设计交互功能设计后台管理功能特色辅助功能项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作同行可拿货,招校园代理 ,本人源头供货商 功能模块设计 用户管理模块 提供微信授…...

hive strict 严格模式

Hive的严格模式&#xff08;Strict Mode&#xff09;是一道经典的面试题。它的核心是一个安全防护机制&#xff0c;通过限制执行高风险的查询&#xff0c;来防止单个“烂SQL”拖垮整个集群。 &#x1f512; 严格模式禁止的三大类查询 在 hive.mapred.modestrict 模式下&#…...

Windows 正版系统安装(重装) - Win10(微星主板 - MSI)

一、启动盘制作 本文章为正版 Windows 安装系统流程&#xff0c;安装版本为 Windows 10 家庭版 官方免费版本&#xff01; Mac 制作 Win10 启动盘&#xff08;不推荐&#xff0c;因为 U盘 无法格式化为 NTFS&#xff0c;以前是可以选择 Microsoft NTFS 格式的&#xff0c;但是…...

从零开始:Qwen2.5-3B大模型LoRA微调与ollama本地部署实战

1. 环境准备与工具安装 想要玩转Qwen2.5-3B大模型的微调和部署&#xff0c;首先得把工具和环境准备好。我建议使用Linux系统&#xff08;Ubuntu 20.04&#xff09;或者MacOS&#xff0c;Windows用户可以考虑WSL2。以下是需要安装的核心工具&#xff1a; Python 3.9&#xff1…...

终极指南:zenodo_get深度解析与高效科研数据下载实战

终极指南&#xff1a;zenodo_get深度解析与高效科研数据下载实战 【免费下载链接】zenodo_get Zenodo_get: Downloader for Zenodo records 项目地址: https://gitcode.com/gh_mirrors/ze/zenodo_get 在科研数据管理领域&#xff0c;zenodo_get作为专业的Zenodo记录下载…...

全网疯传「.SKILL」:只要一句话,就能把任何人蒸馏成 AI,前任、老板、乔布斯。。。

不用懂代码、不用学复杂操作&#xff0c;只要一个SKILL&#xff0c;就能把任何人蒸馏成专属AI——同事、老板、前任&#xff0c;甚至乔布斯、张一鸣&#xff0c;都能被你炼入token&#xff0c;随叫随到陪你对话、帮你干活&#xff0c;实用性直接拉满&#xff01;最近刷X的朋友&…...

思源宋体CN:7种字重完全免费的专业中文字体解决方案

思源宋体CN&#xff1a;7种字重完全免费的专业中文字体解决方案 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还在为专业设计中的字体选择而烦恼吗&#xff1f;Source Han Serif CN&…...

军工数据治理实战:从标准制定到平台落地的全流程解析

1. 军工数据治理的挑战与机遇 军工行业的数据治理一直是个让人头疼的问题。我接触过不少军工企业的CIO&#xff0c;他们最常抱怨的就是"系统越建越多&#xff0c;数据越来越乱"。一个典型的军工企业可能同时运行着几十套业务系统——从研发设计用的CAD/CAE&#xff0…...

Muse Spark 闭源转型背后的系统化演进:PAO 架构、KV Cache 压缩与聚合接入实践

摘要&#xff1a; Meta 推动 Muse Spark 走向闭源并非一时兴起&#xff0c;其底层所采用的并联智能体协调架构&#xff08;PAO&#xff09;标志着大模型由单体推理向系统级协同的跃迁。本文将围绕 Transformer 变体设计、节点调度策略、KV Cache 压缩算法及生产环境调用方案四个…...

5分钟快速上手:抖音无水印批量下载工具完整指南

5分钟快速上手&#xff1a;抖音无水印批量下载工具完整指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖…...