Tôi muốn sử dụng Android MediaCodec để giải mã luồng video, sau đó sử dụng hình ảnh đầu ra để xử lý hình ảnh tiếp theo trong mã gốc.Vi phạm truy cập bằng mã gốc với bộ giải mã Android MediaCodec tăng tốc phần cứng
Nền tảng: ASUS tf700t android 4.1.1. Luồng thử nghiệm: H.264 full HD @ 24 frm/s
Với Tegra-3 SoC bên trong, tôi dựa vào phần cứng hỗ trợ giải mã video. Về mặt chức năng, ứng dụng của tôi hoạt động như mong đợi: Tôi thực sự có thể truy cập hình ảnh bộ giải mã và xử lý chúng đúng cách. Tuy nhiên, tôi trải nghiệm một tải CPU cpu rất cao.
Trong các thí nghiệm sau, tải quy trình/luồng được đo bằng "top -m 32 -t" trong trình bao adb. Để có được đầu ra đáng tin cậy từ "top", tất cả 4 lõi CPU được kích hoạt bằng cách chạy một vài chuỗi lặp mãi mãi ở mức ưu tiên thấp nhất. Điều này được xác nhận bằng cách thực thi liên tục "cat/sys/devices/system/cpu/cpu [0-3]/online". Để giữ cho mọi thứ đơn giản, chỉ có giải mã video, không có âm thanh; và không có điều khiển thời gian để bộ giải mã chạy nhanh nhất có thể.
Thử nghiệm đầu tiên: chạy ứng dụng, gọi hàm xử lý JNI, nhưng tất cả các cuộc gọi xử lý tiếp theo đều được nhận xét. Kết quả:
- thông: 25 frm/s
- 1% tải trọng của chủ đề VideoDecoder của ứng dụng
- 24% tải trọng của chủ đề Binder_3 của quá trình/system/bin/mediaserver
Nó có vẻ như tốc độ giải mã là CPU bị giới hạn (25% của CPU quad-core) ... Khi kích hoạt xử lý đầu ra, hình ảnh được giải mã là chính xác và ứng dụng hoạt động. Chỉ có vấn đề: tải CPU quá cao để giải mã.
Sau hàng loạt thử nghiệm, tôi đã cân nhắc đưa cho MediaCodec một bề mặt để vẽ kết quả của nó. Trong tất cả các khía cạnh khác, mã giống hệt nhau. Kết quả:
- thông 55 frm/s (đẹp !!)
- 2% tải trọng của chủ đề VideoDecoder của ứng dụng
- 1% tải trọng của chủ đề mediaserver của quá trình/system/bin/mediaserver
Thật vậy, video được hiển thị trên Bề mặt được cung cấp. Vì hầu như không có bất kỳ tải CPU nào, điều này phải được tăng tốc phần cứng ...
Dường như de MediaCodec chỉ sử dụng tăng tốc phần cứng nếu một Bề mặt được cung cấp?
Cho đến nay, rất tốt. Tôi đã có xu hướng sử dụng Surface như một công việc xung quanh (không bắt buộc, nhưng trong một số trường hợp thậm chí là một điều tốt đẹp để có). Nhưng, trong trường hợp một bề mặt được cung cấp, tôi không thể truy cập vào các hình ảnh đầu ra! Kết quả là vi phạm truy cập trong mã gốc.
Điều này thực sự giải đố tôi! Tôi không thấy bất kỳ khái niệm nào về các giới hạn truy cập, hoặc bất cứ điều gì trong tài liệu http://developer.android.com/reference/android/media/MediaCodec.html. Cũng không có gì theo hướng này được đề cập tại bản trình bày Google I/O http://www.youtube.com/watch?v=RQws6vsoav8.
Vậy: cách sử dụng bộ giải mã Android MediaCodec tăng tốc phần cứng và truy cập hình ảnh bằng mã gốc?Làm cách nào để tránh vi phạm quyền truy cập? Bất kỳ trợ giúp được đánh giá cao! Ngoài ra bất kỳ lời giải thích hoặc gợi ý.
Tôi khá chắc chắn MediaExtractor và MediaCodec được sử dụng đúng cách, vì ứng dụng có chức năng ok (miễn là tôi không cung cấp Bề mặt). Nó vẫn còn khá thực nghiệm, và một thiết kế API tốt nằm trong danh sách todo ;-)
Lưu ý rằng sự khác biệt duy nhất giữa hai thí nghiệm là biến mSurface: null hoặc một bề mặt thực tế trong "mDecoder.configure (mediaFormat , mSurface, null, 0); "
đang khởi:
mExtractor = new MediaExtractor();
mExtractor.setDataSource(mPath);
// Locate first video stream
for (int i = 0; i < mExtractor.getTrackCount(); i++) {
mediaFormat = mExtractor.getTrackFormat(i);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
Log.i(TAG, String.format("Stream %d/%d %s", i, mExtractor.getTrackCount(), mime));
if (streamId == -1 && mime.startsWith("video/")) {
streamId = i;
}
}
if (streamId == -1) {
Log.e(TAG, "Can't find video info in " + mPath);
return;
}
mExtractor.selectTrack(streamId);
mediaFormat = mExtractor.getTrackFormat(streamId);
mDecoder = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
mDecoder.configure(mediaFormat, mSurface, null, 0);
width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
Log.i(TAG, String.format("Image size: %dx%d format: %s", width, height, mediaFormat.toString()));
JniGlue.decoutStart(width, height);
Decoder vòng (chạy trong một thread riêng biệt):
ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
ByteBuffer[] outputBuffers = mDecoder.getOutputBuffers();
while (!isEOS && !Thread.interrupted()) {
int inIndex = mDecoder.dequeueInputBuffer(10000);
if (inIndex >= 0) {
// Valid buffer returned
int sampleSize = mExtractor.readSampleData(inputBuffers[inIndex], 0);
if (sampleSize < 0) {
Log.i(TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM");
mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
mExtractor.advance();
}
}
int outIndex = mDecoder.dequeueOutputBuffer(info, 10000);
if (outIndex >= 0) {
// Valid buffer returned
ByteBuffer buffer = outputBuffers[outIndex];
JniGlue.decoutFrame(buffer, info.offset, info.size);
mDecoder.releaseOutputBuffer(outIndex, true);
} else {
// Some INFO_* value returned
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.i(TAG, "RunDecoder: INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = mDecoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.i(TAG, "RunDecoder: New format " + mDecoder.getOutputFormat());
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
// Timeout - simply ignore
break;
default:
// Some other value, simply ignore
break;
}
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "RunDecoder: OutputBuffer BUFFER_FLAG_END_OF_STREAM");
isEOS = true;
}
}
Vẫn không có giải pháp. Mọi đề xuất vẫn được hoan nghênh. Ngoài ra đề xuất cho các thử nghiệm để tăng sự hiểu biết. Bất cứ ai có giải mã phần cứng làm việc bằng cách sử dụng MediaCodec? Có lẽ trên một nền tảng khác? – Bram
Bram, tôi đang cố gắng giải quyết chính xác cùng một vấn đề. Dường như sự chậm lại này không phải là về nhiều bản sao của bộ đệm được giải mã.Khi dữ liệu được giải mã có nghĩa là để trình bày lên một bề mặt riêng, có vẻ như có một số đường dẫn dữ liệu trực tiếp và nó sử dụng TILER (kết xuất lát gạch). Khi bạn cần truy cập khung YUV đầy đủ (ví dụ: bạn muốn truy cập bộ giải mã được giải mã) bộ giải mã cần thực hiện thêm một số tác vụ như hiển thị tất cả dữ liệu đó vào bộ nhớ đệm và sao chép nó làm chậm quá trình này. Tôi thực sự lãng phí một tuần trong cuộc đời tôi cố gắng khắc phục vấn đề, nhưng dường như không có gì để sửa chữa. – Pavel
Hơn nữa, trong trường hợp của tôi, tôi đã có một 720p @ 30fps mà tôi đã không thể giải mã thời gian thực trong khi người chơi bản địa không có vấn đề trả tiền. – Pavel