From 419df42dbeba6792538eabc8c4062edf3889f7c8 Mon Sep 17 00:00:00 2001 From: BrettyWhite Date: Thu, 6 Sep 2018 10:27:27 -0400 Subject: remove handler from sdlremote display and put it into the virtual display encoder. --- .../encoder/VirtualDisplayEncoder.java | 64 ++++++++++++++++++++-- .../com/smartdevicelink/proxy/SdlProxyBase.java | 4 +- .../streaming/video/SdlRemoteDisplay.java | 31 +++-------- 3 files changed, 69 insertions(+), 30 deletions(-) diff --git a/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java b/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java index 0fe303c71..d4bf6cd63 100644 --- a/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java +++ b/sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java @@ -40,6 +40,8 @@ import android.media.MediaCodec; 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,6 +67,9 @@ 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; @@ -72,6 +77,28 @@ public class VirtualDisplayEncoder { //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 class VirtualDisplayEncoder { * 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 class VirtualDisplayEncoder { 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 class VirtualDisplayEncoder { 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 class VirtualDisplayEncoder { 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 class VirtualDisplayEncoder { 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(); } diff --git a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java index f8fb1f353..60fc1ac5e 100644 --- a/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java +++ b/sdl_android/src/main/java/com/smartdevicelink/proxy/SdlProxyBase.java @@ -7073,7 +7073,9 @@ public abstract class SdlProxyBase 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() { diff --git a/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java b/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java index 8af6b1c59..fde4cf10d 100644 --- a/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java +++ b/sdl_android/src/main/java/com/smartdevicelink/streaming/video/SdlRemoteDisplay.java @@ -58,7 +58,6 @@ import java.util.concurrent.Callable; @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 @@ public abstract class SdlRemoteDisplay extends Presentation { 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 abstract class SdlRemoteDisplay extends Presentation { } 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 abstract class SdlRemoteDisplay extends Presentation { } try { + Log.i(TAG, "CALLING REMOTE DISPLAY SHOW"); remoteDisplay.show(); remoteDisplay.callback = callback; if(callback!=null){ -- cgit v1.2.1