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

打印 上一主题 下一主题

主题 665|帖子 665|积分 1995

源文件:

  1. #include <iostream>
  2. using namespace std;
  3. extern "C" { //指定函数是c语言函数,函数名不包含重载标注
  4. //引用ffmpeg头文件
  5. #include <libavcodec/avcodec.h>
  6. }
  7. //预处理指令导入库
  8. #pragma comment(lib,"avcodec.lib")
  9. #pragma comment(lib,"avutil.lib")
  10. int main(int argc, char* argv[])
  11. {
  12.     //1 找到编码器
  13.     AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
  14.    
  15.     //2 编码上下文的创建
  16.     AVCodecContext* c = avcodec_alloc_context3(codec);
  17.    
  18.     //3设定上下文参数
  19.     c->width = 400;//视频宽度
  20.     c->height = 300;
  21.     c->time_base = { 1,25 };//   1/25,pts*time_base = 播放时间(秒)
  22.     c->pix_fmt = AV_PIX_FMT_YUV420P;//指定元数据的像素格式 与编码算法相关 h264只能yuv420;
  23.     c->thread_count = 16;//编码的线程数 可以调用系统接口获取cpu核心数
  24.     //4 打开编码上下文
  25.     int re = avcodec_open2(c, codec, NULL);
  26.    
  27.     cout << "avcodec_open2 succece!" << endl;
  28.     //5 创建avframe,存储的是未压缩的元数据
  29.     auto frame = av_frame_alloc();
  30.     frame->width = 400;
  31.     frame->height = 300;
  32.     frame->format = c->pix_fmt;
  33.     re = av_frame_get_buffer(frame, 0);
  34.     auto pkt = av_packet_alloc();
  35.     //6 十秒视频 250帧
  36.     for (int i = 0; i < 250; i++)
  37.     {
  38.         //6.1生成AVFrame 数据 每帧数据不同
  39.         //Y
  40.         for (int y = 0; y < c->height; y++)
  41.         {
  42.             for (int x = 0; x < c->width; x++)
  43.             {
  44.                 frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
  45.             }
  46.         }
  47.         //UV
  48.         for (int y = 0; y < c->height / 2; y++)
  49.         {
  50.             for (int x = 0; x < c->width / 2; x++)
  51.             {
  52.                 frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
  53.                 frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
  54.             }
  55.         }
  56.         frame->pts = i;//显示的时间
  57.         //6.2发送未压缩的帧到线程中进行压缩
  58.         
  59.         //对于解码,调用avcodec_send_packet()以将AVPacket中的原始压缩数据提供给解码器。
  60.         //对于编码,调用avcodec_send_frame()为编码器提供包含未压缩音频或视频的AVFrame。
  61.         re = avcodec_send_frame(c, frame);//此时编码器有了元数据
  62.       
  63.         //6.3接收压缩帧,一般前几次调用返回空(缓冲,立刻返回,编码未完成)
  64.         //编码是在另外独立线程中进行编码的
  65.         //每次调用会重新分配pkt中的空间
  66.         while (re >= 0)//返回多个帧
  67.         {
  68.             //要解码,请调用avcodec_receive_frame()。成功后,它将返回包含未压缩音频或视频数据的AVFrame 。
  69.             //对于编码,请调用avcodec_receive_packet()。成功时,它将返回带有压缩帧的AVPacket 。重复此调用,直到返回AVERROR(EAGAIN)或错误。
  70.             re = avcodec_receive_packet(c, pkt);//此时对编码器中的元数据进行压缩到avpacket中
  71.             cout << pkt->size << " " << flush;//输出压缩后的数据大小 单位为kb
  72.             av_packet_unref(pkt);
  73.         }
  74.     }
  75.     av_packet_free(&pkt);
  76.     av_frame_free(&frame);
  77.     avcodec_free_context(&c);//释放编码器上下文
  78.     auto b = getchar();
  79.     return 0;
  80. }
复制代码
运行效果:


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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表