前言
正文
ios中视频流渲染有三种方法:
AVCaptureVideoPreviewLayer:视频采集时回显使用的图层, 调用简单,功能较少。
AVSampleBufferDisplayLayer:CPU渲染yuv数据也可直接渲染压缩的视频数据,小巧方便,功能比较丰富,可操作性强。
openGl:GPU渲染,功能强大,性能卓越,使用复杂。
本文主要介绍AVSampleBufferDisplayLayer,demo分为两个类,大屏和小屏,小屏继承自大屏类.
openGl推荐参考:落影loyinglin
创建渲染图层
- (void)createLayer
{
if (!self.buffer_layer)
{
self.buffer_layer = [[AVSampleBufferDisplayLayer alloc]init];
self.buffer_layer.frame = self.bounds;
self.buffer_layer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
/*!
@constant AVLayerVideoGravityResizeAspect 根据图像像素比例 绘制图像 图像会填充不满图层size
@abstract Preserve aspect ratio; fit within layer bounds.
@constant AVLayerVideoGravityResizeAspectFill 根据像素比例 填充图层 画面会超出图层size
@abstract Preserve aspect ratio; fill layer bounds.
@constant AVLayerVideoGravityResize 拉伸 用这个自适应不同size图层最好
@abstract Stretch to fill layer bounds.
*/
self.buffer_layer.videoGravity = AVLayerVideoGravityResizeAspect;
//不透明
self.buffer_layer.opaque = YES;
[self.layer addSublayer:self.buffer_layer];
}
else
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.buffer_layer.bounds = self.qlframe;
self.buffer_layer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
[CATransaction commit];
}
}
播放
#pragma mark - play
// 每来一帧数据进行缓存, 从后台模式返回后, 重启layer
- (void)play:(CMSampleBufferRef)buffer
{
if (buffer)
{
[_buffer_layer enqueueSampleBuffer:buffer];
if (_buffer_layer.status == AVQueuedSampleBufferRenderingStatusFailed)
{
//后台唤醒重启渲染层
if (-11847 == _buffer_layer.error.code)
{
NSLog(@"11111");
[self rebuildSampleBufferDisplayLayer];
}
else
{
[self rebuildSampleBufferDisplayLayer];
NSLog(@"%s 第%d行 %@",__func__,__LINE__,_buffer_layer.error.description);
}
}
}
}
#pragma mark - 重启渲染layer
- (void)rebuildSampleBufferDisplayLayer
{
[self remove_layer];
[self createLayer];
}
- (void)remove_layer
{
if (self.buffer_layer)
{
[self.buffer_layer stopRequestingMediaData];
[self.buffer_layer removeFromSuperlayer];
self.buffer_layer = nil;
}
}
小屏
小屏的切换和拖拽功能只是添加了两个手势
- (instancetype)initWithFrame:(CGRect)frame and_touchBlock:(touchBlock)touch_block and_panBlcok:(panblock)pan_block
{
if (self = [super initWithFrame:frame and_touchBlock:touch_block and_panBlcok:pan_block])
{
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
[self addGestureRecognizer:tap];
UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
}
return self;
}
- (void)tap:(UITapGestureRecognizer*)tap
{
// 切换大小屏时,在此block内 调用flushAndRemoveImage 清除缓存
self.touch_block();
}
- (void)pan:(UIPanGestureRecognizer*)pan
{
self.pan_block(pan);
}
最后
demo地址
下一篇:音频采集播放与编解码
欢迎交流指正