Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Creating A DataSource From A Stream 1

Status
Not open for further replies.

silcndrgn

Programmer
Jun 6, 2002
1
0
0
US
I have been entirely unable to create a means of building a DataSource object (and hence a Processor) that gets data from a stream instead of a file, RTP, and so on. I am writing a module for a much larger application that is meant to transparently transcode audio formats. However, by the means I see available in JMF, you can only read data to Process from files and file like device objects (capture devices, URLs, etc). It is utterly absurd to spin the disk to move data between two parts of the same application. It's expensive, potentially adds more bugs, and will defeat the black box functionality of my module. Anyone have any suggestions on how I may proceed?

I have tried creating a DataSource that extends PullDataSource (called StreamDataSource that takes an InputStream object and a ContentDescriptor), but I get this exception. Note that it is properly registered with JMF.

javax.media.NoProcessorException: Cannot find a Processor for: StreamDataSource@6d2633
at javax.media.Manager.createProcessorForSource(Manager.java:1790)
at javax.media.Manager.createProcessor(Manager.java:690)
at AudioTranscoder.configureProcessor(AudioTranscoder.java:90)
at AudioTranscoder.<init>(AudioTranscoder.java:69)

Thanks in advance for any help!
 
Hey ... if you are trying to create a datasource from a stream, try this ... it worked for me. Two things you need before you can do this. First, you need to take the stream and convert it to a byte buffer (easy enough). Secondly, you need to know the content type of the stream. If this isn't what you are looking for, let me know. I may be able to help further. I do have a question for you. Assuming I have a stream of data that has no header (header info has already been parsed), BUT, I do have the info in the header (and I don;t want to rebuild it), is there some way I can use the Formats class to create a datasource instead of using a content descriptor? Thanks

Chad

import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.PullDataSource;

import java.nio.ByteBuffer;
import java.io.IOException;

import javax.media.MediaLocator;
import javax.media.Duration;
import javax.media.Time;


/**
*
* @author Chad McMillan
*/

public class ByteBufferDataSource extends PullDataSource {

protected ContentDescriptor contentType;
protected SeekableStream[] sources;
protected boolean connected;
protected ByteBuffer anInput;

protected ByteBufferDataSource(){
}

/**
* Construct a <CODE>ByteBufferDataSource</CODE> from a <CODE>ByteBuffer</CODE>.
* @param source The <CODE>ByteBuffer</CODE> that is used to create the
* the <CODE>DataSource</CODE>.
*/
public ByteBufferDataSource(ByteBuffer input, String contentType) throws IOException {
anInput = input;
this.contentType = new ContentDescriptor(contentType);
connected = false;
}

/**
* Open a connection to the source described by
* the <CODE>ByteBuffer/CODE>.
* <p>
*
* The <CODE>connect</CODE> method initiates communication with the source.
*
* @exception IOException Thrown if there are IO problems
* when <CODE>connect</CODE> is called.
*/
public void connect() throws java.io.IOException {
connected = true;
sources = new SeekableStream [1];
sources[0] = new SeekableStream(anInput);
}

/**
* Close the connection to the source described by the locator.
* <p>
* The <CODE>disconnect</CODE> method frees resources used to maintain a
* connection to the source.
* If no resources are in use, <CODE>disconnect</CODE> is ignored.
* If <CODE>stop</CODE> hasn't already been called,
* calling <CODE>disconnect</CODE> implies a stop.
*
*/
public void disconnect() {
if(connected) {
sources[0].close();
connected = false;
}
}

/**
* Get a string that describes the content-type of the media
* that the source is providing.
* <p>
* It is an error to call <CODE>getContentType</CODE> if the source is
* not connected.
*
* @return The name that describes the media content.
*/
public String getContentType() {
if( !connected) {
throw new java.lang.Error(&quot;Source is unconnected.&quot;);
}
return contentType.getContentType();
}

public Object getControl(String str) {
return null;
}

public Object[] getControls() {
return new Object[0];
}

public javax.media.Time getDuration() {
return Duration.DURATION_UNKNOWN;
}

/**
* Get the collection of streams that this source
* manages. The collection of streams is entirely
* content dependent. The MIME type of this
* <CODE>DataSource</CODE> provides the only indication of
* what streams can be available on this connection.
*
* @return The collection of streams for this source.
*/
public javax.media.protocol.PullSourceStream[] getStreams() {
if( !connected) {
throw new java.lang.Error(&quot;Source is unconnected.&quot;);
}
return sources;
}

/**
* Initiate data-transfer. The <CODE>start</CODE> method must be
* called before data is available.
*(You must call <CODE>connect</CODE> before calling <CODE>start</CODE>.)
*
* @exception IOException Thrown if there are IO problems with the source
* when <CODE>start</CODE> is called.
*/
public void start() throws IOException {
}

/**
* Stop the data-transfer.
* If the source has not been connected and started,
* <CODE>stop</CODE> does nothing.
*/
public void stop() throws IOException {
}
}

(and for your stream)

import java.lang.reflect.Method;
import java.lang.reflect.Constructor;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.BufferUnderflowException;


import javax.media.protocol.PullSourceStream;
import javax.media.protocol.Seekable;
import javax.media.protocol.ContentDescriptor;
/**
*
* @author Chad McMillan
*/
public class SeekableStream implements PullSourceStream, Seekable {


protected ByteBuffer inputBuffer;

/**
* a flag to indicate EOF reached
*/


/** Creates a new instance of SeekableStream */
public SeekableStream(ByteBuffer byteBuffer) {
inputBuffer = byteBuffer;
this.seek((long)(0)); // set the ByteBuffer to to beginning
}

/**
* Find out if the end of the stream has been reached.
*
* @return Returns <CODE>true</CODE> if there is no more data.
*/
public boolean endOfStream() {
return (! inputBuffer.hasRemaining());
}

/**
* Get the current content type for this stream.
*
* @return The current <CODE>ContentDescriptor</CODE> for this stream.
*/
public ContentDescriptor getContentDescriptor() {
return null;
}

/**
* Get the size, in bytes, of the content on this stream.
*
* @return The content length in bytes.
*/
public long getContentLength() {
return inputBuffer.capacity();
}

/**
* Obtain the object that implements the specified
* <code>Class</code> or <code>Interface</code>
* The full class or interface name must be used.
* <p>
*
* The control is not supported.
* <code>null</code> is returned.
*
* @return <code>null</code>.
*/
public Object getControl(String controlType) {
return null;
}

/**
* Obtain the collection of objects that
* control the object that implements this interface.
* <p>
*
* No controls are supported.
* A zero length array is returned.
*
* @return A zero length array
*/
public Object[] getControls() {
Object[] objects = new Object[0];

return objects;
}

/**
* Find out if this media object can position anywhere in the
* stream. If the stream is not random access, it can only be repositioned
* to the beginning.
*
* @return Returns <CODE>true</CODE> if the stream is random access, <CODE>false</CODE> if the stream can only
* be reset to the beginning.
*/
public boolean isRandomAccess() {
return true;
}

/**
* Block and read data from the stream.
* <p>
* Reads up to <CODE>length</CODE> bytes from the input stream into
* an array of bytes.
* If the first argument is <code>null</code>, up to
* <CODE>length</CODE> bytes are read and discarded.
* Returns -1 when the end
* of the media is reached.
*
* This method only returns 0 if it was called with
* a <CODE>length</CODE> of 0.
*
* @param buffer The buffer to read bytes into.
* @param offset The offset into the buffer at which to begin writing data.
* @param length The number of bytes to read.
* @return The number of bytes read, -1 indicating
* the end of stream, or 0 indicating <CODE>read</CODE>
* was called with <CODE>length</CODE> 0.
* @throws IOException Thrown if an error occurs while reading.
*/
public int read(byte[] buffer, int offset, int length) throws IOException {

// return n (number of bytes read), -1 (eof), 0 (asked for zero bytes)

if ( length == 0 )
return 0;
try {
inputBuffer.get(buffer,offset,length);
return length;
}
catch ( BufferUnderflowException E ) {
return -1;
}
}

public void close() {

}
/**
* Seek to the specified point in the stream.
* @param where The position to seek to.
* @return The new stream position.
*/
public long seek(long where) {
try {
inputBuffer.position((int)(where));
return where;
}
catch (IllegalArgumentException E) {
return this.tell(); // staying at the current position
}
}

/**
* Obtain the current point in the stream.
*/
public long tell() {
return inputBuffer.position();
}

/**
* Find out if data is available now.
* Returns <CODE>true</CODE> if a call to <CODE>read</CODE> would block
* for data.
*
* @return Returns <CODE>true</CODE> if read would block; otherwise
* returns <CODE>false</CODE>.
*/
public boolean willReadBlock() {
return (inputBuffer.remaining() == 0);
}
}

 
If you've solved the problem using Chad's solution above or by some other route then ignore this...

Here's my 2 cents:

You probably need to follow the JMF's package and naming conventions.

The Manager looks for processors in:

Code:
<content package-prefix>.media.processor.<content-type>.Handler

Your package must reflect this and your custom Processor must be a class named Handler.

If you've done this right, the Manager will be able to find your custom Processor for the specific content-type you want it to handle.
 
Hello,

I have read an IBM article on JMF. I found it, is very valuable for me. Even after reading it, some of my doubts are left unanswered. So I request you to give needfull help on my doubts. Here are the details of my doubts.

I have started working on my Video Streaming project, chose JMF in my development by believing that it can give easier solution to my application. The project has to be done on Linux OS.

In this application, I have to access a Video Stream through an HTTP URL of an remote Networking Camera (say Axis, Sony, etc ).
The URLwill be like (this is from HTTP API of Axis).
Here I am not able create a player using, like the above URL. But I am able to access the video from this above URL using Java DataInputStream(s).

So Can I have a note from you that is it possible from JMF using the above URL. If possible what are your suggestions on the JMF constraints to be considered in getting the Video from the above said URL.

Can I achieve the same on Linux OS, now I am working on Windows.

Thanks in advance.

Regards,
Subbu
 
hi!

we have the same problem. have you already addressed the issue of streaming datasource? i tried chad mcmillan's code but i don't know how what to do next.

i converted my byte stream to byte buffer and called ByteBufferDataSource. is this correct?

byte[] buffer = SQLResult.getBytes(1);
String format = SQLResult.getString(&quot;format&quot;);
if(buffer != null)
{
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
ByteBufferDataSource inputBuffer =
newByteBufferDataSource(byteBuffer, format);
}

how can i place the ByteBufferDataSource inside the processor prior to transmission?
 
I am interested in knowing how to construct a processor from a ByteBufferDataSource as well. It works fine with a Player, and the video played fine. However when I put my buffer into a Processor to be written out to a DataSink, I get the NoProcessorFound error.

Also, how can I transmit both audio and video data (interleaved) together using only one RTP session? I hate it when my Processor separates my movie into individual tracks.

Thanks all.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top