使用ffmedia库正常运行一段时间后画面概率出现闪烁/花屏
本帖最后由 MaybeNot 于 2024-10-21 18:44 编辑使用ffmedia对本地mp4视频文件进行mpp解码+rga颜色空间转换和缩放,将获取到的rgb数据通过opencv显示,发现在正常执行一段时间后(从几分钟到半小时不等),概率出现画面异常,如下图所示,且画面出现异常时没有报错信息。
firefly@firefly:~/ymplayer/test/ffmedia/demo$ sudo ./ymtest /home/firefly/material/127.mp4
Firefly FFMedia: v2.3.1
INFO: 16ModuleFileReader: init: Get Video Resolution( 140 x 1080 )
(2024-10-21 18:37:00) (ymtest.cpp:401) source_module_output_para.width=140, height=1080
rga_api version 1.3.2_ ( build: 2024-08-08 03:16:34 base: )
==================Pipe===================
ModuleFileReader (H264 140x1080)
|--->ModuleMppDec (NV12 140x1080)
|--->ModuleRga (RGB24 384x2960)
INFO: 10MppDecoder: getTimeoutSample: 0x55cbd9e300 frame info changed 1 error 0 discard 0
代码大致如下:之所以不用drm显示而是用opencv是为了测试得到的数据画面是否正常,若用drm display的话无法设置384x2960(是16对齐)的宽高。不知道对于宽高差距较大是否有问题,需不需要调节setBufferCount的大小呢?
void callback_external(void* _ctx, shared_ptr<MediaBuffer> buffer)
{
External_ctx* ctx = static_cast<External_ctx*>(_ctx);
shared_ptr<ModuleRga> module = ctx->module;
if (buffer == NULL || buffer->getMediaBufferType() != BUFFER_TYPE_VIDEO)
return;
shared_ptr<VideoBuffer> buf = static_pointer_cast<VideoBuffer>(buffer);
void *data = buf->getActiveData();
uint32_t size = buf->getActiveSize();
pthread_mutex_lock(&rgb_data_ctx.mutex);
while (rgb_data_ctx.count == VBUFFER_SIZE) {
pthread_cond_wait(&rgb_data_ctx.not_full, &rgb_data_ctx.mutex);
}
memcpy(rgb_data_ctx.rgb_buf[(rgb_data_ctx.in % VBUFFER_SIZE)].rgb_frame, (uchar *)data, size);
rgb_data_ctx.in = (rgb_data_ctx.in + 1) % VBUFFER_SIZE;
rgb_data_ctx.count++;
pthread_cond_signal(&rgb_data_ctx.not_empty);
pthread_mutex_unlock(&rgb_data_ctx.mutex);
}
void process_rgb_frame(void *_ctx)
{
while (true){
pthread_mutex_lock(&rgb_data_ctx.mutex);
if (rgb_data_ctx.count == 0 && rgb_data_ctx.done == 1){
pthread_mutex_unlock(&rgb_data_ctx.mutex);
log_info("done, break");
break;
}
while(rgb_data_ctx.count == 0 && rgb_data_ctx.done == 0){
pthread_cond_wait(&rgb_data_ctx.not_empty, &rgb_data_ctx.mutex);
}
void *data = rgb_data_ctx.rgb_buf[rgb_data_ctx.out].rgb_frame;
if(rgb_data_ctx.count > 0)
rgb_data_ctx.count--;
rgb_data_ctx.out = (rgb_data_ctx.out+1) % VBUFFER_SIZE;
cv::Mat mat(cv::Size(384, 2960), CV_8UC3, data);
cv::imshow("display window", mat);
cv::waitKey(1);
pthread_cond_signal(&rgb_data_ctx.not_full);
pthread_mutex_unlock(&rgb_data_ctx.mutex);
}
for(int i=0; i<VBUFFER_SIZE; i++){
free(rgb_data_ctx.rgb_buf[i].rgb_frame);
rgb_data_ctx.rgb_buf[i].rgb_frame = NULL;
rgb_data_ctx.rgb_buf[i].rgb_ts = 0;
}
return;
}
int start_instance(External_ctx* ctx)
{
int ret;
DemoConfig* inst_conf = &(ctx->config);
file_reader->setProductor(NULL);
file_reader->setBufferCount(20);
ret = file_reader->init();
shared_ptr<ModuleMppDec> dec = make_shared<ModuleMppDec>(inst_conf->input_image_para);
dec->setProductor(file_reader);
dec->setBufferCount(10);
ret = dec->init();
if (ret < 0) {
ff_error("Dec init failed\n");
// goto FAILED;
}
shared_ptr<ModuleRga> rga = make_shared<ModuleRga>(inst_conf->output_image_para, inst_conf->rotate);
rga->setProductor(dec);
rga->setBufferCount(2);
ret = rga->init();
if (ret < 0) {
ff_error("rga init failed\n");
// goto FAILED;
}
ctx->module = rga;
ctx->rga_buffer = rga->newModuleMediaBuffer(); // 默认为cacheable的buffer
rga->setOutputDataCallback(ctx, callback_external);
std::thread frame_processor(process_rgb_frame, ctx);
frame_processor.detach();
clock_gettime(CLOCK_MONOTONIC, &ctx->start);
file_reader->start();
file_reader->dumpPipe();
while (true) {
int played_cnt = 0;
if(STATUS_EOS == file_reader->getModuleStatus()){ // 获取当前组件工作状态
log_info("STATUS_EOS, end of stream. cnt = %d", played_cnt++);
goto STOP;
}
usleep(5000);
}
}
1.可以更新版本试试
2.drm在init之后可以通过setPlaneRect或setWindowRect控制显示画面大小。
3.回调传递进来的buffer先调用flushDrmBuf,将数据从cache刷下来。
4. 像这种提前申请了videobuffer的,可以用rga模块导出接口交换buf,避免拷贝。
页:
[1]