BlackBerry 应用程序开发者指南 第一卷:基础--第5章 支持的媒体内容(Media Content)


作者:Confach 发表于April 23,2006 15:02 pm
版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息.
http://www.cnblogs.com/confach/articles/387902.html

5

5 支持的媒体内容(Media Content

PME内容

播放媒体内容

监听媒体内容事件

创建定制的连接

PME内容

BlackBerry设备支持PME格式的富(rich)媒体内容。

开发者可以使用Plazmic Content Developer’s Kit for BlackBerry来创建PME内容。这个工具,以及附带的文档可以在Plazmic网站(www.plazmic.com)找到。

Media Engine API(在net.rim.plazmic.mediaengine net.rim.plazmic.mediaengine.io包中)允许应用程序获取和播放存储在BlackBerry设备上或网络上的PME内容.
Media Engine API支持媒体格式application/x-vnd.rim.pme. Web服务器必须为application/x-vnd.rim.pme设置MIME类型。

PME API概览

下面3个主要类(在net.rim.plazmic.mediaengine包里)提供了加载和播放PME媒体内容的能力。

描述

MediaManager

提供从本地或网络上加载媒体内容的方法。

MediaPlayer

提供播放PME媒体的方法。

MediaException

为获取或播放媒体的错误提供异常代码。

媒体加载

Media Engine API允许应用程序使用下面4种协议种的一种加载媒体内容:

协议

描述

http://

http协议从一个使用HTTP连接网络Web服务器下载内容。这个协议需要一个带有BlackBerry MDS服务的BESBlackBerry Enterprise ServerBlackBerry企业服务器).

https://

https协议从一个使用HTTPS连接网络Web服务器下载内容。这个协议需要一个带有BlackBerry MDS服务的BESBlackBerry Enterprise ServerBlackBerry企业服务器).

Jar:///<pme_file>

jar协议加载存储在本地BlackBerry设备上的jar文件。

jar:///sample.pme

注意:开始的斜线(/)是需要的。

BlackBerry IDE中,.jar文件必须加入到调用应用程序或应用程序依赖的库的相同项目中。

cod://<module><pme_file>

cod协议加载存储在本地BlackBerry设备上的cod文件。

cod://mediasample/sample.pme

为使用其他协议,实现定制的Connector。为获得更多信息,参看91页的“创建定制的Connector”.

播放状态(Playback states

为了获取MediaPlayer的当前状态,调用MediaPlayer.getState().

状态

描述

UNREALIZED

MediaPlayer未准备播放媒体。为了转到REALIZED状态,调用MediaPlayer.setMedia().

REALIZED

MediaPlayer准备好播放媒体。为了开始播放,并转到STARTED状态,调用MediaPlayer.start().

STARTED

MediaPlayer正在播放媒体。为了停止播放和返回到REALIZED状态,调用MediaPlayer.stop().

异常

MediaEngineMediaManager类的方法抛出一个MediaException异常,这个异常包含了一个标准的HTTP响应代码或者下面异常代码之一。为了获取与异常相联系的错误代码,调用MediaException.getCode().

异常代码

描述

INVALID_HEADER

媒体格式无效。

REQUEST_TIMED_OUT

请求超时。

INTERRUPTED_DOWNLOAD

应用程序调用MediaManager.cancel()来取消下载。

UNSUPPORTED_TYPE

媒体类型(MIME类型)不支持。

UPGRADE_PALYER

媒体引擎的版本和请求的内容不兼容。

UPGRADE_MEDIA

媒体引擎的版本不在支持请求的内容。

CHECKSUM_MISMACTH

求和校验失败,因此媒体内容不能读取。

OUT_OF_BOUNDS

数组出界,或应用程序试图访问一个文件结尾后的输入流。

事件

MediaListener接口允许应用程序接受或响应下面的事件:

事件

描述

MEDIA_REQUEST

媒体已请求加载,当animation自动请求新内容或当用户点击媒体内容的超连接时,事件发生。

MEDIA_REALIZED

媒体已经创建播放了。当MediaManager.createMediaManager()已经调用时发生。

MEDIA_COMPLETE

媒体已经加载,并成功播放。

MEDIA_TO

媒体正在加载。

为获得更多信息,参考85页的“监听Media Engine事件”.

播放媒体内容

为了获取BlackBerry设备或网络上的PME内容,使用MediaManager的方法。为了播放已经下载到BlackBerry设备的PME内容,使用MediaPlayer类的方法。

下载内容

为下载PME内容,创建一个MediaManager对象,然后调用MediaManager.createMedia().

try

 {

    Object media = manager.createMedia("http://webserver/sample.pme");

 }

 catch (IOException ioe)

 {

     System.out.println("Error: requested content was not downloaded.");

 }

 catch (MediaException me)

 {

     System.out.println("Error: “ + me.getCode());

 }

下面缺省的协议会被支持:http://,https://.jar://,cod://.为获得更多信息,参看81页的“媒体加载”。

第一次调用MediaManager.createMedia()URL必须是绝对路径,除非首先调用MediaManager.setProperty(“URI_BASE”,<base_url>)设置基URL路径。当你之后调用createMedia()时,前面的URL作为基URL

 

播放PME内容

为播放设置PME对象

调用MedialPlayer.setMedia().

MediaPlayer player = new MediaPlayer();

try

{

 player.setMedia(media);

}

catch (MediaException me)

{

  System.out.println("Error: requested content type is not supported.”);

}

 

获取一个显示PME内容的UI对象

调用MediaPlayer.getUI()。转化getUI()返回的一个作为Field的对象,然后将之加入到屏幕来显示。

add((Field)player.getUI());

开始播放下载的PME内容

调用MediaPlayer.start()

if(player.getState() == MediaPlayer.REALIZED)

{

 try

 {

  player.start();

 }

 catch(MediaException me) {

     System.out.println("Error occurred during media playback: " +

            me.getCode() + me.getMessage());

 }

}

在调用MediaPlayer.start()前检查MediaPlayer的状态,如果媒体播放器不是REALIZED状态,start()方法抛出一个异常。

代码实例

MediaSample.java实例从一个Web服务器获取一个PME文件,然后显示它。


例:MediaSample.java

 

/**

* MediaSample.java

* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.mediasample;

import java.io.*;

import net.rim.device.api.ui.*;

import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.container.*;

import net.rim.device.api.system.*;

import net.rim.plazmic.mediaengine.*;

 

public class MediaSample extends UiApplication {

    public static void main(String[] args) {

       MediaSample app = new MediaSample();

       app.enterEventDispatcher();

    }

    public MediaSample() {

       pushScreen(new MediaSampleScreen());

    }

 

final static class MediaSampleScreen extends MainScreen {

    public MediaSampleScreen() {

       super();

       LabelField title = new LabelField(“Media Sample”, LabelField.ELLIPSIS| LabelField.USE_ALL_WIDTH);

       setTitle(title);

       MediaPlayer player = new MediaPlayer();

       MediaManager manager = new MediaManager();

       try {

           Object media = manager.createMedia(“http://webserver/SVGFILE.pme”);

           player.setMedia(media);

       }  

       catch (IOException ioe) {

       }

       catch (MediaException me) {

           System.out.println(“Error during media loading: “);

           System.out.println(me.getCode());

           System.out.println(me.getMessage());

       }

       add((Field)player.getUI());

       try {

           player.start();

       }

       catch(MediaException me) {

           System.out.println(“Error occured during media playback: “);

           System.out.println(me.getCode());

           System.out.println(me.getMessage());

           }

       }

    }

}


监听媒体引擎事件

MediaListener接口允许应用程序注册接收媒体引擎事件。应用程序可以在注册MediaPlayerMediaEngine对象上注册监听者。

当应用程序实现监听者时,它可以完成以下的动作:

  • 提供内容下载状态的信息。
  •  在后台下载内容,当完成时播放它。
  • 下载一个animation自动请求的内容。

MediaListener接口包含一个方法,listen方法。

public void mediaEvent(Object sender,

int event,

int eventParam,

Object data);

参数

描述

sender

本参数引用了发送事件的对象,如MediaPlayerMediaManager对象。

event

参数可以是下列事件之一:

  • MEDIA_REQUESTED:当新的内容请求时发送事件。
  • MEDIA_COMPLETE:当所有计划好的媒体动作完成时触发事件。
  • MEDIA_REALIZED:由MediaManager发送,返回下载的媒体。
  • MEDIA_IO:MediaPlayer发送,提供现在进度或状态的信息。

eventParam

不要使用这个参数,因为它可能接收一个任意值。它存在是为了为额外的事件提供一个一致的接口。

data

data参数是MEDIA_REQUESTEDdata把请求的URL作为一个String对象。

data参数是MEDIA_REALIZED,data引用了创建的媒体对象。

data参数是MEDIA_IO,data引用了一个net.rim.plazmic.mediaengine.io.LoadingStatus对象。

监听媒体引擎事件

MediaListener接口的实现允许你的应用程序监听一个媒体引擎事件。mediaEvent()的实现应该处理所有可能的媒体事件。下面的例子使用了一个switch语句来处理可能媒体事件。

public final class MediaListenerImpl implements MediaListener {

    public void mediaEvent(Object sender, int event, int eventParam, Object data) {

       switch(event) {

         case MEDIA_REQUESTED:

             // Perform action.

             break;

         case MEDIA_COMPLETE:

             // Perform action.

             break;

         case MEDIA_REALIZED:

             // Perform action.

            break;

         case MEDIA_IO:

             // Perform action.

             break;

            }

       }

}

注册监听者

为了注册你的监听者,调用MediaPlayerMediaManager对象上的addMediaListener()方法。

private MediaListenerImpl _listener = new MediaListenerImpl();

private MediaPlayer player = new MediaPlayer();

private MediaManager manager = new MediaManager();

player.addMediaListener(_listener);

manager.addMediaListener(_listener);

在后台加载内容

当实现MediaListener时,你可以在背后下载PME内容,并且当下载完成后播放内容。

调用MediaManager.createMediaListener()为将来的播放下载内容。

createMedia()不一样,createMediaLater()不返回一个媒体内容的对象。

MediaListener.mediaEvent()中,当请求的内容下载时,加入代码来处理MEDIA_REALIZED事件。为了注册在data参数里指定的内容,调用MediaPlayer.setMedia(data)。为了开始播放,调用MediaPlayer.start()。

manager.createMediaLater("http://webserver/sample.pme");

 

public void mediaEvent(Object sender, int event,

                     int eventParam, Object data) {

    switch(event) {

    ...

    case MEDIA_REALIZED:

     try {

     player.setMedia(data);

     player.start();

     }

     catch(MediaException me) {

     System.out.println("Error playing media” + me.getCode() +" +

           "   me.getMessage());

     }

   break;

 }

}

 

跟踪下载进度

为得到下载进度的信息,使用net.rim.plazmic.mediaengine.io.LoadingStatus类。这个类包含了一些方法来允许你获得媒体内容类型,字节总数,字节读取数,以及内容的源URL

状态

描述

LOADING_STARTED

加载开始。

LOADING_READING

数据流正在解析。

LOADING_FINISHED

加载媒体成功。

LOADING_FAILED

媒体记载失败.

  • 为获取详细的错误代码,调用getCode().参看82页获得更多详情。
  • 为得到异常信息,调用getMessage().

mediaEvent()的实现里,当MEDIA_IO事件发生时,将data参数里的Object转化为一个LoadingStatus对象。

调用LoadingStatus.getStatus()来获取下载的状态,然后处理每个状态。

对每个正常的状态,打印一个消息到控制台。

LOADING_FAILED状态,完成下面的动作:

  • 调用LoadingStatus.getCode()获得错误代码。
  • 调用LoadingStatus.getMessage()获得详细的消息。
  • 调用LoadingStatus.getSource()获得内容的URL字符串。

public void mediaEvent(Object sender, int event,

                      int eventParam, Object data) {

    switch(event) {

       ...

      case MEDIA_IO: {

      }

      ...

      break;

    }

    break;

    ...

 

switch(s.getStatus()) {

    case LoadingStatus.LOADING_STARTED:

       System.out.println("Loading in progress");

       break;

    case LoadingStatus.LOADING_READING:

       System.out.println("Parsing in progress");

       break;

    case LoadingStatus.LOADING_FINISHED:

       System.out.println("Loading completed");

       break;

    case LoadingStatus.LOADING_FAILED:

      String errorName = null;

      int code = s.getCode();

      switch (code) {

         case MediaException.INVALID_HEADER:

          errorName = "Invalid header" + "\n" + s.getSource();

          break;

         case MediaException.REQUEST_TIMED_OUT:

          errorName = "Request timed out" + "\n" +

          s.getSource();

          break;

         case MediaException.INTERRUPTED_DOWNLOAD:

          break;

         case MediaException.UNSUPPORTED_TYPE:

          errorName = "Unsupported type" + s.getMessage() + "\n" + s.getSource();

          break;

         default: {

          if (code > 200) {

            // A code > 200 indicates an HTTP error

            errorName = "URL not found";

          }

          else {

           // default unidentified error

            errorName = "Loading Failed";

           }

        errorName += "\n" + s.getSource() + "\n" + s.getCode()+ ": " + s.getMessage();

        break;

      }

    }

    System.out.println(errorName);

    break;

  } // End switch s.getStatus().

 break;

}

代码实例

MediaSample2.java 实例实现了一个监听者在后台下载媒体内容,并显示下载的状态到控制台。


例:MediaSample2.java

/**

* MediaSample2.java

* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.mediasample;

import java.io.*;

import net.rim.device.api.ui.*;

import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.container.*;

import net.rim.device.api.system.*;

 

import net.rim.plazmic.mediaengine.*;

import net.rim.plazmic.mediaengine.io.*;

 

public class MediaSample2 extends UiApplication {

    private MediaPlayer player = new MediaPlayer();

    private MediaManager manager = new MediaManager();

    private MediaListenerImpl _listener = new MediaListenerImpl();

    private MediaSample2Screen _screen;

   

    public static void main(String[] args) {

       MediaSample2 app = new MediaSample2();

       app.enterEventDispatcher();

       }

   

    public MediaSample2() {

       _screen = new MediaSample2Screen();

       pushScreen(_screen);

       }
 

    public final class MediaListenerImpl implements MediaListener {

       public void mediaEvent(Object sender, int event,

              int eventParam, Object data) {

           switch(event) {

           case MEDIA_REQUESTED:

              System.out.println(“Media requested”);

              break;

           case MEDIA_COMPLETE:

              System.out.println(“Media completed”);

              break;

           case MEDIA_REALIZED:

              try {

                  player.setMedia(data);

                  player.start();

                  }

              catch(MediaException me) {

                  System.out.println(“Error during media loading: “ +

                         me.getCode() + me.getMessage());

                  }

              break;

           case MEDIA_IO: {

              LoadingStatus s = (LoadingStatus)data;

              switch(s.getStatus()) {

              case LoadingStatus.LOADING_STARTED:

                  System.out.println(“Loading in progress”);

                  break;

              case LoadingStatus.LOADING_READING:

                  System.out.println(“Parsing in progress”);

                  break;

              case LoadingStatus.LOADING_FINISHED:

                  System.out.println(“Loading completed”);

                  break;

              case LoadingStatus.LOADING_FAILED:

                  String errorName = null;

                  int code = s.getCode();

                  switch (code) {

                  case MediaException.INVALID_HEADER:

                     errorName = “Invalid header” + “\n” + s.getSource();

                     break;

                  case MediaException.REQUEST_TIMED_OUT:

                     errorName = “Request timed out” + “\n” + s.getSource();

                     break;

                  case MediaException.INTERRUPTED_DOWNLOAD:

                     break;

                  case MediaException.UNSUPPORTED_TYPE:

                     errorName = “Unsupported type” + s.getMessage()

                     + “\n” + s.getSource();

                     break;

                  default: {

                     if (code > 200) {

                         // A code > 200 indicates an HTTP error.

                         errorName = “URL not found”;

                         }

                     else {

                         // Default unidentified error.

                         errorName = “Loading Failed”;

                         }

                  errorName += “\n” + s.getSource() + “\n”+

                  s.getCode() + “: “ + s.getMessage();

                  break;

              }

           }

       System.out.println(errorName);

       break;

    } // End switch s.getStatus().

    break;

    }

   }

  }

}

 

final class MediaSample2Screen extends MainScreen {

   public MediaSample2Screen() {

     super();

     LabelField title = new LabelField(“Media Sample”, LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

     setTitle(title);

     manager.addMediaListener(_listener);

    // Change this to the location of a test .pme file.

    manager.createMediaLater(“http://test.rim.com/SVGBS0001.pme”);

    add((Field)player.getUI());

}

}

}


创建一个定制的连接

MediaManager使用一个Connector对象加载媒体,并打开输入流。缺省的Connector支持下列协议:http://.https://,jar://,以及cod://。为了增加支持一个定制的协议或者为了覆写缺省的行为,通过实现net.rim.plazmic.mediaengine.io.Connector接口创建一个定制的Connector

方法签名

实现

InputStream getInputStream(String, ConnectionInfo)

实现本方法返回一个输入流从指定URI读取内容。

void releaseConnection(ConnectionInfo)

实现本方法释放连接。MediaManager调用本方法来通知Connector可以释放连接了。

void setProperty(String, String)

实现本方法设置连接指定的属性。

实现一个定制的connector

为了完成处理一个定制的协议,实现Connector接口,包含getInputStream()。为了处理一个标准的协议,调用缺省的Connector

setProperty(String name, String value)的实现设置了指定的属性。在本例中,connector不必设置任何指定的属性,因此setProperty()的实现调用了Connector上的setProperty()。

public class SampleConnector implements Connector {

    Connector delegate; // The default Connector.

    SampleConnector(Connector delegate) {

       this.delegate = delegate;

       }

   

    public InputStream getInputStream(String uri, ConnectionInfo info)

    throws IOException, MediaException {

       InputStream input = null;

       if (uri.startsWith("myprotocol://")) {

           // Perform special tasks.

           info.setConnection(new MyProtocolConnection());

           info.setContentType("application/x-vnd.rim.pme");

          

           // openMyInputStream() is a custom method that opens

           //stream for "myprotocol://".

           input = openMyInputStream(uri);

           }

       else {

           input = delegate.getInputStream(uri, info);

           }

       return input;

    }

   

    public void releaseConnection(ConnectionInfo info)

    throws IOException, MediaException {

       Object o = info.getConnection();

       if (o instanceof MyProtocolConnection) {

           ((MyProtocolConnection)o).close(); // Perform cleanup.

           }

       else

       {

           delegate.releaseConnection(info);

       }

    }

   

    public void setProperty(String property, String value) {

       delegate.setProperty(property, value);

       }

    }

注册一个定制的连接器

在你的主要方法里,调用MediaManager.setConnector()注册你的定制的连接器。

MediaManager manager = new MediaManager();

manager.setConnector(new CustomPMEConnector(manager.getDefaultConnector()));

代码实例

CustomPMEConnector.java实例为实现一个定制的连接器提供了一个框架。


 

例:CustomPMEConnector.java

/*

* CustomPMEConnector.java

* Copyright (C) 2003-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.mediasample;

import java.io.*;

import net.rim.plazmic.mediaengine.*;

import net.rim.plazmic.mediaengine.io.*;

 

public class CustomPMEConnector implements Connector {

    private Connector delegate;

    private InputStream input;

   

    CustomPMEConnector(Connector delegate)

    {

       this.delegate = delegate;

    }

   

   

    public InputStream getInputStream(String uri, ConnectionInfo info)

              throws IOException, MediaException

    {

       if (uri.startsWith("myprotocol://"))

       {

           // Perform special tasks.

           info.setConnection(new MyProtocolConnection());

           info.setContentType("application/x-vnd.rim.pme");

          

           // OpenMyInputStream() is a custom method that opens

           //stream for “myprotocol://”

           input = openMyInputStream(uri);

       }

       else

       {

           input = delegate.getInputStream(uri, info);

           return input;

       }

      

       private InputStream openMyInputStream(String uri)

       {

           InputStream input = null;

       }

          

       // @todo: open stream here

       return input;

       }

   

    public void releaseConnection(ConnectionInfo info)

    throws IOException, MediaException

    {

       Object o = info.getConnection();

       if (o instanceof MyProtocolConnection)

       {

           ((MyProtocolConnection)o).close(); // Perform cleanup.

       }

       else

       {

           delegate.releaseConnection(info);

       }

    }

   

   

    public void setProperty(String property, String value) {

       delegate.setProperty(property, value);

       }

   

   

    // Inner class that defines the connection class.

    public static class MyProtocolConnection {

       public MyProtocolConnection()

       {

           // ...

       }

   

       public void close()

       {

           // ...

       }

    }

}

  • Last Updated:2008年4月18日
  • Last Updated:2007年1月10日
  • Last Updated:2006年4月28日
posted @ 2006-04-28 21:38  张太国  阅读(2799)  评论(1编辑  收藏