以下代码存在段错误,分析原因
/* 当前方案使用软件方案将yuv数据缩放到目标尺寸 */
static void scale_yuv420_bilinear(unsigned char *src, int src_w, int src_h,
unsigned char *dst, int dst_w, int dst_h) {
// 提取源YUV平面指针
unsigned char *src_y = src;
unsigned char *src_u = src + src_w * src_h;
unsigned char *src_v = src_u + (src_w/2) * (src_h/2);
// 提取目标YUV平面指针
unsigned char *dst_y = dst;
unsigned char *dst_u = dst + dst_w * dst_h;
unsigned char *dst_v = dst_u + (dst_w/2) * (dst_h/2);
// 缩放Y平面(全分辨率)
for (int j = 0; j < dst_h; j++) {
float y_ratio = (float)j / dst_h * src_h;
int y_idx = (int)y_ratio;
float y_fraction = y_ratio - y_idx;
for (int i = 0; i < dst_w; i++) {
float x_ratio = (float)i / dst_w * src_w;
int x_idx = (int)x_ratio;
float x_fraction = x_ratio - x_idx;
// 双线性插值计算
float y00 = src_y[y_idx * src_w + x_idx];
float y01 = src_y[y_idx * src_w + (x_idx + 1 < src_w ? x_idx + 1 : x_idx)];
float y10 = src_y[(y_idx + 1 < src_h ? y_idx + 1 : y_idx) * src_w + x_idx];
float y11 = src_y[(y_idx + 1 < src_h ? y_idx + 1 : y_idx) * src_w +
(x_idx + 1 < src_w ? x_idx + 1 : x_idx)];
float interpolated = y00 * (1 - x_fraction) * (1 - y_fraction) +
y01 * x_fraction * (1 - y_fraction) +
y10 * (1 - x_fraction) * y_fraction +
y11 * x_fraction * y_fraction;
dst_y[j * dst_w + i] = (unsigned char)interpolated;
}
}
// 缩放U和V平面(半分辨率,方法类似)
int src_u_w = src_w / 2, src_u_h = src_h / 2;
int dst_u_w = dst_w / 2, dst_u_h = dst_h / 2;
for (int j = 0; j < dst_u_h; j++) {
float y_ratio = (float)j / dst_u_h * src_u_h;
int y_idx = (int)y_ratio;
float y_fraction = y_ratio - y_idx;
for (int i = 0; i < dst_u_w; i++) {
float x_ratio = (float)i / dst_u_w * src_u_w;
int x_idx = (int)x_ratio;
float x_fraction = x_ratio - x_idx;
// U平面双线性插值
float u00 = src_u[y_idx * src_u_w + x_idx];
float u01 = src_u[y_idx * src_u_w + (x_idx + 1 < src_u_w ? x_idx + 1 : x_idx)];
float u10 = src_u[(y_idx + 1 < src_u_h ? y_idx + 1 : y_idx) * src_u_w + x_idx];
float u11 = src_u[(y_idx + 1 < src_u_h ? y_idx + 1 : y_idx) * src_u_w +
(x_idx + 1 < src_u_w ? x_idx + 1 : x_idx)];
float u_interp = u00 * (1 - x_fraction) * (1 - y_fraction) +
u01 * x_fraction * (1 - y_fraction) +
u10 * (1 - x_fraction) * y_fraction +
u11 * x_fraction * y_fraction;
dst_u[j * dst_u_w + i] = (unsigned char)u_interp;
// V平面同样处理
float v00 = src_v[y_idx * src_u_w + x_idx];
float v01 = src_v[y_idx * src_u_w + (x_idx + 1 < src_u_w ? x_idx + 1 : x_idx)];
float v10 = src_v[(y_idx + 1 < src_u_h ? y_idx + 1 : y_idx) * src_u_w + x_idx];
float v11 = src_v[(y_idx + 1 < src_u_h ? y_idx + 1 : y_idx) * src_u_w +
(x_idx + 1 < src_u_w ? x_idx + 1 : x_idx)];
float v_interp = v00 * (1 - x_fraction) * (1 - y_fraction) +
v01 * x_fraction * (1 - y_fraction) +
v10 * (1 - x_fraction) * y_fraction +
v11 * x_fraction * y_fraction;
dst_v[j * dst_u_w + i] = (unsigned char)v_interp;
}
}
}
/* 自定义内存目标管理器结构体 */
struct jpeg_mem_dest_mgr {
struct jpeg_destination_mgr pub; /* 公共字段 */
JOCTET *buffer; /* 内存缓冲区指针 */
size_t bufsize; /* 缓冲区总大小 */
size_t datasize; /* 已写入数据大小 */
};
static char* convert_fileid_to_filename(const char* file_id) {
// 检查输入合法性
if (file_id == NULL) {
DBPRINTF(DEBUG_LEVEL_ERROR, "illegal file_id: NULL\n");
return NULL;
}
if (strlen(file_id) != 14) {
DBPRINTF(DEBUG_LEVEL_ERROR, "file_id length must be 14, got %zu\n", strlen(file_id));
return NULL;
}
// 提取前两位作为快照类型字符串("00"/"01"/"02")
char type_str[3];
strncpy(type_str, file_id, 2);
type_str[2] = '\0'; // 确保字符串终止符
int snapshot_type = atoi(type_str);
// 根据类型确定基础路径
const char* base_path = NULL;
switch (snapshot_type) {
case PTZ_SNAPSHOT_PRESET: // "00"对应预设路径
base_path = PRESET_SNAPSHOT_PATH;
break;
case PTZ_SNAPSHOT_LIMIT: // "01"对应限制路径
base_path = LIMIT_SANPSHOT_PATH;
break;
case PTZ_SNAPSHOT_HOME: // "02"对应主页路径
base_path = HOME_SNAPSHOT_PATH;
break;
default:
DBPRINTF(DEBUG_LEVEL_ERROR, "invalid snapshot_type: %s\n", type_str);
return NULL;
}
// 提取最后5位作为文件ID后缀(14位字符串中索引9-13为最后5位)
const char* file_id_suffix = file_id + 9;
// 动态分配文件名缓冲区(避免返回局部变量)
char* file_name = (char*)malloc(256);
if (file_name == NULL) {
DBPRINTF(DEBUG_LEVEL_ERROR, "malloc failed for filename buffer\n");
return NULL;
}
// 拼接完整文件路径
snprintf(file_name, 256, "%s/%s.jpeg", base_path, file_id_suffix);
return file_name;
}
S32 ptz_snapshot(const char* file_id, int dst_width, int dst_height)
{
int ret = -1;
S32 src_width = -1;
S32 src_height = -1;
S32 yuv_size = 0;
U8 *yuvBuf = NULL;
/* libjpeg变量声明 */
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW y_plane[160], cb_plane[80], cr_plane[80]; /* 扫描线指针数组 */
JSAMPARRAY image_data[3] = { y_plane, cb_plane, cr_plane }; /* 分量数据指针 */
size_t final_jpeg_size = 0;
int quality = 95; /* 初始质量因子 */
size_t target_jpeg_size = 10 * 1024;
int retry_count = 3;
char *filename = NULL;
filename = convert_fileid_to_filename(file_id);
size_t items_written = 0;
if (NULL == file_id)
{
DBPRINTF(DEBUG_LEVEL_ERROR, "preset_snap path or name is NULL\n");
return ret;
}
yuv_size = avdc_get_minor_yuv(&yuvBuf, &src_width, &src_height);
if(yuv_size < 0 || src_width < 0 || src_height < 0)
{
DBPRINTF(DEBUG_LEVEL_ERROR, "get minor yuv failed\n");
return ret;
}
DBPRINTF(DEBUG_LEVEL_ERROR, "get minor yuv success\n");
U8* scaled_yuv = (U8*)malloc(src_width * src_height * 1.5);
if(scaled_yuv == NULL)
{
DBPRINTF(DEBUG_LEVEL_ERROR, "malloc error\n");
return ret;
}
scale_yuv420_bilinear(yuvBuf, src_width, src_height, scaled_yuv, dst_width, dst_height);
DBPRINTF(DEBUG_LEVEL_ERROR, "scale success\n");
/* 分配JPEG输出缓冲区(初始20KB) */
size_t jpeg_buf_size = 20 * 1024;
unsigned char *jpeg_buffer = (unsigned char *)malloc(jpeg_buf_size);
if (jpeg_buffer == NULL) {
DBPRINTF(DEBUG_LEVEL_ERROR, "malloc for jpeg_buffer failed\n");
free(scaled_yuv);
return ret;
}
/* 初始化JPEG压缩对象 */
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &jpeg_buffer, &jpeg_buf_size); /* 设置内存目标 */
/* 设置图像参数 */
cinfo.image_width = dst_width; /* 宽度200 */
cinfo.image_height = dst_height; /* 高度160 */
cinfo.input_components = 3; /* 3个分量(Y、Cb、Cr) */
cinfo.in_color_space = JCS_YCbCr; /* 直接使用YCbCr颜色空间 */
/* 设置采样因子(YUV420对应4:2:0) */
cinfo.comp_info[0].h_samp_factor = 2; /* Y水平采样因子2 */
cinfo.comp_info[0].v_samp_factor = 2; /* Y垂直采样因子2 */
cinfo.comp_info[1].h_samp_factor = 1; /* Cb水平采样因子1 */
cinfo.comp_info[1].v_samp_factor = 1; /* Cb垂直采样因子1 */
cinfo.comp_info[2].h_samp_factor = 1; /* Cr水平采样因子1 */
cinfo.comp_info[2].v_samp_factor = 1; /* Cr垂直采样因子1 */
jpeg_set_defaults(&cinfo);
cinfo.raw_data_in = TRUE; /* 启用原始数据输入模式,避免中间转换 */
/* 填充扫描线指针数组 */
for (int i = 0; i < dst_height; i++) {
y_plane[i] = &scaled_yuv[i * dst_width]; /* Y分量每行200字节 */
}
for (int i = 0; i < dst_height / 2; i++) {
cb_plane[i] = &scaled_yuv[dst_width * dst_height + i * (dst_width / 2)]; /* Cb分量每行100字节 */
cr_plane[i] = &scaled_yuv[dst_width * dst_height + (dst_width / 2) * (dst_height / 2) + i * (dst_width / 2)]; /* Cr分量每行100字节 */
}
/* 质量控制循环:do-while调整质量直至JPEG大小<10KB */
do {
jpeg_set_quality(&cinfo, quality, TRUE); /* 设置质量因子 */
jpeg_start_compress(&cinfo, TRUE);
/* 写入原始数据(避免YUV420到YUV444转换) */
while (cinfo.next_scanline < cinfo.image_height) {
int mcu_height = cinfo.max_v_samp_factor * DCTSIZE; /* MCU高度=16像素 */
int rows_to_write = (cinfo.image_height - cinfo.next_scanline) < mcu_height ?
(cinfo.image_height - cinfo.next_scanline) : mcu_height;
jpeg_write_raw_data(&cinfo, image_data, rows_to_write);
/* 更新指针到下一行 */
for (int i = 0; i < rows_to_write; i++) {
y_plane[i] += dst_width; /* Y指针后移一行 */
}
for (int i = 0; i < rows_to_write / 2; i++) {
cb_plane[i] += (dst_width / 2); /* Cb指针后移半行 */
cr_plane[i] += (dst_width / 2); /* Cr指针后移半行 */
}
}
jpeg_finish_compress(&cinfo);
final_jpeg_size = ((struct jpeg_mem_dest_mgr *)cinfo.dest)->datasize;
quality -= 2; /* 不满足条件,降低质量 */
if (quality <= 0) {
DBPRINTF(DEBUG_LEVEL_ERROR, "Unable to compress image below 10KB even at lowest quality\n");
break;
}
} while (final_jpeg_size < target_jpeg_size);
FILE *fp = fopen(filename, "wb");
if (fp) {
/* 提供写入失败处理逻辑,写入失败则丢弃当前缓冲区数据并重试指定次数 */
while(retry_count)
{
items_written = fwrite(jpeg_buffer, 1, final_jpeg_size, fp);
if(items_written == final_jpeg_size)
{
DBPRINTF(DEBUG_LEVEL_ERROR, "success to write %s\n", filename);
fclose(fp);
ret = 0; /* 成功 */
goto release_data;
}
else
{
retry_count--;
DBPRINTF(DEBUG_LEVEL_ERROR, "failed to write %s, retry_count %d\n", filename, retry_count);
if (fflush(fp) != 0)
{
DBPRINTF(DEBUG_LEVEL_ERROR, "failed to fflush\n");
}
clearerr(fp);
}
}
if (0 == retry_count)
{
DBPRINTF(DEBUG_LEVEL_ERROR, "retry_count come limit, failed to write!\n");
}
fclose(fp);
}
else
{
DBPRINTF(DEBUG_LEVEL_ERROR, "Failed to open file for writing: %s\n", filename);
}
release_data:
jpeg_destroy_compress(&cinfo);
free(filename);
free(jpeg_buffer);
free(scaled_yuv);
return ret;
}