[RaspberryPi] minidlna-transcode 설치

라즈베리 파이로 DLNA 뷰어를 통해 동영상을 보려니 코덱 문제로 음성이 안나오는 것들이 있어서 minidlna-transcode로 트랜스코딩을 시도해 보았다. 결론만 말하면 실패. 컴퓨팅 파워 문제인지 툭툭 끊긴다.

원리는 설정된 특정 코덱을 사용하는 동영상은 보내기 전에 설정한 스크립트에서 ffmpeg를 통해 인코딩을 해서 쏘는 것으로 보인다. 설치하다보니 Debian에서 ffmpeg가 avconv로 이름이 바뀌었다는 것도 알게 됐다.

minidlna는 라즈베리안의 경우 현재 1.1.2버전을 apt-get으로 그냥 설치할 수 있다. 트랜스코딩없이 쓴다면 그냥 패키지 설치하는게 맘 편할 수 있겠다. 내가 시도한 방법은 소스 컴파일 설치이다.

  1. 소스 컴파일 설치

먼저 git으로 clone해온다.

$ git clone -b transcode https://bitbucket.org/stativ/readymedia-transcode.git

컴파일에 필요한 패키지를 설치한다.

$ sudo apt-get install libexif-dev libjpeg-dev libid3tag0-dev libflac-dev libvorbis-dev libsqlite3-dev libavformat-dev libavutil-dev libavcodec-dev  libmagickwand-dev autoconf autopoint gettext libav-tools libav-dev mpv

아래 패키지는 이름이 그럴듯해서 그냥 설치해봤는데 확실치 않다. mpv의 경우, mencoder가 또 저걸로 바뀌었대서 깔았는데, mencoder를 이용하진 않아서 잘 모르겠다.

$ sudo apt-get install libavcodec-extra libavcodec-extra-56 mpv

컴파일한다.

$ ./autogen.sh
$ ./configure
$ make

그럼 다음과 같은 컴파일 에러가 난다.

minidlnad-upnphttp.o: In function `SendResp_dlnafile':
/home/pi/src/readymedia-transcode/upnphttp.c:2041: warning: the use of `tmpnam' is dangerous, better use `mkstemp'

tmpnam()이 위험하니까 mkstemp()를 이용하라는 거니까 찾아서 바꿔준다.

$ vi upnphttp.c

char tmp[L_tmpnam];
mkdtemp(tmp);

다시 컴파일하면 잘 된다. 설치를 sudo make install로 해줘도 되는데(사실 이렇게 한 후에 checkinstall을 사용했다-_-), 패키지를 만들어 설치하면 나중에 제거가 편하다. checkinstall이 없으면 설치(sudo apt-get install checkinstall)한 후에 아래 명령을 준다.

$ sudo checkinstall

아래와 같은 게 나오면 ‘Y’

아래와 같은게 나오면 난 MiniDLNA Version 2015-06-18 Compiled June 18, 2017 라고 입력했다.

그럼 아래와 같은게 나오는데, 여기서 3번, 버전만 숫자로 시작해야해서 아래처럼 2015-06-18 로 입력했다.

3 - Version: [ transcode ]
3 - Version: [ 2015-06-18 ]

 

2. 설정

이제 소스 내에 있는 설정 파일을 /etc/ 아래로 복사해서 설정을 시작하자.

$ sudo cp minidlna.conf /etc/minidlna.conf

sudo를 매번 입력하기 귀찮으니 sudo -i 를 입력해서 root shell로 작업하자.

# vi /etc/minidlna.conf

설정 파일에서 아래 “media_dir”, “friendly_name”을 각자 환경에 맞게 적자. “media_dir”은 예상하듯이, 미디어가 있는 경로, “friendly_name”은 DLNA 기기에서 나타나는 이름이다.

media_dir=V,/mnt/NAS/Videos
friendly_name=DasomOLI DLNA

“audio_codecs”나 “video_codecs” 에 적혀있는 코덱에 해당하는 미디어 파일이 재생되면, 그 아래의 “transcode_audio_transcoder”혹은 “transcode_video_transcoder” 에 적혀 있는 스크립트를  실행한다. 원하는 코덱을 transcoding하고 싶다면 해당 코덱을 적어주자. 어떤 것을 적어야 하는지는 avconv -formats 라고 입력하면 찾아볼 수 있다.

transcode_audio_codecs=flac/vorbis/dts
transcode_audio_transcoder=/usr/local/share/minidlna/transcodescripts/transcode_audio
transcode_video_transcoder=/usr/local/share/minidlna/transcodescripts/transcode_video

transcoding 스크립트는 /usr/local/share/minidlna/transcodescripts/ 아래에 있다. 옵션을 변경하고 싶다면 해당 스크립트를 수정한다. 옵션을 변경하지 않더라도 수정을 해주어야 하는데 ffmpeg 대신 avconv를 사용해야 하기 때문이다.

# vi /usr/local/share/minidlna/transcodescripts/transcode_audio

#!/bin/sh

SOURCE=$1
STARTPOSITION=$2
DURATION=$3

#ffmpeg -ss $STARTPOSITION -t $DURATION -i "$SOURCE" -loglevel quiet -acodec pcm_s16le -f s16le -ar 44100 pipe:1
avconv -ss $STARTPOSITION -t $DURATION -i "$SOURCE" -loglevel quiet -acodec libmp3lame -f mp3 -ar 44100 -ab 224k pipe:1

# vi transcodescripts/transcode_video

#!/bin/sh

SOURCE=$1
STARTPOSITION=$2
DURATION=$3

avconv -ss $STARTPOSITION -t $DURATION -i "$SOURCE" -loglevel quiet -threads auto -async 2 -target pal-dvd pipe:1

# vi transcodescripts/transcode_video-hq

#!/bin/sh

SOURCE=$1
STARTPOSITION=$2
DURATION=$3

avconv -ss $STARTPOSITION -t $DURATION -i "$SOURCE" -loglevel quiet -threads auto -async 2 -vcodec mpeg2video -b:v 20000k -f mpegts pipe:1

위와 같이 ffmpeg가 적힌 곳에 avconv를 써주면 된다.

이제 실행하려면 다음과 같이 한다. -R 옵션은 DB update를 해주는 거니까 매번 하진 말자.

/usr/local/sbin/minidlnad -R -f /etc/minidlna.conf

 

3. 자동 실행

매번 위처럼 실행하긴 귀찮으니까, 부팅될 때마다 자동 실행 되도록 하자. /etc/init.d/안에 minidlna 파일을 새로 생성해서 아래와 같이 내용을 채운다. Process가 2개 되는 경우가 보여서 참고로 보았던 글에 있는 스크립트를 좀 수정했다.  잘안되면, 뭐 또 수정해야지..

# vi /etc/init.d/minidlna

#!/bin/bash
# Mini DLNA
### BEGIN INIT INFO
# Provides:          scriptname
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO

case "$1" in
'start')
        /usr/local/sbin/minidlnad -f /etc/minidlna.conf
        echo Started
        ;;
'stop')
        PIDS=`/bin/pidof minidlnad`
        if [ "${PIDS}" != "" ];
        then
                for PID in ${PIDS};
                do
                        kill -SIGTERM ${PID}
                done
        else
                echo Already Stopped
        fi
        ;;
'restart')
        PIDS=`/bin/pidof minidlnad`
        if [ "${PIDS}" != "" ];
        then
                for PID in ${PIDS};
                do
                        kill -SIGTERM ${PID}
                done
        fi
        /usr/local/sbin/minidlnad -f /etc/minidlna.conf
        echo Restarted
        ;;
'status')
        PID=`/bin/pidof minidlnad`
        if [ "${PID}" != "" ];
        then
                echo Running. Process ${PID}
        else
                echo Stopped
        fi
        ;;
'rescan')
        PIDS=`/bin/pidof minidlnad`
        if [ "${PIDS}" != "" ];
        then
                for PID in ${PIDS};
                do
                        kill -SIGTERM ${PID}
                done
        fi
        /usr/local/sbin/minidlnad -R -f /etc/minidlna.conf
        echo Rescanning
        ;;
*)
        echo "Usage: $0 { start | stop | restart | status | rescan }"
        ;;
esac
exit 0

위 파일에 실행 권한을 주자.

# chmod a+x /etc/init.d/minidlna

실행되도록 rc.d를 업데이트 하자.

# sudo update-rc.d minidlna defaults

 

참고:

https://www.htpcbeginner.com/install-minidlna-on-ubuntu-ultimate-guide/

[C/C++] Variadic function의 default argument promotion

C/C++에서 함수에 가변 인자를 사용할 때, 그 parameter의 타입을 컴파일러가 알 수 없기 때문에, 컴파일러가 좀 쉽게 알 수 있도록, int보다 작은 타입은 int 혹은 unsigned int로, float은 double로 promotion이 일어난다고 한다.

이를 무시하고, va_start(), va_args() 매크로를 사용하면, undefined behavior이다.

[RaspberryPi] NAS 설치 시 참고글

NAS를 어떻게 구축할까, OpenMediaVault를 쓸까, Raspbian 위에 그냥 만들까, 그러려면 뭘 깔아야 하나 찾다가 찾은 글.

http://www.spacek.xyz/mle/?p=357

뭘 설치했는지 꽤 잘 나와 있다. 좀 해보다 별로면 OpenMediaVault로 이미지 바꿔보지 뭐.

쓸만한 글을 찾을 때마다 이 글을 업데이트하겠다.

 

[QuickBuild] RESTful API로 빌드 요청

QuickBuild를 이용할 때, 굳이 사이트에 접속해서 빌드를 돌리지 않아도 RESTful API를 이용하면 빌드를 걸 수 있다.

http://wiki.pmease.com/display/QB61/Interact+with+Build+Requests#InteractwithBuildRequests-requestnewbuild 에 해당 내용이 정리되어 있다.

Basic authentication 시에 curl을 이용해서 요청하는 방법은 다음과 같다.

$ curl -X POST -u dasomoli:password -d@request.xml http://<Server>:8810/rest/build_requests

위의 예제에서 사용한 request.xml 은 다음의 형식을 가진다. <varlables> 안에 채울 내용은 해당 configuration에서 실행한 빌드의 variables(http://<Server>:8810/build/<Build id>/variables) 페이지에서 확인 가능하다.

<com.pmease.quickbuild.BuildRequest>
  <!-- This element tells QuickBuild in what configuration to trigger build. -->
  <configurationId>10</configurationId>

  <!-- This element tells whether or not to respect build condition of the configuration. 
       If this is set to true, and if the build condition evaluates to false, build will 
       not be triggered. -->
  <respectBuildCondition>false</respectBuildCondition>

  <!-- This element is optional and is used to specify variables for build triggering. If 
       specified, it will override the variable with the same name defined in configuration
       basic setting. -->
  <variables>
    <entry>
      <string>var_name1</string>
      <string>var_value1</string>
    </entry>
    <entry>
      <string>var_name2</string>
      <string>var_value2</string>
    </entry>
  </variables>

  <!-- This element is optional and is used to tell QuickBuild to request a build promotion. -->
  <promotionSource>

    <!-- This element is optional and is used to tell QuickBuild that the source build resides on another 
         QuickBuild server. -->
    <server>
      <url>http://another-qb-server:8810</url>
      <userName>admin</userName>
      <password>admin</password>
    </server>

    <!-- Identifier of the source build to promote from -->
    <buildId>697</buildId>

    <!-- This element is optional and used to specify files to promote -->
    <deliveries>
      <com.pmease.quickbuild.FileDelivery>
        <srcPath>artifacts/dir1</srcPath>
        <filePatterns>**/*.jar</filePatterns>
      </com.pmease.quickbuild.FileDelivery>
      <com.pmease.quickbuild.FileDelivery>
        <srcPath>artifacts/dir2</srcPath>
        <filePatterns>**/*.war</filePatterns>
      </com.pmease.quickbuild.FileDelivery>
    </deliveries>
  </promotionSource>

</com.pmease.quickbuild.BuildRequest>

Sample XML의 comment에서 확인할 수 있듯이 <promotionSource>내부는 생략 가능하다.

[RaspberryPi] USB Port control

24시간 내내 돌리면 라즈베리 파이가 너무 뜨거울 것 같아서 USB 선풍기를 포트에 연결하고, 이걸 껐다 켰다 하려고 시도했다. 결론적으론 다른 USB 기기를 쓰지 않는다면, 전체 USB 포트를 껐다 켜는 방식으로 가능하다. 다른 USB 기기를 사용한다면, 실패. 아직 디바이스 드라이버에 커널 컴파일까진 시도하고 싶지 않다.

https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=93463 쓰레드를 참고하면, hub-ctrl을 이용하면, 전체 포트 혹은 개별 포트를 껐다 켰다 하는 것을 할 수 있다.  그러나 개별 포트를 끄는 게, 실제 VBUS 전원까지 내리는 건 아니고, 그냥 못쓰게 할 뿐이다. 그래서, 전체 포트를 끄지 않는 한, 개별 포트를 꺼도 해당 포트 VBUS는 살아있기 때문에 USB 선풍기는 계속 돈다-_-;;

다음은 usb-ctrl의 설치 및 사용 방법이다.

라즈베리 파이에서 다음을 설치한다.

# apt-get install libusb-dev

다음으로 바이너리를 만든다.

# apt-get install git gcc
# git clone https://github.com/codazoda/hub-ctrl.c
# gcc -o hub-ctrl hub-ctrl.c -lusb

만든 바이너리를 적당한 곳(예를 들면, /usr/sbin/)에 설치한다.

# cp hub-ctrl /usb/sbin/

나의 경우 한 시간에 한번 정도, 50초 정도 돌게 하고 싶었다. /etc/cron.hourly 아래에 다음과 같은 스크립트를 만들어 실행 권한을 준다.

# vi /etc/cron.hourly/coolingusbfan
#!/bin/sh
hub-ctrl -h 0 -P 2 -p 1; sleep 50; sudo hub-ctrl -h 0 -P 2 -p 0

참고로, 다음 그림과 같이 포트 번호를 붙인다면,

라즈베리 파이 3 Model B의 경우, 다음과 같다고 한다.

Hub:Port — Controlled port(s)
0:1 — Controls the Ethernet port
0:2 — Controls all four USB ports (not the Ethernet)
0:3 — Controls USB Port 4
0:4 — Controls USB Port 2
0:5 — Controls USB Port 3

NAS를 위해, 외장 하드를 붙일 거라 이제 더는 위 스크립트를 사용하지 못한다.

‘진짜배기 코드 평가자라면 하지 말아야 할 네 가지’를 읽고

개인의 경우는 대체적으로 설득 가능하다. 그러나, 모든 팀원이 그래서 모두를 설득해야 한다면, 팀 혹은 회사 차원의 문제다. 이런 경우, 개인을 설득하려 해도, “다들 그래요”, “그게 여기서 되겠어요?”, “그거 한다고 안바뀌어요”, “당신 때문에 내 코드가 못들어가고 있어요. 오늘 릴리즈인데, 당신이 책임질거요?” 따위의 말이나 듣는다. ‘협업 안되는 사람’이 되고.

내가 아는 어떤 회사가 그랬다. 요즘은 좀 바꾸려고 하는 것 같던데, 이런 사람들이 위에서 때리면, 제일 먼저 자기는 안그런다 하더라.

만약 당신이 동료를 향해 신경쓰이는 기분이 든다면 회사 혹은 팀의 경영 측면에서 문제가 있는 겁니다.

(번역) 진짜배기 코드 평가자라면 하지 말아야 할 네 가지

[Eclipse] Source code Navigation 단축키

Eclipse는 내부적으로 Indexer가 돌아서 이를 이용해 찾고 싶은 File, Funtion decalaration/definition, symbol 등을 찾을 수 있다. 내가 자주 쓰는 단축키는 다음과 같다.

  • F3: Funtion declaratiin/definition. 함수 선언이나, 함수 정의로 이동하고 싶을 때 사용한다.
  • Alt + ‘<-‘: 이전 코드. 이전에 보던 부분으로 돌아갈 때 사용한다.
  • Ctrl + Shift + ‘R’: File name 찾아서 열기. 파일 이름을 알 때, 혹은 앞 몇글자만 기억날 때, 찾아서 연다.
  • Ctrl + Shift + ‘G’: Workspace에서 Reference 찾기. 함수 호출되는 부분을 찾고 싶을 때 사용한다.
  • Ctrl + ‘H’: Search. 주로 File Search를 이용한다. Scope을 셋팅해서 쓰는 것도 좋다.
  • Ctrl + Alt + ‘G’: Workspace에서 Text 찾기. Ctrl + ‘H’ 대신 사용하기도 한다.
  • Ctrl + ‘O’: Quick Outline. 주로 함수를 찾아 이동할 때 사용한다.

HTML 자동 이동 – meta refresh

<html>

<head>

<meta http-equiv=”refresh” content=”0; url=./index.php”>

</head>

<body onload=”javascript:window.location=’./index.php'”>

Please follow <a href=”index.php”>this link</a>

</body>

</html>

참고: https://en.m.wikipedia.org/wiki/Meta_refresh

git worktree

git worktree add <path> <branch>

하나의 git repository로 체크 아웃을 한군데 하는게 아니라 여러군데에 하고 싶을 때 쓴다. 브랜치를 아예 물리적으로 다른 경로로 나누어서 작업하고 싶을 때라던지 용도는 매우 다양하다.