登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 程序员学前班[不再更新,只读] >> 主题: 自己动手编写Opera插件[zt]     [回主站]     [分站链接]
标题
自己动手编写Opera插件[zt]
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}


总数:0 页次:1/0 首页 尾页  
总数:0 页次:1/0 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1