[英]Torn images acquired when decoding video frames with FFmpeg
I am trying to decode the images using the tutorial at dranger.com.我正在尝试使用 dranger.com 上的教程解码图像。 Below is the code I'm working with.下面是我正在使用的代码。 The code is pretty much untouched aside from pgm_save() function and replacing the deprecated functions.除了pgm_save()函数和替换已弃用的函数之外,代码几乎没有改动。
The program compiled successfully, but when I tried to process a video, I'm getting tearing effect like this: image1 and this image2 .程序编译成功,但是当我尝试处理视频时,我得到了这样的撕裂效果: image1和 this image2 。
(Side question: I've tried to replace avpicture_fill() which is deprecated with av_image_copy_to_buffer() but I'm getting an access violation error, so I left it as is. I wonder if there is a proper way for me to assign the frame data to a buffer.) (附带问题:我尝试用av_image_copy_to_buffer()替换已弃用的avpicture_fill(),但出现访问冲突错误,所以我将其保留原样。我想知道是否有合适的方法来分配帧数据到缓冲区。)
The library that I'm using is ffmpeg-20160219-git-98a0053-win32-dev .我使用的库是ffmpeg-20160219-git-98a0053-win32-dev 。 Would really appreciate it if someone could help me with this.如果有人能帮我解决这个问题,我将不胜感激。
// Decode video and save frames
char filename[] = "test%0.3d.ppm";
static void ppm_save(unsigned char *buf, int wrap, int xsize, int ysize,
int framenum )
{
char filenamestr[sizeof(filename)];
FILE *f;
int i;
sprintf_s(filenamestr, sizeof(filenamestr), filename, framenum);
fopen_s(&f,filenamestr,"w");
fprintf(f,"P6\n%d %d\n%d\n",xsize,ysize,255);
for(i=0;i<ysize;i++)
fwrite(buf + i * wrap,1,xsize*3,f);
fclose(f);
}
int main(int argc, char** argv)
{
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *codecCtx= NULL;
AVCodec *codec;
int videoStream;
int frameFinished;
AVFrame *inframe;
AVFrame *outframe;
struct SwsContext *sws_ctx = NULL;
AVPacket avpkt;
unsigned int i;
printf("Video decoding application\n");
// Register all formats and codecs
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// Dump information about file onto standard error (Not necessary)
av_dump_format(pFormatCtx, 0, argv[1], 0);
// Find the first video stream
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
if (videoStream == -1)
return -1; // Didn't find a video stream
/* find the video decoder */
codec = avcodec_find_decoder(pFormatCtx->streams[videoStream]->codec->codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
codecCtx= avcodec_alloc_context3(codec);
if(avcodec_copy_context(codecCtx, pFormatCtx->streams[i]->codec) != 0) {
fprintf(stderr, "Couldn't copy codec context");
return -1; // Error copying codec context
}
/* open it */
if (avcodec_open2(codecCtx, codec, NULL) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
// Allocate video frame
inframe= av_frame_alloc();
if(inframe==NULL)
return -1;
// Allocate output frame
outframe=av_frame_alloc();
if(outframe==NULL)
return -1;
// Determine required buffer size and allocate buffer
int numBytes=av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecCtx->width,
codecCtx->height,1);
uint8_t* buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
// Assign appropriate parts of buffer to image planes in outframe
// Note that outframe is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture *)outframe, buffer, AV_PIX_FMT_RGB24,
codecCtx->width, codecCtx->height );
//av_image_copy_to_buffer(buffer, numBytes,
// outframe->data, outframe->linesize,
// AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height,1);
// initialize SWS context for software scaling
sws_ctx = sws_getContext(codecCtx->width,
codecCtx->height,
codecCtx->pix_fmt,
codecCtx->width,
codecCtx->height,
AV_PIX_FMT_RGB24,
SWS_BILINEAR,
NULL,
NULL,
NULL
);
// av_init_packet(&avpkt);
i = 0;
while(av_read_frame(pFormatCtx, &avpkt)>=0) {
// Is this a packet from the video stream?
if(avpkt.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video2(codecCtx, inframe, &frameFinished, &avpkt);
// Did we get a video frame?
if(frameFinished) {
// Convert the image from its native format to RGB
sws_scale(sws_ctx, (uint8_t const * const *)inframe->data,
inframe->linesize, 0, codecCtx->height,
outframe->data, outframe->linesize);
// Save the frame to disk
if(++i%15 == 0)
ppm_save(outframe->data[0], outframe->linesize[0],
codecCtx->width, codecCtx->height, i);
}
}
// Free the packet that was allocated by av_read_frame
av_packet_unref(&avpkt);
}
// Free the RGB image
av_free(buffer);
av_frame_free(&outframe);
// Free the original frame
av_frame_free(&inframe);
// Close the codecs
avcodec_close(codecCtx);
av_free(codecCtx);
// Close the video file
avformat_close_input(&pFormatCtx);
printf("\n");
return 0;
}
Solved.解决了。 The problem lies in the pgm_save() function.问题在于pgm_save()函数。 I was opening the file as a text file when I was writing binary data.我在编写二进制数据时将文件作为文本文件打开。 The correct mode should have been "wb" not "w" .正确的模式应该是"wb"而不是"w" 。
The correct code should have been:正确的代码应该是:
// fopen_s(&f,filenamestr,"w"); // text mode
fopen_s(&f,filenamestr,"wb"); // binary mode
It feels silly now that I realised that the problem is unrelated to ffmpeg after all.现在我意识到这个问题毕竟与 ffmpeg 无关,这感觉很傻。 On the bright side, at least now I know the code works.从好的方面来说,至少现在我知道代码有效。 ;-) ;-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.