Skip to content

Commit

Permalink
Potentially improve FPS (#6)
Browse files Browse the repository at this point in the history
* Reduced JPEG quality to 90 - seems to not affect stream that much while improving FPS
* Implemented a BlockingQueue and running JPEG conversion in a background thread potentially increasing FPS a little bit more
  • Loading branch information
shamanec authored Apr 12, 2023
1 parent 8b727d6 commit e8220a7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ScreenCaptureActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jpegQuality = getIntent().getIntExtra("jpegQuality", 100);
jpegQuality = getIntent().getIntExtra("jpegQuality", 90);
startProjection();
}

Expand Down
57 changes: 39 additions & 18 deletions app/src/main/java/com/shamanec/stream/ScreenCaptureService.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;

import androidx.core.util.Pair;
import androidx.test.platform.app.InstrumentationRegistry;
Expand Down Expand Up @@ -99,12 +101,11 @@ private Bitmap imageToBitmap(Image image) {

// Create the initial bitmap object
// And copy into it the pixels from the buffer declared above
Bitmap bitmap = Bitmap.createBitmap(newWidth, mHeight, Bitmap.Config.ARGB_8888);
Bitmap bitmap = Bitmap.createBitmap(newWidth, mHeight, Bitmap.Config.ARGB_4444);
bitmap.copyPixelsFromBuffer(buffer);

// Close the Image to free up memory
image.close();
System.gc();

// We reinitialize the bitmap object using the original bitmap
// but with the display width and height
Expand All @@ -114,6 +115,32 @@ private Bitmap imageToBitmap(Image image) {
return bitmap;
}

BlockingQueue<Bitmap> imageQueue = new LinkedBlockingDeque<>(3);
private class ImageConsumer implements Runnable {
@Override
public void run() {
while (true) {
try {
// Take the next image from the queue (this will block if the queue is empty)
Bitmap bitmap = imageQueue.take();

// Compress the image
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, ScreenCaptureActivity.jpegQuality, outputStream);

bitmap.recycle();
byte[] compressedImage = outputStream.toByteArray();

// Send the compressed image over the WebSocket
server.broadcast(compressedImage);

} catch (InterruptedException e) {
// Handle interruption or exit the loop
break;
}
}
}
}

private class ImageAvailableListener implements ImageReader.OnImageAvailableListener {
@Override
Expand All @@ -123,20 +150,7 @@ public void onImageAvailable(ImageReader reader) {
try (Image image = mImageReader.acquireLatestImage()) {
if (image != null) {
bitmap = imageToBitmap(image);

// Compress the Bitmap as JPEG into the ByteArrayOutputStream
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, ScreenCaptureActivity.jpegQuality, stream);

// Recycle the bitmap to free up memory
bitmap.recycle();
System.gc();

// Get the JPEG as byte array
byte[] byteArray = stream.toByteArray();

// Broadcast the JPEG image over the websocket
server.broadcast(byteArray);
imageQueue.put(bitmap);
}
} catch (Exception e) {
e.printStackTrace();
Expand All @@ -153,6 +167,7 @@ private class OrientationChangeCallback extends OrientationEventListener {

@Override
public void onOrientationChanged(int orientation) {
imageQueue.clear();
// When orientation changes get the display rotation
final int rotation = mDisplay.getRotation();
// If the current rotation is different than the previous rotation
Expand Down Expand Up @@ -280,8 +295,11 @@ private void createVirtualDisplay() {
// Set up the width and height for the image reader to be half of the real display metrics
// This significantly increases the FPS even with JPEG quality of 100
// Instead of rescaling bitmaps which reduces quality even further
mWidth = metrics.widthPixels / 2;
mHeight = metrics.heightPixels / 2;
int metricsWidth = metrics.widthPixels;
int metricsHeight = metrics.heightPixels;

mWidth = metricsWidth / 2;
mHeight = metricsHeight / 2;
mDensity = metrics.densityDpi;

// Create an ImageReader object with the proper display dimensions and PixelFormat
Expand All @@ -291,6 +309,9 @@ private void createVirtualDisplay() {
mVirtualDisplay = mMediaProjection.createVirtualDisplay("screencapture", mWidth, mHeight,
mDensity, getVirtualDisplayFlags(), mImageReader.getSurface(), null, mHandler);

Thread imageConsumerThread = new Thread(new ImageConsumer());
imageConsumerThread.start();

// Set an ImageAvailableListener on the ImageReader object
mImageReader.setOnImageAvailableListener(new ImageAvailableListener(), mHandler);
}
Expand Down

0 comments on commit e8220a7

Please sign in to comment.