Подтвердить что ты не робот

Экранная видеозапись текущей активности Android

Возможно ли записать видеоизображение текущей текущей активности из той же активности?
Я знаю, как сделать снимок экрана текущей активности, но не имею ни малейшего представления о записи видео на экране. Как мне начать с этого? Я не знаю, как это начать.

4b9b3361

Ответ 1

РЕДАКТИРОВАТЬ. Этот ответ заменяется ответом ниже от Данпе.

Программная запись видео из вашего приложения потребует root-доступа. Вы заметите, что приложения, доступные для этого в Play Store, в списке своих приложений видны в списке "ТРЕБУЕМЫЙ КОРЕНЬ". Вы также заметите, что для работы этого подхода могут также существовать некоторые особые требования к оборудованию ("Не работает на Galaxy Nexus или Tegra 2/3..." - из описания Screencast Video Recorder app.

Я никогда не писал этот код сам, но я собрал идею очень высокого уровня требуемого подхода. Из этого сообщения видно, что вы должны получить доступ к данным буфера кадров через "/dev/graphics/fb0". Режим доступа для кадрового буфера - 660, что означает, что вам нужен root-доступ для доступа к нему. Получив root-доступ, вы можете использовать данные буфера кадров для создания снимков экрана (этот проект может работать для этой задачи), а затем создавать видео из этих снимков экрана (см. этот другой вопрос SO о том, как создавать видео из последовательности изображений).

Я использовал приложение Screencast, и оно хорошо работает на Samsung Note. Я подозреваю, что это основной подход, который они выбрали.

Ответ 2

С 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*/);
}

Это не окончательный код, а ХОРОШАЯ база для запуска:)

Ответ 3

Обычным приложениям Android не хватает разрешения на захват буфера кадров (в частности, они не являются членами группы AID_GRAPHICS). Это по соображениям безопасности - в противном случае они могли бы скрыть пароли и т.д. С помощью мягкой клавиатуры. Таким образом, вы вообще НЕ МОЖЕШЬ отображать экран из приложения для Android, не обойдя проблему с привилегиями.

Вы можете более или менее фиксировать снимок области экрана, которая в настоящее время используется вашим приложением, перейдя в верхнюю часть View в иерархии вашего представления и введя ее в растровое изображение, используя View.draw(Canvas), однако это будет не записывать строку состояния, мягкую клавиатуру, поверхности OpenGL и т.д.

Если вы хотите сделать это лучше, вам нужно будет использовать внешний инструмент. Инструменты либо нуждаются в корне, либо используют интерфейс ADB, так как процессы, запущенные через интерфейс ADB, имеют привилегию AID_GRAPHICS. Используя последний метод, непривилегированное приложение может подключиться к привилегированному серверу для записи.

Грубо инструменты можно разделить на следующие категории:

  • Приложения для рекордеров с фрейм-буфером (например, Screencast). Они записываются непосредственно с устройства /dev/graphics/fb 0, но работают только на устройствах, где фреймбуфер читается (например, не на Tegra 2 Nexus 7).

  • Приложения для записи на экране только для корневых каналов (например, SCR, Rec и т.д.). Они захватывают экран через SurfaceFlinger и работают на гораздо более широком диапазоне устройств.

  • Приложения без регистратора захвата экрана (например, Recordable, Ascrecorder). Они требуют от пользователя включить отладку USB и запустить демон при подключении через главный компьютер. После этого хост-компьютер не требуется, пока устройство не перезагрузится. Может записывать и аудио.

  • Инструменты ADB (например, встроенный screenrecorder на Android 4.4). Требовать, чтобы вы подключались через USB и не могли записывать аудио.

Несколько месяцев назад я сделал сравнение доступных приложений, которые доступны здесь:

http://recordable.mobi/compare

Для полноты есть также USB-инструменты (например, Mobizen), которые транслируют экран по USB (ограничен низкой пропускной способностью USB и не могут записывать аудио), а некоторые устройства также могут передавать экран через Wi-Fi, который затем можно отдельное устройство.

Ответ 4

Это довольно старый пост, но я надеюсь, что это поможет кому-то, кто все еще ищет способ записи экрана устройства Android:

Начиная с Android 5.0 появился новый API, который можно использовать для записи на экране: MediaProjection MediaProjection предоставляет возможность захвата содержимого экрана, но не системного аудио. Также он не будет захватывать защищенный экранный контент.

На странице Мэтта Снайдера есть хороший пример того, как использовать API для фактической записи экрана в файл на SD-карте: LINK

Ответ 5

вы можете захватить экран с помощью DDMS при запуске adb и иметь разрешение на фреймбуфер:

перейдите по этой ссылке для получения более подробной информации:

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/

надеюсь, что эта помощь.

Ответ 6

Я создал библиотеку, которая обрабатывает это для вас. Включая отображение уведомления, которое можно настраивать и отключить, если вы не хотите показывать уведомление.

Требуется 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 и т.д.