최근 한달동안 작업한 것

그것은 게임에 특화(?)된 원격 프로그램.

목표는 고향에 갔을 때 내 맥북이나 아이폰으로 내 PC에 게임을 띄워 문제없이 렙에 맞는 사냥터에서 사냥하는 정도. 처음엔 삼주씩이나 동영상 디코더랑 씨름할줄은 몰랐다(…)

여튼 어느정도 완성도 높여서 이걸 앱스토어에 올려볼까 생각하고있다. 살작 광고하나 접속하기 전에 하단에 뜨도록 한 다음(…) 뭐 문제는 언제 그정도 조작에 퀄리티있게 만들게 될지는 미지수지만 오랜만에 한가지에 몰두해본거같다.

Video Decode Acceleration Framework 사용 시 주의점

최근 거의 2주일동안 apple의 하드웨어 H264 디코더인 VDA와 씨름을 하였다. 이건 H264의 깊이있는 지식을 가지고 쓴것이 아니고 단지 VDA로 하드웨어 디코딩을 하기위해 중점을 맞춘것이니 깊이있는 지식은 넘어가고 VDA나 VideoToolbox를 사용하기위해 참고하는 정도만으로 넘어가야 할 것이다.

VDA에 관한 기술문서로 https://developer.apple.com/library/content/technotes/tn2267/_index.html 페이지가 거의 유일하며, 그나마 참조할건 http://stackoverflow.com/questions/29525000/how-to-use-videotoolbox-to-decompress-h-264-video-stream 이 글의 댓글이 거의 유일하다. (물론 VideoToolbox와 VDA는 초기화 방법이 서로 다르지만, VDA에서 지원되는 기능은 VideoToolbox에서도 동일하게 지원하는거로 보이고 avcC라는 것을 생성하지 않아도 되기때문에 초기화가 더 수월하다.)

먼저 이론적인 기본은 위 stackoverflow의 댓글로 확인하면 될것이다. 약간 첨언한다면 H264는 3바이트, 또는 4바이트짜리 Start Code라고 불리는 코드로 각각의 프레임을 구분한다. 그리고 디코딩에 필요한 NALU 타입은 7 (SPS), 8 (PPS), 5 (IDR), 1 (non-IDR) 정도로 보인다.

디코더를 초기화하기 위해서는 SPS, PPS가 필요하며, 이 정보를 바탕으로 디코딩을 한다. (영어가 된다면 https://developer.apple.com/videos/play/wwdc2014/703/ 이것이 참고가 될것이고, 프레젠테이션 자료는 Resource 탭에서 받을 수 있다.) Continue reading Video Decode Acceleration Framework 사용 시 주의점

Edge(엣지) 브라우저에서 한국어도 영어도 아닌 다른 언어로 페이지가 열릴 때

이전에도 종종 한국어 또는 영문페이지가 멀정하게 뜨다가 엉뚱하게 일본어로 뜨는 경우가있었다. 그냥 종종 그랬기때문에 불편해도 넘어갔지만 오늘은 좀 자세하게 알아봤다. (만약 외국 사이트에서 한국어로 뜨다가 일본어가 뜬다면 그 페이지는 한국어 번역이 되어있지않지만 일본어로는 번역되어진 페이지이다.)

만약 일본 홈페이지도아닌데 영어도, 한국어도 아닌 일본어 등 다른 언어로 뜬다면 아래처럼 언어가 추가되어있는 경우라고 본다.

2016-10-19-2

이것이 연관되어 엣지에서 아래처럼 브라우저의 언어정보가 한국어와 일본어 동일한 가중치로 전송된다.

2016-10-19-4

Continue reading Edge(엣지) 브라우저에서 한국어도 영어도 아닌 다른 언어로 페이지가 열릴 때

닷넷 Any CPU 빌드한 바이너리가 64비트 OS에서 32비트로 동작할 때

닷넷으로 Text to Speech. 즉 입력 된 텍스트를 읽어주는 TTS를 해달라는 부탁으로 시작하게 된 삽질.

내가 사용하는 OS는 윈도 10이고 타겟은 윈도 7이였다. 윈도 TTS는 https://msdn.microsoft.com/en-us/library/hh361572(v=office.14).aspx 이곳에서 Runtime, Language Packs 두가지를 설치하면 된다고 되어있는데… 이상하게 아무리 재설치를해도 한글 음성이 지원되는 Voice 객체가 나타나지않았다.

윈도 제어판에서는 한글 음성이 나타나는데 닷넷에선 아무리 해도 나타나지않아 포기하고 C++로 Voice 객체를 조회해보았지만 역시나 실패. 혹시나해서 64비트로 빌드하여 다시 조회하니 Heami가 나타나는 것이였다.

그런것이였다. 윈 10은 32비트, 64비트 둘 다 한글 Voice가 재공되는 것이였다… 근데?! 뭐지? 싶어 닷넷 실행파일 띄워놓고 작업관리자 열어보니 32비트로 실행되고있고, 구글링해보니 http://stackoverflow.com/a/23351613 이 댓글이 나왔고, 프로젝트 속성을 보니 아래 옵션이 있었다.

2016-10-16-1

32비트 기본 사용…!!! 32비트 기본이라니! 하.하!? VS2015에서 기본으로 체크되는 옵션인지 어떤지는 모르겠지만 회사에서 VS2015가 나오자마자 구입하였는데… 왠지 최근 만든 닷넷 어플들 32비트 모드로 동작하고있을거같다.

아마도 ActiveX라던지 COM Object, 기타 외부 네이티브 라이브러리가 32비트가 대다수라 생기는 문제가 많기때문에 이런걸 기본옵션으로 체크되어있는거같은데… 나같은 경우엔 그 반대라서 하루 삽질을 하였다.

아… 해결되어서 좋긴한데 왜 눈물이 나려하지… 내 시간은..

Continue reading 닷넷 Any CPU 빌드한 바이너리가 64비트 OS에서 32비트로 동작할 때

shared_ptr 객체를 멀티스레드에서 사용할 때

분명 shared_ptr은 레퍼런스 카운트가 스레드 안정적이라고 되어있다고 나와있지만 아래와같은 코드를 실행하면 실행하자마자 에러가 발생한다.

#include <memory>

std::shared_ptr<int> g;

DWORD WINAPI U(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = g;
    }
    return 0;
}

DWORD WINAPI C(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = std::make_shared<int>(0);

        g = data;
    }
    return 0;
}

int main()
{
    HANDLE h1 = CreateThread(NULL, 0, U, NULL, 0, NULL);
    HANDLE h2 = CreateThread(NULL, 0, C, NULL, 0, NULL);

    WaitForSingleObject(h1, -1);
    WaitForSingleObject(h2, -1);

    return 0;
}

거의 수시간동안 구글링해도 한결같이 나오는건 레퍼런스 카운트는 스레드 안전하다는 것 정도.
그래도 다행이도 계속 검색해보니 결국 아래와같이 atomic을 사용하는 코드가 나왔다.

#include <atomic>
#include <memory>

std::shared_ptr<int> g;

DWORD WINAPI U(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = std::atomic_load(&g);
    }
    return 0;
}

DWORD WINAPI C(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = std::make_shared<int>(0);
        std::atomic_store(&g, data);
    }
    return 0;
}

int main()
{
    HANDLE h1 = CreateThread(NULL, 0, U, NULL, 0, NULL);
    HANDLE h2 = CreateThread(NULL, 0, C, NULL, 0, NULL);

    WaitForSingleObject(h1, -1);
    WaitForSingleObject(h2, -1);

    return 0;
}

저렇게 atomic_store, atomic_load를 사용하니 이제 정상적으로 shared_ptr 객체가 두 스레드간의 참조가 문제없이 되었다. 분명 부스트의 shared_ptr 기준으로 코드를 보면 InterlockedIncrement 함수를 사용하여 카운트하던데 그마저도 저런식으로 사용하니 0xDDDDDDDD로 채워진 이미 초기화 된 변수가 나타났다. 좀처럼 이해하기 힘든 동작이였다.

수시간, 그리고 며칠동안 구글링 아무리 해봐도 shared_ptr는 참조 카운트가 스레드 안전하다고 할 뿐 좀 더 자세한 내용 잘 나오지도않고(…) 그냥 이렇게 사용해야 정말 안전하다 정도로 알고 넘어가야겠다 -_-;;;