Premiere&After Effects的实时预览插件开发

一、介绍

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/

时间: 2024-07-30 21:05:01

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

Linux下markdown编辑软件 — retext 支持实时预览,存为pdf、html、ODT等

本文由Suzzz原创,发布于 http://www.cnblogs.com/Suzzz/p/4129368.html,转载请保留此声明 ReText是一个linux下的markdown和reStructedText的编辑器,支持实时预览.输出为pdf.html.ODT等功能. 直接上效果图 查看生成的 html 代码

ubuntu vim markdown 实时预览

vim-instant-markdown插件 该插件支持vim编辑markdown文件时实时预览,不需要手动做任何事情! 使用vim打开一个xxx.md文件,浏览器会自动打开一个预览网页,在编辑这个文件的过程中,浏览器会自动更新,并不用保存该文档. 安装vim-instant-markdown 1.安装node.js curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -sudo apt-get install -y node

Atom编辑器折腾记_(11)编辑器实时预览HTML页面(插件:Atom HTML Preview)

为何寻找 每次预览HTML页面,都需要打开各种浏览器;哪怕不是调试,只是为了查看下效果; 切换来切换去,各种刷新,感觉有些浪费时间;以前用过DW的实时预览,感觉这个功能很赞; 又踏上了atom插件仓库慢慢寻找之路-.. 插件:atom-html-preview 官方描述:A live preview tool for Atom Editor. 简言之:Atom编辑器内实时预览的工具 获取方式 通过命令行安装 apm install atom-html-preview 通过编辑器内部的instal

Android中实时预览UI和编写UI的各种技巧

一.啰嗦 之前有读者反馈说,你搞这个所谓的最佳实践,每篇文章最后就给了一个库,感觉不是很高大上.其实,我在写这个系列之初就有想过这个问题.我的目的是:给出最实用的库来帮助我们开发,并且尽可能地说明这个库是如何编写的,希望让初创公司的程序员少写点给后人留坑的代码(想必大家对此深有体会).我之前给出的库都是很简单基础的,基本是一看就懂(但足够精妙),如果以后的文章涉及到了复杂的库,我会专门附加一篇库的讲解文.如果一个库的原理你知道,此外这个库很容易扩展和维护,而且它还用到了很多最佳实践的经验,你为什

RunJS个人使用推荐(好用的JS、css实时预览、编辑、管理等功能)

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

用 grunt-contrib-connect 构建实时预览开发环境 实时刷新

本文基本是参照着 用Grunt与livereload构建实时预览的开发环境 实操了一遍,直接实现能实时预览文件列表,内容页面.不用刷新页面了,这比以前开发网页程序都简单. 这里要用到的 Grunt 插件有 grunt-contrib-connect , 用来充当一个静态文件服务器,本身集成了 livereload 功能 grunt-contrib-watch , 监视文件的改变,然后执行指定任务,这里用来刷新  grunt serve 打开的页面 以下是个辅助的插件 load-grunt-tas

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

UI实时预览最佳实践 概要:Android中实时预览UI和编写UI的各种技巧.本文的例子都可以在结尾处的示例代码中看到并下载.如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request.本文的代码主要是基于作者的实际经验编写的,如果你有其他的技巧和方法也可以参与进来一起完善此文. 文章固定连接:https://github.com/tianzhijiexian/Android-Best-Practices/blob/master/2015.9/ui/u

整合VIM和Graphviz,并且使用本办法实现实时预览

在编程或是整理知识的时候一直苦于没有一款可以帮助理清思路的工具. 在网上苦寻良久,终于找到了一款可心可意的小软件 -- Graphviz. 折腾了一番,终于可以凑合着用了. 现将折腾的成果记录于此以作备忘,当然如果能够抛砖引玉那就再好不过了. 因为本人主要使用 Windows 以下将用 Windows 环境为例进行介绍. First 于此处下载需要的版本:http://www.graphviz.org/Download..php 将下载好的 msi 文件或 zip 文件安装或解压,记下安装路径.

利用less监视模式实时预览样式刷新浏览器

[前言]此处介绍的方法只是我个人的用法,相信大家有更好更简洁的方式. 上次写到利用LiveReload解放F5.而且LiveReload可以编辑sass/less/stylus.但是可惜发现LiveReload在编译的时候不能抛错,这就很麻烦了,少了个标点less编译就不过,查找起来太麻烦. 我目前的解决方法: 利用Less自带的客户端开发模式(development). 在开发的时候less的编译还是利用客户端浏览器,即 <link rel="stylesheet/less"