SlideShare une entreprise Scribd logo
1  sur  8
안녕하세요 MediaCodec 사용법을 발표하게 된 권태환입니다. 저는 꿈 많은 개발자가 되자!라는
블로그를 운영중입니다. 1년 5개월째 회사를 다니고 있고, 거의 FFMpeg와 MediaCodec을
다뤄볼 일이 많았습니다. 그간 했던것을 정리하고자 발표를 하게 되었습니다.
목차
이번 발표는 인코딩/디코딩이 무슨 뜻인지, 일반적으로 MP4라고 하는 컨테이너는 무엇인지
코덱 중 H.264, AAC가 무엇인지를 살펴보고,
이번 발표의 주제인 Android API MediaCodec을 이야기 해보겠습니다.
동영상?
동영상은 움직이는 그림을 연속적으로 보여주는 것을 동영상이라고 합니다.
아래 한번쯤은 접해보았던 이미지가 보이실 겁니다. 연속으로 보여주게 되면 마치 움직이는
사진처럼 보여지게 되는것! 그냥 그 자체가 동영상입니다.
1. 인코딩/디코딩 1페이지
그렇다면 인코딩 디코딩은 뭘 말할까요?
1. 인코딩/디코딩 2페이지
사전적으로는 부호화라고 표현하더군요. 원본을 특정 알고리즘에 따라서 압축하는 것을
말합니다. 반대로 디코딩이란 복호화 라고하고, 압축을 해제하는 것을 말합니다.
1. 인코딩/디코딩 3페이지
김보성의 “의리”를 통해 디코딩/인코딩을 살펴보겠습니다.
1. 인코딩/디코딩 4페이지
코덱을 알기 전에 디코딩과 인코딩에 대해서 좀 더 살펴보겠습니다. 동영상을 디코딩한다는
표현은 바로 아래와 같습니다. 2장의 완전한 이미지가 표시되고 있습니다. 이는 디코딩한
이미지가 완전한 하나의 사진으로 보여지는 것을 볼 수 있습니다.
1. 인코딩/디코딩 5페이지
반대로 인코딩을 보겠습니다. 첫번째 사진은 디코딩과 동일하지만 2번째 이미지는 중복된
데이터가 사라진 것을 확인 가능합니다.
1. 인코딩/디코딩 6페이지
한번에 모아놓고 보니 확실한 차이가 보이실것이라고 생각됩니다.
Codec?
정리하면 어떠한 데이터 스트림이나 신호에 대해, 인코딩과 디코딩, 혹은 둘 다를 할 수 있는
하드웨어나 소프트웨어를 일컷는 말입니다. 일반적으로 코덱이라고 하면 영상, 음성 등 미디어
정보를 압축하는 기술을 말합니다.
2. Codec - AVC
그러면 Android에서 주로 사용되는 H.264와 AAC를 살펴보겠습니다.
H.264/AVC
ITU-T의 VCEG(Video Coding Expert Group)와 ISO/IEC의 MPEG(Moving Picture Expert
Group)의 JVT(Joint Video Team)에서 개발한 프로젝트로 ITU-T에서는 H.264라는 이름을
사용하며, MPEG 에서는 MPEG-4 part 10/AVC라는 이름을 사용합니다. 일반적으로 H.264라는
이름을 더 많이 쓰는것 같습니다.
특징
1) H.263에 비해서 H.264는 대부분의 Bit-Rates에서 50% 이상의 압축 효율을 보여주게 됩니다.
새로 나올 H.265나 VP9 역시 H.264에 비해서 50% 이상의 압축 효율을 보여준다고 합니다.
2) 고품질의 영상 제공
3) 에러 복원 기능
4) 네트워크 전송에 유리한 코덱입니다.
Frame
동영상은 하나의 이미지를 프레임이라고 합니다. H.264에는 아래와 같이 3가지의 Frame이
있습니다. 바트가 자고있는 사진을 이용하여 프레임을 구분해보겠습니다.
I-Frame은 Intra-frame으로 원본 이미지라고 보시면 됩니다. 일명 키프레임이라는 말도 사용하고
있는데, 다음 프레임인 B, P-Frame을 디코딩하는데 있어서는 필수적인 요소가 됩니다.
P-Frame은 Predictive-frame으로 이전 프레임과의 차이 값을 가지게 됩니다. 3번째 사진을
보시면 바트가 일 부분만 표시되는 것을 보실 수 있습니다. 이런 이미지를 P-Frame이라고
표현합니다.
B-Frame은 Bi-directionally-frame으로 프레임간 이동 성능을 향상시키기 위하여 예측 정보와
잡음을 줄이는데 주로 사용하게 됩니다. 연산량이 많이 필요하여 Baseline 프로파일에서는
사용되지 않는 프레임입니다.
색공간
기본 프레임정보를 알았으니 이 Frame을 구성하는 색상값을 알아합니다. H.264는 YUV420
색공간을 사용합니다. YUV는 밝기 신호, 색차신호를 분리하여 인코딩하게 됩니다.
YUV는 흑백 TV가 존재하던 시대에 호환성을 위해서 만들어진 색상입니다. 과거 흑백 TV와 컬러
TV가 함께 존재하던 시기에 만들어지다보니 YUV 색상값이 기본으로 사용됩니다.
Android에서는 I420과 NV12 2가지 색상값으로 인코딩을 하게 되는데, I420, NV12의 사이즈는
가로x세로x3/2의 사이즈로 왼쪽 2번째 이미지와 같은 사이즈가 됩니다. UV는 색상값에 따라서
위치가 달라지게 됩니다.
MediaCodec의 BIT RATE
동영상 인코딩에 사용되는 간단한 몇가지 용어를 MediaCodec을 초기화할때 사용하는 것
위주로 살펴보겠습니다.
Bitrate는 특정 시간 단위마다 처리하는 비트의 수를 말합니다. H.264에서는 이 bitrate가
가변적으로 변하게 됩니다.
MediaCodec의 FRAME RATE
FPS라고 하며 Frame Per Second 의 약자로 1초동안 보여주는 화면의 수를 말합니다. 예를 들어
30 FPS라면 초당 약 30장의 이미지가 표시된다고 생각 하시면 됩니다.
MediaCodec에서는 Frame rate를 지정하면 최대 FPS로 설정되고 실제 FPS는 동적으로
계산되어 설정됩니다.
MediaCodec의 I FRAME INTERVAL
I-Frame 간의 간격을 GOP라고하며, 특정 프레임이 아래와 같다면 I-Frame에서 I-Frame 이전의
간격을 수로 나타내면 5가 됩니다. 이말은 5 frame 마다 매번 I-Frame을 생성하겠다는 의미가
됩니다. 5프레임 마다 한번씩 생성하면 용량이 늘어나는 효과를 보실 수 있겠지만.
안드로이드에서는 이 I-Frame 간격을 대략 초 단위로 지정하다보니 1초 또는 5초를 사용하시면
됩니다. FPS가 유동적이다보니 1초라고해서 30장이 GOP가 되는 것은 아닙니다.
AAC
사운드 코덱인 AAC 입니다. AAC는 Advanced Audio Coding의 약자로 고음질 오디오를
압축하는 코덱으로 ISO/IEC의 표준문서에 따라 정의됩니다. 디지털 오디오에서 쓰이는 표준적인
손실데이터 압축 방식을 말합니다.
MP3 대비 샘플 주파수가 8~96 Khz로 확장되었으며, 최대 48채널을 사용가능합니다.
Android에서는 1, 2채널 정도를 사용하고 있으며, 고정 비트레이트의 경우는 필요에 따라서
가변적으로 생성되기도 합니다.
AAC에 대해서는 http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio 사이트에 접속하시면
상세하게 설명을 보실 수 있습니다.
이정도로 정리를 해두고, 이제 이번 발표의 제목인 MediaCodec을 살펴보겠습니다.
MediaCodec
MediaCodec을 사용하기 위한 API와 도구? 입니다. MediaCodec을 이용하여 디코딩을
하기위해서는 MediaExtractor를 사용하여야 합니다. 인코딩시에는 MediaMuxer를 사용이
가능합니다. 그외 OpenGL ES와 NDK 정도를 이해하시면 더 좋은 방법의 인/디코딩이
가능합니다.
MediaCodec 이란?
안드로이드에서는 음성, 영상을 녹화해주는 API가 있는데 이걸 사용해야 할 이유가 있을까요?
MediaCodec이 API로 공개된 이유는 하드웨어 성능 향상이 큽니다. 기존에는 동영상을 찍고,
재생하는 정도의 역활을 하였다면, 단말기의 동영상을 실시간 인코딩하여 실시간 스트리밍을
한다거나, 음악을 실시간으로 디코딩한다거나 하는 byte 단위 처리가 가능한 MediaCodec API
입니다.
그럼 MediaCodec을 이용하여 인코딩/디코딩 하는 방법을 살펴보기 전에 각 파트별로 나누어
보겠습니다. 우선 Android 4.1부터 추가되었고, Surface를 통한 디코딩을 제공합니다. 디코딩을
byte 단위로 직접 처리할 일이 있으시다면 추천하는 API 입니다.
Android 4.3부터 인코딩 기능이 추가되어 Surface를 통한 인코딩이 가능하며, MediaMuxer를
사용할 수 있게 되었습니다. VP8, VP9 인코딩 기능이 추가되었습니다.
MediaCodec - 2페이지
인코딩과 디코딩을 분리하여 보면 Android 4.1 이상에서는 YUV 색공간을 직접 사용하여
인코딩이 가능하였고, 4.3부터는 Surface를 통하여 인코딩 기능이 추가되었습니다. 그렇다고
게임을 Surface 생성해두고 직접 녹화 할 수 있지는 않습니다. EGL을 사용하여 off screen을
사용하시는 것을 추천드립니다.
디코딩은 특이하게도 Surface를 사용하는 경우와 그렇지 않은 경우가 좀 다릅니다. Surface는
RGB 데이터를 원하지만 H.264를 인코딩했던 YUV 색상값으로 디코딩되지 않고, 해당 단말기의
색상값으로 디코딩 됩니다. 예를 들어 NV12를 사용하는 단말기면 NV12로 디코딩하게 됩니다.
그래서 Surface를 초기화시에 사용하시면 자동으로 변환을 하여 화면에 출력하게 됩니다.
MediaCodec - 지원 코덱
지원 코덱은 Video와 Audio가 다음과 같이 구분되어 있습니다.
MediaCodec - init
MediaCodec을 사용하기 위해서는 Decoder와 Encoder를 초기화 해주어야 합니다. Type은 앞서
소개한 코덱 이름이 되겠고, 이 코덱에 맞는 Decoder와 Encoder를 자동으로 검색하여 초기화
합니다. 좀 더 좋은 코드는 Github와 블로그에 등록해두었으니 추후 참고하시면 되겠습니다.
코덱 생성이 끝났으면 configure를 해주어야 합니다. Configure는 디코딩/인코딩에 따라서
종류가 많습니다. 각각 부분을 살펴보기전에 configure의 원문을 보시면 설정해주어야 하는 값이
많이 있습니다. MediaFormat과 Surface, 그리고 암호화도 지원하고 있습니다. 마지막 flags는
인코딩과 디코딩에 따라서 설정값이 다른데 Encoder는 1이 됩니다. 설정이 끝나면 start()를
호출하면 MediaCodec 사용 준비가 끝이 나는것입니다.
MediaCodec - MediaFormat
MediaFormat 설정은 인코딩/디코딩에 따라서 설정이 모두 다릅니다. 그 정보를 다 설명할수는
없고, 이 중 다음과 같이 2가지 정도만 설명하겠습니다.
인코딩을 할때에는 단말기의 색상값을 확인해야 합니다. 앞서 소개한것 처럼 I420, NV12를
사용한다고 하더라도 단말기 마다 정확한 색상값 명칭은 5가지 정도가 됩니다. 이를 고정으로
설정하면 당연히 인코딩이 불가능합니다. 관련 예제를 참고하셔서 사용하시면 되겠습니다.
Audio 를 byte를 받아와 직접 디코딩할 때에는 csd-0 값을 추가로 넣어야 합니다.
MediaExtractor를 이용하면 자동으로 받아지지만 byte를 직접 디코딩해야 할 경우에는
필수요소입니다. 2 byte의 코드로 작성되어야 하는데 여기에는 채널, samplerate, audioProfile
정보입니다. 조합하는 코드는 블로그에 올려두었으니 참고하시면 되겠습니다.
인코딩 디코딩 방법
초기화와 start를 호출하였으니 InputBuffer와 outputBuffer를 생성해야 합니다. 각 buffer는
framework에서 자동으로 생성되니 몇개가 생성될지는 알 수 없습니다.
인코딩 InputBuffer
생성된 Buffer를 이용하여 데이터를 채워주고, 받아오면 되는 것입니다. 먼저 채워 주는 부분은
아래와 같습니다. dequeueInputBuffer를 통해 index를 받아오고, 해당 buffer에 데이터를
채어넣어 queueInputBuffer를 호출하여 주면 됩니다.
참고로 Muxer를 사용할 때는 public final void queueInputBuffer (int index, int offset, int size, long
presentationTimeUs, int flags) 에 4번째 변수인 long을 채워주어야 합니다. 시간은 마이크로 초를
넣어주시면 됩니다.
인코딩 OutputBuffer
OutputBuffer를 사용하는 방법입니다. inputbuffer를 하면 인코딩 또는 디코딩을 자동으로
진행하게 됩니다. 진행이 완료되면 outputBuffer에 bufferInfo와 함께 실제 인/디코딩 된 byte가
출력됩니다. 디코딩시에는 Surface에 바로 그려서 사용이 가능하도록 함수가 제공되고 있는데,
releaseOutputBuffer()에outputIndex와 boolean 값을 통해 바로 Surface에 Rendering을 할 수
있습니다.
이 코드는 outputBufferIndex는 0 보다 커야 데이터가 출력되는 것으로, 처음 실행시에는
BufferChanged와 OutputFormat changed가 우선 호출됩니다.
코덱 사용 종료.
다음 코드로 코덱 사용을 종료하면 MediaCodec 사용법 설명은 끝이 납니다. 실제 코드로 적용할
부분은 더 많이 있는데 간단하게 MediaCodec 사용법을 설명해보았습니다.
참고하세요.
이제 진짜 중요한 부분을 간단하게 설명하고 MediaMuxer를 설명하도록 하겠습니다.
Video 인코딩을 원하시는 분이라면 꼭 필요한 정보입니다.
우선 H.264는 넓이가 16의 배수여야 합니다. 1920x1080의 16의 배수는 1920x1088 입니다.
MediaCodec의 경우 실제 인코딩시 1920x1080으로 인코딩이 안될 수도 있습니다. 가지고
있으신 단말기에서는 되더라도 다른 폰에서는 안될 수 있으니 16의 배수로 꼭 설정해주셔야
합니다.
색상값을 직접 처리하시기 부담스러우시다면 Surface를 사용하여 인코딩하는게 좋습니다.
단점이라면 OpenGL ES를 알아야 사용이 가능합니다.
디코딩 시에는 Surface를 사용하여 화면 랜더링이 가능합니다.
MediaMuxer
MediaMuxer는 안드로이드 4.3 이상에서 사용가능합니다. MediaCodec과 함께 사용해야 하며,
MP4 파일 생성이 가능합니다.
MediaCodec의 경우 순수 데이터로의 H.264와 AAC가 나오게 되며, 모든 프로그램에서 재생이
불가능합니다. 이를 MP4라는 파일 컨테이너에 추가하여야 파일 재생이 가능합니다.
MediaMuxer 초기화
MediaMuxer muxer = new MediaMuxer("temp.mp4",
OutputFormat.MUXER_OUTPUT_MPEG_4);
muxer add
MediaCodec의 return 값 중 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED 에서 다음을
실행하면 됩니다.
각 트랙에 Audio, Video를 순서대로 넣으면 Audio의 track 번호와 Video의 track 번호가 return
됩니다.
// More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat()
// or MediaExtractor.getTrackFormat().
MediaFormat audioFormat = new MediaFormat(...);
MediaFormat videoFormat = new MediaFormat(...);
int audioTrackIndex = muxer.addTrack(audioFormat);
int videoTrackIndex = muxer.addTrack(videoFormat);
muxer.start();
실제 데이터를 muxer에 쓰기
Muxer를 초기화 하고, track번호가 return 되었다면 실제 byte를 써주면 됩니다. MediaCodec의
outputIndex가 0보다 큰 부분에서 해당 코드를 짧게 넣어주시면 됩니다.
byte와 BufferInfo를 받아오고, 이를 Muxer에 넘겨주기만 하면 됩니다.
Muxer의 종료
muxer.stop();
muxer.release();
Muxer 주의사항
마지막으로 Muxer를 살펴보았습니다. Muxer를 사용할 경우 주의사항은 아래와 같습니다.
- MediaMuxer는 파일쓰기 용량이 최대 2GB를 초과하면 안된다.
- 기기마다 차이가 나겠지만 Audio는 1또는 2채널로 설정하여야 한다.
- Muxer를 사용할 경우 Video/Audio의 동기화 시간을 적어주어야 한다.
MediaCodec 예제 코드
MediaCodec을 가장 잘 설명해둔 사이트입니다.
제 github에 MediaCodec 예제코드를 올려두었습니다.
마무리
짧은 시간이라 많은 부분을 설명하지 못하였습니다. Surface를 사용하여 화면을 랜더링하고,
Encoder를 할 수 있는 예제가 많이 있습니다. 동영상에 대한 이해가 없다면 인코딩/디코딩을
하기가 쉽지는 않습니다. 관련 자료들을 더 많이 찾아보시고, 오늘 짧게 발표한 내용을
참고하시면 개발에 도움이 되지 않을까 생각됩니다.
질문이 있으시다면 질문해주시기 바랍니다.

Contenu connexe

Similaire à Android mediacodec

게임프로그래머에게 배우는 C#1권(버전1)
게임프로그래머에게 배우는 C#1권(버전1)게임프로그래머에게 배우는 C#1권(버전1)
게임프로그래머에게 배우는 C#1권(버전1)Kiyoung Moon
 
처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차
처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차
처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차Michael Yang
 
다음 팟인코더 개선방안(최종)
다음 팟인코더 개선방안(최종)다음 팟인코더 개선방안(최종)
다음 팟인코더 개선방안(최종)hahahiho
 
20140514 team blender_v01 (Korean)
20140514 team blender_v01 (Korean)20140514 team blender_v01 (Korean)
20140514 team blender_v01 (Korean)Dongho Kim
 
전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012
전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012
전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012devCAT Studio, NEXON
 
MGS 툴세미나
MGS 툴세미나MGS 툴세미나
MGS 툴세미나Bonex Gu
 
Ndc2013 정리(upload버전)
Ndc2013 정리(upload버전)Ndc2013 정리(upload버전)
Ndc2013 정리(upload버전)Minsu Park
 
한글시계웍샵_ SW
한글시계웍샵_ SW한글시계웍샵_ SW
한글시계웍샵_ SW영광 송
 
[IoT] MAKE with Open H/W + Node.JS - 5th
[IoT] MAKE with Open H/W + Node.JS - 5th[IoT] MAKE with Open H/W + Node.JS - 5th
[IoT] MAKE with Open H/W + Node.JS - 5thPark Jonggun
 
한글시계웍샵_SW
한글시계웍샵_SW한글시계웍샵_SW
한글시계웍샵_SW영광 송
 
빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)YEONG-CHEON YOU
 
제2회 hello world 오픈세미나 Web Audio API-가능성엿보기
제2회 hello world 오픈세미나 Web Audio API-가능성엿보기제2회 hello world 오픈세미나 Web Audio API-가능성엿보기
제2회 hello world 오픈세미나 Web Audio API-가능성엿보기NAVER D2
 
22 best free video editors 2019
22 best free video editors 201922 best free video editors 2019
22 best free video editors 2019Jahee Lee
 
피지컬 컴퓨팅 도구
피지컬 컴퓨팅 도구피지컬 컴퓨팅 도구
피지컬 컴퓨팅 도구Kisoon Eom
 
당신의 디버깅에 니코니코니
당신의 디버깅에 니코니코니당신의 디버깅에 니코니코니
당신의 디버깅에 니코니코니Lusain Kim
 
C#강좌
C#강좌C#강좌
C#강좌e12g
 
3D카툰메이커 완료세미나(복구됨)
3D카툰메이커 완료세미나(복구됨)3D카툰메이커 완료세미나(복구됨)
3D카툰메이커 완료세미나(복구됨)Daniel Shin
 
[박민근] 3 d렌더링 옵티마이징_nv_perfhud
[박민근] 3 d렌더링 옵티마이징_nv_perfhud[박민근] 3 d렌더링 옵티마이징_nv_perfhud
[박민근] 3 d렌더링 옵티마이징_nv_perfhudMinGeun Park
 
[170403 2주차]C언어 A반
[170403 2주차]C언어 A반[170403 2주차]C언어 A반
[170403 2주차]C언어 A반arundine
 

Similaire à Android mediacodec (20)

게임프로그래머에게 배우는 C#1권(버전1)
게임프로그래머에게 배우는 C#1권(버전1)게임프로그래머에게 배우는 C#1권(버전1)
게임프로그래머에게 배우는 C#1권(버전1)
 
처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차
처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차
처음부터 다시 배우는 HTML5 & CSS3 강의자료 6일차
 
다음 팟인코더 개선방안(최종)
다음 팟인코더 개선방안(최종)다음 팟인코더 개선방안(최종)
다음 팟인코더 개선방안(최종)
 
20140514 team blender_v01 (Korean)
20140514 team blender_v01 (Korean)20140514 team blender_v01 (Korean)
20140514 team blender_v01 (Korean)
 
전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012
전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012
전형규, 가성비 좋은 렌더링 테크닉 10선, NDC2012
 
MGS 툴세미나
MGS 툴세미나MGS 툴세미나
MGS 툴세미나
 
Ndc2013 정리(upload버전)
Ndc2013 정리(upload버전)Ndc2013 정리(upload버전)
Ndc2013 정리(upload버전)
 
한글시계웍샵_ SW
한글시계웍샵_ SW한글시계웍샵_ SW
한글시계웍샵_ SW
 
[IoT] MAKE with Open H/W + Node.JS - 5th
[IoT] MAKE with Open H/W + Node.JS - 5th[IoT] MAKE with Open H/W + Node.JS - 5th
[IoT] MAKE with Open H/W + Node.JS - 5th
 
한글시계웍샵_SW
한글시계웍샵_SW한글시계웍샵_SW
한글시계웍샵_SW
 
빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)빌드관리 및 디버깅 (2010년 자료)
빌드관리 및 디버깅 (2010년 자료)
 
제2회 hello world 오픈세미나 Web Audio API-가능성엿보기
제2회 hello world 오픈세미나 Web Audio API-가능성엿보기제2회 hello world 오픈세미나 Web Audio API-가능성엿보기
제2회 hello world 오픈세미나 Web Audio API-가능성엿보기
 
22 best free video editors 2019
22 best free video editors 201922 best free video editors 2019
22 best free video editors 2019
 
피지컬 컴퓨팅 도구
피지컬 컴퓨팅 도구피지컬 컴퓨팅 도구
피지컬 컴퓨팅 도구
 
당신의 디버깅에 니코니코니
당신의 디버깅에 니코니코니당신의 디버깅에 니코니코니
당신의 디버깅에 니코니코니
 
C#강좌
C#강좌C#강좌
C#강좌
 
3D카툰메이커 완료세미나(복구됨)
3D카툰메이커 완료세미나(복구됨)3D카툰메이커 완료세미나(복구됨)
3D카툰메이커 완료세미나(복구됨)
 
[박민근] 3 d렌더링 옵티마이징_nv_perfhud
[박민근] 3 d렌더링 옵티마이징_nv_perfhud[박민근] 3 d렌더링 옵티마이징_nv_perfhud
[박민근] 3 d렌더링 옵티마이징_nv_perfhud
 
Node.js in Flitto
Node.js in FlittoNode.js in Flitto
Node.js in Flitto
 
[170403 2주차]C언어 A반
[170403 2주차]C언어 A반[170403 2주차]C언어 A반
[170403 2주차]C언어 A반
 

Android mediacodec

  • 1. 안녕하세요 MediaCodec 사용법을 발표하게 된 권태환입니다. 저는 꿈 많은 개발자가 되자!라는 블로그를 운영중입니다. 1년 5개월째 회사를 다니고 있고, 거의 FFMpeg와 MediaCodec을 다뤄볼 일이 많았습니다. 그간 했던것을 정리하고자 발표를 하게 되었습니다. 목차 이번 발표는 인코딩/디코딩이 무슨 뜻인지, 일반적으로 MP4라고 하는 컨테이너는 무엇인지 코덱 중 H.264, AAC가 무엇인지를 살펴보고, 이번 발표의 주제인 Android API MediaCodec을 이야기 해보겠습니다. 동영상? 동영상은 움직이는 그림을 연속적으로 보여주는 것을 동영상이라고 합니다. 아래 한번쯤은 접해보았던 이미지가 보이실 겁니다. 연속으로 보여주게 되면 마치 움직이는 사진처럼 보여지게 되는것! 그냥 그 자체가 동영상입니다. 1. 인코딩/디코딩 1페이지 그렇다면 인코딩 디코딩은 뭘 말할까요? 1. 인코딩/디코딩 2페이지 사전적으로는 부호화라고 표현하더군요. 원본을 특정 알고리즘에 따라서 압축하는 것을 말합니다. 반대로 디코딩이란 복호화 라고하고, 압축을 해제하는 것을 말합니다. 1. 인코딩/디코딩 3페이지 김보성의 “의리”를 통해 디코딩/인코딩을 살펴보겠습니다. 1. 인코딩/디코딩 4페이지 코덱을 알기 전에 디코딩과 인코딩에 대해서 좀 더 살펴보겠습니다. 동영상을 디코딩한다는 표현은 바로 아래와 같습니다. 2장의 완전한 이미지가 표시되고 있습니다. 이는 디코딩한 이미지가 완전한 하나의 사진으로 보여지는 것을 볼 수 있습니다. 1. 인코딩/디코딩 5페이지 반대로 인코딩을 보겠습니다. 첫번째 사진은 디코딩과 동일하지만 2번째 이미지는 중복된 데이터가 사라진 것을 확인 가능합니다. 1. 인코딩/디코딩 6페이지 한번에 모아놓고 보니 확실한 차이가 보이실것이라고 생각됩니다.
  • 2. Codec? 정리하면 어떠한 데이터 스트림이나 신호에 대해, 인코딩과 디코딩, 혹은 둘 다를 할 수 있는 하드웨어나 소프트웨어를 일컷는 말입니다. 일반적으로 코덱이라고 하면 영상, 음성 등 미디어 정보를 압축하는 기술을 말합니다. 2. Codec - AVC 그러면 Android에서 주로 사용되는 H.264와 AAC를 살펴보겠습니다. H.264/AVC ITU-T의 VCEG(Video Coding Expert Group)와 ISO/IEC의 MPEG(Moving Picture Expert Group)의 JVT(Joint Video Team)에서 개발한 프로젝트로 ITU-T에서는 H.264라는 이름을 사용하며, MPEG 에서는 MPEG-4 part 10/AVC라는 이름을 사용합니다. 일반적으로 H.264라는 이름을 더 많이 쓰는것 같습니다. 특징 1) H.263에 비해서 H.264는 대부분의 Bit-Rates에서 50% 이상의 압축 효율을 보여주게 됩니다. 새로 나올 H.265나 VP9 역시 H.264에 비해서 50% 이상의 압축 효율을 보여준다고 합니다. 2) 고품질의 영상 제공 3) 에러 복원 기능 4) 네트워크 전송에 유리한 코덱입니다. Frame 동영상은 하나의 이미지를 프레임이라고 합니다. H.264에는 아래와 같이 3가지의 Frame이 있습니다. 바트가 자고있는 사진을 이용하여 프레임을 구분해보겠습니다. I-Frame은 Intra-frame으로 원본 이미지라고 보시면 됩니다. 일명 키프레임이라는 말도 사용하고 있는데, 다음 프레임인 B, P-Frame을 디코딩하는데 있어서는 필수적인 요소가 됩니다. P-Frame은 Predictive-frame으로 이전 프레임과의 차이 값을 가지게 됩니다. 3번째 사진을 보시면 바트가 일 부분만 표시되는 것을 보실 수 있습니다. 이런 이미지를 P-Frame이라고 표현합니다. B-Frame은 Bi-directionally-frame으로 프레임간 이동 성능을 향상시키기 위하여 예측 정보와 잡음을 줄이는데 주로 사용하게 됩니다. 연산량이 많이 필요하여 Baseline 프로파일에서는 사용되지 않는 프레임입니다.
  • 3. 색공간 기본 프레임정보를 알았으니 이 Frame을 구성하는 색상값을 알아합니다. H.264는 YUV420 색공간을 사용합니다. YUV는 밝기 신호, 색차신호를 분리하여 인코딩하게 됩니다. YUV는 흑백 TV가 존재하던 시대에 호환성을 위해서 만들어진 색상입니다. 과거 흑백 TV와 컬러 TV가 함께 존재하던 시기에 만들어지다보니 YUV 색상값이 기본으로 사용됩니다. Android에서는 I420과 NV12 2가지 색상값으로 인코딩을 하게 되는데, I420, NV12의 사이즈는 가로x세로x3/2의 사이즈로 왼쪽 2번째 이미지와 같은 사이즈가 됩니다. UV는 색상값에 따라서 위치가 달라지게 됩니다. MediaCodec의 BIT RATE 동영상 인코딩에 사용되는 간단한 몇가지 용어를 MediaCodec을 초기화할때 사용하는 것 위주로 살펴보겠습니다. Bitrate는 특정 시간 단위마다 처리하는 비트의 수를 말합니다. H.264에서는 이 bitrate가 가변적으로 변하게 됩니다. MediaCodec의 FRAME RATE FPS라고 하며 Frame Per Second 의 약자로 1초동안 보여주는 화면의 수를 말합니다. 예를 들어 30 FPS라면 초당 약 30장의 이미지가 표시된다고 생각 하시면 됩니다. MediaCodec에서는 Frame rate를 지정하면 최대 FPS로 설정되고 실제 FPS는 동적으로 계산되어 설정됩니다. MediaCodec의 I FRAME INTERVAL I-Frame 간의 간격을 GOP라고하며, 특정 프레임이 아래와 같다면 I-Frame에서 I-Frame 이전의 간격을 수로 나타내면 5가 됩니다. 이말은 5 frame 마다 매번 I-Frame을 생성하겠다는 의미가 됩니다. 5프레임 마다 한번씩 생성하면 용량이 늘어나는 효과를 보실 수 있겠지만. 안드로이드에서는 이 I-Frame 간격을 대략 초 단위로 지정하다보니 1초 또는 5초를 사용하시면 됩니다. FPS가 유동적이다보니 1초라고해서 30장이 GOP가 되는 것은 아닙니다. AAC
  • 4. 사운드 코덱인 AAC 입니다. AAC는 Advanced Audio Coding의 약자로 고음질 오디오를 압축하는 코덱으로 ISO/IEC의 표준문서에 따라 정의됩니다. 디지털 오디오에서 쓰이는 표준적인 손실데이터 압축 방식을 말합니다. MP3 대비 샘플 주파수가 8~96 Khz로 확장되었으며, 최대 48채널을 사용가능합니다. Android에서는 1, 2채널 정도를 사용하고 있으며, 고정 비트레이트의 경우는 필요에 따라서 가변적으로 생성되기도 합니다. AAC에 대해서는 http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio 사이트에 접속하시면 상세하게 설명을 보실 수 있습니다. 이정도로 정리를 해두고, 이제 이번 발표의 제목인 MediaCodec을 살펴보겠습니다. MediaCodec MediaCodec을 사용하기 위한 API와 도구? 입니다. MediaCodec을 이용하여 디코딩을 하기위해서는 MediaExtractor를 사용하여야 합니다. 인코딩시에는 MediaMuxer를 사용이 가능합니다. 그외 OpenGL ES와 NDK 정도를 이해하시면 더 좋은 방법의 인/디코딩이 가능합니다. MediaCodec 이란? 안드로이드에서는 음성, 영상을 녹화해주는 API가 있는데 이걸 사용해야 할 이유가 있을까요? MediaCodec이 API로 공개된 이유는 하드웨어 성능 향상이 큽니다. 기존에는 동영상을 찍고, 재생하는 정도의 역활을 하였다면, 단말기의 동영상을 실시간 인코딩하여 실시간 스트리밍을 한다거나, 음악을 실시간으로 디코딩한다거나 하는 byte 단위 처리가 가능한 MediaCodec API 입니다. 그럼 MediaCodec을 이용하여 인코딩/디코딩 하는 방법을 살펴보기 전에 각 파트별로 나누어 보겠습니다. 우선 Android 4.1부터 추가되었고, Surface를 통한 디코딩을 제공합니다. 디코딩을 byte 단위로 직접 처리할 일이 있으시다면 추천하는 API 입니다. Android 4.3부터 인코딩 기능이 추가되어 Surface를 통한 인코딩이 가능하며, MediaMuxer를 사용할 수 있게 되었습니다. VP8, VP9 인코딩 기능이 추가되었습니다. MediaCodec - 2페이지 인코딩과 디코딩을 분리하여 보면 Android 4.1 이상에서는 YUV 색공간을 직접 사용하여 인코딩이 가능하였고, 4.3부터는 Surface를 통하여 인코딩 기능이 추가되었습니다. 그렇다고
  • 5. 게임을 Surface 생성해두고 직접 녹화 할 수 있지는 않습니다. EGL을 사용하여 off screen을 사용하시는 것을 추천드립니다. 디코딩은 특이하게도 Surface를 사용하는 경우와 그렇지 않은 경우가 좀 다릅니다. Surface는 RGB 데이터를 원하지만 H.264를 인코딩했던 YUV 색상값으로 디코딩되지 않고, 해당 단말기의 색상값으로 디코딩 됩니다. 예를 들어 NV12를 사용하는 단말기면 NV12로 디코딩하게 됩니다. 그래서 Surface를 초기화시에 사용하시면 자동으로 변환을 하여 화면에 출력하게 됩니다. MediaCodec - 지원 코덱 지원 코덱은 Video와 Audio가 다음과 같이 구분되어 있습니다. MediaCodec - init MediaCodec을 사용하기 위해서는 Decoder와 Encoder를 초기화 해주어야 합니다. Type은 앞서 소개한 코덱 이름이 되겠고, 이 코덱에 맞는 Decoder와 Encoder를 자동으로 검색하여 초기화 합니다. 좀 더 좋은 코드는 Github와 블로그에 등록해두었으니 추후 참고하시면 되겠습니다. 코덱 생성이 끝났으면 configure를 해주어야 합니다. Configure는 디코딩/인코딩에 따라서 종류가 많습니다. 각각 부분을 살펴보기전에 configure의 원문을 보시면 설정해주어야 하는 값이 많이 있습니다. MediaFormat과 Surface, 그리고 암호화도 지원하고 있습니다. 마지막 flags는 인코딩과 디코딩에 따라서 설정값이 다른데 Encoder는 1이 됩니다. 설정이 끝나면 start()를 호출하면 MediaCodec 사용 준비가 끝이 나는것입니다. MediaCodec - MediaFormat MediaFormat 설정은 인코딩/디코딩에 따라서 설정이 모두 다릅니다. 그 정보를 다 설명할수는 없고, 이 중 다음과 같이 2가지 정도만 설명하겠습니다. 인코딩을 할때에는 단말기의 색상값을 확인해야 합니다. 앞서 소개한것 처럼 I420, NV12를 사용한다고 하더라도 단말기 마다 정확한 색상값 명칭은 5가지 정도가 됩니다. 이를 고정으로 설정하면 당연히 인코딩이 불가능합니다. 관련 예제를 참고하셔서 사용하시면 되겠습니다. Audio 를 byte를 받아와 직접 디코딩할 때에는 csd-0 값을 추가로 넣어야 합니다. MediaExtractor를 이용하면 자동으로 받아지지만 byte를 직접 디코딩해야 할 경우에는 필수요소입니다. 2 byte의 코드로 작성되어야 하는데 여기에는 채널, samplerate, audioProfile 정보입니다. 조합하는 코드는 블로그에 올려두었으니 참고하시면 되겠습니다. 인코딩 디코딩 방법 초기화와 start를 호출하였으니 InputBuffer와 outputBuffer를 생성해야 합니다. 각 buffer는 framework에서 자동으로 생성되니 몇개가 생성될지는 알 수 없습니다.
  • 6. 인코딩 InputBuffer 생성된 Buffer를 이용하여 데이터를 채워주고, 받아오면 되는 것입니다. 먼저 채워 주는 부분은 아래와 같습니다. dequeueInputBuffer를 통해 index를 받아오고, 해당 buffer에 데이터를 채어넣어 queueInputBuffer를 호출하여 주면 됩니다. 참고로 Muxer를 사용할 때는 public final void queueInputBuffer (int index, int offset, int size, long presentationTimeUs, int flags) 에 4번째 변수인 long을 채워주어야 합니다. 시간은 마이크로 초를 넣어주시면 됩니다. 인코딩 OutputBuffer OutputBuffer를 사용하는 방법입니다. inputbuffer를 하면 인코딩 또는 디코딩을 자동으로 진행하게 됩니다. 진행이 완료되면 outputBuffer에 bufferInfo와 함께 실제 인/디코딩 된 byte가 출력됩니다. 디코딩시에는 Surface에 바로 그려서 사용이 가능하도록 함수가 제공되고 있는데, releaseOutputBuffer()에outputIndex와 boolean 값을 통해 바로 Surface에 Rendering을 할 수 있습니다. 이 코드는 outputBufferIndex는 0 보다 커야 데이터가 출력되는 것으로, 처음 실행시에는 BufferChanged와 OutputFormat changed가 우선 호출됩니다. 코덱 사용 종료. 다음 코드로 코덱 사용을 종료하면 MediaCodec 사용법 설명은 끝이 납니다. 실제 코드로 적용할 부분은 더 많이 있는데 간단하게 MediaCodec 사용법을 설명해보았습니다. 참고하세요. 이제 진짜 중요한 부분을 간단하게 설명하고 MediaMuxer를 설명하도록 하겠습니다. Video 인코딩을 원하시는 분이라면 꼭 필요한 정보입니다. 우선 H.264는 넓이가 16의 배수여야 합니다. 1920x1080의 16의 배수는 1920x1088 입니다. MediaCodec의 경우 실제 인코딩시 1920x1080으로 인코딩이 안될 수도 있습니다. 가지고 있으신 단말기에서는 되더라도 다른 폰에서는 안될 수 있으니 16의 배수로 꼭 설정해주셔야 합니다. 색상값을 직접 처리하시기 부담스러우시다면 Surface를 사용하여 인코딩하는게 좋습니다. 단점이라면 OpenGL ES를 알아야 사용이 가능합니다. 디코딩 시에는 Surface를 사용하여 화면 랜더링이 가능합니다.
  • 7. MediaMuxer MediaMuxer는 안드로이드 4.3 이상에서 사용가능합니다. MediaCodec과 함께 사용해야 하며, MP4 파일 생성이 가능합니다. MediaCodec의 경우 순수 데이터로의 H.264와 AAC가 나오게 되며, 모든 프로그램에서 재생이 불가능합니다. 이를 MP4라는 파일 컨테이너에 추가하여야 파일 재생이 가능합니다. MediaMuxer 초기화 MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4); muxer add MediaCodec의 return 값 중 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED 에서 다음을 실행하면 됩니다. 각 트랙에 Audio, Video를 순서대로 넣으면 Audio의 track 번호와 Video의 track 번호가 return 됩니다. // More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat() // or MediaExtractor.getTrackFormat(). MediaFormat audioFormat = new MediaFormat(...); MediaFormat videoFormat = new MediaFormat(...); int audioTrackIndex = muxer.addTrack(audioFormat); int videoTrackIndex = muxer.addTrack(videoFormat); muxer.start(); 실제 데이터를 muxer에 쓰기 Muxer를 초기화 하고, track번호가 return 되었다면 실제 byte를 써주면 됩니다. MediaCodec의 outputIndex가 0보다 큰 부분에서 해당 코드를 짧게 넣어주시면 됩니다. byte와 BufferInfo를 받아오고, 이를 Muxer에 넘겨주기만 하면 됩니다. Muxer의 종료 muxer.stop(); muxer.release(); Muxer 주의사항 마지막으로 Muxer를 살펴보았습니다. Muxer를 사용할 경우 주의사항은 아래와 같습니다. - MediaMuxer는 파일쓰기 용량이 최대 2GB를 초과하면 안된다. - 기기마다 차이가 나겠지만 Audio는 1또는 2채널로 설정하여야 한다.
  • 8. - Muxer를 사용할 경우 Video/Audio의 동기화 시간을 적어주어야 한다. MediaCodec 예제 코드 MediaCodec을 가장 잘 설명해둔 사이트입니다. 제 github에 MediaCodec 예제코드를 올려두었습니다. 마무리 짧은 시간이라 많은 부분을 설명하지 못하였습니다. Surface를 사용하여 화면을 랜더링하고, Encoder를 할 수 있는 예제가 많이 있습니다. 동영상에 대한 이해가 없다면 인코딩/디코딩을 하기가 쉽지는 않습니다. 관련 자료들을 더 많이 찾아보시고, 오늘 짧게 발표한 내용을 참고하시면 개발에 도움이 되지 않을까 생각됩니다. 질문이 있으시다면 질문해주시기 바랍니다.