MediaExtractor.java revision a242deb1de365f0ed0032a87565df1971cb6bbe2
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.media.MediaCodec;
23import android.media.MediaFormat;
24import android.net.Uri;
25
26import java.io.FileDescriptor;
27import java.io.IOException;
28import java.nio.ByteBuffer;
29import java.util.Map;
30
31/**
32 * MediaExtractor facilitates extraction of demuxed, typically encoded,  media data
33 * from a data source.
34 * <p>It is generally used like this:
35 * <pre>
36 * MediaExtractor extractor = new MediaExtractor();
37 * extractor.setDataSource(...);
38 * int numTracks = extractor.getTrackCount();
39 * for (int i = 0; i &lt; numTracks; ++i) {
40 *   MediaFormat format = extractor.getTrackFormat(i);
41 *   String mime = format.getString(MediaFormat.KEY_MIME);
42 *   if (weAreInterestedInThisTrack) {
43 *     extractor.selectTrack(i);
44 *   }
45 * }
46 * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
47 * while (extractor.readSampleData(inputBuffer, ...) &gt;= 0) {
48 *   int trackIndex = extractor.getSampleTrackIndex();
49 *   long presentationTimeUs = extractor.getSampleTime();
50 *   ...
51 *   extractor.advance();
52 * }
53 *
54 * extractor.release();
55 * extractor = null;
56 * </pre>
57 */
58final public class MediaExtractor {
59    public MediaExtractor() {
60        native_setup();
61    }
62
63    /**
64     * Sets the DataSource object to be used as the data source for this extractor
65     * {@hide}
66     */
67    public native final void setDataSource(DataSource source);
68
69    /**
70     * Sets the data source as a content Uri.
71     *
72     * @param context the Context to use when resolving the Uri
73     * @param uri the Content URI of the data you want to extract from.
74     * @param headers the headers to be sent together with the request for the data
75     */
76    public final void setDataSource(
77            Context context, Uri uri, Map<String, String> headers)
78        throws IOException {
79        String scheme = uri.getScheme();
80        if(scheme == null || scheme.equals("file")) {
81            setDataSource(uri.getPath());
82            return;
83        }
84
85        AssetFileDescriptor fd = null;
86        try {
87            ContentResolver resolver = context.getContentResolver();
88            fd = resolver.openAssetFileDescriptor(uri, "r");
89            if (fd == null) {
90                return;
91            }
92            // Note: using getDeclaredLength so that our behavior is the same
93            // as previous versions when the content provider is returning
94            // a full file.
95            if (fd.getDeclaredLength() < 0) {
96                setDataSource(fd.getFileDescriptor());
97            } else {
98                setDataSource(
99                        fd.getFileDescriptor(),
100                        fd.getStartOffset(),
101                        fd.getDeclaredLength());
102            }
103            return;
104        } catch (SecurityException ex) {
105        } catch (IOException ex) {
106        } finally {
107            if (fd != null) {
108                fd.close();
109            }
110        }
111
112        setDataSource(uri.toString(), headers);
113    }
114
115    /**
116     * Sets the data source (file-path or http URL) to use.
117     *
118     * @param path the path of the file, or the http URL
119     * @param headers the headers associated with the http request for the stream you want to play
120     */
121    public final void setDataSource(String path, Map<String, String> headers) {
122        String[] keys = null;
123        String[] values = null;
124
125        if (headers != null) {
126            keys = new String[headers.size()];
127            values = new String[headers.size()];
128
129            int i = 0;
130            for (Map.Entry<String, String> entry: headers.entrySet()) {
131                keys[i] = entry.getKey();
132                values[i] = entry.getValue();
133                ++i;
134            }
135        }
136        setDataSource(path, keys, values);
137    }
138
139    private native final void setDataSource(
140            String path, String[] keys, String[] values);
141
142    /**
143     * Sets the data source (file-path or http URL) to use.
144     *
145     * @param path the path of the file, or the http URL of the stream
146     *
147     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
148     * process other than the calling application.  This implies that the pathname
149     * should be an absolute path (as any other process runs with unspecified current working
150     * directory), and that the pathname should reference a world-readable file.
151     * As an alternative, the application could first open the file for reading,
152     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
153     */
154    public final void setDataSource(String path) {
155        setDataSource(path, null, null);
156    }
157
158    /**
159     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
160     * to close the file descriptor. It is safe to do so as soon as this call returns.
161     *
162     * @param fd the FileDescriptor for the file you want to extract from.
163     */
164    public final void setDataSource(FileDescriptor fd) {
165        setDataSource(fd, 0, 0x7ffffffffffffffL);
166    }
167
168    /**
169     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be
170     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
171     * to close the file descriptor. It is safe to do so as soon as this call returns.
172     *
173     * @param fd the FileDescriptor for the file you want to extract from.
174     * @param offset the offset into the file where the data to be extracted starts, in bytes
175     * @param length the length in bytes of the data to be extracted
176     */
177    public native final void setDataSource(
178            FileDescriptor fd, long offset, long length);
179
180    @Override
181    protected void finalize() {
182        native_finalize();
183    }
184
185    /**
186     * Make sure you call this when you're done to free up any resources
187     * instead of relying on the garbage collector to do this for you at
188     * some point in the future.
189     */
190    public native final void release();
191
192    /**
193     * Count the number of tracks found in the data source.
194     */
195    public native final int getTrackCount();
196
197    /**
198     * Get the track format at the specified index.
199     * More detail on the representation can be found at {@link android.media.MediaCodec}
200     */
201    public MediaFormat getTrackFormat(int index) {
202        return new MediaFormat(getTrackFormatNative(index));
203    }
204
205    private native Map<String, Object> getTrackFormatNative(int index);
206
207    /**
208     * Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
209     * {@link #getSampleTime} only retrieve information for the subset of tracks
210     * selected.
211     * Selecting the same track multiple times has no effect, the track is
212     * only selected once.
213     */
214    public native void selectTrack(int index);
215
216    /**
217     * Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
218     * {@link #getSampleTime} only retrieve information for the subset of tracks
219     * selected.
220     */
221    public native void unselectTrack(int index);
222
223    /**
224     * If possible, seek to a sync sample at or before the specified time
225     */
226    public static final int SEEK_TO_PREVIOUS_SYNC       = 0;
227    /**
228     * If possible, seek to a sync sample at or after the specified time
229     */
230    public static final int SEEK_TO_NEXT_SYNC           = 1;
231    /**
232     * If possible, seek to the sync sample closest to the specified time
233     */
234    public static final int SEEK_TO_CLOSEST_SYNC        = 2;
235
236    /**
237     * All selected tracks seek near the requested time according to the
238     * specified mode.
239     */
240    public native void seekTo(long timeUs, int mode);
241
242    /**
243     * Advance to the next sample. Returns false if no more sample data
244     * is available (end of stream).
245     */
246    public native boolean advance();
247
248    /**
249     * Retrieve the current encoded sample and store it in the byte buffer
250     * starting at the given offset. Returns the sample size (or -1 if
251     * no more samples are available).
252     */
253    public native int readSampleData(ByteBuffer byteBuf, int offset);
254
255    /**
256     * Returns the track index the current sample originates from (or -1
257     * if no more samples are available)
258     */
259    public native int getSampleTrackIndex();
260
261    /**
262     * Returns the current sample's presentation time in microseconds.
263     * or -1 if no more samples are available.
264     */
265    public native long getSampleTime();
266
267    // Keep these in sync with their equivalents in NuMediaExtractor.h
268    /**
269     * The sample is a sync sample
270     */
271    public static final int SAMPLE_FLAG_SYNC      = 1;
272
273    /**
274     * The sample is (at least partially) encrypted, see also the documentation
275     * for {@link android.media.MediaCodec#queueSecureInputBuffer}
276     */
277    public static final int SAMPLE_FLAG_ENCRYPTED = 2;
278
279    /**
280     * Returns the current sample's flags.
281     */
282    public native int getSampleFlags();
283
284    /**
285     * If the sample flags indicate that the current sample is at least
286     * partially encrypted, this call returns relevant information about
287     * the structure of the sample data required for decryption.
288     * @param info The android.media.MediaCodec.CryptoInfo structure
289     *             to be filled in.
290     * @return true iff the sample flags contain {@link #SAMPLE_FLAG_ENCRYPTED}
291     */
292    public native boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info);
293
294    /**
295     * Returns an estimate of how much data is presently cached in memory
296     * expressed in microseconds. Returns -1 if that information is unavailable
297     * or not applicable (no cache).
298     */
299    public native long getCachedDuration();
300
301    /**
302     * Returns true iff we are caching data and the cache has reached the
303     * end of the data stream (for now, a future seek may of course restart
304     * the fetching of data).
305     * This API only returns a meaningful result if {@link #getCachedDuration}
306     * indicates the presence of a cache, i.e. does NOT return -1.
307     */
308    public native boolean hasCacheReachedEndOfStream();
309
310    private static native final void native_init();
311    private native final void native_setup();
312    private native final void native_finalize();
313
314    static {
315        System.loadLibrary("media_jni");
316        native_init();
317    }
318
319    private int mNativeContext;
320}
321