一、介绍

Adobe Premiere和After Effects在影视编辑、渲染领域已经得到广泛应用。全景视频在相应工具拼接好后也可以导入Premiere/After Effects后也可进行剪辑、渲染。但由于全景视频存在畸变、视角、拼接技术等因素,即使平铺时也无法很好的查看场景细节。这对于视频剪辑带来一定的不变。如果能一边剪辑视频一边在全景播放器中查看效果,那便再好不过了。gopro旗下的Kolor eye视频播放器就实现了这样的一种功能。实际上这个功能做起来并不难,其实就是基于Adobe Premiere Transmitter插件实现的。当然,Kolor Eye播放器插件也不例外。

二、插件开发

下面就聊聊如何开发吧。Adobe Premiere插件开发使用C++语言,并且依赖官方提供的开发包。因此在正式动手前需要下载好Adobe Plugin SDK。在SDK中的Projects目录下即可打开Demo工程:

TransmitterPlugin.h文件中,我们先把插件名称修改成自己需要的名字:

#define    PLUGIN_DISPLAY_NAME    L"Demo Preview"

  其他地方保持原样。然后打开对应的cpp文件进行修改。这里要实现两个功能:

  • 在恰当的时候启动外部全景播放器。
  • 将视频流持续转发给外部全景播放器。

那么应该怎么做呢。TransmitterPlugin.cpp文件中主要注意两个方法即可:StartPlaybackClock()PushVideo()方法。StartPlaybackClock()方法在即将播放视频的时候调用,我们选择在这个时候启动外部播放器是再自然不过了。这里通过进程枚举来判断外部播放器是否启动了。如果安装了外部播放器且没有启动,则启动播放器;否则直接利用已启动的播放器进行播放。

tmResult TransmitInstance::StartPlaybackClock(
const tmStdParms* inStdParms,
const tmInstance* inInstance,
const tmPlaybackClock* inClock)
{
...
frameTimeInSeconds = (float)inClock->inStartTime / mTicksPerSecond;
// If not yet playing, and called to play,
// then register our UpdateClock function that calls the audio callback asynchronously during playback
// Note that StartPlaybackClock can be called multiple times without a StopPlaybackClock,
// for example if changing playback speed in the timeline.
// If already playing, we the callbackContext doesn't change, and we let the current clock continue.
if (!mPlaying && inClock->inPlayMode == playmode_Playing)
{
mPlaying = kPrTrue;
if (installFlag && !FindProcessByName(wcsrchr(mLocation, L'/') + 1))
{
HINSTANCE hInstance;
hInstance = ShellExecute(NULL, TEXT("open"), mLocation, TEXT("previewplugin 2048 1024"), NULL, SW_SHOWNORMAL);
LOGINFO(L"ShellExecute returns %d", (int)hInstance);
}
// Initialize the ClockInstanceData that the UpdateClock function will need
// We allocate the data here, and the data will be disposed at the end of the UpdateClock function
...
}
return tmResult_Success;
}

  而PushVideo()根据字面意思就可以知道,是用来转发视频帧数据的,这也是为啥工程名叫Transmitter的原因。接下来,如何将视频帧数据传递给外部播放器呢?这里选择了Windows平台的内存共享技术。

tmResult TransmitInstance::PushVideo(
const tmStdParms* inStdParms,
const tmInstance* inInstance,
const tmPushVideo* inPushVideo)
{
....
frameTimeInSeconds = (float)inPushVideo->inTime / mTicksPerSecond;
mSuites.PPixSuite->GetBounds(inPushVideo->inFrames[0].inFrame, &frameBounds);
videoSize[0] = (frameBounds.right - frameBounds.left);
videoSize[1] = (frameBounds.bottom - frameBounds.top);
// Since we have ARGB color space mode.
mSuites.PPixSuite->GetPixelAspectRatio(inPushVideo->inFrames[0].inFrame, &parNum, &parDen);
mSuites.PPixSuite->GetPixelFormat(inPushVideo->inFrames[0].inFrame, &pixelFormat); mSuites.SequenceInfoSuite->GetZeroPoint(inInstance->inTimelineID, &zeroPointTime);
mSuites.SequenceInfoSuite->GetTimecodeDropFrame(inInstance->inTimelineID, &dropFrame);
mSuites.PPixSuite->GetPixels(inPushVideo->inFrames[0].inFrame, PrPPixBufferAccess_ReadWrite, &pixelsBuffer); if (videoSize[0] <= 0 || videoSize[1] <= 0)
{
// Dispose of the PPix(es) when done!
for (int i = 0; i < inPushVideo->inFrameCount; i++)
{
mSuites.PPixSuite->Dispose(inPushVideo->inFrames[i].inFrame);
} return tmResult_Success;
}
resizePixels((unsigned int*)pixelsBuffer, videoSize[0], videoSize[1], SCALED_WIDTH, SCALED_HEIGHT); if (!startupFlag)
{
startupFlag = 1;
// read registry and launch the player
HKEY hKey;
DWORD dwSize = MAX_PATH;
DWORD dwType = REG_SZ;
LPCTSTR studioPath = TEXT("studio");
LPCTSTR playerPath = TEXT("player");
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, studioPath, 0, KEY_READ, &hKey) ||
ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, playerPath, 0, KEY_READ, &hKey))
{
if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("install_location"), 0, &dwType, (LPBYTE)&mLocation, &dwSize))
{
installFlag = 1;
}
RegCloseKey(hKey);
}
else
{
ret = MessageBox(NULL, TEXT("We failed to find your Studio/Player installation。"), TEXT("Information"), MB_ICONINFORMATION | MB_OKCANCEL); }
if (installFlag)
{
HINSTANCE hInstance;
hInstance = ShellExecute(NULL, TEXT("open"), mLocation, TEXT("previewplugin 2048 1024"), NULL, SW_SHOWNORMAL);
LOGINFO(L"ShellExecute returns %d", (int)hInstance);
}
} // get memory file mapping for pixels buffer.
if (hPixelsMappingFile == NULL)
{
hPixelsMappingFile = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0, RESIZED_BUFFER_SIZE,
TEXT("pixels_buffer"));
pbPixelsFile = (void*)MapViewOfFile(hPixelsMappingFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
} if (hPixelsMappingFile != NULL && pbPixelsFile != NULL)
{
if (videoSize[0] / videoSize[1] == 2)
{
CopyMemory(pbPixelsFile, resizedBuffer, RESIZED_BUFFER_SIZE);
FlushViewOfFile(pbPixelsFile, RESIZED_BUFFER_SIZE);
}
} ...
return tmResult_Success;
}

  通过查找注册表判断是否安装外部全景播放器。如果已安装则通过安装路径直接启动,否则提示用户。每一帧的数据通过内存共享暴露给外部全景播放器。播放器只需读取这块共享内存即可。至此编码工作完成,简单的不能再简单。将编译好的插件复制到Premiere的插件目录即可查看效果。

三、注意事项

  • 依赖库。如果插件依赖外部程序库,在安装的时候也要复制到插件安装目录,或者是windows系统目录,否则插件是无法正常加载的。要查看插件依赖哪些外部程序库,可以使用VS附带的dumpbin命令:dumpbin /imports。有的时候安装可能会混淆32位和64位程序,那么还阔以通过dumpbin /headers查看程序库的版本。
  • Premiere/After Effects使用的是ARGB颜色模型。因此在利用外部程序库处理时,可能需要进行适当的转换。
  • 权限问题。在高版本的windows上,VS调试系统盘的程序时需要以管理员权限运行打开工程,否则是无法启动程序调试的。

四、参考链接

1. https://forums.adobe.com/thread/1661575

2. http://www.kolor.com/kolor-eyes/

Premiere&After Effects的实时预览插件开发的更多相关文章

  1. Sublime写MarkDown实时预览

    [TOC] Sublime写MarkDown实时预览 Sublime作为神器,实至名归. 首先 1.安装Sublime,并安装Package Control,这里不多说. 2.安装MarkDown P ...

  2. Sublime、Webstorm等在APICloud平台上全面支持WiFi真机同步和实时预览功能

    APICloud工具插件包括APICloud Studio.Sublime Text和Webstorm全面为开发者提供iOS和Android平台真机同步调试功能,不仅可以通过USB方式进行APP真机同 ...

  3. MWeb 1.4 新功能介绍一:引入文件夹到 MWeb 中管理,支持 Octpress、Jekyll 等静态博客拖拽插入图片和实时预览

    之前在 MWeb 中打开非文档库中的 Markdown 文档,如果文档中有引用到本机图片,是没办法在 MWeb 中显示出来和预览的.这是因为 Apple 规定在 Mac App Store(MAS) ...

  4. TypeWonder – 在任何网站上实时预览字体效果

    TypeWonder 让网页字体的选择过程变得轻松愉快.它可以帮助您在任何网站上快速测试 Web 字体效果!输入网站网址,就能够即时预览的字体的实际效果,还可以从数百种字体中进行挑选,您还可以得到所需 ...

  5. APICloud全面支持WiFi真机同步和实时预览功能

    APICloud工具插件包括APICloud Studio.Sublime Text和Webstorm全面为开发者提供iOS和Android平台真机同步调试功能,不仅可以通过USB方式进行APP真机同 ...

  6. 新增WiFi真机同步与实时预览功能 简化真机调试步骤

    APICloud工具插件为开发者提供iOS和Android平台真机同步调试功能,不仅可以通过USB方式进行APP真机同步功能,更新增WiFi真机同步和WiFi真机实时预览两大功能,方便开发者在开发过程 ...

  7. UI实时预览最佳实践(转)

    UI实时预览最佳实践 概要:Android中实时预览UI和编写UI的各种技巧.本文的例子都可以在结尾处的示例代码中看到并下载.如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以 ...

  8. 一个支持实时预览的在线 Markdown 编辑器 - Markdoc

    最近组内需要为一些项目和系统写文档,发表在公司内的文档平台上,这个平台并不支持markdown,所以打算做一个在线markdown编辑器,支持实时预览,并且可以很容易的迁移发表到公司文档平台上,所以就 ...

  9. RunJS推荐用于个人使用(使用方便JS、css实时预览、编辑、管理等功能)

    RunJS,在线编写.展示html.js.css代码,拥有实时预览.分享.Fork.代码高亮.自己主动完毕等多项特性,提供文件上传.多种登录方式. 地址:http://runjs.cn/ waterm ...

随机推荐

  1. 中奖概率算法(php 可用于刮刮卡,大转盘等抽奖算法)

    <?php //中奖概率算法(php 可用于刮刮卡,大转盘等抽奖算法) /* * 经典的概率算法, * $proArr是一个预先设置的数组, * 假设数组为:array(100,200,300, ...

  2. yiic执行出现不是内部或外部命令的解决办法

    右击我的电脑-->属性-->高级系统设置-->高级-->环境变量-->系统变量 设置为"D:\Program Files (x86)\wamp\bin\php\ ...

  3. 14.如何解决使用webpack打包之后,font-awsome路径不对的问题,终极解决方法

    问题描述: 使用webpack打包vue项目,使用font-awsome字体,发现打包之后,font-awsome图标不显示,报错为路径不对 看了下打包的路径,的确路径不对,打包之后font-awso ...

  4. Navigation Controller 创建方法

    添加Navigation Controller的方法主要有两种: 第一种:主要是通过在storyboard中拖入Object library 中的Navigation Controller 第二种方法 ...

  5. JavaScript学习笔记(散)——addLoadEvent函数

    先贴源码 function addLoadEvent(func) { var oldonload = window.onload; //存入当前onload事件 if(typeof window.on ...

  6. Ext常用开发基础知识

    Ext常用开发基础知识 组件定义 //这种方法可以缓存所需要的组件 调用起来比较方便(方法一 ) Ext.define('MySecurity.view.home.HomePanel', { //添加 ...

  7. Cordova(PhoneGap) 环境搭建与基础

    Cordova(PhoneGap) 创建步骤:官方Guide 环境准备 安装 Node.js nodejs.org 安装 git git-scm.com (bin目录添加到path) 安装 cordo ...

  8. OpenCV3.2 + VS2015环境配置

    一.准备工作: (1)   到OpenCV的官网(http://opencv.org/)下载OpenCV3.2 (2)   安装好VS2015. (3)   计算机系统:Win7(Win8, Win1 ...

  9. poj3320 (尺取法)

    n个数,求最小区间覆盖着n个数中所有的不相同的数字. 解题思路: AC代码: import java.util.HashMap; import java.util.HashSet; import ja ...

  10. 【TensorFlow入门完全指南】模型篇·逻辑斯蒂回归模型

    import库,加载mnist数据集. 设置学习率,迭代次数,batch并行计算数量,以及log显示. 这里设置了占位符,输入是batch * 784的矩阵,由于是并行计算,所以None实际上代表并行 ...