MaybeNot 发表于 2024-10-21 18:41:30

使用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);
    }




}












dengkx 发表于 2024-10-22 09:26:21

1.可以更新版本试试
2.drm在init之后可以通过setPlaneRect或setWindowRect控制显示画面大小。
3.回调传递进来的buffer先调用flushDrmBuf,将数据从cache刷下来。
4. 像这种提前申请了videobuffer的,可以用rga模块导出接口交换buf,避免拷贝。
页: [1]
查看完整版本: 使用ffmedia库正常运行一段时间后画面概率出现闪烁/花屏