Android当前活动的屏幕视频记录

cap*_*oid 23 java android screen record

是否可以从同一活动中记录当前运行活动的屏幕视频?
我知道如何截取当前活动的截图,但对屏幕视频记录没有任何想法.我该如何开始呢?我不知道如何开始它.

Dan*_*npe 27

自从棒棒糖以来我们可以使用Media Projection API!(API 21+)

以下是我用于记录的以下代码,请注意,我们首先需要获取用户的权限;)

private static final int CAST_PERMISSION_CODE = 22;
private DisplayMetrics mDisplayMetrics;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private MediaRecorder mMediaRecorder;

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

    mMediaRecorder = new MediaRecorder();

    mProjectionManager = (MediaProjectionManager) getSystemService
            (Context.MEDIA_PROJECTION_SERVICE);

    getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);

    prepareRecording();
}

private void startRecording() {
    // If mMediaProjection is null that means we didn't get a context, lets ask the user
    if (mMediaProjection == null) {
        // This asks for user permissions to capture the screen
        startActivityForResult(mProjectionManager.createScreenCaptureIntent(), CAST_PERMISSION_CODE);
        return;
    }
    mVirtualDisplay = createVirtualDisplay();
    mMediaRecorder.start();
}

private void stopRecording() {
    if (mMediaRecorder != null) {
        mMediaRecorder.stop();
        mMediaRecorder.reset();
    }
    if (mVirtualDisplay != null) {
        mVirtualDisplay.release();
    }
    if (mMediaProjection != null) {
        mMediaProjection.stop();
    }
    prepareRecording();
}

public String getCurSysDate() {
    return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
}

private void prepareRecording() {
    try {
        mMediaRecorder.prepare();
    } catch (Exception e) {
        e.printStackTrace();
        return;
    }

    final String directory = Environment.getExternalStorageDirectory() + File.separator + "Recordings";
    if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
        Toast.makeText(this, "Failed to get External Storage", Toast.LENGTH_SHORT).show();
        return;
    }
    final File folder = new File(directory);
    boolean success = true;
    if (!folder.exists()) {
        success = folder.mkdir();
    }
    String filePath;
    if (success) {
        String videoName = ("capture_" + getCurSysDate() + ".mp4");
        filePath = directory + File.separator + videoName;
    } else {
        Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
        return;
    }

    int width = mDisplayMetrics.widthPixels;
    int height = mDisplayMetrics.heightPixels;

    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
    mMediaRecorder.setVideoFrameRate(30);
    mMediaRecorder.setVideoSize(width, height);
    mMediaRecorder.setOutputFile(filePath);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode != CAST_PERMISSION_CODE) {
        // Where did we get this request from ? -_-
        Log.w(TAG, "Unknown request code: " + requestCode);
        return;
    }
    if (resultCode != RESULT_OK) {
        Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
        return;
    }
    mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    // TODO Register a callback that will listen onStop and release & prepare the recorder for next recording
    // mMediaProjection.registerCallback(callback, null);
    mVirtualDisplay = getVirtualDisplay();
    mMediaRecorder.start();
}

private VirtualDisplay getVirtualDisplay() {
    screenDensity = mDisplayMetrics.densityDpi;
    int width = mDisplayMetrics.widthPixels;
    int height = mDisplayMetrics.heightPixels;

    return mMediaProjection.createVirtualDisplay(this.getClass().getSimpleName(),
            width, height, screenDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
}
Run Code Online (Sandbox Code Playgroud)

这不是最终的代码,但是开始的GOOD基础:)


mik*_*guy 15

编辑:这个答案是答案所取代下面从Danpe.

以编程方式记录您应用内的视频将需要root访问权限.您会注意到Play商店中可用的应用程序在其应用程序描述中突出显示"需要根".您还会注意到,这种方法可能还有一些特定的硬件要求("不适用于Galaxy Nexus或Tegra 2/3 ......" - 来自Screencast Video Recorder应用程序的描述.

我自己从未编写过这段代码,但我已经对所需的方法提出了非常高级的想法.从这篇文章中可以看出,您必须通过"/ dev/graphics/fb0"访问帧缓冲区数据.帧缓冲区的访问模式是660,这意味着您需要root访问权限才能访问它.一旦您具有root访问权限,就可以使用帧缓冲区数据来创建屏幕截图(此项目可能适用于此任务),然后从这些屏幕截图创建视频(请参阅另一个关于如何从图像序列创建视频的问题).

我使用过Screencast应用程序,它在三星Note上运行良好.我怀疑这是他们采取的基本方法.

  • 选择的解决方案必须过时,因为Play商店中肯定有不需要root用户权限才能记录设备屏幕的应用。因此可以肯定地说,如果这些应用程序可以记录任何应用程序的整个屏幕,那么您也可以记录活动。 (2认同)

小智 11

普通的Android应用程序缺少捕获帧缓冲区的权限(具体来说,它们不是AID_GRAPHICS组的成员).这是出于安全原因 - 否则他们可能会从软键盘中窃取密码等.因此,一般情况下,如果没有某种方式解决权限问题,您无法从Android应用程序捕获屏幕.

您可以或多或少地捕获应用程序当前占用的屏幕区域的快照,方法是遍历视图层次结构中的顶部视图,并使用View.draw(Canvas)将其绘制到位图中,但是这不会记录状态栏,软键盘,OpenGL表面等

如果你想做得比这更好,你需要使用外部工具.工具需要root或使用ADB接口,因为通过ADB接口启动的进程具有AID_GRAPHICS权限.使用后一种方法,非特权应用程序可以连接到特权服务器进行录制.

粗略的工具可以分为以下几类:

  • 仅根帧缓冲记录器应用程序(例如Screencast).这些记录直接来自/ dev/graphics/fb0设备,但仅适用于帧缓冲区可读的设备(例如,不在Tegra 2 Nexus 7上).

  • 仅限根屏幕捕获记录器应用程序(例如SCR,Rec等).它们通过SurfaceFlinger捕获屏幕,并在更广泛的设备上工作.

  • 非根屏幕捕获记录器应用程序(例如,可记录,Ascrecorder).这些要求用户启用USB调试并在通过主机PC连接时启动守护程序.此后,在重启设备之前不需要主机PC.也可以录制音频.

  • ADB工具(例如,Android 4.4上的内置屏幕录像机).要求您通过USB连接,无法捕获音频.

几个月前,我对这里提供的可用应用进行了比较:

http://recordable.mobi/compare

为了完整性,还有USB工具(例如,Mobizen)通过USB流式传输屏幕(受低USB带宽限制,无法录制音频),有些设备也可以通过wifi传输屏幕,然后可以在单独的设备上捕获.


HB.*_*HB. 6

我创建了一个来为你处理这个问题。包括可自定义的通知显示,如果您不想显示通知,可以将其禁用。

它需要API 21>


这是有关如何使用它的简单演示:(更多信息可以在库的自述文件中找到):

首先,在您的 中声明并初始化它Activity

public class MainActivity extends AppCompatActivity implements HBRecorderListener {
    //Declare HBRecorder
    HBRecorder hbRecorder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     

        //Init HBRecorder
        hbRecorder = new HBRecorder(this, this);        

}
Run Code Online (Sandbox Code Playgroud)

然后当你想开始录音时,你可以调用:

private void startRecordingScreen() {
    MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    Intent permissionIntent = mediaProjectionManager != null ? mediaProjectionManager.createScreenCaptureIntent() : null;
    startActivityForResult(permissionIntent, SCREEN_RECORD_REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == SCREEN_RECORD_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            //It is important to call this before starting the recording
            hbRecorder.onActivityResult(resultCode, data, this);
            //Start screen recording
            hbRecorder.startScreenRecording(data);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过调用以下命令来停止录音:

hbRecorder.stopScreenRecording();
Run Code Online (Sandbox Code Playgroud)

onCompleteListener您知道文件的创建时间:

@Override
public void HBRecorderOnComplete() {
    //This is called once the file was created
}
Run Code Online (Sandbox Code Playgroud)

我还添加了一些可以设置的参数,例如更改等AudioBitrateAudioSamplingRate