Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: media/base/android/media_codec_bridge.cc

Issue 16114009: Add AAC codec specific data for MSE on android (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressing comments Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/android/media_codec_bridge.h ('k') | media/mp4/aac.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/android/media_codec_bridge.h" 5 #include "media/base/android/media_codec_bridge.h"
6 6
7 #include <jni.h> 7 #include <jni.h>
8 8
9 #include "base/android/build_info.h" 9 #include "base/android/build_info.h"
10 #include "base/android/jni_android.h" 10 #include "base/android/jni_android.h"
11 #include "base/android/jni_array.h" 11 #include "base/android/jni_array.h"
12 #include "base/android/jni_string.h" 12 #include "base/android/jni_string.h"
13 #include "base/basictypes.h" 13 #include "base/basictypes.h"
14 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/safe_numerics.h" 16 #include "base/safe_numerics.h"
17 #include "base/stringprintf.h" 17 #include "base/stringprintf.h"
18
19 #include "jni/MediaCodecBridge_jni.h" 18 #include "jni/MediaCodecBridge_jni.h"
19 #include "media/base/bit_reader.h"
20 20
21 using base::android::AttachCurrentThread; 21 using base::android::AttachCurrentThread;
22 using base::android::ConvertUTF8ToJavaString; 22 using base::android::ConvertUTF8ToJavaString;
23 using base::android::ScopedJavaLocalRef; 23 using base::android::ScopedJavaLocalRef;
24 24
25 namespace media { 25 namespace media {
26 26
27 enum { kBufferFlagEndOfStream = 4 }; 27 enum { kBufferFlagEndOfStream = 4 };
28 28
29 static const char* AudioCodecToMimeType(const AudioCodec codec) { 29 static const char* AudioCodecToMimeType(const AudioCodec codec) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 76
77 MediaCodecBridge::~MediaCodecBridge() { 77 MediaCodecBridge::~MediaCodecBridge() {
78 JNIEnv* env = AttachCurrentThread(); 78 JNIEnv* env = AttachCurrentThread();
79 CHECK(env); 79 CHECK(env);
80 Java_MediaCodecBridge_release(env, j_media_codec_.obj()); 80 Java_MediaCodecBridge_release(env, j_media_codec_.obj());
81 } 81 }
82 82
83 void MediaCodecBridge::StartInternal() { 83 void MediaCodecBridge::StartInternal() {
84 JNIEnv* env = AttachCurrentThread(); 84 JNIEnv* env = AttachCurrentThread();
85 Java_MediaCodecBridge_start(env, j_media_codec_.obj()); 85 Java_MediaCodecBridge_start(env, j_media_codec_.obj());
86 GetOutputBuffers();
86 } 87 }
87 88
88 void MediaCodecBridge::Reset() { 89 void MediaCodecBridge::Reset() {
89 JNIEnv* env = AttachCurrentThread(); 90 JNIEnv* env = AttachCurrentThread();
90 Java_MediaCodecBridge_flush(env, j_media_codec_.obj()); 91 Java_MediaCodecBridge_flush(env, j_media_codec_.obj());
91 } 92 }
92 93
93 void MediaCodecBridge::Stop() { 94 void MediaCodecBridge::Stop() {
94 JNIEnv* env = AttachCurrentThread(); 95 JNIEnv* env = AttachCurrentThread();
95 Java_MediaCodecBridge_stop(env, j_media_codec_.obj()); 96 Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 JNIEnv* env = AttachCurrentThread(); 187 JNIEnv* env = AttachCurrentThread();
187 DCHECK(AudioCodecToMimeType(codec)); 188 DCHECK(AudioCodecToMimeType(codec));
188 189
189 ScopedJavaLocalRef<jstring> j_mime = 190 ScopedJavaLocalRef<jstring> j_mime =
190 ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec)); 191 ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec));
191 ScopedJavaLocalRef<jobject> j_format( 192 ScopedJavaLocalRef<jobject> j_format(
192 Java_MediaCodecBridge_createAudioFormat( 193 Java_MediaCodecBridge_createAudioFormat(
193 env, j_mime.obj(), sample_rate, channel_count)); 194 env, j_mime.obj(), sample_rate, channel_count));
194 DCHECK(!j_format.is_null()); 195 DCHECK(!j_format.is_null());
195 196
196 if (extra_data_size > 0) { 197 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size))
197 DCHECK_EQ(kCodecVorbis, codec); 198 return false;
198 if (extra_data[0] != 2) {
199 LOG(ERROR) << "Invalid number of headers before the codec header: "
200 << extra_data[0];
201 return false;
202 }
203
204 size_t header_length[2];
205 // |total_length| keeps track of the total number of bytes before the last
206 // header.
207 size_t total_length = 1;
208 const uint8* current_pos = extra_data;
209 // Calculate the length of the first 2 headers.
210 for (int i = 0; i < 2; ++i) {
211 header_length[i] = 0;
212 while (total_length < extra_data_size) {
213 size_t size = *(++current_pos);
214 total_length += 1 + size;
215 if (total_length > 0x80000000) {
216 LOG(ERROR) << "Header size too large";
217 return false;
218 }
219 header_length[i] += size;
220 if (size < 0xFF)
221 break;
222 }
223 if (total_length >= extra_data_size) {
224 LOG(ERROR) << "Invalid header size in the extra data";
225 return false;
226 }
227 }
228 current_pos++;
229 // The first header is identification header.
230 jobject identification_header = env->NewDirectByteBuffer(
231 const_cast<uint8*>(current_pos), header_length[0]);
232 Java_MediaCodecBridge_setCodecSpecificData(
233 env, j_format.obj(), 0, identification_header);
234 // The last header is codec header.
235 jobject codec_header = env->NewDirectByteBuffer(
236 const_cast<uint8*>(extra_data + total_length),
237 extra_data_size - total_length);
238 Java_MediaCodecBridge_setCodecSpecificData(
239 env, j_format.obj(), 1, codec_header);
240 env->DeleteLocalRef(codec_header);
241 env->DeleteLocalRef(identification_header);
242 }
243 199
244 Java_MediaCodecBridge_configureAudio( 200 Java_MediaCodecBridge_configureAudio(
245 env, media_codec(), j_format.obj(), NULL, 0, play_audio); 201 env, media_codec(), j_format.obj(), NULL, 0, play_audio);
246 StartInternal(); 202 StartInternal();
247 return true; 203 return true;
248 } 204 }
249 205
206 bool AudioCodecBridge::ConfigureMediaFormat(
207 jobject j_format, const AudioCodec codec, const uint8* extra_data,
208 size_t extra_data_size) {
209 if (extra_data_size == 0)
210 return true;
211
212 JNIEnv* env = AttachCurrentThread();
213 switch(codec) {
214 case kCodecVorbis:
215 {
216 if (extra_data[0] != 2) {
217 LOG(ERROR) << "Invalid number of vorbis headers before the codec "
218 << "header: " << extra_data[0];
219 return false;
220 }
221
222 size_t header_length[2];
223 // |total_length| keeps track of the total number of bytes before the last
224 // header.
225 size_t total_length = 1;
226 const uint8* current_pos = extra_data;
227 // Calculate the length of the first 2 headers.
228 for (int i = 0; i < 2; ++i) {
229 header_length[i] = 0;
230 while (total_length < extra_data_size) {
231 size_t size = *(++current_pos);
232 total_length += 1 + size;
233 if (total_length > 0x80000000) {
234 LOG(ERROR) << "Vorbis header size too large";
235 return false;
236 }
237 header_length[i] += size;
238 if (size < 0xFF)
239 break;
240 }
241 if (total_length >= extra_data_size) {
242 LOG(ERROR) << "Invalid vorbis header size in the extra data";
243 return false;
244 }
245 }
246 current_pos++;
247 // The first header is identification header.
248 jobject identification_header = env->NewDirectByteBuffer(
249 const_cast<uint8*>(current_pos), header_length[0]);
250 Java_MediaCodecBridge_setCodecSpecificData(
251 env, j_format, 0, identification_header);
252 // The last header is codec header.
253 jobject codec_header = env->NewDirectByteBuffer(
254 const_cast<uint8*>(extra_data + total_length),
255 extra_data_size - total_length);
256 Java_MediaCodecBridge_setCodecSpecificData(
257 env, j_format, 1, codec_header);
258 env->DeleteLocalRef(codec_header);
259 env->DeleteLocalRef(identification_header);
260 break;
261 }
262 case kCodecAAC:
263 {
264 media::BitReader reader(extra_data, extra_data_size);
265
266 // The following code is copied from aac.cc
267 // TODO(qinmin): refactor the code in aac.cc to make it more reusable.
268 uint8 profile = 0;
269 uint8 frequency_index = 0;
270 uint8 channel_config = 0;
271 if (!reader.ReadBits(5, &profile) ||
272 !reader.ReadBits(4, &frequency_index)) {
273 LOG(ERROR) << "Unable to parse AAC header";
274 return false;
275 }
276 if (0xf == frequency_index && !reader.SkipBits(24)) {
277 LOG(ERROR) << "Unable to parse AAC header";
278 return false;
279 }
280 if (!reader.ReadBits(4, &channel_config)) {
281 LOG(ERROR) << "Unable to parse AAC header";
282 return false;
283 }
284
285 if (profile < 1 || profile > 4 || frequency_index == 0xf ||
286 channel_config > 7) {
287 LOG(ERROR) << "Invalid AAC header";
288 return false;
289 }
290 uint8 csd[2];
291 csd[0] = profile << 3 | frequency_index >> 1;
292 csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3;
293 jobject header = env->NewDirectByteBuffer(csd, 2);
294 Java_MediaCodecBridge_setCodecSpecificData(
295 env, j_format, 0, header);
296 // TODO(qinmin): pass an extra variable to this function to determine
297 // whether we need to call this.
298 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format);
299 env->DeleteLocalRef(header);
300 break;
301 }
302 default:
303 LOG(ERROR) << "Invalid header encountered for codec: "
304 << AudioCodecToMimeType(codec);
305 return false;
306 }
307 return true;
308 }
309
250 void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) { 310 void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) {
251 DCHECK_LE(0, index); 311 DCHECK_LE(0, index);
252 int numBytes = base::checked_numeric_cast<int>(size); 312 int numBytes = base::checked_numeric_cast<int>(size);
253 JNIEnv* env = AttachCurrentThread(); 313 JNIEnv* env = AttachCurrentThread();
254 ScopedJavaLocalRef<jobject> buf = 314 ScopedJavaLocalRef<jobject> buf =
255 Java_MediaCodecBridge_getOutputBuffer(env, media_codec(), index); 315 Java_MediaCodecBridge_getOutputBuffer(env, media_codec(), index);
256 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(buf.obj())); 316 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(buf.obj()));
257 317
258 ScopedJavaLocalRef<jbyteArray> byte_array = 318 ScopedJavaLocalRef<jbyteArray> byte_array =
259 base::android::ToJavaByteArray(env, buffer, numBytes); 319 base::android::ToJavaByteArray(env, buffer, numBytes);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 const char* mime = VideoCodecToMimeType(codec); 351 const char* mime = VideoCodecToMimeType(codec);
292 return mime ? new VideoCodecBridge(mime) : NULL; 352 return mime ? new VideoCodecBridge(mime) : NULL;
293 } 353 }
294 354
295 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) { 355 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
296 return RegisterNativesImpl(env); 356 return RegisterNativesImpl(env);
297 } 357 }
298 358
299 } // namespace media 359 } // namespace media
300 360
OLDNEW
« no previous file with comments | « media/base/android/media_codec_bridge.h ('k') | media/mp4/aac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698