Android之多媒体数据采集

Demo1 录音机

下面来分析:

在这里插入图片描述
各种引用的创建(比较特殊的ImageButton 和 MediaRecorder)
在这里插入图片描述
初始化我就不多说
在这里插入图片描述
Handler的使用 上篇博文谈过不多说
在这里插入图片描述
关于这种写法的监听可以借鉴(毕竟所有控件只不过是View的子类而已)
然后读取有没有内存卡
Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)
在这里插入图片描述
初始化临时文件File.createTempFile( 参数一基本文件名 参数二后缀 参数三目录路径)

在这里插入图片描述
不多说下面看settime的代码
在这里插入图片描述
发送Bundle 不多谈

在这里插入图片描述
结束录音的时候
源代码如下

public class MyAudioRecorderActivity extends Activity implements OnClickListener{
	public static final int UPDATE_TIME=0;//更新录音时间的消息编号

	ImageButton ibRecord;//录制按钮
	ImageButton ibStop;//停止按钮

	TextView tvTime;//时间长度显示
	Handler hd;//消息处理器

	File myFile ;//用于存放音轨的文件
	MediaRecorder myMediaRecorder;//媒体录音机
	int countSecond=0;//录制的秒数
	boolean recordFlag=false;//录制中标志

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		//初始化按钮引用
		ibRecord=(ImageButton)findViewById(R.id.ImageButton01);
		ibStop=(ImageButton)findViewById(R.id.ImageButton02);
		//初始化显示录音时长的文本框
		tvTime=(TextView)findViewById(R.id.TextView02);
		//为录制按钮添加监听器
		ibRecord.setOnClickListener(this);
		//为停止按钮添加监听器
		ibStop.setOnClickListener(this);
		//初始化消息处理器对象
		//本案例中希望通过附加线程修改TextView中的内容,因此要在主
		//线程中创建一个Handler
		hd=new Handler()
		{
			@Override
			public void handleMessage(Message msg)
			{
				//调用父类处理
				super.handleMessage(msg);
				//根据消息what编号的不同,执行不同的业务逻辑
				switch(msg.what)
				{
					//将消息中的内容提取出来显示在Toast中
					case UPDATE_TIME:
						//获取消息中的数据
						Bundle b=msg.getData();
						//获取内容字符串
						String msgStr=b.getString("msg");
						//设置字符串到显示录音时长的文本框中
						tvTime.setText(msgStr);
						break;
				}
			}
		};
	}

	@Override
	public void onClick(View v) {
		if(v == ibRecord){//按下录音按钮
			if(!Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
			{//若没有插闪存卡则报错
				Toast.makeText(this, "请检测内存卡", Toast.LENGTH_SHORT).show();
				return;
			}
			try
			{
				if(recordFlag==true)
				{//若已经在录音中则提示并返回
					Toast.makeText(this, "录音中,请结束本次录音再开始新录音!", Toast.LENGTH_SHORT).show();
					return;
				}

				//初始化临时文件对象
				myFile = File.createTempFile
						(
								"myAudio",  //基本文件名
								".amr",     //后缀
								Environment.getExternalStorageDirectory() //目录路径
						);
				//创建录音机对象
				myMediaRecorder = new MediaRecorder();
				//设置输入设备为麦克风
				myMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
				//设置输出格式为默认的amr格式
				myMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
				//设置音频编码器为默认的编码器
				myMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
				//设置输出文件的路径
				myMediaRecorder.setOutputFile(myFile.getAbsolutePath());
				//准备录音
				myMediaRecorder.prepare();
				//开始录音
				myMediaRecorder.start();
				//设置录音中标记为true
				recordFlag=true;
				//启动一个线程进行计时
				new Thread()
				{
					public void run()
					{
						while(recordFlag)
						{
							//计时器加一
							countSecond++;
							//调用方法设置新时长
							setTime();
							//休息1000ms
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}.start();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		else if(v == ibStop){//按下停止按钮
			if(myFile != null&&myMediaRecorder!=null)
			{
				//停止录音
				myMediaRecorder.stop();
				//释放录音机对象
				myMediaRecorder.release();
				//将录音机对象引用设置为null
				myMediaRecorder = null;
			}
			//设置录音中标记为false
			recordFlag=false;
			//计时器清0
			countSecond=0;
			//调用方法设置新时长
			setTime();
		}
	}

	//设置显示时间的方法
	public void setTime()
	{
		//计算分钟和秒
		int second=countSecond%60;
		int minute=countSecond/60;
		//创建内容字符串
		String msgStr=minute+"m:"+second+"s";
		//创建消息数据Bundle
		Bundle b=new Bundle();
		//将内容字符串放进数据Bundle中
		b.putString("msg", msgStr);
		//创建消息对象
		Message msg=new Message();
		//设置数据Bundle到消息中
		msg.setData(b);
		//设置消息的what值
		msg.what=UPDATE_TIME;
		//发送消息
		hd.sendMessage(msg);
	}

最后注意要
在这里插入图片描述
声明权限!!!!

=================================================================================

Demo2 照相机

重点分析:
Uri 的临时存储
在这里插入图片描述
由于使用了startActivityForResult来发送intent的所有必须要实现该方法
在这里插入图片描述
自定义的图片保存进手机闪存的方法
在这里插入图片描述
flush 方法
在这里插入图片描述

照片路径处理的工具类代码

功能是获取下一个可以储存的文件 以及创建一个临时文件

public class StoreFileUtil
{
    //当前存储照片对应的文件
    static File currFile;

    //获取下一个可以存储的文件
    public static File nextFile()
    {
        //获取闪存卡路径
        String path= Environment.getExternalStorageDirectory().getAbsolutePath();
        //寻找可以使用的文件名
        int c=0;
        File fTest=new File(path+"/mc"+c+".jpg");
        while(fTest.exists())
        {
            c++;
            fTest=new File(path+"/mc"+c+".jpg");
        }
        currFile=fTest;
        return fTest;
    }

    //临时文件
    public static File tempFile()
    {
        //获取闪存卡路径
        String path= Environment.getExternalStorageDirectory().getAbsolutePath();
        File fTest=new File(path+"/BNtemp.jpg");
        return fTest;
    }

Activity代码

@SuppressLint("HandlerLeak")
public class MyCameraActivity extends Activity
{
	private static int REQUEST_ORIGINAL=0;// 请求图片信号标识

	private Button  photo;//拍照按钮
	private Button save;//保存按钮
	private ImageView picture;//用于显示图片的ImageView
	public static Bitmap bitmap;//当前拍的照片

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//获取显示图片的ImageView
		picture = (ImageView) findViewById(R.id.picture_imageView);
		//获取拍照按钮
		photo = (Button) findViewById(R.id.main_Button_paizhao);
		//给拍照按钮添加监听器
		photo.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				//调用系统相机的Intent
				Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
				//临时照片文件的位置
				Uri uri = Uri.fromFile(StoreFileUtil.tempFile());
				//将照片文件的位置传入intent
				intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
				//发出intent启动系统相机
				startActivityForResult(intent, REQUEST_ORIGINAL);
			}
		});
		//保存按钮
		save = (Button) findViewById(R.id.main_Button_baocun);
		//为保存按钮添加监听器
		save.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				if(bitmap==null)
				{
					Toast.makeText(MyCameraActivity.this, "请先拍照再保存!", Toast.LENGTH_SHORT)	.show();
				}
				//保存照片
				setInSDBitmap(bitmap);
				Toast.makeText(MyCameraActivity.this, "保存成功:"+StoreFileUtil.currFile.getName()+"!", Toast.LENGTH_SHORT)	.show();
			}
		});
	}

	//系统相机返回时的回调方法
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK)
		{
			if(requestCode == REQUEST_ORIGINAL)
			{
				//从临时照片文件的位置加载照片
				bitmap=BitmapFactory.decodeFile(StoreFileUtil.tempFile().getAbsolutePath());
				//将图片设置给ImageView显示
				picture.setImageBitmap(bitmap);
			}
		}
	}
	//将图片保存进手机闪存的方法
	public static void setInSDBitmap(Bitmap bitmapToStore)
	{
		File file=StoreFileUtil.nextFile();
		try
		{
			FileOutputStream fos=new FileOutputStream(file);
			bitmapToStore.compress(Bitmap.CompressFormat.JPEG, 70, fos);
			fos.flush();
			fos.close();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	//重写返回按钮按下的处理方法
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		if(keyCode == KeyEvent.KEYCODE_BACK)
		{
			finish();
		}
		return false;
	}

Demo3 摄像机

注意代码只是讲述了如何去调用摄像的功能,然后以及在此基础上去实现一些自己定义的功能
下面还是接着来说代码吧
在这里插入图片描述
值得注意的是 SurfaceView 是摄像预览用的
还有SurfaceHolder的作用

这段代码有个重点 即是摄像机的代码要用横屏实现
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
如果用竖屏会出现90°bug 即拍摄的时候会选择90° 而且至今也未处理
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
在这里插入图片描述
Handler我就不多说了
在这里插入图片描述

分析一下录音机和摄影机
关于媒体的记录用的都是 MediaRecorder这个类
在这里插入图片描述
直接上Activity吧

public class MyVideoRecorderActivity extends Activity implements OnClickListener{
	public static final int UPDATE_TIME=0;//更新录音时间的消息编号

	SurfaceView mSurfaceView;   //摄像预览用的SurfaceView
	private SurfaceHolder mSurfaceHolder;
	private ImageButton  buttonStart;//开始录制按钮
	private ImageButton  buttonStop;//停止录制按钮
	private MediaRecorder recorder;//多媒体录制器
	Handler hd;//消息处理器
	int countSecond=0;//录制的秒数
	private TextView tvTime;//显示录制时间的文本View

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//设置为横屏
		this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
		//设置全屏显示
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags
				(
						WindowManager.LayoutParams.FLAG_FULLSCREEN ,
						WindowManager.LayoutParams.FLAG_FULLSCREEN
				);
		//加载主界面
		setContentView(R.layout.main);
		//对摄像预览用的SurfaceView及其SurfaceHolder进行初始化
		mSurfaceView=(SurfaceView)this.findViewById(R.id.mySurfaceView);
		mSurfaceHolder=mSurfaceView.getHolder();

		//给录制、停止按钮添加监听器
		buttonStart=(ImageButton)this.findViewById(R.id.ImageButton01);
		buttonStop=(ImageButton)this.findViewById(R.id.ImageButton02);
		buttonStart.setOnClickListener(this);
		buttonStop.setOnClickListener(this);

		//拿到显示录制时长的文本框的引用
		tvTime=(TextView)this.findViewById(R.id.tvTime);

		//线程中创建一个Handler
		hd=new Handler()
		{
			@Override
			public void handleMessage(Message msg)
			{
				//调用父类处理
				super.handleMessage(msg);
				//根据消息what编号的不同,执行不同的业务逻辑
				switch(msg.what)
				{
					//将消息中的内容提取出来显示在Toast中
					case UPDATE_TIME:
						//获取消息中的数据
						Bundle b=msg.getData();
						//获取内容字符串
						String msgStr=b.getString("msg");
						//设置字符串到显示录音时长的文本框中
						tvTime.setText(msgStr);
						break;
				}
			}
		};
	}

	@Override
	public void onClick(View v)
	{
		if(v== buttonStart)
		{//按下了开始录制按钮
			if(recorder!=null)
			{//若录制器不为空则报错并返回
				Toast.makeText
						(
								this,
								"请停止本次拍摄再开始新的拍摄!",
								Toast.LENGTH_SHORT
						).show();
				return;
			}

			try
			{
				//创建录制器对象
				recorder = new MediaRecorder();
				//创建输出文件对象
				File outf=File.createTempFile
						(
								"aas",
								".mp4",
								Environment.getExternalStorageDirectory()
						);
				//设置预览的View
				recorder.setPreviewDisplay(mSurfaceHolder.getSurface());
				//设置视频输入设备
				recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
				//设置录音源为麦克风
				recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
				//设置输出格式为mp4
				recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
				//设置视频大小(640,480)    不能自己随便乱写 必须和硬件匹配
				recorder.setVideoSize(640,480);
				//设置视频帧速率
				recorder.setVideoFrameRate(15);//高端机可以到20,山寨只能15
				//设置视频编码
				recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
				//设置音频编码
				recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
				//设置最大时长
				recorder.setMaxDuration(10000);
				//设置输出文件
				recorder.setOutputFile(outf.getAbsolutePath());
				//准备录制器
				recorder.prepare();
				//开始录制
				recorder.start();

				//启动一个线程进行计时
				new Thread()
				{
					public void run()
					{
						while(recorder!=null)
						{
							//计时器加一
							countSecond++;
							//调用方法设置新时长
							setTime();
							//休息1000ms
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}.start();
			}
			catch(Exception e)
			{
				e.printStackTrace();
				Toast.makeText
						(
								this,
								"录制故障:"+e.toString(),
								Toast.LENGTH_SHORT
						).show();
			}
		}
		else if(v==buttonStop)
		{
			//停止录制
			recorder.stop();
			//释放录制器
			recorder.release();
			//清空录制器引用
			recorder=null;
			//计时器清0
			countSecond=0;
			//调用方法设置新时长
			setTime();
		}
	}

	@Override
	protected void onPause() {
		super.onPause();
		if(recorder!= null)
		{//若相机不为空则释放相机
			recorder.stop();
			recorder.release();
			recorder = null;
		}
	}

	//设置显示时间的方法
	public void setTime()
	{
		//计算分钟和秒
		int second=countSecond%60;
		int minute=countSecond/60;
		//创建内容字符串
		String msgStr=minute+"m:"+second+"s";
		//创建消息数据Bundle
		Bundle b=new Bundle();
		//将内容字符串放进数据Bundle中
		b.putString("msg", msgStr);
		//创建消息对象
		Message msg=new Message();
		//设置数据Bundle到消息中
		msg.setData(b);
		//设置消息的what值
		msg.what=UPDATE_TIME;
		//发送消息
		hd.sendMessage(msg);
	}
}

====================================================================================
Demo4 媒体播放器(当然和爱奇艺和腾讯视频之类的差远了0.0)

需要注意的主要是 媒体播放器MediaPlayer(不管播放音乐还是播放视频 机制其实差不多,当然目前播放视频都需要GPU来解压!!)
然后还有 进度条拖拉 SeekBar
在这里插入图片描述
依旧还是这么使用我们的Handler
在这里插入图片描述

MediaPlayer

MediaPlayer的使用 (我这里没有讲逻辑 逻辑的话下面的源码中有 需要的话可以去看 不难理解的)
先 创建对象
然后 设置成音频流格式 mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
然后 设置播放显示用的SurfaceView的SurfaceHolder!!这个很重要
给 该对象结束的时候设置监听
在这里插入图片描述
然后 设置播放路径 mp.setDataSource(currentPlay);
准备播放 mp.prepare();
开始播放 mp.start();
播放的总间隔(即时长) mp.getDuration()
获取当前播放的位置 mp.getCurrentPosition()
播放暂停 mp.pause();
播放停止 mp.stop();
释放播放器 mp.release();
清空引用 mp=null;

/进度拖拉到指定位置
mp.seekTo(progress*mp.getDuration()/sb.getMax());
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

SeekBar

SeekBar的使用方法
1.禁用拖拉条 sb.setEnabled(false); true则是启用
2.根据片长设置拖拉条的最大值 sb.setMax(mp.getDuration()/1000);
3.设置拖拉条当前的进度(这样写的代码要自动拖拉 所以根据播放的位置来实现拖拉)sb.setProgress(mp.getCurrentPosition()/1000);

在这里插入图片描述
在这里插入图片描述
实现进度拖拉的监听方法
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser)
在这里插入图片描述

Activity 代码

public class MyVideoPlayerActivity extends Activity
		implements OnClickListener,OnSeekBarChangeListener
{
	public static final int UPDATE_TIME=0;//更新播放时间的消息编号
	public static final String currentPlay= Environment.getExternalStorageDirectory().getAbsolutePath()+"/aa.3gp";//播放路径

	ImageButton play;	//播放按钮
	ImageButton pause;  //暂停按钮
	ImageButton stop;   //停止按钮

	SurfaceView sv;     //播放显示用的SurfaceView
	SurfaceHolder sh;   //播放用的SurfaceHolder
	MediaPlayer mp;     //媒体播放器

	SeekBar sb;			//进度显示拖拉条
	TextView tvTime;	//时间长度显示
	Handler hd;			//消息处理器

	int state=0;		//播放状态指示  0-未准备 1-播放中 2-暂停中

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		//为播放、暂停、停止三个按钮添加监听器
		play=(ImageButton)this.findViewById(R.id.ImageButton01);
		pause=(ImageButton)this.findViewById(R.id.ImageButton02);
		stop=(ImageButton)this.findViewById(R.id.ImageButton03);
		play.setOnClickListener(this);
		pause.setOnClickListener(this);
		stop.setOnClickListener(this);

		//初始化播放用的SurfaceView及SurfaceHolder
		sv=(SurfaceView)this.findViewById(R.id.VideoView01);
		sh=sv.getHolder();

		//初始化进度拖拉条引用
		sb=(SeekBar)this.findViewById(R.id.SeekBar01);
		//不在暂停状态禁用拖拉条
		sb.setEnabled(false);
		//给进度拖拉条添加监听器
		sb.setOnSeekBarChangeListener(this);

		//初始化显示播放时长的文本框
		tvTime=(TextView)findViewById(R.id.TextView01);

		//线程中创建一个Handler
		hd=new Handler()
		{
			@Override
			public void handleMessage(Message msg)
			{
				//调用父类处理
				super.handleMessage(msg);
				//根据消息what编号的不同,执行不同的业务逻辑
				switch(msg.what)
				{
					//将消息中的内容提取出来显示在Toast中
					case UPDATE_TIME:
						//获取消息中的数据
						Bundle b=msg.getData();
						//获取内容字符串
						String msgStr=b.getString("msg");
						//设置字符串到显示录音时长的文本框中
						tvTime.setText(msgStr);
						break;
				}
			}
		};
	}

	@Override
	public void onClick(View v) {
		if(v==play)
		{//按下播放按钮
			if(state==1)
			{//若当前已经是播放状态则报错返回
				Toast.makeText
						(
								this,
								"播放中,请结束本次播放再开始新的播放!",
								Toast.LENGTH_SHORT
						).show();
				return;
			}
			else if(state==0)
			{//若当前是未准备状态则进行播放前的准备工作
				//创建媒体播放器对象
				mp=new MediaPlayer();
				//设置音频流格式
				mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
				//设置播放显示用SurfaceView的SurfaceHolder
				mp.setDisplay(sh);
				//给视频播放结束事件添加的监听器
				mp.setOnCompletionListener(
						new OnCompletionListener()
						{
							@Override
							public void onCompletion(MediaPlayer arg0)
							{//歌曲播放结束停止播放并更新界面状态
								state=2;
							}
						}
				);

				try
				{
					//设置播放路径
					mp.setDataSource(currentPlay);
					//准备播放
					mp.prepare();
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				//根据片长设置拖拉条最大值
				sb.setMax(mp.getDuration()/1000);
			}

			mp.start();	   	//开始播放
			state=1;			//状态设置为1-播放中
			sb.setEnabled(false); //禁用拖拉条

			new Thread() //启动一个线程定时更新进度条及时间
			{
				public void run()
				{
					while(state==1)
					{
						sb.setProgress(mp.getCurrentPosition()/1000);
						setTime(mp.getCurrentPosition()/1000);
						try
						{
							Thread.sleep(1000);
						}
						catch(Exception e)
						{
							e.printStackTrace();
						}
					}
				}
			}.start();
		}
		else if(v==pause)
		{//按下暂停按钮
			if(state!=1)
			{//若当前不是播放状态
				Toast.makeText
						(
								this,
								"请在播放状态再暂停!",
								Toast.LENGTH_SHORT
						).show();
				return;
			}
			mp.pause();		//暂停
			state=2;		//设置状态为2-暂停
			sb.setEnabled(true);//启用拖拉条
		}
		else if(v==stop)
		{//按下停止按钮
			if(state==0)
			{
				return;
			}
			state=0;
			mp.stop();		//停止播放
			mp.release();	//释放播放器
			mp=null;		//清空引用
			sb.setEnabled(false);//禁用拖拉条
			sb.setProgress(0);//设置进度为0
			setTime(0);//设置时间为0
		}
	}

	//设置显示时间的方法
	public void setTime(int countSecond)
	{
		//计算分钟和秒
		int second=countSecond%60;
		int minute=countSecond/60;
		//创建内容字符串
		String msgStr=minute+"m:"+second+"s";
		//创建消息数据Bundle
		Bundle b=new Bundle();
		//将内容字符串放进数据Bundle中
		b.putString("msg", msgStr);
		//创建消息对象
		Message msg=new Message();
		//设置数据Bundle到消息中
		msg.setData(b);
		//设置消息的what值
		msg.what=UPDATE_TIME;
		//发送消息
		hd.sendMessage(msg);
	}

	//实现进度拖拉的监听方法
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
								  boolean fromUser) {
		if(mp!=null&&state==2)//=======Emulator work no "&&state==2"
		{
			//进度拖拉到指定位置
			mp.seekTo(progress*mp.getDuration()/sb.getMax());
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {	}
	@Override
	public void onStopTrackingTouch(SeekBar seekBar) { }
}

猜你喜欢

转载自blog.csdn.net/qq_41910103/article/details/82940712