第29讲 slowmotion实战 -凯发k8手机登录

本讲是android camera专题系列的第29讲,我们介绍android camera2 api专题的slowmotion实战。

更多资源:

资源 描述
在线课程
知识星球 星球名称:深入浅出android camera
星球id: 17296815
wechat 极客笔记圈

判断是否支持slow motion

camera方面

capability

  • 是否支持request_available_capabilities_constrained_high_speed_video

streamconfigurationmap

  • gethighspeedvideosizes()不为null
  • 每一种size对应的gethighspeedvideofpsrangesfor不为null

实战代码

geekcamera2\app\src\main\java\com\deepinout\geekcamera\cts\helpers\staticmetadata.java#ishighspeedvideosupported

public boolean ishighspeedvideosupported() {
    if (!iscapabilitysupported(
            cameracharacteristics.request_available_capabilities_constrained_high_speed_video)) {
        return false;
    }
    streamconfigurationmap config =
            getvaluefromkeynonnull(cameracharacteristics.scaler_stream_configuration_map);
    if (config == null) {
        return false;
    }
    size[] availablesizes = config.gethighspeedvideosizes();
    if (availablesizes.length == 0) {
        return false;
    }
    for (size size : availablesizes) {
        range[] availablefpsranges = config.gethighspeedvideofpsrangesfor(size);
        if (availablefpsranges.length == 0) {
            return false;
        }
    }
    return true;
}

video encoder方面

从camcorderprofile判断是否支持high speed quality的profile

实战代码

geekcamera2\app\src\main\java\com\deepinout\geekcamera\cameracontroller\cameracontroller2.java#getfpsfromhighspeedprofileforsize

private int getfpsfromhighspeedprofileforsize(android.util.size size) {
    for (int quality = camcorderprofile.quality_high_speed_low;
         quality <= camcorderprofile.quality_high_speed_2160p; quality  ) {
        if (camcorderprofile.hasprofile(quality)) {
            camcorderprofile profile = camcorderprofile.get(quality);
            if (size.equals(new android.util.size(profile.videoframewidth, profile.videoframeheight))){
                return profile.videoframerate;
            }
        }
    }
    return 0;
}

slow motion支持的size和fps

遍历camera支持的size和fps,对每一种size和fps的组合去检查camcorderprofile是否支持

实战代码

geekcamera2\app\src\main\java\com\deepinout\geekcamera\cameracontroller\cameracontroller2.java#doinitsupportedhighspeedvideosizes

private void doinitsupportedhighspeedvideosizes(camerafeatures camera_features,
                                                streamconfigurationmap configs) {
    log.i(tag, "[slow_motion] doinitsupportedhighspeedvideosizes");
    hs_fps_ranges = new arraylist<>();
    camera_features.msupportedvideosizeshighspeed = new arraylist<>();
    for (range r : configs.gethighspeedvideofpsranges()) {
        hs_fps_ranges.add(new int[] {r.getlower(), r.getupper()});
    }
    collections.sort(hs_fps_ranges, new cameracontroller.rangesorter());
    if( mydebug.log ) {
        log.i(tag, "[slow_motion] camera supported high speed video fps ranges: ");
        for (int[] f : hs_fps_ranges) {
            log.i(tag, "[slow_motion]   camera hs range: ["   f[0]   "-"   f[1]   "]");
        }
        log.i(tag, "[slow_motion] video supported high speed video camcorder profiles: ");
        for (int quality = camcorderprofile.quality_high_speed_low;
             quality <= camcorderprofile.quality_high_speed_2160p; quality  ) {
            if (camcorderprofile.hasprofile(quality)) {
                camcorderprofile profile = camcorderprofile.get(quality);
                log.i(tag, "[slow_motion]   video hs camcorder profile:"   profile.videoframewidth
                                  "x"   profile.videoframeheight   "@"   profile.videoframerate   " fps"  
                                   ",quality:"   quality);
            }
        }
    }
    android.util.size[] camera_video_sizes_high_speed = configs.gethighspeedvideosizes();
    for(android.util.size camera_size : camera_video_sizes_high_speed) {
        for (range r : configs.gethighspeedvideofpsrangesfor(camera_size)) {
            int profile_fps = getfpsfromhighspeedprofileforsize(camera_size);
            if (r.getupper() > r.getlower()) {
                log.w(tag, "[slow_motion] skip "   camera_size   "@fps range:"   r.tostring());
                continue;
            }
            if (r.getupper() != profile_fps) {
                log.w(tag, "[slow_motion] high speed recording "   camera_size   "@"   r.getupper()   "fps"
                          " is not supported by camcorderprofile");
                continue;
            }
            arraylist fr = new arraylist<>();
            fr.add(new int[] { r.getlower(), r.getupper()});
            cameracontroller.size hs_video_size = new cameracontroller.size(
                    camera_size.getwidth(),
                    camera_size.getheight(),
                    fr,
                    true);
            if (mydebug.log) {
                log.i(tag, "[slow_motion] added high speed video size: "  
                        hs_video_size  
                        ", fps range:"   r.tostring());
            }
            camera_features.msupportedvideosizeshighspeed.add(hs_video_size);
        }
    }
    collections.sort(camera_features.msupportedvideosizeshighspeed, new cameracontroller.sizesorter());
}

camera流程控制

session创建

  • 创建sessionconfiguration时,session type要设置为sessionconfiguration.session_high_speed
  • 只配置一个preview surface 一个video recording surface,不支持video snapshot

实战代码

geekcamera2\app\src\main\java\com\deepinout\geekcamera\cameracontroller\cameracontroller2.java#createcapturesession

msessionconfiguration = new sessionconfiguration(
        is_video_high_speed ?
                sessionconfiguration.session_high_speed : sessionconfiguration.session_regular,
        outputconfigurations,
        new cameratestutils.handlerexecutor(mcamerabackgroundhandler),
        mystatecallback
);

repeating burst request创建

  • 调用cameraconstrainedhighspeedcapturesession# createhighspeedrequestlist,根据一个request产生一组capturerequest

实战代码

geekcamera2\app\src\main\java\com\deepinout\geekcamera\cameracontroller\cameracontroller2.java#setrepeatingrequest

if( is_video_high_speed && build.version.sdk_int >= build.version_codes.m ) {
    cameraconstrainedhighspeedcapturesession capturesessionhighspeed = (cameraconstrainedhighspeedcapturesession) mcameracapturesession;
    list mpreviewbuilderburst = capturesessionhighspeed.createhighspeedrequestlist(request);
    log.i(tag, "[slow_motion] setrepeatingburst createhighspeedrequestlist size:"   mpreviewbuilderburst.size());
    capturesessionhighspeed.setrepeatingburst(mpreviewbuilderburst, previewcapturecallback, mcamerabackgroundhandler);
}

repeating burst capturerequest的个数(batch size)是如何决定决定的

  • 录像过程中预览一般30fps就足够了,因此batch size的计算会想办法将预览帧率限制在30fps

    mediarecorder流程控制

  • 举例240fps的capturerequest list有8个batch size

    mediarecorder流程控制

mediarecorder流程控制

将camcorderprofile中的值设置给mediarecorder

setvideoframerate

  • slow motion
    • 建议不要录制audio
    • 通过setvideoframerate设置的video frame rate要小于capture rate,建议为30

  • 高帧率视频

    • video frame rate与capture rate相等

实战代码

geekcamera2\app\src\main\java\com\deepinout\geekcamera\preview\videoprofile.java#copytomediarecorder

public void copytomediarecorder(mediarecorder media_recorder, boolean slow_motion) {
    if( mydebug.log )
        log.d(tag, "copytomediarecorder: "   media_recorder   tostring());
    if( record_audio && !slow_motion) {
        if( mydebug.log )
            log.d(tag, "record audio");
        media_recorder.setaudiosource(this.audiosource);
    }
    media_recorder.setvideosource(this.videosource);
    // n.b., order may be important - output format should be first, at least
    // also match order of mediarecorder.setprofile() just to be safe, see https://stackoverflow.com/questions/5524672/is-it-possible-to-use-camcorderprofile-without-audio-source
    media_recorder.setoutputformat(this.fileformat);
    if (slow_motion) {
        media_recorder.setvideoframerate(30);
    } else {
        media_recorder.setvideoframerate(this.videoframerate);
    }
    media_recorder.setcapturerate(this.videocapturerate);
    media_recorder.setvideosize(this.videoframewidth, this.videoframeheight);
    media_recorder.setvideoencodingbitrate(this.videobitrate);
    media_recorder.setvideoencoder(this.videocodec);
    if( record_audio && !slow_motion) {
        media_recorder.setaudioencodingbitrate(this.audiobitrate);
        media_recorder.setaudiochannels(this.audiochannels);
        media_recorder.setaudiosamplingrate(this.audiosamplerate);
        media_recorder.setaudioencoder(this.audiocodec);
    }
    if( mydebug.log )
        log.d(tag, "done: "   media_recorder);
}

camera课程

python教程

java教程

web教程

数据库教程

图形图像教程

办公软件教程

linux教程

计算机教程

大数据教程

开发工具教程

android camera2 api

网站地图