OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/base/android/media_codec_bridge.h" | |
6 | |
7 #include <jni.h> | |
8 | |
9 #include "base/android/jni_android.h" | |
10 #include "base/android/jni_array.h" | |
11 #include "base/android/jni_string.h" | |
12 #include "base/basictypes.h" | |
13 #include "base/logging.h" | |
14 #include "base/stringprintf.h" | |
15 | |
16 #include "jni/MediaFormat_jni.h" | |
17 #include "jni/MediaCodec_jni.h" | |
18 | |
19 | |
20 using base::android::AttachCurrentThread; | |
21 using base::android::ConvertUTF8ToJavaString; | |
22 using base::android::ScopedJavaLocalRef; | |
23 | |
24 namespace { | |
25 | |
26 static jclass g_MediaCodecBufferInfo_clazz = NULL; | |
27 | |
28 static const char kMediaCodecBufferInfoClassPath[] = | |
29 "android/media/MediaCodec$BufferInfo"; | |
30 | |
31 static bool MediaCodecBufferInfo_RegisterNativesImpl(JNIEnv* env) { | |
32 g_MediaCodecBufferInfo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( | |
33 base::android::GetUnscopedClass(env, kMediaCodecBufferInfoClassPath))); | |
34 base::android::CheckException(env); | |
35 return true; | |
36 } | |
37 | |
38 static void GetBufferInfo(JNIEnv* env, jobject buffer_info, int* offset, | |
39 int* size, int64* presentation_time, int* flags) { | |
40 static jfieldID offset_id = | |
41 env->GetFieldID(g_MediaCodecBufferInfo_clazz, "offset", "I"); | |
42 static jfieldID size_id = | |
43 env->GetFieldID(g_MediaCodecBufferInfo_clazz, "size", "I"); | |
44 static jfieldID presentation_time_id = | |
45 env->GetFieldID(g_MediaCodecBufferInfo_clazz, "presentationTimeUs", "J"); | |
46 static jfieldID flags_id = | |
47 env->GetFieldID(g_MediaCodecBufferInfo_clazz, "flags", "I"); | |
48 | |
49 *offset = static_cast<int>(env->GetIntField(buffer_info, offset_id)); | |
50 *size = static_cast<int>(env->GetIntField(buffer_info, size_id)); | |
51 *presentation_time = | |
52 static_cast<int64>(env->GetLongField(buffer_info, presentation_time_id)); | |
53 *flags = static_cast<int>(env->GetIntField(buffer_info, flags_id)); | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
are the static_cast<int>'s really necessary?
dwkang1
2013/02/04 14:08:26
Removed.
dwkang1
2013/02/04 14:08:26
Removed.
| |
54 } | |
55 | |
56 static base::subtle::AtomicWord g_MediaCodecBufferInfo_Constructor = 0; | |
57 static ScopedJavaLocalRef<jobject> Java_MediaCodecBufferInfo_Constructor( | |
58 JNIEnv* env) { | |
59 /* Must call RegisterNativesImpl() */ | |
60 DCHECK(g_MediaCodecBufferInfo_clazz); | |
61 jmethodID method_id = | |
62 base::android::MethodID::LazyGet<base::android::MethodID::TYPE_INSTANCE>( | |
63 env, g_MediaCodecBufferInfo_clazz, | |
64 "<init>", "()V", | |
65 &g_MediaCodecBufferInfo_Constructor); | |
66 | |
67 jobject ret = env->NewObject(g_MediaCodecBufferInfo_clazz, method_id); | |
68 base::android::CheckException(env); | |
69 return ScopedJavaLocalRef<jobject>(env, ret); | |
70 } | |
71 | |
72 void RegisterNativesIfNeeded(JNIEnv* env) { | |
73 static bool jni_initialized = false; | |
74 if (!jni_initialized) { | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
This is both racy and unreadable :)
You have:
st
dwkang1
2013/02/04 14:08:26
Thanks for the advise. btw, do you have any refere
| |
75 jni_initialized = ( | |
76 JNI_MediaCodec::RegisterNativesImpl(env) | |
77 && MediaCodecBufferInfo_RegisterNativesImpl(env) | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
operator goes on previous line (here and elsewhere
dwkang1
2013/02/04 14:08:26
Done.
| |
78 && JNI_MediaFormat::RegisterNativesImpl(env)); | |
79 DCHECK(jni_initialized); | |
80 } | |
81 } | |
82 } // namespace | |
83 | |
84 namespace media { | |
85 | |
86 typedef struct { | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
This is C++;
typedef struct { ... } Name;
is more
dwkang1
2013/02/04 14:08:26
Done.
| |
87 MediaCodecBridge::Codec codec_type_; | |
88 const char* mime_type_; | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
de-indent 2 spaces
dwkang1
2013/02/04 14:08:26
Done.
| |
89 } CodecMapEntry; | |
90 | |
91 static | |
92 const CodecMapEntry kCodecMimeTypeTable[] = { | |
93 { MediaCodecBridge::AUDIO_MPEG, "audio/mpeg" }, | |
94 { MediaCodecBridge::VIDEO_H264, "video/avc" }, | |
95 { MediaCodecBridge::VIDEO_VP8, "video/x-vnd.on2.vp8" }, | |
96 { MediaCodecBridge::UNKNOWN, NULL }, | |
97 }; | |
98 | |
99 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
Drop in favor of arraysize()
https://code.google.c
dwkang1
2013/02/04 14:08:26
Thanks for the link.
| |
100 | |
101 static | |
102 const char* CodecToMimeType(const MediaCodecBridge::Codec codec) { | |
103 for (int i = 0; i < NELEM(kCodecMimeTypeTable); ++i) { | |
104 if (kCodecMimeTypeTable[i].codec_type_ == codec) { | |
105 return kCodecMimeTypeTable[i].mime_type_; | |
106 } | |
107 } | |
108 return NULL; | |
109 } | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
l.86-109 can be replaced with the 9 lines:
static
dwkang1
2013/02/04 14:08:26
Done.
| |
110 | |
111 MediaCodecBridge::MediaCodecBridge(const Codec codec) { | |
112 JNIEnv* env = AttachCurrentThread(); | |
113 CHECK(env); | |
114 RegisterNativesIfNeeded(env); | |
115 DCHECK(CodecToMimeType(codec)); | |
116 | |
117 ScopedJavaLocalRef<jstring> j_type = | |
118 ConvertUTF8ToJavaString(env, CodecToMimeType(codec)); | |
119 | |
120 ScopedJavaLocalRef<jobject> tmp( | |
121 JNI_MediaCodec::Java_MediaCodec_createDecoderByType(env, j_type.obj())); | |
122 DCHECK(!tmp.is_null()); | |
123 j_media_codec_.Reset(tmp); | |
124 } | |
125 | |
126 MediaCodecBridge::~MediaCodecBridge() { | |
127 JNIEnv* env = AttachCurrentThread(); | |
128 CHECK(env); | |
129 | |
130 JNI_MediaCodec::Java_MediaCodec_release(env, j_media_codec_.obj()); | |
131 } | |
132 | |
133 void MediaCodecBridge::ConfigureAudio( | |
134 const Codec codec, int sample_rate, int channel_count) { | |
135 JNIEnv* env = AttachCurrentThread(); | |
136 CHECK(env); | |
137 DCHECK(CodecToMimeType(codec)); | |
138 | |
139 ScopedJavaLocalRef<jstring> j_mime = | |
140 ConvertUTF8ToJavaString(env, CodecToMimeType(codec)); | |
141 ScopedJavaLocalRef<jobject> j_format( | |
142 JNI_MediaFormat::Java_MediaFormat_createAudioFormat( | |
143 env, j_mime.obj(), sample_rate, channel_count)); | |
144 DCHECK(!j_format.is_null()); | |
145 | |
146 JNI_MediaCodec::Java_MediaCodec_configure( | |
147 env, j_media_codec_.obj(), j_format.obj(), NULL, NULL, 0); | |
148 | |
149 JNI_MediaCodec::Java_MediaCodec_start(env, j_media_codec_.obj()); | |
150 } | |
151 | |
152 void MediaCodecBridge::ConfigureVideo( | |
153 const Codec codec, const gfx::Size& size, jobject surface) { | |
154 JNIEnv* env = AttachCurrentThread(); | |
155 CHECK(env); | |
156 DCHECK(CodecToMimeType(codec)); | |
157 | |
158 ScopedJavaLocalRef<jstring> j_mime = | |
159 ConvertUTF8ToJavaString(env, CodecToMimeType(codec)); | |
160 ScopedJavaLocalRef<jobject> j_format( | |
161 JNI_MediaFormat::Java_MediaFormat_createVideoFormat( | |
162 env, j_mime.obj(), size.width(), size.height())); | |
163 DCHECK(!j_format.is_null()); | |
164 | |
165 JNI_MediaCodec::Java_MediaCodec_configure( | |
166 env, j_media_codec_.obj(), j_format.obj(), surface, NULL, 0); | |
167 | |
168 JNI_MediaCodec::Java_MediaCodec_start(env, j_media_codec_.obj()); | |
169 } | |
170 | |
171 void MediaCodecBridge::Flush() { | |
172 JNIEnv* env = AttachCurrentThread(); | |
173 CHECK(env); | |
174 | |
175 JNI_MediaCodec::Java_MediaCodec_flush(env, j_media_codec_.obj()); | |
176 } | |
177 | |
178 void MediaCodecBridge::Stop() { | |
179 JNIEnv* env = AttachCurrentThread(); | |
180 CHECK(env); | |
181 | |
182 JNI_MediaCodec::Java_MediaCodec_stop(env, j_media_codec_.obj()); | |
183 } | |
184 | |
185 void MediaCodecBridge::GetOutputFormat(int* format, int* width, int* height) { | |
186 JNIEnv* env = AttachCurrentThread(); | |
187 CHECK(env); | |
188 | |
189 ScopedJavaLocalRef<jobject> j_format( | |
190 JNI_MediaCodec::Java_MediaCodec_getOutputFormat( | |
191 env, j_media_codec_.obj())); | |
192 if (!j_format.is_null()) { | |
193 ScopedJavaLocalRef<jstring> j_key_format = | |
194 ConvertUTF8ToJavaString(env, "color-format"); | |
195 *format = static_cast<int>(JNI_MediaFormat::Java_MediaFormat_getInteger( | |
196 env, j_format.obj(), j_key_format.obj())); | |
197 | |
198 ScopedJavaLocalRef<jstring> j_key_width = | |
199 ConvertUTF8ToJavaString(env, "width"); | |
200 *width = static_cast<int>(JNI_MediaFormat::Java_MediaFormat_getInteger( | |
201 env, j_format.obj(), j_key_width.obj())); | |
202 | |
203 ScopedJavaLocalRef<jstring> j_key_height = | |
204 ConvertUTF8ToJavaString(env, "height"); | |
205 *height = static_cast<int>(JNI_MediaFormat::Java_MediaFormat_getInteger( | |
206 env, j_format.obj(), j_key_height.obj())); | |
207 } | |
208 } | |
209 | |
210 void MediaCodecBridge::QueueInputBuffer( | |
211 int index, int offset, int size, int64 presentation_time_us, int flags) { | |
212 JNIEnv* env = AttachCurrentThread(); | |
213 CHECK(env); | |
214 | |
215 JNI_MediaCodec::Java_MediaCodec_queueInputBuffer( | |
216 env, j_media_codec_.obj(), | |
217 static_cast<jint>(index), static_cast<jint>(offset), | |
218 static_cast<jint>(size), static_cast<jlong>(presentation_time_us), | |
219 static_cast<jint>(flags)); | |
220 } | |
221 | |
222 int MediaCodecBridge::DequeueInputBuffer(int64 timeout_us) { | |
223 JNIEnv* env = AttachCurrentThread(); | |
224 CHECK(env); | |
225 | |
226 return JNI_MediaCodec::Java_MediaCodec_dequeueInputBuffer( | |
227 env, j_media_codec_.obj(), static_cast<jlong>(timeout_us)); | |
228 } | |
229 | |
230 int MediaCodecBridge::DequeueOutputBuffer( | |
231 int64 timeout_us, int* offset, int* size, int64* presentation_time_us, | |
232 int* flags) { | |
233 JNIEnv* env = AttachCurrentThread(); | |
234 CHECK(env); | |
235 | |
236 ScopedJavaLocalRef<jobject> j_info( | |
237 Java_MediaCodecBufferInfo_Constructor(env)); | |
238 jint j_buffer = JNI_MediaCodec::Java_MediaCodec_dequeueOutputBuffer( | |
239 env, j_media_codec_.obj(), j_info.obj(), static_cast<jlong>(timeout_us)); | |
240 | |
241 if (j_buffer >= 0) { | |
242 GetBufferInfo(env, j_info.obj(), offset, size, presentation_time_us, flags); | |
243 } | |
244 return static_cast<int>(j_buffer); | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
drop the cast? (here and elsewhere)
dwkang1
2013/02/04 14:08:26
Done.
| |
245 } | |
246 | |
247 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) { | |
248 JNIEnv* env = AttachCurrentThread(); | |
249 CHECK(env); | |
250 | |
251 JNI_MediaCodec::Java_MediaCodec_releaseOutputBuffer( | |
252 env, j_media_codec_.obj(), static_cast<jint>(index), | |
253 static_cast<jboolean>(render)); | |
254 } | |
255 | |
256 int MediaCodecBridge::GetInputBuffers() { | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
Why do you need to expose this as a public API of
dwkang1
2013/02/04 14:08:26
According to the api doc we need to call getOutput
| |
257 JNIEnv* env = AttachCurrentThread(); | |
258 CHECK(env); | |
259 | |
260 j_input_buffers_.Reset( | |
261 JNI_MediaCodec::Java_MediaCodec_getInputBuffers( | |
262 env, j_media_codec_.obj())); | |
263 | |
264 return env->GetArrayLength(j_input_buffers_.obj()); | |
265 } | |
266 | |
267 int MediaCodecBridge::GetOutputBuffers() { | |
268 JNIEnv* env = AttachCurrentThread(); | |
269 CHECK(env); | |
270 | |
271 j_output_buffers_.Reset( | |
272 JNI_MediaCodec::Java_MediaCodec_getOutputBuffers( | |
273 env, j_media_codec_.obj())); | |
274 | |
275 return env->GetArrayLength(j_output_buffers_.obj()); | |
276 } | |
277 | |
278 void MediaCodecBridge::PutToInputBuffer( | |
279 int index, const uint8* data, int size) { | |
280 JNIEnv* env = AttachCurrentThread(); | |
281 CHECK(env); | |
282 | |
283 ScopedJavaLocalRef<jobject> j_buffer( | |
284 env, env->GetObjectArrayElement(j_input_buffers_.obj(), index)); | |
285 | |
286 uint8* direct_buffer = | |
287 static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj())); | |
288 memcpy(direct_buffer, data, size); | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
I think you missed my comment about |size| being t
dwkang1
2013/01/29 03:58:48
Sorry for the missing your previous comment. Will
dwkang1
2013/02/04 14:08:26
Changed to return # of bytes written.
| |
289 } | |
290 | |
291 void MediaCodecBridge::GetFromOutputBuffer( | |
292 int index, int offset, uint8* data, int size) { | |
293 JNIEnv* env = AttachCurrentThread(); | |
294 CHECK(env); | |
295 | |
296 ScopedJavaLocalRef<jobject> j_buffer( | |
297 env, env->GetObjectArrayElement(j_output_buffers_.obj(), index)); | |
298 | |
299 uint8* direct_buffer = | |
300 static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj())); | |
301 memcpy(data, direct_buffer + offset, size); | |
Ami GONE FROM CHROMIUM
2013/01/28 19:49:45
Ditto you need some way to guarantee the requested
dwkang1
2013/02/04 14:08:26
Dropped. :)
| |
302 } | |
303 | |
304 } // namespace media | |
305 | |
OLD | NEW |