天天看点

Python&C++相互混合调用编程全面实战-34完成扩展库pyffmpeg尺寸转换空间申请释放和处理

作者:虚坏叔叔

完成扩展库pyffmpeg尺寸转换空间申请释放和处理

​XFFmpeg.h​

​​添加成员变量​

​rgb​

​用于存储输出的图像数据

// 输出的图像数据
  unsigned char *rgb = 0;      

在​

​XFFmepg.cpp​

​中, 分配这块内存

bool XFFmpeg::Open(const char *url)
{
  printf("XFFmpeg::open %s\n", url);
  // 打开视频 解封装
  int re =avformat_open_input(&ic, url, 0, 0);
  if (re != 0)
  {
    char buf[1024] = { 0 };
    av_strerror(re, buf, 1023);
    printf("avformat open fail:%s\n", buf);
    return false;
  }

  // 获取流
  avformat_find_stream_info(ic, 0);

  // 获取视频总时长
  this->totalms = ic->duration / (AV_TIME_BASE / 1000);
  printf("Total Ms =%d\n", totalms);

  // 打开解码器 0视频 1音频
  AVCodecParameters *para = ic->streams[0]->codecpar;

  // 找到解码器
  AVCodec * codec = avcodec_find_decoder(para->codec_id);

  if (!codec)
  {
    printf("avcodec_find_decoder %d failed!\n", para->codec_id);
  }

  // 分配解码器上下文
  vcodec = avcodec_alloc_context3(codec);

  // 配置解码器上下文
  avcodec_parameters_to_context(vcodec, para);
  // 多线程解码
  vcodec->thread_count = 8;

  // 打开上下文
  re = avcodec_open2(vcodec, 0, 0);
  if (re != 0)
  {
    avcodec_free_context(&vcodec);
    char buf[1024];
    av_strerror(re, buf, sizeof(buf) - 1);
    printf("avcodec_open2 failec:%s!\n", buf);
  }
  printf("avcodec_open2 successed \n");

  // 空间分多了没事 不能少
  rgb = new unsigned char[4096*2160*4];
  return true;
}      

在​

​Close​

​函数中释放这块内存

void XFFmpeg::Close()
{
  printf("XFFmpeg::Close\n");
  if (ic)
  {
    avformat_close_input(&ic);

  }
  if (vcodec)
  {
    avcodec_free_context(&vcodec);
  }
  if (pkt)
  {
    av_packet_free(&pkt);
  }
  if (frame)
  {
    av_frame_free(&frame);
  }
  if (rgb)
  {
    delete rgb;
    rgb = NULL;
  }
}      

然后在​

​Decode​

​函数中开始尺寸格式转换

bool XFFmpeg::Decode(int outwidth, int outheight) {
  if (!vcodec || !pkt) return false;

  // 发送到解码线程
  int re = avcodec_send_packet(vcodec, pkt);
  if (re != 0) return false;
  if (!frame)
    frame = av_frame_alloc();

  // 取到解码后的数据 yuv 前几帧会失败 失败不代表解码失败 只表示解码缓冲没有数据
  re = avcodec_receive_frame(vcodec, frame);
  if (re != 0) return false;

  // 像素格式和尺寸转换上下文
  // 将yuv转为rgb 并调整尺寸
  sws = sws_getCachedContext(sws,
    vcodec->width, vcodec->height, vcodec->pix_fmt, //原宽高/像素格式(YUV420p)
    outwidth, outheight, AV_PIX_FMT_BGRA, //目标宽高/像素格式(RGB)
    SWS_BICUBIC, // 转换的算法
    0, 0, 0
  );
  if (!sws)
  {
    // 出错一般都是参数格式有问题
    printf("sws_getCachedContext failed\n");
    return false;
  }

  if (!rgb)
  {
    printf("rgb is null\n");
    return false;
  }
  uint8_t *data[AV_NUM_DATA_POINTERS] = { 0 };
  data[0] = rgb;
  int linesize[AV_NUM_DATA_POINTERS] = { 0 };
  linesize[0] = outwidth * 4;// 一行的大小 width*单像素字节
  int h = sws_scale(sws,
    frame->data, // 源数据
    frame->linesize, // 行大小 行对齐
    0,
    frame->height,
    data, // sws输出数据和行大小
    linesize
  );
  printf("[%d]", h);

  return true;
}