【问题标题】:Screen Video Record of Current Activity Android当前活动Android的屏幕视频记录
【发布时间】:2012-12-29 11:15:32
【问题描述】:

是否可以从同一活动中录制当前正在运行的活动的屏幕视频?
我知道如何截取当前活动的屏幕截图,但对截取屏幕视频一无所知。 我该如何开始呢?我不知道如何开始。

【问题讨论】:

  • 我认为我们必须使用工具进行录制..
  • 好吧,我的要求和play.google.com/store/apps/… 的要求不一样,但是他们如何在不使用任何外部工具的情况下做到这一点?
  • 是的,可以截屏然后添加到视频中
  • 不使用任何外部工具我将如何做到这一点?你能给我一些指导吗?
  • 你知道如何捕获屏幕,然后添加图像以获取视频

标签: java android screen record


【解决方案1】:

普通的 Android 应用缺乏捕获帧缓冲区的权限(具体来说,它们不是 AID_GRAPHICS 组的成员)。这是出于安全原因 - 否则他们可以从软键盘上窥探密码等。因此,一般来说,如果没有解决权限问题的方法,您将无法从 Android 应用程序捕获屏幕。

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

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

工具大致可以分为以下几类:

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

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

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

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

为了完整起见,还有 USB 工具(例如 Mobizen)通过 USB 流式传输屏幕(受低 USB 带宽限制且无法录制音频),一些设备还可以通过 wifi 传输屏幕,然后可以在一个单独的设备。

【讨论】:

  • 虽然帖子已有 7 年的历史,但单击 .mobi 的链接会将您带到看起来像病毒的地方
  • 是的,域名已被抢注。链接已删除。
【解决方案2】:

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

它需要 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);        

}

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

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);
        }
    }
}

您可以通过调用停止录制:

hbRecorder.stopScreenRecording();

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

@Override
public void HBRecorderOnComplete() {
    //This is called once the file was created
}

我还添加了一堆可以设置的参数,比如更改AudioBitrateAudioSamplingRate等。

【讨论】:

  • 另外,方法hbRecorder.onActivityResult 不存在
  • @KonstantinKonopko 在图书馆打开一个问题。
【解决方案3】:

编辑:此答案已被 Danpe 的答案 below 取代。

在您的应用中以编程方式录制视频需要 root 访问权限。您会注意到 Play 商店中可用于执行此操作的应用程序在其应用程序描述中显着地列出了“REQUIRES ROOT”。您还会注意到,这种工作方法可能还存在一些特定的硬件要求(“不适用于 Galaxy Nexus 或 Tegra 2/3...”——来自 Screencast Video Recorder 应用程序的描述。

我自己从未编写过这段代码,但我已经对所需的方法提出了一个非常高级的想法。从这个post 看来,您必须通过“/dev/graphics/fb0”访问帧缓冲区数据。帧缓冲区的访问模式是 660,这意味着您需要 root 访问权限才能访问它。获得 root 访问权限后,您可以使用帧缓冲区数据创建屏幕截图(此 project 可能适用于此任务),然后从这些屏幕截图创建视频(请参阅其他 SO question on how to create video from an image sequence)。

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

【讨论】:

  • 虽然我没有得到具体的答案,但你已经提供了一些关于截图帧缓冲区和 root 访问的想法。我将进一步研究它。并将其标记为正确答案。感谢您的指导。
  • 这个选择的解决方案一定是过时的,因为Play Store中肯定有应用不需要root权限来记录设备的屏幕。因此可以肯定地说,如果这些应用程序可以记录任何应用程序的整个屏幕,那么您也可以记录一个活动。
【解决方案4】:

自从 Lollipop 我们可以使用 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*/);
}

这不是最终代码,而是开始的良好基础:)

【讨论】:

  • 这很好。在 sdcard 中获取 mp4 视频文件,但它在视频中包含黑框。全屏视频和处理渗透弹出的任何解决方案?
  • 太棒了!谢谢!
  • 在棉花糖中对 medirecorder.getsurface() illigalstateexception 不起作用
  • 每次启动应用都会请求权限?还有其他方法吗?
  • 我创建了一个库来为您处理所有这些,包括显示通知,看看我的回答 - stackoverflow.com/a/57533525/5550161
【解决方案5】:

这是一篇很老的帖子,但我希望这对仍在寻找记录安卓设备屏幕的方法的人有所帮助:

从 Android 5.0 开始,有一个新的 API 可用于屏幕录制: MediaProjection MediaProjection 允许捕获屏幕内容,但不能捕获系统音频。它也不会捕获安全的屏幕内容。

在 Matt Snider 的页面上有一个很好的例子,说明如何使用 API 将屏幕实际记录到 sdcard 上的文件中:LINK

【讨论】:

    【解决方案6】:

    您可以在 adb 运行时使用 DDMS 来捕获屏幕,并且对帧缓冲区具有权限:

    点击此链接了解更多详情:

    http://thetechjournal.com/electronics/android/how-to-capture-screenshots-and-record-video-on-android-device.xhtml

    也 检查此链接可能会对您的需求有所了解:

    http://answers.oreilly.com/topic/951-how-to-capture-video-of-the-screen-on-android/

    http://www.mightypocket.com/2010/09/installing-android-screenshots-screen-capture-screen-cast-for-windows/

    并检查这个项目:

    http://sourceforge.net/projects/ashot/

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多