Android App

MediaRecorder (동영상 녹화), 권한 묻기 in Android Studio

YunSeong 2021. 8. 16. 13:53
728x90
반응형

https://youtu.be/tph1U3PfMe0

 

1. activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn_record"
        android:text="녹화 시작"/>
    <SurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/surfaceView"/>
</LinearLayout>
cs

먼저 위와 같이 녹화를 시작하고 종료하기 위한 Button과 

지금 찍히고 있는 화면을 보여주기 위한 SurfaceView를 만들어줬다. 

 

 


 

2. MainActivity.java (권한 묻기)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.example.videorecordexample;
 
import ...
 
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
 
    private Button btn_record;
    private SurfaceView surfaceView;
    private Camera camera;
    private MediaRecorder mediaRecorder;
    private SurfaceHolder surfaceHolder;
    private boolean recording = false;
 
    private String TAG = "MainActivity.java";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        TedPermission.with(this//권한을 얻기 위한 코드이다.
                .setPermissionListener(permission)
                .setRationaleMessage("녹화를 위하여 권한을 허용해주세요.")
                .setDeniedMessage("권한이 거부되었습니다. 설정 > 권한에서 허용할 수 있습니다.")
                .setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO)
                .check();
 
        btn_record = (Button)findViewById(R.id.btn_record);
        btn_record.setOnClickListener(v -> {
            if (recording) { //녹화 중일 때 버튼을 누르면 녹화가 종료하도록 한다.
                mediaRecorder.stop();
                mediaRecorder.release();
                camera.lock();
                recording = false;
                btn_record.setText("녹화 시작");
            } else { //녹화 중이 아닐 때 버튼을 누르면 녹화가 시작하게 한다.
                runOnUiThread(new Runnable() { //녹화를 하는 것은 백그라운드로 하는 것이 좋다.
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this"녹화가 시작되었습니다.", Toast.LENGTH_SHORT).show();
                        try {
                            mediaRecorder = new MediaRecorder();
                            camera.unlock();
                            mediaRecorder.setCamera(camera);
                            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
                            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                            mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P));
                            mediaRecorder.setOrientationHint(90);
                            mediaRecorder.setOutputFile("/storage/emulated/0/Download/test.mp4");
                            mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
                            mediaRecorder.prepare();
                            mediaRecorder.start();
                            recording = true;
                            btn_record.setText("녹화 종료");
                        } catch (IOException e) {
                            Log.e(TAG, "Error in 79" + e.getMessage());
                            e.printStackTrace();
                            mediaRecorder.release();
                        }
                    }
 
                });
            }
        });
    }
 
    PermissionListener permission = new PermissionListener() {
        @Override
        public void onPermissionGranted() { //권한을 허용받았을 때 camera와 surfaceView에 대한 설정을 해준다.
            camera = Camera.open();
            camera.setDisplayOrientation(90);
            surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
            surfaceHolder = surfaceView.getHolder();
            surfaceHolder.addCallback(MainActivity.this);
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            Toast.makeText(MainActivity.this"권한 허가", Toast.LENGTH_SHORT).show();
        }
 
        @Override
        public void onPermissionDenied(ArrayList<String> deniedPermissions) { //권한이 거부됐을 때 이벤트를 설정할 수 있다.
            Toast.makeText(MainActivity.this"권한 거부", Toast.LENGTH_SHORT).show();
        }
    };
 
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
    }
 
    private void refreshCamera(Camera camera) {
        if (surfaceHolder.getSurface() == null) {
            return;
        }
        try {
            camera.stopPreview();
        } catch (Exception e) {
            e.printStackTrace();
        }
        setCamera(camera);
    }
 
    private void setCamera(Camera cam) {
        camera = cam;
    }
 
    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int formatint width, int height) {
        refreshCamera(camera);
    }
 
    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
 
    }
}
cs

 


21~26 - (권한 묻기)

1
2
3
4
5
6
TedPermission.with(this) //권한을 얻기 위한 코드이다.
        .setPermissionListener(permission)
        .setRationaleMessage("녹화를 위하여 권한을 허용해주세요.")
        .setDeniedMessage("권한이 거부되었습니다. 설정 > 권한에서 허용할 수 있습니다.")
        .setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO)
        .check();
cs

위 코드는 권한을 묻는 것을 쉽게 해줄 수 있는 라이브러리이다.

build.gradle (:app)의 dependencies에 [implementation 'gun0912.ted:tedpermission:2.0.0']를 추가해서 불러올 수 있다.

 

카메라를 사용하거나 외부저장소에 접근할 때 등 권한이 필요한 작업을 해야할 때는 위 라이브러리를 사용해서 권한을 물어야한다.

 

더 자세한 것은 밑의 페이지에서 볼 수 있다.

https://gun0912.tistory.com/61

 

[안드로이드/Android]유용한 라이브러리 - TedPermission(마시멜로우 권한체크)

안드로이드 6.0 마시멜로우버전부터 개발자들에게는 귀찮은(?) 변경이 있었습니다. 카메라를 사용하거나 문자를 읽어오는 등의 권한을 사용할때 기존에는 앱을 다운받을때에만 사용자로부터 동

gun0912.tistory.com

 


42~52 -

1
2
3
4
5
6
7
8
9
10
11
mediaRecorder = new MediaRecorder();
camera.unlock();
mediaRecorder.setCamera(camera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P));
mediaRecorder.setOrientationHint(90);
mediaRecorder.setOutputFile("/storage/emulated/0/Download/test.mp4");
mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
mediaRecorder.prepare();
mediaRecorder.start();
cs

위 코드는 mediaRecorder를 이용해서 녹화를 시작시킨다.

2 - camera를 활성화시킨다.

8 - 동영상을 저장할 경로를 설정한다.

10 - 녹화를 준비하는 것으로 보이는데 오류가 잘 나서 try catch문으로 감싸줘야한다.

 

아래 링크에서 더 자세히 알 수 있다.

https://developer.android.com/guide/topics/media/camera?hl=ko#java 

 

카메라 API  |  Android 개발자  |  Android Developers

Android 프레임워크에는 기기에서 이용 가능한 다양한 카메라와 카메라 기능에 대한 지원을 포함하여 애플리케이션에서 사진과 동영상을 캡처할 수 있도록 합니다. 이 문서에서는 신속하고 간단

developer.android.com

 


70~75 -

1
2
3
4
5
6
camera = Camera.open();
camera.setDisplayOrientation(90);
surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(MainActivity.this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cs

위 코드를 통해서 카메라를 설정하고 surfaceHolder을 통해서 surfaceView에 녹화되는 화면을 띄울 준비를 한다.

5- surfaceHoldercallback을 설정한다. callbacksurfaceView의 변경사항에 대한 정보를 수신해주는 무언가 인 거 같다.

 


85~103 -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void refreshCamera(Camera camera) {
    if (surfaceHolder.getSurface() == null) {
        return;
    }
    try {
        camera.stopPreview();
    } catch (Exception e) {
        e.printStackTrace();
    }
    setCamera(camera);
}
 
 
private void setCamera(Camera cam) {camera = cam;}
cs

refreshCamera() 함수를 105~108의 surfaceChanged()에서 호출해준다.

2- 만약 surfaceHoldersurfacenull일 때는 반환해서 refreshCamera() 함수를 종료해준다.

6- 사실 왜 여기서 .stopPreview()를 호출해야하는 지 모르겠다.

 

 

더 자세한 내용은 밑의 링크에 있다.

https://developer.android.com/training/camera/cameradirect?hl=ko#java 

 

카메라 제어  |  Android 개발자  |  Android Developers

이 과정에서는 프레임워크 API를 사용하여 직접 카메라 하드웨어를 제어하는 방법을 논의합니다. 기기의 카메라를 직접 제어하는 것은 기존 카메라 애플리케이션에 사진이나 동영상을 요청하는

developer.android.com

 

 


 

3. AndroidManifest.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.videorecordexample">
 
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-feature android:name="android.hardware.camera2"/>
    <application
        android:requestLegacyExternalStorage="true"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.VideoRecordExample">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
cs

5~7에서 각각 카메라, 외부저장소에 쓰기, 오디오 녹음에 대한 권한을 허용시킨다.

물론 java파일에서 TedPermission을 통해서 사용자한테 물어야한다.

 

 

 

 

 

728x90
반응형