用ffmpeg将bmp文件序列编码为h264,使用软编码器AV_CODEC_ID_H264时
程序可以正常运行,换成硬编码器h264_nvenc后,程序有时可以正常运行,但有时会报错,错误现象为:
编码生成的h264文件大小为0KB,avcodec_encode_video2()函数返回错误码-11,使用av_strerror显示错误码映射为“Resource temporarily unavailable”。
换成新的API(avcodec_send_frame和avcodec_receive_packet)后,已经返回-11。程序如下:
#include<stdio.h>
#include<iostream>
#include<afx.h>
using namespace std;
extern"C"
{
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
#include <libswscale\swscale.h>
#include <libavutil\pixfmt.h>
#include <libavutil\imgutils.h>
#include <libavutil/opt.h>
#include "libavutil/time.h"
}
#define bmpImagePath "F:/laboratory/holiday/bmp2H264/image_bmp1/%03d.bmp" //bmp图像路径
#define H264FilePath "F:/laboratory/holiday/bmp2H264/h264/text.h264" //H264文件输出路径
const int image_number = 100; //bmp图片数量
int main()
{
CFile file[image_number + 1000];
BYTE *szTxt[image_number + 1000];
int nWidth = 0;
int nHeight = 0;
int nDataLen = 0;
int nLen;
CString csFileName;
for (int fileI = 1; fileI <= image_number; fileI++)
{
csFileName.Format(bmpImagePath, fileI);
file[fileI - 1].Open(csFileName, CFile::modeRead | CFile::typeBinary);
nLen = file[fileI - 1].GetLength();
szTxt[fileI - 1] = new BYTE[nLen];
file[fileI - 1].Read(szTxt[fileI - 1], nLen);
file[fileI - 1].Close();
BITMAPFILEHEADER bmpFHeader;
BITMAPINFOHEADER bmpIHeader;
memcpy(&bmpFHeader, szTxt[fileI - 1], sizeof(BITMAPFILEHEADER));
int nHeadLen = bmpFHeader.bfOffBits - sizeof(BITMAPFILEHEADER);
memcpy(&bmpIHeader, szTxt[fileI - 1] + sizeof(BITMAPFILEHEADER), nHeadLen);
nWidth = bmpIHeader.biWidth;
nHeight = bmpIHeader.biHeight;
szTxt[fileI - 1] += bmpFHeader.bfOffBits;
nDataLen = nLen - bmpFHeader.bfOffBits;
cout << "fileI:" << fileI << endl;
}
av_register_all();
avcodec_register_all();
AVFrame *m_pRGBFrame = new AVFrame[1]; //RGB帧数据
AVFrame *m_pYUVFrame = new AVFrame[1];; //YUV帧数据
AVCodecContext *c = NULL;
//AVCodecContext *in_c = NULL;
AVCodec *pCodecH264 = NULL; //编码器
uint8_t * yuv_buff = NULL;//
//查找h264编码器
//pCodecH264 = avcodec_find_encoder(AV_CODEC_ID_H264); //软编码器
pCodecH264 = avcodec_find_encoder_by_name("h264_nvenc"); //硬编码器
if (!pCodecH264)
{
fprintf(stderr, "h264 codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(pCodecH264);
if (!c) {
throw exception("avcodec_alloc_context3 failed!");
}
c->bit_rate = 3000000;// put sample parameters
//c->bit_rate = 2500000;// put sample parameters
c->width = nWidth;
c->height = nHeight;
AVRational rate;
rate.num = 1;
rate.den = 25;
c->time_base = rate;//(AVRational){1,25};
c->gop_size = 10; // emit one intra frame every ten frames
c->max_b_frames = 1;
c->thread_count = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;//PIX_FMT_RGB24;
if (avcodec_open2(c, pCodecH264, NULL)<0) //打开编码器
TRACE("不能打开编码库");
int size = c->width * c->height;
yuv_buff = (uint8_t *)malloc((size * 3) / 2); // size for YUV 420
uint8_t * rgb_buff = new uint8_t[nDataLen]; //将rgb图像数据填充rgb帧
//图象编码
//int outbuf_size = 100000000;
int outbuf_size = nWidth * nHeight * 3;
uint8_t * outbuf = (uint8_t*)malloc(outbuf_size);
int u_size = 0;
FILE *f = NULL;
char * filename = H264FilePath;
f = fopen(filename, "wb");
if (!f)
{
TRACE("could not open %s\n", filename);
exit(1);
}
//初始化SwsContext
SwsContext * scxt = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR24, c->width, c->height, AV_PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL);
AVPacket avpkt;
//AVFrame *pTFrame=new AVFrame
int num = 0;
long long int vpts = 0;
for (int i = 0; i< image_number; ++i)
{
int index = i;
memcpy(rgb_buff, szTxt[index], nDataLen);
avpicture_fill((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, AV_PIX_FMT_RGB24, nWidth, nHeight);
//将YUV buffer 填充YUV Frame
avpicture_fill((AVPicture*)m_pYUVFrame, (uint8_t*)yuv_buff, AV_PIX_FMT_YUV420P, nWidth, nHeight);
// 翻转RGB图像
m_pRGBFrame->data[0] += m_pRGBFrame->linesize[0] * (nHeight - 1);
m_pRGBFrame->linesize[0] *= -1;
m_pRGBFrame->data[1] += m_pRGBFrame->linesize[1] * (nHeight / 2 - 1);
m_pRGBFrame->linesize[1] *= -1;
m_pRGBFrame->data[2] += m_pRGBFrame->linesize[2] * (nHeight / 2 - 1);
m_pRGBFrame->linesize[2] *= -1;
//将RGB转化为YUV
sws_scale(scxt, m_pRGBFrame->data, m_pRGBFrame->linesize, 0, c->height, m_pYUVFrame->data, m_pYUVFrame->linesize);
int got_packet_ptr = 0;
av_init_packet(&avpkt);
avpkt.data = outbuf;
avpkt.size = outbuf_size;
//m_pYUVFrame->pts = vpts;
/*u_size = avcodec_send_frame(c, m_pYUVFrame);
if (u_size != 0)
{
char errorbuf[1024] = { 0 };
av_strerror(u_size, errorbuf, sizeof(errorbuf));
cout << "error number:" << u_size << "avcodec_send_frame error:" << errorbuf << endl;
}
u_size = avcodec_receive_packet(c, &avpkt);
if (u_size != 0)
{
char errorbuf[1024] = { 0 };
av_strerror(u_size, errorbuf, sizeof(errorbuf));
cout << "error number:"<< u_size << " avcodec_receive_packet error:" << errorbuf << endl;
}*/
u_size = avcodec_encode_video2(c, &avpkt, m_pYUVFrame, &got_packet_ptr);
if (u_size != 0)
{
char errorbuf[1024] = { 0 };
av_strerror(u_size, errorbuf, sizeof(errorbuf));
cout << "error number:" << u_size << "avcodec_encode_video2 error:" << errorbuf << endl;
}
m_pYUVFrame->pts++;
//cout << "encode frame" << index + 1 << " successfully!" << endl;
cout << "u_size:" << u_size << endl;
if (u_size == 0)
{
cout << "encode frame" << index + 1 << " successfully!" << endl;
cout << "*************" << ++num << "************" << endl;
fwrite(avpkt.data, 1, avpkt.size, f);
}
//vpts++;
else
{
avcodec_send_packet(c, &avpkt);
}
}
cout << "nWidth" << nWidth << endl;
cout << "nHeight" << nHeight << endl;
fclose(f);
delete[]m_pRGBFrame;
delete[]m_pYUVFrame;
delete[]rgb_buff;
free(outbuf);
free(yuv_buff);
avcodec_close(c);
av_free(c);
//avcodec_free_context(&c);
system("pause");
return 0;
}
错误结果截图如下: