基于iOS的网络音视频实时传输系统(H264+pcm+videoToolbox)无第三方实现

基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据 获取音视频数据,这里使用的是AVCaptureSession,可以方便地自定义相机界面,看起来大概是这样的: 阅读详情

代码下载
在这里插入图片描述
此图为客户端采集数据,下面的视频是摄像头采集的数据
上面的视频是摄像头解码h264的试试绘制效果
IP地址 是 同一个局域网内另外一台设备的ip地址,在wifi里面详情就能看到

在这里插入图片描述

上图是tcp接收端的显示效果

ios 录音播放udp数据包传输过来的pcmData流
在这篇文章中,我实现了在局域网内通过udp协议 完成了pcm音频的录音与播放,
于是想把视频也能够通过局域网达到传输的效果,
这就有了本篇代码的实现方案。

最开始我和音频一样采用了udp的方案,发现了视频花屏非常严重,
意识到是udp丢包导致的,于是转换方案采用了tcp的方案,tcp不再丢包,
但在tcp接收端处理视频流的地方,遇到了分包和粘包的问题,
解决分包、粘包,只能通过协议包头和内容长度机制来解决。

以下是分包、粘包的解决思路:

由于tcp是可靠性连接,那么数据都不会丢失。
当我收到第一个包的前4个字节,我就可以解析这4个字节,
判定是否为发送端定义的包头,如果和包头一致,
我们就知道 这是视频流数据的包头了,然后再继续解析4个字节
,一般我们将这4个字节解析成为包内容的长度,然后我们判定
我们现在的包是否达到了包内容的长度,如果不够就继续接收下去
如果够了,就把包内容解析出来,解析完成后把数据缓冲清空。

总结上面这一段的意思
1.来了任何的数据都拼接到缓冲队列的最后
2.开一个while循环,当字节头大于4个字节就开始解析,
解析出包体长度后,如果当前缓冲长度不够,就继续等待数据拼接
3.如果缓冲长度够了,就解析这段内容,然后将这段内容从缓冲队列中移除。

代码一

// 接收到了数据 自动回调  sock客户端
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
   [self.currentLock lock];
    //收到一段data
   [self.completeData appendData:data];
   [self.currentLock unlock];
   
   [sock readDataWithTimeout:-1 tag:0];
}

while缓冲的内容,这里加了一个自动释放池防止内存增长过快


- (void)receiveDataHanle {
    while (!_exit) {
        @autoreleasepool {
            if (self.completeData.length <16) {
                usleep(20*1000);
                continue;
            }
            //缓冲队列大小大于16才能继续处理
            NSData *data = [self.completeData copy];
            NSRange range = NSMakeRange(0, 4);
            NSData *headData = [data subdataWithRange:range];
            int head= [self intWithData:headData];
            
            NSRange countRange = NSMakeRange(4,4);
            NSData *countData = [data subdataWithRange:countRange];
            int count = [self intWithData:countData];
            
            NSRange lengthRange = NSMakeRange(8,4);
            NSData *lengthData = [data subdataWithRange:lengthRange];
            int length = [self intWithData:lengthData];
            
            
            NSRange typeRange = NSMakeRange(12,4);
            NSData *typeData = [data subdataWithRange:typeRange];
            int type = [self intWithData:typeData];
            int completeDataLength = length+16;
            //打印字节头  序列号 消息内容长度  这个包总长
            NSLog(@"head=%d count=%d bodylength=%d completeDataLength=%d completeData.length=%lu",head,count,length,completeDataLength,(unsigned long)data.length);
            
            if (data.length>=completeDataLength) {
                //取出body数据
                NSRange dataRange = NSMakeRange(16, length);
                NSData *mData = [data subdataWithRange:dataRange];
                NSString *msg = [NSString stringWithFormat:@"序号[%d]类型[%@]应收长度[%d]收到长度[%lu]",count,type==0?@"A":@"V",length,(unsigned long)mData.length];
                //移除缓冲队列里面处理的部分
                NSLog(@"%@",msg);
                NSLog(@"[before]%lu",(unsigned long)self.completeData.length);
                [self.currentLock lock];
                self.completeData = [[self.completeData subdataWithRange:NSMakeRange(completeDataLength, self.completeData.length - completeDataLength)] mutableCopy];
                [self.currentLock unlock];
                NSLog(@"[after]%lu",(unsigned long)self.completeData.length);
                if (type == 0) {
                    // 音频
                    [self.audioPlayer addPCM:(void *)mData.bytes length:(UInt32)mData.length timeStamp:count];
                }else if (type == 1) {
                    // 视频
                    [self.decoder startH264DecodeWithVideoData:(char *)mData.bytes andLength:(int)mData.length andReturnDecodedData:^(CVPixelBufferRef pixelBuffer) {
                        [self.playView displayPixelBuffer:pixelBuffer];
                    }];
                }
                
            } else {
                //遇到了拆包 需要继续接收 直到满足 包大小;
                usleep(10*1000);
                continue;
            }
        }
       
    }
}

可以看下发送端的逻辑
视频发送

// 默认情况下,为30 fps,意味着该函数每秒调用30次
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    
    // 获取输入设备数据,有可能是音频有可能是视频
    if (captureOutput == self.videoOutput) {
        if ([sendSocket isConnected]) {
            // 收到数据,开始编码
            [self.videoEncoder startH264EncodeWithSampleBuffer:sampleBuffer andReturnData:^(NSData *data) {
                
                _count++;
                NSMutableData *mData = [[NSMutableData alloc] init];
                NSData *headData = [self bytewithInt:60000];//协议头 4位 (0-4)
                NSData *countData = [self bytewithInt:_count];//发到第几个包 4位 (4-8)
                NSData *legnthData = [self bytewithInt:(int)data.length];//当前包的长度 4位 (8-12)
                NSData *dataType = [self bytewithInt:1];//type 1为视频
                [mData appendData:headData];
                [mData appendData:countData];
                [mData appendData:legnthData];
                [mData appendData:dataType];
                [mData appendData:data];
                NSLog(@"序号[%d]视频 %lu data[%d]",_count,(unsigned long)data.length,mData.length);
                [sendSocket writeData:[mData copy] withTimeout:60 tag:201];
                [self.decoder startH264DecodeWithVideoData:(char *)data.bytes andLength:(int)data.length andReturnDecodedData:^(CVPixelBufferRef pixelBuffer) {
                        [self.playView displayPixelBuffer:pixelBuffer];
                }];
            }];
        }
    }
}

音频发送

- (void)didReceiveATAudioData:(NSData*)data {
    _count++;
    NSMutableData *mData = [[NSMutableData alloc] init];
    NSData *headData = [self bytewithInt:60000];//协议头 4位 (0-4)
    NSData *countData = [self bytewithInt:_count];//发到第几个包 4位 (4-8)
    NSData *legnthData = [self bytewithInt:(int)data.length];//当前包的长度 4位 (8-12)
    NSData *dataType = [self bytewithInt:0];//type 0为音频
    [mData appendData:headData];
    [mData appendData:countData];
    [mData appendData:legnthData];
    [mData appendData:dataType];
    [mData appendData:data];

    NSLog(@"音频 data%lu",(unsigned long)data.length);
    if ([sendSocket isConnected]) {
        [sendSocket writeData:[mData copy] withTimeout:60 tag:200];
    }
}

这两段代码只是为了让你理解发送端会将int型的固定长度的约定字段 转换成二进制,
而接收端会则会将二进制再次转换为约定字段,来判断协议头,当前序号,是音频还是视频,内容长度。没有这些约定内容,就算你有数据也不知道如何解析。

解决了这个问题后,可以看到tcp 的视频效果远比udp的花屏效果好,
而视频采集转码,使用的都是videotoolbox转换成H264

播放也是用videotoolbox再将H264转换回来。

附byte 和data型数据的互转
这个要求都是用4位的,如果你用别的位数,可以写个循环即可。

- (NSData * )bytewithInt:(int )i {
    Byte b1=i & 0xff;
    Byte b2=(i>>8) & 0xff;
    Byte b3=(i>>16) & 0xff;
    Byte b4=(i>>24) & 0xff;
    Byte byte[] = {b4,b3,b2,b1};
    NSData *data = [NSData dataWithBytes:byte length:sizeof(byte)];
    return data;
}

- (int)intWithData:(NSData *)data {
    Byte *byteK = (Byte *)data.bytes;
    int valueK;
    valueK = (int) (((byteK[0] & 0xFF)<<24)
                    |((byteK[1] & 0xFF)<<16)
                    |((byteK[2] & 0xFF)<<8)
                    |(byteK[3] & 0xFF));
    return valueK;
}

iOS音频编程之实时语音通信 iOS音频编程之实时语音通信需求:手机通过Mic采集PCM编码的原始音频数据,将PCM转换为AAC编码格式,通过MultipeerConnectivity框架连接手机并发送AAC数据,在接收端使用Audio Queue播放收到的AAC音频音频设置 对音频以44.1KHZ的采样率来采样,以64000的比特率对PCM进行AAC转码 1)对AVAudioSession的设置NSError *error 阅读详情

相关推荐

iOS录屏引擎实战:突破Broadcast Extension 50MB内存限制的优化方案

在iOS开发中,屏幕录制、实时视频采集与直播推流是常见的工程需求。ReplayKit虽然提供了系统级录屏能力,但默认输出到相册的模式难以满足水印叠加、自定义码率与实时传输等业务要求。Broadcast Upload Extension允许开发者获取CMSampleBuffer原始帧,通过VideoToolbox进行H.264硬编码,从而构建自主可控的录屏管线。然而,扩展进程受到Jetsam机制的严格约束,30-50MB的物理内存红线成为方案选型的核心限制。本文从内存管理的原理出发,讨论CVPixelBuff

weixin_33861800的博客 226

实时传输协议RTP

      温故而知新。      实时传输协议RTP(Real-time Transport Protocol)是IETF的AVT工作组(Audio/Video Transport WG)开发的协议。RTP[RFC 3550,3551]为实时应用提供端到端的运输,但不提供任何服务质量的保证。需要发送的多媒体数据块(音频/视频)经过压缩编码处理后,先送给RTP封装成RTP分组,RTP分组再装入

为之,则难者亦易矣;不为,则易者亦难矣。 2864

iOS (socket+H264+videoToolbox)视频内存增长与播放速度控制

通过对视频流的内存预分配,避免数据传输的多次创建和free操作,从而避免内存的无限攀升问题 参见 https://blog.youkuaiyun.com/github_35041937/article/details/92075305 文章采用Videotoolbox对H264文件进行硬解码,同时保持播放速度为40毫秒数值。

iOS-VideoToolbox硬编码H264

前言 VideoToolBox是iOS8之后,苹果开发的用于硬解码编码H264/H265(iOS11以后支持)的API。 对于H264还不了解的童鞋一定要先看下这边的H264的简介。 H.264基础简介 编码流程 我们实现一个简单的Demo,从摄像头获取到视频数据,然后再编码成H264裸数据保存在沙盒中。 1. 创建初始化VideoToolBox 核心代码如下 - (void)initVideo...

weixin_34099526的博客 311

手把手带你编写miniQMT实盘量化执行程序(3) | 交易系统

本文介绍了miniQMT实盘量化执行系统的核心交易系统代码,重点讲解了其模块化设计和工作流程。系统采用主控类LiveSystem管理交易全流程,包含初始化引擎、交易日判断、交易时段划分(开盘前、盘中、收盘等)、主循环调度和异常处理等核心功能。作者详细解析了系统如何实现365天不间断运行、精准判断交易日、分阶段执行交易策略等功能,并强调系统的稳定性和异常处理机制。

1306

给爸妈买的红米12C想装个老年桌面?先别急,解锁BL和Root前你得知道这些

本文详细解析了红米12C解锁BL和Root的利弊,为想要为长辈简化手机操作的用户提供全面指南。文章对比了BL解锁与Root的技术差异,推荐优先使用MIUI内置的极简模式等官方功能,并评估了Root的实际必要性。若必须Root,提供了安全操作流程和长期维护建议,帮助用户做出明智选择。

weixin_30265103的博客 317

iOS 简单的视频直播功能开发(实时视音频流录制编码+RTMP传输+实时拉流解码播放)

推流端:自己开发难度很大,视频直播就被卡死了,音频根本没来得及弄,最终使用了github上开源的框架。                原生开发基本流程:AVFoundation获取视频流,得到未编码的CMSampleBuffer,需要编码成Mpeg-4格式。编码分软编码和硬编码,考虑到iOS8之后VideoToolBox开放使用,选用VideoToolBox进行编码。坑爹的是针对它连

pilgrim1385的专栏 1万+

iOS-音视频小结

iOS音频播放 豆瓣开源播放器代码DOUAudioStreamer starRTC,免费IM(含单聊,群聊,聊天室),免费一对一视频聊天(回音消除),语音聊天,直播连麦,白板,小班课,多人会议,局域网无服务器直连,兼容webRTC, 支持webRTC加速,P2P高清传输,安卓、iOS、web互通,支持门禁可视对讲,电视盒子,树莓派,海思,全志,OTT设备,C语言自研方案 AudioUnit框架详细...

samuelandkevin的专栏 1万+

BES (恒玄)HFP通话笔记

1.audio_developer 调试:SDK 需要打开某个算法,需要原厂打开对应宏定义编译出新的SDK,只要涉及到lib库里的功能都需要原厂手动修改编译。开发商和原厂FAE做起来都会比较累。如果没有原厂支持根本没法做,很少文档,SDK也很多问题,没法开箱即用如果要支持audio_developer上位机调试,还需改代码,如果对整个原理不清楚就没法做,没文档只能啃代码调试工具设计的也有待加强,串口通讯调试对耳机这类产品非常麻烦,本来板子就不大,还要焊接一堆线,调试还要拖着串口线。

飞天鱼 685

USB接口ESD保护电路:深度剖析与选型建议

USB接口在热插拔和频繁使用中极易遭遇静电放电(ESD)冲击,导致芯片损坏或通信异常。本文结合实际电路设计经验,详解TVS二极管、集成ESD防护器件等方案在USB接口上的应用要点,重点分析钳位电压、结电容、IEC 61000-4-2等级等关键参数对信号完整性与防护效果的影响,助你为USB接口匹配高可靠、低干扰的ESD保护方案。

weixin_36289813的博客 510

iOS完整推流采集音视频数据编码同步合成流

需求 众所周知,原始的音视频数据无法直接在网络上传输,推流需要编码后的音视频数据以合成的视频流,如flv, mov, asf流等,根据接收方需要的格式进行合成并传输,这里以合成asf流为例,讲述一个完整推流过程:即音视频从采集到编码,同步合成asf视频流,然后可以将流进行传输,为了方便,本例将合成的视频流写入一个asf文件中,以供测试. 注意: 测试需要使用终端通过: ffplay播放demo中录制好的文件,因为asf是windows才支持的格式,mac自带播放器无法播放. 实现原理 采集: 采

翻肚鱼儿的博客 1192

AgentScope Java 2.0 项目实战: 从零构建自己的个人AI助手“小龙虾“

本文系统介绍如何基于Spring Boot WebFlux、React 18和TypeScript,从零搭建一个本地化的个人AI助手管理平台——AgentScope Paw。项目支持多Agent创建与管理、SSE流式对话、工作区文件CRUD、技能市场、子智能体孵化、AI辅助起草Agent配置等核心功能,并深度集成钉钉、企业微信、飞书、GitHub等IM通道。

program哲学 1422

ios视频传输udp方案分析

基于iOS的网络音视频实时传输系统(H264+pcm+videoToolbox)无第三方实现 这篇文章中,视频的传输采用的是tcp 的方案来实现的 那么为什么不用udp来实现呢? 实际上,一开始采用的udp的方案,但实际在传输的过程中 出现了大量的丢包现象,还有乱序的可能性 丢包会导致花屏,乱序会导致视频抖动。 采用tcp 的好处是tcp不会丢包和乱序,但需要牺牲一定的网络延时。和包大小的不定长度...

github_35041937的博客 951

得物(毒)App潮鞋价格波动监控系统实战:从爬虫开发到数据可视化完整指南

本文将带领您从零开始构建一套完整的得物潮鞋价格监控系统,涵盖爬虫开发、数据存储、价格波动分析和可视化展示等全流程技术。我们将使用最新的Python技术栈,包括异步爬虫框架、智能代理池、反爬虫绕过技巧,以及基于机器学习的时间序列预测模型。无论您是想要追踪特定鞋款价格的潮流爱好者,还是希望构建商业级监控系统的开发者,这篇文章都将为您提供切实可行的解决方案。

2201_76125261的博客 2504

RK3576 Buildroot 双机 ADB 异常排障实录:同版 `boot.img`,一台可识别一台不可识别

进程在跑”不等于“USB 枚举成功”,adbd存活只是必要不充分条件。生产环境中的全局别名可能反向污染系统脚本。shell 命令替换中的字符串问题,必须做字节级验证(od -tx1相比“改环境规避”,核心脚本对输入做鲁棒处理更可长期维护。

小灰灰的博客 209

iOS 音视频底层架构

iOS音视频底层架构解析:系统通过并行处理管线实现音视频同步。音频和视频采用独立的硬件采集与处理通道,仅在最终渲染阶段通过PTS(显示时间戳)实现同步。音频通常作为主时钟基准,视频通过比较PTS差值进行帧同步控制(等待/丢弃/渲染)。核心框架包括AVFoundation(采集/播放)、VideoToolbox/AudioToolbox(编解码)、CoreMedia(时间戳管理)和CoreAnimation(渲染)。设计关键点在于物理隔离、PTS统一机制和音频主时钟同步策略。

小桥流水哗啦啦,iOS Coder 哒哒哒 545

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

ffmpeg实时h264 打包ts流_音视频学习从零到整-视频H264编码

一.学习背景5G网络作为第5代的移动通信网络,它的网络峰值传播速度可1以达到10Gbps/s.这比4G的的传输速度快数百倍.举个例子,整部超高画质电影下载可在1秒钟之内下载完成.当然,随着5G技术的诞生,用在智能终端分享3D电影,游戏或者超高画质节目的时代已经毫无悬念的向我们走来.想必大家也逐步了解,国内外的互联网公司也已经布局音视频,3D技术方面的开发者招聘和相关产品研发.目前落地推广最普遍的就...

weixin_39543835的博客 944

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

iOS开发之直播App流程介绍,直播资料收集汇总,视频推流,视频拉流,SMTP、RTMP、HLS、 PLPlayerKit

(一) iOS 直播类APP开发流程分解:  1 . 音视频处理的一般流程: 数据采集→数据编码→数据传输(流媒体服务器) →解码数据→播放显示 1、数据采集: 摄像机及拾音器收集视频及音频数据,此时得到的为原始数据 涉及技术或协议: 摄像机:CCD、CMOS 拾音器:声电转换装置(咪头)、音频放大电路 2、数据编码: 使用相关硬件或软件对音视频原始数据进行编码处理(

zhonggaorong的专栏 2万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

iOS 直播类APP开发流程

(一) iOS 直播类APP开发流程分解:  1 . 音视频处理的一般流程: 数据采集→数据编码→数据传输(流媒体服务器) →解码数据→播放显示 1、数据采集: 摄像机及拾音器收集视频及音频数据,此时得到的为原始数据 涉及技术或协议: 摄像机:CCD、CMOS 拾音器:声电转换装置(咪头)、音频放大电路 2、数据编码: 使用相关硬件或软件对音视频原始数据进行编码处理(

wolaikanyanhau的博客 2983

直播视频流技术名词

1、 FFmpeg FFmpeg 是一个开源免费跨平台的视频和音频流方案,属于自由软件,它提供了录制、转换以及流化音视频的完整解决方案。直播系统多使用该方案。 复制代码2、 RTMP(Real Time Messaging Protocol:实时消息传输协议) Adobe公司开发。一个专门为高效传输视频,音频和数据而设计的协议。它通过建立一个二进制TCP连接或者连接HTTP隧道实现实时的视频和声音...

weixin_33817333的博客 299

iOS动手做一个直播(原理篇)

原文出处: 夜3033    开篇 传输简单示意图 上篇文章主要给出了代码,但是并没有详细说明直播相关的知识,这篇文章就说一下直播的相关理论知识。附上直播代码篇地址。 推流 腾讯直播平台,阿里直播平台,百度直播平台提供均为RTMP的推流和HLS/RTMP等拉流. 推流是一个直播不可缺少的成分,说起推流都会说基于RTMP协议,那什么是RTMP呢? RTM

LLy_Alex的博客 2487
上一篇: ios 播放ts流视频思路
下一篇: ios视频传输udp方案分析
csdn_Damon
博客等级 码龄10年 37粉丝 143原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值