Est-il possible d'enregistrer une vidéo à l'écran de l'activité en cours d'exécution à partir de la même activité?
Je sais prendre une capture d'écran de l'activité en cours, mais je n'ai aucune idée de l'enregistrement vidéo à l'écran. Comment pourrais-je commencer avec ça? Je ne sais pas comment le démarrer.
[~ # ~] modifier [~ # ~] : Cette réponse est remplacée par la réponse ci-dessous de Danpe.
L'enregistrement par programme de vidéos à partir de votre application nécessite un accès root. Vous remarquerez que les applications disponibles pour ce faire dans le Play Store répertorient bien "REQUIRE ROOT" dans leurs descriptions d'applications. Vous remarquerez également qu'il peut également y avoir des exigences matérielles spécifiques pour que cette approche fonctionne ("Ne fonctionne pas sur Galaxy Nexus ou Tegra 2/3 ..." - à partir de la description de la Screencast Video Recorder app.
Je n'ai jamais écrit ce code moi-même, mais j'ai mis en place une idée de très haut niveau de l'approche requise. Il ressort de ce post que vous devez accéder aux données du tampon de trame via "/ dev/graphics/fb0". Le mode d'accès pour le tampon de trame est 660, ce qui signifie que vous avez besoin d'un accès root pour y accéder. Une fois que vous avez un accès root, vous pouvez utiliser les données du tampon d'image pour créer des captures d'écran (ce projet pourrait fonctionner pour cette tâche), puis créer une vidéo à partir de ces captures d'écran (voir cet autre SO question sur la façon de créer une vidéo à partir d'une séquence d'images ).
J'ai utilisé l'application Screencast et cela fonctionne bien sur un Samsung Note. Je soupçonne que c'est l'approche de base qu'ils ont adoptée.
Depuis Lollipop, nous pouvons utiliser l'API Media Projection! (API 21 +)
Voici le code suivant que j'utilise pour l'enregistrement, notez que nous devons d'abord obtenir les autorisations utilisateur pour cela;)
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*/);
}
Ce n'est pas le code final mais une bonne base pour commencer :)
Normal Android ne sont pas autorisées à capturer le tampon de trame (en particulier, elles ne sont pas membres du groupe AID_GRAPHICS). C'est pour des raisons de sécurité - sinon elles pourraient espionner les mots de passe, etc. à partir du clavier virtuel. Donc, en général, vous NE POUVEZ PAS capturer l'écran à partir d'une application Android sans aucun moyen de contourner le problème des privilèges.
Vous POUVEZ plus ou moins capturer un instantané de la zone d'écran actuellement occupée par votre application en parcourant la vue supérieure de votre hiérarchie de vues et en la dessinant dans un bitmap à l'aide de View.draw (Canvas), mais cela n'enregistrera pas la barre d'état, clavier logiciel, surfaces OpenGL, etc.
Si vous voulez faire mieux que cela, vous devrez utiliser un outil externe. Les outils ont besoin de root ou d'utiliser l'interface ADB, car les processus démarrés via l'interface ADB ont le privilège AID_GRAPHICS. En utilisant cette dernière méthode, une application non privilégiée peut se connecter à un serveur privilégié pour effectuer l'enregistrement.
En gros, les outils peuvent être répartis dans les catégories suivantes:
Applications d'enregistrement de framebuffer uniquement root (par exemple Screencast). Ceux-ci enregistrent directement à partir du périphérique/dev/graphics/fb0 mais ne fonctionnent que sur les périphériques où le framebuffer est lisible (par exemple, pas sur le Tegra 2 Nexus 7).
Applications d'enregistrement de capture d'écran racine uniquement (par exemple, SCR, Rec, etc.). Ceux-ci capturent l'écran via SurfaceFlinger et fonctionnent sur une gamme beaucoup plus large d'appareils.
Applications d'enregistrement de capture d'écran non root (par exemple, enregistrable, Ascrecorder). Ceux-ci nécessitent que l'utilisateur active le débogage USB et démarre un démon lorsqu'il est connecté via un PC hôte. Par la suite, le PC hôte n'est pas requis tant que l'appareil n'a pas été redémarré. Peut également enregistrer de l'audio.
Outils ADB (par exemple, l'enregistreur d'écran intégré sur Android 4.4). Vous obliger à être connecté via un port USB et ne peut pas capturer l'audio.
Il y a quelques mois, j'ai fait une comparaison des applications disponibles qui sont disponibles ici:
http://recordable.mobi/compare
Pour être complet, il existe également des outils USB (par exemple, Mobizen) qui diffusent l'écran via USB (limité par une bande passante USB faible et ne peuvent pas enregistrer l'audio) et certains appareils peuvent également transmettre l'écran via wifi, qui peut ensuite être capturé sur un appareil séparé .
Il s'agit d'un article assez ancien, mais j'espère que cela aidera quelqu'un qui cherche toujours un moyen d'enregistrer l'écran d'un appareil Android:
Depuis Android 5.0, il existe une nouvelle API qui peut être utilisée pour l'enregistrement d'écran: MediaProjection La MediaProjection permet de capturer le contenu de l'écran, mais pas l'audio du système. ne capturera pas le contenu d'écran sécurisé.
Sur la page de Matt Snider, il y a un bon exemple sur la façon d'utiliser l'API pour enregistrer réellement l'écran dans un fichier sur la carte SD: lien [~ # ~] [~ # ~]
vous pouvez capturer l'écran via DDMS lors de l'exécution de adb et avoir l'autorisation du framebuffer:
suivez ce lien pour plus de détails :
Vérifiez également que ces liens peuvent vous donner quelques idées sur ce dont vous avez besoin:
http://answers.oreilly.com/topic/951-how-to-capture-video-of-the-screen-on-Android/
et vérifiez ce projet:
http://sourceforge.net/projects/ashot/
j'espère que cette aide.
J'ai créé une bibliothèque qui gère cela pour vous. Y compris l'affichage d'une notification personnalisable et pouvant être désactivée si vous ne souhaitez pas afficher de notification.
Il nécessite l'API 21>
Voici une démonstration simple sur la façon de l'utiliser: (plus d'informations peuvent être trouvées dans le readme de la bibliothèque):
Commencez par le déclarer et l'initier dans votre 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);
}
Ensuite, lorsque vous souhaitez démarrer l'enregistrement, vous pouvez appeler:
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);
}
}
}
Vous pouvez arrêter l'enregistrement en appelant:
hbRecorder.stopScreenRecording();
Le onCompleteListener
vous permet de savoir quand le fichier a été créé:
@Override
public void HBRecorderOnComplete() {
//This is called once the file was created
}
J'ai également ajouté un tas de paramètres qui peuvent être définis, comme changer AudioBitrate
, AudioSamplingRate
etc.