FFmpeg 编码图片文件为h265或者h264

FFmpeg编码流程

FFmpeg版本为 FFmpeg6

1.FFmpeg的编码流程比较固定,只有一些细节需要自己设计,这里为了展示方便,一些可以封装的代码并没有封装
2.编码h265或者h264只需要更改pCodec的初始化函数参数即可
3.该代码只读取灰度图,如果要读取彩图,只需要给pFrame的UV分量设置数据即可
4.编码出来的数据存放在 pPkt中,无论是想写入文件还是发送出去,都可以根据这个pPkt->data 来获取数据
void FFmpeg_Encode( const QVector< QString > &vecFileNames )
{
    // 1. 初始化编码所需要的对象
    AVCodecContext *pCodecCtx = nullptr;
    AVCodec        *pCodec    = nullptr;
    AVFrame        *pFrame    = nullptr;
    AVPacket       *pPkt      = nullptr;
    
    // 2. 打开编码器  flows: 软编,英伟达独显编码, 因特尔核显编码( HD620以上? )
    pCodec = avcodec_find_encoder( AV_CODEC_ID_HEVC );
    pCodec = avcodec_find_encoder_by_name( "hevc_nvenc" );
    pCodec = avcodec_find_encoder_by_name( "hevc_qsv" );
    
    //确保编码器打开成功
    if( nullptr == pCodec ){
        std::cout << "find encoder failed..." << std::endl;
        return;
    }
    
    // 3. 创建编码上下文, 并确保创建上下文成功
    pCodecCtx = avcodec_alloc_context3( pCodec );
    if( nullptr == pCodecCtx ){
        std::cout << "create codec context failed..." << std::endl;
        return;
    }
    
    // 4. 设置编码信息, 帧高,帧宽, 像素格式等等信息
    pCodecCtx->width = 1920;
    pCodecCtx->height = 1280;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    
    // 5. 打开编码器, 第三个参数是设置一些编码额外的参数,如果遇到编码延迟,可通过第三个参数来降低延迟,并不能全完解决延迟?
    int ret = avcodec_open2( pCodecCtx, pCodec, nullptr );
    if( 0 != ret ){
        std::cout << "open codec failed..." << std::endl;
        return;
    }
    
    // 6. 初始化frame信息 和 packet 信息
    pFrame         = av_frame_alloc();
    pFrame->width  = pCodecCtx->width;
    pFrame->height = pCodecCtx->height;
    pFrame->format = pCodecCtx->pix_fmt;
    
    //这一步好像可以不用?
    ret = av_frame_get_buffer( pFrame, 0 );
    
    pPkt = av_packet_alloc();
    
    
    // 7.初始化文件对象
    std::ofstream ofs;
    ofs.open( "./test.h265", std::ios::binary );
    
    // 8.读取要编码的图片
    for( auto &ele : vecFileNames ){
    	QImage img( ele);
    	img            = img.convertToFormat( QImage::Format_Grayscale8 );
    	uchar *imgData = img.bits();
    	int    imgSize = img.byteCount();

	    //此处设置 Y 分量, UV分量在调用处,根据图片尺寸信息设置
	    memcpy( pFrame->data[ 0 ], imgData, imgSize );
        
        //设置UV分量
        memset( pFrame->data[ 1 ], 0x80, pCodecCtx->width * pCodecCtx->height / 4 );
        memset( pFrame->data[ 2 ], 0x80, pCodecCtx->width * pCodecCtx->height / 4 );
        
        // 发送要编码的frame给编码器
        ret = avcodec_send_frame( pCodecCtx, pFrame );
        
        // 大于 0 表示有数据返回
        while( ret >= 0 ){
            // 接收编码器编码出来的帧
            ret = avcodec_receive_packet( pCodecCtx, pPkt );
            
            // ffmpeg 有可能会做帧缓存,导致编码延迟,编码一帧数据,可能需要多帧原始图像
            if ( ret == AVERROR( EAGAIN ) ){
                break;
            }
            
            // 编码错误
            if( ret == AVERROR_EOF ){
                break;
            }
            
            //写入文件
            ofs.write( (char*)(pPkt->data), pPkt->size );
        }
        
        // 9.释放相关对象
        av_packet_free( &pPkt );
        av_frame_free( &pFrame );
        avcodec_free_context( &pCodecCtx );
        
    }
}


  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值