📄 ~video_channel.~cpp
字号:
// video_channel.cpp : implementation file
//
#include "stdafx.h"
#include "../DvrManager.h"
#include "net.h"
#include "../toolbars/RightCamera.h"
#include "../toolbars/RightLogin.h"
#include "../toolbars/RightLR.h"
#include "../toolbars/RightMD.h"
#include "../toolbars/RightVOD.h"
#include "../utils/balloonhelp.h"
#include "../utils/common.h"
#include "../utils/custom_msgs.h"
#include "msgbox.h"
#include "video_channel.h"
#include "reg.h"
#include "../utils/BitmapPicture.h"
#include "../utils/Picture.h"
#include "memdc.h"
#include "vector"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define SEL_STYLE WS_EX_CLIENTEDGE
/////////////////////////////////////////////////////////////////////////////
// video_channel
#define WIDTH 352
#define HEIGHT 288
extern LPCTSTR rvVideoLogo;
CPicture VIDEO_LOGO;
typedef std::vector<video_channel*> vclist;
vclist video_wnds;
video_channel* video_channel::current_sel()
{
if( cur_sel )
return (video_channel*)cur_sel;
else
return (video_channel*)def;
}
video_channel* video_channel::number(int idx)
{
return video_wnds[idx];
}
int video_channel::count()
{
return video_wnds.size();
}
video_channel::video_channel(): v_chnl(-2), v_ip(0), drawing_grid(false)
, w(0), h(0)
{
mask.alloc(8);
}
video_channel::~video_channel()
{
}
BEGIN_MESSAGE_MAP(video_channel, baseclass)
//{{AFX_MSG_MAP(video_channel)
ON_WM_DESTROY()
ON_WM_MOVE()
ON_WM_SIZE()
ON_WM_LBUTTONDOWN()
ON_WM_PAINT()
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SNAPSHOT, on_snapshot)
MSG2(NTM_CMD_LOGOUT_OK, on_logout)
MSG2(NTM_CMD_CHANNEL_OPENED, on_channel_opened)
MSG2(NTM_CMD_CHANNEL_CLOSED, on_channel_closed)
MSG2(NTM_VIDEO_FRAME, on_video_frame)
MSG2(NTM_VOD_SET_SPEED, on_vod_set_speed)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// video_channel message handlers
void video_channel::dd_update()
{
CRightLogin* rl = CRightLogin::the_one();
if( IsWindow(rl->m_hWnd) )
rl->PostMessage(WM_UPDATE_WINDOW, (WPARAM)index());
// if( dd )
// dd_update_bound(dd);
}
bool video_channel::create(int index, CWnd* parent, const CRect& rc /* = CRect */,
DWORD style /* = ... */)
{
if( !baseclass::create(index, parent, rc, style) )
return false;
if( index == 0 )
def = this;
CString str;
str.Format(_T("%02d"), index+1);
title = read_string(rkVWTitle, str);
if( !VIDEO_LOGO.IsLoaded() )
{
CString str = read_string(rkSettings, rvVideoLogo);
if( !str.IsEmpty() )
VIDEO_LOGO.Load(str);
}
video_wnds.push_back(this);
// return dd != 0;
return true;
}
void video_channel::OnDestroy()
{
// if( dd )
// {
// dd_destroy(dd);
// dd = 0;
// }
baseclass::OnDestroy();
}
void video_channel::report_channel()
{
if( cur_sel && cur_sel != this )
return;
CRightLogin* rl = CRightLogin::the_one();
CRightCamera* rc = CRightCamera::the_one();
CRightLR* rlr = CRightLR::the_one();
rl->m_strVideoTitle.Empty();
rl->m_strChannelIndex.Empty();
rl->m_strChannelIP.Empty();
if( v_chnl != -1 &&
v_chnl != VOD_GROUP )
if( rc->m_hWnd )
rc->m_control.Format(IDS_CHNL_FMT, v_chnl+1);
rl->m_strVideoTitle = title;
if( is_video_opened() )
{
if( v_chnl != VOD_GROUP )
rl->m_strChannelIndex.Format(IDS_CHNL_FMT, v_chnl+1);
else
rl->m_strChannelIndex = IDString(IDS_VOD);
rl->m_strChannelIP = get_alias(v_ip);
if( rlr->m_hWnd )
{
rlr->m_ctrl = rl->m_strChannelIP;
rlr->m_str_chnl_info.Format(IDS_CHNL_FMT, v_chnl+1);
}
}
else
{
static IDString NOT_OPENED_YET(IDS_NOT_OPENED_YET);
rl->m_strChannelIndex = NOT_OPENED_YET;
rl->m_strChannelIP = NOT_OPENED_YET;
rc->m_control = NOT_OPENED_YET;
rlr->m_str_chnl_info = NOT_OPENED_YET;
rlr->m_ctrl = NOT_OPENED_YET;
}
// 2003.7.16. nodman
// 不能直接使用UpdateData,
// 因为在登出成功后, 由网络线程执行到这里, MFC对多线程比较感冒
// rlogin->UpdateData(FALSE); 会出错
if( rl->m_hWnd )
rl->SendMessage(WM_UPDATE_DATA, FALSE);
if( rc->m_hWnd )
{
rc->ipp = v_ip;
rc->channel = v_chnl;
rc->PostMessage(WM_UPDATE_DATA, FALSE);
}
if( rlr->m_hWnd )
{
rlr->PostMessage(WM_UPDATE_DATA, FALSE, (LPARAM)this);
}
}
/// 从net_cmd得到消息
/// @{
//void video_channel::on_channel_opened(IPPORT_TYPE, ULONG mip, USHORT mport, ULONG channel)
LRESULT video_channel::on_channel_opened(WPARAM w, LPARAM l)
{
ULONG ip = w;
USHORT port = HSHORT(l);
SHORT channel = LSHORT(l);
video_opened(ip, port, channel);
RedrawWindow();
return 0;
}
//void video_channel::on_channel_closed(IPPORT_TYPE, ULONG channel)
LRESULT video_channel::on_channel_closed(WPARAM w, LPARAM l)
{
drawing_grid = false;
ULONG ip = w;
USHORT port = HSHORT(l);
SHORT channel = LSHORT(l);
video_closed(ip, port, channel);
CRightLogin::the_one()->PostMessage(NTM_CMD_CHANNEL_CLOSED, w, l);
on_unsel();
return 0;
}
//void video_channel::on_logout_success(IPPORT_TYPE)
LRESULT video_channel::on_logout(WPARAM w, LPARAM l)
{
ULONG ip = w;
USHORT port = HSHORT(l);
SHORT channel = LSHORT(l);
if( v_ip == ip_port(ip, port) )
video_closed(ip, port, v_chnl);
return 0;
}
/// @}
// 当前是否打开通道
bool video_channel::is_video_opened()
{
return v_ip;
}
// 当选择时的处理
void video_channel::on_sel()
{
report_channel();
}
void video_channel::on_unsel()
{
CRect rc;
GetWindowRect(rc);
CWnd* p = GetParent();
if( !p )
return;
p->ScreenToClient(rc);
rc.InflateRect(2,2,2,2);
p->RedrawWindow(rc);
}
// 查询打开通道的IP
ip_port video_channel::channel_ip()
{
return v_ip;
}
// 查询打开通道的索引
int video_channel::channel_index()
{
return v_chnl;
}
void video_channel::OnMove(int x, int y)
{
baseclass::OnMove(x, y);
dd_update();
}
void video_channel::OnSize(UINT nType, int cx, int cy)
{
baseclass::OnSize(nType, cx, cy);
dd_update();
}
void video_channel::draw(void* buf)
{
check_grid((byte*)buf);
// dd_draw(dd, (LONG)buf);
}
/*
* 已解码视频帧到来
*/
//void video_channel::on_video_frame(int channel, void* vid_buf, ULONG size, int w, int h)
LRESULT video_channel::on_video_frame(WPARAM w, LPARAM l)
{
//nt_video_frame* vf = (nt_video_frame*)w;
if( l )
return 0;
byte* buf = (byte*)w;
// video_buf* vb = (video_buf*)w;
check_grid(buf);
// vb->free();
return 0;
}
BOOL video_channel::PreTranslateMessage(MSG* pMsg)
{
if( AfxGetMainWnd()->SendMessage(WM_FILTER_ACCEL, (WPARAM)pMsg, 0) )
return TRUE;
// if(pMsg->message == WM_RBUTTONDOWN )
// {
// OnRButtonDown();
// if( drawing_grid )
// return TRUE;
// }
return baseclass::PreTranslateMessage(pMsg);
}
bool video_channel::is_vod()
{
return v_chnl == VOD_GROUP;
}
LRESULT video_channel::on_snapshot(WPARAM w, LPARAM)
{
CRightLogin::the_one()->SendMessage(WM_SNAPSHOT);
/*
* 等待下一帧到来
* 下一帧到的时候, h263 解码器中, 会判断snapshot是否为空
* 如果不为空, 就把该帧保存在以snapshot为名的文件中.
* 并设snapshot为空, 以防止多次抓图.
*/
return 0;
}
//////////////////////////////////////////////////////////////////////////
/// 内部处理
void video_channel::video_opened(ULONG ip, USHORT port, int chnl)
{
if( v_ip )
return;
v_ip = ip_port(ip,port);
v_chnl = chnl;
report_channel();
CRightLogin* rl = CRightLogin::the_one();
if( rl->m_hWnd )
rl->PostMessage(WM_VIDEO_WND_INVOKED, (WPARAM)this, WM_LBUTTONDOWN);
CRightVOD* rv = CRightVOD::the_one();
if( chnl == VOD_GROUP && rv->m_hWnd )
rv->PostMessage(WM_OPEN_VOD);
CRightMD* rmd = CRightMD::the_one();
if( rmd->m_hWnd )
rmd->PostMessage(WM_CHANNEL_OPEN);
}
void video_channel::video_closed(ULONG ip, USHORT port, int chnl)
{
if( v_ip != ip_port(ip, port) ||
v_chnl != chnl )
return;
v_ip = 0;
v_chnl = -1;
clear_wnd();
CRightVOD* rv = CRightVOD::the_one();
if( rv->m_hWnd )
rv->PostMessage(WM_CLOSE_VOD);
report_channel();
CRightMD* rmd = CRightMD::the_one();
if( rmd->m_hWnd )
rmd->PostMessage(WM_CHANNEL_CLOSE);
}
/*
* video_mask 实现
*/
byte* video_channel::mask_data()
{
return mask;
}
void video_channel::set_grid(int _w, int _h)
{
if( _w == 0 )
{
drawing_grid = false;
return;
}
drawing_grid = true;
w = _w;
h = _h;
if( !mask )
mask.alloc(h); // 8 bits/byte
}
void video_channel::clear_grid()
{
drawing_grid = false;
mask.remove_all();
}
void video_channel::update()
{
// RedrawWindow();
}
void video_channel::calc_mask(CPoint pt, int& x, int& y)
{
CRect rc;
GetClientRect(rc);
// ScreenToClient(&pt);
// calculate the logical grid coord.
x = (pt.x-rc.left)*10/(rc.Width()/w)/10;
y = (pt.y-rc.top)*10/(rc.Height()/h)/10;
}
void video_channel::check_grid(byte* yuvbuf)
{
if( !drawing_grid )
return;
if( is_fulled() )
return;
int width = WIDTH;
int height = HEIGHT;
int pitch = width;
//DWORD* p = (DWORD*)buf;
byte* p = (byte*)yuvbuf;
for( int i=0; i<height; i+=height/h )
{
if( i == 0 )
continue;
for( int j=0; j<width; j++ )
{
p[(i*width+j)] = 239;
// p[(j*height+i)/2] = yuv;
}
}
for( i=0; i<width; i+=width/w )
{
if( i== 0 )
continue;
for( int j=0; j<height; j++ )
{
p[(j*width+i)] = 239;
}
}
for( i=0; i<8; i++ )
{
for( int j=0; j<8; j++ )
{
if( mask.is_set(j, i) )
{
fill_black(yuvbuf, j, i);
}
}
}
}
void video_channel::fill_black(byte* buf, int x, int y)
{
// YV12
// YUV planar
int width = WIDTH;
int height = HEIGHT;
int pitch = width;
int left = x*width/w;
int right = (x+1)*width/w;
int top = y*height/h;
int bottom = (y+1)*height/h;
for( int i=top; i<bottom; i++ )
{
for( int j=left; j<right; j++ )
{
int tmp1, tmp2;
int offset = (i*width+j);
tmp1 = buf[offset];
tmp2 = buf[offset+1];
tmp1 -= 90;
tmp2 -= 90;
const int mn = 16;
tmp1 = max(tmp1, mn);
tmp2 = max(tmp2, mn);
buf[offset] = tmp1;
buf[offset+1] = tmp2;
}
}
/*
// YUY2:
int width = 352;
int height = 288;
int pitch = width*2;
int left = x*width/w;
int right = (x+1)*width/w;
int top = y*height/h;
int bottom = (y+1)*height/h;
for( int i=top; i<bottom; i++ )
{
for( int j=left; j<right; j++ )
{
int tmp1, tmp2;
int offset = (i*width+j)*2;
tmp1 = buf[offset];
tmp2 = buf[offset+2];
tmp1 -= 90;
tmp2 -= 90;
const mn = 20;
if( tmp1 < mn )
tmp1 = mn;
if( tmp2 < mn )
tmp2 = mn;
buf[offset] = tmp1;
buf[offset+2] = tmp2;
ASSERT(offset<202752);
}
}
*/
}
void video_channel::OnLButtonDown(UINT nFlags, CPoint point)
{
if( drawing_grid )
{
int x, y;
calc_mask(point, x, y);
mask.toggle(x,y);
}
else
{
CRightCamera::the_one()->ipp = v_ip;
baseclass::OnLButtonDown(nFlags, point);
}
}
void video_channel::OnRButtonDown()
{
if( GetAsyncKeyState(VK_CONTROL) )
mask.select_all();
else
mask.remove_all();
}
void video_channel::OnRButtonDown(UINT nFlags, CPoint point)
{
if( drawing_grid )
{
if( (nFlags & MK_CONTROL) == MK_CONTROL )
mask.select_all();
else
mask.remove_all();
return;
}
baseclass::OnRButtonDown(nFlags, point);
}
LRESULT video_channel::on_vod_set_speed(WPARAM w, LPARAM)
{
if( !IsWindow(CRightVOD::the_one()->m_hWnd))
return 0;
CRightVOD::the_one()->PostMessage(WM_SET_VOD_SPEED, w);
return 0;
}
extern void DrawBitmap( CDC *pDC, HBITMAP hBitmap, HPALETTE hPal, int xDest, int yDest,
int wDest, int hDest);
void video_channel::OnPaint()
{
if( !VIDEO_LOGO.IsLoaded() )
baseclass::OnPaint();
else
{
CPaintDC dc(this);
if( is_video_opened() )
{
CRect rc;
GetWindowRect(rc);
CWnd* p = GetParent();
if( !p )
return;
COLORREF bk = RGB(255,255,255);
if( is_sel() )
{
bk = RGB(255,0,0);
}
CClientDC dc(p);
p->ScreenToClient(rc);
rc.InflateRect(1,1,1,1);
dc.FrameRect(rc, &CBrush(bk));
return;
}
CRect rc;
GetClientRect(rc);
CMemDC mdc(&dc, rc);
VIDEO_LOGO.Draw(&mdc, CPoint(0,0), rc.Size());
if( is_fulled() )
return;
COLORREF cl = RGB(255,255,255);
if( is_sel() )
{
cl = RGB(255,0,0);
}
mdc.FrameRect(rc, &CBrush(cl));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -