AndroidTV视频录制遇到的问题

公司现在的项目是一个在AndroidTV上开发的,要添加一个新的需求,录制视频。记录一下在AndroidTV上开发录制视频时遇到的小问题:

注: 对于只有一个摄像头的手机可能会有同样的问题,未测试过

  • 无法获取到Camera对象
  • 获取到Camera对象,在设置录制质量等一系列数据时MediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));时,捕获到空指针

  1. 无法获取到Camera对象(目标TV上只有一个摄像头,QQ在该TV上同样无法获取到摄像头)
    注意的地方: 通常我们获取Camera对象直接调用Camera.open()
        Camera c = null;
        try {
            c = Camera.open();
        } catch (Exception e) {
            LogUtils.e("camera", "Open Camera Failed", e);
        }

Camera类中提供给我们两个获取Camera对象的方法(无参或有参):

  /**
     * Creates a new Camera object to access the first back-facing camera on the
     * device. If the device does not have a back-facing camera, this returns
     * null.
     * @see #open(int)
     */
    public static Camera open() {
        int numberOfCameras = getNumberOfCameras();
        CameraInfo cameraInfo = new CameraInfo();
        for (int i = 0; i < numberOfCameras; i++) {
            getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                return new Camera(i);
            }
        }
        return null;
    }

注意到该方法的提示信息If the device does not have a back-facing camera, this returns null.,如果没有后置摄像头,那么返回值为 NULL,即我们并没有获取到Camera对象。只有一个摄像头时,系统并没有获取到cameraInfo.facingCamera.open()无参默认打开后置摄像头。讲到这里,你可能已经明白我没有获取到Camera对象的原因了...
接下来继续看一下,Camera.open(number)带参数的系统方法:

 /**
     * Creates a new Camera object to access a particular hardware camera. If
     * the same camera is opened by other applications, this will throw a
     * RuntimeException.
     *
     * 

You must call {@link #release()} when you are done using the camera, * otherwise it will remain locked and be unavailable to other applications. * *

Your application should only have one Camera object active at a time * for a particular hardware camera. * *

Callbacks from other methods are delivered to the event loop of the * thread which called open(). If this thread has no event loop, then * callbacks are delivered to the main application event loop. If there * is no main application event loop, callbacks are not delivered. * *

Caution: On some devices, this method may * take a long time to complete. It is best to call this method from a * worker thread (possibly using {@link android.os.AsyncTask}) to avoid * blocking the main application UI thread. * * @param cameraId the hardware camera to access, between 0 and * {@link #getNumberOfCameras()}-1. * @return a new Camera object, connected, locked and ready for use. * @throws RuntimeException if opening the camera fails (for example, if the * camera is in use by another process or device policy manager has * disabled the camera). * @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName) */ public static Camera open(int cameraId) { return new Camera(cameraId); }

注意到该方法返回我们输入参数获取对应的Camera对象,项目中我是通过Camera.open(0)获取到Camera对象的。

  1. 程序运行到mediarecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));捕获到空指针异常。
    我们先来了解一下setProfile(getProfile())方法有什么作用:

百度上的解释 设置录制文件质量,格式,分辨率之类

Camcorder.get()方法和Camera.open()相似系统同样有两个重载方法

  • CamcorderProfile.get(int) 单参数
  • CamcorderProfile.get(int,int) 双参数

我们看一下系统中两个方法的定义:

   /**
     * Returns the camcorder profile for the first back-facing camera on the
     * device at the given quality level. If the device has no back-facing
     * camera, this returns null.
     * @param quality the target quality level for the camcorder profile
     * @see #get(int, int)
     */
    public static CamcorderProfile get(int quality) {
        int numberOfCameras = Camera.getNumberOfCameras();
        CameraInfo cameraInfo = new CameraInfo();
        for (int i = 0; i < numberOfCameras; i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                return get(i, quality);
            }
        }
        return null;
    }

**和Camera.open()一样,并没有返回要设置的内容,而是返回一个NULL,所以我们只能调用CamcorderProfile.get(int,int);来设置录制质量,看一下双参数的系统方法,如下: **

 /**
     * Returns the camcorder profile for the given camera at the given
     * quality level.
     *
     * A camcorder recording session with higher quality level usually has higher output
     * bit rate, better video and/or audio recording quality, larger video frame
     * resolution and higher audio sampling rate, etc, than those with lower quality
     * level.
     *
     * @param cameraId the id for the camera
     * @param quality the target quality level for the camcorder profile.
     * @see #QUALITY_LOW
    */
    public static CamcorderProfile get(int cameraId, int quality) {
        if (!((quality >= QUALITY_LIST_START &&
               quality <= QUALITY_LIST_END) ||
              (quality >= QUALITY_TIME_LAPSE_LIST_START &&
               quality <= QUALITY_TIME_LAPSE_LIST_END) ||
               (quality >= QUALITY_HIGH_SPEED_LIST_START &&
               quality <= QUALITY_HIGH_SPEED_LIST_END))) {
            String errMessage = "Unsupported quality level: " + quality;
            throw new IllegalArgumentException(errMessage);
        }
        return native_get_camcorder_profile(cameraId, quality);
    }

setProfile(CamcorderProfile)方法也可以看一下具体设置那些东西

 /**
     * Uses the settings from a CamcorderProfile object for recording. This method should
     * be called after the video AND audio sources are set, and before setOutputFile().
     * If a time lapse CamcorderProfile is used, audio related source or recording
     * parameters are ignored.
     *
     * @param profile the CamcorderProfile to use
     * @see android.media.CamcorderProfile
     */
    public void setProfile(CamcorderProfile profile) {
        setOutputFormat(profile.fileFormat);
        setVideoFrameRate(profile.videoFrameRate);
        setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
        setVideoEncodingBitRate(profile.videoBitRate);
        setVideoEncoder(profile.videoCodec);
        if (profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
             profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) {
            // Nothing needs to be done. Call to setCaptureRate() enables
            // time lapse video recording.
        } else {
            setAudioEncodingBitRate(profile.audioBitRate);
            setAudioChannels(profile.audioChannels);
            setAudioSamplingRate(profile.audioSampleRate);
            setAudioEncoder(profile.audioCodec);
        }
    }

你可能感兴趣的:(AndroidTV视频录制遇到的问题)