2017-01-07 26 views
5

Tôi đang cố gắng lưu chuỗi hình ảnh với khung hình cố định (tốt nhất là tối đa 30) trên thiết bị Android có khả năng FULL cho camera2 (Galaxy S7), nhưng tôi không thể a) có tốc độ khung hình ổn định, b) đạt đến 20fps (với mã hóa jpeg). Tôi đã bao gồm các đề xuất từ ​​Android camera2 capture burst is too slow.Android camera2 jpeg framerate

Thời gian khung tối thiểu đối với JPEG là 33,33 mili giây (đối với độ phân giải thấp hơn 1920x1080) theo

characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputMinFrameDuration(ImageFormat.JPEG, size); 

và stallduration là 0ms cho mỗi kích thước (tương tự cho YUV_420_888).

builder chụp của tôi trông như sau:

captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF); 
captureBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, _exp_time); 
captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); 

captureBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, _iso_value); 

captureBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, _foc_dist); 
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CONTROL_AF_MODE_OFF); 

captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, _wb_value); 

// https://stackoverflow.com/questions/29265126/android-camera2-capture-burst-is-too-slow 
captureBuilder.set(CaptureRequest.EDGE_MODE,CaptureRequest.EDGE_MODE_OFF); 
captureBuilder.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE, CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF); 
captureBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF); 
captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 

// Orientation 
int rotation = getWindowManager().getDefaultDisplay().getRotation();   
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation)); 

Focus khoảng cách được thiết lập để 0.0 (inf), iso được thiết lập đến 100, tiếp xúc với thời gian đáp ứng 5ms. Độ trắng có thể được đặt thành TẮT/TỰ ĐỘNG/BẤT K VALUE GIÁ TRỊ, nó không ảnh hưởng đến thời gian dưới đây.

tôi bắt đầu phiên chụp với lệnh sau đây:

session.setRepeatingRequest(_capReq.build(), captureListener, mBackgroundHandler); 

Lưu ý: Nó không tạo sự khác biệt nếu tôi yêu cầu RepeatingRequest hoặc RepeatingBurst ..

Trong preview (chỉ bề mặt kết cấu kèm theo) , mọi thứ ở tốc độ 30 khung hình/giây. Tuy nhiên, ngay sau khi tôi đính kèm một đầu đọc hình ảnh (listener chạy trên HandlerThread) mà tôi nhanh chóng như sau (mà không lưu, thời gian chỉ đo giữa khung):

reader = ImageReader.newInstance(_img_width, _img_height, ImageFormat.JPEG, 2); 
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler); 

Với mã thời gian đo:

ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() { 
    @Override 
    public void onImageAvailable(ImageReader myreader) { 
     Image image = null; 

     image = myreader.acquireNextImage(); 
     if (image == null) { 
      return; 
     } 
     long curr = image.getTimestamp(); 
     Log.d("curr- _last_ts", "" + ((curr - last_ts)/1000000) + " ms"); 
     last_ts = curr; 
     image.close(); 
    } 
} 

tôi nhận được định kỳ lặp đi lặp lại thời gian khác nhau như thế này:

99 ms - 66 ms - 66 ms - 99 ms - 66 ms - 66 ms ...

Tôi không hiểu tại sao chúng lại tăng gấp đôi hoặc gấp ba lần thời gian mà bản đồ cấu hình luồng được quảng cáo cho jpeg? Thời gian phơi sáng thấp hơn thời lượng khung 33ms. Có một số xử lý nội bộ khác xảy ra mà tôi không biết?

Tôi đã thử cùng định dạng YUV_420_888, dẫn đến chênh lệch thời gian không đổi là 33ms. Vấn đề tôi có ở đây là điện thoại di động thiếu băng thông để lưu trữ hình ảnh đủ nhanh (tôi đã thử phương pháp được mô tả trong How to save a YUV_420_888 image?). Nếu bạn biết cách nào để nén hoặc mã hóa những hình ảnh này đủ nhanh, hãy cho tôi biết.

Chỉnh sửa: Từ tài liệu getOutputStallDuration: "Nói cách khác, sử dụng yêu cầu YUV lặp lại sẽ dẫn đến tốc độ khung hình ổn định (giả sử là 30 FPS). Nếu một yêu cầu JPEG được gửi định kỳ, tốc độ khung hình sẽ ở mức 30 FPS (miễn là chúng tôi đợi cho ảnh JPEG trước đó quay trở lại mỗi lần). Nếu chúng tôi cố gắng gửi yêu cầu YUV + JPEG lặp lại, thì tốc độ khung hình sẽ giảm từ 30 FPS. " Điều này có nghĩa là tôi cần phải định kỳ yêu cầu một lần chụp()?

Chỉnh sửa2: Từ https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html: "Thông tin cần thiết cho ứng dụng, được cung cấp mô hình ở trên, được cung cấp qua trường Android.scaler.streamConfigurationMap sử dụng getOutputMinFrameDuration (int, Size). Các giá trị này được sử dụng để xác định tốc độ khung hình tối đa/thời lượng khung tối thiểu có thể cho một cấu hình luồng nhất định.

Cụ thể, ứng dụng có thể sử dụng các quy tắc sau đây để xác định thời gian tối thiểu khung nó có thể yêu cầu từ thiết bị camera:

Hãy tập các đầu vào hiện cấu hình/suối đầu ra được gọi là S. Tìm khung tối thiểu thời lượng cho mỗi luồng trong S, bằng cách tìm kiếm nó trong android.scaler.streamConfigurationMap bằng cách sử dụng getOutputMinFrameDuration (int, Size) (với kích thước/định dạng tương ứng của nó). Để khoảng thời gian khung này được gọi là F. Đối với bất kỳ yêu cầu R nào, thời lượng khung tối thiểu được phép cho R là giá trị tối đa trong tất cả các giá trị trong F. Cho phép các luồng được sử dụng trong R được gọi là S_r. Nếu không có luồng nào trong S_r có thời gian dừng (được liệt kê trong getOutputStallDuration (int, Size) sử dụng kích thước/định dạng tương ứng), thì thời lượng khung trong F xác định tỷ lệ khung hình trạng thái ổn định mà ứng dụng sẽ nhận được nếu nó sử dụng R như một yêu cầu lặp lại."

+0

Nếu bạn đang chụp dưới dạng JPEG, bạn cần chờ bộ mã hóa nén mỗi khung hình. Chụp dưới dạng YUV_420_888 lấy hình ảnh máy ảnh thô mà không cần nén. Bạn có khả năng có thể thử chạy JPEG nén trên các chủ đề khác, nhưng sau đó bạn có thể sẽ thấy rằng bạn áp đảo các giới hạn nhiệt của CPU trong một phút chạy. Bạn có chắc chắn rằng ngay cả phần cứng mã hóa JPEG có khả năng chạy ở tốc độ 30fps với độ phân giải đã chọn không? Có vẻ như không phải vậy. Tùy chọn của bạn dường như là: giảm độ phân giải hoặc tốc độ khung hình. – BitBank

+0

Vui lòng xem Chỉnh sửa2, quá dài để nhận xét. Từ tuyên bố này và các giá trị trên, sự hiểu biết của tôi là 30fps jpeg nên có thể. – TobiasWeis

+0

Có vẻ như bạn đã đọc tài liệu chính xác, nhưng nó không thực sự rõ ràng nếu bạn có thể chụp toàn bộ khung hình JPEG. Tôi nghĩ rằng kinh nghiệm của bạn với nó cho thấy rằng nó sẽ không cung cấp tốc độ khung hình mong muốn. – BitBank

Trả lời

1

sản lượng JPEG là bằng cách không phải là cách nhanh nhất để lấy khung. Bạn có thể thực hiện điều này nhanh hơn rất nhiều bằng cách vẽ các khung hình trực tiếp vào một Quad sử dụng OpenGL.

Đối với chụp burst, giải pháp nhanh hơn sẽ thu được hình ảnh vào RAM mà không mã hóa chúng, sau đó mã hóa và lưu chúng một cách không đồng bộ.

On this website bạn có thể f ind rất nhiều mã tuyệt vời liên quan đến đa phương tiện Android nói chung.

This specific program sử dụng OpenGL để tìm nạp dữ liệu pixel từ video MPEG. Không khó sử dụng máy ảnh làm đầu vào thay vì video. Về cơ bản, bạn có thể sử dụng kết cấu được sử dụng trong lớp CodecOutputSurface từ chương trình được đề cập dưới dạng kết cấu đầu ra cho yêu cầu chụp của bạn.

+0

Chính xác thì ý của bạn là gì "Bạn có thể thực hiện điều này nhanh hơn rất nhiều ..."? Điều này sẽ không thay đổi thời gian cần thiết để có được hoặc lưu hình ảnh, phải không? Nó chỉ là một cách để hiển thị chúng nhanh hơn, hoặc tôi đang thiếu một cái gì đó?Ý tưởng với bộ nhớ RAM và mã hóa thủ công có thể tốt cho các vụ nổ, nhưng tôi đang tìm cách chụp các chuỗi ở các khung hình ổn định trong một khoảng thời gian dài hơn (ít nhất 10 phút). – TobiasWeis

+0

Đây là cách lấy dữ liệu RGB trong ứng dụng của bạn nhanh nhất có thể để xử lý tiếp hoặc lưu tùy chỉnh. Giải mã YUV và mã hóa lại dưới dạng JPEG chậm. Tôi đã sử dụng cách tiếp cận ở trên với bộ mã hóa JPEG của bên thứ 3 mang lại kết quả rất tốt. Tuy nhiên, nếu bạn muốn lưu một chuỗi hình ảnh trong một thời gian dài, tại sao bạn không quay video? Về cơ bản nó được thực hiện cho trường hợp sử dụng đó, giữ cho hiệu suất và tiêu thụ bộ nhớ trong tâm trí. – Emiswelt

1

Một giải pháp có thể được tìm thấy bao gồm việc sử dụng và bán phá giá YUV mà không mã hóa nó dưới dạng JPEG kết hợp với thẻ Sd micro có thể tiết kiệm tới 95Mb mỗi giây. (Tôi đã có quan niệm sai lầm rằng hình ảnh YUV sẽ lớn hơn, vì vậy với điện thoại di động có hỗ trợ đầy đủ cho camera2-pipeline, tốc độ ghi phải là yếu tố hạn chế.

Với thiết lập này, tôi đã có thể đạt được các điều sau giá ổn định:

  • 1920x1080, 15fps (. khoảng 4Mb * 15 == 60MB/giây)
  • 960x720, 30fps (khoảng 1.5MB * 30 == 45MB/sec.)

. Sau đó tôi mã hóa hình ảnh ngoại tuyến từ YUV sang PNG bằng cách sử dụng tập lệnh python.

Các vấn đề liên quan