xiguanlant 2024-06-11 16:19 采纳率: 0%
浏览 54

FFMPEG + SDL2 播放黑屏

代码如下:实际运行中 收到的frame队列pts顺序正确 LOG打印也没有问题,但是SDL的窗口一直是黑屏状态,不知道如何排查问题。请各位看看。

void VideoPlay::play_video() {
  while (is_running_) {
    refresh_loop_wait_event(&event_);

    switch (event_.type) {
      case SDL_KEYDOWN:
        if (event_.key.keysym.sym == SDLK_q) {
          LOG_INFO("Q quit");
          is_running_ = false;
          frame_queue_->abort();
        }
        break;
      case SDL_QUIT:
        LOG_INFO("SDL_QUIT");
        is_running_ = false;
        frame_queue_->abort();
        break;

      default:
        break;
    }
  }
}

void VideoPlay::refresh_loop_wait_event(SDL_Event *event) {
  SDL_PumpEvents();

  while (
      !SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
    video_refresh();
    SDL_PumpEvents();
  }
}

void VideoPlay::video_refresh() {
  int ret = 0;
  frame_queue_->pop(frame_);
  if (!frame_) {
    LOG_ERROR("frame_queue_ pop failed.");
    is_running_ = false;
    frame_queue_->abort();
    return;
  }

  rect_.x = 0;
  rect_.y = 0;
  rect_.w = video_width_;
  rect_.h = video_height_;

  ret = SDL_UpdateYUVTexture(
      texture_, &rect_, frame_->data[0], frame_->linesize[0], frame_->data[1],
      frame_->linesize[1], frame_->data[2], frame_->linesize[2]);

  LOG_DEBUG("frame pts: %ld, tot size: %d, Y size: %d, U size: %d, V size: %d",
            frame_->pts, video_width_ * video_height_, frame_->linesize[0],
            frame_->linesize[1], frame_->linesize[2]);
  if (ret != 0) {
    LOG_ERROR("SDL_UpdateYUVTexture failed. %s", SDL_GetError());
    is_running_ = false;
    frame_queue_->abort();
    return;
  }
  ret = SDL_RenderClear(renderer_);
  if (ret != 0) {
    LOG_ERROR("SDL_RenderClear failed. %s", SDL_GetError());
    is_running_ = false;
    frame_queue_->abort();
    return;
  }
  ret = SDL_RenderCopy(renderer_, texture_, nullptr, &rect_);
  if (ret != 0) {
    LOG_ERROR("SDL_RenderCopy failed. %s", SDL_GetError());
    is_running_ = false;
    frame_queue_->abort();
    return;
  }
  SDL_RenderPresent(renderer_);
  SDL_Delay(10);
  av_frame_free(&frame_);
  frame_ = nullptr;
}

img

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-06-11 16:19
    关注

    引自免费微信小程序:皆我百晓生

    从你提供的代码来看,视频播放逻辑基本上是正确的,但有几个可能的问题点需要注意,这可能是导致黑屏的原因。让我们逐个检查这些可能的问题,并提供相应的解决思路。

    1. SDL初始化

    确保在你的程序开始时正确初始化了SDL库。这通常涉及到调用SDL_Init()函数,并且在结束时调用SDL_Quit()。例如:

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        LOG_ERROR("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        return -1;
    }
    // ... your code ...
    SDL_Quit();
    

    2. 窗口和渲染器创建

    确保窗口和渲染器正确创建。这包括设置正确的格式和尺寸。例如:

    window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, video_width_, video_height_, SDL_WINDOW_SHOWN);
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, video_width_, video_height_);
    

    3. YUV数据处理

    确认从FFmpeg获取的YUV数据是否正确。av_frame_free()在每次刷新后释放frame_可能会导致问题,因为你可能正在释放FFmpeg解码器还在使用的帧数据。如果使用的是FFmpeg的帧缓冲池,确保正确管理这些帧。

    4. YUV纹理更新

    SDL_UpdateYUVTexture函数的使用看起来是正确的。但是,确保frame_中的YUV数据确实包含了有效的像素信息。可以尝试在video_refresh函数开始时打印frame_->data[0]的前几个值,检查是否有非零的数据存在。

    5. 同步问题

    在多线程环境中,确保frame_queue_的读写操作是线程安全的。使用互斥锁或其他同步机制保护共享资源。

    6. 延迟问题

    SDL_Delay(10);可能导致帧率不匹配。考虑根据视频的实际帧率动态调整延迟时间,或者完全移除这个延迟,让SDL的刷新频率自然地由硬件决定。

    7. 错误处理

    确保所有可能返回错误的SDL函数都进行了适当的错误检查。例如,SDL_RenderClear, SDL_RenderCopy, 和 SDL_RenderPresent

    8. FFmpeg解码器配置

    检查FFmpeg解码器的配置,确保它正确输出了YUV420P格式的帧数据。如果解码器输出的格式与预期不同,你可能需要使用FFmpeg的sws_scale函数进行格式转换。

    解决方案概览

    • 验证SDL初始化、窗口和渲染器创建。
    • 确认YUV数据的正确性。
    • 检查并修复任何潜在的同步问题。
    • 调整延迟策略以适应视频帧率。
    • 彻底检查并处理所有可能的错误情况。
    • 如果必要,重新审视FFmpeg解码器的配置和输出格式。

    通过上述步骤,你应该能够定位并解决黑屏问题。如果问题仍然存在,建议在FFmpeg和SDL相关的开发论坛或社区寻求进一步的帮助,可能需要更详细的日志或代码示例来诊断具体问题。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 6月11日