Skip to content

WIP: Feature / remove handler from sdl remote display #859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -40,6 +40,8 @@
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
@@ -65,13 +67,38 @@ public class VirtualDisplayEncoder {
private IVideoStreamListener mOutputListener;
private Boolean initPassed = false;
private final Object STREAMING_LOCK = new Object();
private static final long KEEPALIVE_INTERVAL_MSEC = 100;
protected Handler handler = new Handler(Looper.getMainLooper());
private long mLastEmittedFrameTimestamp;

// Codec-specific data (SPS and PPS)
private byte[] mH264CodecSpecificData = null;

//For older (<21) OS versions
private Thread encoderThread;

private void startRefreshTask() {
handler.postDelayed(mStartRefreshTaskCallback, KEEPALIVE_INTERVAL_MSEC);
}

private void stopRefreshTask() {
handler.removeCallbacks(mStartRefreshTaskCallback);
}

private Runnable mStartRefreshTaskCallback = new Runnable() {
public void run() {

if (mOutputListener != null && mH264CodecSpecificData != null && mVideoBufferInfo != null) {
long timeSinceLastEmitted = System.currentTimeMillis() - mLastEmittedFrameTimestamp;
if (timeSinceLastEmitted >= KEEPALIVE_INTERVAL_MSEC) {
mOutputListener.sendFrame(mH264CodecSpecificData, 0, mH264CodecSpecificData.length, mVideoBufferInfo.presentationTimeUs);
mLastEmittedFrameTimestamp = System.currentTimeMillis();
}
}
handler.postDelayed(this, KEEPALIVE_INTERVAL_MSEC);
}
};


/**
* Initialization method for VirtualDisplayEncoder object. MUST be called before start() or shutdown()
@@ -120,7 +147,7 @@ public void setStreamingParams(VideoStreamingParameters streamingParams) {
* NOTE: Must call init() without error before calling this method.
* Prepares the encoder and virtual display.
*/
public void start() throws Exception {
public void start() {
if (!initPassed) {
Log.e(TAG, "VirtualDisplayEncoder was not properly initialized with the init() method.");
return;
@@ -141,6 +168,10 @@ public void start() throws Exception {

startEncoder();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startRefreshTask();
}

} catch (Exception ex) {
Log.e(TAG, "Unable to create Virtual Display.");
throw new RuntimeException(ex);
@@ -153,30 +184,52 @@ public void shutDown() {
Log.e(TAG, "VirtualDisplayEncoder was not properly initialized with the init() method.");
return;
}

Log.i(TAG, "SHUTDOWN CALLED");

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
stopRefreshTask();
}

try {
if (encoderThread != null) {
encoderThread.interrupt();
encoderThread = null;
}
} catch (Exception ex) {
Log.e(TAG, "interrupting encoderThread failed");
}

try {
if (mVideoEncoder != null) {
mVideoEncoder.flush();
mVideoEncoder.stop();
mVideoEncoder.release();
mVideoEncoder = null;
}
} catch (Exception ex) {
Log.e(TAG, "stopping mVideoEncoder failed");
}

try {
if (virtualDisplay != null) {
virtualDisplay.release();
virtualDisplay = null;
}
} catch (Exception ex) {
Log.e(TAG, "interrupting virtualDisplay failed");
}

try {
if (inputSurface != null) {
inputSurface.release();
inputSurface = null;
}
} catch (Exception ex) {
Log.e(TAG, "shutDown() failed");
Log.e(TAG, "interrupting inputSurface failed");
}

Log.i(TAG, "SHUTDOWN FINISHED");
}

private Surface prepareVideoEncoder() {
@@ -220,9 +273,9 @@ public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.Buff
ByteBuffer encodedData = codec.getOutputBuffer(index);
if (encodedData != null) {
if (info.size != 0) {
byte[] dataToWrite;// = new byte[info.size];
int dataOffset = 0;

byte[] dataToWrite;
mVideoBufferInfo = info;
// append SPS and PPS in front of every IDR NAL unit
if ((info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0 && mH264CodecSpecificData != null) {
dataToWrite = new byte[mH264CodecSpecificData.length + info.size];
@@ -238,11 +291,12 @@ public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.Buff
encodedData.get(dataToWrite, dataOffset, info.size);
if (mOutputListener != null) {
mOutputListener.sendFrame(dataToWrite, 0, dataToWrite.length, info.presentationTimeUs);
mLastEmittedFrameTimestamp = System.currentTimeMillis();
}
}

codec.releaseOutputBuffer(index, false);
}

} catch (Exception ex) {
ex.printStackTrace();
}
Original file line number Diff line number Diff line change
@@ -7073,7 +7073,9 @@ private class VideoStreamingManager implements ISdlServiceListener{
public VideoStreamingManager(Context context,ISdl iSdl){
this.context = context;
this.internalInterface = iSdl;
encoder = new VirtualDisplayEncoder();
if (encoder == null) {
encoder = new VirtualDisplayEncoder();
}
internalInterface.addServiceListener(SessionType.NAV,this);
//Take care of the touch events
internalInterface.addOnRPCNotificationListener(FunctionID.ON_TOUCH_EVENT, new OnRPCNotificationListener() {
Original file line number Diff line number Diff line change
@@ -58,7 +58,6 @@
@TargetApi(17)
public abstract class SdlRemoteDisplay extends Presentation {
private static final String TAG = "SdlRemoteDisplay";
private static final int REFRESH_RATE_MS = 50;

protected Window w;
protected View mainView;
@@ -78,32 +77,15 @@ protected void onCreate(Bundle savedInstanceState) {

w = getWindow();

startRefreshTask();
getMainView();

w.setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
}

protected void startRefreshTask() {
handler.postDelayed(mStartRefreshTaskCallback, REFRESH_RATE_MS);
}
if (mainView != null) {
mainView.invalidate();
}

protected void stopRefreshTask() {
handler.removeCallbacks(mStartRefreshTaskCallback);
w.setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
}

protected Runnable mStartRefreshTaskCallback = new Runnable() {
public void run() {
if(mainView == null){
mainView = w.getDecorView().findViewById(android.R.id.content);
}
if (mainView != null) {
mainView.invalidate();
}

handler.postDelayed(this, REFRESH_RATE_MS);
}
};

@SuppressWarnings("unused")
public View getMainView(){
if(mainView == null){
@@ -130,11 +112,11 @@ public void run() {
}

public void stop(){
stopRefreshTask();
dismissPresentation();
}

public void dismissPresentation() {
Log.i(TAG, "DISMISS PRESENTATION CALLED");
uiHandler.post(new Runnable() {
@Override
public void run() {
@@ -186,6 +168,7 @@ public void run() {
}

try {
Log.i(TAG, "CALLING REMOTE DISPLAY SHOW");
remoteDisplay.show();
remoteDisplay.callback = callback;
if(callback!=null){