상세 컨텐츠

본문 제목

ffmpeg for Delphi 온라인 강의를 임시 중단합니다.

etc

by ryujt 2013. 1. 18. 18:18

본문

좀 더 재미있는 주제를 찾아서 고민하고 준비한 후 조속히 다시 온라인 강의를 재개하겠습니다 ^^*


소수의 몇 분께서 ffmpeg에 대한 몇 가지 다른 주제를 요청하셨으나, 참여가 1회에 비해서 저조하기도 했고, 이후 반응도 다소 미지근했던 지라, 보다 자극적인 주제를 찾아봐야 할 듯 합니다 ㅠ.ㅠ 


1회 70명 넘어갔을 때 와!! 하면서 놀랬닥, 2회에서 급실망 ㅠ.ㅠ


사실 강사의 준비가 미흡하기 때문에 연기하는 겁니다 ^^;


다음 강의에 대한 요청이 접수되면, 제가 못다루는 분야라고 해도, 해당 분야의 전문가를 졸라서라도 진행해 보겠습니다!!


현재까지의 강의에서 미흡하거나 요청을 받은 것들을 정리하고 "ffmpeg for Delphi"는 잠정적으로 마무리하려고 합니다.



오디오 기준 싱크의 문제점


현재까지 진행했던 강의는 제가 2년 전에 진행한 어떤 프로젝트의 부산물을 정리한 것입니다.  원래는 안드로이드 플랫폼이 타켓인 프로젝트였는데, ffmpeg을 처음 다룬 것이어서, 일단 익숙한 델파이로 구현을 해보고 안드로이드로 다시 구현하는 과정을 겪었습니다.


해당 프로젝트의 특이성 때문에 저에게는 문제가 없는 방식이었으나, 일반적인 방식에서는 고려해야 할 사항 들이 있습니다.


그 중 하나가 바로, 오디오가 없는 비디오를 다룰 때입니다.  헉!!  


가끔은 일부 구간 또는 전체 구간에 오디오가 없는 경우가 있습니다.  오디오가 없는 구간에서는 비디오가 미친듯이 빠르게 재생됩니다 ^^;;


따라서, 이런 경우를 다루기 위해서는 "libRyuMPEG.dll" 소스에서 오디오 부분에서만 현재 재생 위치를 가져오는 것을 비디오에서도 가져와야 합니다.  아래 소스를 참고하세요, 빌드하지 않고 메모장에서 수정해서 올립니다 ^^;


이후 오디오에서처럼 비디오가 너무 바쁜 경우에도 패킷 처리를 유보시켜주시면 됩니다.

extern int readData(RyuMPEG_Handle *pHandle, void *pData, int *pDataSize, int *pPacketType, int *pPosition) {
	AVPacket packet;

	 av_init_packet(&packet);

	if ((pHandle->isEOF == false) && (av_read_frame(pHandle->pFormatCtx, &packet) >= 0)) {
		if (packet.stream_index == pHandle->audioStream) {
			*pPacketType = AUDIO_PACKET;

			pHandle->currentPosition = pHandle->pFormatCtx->streams[pHandle->audioStream]->cur_dts *
					av_q2d(pHandle->pFormatCtx->streams[pHandle->audioStream]->time_base)*1000;
		} else if (packet.stream_index == pHandle->videoStream) {
			*pPacketType = VIDEO_PACKET;


			pHandle->currentPosition = pHandle->pFormatCtx->streams[pHandle->videoStream]->cur_dts *
					av_q2d(pHandle->pFormatCtx->streams[pHandle->videoStream]->time_base)*1000;
		}

		*pDataSize = packet.size;

		if (packet.size <= READ_BUFFER_SIZE) {
			memcpy(pData, packet.data, packet.size);
		}

		*pPosition = pHandle->currentPosition;

		av_free_packet(&packet);

		return true;
	} else {
		pHandle->isEOF = true;

		*pDataSize = 0;
		*pPacketType = UNKNOWN_PACKET;
		*pPosition = 0;

		return false;
	}
}



비디오 디코딩을 원할하게


두 번째 강의에서 첫 번째 강의를 정리해서 다시 보내드린 것처럼, 매 강의를 단계적으로 진행하면서 현재 포커스가 되는 부분은 막코딩을 하고 이전 진행 된 부분 정리하는 형식을 취하려고 했습니다.  이유는 OOP 등을 남발하게 되면 초보분들이 따라오기가 어렵기 때문입니다.


두 번째 강의에서는 메인 스레드에서 패킷을 무한히 반복하면서 읽고 처리하고 있는데, 패킷 읽기도 비디오 디코딩도 오디오와 같이 별도의 스레드에서 처리되는 것이 좋습니다.



가장 많이(?) 요구받은 자막 처리


자막 처리는 대략 십 여년 전 DSPack에 포함 된 동영상 플레이어 위에 오버레이를 씌우다가 하도 에러가 나서 꼼수로 넘어간 이후 다룰 일이 없어서 저도 준비가 필요한 부분입니다.  (오버레이 용어가 맞는지 기억도 잘 ^^;)


꼼수는 바로 양병규님이 오픈해주신 BitmapRgn 이라는 유닛을 이용해서 자막 크기의 윈도우에 자막을 그리고, 자막 이외의 공간은 구멍내서 비디오 화면 위에 덮어 씌우는 것입니다.  다루기도 편하고 특별히 문제가 될 만한 것은 없어서 그렇게 마무리 하고 말았습니다.


제 강의 프로그램에 보면 화면 크기를 변경 할 때 아래 그림처럼 구멍 뚫린 공간 안에 글자(숫자)가 쓰여져 있습니다.  같은 원리를 이용한 것 입니다.



해당 유닛은 제가 조금 수정한 상태로 다음과 같은 링크에서 구하실 수가 있습니다.

http://code.google.com/p/ryulib4delphi/source/browse/trunk/XE2/BitmapRgn.pas



부족한 강의에 참석해주신 분들에게 다시 한 번 감사드리며, 보다 재미있는 주제를 준비해서 조만간 다시 온라인 강의를 진행하겠습니다 ^^*


'etc' 카테고리의 다른 글

고수로 가는 5단계  (0) 2013.02.12
지나가는 길에 만든 컴퓨터 화면 녹화 프로그램  (0) 2013.02.03
불면의 밤을 지새고...  (0) 2012.12.20
투표 합시다!  (0) 2012.12.10
HiMyTV - 실시간 강의 솔루션  (0) 2012.09.25

관련글 더보기