更新2015年10月28日以反映當前進度。 我有一個應用程序,允許用戶爲Motion JPEG錄製設置攝像機參數,創建一個MJPEG文件,然後用戶可以修改這些設置並使用更新的設置創建另一個文件。當初始值不是30 FPS時,我在更新幀每秒設置時遇到問題。當初始值爲30 FPS時,我可以更新到不同的FPS級別併成功錄製該級別的視頻。但是,我無法將不等於30FPS的級別更新爲另一個FPM級別。我碰到LogCat出現問題.setPreviewFpsRange():更新攝像頭時每秒更新幀數.setParameters()
camera.setParameters(parameters);
錯誤的完整的logcat低於,
10-26 20:27:36.414: E/AndroidRuntime(2275): FATAL EXCEPTION: main
10-26 20:27:36.414: E/AndroidRuntime(2275): java.lang.RuntimeException: setParameters failed
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.hardware.Camera.native_setParameters(Native Method)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.hardware.Camera.setParameters(Camera.java:1333)
10-26 20:27:36.414: E/AndroidRuntime(2275): at net.blepsias.riverwatch.RiverWatch.setCamera(RiverWatch.java:191)
10-26 20:27:36.414: E/AndroidRuntime(2275): at net.blepsias.riverwatch.RiverWatch.onClick(RiverWatch.java:167)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.view.View.performClick(View.java:3514)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.view.View$PerformClick.run(View.java:14111)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.os.Handler.handleCallback(Handler.java:605)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.os.Handler.dispatchMessage(Handler.java:92)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.os.Looper.loop(Looper.java:137)
10-26 20:27:36.414: E/AndroidRuntime(2275): at android.app.ActivityThread.main(ActivityThread.java:4429)
10-26 20:27:36.414: E/AndroidRuntime(2275): at java.lang.reflect.Method.invokeNative(Native Method)
10-26 20:27:36.414: E/AndroidRuntime(2275): at java.lang.reflect.Method.invoke(Method.java:511)
10-26 20:27:36.414: E/AndroidRuntime(2275): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
10-26 20:27:36.414: E/AndroidRuntime(2275): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
10-26 20:27:36.414: E/AndroidRuntime(2275): at dalvik.system.NativeStart.main(Native Method)
檢查logcat的引線5和6,它們分別對應於:
(191) camera.setParameters(parameters);
(167) setCamera(camera);
下面是該應用程序。我還將包含用於參考的佈局.xml文件以及用於接地的屏幕截圖。
RiverWatch.java
public class RiverWatch extends Activity implements OnClickListener, SurfaceHolder.Callback, Camera.PreviewCallback {
public static final String LOGTAG = "VIDEOCAPTURE";
String szBoundaryStart = "\r\n\r\n--myboundary\r\nContent-Type: image/jpeg\r\nContent-Length: ";
String szBoundaryDeltaTime = "\r\nDelta-time: 110";
String szBoundaryEnd = "\r\n\r\n";
private SurfaceHolder holder;
private Camera camera;
private CamcorderProfile camcorderProfile;
Spinner spinnerCamcorderProfile;
public TextView tvFramesPerSecond, tvJpegQuality, tvSegmentDuration;
boolean bRecording = false;
boolean bPreviewRunning = false;
int intFramesPerSecond = 30000; //this is 30fps...mult by 1,000
int intJpegQuality=50; //must be above 20
int intSegmentDuration=10;
boolean ckbxRepeat=false;
byte[] previewCallbackBuffer;
File mjpegFile;
FileOutputStream fos;
BufferedOutputStream bos;
Button btnStartRecord, btnStopRecord, btnExit, btnChange;
Camera.Parameters parameters;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Date T = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String szFileName = "videocapture-"+sdf.format(T)+"-";
try {
mjpegFile = File.createTempFile(szFileName, ".mjpeg", Environment.getExternalStorageDirectory());
} catch (Exception e) {
finish();
}
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.main);
tvFramesPerSecond = (TextView) this.findViewById(R.id.textboxframespersecondxml);
int iFPS = intFramesPerSecond/1000;
String szFPS = Integer.toString(iFPS);
tvFramesPerSecond.setClickable(true);
tvFramesPerSecond.setText(szFPS);
tvFramesPerSecond.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
getSupportedPreviewFpsRange();
}
});
tvJpegQuality = (TextView) this.findViewById(R.id.textboxJpegQualityxml);
String szJpegQuality = Integer.toString(intJpegQuality);
tvJpegQuality.setText(szJpegQuality);
tvSegmentDuration = (TextView) this.findViewById(R.id.textboxSegmentDurationxml);
String szSegmentDuration = Integer.toString(intSegmentDuration);
tvSegmentDuration.setText(szSegmentDuration);
btnStartRecord = (Button) this.findViewById(R.id.StartRecordButton);
btnStartRecord.setOnClickListener(this);
btnStopRecord = (Button) this.findViewById(R.id.StopRecordButton);
btnStopRecord.setOnClickListener(this);
btnExit = (Button) this.findViewById(R.id.ExitButton);
btnExit.setOnClickListener(this);
btnChange = (Button) this.findViewById(R.id.ChangeButton);
btnChange.setOnClickListener(this);
camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_480P);
SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView);
holder = cameraView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cameraView.setClickable(true);
cameraView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.StartRecordButton:
try {
fos = new FileOutputStream(mjpegFile);
bos = new BufferedOutputStream(fos);
bRecording = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Toast.makeText(this, "Recording started.", Toast.LENGTH_SHORT).show();
break;
case R.id.StopRecordButton:
try {
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(this, "Recording stopped.", Toast.LENGTH_SHORT).show();
break;
case R.id.ChangeButton:
//Frames Per Second- expressed x1000 in the function
String szFPS=tvFramesPerSecond.getText().toString();
int iFPS = Integer.parseInt(szFPS);
intFramesPerSecond = iFPS *1000;
//Jpeg quality- cant be <20 or >100, checks this and populates field with entered or corrected value.
String szJpegQuality=tvJpegQuality.getText().toString();
int intJpegQualityTemp = Integer.parseInt(szJpegQuality);
if (intJpegQualityTemp < 21){//...can't be less than 21
intJpegQuality = 21;
}else if(intJpegQualityTemp > 100){//can't be greater than 100
intJpegQuality = 100;
}else{ //quality is between 21 and 100...
intJpegQuality = intJpegQualityTemp;
}
szJpegQuality = Integer.toString(intJpegQuality);
tvJpegQuality.setText(szJpegQuality);
//Segment duration
String szSegmentDuration=tvSegmentDuration.getText().toString();
intSegmentDuration = Integer.parseInt(szSegmentDuration);
releaseCamera();
setCamera(camera);
camera.startPreview();
Toast.makeText(this, "Change button pressed.", Toast.LENGTH_SHORT).show();
break;
case R.id.ExitButton:
System.exit(0);
break;
}
}
public void releaseCamera(){
camera.stopPreview();
//camera.release(); //...cause crash
//camera = null;
}
public void setCamera(Camera camera){
Camera.Parameters parameters=camera.getParameters();
parameters.setPreviewFpsRange(intFramesPerSecond, intFramesPerSecond);//note: This is fps x 1000 (!)
parameters.setPreviewSize(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
Log.v(LOGTAG,"FPS: " + parameters.getSupportedPreviewFpsRange());
camera.setParameters(parameters);
}
public void getSupportedPreviewFpsRange(){
/****************************************************************
* getSupportedPreviewFpsRange()- Returns specified frame rate
* (.getSupportedPreviewFpsRange()) to log file and also displays
* as toast message.
****************************************************************/
Camera.Parameters camParameter = camera.getParameters();
List<int[]> frame = camParameter.getSupportedPreviewFpsRange();
Iterator<int[]> supportedPreviewFpsIterator = frame.iterator();
while (supportedPreviewFpsIterator.hasNext()) {
int[] tmpRate = supportedPreviewFpsIterator.next();
StringBuffer sb = new StringBuffer();
sb.append("SupportedPreviewRate: ");
for (int i = tmpRate.length, j = 0; j < i; j++) {
sb.append(tmpRate[j] + ", ");
}
Log.d(LOGTAG, "FPS6: " + sb.toString());
Toast.makeText(this, "FPS = "+sb.toString(), Toast.LENGTH_SHORT).show();
}//*****************end getSupportedPreviewFpsRange()**********************
}
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
}
@SuppressLint("NewApi")
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (!bRecording) {
if (bPreviewRunning = true){
camera.stopPreview();
} try {
parameters = camera.getParameters();
parameters.setPreviewSize(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
parameters.setPreviewFpsRange(intFramesPerSecond, intFramesPerSecond);//note: This is fps x 1000 (!)
//p.setPreviewFrameRate(intFramesPerSecond);
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
camera.setPreviewCallback(this);
camera.setDisplayOrientation(90);
camera.startPreview();
bPreviewRunning = true;
}
catch (IOException e) {
e.printStackTrace();
}
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (bRecording) {
bRecording = false;
try {
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
bPreviewRunning = false;
camera.release();
finish();
}
public void onPreviewFrame(byte[] b, Camera c) {
if (bRecording) {
// Assuming ImageFormat.NV21
if (parameters.getPreviewFormat() == ImageFormat.NV21) {
try {
YuvImage im = new YuvImage(b, ImageFormat.NV21, parameters.getPreviewSize().width, parameters.getPreviewSize().height, null);
Rect r = new Rect(0,0,parameters.getPreviewSize().width,parameters.getPreviewSize().height);
ByteArrayOutputStream jpegByteArrayOutputStream = new ByteArrayOutputStream();
im.compressToJpeg(r, intJpegQuality, jpegByteArrayOutputStream);//note: qual = 20 or less doesn't work.
byte[] jpegByteArray = jpegByteArrayOutputStream.toByteArray();
byte[] boundaryBytes = (szBoundaryStart + jpegByteArray.length + szBoundaryDeltaTime + szBoundaryEnd).getBytes();
bos.write(boundaryBytes);
bos.write(jpegByteArray);
bos.flush();
//bos.close();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Log.v(LOGTAG,"NOT THE RIGHT FORMAT");
}
}
}
@Override
public void onConfigurationChanged(Configuration conf){
super.onConfigurationChanged(conf);
}
}
佈局main.xml中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/StartRecordButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Recording" />
<Button
android:id="@+id/StopRecordButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop Recording" />
<Button
android:id="@+id/ChangeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dip"
android:text="Reset settings" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<TextView
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Frames/second:" />
<EditText
android:id="@+id/textboxframespersecondxml"
android:editable="true"
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text="0"
android:layout_marginRight="10dip"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<TextView
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JPEG image quality:" />
<EditText
android:id="@+id/textboxJpegQualityxml"
android:editable="true"
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text="0"
android:layout_marginRight="10dip"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="Camcorder profile: " />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<TextView
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Segment duration (file length):" />
<EditText
android:id="@+id/textboxSegmentDurationxml"
android:editable="true"
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:text="0"
android:layout_marginRight="10dip"/>
<TextView
style="@style/myStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" minutes" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="right" >
<CheckBox
android:id="@+id/repeat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Repeat" />
<Button
android:id="@+id/ExitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Exit Application" />
</LinearLayout>
<SurfaceView
android:id="@+id/CameraView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
截圖:顯示字段,按鈕和表面配置
分辨率:看起來上述不規律行爲可能與松下Toughpad JT-B1的主要測試設備有關。運行
.getSupportedPreviewFpsRange();
在此設備上返回的範圍爲8,000-30,000 fps。但是,此範圍內的許多值會導致崩潰,並且此範圍之外的某些值看起來工作正常。測試Samsung S4 Active並不會導致這些不一致,返回範圍內的所有值(4,000 - 30,000)都可以正常工作,而且此範圍外的測試值也不會展示任何預期的功能。
插入以下內容, 'camera.stopPreview(); p = camera.getParameters(); p.setPreviewSize(camcorderProfile.videoFrameWidth,camcorderProfile.videoFrameHeight); p.setPreviewFpsRange(intFramesPerSecond,intFramesPerSecond); camera.setParameters(p); camera.startPreview();在開關殼體R.id.ChangeButton代碼做' 導致幀速率的正確變化,但是,我仍然在 'camera.setParameters(P)得到的崩潰;' 爲了後續更新,爲什麼? – portsample
問題的癥結似乎是'p.setPreviewFpsRange(intFramesPerSecond,intFramesPerSecond);'作爲註釋停止崩潰並允許重複更新。 – portsample
請注意,相機API不允許將預覽FPS範圍設置爲任意值。您應該查詢支持範圍列表的相機參數,並且不保證其他任何組合都能正常工作。 –