Update List scheduled for v2.0

by Blogger 하얀쿠아
2013. 5. 22. 12:51 수행 프로젝트 이력/한기대App (Android App) [2010.12~ ing]

익명게시판 - URL, URI (Telephone) Link 

공지사항 - Koreatech mobile web parsing

식단 - Home screen widget

이 댓글을 비밀 댓글로

데이터 글러브 동작 테스트 영상

by Blogger 하얀쿠아
2012. 10. 20. 21:41 수행 프로젝트 이력/Air Haptic Glove [2011.07~09]

Air Haptic Glove 프로젝트 초기의 데이터 글러브 테스트 영상 입니다.


3D Rendering Part : 전영호

3D Rendering Engine : microsoft XNA 3.1

Implement Language : C#

Physics Engine : JigLibX.Net

3D Modeling : 3D studio max 2011


Hardware Part : 김재민, 권기우

MCU : cortex m3

acceleration sensor, magnetic sensor, flex sensor : can`t remember



 첫번째 영상은 데이터글러브를 착용한 사용자의 손가락 구부림 정도를 추정하여 3D 손에 적용하는 테스트 영상이다. 프로젝트 초기의 영상이라 손가락 떨림 보정이 적용되어있지 않은 것을 알 수 있다.



'손가락 움직임 추정' 테스트 영상

flex 센서 5개를 이용하여 손가락의 움직임을 추정하고 3D로 표현하였다.




 두번째와 세번째 영상은 데이터글러브를 착용한 사용자의 손 자세를 추정하여 3D 가상손에 적용하는 것을 테스트하는 영상이다. 역시 떨림 보정이 전혀 되어있지 않아 3D 손이 심하게 떨리는 것을 확인할 수 있다.



'손 자세 추정' 테스트 영상 1

가속도 센서 + 지자기 센서 를 이용한 ARS 모듈을 만들고 자세 추정값을 이용하여 추정한 손의 자세를 3D로 표현하였다.





'손 자세 추정' 테스트 영상 2
가속도 센서 + 지자기 센서 를 이용한 ARS 모듈을 만들고 자세 추정값을 이용하여 추정한 손의 자세를 3D로 표현하였다. (부가적인것)또한, world 전체에 거대한 sphere를 씌우고 내부에 낮/밤 텍스쳐를 반씩 입혀 를 서서히 회전시키면서 낮/밤의 전환을 구현 한 것을 확인 할 수 있다.



다음 영상은 물리엔진 테스트 영상이다.
3D공간 상에서 손으로 물체를 잡거나 던지는 등의 행위를 구현하기 위하여, 3D공간상에 물리엔진을 적용하였다.
테스트 영상에서 나오는 공들은 물리 테스트를 쉽게 하기 위해 Camera 위치에서부터 발사되도록 한 것이며, height map으로 생성한 지형, 공끼리, 그외의 물체(흰 상자)와의 충돌, 튕김 등의 물리 테스트를 하고 있는 모습이다.


물리 엔진 테스트 영상
 물체 picking 을 구현하였고, 마우스 가운데를 이용해 물체를 잡아 던질 수 있도록 하여 물리 테스트를 수월하게 하였다.

 아직 shadow mapping을 하지 않아서 그림자가 적용되지 않은 시점에서의 테스트 영상이기에, 공의 위치에 대한 인지가 부정확 함을 확인 할 수 있다. 최종 버전은 shadow mapping이 완료되어 그림자를 통해 공간상의 물체들에 대한 위치 인지도와 입체감을 높이기 위해 노력했다. (영상은 진행project-Air Hapitc Glove 카테고리의 이전 포스팅에서 확인 가능)
 


이 댓글을 비밀 댓글로
    • 김동우
    • 2013.02.06 17:26
    안녕하세요.
    윈도우 3D를 화면에 구현하려 하는데 조언을 구하고자 글을 남깁니다.

    양쪽 팔에 3개의 센서를 달고 팔의움직임을 화면에 그대로 보여주고 싶습니다.
    데이터를 받아서 3D 모델을 처리해 주는 부분(XNA)에 관한 자료나 조언을 부탁드립니다.

    3D는 처음이라 많이 어렵습니다.
    • 처음이시라면 우선 기본적인 3D 그래픽 이론적인 지식을 간단하게 습득 하고 시작하시는게 여러모로 도움이 될 것 같습니다.
      (카메라, 프로젝션, 뷰, 3차원 좌표, 폴리곤, 텍스쳐 등등.. 의 3D 그래픽 이론 말이죠..)
      그 후 XNA를 사용하여 3D를 윈도우에서 렌더링 하신다면, 언어로는 C#을 사용하실 텐데.. 윈도우라고 하셨으니 XNA는 PC에서 돌아간다고 가정하겠습니다.

      간단히 말하면 센서의 값을 받아서 3D 모델의 위치좌표를 변경해 주시면 됩니다. 3D모델이 사람모양이라면, 팔 부분의 폴리곤들의 위치좌표를 변경해 주시면 될 것이고요..

      센서의 값을 PC로 보내는 방식은 블루투스를 사용하던, 시리얼 통신을 사용하던.. 하실것이고.. 센서는 아마도 자이로 + 가속도 센서 조합을 하시겠죠? 캘리브레이션 후에 X, Y, Z 좌표를 뽑아서 3D를 그리는 PC로 보내시면 되겠죠..

      PC에서는 받은 센서값을 3D 모델에 대입하시면 되는데..

      말은 쉬운데 3D가 처음이시라고 하셔서 어떻게 설명 드려야 할지 난감하네요 ^^;

      우선 3D 맥스 같은 모델링 툴로 간단하게 팔 부분을 모델링 해보세요
      본(Bone)을 모델에 심고, 이것을 fbx 파일로 뽑아서 XNA에서 로드 하시면 됩니다.
      fbx 모델을 XNA에서 로드 하는 기능도 구현을 해야 하는데, MS 의 XNA 예제 사이트에 이미 구현된 fbx 로더가 있으니 참고하시면 됩니다.
      XNA에서 로드된 3D 모델이 Bone을 가지고 있다면 Bone의 관절 하나하나를 제어할 수 있습니다. 마치 배열의 인덱스를 지정해서 배열값에 접근 하듯.. 이것도 MS의 예제를 찾아보시면 나올것이고요..
      관절 하나 하나를 실제 팔에 부착된 센서 하나하나와 매칭시켜주시고, 3D 모델 관절의 좌표값을 바꿔주시면 될것입니다.
    • 김동우
    • 2013.02.15 20:33
    조언 감사합니다.

    이야기해주신 대로 해보도록 하겠습니다.

    자료들 잔뜩 모아서 보고있습니다.

    마지막의 Bone을 제어하는 예제를 찾을수가 없어서... 여기 주소좀 알려 주실수 있나요?

    추가 ==> indie games 사이트에서 [Simple Animation] [Inverse Kinematics] 로 검색 하시면 됩니다.

    감사합니다.

스마트폰 거치대 기구부 설계

by Blogger 하얀쿠아
2012. 10. 19. 19:56 수행 프로젝트 이력/스마트폰을 이용한 감시시스템 [2011.09~ 2012.09]

본 프로젝트의 기구부를 만들 필요가 있었다.

 

회로를 보관할 박스 부분과, 스마트폰 거치대를 붙일 부분, Panning 모터와 Tilting 모터를 붙일 부분 등이 필요했다.

 

일단, 손으로 대충 구상하여 설계한 뒤, 가공이 쉬운 아크릴과 MDF, 이미 가공되어있던 알루미늄 가공물등을 이용해 프로토 타입을 만들어 보았다. 프로토타입 제작에 2일 걸렸다.

 

 

 

스마트폰 거치대 초기  프로토타입의 모습

 

 

 

이후 프로토타입이 어느정도 가용하다고 판단을 하고, 프로토타입의 설계도를 기준으로 솔리드웍스로 재설계를 했다. 

솔리드웍스 재설계는 팀원중 종섭이가 전담하여 진행해 주었다.

솔리드웍스 완전 처음 사용한다고 하며 튜토리얼 보고 학습후 진행 했으나, 진행속도는 빠른 편이었다.

약 2일 가량 소요.

 

설계된 파일에서 2D 도면만을 추출하여, 알루미늄 가공업체에 의뢰하였다.

 

 

설계도면

 

견적가격은 약 16만5천원 쯤 이었던 것으로 기억한다.

2set를 의뢰 하여 33만원 가량 사용하였다.

 

가공 결과물 - 1세트

 

 

의뢰한 도면대로 가공 결과물이 나왔음을 확인 하고 수령해왔다.

가공 결과물을 열심히 조립하였다.

 

 

조립중 - 회로 보관 박스 부분이다.

 

 

조립이 완료 된 뒤, 갤럭시S2를 거치한 모습은 아래와 같았다.

 

 

 

 

 

 

회로 보관 박스 위에 스마트폰 거치대를 부착하여 사용하였다.

스마트폰 거치대는 차량용으로 판매되는 기성품을 사용하였다.

이 댓글을 비밀 댓글로

식물 감성 모니터링 시스템 : Youtube 업로드 영상

by Blogger 하얀쿠아
2012. 10. 18. 10:44 수행 프로젝트 이력/식물 감성 모니터링 시스템 [2012.04~06月]




이 프로젝트를 수행했던 김들이, 김예슬, 이지우, 최윤미, 팀장 최경호 모두 수고 많았습니다!


특히, 졸업작품 때문에 바쁜 와중에 영상 편집까지 하느라 날밤을 많이 지새웠을 지우에게 정말 고생했다고 말하고 싶습니다.  (팀장 최경호의 말)


한글 버전 링크 : http://youtu.be/YNmFbD_uDm4


English version link : http://youtu.be/2GKDcoodOCs







이 댓글을 비밀 댓글로

FFmpeg 참고자료

by Blogger 하얀쿠아
2012. 10. 3. 06:26 수행 프로젝트 이력/스마트폰을 이용한 감시시스템 [2011.09~ 2012.09]

* 스마트폰을 이용한 가정용 화상감시 장비 프로젝트 진행 과정에서 얻게된 지식을 공유하는 포스팅 입니다.


본 프로젝트에서는 FFmpeg와 x264 라이브러리를 안드로이드에 포팅하여 H.264 인코딩/디코딩을 사용하였다.

결국 인코딩/디코딩 모두 성공 했지만 불완전 하다. 

네트워크 전송시 Intra 코딩만 가능. Inter 코딩 시 수신 측에서 디코딩 불가 문제가 있다. 

이 문제를 해결 중에 있다.(2012. 10월)

아래 링크는 이 작업과정에서 참조했던 사이트의 링크들 이다.


- ffmpeg 사용시 참고했던 사이트 링크

ffmpeg는 레퍼런스 문서나 예제가 많지 않아서 상당히 애를 먹었던 기억이 있다.

doxygen 문서가 있긴 하지만, 필요한 걸 찾기가 개인적으로 불편했었다. 

그래서 각 섹션마다 링크를 걸어둔다.


전역함수 레퍼런스

http://ffmpeg.org/doxygen/trunk/globals_func.html


AVCodecContext 구조체 레퍼런스

http://ffmpeg.org/doxygen/trunk/structAVCodecContext.html#7abe7095de73df98df4895bf9e25fc6b


AVPacket 구조체 레퍼런스

http://ffmpeg.org/doxygen/trunk/structAVPacket.html


libavcodec/h264.h 파일 레퍼런스

http://www.ffmpeg.org/doxygen/trunk/h264_8h.html


ffmpeg 파일 목록

http://www.ffmpeg.org/doxygen/trunk/files.html


ffmpeg 와 SDL 튜토리얼

http://dranger.com/ffmpeg/tutorial01.html



- 그외에 참조했던 사이트 (인코딩/디코딩)


FFmpeg을 이용한 Android 동영상 플레이어 개발 

http://helloworld.naver.com/helloworld/8794


ffmpeg 비디오 디코더(decoder) 사용법 - how to use ffmpeg video decoder

http://greenday96.blogspot.kr/2011/07/ffmpeg-decoder.html


Using libavformat and libavcodec

http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html


x264 옵션 값

http://yg05123.blog.me/70042737774


FFmpeg에 x264 인코더 사용방법 

http://iamlow.tistory.com/entry/FFmpeg%EC%97%90-x264-%EC%9D%B8%EC%BD%94%EB%8D%94-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95


ffmpeg의 api-example을 기반으로 한 mpeg 인코딩 방법(인코딩 시나리오 파악용으로 참조했다)

http://blog.daum.net/thflfkaus/6


이 댓글을 비밀 댓글로
    • 박가람
    • 2012.11.13 16:38
    안녕하세요~

    저도 ffmpeg + x264로 스마트폰에서 서버로 동영상 전송을 구현하려고하고 있습니다.

    혹시 ffmpeg 과 x264 포팅을 어떻게 하셨는지 여쭈어 봐도 될까요?
    • 저는 halfninja 라는 프로젝트를 참조했습니다.
      다음 URL에서 그 프로젝트의 자료를 다운로드 받을 수 있습니다.

      https://github.com/halfninja/android-ffmpeg-x264

    • 박가람
    • 2012.11.15 22:07
    감사합니다.
    • 박가람
    • 2012.11.25 23:31
    혹시 성능은 어느정도 나오는지 알 수 있을까요?

    실시간으로 적용하려고 하는데 성능이 어느정도 나오는지 궁금해서요~

    싸이즈는 몇에 몇 프레임 정도 나왔나요?

    • 320 X 240 에 대략 10~15 프레임 정도 였던것 같습니다.

      프레임 수치는 측정치는 아니고 제 느낌이(;;) 그렇다는것이므로 참고만 해주시기 바랍니다.
    • 박가람
    • 2013.01.02 10:39
    안녕하세요~ 혹시 인코드 디코드 할때 컨텍스트랑 코덱 세팅 값을 어떻게 하셨는지 알수 있을까요..
    돌아가는거 보니깐 인코딩은 되는 것 같은데 디코딩에서 에러가 나네요ㅠ
    • 김철표
    • 2013.08.16 02:47
    안녕하세요!
    박가람님과 마찬가지 이유로 문의드립니다.
    네트워크로 오디오 패킷을 전송해서 디코딩해보려고 하는데요, 코덱컨텍스트 세팅을 어떻게 하면될까요? 마찬가지고 원격으로는 자꾸 오류가나네요

libavcodec을 사용한 H.264 인코딩/디코딩 - C code

by Blogger 하얀쿠아
2012. 10. 3. 05:58 수행 프로젝트 이력/스마트폰을 이용한 감시시스템 [2011.09~ 2012.09]


* 스마트폰을 이용한 가정용 화상감시 장비 프로젝트 진행 과정에서 얻게된 지식을 공유하는 포스팅 입니다.


본 프로젝트의 전체적인 시스템 구성도는 아래와 같다.



여기에서 코덱이 필요한 이유는, 감시 영상을 네트워크를 통해 전달하기 때문이다.

raw data를 그대로 전달 할 경우, 1프레임 영상의 크기가 1메가를 상회하게 된다. 

(지원 해상도는 QCIF, QVGA 만 허용함. 이는 각각 352 x 288과 320 x 240 이다.)


네트워크 대역폭 제한으로 인해 받아 보는 쪽에서 영상의 프레임이 낮을 것이다.

또한 3G/4G 를 사용한다면 데이터 요금도 상당할 것이다.

 이를 h.264 코덱으로 인코딩 하여 네트워크로 보내게 된다면, 이런 문제를 해결 가능 할 것이라 판단하여 코덱을 사용하였다. 물론 인코딩 하는 카메라 스마트폰의 CPU사용량이 상당히 증가할 것이지만, 뷰어 측의 원할한 영상 수신을 위해서 이정도는 감수하기로 하였다.


감시카메라 Application을 구동하는 스마트폰에서는 입력되는 카메라 영상을 H.264 코덱으로 인코딩 하여 중계서버로 전송한다.


사용자뷰어 Application을 구동하는 스마트폰에서는 중계서버로부터 전송받는 인코딩된 데이터를 디코딩하여 사용자에게 보여준다.


위 과정에서 이루어지는 인코딩/디코딩은 ffmpeg 를 android 용으로 포팅하여 사용했다.

1. 안드로이드에서 ffmpeg의 라이브러리 함수를 호출할 수 있도록 C로 인터페이스 함수를 만들었다.

2. 이 인터페이스 함수들만 모아 .so파일로 만들어 dynamic link 하여 사용하였다.


아래는 인터페이스 함수 제작 과정에 참고한 예제 코드이다.


출처 : http://natnoob.blogspot.kr/search?updated-min=2011-01-01T00:00:00%2B07:00&updated-max=2012-01-01T00:00:00%2B07:00&max-results=6


이 예제는 api-example을 기반으로 구현했다.

이것은 C코드를 이용하여 raw data 영상(QCIF)을 H264로 인코딩 하는 방법과 인코딩 된 영상을 yuv로 디코딩 하는 방법을 보여준다.



 - 아래는 main 함수 부분이다.

int main(int argc, char **argv)

{


/* must be called before using avcodec lib */

avcodec_init();


/* register all the codecs */

avcodec_register_all();


h264_encode_decode("Foreman.qcif","Decoded.yuv");


return 0;

}



- 시작 부분은 언제나 코덱의 등록과 초기화이다.

그 후 이 예제에서는 h264_encode_decode( ) 함수를 호출할 것인데, 이 함수는 Foreman.qcif 라는 파일로 입력되는 영상을 h.264로 인코딩 한 뒤, 다시 yuv 파일로 디코딩 하여 Decoded.yuv 로 저장 할 것이다.


총 5단계로 나눠서 보이겠다.

1. 인코딩/디코딩에 사용할 변수 선언

AVCodec *codecEncode, *codecDecode;

AVCodecContext *ctxEncode= NULL, *ctxDecode = NULL; 


FILE *fin, *fout;

AVFrame *pictureEncoded, *pictureDecoded;


uint8_t *encoderOut, *picEncodeBuf;

int encoderOutSize, decoderOutSize;

int pic_size;


AVPacket avpkt;

int got_picture, len;


const int clip_width = 176;

const int clip_height = 144;


int frame = 0;

uint8_t *decodedOut;



2. 코덱 초기화/디코더를 위한 picture 구조체

codecDecode = avcodec_find_decoder(CODEC_ID_H264);

if (!codecDecode) {

fprintf(stderr, "codec not found\n");

exit(1);

}


ctxDecode= avcodec_alloc_context();

avcodec_get_context_defaults(ctxDecode);

ctxDecode->flags2 |= CODEC_FLAG2_FAST;

ctxDecode->pix_fmt = PIX_FMT_YUV420P;

ctxDecode->width = clip_width;

ctxDecode->height = clip_height; 

ctxDecode->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE);


if (avcodec_open(ctxDecode, codecDecode) < 0) {

fprintf(stderr, "could not open codec\n");

exit(1);

}


pictureDecoded= avcodec_alloc_frame();

avcodec_get_frame_defaults(pictureDecoded);

pic_size = avpicture_get_size(PIX_FMT_YUV420P, clip_width, clip_height);


decodedOut = (uint8_t *)malloc(pic_size);

fout = fopen(fileout, "wb");

if (!fout) {

fprintf(stderr, "could not open %s\n", fileout);

exit(1);

}



3. 코덱 초기화/인코더를 위한 picture 구조체

codecEncode = avcodec_find_encoder(CODEC_ID_H264);

if (!codecEncode) {

printf("codec not found\n");

exit(1);

}


ctxEncode= avcodec_alloc_context();

ctxEncode->coder_type = 0; // coder = 1

ctxEncode->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop

ctxEncode->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1

ctxEncode->partitions|=X264_PART_I8X8+X264_PART_I4X4+X264_PART_P8X8+X264_PART_B8X8; // partitions=+parti8x8+parti4x4+partp8x8+partb8x8

ctxEncode->me_method=ME_HEX; // me_method=hex

ctxEncode->me_subpel_quality = 0; // subq=7

ctxEncode->me_range = 16; // me_range=16

ctxEncode->gop_size = 30*3; // g=250

ctxEncode->keyint_min = 30; // keyint_min=25

ctxEncode->scenechange_threshold = 40; // sc_threshold=40

ctxEncode->i_quant_factor = 0.71; // i_qfactor=0.71

ctxEncode->b_frame_strategy = 1; // b_strategy=1

ctxEncode->qcompress = 0.6; // qcomp=0.6

ctxEncode->qmin = 0; // qmin=10

ctxEncode->qmax = 69; // qmax=51

ctxEncode->max_qdiff = 4; // qdiff=4

ctxEncode->max_b_frames = 3; // bf=3

ctxEncode->refs = 3; // refs=3

ctxEncode->directpred = 1; // directpred=1

ctxEncode->trellis = 1; // trellis=1

ctxEncode->flags2|=CODEC_FLAG2_FASTPSKIP; // flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip

ctxEncode->weighted_p_pred = 0; // wpredp=2

ctxEncode->bit_rate = 32000;

ctxEncode->width = clip_width;

ctxEncode->height = clip_height;

ctxEncode->time_base.num = 1;

ctxEncode->time_base.den = 30;

ctxEncode->pix_fmt = PIX_FMT_YUV420P; 

ctxEncode->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE);

ctxEncode->rc_lookahead = 0;

ctxEncode->max_b_frames = 0;

ctxEncode->b_frame_strategy =1;

ctxEncode->chromaoffset = 0;

ctxEncode->thread_count =1;

ctxEncode->bit_rate = (int)(128000.f * 0.80f);

ctxEncode->bit_rate_tolerance = (int) (128000.f * 0.20f);

ctxEncode->gop_size = 30*3; // Each 3 seconds


/* open codec for encoder*/

if (avcodec_open(ctxEncode, codecEncode) < 0) {

printf("could not open codec\n");

exit(1);

}


//open file to read

fin = fopen(filein, "rb");

if (!fin) {

printf("could not open %s\n", filein);

exit(1);

}


/* alloc image and output buffer for encoder*/

pictureEncoded= avcodec_alloc_frame();

avcodec_get_frame_defaults(pictureEncoded);


//encoderOutSize = 100000;

encoderOut = (uint8_t *)malloc(100000);

//int size = ctxEncode->width * ctxEncode->height;

picEncodeBuf = (uint8_t *)malloc(3*pic_size/2); /* size for YUV 420 */

pictureEncoded->data[0] = picEncodeBuf;

pictureEncoded->data[1] = pictureEncoded->data[0] + pic_size;

pictureEncoded->data[2] = pictureEncoded->data[1] + pic_size / 4;

pictureEncoded->linesize[0] = ctxEncode->width;

pictureEncoded->linesize[1] = ctxEncode->width / 2;

pictureEncoded->linesize[2] = ctxEncode->width / 2; 



4. 입력 파일로 부터 데이터를 읽고, avcodec_encode_video 를 사용해서 인코딩 한다.

인코딩된 데이터는 디코더로 보내질 것인데, yuv 포맷으로 디코딩 된 결과가 나올 것이고, avcodec_decode_video2 를 사용할 것이다. 

디코딩 된 데이터는 decoded.yuv 라는 파일로 만들 것 이다.

//encode and decode loop

for(int i=0;i<30;i++) 

{

fflush(stdout);

//read qcif 1 frame to buufer

fread(pictureEncoded->data[0],ctxEncode->width * ctxEncode->height, 1, fin);

fread(pictureEncoded->data[1],ctxEncode->width * ctxEncode->height/4, 1, fin);

fread(pictureEncoded->data[2],ctxEncode->width * ctxEncode->height/4, 1, fin); 

pictureEncoded->pts = AV_NOPTS_VALUE;


/* encode frame */

encoderOutSize = avcodec_encode_video(ctxEncode, encoderOut, 100000, pictureEncoded);

printf("encoding frame %3d (size=%5d)\n", i, encoderOutSize);

if(encoderOutSize <= 0)

continue;


//send encoderOut to decoder

avpkt.size = encoderOutSize;

avpkt.data = encoderOut;

//decode frame

len = avcodec_decode_video2(ctxDecode, pictureDecoded, &got_picture, &avpkt);

if (len < 0) {

printf("Error while decoding frame %d\n", frame);

exit(1);

}

if (got_picture) {

printf("len = %d saving frame %3d\n", len, frame);

fflush(stdout);


avpicture_layout((AVPicture *)pictureDecoded, ctxDecode->pix_fmt

, clip_width, clip_height, decodedOut, pic_size);

fwrite(decodedOut, pic_size, 1, fout);

frame++;

}

}



5. 할당된 메모리를 해제하고, 파일 포인터를 닫아준다.

fclose(fout);

fclose(fin);


avcodec_close(ctxEncode);

avcodec_close(ctxDecode);

av_free(ctxEncode);

av_free(ctxDecode);

av_free(pictureEncoded); 

av_free(pictureDecoded); 



나는 이 구현코드가 libavcodec을 사용해서 C언어로 h264의 인코딩과 디코딩을 올바르게 하는 방법을 보여주는 적절한 예제라고 생각한다.

이 예제코드를 바로 사용하긴 힘들지만, 인코딩/디코딩 하는 시나리오를 이해하는데 도움이 될 것이다.



이 댓글을 비밀 댓글로
    • 밀레니안
    • 2012.10.12 17:42
    안녕하세요..? 저랑 비슷한 프로젝트를 진행중이셔서 질문이 있어 글 남깁니다..

    저도 ffmpeg를 이용해서 동영상 인코딩을 하는데

    안드로이드에서 영상을 받을때 mediarecoder를 이용해 raw data를 받아서 하신건가요?
    미디어레코더와 로컬 소켓을 이용해 받은 것을 어떻게 활용해야 할지 모르겠어서
    현재 카메라 프리뷰 콜백을 이용해 이미지를 영상으로 인코딩해서 하고 있는데

    최저 화질을 사용해도 15초 촬영에 인코딩 시간이 20초 걸려서 활용할 수가 없어 막혀있습니다....

    미디어레코더로 받은 것을 활용하신거라면...노하우좀 전수해주세요 ㅠㅠ
    • 저 역시 카메라 프리뷰 콜백을 이용했습니다. ^^;
      콜백의 파라미터로 들어오는 byte[ ]형태의 1프레임 짜리 이미지를 콜백 호출이 될 때마다 인코더에 넣어서 인코딩 하는 방식으로 구현했습니다.

      저같은 경우는 영상을 파일로 저장하는게 목적이 아니라 네트워크를 통해 Viewer 쪽에 최대한 빠르게 전송 + 1프레임 영상 하나하나에 대한 영상처리(차영상을 통한 detection & tracking)가 목적이었기 때문에 미디어레코더를 애초에 배제하고 raw image를 받을 수 있는 카메라 프리뷰를 이용했네요.
      제 포스팅이 도움이 되지는 못할 듯 해서 아쉽습니다 ^^;
    • 밀레니안
    • 2012.10.13 01:10
    아...감사합니다..

    Dev고양이님의 글이 저에게 충분히 도움이 되고있습니다...;;

    모든 것을 ffmpeg.c에 기대어 할 생각을 했는데 따로 인코딩 소스를 짜서 할 생각이 생기게 해주셨네요..

    한가지 질문 더 할게요 ㅠㅠ

    위에 적은것 처럼 저두 콜백 이용해서 하는 중인데 저의 경우에는 콜백 통해 받은 바이트를 한 파일에 이어 붙여 그걸 인코딩 하는 식으로 했는데 Yuvimage 객체 를 이용해 사이즈를 변환 해 보려구 했지만 jpeg 로 압축하지 않으면 800X480에서 변하질 않더군여;; 352X288 로는 어떻게 변환 하신건가요?
    사이즈가 줄어들면 인코딩 시간이 줄어들까 싶어서..
    • Camera 객체를 open 한 이후에 여러가지 세팅을 하고(set 계열 메소드들을 호출함으로써) 최종적으로 startPreview( ) 메소드를 호출 하여 카메라 콜백을 하셨을 텐데요.

      그 세팅 과정에서 다음과 같이 파라메터를 카메라에 넣음으로써 콜백함수의 byte[ ] 영상의 해상도를 설정 할 수 있습니다. (try catch 는 댓글의 간략화를 위해 생략했습니다)

      Camera mCamera = Camera.open();
      Camera.Parameters parameters = mCamera.getParameters();
      parameters.setPictureSize(width, height); // width 352, height 288 넣으면.
      mCamera.setParameters(parameters);

      ** 여기서 문제가 있습니다. **
      만약 setPictureSize 에 임의의 수치를 넣게 되면 예외가 발생할 수 있는데, 이 코드가 돌고 있는 안드로이드 폰이 지원하지 않는 해상도를 넣게 되면 예외가 발생 하게됩니다.

      넥서스S 는 352x288을 지원하지만(확실) 320x240을 지원하지 않고요.(확실)
      갤럭시S2는 320x240을 지원하지만(확실), 352x288을 지원 하지 않았던것 같습니다.(긴가민가)

      다음과 같이 현재 코드가 돌고 있는 폰이 지원하는 해상도를 List 형태로 얻을수 있습니다.

      // 카메라에서 찍을 수 있는 모든 사이즈를 List 형태로 얻음

      Camera mCamera = Camera.open();
      Camera.Parameters parameters = mCamera.getParameters();
      List<Size> sizes = parameters.getSupportedPictureSizes();
      Size optimalSize;
      optimalSize = getOptimalPreviewSize(sizes, IMAGE_WIDTH, IMAGE_HEIGHT);
      parameters.setPictureSize(optimalSize.width, optimalSize.height);
      mCamera.setParameters(parameters);

      getOptimalPreviewSize( ) 함수는 뭐.. 다음과 같이 구현 하면 될 것 같습니다.
      파라메터는 지원하는 해상도 목록 sizes, 원하는 해상도의 width와 height 를 넣고요.
      그러면, getOptimalPreviewSize(sizes, 352, 288 ) 이렇게 호출했을때 352x288 지원 불가 폰이라면 가장 인접한 해상도를 리턴해주던지 null을 리턴해 줄 겁니다. (아마도 말이죠)

      private Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {
      final double ASPECT_TOLERANCE = 0.05;
      double targetRatio = (double) width / height;
      if (sizes == null) {
      return null;
      }

      Size optimalSize = null;
      double minDiff = Double.MAX_VALUE;

      int targetHeight = height;

      // Try to find an size match aspect ratio and size
      for (Size size : sizes) {
      double ratio = (double) size.width / size.height;
      if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
      continue;
      }
      if (Math.abs(size.height - targetHeight) < minDiff) {
      optimalSize = size;
      minDiff = Math.abs(size.height - targetHeight);
      }
      }

      // Cannot find the one match the aspect ratio, ignore the requirement
      if (optimalSize == null) {
      minDiff = Double.MAX_VALUE;
      for (Size size : sizes) {
      if (Math.abs(size.height - targetHeight) < minDiff) {
      optimalSize = size;
      minDiff = Math.abs(size.height - targetHeight);
      }
      }
      }
      Log.i("optimal size", ""+optimalSize.width+" x "+optimalSize.height); //for debugging
      return optimalSize;
      }

      그럼 좋은 결과 있기를 바랍니다 ^^
    • 밀레니안
    • 2012.10.13 01:44
    헐...완전 자세한 답변에 감동했네요.. 감사합니다 (__)

    이걸로 인코딩 속도는 무조건 줄어들겠죠

    그리고 찾아보니 저랑 같은 곳에 소속되어 있는 곳이 있더군요^^; 지역은 틀리지만...

    반갑습니다. ㅋㅋ

    이 프로젝트 진행중이시던데 좋은 결과 얻길 바라겠습니다.
    • 아! 어느 지역에 계신가요?
      저는 곧 이 프로젝트 마감이라 한창 준비하고 있습니다ㅎ.
      아무튼 무척 반갑습니다. ^^
      해상도를 줄이면 아무래도 인코딩에 소요되는 시간은 줄어들거 같네요. 화이팅 입니다 ~
    • 밀레니안
    • 2012.10.14 21:51
    부산이에요..ㅎ

    15초짜리 20초에서 15초짜리 14초 정도로 줄어들었네요 ㅎㅎ 폰을 좀더 좋은걸 쓴다면 사용 하능 할 것 같아요 ^^

    도움 감사합니다.
    Dev고양이님도 화이팅이요~

[작업일지] 2012년 9월 21일 - 금

by Blogger 하얀쿠아
2012. 9. 21. 05:20 수행 프로젝트 이력/스마트폰을 이용한 감시시스템 [2011.09~ 2012.09]

중계서버 - (전영호)

  - 영상 스트리밍 부분을 수정

  - 기존의 16bit start 마크 / 고정폭raw영상데이터 /16bit end마크 를 빼고.

  - start와 end 를 문자열로 대체. start - 데이터size를나타내는int값(4byte) - 데이터 - end

  - 이렇게 4부분으로 분할

  - camclient, viewclient, clientconnection  3개 스레드의 타이밍 조정. wait( ), notify( ) 활용


카메라앱 - (전영호)

  - 영상 인코딩 h264 , (gop 를 0으로 하여 intra 코딩만 하도록 함)

  - 전송되는 스레드의 타이밍 조정


뷰어 앱 - (전영호)

  - 영상 디코딩 h264

  - ui layout 수정

  - 패키지 재분류

  - recvView 스레드를 없애고 displayer 클래스를 서피스뷰를 상속받아 만들었으며 이 클래스는 이너클래스로 워커스레드 2개를 가진다. 각각 디코딩 워커, draw 워커 이다.

  - 디코딩 워커, draw 워커, 타이밍 조정.



이 댓글을 비밀 댓글로

[ffmpeg] NDK 를 이용해 안드로이드 용 library 빌드시 문제 : codec_names.h 누락

by Blogger 하얀쿠아
2012. 9. 7. 15:46 수행 프로젝트 이력/스마트폰을 이용한 감시시스템 [2011.09~ 2012.09]

ndk version : r8

ffmpeg version : 0.10.4

host os : windows 7

terminal : cygwin


참고 자료 : [Android NDK FFmpeg 컴파일 강좌 (4/4)]

 http://www.androidpub.com/index.php?mid=android_dev_info&page=1&search_target=tag&search_keyword=FFmpeg&document_srl=1646540


문제 내용

참고 자료를 통해 ffmpeg를 빌드하던 중 codec_names.h 를 찾지 못한다는 문제가 발생.


D:/Eclipse_Workspace_Android/FFmpegBasic/jni/ffmpeg/libavcodec/utils.c:1568:36: error: libavcodec/codec_names.h: No such file or directory

/home/JeonYoungHo/android-ndk-r8/build/core/build-binary.mk:240: recipe for target `/cygdrive/d/Eclipse_Workspace_Android/FFmpegBasic/obj/local/armeabi-v7a/objs/avcodec/utils.o' failed

make: *** [/cygdrive/d/Eclipse_Workspace_Android/FFmpegBasic/obj/local/armeabi-v7a/objs/avcodec/utils.o] Error 1





문제 원인

ffmpeg 빌드시 make 파일들을 쭉 따라가다보면 

ffmpeg/libavcodec 에 보면 codec_names.sh 파일이 존재한다. (헤더가 아닌, 쉘 스크립트 프로그램 파일임)

이 쉘 스크립트를 실행 하여 codec_names.h 를 생성하는 구조이다.


codec_names.h는 보통 ndk-build 명령을 통해 build 진행시 auto generate 된다. (make 파일들을 제대로 작성했다는 가정 아래)

어떤 이유인지는 모르겠지만 본인은 codec_names.h 가 자동 생성되지 않아서 build 가 진행되다가 멈추었다.


참조 자료를 따라하며 build 를 시도한다면, libavcodec 디렉토리에 

Makefile2 를 만들었을 것이고, 그것을 열어보면 
65번 line 부터
$(SUBDIR)codec_names.h: $(CODEC_NAMES_SH) config.h $(AVCODEC_H)
$(CC) $(CPPFLAGS) $(CFLAGS) -E $(AVCODEC_H) | \
$(CODEC_NAMES_SH) config.h $@

이런 내용이 있다.
이부분이 codec_names.h 를 자동 생성하는 부분이다. config.h 는 현재 디렉토리에서 찾게 되어있지만 상위 디렉토리에 있으므로 못 찾을 것이고.. 소스상에서도 수정이 약간 필요했다.


해결 방법

요약 : codec_names.sh 를 이용해 codec_name.h 를 수동으로 생성해준다.

구체적 방법 

ffmpeg/libavcodec 디렉토리에 위치한 상태에서 gcc를 통해 다음과 같이 실행.

$ gcc -DLIBAVCODEC_VERSION_MAJOR=53 -E avcodec.h | ./codec_names.sh ../config.h codec_names.h


에러가 날 것이다.

에러내용을 자세히 읽어보면 #include "경로/헤더파일" 의 상대경로/절대경로 문제이다.

에러난 파일을 vi로 열어서 경로를 상대경로로 지정해준다.

 예) In file included from ../libavutil/avutil.h:328,

                 from ../libavutil/samplefmt.h:22,

                 from avcodec.h:30:

../libavutil/common.h:38:32: libavutil/avconfig.h: No such file or directory

avcodec.h:457:36: libavutil/audioconvert.h: No such file or directory


avcodec.h 의 457라인에서 libavutil/audioconvert.h 를 찾을수 없다는 뜻.

avcodec.h 를 열어 457라인을 보면 #include "libavutil/audioconvert.h" 가 있을 것이다.

#include "../libavutil/audioconvert.h" 로 수정해준다. (각자 자신의 기준에서 수정할 필요가 있다)


이런식으로 몇개의 include 관련 에러가 발생하는데, 모두 유사한 방법으로 수정하고  $ gcc -DLIBAVCODEC_VERSION_MAJOR=53 -E avcodec.h | ./codec_names.sh ../config.h codec_names.h 를 다시 해보면 codec_names.h 가 정상적으로 생성될 것이다.

이후, ndk-build 를 통해 다시 진행하여 정상 빌드 되었다.

결론
에러내용을 꼼꼼히 읽고 차근차근 생각해서 잘하자


이 댓글을 비밀 댓글로
    • 한기대졸업생
    • 2013.07.05 16:09
    저도 한기대 졸업했는데 05학번으로 ㅋㅋ 오랜만에 한기대 이름 보니까 반갑네요