FileDocCategorySizeDatePackage
DisplaySinkService.javaAPI DocAndroid 5.1 API8472Thu Mar 12 22:22:42 GMT 2015com.android.accessorydisplay.sink

DisplaySinkService

public class DisplaySinkService extends com.android.accessorydisplay.common.Service implements SurfaceHolder.Callback

Fields Summary
private final ByteBuffer
mBuffer
private final android.os.Handler
mTransportHandler
private final int
mDensityDpi
private android.view.SurfaceView
mSurfaceView
private final Object
mSurfaceAndCodecLock
private android.view.Surface
mSurface
private int
mSurfaceWidth
private int
mSurfaceHeight
private android.media.MediaCodec
mCodec
private ByteBuffer[]
mCodecInputBuffers
private android.media.MediaCodec.BufferInfo
mCodecBufferInfo
Constructors Summary
public DisplaySinkService(android.content.Context context, com.android.accessorydisplay.common.Transport transport, int densityDpi)


           
        super(context, transport, Protocol.DisplaySinkService.ID);
        mTransportHandler = transport.getHandler();
        mDensityDpi = densityDpi;
    
Methods Summary
private voidconsumeCodecOutputLocked()

        for (;;) {
            final int index = mCodec.dequeueOutputBuffer(mCodecBufferInfo, 0);
            if (index >= 0) {
                mCodec.releaseOutputBuffer(index, true /*render*/);
            } else if (index != MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED
                    && index != MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                break;
            }
        }
    
private voiddecode(java.nio.ByteBuffer content)

        if (content == null) {
            return;
        }
        synchronized (mSurfaceAndCodecLock) {
            if (mCodec == null) {
                return;
            }

            while (content.hasRemaining()) {
                if (!provideCodecInputLocked(content)) {
                    getLogger().log("Dropping content because there are no available buffers.");
                    return;
                }

                consumeCodecOutputLocked();
            }
        }
    
public voidonMessageReceived(int service, int what, java.nio.ByteBuffer content)

        switch (what) {
            case Protocol.DisplaySinkService.MSG_QUERY: {
                getLogger().log("Received MSG_QUERY.");
                sendSinkStatus();
                break;
            }

            case Protocol.DisplaySinkService.MSG_CONTENT: {
                decode(content);
                break;
            }
        }
    
private booleanprovideCodecInputLocked(java.nio.ByteBuffer content)

        final int index = mCodec.dequeueInputBuffer(0);
        if (index < 0) {
            return false;
        }
        if (mCodecInputBuffers == null) {
            mCodecInputBuffers = mCodec.getInputBuffers();
        }
        final ByteBuffer buffer = mCodecInputBuffers[index];
        final int capacity = buffer.capacity();
        buffer.clear();
        if (content.remaining() <= capacity) {
            buffer.put(content);
        } else {
            final int limit = content.limit();
            content.limit(content.position() + capacity);
            buffer.put(content);
            content.limit(limit);
        }
        buffer.flip();
        mCodec.queueInputBuffer(index, 0, buffer.limit(), 0, 0);
        return true;
    
private voidsendSinkStatus()

        synchronized (mSurfaceAndCodecLock) {
            if (mCodec != null) {
                mBuffer.clear();
                mBuffer.putInt(mSurfaceWidth);
                mBuffer.putInt(mSurfaceHeight);
                mBuffer.putInt(mDensityDpi);
                mBuffer.flip();
                getTransport().sendMessage(Protocol.DisplaySourceService.ID,
                        Protocol.DisplaySourceService.MSG_SINK_AVAILABLE, mBuffer);
            } else {
                getTransport().sendMessage(Protocol.DisplaySourceService.ID,
                        Protocol.DisplaySourceService.MSG_SINK_NOT_AVAILABLE, null);
            }
        }
    
public voidsetSurfaceView(android.view.SurfaceView surfaceView)

        if (mSurfaceView != surfaceView) {
            final SurfaceView oldSurfaceView = mSurfaceView;
            mSurfaceView = surfaceView;

            if (oldSurfaceView != null) {
                oldSurfaceView.post(new Runnable() {
                    @Override
                    public void run() {
                        final SurfaceHolder holder = oldSurfaceView.getHolder();
                        holder.removeCallback(DisplaySinkService.this);
                        updateSurfaceFromUi(null);
                    }
                });
            }

            if (surfaceView != null) {
                surfaceView.post(new Runnable() {
                    @Override
                    public void run() {
                        final SurfaceHolder holder = surfaceView.getHolder();
                        holder.addCallback(DisplaySinkService.this);
                        updateSurfaceFromUi(holder);
                    }
                });
            }
        }
    
public voidsurfaceChanged(android.view.SurfaceHolder holder, int format, int width, int height)

        updateSurfaceFromUi(holder);
    
public voidsurfaceCreated(android.view.SurfaceHolder holder)

        // Ignore.  Wait for surface changed event that follows.
    
public voidsurfaceDestroyed(android.view.SurfaceHolder holder)

        updateSurfaceFromUi(null);
    
private voidupdateSurfaceFromUi(android.view.SurfaceHolder holder)

        Surface surface = null;
        int width = 0, height = 0;
        if (holder != null && !holder.isCreating()) {
            surface = holder.getSurface();
            if (surface.isValid()) {
                final Rect frame = holder.getSurfaceFrame();
                width = frame.width();
                height = frame.height();
            } else {
                surface = null;
            }
        }

        synchronized (mSurfaceAndCodecLock) {
            if (mSurface == surface &&  mSurfaceWidth == width && mSurfaceHeight == height) {
                return;
            }

            mSurface = surface;
            mSurfaceWidth = width;
            mSurfaceHeight = height;

            if (mCodec != null) {
                mCodec.stop();
                mCodec = null;
                mCodecInputBuffers = null;
                mCodecBufferInfo = null;
            }

            if (mSurface != null) {
                MediaFormat format = MediaFormat.createVideoFormat(
                        "video/avc", mSurfaceWidth, mSurfaceHeight);
                try {
                    mCodec = MediaCodec.createDecoderByType("video/avc");
                } catch (IOException e) {
                    throw new RuntimeException(
                            "failed to create video/avc decoder", e);
                }
                mCodec.configure(format, mSurface, null, 0);
                mCodec.start();
                mCodecBufferInfo = new BufferInfo();
            }

            mTransportHandler.post(new Runnable() {
                @Override
                public void run() {
                    sendSinkStatus();
                }
            });
        }