avcodec_encode_video2时出现分段错误 [英] Segmentation fault while avcodec_encode_video2
问题描述
在尝试将AVFrame编码为数据包时遇到一些问题。
在阅读整个代码之前,输入的东西已经正常工作,我已经对其进行了测试。输出的内容来自示例。
最后,我解决了我的问题。
问题出在(除了libav的文档之外) )avpacket不是数据包中图片的(真实)副本。它只是指向数据包的数据。
所以首先我为输出创建了一个新的avframe,并在其上创建了一个缓冲区avframe
AVFrame * outpic = avcodec_alloc_frame();
nbytes = avpicture_get_size(codecCtxOut-> pix_fmt,codecCtxOut->宽度,codecCtxOut->高度);
uint8_t *外缓冲区=(uint8_t *)av_malloc(nbytes);
此缓冲区用于从输入到输出的转换。然后在循环中,我必须用缓冲区填充主题(avframe)。我在代码中发现
,该函数正在用缓冲区填充平面指针。
请参见此处
avpicture_fill((AVPicture *)outpic,outbuffer,AV_PIX_FMT_YUV420P,codecCtxOut->宽度,codecCtxOut->高度);
然后我使用 sws_scale
。但是首先必须设置swscontext。
SwsContext * swsCtx_ = sws_getContext(codecCtxIn-> width,codecCtxIn-> height ,
codecCtxIn-> pix_fmt,
codecCtxOut->宽度,codecCtxOut->高度,
codecCtxOut-> pix_fmt,
SWS_BICUBIC,NULL,NULL,NULL);
sws_scale(swsCtx_,inpic-> data,inpic-> linesize,0,codecCtxIn-> height,outpic-> data,outpic-> linesize);
然后,您可以将主题编码为pktout(用于输出的avpacket)。但是首先请释放输出数据包,否则您将得到一个错误和泄漏... 参见此处
av_free_packet(pktOut);
if(avcodec_encode_video2(streamOut->编解码器,pktOut,outpic和&fff)< 0){
std :: cout<< 屎框<< std :: endl;
继续;
}
//并将其写入文件
formatOut-> write_packet(formatCtxOut,pktOut);
所以现在对我来说(几乎可以使用)。仍然是一个小内存泄漏,但是我以后可以发现。
I have some problems while trying to encode a AVFrame to a packet.
Before reading the whole code, the input stuff is working, I tested it. The output stuff is from an example here. I think there is the problem. But the segmentation fault occurs in the loop near the end.
Here is my reduced code:
void nmain() {
// input stuff
AVFormatContext *formatCtxIn=0;
AVInputFormat *formatIn=0;
AVCodecContext *codecCtxIn=0;
AVCodec *codecIn;
AVPacket *pktIn;
av_register_all();
avdevice_register_all();
avcodec_register_all();
formatIn = av_find_input_format("dshow");
if(!formatIn)
return;
AVDictionary *avoption=0;
av_dict_set(&avoption, "rtbufsize", "1000000000", NULL);
if(avformat_open_input(&formatCtxIn, "video=Integrated Camera", formatIn, &avoption)!=0)
return;
if(avformat_find_stream_info(formatCtxIn, NULL)<0)
return;
codecCtxIn = formatCtxIn->streams[0]->codec;
codecIn = avcodec_find_decoder(codecCtxIn->codec_id);
if(avcodec_open2(codecCtxIn, codecIn, NULL)<0)
return;
// end input stuff
//------------------------------------------------------------------------------
// output stuff
AVOutputFormat *formatOut=0;
AVFormatContext *formatCtxOut=0;
AVStream *streamOut=0;
AVFrame *frame=0;
AVCodec *codecOut=0;
AVPacket *pktOut;
const char *filename = "test.mpeg";
formatOut = av_guess_format(NULL, filename, NULL);
if(!formatOut)
formatOut = av_guess_format("mpeg", NULL, NULL);
if(!formatOut)
return;
formatCtxOut = avformat_alloc_context();
if(!formatCtxOut)
return;
formatCtxOut->oformat = formatOut;
sprintf(formatCtxOut->filename, "%s", filename);
if(formatOut->video_codec != AV_CODEC_ID_NONE) {
AVCodecContext *ctx;
codecOut = avcodec_find_encoder(formatOut->video_codec);
if(!codecOut)
return;
streamOut = avformat_new_stream(formatCtxOut, codecOut);
if(!streamOut)
return;
ctx = streamOut->codec;
ctx->bit_rate = 400000;
ctx->width = 352;
ctx->height = 288;
ctx->time_base.den = 25;
ctx->time_base.num = 1;
ctx->gop_size = 12;
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if(ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
ctx->max_b_frames = 2;
if(ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
ctx->mb_decision = 2;
if(formatCtxOut->oformat->flags & AVFMT_GLOBALHEADER)
ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
if(streamOut) {
AVCodecContext *ctx;
ctx = streamOut->codec;
if(avcodec_open2(ctx, codecOut, NULL) < 0)
return;
}
if(!(formatCtxOut->flags & AVFMT_NOFILE))
if(avio_open(&formatCtxOut->pb, filename, AVIO_FLAG_WRITE) < 0)
return;
avformat_write_header(formatCtxOut, NULL);
// doit
pktIn = new AVPacket;
pktOut = new AVPacket;
av_init_packet(pktOut);
pktOut->data = 0;
frame = avcodec_alloc_frame();
if(!frame)
return;
for(;;) {
if(av_read_frame(formatCtxIn, pktIn) >= 0) {
av_dup_packet(pktIn);
int fff;
if(avcodec_decode_video2(codecCtxIn, frame, &fff, pktIn) < 0)
std::cout << "bad frame" << std::endl;
if(!fff)
return; // ok
static int counter=0;
SaveFrame(frame, codecCtxIn->width, codecCtxIn->height, counter++); // work fine
// here a segmentation fault is occured.
if(avcodec_encode_video2(streamOut->codec, pktOut, frame, &fff) < 0)
std::cout << "bad frame" << std::endl;
}
}
}
// only for testing
// add to ensure frame is valid
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
FILE *pFile;
char szFilename[32];
int y;
// Open file
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile=fopen(szFilename, "wb");
if(pFile==NULL)
return;
// Write header
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
// Write pixel data
for(y=0; y<height; y++)
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
// Close file
fclose(pFile);
}
What am i doing wrong?
While debugging i didn't found any problems with the parameters. streamOut->codec
is filled. pktOut
is allocated and frame
is filled with the picture encoded before.
I think the problem is while creating the output codec but watching the example and looking to the doxypages it seems to be correct.
The trace route is from QT using msvc11 and framework 5.
I also tried to run with dr. memory and get this:
Error #26: UNADDRESSABLE ACCESS: reading 0x00000000-0x00000004 4 byte(s)
# 0 replace_memcpy [d:\derek\drmemory\withwiki\trunk\drmemory\replace.c:203]
# 1 avcodec-54.dll!ff_dct_quantize_c +0xd463 (0x6a482364 <avcodec-54.dll+0x3c2364>)
# 2 avcodec-54.dll!avcodec_encode_video2+0xb7 (0x6a56a5b8 <avcodec-54.dll+0x4aa5b8>)
# 3 nmain [d:\prg\tests\recording system-qt\libav\recsys\main.cpp:610]
# 4 main [d:\prg\tests\recording system-qt\libav\recsys\main.cpp:182]
Note: @0:00:06.318 in thread 5312
Note: instruction: mov (%edx) -> %ebx
It seems like the reading process while memcpy is going wrong.
Version:
I've forgot to mention the version of libav/ffmpeg i'm using:
libavutil 51. 76.100 / 51. 76.100
libavcodec 54. 67.100 / 54. 67.100
libavformat 54. 33.100 / 54. 33.100
libavdevice 54. 3.100 / 54. 3.100
libavfilter 3. 19.103 / 3. 19.103
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 16.100 / 0. 16.100
libpostproc 52. 1.100 / 52. 1.100
Addendum:
Function SafeFrame
is copied from tutorial 1.
Finally i solved my problem.
The problem is (apart from the documentation of libav) avpacket is not a (real) copy of the picture in the packet. it just points to the data of the packet. You have to make a copy, or better you have to let it libav do.
So first i created a new avframe for the output and a buffer on which the output avframe is pointing to.
AVFrame *outpic = avcodec_alloc_frame();
nbytes = avpicture_get_size(codecCtxOut->pix_fmt, codecCtxOut->width, codecCtxOut->height);
uint8_t* outbuffer = (uint8_t*)av_malloc(nbytes);
This buffer is used for the conversion from input to output. Then in the loop i have to fillup the outpic (avframe) with the buffer. I have found in the code that this function is filling up the plane pointers with the buffer. see here
avpicture_fill((AVPicture*)outpic, outbuffer, AV_PIX_FMT_YUV420P, codecCtxOut->width, codecCtxOut->height);
Then i converted the inpic to outpic using sws_scale
. But first you have to setup the swscontext.
SwsContext* swsCtx_ = sws_getContext(codecCtxIn->width, codecCtxIn->height,
codecCtxIn->pix_fmt,
codecCtxOut->width, codecCtxOut->height,
codecCtxOut->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(swsCtx_, inpic->data, inpic->linesize, 0, codecCtxIn->height, outpic->data, outpic->linesize);
Then you can encode the outpic into pktout (avpacket for output). But first do free the output packet, otherwise you will get an error and a leak... see here
av_free_packet(pktOut);
if(avcodec_encode_video2(streamOut->codec, pktOut, outpic, &fff) < 0) {
std::cout << "shit frame" << std::endl;
continue;
}
// and write it to the file
formatOut->write_packet(formatCtxOut, pktOut);
So now it works (nearly fine) for me. Still a small memory leak, but this i can spot later.
这篇关于avcodec_encode_video2时出现分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!