Видеозапись экрана текущей активности Android
Возможно ли записать видео с экрана текущей текущей активности из того же действия?
Я знаю, как сделать снимок экрана текущей активности, но не имею ни малейшего представления о записи видео с экрана. С чего бы мне начать с этого? Я не знаю, как это запустить.
Переведено автоматически
Ответ 1
Начиная с Lollipop, мы можем использовать 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*/);
}
Это не окончательный код, но ХОРОШАЯ база для начала :)
Ответ 2
РЕДАКТИРОВАТЬ: Этот ответ заменен ответом ниже от Danpe.
Для программной записи видео из вашего приложения потребуется root-доступ. Вы заметите, что приложения, доступные для этого в Play Store, в описаниях своих приложений на видном месте указывают "ТРЕБУЕТСЯ ROOT". Вы также заметите, что для работы этого подхода также могут быть определенные требования к оборудованию ("Не работает на Galaxy Nexus или Tegra 2/3 ..." - из описания приложения Screencast Video Recorder.
Я никогда не писал этот код сам, но я составил представление о требуемом подходе на очень высоком уровне. Из этого поста следует, что вам необходимо получить доступ к данным буфера кадров через "/ dev / graphics / fb0". Режим доступа к буферу кадров равен 660, что означает, что для доступа к нему вам нужен root-доступ. Получив root-доступ, вы можете использовать данные буфера кадров для создания снимков экрана (этот проект может подойти для этой задачи), а затем создать видео из этих снимков экрана (смотрите Этот другой вопрос SO о том, как создать видео из последовательности изображений).
Я использовал приложение Screencast, и оно хорошо работает на Samsung Note. Я подозреваю, что это базовый подход, который они использовали.
Ответ 3
Обычным приложениям Android не хватает разрешения на захват буфера кадров (в частности, они не являются членами группы AID_GRAPHICS). Это сделано по соображениям безопасности - в противном случае они могли бы перехватывать пароли и т.д. С программной клавиатуры. Таким образом, в общем случае вы НЕ МОЖЕТЕ захватить экран из приложения для Android без какого-либо способа обойти проблему с привилегиями.
Вы МОЖЕТЕ более или менее сделать снимок области экрана, занимаемой в данный момент вашим приложением, перейдя к верхнему виду в вашей иерархии представлений и изобразив его в виде растрового изображения с помощью View.draw (Canvas), однако при этом не будут записаны строка состояния, программная клавиатура, поверхности OpenGL и т.д.
Если вы хотите добиться большего, вам нужно будет использовать внешний инструмент. Инструментам требуется либо root, либо использовать интерфейс ADB, поскольку процессы, запускаемые через интерфейс ADB, имеют привилегию AID_GRAPHICS. Используя последний метод, непривилегированное приложение может подключиться к привилегированному серверу для выполнения записи.
Грубо говоря, инструменты можно разделить на следующие категории:
Приложения для записи кадрового буфера только с правами Root (например, Screencast). Они записываются непосредственно с устройства / dev / graphics / fb0, но работают только на устройствах, где доступен для чтения фреймбуфер (например, не на Tegra 2 Nexus 7).
Приложения для записи снимков экрана только с правами Root (например, SCR, Rec и т.д.). Они захватывают экран с помощью SurfaceFlinger и работают на гораздо более широком спектре устройств.
Приложения для записи экрана, не являющиеся корневыми (например, Recordable, Ascrecorder). Они требуют, чтобы пользователь включил отладку по USB и запустил демон при подключении через главный компьютер. После этого главный компьютер не требуется до перезагрузки устройства. Также можно записывать аудио.
Инструменты ADB (например, встроенный screenrecorder на Android 4.4). Требуют подключения через USB и не могут записывать звук.
Для полноты картины существуют также инструменты USB (например, Mobizen), которые передают изображение с экрана по USB (ограничено низкой пропускной способностью USB и не позволяет записывать звук), а некоторые устройства также могут передавать изображение с экрана по Wi-Fi, которое затем может быть записано на отдельное устройство.
Ответ 4
Я создал библиотеку, которая справляется с этим за вас. Включая отображение настраиваемого уведомления, которое можно отключить, если вы не хотите показывать уведомление.
Для этого требуется API 21>
Вот простая демонстрация того, как ее использовать: (более подробную информацию можно найти в readme библиотеки):
Сначала объявите и инициализируйте ее в своем 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
}
Я также добавил кучу параметров, которые можно установить, например, изменение AudioBitrate
, AudioSamplingRate
и т.д.