iOS H264,H265视频编码(Video encode)

本例需求:使用H264, H265实现视频数据的编码并录制开始200帧存为文件.

原理:比如做直播功能,需要将客户端的视频数据传给服务器,如果分辨率过大如2K,4K则传输压力太大,所以需要对视频数据进行编码,传给服务器后再解码以实现大数据量的视频数据的传输,而利用硬件编码则可以极大限度减小CPU压力,

H264进行编码,iOS 11 之后,iPhone 7以上的设备可以支持新的编码器H265编码器,使得同等质量视频占用的存储空间更小。所以本例中可以使用两种方式实现视频数据的编码

最终效果如下 : h264

H264 编码

h265 :

H265编码

GitHub地址(附代码) : H264,H265Encode

简书地址 : H264,H265Encode

博客地址 : H264,H265Encode

掘金地址 : H264,H265Encode

实现方式

  1. H264 : H264是当前主流编码标准,以高压缩高质量和支持多种网络的流媒体传输著称

  1. H265 :H264编码器的下一代,它的主要优点提供的压缩比高,相同质量的视频是H264的两倍。

1、.本文需要基本知识点

注意:可以先通过H264,H265编码器介绍, H.264 Data Structure了解预备知识。

1.1 软编与硬编概念

  • 软编码:使用CPU进行编码。

  • 硬编码:不使用CPU进行编码,使用显卡GPU,专用的DSP、FPGA、ASIC芯片等硬件进行编码。

    • 比较

      • 软编码:实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。

      • 性能高,低码率下通常质量低于软编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。

      • 苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统一直有,被称为Video ToolBox的框架来处理硬件的编码和解码,终于在iOS 8.0后,苹果将该框架引入iOS系统

1.2 H265优点

  • 压缩比高,在相同图片质量情况下,比JPEG高两倍

  • 能增加如图片的深度信息,透明通道等辅助图片。

  • 支持存放多张图片,类似相册和集合。(实现多重曝光的效果)

  • 支持多张图片实现GIF和livePhoto的动画效果。

  • 无类似JPEG的最大像素限制

  • 支持透明像素

  • 分块加载机制

  • 支持缩略图

2、代码解析

2.1 实现流程

  • 初始化相机参数,设置相机代理,这里就固定只有竖屏模式。

  • 初始化编码器参数,并启动编码器

  • 在编码成功的回调中从开始录制200帧(文件大小可自行修改)的视频,存到沙盒中,可以通过连接数据线到电脑从itunes中将文件(test0.asf)提取出来

2.2 编码器实现流程

  • 创建编码器需要的session (h264, h265 或同时创建)

  • 设置session属性,如实时编码,码率,fps, 编码的分辨率的宽高,相邻I帧的最大间隔等等

    • 注意H265目前不支持码率的限制

  • 当相机回调AVCaptureVideoDataOutputSampleBufferDelegate采集到一帧数据的时候则使用H264/H265编码器对每一帧数据进行编码。

  • 若编码成功会触发回调,回调函数首先检测是否有I帧出现,如果有I帧出现则将sps,pps信息写入否则遍历NALU码流并将startCode替换成{0x00, 0x00, 0x00, 0x01}

2.3 主要方法解析

  • 初始化编码器 首先选择使用哪种方式实现,在本例中可以设置[XDXHardwareEncoder getInstance].enableH264 = YES 或者 [XDXHardwareEncoder getInstance].enableH265 = YES,也可以同时设置,如果同时设置需要将其中一个回调函数中的writeFile的方法屏蔽掉,并且只有较新的iPhone(> iPhone8 稳定)才支持同时打开两个session。

判断当前设备是否支持H265编码,必须满足两个条件,一是iPhone 7 以上设备,二是版本大于iOS 11

if (@available(iOS 11.0, *)) {
            BOOL hardwareDecodeSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
            if (hardwareDecodeSupported) {
                _deviceSupportH265 = YES;
                NSLog(@"XDXHardwareEncoder : Support H265 Encode/Decode!");
            }
        }else {
            _deviceSupportH265 = NO;
            NSLog(@"XDXHardwareEncoder : Not support H265 Encode/Decode!");
        }

系统已经提供VTIsHardwareDecodeSupported判断当前设备是否支持H265编码

初始化编码器操作

- (void)prepareForEncode {
    if(self.width == 0 || self.height == 0) {
        NSLog(@"XDXHardwareEncoder : VTSession need with and height for init,with = %d,height = %d",self.width, self.height);
        return;
    }
    
    if(g_isSupportRealTimeEncoder)  NSLog(@"XDXHardwareEncoder : Device processor is 64 bit");
    else                            NSLog(@"XDXHardwareEncoder : Device processor is not 64 bit");
    
    NSLog(@"XDXHardwareEncoder : Current h264 open state : %d, h265 open state : %d",self.enableH264, self.enableH265);
    
    OSStatus h264Status,h265Status;
    BOOL isRestart = NO;
    if (self.enableH264) {
        if (h264CompressionSession != NULL) {
            NSLog(@"XDXHardwareEncoder : H264 session not NULL");
            return;
        }
        [m_h264_lock lock];
        NSLog(@"XDXHardwareEncoder : Prepare H264 hardware encoder");
        
        //[self.delegate willEncoderStart];
        
        self.h264ErrCount = 0;
        
        h264Status = VTCompressionSessionCreate(NULL, self.width, self.height, kCMVideoCodecType_H264, NULL, NULL, NULL, vtCallBack,(__bridge void *)self, &h264CompressionSession);
        if (h264Status != noErr) {
            self.h265ErrCount++;
            NSLog(@"XDXHardwareEncoder : H264 VTCompressionSessionCreate Failed, status = %d",h264Stat
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Qt和FFmpeg进行视频编码,您需要使用FFmpeg的libavcodec库。以下是一些大致的步骤: 1. 在Qt中创建一个新的C++项目,添加FFmpeg库的头文件和链接库。 2. 设置编码器参数,例如分辨率,帧率和比特率。 3. 使用FFmpeg的AVFormatContext和AVOutputFormat结构来打开一个输出文件。 4. 使用AVCodecContext和AVCodec结构来打开编码器。 5. 循环读取帧,使用AVFrame结构将其转换为编码器使用的格式。 6. 使用AVPacket结构将编码的帧写入输出文件。 7. 在完成编码后,关闭编码器和输出文件。 下面是一些示例代码,以便您更好地理解: ```c++ #include <QtCore/QCoreApplication> #include <QDebug> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // Set up codec parameters AVCodecParameters *codecParams = avcodec_parameters_alloc(); codecParams->width = 640; codecParams->height = 480; codecParams->format = AV_PIX_FMT_YUV420P; codecParams->bit_rate = 400000; codecParams->codec_type = AVMEDIA_TYPE_VIDEO; codecParams->codec_id = AV_CODEC_ID_H264; // Set up output file AVFormatContext *outputContext; avformat_alloc_output_context2(&outputContext, NULL, NULL, "output.mp4"); AVStream *outputStream = avformat_new_stream(outputContext, NULL); outputStream->codecpar = codecParams; // Open codec AVCodec *codec = avcodec_find_encoder(codecParams->codec_id); AVCodecContext *codecContext = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codecContext, codecParams); avcodec_open2(codecContext, codec, NULL); // Open output file avio_open(&outputContext->pb, "output.mp4", AVIO_FLAG_WRITE); avformat_write_header(outputContext, NULL); // Set up scaling context SwsContext *imgConvertCtx = sws_getContext(codecParams->width, codecParams->height, AV_PIX_FMT_RGB24, codecParams->width, codecParams->height, codecParams->format, SWS_BICUBIC, NULL, NULL, NULL); // Loop through frames for (int i = 0; i < numFrames; i++) { // Read frame from input file QImage frame = getNextFrame(); // Convert frame to codec format AVFrame *inputFrame = av_frame_alloc(); inputFrame->width = codecParams->width; inputFrame->height = codecParams->height; inputFrame->format = AV_PIX_FMT_RGB24; av_image_alloc(inputFrame->data, inputFrame->linesize, codecParams->width, codecParams->height, AV_PIX_FMT_RGB24, 32); QImage convertedFrame = frame.convertToFormat(QImage::Format_RGB888); sws_scale(imgConvertCtx, &convertedFrame.bits(), &convertedFrame.bytesPerLine(), 0, codecParams->height, inputFrame->data, inputFrame->linesize); // Encode frame AVPacket *outputPacket = av_packet_alloc(); avcodec_send_frame(codecContext, inputFrame); avcodec_receive_packet(codecContext, outputPacket); // Write encoded frame to output file av_interleaved_write_frame(outputContext, outputPacket); // Clean up av_packet_unref(outputPacket); av_frame_free(&inputFrame); } // Close codec, output file, and cleanup avcodec_close(codecContext); avio_close(outputContext->pb); avformat_free_context(outputContext); sws_freeContext(imgConvertCtx); return a.exec(); } ``` 请注意,这只是一个大致的示例,可能需要根据您的具体情况进行修改。此外,为了简化代码,一些错误检查和异常处理可能被省略了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值