当前活动的屏幕录像logging
是否有可能从同一活动logging当前正在运行的活动的屏幕video?
我知道如何截取目前的活动,但不知道如何拍摄屏幕录像。 我将如何开始呢? 我不知道如何启动它。
以编程方式从您的应用程序录制video将需要root权限。 您会注意到Play商店中可用的应用在其应用说明中突出显示了“需要ROOT”。 您还会注意到,对于这种工作方式(“不适用于Galaxy Nexus或Tegra 2/3 …”),也可能存在某些特定的硬件要求(从Screencast Video Recorder应用程序的描述中)。
我从来没有自己写过这个代码,但是我已经把所需要的方法放在了一个非常高的层次上。 从这篇文章看来,你必须通过“/ dev / graphics / fb0”来访问帧缓冲区数据。 帧缓冲区的访问模式是660,这意味着您需要root访问才能访问它。 一旦你有root权限,你可以使用帧缓冲数据来创build屏幕截图(这个项目可能适用于这个任务),然后从这些截图创buildvideo(请参阅这个其他如何从图像序列创buildvideo问题)。
我已经使用了Screencast应用程序,它在Samsung Note上运行良好。 我怀疑这是他们采取的基本方法。
由于棒棒糖我们可以使用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*/); }
这不是最终的代码,而是一个好的基础:)
正常的Android应用程序没有权限捕获帧缓冲区(具体而言,它们不是AID_GRAPHICS组的成员)。 这是出于安全原因 – 否则他们可以从软键盘上窃听密码等。 所以一般来说你不能捕捉Android应用程序的屏幕,而没有任何方式来解决特权问题。
您可以通过遍历视图层次结构中的顶层视图并使用View.draw(canvas)将其绘制到位图中来捕获当前占用的屏幕区域的快照,但是这不会logging状态栏,软键盘,OpenGL表面等
如果你想做的比这更好,你将需要使用一个外部工具。 工具需要root或使用ADB接口,因为通过ADB接口启动的进程具有AID_GRAPHICS特权。 使用后一种方法,非特权应用可以连接到特权服务器来进行录制。
大致的工具可以分为以下几类:
-
仅限根帧缓冲logging器应用程序(例如Screencast)。 这些logging直接来自/ dev / graphics / fb0设备,但仅适用于帧缓冲区可读的设备(例如,不在Tegra 2 Nexus 7上)。
-
仅根屏幕捕获logging器应用程序(例如SCR,Rec等)。 这些通过SurfaceFlinger捕获屏幕,并在更广泛的设备上工作。
-
非根屏幕捕获logging器应用程序(例如,可logging,Ascrecorder)。 这些要求用户启用USBdebugging,并通过主机PC连接时启动守护进程。 此后主机PC不需要,直到设备重新启动。 也可以录制audio。
-
ADB工具(例如,Android 4.4中的内置屏幕录像机)。 要求您通过USB连接,无法捕捉audio。
几个月前,我做了一个在这里可用的应用程序的比较:
http://recordable.mobi/compare
为了完整性,还有USB工具(例如,Mobizen)跨USBstream动屏幕(由低USB bandwdith限制,不能录制audio),一些设备也可以通过wifi传输屏幕,然后可以在单独的设备上捕获。
这是一个很老的post,但我希望这将帮助仍在寻找一种方式来loggingAndroid设备的屏幕的人:
由于Android 5.0有一个可用于屏幕录制的新API: MediaProjection MediaProjection可以捕获屏幕内容,但不能捕获系统audio。 也不会捕获安全的屏幕内容。
在Matt Snider的页面上,有一个关于如何使用API实际将屏幕logging到SD卡上的文件的好例子: LINK
您可以通过使用DDMS捕获屏幕,因为adb运行并且具有帧缓冲区的权限:
点击此链接了解更多详情:
另外检查这个链接可能会得到你需要什么的一些想法:
http://answers.oreilly.com/topic/951-how-to-capture-video-of-the-screen-on-android/
并检查这个项目:
http://sourceforge.net/projects/ashot/
希望这个帮助。
您也可以通过这种方式logging您的屏幕: http : //www.youtube.com/watch?v= 4K2UDfP4lN8& list= UU4fDGas-Vz1xruuUY4QbF0w& feature=c4-overview 。
该video的标题是“如何捕捉/logging没有根(Mobizen)的Android屏幕”。
该video参考了Mobizen的使用: https : //play.google.com/store/apps/details? id = com.rsupport.mvagent