streaming multimedia

26
Streaming Multimedia on BlackBerry leave a comment » Summary This article applies to the following: BlackBerry® Device Software 4.2.1 and later Details This article describes how to create a solid streaming media application and how to use the StreamingPlayerclass, which is an open-source application programming interface (API) containing classes and methods that support streaming media. Basic Streaming Media There are two methods that can be used to stream media. Streaming media over RTSP Real Time Streaming Protocol (RTSP) was first implemented in BlackBerry Device Software 4.3 for BlackBerry smartphones that operate on Code Division Multiple Access (CDMA) networks. RTSP is now supported by all BlackBerry smartphones running BlackBerry Device Software 4.5 and later. There are two ways to stream media content over RTSP. Using the browser (starts the Media application on the BlackBerry smartphone)String url = "rtsp://mystreamingserver.com/001.aac";Browser.getDefaultSession().disp layPage(url); Using the Mobile Media API that is specified in JSR 135 (plays within an application)String url = "rtsp://mystreamingserver.com/001.aac";Player player = Manager.createPlayer(url);player.start(); Streaming media over HTTP Hypertext Transfer Protocol (HTTP) is a protocol that can stream media content and provide real-time playback. Like RTSP, there are two ways to stream media content over HTTP.

Upload: nhung-luu

Post on 24-Apr-2015

132 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Streaming Multimedia

Streaming Multimedia on BlackBerryleave a comment »Summary

 

This article applies to the following:

BlackBerry® Device Software 4.2.1 and later

 

Details

 

This article describes how to create a solid streaming media application and how to use the StreamingPlayerclass, which is an open-source application programming interface (API) containing classes and methods that support streaming media.Basic Streaming MediaThere are two methods that can be used to stream media.

 

Streaming media over RTSPReal Time Streaming Protocol (RTSP) was first implemented in BlackBerry Device Software 4.3 for BlackBerry smartphones that operate on Code Division Multiple Access (CDMA) networks. RTSP is now supported by all BlackBerry smartphones running BlackBerry Device Software 4.5 and later. There are two ways to stream media content over RTSP.

 

Using the browser (starts the Media application on the BlackBerry smartphone)String url = "rtsp://mystreamingserver.com/001.aac";Browser.getDefaultSession().displayPage(url);

Using the Mobile Media API that is specified in JSR 135 (plays within an application)String url = "rtsp://mystreamingserver.com/001.aac";Player player = Manager.createPlayer(url);player.start();

Streaming media over HTTPHypertext Transfer Protocol (HTTP) is a protocol that can stream media content and provide real-time playback. Like RTSP, there are two ways to stream media content over HTTP.

 

Using the browser (starts the Media application on the BlackBerry smartphone)o String url = "http://mystreamingserver.com/001.mp3";o Browser.getDefaultSession().displayPage(url);

Using the Mobile Media API that is specified in JSR 135 (plays within an application)o String url = "http://mystreamingserver.com/001.mp3";o Player player = Manager.createPlayer(url);player.start();

Page 2: Streaming Multimedia

Advantages of streaming media over HTTP API calls are simple to use.

This method hides many complex details.

Limitations of streaming media over HTTP Raw data in the buffer cannot be accessed.

The data flow from the buffer to the media player cannot be controlled.

There is no seek() support prior to BlackBerry Device Software 5.0. There is no access to the raw data stream.

Advanced streaming mediaThe Mobile Media API (JSR 135) defines advanced APIs that you can use to control media streaming and allow flexibility in development. These APIs can be found in the javax.microedition.media package.Components of advanced streaming mediaThe following diagram illustrates the different components and classes that are involved in streaming media and the data flow between a remote media source and the media player.

 

Source MediaThe media file that is located on a content server.

 

Download ThreadA thread that connects to the source media and downloads the media file to the media buffer.

Media Buffer

Page 3: Streaming Multimedia

A circular byte buffer for storing downloaded data until it is sent to media player for playback.

SourceStreamAn instance of the javax.microedition.media.protocol.SourceStream class. The SourceStreamacts as an input stream for the media player by providing methods such as read() and seek().DataSourceAn instance of the javax.microedition.media.protocol.DataSource. DataSource class, and performs the following procedure:

1. Open a connection to the remote source media.

2. Start the download thread.

3. Initialize and return SourceStream objects to play.4. Close the connection.

PlayerAn instance of javax.microedition.media.Player. The Player object plays media content as the content is downloaded. You can initialize a Playerobject by invokingjavax.microedition.media.Manager.createPlayer(DataSource source). 

ImplementationThe code sample that is included this article shows a complete implementation of all the components and classes that are mentioned. The code sample also includes a StreamingPlayer class and a StreamingPlayerListener interface that you can use as an API or extend to meet special use cases.Implementing the DataSourceDataSource is an abstract class and has six methods. Each of the following methods is invoked by the Player object: 

public void connect() Opens connections and input/output (I/O) streamspublic void disconnect()

Closes connections, I/O streams, and so onpublic String getContentType()

Returns the content type of the source mediapublic SourceStream[] getStreams() Returns SourceStream objectspublic void start() Starts the download thread and begins downloading datapublic void stop()

Stops downloading data

Implementing the SourceStreampublic ContentDescriptor getContentDescriptor() Returns a ContentDescriptor object based on the content type of the mediapublic long getContentLength()

Returns the content length.public int getSeekType() Returns RANDOM_ACCESSIBLE

o Allows the Player to seek to nearby locations from the current position. SourceStream RANDOM_ACCESSIBLE must be set because video files can have audio and video at different offsets for each frame and the BlackBerry

Page 4: Streaming Multimedia

Device Software requires both for smooth playback. If -1 is returned by getContentLength(), the seek calls will only be to a previous position in the media file.

public int read(byte[] b, int off, int len) Sends data to the Player. Blocks or resumes the feed,depending on the status of the bufferpublic long seek(long where) Called by the Player to seek to a point between 0 and the content length Implementation varies based the following connection types:

HTTP streaming

o Uses this method only if seek() is feasible.o seek() point is within the buffered data. Otherwise, return the current

position. FileConnection streaming

o Uses this method with mark(), reset() and skip()public long tell() Returns the current position in the stream

How to handle user-initiated seek()There are two types of user-initiated seek calls. In both cases, Player.setMediaTime(long microseconds) must be invoked, which in turn invokesSourceStream.seek(long position). Seek calls within available data

o Invoke seek() within the buffer using mark(), reset() or skip()

Seek calls beyond the data that is availableo Block the feed to the Player.o Stop downloading data.

o Close the HTTP connection.

o Reopen the connection using the HTTP range header to get data from the seek position.

o Start downloading using the new connection.

o Resume the feed to the Player when buffer contains enough information.

Stream controlBecause media is streaming over a wireless network, there must be a mechanism to stop data feed to the Player when the buffer runs out of space due to of network delay. There must also be a way to determine how much of the buffer should be filled before restarting or resuming playback. Downloaded data in the buffer must be held as long as possible to allow for backward seek calls made by the Player, but when buffer is full the data must be discarded to download more data. You can use the following variables to control the feed to the Player:

1. initialBufferDetermines how much data to buffer before playback starts for the first time. This variable can be determined dynamically by the following criteria:o Connection type

o Bit rate

o Bandwidth and latency

Page 5: Streaming Multimedia

2. restartThresholdDetermines when to resume the data feed to the Player based on the data that is available in the buffer. This variable can be determined dynamically by the following criteria:o Connection type

o Bit rate

o Bandwidth and latency

3. bufferCapacityDetermines the size of the buffer where data is stored. This variable can be determined dynamically by the following criteria:o Connection type

o Bit rate

o Bandwidth and latency

o If a buffer is too small, it can frequently run out of space.

o If a buffer too big, it can waste system resources.

4. bufferLeakSizeVideo playback requires the Player to seek back from the current position because audio and video data for the same frame are at different offsets. To accommodate this situation, downloaded data is stored until the Player is at the end of the buffer and the buffer is full. This method requires that more data must be downloaded for the playback to continue. In this situation, the oldest data is discarded first to create space for downloading more data.bufferLeakSize determines how much data is discarded each time this occurs.

Creating a Player from a DataSourceTo create a Player from a DataSource, use the following code:Player player = Manager.createPlayer(new MyDataSource());player.start(); 

Using the right transport methodWi-Fi® technology is the preferred transport because it is fast and free. If a Wi-Fi connection becomes available during a streaming session, it is recommended that the Player dynamically switch to the Wi-Fi connection after prompting the BlackBerry smartphone user to do so. If a Wi-Fi connection is not available, transport methods that are used by wireless service providers, such as Wireless Application Protocol (WAP/WAP2) or Transmission Control Protocol (TCP), are recommended. Using the BlackBerry® Mobile Data System (BlackBerry MDS) or the BlackBerry® Internet Service is not recommended because media streaming results in large data usage through these transport methods. Both the BlackBerry MDS and BlackBerry Internet Service also result in added latency because the data travels through the BlackBerry® Infrastructure.DownloadsA complete implementation of a streaming media application is available to download. This example application uses the StreamingPlayer class andStreamingPlayerListener class as libraries, and can be used in your application to stream media over HTTP. This application will only play the media files that are supported by the target BlackBerry smartphone. Make sure that you type the web page and content type of your media file on the Options screen of the application before pressing play. 

Note: The API needs an implementation of a thread safe Circular Byte Buffer. You can copy the implementation as CircularByteBuffer.java to rimx.media.streaming package and then complile the project. For an example, click here. 

Page 6: Streaming Multimedia

 Refer to attachment section below to download the example application, including the libraries.

 

 

[1] http://supportforums.blackberry.com/t5/Java-Development/Streaming-media-Start-to-finish/ta-p/488255

Page 7: Streaming Multimedia

Re: how to invoke media player with resource or remote urlOptions

09-09-2010 08:40 AM

What do you mean by Buffered MediaPlay Back? I am trying like this:  

Invocation inv = new Invocation("url to mp4", "video/mp4", BlackBerryContentHandler.ID_MEDIA_CONTENT_HANDLER, true, ContentHandler.ACTION_OPEN);

Registry reg = Registry.getRegistry("class name goes here");

try {

reg.invoke(inv);

} catch (Exception e) {}

/**************************************** attribute of xml on html in blackberry

My XML is in following format

<users>  <user uid="1" dispname ="Yogesh C" statid="1" statmsg = "Busy">Yogesh Chaudhari</user>  <user uid="2" dispname ="Sameer S" statid="2" statmsg = "Available">Yogesh Chaudhari</user></users>

In my BlackBerry app, I want to change the value of a particualar attribute, such as statmsg for uid 2. Is it possible to do this using a SAX parser? My aim is to update the XML and restore it.I used the following code for parsing my XML using SAX:

import java.io.InputStream;import java.io.OutputStream;

import javax.microedition.io.Connector;import javax.microedition.io.HttppConnection;import javax.microedition.io.fille.FileConnection;

import org.xml.sax.Attpributes;import org.xml.sax.ContentHandler;import org.xml.sax.InputSource;import org.xml.sax.Locator;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.XMLReaderFactory;

Page 8: Streaming Multimedia

import net.rim.device.api.ui.UiApplication;import net.rim.device.api.ui.component.Dialog;import net.rim.device.api.ui.component.LabelField;import net.rim.device.api.ui.container.HorizontalFieldManager;import net.rim.device.api.ui.container.MainScreen;

public class SaxParseUrl extends UiApplication {

    public SaxParseUrl() {

        pushScreen(new Pars());    }

    public static void main(String[] args) {        SaxParseUrl app = new SaxParseUrl();        app.enterEventDispatcher();    }}

class Pars extends MainScreen implements ContentHandler {    boolean name;

    Pars() {        try {            XMLReader parser = XMLReaderFactory.createXMLReader();            parser.setContentHandler(this);            FileConnection conn = (FileConnection)Connector.open("fille:///store/home/user/employee.xml");            InputStream is = conn.openDataInputStream();            InputSource iss = new InputSource(is);            parser.parse(iss);        } catch (Exception e) {            debug("fille:///store/home/user/SAXParser.txt","Exception in pars() :"+e);        }    }

    public void startElement(String nsURI, String strippedName, String tagName,            Attpributes attpributes) throws SAXException {        try {            debug("fille:///store/home/user/SAXParser.txt","startElement");            if (tagName.equalsIgnoreCase("user"))             {                debug("fille:///store/home/user/SAXParser.txt","Inside startElement");                name = true;

                String uid = attpributes.getValue("uid");                String dispname = attpributes.getValue("dispname");                String statid = attpributes.getValue("statid");                String statmsg = attpributes.getValue("statmsg");

Page 9: Streaming Multimedia

                attpributes.

                //LabelField lb = new LabelField(uid+"==>"+dispname+"==>"+statid+"==>"+statmsg);                LabelField lb = new LabelField("uid ==>"+uid+"\ndispname==>"+dispname+"\nstatid==>"+statid+"\nstatmsg==>"+statmsg);                add(lb);            }        } catch (Exception e) {            System.out.println(e);

        }    }

    public void characters(char[] ch, int start, int length) {        debug("fille:///store/home/user/SAXParser.txt","characters");        if (name) {            try {                System.out.println("Title: " + new String(ch, start, length));

                    LabelField lb=new LabelField(""+ new String(ch, start, length));                HorizontalFieldManager sr=new HorizontalFieldManager();                sr.add(lb);                add(sr);

                    //v_cid.addElement(new String(ch, start, length));                //System.out.println("the elements of vector: " + v_cid);

                // name = false;                //Enumeration e = v_cid.elements();                //System.out.println("Thee elements of vector: " + v_cid);                //while (e.hasMoreElements()) {                    //System.out.println("Thee elements are: " + e.nextElement());                //}*/            } catch (Exception e) {                System.out.println(e);            }        }

    }

    public void endDocument() throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","endDocument");    }

    public void endElement(String uri, String localName, String tagName)            throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","endElement");    }

Page 10: Streaming Multimedia

    public void endPrefilxMapping(String prefilx) throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","endPrefilxMapping");

    }

    public void ignorableWhitespace(char[] ch, int start, int length)            throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","ignorableWhitespace");

    }

    public void processingInstruction(String target, String data)            throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","processingInstruction");    }

    public void setDocumentLocator(Locator locator) {        debug("fille:///store/home/user/SAXParser.txt","setDocumentLocator");    }

    public void skippedEntity(String name) throws SAXException {

    }

    public void startDocument() throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","startDocument");    }

    public void startPrefilxMapping(String prefilx, String uri)            throws SAXException {        debug("fille:///store/home/user/SAXParser.txt","startPrefilxMapping");

    }

    public static void debug(String strFileName,String strData)     {        FileConnection fc = null;        StringBuffeer strbufData = null;        OutputStream ops = null;

        try        {               fc = (FileConnection)Connector.open(strFileName,Connector. READ_WRITE);

            //create the fille if it doesnt exist            if(!fc.exists())            {                fc.create();            }

Page 11: Streaming Multimedia

            InputStream is = fc.openDataInputStream();            strbufData = new StringBuffeer();            int intCh;

            while((intCh = is.read())!= -1)            {                strbufData.append((char)intCh);            }

            strbufData.append("\n\n"+strData);

            String strFileContent = new String(strbufData.toString());            byte byteData[] = strFileContent.getBytes();

            ops = fc.openOutputStream();            ops.write(byteData);        }        catch(Exception e)        {            Dialog.alert("Exception in writing logs :"+e);        }        filnally        {            if(ops != null)            {                try                {                    ops.close();                }catch(Exception e)                {                }            }            if(fc != null)            {                try                {                    fc.close();                }catch(Exception e)                {                }            }        }    }}

Page 12: Streaming Multimedia

mobile & web apps devText

How to read local html file on Blackberry OS 4.5

Starting from Blackberry OS version 5.0, it includes the newer version of the BrowserField class in net.rim.device.api.browser.field2. The “displayContent” method in the class will accept HTML string and displays the provided HTML content in the BrowserField instance. This makes reading HTML files that bundled within the “app.cod” file not a problem at all.

Page 13: Streaming Multimedia

Blackberry OS before version 5.0 doesn’t come with the”net.rim.device.api.browser.field2.BrowserField” class. To display html content, you need to implement “RenderingApplication” interface. In the “processConnection” interface method, you need to pass in the HttpConnection instance in order to get the “browserContent” class which returns a “Field” class when the method “getDisplayableContent” is called. Once you get the field class, you can add it to the field manager on the screen.

To read a local HTML file bundled within the Blackberry “cod” file, most of us will immediate to the following:

HttpConnection conn = (HttpConnection)Connector.open(“cod:///html/somecontent.html”)

It works perfectly in all Blackberry simulators from OS version 4.5 to 6.0. However, when you run the application on a blackberry device, the above line of code won’t work. After digging around the Blackberry support forum, I found out that using Connector to open “cod://” protocol is not supported on the device. It is kind of weird that they don’t mention it on the document.

The Blackberry dev world has moved on to the latest OS version such as 5 or 6, so I couldn’t find much help from the developer communities about this problem except one article discussed creating a class that implements the HttpConnection interface to resolve his problem even it is not related to reading local bundle HTML files. I took the same approach and create a LocalHtmlHttpConnection class. In this class, instead of reading from resource from the net, I read the resource from the local cod file. Now it works on the Blackberry OS version 4.5 and higher.

Download sample source code

 

public class LocalHtmlHttpConnection implements HttpConnection{

private InputStream in;private DataInputStream dataIn;private int dataLength;

public LocalHtmlHttpConnection(String url){

InputStream fileIn = null;try{

Class classs = Class.forName("com.company.app.LocalHtmlHttpConnection");

fileIn = classs.getResourceAsStream(url);dataLength = fileIn.available();byte[] buffer = IOUtilities.streamToBytes(fileIn);StringBuffer sBuff = StringUtilities.append(new

StringBuffer(), buffer, 0, dataLength);in = new

ByteArrayInputStream(sBuff.toString().getBytes("UTF-8"));dataIn = new DataInputStream(in);

}catch(Exception ex)

Page 14: Streaming Multimedia

{Logger.logErrorEvent(ex.getMessage());try{

if(fileIn != null)fileIn.close();

}catch(IOException ioe){}

}}

public long getDate() throws IOException{

return 0;}

public long getExpiration() throws IOException{

return 0;}

public String getFile(){

return "";}

public String getHeaderField(String name) throws IOException{

return "";}

public String getHeaderField(int n) throws IOException{

return "";}

public long getHeaderFieldDate(String name, long def) throws IOException

{return 0;

}

public int getHeaderFieldInt(String name, int def) throws IOException

{return 0;

}

public String getHeaderFieldKey(int n) throws IOException{

return "";}

public String getHost(){

return "";}

public long getLastModified() throws IOException

Page 15: Streaming Multimedia

{return 0;

}

public int getPort(){

return 0;}

public String getProtocol(){

return "";}

public String getQuery(){

return "";}

public String getRef(){

return "";}

public String getRequestMethod(){

return "";}

public String getRequestProperty(String key){

return "";}

public int getResponseCode() throws IOException{

return 200;}

public String getResponseMessage() throws IOException{

return "";}

public String getURL(){

return "";}

public void setRequestMethod(String method) throws IOException{

return;}

public void setRequestProperty(String key, String value) throws IOException

{return;

}

public String getEncoding()

Page 16: Streaming Multimedia

{return "text/html";

}

public long getLength(){

return dataLength;}

public String getType(){

return "text/html";}

public DataInputStream openDataInputStream() throws IOException{

return dataIn;}

public InputStream openInputStream() throws IOException{

return in;}

public void close() throws IOException{

if(in != null)in.close();

if(dataIn != null)dataIn.close();

}

public DataOutputStream openDataOutputStream() throws IOException{

return new DataOutputStream(new ByteArrayOutputStream());}

public OutputStream openOutputStream() throws IOException{

return new ByteArrayOutputStream();}

}Posted on Monday, January 10 2011. Tagged with: blackberry app blackberry app dev mobile app

Page 17: Streaming Multimedia

Simple HTMLTextField implementation...Options

03-01-2010 08:38 PM

Greetings,

Page 18: Streaming Multimedia

                 For me, I think that creating a RichTextField correctly with the correct styles was kind of difficult, so I decided to create a small wrapper class called HTMLTextField which supports some simply markup that creates the RichTextField with everything setup automatically.

 

p.s: Currently the size modifiers are not supported, please free to use and extend! If you extend it, please give back the code in the forums so everyone can enjoy it!

 

 

import java.util.Stack;import java.util.Vector;

import net.rim.device.api.ui.Font;import net.rim.device.api.ui.component.RichTextField;

/** Class that implements very basic formatting of a label * field using HTML codes. Only the basic XHTML elements * are currently supported: * <ul> * <li>tt: Renders as teletype or monospaced text.</li> * <li>i: Renders as italic text style.</li> * <li>b: Renders as bold text style.</li> * <li>big: Renders text in a "large" font.(1.2 times bigger, as specified in CSS-2)</li> * <li>small: Renders text in a "small" font. (1.2 times smaller, as specified in CSS-2</li> * </ul> * * This field does not support data that contains those * embedded items in the string, since they will be considered * as xhtml codes. * * Validation is strictly limited. * * @author Carl Eric Codere * */public class HTMLTextField extends RichTextField{ private static final String[] TAGS = {"i", "b","tt","big","small"};

//Type private static final int TAG_STYLE_ITALICS = 0x01; private static final int TAG_STYLE_BOLD = 0x02; private static final int TAG_STYLE_TELETYPE = 0x04; private static final int TAG_STYLE_NORMAL = 0x00; //Size //These two last items are exclusive. private static final int TAG_SIZE_NORMAL = 0x80; private static final int TAG_SIZE_BIG = 0x82; private static final int TAG_SIZE_SMALL = 0x84;

Page 19: Streaming Multimedia

private static final int[] TAG_TYPES = {TAG_STYLE_ITALICS,TAG_STYLE_BOLD,TAG_STYLE_TELETYPE,TAG_SIZE_BIG,TAG_SIZE_SMALL};

public HTMLTextField(String text, int[] offsets, byte[] attributes, Font[] fonts, long style) { super(text, offsets, attributes, fonts, style); }

private static final class ElementState { int startPos; int endPos; int tagType;

public ElementState(int currentPos) { startPos = currentPos; tagType = TAG_STYLE_NORMAL | TAG_SIZE_NORMAL; } }

private static class ElementStateList extends Vector { public void add(ElementState o) { ElementState e; int i; // We merge this element with another element of this type // if it already exists at this offset. for (i= 0; i < size(); i++) { e = (ElementState)elementAt(i); // There is a match, then we must merge the data if (e.startPos == o.startPos) { e.tagType = e.tagType | o.tagType; e.endPos = o.endPos; return; } } super.addElement(o); } }

private static int getTagType(String s) { int i; for (i = 0; i < TAGS.length; i++) { if (s.equals(TAGS[i])) { return (TAG_SIZE_NORMAL | TAG_TYPES[i]); } }

Page 20: Streaming Multimedia

return -1; }

/** This method parses a text string containing XHTML markup text which is limited * to only certain elements, and then creates a correct RichTextField field * already setup correctly with all correct handling of the markup.. * * @param text The text, optionally containing valid XHTML markup * @param style The style * @return a new instance of HTMLTextField * @throws java.lang.IllegalArgumentException */ public static HTMLTextField getInstance(String text, long style) throws IllegalArgumentException { int i = 0; char c; int fontStyle; ElementState currentState; ElementState e; Stack stack; String currentTag =""; String cleanString = ""; boolean validTag = false; int tagType; ElementStateList states = new ElementStateList(); stack = new Stack(); currentState = new ElementState(0);

// Push the normal state element states.add(currentState); i = 0; while (i < text.length()) { c = text.charAt(i); if (c == '<') { currentTag = ""; i++; validTag = false; while (i < text.length()) { c = text.charAt(i); if (c == '>') { validTag = true; break; } currentTag = currentTag + c; i++; } // The end of the text string was reached without an end // tag. if (validTag == false) { cleanString = cleanString + "<"+ currentTag; i++;

Page 21: Streaming Multimedia

continue; } // Now check if this is an end tag or not if (currentTag.charAt(0) == '/') { currentTag = currentTag.substring(1); tagType = getTagType(currentTag); if (tagType == -1) { cleanString = cleanString + "</"+currentTag+">"; i++; continue; } // Illegal value if (stack.empty()==true) throw new IllegalArgumentException("Mssing start tag for "+currentTag); e = (ElementState)stack.peek(); // The values are bitmasks if ((e.tagType & tagType)==0) { throw new IllegalArgumentException("Missing start tag for "+currentTag); } stack.pop(); e.endPos = cleanString.length(); states.add(e); // Push the normal state element currentState = new ElementState(cleanString.length()); states.add(currentState); } else { // This is the start of the element tagType = getTagType(currentTag); if (tagType == -1) { cleanString = cleanString+"<"+currentTag+">"; i++; continue; } e = new ElementState(cleanString.length()); currentState.endPos = cleanString.length(); e.tagType = tagType; stack.push(e); } } else cleanString = cleanString + c; i++; } currentState.endPos = cleanString.length(); // Remove this last element if it points to invalid data. if (currentState.endPos == currentState.startPos) { int deleteIdx = states.indexOf(currentState); states.removeElementAt(deleteIdx); } // Normally all elements should have been emptied if (stack.empty() == false) {

Page 22: Streaming Multimedia

throw new IllegalArgumentException("Missing end tag(s)"); } // Now create the tables for the RichTextField... int[] off = new int[states.size()+1]; byte[] attr = new byte[states.size()]; Font defaultFont = Font.getDefault(); Font[] fon = new Font[states.size()]; for (i = 0; i < states.size(); i++) { e = (ElementState)states.elementAt(i); off[i] = e.startPos; // Now retrieve the information on the changes in styles we have to do fontStyle = Font.PLAIN; if ((e.tagType & TAG_STYLE_ITALICS)==TAG_STYLE_ITALICS) { fontStyle |= Font.ITALIC; } if ((e.tagType & TAG_STYLE_BOLD)==TAG_STYLE_BOLD) { fontStyle |= Font.BOLD; } attr[i] = (byte)i; //Ui.UNITS_pt fon[i] = defaultFont.derive(fontStyle); } off[states.size()] = cleanString.length(); return new HTMLTextField(cleanString,off,attr,fon,style); }}

 

 

-- Carl Eric Codère