MediaExtractor.java revision 07ea426e3ae8915ca6bf67135f523f42cd920af0
1/*
2 * Copyright (C) 2012 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
17package android.media;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.content.res.AssetFileDescriptor;
22import android.net.Uri;
23import java.io.FileDescriptor;
24import java.io.IOException;
25import java.nio.ByteBuffer;
26import java.util.Map;
27
28/**
29 * MediaExtractor facilitates extraction of demuxed, typically encoded,  media data
30 * from a data source.
31 * <p>It is generally used like this:
32 * <pre>
33 * MediaExtractor extractor = new MediaExtractor();
34 * extractor.setDataSource(...);
35 * int numTracks = extractor.countTracks();
36 * for (int i = 0; i &lt; numTracks; ++i) {
37 *   Map%lt;String, Object&gt; format = extractor.getTrackFormat(i);
38 *   String mime = (String)format.get("mime");
39 *   if (weAreInterestedInThisTrack) {
40 *     extractor.selectTrack(i);
41 *   }
42 * }
43 * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
44 * while (extractor.readSampleData(inputBuffer, ...) &gt;= 0) {
45 *   int trackIndex = extractor.getTrackIndex();
46 *   long presentationTimeUs = extractor.getSampleTime();
47 *   ...
48 *   extractor.advance();
49 * }
50 *
51 * extractor.release();
52 * extractor = null;
53 * </pre>
54*/
55final public class MediaExtractor {
56    public MediaExtractor() {
57        native_setup();
58    }
59
60    /**
61     * Sets the data source as a content Uri.
62     *
63     * @param context the Context to use when resolving the Uri
64     * @param uri the Content URI of the data you want to extract from.
65     * @param headers the headers to be sent together with the request for the data
66     */
67    public final void setDataSource(
68            Context context, Uri uri, Map<String, String> headers)
69        throws IOException {
70        String scheme = uri.getScheme();
71        if(scheme == null || scheme.equals("file")) {
72            setDataSource(uri.getPath());
73            return;
74        }
75
76        AssetFileDescriptor fd = null;
77        try {
78            ContentResolver resolver = context.getContentResolver();
79            fd = resolver.openAssetFileDescriptor(uri, "r");
80            if (fd == null) {
81                return;
82            }
83            // Note: using getDeclaredLength so that our behavior is the same
84            // as previous versions when the content provider is returning
85            // a full file.
86            if (fd.getDeclaredLength() < 0) {
87                setDataSource(fd.getFileDescriptor());
88            } else {
89                setDataSource(
90                        fd.getFileDescriptor(),
91                        fd.getStartOffset(),
92                        fd.getDeclaredLength());
93            }
94            return;
95        } catch (SecurityException ex) {
96        } catch (IOException ex) {
97        } finally {
98            if (fd != null) {
99                fd.close();
100            }
101        }
102
103        setDataSource(uri.toString(), headers);
104    }
105
106    /**
107     * Sets the data source (file-path or http URL) to use.
108     *
109     * @param path the path of the file, or the http URL
110     * @param headers the headers associated with the http request for the stream you want to play
111     */
112    public final void setDataSource(String path, Map<String, String> headers) {
113        String[] keys = null;
114        String[] values = null;
115
116        if (headers != null) {
117            keys = new String[headers.size()];
118            values = new String[headers.size()];
119
120            int i = 0;
121            for (Map.Entry<String, String> entry: headers.entrySet()) {
122                keys[i] = entry.getKey();
123                values[i] = entry.getValue();
124                ++i;
125            }
126        }
127        setDataSource(path, keys, values);
128    }
129
130    private native final void setDataSource(
131            String path, String[] keys, String[] values);
132
133    /**
134     * Sets the data source (file-path or http URL) to use.
135     *
136     * @param path the path of the file, or the http URL of the stream
137     *
138     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
139     * process other than the calling application.  This implies that the pathname
140     * should be an absolute path (as any other process runs with unspecified current working
141     * directory), and that the pathname should reference a world-readable file.
142     * As an alternative, the application could first open the file for reading,
143     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
144     */
145    public final void setDataSource(String path) {
146        setDataSource(path, null, null);
147    }
148
149    /**
150     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
151     * to close the file descriptor. It is safe to do so as soon as this call returns.
152     *
153     * @param fd the FileDescriptor for the file you want to extract from.
154     */
155    public final void setDataSource(FileDescriptor fd) {
156        setDataSource(fd, 0, 0x7ffffffffffffffL);
157    }
158
159    /**
160     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be
161     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
162     * to close the file descriptor. It is safe to do so as soon as this call returns.
163     *
164     * @param fd the FileDescriptor for the file you want to extract from.
165     * @param offset the offset into the file where the data to be extracted starts, in bytes
166     * @param length the length in bytes of the data to be extracted
167     */
168    public native final void setDataSource(
169            FileDescriptor fd, long offset, long length);
170
171    @Override
172    protected void finalize() {
173        native_finalize();
174    }
175
176    /** Make sure you call this when you're done to free up any resources
177     *  instead of relying on the garbage collector to do this for you at
178     *   some point in the future.
179    */
180    public native final void release();
181
182    /** Count the number of tracks found in the data source.
183     */
184    public native int countTracks();
185
186    /** Get the track format at the specified index.
187      * More detail on the representation can be found at {@link android.media.MediaCodec}
188    */
189    public native Map<String, Object> getTrackFormat(int index);
190
191    /** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
192     *  {@link #getSampleTime} only retrieve information for the subset of tracks
193     *  selected by the call below.
194     *  Selecting the same track multiple times has no effect, the track
195     *  only selected once.
196     *  Media data will be returned in the order of their timestamps.
197    */
198    public native void selectTrack(int index);
199
200    /** All selected tracks seek near the requested time. The next sample
201     *  returned for each selected track will be a sync sample.
202    */
203    public native void seekTo(long timeUs);
204
205    /** Advance to the next sample. Returns false if no more sample data
206     *  is available (end of stream).
207     */
208    public native boolean advance();
209
210    /** Retrieve the current encoded sample and store it in the byte buffer
211     *  starting at the given offset. Returns the sample size (or -1 if
212     *  no more samples are available).
213    */
214    public native int readSampleData(ByteBuffer byteBuf, int offset);
215
216    /** Returns the track index the current sample originates from (or -1
217     *  if no more samples are available)
218    */
219    public native int getSampleTrackIndex();
220
221    /** Returns the current sample's presentation time in microseconds.
222     *  or -1 if no more samples are available.
223    */
224    public native long getSampleTime();
225
226    // Keep these in sync with their equivalents in NuMediaExtractor.h
227    /** The sample is a sync sample */
228    public static final int SAMPLE_FLAG_SYNC      = 1;
229
230    /** The sample is (at least partially) encrypted, see also the documentation
231     *  for {@link android.media.MediaCodec#queueSecureInputBuffer}
232    */
233    public static final int SAMPLE_FLAG_ENCRYPTED = 2;
234
235    /** Returns the current sample's flags. */
236    public native int getSampleFlags();
237
238    private static native final void native_init();
239    private native final void native_setup();
240    private native final void native_finalize();
241
242    static {
243        System.loadLibrary("media_jni");
244        native_init();
245    }
246
247    private int mNativeContext;
248}
249