정보공간_1

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

IT 놀이터/Elite Member Tech & Talk

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

알 수 없는 사용자 2013. 5. 6. 20:00

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


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

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

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

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

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

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

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

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


9. audio 디코딩


AVFrame AudioFrame; //디코딩 결과가 저장될 프레임

if(Packet.stream_index == nAudioStreamIdx) //전에 저장했던 stream index를 비교해서 audio 패킷을 분류한다.

{

int nRemainByte = Packet.size;

void * pOrgData = Packet.data;

while (nRemainByte > 0) 

{

int got_frame = 0;


avcodec_get_frame_defaults(&AudioFrame);

int Decoded= avcodec_decode_audio4(pAudioCodecContext, &AudioFrame,&got_frame,&Packet);

//audio decoding !!

if(nDecoded < 0) //0보다 작은건 디코딩 실패이므로 패킷 무시

{

nRemainByte = 0;

Packet.data = (uint8_t *)pOrgData;

av_free_packet(&Packet);

continue;

}


nRemainByte -= nDecoded;

Packet.size -= nDecoded;

Packet.data += nDecoded;



if(nRemainByte <= 0) //packet 디코딩을 완료하면...

{

Packet.data = (uint8_t *)pOrgData;

av_free_packet(&Packet); //패킷 삭제

nRemainByte = 0;

}


if(got_frame) //FRAME 이 얻어짐!

{

이제 이 얻어진 frame을 출력 장치에 알맞는 포멧으로 변환 해야한다.

}

}




10. audio 변환

이제는 얻어진 frame을 알맞은 형식으로 변환합니다.

if(got_frame)

{

int nDataSize = av_samples_get_buffer_size(NULL, pAudioCodecContext->channels,

AudioFrame.nb_samples,

pAudioCodecContext->sample_fmt, 1); //디코딩된 audio data의 길이를 구함

if(pAudioCodecContext->sample_fmt != AV_SAMPLE_FMT_S16)

{

SwrContext * pAudioCvtContext;

pAudioCvtContext = NULL;

pAudioCvtContext  = swr_alloc_set_opts(pAudioCvtContext,

pAudioCodecContext->channel_layout, AV_SAMPLE_FMT_S16,pAudioCodecContext->sample_rate,pAudioCodecContext->channel_layout, pAudioCodecContext->sample_fmt,pAudioCodecContext->sample_rate,0,0); //SwrContext를 생성한다. 여기서는 singed 16bits로 변환하고자 한다.

int err;

if ((err = swr_init(pAudioCvtContext)) < 0) { //초기화

if(err == AVERROR(EINVAL))

fprintf(stderr, "Failed to initialize the resampling context\n");

}


static uint8_t AudioCvtBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; //변환결과 저장되는 버퍼

uint8_t *out[] = {AudioCvtBuffer};

const uint8_t *in[] = {AudioFrame.data[0]};


uint8_t *ain[SWR_CH_MAX];

if(!av_sample_fmt_is_planar(pAudioCodecContext->sample_fmt))

{

ain[0] = AudioFrame.data[0];

}

else

{

ain[0] = AudioFrame.data[0]; //8.1ch대비 9개를 만들었다

ain[1] = AudioFrame.data[0];

ain[2] = AudioFrame.data[0];

ain[3] = AudioFrame.data[0];

ain[4] = AudioFrame.data[0];

ain[5] = AudioFrame.data[0];

ain[6] = AudioFrame.data[0];

ain[7] = AudioFrame.data[0];

ain[8] = AudioFrame.data[0];

}

swr_convert(pAudioCvtContext,out,AudioFrame.nb_samples,(const uint8_t *)ain,AudioFrame.nb_samples);  //변환수행!


int nDataSize2 = av_samples_get_buffer_size(NULL, pAudioCodecContext->channels,

AudioFrame.nb_samples,

AV_SAMPLE_FMT_S16, 1); //결과 데이터 길이 구하기

memcpy(pBuffer,AudioCvtBuffer,nDataSize2); //결과 데이터 저장 pBuffer이 결과 값 저장 배열이다

}

else

{

memcpy(pBuffer,AudioFrame.data[0],nDataSize); //결과 데이터 저장 pBuffer이 결과 값 저장 배열이다 . 변환하지 않고 그냥 복사

}

}


다음 포스트에는...

seeking, 파일 끝 처리 등을 을 다룰 예정입니다!

....