Vì vậy, tôi đang phát triển một thứ tương tự như ứng dụng máy ảnh. Nó vẽ các bản xem trước của máy ảnh theo thời gian thực trên kết cấu OpenGL gốc. Nếu nhấn nút, ảnh tĩnh sẽ được chụp ở dạng ban đầu (có thể ở độ phân giải cao hơn bản xem trước trực tiếp).
Đây là phác thảo mã của tôi. Để cho rõ ràng, tôi sẽ không hiển thị những phần ít liên quan hơn. Đây là trường hợp đơn giản hóa trong đó độ phân giải xem trước và độ phân giải giới hạn tĩnh giống nhau.
void Setup(Hoạt động a) {
// .. bắn tỉa ..
mSurfaceView = SurfaceView mới(a);
mSurfaceView.getHolder().addCallback(this);
//đưa bề mặt ra khỏi màn hình
Tuyệt đốiLayout.LayoutParams alp = new Tuyệt đốiLayout.LayoutParams (8, 8, -8, -8);
a.addContentView(mSurfaceView, alp); // cần cái này, nếu không thì bề mặt sẽ không được tạo
mCamera = Camera.open(miCameraId);
mCamera.setPreviewCallbackWithBuffer(this);
Cấu hìnhCameraDefaults(640,480);
}
//------------------------------------------------ ------------------ //
void Cấu hìnhCameraDefaults(int iX, int iY) {
Camera.Parameters oParameters=mCamera.getParameters();
oParameters.setPreviewFormat(ImageFormat.NV21);
oParameters.setPictureFormat(ImageFormat.NV21);
oParameters.setPreviewSize(iX, iY); // để xem trước trực tiếp
oParameters.setPictureSize(iX, iY); // để chụp ảnh tĩnh
int bpp = ImageFormat.getBitsPerPixel(ImageFormat.NV21);
int iBufSize = (int) (iX*iY*((float)bpp/8));
mBuffer = byte mới[iBufSize];
mCamera.addCallbackBuffer(mBuffer);
thử {
mCamera.setParameter(oParameter);
} catch (Exception e) {
// .. bắn tỉa ..
}
}
void startPreview() {
mCamera.startPreview();
}
void stopPreview() {
mCamera.stopPreview();
}
void takePicture() {
mCamera.takePicture(null, this, null, null); //thứ 2 là lệnh gọi lại thô
}
//------------------------------------------------ ------------------ //
@Ghi đè
public void onPreviewFrame(byte[] data, Camera camera) {
// -- lúc này bộ đệm ở trạng thái an toàn cho đến khi được thêm lại
onPreviewFrame_native(data);
// -- làm cho bộ đệm có thể ghi lại được
mCamera.addCallbackBuffer(mBuffer);
}
@Ghi đè
public void onPictureTaken(byte[] data, Camera camera) {
onStillCapture_native(data);
mCamera.startPreview(); //nếu không thì việc xem trước sẽ dừng
}
Được rồi, bây giờ là câu hỏi. khi chụp ảnh()
Khi không được gọi, mọi thứ sẽ chạy theo kế hoạch. Các khung xem trước đến, chúng được xử lý và bộ đệm được yêu cầu xếp hàng đợi. Nhưng nếu tôi bắt đầuPreview()
và sau đó thực hiện chụp ảnh()
, lệnh gọi lại hình ảnh sẽ nhận được một mảng dữ liệu trống. mọi lúc. Cặp Google Tài liệu chụp ảnh()
Có một câu nói như thế này:
Cuộc gọi lại thô xảy ra khi có sẵn dữ liệu hình ảnh thô (lưu ý: dữ liệu sẽ
null nếu không có bộ đệm gọi lại hình ảnh thô hoặc gọi lại hình ảnh thô
Bộ đệm không đủ lớn để chứa ảnh gốc).
Tôi không chắc chắn vì:
- Không có khả năng đặt bộ đệm để chụp tĩnh, chỉ để xem trước khung hình
- Mặc dù cả giới hạn tĩnh và khung xem trước đều sử dụng cùng một bộ đệm nhưng tôi vẫn có một bộ đệm được xếp hàng đợi.
- Việc thêm bộ đệm thứ hai (giống như bộ đệm xem trước) dành riêng cho giới hạn tĩnh hoàn toàn không có tác dụng
- Xem trước phải được bật để kích hoạt
chụp ảnh()
trở thành một cuộc gọi hợp lệ.
Tôi có thiếu điều gì đó hiển nhiên không? Hay chúng ta không được phép lấy các khung hình thô từ video cùng một lúc? Không có gì về điều này trong tài liệu. Tôi cũng đã xem nguồn camera nhưng không có kết quả.
Bất kỳ trợ giúp sẽ được đánh giá rất cao.
tái bút Tôi đã thử sử dụng các định dạng màu khác nhau trên lệnh gọi lại xem trước tĩnh, chưa đặt trước khi chụp ảnh, thêm bộ đệm thứ hai, yêu cầu bộ đệm thứ hai, đặt giá treo bề mặt thành loại đẩy và tôi đang ở trong giây lát. Không có sự khác biệt.
Dường như không có cách nào để có được hình ảnh gốc. thêmCallbackBuffer
Phương pháp chỉ sử dụng gọi lại xem trước. Có một cách khác addRawImageCallbackBuffer
nên làm những gì bạn muốn. Nó ở chế độ công khai nhưng không được xuất nên bạn không thể gọi trực tiếp. Bạn có thể gọi nó như thế này:
thử {
Phương thức cuối cùng addRawImageCallbackBuffer =
camera0.getClass()
.getDeclaredMethod("addRawImageCallbackBuffer",
byte[].class);
addRawImageCallbackBuffer.invoke(Camera0, byte mới[100000000]);
} catch (Exception e) {
Log.e("RNG", "Lỗi", e);
}
Nhưng trên Nexus 5 của tôi, nó vẫn trả về trong cuộc gọi lại null
, vì vậy tôi nghĩ nó không được hỗ trợ chút nào.
Tôi là một lập trình viên xuất sắc, rất giỏi!