#android #camera #screen #photo
#Android #камера #экран #фото
Вопрос:
Я разрабатываю приложение для Android, которое фиксирует максимальное количество кадров в секунду и сохраняет на SD-карту.
Проблема в том, что сохраненная фотография имеет черный экран, и я не могу понять, почему.
Кто-нибудь может сказать мне, в чем проблема?
Код, в котором я это делаю:
public class PhotoFragment extends Fragment {
private Camera cam;
private CameraPreview camPreview;
private boolean recording = false;
private ArrayList<byte[]> fotos;
private ArrayList<String> tempos;
private Thread thread;
public PhotoFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_photofinish, container, false);
cam = getCameraInstance();
if(cam != null) {
cam.setDisplayOrientation(90);
// set Camera parameters
Camera.Parameters cameraParameters = cam.getParameters();
//set color efects to none
cameraParameters.setColorEffect(Camera.Parameters.EFFECT_NONE);
//set antibanding to none
if (cameraParameters.getAntibanding() != null) {
cameraParameters.setAntibanding(Camera.Parameters.ANTIBANDING_OFF);
}
// set white ballance
if (cameraParameters.getWhiteBalance() != null) {
cameraParameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT);
}
//set flash
if (cameraParameters.getFlashMode() != null) {
cameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
//set zoom
if (cameraParameters.isZoomSupported()) {
cameraParameters.setZoom(0);
}
//set focus mode
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
List<Size> sizes = cameraParameters.getSupportedPictureSizes();
Camera.Size size = sizes.get(0);
cameraParameters.setPictureSize(size.width, size.height);
cam.setParameters(cameraParameters);
fotos = new ArrayList<byte[]>();
tempos = new ArrayList<String>();
camPreview = new CameraPreview(this.getActivity(), cam);
FrameLayout preview = (FrameLayout) rootView.findViewById(R.id.camera_preview);
preview.addView(camPreview);
TextView startRecording = (TextView) rootView.findViewById(R.id.start_record_button);
startRecording.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
if(!recording)
{
recording = true;
Size previewSize = cam.getParameters().getPreviewSize();
int dataBufferSize=(int)(previewSize.height*previewSize.width*(ImageFormat.getBitsPerPixel(cam.getParameters().getPreviewFormat())/8.0));
thread.start();
cam.addCallbackBuffer(new byte[dataBufferSize]);
cam.addCallbackBuffer(new byte[dataBufferSize]);
cam.addCallbackBuffer(new byte[dataBufferSize]);
cam.setPreviewCallbackWithBuffer(new PreviewCallback() {
public void onPreviewFrame(byte[] imageData, Camera arg1) {
try {
fotos.add(imageData);
tempos.add(new SimpleDateFormat("HH_mm_ss_SSS", Locale.getDefault()).format(new Date()));
} catch(Exception e) {
System.out.println("ERRO: " e);
}
}
});
}
else
{
recording = false;
try {
thread.join();
} catch (Exception e) {
}
}
}
});
thread = new Thread(new Runnable() {
public void run() {
while(recording) {
if(fotos.size()>0 amp;amp; tempos.size()>0)
{
File pictureFile = getOutputMediaFile(1, tempos.get(0));
if (pictureFile == null){
System.out.println("Error creating media file, check storage permissions: ");
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(fotos.get(0));
fos.close();
pictureFile = null;
cam.addCallbackBuffer(fotos.get(0));
fotos.remove(0);
tempos.remove(0);
} catch (FileNotFoundException e) {
System.out.println("ERRO FILE NOT FOUND! : " e);
} catch (IOException e) {
System.out.println("ERRO IOException!");
}
}
}
}
});
}
else
{
Toast.makeText(getActivity(), "Camera not available", Toast.LENGTH_LONG).show();
}
return rootView;
}
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
}
catch (Exception e){
}
return c;
}
@Override
public void onDestroyView() {
super.onDestroyView();
cam.release();
}
private static File getOutputMediaFile(int type, String timeStamp){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "L_P");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
System.out.println("L_P failed to create directory");
return null;
}
}
String timeStampDay = new SimpleDateFormat("ddMMyyyy", Locale.getDefault()).format(new Date());
new File(mediaStorageDir.getPath() File.separator timeStampDay).mkdirs();
File mediaFile;
if (type == 1){
mediaFile = new File(mediaStorageDir.getPath() File.separator timeStampDay File.separator "IMG_" timeStamp ".jpg");
} else if(type == 2) {
mediaFile = new File(mediaStorageDir.getPath() File.separator "VID_" timeStamp ".mp4");
} else {
return null;
}
return mediaFile;
}
}
Ответ №1:
Вы утверждаете, что файл является JPEG. Однако вы ничего не сделали, чтобы преобразовать изображение в формат JPEG. Кадры предварительного просмотра по умолчанию не в формате JPEG, а в формате NV21. Используйте getSupportedPreviewFormats()
, чтобы узнать, возможны ли предварительные просмотры в формате JPEG, затем используйте setPreviewFormat()
для запроса предварительных просмотров в формате JPEG.
И, как я отметил в вашем предыдущем вопросе, у вас нет двух потоков, работающих с ArrayList
. Кроме того, не загружайте фоновый поток — подождите, постоянно ожидая появления изображения на ArrayList
экране. Используйте a LinkedBlockingQueue
или что-то еще, что является потокобезопасным и позволяет фоновому потоку блокироваться во время ожидания изображения.
Комментарии:
1. спасибо за вашу помощь! Теперь я конвертирую NV21 в JPEG, и фотографии работают нормально. Сегодня я изменю arraylist на LinkedBlockingQueue. Теперь у меня еще один вопрос: я пытаюсь получить предварительные просмотры и отбросить их (просто чтобы посмотреть, сколько кадров в секунду я могу получить), и я не могу получить больше 16/17 кадров в секунду. Я загрузил приложение, которое может получать 27/28 кадров в секунду с моего смартфона. Знаете почему? Еще раз спасибо! 🙂
2. @user2989493: возможно, вам потребуется добавить еще пару буферов через
addCallbackBuffer()
. Если появляется рамка предварительного просмотра и используются все ваши существующие буферы, этот кадр удаляется. Вы не можете сойти с ума и добавить 100 буферов, так как у вас закончится память. Но вы могли бы поэкспериментировать, добавив четвертый, затем пятый и т.д., пока не дойдете до точки, когда добавление дополнительных буферов не поможет.3. Я добавил еще два и три буфера, и количество кадров в секунду осталось прежним. Но я пробовал только с одним буфером, и количество кадров в секунду такое же, как и с тремя и более буферами. Это нормально?
4. @user2989493: извините, я не могу ответить на этот вопрос. Это звучит неправильно.