#include <stdio.h>
#include <libavutil/imgutils.h>
int main() {
const char *inputFileName = "input.jpg"; // 输入图片文件名
const char *outputFileName = "output.jpg"; // 输出图片文件名
int srcWidth, srcHeight, dstWidth, dstHeight; // 图像宽度和高度
uint8_t *srcData[4], *dstData[4]; // 输入和输出图像数据指针
int srcLinesize[4], dstLinesize[4]; // 输入和输出图像数据步长
// 注册 FFmpeg 所有组件
av_register_all();
// 打开输入文件
FILE *inputFile = fopen(inputFileName, "rb");
if (!inputFile) {
printf("无法打开输入文件\n");
return -1;
}
// 读取输入图片的宽度和高度 //文件指针的移动只是为了获取文件大小
fseek(inputFile, 0, SEEK_END); //第二第三个参数是一对,偏移量是相对于定位方式而言的。负为左,0当前,正为右方
int fileSize = ftell(inputFile); //返回一个字节数。
fseek(inputFile, 0, SEEK_SET); //还原指针。
uint8_t *fileBuffer = (uint8_t *)av_malloc(fileSize);
fread(fileBuffer, 1, fileSize, inputFile); //把整个图像读入缓冲区了。
fclose(inputFile);
// 获取输入图片的宽度和高度
AVFrame *pFrame = av_frame_alloc();
AVFrame *pFrameRGB = av_frame_alloc();
//第一个参数存了各个分量的数据,第二个分量存了,步长。最后一个参数的对此方式,1表示不进行内存对齐,四五六参数,分别表示输入图像的像素格式,宽度和高度。
//这个方法将,图像数据填充到 AVFrame 结构体中。
int ret = av_image_fill_arrays(pFrame->data, pFrame->linesize, fileBuffer,
AV_PIX_FMT_RGB24, srcWidth, srcHeight, 1);
if (ret < 0) {
printf("无法填充输入图像数据\n");
av_free(fileBuffer);
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
return -1;
}
srcWidth = pFrame->width;
srcHeight = pFrame->height;
// 设置输出图像的宽度和高度(缩放后的大小)
dstWidth = srcWidth / 2;
dstHeight = srcHeight / 2;
// 分配输出图像数据缓冲区 //最后的参数也是对齐方式。
int dstBufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, dstWidth, dstHeight, 1);
uint8_t *dstBuffer = (uint8_t *)av_malloc(dstBufferSize);
// 获取输入和输出图像数据指针和步长
av_image_fill_pointers(srcData, AV_PIX_FMT_RGB24, srcHeight, pFrame->data, pFrame->linesize); //真实 填充了。
av_image_fill_pointers(dstData, AV_PIX_FMT_RGB24, dstHeight, dstBuffer, dstWidth * 3); //填充了空
// 创建图像转换上下文
struct SwsContext *swsContext = sws_getContext(srcWidth, srcHeight, AV_PIX_FMT_RGB24,
dstWidth, dstHeight, AV_PIX_FMT_RGB24,
SWS_BILINEAR, NULL, NULL, NULL);
if (!swsContext) {
printf("图像转换上下文创建失败\n");
av_free(dstBuffer);
av_free(fileBuffer);
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
return -1;
}
// 进行图像缩放和转换
//转换上下文,源,源的步长,源的起始行号,需要处理源的行数,目标,目标步长。
sws_scale(swsContext, srcData, pFrame->linesize, 0, srcHeight, dstData, dstLinesize);
// 保存输出图像到文件
FILE *outputFile = fopen(outputFileName, "wb");
if (!outputFile) {
printf("无法打开输出文件\n");
av_free(dstBuffer);
av_free(fileBuffer);
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
sws_freeContext(swsContext);
return -1;
}
//fwrite(dstBuffer, 1, dstBufferSize, outputFile);
// 写入图像数据到输出文件
for (int i = 0; i < dstHeight; i++) {
fwrite(dstData[0] + i * dstLinesize[0], 1, dstWidth * 3, outputFile);
}
fclose(outputFile);
// 释放资源
av_free(dstBuffer);
av_free(fileBuffer);
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
sws_freeContext(swsContext);
return 0;
}
**
**
假设有一个 RGB24 格式的图像,图像宽度为 640 像素,高度为 480 像素。那么步长数组可以定义为:
int linesize[3] = {640 * 3, 0, 0};
在这个例子中,linesize[0] 表示 R 分量的步长,它等于图像宽度乘以 3,因为 RGB24 格式每个像素有 3 个分量(R、G、B),每个分量占据一个字节。
linesize[1] 和 linesize[2] 分别表示 G 和 B 分量的步长,因为在 RGB24 格式中,G 和 B 分量紧随 R 分量存储,它们的步长可以设为 0,表示它们与 R 分量存储在同一行内。
这样,通过 linesize 数组,可以正确地访问图像数据中的每个像素和分量。例如,要访问图像中第 i 行第 j 列的像素的 R 分量,可以使用以下代码:
uint8_t r = frame->data[0][i * linesize[0] + j * 3];
其中,frame 是 AVFrame 结构体,frame->data[0] 表示 R 分量的指针数组,i * linesize[0] 表示第 i 行的偏移量,j * 3 表示第 j 列的偏移量。通过这样的方式,可以准确地访问图像中的像素数据。
要访问图像中第 i 行第 j 列的像素的 G分量:
uint8_t r = frame->data[1][i * linesize[0] + j * 3];
以此类推。