RTSP、RTMP播放器拉到的视频图像角度不对怎么办?
2023-02-18 16:41:00 时间
我们在做RTSP、RTMP播放器的时候,遇到这样的诉求:特别是RTSP,有些摄像头安装可能倒置或者旋转了90°亦或270°,拉取到图像,势必需要对视频图像做一定的处理,确保显示正常。
为此,我们提供了以下接口:视频数据水平反转、垂直反转、设置旋转角度。
好多开发者搞不清楚特别是水平反转和垂直反转,以下我们以图例的形式,做个效果展示。
先看原始图像:
水平反转后:
垂直反转后:
按照设定角度旋转(90°、180°、270°):
以C++的接口为例,设计如下:
/*
*上下反转(垂直反转)
*is_flip: 1:表示反转, 0:表示不反转
*/
NT_UINT32(NT_API *SetFlipVertical)(NT_HANDLE handle, NT_INT32 is_flip);
/*
*水平反转
*is_flip: 1:表示反转, 0:表示不反转
*/
NT_UINT32(NT_API *SetFlipHorizontal)(NT_HANDLE handle, NT_INT32 is_flip);
/*
设置旋转,顺时针旋转
degress: 设置0, 90, 180, 270度有效,其他值无效
注意:除了0度,其他角度播放会耗费更多CPU
接口调用成功返回NT_ERC_OK
*/
NT_UINT32(NT_API* SetRotation)(NT_HANDLE handle, NT_INT32 degress);
以上接口设计,考虑到图像出来后,才可以知道要怎么调整,设计成了可实时调用的接口模式。
具体调用逻辑非常简单:
player_api_.SetFlipVertical(player_handle_, BST_CHECKED == btn_check_flip_vertical_.GetCheck() ? 1 :0 );
player_api_.SetFlipHorizontal(player_handle_, BST_CHECKED == btn_check_flip_horizontal_.GetCheck() ? 1 : 0);
player_api_.SetRotation(player_handle_, rotate_degrees_);
旋转角度按钮逻辑:
void CSmartPlayerDlg::OnBnClickedButtonRotation()
{
rotate_degrees_ += 90;
rotate_degrees_ = rotate_degrees_ % 360;
if (0 == rotate_degrees_)
{
btn_rotation_.SetWindowText(_T("旋转90度"));
}
else if (90 == rotate_degrees_)
{
btn_rotation_.SetWindowText(_T("旋转180度"));
}
else if (180 == rotate_degrees_)
{
btn_rotation_.SetWindowText(_T("旋转270度"));
}
else if (270 == rotate_degrees_)
{
btn_rotation_.SetWindowText(_T("不旋转"));
}
if ( player_handle_ != NULL )
{
player_api_.SetRotation(player_handle_, rotate_degrees_);
}
}
总的来说,实现难度不大,此外,我们针对视频数据,还设计了只解关键帧、按照视频宽高scale显示图像,最大限度的方便用户使用。
/*
*设置只解码视频关键帧
*is_only_dec_key_frame: 1:表示只解码关键帧, 0:表示都解码, 默认是0
*成功返回NT_ERC_OK
*/
NT_UINT32(NT_API *SetOnlyDecodeVideoKeyFrame)(NT_HANDLE handle, NT_INT32 is_only_dec_key_frame);
/*
设置视频画面的填充模式,如填充整个绘制窗口、等比例填充绘制窗口,如不设置,默认填充整个绘制窗口
handle: 播放句柄
mode: 0: 填充整个绘制窗口; 1: 等比例填充绘制窗口, 默认值是0
成功返回NT_ERC_OK
*/
NT_UINT32 (NT_API *SetRenderScaleMode)(NT_HANDLE handle, NT_INT32 mode);
如果以上数据都还不满足开发者或终端用户的需求,我们还可以把数据(YUV/RGB)回调上来,用户自行处理。
player_api_.SetVideoFrameCallBack(player_handle_, NT_SP_E_VIDEO_FRAME_FORMAT_RGB32,
GetSafeHwnd(), SM_SDKVideoFrameHandle);
extern "C" NT_VOID NT_CALLBACK SM_SDKVideoFrameHandle(NT_HANDLE handle, NT_PVOID userData, NT_UINT32 status,
const NT_SP_VideoFrame* frame)
{
/*if (frame != NULL)
{
std::ostringstream ss;
ss << "Receive frame time_stamp:" << frame->timestamp_ << "ms" << "\r\n";
OutputDebugStringA(ss.str().c_str());
}*/
if ( frame != NULL )
{
if ( NT_SP_E_VIDEO_FRAME_FORMAT_RGB32 == frame->format_
&& frame->plane0_ != NULL
&& frame->stride0_ > 0
&& frame->height_ > 0 )
{
std::unique_ptr<nt_rgb32_image > pImage(new nt_rgb32_image());
pImage->size_ = frame->stride0_* frame->height_;
pImage->data_ = new NT_BYTE[pImage->size_];
memcpy(pImage->data_, frame->plane0_, pImage->size_);
pImage->width_ = frame->width_;
pImage->height_ = frame->height_;
pImage->stride_ = frame->stride0_;
HWND hwnd = (HWND)userData;
if ( hwnd != NULL && ::IsWindow(hwnd) )
{
::PostMessage(hwnd, WM_USER_SDK_RGB32_IMAGE, (WPARAM)handle, (LPARAM)pImage.release());
}
}
}
}
有了这些数据接口的加持,播放端对数据处理非常方便。
相关文章
- ps工具栏快捷键大全-详细介绍5种PS中常用的抠图技巧,助你快速抠出你想要的区域
- 电力煤矿液体泄漏识别系统
- 视频监控边缘分析盒
- 河道水尺水位监测系统
- ps工具栏快捷键大全-大神教你这10招PS操作技巧, 提高你的工作效率
- 占道经营出店摆摊监测识别系统
- 热成像成像不清楚是什么时候_红外热成像技术竟然可以做这些事情?
- 西门子SCL---气缸逻辑控制
- 红外测试操作步骤_红外热成像技术竟然可以做这些事情?(二)
- 口罩佩戴监测系统
- 模态对话框-B 类产品设计细节:对话框 vs 抽屉
- 人脸打卡机怎么作弊-指纹考勤机的常见问题及解决方法
- 循环队列出队-循环队列的c语言实现
- 循环队列出队-数据结构与算法 | 循环队列
- 河道非法采砂识别系统
- 循环队列出队-栈和队列的实现
- 循环队列出队-单个指针下循环链表的入队与出队
- spring 有哪些日志级别-LogBack 日志等级设置无效,原因竟然是因为这个
- 循环队列出队-队列,顺序队列与循环队列
- 渣土车空车未盖盖识别系统