diff options
Diffstat (limited to 'sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java')
-rw-r--r-- | sdl_android/src/main/java/com/smartdevicelink/encoder/VirtualDisplayEncoder.java | 64 |
1 files changed, 59 insertions, 5 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(); } |