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;
39855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvalaimport android.opengl.Matrix;
401ae8bcdf7dc3df7be3ca14b6f63d0009654fab69Jamie Gennisimport android.view.Surface;
414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.IOException;
434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.io.FileDescriptor;
444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.lang.IllegalArgumentException;
454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.List;
464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport java.util.Set;
474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalaimport android.util.Log;
494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
50a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/**
51a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide
52a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */
534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvalapublic class MediaSource extends Filter {
544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** User-visible parameters */
564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** The source URL for the media source. Can be an http: link to a remote
58855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * resource, or a file: link to a local media file
59855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     */
6021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFieldPort(name = "sourceUrl", hasDefault = true)
614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private String mSourceUrl = "";
624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
632dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    /** An open asset file descriptor to a local media source. Default is null */
6421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFieldPort(name = "sourceAsset", hasDefault = true)
659b393be2b4b7e70abe38237ba3eda3dc009d6230Eino-Ville Talvala    private AssetFileDescriptor mSourceAsset = null;
664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
67855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    /** Whether the media source is a URL or an asset file descriptor. Defaults
68855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * to false.
69855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     */
70c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala    @GenerateFieldPort(name = "sourceIsUrl", hasDefault = true)
71c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala    private boolean mSelectedIsUrl = false;
72c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala
734a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Whether the filter will always wait for a new video frame, or whether it
74855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * will output an old frame again if a new frame isn't available. Defaults
75855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * to true.
764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala     */
7721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFinalPort(name = "waitForNewFrame", hasDefault = true)
784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mWaitForNewFrame = true;
794a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
80855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    /** Whether the media source should loop automatically or not. Defaults to
81855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * true.
82855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     */
8321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    @GenerateFieldPort(name = "loop", hasDefault = true)
844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mLooping = true;
854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
86855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    /** Volume control. Currently sound is piped directly to the speakers, so
87855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * this defaults to mute.
88855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     */
89c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala    @GenerateFieldPort(name = "volume", hasDefault = true)
90c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala    private float mVolume = 0.f;
912dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen
92855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    /** Orientation. This controls the output orientation of the video. Valid
93855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     * values are 0, 90, 180, 270
94855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala     */
95855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    @GenerateFieldPort(name = "orientation", hasDefault = true)
96855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    private int mOrientation = 0;
97855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala
984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer mMediaPlayer;
994a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private GLFrame mMediaFrame;
1004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private SurfaceTexture mSurfaceTexture;
1014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private ShaderProgram mFrameExtractor;
1024a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MutableFrameFormat mOutputFormat;
103855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    private int mWidth, mHeight;
1044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
10590397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala    // Total timeouts will be PREP_TIMEOUT*PREP_TIMEOUT_REPEAT
10690397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala    private static final int PREP_TIMEOUT = 100; // ms
107fa2124c46e4e6486465f6b85db7e6780eda46c3bEino-Ville Talvala    private static final int PREP_TIMEOUT_REPEAT = 100;
10890397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala    private static final int NEWFRAME_TIMEOUT = 100; //ms
10990397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala    private static final int NEWFRAME_TIMEOUT_REPEAT = 10;
11090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala
111855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    // This is an identity shader; not using the default identity
112855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    // shader because reading from a SurfaceTexture requires the
113855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    // GL_OES_EGL_image_external extension.
1144a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private final String mFrameShader =
1154a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "#extension GL_OES_EGL_image_external : require\n" +
1164a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "precision mediump float;\n" +
1174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "uniform samplerExternalOES tex_sampler_0;\n" +
1184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "varying vec2 v_texcoord;\n" +
1194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "void main() {\n" +
120855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            "  gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" +
1214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            "}\n";
1224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
123760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // The following transforms enable rotation of the decoded source.
124760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // These are multiplied with the transform obtained from the
125760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // SurfaceTexture to get the final transform to be set on the media source.
126760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // Currently, given a device orientation, the MediaSource rotates in such a way
127760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // that the source is displayed upright. A particular use case
128760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // is "Background Replacement" feature in the Camera app
129760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // where the MediaSource rotates the source to align with the camera feed and pass it
130760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // on to the backdropper filter. The backdropper only does the blending
131760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // and does not have to do any rotation
132760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // (except for mirroring in case of front camera).
133760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // TODO: Currently the rotations are spread over a bunch of stages in the
134760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // pipeline. A cleaner design
135760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // could be to cast away all the rotation in a separate filter or attach a transform
136760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    // to the frame so that MediaSource itself need not know about any rotation.
137855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    private static final float[] mSourceCoords_0 = { 1, 1, 0, 1,
138855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                     0, 1, 0, 1,
139855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                     1, 0, 0, 1,
140855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                     0, 0, 0, 1 };
141760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    private static final float[] mSourceCoords_270 = { 0, 1, 0, 1,
142855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                      0, 0, 0, 1,
143855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                      1, 1, 0, 1,
144855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                      1, 0, 0, 1 };
145855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    private static final float[] mSourceCoords_180 = { 0, 0, 0, 1,
146855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                       1, 0, 0, 1,
147855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                       0, 1, 0, 1,
148855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                       1, 1, 0, 1 };
149760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi    private static final float[] mSourceCoords_90 = { 1, 0, 0, 1,
150855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                       1, 1, 0, 1,
151855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                       0, 0, 0, 1,
152855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                                       0, 1, 0, 1 };
153855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala
1544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mGotSize;
1554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mPrepared;
1564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private boolean mPlaying;
15790397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala    private boolean mNewFrameAvailable;
158855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala    private boolean mOrientationUpdated;
1591df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    private boolean mPaused;
160c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala    private boolean mCompleted;
1614a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1628dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala    private final boolean mLogVerbose;
1634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private static final String TAG = "MediaSource";
1644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public MediaSource(String name) {
1664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        super(name);
16790397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala        mNewFrameAvailable = false;
1688dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala
1698dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
1704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
17321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void setupPorts() {
17421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Add input port
17521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
17621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                                  FrameFormat.TARGET_GPU));
1774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
17921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private void createFormats() {
18021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mOutputFormat = ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
18121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                           FrameFormat.TARGET_GPU);
1824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
1854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    protected void prepare(FilterContext context) {
1868dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Preparing MediaSource");
1874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
188511360e61650864ea22a171159efe073c80d0cdbMarius Renn        mFrameExtractor = new ShaderProgram(context, mFrameShader);
1894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // SurfaceTexture defines (0,0) to be bottom-left. The filter framework
1904a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // defines (0,0) as top-left, so do the flip here.
1914a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor.setSourceRect(0, 1, 1, -1);
1924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
19321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        createFormats();
1944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
1954a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
1964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
19721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void open(FilterContext context) {
1982dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen        if (mLogVerbose) {
1991cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala            Log.v(TAG, "Opening MediaSource");
2001cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala            if (mSelectedIsUrl) {
2011cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala                Log.v(TAG, "Current URL is " + mSourceUrl);
2021cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala            } else {
2031cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala                Log.v(TAG, "Current source is Asset!");
2041cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala            }
2052dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen        }
2061cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala
2071cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala        mMediaFrame = (GLFrame)context.getFrameManager().newBoundFrame(
2081cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala                mOutputFormat,
2091cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala                GLFrame.EXTERNAL_TEXTURE,
2101cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala                0);
2111cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala
2121cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala        mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId());
2131cfcfd55f22577bbc70cddb6137c286b8d3c8491Eino-Ville Talvala
2142dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen        if (!setupMediaPlayer(mSelectedIsUrl)) {
2152dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen          throw new RuntimeException("Error setting up MediaPlayer!");
21621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
2174a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
2184a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
22021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void process(FilterContext context) {
2216aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        // Note: process is synchronized by its caller in the Filter base class
2228dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Processing new frame");
2234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer == null) {
2254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Something went wrong in initialization or parameter updates
22621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            throw new NullPointerException("Unexpected null media player!");
2274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2284a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
229c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        if (mCompleted) {
230c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            // Video playback is done, so close us down
231c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            closeOutputPort("video");
232c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            return;
233c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        }
234c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala
2354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (!mPlaying) {
2366aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            int waitCount = 0;
23790397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Waiting for preparation to complete");
2386aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            while (!mGotSize || !mPrepared) {
2396aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                try {
24090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                    this.wait(PREP_TIMEOUT);
2416aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                } catch (InterruptedException e) {
2426aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                    // ignoring
2436aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                }
244c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                if (mCompleted) {
245c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                    // Video playback is done, so close us down
246c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                    closeOutputPort("video");
247c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                    return;
248c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                }
2496aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                waitCount++;
25090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                if (waitCount == PREP_TIMEOUT_REPEAT) {
2516aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                    mMediaPlayer.release();
25221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    throw new RuntimeException("MediaPlayer timed out while preparing!");
2534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
2544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
25590397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Starting playback");
2564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.start();
2574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
2584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2591df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // Use last frame if paused, unless just starting playback, in which case
2601df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        // we want at least one valid frame before pausing
2611df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        if (!mPaused || !mPlaying) {
2621df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            if (mWaitForNewFrame) {
26390397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Waiting for new frame");
26490397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala
26590397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                int waitCount = 0;
26690397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                while (!mNewFrameAvailable) {
26790397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                    if (waitCount == NEWFRAME_TIMEOUT_REPEAT) {
26890397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                        if (mCompleted) {
26990397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                            // Video playback is done, so close us down
27090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                            closeOutputPort("video");
27190397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                            return;
27290397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                        } else {
27390397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                            throw new RuntimeException("Timeout waiting for new frame!");
27490397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                        }
27590397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                    }
27690397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                    try {
27790397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                        this.wait(NEWFRAME_TIMEOUT);
27890397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                    } catch (InterruptedException e) {
27990397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                        if (mLogVerbose) Log.v(TAG, "interrupted");
28090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                        // ignoring
281c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                    }
28290397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                    waitCount++;
2831df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala                }
28490397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                mNewFrameAvailable = false;
28590397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Got new frame");
2864a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
2874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
2881df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala            mSurfaceTexture.updateTexImage();
289855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            mOrientationUpdated = true;
290855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        }
291855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        if (mOrientationUpdated) {
292855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            float[] surfaceTransform = new float[16];
293855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            mSurfaceTexture.getTransformMatrix(surfaceTransform);
294855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala
295855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            float[] sourceCoords = new float[16];
296855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            switch (mOrientation) {
297855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                default:
298855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                case 0:
299855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    Matrix.multiplyMM(sourceCoords, 0,
300855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      surfaceTransform, 0,
301855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      mSourceCoords_0, 0);
302855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    break;
303855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                case 90:
304855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    Matrix.multiplyMM(sourceCoords, 0,
305855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      surfaceTransform, 0,
306855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      mSourceCoords_90, 0);
307855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    break;
308855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                case 180:
309855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    Matrix.multiplyMM(sourceCoords, 0,
310855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      surfaceTransform, 0,
311855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      mSourceCoords_180, 0);
312855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    break;
313855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                case 270:
314855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    Matrix.multiplyMM(sourceCoords, 0,
315855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      surfaceTransform, 0,
316855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                                      mSourceCoords_270, 0);
317855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    break;
318855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            }
319760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi            if (mLogVerbose) {
320760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi                Log.v(TAG, "OrientationHint = " + mOrientation);
321760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi                String temp = String.format("SetSourceRegion: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f",
322760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi                        sourceCoords[4], sourceCoords[5],sourceCoords[0], sourceCoords[1],
323760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi                        sourceCoords[12], sourceCoords[13],sourceCoords[8], sourceCoords[9]);
324760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi                Log.v(TAG, temp);
325760eb949cf0abe299e6c6710cda5c52364945ae0Pannag Sanketi            }
32653573cd771f2c731d1e7f1fad4df9beba09d237dPannag Sanketi            mFrameExtractor.setSourceRegion(sourceCoords[4], sourceCoords[5],
32753573cd771f2c731d1e7f1fad4df9beba09d237dPannag Sanketi                    sourceCoords[0], sourceCoords[1],
32853573cd771f2c731d1e7f1fad4df9beba09d237dPannag Sanketi                    sourceCoords[12], sourceCoords[13],
32953573cd771f2c731d1e7f1fad4df9beba09d237dPannag Sanketi                    sourceCoords[8], sourceCoords[9]);
330855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            mOrientationUpdated = false;
3311df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        }
3324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        Frame output = context.getFrameManager().newFrame(mOutputFormat);
3344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mFrameExtractor.process(mMediaFrame, output);
3354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3368dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        long timestamp = mSurfaceTexture.getTimestamp();
3378dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Timestamp: " + (timestamp / 1000000000.0) + " s");
3388dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        output.setTimestamp(timestamp);
3398dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala
34021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        pushOutput("video", output);
3414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        output.release();
3424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3431df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mPlaying = true;
3444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
3454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
3474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void close(FilterContext context) {
3484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer.isPlaying()) {
3494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.stop();
3504a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
351855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        mPrepared = false;
352855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        mGotSize = false;
353855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        mPlaying = false;
354855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        mPaused = false;
355855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        mCompleted = false;
356855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        mNewFrameAvailable = false;
357855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala
3584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.release();
3594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer = null;
360aae596d15186de172632499692d44bc5436108f7Eino-Ville Talvala        mSurfaceTexture.release();
361aae596d15186de172632499692d44bc5436108f7Eino-Ville Talvala        mSurfaceTexture = null;
3628dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "MediaSource closed");
3634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
3644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
3664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    public void tearDown(FilterContext context) {
3674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaFrame != null) {
3684a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaFrame.release();
3694a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
3704a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
3714a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
3722dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    // When updating the port values of the filter, users can update sourceIsUrl to switch
3732dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    //   between using URL objects or Assets.
3742dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    // If updating only sourceUrl/sourceAsset, MediaPlayer gets reset if the current player
3752dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    //   uses Url objects/Asset.
3762dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    // Otherwise the new sourceUrl/sourceAsset is stored and will be used when users switch
3772dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    //   sourceIsUrl next time.
3784a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    @Override
37921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void fieldPortValueUpdated(String name, FilterContext context) {
38090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Parameter update");
3812dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen        if (name.equals("sourceUrl")) {
3822dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen           if (isOpen()) {
3838dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Opening new source URL");
3842dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                if (mSelectedIsUrl) {
3852dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                    setupMediaPlayer(mSelectedIsUrl);
3862dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                }
3874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
38821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        } else if (name.equals("sourceAsset") ) {
3894a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
3902dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                if (mLogVerbose) Log.v(TAG, "Opening new source FD");
3912dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                if (!mSelectedIsUrl) {
3922dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                    setupMediaPlayer(mSelectedIsUrl);
3934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
3944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
39521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        } else if (name.equals("loop")) {
3964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (isOpen()) {
39721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                mMediaPlayer.setLooping(mLooping);
3984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
3992dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen        } else if (name.equals("sourceIsUrl")) {
4002dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen            if (isOpen()){
4012dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                if (mSelectedIsUrl){
4022dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                    if (mLogVerbose) Log.v(TAG, "Opening new source URL");
4032dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                } else {
4042dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                    if (mLogVerbose) Log.v(TAG, "Opening new source Asset");
4052dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                }
4062dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen                setupMediaPlayer(mSelectedIsUrl);
4072dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen            }
408c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        } else if (name.equals("volume")) {
409c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            if (isOpen()) {
410c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                mMediaPlayer.setVolume(mVolume, mVolume);
411c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            }
412855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala        } else if (name.equals("orientation") && mGotSize) {
413855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            if (mOrientation == 0 || mOrientation == 180) {
414855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                mOutputFormat.setDimensions(mWidth, mHeight);
415855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            } else {
416855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                mOutputFormat.setDimensions(mHeight, mWidth);
417855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            }
418855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala            mOrientationUpdated = true;
4194a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
4204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
4214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4221df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    synchronized public void pauseVideo(boolean pauseState) {
4236aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        if (isOpen()) {
4246aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            if (pauseState && !mPaused) {
4256aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                mMediaPlayer.pause();
4266aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            } else if (!pauseState && mPaused) {
4276aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala                mMediaPlayer.start();
4286aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala            }
4296aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        }
4301df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala        mPaused = pauseState;
4311df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala    }
4321df612099dde7e43249468d46e5b8064d8c33b77Eino-Ville Talvala
4334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    /** Creates a media player, sets it up, and calls prepare */
4342dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen    synchronized private boolean setupMediaPlayer(boolean useUrl) {
4354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mPrepared = false;
4364a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mGotSize = false;
4374a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mPlaying = false;
4386aa4072be405da80b7abcc732befe819cfa932eaEino-Ville Talvala        mPaused = false;
439c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        mCompleted = false;
44090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala        mNewFrameAvailable = false;
441c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala
442c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Setting up playback.");
4434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer != null) {
44590397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            // Clean up existing media players
446c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Resetting existing MediaPlayer.");
4474a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.reset();
4484a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } else {
4494a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            // Create new media player
450c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Creating new MediaPlayer.");
4514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = new MediaPlayer();
4524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
4534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        if (mMediaPlayer == null) {
455c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            throw new RuntimeException("Unable to create a MediaPlayer!");
4564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
4574a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4584a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Set up data sources, etc
4594a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        try {
4602dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen            if (useUrl) {
461c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to URI " + mSourceUrl);
4624a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setDataSource(mSourceUrl);
4634a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
464c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to asset " + mSourceAsset);
4654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength());
4664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
4674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        } catch(IOException e) {
468c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            mMediaPlayer.release();
469c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            mMediaPlayer = null;
4702dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen            if (useUrl) {
471c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e);
4724a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
473c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e);
4744a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
475c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        } catch(IllegalArgumentException e) {
4764a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer.release();
4774a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            mMediaPlayer = null;
4782dfe9bbf05b260944ef5fa42aa5dfd2fd312aba1Christine Chen            if (useUrl) {
479c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e);
4804a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
481c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e);
4824a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
4834a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
4844a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4854a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setLooping(mLooping);
486c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        mMediaPlayer.setVolume(mVolume, mVolume);
4874a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4884a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Bind it to our media frame
4891ae8bcdf7dc3df7be3ca14b6f63d0009654fab69Jamie Gennis        Surface surface = new Surface(mSurfaceTexture);
4901ae8bcdf7dc3df7be3ca14b6f63d0009654fab69Jamie Gennis        mMediaPlayer.setSurface(surface);
4911ae8bcdf7dc3df7be3ca14b6f63d0009654fab69Jamie Gennis        surface.release();
4924a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4934a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Connect Media Player to callbacks
4944a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4954a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener);
4964a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnPreparedListener(onPreparedListener);
4974a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.setOnCompletionListener(onCompletionListener);
4984a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
4994a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        // Connect SurfaceTexture to callback
5004a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mSurfaceTexture.setOnFrameAvailableListener(onMediaFrameAvailableListener);
5014a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
502c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Preparing MediaPlayer.");
5034a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        mMediaPlayer.prepareAsync();
5044a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
50521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return true;
5064a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    }
5074a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
5084a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener =
5094a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnVideoSizeChangedListener() {
5104a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
5118dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "MediaPlayer sent dimensions: " + width + " x " + height);
5124a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            if (!mGotSize) {
513855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                if (mOrientation == 0 || mOrientation == 180) {
514855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    mOutputFormat.setDimensions(width, height);
515855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                } else {
516855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                    mOutputFormat.setDimensions(height, width);
517855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                }
518855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                mWidth = width;
519855b25acc20d38dfb98eff8bf73fbc441e174a92Eino-Ville Talvala                mHeight = height;
5204a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            } else {
5214a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                if (mOutputFormat.getWidth() != width ||
5224a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    mOutputFormat.getHeight() != height) {
5234a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                    Log.e(TAG, "Multiple video size change events received!");
5244a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                }
5254a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
52690397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            synchronized(MediaSource.this) {
5274a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mGotSize = true;
52890397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                MediaSource.this.notify();
5294a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
5304a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
5314a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
5324a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
5334a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnPreparedListener onPreparedListener =
5344a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnPreparedListener() {
5354a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onPrepared(MediaPlayer mp) {
5368dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "MediaPlayer is prepared");
53790397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            synchronized(MediaSource.this) {
5384a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala                mPrepared = true;
53990397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                MediaSource.this.notify();
5404a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            }
5414a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
5424a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
5434a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
5444a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private MediaPlayer.OnCompletionListener onCompletionListener =
5454a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new MediaPlayer.OnCompletionListener() {
5464a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onCompletion(MediaPlayer mp) {
5478dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "MediaPlayer has completed playback");
54890397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            synchronized(MediaSource.this) {
549c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala                mCompleted = true;
550c8afe66093a29852779745ddf7c45dee6f0dc414Eino-Ville Talvala            }
5514a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
5524a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
5534a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
5544a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    private SurfaceTexture.OnFrameAvailableListener onMediaFrameAvailableListener =
5554a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala            new SurfaceTexture.OnFrameAvailableListener() {
5564a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
5578dd704358d808382465666354fc891af59b21e18Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "New frame from media player");
55890397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            synchronized(MediaSource.this) {
55990397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "New frame: notify");
56090397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                mNewFrameAvailable = true;
56190397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                MediaSource.this.notify();
56290397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "New frame: notify done");
56390397368b3af2279e6aa739182b4e50b26a90bebEino-Ville Talvala            }
5644a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala        }
5654a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala    };
5664a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala
5674a0c538853d7858d59cbc7f4dc7ece5d942e0b7cEino-Ville Talvala}
568