Notice
Recent Posts
Recent Comments
Link
투케이2K
147. (TWOK/LOGIC) [android] 안드로이드 휴대폰 실시간 카메라 스트림 영상을 마스터 역할로 Aws Kvs HLS 라이브 스트리밍 업로드 로직 정리 본문
투케이2K 로직정리
147. (TWOK/LOGIC) [android] 안드로이드 휴대폰 실시간 카메라 스트림 영상을 마스터 역할로 Aws Kvs HLS 라이브 스트리밍 업로드 로직 정리
투케이2K 2025. 9. 5. 19:23728x90
반응형
[로직 정리]
정리 로직 : Mobile
상태 : [android] 안드로이드 휴대폰 실시간 카메라 스트림 영상을 마스터 역할로 Aws Kvs HLS 라이브 스트리밍 업로드 로직 정리
[설 명]
// --------------------------------------------------------------------------------------
[사전) 설정 및 정보 확인 사항]
// --------------------------------------------------------------------------------------
1. 사전) 인프라 환경 구축 및 파일 준비 필요 사항
>> Aws Kinesis Video Streams (Kvs) 인프라 구축 필요
- IAM 계정 생성 (KVS 권한 할당) 및 AccessKey , SecretKey 생성 준비
>> Aws 사이트에서 KVS HLS 비디오 스트림 채널 생성 필요 (테스트 고유 디바이스 스트림 명칭)
>> Aws Kvs HLS 에 업로드 하려는 동영상 파일 (mp4) 준비 필요
>> 재생 되고 있는 실시간 스트리밍 정보를 보기 위한 Viewer 뷰어 프로그램 준비 필요
2. 사전) 비디오 스트림 학습 :
>> 비디오 스트림은 라이브 비디오 및 기타 시간이 인코딩된 데이터를 캡처하고, 선택적으로 저장하고, 실시간, 배치 혹은 애드혹 형식으로 데이터의 소비를 가능하게 할 수 있도록 해 주는 리소스입니다
>> 일반적인 구성에서는 Kinesis 비디오 스트림은 데이터를 푸시해 주는 생산자가 하나만 있습니다 (실시간 스트리밍 데이터를 밀어 넣어주는 하드웨어 기기)
3. 사전) KVS 개념 학습 :
>> KVS 는 ML (기계 학습), 재생 및 기타 처리를 위해 커넥티드 디바이스에서 AWS로 비디오를 쉽고 안전하게 스트리밍할 수 있는 기술입니다
4. 사전) HLS 개념 학습 :
>> HTTP 라이브 스트리밍으로 인터넷을 통해 소비자에게 미디어 콘텐츠를 제공하는 데 사용되는 스트리밍 프로토콜입니다
>> HLS 는 Apple 장치에서 지원하는 유일한 형식입니다
>> 미디어는 h.264 또는 h.265 인코딩된 비디오를 포함해야 하며 AAC 인코딩된 오디오는 선택 사항입니다
>> 미디어 타입 유효한 값의 예로는 "video/h264" 및 "video/h264,audio/aac" 가 있습니다
5. 사전) PutMedia 개념 학습 :
>> Kinesis 비디오 스트림 전송 API 입니다. (미디어 데이터 전송)
>> PutMedia 전송 시 파라미터에는 streamName 또는 streamARN 중 하나를 지정해야합니다
6. 사전) Signature V4 서명 학습 :
>> AWS API 요청에 인증 정보를 추가하기 위한 AWS 서명 프로토콜입니다
>> HTTP Authorization 헤더에서 또는 URL의 쿼리 문자열로 표현될 수 있습니다
7. 사전) MKV 비디오 파일 학습 :
>> 멀티미디어 컨테이너 형식으로 여러 개의 오디오, 비디오, 자막 트랙을 하나의 파일에 포함할 수 있는 컨테이너 형식입니다
>> MKV 편집이 가능한 프로그램 :
- DaVinci Resolve : 무료 + 고급 영상 편집 가능
- VLC Media Player : 간단한 컷 편집 가능
- FFmpeg : MKV 변환 & 편집 (커맨드 라인)
- Avidemux : 간단한 트리밍 & 편집
8. 사전) FFMpecg (미디어 포맷 변환 도구) 학습 :
>> FFmpeg 이란 디지털 음성 스트림과 영상 스트림에 대해서 다양한 종류의 형태로 기록하고 변환하는 컴퓨터 프로그램입니다 (미디어 포맷 변환 도구)
>> FFmpeg을 기반으로 하는 동영상 플레이어 :
- iOS : AV player, nPlayer
- 안드로이드 : Dice Player, MX 플레이어, 안드로이드용 곰플레이어, 안드로이드용 KMPlayer
- Microsoft Windows : 팟플레이어, 곰플레이어, KMPlayer, MPC-HC, 콘플레이어
- macOS : 무비스트
- 크로스 플랫폼 : VLC, MPlayer
9. 사전) 안드로이드 Aws Kvs HLS 에 동영상 업로드를 위한 build.gradle 의존성 부여
implementation 'com.amazonaws:aws-android-sdk-kms:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-s3:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-iot:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-mobile-client:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-kinesisvideo:2.57.0'
10. 사전) 안드로이드 Aws Kvs HLS 동영상 업로드를 위한 OKHTTP 네트워킹 라이브러리 build.gradle 의존성 부여
implementation("com.squareup.okhttp3:okhttp:4.9.0")
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
11. 사전) 안드로이드 FFmpeg 트랜스 코딩 라이브러리 build.gradle 의존성 부여
[ffmpeg aar 파일 다운로드 사이트] : https://artifactory.appodeal.com/appodeal-public/com/arthenica/ffmpeg-kit-full-gpl/6.0-2.LTS/
[안드로이드 프로젝트 libs 폴더 생성 방법] : https://blog.naver.com/kkh0977/222355981962?trackingCode=blog_bloghome_searchlist
implementation files('libs/ffmpeg-kit-full-gpl-6.0-2.LTS.aar')
implementation 'com.arthenica:smart-exception-java:0.2.1'
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[로직 설명]
// --------------------------------------------------------------------------------------
1. 안드로이드 Camera , MediaRecorder , SurfaceView 객체를 사용해 휴대폰 실시간 카메라 영상 출력 및 외부 저장소에 녹화 된 파일을 MP4 형태로 저장 수행
>> 외부 저장소 다운로드 경로 확인 코드 : String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath().trim()+"/video.mp4";
>> MediaRecorder 에 녹화 파일 저장 설정 값 지정 :
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); // [오디오 데이터를 얻어올 곳]
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // [비디오 데이터를 얻어올 곳]
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // [비디오 저장 파입]
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // [비디오 인코딩 타입]
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); // [오디오 인코딩 타입]
mediaRecorder.setOrientationHint(90); // [세로 모드 고정 (0, 90, 180, 270)]
mediaRecorder.setVideoSize(1280, 720); // 원하는 해상도
mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024); // 5Mbps 비트레이트 (높을수록 화질↑, 용량↑)
mediaRecorder.setVideoFrameRate(30); // FPS 설정 (30 또는 60)
mediaRecorder.setOutputFile(filePath); // [비디오 저장 경로]
mediaRecorder.setPreviewDisplay(holder.getSurface()); // [홀더에 표시 된 영상 화면 레코더에 지정]
mediaRecorder.prepare(); // [Recorder 준비]
mediaRecorder.start(); // [Recorder 시작]
2. 안드로이드 FFmpeg 라이브러리를 사용해 외부 저장소에 저장 된 MP4 파일을 MKV 파일 형식으로 트랜스 코딩 수행 (FFmpegKit.executeAsync)
>> mp4 파일을 mkv 파일로 변환 커맨드 코드 :
String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath().trim();
String mp4Path = filePath + "/video.mp4";
String mkvPath = filePath + "/video.mkv";
String command = String.format("-i %s -c copy %s", mp4Path, mkvPath);
3. 안드로이드에서 변환 된 mkv 파일을 InputStream 으로 읽어 byte[] 에 담기 수행
>> 외부 저장소에 저장 된 mkv 파일을 File 로 읽은 후 byte[] 담는 코드 :
String mkvPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath().trim() + "/video.mkv";
byte[] rawMkvByte = null;
try (InputStream inputStream = new FileInputStream(new File(mkvPath));
ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
byte[] temp = new byte[4096]; // 임시 버퍼
int bytesRead;
while ((bytesRead = inputStream.read(temp)) != -1) {
buffer.write(temp, 0, bytesRead);
}
rawMkvByte = buffer.toByteArray();
}
4. 안드로이드 AWSKinesisVideoClient 사용해 GetDataEndpointRequest 호출로 DataEndpoint 정보 확인
>> GetDataEndpointRequest 정보 확인 코드 :
AWSKinesisVideo awsKinesisVideoClient = new AWSKinesisVideoClient(credentials);
awsKinesisVideoClient.setRegion(Region.getRegion(REGION));
GetDataEndpointRequest dataEndPointRequest = new GetDataEndpointRequest()
.withStreamName(STREAM_NAME) // 스트림 이름 설정
.withAPIName(APIName.PUT_MEDIA); // TODO API 이름 설정 (PUT_MEDIA, GET_MEDIA 등)
GetDataEndpointResult result = awsKinesisVideoClient.getDataEndpoint(dataEndPointRequest);
String dataEndpoint = result.getDataEndpoint();
5. 안드로이드 AWS4Signer 사용해 http 호출에 필요한 사인 header 값 확인 수행 :
>> AWS4Signer 사용해 사인 header 값 확인 및 okhttp 헤더에 추가 코드 :
// -----------------------------------------------
Request<?> signRequest = new DefaultRequest<>("kinesisvideo");
signRequest.setHttpMethod(HttpMethodName.POST);
signRequest.setEndpoint(new URI(dataEndpoint)); // TODO [DataEndpoint 적용]
signRequest.setEncodedResourcePath("/putMedia"); // TODO [Path 설정 : 해당 값 추가 중요]
signRequest.addHeader("Host", new URI(dataEndpoint).getHost()); // TODO [호스트 지정]
signRequest.addHeader("x-amzn-stream-name", STREAM_NAME); // TODO [스트림 명칭]
signRequest.addHeader("x-amzn-fragment-timecode-type", "ABSOLUTE"); // TODO [타임 코드]
signRequest.addHeader("Content-Type", "application/octet-stream"); // TODO [Body 에서 지정한 MediaType 타입]
signRequest.setContent(new StringInputStream("")); // TODO [Empty Body 지정 필요]
// -----------------------------------------------
AWS4Signer signer = new AWS4Signer();
signer.setServiceName("kinesisvideo");
signer.setRegionName(REGION);
signer.sign(signRequest, credentials); // TODO [Sign 인증 수행]
// -----------------------------------------------
Headers.Builder okHttpHeaders = new Headers.Builder();
for (Map.Entry<String, String> entry : signRequest.getHeaders().entrySet()) {
okHttpHeaders.add(entry.getKey(), entry.getValue());
S_Log.w("KWON_TWOK", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Okhttp Header Insert :: " + String.valueOf(entry.getKey()) + " :: " + String.valueOf(entry.getValue()) + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
// -----------------------------------------------
6. 안드로이드 okhttp RequestBody 에 상위에서 읽은 mkv 파일 byte[] 값 지정 후 putMedia 스트리밍 재생 http 호출 수행
>> RequestBody 에 byte[] 지정 및 okhttp3.Request 생성 코드 :
// -----------------------------------------------
RequestBody requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MediaType.parse("application/octet-stream");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
try (InputStream fis = new ByteArrayInputStream(rawMkvByte)) {
byte[] buffer = new byte[4096]; // TODO [4KB 단위로 스트리밍 데이터 전송]
int len;
while ((len = fis.read(buffer)) != -1) {
S_Log.w("KWON_TWOK", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KVS HLS 스트리밍 데이터 Body Write 수행 :: " + String.valueOf(len) + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
sink.write(buffer, 0, len);
sink.flush();
}
}
}
};
// -----------------------------------------------
String putMediaUrl = dataEndpoint + "/putMedia";
okhttp3.Request request = new okhttp3.Request.Builder()
.url(putMediaUrl) // TODO [최종 요청 URL]
.headers(okHttpHeaders.build()) // TODO [Signature V4 인증 헤더 값 추가]
.post(requestBody) // TODO [실시간 스트리밍 데이터 업로드 Body 추가 : writeTo]
.build();
// -----------------------------------------------
7. AWS 콘솔 KVS 대시보드에서 정상적으로 HLS 라이브 스트리밍 영상이 재생 되는 것 확인
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[참고 사이트]
// --------------------------------------------------------------------------------------
[안드로이드 Aws HLS PutMedia API 호출에 필요한 GetDataEndpoint 호출 방법]
https://blog.naver.com/kkh0977/223876132661?trackingCode=blog_bloghome_searchlist
[안드로이드 Aws Kvs HLS 비디오 스트리밍 putMedia 호출 시 필요한 Signature V4 서명 방법]
https://blog.naver.com/kkh0977/223874442189?trackingCode=blog_bloghome_searchlist
[Aws KVS HLS MKV 파일 설명 - PutMedia API 스트리밍 업로드 시 전송 파일]
https://blog.naver.com/kkh0977/223874472088?trackingCode=blog_bloghome_searchlist
[업무 이슈] android 안드로이드 aws kvs hls 스트리밍 동영상 업로드 이슈 - mp4 파일 ffmpeg 트랜스코딩 mkv 파일 변환
https://blog.naver.com/kkh0977/223878649342?trackingCode=blog_bloghome_searchlist
[안드로이드 Raw 폴더에 저장 된 MKV 형식 파일 Aws Kvs HLS 비디오 스트리밍 업로드 수행]
https://blog.naver.com/kkh0977/223874458019?trackingCode=blog_bloghome_searchlist
// --------------------------------------------------------------------------------------
728x90
반응형
'투케이2K 로직정리' 카테고리의 다른 글
Comments
