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