ios直播技术(2)-- 视频编码

今天给大家分享下视频的编码,由于ios在8.0才支持硬编码,所以这里加入了软编码,openH264和X264均可,这里介绍的是X264。

硬编码由于耗用CPU极低,编码效率高所以优先选择,软编码(X264)占用CPU高,一般在4s上720P 20帧就编不动了吧,当然也有优点,6.X、7.X系统都可用。


首先是编码器的设计图:


H264Encoder作为基类首先是创建编码器接口,当8.0以上系统 选择硬编码 其他软编码

+ (id)create
{
    if (Version_iOS_8) {
        H264VideoToolboxEncoder *encoder = [[H264VideoToolboxEncoder alloc] init];
        return encoder;
    } else
    {
        H264EncoderImpl *encoder = [[H264EncoderImpl alloc] init];
        return encoder;
    }
    return nil;
}
编码接口,首先检查采集数据的分辨率帧率有无变化,如有变化则去销毁原有的,重新创建编码器,若无则直接编码

- (int)checkEncoder:(struct VideoCapability*)capability
{
    if((*capability)!=(*_usingParam))
    {
        memcpy(_usingParam,capability,sizeof(struct VideoCapability));
        [self finiEncoder];
        if (_pTmpOut)
        {
            free(_pTmpOut);
            _pTmpOut = 0;
        }
        [self initEncoder];
        
        if (!_pTmpCfg)
            _pTmpCfg = (uint8_t*)malloc(100);
        if (!_pTmpOut)
            _pTmpOut = (uint8_t*)malloc(_usingParam->width * _usingParam->height * 2 + 100);
    }
    return 0;
}
- (int)encode:(NativeVideoFrame*)avframe Capability:(struct VideoCapability*)capability
{
    NSAutoLock* autolock = [[NSAutoLock alloc] initWithLock:_lock];
    UNUSED(autolock);
    if (!_running)
        return 0;
    [self checkEncoder:capability];
    
    return [self realEncode:avframe TimeStamp:[Utils now_ms]];
}

H264Encoder的派生类有H264Encoderlmpl(软编)和H264VideoToolboxEncoder(硬编),他们都实现了基类的三个protected方法。

顺带介绍下OC中protected方法的写法

@interface H264EncoderImpl (Protected)
- (BOOL)initEncoder;
- (void)finiEncoder;
- (int)realEncode:(NativeVideoFrame *)avFrame TimeStamp:(long)ts;
@end
先来介绍下H264Encoderlmpl

//
//  H264EncoderImpl.m
//  AVSession
//
//  Created by whw on 2016/11/22.
//  Copyright © 2016年 meixin. All rights reserved.
//

#import "H264EncoderImpl.h"
#import "x264.h"
#import "AVDefine.h"
#import "libavformat/avformat.h"
#import "Utils.h"
#import "libyuv.h"
#include "VideoDefines.h"
#include "VideoFrame.h"
typedef struct
{
    x264_param_t * param;
    x264_t *handle;
    x264_picture_t * picture;
    x264_nal_t  *nal;
} Encoder;

@interface H264EncoderImpl ()
{
    Encoder*        _encoder;
}

@end
@interface H264EncoderImpl (Protected)
- (BOOL)initEncoder;
- (void)finiEncoder;
- (int)realEncode:(NativeVideoFrame *)avFrame TimeStamp:(long)ts;
@end

@implementation H264EncoderImpl

- (instancetype)init
{
    self = [super init];
    if (self) {
        
    }
    return self;
}
- (int)realEncode:(NativeVideoFrame *)raw TimeStamp:(long)ts
{
    raw->native2i420();
    int framesize = raw->width()*raw->height();
    _encoder->picture->img.i_stride[kYPlane] = raw->stride(kYPlane);
    _encoder->picture->img.i_stride[kUPlane] = raw->stride(kUPlane);
    _encoder->picture->img.i_stride[kVPlane] = raw->stride(kVPlane);
    _encoder->picture->img.i_stride[kNumOfPlanes] = 0;
    memcpy(_encoder->picture->img.plane[kYPlane],raw->buffer(kYPlane), framesize);
    memcpy(_encoder->picture->img.plane[kUPlane],raw->buffer(kUPlane), framesize>>2);
    memcpy(_encoder->picture->img.plane[kVPlane],raw->buffer(kVPlane), framesize>>2);
    _encoder->picture->img.plane[kNumOfPlanes] = 0;
    _encoder->picture->img.i_csp = X264_CSP_I420;
    return [self CompressBuffer:_encoder TS:ts];
}
- (BOOL)initEncoder
{
    Encoder *en = (Encoder *) malloc(sizeof(Encoder));
    en->param = (x264_param_t *) malloc(sizeof(x264_param_t));
    en->picture = (x264_picture_t *) malloc(sizeof(x264_picture_t));
    
    x264_param_default_preset(en->param, "superfast" , "zerolatency");
    
    en->param->b_sliced_threads = 0;
    en->param->i_threads = 1;
    en->param->rc.i_rc_method = X264_RC_ABR;
    
    int realBitrate = [Utils calcBiteRate:_usingParam->width heght:_usingParam->height fps:_usingParam->fps];
    realBitrate = realBitrate>>10;
    en->param->rc.i_vbv_max_bitrate= 2 * realBitrate;
    en->param->rc.i_bitrate = realBitrate;
    en->param->rc.i_vbv_buffer_size = 2 * realBitrate;
    
    en->param->i_fps_num = _usingParam->fps;
    en->param->i_fps_den = 1;
    en->param->i_keyint_min = _usingParam->fps * 2;
    en->param->i_keyint_max = _usingParam->fps * 2;
    
    en->param->i_timebase_num        = 1;
    en->param->i_timebase_den        = 1000;
    
    x264_param_apply_profile(en->param,"baseline");
    
    en->param->i_csp = X264_CSP_I420;
    en->param->i_log_level = X264_LOG_NONE;
    en->param->i_width = _usingParam->width; //set frame width
    en->param->i_height = _usingParam->height; //set frame height

    if ((en->handle = x264_encoder_open(en->param)) == 0) {
        //tyy
        free(en->param);
        free(en->picture);
        free(en);
        return NO;
    }
    /* Create a new pic */
    x264_picture_alloc(en->picture, X264_CSP_I420, en->param->i_width, en->param->i_height);
    
    _encoder = en;
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值