18f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown/* 28f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Copyright (C) 2013 The Android Open Source Project 38f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 48f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 58f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * you may not use this file except in compliance with the License. 68f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * You may obtain a copy of the License at 78f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 88f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 98f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Unless required by applicable law or agreed to in writing, software 118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * See the License for the specific language governing permissions and 148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * limitations under the License. 158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpackage com.android.accessorydisplay.source; 188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport com.android.accessorydisplay.common.Protocol; 208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport com.android.accessorydisplay.common.Service; 218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport com.android.accessorydisplay.common.Transport; 228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.content.Context; 248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.display.DisplayManager; 258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.hardware.display.VirtualDisplay; 268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaCodec; 278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaCodec.BufferInfo; 288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaCodecInfo; 298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.media.MediaFormat; 308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.os.Handler; 318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.os.Message; 328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.Display; 338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.view.Surface; 348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3583511d2f49c9e272f328730586c3d0a7852247f2Andy Hungimport java.io.IOException; 368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.nio.ByteBuffer; 378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpublic class DisplaySourceService extends Service { 398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int MSG_DISPATCH_DISPLAY_ADDED = 1; 408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int MSG_DISPATCH_DISPLAY_REMOVED = 2; 418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final String DISPLAY_NAME = "Accessory Display"; 438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int BIT_RATE = 6000000; 448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int FRAME_RATE = 30; 458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int I_FRAME_INTERVAL = 10; 468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final Callbacks mCallbacks; 488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final ServiceHandler mHandler; 498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final DisplayManager mDisplayManager; 508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private boolean mSinkAvailable; 528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private int mSinkWidth; 538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private int mSinkHeight; 548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private int mSinkDensityDpi; 558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private VirtualDisplayThread mVirtualDisplayThread; 578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public DisplaySourceService(Context context, Transport transport, Callbacks callbacks) { 598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super(context, transport, Protocol.DisplaySourceService.ID); 608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mCallbacks = callbacks; 618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHandler = new ServiceHandler(); 628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); 638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void start() { 678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super.start(); 688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Sending MSG_QUERY."); 708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getTransport().sendMessage(Protocol.DisplaySinkService.ID, 718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Protocol.DisplaySinkService.MSG_QUERY, null); 728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void stop() { 768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super.stop(); 778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown handleSinkNotAvailable(); 798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onMessageReceived(int service, int what, ByteBuffer content) { 838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown switch (what) { 848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case Protocol.DisplaySourceService.MSG_SINK_AVAILABLE: { 858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Received MSG_SINK_AVAILABLE"); 868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (content.remaining() >= 12) { 878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int width = content.getInt(); 888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int height = content.getInt(); 898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int densityDpi = content.getInt(); 908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (width >= 0 && width <= 4096 918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown && height >= 0 && height <= 4096 928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown && densityDpi >= 60 && densityDpi <= 640) { 938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown handleSinkAvailable(width, height, densityDpi); 948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Receive invalid MSG_SINK_AVAILABLE message."); 988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case Protocol.DisplaySourceService.MSG_SINK_NOT_AVAILABLE: { 1028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Received MSG_SINK_NOT_AVAILABLE"); 1038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown handleSinkNotAvailable(); 1048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 1058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void handleSinkAvailable(int width, int height, int densityDpi) { 1108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mSinkAvailable && mSinkWidth == width && mSinkHeight == height 1118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown && mSinkDensityDpi == densityDpi) { 1128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return; 1138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Accessory display sink available: " 1168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown + "width=" + width + ", height=" + height 1178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown + ", densityDpi=" + densityDpi); 1188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkAvailable = true; 1198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkWidth = width; 1208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkHeight = height; 1218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkDensityDpi = densityDpi; 1228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown createVirtualDisplay(); 1238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void handleSinkNotAvailable() { 1268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Accessory display sink not available."); 1278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkAvailable = false; 1298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkWidth = 0; 1308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkHeight = 0; 1318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkDensityDpi = 0; 1328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown releaseVirtualDisplay(); 1338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void createVirtualDisplay() { 1368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown releaseVirtualDisplay(); 1378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mVirtualDisplayThread = new VirtualDisplayThread( 1398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mSinkWidth, mSinkHeight, mSinkDensityDpi); 1408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mVirtualDisplayThread.start(); 1418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void releaseVirtualDisplay() { 1448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mVirtualDisplayThread != null) { 1458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mVirtualDisplayThread.quit(); 1468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mVirtualDisplayThread = null; 1478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public interface Callbacks { 1518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onDisplayAdded(Display display); 1528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onDisplayRemoved(Display display); 1538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final class ServiceHandler extends Handler { 1568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 1578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void handleMessage(Message msg) { 1588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown switch (msg.what) { 1598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case MSG_DISPATCH_DISPLAY_ADDED: { 1608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mCallbacks.onDisplayAdded((Display)msg.obj); 1618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 1628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown case MSG_DISPATCH_DISPLAY_REMOVED: { 1658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mCallbacks.onDisplayRemoved((Display)msg.obj); 1668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 1678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final class VirtualDisplayThread extends Thread { 1738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int TIMEOUT_USEC = 1000000; 1748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final int mWidth; 1768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final int mHeight; 1778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final int mDensityDpi; 1788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private volatile boolean mQuitting; 1808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public VirtualDisplayThread(int width, int height, int densityDpi) { 1828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mWidth = width; 1838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHeight = height; 1848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mDensityDpi = densityDpi; 1858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 1888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void run() { 1898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown MediaFormat format = MediaFormat.createVideoFormat("video/avc", mWidth, mHeight); 1908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 1918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); 1928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); 1938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); 1948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL); 19583511d2f49c9e272f328730586c3d0a7852247f2Andy Hung MediaCodec codec; 19683511d2f49c9e272f328730586c3d0a7852247f2Andy Hung try { 19783511d2f49c9e272f328730586c3d0a7852247f2Andy Hung codec = MediaCodec.createEncoderByType("video/avc"); 19883511d2f49c9e272f328730586c3d0a7852247f2Andy Hung } catch (IOException e) { 19983511d2f49c9e272f328730586c3d0a7852247f2Andy Hung throw new RuntimeException( 20083511d2f49c9e272f328730586c3d0a7852247f2Andy Hung "failed to create video/avc encoder", e); 20183511d2f49c9e272f328730586c3d0a7852247f2Andy Hung } 2028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 2038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Surface surface = codec.createInputSurface(); 2048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown codec.start(); 2058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2067d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay( 2077d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown DISPLAY_NAME, mWidth, mHeight, mDensityDpi, surface, 0); 2088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (virtualDisplay != null) { 2098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHandler.obtainMessage(MSG_DISPATCH_DISPLAY_ADDED, 2108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown virtualDisplay.getDisplay()).sendToTarget(); 2118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown stream(codec); 2138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHandler.obtainMessage(MSG_DISPATCH_DISPLAY_REMOVED, 2158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown virtualDisplay.getDisplay()).sendToTarget(); 2168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown virtualDisplay.release(); 2178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown codec.signalEndOfInputStream(); 2208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown codec.stop(); 2218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void quit() { 2248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mQuitting = true; 2258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void stream(MediaCodec codec) { 2288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown BufferInfo info = new BufferInfo(); 2298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ByteBuffer[] buffers = null; 2308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown while (!mQuitting) { 2318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int index = codec.dequeueOutputBuffer(info, TIMEOUT_USEC); 2328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (index >= 0) { 2338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (buffers == null) { 2348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffers = codec.getOutputBuffers(); 2358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ByteBuffer buffer = buffers[index]; 2388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.limit(info.offset + info.size); 2398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.position(info.offset); 2408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getTransport().sendMessage(Protocol.DisplaySinkService.ID, 2428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown Protocol.DisplaySinkService.MSG_CONTENT, buffer); 2438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown codec.releaseOutputBuffer(index, false); 2448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 2458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffers = null; 2468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { 2478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown getLogger().log("Codec dequeue buffer timed out."); 2488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown} 253