Passes desktop captured images to scaler/colorspace converter as native memory.

cusax-fix
Sebastien Vincent 16 years ago
parent 89e6467a8c
commit fef3d696e2

@ -462,7 +462,7 @@ static int x11_grab_screen(const char* x11display, jbyte* data, int32_t x, int32
/**
* \brief JNI native method to grab desktop screen and retrieve ARGB pixels.
* \param env JVM environment
* \param obj NativeScreenCapture Java class
* \param clazz NativeScreenCapture Java class
* \param x x position to start capture
* \param y y position to start capture
* \param width capture width
@ -470,13 +470,13 @@ static int x11_grab_screen(const char* x11display, jbyte* data, int32_t x, int32
* \param output output buffer, screen bytes will be stored in
* \return true if success, false otherwise
*/
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen
(JNIEnv* env, jclass obj, jint x, jint y, jint width, jint height, jbyteArray output)
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIII_3B
(JNIEnv* env, jclass clazz, jint x, jint y, jint width, jint height, jbyteArray output)
{
jint size = width * height * 4;
jbyte* data = NULL;
obj = obj; /* not used */
clazz = clazz; /* not used */
if(!output || (*env)->GetArrayLength(env, output) < size)
{
@ -506,3 +506,43 @@ JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstrea
return JNI_TRUE;
}
/**
* \brief JNI native method to grab desktop screen and retrieve ARGB pixels.
* \param env JVM environment
* \param clazz NativeScreenCapture Java class
* \param x x position to start capture
* \param y y position to start capture
* \param width capture width
* \param height capture height
* \param output native output buffer
* \return true if success, false otherwise
*/
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIIIJI
(JNIEnv* env, jclass clazz, jint x, jint y, jint width, jint height, jlong output, jint outputLength)
{
jint size = width * height * 4;
jbyte* data = (jbyte*)output;
/* not used */
clazz = clazz;
env = env;
if(!data || outputLength < size)
{
return JNI_FALSE;
}
#if defined (_WIN32) || defined(_WIN64)
if(windows_grab_screen(data, x, y, width, height) == -1)
#elif defined(__APPLE__)
if(quartz_grab_screen(data, x, y, width, height) == -1)
#else /* Unix */
if(x11_grab_screen(NULL, data, x, y, width, height) == -1)
#endif
{
return JNI_FALSE;
}
return JNI_TRUE;
}

@ -12,9 +12,17 @@ extern "C" {
* Method: grabScreen
* Signature: (IIII[B)Z
*/
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIII_3B
(JNIEnv *, jclass, jint, jint, jint, jint, jbyteArray);
/*
* Class: net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture
* Method: grabScreen
* Signature: (IIIIJI)Z
*/
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_neomedia_imgstreaming_NativeScreenCapture_grabScreen__IIIIJI
(JNIEnv *, jclass, jint, jint, jint, jint, jlong, jint);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,116 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.neomedia.codec.video;
/**
* Represents a buffer of native memory with a specific size/capacity which
* either contains a specific number of bytes of valid data or is free for
* consumption.
*
* @author Lubomir Marinov
*/
public class ByteBuffer
{
/**
* The maximum number of bytes which can be written into the native
* memory represented by this instance.
*/
public final int capacity;
/**
* The indicator which determines whether this instance is free to be
* written bytes into.
*/
private boolean free;
/**
* The number of bytes of valid data that the native memory represented
* by this instance contains.
*/
private int length;
/**
* The pointer to the native memory represented by this instance.
*/
public final long ptr;
/**
* Initializes a new <tt>ByteBuffer</tt> instance with a specific
* <tt>capacity</tt>.
*
* @param capacity the maximum number of bytes which can be written into
* the native memory represented by the new instance
*/
public ByteBuffer(int capacity)
{
this.capacity = capacity;
this.ptr = FFmpeg.av_malloc(this.capacity);
this.free = true;
this.length = 0;
if (this.ptr == 0)
{
throw
new OutOfMemoryError(
getClass().getSimpleName()
+ " with capacity "
+ this.capacity);
}
}
/**
* Gets the number of bytes of valid data that the native memory
* represented by this instance contains.
*
* @return the number of bytes of valid data that the native memory
* represented by this instance contains
*/
public int getLength()
{
return length;
}
/**
* Determines whether this instance is free to be written bytes into.
*
* @return <tt>true</tt> if this instance is free to be written bytes
* into or <tt>false</tt> is the native memory represented by this
* instance is already is use
*/
public boolean isFree()
{
return free;
}
/**
* Sets the indicator which determines whether this instance is free to
* be written bytes into.
*
* @param free <tt>true</tt> if this instance is to be made available
* for writing bytes into; otherwise, <tt>false</tt>
*/
public void setFree(boolean free)
{
this.free = free;
if (this.free)
setLength(0);
}
/**
* Sets the number of bytes of valid data that the native memory
* represented by this instance contains.
*
* @param length the number of bytes of valid data that the native
* memory represented by this instance contains
*/
public void setLength(int length)
{
this.length = length;
}
}

@ -58,6 +58,9 @@ public class SwScaler
new RGBFormat(null, -1, Format.shortArray, -1.0f, 24, -1, -1, -1),
};
/**
* Libswscale context pointer.
*/
private long swsContext = 0;
/**

@ -11,7 +11,7 @@
/**
* Interface to interact with the desktop such as taking
* screen capture or to generate mouse/keyboard event.
*
*
* @author Sebastien Vincent
*/
public interface DesktopInteract
@ -23,7 +23,8 @@ public interface DesktopInteract
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for convertion operation.
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param output output buffer to store bytes in.
* Be sure that output length is sufficient
@ -31,6 +32,23 @@ public interface DesktopInteract
*/
public boolean captureScreen(byte output[]);
/**
* Capture the full desktop screen using native grabber.
*
* Contrary to other captureScreen method, it only returns raw bytes
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param buffer native output buffer to store bytes in.
* Be sure that output length is sufficient
* @param bufferLength length of native buffer
* @return true if success, false if JNI error or output length too short
*/
public boolean captureScreen(long buffer, int bufferLength);
/**
* Capture a part of the desktop screen using native grabber.
*
@ -38,7 +56,8 @@ public interface DesktopInteract
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for convertion operation.
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param x x position to start capture
* @param y y position to start capture
@ -48,7 +67,30 @@ public interface DesktopInteract
* Be sure that output length is sufficient
* @return true if success, false if JNI error or output length too short
*/
public boolean captureScreen(int x, int y, int width, int height, byte output[]);
public boolean captureScreen(int x, int y, int width, int height,
byte output[]);
/**
* Capture a part of the desktop screen using native grabber.
*
* Contrary to other captureScreen method, it only returns raw bytes
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param x x position to start capture
* @param y y position to start capture
* @param width capture width
* @param height capture height
* @param buffer native output buffer to store bytes in.
* Be sure that output length is sufficient
* @param bufferLength length of native buffer
* @return true if success, false if JNI error or output length too short
*/
public boolean captureScreen(int x, int y, int width, int height,
long buffer, int bufferLength);
/**
* Capture the full desktop screen.

@ -12,19 +12,20 @@
import net.java.sip.communicator.util.*;
/**
* This singleton class provide screen capture and key/mouse
* This singleton class provide screen capture and key/mouse
* events generation by wrapping partial or all <tt>java.awt.Robot</tt>
* methods to interact with desktop.
*
* @see java.awt.Robot
* @author Sebastien Vincent
*/
public class DesktopInteractImpl implements DesktopInteract
public class DesktopInteractImpl implements DesktopInteract
{
/**
* The <tt>Logger</tt>.
*/
private static final Logger logger = Logger.getLogger(DesktopInteractImpl.class);
private static final Logger logger =
Logger.getLogger(DesktopInteractImpl.class);
/**
* Screen capture robot.
@ -33,11 +34,12 @@ public class DesktopInteractImpl implements DesktopInteract
/**
* Constructor.
*
* @throws AWTException if platform configuration does not allow low-level input control
*
* @throws AWTException if platform configuration does not allow low-level
* input control
* @throws SecurityException if Robot creation is not permitted
*/
public DesktopInteractImpl() throws AWTException, SecurityException
public DesktopInteractImpl() throws AWTException, SecurityException
{
robot = new Robot();
}
@ -49,7 +51,8 @@ public DesktopInteractImpl() throws AWTException, SecurityException
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for convertion operation.
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param output output buffer to store bytes in.
* Be sure that output length is sufficient
@ -59,7 +62,29 @@ public boolean captureScreen(byte output[])
{
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
return captureScreen(0, 0, (int)dim.getWidth(), (int)dim.getHeight(), output);
return captureScreen(0, 0, dim.width, dim.height,
output);
}
/**
* Capture the full desktop screen using native grabber.
*
* Contrary to other captureScreen method, it only returns raw bytes
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param buffer native output buffer to store bytes in.
* Be sure that output length is sufficient
* @param bufferLength length of native buffer
* @return true if success, false if JNI error or output length too short
*/
public boolean captureScreen(long buffer, int bufferLength)
{
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
return captureScreen(0, 0, dim.width, dim.height, buffer, bufferLength);
}
/**
@ -67,9 +92,10 @@ public boolean captureScreen(byte output[])
*
* Contrary to other captureScreen method, it only returns raw bytes
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for convertion operation.
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param x x position to start capture
* @param y y position to start capture
@ -79,7 +105,8 @@ public boolean captureScreen(byte output[])
* Be sure that output length is sufficient
* @return true if success, false if JNI error or output length too short
*/
public boolean captureScreen(int x, int y, int width, int height, byte output[])
public boolean captureScreen(int x, int y, int width, int height,
byte output[])
{
if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD || OSUtils.IS_WINDOWS
|| OSUtils.IS_MAC)
@ -91,6 +118,38 @@ public boolean captureScreen(int x, int y, int width, int height, byte output[])
return false;
}
/**
* Capture a part of the desktop screen using native grabber.
*
* Contrary to other captureScreen method, it only returns raw bytes
* and not <tt>BufferedImage</tt>. It is done in order to limit
* slow operation such as converting ARGB images (uint32_t) to bytes
* especially for big big screen. For example a 1920x1200 desktop consumes
* 9 MB of memory for grabbing and another 9 MB array for conversion
* operation.
*
* @param x x position to start capture
* @param y y position to start capture
* @param width capture width
* @param height capture height
* @param buffer native output buffer to store bytes in.
* Be sure that output length is sufficient
* @param bufferLength length of native buffer
* @return true if success, false if JNI error or output length too short
*/
public boolean captureScreen(int x, int y, int width, int height,
long buffer, int bufferLength)
{
if(OSUtils.IS_LINUX || OSUtils.IS_FREEBSD || OSUtils.IS_WINDOWS
|| OSUtils.IS_MAC)
{
return NativeScreenCapture.grabScreen(
x, y, width, height, buffer, bufferLength);
}
return false;
}
/**
* Capture the full desktop screen using <tt>java.awt.Robot</tt>.
*
@ -100,7 +159,7 @@ public BufferedImage captureScreen()
{
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
return captureScreen(0, 0, (int)dim.getWidth(), (int)dim.getHeight());
return captureScreen(0, 0, dim.width, dim.height);
}
/**
@ -117,7 +176,7 @@ public BufferedImage captureScreen(int x, int y, int width, int height)
{
BufferedImage img = null;
Rectangle rect = null;
if(robot == null)
{
/* Robot has not been created so abort */
@ -128,7 +187,7 @@ public BufferedImage captureScreen(int x, int y, int width, int height)
rect = new Rectangle(x, y, width, height);
img = robot.createScreenCapture(rect);
logger.info("End capture: " + System.nanoTime());
return img;
}

@ -6,12 +6,10 @@
*/
package net.java.sip.communicator.impl.neomedia.imgstreaming;
import java.awt.image.*;
/**
* This class uses native code to capture desktop screen.
*
* It should work for Windows, Mac OS X and X11-based Unix such as Linux
*
* It should work for Windows, Mac OS X and X11-based Unix such as Linux
* and FreeBSD.
*
* @author Sebastien Vincent
@ -25,7 +23,7 @@ public class NativeScreenCapture
/**
* Grab desktop screen and get raw bytes.
*
*
* @param x x position to start capture
* @param y y position to start capture
* @param width capture width
@ -33,5 +31,20 @@ public class NativeScreenCapture
* @param output output buffer to store screen bytes
* @return true if grab success, false otherwise
*/
public static native boolean grabScreen(int x, int y, int width, int height, byte output[]);
public static native boolean grabScreen(int x, int y, int width, int height,
byte output[]);
/**
* Grab desktop screen and get raw bytes.
*
* @param x x position to start capture
* @param y y position to start capture
* @param width capture width
* @param height capture height
* @param output native output buffer to store screen bytes
* @param outputLength native output length
* @return true if grab success, false otherwise
*/
public static native boolean grabScreen(int x, int y, int width, int height,
long output, int outputLength);
}

@ -12,10 +12,11 @@
import javax.media.control.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.*;
/**
* DataSource for our image streaming (which is used for
* DataSource for our image streaming (which is used for
* Desktop streaming).
*
* @author Sebastien Vincent
@ -32,7 +33,11 @@ public class DataSource
private static final Format[] formats
= new Format[]
{
new RGBFormat(
new AVFrameFormat(
Toolkit.getDefaultToolkit().getScreenSize(),
Format.NOT_SPECIFIED,
FFmpeg.PIX_FMT_ARGB),
new RGBFormat(
Toolkit.getDefaultToolkit().getScreenSize(), // size
Format.NOT_SPECIFIED, // maxDataLength
Format.byteArray, // dataType

@ -14,14 +14,13 @@
import javax.media.control.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.impl.neomedia.imgstreaming.*;
import net.java.sip.communicator.impl.neomedia.jmfext.media.protocol.*;
import net.java.sip.communicator.util.*;
/**
* The stream used by JMF for our image streaming.
*
* This class launches a thread to handle desktop capture interactions.
*
* @author Sebastien Vincent
* @author Lubomir Marinov
@ -45,6 +44,11 @@ public class ImageStream
*/
private DesktopInteract desktopInteract = null;
/**
* Native buffer pointer.
*/
ByteBuffer data = null;
/**
* Initializes a new <tt>ImageStream</tt> instance which is to have a
* specific <tt>FormatControl</tt>
@ -67,41 +71,80 @@ public void read(Buffer buffer)
throws IOException
{
//System.out.println(System.currentTimeMillis());
byte data[] = (byte[])buffer.getData();
int dataLength = (data != null) ? data.length : 0;
long begin = System.currentTimeMillis();
/* maximum time allowed for a capture to respect frame rate */
long maxTime = 1000 / 10;
long maxTime = 1000 / 10;
int wait = 0;
if((data != null) || (dataLength != 0))
if(buffer.getFormat() instanceof AVFrameFormat)
{
byte buf[] = readScreen(data);
/* native transfert: we keep data in native memory rather
* than Java Heap until we reach SwScaler
*/
Object dataAv = buffer.getData();
AVFrame bufferFrame = null;
long bufferFramePtr = 0;
if(buf != data)
if (dataAv instanceof AVFrame)
{
/* readScreen returns us a different buffer than JMF ones,
* it means that JMF's initial buffer was too short.
*/
//System.out.println("use our own buffer");
buffer.setData(buf);
bufferFrame = (AVFrame)dataAv;
bufferFramePtr = bufferFrame.getPtr();
}
else
{
bufferFrame = new FinalizableAVFrame();
bufferFramePtr = bufferFrame.getPtr();
}
buffer.setOffset(0);
buffer.setLength(buf.length);
buffer.setFormat(getFormat());
buffer.setHeader(null);
buffer.setTimeStamp(System.nanoTime());
buffer.setSequenceNumber(seqNo);
buffer.setFlags(Buffer.FLAG_SYSTEM_TIME | Buffer.FLAG_LIVE_DATA);
seqNo++;
AVFrameFormat bufferFrameFormat = (AVFrameFormat)buffer.getFormat();
Dimension bufferFrameSize = bufferFrameFormat.getSize();
if(readScreenNative(bufferFrameSize))
{
FFmpeg.avpicture_fill(
bufferFramePtr,
data.ptr,
bufferFrameFormat.getPixFmt(),
bufferFrameSize.width, bufferFrameSize.height);
}
buffer.setData(bufferFrame);
}
else
{
byte dataByte[] = (byte[])buffer.getData();
int dataLength = (dataByte != null) ? dataByte.length : 0;
if((dataByte != null) || (dataLength != 0))
{
byte buf[] = readScreen(dataByte);
if(buf != dataByte)
{
/* readScreen returns us a different buffer than JMF ones,
* it means that JMF's initial buffer was too short.
*/
//System.out.println("use our own buffer");
buffer.setData(buf);
}
buffer.setOffset(0);
buffer.setLength(buf.length);
}
}
buffer.setFormat(buffer.getFormat());
buffer.setHeader(null);
buffer.setTimeStamp(System.nanoTime());
buffer.setSequenceNumber(seqNo);
buffer.setFlags(Buffer.FLAG_SYSTEM_TIME | Buffer.FLAG_LIVE_DATA);
seqNo++;
wait = (int)(maxTime - (System.currentTimeMillis() - begin));
try
{
/* sleep to respect as much as possible the
/* sleep to respect as much as possible the
* frame rate
*/
if(wait > 0)
@ -110,7 +153,7 @@ public void read(Buffer buffer)
}
else
{
/* yield a little bit to not use all the
/* yield a little bit to not use all the
* CPU
*/
Thread.yield();
@ -151,14 +194,54 @@ public void start()
public void stop()
{
logger.info("Stop stream");
/* native pointer is freed in FinalizableAVFrame */
data = null;
}
/**
* Read screen and store result in native buffer.
*
* @param dim dimension of the video
* @return true if success, false otherwise
*/
private boolean readScreenNative(Dimension dim)
{
int size = dim.width * dim.height * 4;
/* pad the buffer */
size += FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE;
/* allocate native array */
if(data == null)
{
data = new ByteBuffer(size);
data.setLength(size);
}
/* reallocate native array if capacity is not enough */
if(data.getLength() < size)
{
data.setFree(true);
FFmpeg.av_free(data.ptr);
data = new ByteBuffer(size);
data.setLength(size);
}
/* get desktop screen via native grabber */
if(desktopInteract.captureScreen(data.ptr, data.getLength()))
{
return true;
}
return false;
}
/**
* Read screen.
*
*
* @param output output buffer for screen bytes
* @return raw bytes, it could be equal to output or not. Take care in the caller
* to check if output is the returned value.
* @return raw bytes, it could be equal to output or not. Take care in the
* caller to check if output is the returned value.
*/
public byte[] readScreen(byte output[])
{
@ -194,8 +277,8 @@ public byte[] readScreen(byte output[])
* Note that it is very memory consuming since memory are allocated
* to capture screen (via Robot) and then for converting to raw bytes
*
* Normally not of our supported platform (Windows (x86, x64),
* Linux (x86, x86-64), Mac OS X (i386, x86-64, ppc) and
* Normally not of our supported platform (Windows (x86, x64),
* Linux (x86, x86-64), Mac OS X (i386, x86-64, ppc) and
* FreeBSD (x86, x86-64) should go here.
*/
screen = desktopInteract.captureScreen();
@ -203,7 +286,7 @@ public byte[] readScreen(byte output[])
if(screen != null)
{
/* convert to ARGB BufferedImage */
scaledScreen
scaledScreen
= ImageStreamingUtils
.getScaledImage(
screen,
@ -219,4 +302,61 @@ public byte[] readScreen(byte output[])
scaledScreen = null;
return data;
}
/**
* Represents an <tt>AVFrame</tt> used by this instance to provide captured
* media data in native format without representing the very frame data in
* the Java heap. Since this instance cannot know when the <tt>AVFrame</tt>
* instances are really safe for deallocation, <tt>FinalizableAVFrame</tt>
* relies on the Java finalization mechanism to reclaim the represented
* native memory.
*/
public class FinalizableAVFrame
extends AVFrame
{
/**
* The indicator which determines whether the native memory represented
* by this instance has already been freed/deallocated.
*/
private boolean freed = false;
/**
* Initializes a new <tt>FinalizableAVFrame</tt> instance which is to
* allocate a new native FFmpeg <tt>AVFrame</tt> and represent it.
*/
public FinalizableAVFrame()
{
super(FFmpeg.avcodec_alloc_frame());
}
/**
* Deallocates the native memory represented by this instance.
*
* @see Object#finalize()
*/
@Override
protected void finalize()
throws Throwable
{
try
{
if (!freed)
{
long ptr = getPtr();
long bufferPtr = FFmpeg.avpicture_get_data0(ptr);
if(bufferPtr != 0)
FFmpeg.av_free(bufferPtr);
FFmpeg.av_free(ptr);
freed = true;
}
}
finally
{
super.finalize();
}
}
}
}

@ -694,7 +694,7 @@ private void runInTransferDataThread()
nextData = null;
}
}
synchronized (dataSyncRoot)
{
if (data == null)
@ -879,119 +879,12 @@ public void stop()
}
}
/**
* Represents a buffer of native memory with a specific size/capacity which
* either contains a specific number of bytes of valid data or is free for
* consumption.
*/
private static class ByteBuffer
{
/**
* The maximum number of bytes which can be written into the native
* memory represented by this instance.
*/
public final int capacity;
/**
* The indicator which determines whether this instance is free to be
* written bytes into.
*/
private boolean free;
/**
* The number of bytes of valid data that the native memory represented
* by this instance contains.
*/
private int length;
/**
* The pointer to the native memory represented by this instance.
*/
public final long ptr;
/**
* Initializes a new <tt>ByteBuffer</tt> instance with a specific
* <tt>capacity</tt>.
*
* @param capacity the maximum number of bytes which can be written into
* the native memory represented by the new instance
*/
public ByteBuffer(int capacity)
{
this.capacity = capacity;
this.ptr = FFmpeg.av_malloc(this.capacity);
this.free = true;
this.length = 0;
if (this.ptr == 0)
{
throw
new OutOfMemoryError(
getClass().getSimpleName()
+ " with capacity "
+ this.capacity);
}
}
/**
* Gets the number of bytes of valid data that the native memory
* represented by this instance contains.
*
* @return the number of bytes of valid data that the native memory
* represented by this instance contains
*/
public int getLength()
{
return length;
}
/**
* Determines whether this instance is free to be written bytes into.
*
* @return <tt>true</tt> if this instance is free to be written bytes
* into or <tt>false</tt> is the native memory represented by this
* instance is already is use
*/
public boolean isFree()
{
return free;
}
/**
* Sets the indicator which determines whether this instance is free to
* be written bytes into.
*
* @param free <tt>true</tt> if this instance is to be made available
* for writing bytes into; otherwise, <tt>false</tt>
*/
public void setFree(boolean free)
{
this.free = free;
if (this.free)
setLength(0);
}
/**
* Sets the number of bytes of valid data that the native memory
* represented by this instance contains.
*
* @param length the number of bytes of valid data that the native
* memory represented by this instance contains
*/
public void setLength(int length)
{
this.length = length;
}
}
/**
* Represents an <tt>AVFrame</tt> used by this instance to provide captured
* media data in native format without representing the very frame data in
* the Java heap. Since this instance cannot know when the <tt>AVFrame</tt>
* instances are really safe for deallocation, <tt>FinalizableAVFrame</tt>
* relies on the Java finialization mechanism to reclaim the represented
* relies on the Java finalization mechanism to reclaim the represented
* native memory.
*/
private class FinalizableAVFrame

Loading…
Cancel
Save