Android使用MediaRecorder类实现视频和音频录制功能

一、前期基础知识储备

Android提供了MediaRecorder这一个类来实现视频和音频的录制。

由官方配图可知,MediaRecorder用于录制视频时需要调用一系列的API来设置和录制相关的配置,而且调用方法的顺序是固定的,必须按照这个顺序进行API调用才能正确利用手机摄像头实现录像功能。

调用MediaRecorder的录像API顺序如下:

1)Open Camera - Use the Camera.open() to get an instance of the camera object.

2)Connect Preview - Prepare a live camera image preview by connecting a SurfaceView to the camera using Camera.setPreviewDisplay().

3)Start Preview - Call Camera.startPreview() to begin displaying the live camera images.

4)Start Recording Video - The following steps must be completed in order to successfully record video:

a.Unlock the Camera - Unlock the camera for use by MediaRecorder by calling Camera.unlock().

b.Configure MediaRecorder - Call in the following MediaRecorder methods in this order:

setCamera() - Set the camera to be used for video capture,绑定Camera进行视频录制。
setAudioSource() - Set the audio source,设置音频源。
setVideoSource() - Set the video source,设置视频源。
setProfile() - Set the video output format and encoding,录制效果的配置。
setOutputFile() - Set the output file, 设置录制好的文件存储位置。
setPreviewDisplay() - Connect Preview,设置预览效果。

c.Prepare MediaRecorder- Prepare the MediaRecorder with provided configuration settings by calling MediaRecorder.prepare().

d.Start MediaRecorder - Start recording video by calling MediaRecorder.start().

停止录像时调用的API顺序如下:

1)Stop MediaRecorder - Stop recording video by calling MediaRecorder.stop().
 2)Reset MediaRecorder - Optionally, remove the configuration settings from the recorder by calling MediaRecorder.reset().
 3)Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release().
 4)Lock the Camera - Lock the camera so that future MediaRecorder sessions can use it by calling Camera.lock().
 5)Stop the Preview - When your activity has finished using the camera, stop the preview using Camera.stopPreview().
 6)Release Camera - Release the camera so that other applications can use it by calling Camera.release().

二、上代码,具体实现录制视频和视频播放功能

这里调用MediaRecorder的API实现视频录制功能并借用MediaPlayer多媒体播放类实现录制好的视频播放。

(1)布局文件如下,非常简单两个按钮下放置一个SurfaceView;

<LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
  <LinearLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:orientation="horizontal">
   <Button
    android:id="@+id/record_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="15dp"
    android:layout_weight="1"
    android:text="record" />
   <Button
    android:id="@+id/play_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginRight="15dp"
    android:layout_weight="1"
    android:text="play" />
  </LinearLayout>
  <SurfaceView
   android:id="@+id/surface_view"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginBottom="20dp" />
 </LinearLayout>

(2)相机录像前的准备代码;

 /*
 * 相机预览前的准备工作代码 单独抽出来
 * */
 private boolean prepareVideoRecorder() throws IOException {
  if (mMediaRecorder == null) {
   mMediaRecorder = new MediaRecorder();
   mMediaRecorder.reset();
  }
   /*camera相关设置部分*/
  mCamera = Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
  if (mCamera != null) {
   //设置旋转角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了
   mCamera.setDisplayOrientation(90);
   mCamera.unlock();
   mMediaRecorder.setCamera(mCamera);
  }
   /*recorder设置部分*/
  mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
  mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
  mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
  mMediaRecorder.setOutputFile(getOutputMediaFile());
  mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
  mMediaRecorder.prepare();
  return true;
 }

(3)创建录像文件存储位置代码;

 /*
 * 获取手机外部存储路径
 * */
 private String getOutputFile() {
  File mediaFile = null;
  boolean OutputExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
  if (OutputExist) {
   mediaFile = Environment.getExternalStorageDirectory();
   return mediaFile.toString();
  }
  return null;
 }
 /*
 * 获取录制视频的日期 作为存储文件路径一部分
 * */
 private String getDate() {
  Log.d(TAG, "获取录制视频的日期 ");
  Calendar ca = Calendar.getInstance();
  int year = ca.get(Calendar.YEAR);   // 获取年份
  int month = ca.get(Calendar.MONTH);   // 获取月份
  int day = ca.get(Calendar.DATE);   // 获取日
  String date = "" + year + "_" + (month + 1) + "_" + day;
  return date;
 }
 /*
 *创建视频存储文件夹 录制好的视频存储在手机外部存储中 以录像时间+mp4格式命名
 * */
 private String getOutputMediaFile() {
  Log.d(TAG, "获取视频存储的位置 ");
  String mediaPath = getOutputFile();
  if (mediaPath != null) {
   File mediaFile = new File(mediaPath + "/recordVideo");
   if (!mediaFile.exists()) {
    mediaFile.mkdir();
   }
   return mMediaPath = mediaFile.getAbsolutePath() + File.separator + getDate() + ".mp4";
  }
  return null;
 }

(4)录制视频结束时释放相机资源;

 /*
 * 录制视频结束时释放相机资源
 * */
 private void releaseMediaRecorder() {
  Log.d(TAG, "录制结束后释放资源 ");
  if (mMediaRecorder != null) {
   mMediaRecorder.reset(); // clear recorder configuration
   mMediaRecorder.release(); // release the recorder object
   mMediaRecorder = null;
   mCamera.lock();   // lock camera for later use
  }
 }

(5)点击录制视频按钮mRecordBtn开始录制和再次点击停止录制;

 private void initBtnClick() {
  StartRecording();
  mPlayBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    if (mMediaPlayer == null) {
     mMediaPlayer = new MediaPlayer();
     mMediaPlayer.reset();
     Uri uri = Uri.parse(mMediaPath);
     mMediaPlayer = MediaPlayer.create(MainActivity.this,uri);
     mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
     mMediaPlayer.setDisplay(mSurfaceHolder);
     try{
      mMediaPlayer.prepare();
     }catch (Exception e){
      e.printStackTrace();
     }
     mMediaPlayer.start();
    }
   }
  });
 }
 private void StartRecording(){
  mRecordBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    if (!mIsRecord) {
     try {
      Log.d(TAG, "首次点击开始录像 ");
      if (prepareVideoRecorder()) {
       mMediaRecorder.start();
       mIsRecord = true;
       mRecordBtn.setText("stop");
      }
     } catch (IOException e) {
      e.printStackTrace();
     }
    } else {
     Log.d(TAG, "再次点击停止录像");
     mMediaRecorder.stop();
     releaseMediaRecorder();
     mCamera.lock();
     mRecordBtn.setText("record");
     mIsRecord = false;
     if (mCamera != null) {
      mCamera.release();
      mCamera = null;
     }
    }
   }
  });
 }

(6)点击播放视频按钮 mPlayBtn开始播放录制刚刚录制好的视频;

 mPlayBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    if (mMediaPlayer == null) {
     mMediaPlayer = new MediaPlayer();
     mMediaPlayer.reset();
     Uri uri = Uri.parse(mMediaPath);
     mMediaPlayer = MediaPlayer.create(MainActivity.this,uri);
     mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
     mMediaPlayer.setDisplay(mSurfaceHolder);
     try{
      mMediaPlayer.prepare();
     }catch (Exception e){
      e.printStackTrace();
     }
     mMediaPlayer.start();
    }
   }
  });

(7)针对6.0以上系统进行运行时权限申请

 private void requestCameraAndStoragePermission() {
  //检查用户是否授权
  for (int i = 0; i < permissions.length; i++) {
   if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
    //没有授权则请求相应权限
    ActivityCompat.requestPermissions(MainActivity.this, new String[]{permissions[i]}, 1);
   }
  }
  //利用权限申请工具类来实现
  mPermissionsUtils = PermissionsUtils.getInstance();
  mPermissionsUtils.chekPermissions(MainActivity.this,permissions, permissionsResult);
 }
 //创建监听权限的接口对象
 PermissionsUtils.IPermissionsResult permissionsResult = new PermissionsUtils.IPermissionsResult() {
  @Override
  public void passPermissons() {
  //StartRecording(); 注意这里的逻辑 并不是权限通过了就立即开始录像了 而是权限通过了 就可以打开Camera进行预览
   mCamera = Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
  }
  @Override
  public void forbitPermissons() {
   Toast.makeText(MainActivity.this, "You denyied the permission", Toast.LENGTH_SHORT).show();
  }
 };

录制视频及播放录制视频完整代码如下

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{
 private static final String TAG = "MainActivity";
 private SurfaceView mSurfaceView;
 private Button mRecordBtn, mPlayBtn;
 private boolean mIsRecord = false; //是否正在录像
 private Camera mCamera;
 private MediaRecorder mMediaRecorder;
 private String mMediaPath;
 private MediaPlayer mMediaPlayer;
 private SurfaceHolder mSurfaceHolder;
 private PermissionsUtils mPermissionsUtils;
 private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
         Manifest.permission.CAMERA,
         Manifest.permission.RECORD_AUDIO};
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //6.0及以上系统请求运行时权限 利用权限申请工具类(见下文)
  requestCameraAndStoragePermission();
  mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
  mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 必须-设置Surface不需要维护自己的缓冲区
  mRecordBtn = (Button) findViewById(R.id.record_btn);
  mPlayBtn = (Button) findViewById(R.id.play_btn);
  initBtnClick();
  SurfaceHolder holder = mSurfaceView.getHolder();
  holder.addCallback(this);
 }
 private void requestCameraAndStoragePermission() {
  //检查用户是否授权
  for (int i = 0; i < permissions.length; i++) {
   if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
    //没有授权则请求相应权限
    ActivityCompat.requestPermissions(MainActivity.this, new String[]{permissions[i]}, 1);
   }
  }
  //利用权限申请工具类来实现
  mPermissionsUtils = PermissionsUtils.getInstance();
  mPermissionsUtils.chekPermissions(MainActivity.this,permissions, permissionsResult);
 }
 //创建监听权限的接口对象
 PermissionsUtils.IPermissionsResult permissionsResult = new PermissionsUtils.IPermissionsResult() {
  @Override
  public void passPermissons() {
//   StartRecording(); 注意这里的逻辑 并不是权限通过了就立即开始录像了 而是权限通过了 就可以打开Camera进行预览
   mCamera = Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
  }
  @Override
  public void forbitPermissons() {
   Toast.makeText(MainActivity.this, "You denyied the permission", Toast.LENGTH_SHORT).show();
  }
 };
 private void StartRecording(){
  mRecordBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    if (!mIsRecord) {
     try {
      Log.d(TAG, "首次点击开始录像 ");
      if (prepareVideoRecorder()) {
       mMediaRecorder.start();
       mIsRecord = true;
       mRecordBtn.setText("stop");
      }
     } catch (IOException e) {
      e.printStackTrace();
     }
    } else {
     Log.d(TAG, "再次点击停止录像");
     mMediaRecorder.stop();
     releaseMediaRecorder();
     mCamera.lock();
     mRecordBtn.setText("record");
     mIsRecord = false;
     if (mCamera != null) {
      mCamera.release();
      mCamera = null;
     }
    }
   }
  });
 }
 private void initBtnClick() {
  StartRecording();
  mPlayBtn.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    if (mMediaPlayer == null) {
     mMediaPlayer = new MediaPlayer();
     mMediaPlayer.reset();
     Uri uri = Uri.parse(mMediaPath);
     mMediaPlayer = MediaPlayer.create(MainActivity.this,uri);
     mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
     mMediaPlayer.setDisplay(mSurfaceHolder);
     try{
      mMediaPlayer.prepare();
     }catch (Exception e){
      e.printStackTrace();
     }
     mMediaPlayer.start();
    }
   }
  });
 }
 /*
 * 相机预览前的准备工作代码 单独抽出来
 * */
 private boolean prepareVideoRecorder() throws IOException {
  if (mMediaRecorder == null) {
   mMediaRecorder = new MediaRecorder();
   mMediaRecorder.reset();
  }
   /*camera相关设置部分*/
  mCamera = Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
  if (mCamera != null) {
   //设置旋转角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了
   mCamera.setDisplayOrientation(90);
   mCamera.unlock();
   mMediaRecorder.setCamera(mCamera);
  }
   /*recorder设置部分*/
  mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
  mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
  mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
  mMediaRecorder.setOutputFile(getOutputMediaFile());
  mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
  mMediaRecorder.prepare();
  return true;
 }
 /*
 * 获取手机外部存储路径
 * */
 private String getOutputFile() {
  File mediaFile = null;
  boolean OutputExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
  if (OutputExist) {
   mediaFile = Environment.getExternalStorageDirectory();
   return mediaFile.toString();
  }
  return null;
 }
 /*
 * 获取录制视频的日期 作为存储文件路径一部分
 * */
 private String getDate() {
  Log.d(TAG, "获取录制视频的日期 ");
  Calendar ca = Calendar.getInstance();
  int year = ca.get(Calendar.YEAR);   // 获取年份
  int month = ca.get(Calendar.MONTH);   // 获取月份
  int day = ca.get(Calendar.DATE);   // 获取日
  String date = "" + year + "_" + (month + 1) + "_" + day;
  return date;
 }
 /*
 *创建视频存储文件夹 录制好的视频存储在手机外部存储中 以录像时间+mp4格式命名
 * */
 private String getOutputMediaFile() {
  Log.d(TAG, "获取视频存储的位置 ");
  String mediaPath = getOutputFile();
  if (mediaPath != null) {
   File mediaFile = new File(mediaPath + "/recordVideo");
   if (!mediaFile.exists()) {
    mediaFile.mkdir();
   }
   return mMediaPath = mediaFile.getAbsolutePath() + File.separator + getDate() + ".mp4";
  }
  return null;
 }
 /*
 * 录制视频结束时释放相机资源
 * */
 private void releaseMediaRecorder() {
  Log.d(TAG, "录制结束后释放资源 ");
  if (mMediaRecorder != null) {
   mMediaRecorder.reset(); // clear recorder configuration
   mMediaRecorder.release(); // release the recorder object
   mMediaRecorder = null;
   mCamera.lock();   // lock camera for later use
  }
 }
 @Override
 public void surfaceCreated(SurfaceHolder surfaceHolder) {
  mSurfaceHolder = surfaceHolder;
 }
 @Override
 public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
  mSurfaceHolder = surfaceHolder;
 }
 @Override
 public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
  mSurfaceView = null;
  mSurfaceHolder = null;
  releaseMediaRecorder();
  if (mCamera != null) {
   mCamera.release();
   mCamera = null;
  }
  if (mMediaPlayer != null){
   mMediaPlayer.release();
   mMediaPlayer = null;
  }
 }
}

三、延伸知识,运行时权限申请工具类

调用手机系统内置的摄像头进行视频录制时及录制视频后将视频保存在本地都需要申请系统权限,而且申请的权限(调用摄像头权限、存储权限)都属于26个危险权限,针对6.0以上的手机,需要进行运行时权限的申请,由于申请的权限过多,而且申请的时间不一致,所以这里提供一个权限申请工具类协助实现权限申请。(来自我们文章:Android动态请求权限的工具类(可请求多个,并且功能完善))

完整代码如下

/**
 * 运行时权限申请工具类:
 * 检查用户是否授权——ContextCompat.checkSelfPermission
 * 如果没有授权,那么申请授权——ActivityCompat.requestPermissions
 * 申请授权之后的回调——onRequestPermissionsResult
 * 精髓:检查权限 申请权限的代码写在工具类内 同时写入一个接口 两个抽象方法-获取权限成功 + 获取权限失败 然后在外部使用权限工具类时实现这两个抽象方法
 * Created by Administrator on 2018/7/3.
 */
public class PermissionsUtils {
 private final int mRequestCode = 100;//权限请求码
 public static boolean showSystemSetting = true;
 private PermissionsUtils() {
 }
 private static PermissionsUtils permissionsUtils;
 private IPermissionsResult mPermissionsResult;
 /*
 * 单例模式创建PermissionUtils实例 工具类中的静态方法可以直接使用类名+方法名调用 非静态方法还是需要获取到工具类的实例 实例对方法进行调用
 * */
 public static PermissionsUtils getInstance() {
  if (permissionsUtils == null) {
   synchronized (PermissionsUtils.class) {
    if (permissionsUtils == null)
    permissionsUtils = new PermissionsUtils();
   }
  }
  return permissionsUtils;
 }
 /*
 * 检查用户是否授权 + 如果没有授权 则申请授权 - 系统标准方法
 * */
 public void chekPermissions(Activity context, String[] permissions, @NonNull IPermissionsResult permissionsResult) {
  mPermissionsResult = permissionsResult;
  if (Build.VERSION.SDK_INT < 23) {//6.0系统及以上才会动态申请权限 以下不用 所以直接return出去
   permissionsResult.passPermissons();
   return;
  }
  //创建一个mPermissionList,逐个判断哪些权限未授予,未授予的权限存储到mPerrrmissionList中
  List<String> mPermissionList = new ArrayList<>();
  //逐个判断你要的权限是否已经通过
  for (int i = 0; i < permissions.length; i++) {
   if (ContextCompat.checkSelfPermission(context, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
    mPermissionList.add(permissions[i]);//添加还未授予的权限
   }
  }
  //申请权限
  if (mPermissionList.size() > 0) {//有权限没有通过,需要申请
   ActivityCompat.requestPermissions(context, permissions, mRequestCode);
  } else {
   //说明权限都已经通过,利用接口变量调用实现的接口方法 即有权限之后需要调用的方法
   permissionsResult.passPermissons();
   return;
  }
 }
 //请求权限后回调的方法
 //参数: requestCode 是我们自己定义的权限请求码
 //参数: permissions 是我们请求的权限名称数组
 //参数: grantResults 是我们在弹出页面后是否允许权限的标识数组,数组的长度对应的是权限名称数组的长度,数组的数据0表示允许权限,-1表示我们点击了禁止权限
 public void onRequestPermissionsResult(Activity context, int requestCode, @NonNull String[] permissions,
           @NonNull int[] grantResults) {
  boolean hasPermissionDismiss = false;//有权限没有通过
  if (mRequestCode == requestCode) {
   for (int i = 0; i < grantResults.length; i++) {
    if (grantResults[i] == -1) {
     hasPermissionDismiss = true;
    }
   }
   //如果有权限没有被允许
   if (hasPermissionDismiss) {
    if (showSystemSetting) {
     showSystemPermissionsSettingDialog(context);//跳转到系统设置权限页面,或者直接关闭页面,不让他继续访问
    } else {
     mPermissionsResult.forbitPermissons();
    }
   } else {
    //全部权限通过,可以进行下一步操作。。。
    mPermissionsResult.passPermissons();
   }
  }
 }
 /**
  * 不再提示权限时的展示对话框
  */
 AlertDialog mPermissionDialog;
 private void showSystemPermissionsSettingDialog(final Activity context) {
  final String mPackName = context.getPackageName();
  if (mPermissionDialog == null) {
   mPermissionDialog = new AlertDialog.Builder(context)
     .setMessage("已禁用权限,请手动授予")
     .setPositiveButton("设置", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
       cancelPermissionDialog();
       Uri packageURI = Uri.parse("package:" + mPackName);
       Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
       context.startActivity(intent);
       context.finish();
      }
     })
     .setNegativeButton("取消", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
       //关闭页面或者做其他操作
       cancelPermissionDialog();
       //mContext.finish();
       mPermissionsResult.forbitPermissons();
      }
     })
     .create();
  }
  mPermissionDialog.show();
 }
 //关闭对话框
 private void cancelPermissionDialog() {
  if (mPermissionDialog != null) {
   mPermissionDialog.cancel();
   mPermissionDialog = null;
  }
 }
 public interface IPermissionsResult {
  void passPermissons();
  void forbitPermissons();
 }
}

总结

以上所述是小编给大家介绍的Android使用MediaRecorder实现录制视频功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android音频系统AudioTrack使用方法详解

    今天,简单讲讲AudioTrack的使用方法. 1.Android AudioTrack简介 在android中播放声音可以用MediaPlayer和AudioTrack两种方案的,但是两种方案是有很大区别的,MediaPlayer可以播放多种格式的声音文件,例如MP3,AAC,WAV,OGG,MIDI等.而AudioTrack只能播放PCM数据流. 事实上,两种本质上是没啥区别的,MediaPlayer在播放音频时,在framework层还是会创建AudioTrack,把解码后的PCM数流传递

  • Android音频编辑之音频转换PCM与WAV

    前言 本篇开始讲解在Android平台上进行的音频编辑开发,首先需要对音频相关概念有基础的认识.所以本篇要讲解以下内容: 1. 常用音频格式简介 2. WAV和PCM的区别和联系 3. WAV文件头信息 4. 采样率简介 5. 声道数和采样位数下的PCM编码 6. 音频文件解码 7. PCM文件转WAV文件 现在先给出音频编辑的效果图,看看能不能提高大家的积极性~,哈哈 常用音频格式简介 在Android平台上进行音频开发,首先需要对常用的音频格式有个大致的了解.在Android平台上,常用的音

  • android采用FFmpeg实现音频混合与拼接剪切

    接触FFmpeg有一段时间了,它是音视频开发的开源库,几乎其他所有播放器.直播平台都基于FFmpeg进行二次开发.本篇文章来总结下采用FFmpeg进行音频处理:音频混合.音频剪切.音频拼接与音频转码. 采用android studio进行开发,配置build.gradle文件: defaultConfig { ...... externalNativeBuild { cmake { cppFlags "" } } ndk { abiFilters "armeabi-v7a&q

  • Android添加音频的几种方法

    在res文件夹中新建一个文件夹,命名为raw.在里面放入我们需要的音频文件. 第一种: // 根据资源创建播放器对象 player = MediaPlayer.create(this, R.raw.xiaoxiaole); try { player.prepare();// 同步 } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOExcept

  • Android传感器SensorEventListener之加速度传感器

    这个类(我的是Activity中)继承SensorEventListener接口 先获取传感器对象,再获取传感器对象的类型 //获取传感器管理对象 SensorManager mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); // 获取传感器的类型(TYPE_ACCELEROMETER:加速度传感器) Sensor mSensor = mSensorManager.getDefaultSensor(

  • Android线程中Handle的使用讲解

    Android UI线程是不安全的,子线程中进行UI操作,可能会导致程序的崩溃,解决办法:创建一个Message对象,然后借助Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不会再出现崩溃了 定义类继承Handler public class BallHandler extends Handler{ ImageView imageview; Bitmap bitmap; public BallHandle

  • Android 判断网络状态对音频静音的实现方法

    在实际应用中,我们不希望在教室网络,打开游戏就显示较大的声音,进而影响上课质量.因此,就需要让app变得智能,让app可以根据使用者当前网络状态,自动进行静音等操作. 本次内容分为两部分:1. 识别网络环境 2. 实现app自动静音. 自动静音 /** * 实现静音功能 */ private void silentSwitchOn() { AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVI

  • Android音频编辑之音频合成功能

    前言 音频编辑系列: - android音频编辑之音频转换PCM与WAV -android音频编辑之音频裁剪 - android音频编辑之音频合成 本篇主要讲解音频PCM数据的合成,这里合成包括音频之间的拼接,混合. - 音频拼接:一段音频连接着另一段音频,两段音频不会同时播放,有先后顺序. - 音频混合:一段音频和另一段音频存在相同的区间,两者会有同时播放的区间. 下面是音频拼接,音频混合的效果图: 音频拼接 如果大家理解了android音频编辑之音频转换PCM与WAV和android音频编辑

  • Android亮屏速度分析总结

    前面聊的 最近在调试项目的亮屏速度,我们希望在按下power键后到亮屏这个时间能达到500MS以内,在Rockchip 3399和3288上面的时间都不能达到要求,因此引发了一系列的调试之路. 计算按下power键到亮屏的时间 Android 唤醒时间统计 刚开始的时候,我只在android阶段统计时间,也能看到时间的差异,但是不是最准确的,我统计的时间日志如下 01-18 09:13:40.992 683 772 D SurfaceControl: Excessive delay in set

  • Android视频/音频缓存框架AndroidVideoCache(Okhttp)详解

    关于安卓边下边播功能,供大家参考,具体内容如下 对于视频/音频软件,音乐软件,视频软件,都有缓存这个功能,那如何实现边下边播功能: 如何实现这个边下边播功能? 文件是否支持同时读写?(Mediaplayer 播放文件,从网络上下载文件) 播放与下载进度如何协调? 已缓存的文件需及时清理 经过一番折腾,我 find 了 : [ AndroidVideoCache ],这个库是 danikula 大神写,看完源码后收益匪浅.实现流媒体边下边播原理利用socket 开启一个本机的代理服务器 结合自身需

随机推荐