[FFmpeg C/C++]AVFrame转PNG
2020-04-23 本文已影响0人
_小老虎_
- 主要
Codec ID :AV_CODEC_ID_PNG
PIX_FMT 转换为AV_PIX_FMT_RGB24
最终Pkt直接写入文件也可以,总之都是压缩编码的。
- 如下代码 eg1 (个人)
static int EncodeYUVToPNG(AVFrame* pictureFrame, const char* OutputFileName, int in_w, int in_h) {
AVFormatContext *pFormatCtx = NULL;
AVStream *video_st = NULL;
AVCodecContext* pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVPacket *pkt = NULL; //编码后数据,如jpeg等
fflush(stdout);
pFormatCtx = avformat_alloc_context();
avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, OutputFileName);
// // 创建并初始化一个和该url相关的AVIOContext
// if (avio_open(&pFormatCtx->pb, OutputFileName, AVIO_FLAG_READ_WRITE) < 0) {
// printf("Couldn't open output file");
// return -1;
// }
// pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);
struct SwsContext *swCtx = sws_getContext(pictureFrame->width,
pictureFrame->height,
AV_PIX_FMT_YUV420P,
in_w,
in_h,
AV_PIX_FMT_RGB24,
SWS_FAST_BILINEAR, 0, 0, 0);
AVFrame * rgbFrame = av_frame_alloc();
rgbFrame->width = in_w;
rgbFrame->height = in_h;
rgbFrame->format = AV_PIX_FMT_RGB24;
avpicture_alloc((AVPicture *)rgbFrame, AV_PIX_FMT_RGB24, in_w, in_h);
sws_scale(swCtx, pictureFrame->data, pictureFrame->linesize, 0, pictureFrame->height, rgbFrame->data, rgbFrame->linesize);
// 获取编解码上下文信息
pCodecCtx = avcodec_alloc_context3(NULL);
// pCodecCtx->codec_id = pFormatCtx->oformat->video_codec;
pCodecCtx->codec_id = AV_CODEC_ID_PNG;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = AV_PIX_FMT_RGB24;
pCodecCtx->width = in_w;
pCodecCtx->height = in_h;
pCodecCtx->time_base = (AVRational){1, 30};
//print log info;
av_dump_format(pFormatCtx, 0, OutputFileName, 1);
pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if (!pCodec) {
printf("Codec not found.");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf("Could not open codec.\n");
return -1;
}
// start encoder
int ret = avcodec_send_frame(pCodecCtx, rgbFrame);
pkt = av_packet_alloc();
av_new_packet(pkt, in_w*in_h*3);
//Read encoded data from the encoder.
ret = avcodec_receive_packet(pCodecCtx, pkt);
video_st = avformat_new_stream(pFormatCtx, 0);
if (video_st == NULL) {
return -1;
}
//Write Header
avformat_write_header(pFormatCtx, NULL);
//Write body
av_write_frame(pFormatCtx, pkt);
//Write Trailer
av_write_trailer(pFormatCtx);
printf("Encode Successful.\n");
av_packet_unref(pkt); //av_packet_alloc()
av_frame_free(&rgbFrame); //av_frame_alloc()
avformat_free_context(pFormatCtx); //avformat_alloc_context()
pkt = NULL;
rgbFrame = NULL;
pFormatCtx = NULL;
return 0;
}
#define CHECK_ERR(ERR) {if ((ERR)<0) return -1; }
int convert_first_frame_to_png(std::string const & inputVideoFileName, std::string const & outputPngName)
{
av_register_all();
avcodec_register_all();
::AVFormatContext * ctx = NULL;
int err = avformat_open_input(&ctx, inputVideoFileName.c_str(), NULL, NULL);
CHECK_ERR(err);
err = av_find_stream_info(ctx);
CHECK_ERR(err);
AVCodec * codec = NULL;
int strm = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
AVCodecContext * codecCtx = ctx->streams[strm]->codec;
err = avcodec_open2(codecCtx, codec, NULL);
CHECK_ERR(err);
SwsContext * swCtx = sws_getContext(codecCtx->width,
codecCtx->height,
codecCtx->pix_fmt,
codecCtx->width,
codecCtx->height,
PIX_FMT_RGB24,
SWS_FAST_BILINEAR, 0, 0, 0);
for (;;)
{
AVPacket pkt;
err = av_read_frame(ctx, &pkt);
CHECK_ERR(err);
if (pkt.stream_index == strm)
{
int got = 0;
AVFrame * frame = avcodec_alloc_frame();
err = avcodec_decode_video2(codecCtx, frame, &got, &pkt);
CHECK_ERR(err);
if (got)
{
AVFrame * rgbFrame = avcodec_alloc_frame();
avpicture_alloc((AVPicture *)rgbFrame, PIX_FMT_RGB24, codecCtx->width, codecCtx->height);
sws_scale(swCtx, frame->data, frame->linesize, 0, frame->height, rgbFrame->data, rgbFrame->linesize);
AVCodec *outCodec = avcodec_find_encoder(CODEC_ID_PNG);
AVCodecContext *outCodecCtx = avcodec_alloc_context3(codec);
if (!codecCtx)
return -1;
outCodecCtx->width = codecCtx->width;
outCodecCtx->height = codecCtx->height;
outCodecCtx->pix_fmt = PIX_FMT_RGB24;
outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
outCodecCtx->time_base.num = codecCtx->time_base.num;
outCodecCtx->time_base.den = codecCtx->time_base.den;
if (!outCodec || avcodec_open2(outCodecCtx, outCodec, NULL) < 0) {
return -1;
}
AVPacket outPacket;
av_init_packet(&outPacket);
outPacket.size = 0;
outPacket.data = NULL;
int gotFrame = 0;
int ret = avcodec_encode_video2(outCodecCtx, &outPacket, rgbFrame, &gotFrame);
if (ret >= 0 && gotFrame)
{
FILE * outPng = fopen(outputPngName.c_str(), "wb");
fwrite(outPacket.data, outPacket.size, 1, outPng);
fclose(outPng);
}
avcodec_close(outCodecCtx);
av_free(outCodecCtx);
break;
}
avcodec_free_frame(&frame);
}
}
}