一般我们都是用ffmpeg来解码音视频,如果是JPG和PNG等图片呢,其实跟解码视频是一样的,因为视频也是一幅一幅的图片进行解码的,只不过视频的帧是会前后参考的,而JPG等图片来讲,就是独立的一帧而已。
那么,我们参考之前的一篇文章《一段ffmpeg视频解码为YUV420P的示例代码》,稍作修改即可来演示。
同时为了能够保存解码后的图片,我们还需要了解一些YUV或者RGB等各种格式的数据的内存存储方式,这些知识可以参照我之前的另一篇文章《YUV420格式解析》,这里详细描述了各种格式的空间存储机制。
一般解码视频时,我们在调用ffmpeg进行解码时,生成的格式一般都是YUV420P的,但解码图皮时可能会有各种形式,如YUVJ422P、YUVJ444P、RGB24等等,本文没有采用ffmpeg的sws_scale函数做统一的转
换,为的是记录如何来存储这些解码后的图片。
先给出如何从ffmpeg的Frame结构体中保存上述的四种解码后的数据:
/**
* save yuv420p frame [YUV]
*/
void yuv420p_save(AVFrame *pFrame, AVCodecContext *pCodecCtx)
{
int i = 0;
int width = pCodecCtx->width, height = pCodecCtx->height;
int height_half = height / 2, width_half = width / 2;
int y_wrap = pFrame->linesize[0];
int u_wrap = pFrame->linesize[1];
int v_wrap = pFrame->linesize[2];
unsigned char *y_buf = pFrame->data[0];
unsigned char *u_buf = pFrame->data[1];
unsigned char *v_buf = pFrame->data[2];
//save y
for (i = 0; i < height; i++)
fwrite(y_buf + i * y_wrap, 1, width, pfout);
fprintf(stderr, "===>save Y success\n");
//save u
for (i = 0; i < height_half; i++)
fwrite(u_buf + i * u_wrap, 1, width_half, pfout);
fprintf(stderr, "===>save U success\n");
//save v
for (i = 0; i < height_half; i++)
fwrite(v_buf + i * v_wrap, 1, width_half, pfout);
fprintf(stderr, "===>save V success\n");
fflush(pfout);
}
/**
* save yuv422p frame [YUV]
*/
void yuv422p_save(AVFrame *pFrame, AVCodecContext *pCodecCtx)
{
int i = 0;
int width = pCodecCtx->width, height = pCodecCtx->height;
int height_half = height / 2, width_half = width / 2;
int y_wrap = pFrame->linesize[0];
int u_wrap = pFrame->linesize[1];
int v_wrap = pFrame->linesize[2];
uns