news 2026/2/26 5:31:33

使用c/c++实现一个rtmp客户端程序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用c/c++实现一个rtmp客户端程序

一 概述 

        该文章主要实现了rtmp拉流的功能。rtmp协议中的负载视频为h264格式,音频为aac格式.将接收到的流提取出h264裸码流和aac裸码流可以进行解码播放,存储和传输。该客户端程序只实现了将h264视频数据和aac音频数据存入文件.

二 程序的依赖库

     1.ssl(加密认证库)

     2.zip(压缩库)

     3.librtmp(开源库)

     4.rtmp_pull(基于librtmp库封装的拉流库)

        rtmp_pull库,参考下面链接:

https://blog.csdn.net/kk821521286/article/details/157728972?spm=1001.2014.3001.5502https://blog.csdn.net/kk821521286/article/details/157728972?spm=1001.2014.3001.5502

三 关键代码实现

    1.rtmpparse.h  

#ifndef RTMPPARSE_H #define RTMPPARSE_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include "rtmp_pull.h" // 宏定义:RTMP包类型(协议规定) #define RTMP_PACKET_TYPE_AUDIO 0x08 // 音频包 #define RTMP_PACKET_TYPE_VIDEO 0x09 // 视频包 #define RTMP_PACKET_TYPE_AMF0_DATA 0x12 // AMF0数据(包含onMetaData元数据) // 视频编码ID(RTMP协议) #define RTMP_VIDEO_CODEC_H264 0x07 // H.264/AVC // 音频编码ID(RTMP协议) #define RTMP_AUDIO_CODEC_AAC 0x0A // AAC // 帧类型(视频包高4位) #define RTMP_VIDEO_FRAME_KEY 0x10 // 关键帧(I帧) #define RTMP_VIDEO_FRAME_SEQ_HEADER 0x00 // AVC序列头(SPS/PPS) // AAC包类型(音频包扩展位) #define RTMP_AAC_PACKET_CONFIG 0x00 // AAC配置帧(ADTS头参数) #define RTMP_AAC_PACKET_RAW 0x01 // AAC原始数据帧 /************************** 解析结果结构化定义 **************************/ // 视频包解析结果 typedef struct { int is_h264; // 是否为H.264编码 int is_seq_header; // 是否为AVC序列头(SPS/PPS,必须先解析这个才能解码) int is_key_frame; // 是否为关键帧 uint8_t* raw_data; // 原始H.264数据(去掉RTMP头部后的纯数据) int raw_data_len; // 原始H.264数据长度 } RtmpVideoFrame; // 音频包解析结果 typedef struct { int is_aac; // 是否为AAC编码 int is_config; // 是否为AAC配置帧(必须先解析这个才能解码) uint8_t* raw_data; // 原始AAC数据(去掉RTMP头部后的纯数据) int raw_data_len; // 原始AAC数据长度 int sample_rate; // 采样率(8k/16k/32k/44.1k/48k) int channel; // 声道(1:单声道,2:立体声) int bit_depth; // 位深(8/16位) } RtmpAudioFrame; // 元数据解析结果(onMetaData,包含流的基础信息) typedef struct { double video_width; // 视频宽度 double video_height; // 视频高度 double frame_rate; // 视频帧率 double audio_samplerate; // 音频采样率 double audio_channels; // 音频声道 double duration; // 流总时长(秒,直播流为0) double video_bitrate; // 视频码率(kbps) double audio_bitrate; // 音频码率(kbps) } RtmpMetaData; // 通用RTMP包解析结果 typedef struct { int packet_type; // 包类型:音频/视频/元数据/其他 uint32_t timestamp; // 时间戳(毫秒) uint32_t body_len; // 数据包体长度 RtmpVideoFrame video; // 视频包数据(仅packet_type=视频时有效) RtmpAudioFrame audio; // 音频包数据(仅packet_type=音频时有效) RtmpMetaData meta; // 元数据(仅packet_type=元数据时有效) int is_valid; // 解析是否有效(0:无效,1:有效) } RtmpPacketParseResult; #ifdef __cplusplus extern "C"{ #endif void RtmpParseResult_Init(RtmpPacketParseResult* result); void RtmpParseResult_Free(RtmpPacketParseResult* result); int RTMPPullPacket_Parse(RTMPPullPacket* packet, RtmpPacketParseResult* result); #ifdef __cplusplus } #endif #endif // RTMPPARSE_H

2.rtmpparse.cpp

#include "rtmpparse.h" #include <iostream> /************************** 工具函数:初始化/释放解析结果 **************************/ // 初始化解析结果结构体 void RtmpParseResult_Init(RtmpPacketParseResult* result) { if (result == NULL) return; memset(result, 0, sizeof(RtmpPacketParseResult)); // 初始化默认值 result->is_valid = 0; result->meta.video_width = 0; result->meta.video_height = 0; result->audio.sample_rate = 0; result->audio.channel = 0; } // 释放解析结果的内存(防止内存泄漏) void RtmpParseResult_Free(RtmpPacketParseResult* result) { if (result == NULL) return; // 释放视频原始数据 if (result->video.raw_data != NULL) { free(result->video.raw_data); result->video.raw_data = NULL; } // 释放音频原始数据 if (result->audio.raw_data != NULL) { free(result->audio.raw_data); result->audio.raw_data = NULL; } // 重置结构体 memset(result, 0, sizeof(RtmpPacketParseResult)); } /************************** 核心解析接口:解析RTMPPacket **************************/ /** * @brief 解析RTMP元数据(onMetaData,AMF0格式) * @param body RTMP包体指针 * @param body_len 包体长度 * @param meta 解析后的元数据结果 * @return 0:失败,1:成功 */ static int parse_amf0_metadata(uint8_t* body, int body_len, RtmpMetaData* meta) { #if 0 /************************ 第一步:入参合法性校验 ************************/ if (body == NULL || body_len < 10 || meta == NULL) { printf("【元数据解析】失败:入参无效或包体过短(长度:%d)\n", body_len); return 0; } memset(meta, 0, sizeof(RtmpMetaData)); const char* amf_buf = (const char*)body; int parse_offset = 0; // 定义需要的AVal键名(原生amf.h的AVC宏) const AVal av_onMetaData = AVC("onMetaData"); const AV
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/25 10:40:11

ClearerVoice-Studio语音分离作品集:演唱会现场混音分离主唱/伴奏/观众声

ClearerVoice-Studio语音分离作品集&#xff1a;演唱会现场混音分离主唱/伴奏/观众声 1. 项目概述 ClearerVoice-Studio 是一个专业的语音处理全流程一体化开源工具包&#xff0c;专为音频工程师和音乐制作人设计。这个工具包最令人惊艳的能力之一&#xff0c;就是能够将演唱…

作者头像 李华
网站建设 2026/2/19 22:04:30

3步激活老Mac隐藏性能:开源工具让2012款iMac流畅运行最新系统

3步激活老Mac隐藏性能&#xff1a;开源工具让2012款iMac流畅运行最新系统 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你的设备本该拥有第二次生命。在电子设备更新换代…

作者头像 李华
网站建设 2026/2/24 23:10:27

通义千问3-Reranker-0.6B效果展示:中英混杂Query下跨语言文档重排能力

通义千问3-Reranker-0.6B效果展示&#xff1a;中英混杂Query下跨语言文档重排能力 1. 这不是普通排序模型&#xff0c;而是能“听懂混搭语言”的重排专家 你有没有试过这样搜索&#xff1a;用中文提问&#xff0c;但文档里夹着英文术语&#xff1b;或者输入一句中英混排的查询…

作者头像 李华
网站建设 2026/2/10 12:13:51

DAMO-YOLO惊艳效果:暗光增强+目标检测联合pipeline端到端演示

DAMO-YOLO惊艳效果&#xff1a;暗光增强目标检测联合pipeline端到端演示 1. 为什么暗光下的目标检测一直是个难题&#xff1f; 你有没有试过在深夜停车场拍一张车的照片&#xff0c;结果连车牌都看不清&#xff1f;或者在工厂车间顶灯昏暗的角落&#xff0c;监控画面里人影模…

作者头像 李华
网站建设 2026/2/12 18:07:38

1.25 亿,黑龙江高质量数据集建设项目

2026 年 1 月 23 日&#xff0c; 黑龙江善行医疗科技有限公司 《 多区域心血管病高质量数据集建设项目 》获备案。一、项目信息&#xff1a;项目名称&#xff1a;多区域心血管病高质量数据集建设项目预算&#xff1a;12500万采购人&#xff1a;黑龙江善行医疗科技有限公司预计采…

作者头像 李华
网站建设 2026/2/23 9:28:59

快手视频批量下载工具使用指南:从效率痛点到合规解决方案

快手视频批量下载工具使用指南&#xff1a;从效率痛点到合规解决方案 【免费下载链接】douyin-downloader 项目地址: https://gitcode.com/GitHub_Trending/do/douyin-downloader &#x1f50d; 问题诊断&#xff1a;短视频创作者的数字困境 凌晨3点&#xff0c;教学博…

作者头像 李华