我写了以下代码,将解码后的视频帧转换为PNG图像。代码不会崩溃,但存储在'avpkt'中的图像数据会产生全绿色图像。我究竟做错了什么?任何帮助将不胜感激。
// pFrame - the decoded frame
// avpkt - the packet to fill with the converted image
void convert_image(AVCodecContext *pCodecCtx, AVFrame *pFrame, AVPacket *avpkt, int *got_packet_ptr) {
AVCodecContext *codecCtx;
AVCodec *codec;
*got_packet_ptr = 0;
codec = avcodec_find_encoder(TARGET_IMAGE_CODEC);
if (!codec) {
printf("avcodec_find_decoder() failed to find decoder\n");
goto fail;
}
codecCtx = avcodec_alloc_context3(codec);
if (!codecCtx) {
printf("avcodec_alloc_context3 failed\n");
goto fail;
}
codecCtx->bit_rate = pCodecCtx->bit_rate;
codecCtx->width = pCodecCtx->width;
codecCtx->height = pCodecCtx->height;
codecCtx->pix_fmt = TARGET_IMAGE_FORMAT;
codecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
codecCtx->time_base.num = pCodecCtx->time_base.num;
codecCtx->time_base.den = pCodecCtx->time_base.den;
if (!codec || avcodec_open2(codecCtx, codec, NULL) < 0) {
printf("avcodec_open2() failed\n");
goto fail;
}
int src_width = pCodecCtx->width;
int src_height = pCodecCtx->height;
enum PixelFormat src_pixfmt = pCodecCtx->pix_fmt;
int dst_width = pCodecCtx->width;
int dst_height = pCodecCtx->height;
struct SwsContext *scalerCtx;
scalerCtx = sws_getContext(src_width,
src_height,
src_pixfmt,
dst_width,
dst_height,
TARGET_IMAGE_FORMAT,
SWS_BILINEAR, //SWS_BICUBIC
NULL, NULL, NULL);
if (!scalerCtx) {
printf("sws_getContext() failed\n");
goto fail;
}
AVFrame *pSrcFrame = avcodec_alloc_frame();
if (!pSrcFrame) {
goto fail;
}
AVFrame *pFrameRGB = avcodec_alloc_frame();
if (!pFrameRGB) {
goto fail;
}
if (avpicture_fill((AVPicture *) pSrcFrame,
pFrame->data,
src_pixfmt,
src_width,
src_height) < 0) {
printf("avpicture_fill() failed\n");
goto fail;
}
int numBytes = avpicture_get_size(TARGET_IMAGE_FORMAT, src_width, src_height);
uint8_t *buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
if (avpicture_fill((AVPicture *) pFrameRGB,
buffer,
TARGET_IMAGE_FORMAT,
src_width,
src_height) < 0) {
printf("avpicture_fill() failed\n");
goto fail;
}
sws_scale(scalerCtx,
(const uint8_t * const *) pSrcFrame->data,
pSrcFrame->linesize,
0,
src_height,
pFrameRGB->data,
pFrameRGB->linesize);
int ret = avcodec_encode_video2(codecCtx, avpkt, pFrameRGB, got_packet_ptr);
if (ret < 0) {
*got_packet_ptr = 0;
}
fail:
if (codecCtx) {
avcodec_close(codecCtx);
}
if (scalerCtx) {
sws_freeContext(scalerCtx);
}
if (ret < 0 || !*got_packet_ptr) {
av_free_packet(avpkt);
}
}
答案 0 :(得分:6)
以下代码读取第一帧并将其保存到PNG。
#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);
}
}
}