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 format, int 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
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
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- surfaceHolder의 callback을 설정한다. callback은 surfaceView의 변경사항에 대한 정보를 수신해주는 무언가 인 거 같다.
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- 만약 surfaceHolder의 surface가 null일 때는 반환해서 refreshCamera() 함수를 종료해준다.
6- 사실 왜 여기서 왜 .stopPreview()를 호출해야하는 지 모르겠다.
더 자세한 내용은 밑의 링크에 있다.
https://developer.android.com/training/camera/cameradirect?hl=ko#java
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을 통해서 사용자한테 물어야한다.
'Android App' 카테고리의 다른 글
spinner (드롭다운 메뉴) in Android Studio (0) | 2021.08.23 |
---|---|
FirebaseCloudMessaging (푸시 알림) in Android Studio (0) | 2021.08.16 |
드래그로 Fragment 크기 조절 in Android Studio (2) | 2021.08.09 |
Service (백그라운드) in Android Studio (0) | 2021.08.09 |
dialog (팝업창) in Android Studio (0) | 2021.08.08 |