165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/* 265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project 365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License"); 565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License. 665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at 765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * http://www.apache.org/licenses/LICENSE-2.0 965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software 1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS, 1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and 1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License. 1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpackage android.filterpacks.videosrc; 1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.content.Context; 2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.content.res.AssetFileDescriptor; 2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Filter; 2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterContext; 2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Frame; 2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FrameFormat; 2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GenerateFieldPort; 2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GenerateFinalPort; 2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GLFrame; 2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.MutableFrameFormat; 3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.ShaderProgram; 3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.format.ImageFormat; 3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.graphics.SurfaceTexture; 3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.media.MediaPlayer; 342253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhuimport android.net.Uri; 3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.opengl.Matrix; 3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.view.Surface; 3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.io.IOException; 3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.IllegalArgumentException; 4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.util.Log; 4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/** 4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide 4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic class MediaSource extends Filter { 4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** User-visible parameters */ 4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** The source URL for the media source. Can be an http: link to a remote 5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * resource, or a file: link to a local media file 5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "sourceUrl", hasDefault = true) 5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private String mSourceUrl = ""; 5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** An open asset file descriptor to a local media source. Default is null */ 5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "sourceAsset", hasDefault = true) 5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private AssetFileDescriptor mSourceAsset = null; 5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 602253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu /** The context for the MediaPlayer to resolve the sourceUrl. 612253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu * Make sure this is set before the sourceUrl to avoid unexpected result. 622253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu * If the sourceUrl is not a content URI, it is OK to keep this as null. */ 632253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu @GenerateFieldPort(name = "context", hasDefault = true) 642253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu private Context mContext = null; 652253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu 6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the media source is a URL or an asset file descriptor. Defaults 6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * to false. 6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "sourceIsUrl", hasDefault = true) 7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mSelectedIsUrl = false; 7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the filter will always wait for a new video frame, or whether it 7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * will output an old frame again if a new frame isn't available. Defaults 7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * to true. 7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFinalPort(name = "waitForNewFrame", hasDefault = true) 7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mWaitForNewFrame = true; 7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the media source should loop automatically or not. Defaults to 8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * true. 8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "loop", hasDefault = true) 8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mLooping = true; 8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Volume control. Currently sound is piped directly to the speakers, so 8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * this defaults to mute. 8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "volume", hasDefault = true) 8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private float mVolume = 0.f; 9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Orientation. This controls the output orientation of the video. Valid 9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * values are 0, 90, 180, 270 9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "orientation", hasDefault = true) 9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mOrientation = 0; 9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer mMediaPlayer; 9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private GLFrame mMediaFrame; 9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private SurfaceTexture mSurfaceTexture; 10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private ShaderProgram mFrameExtractor; 10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MutableFrameFormat mOutputFormat; 10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mWidth, mHeight; 10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Total timeouts will be PREP_TIMEOUT*PREP_TIMEOUT_REPEAT 10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int PREP_TIMEOUT = 100; // ms 10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int PREP_TIMEOUT_REPEAT = 100; 10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int NEWFRAME_TIMEOUT = 100; //ms 10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int NEWFRAME_TIMEOUT_REPEAT = 10; 10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // This is an identity shader; not using the default identity 11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // shader because reading from a SurfaceTexture requires the 11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // GL_OES_EGL_image_external extension. 11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private final String mFrameShader = 11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "#extension GL_OES_EGL_image_external : require\n" + 11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "precision mediump float;\n" + 11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "uniform samplerExternalOES tex_sampler_0;\n" + 11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "varying vec2 v_texcoord;\n" + 11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "void main() {\n" + 11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "}\n"; 12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // The following transforms enable rotation of the decoded source. 12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // These are multiplied with the transform obtained from the 12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // SurfaceTexture to get the final transform to be set on the media source. 12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Currently, given a device orientation, the MediaSource rotates in such a way 12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // that the source is displayed upright. A particular use case 12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // is "Background Replacement" feature in the Camera app 12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // where the MediaSource rotates the source to align with the camera feed and pass it 12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // on to the backdropper filter. The backdropper only does the blending 13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // and does not have to do any rotation 13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // (except for mirroring in case of front camera). 13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // TODO: Currently the rotations are spread over a bunch of stages in the 13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // pipeline. A cleaner design 13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // could be to cast away all the rotation in a separate filter or attach a transform 13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // to the frame so that MediaSource itself need not know about any rotation. 13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_0 = { 1, 1, 0, 1, 13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 1, 0, 1, 13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1, 13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1 }; 14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_270 = { 0, 1, 0, 1, 14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1, 14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1, 14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1 }; 14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_180 = { 0, 0, 0, 1, 14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1, 14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 1, 0, 1, 14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1 }; 14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_90 = { 1, 0, 0, 1, 14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1, 15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1, 15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 1, 0, 1 }; 15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mGotSize; 15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mPrepared; 15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mPlaying; 15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mNewFrameAvailable; 15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mOrientationUpdated; 15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mPaused; 15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mCompleted; 16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private final boolean mLogVerbose; 16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final String TAG = "MediaSource"; 16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public MediaSource(String name) { 16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn super(name); 16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void setupPorts() { 17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Add input port 17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat.TARGET_GPU)); 17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void createFormats() { 17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat = ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat.TARGET_GPU); 18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn protected void prepare(FilterContext context) { 18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Preparing MediaSource"); 18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor = new ShaderProgram(context, mFrameShader); 18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // SurfaceTexture defines (0,0) to be bottom-left. The filter framework 18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // defines (0,0) as top-left, so do the flip here. 19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.setSourceRect(0, 1, 1, -1); 19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn createFormats(); 19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void open(FilterContext context) { 19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) { 19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "Opening MediaSource"); 19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mSelectedIsUrl) { 20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "Current URL is " + mSourceUrl); 20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "Current source is Asset!"); 20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaFrame = (GLFrame)context.getFrameManager().newBoundFrame( 20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat, 20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn GLFrame.EXTERNAL_TEXTURE, 20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0); 21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId()); 21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!setupMediaPlayer(mSelectedIsUrl)) { 21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Error setting up MediaPlayer!"); 21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void process(FilterContext context) { 22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Note: process is synchronized by its caller in the Filter base class 22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Processing new frame"); 22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer == null) { 22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Something went wrong in initialization or parameter updates 22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new NullPointerException("Unexpected null media player!"); 22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCompleted) { 22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Video playback is done, so close us down 23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeOutputPort("video"); 23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return; 23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mPlaying) { 23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int waitCount = 0; 23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Waiting for preparation to complete"); 23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn while (!mGotSize || !mPrepared) { 23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn this.wait(PREP_TIMEOUT); 24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch (InterruptedException e) { 24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // ignoring 24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCompleted) { 24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Video playback is done, so close us down 24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeOutputPort("video"); 24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return; 24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn waitCount++; 24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (waitCount == PREP_TIMEOUT_REPEAT) { 25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("MediaPlayer timed out while preparing!"); 25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Starting playback"); 25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.start(); 25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Use last frame if paused, unless just starting playback, in which case 25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // we want at least one valid frame before pausing 26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mPaused || !mPlaying) { 26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mWaitForNewFrame) { 26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Waiting for new frame"); 26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int waitCount = 0; 26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn while (!mNewFrameAvailable) { 26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (waitCount == NEWFRAME_TIMEOUT_REPEAT) { 26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCompleted) { 26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Video playback is done, so close us down 26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeOutputPort("video"); 27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return; 27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Timeout waiting for new frame!"); 27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn this.wait(NEWFRAME_TIMEOUT); 27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch (InterruptedException e) { 27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "interrupted"); 27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // ignoring 28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn waitCount++; 28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Got new frame"); 28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.updateTexImage(); 28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOrientationUpdated = true; 28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOrientationUpdated) { 29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn float[] surfaceTransform = new float[16]; 29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.getTransformMatrix(surfaceTransform); 29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn float[] sourceCoords = new float[16]; 29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn switch (mOrientation) { 29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn default: 29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 0: 29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_0, 0); 30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 90: 30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_90, 0); 30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 180: 30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_180, 0); 31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 270: 31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_270, 0); 31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) { 31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "OrientationHint = " + mOrientation); 32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String temp = String.format("SetSourceRegion: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f", 32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[4], sourceCoords[5],sourceCoords[0], sourceCoords[1], 32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[12], sourceCoords[13],sourceCoords[8], sourceCoords[9]); 32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, temp); 32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.setSourceRegion(sourceCoords[4], sourceCoords[5], 32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[0], sourceCoords[1], 32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[12], sourceCoords[13], 32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[8], sourceCoords[9]); 32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOrientationUpdated = false; 33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Frame output = context.getFrameManager().newFrame(mOutputFormat); 33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.process(mMediaFrame, output); 33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn long timestamp = mSurfaceTexture.getTimestamp(); 33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Timestamp: " + (timestamp / 1000000000.0) + " s"); 33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn output.setTimestamp(timestamp); 33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn pushOutput("video", output); 34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn output.release(); 34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPlaying = true; 34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void close(FilterContext context) { 34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer.isPlaying()) { 34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.stop(); 34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPrepared = false; 35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mGotSize = false; 35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPlaying = false; 35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPaused = false; 35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCompleted = false; 35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = null; 35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.release(); 36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture = null; 36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaSource closed"); 36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void tearDown(FilterContext context) { 36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaFrame != null) { 36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaFrame.release(); 36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // When updating the port values of the filter, users can update sourceIsUrl to switch 37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // between using URL objects or Assets. 37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // If updating only sourceUrl/sourceAsset, MediaPlayer gets reset if the current player 37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // uses Url objects/Asset. 37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Otherwise the new sourceUrl/sourceAsset is stored and will be used when users switch 37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // sourceIsUrl next time. 37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void fieldPortValueUpdated(String name, FilterContext context) { 37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Parameter update"); 38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (name.equals("sourceUrl")) { 38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source URL"); 38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mSelectedIsUrl) { 38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn setupMediaPlayer(mSelectedIsUrl); 38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("sourceAsset") ) { 38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source FD"); 39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mSelectedIsUrl) { 39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn setupMediaPlayer(mSelectedIsUrl); 39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("loop")) { 39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setLooping(mLooping); 39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("sourceIsUrl")) { 39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()){ 40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mSelectedIsUrl){ 40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source URL"); 40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source Asset"); 40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn setupMediaPlayer(mSelectedIsUrl); 40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("volume")) { 40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setVolume(mVolume, mVolume); 41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("orientation") && mGotSize) { 41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOrientation == 0 || mOrientation == 180) { 41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(mWidth, mHeight); 41465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 41565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(mHeight, mWidth); 41665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 41765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOrientationUpdated = true; 41865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 41965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 42065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 42165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized public void pauseVideo(boolean pauseState) { 42265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 42365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (pauseState && !mPaused) { 42465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.pause(); 42565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (!pauseState && mPaused) { 42665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.start(); 42765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 42865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 42965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPaused = pauseState; 43065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 43165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 43265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Creates a media player, sets it up, and calls prepare */ 43365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized private boolean setupMediaPlayer(boolean useUrl) { 43465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPrepared = false; 43565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mGotSize = false; 43665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPlaying = false; 43765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPaused = false; 43865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCompleted = false; 43965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 44065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 44165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Setting up playback."); 44265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 44365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer != null) { 44465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Clean up existing media players 44565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Resetting existing MediaPlayer."); 44665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.reset(); 44765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 44865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Create new media player 44965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Creating new MediaPlayer."); 45065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = new MediaPlayer(); 45165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 45265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 45365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer == null) { 45465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Unable to create a MediaPlayer!"); 45565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 45665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 45765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Set up data sources, etc 45865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 45965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (useUrl) { 46065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to URI " + mSourceUrl); 4612253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu if (mContext == null) { 4622253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu mMediaPlayer.setDataSource(mSourceUrl); 4632253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu } else { 4642253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu mMediaPlayer.setDataSource(mContext, Uri.parse(mSourceUrl.toString())); 4652253eeab6c0c20e0b03f144c5bc23ae13e8ab234Teng-Hui Zhu } 46665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 46765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to asset " + mSourceAsset); 46865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength()); 46965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 47065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch(IOException e) { 47165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 47265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = null; 47365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (useUrl) { 47465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e); 47565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 47665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e); 47765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 47865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch(IllegalArgumentException e) { 47965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 48065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = null; 48165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (useUrl) { 48265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e); 48365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 48465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e); 48565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 48665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 48765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 48865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setLooping(mLooping); 48965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setVolume(mVolume, mVolume); 49065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 49165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Bind it to our media frame 49265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Surface surface = new Surface(mSurfaceTexture); 49365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setSurface(surface); 49465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface.release(); 49565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 49665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Connect Media Player to callbacks 49765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 49865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener); 49965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setOnPreparedListener(onPreparedListener); 50065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setOnCompletionListener(onCompletionListener); 50165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 50265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Connect SurfaceTexture to callback 50365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.setOnFrameAvailableListener(onMediaFrameAvailableListener); 50465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 50565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Preparing MediaPlayer."); 50665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.prepareAsync(); 50765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 50865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 50965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 51065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 51165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener = 51265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new MediaPlayer.OnVideoSizeChangedListener() { 51365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 51465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaPlayer sent dimensions: " + width + " x " + height); 51565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mGotSize) { 51665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOrientation == 0 || mOrientation == 180) { 51765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(width, height); 51865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 51965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(height, width); 52065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 52165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mWidth = width; 52265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mHeight = height; 52365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 52465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOutputFormat.getWidth() != width || 52565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.getHeight() != height) { 52665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.e(TAG, "Multiple video size change events received!"); 52765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 52865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 52965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 53065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mGotSize = true; 53165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn MediaSource.this.notify(); 53265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 53365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 53465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 53565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 53665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer.OnPreparedListener onPreparedListener = 53765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new MediaPlayer.OnPreparedListener() { 53865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onPrepared(MediaPlayer mp) { 53965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaPlayer is prepared"); 54065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 54165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPrepared = true; 54265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn MediaSource.this.notify(); 54365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 54465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 54565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 54665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 54765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer.OnCompletionListener onCompletionListener = 54865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new MediaPlayer.OnCompletionListener() { 54965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onCompletion(MediaPlayer mp) { 55065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaPlayer has completed playback"); 55165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 55265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCompleted = true; 55365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 55465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 55565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 55665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 55765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private SurfaceTexture.OnFrameAvailableListener onMediaFrameAvailableListener = 55865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new SurfaceTexture.OnFrameAvailableListener() { 55965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onFrameAvailable(SurfaceTexture surfaceTexture) { 56065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame from media player"); 56165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 56265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame: notify"); 56365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = true; 56465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn MediaSource.this.notify(); 56565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame: notify done"); 56665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 56765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 56865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 56965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 57065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 571