修改后的代码编译执行报错mpp[27610]: mpp_cfg: mpp_enc_cfg_set_s32: cfg h264:cabac_init_idc is invalid Set h264:cabac_init_idc failed: -1 mpp[27610]: mpp_cfg: mpp_enc_cfg_set_s32: cfg rc:max is invalid mpp[27610]: mpp_cfg: mpp_enc_cfg_set_s32: cfg h264:max is invalid mpp[27610]: mpp_enc: MPP_ENC_SET_RC_CFG bps 4000000 [2000000 : 6000000] fps [30:30] gop 60 mpp[27610]: h264e_api_v2: MPP_ENC_SET_PREP_CFG w:h [1920:1080] stride [1920:1088] mpp[27610]: h264e_api_v2: Warning: invalid cabac_init_idc 0 for profile 66, set to -1. mpp[27610]: mpp_enc: mode cbr bps [2000000:4000000:6000000] fps fix [30/1] -> fix [30/1] gop i [60] v [0] Flushing encoder... mpp[27610]: mpi: mpi_encode_put_frame found NULL input frame Warning: Encoder rejected NULL frame Flushed 0 packets Cleaning up resources... mpp[27610]: mpp_buffer: mpp_buffer_ref_dec buffer from main found non-positive ref_count 0 caller mpp_packet_deinit mpp[27610]: mpp_mem_pool: mpp_mem_pool_put_f invalid mem pool ptr 0x5591df4d08 node 0x5591df4ce0 check (nil) Transcoding completed successfully. Processed 3 frames. 怎么解决
时间: 2025-07-20 11:26:16 浏览: 3
<think>我们遇到了几个配置项无效的错误,包括`h264:cabac_init_idc`、`rc:max`和`h264:max`。此外,在清理资源时出现了引用计数问题和内存池错误。我们需要解决这些配置问题,并确保资源正确释放。
### 问题分析:
1. **无效配置项**:`h264:cabac_init_idc`、`rc:max`、`h264:max`在当前的MPP版本中可能不存在或已更名。我们需要找到正确的配置项名称。
2. **cabac_init_idc警告**:尽管我们尝试设置`cabac_init_idc`为-1,但MPP内部仍然有警告,说明设置可能未生效或设置方式不正确。
3. **刷新编码器时的问题**:发送空帧被拒绝,且没有刷新出任何数据包。
4. **资源释放问题**:在程序退出时,出现了引用计数为0时仍尝试减少引用计数和无效的内存池指针问题。
### 解决方案:
1. **配置项修正**:
- 对于`h264:cabac_init_idc`:在Baseline profile下,CABAC是被禁用的,因此这个参数可能被忽略。我们可以尝试不设置它,或者确认当前MPP版本是否支持该配置项。
- 对于QP设置:我们尝试了`rc:max`、`h264:max`等,但都失败了。正确的配置项可能是`rc:qp_max`和`rc:qp_min`(或`h264:qp_max`等)。我们将统一使用`rc:qp_max`和`rc:qp_min`。
2. **移除无效配置**:
- 移除`h264:cabac_init_idc`的设置,因为它在Baseline profile下无效,且可能已被弃用。
3. **刷新编码器**:
- 在发送空帧之前,先确保所有输入帧都已被编码器处理完毕。然后,多次调用`encode_get_packet`直到返回`MPP_OK`但无数据包。
4. **资源释放**:
- 确保每个`mpp_packet`和`mpp_frame`在使用后立即被释放,且不重复释放。
- 调整资源释放顺序,先释放编码器、解码器等上下文,再释放内存组和配置。
### 修改后的代码部分:
#### 1. 修正配置项设置
```cpp
// 移除cabac_init_idc的设置,因为它在Baseline下无效
// 不再设置:SAFE_SET_CFG(enc_cfg, "h264:cabac_init_idc", -1);
// 使用正确的QP配置项
SAFE_SET_CFG(enc_cfg, "rc:qp_max", 38);
SAFE_SET_CFG(enc_cfg, "rc:qp_min", 20);
SAFE_SET_CFG(enc_cfg, "rc:qp_init", 26);
```
#### 2. 刷新编码器的改进
```cpp
// 刷新编码器
if (eos && !encoder_flushed) {
std::cout << "Flushing encoder..." << std::endl;
// 发送空帧以刷新编码器
ret = encoder_mpi->encode_put_frame(encoder_ctx, nullptr);
if (ret != MPP_OK) {
std::cerr << "Warning: Encoder rejected NULL frame, ret=" << ret << std::endl;
}
// 循环获取所有剩余的数据包
int flush_count = 0;
MppPacket enc_pkt = nullptr;
while (1) {
ret = encoder_mpi->encode_get_packet(encoder_ctx, &enc_pkt);
if (ret != MPP_OK || !enc_pkt) {
break;
}
void *ptr = mpp_packet_get_data(enc_pkt);
size_t len = mpp_packet_get_length(enc_pkt);
out_file.write(static_cast<char*>(ptr), len);
mpp_packet_deinit(&enc_pkt);
flush_count++;
}
std::cout << "Flushed " << flush_count << " packets" << std::endl;
encoder_flushed = true;
}
```
#### 3. 资源释放顺序调整
在程序结束前,按照以下顺序释放资源:
1. 销毁MPP上下文(编码器、解码器、解析器)
2. 销毁编码配置
3. 销毁内存组
```cpp
// 释放顺序:先销毁上下文,再释放配置和内存组
if (encoder_ctx) {
mpp_destroy(encoder_ctx);
encoder_ctx = nullptr;
}
if (decoder_ctx) {
mpp_destroy(decoder_ctx);
decoder_ctx = nullptr;
}
if (parser_ctx) {
mpp_destroy(parser_ctx);
parser_ctx = nullptr;
}
if (enc_cfg) {
mpp_enc_cfg_deinit(enc_cfg);
enc_cfg = nullptr;
}
if (buf_group) {
mpp_buffer_group_put(buf_group);
buf_group = nullptr;
}
```
#### 4. 确保不重复释放资源
在代码中,我们确保每个`mpp_packet`和`mpp_frame`在不再使用后立即释放,且只释放一次。特别注意在循环中每次使用后都要释放。
### 完整代码修改部分:
由于代码较长,这里只提供修改的关键部分。在原有代码基础上进行以下修改:
**配置编码器部分:**
```cpp
// 基本参数设置(不变)
...
// 码率控制(不变)
...
// 帧率控制(不变)
...
// 编码参数
SAFE_SET_CFG(enc_cfg, "codec:type", MPP_VIDEO_CodingAVC);
SAFE_SET_CFG(enc_cfg, "h264:profile", 66); // Baseline profile
SAFE_SET_CFG(enc_cfg, "h264:cabac_en", 0); // 必须为0
SAFE_SET_CFG(enc_cfg, "h264:level", 40); // Level 4.0
SAFE_SET_CFG(enc_cfg, "h264:trans8x8", 0);
// QP设置 - 使用正确的配置项
SAFE_SET_CFG(enc_cfg, "rc:qp_max", 38);
SAFE_SET_CFG(enc_cfg, "rc:qp_min", 20);
SAFE_SET_CFG(enc_cfg, "rc:qp_init", 26);
// 设置GOP长度
SAFE_SET_CFG(enc_cfg, "rc:gop", 60); // GOP长度60帧
```
**刷新编码器部分:**
```cpp
if (eos && !encoder_flushed) {
std::cout << "Flushing encoder..." << std::endl;
// 发送空帧
ret = encoder_mpi->encode_put_frame(encoder_ctx, nullptr);
if (ret != MPP_OK) {
std::cerr << "Warning: Encoder rejected NULL frame, ret=" << ret << std::endl;
} else {
std::cout << "Sent NULL frame to encoder for flushing." << std::endl;
}
int flush_count = 0;
while (true) {
MppPacket enc_pkt = nullptr;
ret = encoder_mpi->encode_get_packet(encoder_ctx, &enc_pkt);
if (ret != MPP_OK || !enc_pkt) {
// 没有更多的数据包
break;
}
void *ptr = mpp_packet_get_data(enc_pkt);
size_t len = mpp_packet_get_length(enc_pkt);
out_file.write(static_cast<char*>(ptr), len);
mpp_packet_deinit(&enc_pkt);
flush_count++;
}
std::cout << "Flushed " << flush_count << " packets" << std::endl;
encoder_flushed = true;
}
```
**资源释放部分:**
```cpp
// 先销毁上下文
if (encoder_ctx) {
mpp_destroy(encoder_ctx);
encoder_ctx = nullptr;
}
if (decoder_ctx) {
mpp_destroy(decoder_ctx);
decoder_ctx = nullptr;
}
if (parser_ctx) {
mpp_destroy(parser_ctx);
parser_ctx = nullptr;
}
// 再释放配置
if (enc_cfg) {
mpp_enc_cfg_deinit(enc_cfg);
enc_cfg = nullptr;
}
// 最后释放内存组
if (buf_group) {
mpp_buffer_group_put(buf_group);
buf_group = nullptr;
}
```
### 其他注意事项:
- 在解码循环中,确保每次循环都释放了`dec_frame`,并且没有遗漏。
- 在读取输入文件时,如果读取失败或文件结束,确保释放已分配的缓冲区。
### 验证:
重新编译运行程序,观察是否还有配置项无效的错误,以及资源释放时是否还有错误信息。
如果仍然出现配置项无效,可能需要根据MPP版本调整配置项名称。可以尝试打印当前MPP版本支持的配置项列表(如果有相关API)。
### 打印支持的配置项(可选):
```cpp
// 在配置之前,打印支持的配置项
void print_supported_enc_cfgs(MppEncCfg cfg) {
MppEncCfgInfo *info = NULL;
mpp_enc_cfg_get_info(cfg, &info);
if (info) {
while (info->name) {
std::cout << "Supported config: " << info->name << " (type: " << info->type << ")" << std::endl;
info++;
}
}
}
// 在mpp_enc_cfg_init后调用
print_supported_enc_cfgs(enc_cfg);
```
### 最后:
通过以上修改,应该能解决配置项无效和资源释放的问题。如果问题仍然存在,请提供MPP的版本信息,以便进一步适配。
---
§§相关问题§§:
1. 在Rockchip MPP中如何正确设置H.264编码的QP参数?
2. 如何在不同版本的Rockchip MPP中保持配置兼容性?
3. 视频编码中刷新编码器缓冲区的最佳实践是什么?
4. 如何避免多媒体处理中的资源泄漏?</think>### 解决多层级配置错误与资源释放问题
您的问题涉及三个关键问题:配置项无效、空帧处理错误和资源释放错误。我将提供完整的修复方案:
#### 问题分析
1. **配置项无效错误**:
- `h264:cabac_init_idc is invalid`
- `rc:max is invalid`
- `h264:max is invalid`
- 这些配置项在当前MPP版本中已被弃用或更名
2. **空帧处理错误**:
- `mpi_encode_put_frame found NULL input frame`
- 刷新编码器时发送空帧被拒绝
3. **资源释放错误**:
- `mpp_buffer_ref_dec buffer from main found non-positive ref_count 0`
- `mpp_mem_pool_put_f invalid mem pool ptr`
### 完整修复代码
```cpp
#include <fstream>
#include <iostream>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/dma-buf.h>
#include "rk_mpi.h"
#include "mpp_log.h" // 添加MPP日志支持
#define MPP_ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
// 检查MPP返回值
#define CHECK_MPP_RET(ret, msg) \
if (ret != MPP_OK) { \
std::cerr << msg << " failed: " << ret << std::endl; \
return -1; \
}
// 安全设置编码参数
#define SAFE_SET_CFG(cfg, key, value) \
do { \
MPP_RET tmp_ret = mpp_enc_cfg_set_s32(cfg, key, value); \
if (tmp_ret != MPP_OK) { \
std::cerr << "Set " key " failed: " << tmp_ret << std::endl; \
} \
} while (0)
// 打印支持的配置项
void print_supported_configs(MppEncCfg cfg) {
MppEncCfgInfo info;
MPP_RET ret = mpp_enc_cfg_get_info(cfg, &info);
if (ret != MPP_OK) {
std::cerr << "Failed to get config info" << std::endl;
return;
}
std::cout << "Supported configurations:" << std::endl;
while (info.name) {
std::cout << " " << info.name << " (type: " << info.type << ")" << std::endl;
info++;
}
}
int main() {
// 启用详细日志
mpp_log_set_level(MPP_LOG_VERBOSE);
// 检查权限
if (geteuid() != 0) {
std::cerr << "ERROR: This program must be run as root!" << std::endl;
return -1;
}
// 1. 初始化MPP系统
MppCtx parser_ctx = nullptr, decoder_ctx = nullptr, encoder_ctx = nullptr;
MppApi *parser_mpi = nullptr, *decoder_mpi = nullptr, *encoder_mpi = nullptr;
// 创建解析器
MPP_RET ret = mpp_create(&parser_ctx, &parser_mpi);
CHECK_MPP_RET(ret, "Create parser");
ret = mpp_init(parser_ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC);
CHECK_MPP_RET(ret, "Init parser");
// 创建解码器
ret = mpp_create(&decoder_ctx, &decoder_mpi);
CHECK_MPP_RET(ret, "Create decoder");
ret = mpp_init(decoder_ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC);
CHECK_MPP_RET(ret, "Init decoder");
// 创建编码器
ret = mpp_create(&encoder_ctx, &encoder_mpi);
CHECK_MPP_RET(ret, "Create encoder");
ret = mpp_init(encoder_ctx, MPP_CTX_ENC, MPP_VIDEO_CodingAVC);
CHECK_MPP_RET(ret, "Init encoder");
// 2. 配置编码器参数 - 修复参数冲突
MppEncCfg enc_cfg = nullptr;
ret = mpp_enc_cfg_init(&enc_cfg);
CHECK_MPP_RET(ret, "Init encoder config");
// 先获取默认配置
ret = encoder_mpi->control(encoder_ctx, MPP_ENC_GET_CFG, enc_cfg);
CHECK_MPP_RET(ret, "Get default encoder config");
// 打印支持的配置项用于调试
print_supported_configs(enc_cfg);
// 设置视频参数
int width = 1920;
int height = 1080;
int hor_stride = MPP_ALIGN(width, 16); // H.264要求16字节对齐
int ver_stride = MPP_ALIGN(height, 16);
int fps = 30;
int bps_target = 4000000; // 4Mbps
// 基本参数设置
SAFE_SET_CFG(enc_cfg, "prep:width", width);
SAFE_SET_CFG(enc_cfg, "prep:height", height);
SAFE_SET_CFG(enc_cfg, "prep:hor_stride", hor_stride);
SAFE_SET_CFG(enc_cfg, "prep:ver_stride", ver_stride);
SAFE_SET_CFG(enc_cfg, "prep:format", MPP_FMT_YUV420SP);
// 码率控制
SAFE_SET_CFG(enc_cfg, "rc:mode", MPP_ENC_RC_MODE_CBR);
SAFE_SET_CFG(enc_cfg, "rc:bps_target", bps_target);
SAFE_SET_CFG(enc_cfg, "rc:bps_max", bps_target * 3 / 2);
SAFE_SET_CFG(enc_cfg, "rc:bps_min", bps_target / 2);
// 帧率控制
SAFE_SET_CFG(enc_cfg, "rc:fps_in_flex", 0);
SAFE_SET_CFG(enc_cfg, "rc:fps_in_num", fps);
SAFE_SET_CFG(enc_cfg, "rc:fps_in_denorm", 1);
SAFE_SET_CFG(enc_cfg, "rc:fps_out_flex", 0);
SAFE_SET_CFG(enc_cfg, "rc:fps_out_num", fps);
SAFE_SET_CFG(enc_cfg, "rc:fps_out_denorm", 1);
// ===== 修复CABAC冲突 =====
SAFE_SET_CFG(enc_cfg, "codec:type", MPP_VIDEO_CodingAVC);
SAFE_SET_CFG(enc_cfg, "h264:profile", 66); // Baseline profile
// 对于Baseline profile,禁用CABAC相关设置
SAFE_SET_CFG(enc_cfg, "h264:cabac_en", 0); // 必须为0
// 不再设置cabac_init_idc,因为它已被弃用
// SAFE_SET_CFG(enc_cfg, "h264:cabac_init_idc", -1); // 已弃用
SAFE_SET_CFG(enc_cfg, "h264:level", 40); // Level 4.0
SAFE_SET_CFG(enc_cfg, "h264:trans8x8", 0);
// ===== 修复QP配置错误 =====
// 使用正确的配置项名称
SAFE_SET_CFG(enc_cfg, "rc:qp_max_i", 26); // I帧最大QP
SAFE_SET_CFG(enc_cfg, "rc:qp_min_i", 22); // I帧最小QP
SAFE_SET_CFG(enc_cfg, "rc:qp_max", 38); // 所有帧最大QP
SAFE_SET_CFG(enc_cfg, "rc:qp_min", 20); // 所有帧最小QP
// 设置初始QP值
SAFE_SET_CFG(enc_cfg, "rc:qp_init", 26);
// 设置GOP长度
SAFE_SET_CFG(enc_cfg, "rc:gop", 60); // GOP长度60帧
// 应用配置
ret = encoder_mpi->control(encoder_ctx, MPP_ENC_SET_CFG, enc_cfg);
CHECK_MPP_RET(ret, "Apply encoder config");
// 3. 准备输入/输出文件
std::ifstream in_file("input.h264", std::ios::binary);
if (!in_file.is_open()) {
std::cerr << "Failed to open input file" << std::endl;
return -1;
}
std::ofstream out_file("output.h264", std::ios::binary);
if (!out_file.is_open()) {
std::cerr << "Failed to open output file" << std::endl;
return -1;
}
// 4. 创建内存组
MppBufferGroup buf_group = nullptr;
ret = mpp_buffer_group_get_internal(&buf_group, MPP_BUFFER_TYPE_DRM);
CHECK_MPP_RET(ret, "Create internal buffer group");
// 设置内存组限制
ret = mpp_buffer_group_limit_config(buf_group, 0, 8); // 最大8个缓冲区
CHECK_MPP_RET(ret, "Set buffer group limit");
// 5. 主处理循环
int frame_count = 0;
bool eos = false;
bool encoder_flushed = false;
while (!eos || !encoder_flushed) {
MppPacket in_pkt = nullptr;
// 仅当未到达文件结尾时读取数据
if (!eos) {
// 分配输入缓冲区
MppBuffer pkt_buf = nullptr;
size_t buf_size = width * height * 3 / 2;
buf_size = MPP_ALIGN(buf_size, 4096);
ret = mpp_buffer_get(buf_group, &pkt_buf, buf_size);
if (ret != MPP_OK) {
std::cerr << "Allocate input buffer failed: " << ret << std::endl;
// 短暂休眠后重试
usleep(10000); // 10ms
continue;
}
// 读取数据
void *dst = mpp_buffer_get_ptr(pkt_buf);
in_file.read(static_cast<char*>(dst), buf_size);
size_t read_size = in_file.gcount();
if (read_size == 0) {
// 文件结束
mpp_buffer_put(pkt_buf);
eos = true;
continue;
}
// 创建输入包
ret = mpp_packet_init_with_buffer(&in_pkt, pkt_buf);
if (ret != MPP_OK) {
std::cerr << "Init input packet failed: " << ret << std::endl;
mpp_buffer_put(pkt_buf);
continue;
}
mpp_packet_set_size(in_pkt, buf_size);
mpp_packet_set_length(in_pkt, read_size);
mpp_packet_set_pts(in_pkt, frame_count * 1000000 / fps);
// 提交到解析器
ret = parser_mpi->decode_put_packet(parser_ctx, in_pkt);
if (ret != MPP_OK) {
std::cerr << "Put packet to parser failed: " << ret << std::endl;
}
// 释放资源 - 先释放packet,再释放buffer
mpp_packet_deinit(&in_pkt);
mpp_buffer_put(pkt_buf);
frame_count++;
if (frame_count % 10 == 0) {
std::cout << "Processed " << frame_count << " frames" << std::endl;
}
}
// === 解码阶段 ===
MppFrame dec_frame = nullptr;
while (1) {
ret = decoder_mpi->decode_get_frame(decoder_ctx, &dec_frame);
if (ret != MPP_OK || !dec_frame) break;
// 检查帧有效性
if (mpp_frame_get_info_change(dec_frame)) {
// 处理分辨率变化
uint32_t new_width = mpp_frame_get_width(dec_frame);
uint32_t new_height = mpp_frame_get_height(dec_frame);
std::cout << "Resolution changed to: " << new_width << "x" << new_height << std::endl;
// 更新编码器配置
width = new_width;
height = new_height;
hor_stride = MPP_ALIGN(width, 16);
ver_stride = MPP_ALIGN(height, 16);
SAFE_SET_CFG(enc_cfg, "prep:width", width);
SAFE_SET_CFG(enc_cfg, "prep:height", height);
SAFE_SET_CFG(enc_cfg, "prep:hor_stride", hor_stride);
SAFE_SET_CFG(enc_cfg, "prep:ver_stride", ver_stride);
// 应用新配置
ret = encoder_mpi->control(encoder_ctx, MPP_ENC_SET_CFG, enc_cfg);
if (ret != MPP_OK) {
std::cerr << "Apply updated encoder config failed: " << ret << std::endl;
}
// 重新配置解码器
decoder_mpi->control(decoder_ctx, MPP_DEC_SET_INFO_CHANGE_READY, nullptr);
mpp_frame_deinit(&dec_frame);
continue;
}
// 检查帧是否有效
if (mpp_frame_get_buffer(dec_frame) == nullptr) {
std::cerr << "Warning: Got frame with NULL buffer" << std::endl;
mpp_frame_deinit(&dec_frame);
continue;
}
// === 编码阶段 ===
if (!encoder_flushed) {
ret = encoder_mpi->encode_put_frame(encoder_ctx, dec_frame);
if (ret == MPP_ERR_NULL_PTR) {
// 特殊处理空指针错误
std::cerr << "Encoder rejected frame (possible flush state)" << std::endl;
} else if (ret != MPP_OK) {
std::cerr << "Put frame to encoder failed: " << ret << std::endl;
}
}
// 获取编码后的包
MppPacket enc_pkt = nullptr;
while (1) {
ret = encoder_mpi->encode_get_packet(encoder_ctx, &enc_pkt);
if (ret != MPP_OK || !enc_pkt) break;
// 写入输出文件
void *ptr = mpp_packet_get_data(enc_pkt);
size_t len = mpp_packet_get_length(enc_pkt);
out_file.write(static_cast<char*>(ptr), len);
// 正确释放编码包
mpp_packet_deinit(&enc_pkt);
}
// 正确释放解码帧
mpp_frame_deinit(&dec_frame);
}
// 6. 刷新编码器缓冲区 - 修复空帧处理错误
if (eos && !encoder_flushed) {
std::cout << "Flushing encoder..." << std::endl;
// 正确刷新编码器的方法
// 首先发送空帧表示结束
ret = encoder_mpi->encode_put_frame(encoder_ctx, nullptr);
if (ret == MPP_ERR_NULL_PTR) {
std::cerr << "Warning: Encoder rejected NULL frame" << std::endl;
} else if (ret != MPP_OK) {
std::cerr << "Flush encoder failed: " << ret << std::endl;
} else {
std::cout << "Sent NULL frame to encoder for flushing" << std::endl;
}
// 然后获取剩余的包
int flush_count = 0;
while (true) {
MppPacket enc_pkt = nullptr;
ret = encoder_mpi->encode_get_packet(encoder_ctx, &enc_pkt);
if (ret == MPP_ERR_TIMEOUT) {
// 超时表示没有更多数据包
break;
}
if (ret != MPP_OK || !enc_pkt) {
break;
}
void *ptr = mpp_packet_get_data(enc_pkt);
size_t len = mpp_packet_get_length(enc_pkt);
out_file.write(static_cast<char*>(ptr), len);
mpp_packet_deinit(&enc_pkt);
flush_count++;
}
std::cout << "Flushed " << flush_count << " packets" << std::endl;
encoder_flushed = true;
}
}
// 7. 资源清理 - 修复资源释放错误
std::cout << "Cleaning up resources..." << std::endl;
// 正确的资源释放顺序:
// 1. 先销毁上下文
if (parser_ctx) {
mpp_destroy(parser_ctx);
parser_ctx = nullptr;
}
if (decoder_ctx) {
mpp_destroy(decoder_ctx);
decoder_ctx = nullptr;
}
if (encoder_ctx) {
mpp_destroy(encoder_ctx);
encoder_ctx = nullptr;
}
// 2. 再释放配置
if (enc_cfg) {
mpp_enc_cfg_deinit(enc_cfg);
enc_cfg = nullptr;
}
// 3. 最后释放内存组
if (buf_group) {
// 先清空内存组
mpp_buffer_group_clear(buf_group);
// 再释放内存组
mpp_buffer_group_put(buf_group);
buf_group = nullptr;
}
in_file.close();
out_file.close();
std::cout << "Transcoding completed successfully. Processed "
<< frame_count << " frames." << std::endl;
return 0;
}
```
### 关键修复点详解
#### 1. 修复无效配置项错误
```cpp
// 不再设置已被弃用的配置项
// SAFE_SET_CFG(enc_cfg, "h264:cabac_init_idc", -1); // 已弃用
// 使用正确的QP配置项名称
SAFE_SET_CFG(enc_cfg, "rc:qp_max_i", 26); // I帧最大QP
SAFE_SET_CFG(enc_cfg, "rc:qp_min_i", 22); // I帧最小QP
SAFE_SET_CFG(enc_cfg, "rc:qp_max", 38); // 所有帧最大QP
SAFE_SET_CFG(enc_cfg, "rc:qp_min", 20); // 所有帧最小QP
```
#### 2. 添加配置项调试支持
```cpp
// 打印支持的配置项
void print_supported_configs(MppEncCfg cfg) {
MppEncCfgInfo info;
MPP_RET ret = mpp_enc_cfg_get_info(cfg, &info);
if (ret != MPP_OK) {
std::cerr << "Failed to get config info" << std::endl;
return;
}
std::cout << "Supported configurations:" << std::endl;
while (info.name) {
std::cout << " " << info.name << " (type: " << info.type << ")" << std::endl;
info++;
}
}
// 在配置前调用
print_supported_configs(enc_cfg);
```
#### 3. 修复资源释放错误
```cpp
// 正确的资源释放顺序:
// 1. 先销毁上下文
mpp_destroy(parser_ctx);
mpp_destroy(decoder_ctx);
mpp_destroy(encoder_ctx);
// 2. 再释放配置
mpp_enc_cfg_deinit(enc_cfg);
// 3. 最后释放内存组
// 先清空内存组
mpp_buffer_group_clear(buf_group);
// 再释放内存组
mpp_buffer_group_put(buf_group);
```
#### 4. 改进空帧处理
```cpp
// 刷新编码器的正确方法
if (eos && !encoder_flushed) {
// 发送空帧表示结束
ret = encoder_mpi->encode_put_frame(encoder_ctx, nullptr);
// 处理可能的错误
if (ret == MPP_ERR_NULL_PTR) {
std::cerr << "Warning: Encoder rejected NULL frame" << std::endl;
}
// 获取剩余包
int flush_count = 0;
while (true) {
MppPacket enc_pkt = nullptr;
ret = encoder_mpi->encode_get_packet(encoder_ctx, &enc_pkt);
// 处理超时情况
if (ret == MPP_ERR_TIMEOUT) {
break;
}
if (ret != MPP_OK || !enc_pkt) {
break;
}
// 处理数据包...
flush_count++;
}
encoder_flushed = true;
}
```
### MPP版本兼容性处理
#### 1. 动态配置项处理
```cpp
// 根据配置项有效性动态设置参数
void set_qp_config(MppEncCfg cfg, const char* key, int value) {
MppEncCfgInfo info;
MPP_RET ret = mpp_enc_cfg_get_info(cfg, &info);
if (ret != MPP_OK) return;
bool found = false;
while (info.name) {
if (strcmp(info.name, key) == 0) {
found = true;
break;
}
info++;
}
if (found) {
ret = mpp_enc_cfg_set_s32(cfg, key, value);
if (ret == MPP_OK) {
std::cout << "Set " << key << " = " << value << std::endl;
} else {
std::cerr << "Failed to set " << key << ": " << ret << std::endl;
}
} else {
std::cerr << "Configuration " << key << " not supported" << std::endl;
}
}
// 使用动态设置
set_qp_config(enc_cfg, "rc:qp_max", 38);
set_qp_config(enc_cfg, "rc:qp_min", 20);
```
#### 2. 版本检测
```cpp
#include "rk_mpi_version.h"
// 获取MPP版本
const char* version = mpp_get_version();
std::cout << "MPP version: " << (version ? version : "unknown") << std::endl;
// 根据版本选择配置策略
if (version && strstr(version, "2.0")) {
// MPP 2.0+ 配置
SAFE_SET_CFG(enc_cfg, "rc:qp_max", 38);
SAFE_SET_CFG(enc_cfg, "rc:qp_min", 20);
} else {
// 旧版本兼容方案
SAFE_SET_CFG(enc_cfg, "rc:max_qp", 38);
SAFE_SET_CFG(enc_cfg, "rc:min_qp", 20);
}
```
### 验证修复效果
1. **检查配置项**:
- 不再出现 `cfg h264:cabac_init_idc is invalid` 错误
- 不再出现 `cfg rc:max is invalid` 错误
- 不再出现 `cfg h264:max is invalid` 错误
2. **检查空帧处理**:
- 刷新编码器时不再出现 `mpi_encode_put_frame found NULL input frame` 错误
- 成功刷新出剩余数据包
3. **检查资源释放**:
- 不再出现 `non-positive ref_count` 错误
- 不再出现 `invalid mem pool ptr` 错误
4. **验证输出文件**:
```bash
ffmpeg -i output.h264 -f null -
```
### 备选方案:简化配置
如果仍然遇到配置问题,可以使用固定QP模式简化配置:
```cpp
// 启用固定QP模式
SAFE_SET_CFG(enc_cfg, "rc:mode", MPP_ENC_RC_MODE_FIXQP);
// 设置固定QP值
SAFE_SET_CFG(enc_cfg, "rc:qp_init", 26);
SAFE_SET_CFG(enc_cfg, "rc:qp_max", 26);
SAFE_SET_CFG(enc_cfg, "rc:qp_min", 26);
```
---
阅读全文
相关推荐












