当前位置: 首页 > news >正文

mpv - write_video 流程解析


函数概述

write_video 是视频输出管道的核心函数,负责从解码器获取视频帧,处理视频重新配置、帧定时、同步、字幕更新,并将帧发送到视频输出(VO)进行渲染。


4. 获取视频帧

• 调用 video_output_image 获取视频帧,可能返回多种状态:

  • 错误(<0): 跳转到错误处理
  • 等待(VD_WAIT): 检查是否发生下溢(underrun),等待更多数据
  • EOF(VD_EOF): 处理结束状态,设置排水(DRAINING)状态,等待VO完成渲染
  • 新帧(VD_NEW_FRAME): 继续处理帧
bool logical_eof = false;
int r = video_output_image(mpctx, &logical_eof);
MP_TRACE(mpctx, "video_output_image: r=%d/eof=%d/st=%s\n", r, logical_eof,mp_status_str(mpctx->video_status));if (r < 0)goto error;if (r == VD_WAIT) {if (mpctx->video_status == STATUS_PLAYING && !vo_still_displaying(vo) &&!vo_c->underrun_signaled){vo_c->underrun = true;vo_c->underrun_signaled = true;}return;
}if (r == VD_EOF) {if (check_for_hwdec_fallback(mpctx))return;if (check_for_forced_eof(mpctx)) {uninit_video_chain(mpctx);handle_force_window(mpctx, true);return;}...if (mpctx->video_status == STATUS_DRAINING &&(vo_is_ready_for_frame(vo, -1) || !has_frame)){mpctx->time_frame -= get_relative_time(mpctx);mp_set_timeout(mpctx, mpctx->time_frame);if (mpctx->time_frame <= 0 || !has_frame) {MP_VERBOSE(mpctx, "video EOF reached\n");mpctx->video_status = STATUS_EOF;}}return;
}

6. 视频参数更新

• 应用视频裁剪设置
• 检查视频参数是否变化,需要时重新配置VO
• 更新动态参数(如色彩空间)

// Inject vo crop to notify and reconfig if needed
apply_video_crop(mpctx, vo);// Filter output is different from VO input?
struct mp_image_params *p = &mpctx->next_frames[0]->params;
if (!vo->params || !mp_image_params_static_equal(p, vo->params)) {if (vo_still_displaying(vo)) {vo_request_wakeup_on_done(vo);return;}int vo_r = vo_reconfig2(vo, mpctx->next_frames[0]);if (vo_r < 0) {mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED;goto error;}mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL);
} else {mp_mutex_lock(&vo->params_mutex);mp_image_params_update_dynamic(vo->params, p, vo->has_peak_detect_values);mp_mutex_unlock(&vo->params_mutex);
}

7. 同步处理

• 调整帧时间,更新音视频同步信息
• 强制字幕与视频帧同步
• 等待字幕准备就绪

mpctx->time_frame -= get_relative_time(mpctx);
update_avsync_before_frame(mpctx);// Enforce timing subtitles to video frames.
osd_set_force_video_pts(mpctx->osd, MP_NOPTS_VALUE);if (!update_subtitles(mpctx, mpctx->next_frames[0]->pts)) {MP_VERBOSE(mpctx, "Video frame delayed due to waiting on subtitles.\n");return;
}

8. 帧发送准备

• 检查VO是否准备好接收帧
• 编码模式下等待音频输出初始化

double time_frame = MPMAX(mpctx->time_frame, -1);
int64_t pts = mp_time_ns() + (int64_t)(time_frame * 1e9);if (!vo_is_ready_for_frame(vo, mpctx->display_sync_active ? -1 : pts))return;if (mpctx->encode_lavc_ctx && mpctx->current_track[0][STREAM_AUDIO] && !mpctx->ao)return;

9. 帧队列管理

• 维护过去帧信息队列
• 计算帧持续时间 calculate_frame_duration
• 构建VO帧数据结构

if (mpctx->num_past_frames >= MAX_NUM_VO_PTS)mpctx->num_past_frames--;
MP_TARRAY_INSERT_AT(mpctx, mpctx->past_frames, mpctx->num_past_frames, 0,(struct frame_info){0});
mpctx->past_frames[0] = (struct frame_info){.pts = mpctx->next_frames[0]->pts,.num_vsyncs = -1,
};
calculate_frame_duration(mpctx);int req = vo_get_num_req_frames(mpctx->video_out);
struct vo_frame dummy = {.pts = pts,.duration = -1,.still = mpctx->step_frames > 0,.can_drop = opts->frame_dropping & 1,.num_frames = MPMIN(mpctx->num_next_frames, req),.num_vsyncs = 1,
};
for (int n = 0; n < dummy.num_frames; n++)dummy.frames[n] = mpctx->next_frames[n];
struct vo_frame *frame = vo_frame_ref(&dummy);

10. 帧发送和状态更新

• 发送帧到VO进行渲染
• 检查是否需要丢帧
• 更新已显示帧计数
• 处理状态转换(准备就绪→播放中)

schedule_frame(mpctx, frame);
vo_queue_frame(vo, frame);
check_framedrop(mpctx, vo_c);if (mpctx->num_next_frames >= 1)handle_new_frame(mpctx);mpctx->shown_vframes++;
if (mpctx->video_status < STATUS_PLAYING) {mpctx->video_status = STATUS_READY;if (!opts->video_latency_hacks) {vo_wait_frame(vo);MP_VERBOSE(mpctx, "first video frame after restart shown\n");}
}mp_notify(mpctx, MPV_EVENT_TICK, NULL);

11. 特殊情况处理

• 处理逻辑EOF情况
• 处理步进(step)模式
• 检查最大帧数限制

if (logical_eof && !mpctx->num_next_frames && mpctx->ao_chain)mpctx->video_status = STATUS_EOF;if (mpctx->video_status != STATUS_EOF) {if (mpctx->step_frames > 0) {mpctx->step_frames--;if (!mpctx->step_frames) {set_pause_state(mpctx, true);step_frame_mute(mpctx, false);}}if (mpctx->max_frames == 0 && !mpctx->stop_play)mpctx->stop_play = AT_END_OF_FILE;if (mpctx->max_frames > 0)mpctx->max_frames--;
}vo_c->underrun_signaled = false;if (mpctx->video_status == STATUS_EOF || mpctx->stop_play)mp_wakeup_core(mpctx);

11. 流程图

在这里插入图片描述


http://www.dtcms.com/a/349082.html

相关文章:

  • 从技术精英到“芯”途末路:一位工程师的沉沦与救赎
  • 暖色调街头人像摄影照片Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • OpenHarmony Audio子系统全栈解码:从HDI驱动到DSP算法的低延迟高保真之路
  • SQL Server缩小日志文件.ldf的方法(适用于开发环境)
  • 复杂水域场景识别率↑89%!陌讯多模态融合算法在岸边垃圾检测的落地实践
  • Python学习笔记之(二)变量和简单的数据类型
  • 鸿蒙中Image白块问题分析与解决方案
  • Java:HashMap的使用
  • 2025/8/24 DockerDesktop安装使用
  • 云原生俱乐部-RH294知识点归纳(3)
  • Python内置函数全解析:30个核心函数语法、案例与最佳实践指南
  • Linux应急响应一般思路(二)
  • C++测试框架高级资源管理模块完整实现指南
  • 八、redis 入门 之 雪崩、穿透、击穿
  • 小米AX3600访问桥接的光猫
  • 如何一键统一文件名大小写?
  • Springboot框架的“上海迪士尼”旅游管理网站设计与开发
  • C++---双指针
  • 工作后的总结和反思3
  • cookie,session,token之间有什么关系
  • 大模型知识--Function Calls
  • Kubernetes — 学习 Sidecar 容器模式
  • 面经-自用
  • CVPR 2025 | 医学影像加速进化:深度学习×多模态,精准诊断再升级
  • Transformer 模型详解:从自注意力到编码器-解码器结构
  • 拓展:simulink中将仿真环境离散化
  • 关于熵减 - 飘升机
  • Vue3路由
  • C++11新特性全面解析(万字详解)
  • SQL Server从入门到项目实践(超值版)读书笔记 24