zoukankan      html  css  js  c++  java
  • 2018-2019-2 20189203 移动平台应用开发实践第十一周学习总结

    第43,44,45,46章

    第43章 制作视频

    • 制作视频主要有两种方法,一种是使用内建意图,一种是使用MediaRecorder。
      如果使用默认的Camera应用程序来制作视频,可以使用内建意图。
      如果选择直接处理API而不是使用Camera来为应用程序提供视频制作功能,需要使用MediaRecorder。
      当使用MediaRecorder录制视频时,必须以指定的顺序执行配置步骤,然后调用MediaRecorder.prepare()检查和使用配置。
    private boolean prepareVideoRecorder(){
    
        mCamera = getCameraInstance();
        mMediaRecorder = new MediaRecorder();
    
        // Step 1: Unlock and set camera to MediaRecorder
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);
    
        // Step 2: Set sources
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    
        // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
    
        // Step 4: Set output file
        mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
    
        // Step 5: Set the preview output
        mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
    
        // Step 6: Prepare configured MediaRecorder
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }
        return true;
    }
    

    以下MediaRecorder的视频录制参数已经有了预设值,不过也可以用下面的方法调整以适用自己的应用:
    setVideoEncodingBitRate()
    setVideoSize()
    setVideoFrameRate()
    setAudioEncodingBitRate()
    setAudioChannels()
    setAudioSamplingRate()
    启动和停止MediaRecorder
    当使用MediaRecorder启动和停止录制时,必须遵从指定的顺序:

    1. Camera.unlock()
    2. 如以上的代码示例配置MediaRecorder
    3. MediaRecorder.start()启动录制
    4. 录制视频
    5. MediaRecorder.stop()停止录制
    6. MediaRecorder.release()释放MediaRecorder
    7. Camera.lock()锁定摄像头
      以下代码演示了怎样使用Camera和MediaRecorder通过一个按钮正确的启动和停止视频录制
      当完成一个视频录制后,不要释放Camera,否则预览视图也会停止
    private boolean isRecording = false;
    
    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(id.button_capture);
    captureButton.setOnClickListener(
        new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRecording) {
                    // stop recording and release camera
                    mMediaRecorder.stop();  // stop the recording
                    releaseMediaRecorder(); // release the MediaRecorder object
                    mCamera.lock();         // take camera access back from MediaRecorder
    
                    // inform the user that recording has stopped
                    setCaptureButtonText("Capture");
                    isRecording = false;
                } else {
                    // initialize video camera
                    if (prepareVideoRecorder()) {
                        // Camera is available and unlocked, MediaRecorder is prepared,
                        // now you can start recording
                        mMediaRecorder.start();
    
                        // inform the user that recording has started
                        setCaptureButtonText("Stop");
                        isRecording = true;
                    } else {
                        // prepare didn't work, release the camera
                        releaseMediaRecorder();
                        // inform user
                    }
                }
            }
        }
    );
    

    释放相机
    一个设备上,摄像头是所有应用的共享资源,因此在自身的应用处于onPause状态时,要立即释放掉正在使用的Camera对象

    public class CameraActivity extends Activity {
        private Camera mCamera;
        private SurfaceView mPreview;
        private MediaRecorder mMediaRecorder;
    
        ...
    
        @Override
        protected void onPause() {
            super.onPause();
            releaseMediaRecorder();       // if you are using MediaRecorder, release it first
            releaseCamera();              // release the camera immediately on pause event
        }
    
        private void releaseMediaRecorder(){
            if (mMediaRecorder != null) {
                mMediaRecorder.reset();   // clear recorder configuration
                mMediaRecorder.release(); // release the recorder object
                mMediaRecorder = null;
                mCamera.lock();           // lock camera for later use
            }
        }
    
        private void releaseCamera(){
            if (mCamera != null){
                mCamera.release();        // release the camera for other applications
                mCamera = null;
            }
        }
    }
    

    第44章 声音录制

    下边来介绍下这三种录制的方式;
    1、通过Intent调用系统的录音器功能,然后在录制完毕保存以后在onActivityResult中返回录制的音频的uri,然后通过Mediaplayer进行播放
    调用系统的录音器

     private final static int REQUEST_RECORDER = 100;
        private Uri uri;
        public void recorder_Intent(){
            Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
            startActivityForResult(intent,REQUEST_RECORDER);
        }
    获取返回的信息
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && REQUEST_RECORDER == requestCode){
            uri = data.getData();
        }
    }
    <span style="background-color: rgb(255, 255, 255);"><span style="font-size:24px;">通过Mediaplayer进行播放</span></span>
      if (uri != null){
                                if (mediaPlayer != null) {
                                    try {
                                        mediaPlayer.reset();
                                        mediaPlayer.setDataSource(RecorderActivity.this, uri);
                                        mediaPlayer.prepare();
    
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
    
                                }else
                                    Toast.makeText(RecorderActivity.this,"没有成功创建Mediaplayer",Toast.LENGTH_SHORT).show();
                            }
    

    2、通过MediaRecorder来进行音频的录制:
    MediaRecorder 类可用于音频和视频的捕获。再构造了一个MediaRecorder对象之后,为了捕获音频,必须调用setAudioEncoder和setAudioSource这俩个方法。
    假设不调用这些方法,那么将不会录制音频(视频也相同不会),另外,MediaRecorder在准备录制之前通常还会调用setOutputFormat 和setOutputFile,
    在实例化MediaRecorder之后。应该调用的第一个方法是setAudioSource。它採用一个AudioSource内部类中定义的常量作为參数,我们通常使用的常量是MediaRecorder。
    AudioSource.MIC.
    依据顺序,下一个调用的就是setOutputFormat ,这种方法採用在MediaRecorder.OutputFormat内部类中指定的常量作为參数:
    (1)MediaRecorder.OutputFormat.MPEG_4:这个常量指定输出的文件将是一个MPEG_4文件,包括音频跟视频轨
    (2)MediaRecorder.OutputFormat.RAW_AMR;这个常量表示输出一个没有不论什么容器类型的原始文件,仅仅有在捕获没有视频的音频且音频编码器是AMR_NB时才会使用这个常量。
    (3)MediaRecorder.OutputFormat.THREE_GPP:这个常量指定输出的文件将是一个3gpp文件(.3gp)。它可能同一时候包括音频跟视频轨

    MediaRecorder音频编码。在设置输出格式之后,能够调用setAudioEncoder方法来设置应该使用编码器,可能的值指定为MediaRecorder.AudioEncoder类中的常量。出来使用DEFAULT之外,仅仅存在一个其它的值:MediaRecorder.AudioEncoder.AMR_NB,这是自适应多速率窄带编解码器。
    这样的编解码器针对语音进行了优化,因此不适应于语音之外的其它内容。默认情况下他的採样率是8kHz,码率在 4.75~12.2kbps之间。这个俩个数据对于录制语音之外的其它内容而言很低。可是,这是当前可用于MediaRecorder的唯一选择。

    3 使用AudioRecord录制原始音频:
    这就是第三种捕获音频的方法。使用AudioRecord的类。AudioRecord是三个方法中最灵活的(由于他同意訪问原始音频流),可是他是拥有最少的内置功能。如不会自己主动压缩音频等等。
    使用AudioRecord的基础知识很easy。我们仅仅须要构造一个AudioRecord类型的对象,并传入各种不同配置參数。
    须要制定的第一个值就是音频源。以下使用值与之前用于MediaRecorder的值同样,其在MediaRecorder.AudioSource 中定义。实际上。这意味着能够使用MediaRecorder.AudioSource.MIC;
    int audiosource = MediaRecorder.AudioSource.MIC;
    须要指定的下一个值是录制的採样率,应以赫兹为单位,我们知道。MediaRecorder採样的音频是8000赫兹。
    而CD质量的音频一般是44100赫兹(44100Hz)。Hz或赫兹是每秒的样本数量。
    不同的Android手机硬件将可以以不同的採样率进行採样。对于我的这个样例将以11025Hz的採样率来进行採样,这是一个经常使用的採样率。
    int sampleRateInHz = 11025;

       接下来,须要指定捕获的音频通道的数量,在AudioFormat类中指定了用于此參数的常量。并且可依据名称理解他们。
    

    下面将使用单声道配置。
    int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    随后。须要指定音频格式。
    在AudioFormat类中也指定了一下各种可能的常量。
    AudioFormat.ENCODING_DEFAULT
    AudioFormat.ENCODING_INVALID
    AudioFormat.ENCODING_PCM_16BIT
    AudioFormat.ENCODING_PCM_8BIT

    在这四个选择中,选择PCM_16位和PCM 8位。
    

    PCM代表脉冲编码调制(Pulse Code Modulation) ,这个实际上是原始的音频样本。
    因此能够设置每一个样本的分辨率为16位或8位。16位将占用很多其它的控件和处理能力,但表示的音频将更接近真实。
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    最后将须要指定缓冲区大小。
    时间上能够查询AudioRecord类以获得最小缓冲区大小。查询方式是调用getMinBufferSize的静态方法,同一时候传入採样率,通道配置以及音频格式。

    第45章 处理Handler

    Handler的主要用途

    1. 推送未来某个时间点将要执行的Message或者Runnable到消息队列。
      方法一,通过Handler + Message的方式实现倒计时。代码如下:
    public class MainActivity extends AppCompatActivity {
        private ActivityMainBinding mBinding;
     
        private Handler mHandler ;
     
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
     
            //设置监听事件
            mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //通过Handler + Message的方式实现倒计时
                    for (int i = 1; i <= 10; i++) {
                        Message message = Message.obtain(mHandler);
                        message.what = 10 - i;
                        mHandler.sendMessageDelayed(message, 1000 * i); //通过延迟发送消息,每隔一秒发送一条消息
                    }
                }
            });
     
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    mBinding.time.setText(msg.what + "");   //在handleMessage中处理消息队列中的消息
                }
            };
        }
    }
    

    可以了解到Handler的一个作用就是,在主线程中,可以通过Handler来处理一些有顺序的操作,让它们在固定的时间点被执行。
    方法二,通过Handler + Runnable的方式实现倒计时。代码如下:

    public class MainActivity extends AppCompatActivity {
        private ActivityMainBinding mBinding;
        private Handler mHandler = new Handler();
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
     
            //设置监听事件
            mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    for (int i = 1; i <= 10; i++) {
                        final int fadedSecond = i;
                        //每延迟一秒,发送一个Runnable对象
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                mBinding.time.setText((10 - fadedSecond) + "");
                            }
                        }, 1000 * i);
                    }
                }
            });
        }
    }
    
    1. 在子线程把需要在另一个线程执行的操作加入到消息队列中去。

    第46章 异步工具

    AsyncTask提供了方便的接口实现工作线程和主线程的通信,代码如下:

    public class MyAsyncTask extends AsyncTask<Integer, String, String> {
            private Button btn;
            public MyAsyncTask(Button btn) {
                super();
                this.btn = btn;
            }
      
            @Override
            protected String doInBackground(Integer... integers) {
                Log.e("xxxxxx","xxxxxxexecute传入参数="+integers[0]);
                try {
                    Thread.sleep(1000);
                    publishProgress("过了一秒");
                    Thread.sleep(1000);
                    publishProgress("过了两秒");
                    Thread.sleep(1000);
                    publishProgress("过了三秒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "doInBackground的返回";
            }
            /**
             * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
             * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
             */
            @Override
            protected void onPostExecute(String result) {
                btn.setText("线程结束" + result);
            }
            //该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
            @Override
            protected void onPreExecute() {
                btn.setText("开始执行异步线程");
            }
            /**
             * 这里的Intege参数对应AsyncTask中的第二个参数
             * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
             * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
             */
            @Override
            protected void onProgressUpdate(String... values) {
    
                String vlaue = values[0]+"";
                Log.e("xxxxxx","xxxxxx vlaue="+vlaue);
                btn.setText(vlaue+"");
    
    
            }
        }
    

    AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。
    AsyncTask定义了三种泛型类型 Params,Progress和Result。
    Params 启动任务执行的输入参数,比如HTTP请求的URL。
    Progress 后台任务执行的百分比。
    Result 后台执行任务最终返回的结果,比如String。
    对应到上面的demo就是Integer, String, String。
    doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
    onProgressUpdate(String... Progress)这里对应的是doInBackground中调用的publicProgress,在这里进行处理,这里是UI主线程可以进行界面的更新
    onPreExecute()这里相当于线程的开始,可以进行UI的处理
    onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
    我们再来看一下如何开启
    myAsyncTask.execute(1000);
    execute的参数对应的就是上面提到过的Params。

  • 相关阅读:
    Ubuntu配置sublime text 3的c编译环境
    ORA-01078错误举例:SID的大写和小写错误
    linux下多进程的文件拷贝与进程相关的一些基础知识
    ASM(四) 利用Method 组件动态注入方法逻辑
    基于Redis的三种分布式爬虫策略
    Go语言并发编程总结
    POJ2406 Power Strings 【KMP】
    nyoj 会场安排问题
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
    Java的String、StringBuffer和StringBuilder的区别
  • 原文地址:https://www.cnblogs.com/23du/p/10853703.html
Copyright © 2011-2022 走看看