정보공간_1

[3기 강북 김승현] ffmpeg 를 이용한 간단한 동영상 플레이어 제작 #2 본문

IT 놀이터/Elite Member Tech & Talk

[3기 강북 김승현] ffmpeg 를 이용한 간단한 동영상 플레이어 제작 #2

알 수 없는 사용자 2013. 5. 6. 19:15

안녕하세요 강북멤버십 김승현입니다.


이번 글 은 저번글에서 이어서 ffmpeg library를 이용해서 간단하게

동영상 플레이어 제작하기를 연재 해보겠습니다.

각 플렛폼에 종속되는 a/v 출력 부분을 제외한, ffmpeg를 이용한

디코딩을 어떻게 하는지를 연재 할 예정입니다.

ffplay.c를 해부하면 해당 버전의 ffmpeg 라이브러리의 사용법을 전부 알아 

낼 수 있지만 좀더 쉽게 개발 하는 데에 본 포스트가 도움이 되었으면 하는 바람이 있습니다.

본 포스트는 ffmpeg 1.0 stable 버전을 기준으로 작성 되었습니다.

필자는 windows 환경에서 개발을 진행 하였습니다.



6. a/v 디코딩을 위한 AVPacket 읽기

avpacket이란 하나의 av파일에서 파일의 한 조각조각을 의미한다고 생각하면됩니다.

avpacket은 보통 video,audio,subtitle 중의 한 조각이며,

하나의 avpacket에 복수의 프레임이 들어있을 수 도있고, packet별로

속성도 제각각입니다.(i,b,p프레임..)


AVPacket Packet; 

av_init_packet(&Packet); //AVPacket 선언 및 초기화

while(av_read_frame(pInputFormatContext,&Packet) >= 0)

{

//무한루프로 패킷을 하나씩 읽는다.. 리턴값이 -1 이하면 에러가 있거나 파일의 끝에 

//도달 한 것입니다.

}


7. video 디코딩

이제는 얻어진 avpacket를 디코딩 합니다.

읽어진 packet을 패킷 사이즈만큼 돌아가면서 decode해서 프레임을 얻어내는 과정입니다.



AVFrame VideoFrame; //이전프레임의 정보가 다음프레임의 디코딩에 사용하기 때문에 전역변수로 두는 것이 좋다..

avcodec_get_frame_defaults(&VideoFrame);


while(av_read_frame(pInputFormatContext,&Packet) >= 0)

{

if(Packet.stream_index == nVideoStreamIdx)

{

int             remainByte = Packet.size; //packet의 남은 디코딩 해야할 byte수

while(remainByte > 0)

{

int frameFinished,bytesDecoded;

// Decode the next chunk of data

bytesDecoded=avcodec_decode_video2(pVideoCodecContext,&VideoFrame,&frameFinished, &Packet);


// Was there an error?

if(bytesDecoded <= 0)

{

//decode error

}


remainByte-=bytesDecoded;


if(remainByte <= 0)

{

av_free_packet(&Packet); //packet 해제 . 안해주면 엄청난 메모리 릭의 원인이 된다.

remainByte = 0;

}


// Did we finish the current frame? Then we can return

if(frameFinished)

{

//디코딩된 프레임이 나오는영역. 이걸 다음장에 나오는 libswscale을 통해 변환해줘야한다.

}

}

}


8. libswscale

이번 과정은 읽어진 video Frame를 rgb등 우리가 모니터에서 사용하는 영역, 크기로 변환하는 작업입니다.

char * pBuffer; //저장될 메모리영역.. 미리 알맞은 사이즈로 메모리 할당을 해놓아야한다.

if(frameFinished)

{

SwsContext * s = sws_getContext(pVideoCodecContext->width,pVideoCodecContext->height,pVideoCodecContext->pix_fmt,

변환할 x사이즈,변환할y사이즈,AVPixelFormat::AV_PIX_FMT_BGRA/*변환할 픽셀 형식*/,SWS_FAST_BILINEAR/* 크기 변화에 사용할 알고리즘 */,NULL,NULL,NULL);

AVFrame * pOutFrame = avcodec_alloc_frame();

avpicture_fill((struct AVPicture *)pOutFrame,pBuffer, AVPixelFormat::AV_PIX_FMT_BGRA ,변환할 x사이즈,변환할y사이즈);  //변환한 값을 저장할 변수

sws_scale(s,VideoFrame.data,VideoFrame.linesize,0,VideoFrame.height,pOutFrame->data,pOutFrame->linesize); //실제 변환함수


av_free(pOutFrame);

sws_freeContext(s);

//변환 완료!

}



다음 포스트에는...

audio 디코딩을 다룰 예정입니다!

....