
二、代码结构


前两个文件mf_sample_grabber.cpp和mf_sample_grabber.hpp实现了一个回调类;主要的作用是:当对视频进行帧采样时,将采样结果送回至UI线程(主线程)进行画面像素的刷新
文件video_controller.h定义了一个接口类,包括play,pause,stop等播放动作,而在video_util.h和video_util_mf.cpp对上述接口进行了具体的定义和实现
最后,在插件代码中分别video_view2d.cpp和video_view2d.hpp中利用前几个文件创建出来的类进行具体的逻辑处理
typedef shared_ptr<VideoView2D> VideoView2DSharedPtr;
class NODE2D_PLUGIN_API VideoView2D : public Node2D
{
public:
/// Represents message arguments of VideoView2D message types.
class VideoNavigationMessageArguments: public MessageArguments
{
public:
KZ_MESSAGE_ARGUMENTS_METACLASS_BEGIN(VideoNavigationMessageArguments, MessageArguments, "Video navigation message arguments")
KZ_METACLASS_END()
};
static MessageType<VideoNavigationMessageArguments> VideoPlayMessage;
static MessageType<VideoNavigationMessageArguments> VideoPauseMessage;
static MessageType<VideoNavigationMessageArguments> VideoRewindMessage;
//三个动作对应的消息
static PropertyType<string> VideoFileNameProperty;//video文件名的属性
static VideoView2DSharedPtr create(Domain* domain, string_view name);
KZ_METACLASS_BEGIN(VideoView2D, Node2D, "VideoView2D")
KZ_METACLASS_PROPERTY_TYPE(VideoFileNameProperty)//将消息和属性添加至容器
KZ_METACLASS_MESSAGE_TYPE(VideoPlayMessage)
KZ_METACLASS_MESSAGE_TYPE(VideoPauseMessage)
KZ_METACLASS_MESSAGE_TYPE(VideoRewindMessage)
KZ_METACLASS_END()
static PropertyTypeEditorInfoSharedPtr makeEditorInfo();
protected:
explicit VideoView2D(Domain* domain, string_view name);
void initialize();
virtual void onAttached() KZ_OVERRIDE;
virtual void onDetached() KZ_OVERRIDE;
virtual Vector2 measureOverride(Vector2 /*availableSize*/) KZ_OVERRIDE;
virtual void updateRenderOverride() KZ_OVERRIDE;
virtual void renderForegroundOverride(Renderer3D& renderer,
CompositionStack& compositionStack, const Matrix3x3& baseTransform) KZ_OVERRIDE;
void onVideoPlay(VideoNavigationMessageArguments& message);
void onVideoPause(VideoNavigationMessageArguments& message);
void onVideoRewind(VideoNavigationMessageArguments& message);
private:
/// Image texture which is used to display video frame.
TextureSharedPtr m_imageTexture;
/// Instance of video to play.
VideoControllerSharedPtr m_video;
};
cpp文件中的代码如下
PropertyTypeEditorInfoSharedPtr VideoView2D::makeEditorInfo()
{
return PropertyTypeEditorInfoSharedPtr(
KZ_PROPERTY_TYPE_EDITOR_INFO(
[]() -> PropertyTypeEditorInfo::AttributeDictionary {
PropertyTypeEditorInfo::AttributeDictionary dict;
dict.displayName = "Video View 2D";//自定义节点的名称
dict["FrequentlyAddedProperties"] = "Node2D.ForegroundBrush";//添加常用属性
return dict;
}()));
}
MessageType<VideoView2D::VideoNavigationMessageArguments> VideoView2D::VideoPlayMessage(kzMakeFixedString("Message.VideoView2D.Play"), 0);
MessageType<VideoView2D::VideoNavigationMessageArguments> VideoView2D::VideoPauseMessage(kzMakeFixedString("Message.VideoView2D.Pause"), 0);
MessageType<VideoView2D::VideoNavigationMessageArguments> VideoView2D::VideoRewindMessage(kzMakeFixedString("Message.VideoView2D.Rewind"), 0);
PropertyType<string> VideoView2D::VideoFileNameProperty(kzMakeFixedString("VideoView2D.VideoFileName"), "", 0, false,
KZ_DECLARE_EDITOR_METADATA
(
metadata.displayName = "Video Filename";
metadata.tooltip = "Video file to be played";
metadata.host = "VideoView2D:freq";
));
VideoView2DSharedPtr VideoView2D::create(Domain* domain, string_view name)
{
VideoView2DSharedPtr videoView2D = make_polymorphic_shared_ptr<Node>(new VideoView2D(domain, name));
videoView2D->initialize();
return videoView2D;
}
void VideoView2D::initialize()
{
// Initialize the base class.
Node2D::initialize();
// Register message handlers.
addMessageHandler(VideoPlayMessage, this, &VideoView2D::onVideoPlay);//三个消息处理动作,直接调用play pause等函数
addMessageHandler(VideoPauseMessage, this, &VideoView2D::onVideoPause);
addMessageHandler(VideoRewindMessage, this, &VideoView2D::onVideoRewind);
}
VideoView2D::VideoView2D(Domain* domain, string_view name):
Node2D(domain, name)
{
setRenderType(RenderTypeTexture);//将渲染形状设置为四边形
//Node will render itself as textured quad.
}
void VideoView2D::onAttached()//节点添加的动作
{
using std::swap;
Domain* domain = getDomain();
Node2D::onAttached();
BrushSharedPtr foregroundBrush;
#ifdef ANDROID
foregroundBrush = acquireResource<Brush>(ResourceID("kzb://node2d_plugin/Brushes/VideoViewBrushAndroid"));
#else
foregroundBrush = acquireResource<Brush>(ResourceID("kzb://node2d_plugin/Brushes/VideoViewBrush"));
#endif
setForegroundBrush(foregroundBrush);//加载并设置前景画刷
// Create new video.
string videoFilename = getProperty(VideoFileNameProperty);
VideoView2DSubmitFunctor task(*domain->getTaskDispatcher(), *this);
VideoControllerSharedPtr video = VideoUtil::create(*domain, videoFilename, task);//创建一个video管理对象
if (video) {//video可用的话,直接交换给全局成员变量
m_imageTexture = video->getRenderTexture(domain, this->shared_from_this());
swap(m_video, video);
}
else {
kzLogWarning(KZ_LOG_CATEGORY_GENERIC, ("Error in \'{}\' video view 2d: failed to load \'{}\' video file", getName(), videoFilename));
}
}
void VideoView2D::onDetached()//节点销毁的动作
{
Node2D::onDetached();
// Delete previous instance of video.
m_imageTexture.reset();
m_video.reset();
}
//******************************************************
void VideoView2D::renderForegroundOverride(//video view节点的渲染
Renderer3D& renderer, CompositionStack& /*compositionStack*/, const Matrix3x3& baseTransform)
{
if (m_video && m_visual) {
m_video->onRendering();//这里通过mf_sample_grabber.cpp的回调类来获取视频帧的数据,然后将数据写入到渲染纹理
m_visual->renderForeground(renderer, baseTransform);//具体的渲染动作函数
}
}
Vector2 VideoView2D::measureOverride(Vector2 /*availableSize*/)//通过video的width和height计算自定义2D节点的size并返回
{
Vector2 nodeSize;
if (m_video && m_imageTexture) {
// Get the node size based on the size of the texture.
if (m_imageTexture) {
nodeSize.setX(static_cast<float>(m_video->getWidth()));
nodeSize.setY(static_cast<float>(m_video->getHeight()));
}
}
return nodeSize;
}
void VideoView2D::updateRenderOverride()//渲染前完成特定节点纹理的更新
{
if (m_imageTexture) {
updateContentTexture(m_imageTexture);//更新前景画笔的内容纹理。
}
}
四、Kanzi工程的属性及触发设置
工程窗口的主要就是三个button,每个button设置一个buttonclick的动作,比如,rewind button点击时,会发一个rewind的消息,从而触发对应的消息处理函数,在消息处理函数中,最终会调用video_util类中的play,pause等动作

每个消息的作用目标都是插件自定义的的节点

参考
《Kanzi官方文档》
本文解析了如何在Kanzi中使用VideoView2D插件,通过mf_sample_grabber实现视频帧采样回调,配合video_controller的播放控制,展示了节点消息机制和属性编辑。重点介绍了VideoView2D类的实现,包括消息类型、属性和关键函数如play/pause/rewind操作。
1909

被折叠的 条评论
为什么被折叠?



