1d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang/*
2d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Copyright (C) 2017 The Android Open Source Project
3d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *
4d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
5d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * you may not use this file except in compliance with the License.
6d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * You may obtain a copy of the License at
7d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *
8d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
9d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *
10d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Unless required by applicable law or agreed to in writing, software
11d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
12d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * See the License for the specific language governing permissions and
14d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * limitations under the License.
15d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */
16d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
17d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangpackage android.media;
18d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
19d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.annotation.NonNull;
202659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport android.hardware.cas.V1_0.*;
21dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhangimport android.media.MediaCasException.UnsupportedCasException;
222659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport android.os.IHwBinder;
23d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.RemoteException;
24dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhangimport android.os.ServiceSpecificException;
25d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.util.Log;
26d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
27d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport java.nio.ByteBuffer;
28d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
29d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang/**
30d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec}
31d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * and {@link android.media.MediaExtractor} to decode media data scrambled by conditional
32d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * access (CA) systems such as those in the ISO/IEC13818-1.
33d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *
34d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * A MediaDescrambler object is initialized from a session opened by a MediaCas object,
35d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * and can be used to descramble media streams scrambled with that session's keys.
36d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *
37d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Scrambling schemes are identified by 16-bit unsigned integer as in CA_system_id.
38d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang *
39d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */
40addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhangpublic final class MediaDescrambler implements AutoCloseable {
41d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private static final String TAG = "MediaDescrambler";
422659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang    private IDescramblerBase mIDescrambler;
43d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
44d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private final void validateInternalStates() {
45d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        if (mIDescrambler == null) {
46d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            throw new IllegalStateException();
47d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        }
48d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
49d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
50d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private final void cleanupAndRethrowIllegalState() {
51d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        mIDescrambler = null;
52d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        throw new IllegalStateException();
53d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
54d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
55d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    /**
56d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * Instantiate a MediaDescrambler.
57d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
58d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @param CA_system_id The system id of the scrambling scheme.
59d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
60d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @throws UnsupportedCasException if the scrambling scheme is not supported.
61d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     */
62d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    public MediaDescrambler(int CA_system_id) throws UnsupportedCasException {
63d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        try {
64d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id);
65d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } catch(Exception e) {
66d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            Log.e(TAG, "Failed to create descrambler: " + e);
67d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            mIDescrambler = null;
68d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } finally {
69d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            if (mIDescrambler == null) {
70d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id);
71d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            }
72d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        }
73d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        native_setup(mIDescrambler.asBinder());
74d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
75d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
762659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang    IHwBinder getBinder() {
77d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        validateInternalStates();
78d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
79d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        return mIDescrambler.asBinder();
80d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
81d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
82d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    /**
83d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * Query if the scrambling scheme requires the use of a secure decoder
84d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * to decode data of the given mime type.
85d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
86d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @param mime The mime type of the media data
87d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
88d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @throws IllegalStateException if the descrambler instance is not valid.
89d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     */
90d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    public final boolean requiresSecureDecoderComponent(@NonNull String mime) {
91d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        validateInternalStates();
92d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
93d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        try {
94d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            return mIDescrambler.requiresSecureDecoderComponent(mime);
95d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } catch (RemoteException e) {
96d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            cleanupAndRethrowIllegalState();
97d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        }
98d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        return true;
99d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
100d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
101d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    /**
102d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * Associate a MediaCas session with this MediaDescrambler instance.
103d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * The MediaCas session is used to securely load decryption keys for
104d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * the descrambler. The crypto keys loaded through the MediaCas session
105d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * may be selected for use during the descrambling operation performed
106d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * by {@link android.media.MediaExtractor or @link
107d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * android.media.MediaCodec#queueSecureInputBuffer} by specifying even
108d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * or odd key in the {@link android.media.MediaCodec.CryptoInfo#key} field.
109d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
110addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang     * @param session the MediaCas session to associate with this
111d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * MediaDescrambler instance.
112d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
113dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang     * @throws IllegalStateException if the descrambler instance is not valid.
114dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang     * @throws MediaCasStateException for CAS-specific state exceptions.
115d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     */
116addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang    public final void setMediaCasSession(@NonNull MediaCas.Session session) {
117d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        validateInternalStates();
118d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
119d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        try {
1202659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang            MediaCasStateException.throwExceptionIfNeeded(
1212659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang                    mIDescrambler.setMediaCasSession(session.mSessionId));
122d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } catch (RemoteException e) {
123d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            cleanupAndRethrowIllegalState();
124d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        }
125d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
126d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
127d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    /**
128d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * Descramble a ByteBuffer of data described by a
129d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * {@link android.media.MediaCodec.CryptoInfo} structure.
130d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
131addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang     * @param srcBuf ByteBuffer containing the scrambled data, which starts at
132addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang     * srcBuf.position().
133addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang     * @param dstBuf ByteBuffer to hold the descrambled data, which starts at
134addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang     * dstBuf.position().
135d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure
136d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * describing the subsamples contained in src.
137d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
138d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @return number of bytes that have been successfully descrambled, with negative
139d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * values indicating errors.
140d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     *
141d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     * @throws IllegalStateException if the descrambler instance is not valid.
142dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang     * @throws MediaCasStateException for CAS-specific state exceptions.
143d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang     */
144d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    public final int descramble(
145addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang            @NonNull ByteBuffer srcBuf, @NonNull ByteBuffer dstBuf,
146d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            @NonNull MediaCodec.CryptoInfo cryptoInfo) {
147d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        validateInternalStates();
148d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
149d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        if (cryptoInfo.numSubSamples <= 0) {
150d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            throw new IllegalArgumentException(
151d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                    "Invalid CryptoInfo: invalid numSubSamples=" + cryptoInfo.numSubSamples);
152d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } else if (cryptoInfo.numBytesOfClearData == null
153d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                && cryptoInfo.numBytesOfEncryptedData == null) {
154d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            throw new IllegalArgumentException(
155d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                    "Invalid CryptoInfo: clearData and encryptedData size arrays are both null!");
156d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } else if (cryptoInfo.numBytesOfClearData != null
157d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                && cryptoInfo.numBytesOfClearData.length < cryptoInfo.numSubSamples) {
158d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            throw new IllegalArgumentException(
159d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                    "Invalid CryptoInfo: numBytesOfClearData is too small!");
160d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } else if (cryptoInfo.numBytesOfEncryptedData != null
161d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                && cryptoInfo.numBytesOfEncryptedData.length < cryptoInfo.numSubSamples) {
162d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            throw new IllegalArgumentException(
163d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                    "Invalid CryptoInfo: numBytesOfEncryptedData is too small!");
164d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        } else if (cryptoInfo.key == null || cryptoInfo.key.length != 16) {
165d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            throw new IllegalArgumentException(
166d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                    "Invalid CryptoInfo: key array is invalid!");
167d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        }
168d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
169dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang        try {
170dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang            return native_descramble(
171dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang                    cryptoInfo.key[0],
172dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang                    cryptoInfo.numSubSamples,
173dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang                    cryptoInfo.numBytesOfClearData,
174dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang                    cryptoInfo.numBytesOfEncryptedData,
175addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang                    srcBuf, srcBuf.position(), srcBuf.limit(),
176addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang                    dstBuf, dstBuf.position(), dstBuf.limit());
177dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang        } catch (ServiceSpecificException e) {
1782659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang            MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
1792659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang        } catch (RemoteException e) {
1802659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang            cleanupAndRethrowIllegalState();
181dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang        }
182dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang        return -1;
183d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
184d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
185addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang    @Override
186addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang    public void close() {
187d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        if (mIDescrambler != null) {
188d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            try {
189d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                mIDescrambler.release();
190d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            } catch (RemoteException e) {
191d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            } finally {
192d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang                mIDescrambler = null;
193d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            }
194d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        }
195d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        native_release();
196d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
197d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
198d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    @Override
199d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    protected void finalize() {
200addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang        close();
201d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
202d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
203d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private static native final void native_init();
2042659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang    private native final void native_setup(@NonNull IHwBinder decramblerBinder);
205d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private native final void native_release();
206d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private native final int native_descramble(
207d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
208addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang            @NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit,
2092659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang            ByteBuffer dstBuf, int dstOffset, int dstLimit) throws RemoteException;
210d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
211d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    static {
212d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        System.loadLibrary("media_jni");
213d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        native_init();
214d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    }
215d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
216d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    private long mNativeContext;
217d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang}