拓展SOUI中SImRichEdit控件的视频OLE控件(VideoOle)

本文介绍了一款基于SOUI框架的视频OLE控件,详细解析了控件的实现原理与布局配置,并提供了使用示例。控件支持视频播放、暂停及加载状态显示等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

视频定位控件数据可分为两部分:

可见部分:播放按钮、加载按钮、视频第一帧图片、视频时长

不可见部分:视频URL

以下为VideoOle控件头文件部分:

	extern "C" const GUID IID_VideoOleCtrl;
	class RichEditVideoOle :public RichEditOleBase
	{
		DECLARE_REOBJ(RichEditVideoOle, L"video")
	public:
		enum ReVideoState
		{
			REVIDEO_STATE_NORMAL,
			REVIDEO_STATE_LOADING,
		};

		RichEditVideoOle();
		~RichEditVideoOle();
		BOOL InitOleWindow(IRichEditObjHost* pHost);

		int GetVideoState(){return _state;}
		SStringW GetVideoUrl(){return _video_url;}
		SStringW GetVideoDuration(){return _video_duration;}
		SStringW GetVideoId(){return GetId();}
		
		void SetVideoPlayState(ReVideoState state);
	protected:
		void UpdatePosition();
		bool OnBnClickPlay(SOUI::EventArgs* pEvt);

	protected:
		SOUI_ATTRS_BEGIN()
			ATTR_STRINGW(L"video_duration", _video_duration, FALSE)
			ATTR_STRINGW(L"video_url", _video_url, FALSE)
			ATTR_STRINGW(L"video_cover_path", _video_cover_path, FALSE)
		SOUI_ATTRS_END()

	private:
		int			_state;
		SStringW	_video_duration;			//视频时长
		SStringW	_video_url;				//视频文件路径
		SStringW	_video_cover_path;			//视频第一帧图片路径
	};

以下为VideoOle控件的源文件部分代码:

	//
	// ------------------------------------------------------------------------------
	// impl RichEditVideoOle
	//
	// {FAB32B7E-AC02-468c-A615-1E730243B62E}
	static const GUID IID_VideoOleCtrl = 
		{ 0xfab32b7e, 0xac02, 0x468c, { 0xa6, 0x15, 0x1e, 0x73, 0x2, 0x43, 0xb6, 0x2e } };
	RichEditVideoOle::RichEditVideoOle()
	{
		_oleGuid = IID_VideoOleCtrl;
		_sizeNatural.cx = 300;
		_sizeNatural.cy = 160;
		_state = REVIDEO_STATE_NORMAL;
		_canBeSelect = FALSE;
		_xmlLayout = L"LAYOUT:VideoOleLayout";
	}

	RichEditVideoOle::~RichEditVideoOle()
	{
	}

	BOOL RichEditVideoOle::InitOleWindow(IRichEditObjHost* pHost)
	{
		BOOL ret = RichEditOleBase::InitOleWindow(pHost);
		SWindow* pVideoWnd = _oleView.FindChildByName2<SWindow>(L"video_frame");
		if (pVideoWnd)
		{
			SImageWnd* pVideoCoverWnd = pVideoWnd->FindChildByName2<SImageWnd>(L"video_cover_img");
			IBitmap* pFrameImg = SResLoadFromFile::LoadImage(_video_cover_path);
			if (pVideoCoverWnd && pFrameImg)
			{
				pVideoCoverWnd->SetImage(pFrameImg);
				UpdateWindowLayout(pVideoCoverWnd);
			}
		}

		SImageView* pPlay = _oleView.FindChildByName2<SImageView>(L"play");
		ISkinObj* pPlaySkin = GETSKIN(L"skin.richvideo_play", 100);
		if (pPlay && pPlaySkin)
		{
			pPlay->SetSkin(pPlaySkin);
			pPlay->SetVisible(TRUE, TRUE);
			pPlay->Resume();

			SUBSCRIBE(pPlay, EVT_CMD, RichEditVideoOle::OnBnClickPlay);
		}
		
		SImageView* pLoading = _oleView.FindChildByName2<SImageView>(L"loading");
		ISkinObj* pLoadingSkin = GETSKIN(L"skin.richvideo_loading", 100);
		if (pLoading && pLoadingSkin)
		{
			pLoading->SetSkin(pLoadingSkin);
			pLoading->SetVisible(FALSE, TRUE);
			pLoading->Resume();
		}

		SStatic* pVideoDuration = _oleView.FindChildByName2<SStatic>(L"video_duration");
		if (pVideoDuration)
		{
			pVideoDuration->SetWindowText(L"00:30");
		}

		return ret;
	}

	bool RichEditVideoOle::OnBnClickPlay(SOUI::EventArgs* pEvt)
	{
		_state = REVIDEO_STATE_LOADING;
		SWindow* pVideoWnd = _oleView.FindChildByName2<SWindow>(L"video_frame");
		if (pVideoWnd)
		{
			SImageWnd* pVideoCoverWnd = pVideoWnd->FindChildByName2<SImageWnd>(L"video_cover_img");
			IBitmap* pFrameImg = SResLoadFromFile::LoadImage(_video_cover_path);
			if (pVideoCoverWnd && pFrameImg)
			{
				pVideoCoverWnd->SetImage(pFrameImg);
				UpdateWindowLayout(pVideoCoverWnd);
			}
		}

		SImageView* pPlay = _oleView.FindChildByName2<SImageView>(L"play");
		ISkinObj* pPlaySkin = GETSKIN(L"skin.richvideo_play", 100);
		if (pPlay && pPlaySkin)
		{
			pPlay->SetSkin(pPlaySkin);
			pPlay->SetVisible(FALSE, TRUE);
			pPlay->Resume();
		}

		SImageView* pLoading = _oleView.FindChildByName2<SImageView>(L"loading");
		ISkinObj* pLoadingSkin = GETSKIN(L"skin.richvideo_loading", 100);
		if (pLoading && pLoadingSkin)
		{
			pLoading->SetSkin(pLoadingSkin);
			pLoading->SetVisible(TRUE, TRUE);
			pLoading->Resume();
		}

		SStatic* pVideoDuration = _oleView.FindChildByName2<SStatic>(L"video_duration");
		if (pVideoDuration)
		{
			pVideoDuration->SetWindowText(L"00:30");
		}

		_pObjHost->NotifyRichObjEvent(this, CLICK_VIDEOPLAY, 0, 0);
		return true;
	}

	void RichEditVideoOle::SetVideoPlayState(ReVideoState state)
	{
		_state = state;
		if (REVIDEO_STATE_NORMAL == state)
		{
			SWindow* pVideoWnd = _oleView.FindChildByName2<SWindow>(L"video_frame");
			if (pVideoWnd)
			{
				SImageWnd* pVideoCoverWnd = pVideoWnd->FindChildByName2<SImageWnd>(L"video_cover_img");
				IBitmap* pFrameImg = SResLoadFromFile::LoadImage(_video_cover_path);
				if (pVideoCoverWnd && pFrameImg)
				{
					pVideoCoverWnd->SetImage(pFrameImg);
					UpdateWindowLayout(pVideoCoverWnd);
				}
			}

			SImageView* pPlay = _oleView.FindChildByName2<SImageView>(L"play");
			ISkinObj* pPlaySkin = GETSKIN(L"skin.richvideo_play", 100);
			if (pPlay && pPlaySkin)
			{
				pPlay->SetSkin(pPlaySkin);
				pPlay->SetVisible(TRUE, TRUE);
				pPlay->Resume();
			}

			SImageView* pLoading = _oleView.FindChildByName2<SImageView>(L"loading");
			ISkinObj* pLoadingSkin = GETSKIN(L"skin.richvideo_loading", 100);
			if (pLoading && pLoadingSkin)
			{
				pLoading->SetSkin(pLoadingSkin);
				pLoading->SetVisible(FALSE, TRUE);
				pLoading->Resume();
			}

			SStatic* pVideoDuration = _oleView.FindChildByName2<SStatic>(L"video_duration");
			if (pVideoDuration)
			{
				pVideoDuration->SetWindowText(L"00:30");
			}
		}
	}

	void RichEditVideoOle::UpdatePosition()
	{
		if (_spAdviseSink)
		{
			_oleView.SetOleWindowRect(CRect(0, 0, 0, 0)); // 已经失效
			_oleView.Move(0, 0, _sizeNatural.cx, _sizeNatural.cy);
			CalculateExtentSize(_sizeNatural);
			_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
		}
	}

IID_VideoOleCtrl为控件GUID,可以自己生成。

接口说明:

InitOleWindow:初始化Ole窗口

GetVideoState:获取视频状态

GetVideoUrl:获取视频URL

GetVideoId:获取元素ID

GetVideoDuration:获取视频时长

OnBnClickPlay:播放按钮点击事件

void SetVideoPlayState:设置视频状态,主要是在下载完成后设置控件状态时使用

以下是布局相关xml:

<root>
  <window pos="0,0,-0,-0" skin="skin.empty">
    <window name="video_frame" pos="0,0,-0,-0">
      <img name="video_cover_img" pos="0,0,-0,-0" />
    </window>
    <image name="play" pos="130,60,-130,-60" cursor="hand" />
    <image name="loading" pos="130,60,-130,-60" />
    <window name="durationWnd" pos="0,-20,-0,-0" skin="skin.richvideo_timebg">
      <text name="video_duration" pos="-40,3,@40,@13" align="center" colorText="#FFFFFF" font="size:12" />
    </window>
  </window>
</root>

控件需要在uires.idx文件中添加相关映射关系

注意事项跟《拓展SOUI中SImRichEdit控件的语音OLE控件(AudioOle)》中一样;


以下为使用示例代码:

        SStringW strVideo;
        std::string strVideoId = KfUtility::GenerateUUID();
	std::wstring wstrVideoId;
	KfUtility::ConvertUtf8ToUtf16(strVideoId, wstrVideoId);
	strVideo.Format(L"<video id=\"%s\" video_duration=\"120\" video_url=\"\" video_cover_path=\"D:\\imrepose\\trunk\\KFClient6\\output\\Debug_Unicode\\default_res\\location.jpg\" />", wstrAudioId.c_str());
	SStringW strContentVideo;
	strContentVideo.Format(
		L"<RichEditContent  type=\"ContentRight\" align=\"right\" auto-layout=\"1\">"
		L"<para break=\"1\" align=\"left\" />"
		L"<bkele data=\"avatar\" id=\"%s\" skin=\"%s\" left-pos=\"0,]-6,@40,@40\" right-pos=\"-50,]-10,@40,@40\" cursor=\"hand\" interactive=\"1\"/>"
		L"<para id=\"msgbody\" margin=\"65,0,45,0\" break=\"1\" simulate-align=\"1\">"		
		L"%s"
		L"</para>"
		L"<bkele data=\"bubble\" left-skin=\"skin_left_bubble\" right-skin=\"skin_right_otherbubble\" left-pos=\"50,{-9,[10,[10\" right-pos=\"{-10,{-9,-55,[10\" />"
		L"%s"
		L"</RichEditContent>",
		wstrId.c_str(), wstrFaceId.c_str(), strVideo, pEmpty);
	pRecvRichEdit->InsertContent(strContentVideo, RECONTENT_LAST);

控件效果图如下:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值