MediaSource.java revision 1df612099dde7e43249468d46e5b8064d8c33b77
14a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala/*
24a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * Copyright (C) 2011 The Android Open Source Project
34a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala *
44a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License");
54a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * you may not use this file except in compliance with the License.
64a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * You may obtain a copy of the License at
74a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala *
84a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala *      http://www.apache.org/licenses/LICENSE-2.0
94a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala *
104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * Unless required by applicable law or agreed to in writing, software
114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS,
124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * See the License for the specific language governing permissions and
144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala * limitations under the License.
154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala */
164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalapackage android.filterpacks.videosrc;
194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.content.Context;
214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.content.res.AssetFileDescriptor;
224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Filter;
234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FilterParameter;
244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FilterContext;
254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Frame;
264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.GLFrame;
274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FrameFormat;
284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FrameManager;
294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.KeyValueMap;
304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.MutableFrameFormat;
314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.NativeFrame;
324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Program;
334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.ShaderProgram;
344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.graphics.SurfaceTexture;
354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.media.MediaPlayer;
364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.os.ConditionVariable;
374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.IOException;
394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.FileDescriptor;
404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.lang.IllegalArgumentException;
414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.List;
424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.Set;
434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.util.Log;
464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalapublic class MediaSource extends Filter {
484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** User-visible parameters */
504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** The source URL for the media source. Can be an http: link to a remote
524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * resource, or a file: link to a local media file */
534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @FilterParameter(name = "sourceUrl", isOptional = true, isUpdatable = true)
544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private String mSourceUrl = "";
554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** An open asset file descriptor to a local media source. If set,
574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * overrides the sourceUrl field. Set to null to use the sourceUrl field
584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * instead. */
594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @FilterParameter(name = "sourceAsset", isOptional = true, isUpdatable = true)
604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private AssetFileDescriptor mSourceAsset;
614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Whether the filter will always wait for a new video frame, or whether it
634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * will output an old frame again if a new frame isn't available. Defaults to true.
644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     */
654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @FilterParameter(name = "waitForNewFrame", isOptional = true, isUpdatable = true)
664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mWaitForNewFrame = true;
674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Whether the media source should loop automatically or not. Defaults to true. */
694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @FilterParameter(name = "loop", isOptional = true, isUpdatable = true)
704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mLooping = true;
714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer mMediaPlayer;
734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private GLFrame mMediaFrame;
744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private SurfaceTexture mSurfaceTexture;
754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private ShaderProgram mFrameExtractor;
764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MutableFrameFormat mOutputFormat;
774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MutableFrameFormat mMediaFormat;
784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private ConditionVariable mNewFrameAvailable;
794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private float[] mFrameTransform;
804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private final String mFrameShader =
824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "#extension GL_OES_EGL_image_external : require\n" +
834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "precision mediump float;\n" +
844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "uniform mat4 frame_transform;\n" +
854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "uniform samplerExternalOES tex_sampler_0;\n" +
864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "varying vec2 v_texcoord;\n" +
874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "void main() {\n" +
884a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "  vec2 transformed_texcoord = (frame_transform * vec4(v_texcoord, 0., 1.) ).xy;" +
894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "  gl_FragColor = texture2D(tex_sampler_0, transformed_texcoord);\n" +
904a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "}\n";
914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mGotSize;
934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mPrepared;
944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mPlaying;
951df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    private boolean mPaused;
964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
974a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final boolean LOGV = true;
984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final boolean LOGVV = false;
994a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final String TAG = "MediaSource";
1004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public MediaSource(String name) {
1024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        super(name);
1034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mNewFrameAvailable = new ConditionVariable();
1044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameTransform = new float[16];
1054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public String[] getInputNames() {
1094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return null;
1104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public String[] getOutputNames() {
1144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return new String[] { "video" };
1154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public boolean acceptsInputFormat(int index, FrameFormat format) {
1194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return false;
1204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public FrameFormat getOutputFormat(int index) {
1244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Format matches that of a GLFrame, but don't want to access an OpenGL
1254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // context yet
1264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mOutputFormat = new MutableFrameFormat(FrameFormat.TYPE_BYTE,
1274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                                               FrameFormat.TARGET_GPU);
1284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mOutputFormat.setBytesPerSample(4);
1291df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // Don't know dimensions until we open the media file
1301df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mOutputFormat.setDimensions(0, 0);
1314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaFormat = mOutputFormat.mutableCopy();
1334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaFormat.setMetaValue(GLFrame.USE_EXTERNAL_TEXTURE, true);
1344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return mOutputFormat;
1364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    protected void prepare(FilterContext context) {
1404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "Preparing MediaSource");
1414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaFrame = (GLFrame)context.getFrameManager().newFrame(mMediaFormat);
1434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor = new ShaderProgram(mFrameShader);
1454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // SurfaceTexture defines (0,0) to be bottom-left. The filter framework
1464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // defines (0,0) as top-left, so do the flip here.
1474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor.setSourceRect(0, 1, 1, -1);
1484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId());
1504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public int open(FilterContext context) {
1544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "Opening MediaSource");
1554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return setupMediaPlayer();
1564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public int process(FilterContext context) {
1604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGVV) Log.v(TAG, "Processing new frame");
1614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer == null) {
1634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Something went wrong in initialization or parameter updates
1644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            return Filter.STATUS_ERROR;
1654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
1664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (!mPlaying) {
1684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            synchronized(this) {
1694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                int waitCount = 0;
1704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                while (!mGotSize || !mPrepared) {
1714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    try {
1724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        this.wait(100);
1734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    } catch (InterruptedException e) {
1744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        // ignoring
1754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    }
1764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    waitCount++;
1774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    if (waitCount == 50) {
1784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        Log.e(TAG, "MediaPlayer timed out while preparing");
1794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        mMediaPlayer.release();
1804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        return Filter.STATUS_ERROR;
1814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    }
1824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
1834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
1844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.start();
1854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
1864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1871df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // Use last frame if paused, unless just starting playback, in which case
1881df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // we want at least one valid frame before pausing
1891df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        if (!mPaused || !mPlaying) {
1901df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            if (mWaitForNewFrame) {
1911df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                boolean gotNewFrame;
1921df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                gotNewFrame = mNewFrameAvailable.block(1000);
1931df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                if (!gotNewFrame) {
1941df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                    Log.e(TAG, "Timeout waiting for new frame");
1951df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                    return Filter.STATUS_ERROR;
1961df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                }
1971df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                mNewFrameAvailable.close();
1984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
1994a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2001df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mSurfaceTexture.updateTexImage();
2014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2021df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mSurfaceTexture.getTransformMatrix(mFrameTransform);
2031df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mFrameExtractor.setHostValue("frame_transform", mFrameTransform);
2041df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        }
2054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        Frame output = context.getFrameManager().newFrame(mOutputFormat);
2074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor.process(mMediaFrame, output);
2084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        putOutput(0, output);
2104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        output.release();
2114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2121df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mPlaying = true;
2131df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala
2144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return Filter.STATUS_WAIT_FOR_FREE_OUTPUTS;
2154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
2184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void close(FilterContext context) {
2194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer.isPlaying()) {
2204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.stop();
2214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.release();
2234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer = null;
2244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "MediaSource closed");
2254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
2284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void tearDown(FilterContext context) {
2294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaFrame != null) {
2304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaFrame.release();
2314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
2354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void parametersUpdated(Set<String> updated) {
2364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (updated.contains("sourceUrl") && mSourceAsset == null) {
2374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
2384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (LOGV) Log.v(TAG, "Opening new source URL");
2394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                setupMediaPlayer();
2404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } else if (updated.contains("sourceAsset") ) {
2424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
2434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (LOGV) {
2444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    if (mSourceAsset == null) {
2454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        if (LOGV) Log.v(TAG, "Opening new source URL");
2464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    } else {
2474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        Log.v(TAG, "Opening new source FD");
2484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    }
2494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
2504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                setupMediaPlayer();
2514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } else if (updated.contains("loop")) {
2534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
2544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setLooping(mLooping);
2554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2591df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    synchronized public void pauseVideo(boolean pauseState) {
2601df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mPaused = pauseState;
2611df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    }
2621df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala
2634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Creates a media player, sets it up, and calls prepare */
2644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    synchronized private int setupMediaPlayer() {
2654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mPrepared = false;
2664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mGotSize = false;
2674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mPlaying = false;
2684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer != null) {
2704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Clean up existing media player
2714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.reset();
2724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } else {
2734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Create new media player
2744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = new MediaPlayer();
2754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer == null) {
2784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            Log.e(TAG, "Unable to create a media player!");
2794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            return Filter.STATUS_ERROR;
2804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Set up data sources, etc
2834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        try {
2844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (mSourceAsset == null) {
2854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setDataSource(mSourceUrl);
2864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
2874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength());
2884a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } catch(IOException e) {
2904a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (mSourceAsset == null) {
2914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceUrl + ". Exception: " + e);
2924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
2934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceAsset + ". Exception: " + e);
2944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2954a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.release();
2964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = null;
2974a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            return Filter.STATUS_ERROR;
2984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } catch(IllegalArgumentException e) {
2994a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (mSourceAsset == null) {
3004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceUrl + ". Exception: " + e);
3014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
3024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceAsset + ". Exception: " + e);
3034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.release();
3054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = null;
3064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            return Filter.STATUS_ERROR;
3074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setLooping(mLooping);
3104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Bind it to our media frame
3124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setTexture(mSurfaceTexture);
3134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Connect Media Player to callbacks
3154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener);
3174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnPreparedListener(onPreparedListener);
3184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnCompletionListener(onCompletionListener);
3194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Connect SurfaceTexture to callback
3214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mSurfaceTexture.setOnFrameAvailableListener(onMediaFrameAvailableListener);
3224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.prepareAsync();
3244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "MediaPlayer now preparing.");
3264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        return Filter.STATUS_WAIT_FOR_FREE_OUTPUTS;
3274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
3284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener =
3304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnVideoSizeChangedListener() {
3314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
3324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGV) Log.v(TAG, "MediaPlayer sent dimensions: " + width + " x " + height);
3334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (!mGotSize) {
3344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mOutputFormat.setDimensions(width, height);
3354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
3364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (mOutputFormat.getWidth() != width ||
3374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    mOutputFormat.getHeight() != height) {
3384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    Log.e(TAG, "Multiple video size change events received!");
3394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
3404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            synchronized(this) {
3424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mGotSize = true;
3434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                this.notify();
3444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnPreparedListener onPreparedListener =
3494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnPreparedListener() {
3504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onPrepared(MediaPlayer mp) {
3514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGV) Log.v(TAG, "MediaPlayer is prepared");
3524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            synchronized(this) {
3534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mPrepared = true;
3544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                this.notify();
3554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnCompletionListener onCompletionListener =
3604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnCompletionListener() {
3614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onCompletion(MediaPlayer mp) {
3624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGV) Log.v(TAG, "MediaPlayer has completed playback");
3634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private SurfaceTexture.OnFrameAvailableListener onMediaFrameAvailableListener =
3674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new SurfaceTexture.OnFrameAvailableListener() {
3684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
3694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGVV) Log.v(TAG, "New frame from media player");
3704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mNewFrameAvailable.open();
3714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala}
375