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

本文探讨了iOS环境下视频流的内存管理和播放速度控制问题,包括如何使用内存池和固定大小缓冲区来避免内存泄露,以及在无时间戳H264流中实现稳定播放速度的方法。

iOS (socket+H264+videoToolbox)视频内存增长与播放速度控制
视频播放的时候 控制视频的内存在这张图的消耗速度上
在这里插入图片描述
录像是存储在某台服务器里面的,服务端一般看客户端要多少数据 ,就会开个while循环,一次读取多少字节的数据。然后几乎没有时间间隔的把数据送出去。这时候在播放端就需要做好播放速度的控制,因为接收速度完全取决于网速,如果没有做这段,那么视频的播放速度就和网速一样,网速快的时候 ,视频呈现快进的效果。网速慢的时候会出现卡帧的效果。直播的时候,由于录像采集方控制了采集的速度,所以传输给播放端的时候不需要处理播放速度。

按照标准的H264来说,应该每一帧都有pts时间戳 ,这样就可以做视频的同步来解决问题。

但就有奇葩的没有pts的H264流,该怎么处理这种流呢?

把流下载下来存文件,放到VLC里面 也能够正常播放,那么VLC是怎么做到流速控制,他怎么在没有pts的情况下知道间隔多少毫秒播放呢。用ffmpeg打印文件信息,ffprose就能什么都打印出来,拿到avformat里面的帧率 是1/25 那么就是每秒25帧,就是每隔40毫秒需要渲染一帧视频画面。

如果不是标准的25帧的帧率,那么可以通过avopeninput多等几帧来尝试解析文件,让ffmpeg

帮你猜测帧率,然后再写好等待函数的具体毫秒时间。

至于流播放的过慢应该怎么控制,可以通过一个视频缓冲区来控制,比如我们一秒钟能够保证视频

的流畅体验,那么小于25帧 就不应该播放,应该继续拉流把缓冲区至少填充到25帧,再以间隔40毫秒的速度

播放下去。而缓冲区也不能够无限的大,当视频比如说已经5秒(125帧)了。那就不要再继续拉流了。

这样可以做到流量节省,同时保证流畅的播放体验,也不会造成缓冲区过大的问题。

从上面的内容,我们知道要实现两个东西

视频缓冲区,播放间隔速度控制

在实际编码的过程中

出现了两个比较严重的问题,一个是内存增长过快,到一定程度就会被苹果杀掉了。

一个是数据拷贝的时候数据已经被其他线程释放了,导致读写的时候出现越界崩溃的问题。

还有播放速度无法控制。

针对内存增长过快,原因是拉流缓冲区释放不及时,接收速度远超过播放速度,高人提供了一个解决方案,

就是提前预分配内存,首先分配一个大概2M大小的内存,拉流收到的视频帧直接存到这个内存里面去

控制一个读写的位置,每次的新帧就会一直拼在后面,这样write的位置就会一直往后,read的位置则每读取

一包数据,就向后移动一个位置,当write写到了内存长度的最后的时候,又从头开始写,因为read已经读过了

的部分,就可以覆盖写了,这样包装所有的数据都是在这2M内的,当播放结束的时候,再把2M的内存完全释放。

这样就不用反复分配释放某个内存,而苹果是ARC的,什么时候释放也不是我们能控制的,因此这段代码就C

代码的实现,需要分配和释放成对出现,当然这从某种角度讲,也叫内存池。这里有一套java的实现,

翻译成C的就好了。

package com.temobi.util;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class VideoBuffer {
	private static final int HEADLEN = 8;
	private static final int MAGIC = 0xabababab;
	
	private Lock lockWrite = new ReentrantLock(); 	// buffer write lock
	private int writePos; 		// write position
	private int readPos; 		// read position
	private int dataLength; 	// data length of the buffer
	private int bufferSize; 	// buffer size
	private byte[] buffer; 		// buffer

	public VideoBuffer(int size) {
		writePos = 0;
		readPos = 0;
		dataLength = 0;
		bufferSize = size;
		buffer = new byte[bufferSize];
	}

	public boolean isHasData() {
		return dataLength > HEADLEN ? true : false;
	}
	
	public int getFreeSpaceSize() {
		return bufferSize - dataLength;
	}

	//splice the buffer to tailed
	public boolean spliceBuffe
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值