Skip to content
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

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

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Expand Up @@ -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;
Expand All @@ -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()
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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() {
Expand Down Expand Up @@ -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];
Expand All @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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){
Expand All @@ -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() {
Expand Down Expand Up @@ -186,6 +168,7 @@ public void run() {
}

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