to top
BasicMediaDecoder / src / com.example.android.basicmediadecoder /

MainActivity.java

1
/*
2
 * Copyright (C) 2013 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.basicmediadecoder;
18
 
19
 
20
import android.animation.TimeAnimator;
21
import android.app.Activity;
22
import android.media.MediaCodec;
23
import android.media.MediaExtractor;
24
import android.net.Uri;
25
import android.os.Bundle;
26
import android.view.Menu;
27
import android.view.MenuInflater;
28
import android.view.MenuItem;
29
import android.view.Surface;
30
import android.view.TextureView;
31
import android.view.View;
32
import android.widget.TextView;
33
 
34
import com.example.android.common.media.MediaCodecWrapper;
35
 
36
import java.io.IOException;
37
 
38
/**
39
 * This activity uses a {@link android.view.TextureView} to render the frames of a video decoded using
40
 * {@link android.media.MediaCodec} API.
41
 */
42
public class MainActivity extends Activity {
43
 
44
    private TextureView mPlaybackView;
45
    private TimeAnimator mTimeAnimator = new TimeAnimator();
46
 
47
    // A utility that wraps up the underlying input and output buffer processing operations
48
    // into an east to use API.
49
    private MediaCodecWrapper mCodecWrapper;
50
    private MediaExtractor mExtractor = new MediaExtractor();
51
    TextView mAttribView = null;
52
 
53
 
54
    /**
55
     * Called when the activity is first created.
56
     */
57
    @Override
58
    public void onCreate(Bundle savedInstanceState) {
59
        super.onCreate(savedInstanceState);
60
        setContentView(R.layout.sample_main);
61
        mPlaybackView = (TextureView) findViewById(R.id.PlaybackView);
62
        mAttribView =  (TextView)findViewById(R.id.AttribView);
63
 
64
    }
65
 
66
    @Override
67
    public boolean onCreateOptionsMenu(Menu menu) {
68
        MenuInflater inflater = getMenuInflater();
69
        inflater.inflate(R.menu.action_menu, menu);
70
        return true;
71
    }
72
 
73
    @Override
74
    protected void onPause() {
75
        super.onPause();
76
        if(mTimeAnimator != null && mTimeAnimator.isRunning()) {
77
            mTimeAnimator.end();
78
        }
79
 
80
        if (mCodecWrapper != null ) {
81
            mCodecWrapper.stopAndRelease();
82
            mExtractor.release();
83
        }
84
    }
85
 
86
    @Override
87
    public boolean onOptionsItemSelected(MenuItem item) {
88
        if (item.getItemId() == R.id.menu_play) {
89
            mAttribView.setVisibility(View.VISIBLE);
90
            startPlayback();
91
            item.setEnabled(false);
92
        }
93
        return true;
94
    }
95
 
96
 
97
    public void startPlayback() {
98
 
99
        // Construct a URI that points to the video resource that we want to play
100
        Uri videoUri = Uri.parse("android.resource://"
101
                + getPackageName() + "/"
102
                + R.raw.vid_bigbuckbunny);
103
 
104
        try {
105
 
107
            mExtractor.setDataSource(this, videoUri, null);
108
            int nTracks = mExtractor.getTrackCount();
109
 
110
            // Begin by unselecting all of the tracks in the extractor, so we won't see
111
            // any tracks that we haven't explicitly selected.
112
            for (int i = 0; i < nTracks; ++i) {
113
                mExtractor.unselectTrack(i);
114
            }
115
 
116
 
117
            // Find the first video track in the stream. In a real-world application
118
            // it's possible that the stream would contain multiple tracks, but this
119
            // sample assumes that we just want to play the first one.
120
            for (int i = 0; i < nTracks; ++i) {
121
                // Try to create a video codec for this track. This call will return null if the
122
                // track is not a video track, or not a recognized video format. Once it returns
123
                // a valid MediaCodecWrapper, we can break out of the loop.
124
                mCodecWrapper = MediaCodecWrapper.fromVideoFormat(mExtractor.getTrackFormat(i),
125
                        new Surface(mPlaybackView.getSurfaceTexture()));
126
                if (mCodecWrapper != null) {
127
                    mExtractor.selectTrack(i);
128
                    break;
129
                }
130
            }
132
 
133
 
134
 
135
 
136
            // By using a {@link TimeAnimator}, we can sync our media rendering commands with
137
            // the system display frame rendering. The animator ticks as the {@link Choreographer}
138
            // recieves VSYNC events.
139
            mTimeAnimator.setTimeListener(new TimeAnimator.TimeListener() {
140
                @Override
141
                public void onTimeUpdate(final TimeAnimator animation,
142
                                         final long totalTime,
143
                                         final long deltaTime) {
144
 
145
                    boolean isEos = ((mExtractor.getSampleFlags() & MediaCodec
146
                            .BUFFER_FLAG_END_OF_STREAM) == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
147
 
149
                    if (!isEos) {
150
                        // Try to submit the sample to the codec and if successful advance the
151
                        // extractor to the next available sample to read.
152
                        boolean result = mCodecWrapper.writeSample(mExtractor, false,
153
                                mExtractor.getSampleTime(), mExtractor.getSampleFlags());
154
 
155
                        if (result) {
156
                            // Advancing the extractor is a blocking operation and it MUST be
157
                            // executed outside the main thread in real applications.
158
                            mExtractor.advance();
159
                        }
160
                    }
162
 
163
                    // Examine the sample at the head of the queue to see if its ready to be
164
                    // rendered and is not zero sized End-of-Stream record.
165
                    MediaCodec.BufferInfo out_bufferInfo = new MediaCodec.BufferInfo();
166
                    mCodecWrapper.peekSample(out_bufferInfo);
167
 
169
                    if (out_bufferInfo.size <= 0 && isEos) {
170
                        mTimeAnimator.end();
171
                        mCodecWrapper.stopAndRelease();
172
                        mExtractor.release();
173
                    } else if (out_bufferInfo.presentationTimeUs / 1000 < totalTime) {
174
                        // Pop the sample off the queue and send it to {@link Surface}
175
                        mCodecWrapper.popSample(true);
176
                    }
178
 
179
                }
180
            });
181
 
182
            // We're all set. Kick off the animator to process buffers and render video frames as
183
            // they become available
184
            mTimeAnimator.start();
185
        } catch (IOException e) {
186
            e.printStackTrace();
187
        }
188
    }
189
}