Skip to content

Commit

Permalink
Merge pull request #128 from abrenoch/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
abrenoch authored Oct 14, 2018
2 parents d412636 + ecc5656 commit 803b22a
Show file tree
Hide file tree
Showing 60 changed files with 1,364 additions and 2,806 deletions.
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
## [v0.5-beta]
### Changes
- Added the ability to send only the average color of the screen
- French translation
- Norwegian translation
- Czech translation
- German translation
- Dutch translation
- Partial Russian translation
- Partial Spanish translation
- Removed openGL grabber option
- Added toggle grabber activity shortcut
- LEDs will now be cleared when rebooting or shutting down

### Fixed
- Lights now clear (if running) when shutting down
- Assertion bug in TV settings
- Possible null intent when starting grabber
- OOM bug

## [v0.4-alpha]
### Changes
- Start grabber on device boot
Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.2.41'
ext.protobufVersion = "0.8.3"
ext.kotlin_version = '1.2.71'
ext.protobufVersion = "0.8.6"

repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "com.google.protobuf:protobuf-gradle-plugin:$protobufVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
Expand Down
5 changes: 3 additions & 2 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6'
}
}

Expand All @@ -31,6 +31,7 @@ sourceSets {
android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 19
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class HyperionNotification {
HyperionNotification (Context ctx, NotificationManager manager) {
mNotificationManager = manager;
mContext = ctx;
NOTIFICATION_TITLE = mContext.getString(R.string.notification_title);
NOTIFICATION_TITLE = mContext.getString(R.string.app_name);
NOTIFICATION_DESCRIPTION = mContext.getString(R.string.notification_description);
NOTIFICATION_CHANNEL_LABEL = mContext.getString(R.string.notification_channel_label);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import android.util.Log;

import com.abrenoch.hyperiongrabber.common.network.HyperionThread;
import com.abrenoch.hyperiongrabber.common.util.BorderProcessor;
import com.abrenoch.hyperiongrabber.common.util.HyperionGrabberOptions;

import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -42,6 +43,8 @@ public class HyperionScreenEncoder extends HyperionScreenEncoderBase {
@TargetApi(Build.VERSION_CODES.M)
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void prepare() throws MediaCodec.CodecException {
if (DEBUG) Log.d(TAG, "Preparing encoder");

mVirtualDisplay = mMediaProjection.createVirtualDisplay(
TAG,
getGrabberWidth(), getGrabberHeight(), mDensity,
Expand Down Expand Up @@ -113,6 +116,7 @@ public void onStopped() {

@RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH)
private void setImageReader() {
if (DEBUG) Log.d(TAG, "Setting image reader " + String.valueOf(isCapturing()));
mImageReader = ImageReader.newInstance(getGrabberWidth(), getGrabberHeight(),
PixelFormat.RGBA_8888, MAX_IMAGE_READER_IMAGES);
mImageReader.setOnImageAvailableListener(imageAvailableListener, mHandler);
Expand All @@ -132,7 +136,7 @@ public void onImageAvailable(ImageReader reader) {
long now = System.nanoTime();
Image img = reader.acquireLatestImage();
if (img != null && now - lastFrame >= min_nano_time) {
mListener.sendFrame(savePixels(img), getGrabberWidth(), getGrabberHeight());
sendImage(img);
img.close();
lastFrame = now;
} else if (img != null) {
Expand All @@ -145,28 +149,93 @@ public void onImageAvailable(ImageReader reader) {
}
};

private byte[] savePixels(Image image) throws IllegalStateException {
Image.Plane plane = image.getPlanes()[0];
ByteBuffer buffer = plane.getBuffer();
private byte[] getPixels(ByteBuffer buffer, int width, int height, int rowStride,
int pixelStride, int firstX, int firstY){
int rowPadding = rowStride - width * pixelStride;
int offset = 0;

int width = image.getWidth();
int height = image.getHeight();
int pixelStride = plane.getPixelStride();
int rowPadding = plane.getRowStride() - width * pixelStride;
ByteArrayOutputStream bao = new ByteArrayOutputStream(
(width - firstX * 2) * (height - firstY * 2) * 3
);

for (int y = 0, compareHeight = height - firstY - 1; y < height; y++, offset += rowPadding) {
if (y < firstY || y > compareHeight) {
offset += width * pixelStride;
continue;
}
for (int x = 0, compareWidth = width - firstX - 1; x < width; x++, offset += pixelStride) {
if (x < firstX || x > compareWidth) continue;
bao.write(buffer.get(offset) & 0xff); // R
bao.write(buffer.get(offset + 1) & 0xff); // G
bao.write(buffer.get(offset + 2) & 0xff); // B
}
}

ByteArrayOutputStream bao = new ByteArrayOutputStream(width * height * 3);
return bao.toByteArray();
}

private byte[] getAverageColor(ByteBuffer buffer, int width, int height, int rowStride,
int pixelStride, int firstX, int firstY) {
long totalRed = 0, totalGreen = 0, totalBlue = 0;
int rowPadding = rowStride - width * pixelStride;
int pixelCount = 0;
int offset = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
bao.write(buffer.get(offset)); // R
bao.write(buffer.get(offset + 1)); // G
bao.write(buffer.get(offset + 2)); // B
offset += pixelStride;

ByteArrayOutputStream bao = new ByteArrayOutputStream(3);

for (int y = 0, compareHeight = height - firstY - 1; y < height; y++, offset += rowPadding) {
if (y < firstY || y > compareHeight) {
offset += width * pixelStride;
continue;
}
for (int x = 0, compareWidth = width - firstX - 1; x < width; x++, offset += pixelStride) {
if (x < firstX || x > compareWidth) continue;
totalRed += buffer.get(offset) & 0xff; // R
totalGreen += buffer.get(offset + 1) & 0xff; // G
totalBlue += buffer.get(offset + 2) & 0xff; // B
pixelCount++;
}
offset += rowPadding;
}

bao.write((int) totalRed / pixelCount);
bao.write((int) totalGreen / pixelCount);
bao.write((int) totalBlue / pixelCount);

return bao.toByteArray();
}

private void sendImage(Image img) {
Image.Plane plane = img.getPlanes()[0];
ByteBuffer buffer = plane.getBuffer();

int width = img.getWidth();
int height = img.getHeight();
int pixelStride = plane.getPixelStride();
int rowStride = plane.getRowStride();
int firstX = 0;
int firstY = 0;

if (mRemoveBorders || mAvgColor) {
mBorderProcessor.parseBorder(buffer, width, height, rowStride, pixelStride);
BorderProcessor.BorderObject border = mBorderProcessor.getCurrentBorder();
if (border != null && border.isKnown()) {
firstX = border.getHorizontalBorderIndex();
firstY = border.getVerticalBorderIndex();
}
}

if (mAvgColor) {
mListener.sendFrame(
getAverageColor(buffer, width, height, rowStride, pixelStride, firstX, firstY),
1,
1
);
} else {
mListener.sendFrame(
getPixels(buffer, width, height, rowStride, pixelStride, firstX, firstY),
width - firstX * 2,
height - firstY * 2
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,26 @@
import android.util.Log;

import com.abrenoch.hyperiongrabber.common.network.HyperionThread;
import com.abrenoch.hyperiongrabber.common.util.BorderProcessor;
import com.abrenoch.hyperiongrabber.common.util.HyperionGrabberOptions;

public class HyperionScreenEncoderBase {
private static final boolean DEBUG = false;
static final boolean DEBUG = false;
private static final String TAG = "ScreenEncoderBase";
private final int CLEAR_COMMAND_DELAY_MS = 100;
private final int INIT_ORIENTATION;
int mWidthScaled;
int mFrameRate;
int mHeightScaled;
int mDensity;
int mCurrentOrientation;
Handler mHandler;

final boolean mRemoveBorders = false; // enables detecting borders for standard grabbing - disabled for now
final boolean mAvgColor;
final int mWidthScaled;
final int mFrameRate;
final int mHeightScaled;
final int mDensity;
boolean mIsCapturing = false;
int mCurrentOrientation;

BorderProcessor mBorderProcessor;
Handler mHandler;
MediaProjection mMediaProjection;
HyperionThread.HyperionThreadListener mListener;

Expand All @@ -33,6 +39,10 @@ public class HyperionScreenEncoderBase {
mMediaProjection = projection;
mDensity = density;
mFrameRate = options.getFrameRate();
mAvgColor = options.useAverageColor();

int blackThreshold = options.getBlackThreshold();
mBorderProcessor = new BorderProcessor(blackThreshold);

mCurrentOrientation = INIT_ORIENTATION = width > height ? Configuration.ORIENTATION_LANDSCAPE :
Configuration.ORIENTATION_PORTRAIT;
Expand All @@ -42,6 +52,8 @@ public class HyperionScreenEncoderBase {
Log.d(TAG, "Frame Rate: " + String.valueOf(mFrameRate));
Log.d(TAG, "Original Width: " + String.valueOf(width));
Log.d(TAG, "Original Height: " + String.valueOf(height));
Log.d(TAG, "Average Color Only: " + String.valueOf(mAvgColor));
Log.d(TAG, "Black Pixel Threshold: " + String.valueOf(blackThreshold));
}

// find the common divisor for width & height best fit for the LED count (defined in options)
Expand All @@ -66,13 +78,25 @@ public class HyperionScreenEncoderBase {

private Runnable clearAndDisconnectRunner = new Runnable() {
public void run() {
if (DEBUG) Log.d(TAG, "Clearing LEDs and disconnecting");
try {
Thread.sleep(CLEAR_COMMAND_DELAY_MS);
} catch (InterruptedException e) {
e.printStackTrace();
}
mListener.clear();
mListener.disconnect();
}
};

private Runnable clearLightsRunner = new Runnable() {
public void run() {
if (DEBUG) Log.d(TAG, "Clearing LEDs");
try {
Thread.sleep(CLEAR_COMMAND_DELAY_MS);
} catch (InterruptedException e) {
e.printStackTrace();
}
mListener.clear();
}
};
Expand Down
Loading

0 comments on commit 803b22a

Please sign in to comment.