網頁

2022年11月25日 星期五

Jetpack L4T 35.1.0 風扇

jtop 無法在這個版本控制和查看 風扇

$ vi get_fan.sh
TEMP=`cat /sys/class/hwmon/hwmon0/temp1_input`
TEMP=$(echo "scale=2; ${TEMP}/1000" | bc)
echo Thermal=${TEMP}C

PWM=`cat /sys/class/hwmon/hwmon2/pwm1`
RPM=`cat /sys/class/hwmon/hwmon1/rpm`
echo FAN=$(( PWM * 100 / 255 ))% ${RPM}rpm


2022年11月24日 星期四

Ubuntu 開關(當)機相關命令

顯示 Linux 開機資訊指令
dmesg -T

顯示系統關機記錄和運行級別改變的日誌
last -x

/var/log/syslog
/var/log/syslog.1
The system log typically contains the greatest deal of information by default about your Ubuntu system.

2022年10月25日 星期二

tensorflow predict memory leak

記憶體越吃越多,直到系統當機
$ top
可看到 VIRT RES 越來越大
$ jtop
看到 Mem 也隨時間越來越大

查詢目前程式占用的記憶體
import psutil
psutil.Process().memory_info().rss / (1024*1024*1024),
psutil.Process().memory_info().vms / (1024*1024*1024),

查詢目前程式碼使用記憶體狀況
from memory_profiler import profile
@profile(precision=4,stream=open('memory_profiler.log','w+'))
def function()
@profile # 直接在 stdout 輸出
def function()
但是看不出所以然

網路上常說因為 numpy 到 tensor 轉換的原因
state = tf.convert_to_tensor(state)
model.predict(state)
state = tf.convert_to_tensor(state)
model.fit(states)
但是沒有用

垃圾收集
import gc
gc.collect()
但是也沒有用

最後一招,有用
import tensorflow as tf
tf.keras.backend.clear_session()

2022年10月20日 星期四

gym tensorflow 衝突

env.render()
出現錯誤
    from pyglet.gl import *
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/gl/__init__.py", line 243, in <module>
    import pyglet.window
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/window/__init__.py", line 1897, in <module>
    gl._create_shadow_window()
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/gl/__init__.py", line 220, in _create_shadow_window
    _shadow_window = Window(width=1, height=1, visible=False)
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/window/xlib/__init__.py", line 173, in __init__
    super(XlibWindow, self).__init__(*args, **kwargs)
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/window/__init__.py", line 595, in __init__
    config = screen.get_best_config(template_config)
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/canvas/base.py", line 192, in get_best_config
    configs = self.get_matching_configs(template)
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/canvas/xlib.py", line 220, in get_matching_configs
    configs = template.match(canvas)
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/gl/xlib.py", line 58, in match
    have_13 = info.have_version(1, 3)
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/pyglet/gl/glx_info.py", line 86, in have_version
    client_version = self.get_client_version().split()[0]
IndexError: list index out of range


解決方案為 env.render() 後才能 import tensorflow
import gym
env = gym.make("CartPole-v0")
env.render()
import tensorflow as tf

python 出現 cannot allocate memory in static TLS block

其實會出現這個問題是 gym tensorflow 衝突 原因
解決這個問題,就部會出現下列問題

OSError: /usr/lib/xxxx/libxxxx.so.0: cannot allocate memory in static TLS block

解決方法為
$ export LD_PRELOAD=/usr/lib/xxxx/libxxxx.so.0:$LD_PRELOAD

tensorflow 在 Xavier 出現 cannot allocate memory in static TLS block 錯誤

其實會出現這個問題是 gym tensorflow 衝突 原因
解決這個問題,就部會出現下列問題

Traceback (most recent call last):
  File "/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/tensorflow/python/pywrap_tensorflow.py", line 62, in <module>
    from tensorflow.python._pywrap_tensorflow_internal import *
ImportError: /home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/tensorflow/python/../../tensorflow_cpu_aws.libs/libgomp-d22c30c5.so.1.0.0: cannot allocate memory in static TLS block

$ vi .bashrc
export LD_PRELOAD=/home/UserName/envs/tf2.10.0/lib/python3.8/site-packages/tensorflow/python/../../tensorflow_cpu_aws.libs/libgomp-d22c30c5.so.1.0.0

2022年10月19日 星期三

安裝 Xavier JetPack 5.0.2

Download NVIDIA SDK Manager 1.8.4
https://developer.nvidia.com/nvidia-sdk-manager
選擇 .deb Ubuntu
$ sudo dpkg -i sdkmanager_1.8.4-10431_amd64.deb
[sudo] password for mark: 
Selecting previously unselected package sdkmanager.
(Reading database ... 340238 files and directories currently installed.)
Preparing to unpack sdkmanager_1.8.4-10431_amd64.deb ...
Unpacking sdkmanager (1.8.4-10431) ...
dpkg: dependency problems prevent configuration of sdkmanager:
 sdkmanager depends on libgconf-2-4; however:
  Package libgconf-2-4 is not installed.
 sdkmanager depends on libcanberra-gtk-module; however:
  Package libcanberra-gtk-module is not installed.

dpkg: error processing package sdkmanager (--install):
 dependency problems - leaving unconfigured
Processing triggers for gnome-menus (3.13.3-11ubuntu1.1) ...
Processing triggers for desktop-file-utils (0.23-1ubuntu3.18.04.2) ...
Processing triggers for mime-support (3.60ubuntu1) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Errors were encountered while processing:
 sdkmanager
出錯,使用下列命令修正
$ sudo apt --fix-broken install
$ sdkmanager
ADDITIONAL SDKS/DeepStream 要打勾
按 CONTINUE TO STEP 02
勾選 I accept the terms and conditions of the license aggrements
按 CONTINUE TO STEP 03
選擇 Manual Setup = Jetson AGX Xavier

角落起算
1. Power Button
2. Force Recovery Button
3. Reset Button

將 xavier 40-Pin 邊的(電源指示燈旁的) USB 連接至安裝主機
關機後先壓工程模式鍵(Recovery)再同時按壓電源鍵(Power),兩秒後放開進入工程模式

開啟螢幕,等待 Xavier 安裝完成開啟登入畫面
不用登入,按下 Install,繼續等待


$ sudo apt-get install python3-pip
$ sudo -H pip3 install jetson-stats
$ sudo systemctl restart jetson_stats.service
$ sudo jtop
$ sudo vi /etc/nvfancontrol.conf
        FAN_PROFILE full {
                #TEMP   HYST    PWM     RPM
                0       8       255     3640
                140     0       255     3640
        }
FAN_DEFAULT_PROFILE quite
FAN_DEFAULT_PROFILE cool

$ sudo systemctl stop nvfancontrol.service
$ sudo rm /var/lib/nvfancontrol/status
$ sudo vi /etc/nvfancontrol.conf
$ sudo systemctl start nvfancontrol.service
$ sudo cat /var/lib/nvfancontrol/status

$ sudo apt update
$ mkdir -p ~/.config/autostart
$ cp /usr/share/applications/vino-server.desktop ~/.config/autostart/
$ gsettings set org.gnome.Vino prompt-enabled false
$ gsettings set org.gnome.Vino require-encryption false
$ gsettings set org.gnome.Vino prompt-enabled false
$ gsettings set org.gnome.Vino require-encryption false
$ gsettings set org.gnome.Vino authentication-methods "['vnc']"
$ gsettings set org.gnome.Vino vnc-password $(echo -n 'ChangeToYourPasswd'|base64)
$ sudo vi /etc/gdm3/custom.conf
WaylandEnable=false
AutomaticLoginEnable = true
AutomaticLogin = UserLoginName

但發現 vino 比 x11vnc 慢,所以刪除 vino-server.desktop, 回復 custom.conf,改安裝 x11vnc
$ sudo apt-get install x11vnc
$ x11vnc -storepasswd
$ vi x11vnc_0.sh #其中124為gdm的user id, 可在 /etc/passwd 查詢
sudo /usr/bin/x11vnc -display :0 -auth /var/run/user/124/gdm/Xauthority -rfbauth /home/UserName/.vnc/passwd
$ cat x11vnc_1.sh
DISP=`ps -u $(id -u) -o pid= | \
    while read pid; do
        cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | grep '^DISPLAY=:'
    done | grep -o ':[0-9]*' | sort -u`
DISPLAY=$DISP x11vnc -rfbport 5900 -rfbauth /home/UserName/.vnc/passwd
$ chmod +x x11vnc_0.sh x11vnc_1.sh
$ ./x11vnc_0.sh
使用 vnc client 登入,並輸入使用者名稱和密碼,然後變成黑畫面
別擔心此時主機已經登入,直接關閉 vnc client
$ ./x11vnc_1.sh
在使用一次 vnc client 登入即可

$ sudo apt-get install xserver-xorg-video-dummy
$ sudo vi /etc/X11/xorg.conf
Section "Module"
    Disable     "dri"
    SubSection  "extmod"
    Option  "omit xfree86-dga"
    EndSubSection
EndSection

Section "Device"
    Identifier  "Tegra0"
    Driver      "nvidia"
    # 必須改成 false, 否則未接螢幕時, vino 會顯示 nvidia 的 long
    Option      "AllowEmptyInitialConfiguration" "false"
EndSection

Section "ServerFlags"
    Option "AutoAddGPU" "false"
EndSection

Section "Screen"
    Identifier  "Nvidia Screen"
    Device      "Tegra0"
EndSection

Section "Device"
    Identifier  "Dummy Video Device"
    Driver      "dummy"
    VideoRam    256000
EndSection

Section "Monitor"
    Identifier  "Dummy Monitor"
    HorizSync   5.0-1000.0
    VertRefresh 5.0-200.0
    Modeline    "1920x1080" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
EndSection

Section "Screen"
    Identifier  "Dummy Screen"
    Monitor     "Dummy Monitor"
    Device      "Dummy Video Device"
    SubSection  "Display"
        Depth   24
        Virtual 1920 1080
    EndSubSection
EndSection

Section "ServerLayout"
    Identifier "Main Layout"
    Screen 0 "Nvidia Screen"
    Screen 1 "Dummy Screen"
EndSection

vi vino.sh
#!/bin/bash

### BEGIN INIT INFO
# Provides:          vino-server
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Should-Start:
# Should-Stop:
# X-Start-Before:
# X-Stop-After:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: vino-server
### END INIT INFO

PIDFILE="/tmp/vino-server.pid"
NAME="vino-server"
GREPFILTER="/usr/lib/vino/vino-server"

service_kill() {

       ### kill -9
       PIDS="`ps aux |grep -v grep |grep -P "${GREPFILTER}" |awk '{print $2}' | tr '\n' ' ' `"
       if [ -n "$PIDS" ]; then
           echo "sleep 5"
           sleep 5
           PIDS="`ps aux |grep -v grep |grep -P "${GREPFILTER}" |awk '{print $2}' | tr '\n' ' ' `"
           if [ -n "$PIDS" ]; then
               echo "kill -9 ${PIDS}"
               kill -9 ${PIDS}
           fi
       fi
       if [ -f ${PIDFILE} ]; then
           echo "rm ${PIDFILE}"
           rm ${PIDFILE}
       fi
}

service_status() {
       PID="`cat ${PIDFILE}`"
       if [ -n "$PID" ]; then
           echo "${PIDFILE} : ${PID}"
       else
           echo "file doesnt' exist : ${PIDFILE}"
       fi
       PIDS="`ps aux |grep -v grep |grep -P "${GREPFILTER}" |awk '{print $2}' | tr '\n' ' ' `"
       if [ -n "$PIDS" ]; then
           echo "PROCESSES:"
           echo "$PIDS"
       fi
}

service_start() {
       PIDS="`ps aux |grep -v grep |grep -P "${GREPFILTER}" |awk '{print $2}' | tr '\n' ' ' `"
       if [ -n "$PIDS" ]; then
            echo "process is present : ${PIDS}"
            echo $PIDS > ${PIDFILE}
            chmod 644 ${PIDFILE}
            exit 0
       else

            gconftool-2 -s -t bool /desktop/gnome/remote_access/enabled true
            gconftool-2 --type bool --set /desktop/gnome/remote_access/prompt_enabled 0
            export DISPLAY=:0.0
            /usr/lib/vino/vino-server --sm-disable &

            sleep 2

            PIDS="`ps aux |grep -v grep |grep -P "${GREPFILTER}" |awk '{print $2}' | tr '\n' ' ' `"
            if [ -n "$PIDS" ]; then
                 echo "$PIDS"
                 echo $PIDS > ${PIDFILE}
                 chmod 644 ${PIDFILE}
            fi
       fi
}
service_stop() {
       PIDS="`ps aux |grep -v grep |grep -P "${GREPFILTER}" |awk '{print $2}' | tr '\n' ' ' `"
       if [ -n "$PIDS" ]; then
           echo "kill ${PIDS}"
           kill ${PIDS}
       fi
       if [ -f ${PIDFILE} ]; then
           echo "rm ${PIDFILE}"
           rm ${PIDFILE}
       fi
}

case $1 in
   start)
     service_start;;
   stop)
     service_stop;
     service_kill;;
   kill)
     service_kill;;
   restart)
     service_stop;
     service_start;;
   status)
     service_status;;
   *)
     echo "usage: $0 {start|stop|kill|restart|status}" ;
     echo "example: $0 start" ;
esac
exit 0

Mount Disks
按左下角 Show Applications, 輸入 Disks
按下 Disks
選擇左側儲存裝置
按設定按鈕,選擇 Edit Mount Options
User Session Defaults 選擇 OFF
輸入 Mount Point
按下 Mount selected partition

2022年9月15日 星期四

OpenAI Gym

OpenAI Gym 目前進到 v0.21.0, 改使用 python 3.7, 導致很多舊程式無法使用
$ pip install gym==v0.20.0
$ pip install pygame

出現下列錯誤
AttributeError: module 'ale_py.gym' has no attribute 'ALGymEnv'
$ pip install ale-py==0.7

出現找不到遊戲 rom
$ pip install autorom
$ AutoROM

在 Xavier 上
$ pip install gym==v0.19.0
$ pip install gym[atari]

2022年8月1日 星期一

VLC 3.0.17.4 之 LIBVLC 新增錄影功能

參考 Add new API to libvlc to record the current media to either an application-specified file or a file automatically created by vlc

建立 git patch
$ sudo git diff HEAD
$ sudo git status
$ sudo git diff HEAD include/vlc/libvlc_events.h
$ sudo git add include/vlc/libvlc_events.h
$ sudo git diff HEAD include/vlc/libvlc_media_player.h
$ sudo git add include/vlc/libvlc_media_player.h
$ sudo git diff HEAD lib/event.c
$ sudo git add lib/event.c
$ sudo git diff HEAD lib/libvlc.sym
$ sudo git add lib/libvlc.sym
$ sudo git diff HEAD lib/media_player.c
$ sudo git add lib/media_player.c
$ sudo git diff HEAD modules/logger/file.c
$ sudo git add modules/logger/file.c
$ sudo git diff HEAD modules/spu/marq.c
$ sudo git add modules/spu/marq.c
$ sudo git diff HEAD modules/stream_out/record.c
$ sudo git add modules/stream_out/record.c
$ sudo git diff HEAD src/input/input.c
$ sudo git add src/input/input.c
$ sudo git diff HEAD src/input/var.c
$ sudo git add src/input/var.c
$ sudo git diff HEAD src/text/strings.c
$ sudo git add src/text/strings.c
$ sudo git diff HEAD src/video_output/vout_subpictures.c
$ sudo git add src/video_output/vout_subpictures.c

$ sudo git commit -m "add record function"
$ sudo git format-patch -1 -o ../patch
$ sudo git apply ../patch/0001-libvlc-add-record-function.patch

$ sudo git log
$ sudo git checkout c650ce1a4e352c

=======
From 6917e3862fdbd2ae7b411ca6d15ce15644b4e5c8 Mon Sep 17 00:00:00 2001
From: root <ingrenn@yahoo.com.tw>
Date: Thu, 4 Aug 2022 11:33:50 +0800
Subject: [PATCH] libvlc add record function

---
 include/vlc/libvlc_events.h         |  10 +++
 include/vlc/libvlc_media_player.h   | 115 ++++++++++++++++++++++++++++
 lib/event.c                         |   3 +
 lib/libvlc.sym                      |   4 +
 lib/media_player.c                  | 114 ++++++++++++++++++++++++++-
 modules/logger/file.c               |  13 +++-
 modules/spu/marq.c                  |   1 +
 modules/stream_out/record.c         |  20 +++++
 src/input/input.c                   |   8 +-
 src/input/var.c                     |   3 +
 src/text/strings.c                  |  56 +++++++++++++-
 src/video_output/vout_subpictures.c |   4 +-
 12 files changed, 344 insertions(+), 7 deletions(-)

diff --git a/include/vlc/libvlc_events.h b/include/vlc/libvlc_events.h
index f8b0e9b5b2..0e2b4d668b 100644
--- a/include/vlc/libvlc_events.h
+++ b/include/vlc/libvlc_events.h
@@ -86,6 +86,8 @@ enum libvlc_event_e {
     libvlc_MediaPlayerAudioVolume,
     libvlc_MediaPlayerAudioDevice,
     libvlc_MediaPlayerChapterChanged,
+    libvlc_MediaPlayerRecordableChanged,
+    libvlc_MediaPlayerRecordingFinished,
 
     libvlc_MediaListItemAdded=0x200,
     libvlc_MediaListWillAddItem,
@@ -283,6 +285,14 @@ typedef struct libvlc_event_t
         {
             libvlc_renderer_item_t *item;
         } renderer_discoverer_item_deleted;
+        struct
+        {
+            int new_recordable;
+        } media_player_recordable_changed;
+        struct
+        {
+            char *psz_filename;
+        } media_player_recording_finished;
     } u; /**< Type-dependent event description */
 } libvlc_event_t;
 
diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
index c431c235e9..1f664b86a6 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -2082,6 +2082,121 @@ LIBVLC_API int libvlc_media_player_set_role(libvlc_media_player_t *p_mi,
 
 /** @} audio */
 
+/**
+ * Can the media player record the current media?
+ *
+ * Media must be buffering or playing before it can be recorded.
+ *
+ * The media player event manager will emit a libvlc_MediaPlayerRecordableChanged event
+ * when the recordable state changes after starting media playback. The event data will
+ * describe the new recordable state, so invocation of this API method is not strictly
+ * necessary to determine when recording can be started.
+ *
+ * A libvlc_MediaPlayerRecordableChanged event will not be emitted if the media is
+ * stopped (notified by a libvlc_MediaPlayerStoppedEvent) or finishes normally (notified
+ * by a libvlc_MediaPlayerFinished event).
+ *
+ * A calling application should therefore register an event callback for those events
+ * so that it may query the new recordable state and manage recording at the appropriate
+ * time.
+ *
+ * \param p_mi media player
+ * \return true if the media player can record, false if it can not
+ * \version LibVLC 2.1.0 or later
+ */
+LIBVLC_API bool libvlc_media_player_is_recordable( libvlc_media_player_t *p_mi );
+
+/**
+ * Is the current media being recorded?
+ *
+ * \param p_mi media player
+ * \return true if recording, false if not
+ * \version LibVLC 2.1.0 or later
+ */
+LIBVLC_API bool libvlc_media_player_is_recording( libvlc_media_player_t *p_mi );
+
+/**
+ * Start recording the current media.
+ *
+ * Media must be buffering or playing before it can be recorded. A calling application
+ * can begin recording immediately on receipt of a libvlc_MediaPlayerRecordableChanged
+ * event sent via the media player event manager (if recording is possible for the
+ * currently playing media), and any time thereafter until the media stops.
+ *
+ * Media will be saved to the file path denoted by the psz_filename parameter if it is
+ * supplied. Any such supplied filename should not include a file extension as the
+ * correct file extension will automatically be appended when the file is created. This
+ * filename may denote a full path name, but each directory in the path must already
+ * exist or recording will silently fail. If the calling application chooses to specify
+ * the filename then it is the responsibility of that application to take account of
+ * this and itself make sure any needed directories are created.
+ *
+ * Alternatively, a calling application need not supply a filename and so instead let
+ * vlc automatically generate a unique filename. This will cause vlc to create a new
+ * file in the appropriate media directory for the user - for example "~/Videos". The
+ * actual filename used will be sent in an event when the recording is complete.
+ *
+ * When recording has finished and the new file has been completely saved, a
+ * libvlc_MediaPlayerRecordingFinished event will be sent via the media player event
+ * manager. The event data will contain the filename of the newly recorded file - this
+ * will either be the filename as specified by the calling application or a filename
+ * generated by vlc if the application did not supply a filename. In either case, this
+ * filename will include the automatically appended file extension.
+ *
+ * The saved media file will not be immediately available or visible until recording
+ * has completely finished and the libvlc_MediaPlayerRecordingFinished event has been
+ * received, or the media has stopped or finished normally.
+ *
+ * Recording can be stopped and started on-the-fly once the recordable state is set;
+ * each time recording is stopped and restarted a new file will be created so a calling
+ * application should take care to provide unique filenames, or defer to vlc to create
+ * unique filenames.
+ *
+ * Recording will be stopped when the media stops playing, and must be explicitly
+ * started again to restart recording, i.e. the recording state is not automatically
+ * preserved when playing media subsequently.
+ *
+ * Media player functionailty such as next/previous chapter, set time or position and
+ * so on are ineffective when recording is enabled. However, pausing the media is
+ * possible and will pause the recording; unpausing the media will resume playback and
+ * recording.
+ *
+ * Recording of the primary media or sub-items is possible.
+ *
+ * \param p_mi media player
+ * \param psz_filename name of the file to save the media to, not including any file extension,
+ *                     or NULL if vlc should generate the filename automatically
+ * \return 0 if recording was started, -1 on error
+ * \version LibVLC 2.1.0 or later
+ */
+LIBVLC_API int libvlc_media_player_record_start( libvlc_media_player_t *p_mi, const char *psz_filename );
+
+/**
+ * Stop recording the current media.
+ *
+ * This method requests that the recording stop, and will return immediately. Recording
+ * will not stop immediately.
+ *
+ * When the recording actually stops some short time later and the new file has
+ * finished being written, a libvlc_MediaPlayerRecordingFinished event will be sent via
+ * the media player event manager. The newly recorded file will not be visible or
+ * available until after this event has been sent.
+ *
+ * The event data will contain the full name of the file that was created. The filename
+ * will either be that as was specified by the calling application on invoking
+ * libvlc_media_player_record_start(), or the filename that vlc automatically generated
+ * if the calling application did not supply its own filename. In either case the
+ * filename will contain the automatically appended file extension.
+ *
+ * There is no need to invoke this method to stop the recording if the media is stopped
+ * or finishes playing normally.
+ *
+ * \param p_mi media player
+ * \return 0 if recording was stopped, -1 on error
+ * \version LibVLC 2.1.0 or later
+ */
+LIBVLC_API int libvlc_media_player_record_stop( libvlc_media_player_t *p_mi );
+
 /** @} media_player */
 
 # ifdef __cplusplus
diff --git a/lib/event.c b/lib/event.c
index f027754181..dba8a55a86 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -173,6 +173,9 @@ static const event_name_t event_list[] = {
     DEF(MediaPlayerAudioVolume)
     DEF(MediaPlayerAudioDevice)
     DEF(MediaPlayerChapterChanged)
+    DEF(MediaPlayerRecordableChanged)
+    DEF(MediaPlayerRecordingFinished)
+
 
     DEF(MediaListItemAdded)
     DEF(MediaListWillAddItem)
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index 482d95f6f1..dbcc49a7ad 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -175,6 +175,8 @@ libvlc_media_player_get_title
 libvlc_media_player_get_title_count
 libvlc_media_player_get_xwindow
 libvlc_media_player_has_vout
+libvlc_media_player_is_recordable
+libvlc_media_player_is_recording
 libvlc_media_player_is_seekable
 libvlc_media_player_is_playing
 libvlc_media_player_new
@@ -184,6 +186,8 @@ libvlc_media_player_set_pause
 libvlc_media_player_pause
 libvlc_media_player_play
 libvlc_media_player_previous_chapter
+libvlc_media_player_record_start
+libvlc_media_player_record_stop
 libvlc_media_player_release
 libvlc_media_player_retain
 libvlc_media_player_set_agl
diff --git a/lib/media_player.c b/lib/media_player.c
index fda1091cc8..43ac2d8154 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -54,6 +54,11 @@ input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval,
                         void * p_userdata );
 static int
+input_recordable_changed( vlc_object_t *p_this, char const *psz_cmd,
+                          vlc_value_t oldval, vlc_value_t newval,
+                          void *p_userdata );
+
+static int
 input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval,
                         void * p_userdata );
@@ -89,6 +94,10 @@ static int
 snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,
                     vlc_value_t oldval, vlc_value_t newval, void *p_data );
 
+static int
+file_recording_finished( vlc_object_t *p_this, char const *psz_cmd,
+                         vlc_value_t oldval, vlc_value_t newval, void *p_data );
+
 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
 
 /*
@@ -174,6 +183,8 @@ static void release_input_thread( libvlc_media_player_t *p_mi )
                      input_seekable_changed, p_mi );
     var_DelCallback( p_input_thread, "can-pause",
                     input_pausable_changed, p_mi );
+    var_DelCallback( p_input_thread, "can-record",
+                     input_recordable_changed, p_mi );
     var_DelCallback( p_input_thread, "program-scrambled",
                     input_scrambled_changed, p_mi );
     var_DelCallback( p_input_thread, "intf-event",
@@ -271,6 +282,25 @@ input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
     return VLC_SUCCESS;
 }
 
+static int
+input_recordable_changed( vlc_object_t *p_this, char const *psz_cmd,
+                          vlc_value_t oldval, vlc_value_t newval,
+                          void *p_userdata )
+{
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(psz_cmd);
+    VLC_UNUSED(oldval);
+
+    libvlc_media_player_t *p_mi = p_userdata;
+    libvlc_event_t event;
+
+    event.type = libvlc_MediaPlayerRecordableChanged;
+    event.u.media_player_recordable_changed.new_recordable = newval.b_bool;
+
+    libvlc_event_send( &p_mi->event_manager, &event );
+    return VLC_SUCCESS;
+}
+
 static int
 input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval,
@@ -529,6 +559,23 @@ static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd,
     return VLC_SUCCESS;
 }
 
+static int file_recording_finished(vlc_object_t *p_this, char const *psz_cmd,
+                                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED(p_this);
+    VLC_UNUSED(psz_cmd);
+    VLC_UNUSED(oldval);
+
+    libvlc_media_player_t *p_mi = p_data;
+    libvlc_event_t event;
+
+    event.type = libvlc_MediaPlayerRecordingFinished;
+    event.u.media_player_recording_finished.psz_filename = newval.psz_string;
+
+    libvlc_event_send( &p_mi->event_manager, &event);
+    return VLC_SUCCESS;
+}
+
 static int corks_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
                          vlc_value_t cur, void *opaque)
 {
@@ -620,6 +667,10 @@ libvlc_media_player_new( libvlc_instance_t *instance )
     /* Input */
     var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
     var_Create (mp, "sout", VLC_VAR_STRING);
+    char *psz = var_GetNonEmptyString( instance->p_libvlc_int, "sout" );
+    if (psz) {
+        var_SetString(mp, "sout", psz);
+    }
     var_Create (mp, "demux-filter", VLC_VAR_STRING);
 
     /* Video */
@@ -713,6 +764,8 @@ libvlc_media_player_new( libvlc_instance_t *instance )
     var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
     var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
     var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+    var_Create (mp, "recording-finished", VLC_VAR_STRING);
+    var_AddCallback (mp, "recording-finished", file_recording_finished, mp);
     var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
 
     /* Video Title */
@@ -807,7 +860,8 @@ static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
     /* Detach Callback from the main libvlc object */
     var_DelCallback( p_mi->obj.libvlc,
                      "snapshot-file", snapshot_was_taken, p_mi );
-
+    var_DelCallback( p_mi, "recording-finished", file_recording_finished, p_mi );
+                     
     /* Detach callback from the media player / input manager object */
     var_DelCallback( p_mi, "volume", volume_changed, NULL );
     var_DelCallback( p_mi, "mute", mute_changed, NULL );
@@ -997,6 +1051,7 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )
 
     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
+    var_AddCallback( p_input_thread, "can-record", input_recordable_changed, p_mi );
     var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
     add_es_callbacks( p_input_thread, p_mi );
@@ -1006,6 +1061,7 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )
         unlock_input(p_mi);
         del_es_callbacks( p_input_thread, p_mi );
         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
+        var_DelCallback( p_input_thread, "can-record", input_recordable_changed, p_mi );
         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
         var_DelCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
@@ -1932,6 +1988,62 @@ void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
     }
 }
 
+bool libvlc_media_player_is_recordable( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    bool b_can_record;
+
+    p_input_thread = libvlc_get_input_thread( p_mi );
+    if( !p_input_thread )
+        return false;
+
+    b_can_record = var_GetBool( p_input_thread, "can-record" );
+
+    vlc_object_release( p_input_thread );
+    return b_can_record;
+}
+bool libvlc_media_player_is_recording( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+    bool b_record;
+
+    p_input_thread = libvlc_get_input_thread( p_mi );
+    if( !p_input_thread )
+        return false;
+
+    b_record = var_GetBool( p_input_thread, "record" );
+
+    vlc_object_release( p_input_thread );
+    return b_record;
+}
+int libvlc_media_player_record_start( libvlc_media_player_t *p_mi, const char* psz_filename )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    var_SetString( p_input_thread, "input-record-path", psz_filename );
+    var_SetBool( p_input_thread, "record", true );
+
+    vlc_object_release( p_input_thread );
+    return 0;
+}
+int libvlc_media_player_record_stop( libvlc_media_player_t *p_mi )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread( p_mi );
+    if( !p_input_thread )
+        return -1;
+
+    var_SetBool( p_input_thread, "record", false );
+
+    vlc_object_release( p_input_thread );
+    return 0;
+}
+
 /**
  * Private lookup table to get subpicture alignment flag values corresponding
  * to a libvlc_position_t enumerated value.
diff --git a/modules/logger/file.c b/modules/logger/file.c
index 6b6dfd2973..80b1bb6066 100644
--- a/modules/logger/file.c
+++ b/modules/logger/file.c
@@ -58,8 +58,19 @@ static void LogText(void *opaque, int type, const vlc_log_t *meta,
     if (sys->verbosity < type)
         return;
 
+    struct timespec ts;
+    struct tm curtime;
+    char tmBuf[128];
+    timespec_get(&ts, TIME_UTC);
+    if (localtime_r(&ts.tv_sec, &curtime) == NULL) {
+        gmtime_r(&ts.tv_sec, &curtime);
+    }
+    if (strftime(tmBuf, sizeof(tmBuf), "%M%S", &curtime) == 0) {
+        strcpy(tmBuf, "no time");
+    }
+    
     flockfile(stream);
-    fprintf(stream, "%s%s: ", meta->psz_module, msg_type[type]);
+    fprintf(stream, "%s.%03d %s%s: ", tmBuf, (int)(ts.tv_nsec / 1000000), meta->psz_module, msg_type[type]);
     vfprintf(stream, format, ap);
     putc_unlocked('\n', stream);
     funlockfile(stream);
diff --git a/modules/spu/marq.c b/modules/spu/marq.c
index 516838ef63..ea7534ab74 100644
--- a/modules/spu/marq.c
+++ b/modules/spu/marq.c
@@ -287,6 +287,7 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
         }
     }
 
+    //msg_Dbg( p_filter, "mark: %s", p_sys->format );
     char *msg = vlc_strftime( p_sys->format ? p_sys->format : "" );
     if( unlikely( msg == NULL ) )
         goto out;
diff --git a/modules/stream_out/record.c b/modules/stream_out/record.c
index be10bb98c4..8f43e72261 100644
--- a/modules/stream_out/record.c
+++ b/modules/stream_out/record.c
@@ -110,6 +110,8 @@ struct sout_stream_sys_t
     int              i_id;
     sout_stream_id_sys_t **id;
     mtime_t     i_dts_start;
+    
+    char *psz_record_file;
 };
 
 static void OutputStart( sout_stream_t *p_stream );
@@ -157,6 +159,8 @@ static int Open( vlc_object_t *p_this )
     p_sys->b_drop = false;
     p_sys->i_dts_start = 0;
     TAB_INIT( p_sys->i_id, p_sys->id );
+    
+    p_sys->psz_record_file = NULL;
 
     return VLC_SUCCESS;
 }
@@ -172,6 +176,19 @@ static void Close( vlc_object_t * p_this )
     if( p_sys->p_out )
         sout_StreamChainDelete( p_sys->p_out, p_sys->p_out );
 
+    if( p_sys->psz_record_file ) {
+        for( vlc_object_t *p_mp = p_stream->obj.parent; p_mp; p_mp = p_mp->obj.parent )
+        {
+            if( var_Type( p_mp, "recording-finished" ) )
+            {
+                var_SetString( p_mp, "recording-finished", p_sys->psz_record_file );
+                break;
+            }
+        }
+
+        free( p_sys->psz_record_file );
+    }
+    
     TAB_CLEAN( p_sys->i_id, p_sys->id );
     free( p_sys->psz_prefix );
     free( p_sys );
@@ -357,7 +374,10 @@ static int OutputNew( sout_stream_t *p_stream,
     }
 
     if( psz_file && psz_extension )
+    {
+        p_sys->psz_record_file = strdup( psz_file );
         var_SetString( p_stream->obj.libvlc, "record-file", psz_file );
+    }
 
     free( psz_file );
     free( psz_output );
diff --git a/src/input/input.c b/src/input/input.c
index 04e5b3bb72..114d8bb1f0 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -3554,9 +3554,13 @@ char *input_CreateFilename(input_thread_t *input, const char *dir,
 
     filename_sanitize(filename);
 
+    //if (((ext != NULL)
+    //        ? asprintf(&path, "%s"DIR_SEP"%s.%s", dir, filename, ext)
+    //        : asprintf(&path, "%s"DIR_SEP"%s", dir, filename)) < 0)
+    //    path = NULL;
     if (((ext != NULL)
-            ? asprintf(&path, "%s"DIR_SEP"%s.%s", dir, filename, ext)
-            : asprintf(&path, "%s"DIR_SEP"%s", dir, filename)) < 0)
+            ? asprintf(&path, "%s.%s", dir, ext)
+            : asprintf(&path, "%s", dir)) < 0)
         path = NULL;
 
     free(filename);
diff --git a/src/input/var.c b/src/input/var.c
index 631b571c19..46a889d1e1 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -202,6 +202,9 @@ void input_ControlVarInit ( input_thread_t *p_input )
 
     var_Create( p_input, "spu-choice", VLC_VAR_INTEGER );
     var_SetInteger( p_input, "spu-choice", -1 );
+    
+    /* ES Out */
+    var_Create( p_input, "input-record-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
 
     /* Special read only objects variables for intf */
     var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
diff --git a/src/text/strings.c b/src/text/strings.c
index a15541afba..a936e5649c 100644
--- a/src/text/strings.c
+++ b/src/text/strings.c
@@ -481,7 +481,7 @@ char *vlc_b64_decode( const char *psz_src )
     return p_dst;
 }
 
-char *vlc_strftime( const char *tformat )
+char *vlc_strftime_old( const char *tformat )
 {
     time_t curtime;
     struct tm loctime;
@@ -511,6 +511,60 @@ char *vlc_strftime( const char *tformat )
     vlc_assert_unreachable ();
 }
 
+char *vlc_strftime( const char *tformat )
+{
+    struct timespec ts;
+    struct tm loctime;
+
+    if (strcmp (tformat, "") == 0)
+        return strdup (""); /* corner case w.r.t. strftime() return value */
+
+    /* Get the current time.  */
+    timespec_get(&ts, TIME_UTC);
+
+    /* Convert it to local time representation.  */
+    if (localtime_r(&ts.tv_sec, &loctime) == NULL) {
+        gmtime_r(&ts.tv_sec, &loctime);
+    }
+    size_t len = strlen(tformat);
+    char *nFormat = malloc(len + 32);
+    BOOL noMs = TRUE;
+    size_t i = 0, j = 0;
+    for (; i < len; i++, j++) {
+        if (tformat[i] == '%' && tformat[i+1] == 'l') {
+            char ms[32];
+            sprintf(ms, "%03d", (int)(ts.tv_nsec / 1000000));
+            nFormat[j] = 0;
+            strcat(nFormat, ms);
+            strcat(nFormat, &(tformat[i+2]));
+            noMs = FALSE;
+            break;
+        } else {
+            nFormat[j] = tformat[i];
+        }
+    }
+    if (noMs) nFormat[i] = 0;
+    for (size_t buflen = strlen (nFormat) + 32;; buflen += 32)
+    {
+        char *str = malloc (buflen);
+        if (str == NULL) {
+            free(nFormat);
+            return NULL;
+        }
+
+        size_t len = strftime (str, buflen, nFormat, &loctime);
+        if (len > 0)
+        {
+            char *ret = realloc (str, len + 1);
+            free(nFormat);
+            return ret ? ret : str; /* <- this cannot fail */
+        }
+        free (str);
+    }
+    free(nFormat);
+    vlc_assert_unreachable ();
+}
+
 static void write_duration(struct vlc_memstream *stream, int64_t duration)
 {
     lldiv_t d;
diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c
index 7dbeee3a2a..d998fd4f70 100644
--- a/src/video_output/vout_subpictures.c
+++ b/src/video_output/vout_subpictures.c
@@ -1064,8 +1064,8 @@ static subpicture_t *SpuRenderSubpictures(spu_t *spu,
                 msg_Err(spu, "original picture size %dx%d is unsupported",
                          subpic->i_original_picture_width,
                          subpic->i_original_picture_height);
-            else
-                msg_Warn(spu, "original picture size is undefined");
+            //else
+            //    msg_Warn(spu, "original picture size is undefined");
 
             subpic->i_original_picture_width  = fmt_src->i_visible_width;
             subpic->i_original_picture_height = fmt_src->i_visible_height;
-- 
2.17.1

2022年7月27日 星期三

Build VideoLAN 3.0.17.4 on Ubuntu 18.04

參考 Build VideoLAN 3.0.16 on Ubuntu 18.04
原先想要在 Ubuntu 20.04 上建立,但發現不容易

$ cd ~/Data/VLC
$ sudo git clone https://code.videolan.org/videolan/vlc.git vlc-3.0
$ cd vlc-3.0
$ sudo git branch -a
$ sudo git log --tags --simplify-by-decoration --pretty="format:%ai %d"
$ sudo git checkout tags/3.0.17.4
$ sudo git describe --tags
// 完整地回復到最後版本,並且刪除不必要的檔案
$ sudo git reset --hard
$ sudo git clean -f -d


$ docker pull ubuntu:18.04
$ docker run --name=vlc -it -v ~/Data/VLC/vlc-3.0:/root/vlc-3.0 -v ~/Data/VLC/build_vlc:/root/build_vlc ubuntu:18.04 /bin/bash
# cd /root/vlc-3.0/
# apt-get update
# apt install software-properties-common
# add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse"
# apt-get update
# apt-cache showpkg gcc-mingw-w64-base
# apt-get install gcc-mingw-w64-base=5.3.1-8ubuntu3+17
# apt-get install gcc-mingw-w64-x86-64=5.3.1-8ubuntu3+17
# apt-get install g++-mingw-w64-x86-64=5.3.1-8ubuntu3+17
# apt-get install gcc-mingw-w64-i686=5.3.1-8ubuntu3+17
# apt-get install g++-mingw-w64-i686=5.3.1-8ubuntu3+17
# apt-get install mingw-w64-tools=5.0.3-1
# apt-get install lua5.2 libtool automake autoconf autopoint make gettext pkg-config
# apt-get install qt4-dev-tools qt5-default git subversion cmake cvs 
# apt-get install wine64-development-tools libwine-dev zip p7zip nsis bzip2
# apt-get install yasm ragel ant default-jdk protobuf-compiler dos2unix
# apt-get install subversion yasm cvs cmake ragel autopoint

以下的 HOST-TRIPLET 在 win32 時換成 i686-w64-mingw32, 在 win64 時換成 x86_64-w64-mingw32
build vlc contrib
# cd /root/vlc-3.0/
# mkdir -p contrib/win32
# cd contrib/win32
# ../bootstrap --host=HOST-TRIPLET
# make fetch
//問題
curl: (56) Recv failure: Connection reset by peer
../src/x264/rules.mak:81: recipe for target '../tarballs/x264-git.tar.bz2' failed
//解決 類似失敗,再 fetch 一次
# make fetch
# make
//問題
env: 'meson': No such file or directory
../src/fribidi/rules.mak:21: recipe for target '.fribidi' failed
make: *** [.fribidi] Error 127
//解決
# apt-get install meson
//問題
meson.build:1:0: ERROR: Meson version is 0.45.1 but project requires >= 0.48.
//解決
# apt-get install python3-pip
# python3 -m pip install meson
//問題
/root/vlc-3.0/contrib/win32/fontconfig/missing: line 81: gperf: command not found
WARNING: 'gperf' is missing on your system.
//解決
# apt-get install gperf
//問題
configure: error: BD-J requires ANT, but ant was not found. Install ant or disable jar file building (--disable-bdjava-jar)
../src/bluray/rules.mak:56: recipe for target '.bluray' failed
//解決
# apt-get install ant
//問題
[javac] /root/vlc-3.0/contrib/win32/bluray/src/libbluray/bdj/java-j2se/java/io/BDFileSystemImpl.java:21: error: BDFileSystemImpl is not abstract and does not override abstract method isInvalid(File) in FileSystem
[javac] error: Source option 5 is no longer supported. Use 6 or later.
[javac] error: Target option 1.5 is no longer supported. Use 1.6 or later.
//解決
# apt-get install openjdk-8-jdk
# update-alternatives --config java
//問題
Program nasm found: NO
meson.build:397:4: ERROR: Program 'nasm' not found or not executable
//解決
# apt-get install wget
# wget https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz
# tar xvf nasm-2.14.02.tar.gz
# cd nasm-2.14.02/
# ./configure
# make
# make install


build vlc
# cd /root/vlc-3.0
# ./bootstrap
//問題
ERROR: flex is not installed.
//解決
# apt-get install flex
//問題
ERROR: GNU bison is not installed.
//解決
# apt-get install bison
# mkdir win32 && cd win32
# export PKG_CONFIG_LIBDIR=/root/vlc-3.0/contrib/HOST-TRIPLET/lib/pkgconfig 
# ../extras/package/win32/configure.sh --host=HOST-TRIPLET --build=x86_64-pc-linux-gnu
# make
//問題
stream_out/chromecast/cast_channel.pb.h:17:2: error: 
#error This file was generated by an older version of protoc which is
//解決
# git clone https://github.com/protocolbuffers/protobuf.git
# cd protobuf
# git checkout tags/v3.1.0
# ./autogen.sh
# ./configure
# make
# make check
# make install
# ldconfig # refresh shared library cache.
# make package-win-common
//問題
/bin/bash: wget: command not found
Makefile:1043: recipe for target 'npapi-sdk' failed
//解決
# apt-get install wget
# make package-win32-zip


Build VideoLAN 3.0.16 on Ubuntu 18.04

參考 三 VideoLAN Compile 成熟篇

下載時要指定版本
$ cd ~/Data/VLC
$ git clone https://code.videolan.org/videolan/vlc.git vlc-3.0
$ cd vlc-3.0
$ git branch -a
$ git log --tags --simplify-by-decoration --pretty="format:%ai %d"
$ git checkout tags/3.0.16
$ git describe --tags
// 完整地回復到最後版本,並且刪除不必要的檔案
$ git reset --hard
$ git clean -f -d

利用 Docker 以利之後的重新建立
$ docker pull ubuntu:18.04
$ docker run --name=vlc -it -v ~/Data/VLC/vlc-3.0:/root/vlc-3.0 -v ~/Data/VLC/build_vlc:/root/build_vlc ubuntu:18.04 /bin/bash
# <ctrl+p><ctrl+q>
$ docker attach vlc
# <ctrl+p><ctrl+q>
$ docker stop vlc
$ docker start vlc
$ docker attach vlc
$ docker ps -a
$ docker container rm vlc
$ docker image ls
$ docker image rm <image_id>


若按照說明,不指定 mingw-w64 工具的版本,在 build 64 位元 VLC 時會產生下列問題
/usr/lib/gcc/x86_64-w64-mingw32/7.3-win32/libstdc++.a(cow-stdexcept.o):
(.text$_ZGTtNSt11logic_errorC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x36) 
relocation truncated to fit: R_X86_64_PC32 against undefined symbol `_ITM_RU8'
解決需要指定 mingw-w64 工具的版本
# cd /root/vlc-3.0/
# apt-get update
# apt install software-properties-common
# add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse"
# apt-get update
# apt-cache showpkg gcc-mingw-w64-base
# apt-get install gcc-mingw-w64-base=5.3.1-8ubuntu3+17
# apt-get install gcc-mingw-w64-x86-64=5.3.1-8ubuntu3+17
# apt-get install g++-mingw-w64-x86-64=5.3.1-8ubuntu3+17
# apt-get install gcc-mingw-w64-i686=5.3.1-8ubuntu3+17
# apt-get install g++-mingw-w64-i686=5.3.1-8ubuntu3+17
# apt-get install mingw-w64-tools=5.0.3-1


其他工具
# apt-get install lua5.2 libtool automake autoconf autopoint make gettext pkg-config
# apt-get install qt4-dev-tools qt5-default git subversion cmake cvs 
# apt-get install wine64-development-tools libwine-dev zip p7zip nsis bzip2
# apt-get install yasm ragel ant default-jdk protobuf-compiler dos2unix
# apt-get install subversion yasm cvs cmake ragel autopoint


以下的 HOST-TRIPLET 在 win32 時換成 i686-w64-mingw32, 在 win64 時換成 x86_64-w64-mingw32
build vlc contrib
# cd /root/vlc-3.0/
# mkdir -p contrib/win32
# cd contrib/win32
# ../bootstrap --host=HOST-TRIPLET
# make fetch
//問題 (改 mingw-w64 版本後,沒問題)
../bootstrap: 393: ../bootstrap: python3: not found
//解決
# apt-get install python3
# make
//問題
env: 'meson': No such file or directory
../src/fribidi/rules.mak:22: recipe for target '.fribidi' failed
make: *** [.fribidi] Error 127
//解決
# apt-get install meson
//問題
/root/vlc-3.0/contrib/win32/fontconfig/missing: line 81: gperf: command not found
WARNING: 'gperf' is missing on your system.
//解決
# apt-get install gperf
//問題
configure: error: Package requirements (fribidi >= 0.19.0) were not met:
No package 'fribidi' found
//解決
# apt-get install python3-pip
# python3 -m pip install meson
//問題
[javac] /root/vlc-3.0/contrib/win32/bluray/src/libbluray/bdj/java-j2se/java/io/BDFileSystemImpl.java:21: error: BDFileSystemImpl is not abstract and does not override abstract method isInvalid(File) in FileSystem
//解決
# apt-get install openjdk-8-jdk
# update-alternatives --config java
//問題
meson.build:388:4: ERROR: Program 'nasm' not found or not executable
//解決
# apt-get install wget
# wget https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz
# tar xvf nasm-2.14.02.tar.gz
# cd nasm-2.14.02/
# ./configure
# make
# make install
文件上說明 build i686-w64-mingw32 時,要移除 moc, uic, rcc,但是不能刪
# cd /root/vlc-3/contrib/i686-w64-mingw32/bin
# mv moc moc.bak
# mv uic uic.bak
# mv rcc rcc.bak
# rm -f i686-w64-mingw32/bin/moc i686-w64-mingw32/bin/uic i686-w64-mingw32/bin/rcc


build vlc
# cd /root/vlc-3.0
# ./bootstrap
//問題
../../extras/package/win32/../../../autotools/ylwrap: line 176: yacc: command not found
//解決
# apt-get install flex
# apt-get install bison
//問題
ERROR: flex is not installed.
//解決
# apt-get install flex
//問題
ERROR: GNU bison is not installed.
//解決
# apt-get install bison
# mkdir win32 && cd win32
# export PKG_CONFIG_LIBDIR=/root/vlc-3.0/contrib/HOST-TRIPLET/lib/pkgconfig 
# ../extras/package/win32/configure.sh --host=HOST-TRIPLET --build=x86_64-pc-linux-gnu
# make
//問題
stream_out/chromecast/cast_channel.pb.h:17:2: error:
#error This file was generated by an older version of protoc which is
//解決
# git clone https://github.com/protocolbuffers/protobuf.git
# cd protobuf
# git checkout tags/v3.1.0
# ./autogen.sh
# ./configure
# make
# make check
# make install
# ldconfig # refresh shared library cache.
//問題
libprotoc.so.11: cannot open shared object file: No such file or directory
//解決
# export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
//問題
/bin/bash: wget: command not found
Makefile:1043: recipe for target 'npapi-sdk' failed
make[4]: *** [npapi-sdk] Error 127
//解決
# apt-get install wget
//問題
gui/qt/main_interface.moc.cpp:22:1: error: 'QT_WARNING_DISABLE_DEPRECATED' 
does not name a type; did you mean 'QT_WARNING_DISABLE_INTEL'?
QT_WARNING_DISABLE_DEPRECATED
//解決
# qmake -v
# qtchooser -install qt5.6.3 /root/vlc-3.0/contrib/win32/qt/bin/qmake
# qtchooser -l
# export QT_SELECT=qt5.6.3
# qmake -v
# make package-win-common
# ls vlc-3.0.16/
# make package-win32-zip
# ls vlc-3.0.16-win32.zip 
//成功

2022年7月5日 星期二

Ubuntu 18.04 重灌

因為 Ubuntu 18.04 只能安裝 DeepStream 6.0.1
在 Ubuntu 20.04 才能安裝 DeepStream 6.1
所以在 Ubuntu 18.04 上安裝 Docker Ubuntu 20.04
版本對應如下
===========================
DS 6.1
Ubuntu 20.04
GCC 9.4.0
CUDA 11.6.1
cuDNN 8.4.0.27
TRT 8.2.5.1
Display Driver:R510.47.03
GStreamer 1.16.2
OpenCV 4.2.0
deepstream:6.1
===========================
DS 6.0.1
Ubuntu 18.04
GCC 7.3.0
CUDA 11.4.1
cuDNN 8.2+
TRT 8.0.1
Display Driver:R470.63.01
GStreamer 1.14.5
OpenCV 3.4.0
deepstream:6.0.1
===========================

安裝作業系統
BIOS 選擇開機
Install Ubuntu
Installation type 選 Something else
Create partition/Mount point 選擇 /

Settings/Details/Users
Unlock
Automatic Login: ON

更新系統,安裝一些常用套件
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install ssh
$ sudo apt-get install python3-pip

mount nfs
$ sudo apt-get install nfs-common
$ sudo mount -t nfs ip:/share_folder /mount_folder
$ sudo vi /etc/fstab
#中間的空格要使用 tab
ip:/share_folder /mnt/mount_folder nfs defaults,bg 0 0
$ sudo mount -a

vnc
$ sudo apt-get install x11vnc
$ sudo x11vnc -storepasswd
$ sudo chown user.group ~/.vnc/passwd

安裝顯示卡驅動,CUDA 和 CUDNN
$ sudo ubuntu-drivers devices
$ sudo apt-get install nvidia-driver-510

https://developer.nvidia.com/cuda-downloads
選擇 Archive of Previous CUDA Releases
選擇 CUDA Toolkit 11.4.1
選擇 deb(local), deb(network) 不可使用了
$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
$ sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ wget https://developer.download.nvidia.com/compute/cuda/11.4.1/local_installers/cuda-repo-ubuntu1804-11-4-local_11.4.1-470.57.02-1_amd64.deb
$ sudo dpkg -i cuda-repo-ubuntu1804-11-4-local_11.4.1-470.57.02-1_amd64.deb
$ sudo apt-key add /var/cuda-repo-ubuntu1804-11-4-local/7fa2af80.pub
$ sudo apt-get update
$ sudo apt-get -y install cuda-11-4
之後再安裝一遍 CUDA Toolkit 11.3.1(因為 TensorRT 8.0.1 需要 CUDA-11-3)
$ sudo apt-get -y install cuda-11-3
之後再安裝一遍 CUDA Toolkit 11.6.1(因為 DeepStream 6.1 需要 CUDA-11-6)
$ sudo apt-get -y install cuda-11-6
$ update-alternatives --display cuda
$ update-alternatives --config cuda


參考 https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html
下載 Local Install for Ubuntu18.04 x86_64(Deb)
$ sudo apt-get install zlib1g
$ sudo dpkg -i cudnn-local-repo-ubuntu1804-8.4.1.50_1.0-1_amd64.deb
$ sudo cp /var/cudnn-local-repo-ubuntu1804-8.4.1.50/cudnn-local-BA71F057-keyring.gpg /usr/share/keyrings/
$ sudo apt-get update
$ apt list -a libcudnn8
$ sudo apt-get install libcudnn8=8.4.1.50-1+cuda11.6
$ sudo apt-get install libcudnn8-dev=8.4.1.50-1+cuda11.6
$ sudo apt-get install libcudnn8-samples=8.4.1.50-1+cuda11.6

安裝 TensorRT 8.0.1
因為使用 Docker 安裝 DeepStream 6.1, 所以不用安裝 TensorRT 8.2.5.1
參考 https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html
TensorRT Archives 切換安裝文件版本
在 3. Downloading TensorRT
連結 https://developer.nvidia.com/tensorrt 按 GET STARTED
連結 https://developer.nvidia.com/tensorrt-getting-started 按 DOWNLOAD NOW
選擇 TensorRT 8
選擇 TensorRT 8.0 GA
選擇 TensorRT 8.0.1 GA for Ubuntu 18.04 and CUDA 11.3 DEB local repo package
$ sudo dpkg -i nv-tensorrt-repo-ubuntu1804-cuda11.3-trt8.0.1.6-ga-20210626_1-1_amd64.deb
$ sudo apt-key add /var/nv-tensorrt-repo-ubuntu1804-cuda11.3-trt8.0.1.6-ga-20210626/7fa2af80.pub
$ sudo apt-get update
$ sudo apt --fix-broken install
$ sudo apt-get upgrade
$ sudo apt-get install tensorrt

安裝 DeepStream
因為不選擇最新的版本
參考 https://docs.nvidia.com/metropolis/deepstream-archive.html
$ sudo apt install libssl1.0.0
$ sudo apt install libgstreamer1.0-0
$ sudo apt install gstreamer1.0-tools
$ sudo apt install gstreamer1.0-plugins-good
$ sudo apt install gstreamer1.0-plugins-bad
$ sudo apt install gstreamer1.0-plugins-ugly
$ sudo apt install gstreamer1.0-libav
$ sudo apt install libgstrtspserver-1.0-0
$ sudo apt install libjansson4
$ sudo apt install gcc
$ sudo apt install make
$ sudo apt install git
$ sudo apt install python3

$ cd /usr/bin
$ sudo ln -s python3 python
$ git clone https://github.com/edenhill/librdkafka.git
$ cd librdkafka
$ git reset --hard 7101c2310341ab3f4675fc565f64f0967e135a6a
$ ./configure
$ make
$ sudo make install
$ sudo mkdir -p /opt/nvidia/deepstream/deepstream-6.0/lib
$ sudo cp /usr/local/lib/librdkafka* /opt/nvidia/deepstream/deepstream-6.0/lib
下載 Deepstream 6.0 dGPU Debian package
https://developer.nvidia.com/deepstream-6.0_6.0.1-1_amd64deb
$ sudo apt-get install ./deepstream-6.0_6.0.1-1_amd64.deb
$ rm ${HOME}/.cache/gstreamer-1.0/registry.x86_64.bin
$ cd /opt/nvidia/deepstream/deepstream-6.0/samples/configs/deepstream-app/
$ deepstream-app -c source4_1080p_dec_infer-resnet_tracker_sgie_tiled_display_int8.txt

安裝  Nvidia Docker
參考 https://docs.docker.com/engine/install/ubuntu/
$ sudo apt-get update
$ sudo apt-get install ca-certificates
$ sudo apt-get install curl
$ sudo apt-get install gnupg
$ sudo apt-get install lsb-release
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
$ sudo docker run --rm hello-world

參考 https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
            sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
            sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
$ sudo apt-get update
$ sudo apt-get install -y nvidia-docker2
$ sudo systemctl restart docker
$ sudo groupadd docker
$ sudo usermod -a -G docker $USER
$ sudo reboot

安裝 NGC CLI
參考 https://ngc.nvidia.com/setup/installers/cli
$ wget --content-disposition https://ngc.nvidia.com/downloads/ngccli_linux.zip && \
  unzip ngccli_linux.zip && \
  chmod u+x ngc-cli/ngc
$ find ngc-cli/ -type f -exec md5sum {} + | LC_ALL=C sort | md5sum -c ngc-cli.md5
$ echo "export PATH=\"\$PATH:$(pwd)/ngc-cli\"" >> ~/.bash_profile && source ~/.bash_profile
$ ngc config set
# 直接 enter 即可
$ docker login nvcr.io
Username: $oauthtoken
Password: <Your API Key>

使用 Docker 安裝 TensorRT OSS
開啟 https://github.com/nvidia/TensorRT
切換至 Tags 8.0.1
$ git clone -b master https://github.com/nvidia/TensorRT TensorRT_OSS-8.0.1
$ cd TensorRT_OSS-8.0.1/
$ git describe --tags
8.2.0-EA-2-g96e2397
$ git tag -l
$ git branch -r
$ git checkout 8.0.1
$ git log -1
$ git describe --tags
8.0.1
$ git submodule update --init --recursive
$ vi docker/ubuntu-18.04.Dockerfile
修改下列一行
RUN cd /usr/local/bin && wget https://ngc.nvidia.com/downloads/ngccli_cat_linux.zip && \
  unzip ngccli_cat_linux.zip && chmod u+x ngc-cli/ngc && \
  rm ngccli_cat_linux.zip ngc-cli.md5 && echo "no-apikey\nascii\n" | ngc-cli/ngc config set

$ cat docker/ubuntu-18.04.Dockerfile | grep CUDA_VERSION
ARG CUDA_VERSION=11.3.1
$ ./docker/build.sh --file docker/ubuntu-18.04.Dockerfile --tag tensorrt-ubuntu18.04-cuda11.3 --cuda 11.3.1
$ ./docker/launch.sh --tag tensorrt-ubuntu18.04-cuda11.3 --gpus all
/workspace$ cd $TRT_OSSPATH
/workspace/TensorRT$ mkdir -p build && cd build
/workspace/TensorRT/build$ cmake .. -DTRT_LIB_DIR=$TRT_LIBPATH -DTRT_OUT_DIR=`pwd`/out
/workspace/TensorRT/build$ make -j$(nproc)
/workspace/TensorRT/build$ exit
$ mkdir backup
$ sudo mv /usr/lib/x86_64-linux-gnu/libnvinfer_plugin.so.8.0.1 backup/
$ sudo cp build/out/libnvinfer_plugin.so.8.0.1 /usr/lib/x86_64-linux-gnu/
另外還要再安裝 TensorRT 8.2.1 給 Docker Ubuntu 20.04
將 8.0.1 改成 8.2.1, 18.04 改成 20.04, 11.3.1 改成 11.4.2, 但不需安裝

用 Docker 開發 DeepStream 6.0.1
參考 https://docs.nvidia.com/metropolis/deepstream/6.0.1/dev-guide/text/DS_docker_containers.html
$ docker pull nvcr.io/nvidia/deepstream:6.0.1-devel
$ xhost +
access control disabled, clients can connect from any host
$ sudo docker run --gpus all -it --rm --net=host \
  -v /tmp/.X11-unix:/tmp/.X11-unix -v /etc/localtime:/etc/localtime \
  -e DISPLAY=$DISPLAY -w /opt/nvidia/deepstream/deepstream-6.0 nvcr.io/nvidia/deepstream:6.0.1-devel
# update-alternatives --display cuda
# cat /etc/os-release
# cd samples/configs/deepstream-app
# deepstream-app -c source4_1080p_dec_infer-resnet_tracker_sgie_tiled_display_int8.txt 
# cd /opt/nvidia/deepstream/deepstream-6.0/sources/apps/sample_apps/deepstream-app
# export CUDA_VER=11.4
# make
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/nvidia/deepstream/deepstream-6.0/lib/gst-plugins/
# export URI=rtsp://user:passwd@192.168.0.108:554/live1s2.sdp
# gst-launch-1.0 uridecodebin uri=$URI ! nvvideoconvert ! nveglglessink
# exit

用 Docker 開發 DeepStream 6.1
https://docs.nvidia.com/metropolis/deepstream/dev-guide/text/DS_docker_containers.html
$ docker pull nvcr.io/nvidia/deepstream:6.1-devel
$ xhost +
access control disabled, clients can connect from any host
$ sudo docker run --gpus all -it --rm --net=host \
  -v /tmp/.X11-unix:/tmp/.X11-unix -v /etc/localtime:/etc/localtime \
  -e DISPLAY=$DISPLAY -w /opt/nvidia/deepstream/deepstream-6.1 nvcr.io/nvidia/deepstream:6.1-devel
# cd samples/configs/deepstream-app
# deepstream-app -c source4_1080p_dec_infer-resnet_tracker_sgie_tiled_display_int8.txt 
# cd /opt/nvidia/deepstream/deepstream-6.1/sources/apps/sample_apps/deepstream-app
# export CUDA_VER=11.6
# make
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/nvidia/deepstream/deepstream-6.1/lib/gst-plugins/
# export URI=rtsp://user:passwd@192.168.0.108:554/live1s2.sdp
# gst-launch-1.0 uridecodebin uri=$URI ! nvvideoconvert ! nveglglessink
# exit

用 Docker DeepStream 6.0.1 測試 Integrate TAO model with DeepStream SDK
$ git clone https://github.com/NVIDIA-AI-IOT/deepstream_tao_apps.git deepstream_tao_apps-tao3.0_ds6.0.1
$ sudo apt install gitk
$ cd deepstream_tao_apps-tao3.0_ds6.0.1/
$ git branch -r
$ git checkout release/tao3.0_ds6.0.1
$ git log -1
$ sudo docker run --gpus all -it --rm --net=host \
> -v /etc/localtime:/etc/localtime \
> -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY \
> -v /home/mark/Data/TensorRT/TensorRT_OSS-8.0.1/:/home/TensorRT \
> -v /home/mark/Data/DeepStream/deepstream_tap_apps/deepstream_tao_apps-tao3.0_ds6.0.1/:/home/deepstream_tao_apps \
> -w /opt/nvidia/deepstream/deepstream-6.0 nvcr.io/nvidia/deepstream:6.0.1-devel
# cd /home/deepstream_tao_apps/
# ./download_models.sh 
# export CUDA_VER=11.4
# make
# cp /home/TensorRT/build/out/libnvinfer_plugin.so.8.0.1 /usr/lib/x86_64-linux-gnu/
# ./apps/tao_detection/ds-tao-detection -c configs/frcnn_tao/pgie_frcnn_tao_config.txt -i /opt/nvidia/deepstream/deepstream-6.0/samples/streams/sample_720p.h264 -d
# cd /opt/nvidia/deepstream/deepstream-6.0/sources/gst-plugins/gst-nvdsvideotemplate/
# make
# cp libnvdsgst_videotemplate.so /opt/nvidia/deepstream/deepstream-6.0/lib/gst-plugins/
# rm -rf ~/.cache/gstreamer-1.0/
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/nvidia/deepstream/deepstream-6.0/lib/cvcore_libs/
# cd /home/deepstream_tao_apps/apps/tao_others/
# make
# export URI=rtsp://user:passwd@192.168.0.108:554/live1s2.sdp
# cd deepstream-bodypose2d-app/
# ./deepstream-bodypose2d-app 3 ../../../configs/bodypose2d_tao/sample_bodypose2d_model_config.txt $URI ./body2dout
# cd ../deepstream-emotion-app/
# ./deepstream-emotion-app 3 ../../../configs/facial_tao/sample_faciallandmarks_config.txt $URI ./landmarks
# cd ../deepstream-faciallandmark-app/
# ./deepstream-faciallandmark-app 3 ../../../configs/facial_tao/sample_faciallandmarks_config.txt $URI ./landmarks
# cd ../deepstream-gaze-app/
# ./deepstream-gaze-app 3 ../../../configs/facial_tao/sample_faciallandmarks_config.txt $URI ./gazenet
# cd ../deepstream-gesture-app/
# ./deepstream-gesture-app 3 3 ../../../configs/bodypose2d_tao/sample_bodypose2d_model_config.txt $URI ./gesture
# cd ../deepstream-heartrate-app/
# ./deepstream-heartrate-app 3 $URI ./heartrate
# exit

用 Docker DeepStream 6.1 測試 Integrate TAO model with DeepStream SDK
$ git clone https://github.com/NVIDIA-AI-IOT/deepstream_tao_apps.git deepstream_tao_apps-tao3.0_ds6.1ga
$ sudo apt install gitk
$ cd deepstream_tao_apps-tao3.0_ds6.1ga/
$ git branch -r
$ git checkout release/tao3.0_ds6.1ga
$ git log -1
$ sudo docker run --gpus all -it --rm --net=host \
> -v /etc/localtime:/etc/localtime \
> -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY \
> -v /home/mark/Data/TensorRT/TensorRT_OSS-8.2.1/:/home/TensorRT \
> -v /home/mark/Data/DeepStream/deepstream_tap_apps/deepstream_tao_apps-tao3.0_ds6.1ga/:/home/deepstream_tao_apps \
> -w /opt/nvidia/deepstream/deepstream-6.1 nvcr.io/nvidia/deepstream:6.1-devel
# cp /home/TensorRT/build/out/libnvinfer_plugin.so.8.2.1 /usr/lib/x86_64-linux-gnu/
# cd /usr/lib/x86_64-linux-gnu/
# rm libnvinfer_plugin.so.8
# ln -s libnvinfer_plugin.so.8.2.1 libnvinfer_plugin.so.8
# cd /home/deepstream_tao_apps/
# ./download_models.sh 
# export CUDA_VER=11.6
# make
# ./apps/tao_detection/ds-tao-detection -c configs/frcnn_tao/pgie_frcnn_tao_config_dgpu.txt -i /opt/nvidia/deepstream/deepstream-6.1/samples/streams/sample_720p.h264 -d
# cd /opt/nvidia/deepstream/deepstream-6.1/sources/gst-plugins/gst-nvdsvideotemplate/
# make
# cp libnvdsgst_videotemplate.so /opt/nvidia/deepstream/deepstream-6.1/lib/gst-plugins/
# rm -rf ~/.cache/gstreamer-1.0/
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/nvidia/deepstream/deepstream-6.1/lib/cvcore_libs/
# cd /home/deepstream_tao_apps/apps/tao_others/
# make
# export URI=rtsp://user:passwd@192.168.0.108:554/live1s2.sdp
# cd deepstream-bodypose2d-app/
# ./deepstream-bodypose2d-app 3 ../../../configs/bodypose2d_tao/sample_bodypose2d_model_config.txt 0 0 $URI ./body2dout
# cd ../deepstream-emotion-app/
# ./deepstream-emotion-app 3 ../../../configs/facial_tao/sample_faciallandmarks_config.txt $URI ./landmarks
# cd ../deepstream-faciallandmark-app/
# ./deepstream-faciallandmark-app 3 ../../../configs/facial_tao/sample_faciallandmarks_config.txt $URI ./landmarks
# cd ../deepstream-gaze-app/
# ./deepstream-gaze-app 3 ../../../configs/facial_tao/sample_faciallandmarks_config.txt $URI ./gazenet
# cd ../deepstream-gesture-app/
# ./deepstream-gesture-app 3 3 ../../../configs/bodypose2d_tao/sample_bodypose2d_model_config.txt $URI ./gesture
# cd ../deepstream-heartrate-app/
# ./deepstream-heartrate-app 3 $URI ./heartrate
# exit

安裝其他元件
參考 Ubuntu 18.04 重灌 上的 安裝 CMake 和 安裝 OpenCV