伤心客 发表于 2024-6-27 07:35:58

ffmpeg视频编码原理和实战-(2)视频帧的创建和编码packet压缩

源文件:

#include <iostream>
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavcodec/avcodec.h>
}
//预处理指令导入库
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
int main(int argc, char* argv[])
{
    //1 找到编码器
    AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
   
    //2 编码上下文的创建
    AVCodecContext* c = avcodec_alloc_context3(codec);
   
    //3设定上下文参数
    c->width = 400;//视频宽度
    c->height = 300;
    c->time_base = { 1,25 };//   1/25,pts*time_base = 播放时间(秒)

    c->pix_fmt = AV_PIX_FMT_YUV420P;//指定元数据的像素格式 与编码算法相关 h264只能yuv420;
    c->thread_count = 16;//编码的线程数 可以调用系统接口获取cpu核心数
    //4 打开编码上下文
    int re = avcodec_open2(c, codec, NULL);
   
    cout << "avcodec_open2 succece!" << endl;
    //5 创建avframe,存储的是未压缩的元数据
    auto frame = av_frame_alloc();
    frame->width = 400;
    frame->height = 300;
    frame->format = c->pix_fmt;
    re = av_frame_get_buffer(frame, 0);
    auto pkt = av_packet_alloc();
    //6 十秒视频 250帧
    for (int i = 0; i < 250; i++)
    {
      //6.1生成AVFrame 数据 每帧数据不同
      //Y
      for (int y = 0; y < c->height; y++)
      {
            for (int x = 0; x < c->width; x++)
            {
                frame->data + x] = x + y + i * 3;
            }
      }
      //UV
      for (int y = 0; y < c->height / 2; y++)
      {
            for (int x = 0; x < c->width / 2; x++)
            {
                frame->data + x] = 128 + y + i * 2;
                frame->data + x] = 64 + x + i * 5;
            }
      }
      frame->pts = i;//显示的时间

      //6.2发送未压缩的帧到线程中进行压缩
      

      //对于解码,调用avcodec_send_packet()以将AVPacket中的原始压缩数据提供给解码器。
      //对于编码,调用avcodec_send_frame()为编码器提供包含未压缩音频或视频的AVFrame。
      re = avcodec_send_frame(c, frame);//此时编码器有了元数据

      

      //6.3接收压缩帧,一般前几次调用返回空(缓冲,立刻返回,编码未完成)
      //编码是在另外独立线程中进行编码的
      //每次调用会重新分配pkt中的空间
      while (re >= 0)//返回多个帧
      {
            //要解码,请调用avcodec_receive_frame()。成功后,它将返回包含未压缩音频或视频数据的AVFrame 。
            //对于编码,请调用avcodec_receive_packet()。成功时,它将返回带有压缩帧的AVPacket 。重复此调用,直到返回AVERROR(EAGAIN)或错误。
            re = avcodec_receive_packet(c, pkt);//此时对编码器中的元数据进行压缩到avpacket中
            cout << pkt->size << " " << flush;//输出压缩后的数据大小 单位为kb
            av_packet_unref(pkt);
      }
    }
    av_packet_free(&pkt);
    av_frame_free(&frame);
    avcodec_free_context(&c);//释放编码器上下文
    auto b = getchar();
    return 0;
} 运行效果:https://img-blog.csdnimg.cn/direct/50376d01d9494cca91bbfc5486d626d9.png

可以看出这250帧中,根本上每帧就几千kb,压缩后的数据存储在avpacket中,下一步我们把数据写进文件并播放出来

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: ffmpeg视频编码原理和实战-(2)视频帧的创建和编码packet压缩