static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
FILE *outfile)
{
int ret;
/* send the frame to the encoder */
if (frame)
printf("Send frame %lld\n", frame->pts);
ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0)
{
fprintf(stderr, "Error sending a frame for encoding\n");
exit(1);
}
while (ret >= 0)
{
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0)
{
fprintf(stderr, "Error during encoding\n");
exit(1);
}
printf("Write packet %lld--size:%d\n", pkt->pts, pkt->size);
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
}
int main()
{
//像素格式转换上下文
Mat input_img;
VideoCapture cap(0);
if (!cap.isOpened())
{
cerr << "can not open camera" << endl;
exit(-1);
}
// 源图像参数
int width = 640;
int height = 480;
int fps = 25;
int iRet = avformat_network_init();
uint8_t endCode[] = { 0, 0, 1, 0xb7 };
//const AVCodec *codec = avcodec_find_encoder_by_name("libx264");
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
fprintf(stderr, "Codec '%s' not found\n", "libx264");
exit(1);
}
// 给编码器分配内存,返回对应编码器上下文
AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
if (!codecCtx)
{
cout << "avcodec_alloc_context3 failed!" << endl;
getchar();
return -1;
}
// 配置编码器上下文的成员
codecCtx->width = width; // 设置编码视频宽度
codecCtx->height = height; // 设置编码视频高度
codecCtx->time_base.num = 1;
codecCtx->time_base.den = 25; // 设置帧率,num为分子,den为分母,如果是1/25则表示25帧/s
codecCtx->framerate.num = 25;
codecCtx->framerate.den = 1;
codecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 设置输出像素格式
AVPacket* pkt = av_packet_alloc();
if (!pkt)
{
exit(1);
}
av_init_packet(pkt);
// 打开编码器
int ret = avcodec_open2(codecCtx, codec, NULL);
if (ret < 0)
{
cout << "avcodec_open2 failed!" << endl;
getchar();
return -1;
}
cout << "avcodec_open2 success!" << endl;
// 3 创建视频重采样上下文:指定源和目标图像分辨率、格式
SwsContext *swsCtx = NULL;
swsCtx = sws_getContext(width, height, AV_PIX_FMT_BGR24,
width, height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL, NULL, NULL
);
FILE* f = fopen("test.mp4", "wb");
if (!f) {
fprintf(stderr, "Could not open %s\n", "test.mp4");
exit(1);
}
//创建BGR视频帧
AVFrame *rgbFrame = av_frame_alloc();
rgbFrame->format = AV_PIX_FMT_BGR24;
rgbFrame->width = width;
rgbFrame->height = height;
ret = av_frame_get_buffer(rgbFrame, 32);
//创建YUV视频帧并配置
AVFrame *yuvFrame = av_frame_alloc();
yuvFrame->format = AV_PIX_FMT_YUV420P;
yuvFrame->width = width;
yuvFrame->height = height;
ret = av_frame_get_buffer(yuvFrame, 32);
if (ret < 0)
{
cout << "av_frame_get_buffer failed!" << endl;
getchar();
return -1;
}
// 循环写视频文件
int pts = 0;
int count = 0;
int i;
for (i = 0; i < 1000; i++)
{
cap >> input_img;
//dealWithImg(input_img);//识别手部
Mat temp;
input_img.copyTo(temp);
uint8_t *src_data[4];
int src_linesize[4];
//BGR24--->YUV420
av_image_fill_arrays(src_data, src_linesize, temp.data, AV_PIX_FMT_BGR24, temp.cols, temp.rows, 1);
cv::Size frameSize = temp.size();
int cvLinesizes[1];
cvLinesizes[0] = temp.step1();
av_image_copy(rgbFrame->data, rgbFrame->linesize, (const uint8_t **)src_data, src_linesize, AV_PIX_FMT_BGR24, temp.cols, temp.rows);
sws_scale(swsCtx, &temp.data, cvLinesizes, 0, height, yuvFrame->data, yuvFrame->linesize);
yuvFrame->pts = i;
/* encode the image */
encode(codecCtx, yuvFrame, pkt, f);
}
/* flush the encoder */
encode(codecCtx, NULL, pkt, f);
/* add sequence end code to have a real MPEG file */
if (codec->id == AV_CODEC_ID_MPEG1VIDEO || codec->id == AV_CODEC_ID_MPEG2VIDEO)
fwrite(endCode, 1, sizeof(endCode), f);
fclose(f);
avcodec_free_context(&codecCtx);
av_frame_free(&yuvFrame);
av_packet_free(&pkt);
return 0;
}