FFmpeg播放Hls录像控制解码速度

打印 上一主题 下一主题

主题 1089|帖子 1089|积分 3267

举行hls录像文件播放,播放速度很快,并未按照正常1秒25帧的帧率举行播放;
播放速度过快的缘故原由是因为代码中没有根据视频的帧率(Frame Rate)来控制帧的显示时间。HLS 视频通常有一个固定的帧率(比方 25 FPS),而代码在解码后立刻显示每一帧,没有思量帧之间的时间隔断,导致播放速度过快。
要办理这个题目,必要在显示每一帧时,根据帧率或帧的时间戳(PTS,Presentation Time Stamp)来控制帧的显示时间。
办理方案


  • 盘算帧隔断时间

    • 根据视频的帧率(FPS)盘算每帧的显示时间。
    • 比方,25 FPS 的视频,每帧的显示时间应为 1 / 25 = 0.04 秒(40 毫秒)。

  • 使用帧的时间戳(PTS)

    • 视频帧通常带偶然间戳(PTS),表示帧应该在什么时间显示。
    • 通过比较当前时间和帧的 PTS,可以精确控制帧的显示时间。

代码:

  1. #include <chrono>
  2. #include <thread>
  3. // 在显示帧的地方增加帧率控制
  4. auto start_time = std::chrono::steady_clock::now(); // 记录开始时间
  5. while (av_read_frame(format_ctx, &packet) >= 0) {
  6.     if (packet.stream_index == video_stream_index) {
  7.         if (avcodec_send_packet(codec_ctx, &packet) < 0) {
  8.             fprintf(stderr, "Error sending packet for decoding\n");
  9.             return -1;
  10.         }
  11.         while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
  12.             // 转换图像格式为 YUV420P
  13.             sws_scale(sws_ctx, (const uint8_t* const*)frame->data, frame->linesize, 0, codec_ctx->height, frame_yuv->data, frame_yuv->linesize);
  14.             // 计算当前帧的显示时间
  15.             double frame_delay = av_q2d(format_ctx->streams[video_stream_index]->time_base); // 时间基
  16.             double pts = frame->pts * frame_delay; // 当前帧的显示时间(秒)
  17.             // 计算已经过去的时间
  18.             auto now = std::chrono::steady_clock::now();
  19.             double elapsed_time = std::chrono::duration<double>(now - start_time).count();
  20.             // 如果当前帧应该在未来显示,则等待
  21.             if (pts > elapsed_time) {
  22.                 double sleep_time = pts - elapsed_time;
  23.                 std::this_thread::sleep_for(std::chrono::duration<double>(sleep_time));
  24.             }
  25.             // 使用 SDL 显示帧
  26.             SDL_UpdateYUVTexture(
  27.                 texture,
  28.                 NULL,
  29.                 frame_yuv->data[0],
  30.                 frame_yuv->linesize[0],
  31.                 frame_yuv->data[1],
  32.                 frame_yuv->linesize[1],
  33.                 frame_yuv->data[2],
  34.                 frame_yuv->linesize[2]
  35.             );
  36.             SDL_RenderClear(renderer);
  37.             SDL_RenderCopy(renderer, texture, NULL, NULL);
  38.             SDL_RenderPresent(renderer);
  39.         }
  40.     }
  41.     av_packet_unref(&packet);
  42. }
复制代码
 
关键点:


  • 时间基(Time Base)

    • av_q2d(format_ctx->streams[video_stream_index]->time_base) 将时间基转换为秒。
    • 帧的 PTS 乘以时间基,得到帧的显示时间(秒)。

  • 帧显示时间控制

    • 使用 std::chrono::steady_clock 记载开始时间。
    • 盘算当前帧的显示时间(pts)和已经已往的时间(elapsed_time)。
    • 如果当前帧应该在未来显示,则使用 std::this_thread::sleep_for 等待。

  • 帧率控制

    • 通过帧的 PTS 和当前时间的比较,确保帧按照正确的时间隔断显示。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

笑看天下无敌手

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表