clq
浏览(0) +
2009-02-17 11:57:01 发表
编辑
关键字:
自己动手编写Opera插件 时间:2008-05-28 10:54:58 类别:脚本收藏 RSS 2.0 评论 作者:未知 \documentclass[a4paper]{article} \usepackage{CJK} \usepackage{color} \usepackage{listings} \usepackage[dvips, CJKbookmarks, colorlinks]{hyperref} \lstset{language=C++,keywordstyle=\color{blue}\textbf} \setlength{\parindent}{2em} \renewcommand{\baselinestretch}{1.5} \begin{document} \begin{CJK*}{GBK}{song} \title{自己动手编写Opera插件} \author{陶冶 \and E-Mail: taoyi5178-at-gmail.com} \maketitle 前段时间看到Firefox有了新版本,便去下了个试试,没想到很不爽,老崩溃。最后终于在N次死掉之后,在忍无可忍之下,怀着十分郁闷的心情把Firefox干干净净地请出来了我的电脑。经过这么长时间新老版本的使用,在我的印象中Firefox并没有传说中的那么神奇。当然也许我的运气比较糟点。不过世界上很多事情大致都是一个道理,看问题的角度不同就会有不同的答案,从相同或相似角度看到的总是多了那么一些共性,而我或许正好因为运气的关系偏离了原本相似的角度。清除了Firefox后,自然还是得找个替代品。Lynx也许很多人没用过,一个基于字符终端的浏览器,速度挺快,资源占用也比较少,不过缺点就是没有那么图形界面下来得有声有色,如果有时候想看看带点颜色的东西那是没有办法的。很久以前就听说过Opera了,不过还没有真正见识过,这次正好可以试试。 从Opera官方网站下载了最新的9.10 for linux版本,大概才9M多点。没想到这么小的东西安装后就什么都有了,除了是浏览器外,还集成了邮件客户端、RSS阅读器、下载管理器、日记本、联系人管理器等等。总之,经过一段时间的使用后,感觉相当爽,页面美观,速度很快,支持类似VIM的查找方式......但是也有让人遗憾的地方,就是没法播放在线音乐和视频,这点很难让人接受。虽然官方网站上有好几种常用的媒体文件播放插件,尽管我没有一一试过,但从其中之一MPlayer的插件来看,却并不是专门为之打造的,都是Firefox、Mozilla的插件。就以MPlayer插件为例,我从\url{http://mplayerplug-in.sourceforge.net}下载了最新的3.35版,折腾了半天就硬是没装上。最终在台湾的一个网站上看到一篇文章后,下载了3.25版并修改了源代码后才装上的。虽然是装上了,也可以播放在线音乐了,可就是出不来界面,一块灰白色的方框,死活没有播放、停止等按钮,很是不便。虽然还有其它选择,比如gxine插件等,但是不是这样依赖就是那么依赖,很烦。最终觉得应该自己写个才行,方便自己,于是在找了些资料后,自己开始研究Opera的插件。 从官方的网站上看到的有关Opera插件API里只有一段话,大概意思就是说Opera实现了Netscape4的插件接口,其它就没啦。后来想来,一些最新的Firefox插件不能用在Opera上的原因,恐怕就在这里,因为最新的Firefox插件基本上都使用的是XPCOM模型实现的,有的根本就没有提供MAC、Netscape老的接口,也难怪了。 Netscape插件模型包括在Mozilla的Gecko-sdk开发包中。Gecko-sdk是Mozilla、Firefox的插件开发包,它提供了跨平台的插件开发接口,包括XPCOM之类的东西(这东西好象很复杂,不太清楚)。Netscape插件模型提供了两套接口,一套接口是浏览器端实现,供插件实例调用的以NPN开头的函数;一套是插件自身实现,供浏览器调用的以NPP开头的函数。浏览器端的接口我们不用管,主要看看插件需要实现的接口就可以了。下面看看几个主要的函数: \begin{lstlisting}[frame=trbl]{} char *NP_GetMIMEDescription(void) \end{lstlisting} 这个函数是浏览器用以查看插件MIME头的描述,相当于是插件的注册函数,浏览器调用此函数返回的MIME描述信息后,就将之接收到的与该函数返回的与MIME信息相同的数据交由插件来处理。 \begin{lstlisting}[frame=trbl]{} NPError NP_GetValue ( void *future, NPPVariable variable, void *value) \end{lstlisting} 浏览器通过这个函数取得有关插件自身的信息,诸如插件的名称、插件的描述等。 \begin{lstlisting}[frame=trbl]{} NPError NP_Initialize( NPNetscapeFuncs* nsFuncs, NPPluginFuncs* pluginFuncs) \end{lstlisting} 浏览器调用这个函数实现插件的初始化。NPNetscapeFuncs结构是浏览器实现的函数表,NPPluginFuncs是插件实现的函数表,插件实现的接口需要在这里注册以供浏览器调用。 \begin{lstlisting}[frame=trbl]{} NPError NP_Shutdown(void) \end{lstlisting} 这个函数在浏览器不需要插件时调用以释放插件。 \begin{lstlisting}[frame=trbl]{} NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved) \end{lstlisting} 这个函数在浏览器创建插件时调用,其中argc是参数的个数,argn是参数名称,argv是参数值,这三个参数相当重要。当然这样说是不会明白的,举个例子: \begin{lstlisting}[frame=trbl]{} type="application/base-plugin" width=600 height=40 src="http://www.music.com/test.mp3"> \end{lstlisting} 如果我们的插件注册成处理application/base-plugin类型的数据,则以上HTML代码对应的NPP\_New函数的参数为: \begin{lstlisting}[frame=trbl]{} argc = 4 argn = {"type", "width", "height", "src"} argv = {"application/base-plugin", "600", "40", "http://www.music.com/test.mp3"} \end{lstlisting} \begin{lstlisting}[frame=trbl]{} NPError NPP_Destroy(NPP instance, NPSavedData **save) \end{lstlisting} 浏览器调用这个函数删除由NPP\_New创建的插件实例。 \begin{lstlisting}[frame=trbl]{} void NP_Shutdown(void) \end{lstlisting} 这个函数最后调用,以释放插件。 好了,几个主要的接口函数就介绍到这里,下面再来回顾一下插件代码的执行顺序: \begin{enumerate} \item 浏览器调用NP\_Initialize传递自身实现接口并注册插件实现接口; \item 浏览器调用NPP\_New创建实例; \item 运行插件逻辑; \item 调用NPP\_Destroy删除插件实例; \item 调用NP\_Shutdown释放插件; \end{enumerate} 大体代码框架如下: \begin{lstlisting}[frame=trbl]{} char *NP_GetMIMEDescription(void) { return "video/mpeg: mpeg, mpg, mpe: MPEG animation;" } NPError NP_GetValue ( void *future, NPPVariable variable, void *value) { NPError err = NPERR_NO_ERROR; switch (variable) { case NPPVpluginNameString: *((char **)value) = "mplayer plugin"; break; case NPPVpluginDescriptionString: *((char **)value) = "writen by taoyi5178@gmail.com"; break; default: err = NPERR_GENERIC_ERROR; } return err; } NPError NP_Initialize( NPNetscapeFuncs* nsFuncs, NPPluginFuncs* pluginFuncs) { pluginFuncs->size = sizeof(NPPluginFuncs); pluginFuncs->newq = NPP_New; ... ... return NPERR_NO_ERROR; } NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved) { ... ... } NPError NPP_Destroy( NPP instance, NPSavedData **save) { return NPERR_NO_ERROR; } NPError NP_Shutdown(void) { return NPERR_NO_ERROR; } \end{lstlisting} 下面是一个调用xine实现播放常见媒体文件的Opera插件代码。将该程序编译成共享库,然后将编译后的共享库复制到\$OPERA\_INSTALL\_PATH/lib/opera/plugins目录下,即完成插件的注册。之后在浏览网页时,凡是遇到相应MIME类型的数据,都将调用xine播放器来播放。稍微想多做点工作的话,还可以将每一个播放地址保存成播放列表,以备下次使用。当然你也可以使用其它你喜欢的播放器来完成这个工作。 \begin{lstlisting}{} #include #include #include #ifdef LOG #include #endif void xprintf(const char *format, ...); NPError NPP_Private_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved); NPError NPP_Private_Destroy(NPP instance, NPSavedData **save); //static NPNetscapeFuncs __nsFuncs; //-------------------------------------------------------------- void xprintf(const char *format, ...) { #ifdef LOG FILE *log_fd = NULL; va_list argp; if (!log_fd) { log_fd = fopen("/tmp/plug-in.log", "a+"); if (log_fd) { setvbuf(log_fd, NULL, _IONBF, 0); fprintf(log_fd, "\n*************\n\n"); } } va_start(argp, format); if (log_fd) vfprintf(log_fd, format, argp); va_end(argp); #endif } //-------------------------------------------------------------- char *NP_GetMIMEDescription(void) { xprintf("NPP_GetMIMEDescription:\n"); return "video/mpeg: mpeg, mpg, mpe: MPEG animation;" "video/x-mpeg: mpeg, mpg, mpe: MPEG animation;" "audio/mpeg2: mp2: MPEG audio;" "audio/x-mpeg2: mp2: MPEG audio;" "audio/mpeg3: mp3: MPEG audio;" "audio/x-mpeg3: mp3: MPEG audio;" "audio/mpeg: mpa,abs,mpega: MPEG audio;" "audio/x-mpeg: mpa,abs,mpega: MPEG audio;" "video/quicktime: mov,qt: Quicktime animation;" "video/x-quicktime: mov,qt: Quicktime animation;" "video/msvideo: avi: AVI animation;" "video/x-msvideo: avi: AVI animation;" "application/x-mplayer2: asf,asx,asp: mplayer2;" "video/x-ms-asf-plugin: asf,asx,asp: mms animation;" /*"audio/x-pn-realaudio-plugin: rpm: Real audio;"*/ "audio/x-ogg: ogg,ogm: OGG Media;" "audio/x-scpls: pls: MPEG audio" ; } //-------------------------------------------------------------- NPError NP_GetValue ( void *future, NPPVariable variable, void *value) { NPError err = NPERR_NO_ERROR; xprintf("NP_GetValue: variable=%d\n", variable); switch (variable) { case NPPVpluginNameString: *((char **)value) = "Opera audio/video plugin"; break; case NPPVpluginDescriptionString: *((char **)value) = "writen by taoyi5178-at-gmail.com"; break; default: err = NPERR_GENERIC_ERROR; } return err; } //-------------------------------------------------------------- NPError NP_Initialize( NPNetscapeFuncs* nsFuncs, NPPluginFuncs* pluginFuncs) { xprintf("NP_Initialize\n"); pluginFuncs->size = sizeof(NPPluginFuncs); pluginFuncs->newp = NPP_Private_New; pluginFuncs->destroy = NPP_Private_Destroy; return NPERR_NO_ERROR; } //-------------------------------------------------------------- NPError NPP_Private_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved) { int i; int ns_major, ns_minor, pluginMajor, pluginMinor; pid_t pid; xprintf("NPP_New\n"); for (i = 0; i < argc; i++) { xprintf("%s=%s\n", argn[i], argv[i]); if (strcasecmp(argn[i], "src") == 0) { xprintf("execute xine to play..."); if ((pid = fork()) < 0) xprintf("fork error"); else if (pid == 0) execlp("xine", "xine", argv[i], NULL); } } //xprintf("UserAgent: %s\n", __nsFuncs.uagent(instance)); return NPERR_NO_ERROR; } //-------------------------------------------------------------- NPError NPP_Private_Destroy(NPP instance, NPSavedData **save) { xprintf("NPP_Destroy\n"); return NPERR_NO_ERROR; } //-------------------------------------------------------------- NPError NP_Shutdown(void) { xprintf("NP_Shutdown\n"); return NPERR_NO_ERROR; } \end{lstlisting} OK,到此结束。看不懂的或不明白的,请自行参考后面的参考资料。 \newpage \begin{thebibliography}{99} \bibitem{pa} \href{http://web.archive.org/web/20040408173931/devedge.netscape.com/library/manuals/2002/plugin/1.0/pluginTOC.html}{Netscape Gecko Plug-in API Reference} \bibitem{pa} \href{http://mplayerplug-in.sourceforge.net/}{mplayer plug-in ---- embedded video player for mozilla} \end{thebibliography} \end{CJK*} \end{document}
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.