iOS视频渲染(大小屏切换,小屏拖拽,后台唤醒)

前言

上一篇 视频采集
demo地址

正文

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地址
下一篇:音频采集播放与编解码
欢迎交流指正

你可能感兴趣的:(iOS视频渲染(大小屏切换,小屏拖拽,后台唤醒))