今天用安卓錄製視頻
用的是別人現成的代碼,代碼原地址http://blog.csdn.net/peijiangping1989/article/details/7049991
但是會報錯
06-03 21:32:32.285: W/System.err(27250): java.lang.RuntimeException: start failed.
06-03 21:32:32.285: W/System.err(27250): at android.media.MediaRecorder.start(Native Method)
06-03 21:32:32.285: W/System.err(27250): at com.it_videorecorder.MainActivity.record(MainActivity.java:87)
06-03 21:32:32.285: W/System.err(27250): at java.lang.reflect.Method.invokeNative(Native Method)
06-03 21:32:32.285: W/System.err(27250): at java.lang.reflect.Method.invoke(Method.java:511)
06-03 21:32:32.285: W/System.err(27250): at android.view.View$1.onClick(View.java:3586)
06-03 21:32:32.285: W/System.err(27250): at android.view.View.performClick(View.java:4084)
06-03 21:32:32.285: W/System.err(27250): at android.view.View$PerformClick.run(View.java:16966)
06-03 21:32:32.285: W/System.err(27250): at android.os.Handler.handleCallback(Handler.java:615)
06-03 21:32:32.289: W/System.err(27250): at android.os.Handler.dispatchMessage(Handler.java:92)
06-03 21:32:32.289: W/System.err(27250): at android.os.Looper.loop(Looper.java:137)
06-03 21:32:32.289: W/System.err(27250): at android.app.ActivityThread.main(ActivityThread.java:4931)
06-03 21:32:32.289: W/System.err(27250): at java.lang.reflect.Method.invokeNative(Native Method)
06-03 21:32:32.289: W/System.err(27250): at java.lang.reflect.Method.invoke(Method.java:511)
06-03 21:32:32.289: W/System.err(27250): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
06-03 21:32:32.292: W/System.err(27250): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
06-03 21:32:32.292: W/System.err(27250): at dalvik.system.NativeStart.main(Native Method)
這個錯誤百度了下,貌似不少人遇到。
我看了下大概有幾個可能的原因
第一 視頻尺寸設定不支援
第二 格式設定不對,是3gp 還是mp4這個不同手機會有不同的實現方式。我的是這個原因
第三 幀率設定不對。可能幀率設定的高手機支援不了那麼高的解析度
大概是這幾個原因,每個人程式不同,即使報同樣的錯誤解決方式也會不一樣。都試一試,逐個排查一下。
貼個代碼,因上面那個連結裡面的代碼會出現小小錯誤,把我的發上來,有用的上的就拿去吧。
package com.dineed.videorecorder;import android.os.Bundle;import android.app.Activity;import android.view.Menu;import java.io.IOException; import javax.security.auth.callback.Callback;import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; import android.media.MediaRecorder; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager; import android.widget.Button; public class VideoRecorderActivity extends Activity {private Button start;// 開始錄製按鈕 private Button stop;// 停止錄製按鈕 private MediaRecorder mediarecorder;// 錄製視頻的類 private SurfaceView surfaceview;// 顯示視頻的控制項 // 用來顯示視頻的一個介面,我靠不用還不行,也就是說用mediarecorder錄製視頻還得給個介面看 // 想偷偷錄視頻的同學可以考慮別的辦法。。嗯需要實現這個介面的Callback介面 private SurfaceHolder surfaceHolder; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉標題列 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);// 設定全屏 // 設定橫屏顯示 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // 選擇支援半透明模式,在有surfaceview的activity中使用。 getWindow().setFormat(PixelFormat.TRANSLUCENT); setContentView(R.layout.activity_video_recorder);init(); } private void init() { start = (Button) this.findViewById(R.id.start); stop = (Button) this.findViewById(R.id.stop); start.setOnClickListener(new TestVideoListener()); stop.setOnClickListener(new TestVideoListener()); surfaceview = (SurfaceView) this.findViewById(R.id.surfaceview); SurfaceHolder holder = surfaceview.getHolder();// 取得holder holder.addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// TODO Auto-generated method stubsurfaceview = null; surfaceHolder = null; mediarecorder = null;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// TODO Auto-generated method stubsurfaceHolder = holder; }@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// TODO Auto-generated method stubsurfaceHolder = holder; }});// holder加入回調介面 // setType必須設定,要不出錯. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } @Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.video_recorder, menu);return true;}class TestVideoListener implements OnClickListener { @Override public void onClick(View v) { if (v == start) { mediarecorder = new MediaRecorder();// 建立mediarecorder對象 // 設定錄製視頻源為Camera(相機) mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 設定錄製完成後視頻的封裝格式THREE_GPP為3gp.MPEG_4為mp4 mediarecorder .setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 設定錄製的視頻編碼h263 h264 mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); // 設定視頻錄製的解析度。必須放在設定編碼和格式的後面,否則報錯 mediarecorder.setVideoSize(640, 480); // 設定錄製的視訊框架率。必須放在設定編碼和格式的後面,否則報錯 //mediarecorder.setVideoFrameRate(20); mediarecorder.setPreviewDisplay(surfaceHolder.getSurface()); // 設定視頻檔案輸出的路徑 mediarecorder.setOutputFile("/sdcard/love.3gp"); try { // 準備錄製 mediarecorder.prepare(); // 開始錄製 mediarecorder.start(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (v == stop) { if (mediarecorder != null) { // 停止錄製 mediarecorder.stop(); // 釋放資源 mediarecorder.release(); mediarecorder = null; } } } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 將holder,這個holder為開始在oncreat裡面取得的holder,將它賦給surfaceHolder surfaceHolder = holder; } public void surfaceCreated(SurfaceHolder holder) { // 將holder,這個holder為開始在oncreat裡面取得的holder,將它賦給surfaceHolder surfaceHolder = holder; } public void surfaceDestroyed(SurfaceHolder holder) { // surfaceDestroyed的時候同時對象設定為null surfaceview = null; surfaceHolder = null; mediarecorder = null; } }
布局檔案
其實就是一個Surfview和兩個BUTTON
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" > <SurfaceView android:id="@+id/surfaceview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="4" android:gravity="center" android:orientation="vertical" > <Button android:id="@+id/start" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Start" /> <Button android:id="@+id/stop" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Stop" /> </LinearLayout></LinearLayout>
要注意在manifest.xml添加外部儲存寫入權限,網路攝影機許可權錄音許可權。
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>