在正常开发中遇到花屏时怎么处理呢?可以把解码后的数据直接保存成帧图片保存起来,然后直接看图片有没有花屏来排除是否是显示的问题,如果花屏,则代表显示无问题,如果图片中没有花屏,则可以往显示的方向去排查了。
void saveFrame(AVFrame* pFrame, int width, int height, int iFrame)
{
FILE *pFile;
char szFilename[32];
int y;
//如果在android上
//sprintf(szFilename, "sdcard/frame%d.ppm", iFrame);
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile = fopen(szFilename, "wb");
if (pFile == NULL)
return;
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
/*
pFrame->data[0]是数据头,y是目前写入的行数,pFrame->linesize[0]是每行的字节数,
pFrame->data[0]+y*pFrame->linesize[0]就是每行数据开头的地址。width是每行像素个数,
width*3就是每行要写的数据个数,以像素分量为单位。
*/
for (y = 0; y < height; y++)
fwrite(pFrame->data[0] + y*pFrame->linesize[0], 1, width * 3, pFile);
fclose(pFile);
}
int main(int argc, char* argv[])
{
AVFormatContext *pFormatCtx;
int i, videoIndex;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVPacket packet;
int frameFinished;
int numBytes;
uint8_t *buffer;
char* filename = "test.3gp";
pFormatCtx = avformat_alloc_context();
av_register_all();
if (avformat_open_input(&pFormatCtx, filename, NULL, 0) != 0)//打开输入流,本质上是filename这个字符串来获取输入流的格式等信息。
return -1;
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)//获取输入流的信息。
return -1;
av_dump_format(pFormatCtx, 0, filename, 0);//输出码流的基本信息到标准错误
videoIndex = -1;
for (i = 0; i < pFormatCtx->nb_streams; ++i){//找到流索引
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
videoIndex = i;
break;
}
}
if (videoIndex == -1)
{
fprintf(stderr, "unsupport codec\n");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoIndex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
return -1;
AVFrame *pFrameRGB, *pFrame;
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
if (pFrame == NULL)
return -1;
numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture*)pFrameRGB, buffer,AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
i = 0;
struct SwsContext* img_convert_ctx;
av_log(NULL, AV_LOG_ERROR, "sws_getContext:width:%d,height:%d,pix_fmt:%d!\n",pCodecCtx->width,pCodecCtx->height, pCodecCtx->pix_fmt);
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
while (av_read_frame(pFormatCtx, &packet) >= 0){//读包
if (packet.stream_index == videoIndex){
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished)
{
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
//取20帧来保存成ppm
if (++i <= 20)
saveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);//保存图片
}
}
av_free_packet(&packet);
}
av_free(buffer);
av_free(pFrameRGB);
av_free(pFrame);
sws_freeContext(swsContext);
avcodec_close(pCodecCtx);
}
本文介绍如何利用FFmpeg将视频解码后的帧数据保存为ppm图片,以排查视频播放过程中的花屏现象。通过对比图片,可以确定花屏是由于解码问题还是显示问题,从而针对性地进行故障排查。
3733

被折叠的 条评论
为什么被折叠?



