MediaSource.java revision a3bfbe5389c6146abe318a7add3fa688d69bc01b
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.FilterContext;
244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Frame;
254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FrameFormat;
264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.FrameManager;
2721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GenerateFieldPort;
2821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GenerateFinalPort;
2921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GLFrame;
304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.KeyValueMap;
314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.MutableFrameFormat;
324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.NativeFrame;
334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.Program;
344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.filterfw.core.ShaderProgram;
3521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.format.ImageFormat;
364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.graphics.SurfaceTexture;
374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.media.MediaPlayer;
384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.os.ConditionVariable;
394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.IOException;
414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.FileDescriptor;
424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.lang.IllegalArgumentException;
434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.List;
444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.Set;
454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.util.Log;
484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
49a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/**
50a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide
51a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */
524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalapublic class MediaSource extends Filter {
534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** User-visible parameters */
554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** The source URL for the media source. Can be an http: link to a remote
574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * resource, or a file: link to a local media file */
5821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFieldPort(name = "sourceUrl", hasDefault = true)
594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private String mSourceUrl = "";
604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** An open asset file descriptor to a local media source. If set,
624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * overrides the sourceUrl field. Set to null to use the sourceUrl field
634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * instead. */
6421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFieldPort(name = "sourceAsset", hasDefault = true)
654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private AssetFileDescriptor mSourceAsset;
664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Whether the filter will always wait for a new video frame, or whether it
684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     * will output an old frame again if a new frame isn't available. Defaults to true.
694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     */
7021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFinalPort(name = "waitForNewFrame", hasDefault = true)
714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mWaitForNewFrame = true;
724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Whether the media source should loop automatically or not. Defaults to true. */
7421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFieldPort(name = "loop", hasDefault = true)
754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mLooping = true;
764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer mMediaPlayer;
784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private GLFrame mMediaFrame;
794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private SurfaceTexture mSurfaceTexture;
804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private ShaderProgram mFrameExtractor;
814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MutableFrameFormat mOutputFormat;
824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private ConditionVariable mNewFrameAvailable;
834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private float[] mFrameTransform;
844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private final String mFrameShader =
864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "#extension GL_OES_EGL_image_external : require\n" +
874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "precision mediump float;\n" +
884a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "uniform mat4 frame_transform;\n" +
894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "uniform samplerExternalOES tex_sampler_0;\n" +
904a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "varying vec2 v_texcoord;\n" +
914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "void main() {\n" +
924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "  vec2 transformed_texcoord = (frame_transform * vec4(v_texcoord, 0., 1.) ).xy;" +
934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "  gl_FragColor = texture2D(tex_sampler_0, transformed_texcoord);\n" +
944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "}\n";
954a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mGotSize;
974a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mPrepared;
984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mPlaying;
991df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    private boolean mPaused;
1004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final boolean LOGV = true;
1024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final boolean LOGVV = false;
1034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final String TAG = "MediaSource";
1044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public MediaSource(String name) {
1064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        super(name);
1074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mNewFrameAvailable = new ConditionVariable();
1084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameTransform = new float[16];
1094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
11221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void setupPorts() {
11321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Add input port
11421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
11521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                                  FrameFormat.TARGET_GPU));
1164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
11821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private void createFormats() {
11921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mOutputFormat = ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
12021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                           FrameFormat.TARGET_GPU);
1214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    protected void prepare(FilterContext context) {
1254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "Preparing MediaSource");
1264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor = new ShaderProgram(mFrameShader);
1284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // SurfaceTexture defines (0,0) to be bottom-left. The filter framework
1294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // defines (0,0) as top-left, so do the flip here.
1304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor.setSourceRect(0, 1, 1, -1);
1314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
13221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        createFormats();
13321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
134edfc0941e7a9480d2bbc70e842015e6fa56a2c3fEddy Talvala        mMediaFrame = (GLFrame)context.getFrameManager().newBoundFrame(mOutputFormat,
135edfc0941e7a9480d2bbc70e842015e6fa56a2c3fEddy Talvala                                                                       GLFrame.EXTERNAL_TEXTURE,
136edfc0941e7a9480d2bbc70e842015e6fa56a2c3fEddy Talvala                                                                       0);
1374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId());
1384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
14121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void open(FilterContext context) {
1424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "Opening MediaSource");
14321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (!setupMediaPlayer()) {
14421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            throw new RuntimeException("Error setting up MediaPlayer!");
14521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
1464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
14921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void process(FilterContext context) {
1506aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        // Note: process is synchronized by its caller in the Filter base class
1514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGVV) Log.v(TAG, "Processing new frame");
1524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer == null) {
1544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Something went wrong in initialization or parameter updates
15521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            throw new NullPointerException("Unexpected null media player!");
1564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
1574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (!mPlaying) {
1596aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            int waitCount = 0;
1606aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            while (!mGotSize || !mPrepared) {
1616aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                try {
16221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                        this.wait(100);
1636aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                } catch (InterruptedException e) {
1646aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                    // ignoring
1656aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                }
1666aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                waitCount++;
1676aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                if (waitCount == 50) {
1686aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                    mMediaPlayer.release();
16921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    throw new RuntimeException("MediaPlayer timed out while preparing!");
1704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
1714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
1724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.start();
1734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
1744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1751df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // Use last frame if paused, unless just starting playback, in which case
1761df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // we want at least one valid frame before pausing
1771df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        if (!mPaused || !mPlaying) {
1781df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            if (mWaitForNewFrame) {
1791df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                boolean gotNewFrame;
1801df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                gotNewFrame = mNewFrameAvailable.block(1000);
1811df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                if (!gotNewFrame) {
18221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    throw new RuntimeException("Timeout waiting for new frame!");
1831df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                }
1841df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                mNewFrameAvailable.close();
1854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
1864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1871df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mSurfaceTexture.updateTexImage();
1884a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1891df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mSurfaceTexture.getTransformMatrix(mFrameTransform);
1901df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mFrameExtractor.setHostValue("frame_transform", mFrameTransform);
1911df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        }
1924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        Frame output = context.getFrameManager().newFrame(mOutputFormat);
1944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor.process(mMediaFrame, output);
1954a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
19621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        pushOutput("video", output);
1974a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        output.release();
1984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1991df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mPlaying = true;
2004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
2034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void close(FilterContext context) {
2044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer.isPlaying()) {
2054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.stop();
2064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.release();
2084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer = null;
2094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "MediaSource closed");
2104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
2134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void tearDown(FilterContext context) {
2144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaFrame != null) {
2154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaFrame.release();
2164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
22021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void fieldPortValueUpdated(String name, FilterContext context) {
22121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (name.equals("sourceUrl") && mSourceAsset == null) {
2224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
2234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (LOGV) Log.v(TAG, "Opening new source URL");
2244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                setupMediaPlayer();
2254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
22621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        } else if (name.equals("sourceAsset") ) {
2274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
2284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (LOGV) {
2294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    if (mSourceAsset == null) {
2304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        if (LOGV) Log.v(TAG, "Opening new source URL");
2314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    } else {
2324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                        Log.v(TAG, "Opening new source FD");
2334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    }
2344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
2354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                setupMediaPlayer();
2364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
23721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        } else if (name.equals("loop")) {
2384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
23921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                mMediaPlayer.setLooping(mLooping);
2404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2441df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    synchronized public void pauseVideo(boolean pauseState) {
2456aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        if (isOpen()) {
2466aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            if (pauseState && !mPaused) {
2476aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                mMediaPlayer.pause();
2486aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            } else if (!pauseState && mPaused) {
2496aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                mMediaPlayer.start();
2506aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            }
2516aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        }
2521df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mPaused = pauseState;
2531df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    }
2541df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala
2554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Creates a media player, sets it up, and calls prepare */
25621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    synchronized private boolean setupMediaPlayer() {
2574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mPrepared = false;
2584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mGotSize = false;
2594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mPlaying = false;
2606aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        mPaused = false;
2614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer != null) {
2634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Clean up existing media player
2644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.reset();
2654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } else {
2664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Create new media player
2674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = new MediaPlayer();
2684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer == null) {
2714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            Log.e(TAG, "Unable to create a media player!");
27221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            return false;
2734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2754a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Set up data sources, etc
2764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        try {
2774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (mSourceAsset == null) {
2784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setDataSource(mSourceUrl);
2794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
2804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength());
2814a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } catch(IOException e) {
2834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (mSourceAsset == null) {
2844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceUrl + ". Exception: " + e);
2854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
2864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceAsset + ". Exception: " + e);
2874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2884a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.release();
2894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = null;
29021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            return false;
2914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } catch(IllegalArgumentException e) {
2924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (mSourceAsset == null) {
2934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceUrl + ". Exception: " + e);
2944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
2954a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                Log.e(TAG, "Unable to set media player source to " + mSourceAsset + ". Exception: " + e);
2964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2974a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.release();
2984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = null;
29921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            return false;
3004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setLooping(mLooping);
3034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Bind it to our media frame
3054a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setTexture(mSurfaceTexture);
3064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Connect Media Player to callbacks
3084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener);
3104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnPreparedListener(onPreparedListener);
3114a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnCompletionListener(onCompletionListener);
3124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3134a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Connect SurfaceTexture to callback
3144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mSurfaceTexture.setOnFrameAvailableListener(onMediaFrameAvailableListener);
3154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.prepareAsync();
3174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (LOGV) Log.v(TAG, "MediaPlayer now preparing.");
31921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return true;
3204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
3214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener =
3234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnVideoSizeChangedListener() {
3244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
3254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGV) Log.v(TAG, "MediaPlayer sent dimensions: " + width + " x " + height);
3264a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (!mGotSize) {
3274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mOutputFormat.setDimensions(width, height);
3284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
3294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (mOutputFormat.getWidth() != width ||
3304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    mOutputFormat.getHeight() != height) {
3314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    Log.e(TAG, "Multiple video size change events received!");
3324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
3334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            synchronized(this) {
3354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mGotSize = true;
3364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                this.notify();
3374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3394a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnPreparedListener onPreparedListener =
3424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnPreparedListener() {
3434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onPrepared(MediaPlayer mp) {
3444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGV) Log.v(TAG, "MediaPlayer is prepared");
3454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            synchronized(this) {
3464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mPrepared = true;
3474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                this.notify();
3484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnCompletionListener onCompletionListener =
3534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnCompletionListener() {
3544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onCompletion(MediaPlayer mp) {
3554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGV) Log.v(TAG, "MediaPlayer has completed playback");
3564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private SurfaceTexture.OnFrameAvailableListener onMediaFrameAvailableListener =
3604a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new SurfaceTexture.OnFrameAvailableListener() {
3614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
3624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (LOGVV) Log.v(TAG, "New frame from media player");
3634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mNewFrameAvailable.open();
3644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
3664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala}
368