diff --git a/.clang-format b/.clang-format deleted file mode 100644 index c632999e0..000000000 --- a/.clang-format +++ /dev/null @@ -1,19 +0,0 @@ -# Aravis clang format configuration -# https://clang.llvm.org/docs/ClangFormatStyleOptions.html -BasedOnStyle: GNU -AlwaysBreakAfterDefinitionReturnType: All -BreakBeforeBinaryOperators: None -BinPackParameters: false -SpaceAfterCStyleCast: true -ColumnLimit: 120 -IndentCaseLabels: true -UseTab: Always -IndentWidth: 8 -TabWidth: 8 -BreakBeforeBraces: Mozilla -PenaltyBreakBeforeFirstCallParameter: 1000 -AlignConsecutiveMacros: true -AlignAfterOpenBracket: Align -AlignEscapedNewlines: Right -AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false diff --git a/.clang-format-include b/.clang-format-include deleted file mode 100644 index 43e4e654d..000000000 --- a/.clang-format-include +++ /dev/null @@ -1,4 +0,0 @@ -src/*.c -viewer/*.c -gst/*.c -tests/*.c diff --git a/.github/workflows/aravis-linux.yml b/.github/workflows/aravis-linux.yml index d2fad0f68..be194e19b 100644 --- a/.github/workflows/aravis-linux.yml +++ b/.github/workflows/aravis-linux.yml @@ -17,7 +17,7 @@ jobs: run: | pip3 install meson ninja Markdown toml typogrify sudo apt update - sudo apt install python3 libusb-1.0-0-dev gobject-introspection valgrind libgstreamer-plugins-bad1.0-dev libgtk-3-dev libgirepository1.0-dev python3-gi + sudo apt install python3 libusb-1.0-0-dev gobject-introspection valgrind libgstreamer-plugins-bad1.0-dev libgtk-3-dev libgirepository1.0-dev python3-gi libunwind-dev gettext - name: Build run: | meson --buildtype=plain -Ddocumentation=enabled -Dgst-plugin=enabled -Dintrospection=enabled -Dusb=disabled -Dviewer=enabled . ./build diff --git a/.github/workflows/aravis-macos.yml b/.github/workflows/aravis-macos.yml index 2a2116604..cd47899ec 100644 --- a/.github/workflows/aravis-macos.yml +++ b/.github/workflows/aravis-macos.yml @@ -16,11 +16,15 @@ jobs: - uses: actions/setup-python@v2 with: python-version: '3.x' + - name: Unbreak Python in Github Actions + run: | + find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete + sudo rm -rf /Library/Frameworks/Python.framework/ + brew install --force python3 && brew unlink python3 && brew unlink python3 && brew link --overwrite python3 - name: Install dependencies run: | - pip install meson ninja brew update - brew install gcc gettext intltool gtk-doc libxml2 libusb gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gnome-icon-theme gobject-introspection glib-utils + brew install meson ninja gcc gettext intltool libxml2 libusb gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gnome-icon-theme gobject-introspection glib - name: Build run: | meson --buildtype=plain -Ddocumentation=disabled -Dgst-plugin=enabled -Dintrospection=disabled -Dusb=enabled -Dviewer=enabled . ./build diff --git a/.github/workflows/aravis-msvc.yml b/.github/workflows/aravis-msvc.yml index e3bbdc7bd..ab0f993f3 100644 --- a/.github/workflows/aravis-msvc.yml +++ b/.github/workflows/aravis-msvc.yml @@ -22,6 +22,9 @@ jobs: - name: pip run: | pip install conan + - name: disable-perl + run: | + rm -r C:\Strawberry\perl - name: checkout uses: actions/checkout@v2 - name: conan @@ -29,17 +32,18 @@ jobs: INPUT_CONANFILE: | [requires] libiconv/1.17 - glib/2.70.0 + glib/2.74.1 #gobject-introspection/1.69.0 - #gstreamer/1.19.1 - #gst-plugins-base/1.19.1 + gstreamer/1.19.2 + gst-plugins-base/1.19.2 #gtk/4.4.0 - libxml2/2.9.12 - zlib/1.2.11 - libusb/1.0.24 + libxml2/2.10.3 + zlib/1.2.13 + libusb/1.0.26 [build_requires] meson/0.59.2 + pkgconf/1.9.3 [generators] pkg_config @@ -60,7 +64,7 @@ jobs: .\build\activate_build.ps1 .\build\activate_run.ps1 echo "::group::configure" - meson --prefix ${{ github.workspace }}\install --buildtype ${{ matrix.build_type_meson }} --pkg-config-path ${{ github.workspace }}\build -Ddocumentation=disabled -Dgst-plugin=disabled -Dintrospection=disabled -Dusb=enabled -Dviewer=disabled -Dgv-n-buffers=1 . .\build + meson --prefix ${{ github.workspace }}\install --buildtype ${{ matrix.build_type_meson }} --pkg-config-path ${{ github.workspace }}\build -Ddocumentation=disabled -Dgst-plugin=enabled -Dintrospection=disabled -Dusb=enabled -Dviewer=disabled -Dgv-n-buffers=1 . .\build echo "::endgroup::" echo "::group::compile" meson compile -C .\build -v diff --git a/.gitignore b/.gitignore index a12d4c8ec..ce0e81fda 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/ *~ build-*/ .cache/ +.vscode/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 61b884ee4..000000000 --- a/.travis.yml +++ /dev/null @@ -1,52 +0,0 @@ -os: - - linux - - osx -arch: - - amd64 - - ppc64le -language: c - -osx_image: xcode12.2 - -compiler: - - gcc - - clang - -jobs: - allow_failures: - -dist: bionic - -addons: - apt: - packages: - - libxml2-dev - - libglib2.0-dev - - intltool - - gtk-doc-tools - - libusb-1.0-0-dev - - libaudit-dev - - python3-pip - - python3-dev - - ninja-build - - gobject-introspection - - valgrind - update: true - homebrew: - packages: - - intltool - update: true - -before_install: - - sudo pip3 install --upgrade setuptools pip==20.3.4 - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo pip3 install ninja ; fi - - sudo pip3 install 'meson==0.47' - -script: - - meson build - - cd build - - meson configure - - ninja - - meson test --no-suite="network" - - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then meson test --suite="network" ; fi - - if [[ "$TRAVIS_CPU_ARCH" != "ppc64le" && "$TRAVIS_OS_NAME" != "osx" ]]; then ../tests/valgrind-memcheck ; fi diff --git a/README.md b/README.md index 819d8cd02..791a3908f 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ Aravis -

Your industrial vision library

- [![Aravis-Linux](https://github.com/AravisProject/aravis/actions/workflows/aravis-linux.yml/badge.svg)](https://github.com/AravisProject/aravis/actions/workflows/aravis-linux.yml) [![Aravis-macOS](https://github.com/AravisProject/aravis/actions/workflows/aravis-macos.yml/badge.svg)](https://github.com/AravisProject/aravis/actions/workflows/aravis-macos.yml) [![Aravis-MinGW](https://github.com/AravisProject/aravis/actions/workflows/aravis-mingw.yml/badge.svg)](https://github.com/AravisProject/aravis/actions/workflows/aravis-mingw.yml) diff --git a/docs/arv-camera-test-0.8.1 b/docs/arv-camera-test-0.8.1 new file mode 100644 index 000000000..9b6327a82 --- /dev/null +++ b/docs/arv-camera-test-0.8.1 @@ -0,0 +1,116 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. +.TH ARV-CAMERA-TEST-0.8 "1" "décembre 2022" "arv-camera-test-0.8 0.8.23" "User Commands" +.SH NAME +arv-camera-test-0.8 \- manual page for arv-camera-test-0.8 0.8.23 +.SH DESCRIPTION +.SS "Usage:" +.IP +arv\-camera\-test\-0.8 [OPTION?] +.PP +Small utility for basic device checks. +.SS "Help Options:" +.TP +\-?, \fB\-\-help\fR +Show help options +.SS "Application Options:" +.TP +\fB\-n\fR, \fB\-\-name=\fR +Camera name +.TP +\fB\-f\fR, \fB\-\-frequency=\fR +Acquisition frequency +.TP +\fB\-t\fR, \fB\-\-trigger=\fR +External trigger +.TP +\fB\-o\fR, \fB\-\-software\-trigger=\fR +Emit software trigger +.TP +\fB\-w\fR, \fB\-\-width=\fR +Width +.TP +\fB\-h\fR, \fB\-\-height=\fR +Height +.TP +\fB\-\-h\-binning=\fR +Horizontal binning +.TP +\fB\-\-v\-binning=\fR +Vertical binning +.TP +\fB\-e\fR, \fB\-\-exposure=\fR +Exposure time +.TP +\fB\-g\fR, \fB\-\-gain=\fR +Gain (dB) +.TP +\fB\-a\fR, \fB\-\-auto\fR +Auto socket buffer size +.TP +\fB\-\-features\fR +Additional configuration as a space separated list of features +.TP +\fB\-j\fR, \fB\-\-packet\-size\-adjustment=\fR{never|always|once|on\-failure|on\-failure\-once} +Packet size adjustment +.TP +\fB\-r\fR, \fB\-\-no\-packet\-resend\fR +No packet resend +.TP +\fB\-q\fR, \fB\-\-packet\-request\-ratio\fR=\fI\,[0\/\fR..2.0] +Packet resend request limit as a frame packet ratio +.TP +\fB\-l\fR, \fB\-\-initial\-packet\-timeout=\fR +Initial packet timeout +.TP +\fB\-p\fR, \fB\-\-packet\-timeout=\fR +Packet timeout +.TP +\fB\-m\fR, \fB\-\-frame\-retention=\fR +Frame retention +.TP +\fB\-c\fR, \fB\-\-gv\-stream\-channel=\fR +GigEVision stream channel id +.TP +\fB\-y\fR, \fB\-\-gv\-packet\-delay=\fR +GigEVision packet delay +.TP +\fB\-i\fR, \fB\-\-gv\-packet\-size=\fR +GigEVision packet size +.TP +\fB\-s\fR, \fB\-\-usb\-mode=\fR{sync|async} +USB device I/O mode +.TP +\fB\-u\fR, \fB\-\-chunks=\fR[,[...]] +Chunks +.TP +\fB\-\-realtime\fR +Make stream thread realtime +.TP +\fB\-\-high\-priority\fR +Make stream thread high priority +.TP +\fB\-\-no\-packet\-socket\fR +Disable use of packet socket +.TP +\fB\-\-register\-cache=\fR{disable|enable|debug} +Register cache policy +.TP +\fB\-\-range\-check=\fR{disable|enable|debug} +Range check policy +.TP +\fB\-\-access\-check=\fR{disable|enable} +Feature access check policy +.TP +\fB\-b\fR, \fB\-\-bandwidth\-limit=\fR +Desired USB3 Vision device bandwidth limit +.TP +\fB\-\-duration=\fR +Test duration (s) +.TP +\fB\-d\fR, \fB\-\-debug=\fR{[:][,...]|help} +Debug output selection +.TP +\fB\-v\fR, \fB\-\-version\fR +Show version +.PP +This tool configures a camera and starts video streaming, infinitely unless a duration is given. diff --git a/docs/arv-test-0.8.1 b/docs/arv-test-0.8.1 new file mode 100644 index 000000000..c40478d00 --- /dev/null +++ b/docs/arv-test-0.8.1 @@ -0,0 +1,48 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. +.TH ARV-TEST-0.8 "1" "décembre 2022" "arv-test-0.8 0.8.23" "User Commands" +.SH NAME +arv-test-0.8 \- manual page for arv-test-0.8 0.8.23 +.SH DESCRIPTION +.SS "Usage:" +.IP +arv\-test\-0.8 [OPTION?] +.PP +Automated test utillity. +.SS "Help Options:" +.TP +\fB\-h\fR, \fB\-\-help\fR +Show help options +.SS "Application Options:" +.TP +\fB\-n\fR, \fB\-\-name=\fR +Device selection +.TP +\fB\-t\fR, \fB\-\-test=\fR +Test selection +.TP +\fB\-c\fR, \fB\-\-configuration=\fR +Alternative configuration +.TP +\fB\-i\fR, \fB\-\-iterations=\fR +Number of test repetitions +.TP +\fB\-s\fR, \fB\-\-usb\-mode=\fR{sync|async} +USB device I/O mode +.TP +\fB\-a\fR, \fB\-\-cache\-check\fR +Register cache check +.TP +\fB\-\-packet\-socket\fR +Enable use of packet socket +.HP +\fB\-d\fR, \fB\-\-debug=\fR{[:][,...]|help} +.TP +\fB\-v\fR, \fB\-\-version\fR +Show version +.PP +arv\-test is an automated test utility that tries to exercise most of the +Aravis functionalities. By default it runs all the tests on all the detected +devices, but devices and tests can be selected using a glob pattern. +.PP +A default configuration file is bundled in the executable. An alternative +one with entries specific to the camera you want to test can be specified. diff --git a/docs/arv-tool-0.8.1 b/docs/arv-tool-0.8.1 index 212a909c0..55f0afd55 100644 --- a/docs/arv-tool-0.8.1 +++ b/docs/arv-tool-0.8.1 @@ -1,11 +1,11 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH ARV-TOOL-0.6 "1" "avril 2019" "arv-tool-0.6 0.6" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. +.TH ARV-TOOL-0.8 "1" "décembre 2022" "arv-tool-0.8 0.8.23" "User Commands" .SH NAME -arv-tool-0.6 \- Small utility for basic control of Genicam devices +arv-tool-0.8 \- manual page for arv-tool-0.8 0.8.23 .SH DESCRIPTION .SS "Usage:" .TP -arv\-tool\-0.6 [OPTION?] +arv\-tool\-0.8 [OPTION?] command .PP Small utility for basic control of a Genicam device. @@ -15,11 +15,26 @@ Small utility for basic control of a Genicam device. Show help options .SS "Application Options:" .HP -\fB\-n\fR, \fB\-\-name=\fR +\fB\-n\fR, \fB\-\-name=\fR .HP \fB\-a\fR, \fB\-\-address=\fR +.TP +\fB\-\-register\-cache=\fR{disable|enable|debug} +Register cache policy +.TP +\fB\-\-range\-check=\fR{disable|enable|debug} +Range check policy +.TP +\fB\-\-access\-check=\fR{disable|enable} +Feature access check policy +.TP +\fB\-t\fR, \fB\-\-time\fR +Show execution time .HP -\fB\-d\fR, \fB\-\-debug=\fR[:][,...] +\fB\-d\fR, \fB\-\-debug=\fR{[:][,...]|help} +.TP +\fB\-v\fR, \fB\-\-version\fR +Show version .PP Command may be one of the following possibilities: .TP @@ -27,30 +42,26 @@ genicam: dump the content of the Genicam xml data .TP features: -list all available features +list all features +.TP +values: +list all available feature values .TP description [] ...: show the full feature description .TP control [=] ...: read/write device features +.TP +network [=]...: +read/write network settings .PP If no command is given, this utility will list all the available devices. For the control command, direct access to device registers is provided using a R[address] syntax in place of a feature name. .SH EXAMPLES -arv\-tool\-0.6 control Width=128 Height=128 Gain R[0x10000]=0x10 -arv\-tool\-0.6 features -arv\-tool\-0.6 description Width Height -arv\-tool\-0.6 \-n Basler\-210ab4 genicam -.SH "SEE ALSO" -The full documentation for -.B arv-tool-0.6 -is maintained as a Texinfo manual. If the -.B info -and -.B arv-tool-0.6 -programs are properly installed at your site, the command -.IP -.B info arv-tool-0.6 -.PP -should give you access to the complete manual. +arv\-tool\-0.8 control Width=128 Height=128 Gain R[0x10000]=0x10 +arv\-tool\-0.8 features +arv\-tool\-0.8 description Width Height +arv\-tool\-0.8 network mode=PersistentIP +arv\-tool\-0.8 network ip=192.168.0.1 mask=255.255.255.0 gateway=192.168.0.254 +arv\-tool\-0.8 \-n Basler\-210ab4 genicam diff --git a/docs/arv-viewer-0.8.1 b/docs/arv-viewer-0.8.1 index d22721cce..686ea4d5e 100644 --- a/docs/arv-viewer-0.8.1 +++ b/docs/arv-viewer-0.8.1 @@ -1,11 +1,11 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH ARV-VIEWER-0.6 "1" "avril 2019" "arv-viewer-0.6 0.6" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. +.TH ARV-VIEWER-0.8 "1" "décembre 2022" "arv-viewer-0.8 0.8.23" "User Commands" .SH NAME -arv-viewer-0.6 \- Basic viewer for Aravis compatible cameras +arv-viewer-0.8 \- manual page for arv-viewer-0.8 0.8.23 .SH DESCRIPTION .SS "Usage:" .IP -arv\-viewer\-0.6 [OPTION?] +arv\-viewer\-0.8 [OPTIONâ\&.¦] .SS "Help Options:" .TP \fB\-h\fR, \fB\-\-help\fR @@ -18,7 +18,7 @@ Show all help options Show GTK+ Options .TP \fB\-\-help\-gst\fR -Show GStreamer Options +Afficher les options de GStreamer .SS "Application Options:" .TP \fB\-a\fR, \fB\-\-auto\-buffer\-size\fR @@ -27,26 +27,28 @@ Auto socket buffer size \fB\-r\fR, \fB\-\-no\-packet\-resend\fR No packet resend .TP +\fB\-l\fR, \fB\-\-initial\-packet\-timeout\fR +Initial packet timeout (ms) +.TP \fB\-p\fR, \fB\-\-packet\-timeout\fR Packet timeout (ms) .TP \fB\-m\fR, \fB\-\-frame\-retention\fR Frame retention (ms) .TP -\fB\-d\fR, \fB\-\-debug\fR -Debug domains +\fB\-\-register\-cache=\fR{disable|enable|debug} +Register cache policy +.TP +\fB\-\-range\-check=\fR{disable|enable} +Range check policy +.TP +\fB\-s\fR, \fB\-\-usb\-mode=\fR{sync|async} +USB device I/O mode +.HP +\fB\-d\fR, \fB\-\-debug=\fR{[:][,...]|help} +.TP +\fB\-v\fR, \fB\-\-version\fR +Show version .TP \fB\-\-display\fR=\fI\,DISPLAY\/\fR X display to use -.SH "SEE ALSO" -The full documentation for -.B arv-viewer-0.6 -is maintained as a Texinfo manual. If the -.B info -and -.B arv-viewer-0.6 -programs are properly installed at your site, the command -.IP -.B info arv-viewer-0.6 -.PP -should give you access to the complete manual. diff --git a/docs/meson.build b/docs/meson.build index 19abd99e2..26471cda3 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -1,4 +1,6 @@ install_man ('arv-tool-0.8.1') +install_man ('arv-test-0.8.1') +install_man ('arv-camera-test-0.8.1') if viewer_enabled install_man ('arv-viewer-0.8.1') diff --git a/docs/reference/aravis/building.md b/docs/reference/aravis/building.md index 4f848a778..0e4a399ca 100644 --- a/docs/reference/aravis/building.md +++ b/docs/reference/aravis/building.md @@ -9,7 +9,7 @@ you can build and install Aravis like [any other meson project](http://mesonbuild.com/Quick-guide.html#compiling-a-meson-project): ```sh -meson build +meson setup build cd build ninja ninja install @@ -23,6 +23,10 @@ On some platforms (like Ubuntu), you may have to configure the dynamic linker (ld) to let it know where the aravis libraries are installed, and run ldconfig as root in order to update ld cache. +```sh +sudo ldconfig +``` + ## Install dependencies on Ubuntu 20.04 Prior to running `meson` and `ninja`, dependencies can be installed using the @@ -32,7 +36,7 @@ following(tested on Ubuntu 20.04): sudo apt install libxml2-dev libglib2.0-dev cmake libusb-1.0-0-dev gobject-introspection \ libgtk-3-dev gtk-doc-tools xsltproc libgstreamer1.0-dev \ libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev \ - libgirepository1.0-dev + libgirepository1.0-dev gettext ``` ## Install dependencies on Fedora 34/35 @@ -43,7 +47,7 @@ installed on Fedora (tested on 34 and 35) with: sudo dnf install libxml2-devel glib2-devel cmake libusb1-devel gobject-introspection \ gobject-introspection-devel gstreamer1-plugins-base-devel gtk3-devel \ gtk-doc libxslt gstreamer1-devel gstreamer1-plugins-good python3-gobject \ - g++ meson + g++ meson gettext ``` ## Building on macOS @@ -54,7 +58,7 @@ settings (tested on macOS Catalina): ```sh brew install gettext intltool gtk-doc libxml2 meson libusb -meson build +meson setup build ninja -C build ``` @@ -63,7 +67,7 @@ packages: ```sh brew install gtk+3 gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad libnotify gnome-icon-theme -meson configure -Dviewer=enabled +meson configure -Dviewer=enabled build ``` ## Building on Windows @@ -101,7 +105,7 @@ crossroad install libnotify gstreamer gst-plugins-good gst-plugins-bad gst-plugi git clone https://github.com/AravisProject/aravis cd aravis # configure, crossroad adjusts meson for cross-compilation; build directory is created -crossroad meson build +crossroad meson setup build # compile and install ninja -C build install ``` @@ -119,21 +123,30 @@ informations: ``` export ARV_DEBUG=stream:3,device:3 ``` -Available categories are: - -* interface : Device lookup for each supported protocol -* device : Device control -* stream : Video stream management -* stream-thread : Video stream thread (likely high volume output) -* cp : Control protocol packets -* sp : Stream protocol packets (likely high volume output) -* genicam : Genicam specialized DOM elements -* policies : Genicam runtime configurable policies -* chunk : Chunk data code -* dom : Genicam DOM document -* evaluator : Expression evaluator -* viewer : Simple viewer application -* misc : Miscellaneous code -* all : Everything +Available debug level and categories are: +``` +Debug categories: +interface : Device lookup for each supported protocol +device : Device control +stream : Video stream management +stream-thread : Video stream thread (likely high volume output) +cp : Control protocol packets +sp : Stream protocol packets (likely high volume output) +genicam : Genicam specialized DOM elements +policies : Genicam runtime configurable policies +chunk : Chunk data code +dom : Genicam DOM document +evaluator : Expression evaluator +viewer : Simple viewer application +misc : Miscellaneous code +all : Everything + +Debug levels: +0: none +1: warning +2: info +3: debug +4: trace +``` diff --git a/src/arvbuffer.c b/src/arvbuffer.c index d5718a0a4..2d081141c 100644 --- a/src/arvbuffer.c +++ b/src/arvbuffer.c @@ -76,7 +76,7 @@ arv_buffer_new_full (size_t size, void *preallocated, void *user_data, GDestroyN ArvBuffer *buffer; buffer = g_object_new (ARV_TYPE_BUFFER, NULL); - buffer->priv->size = size; + buffer->priv->allocated_size = size; buffer->priv->user_data = user_data; buffer->priv->user_data_destroy_func = user_data_destroy_func; buffer->priv->chunk_endianness = G_BIG_ENDIAN; @@ -151,7 +151,7 @@ arv_buffer_get_data (ArvBuffer *buffer, size_t *size) g_return_val_if_fail (ARV_IS_BUFFER (buffer), NULL); if (size != NULL) - *size = buffer->priv->size; + *size = buffer->priv->received_size; return buffer->priv->data; } @@ -205,7 +205,7 @@ arv_buffer_get_chunk_data (ArvBuffer *buffer, guint64 chunk_id, size_t *size) g_return_val_if_fail (buffer->priv->data != NULL, NULL); data = buffer->priv->data; - offset = buffer->priv->size - sizeof (ArvChunkInfos); + offset = buffer->priv->allocated_size - sizeof (ArvChunkInfos); while (offset > 0) { guint32 id; guint32 chunk_size; @@ -561,7 +561,7 @@ arv_buffer_finalize (GObject *object) if (!buffer->priv->is_preallocated) { g_free (buffer->priv->data); buffer->priv->data = NULL; - buffer->priv->size = 0; + buffer->priv->allocated_size = 0; } if (buffer->priv->user_data && buffer->priv->user_data_destroy_func) diff --git a/src/arvbufferprivate.h b/src/arvbufferprivate.h index 9c5a53d46..cdf85e074 100644 --- a/src/arvbufferprivate.h +++ b/src/arvbufferprivate.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS typedef struct { - size_t size; + size_t allocated_size; gboolean is_preallocated; unsigned char *data; @@ -37,6 +37,7 @@ typedef struct { GDestroyNotify user_data_destroy_func; ArvBufferStatus status; + size_t received_size; ArvBufferPayloadType payload_type; diff --git a/src/arvcamera.c b/src/arvcamera.c index a1cbfdec4..213feee64 100644 --- a/src/arvcamera.c +++ b/src/arvcamera.c @@ -63,6 +63,7 @@ static void arv_camera_get_integer_bounds_as_double (ArvCamera *camera, const ch * @ARV_CAMERA_VENDOR_POINT_GREY_FLIR: PointGrey / FLIR * @ARV_CAMERA_VENDOR_XIMEA: XIMEA GmbH * @ARV_CAMERA_VENDOR_MATRIX_VISION: Matrix Vision GmbH + * @ARV_CAMERA_VENDOR_IMPERX: Imperx, Inc */ typedef enum { @@ -74,7 +75,8 @@ typedef enum { ARV_CAMERA_VENDOR_POINT_GREY_FLIR, ARV_CAMERA_VENDOR_RICOH, ARV_CAMERA_VENDOR_XIMEA, - ARV_CAMERA_VENDOR_MATRIX_VISION + ARV_CAMERA_VENDOR_MATRIX_VISION, + ARV_CAMERA_VENDOR_IMPERX } ArvCameraVendor; typedef enum { @@ -88,7 +90,9 @@ typedef enum { ARV_CAMERA_SERIES_POINT_GREY_FLIR, ARV_CAMERA_SERIES_RICOH, ARV_CAMERA_SERIES_XIMEA, - ARV_CAMERA_SERIES_MATRIX_VISION + ARV_CAMERA_SERIES_MATRIX_VISION, + ARV_CAMERA_SERIES_IMPERX_CHEETAH, + ARV_CAMERA_SERIES_IMPERX_OTHER } ArvCameraSeries; typedef struct { @@ -133,7 +137,7 @@ enum }; /** - * arv_camera_create_stream: + * arv_camera_create_stream: (skip) * @camera: a #ArvCamera * @callback: (scope call) (allow-none): a frame processing callback * @user_data: (closure) (allow-none): user data for @callback @@ -149,12 +153,34 @@ enum ArvStream * arv_camera_create_stream (ArvCamera *camera, ArvStreamCallback callback, gpointer user_data, GError **error) +{ + return arv_camera_create_stream_full(camera, callback, user_data, NULL, error); +} + +/** + * arv_camera_create_stream_full: (rename-to arv_camera_create_stream) + * @camera: a #ArvCamera + * @callback: (scope notified) (allow-none): a frame processing callback + * @user_data: (closure) (allow-none): user data for @callback + * @destroy: a #GDestroyNotify placeholder, %NULL to ignore + * @error: a #GError placeholder, %NULL to ignore + * + * Creates a new [class@ArvStream] for video stream reception. See + * [callback@ArvStreamCallback] for details regarding the callback function. + * + * Returns: (transfer full): a new [class@ArvStream], to be freed after use with [method@GObject.Object.unref]. + * + * Since: 0.8.23 + */ + +ArvStream * +arv_camera_create_stream_full (ArvCamera *camera, ArvStreamCallback callback, gpointer user_data, GDestroyNotify destroy, GError **error) { ArvCameraPrivate *priv = arv_camera_get_instance_private (camera); g_return_val_if_fail (ARV_IS_CAMERA (camera), NULL); - return arv_device_create_stream (priv->device, callback, user_data, error); + return arv_device_create_stream_full (priv->device, callback, user_data, destroy, error); } /* Device control */ @@ -1094,6 +1120,7 @@ arv_camera_set_frame_rate (ArvCamera *camera, double frame_rate, GError **error) case ARV_CAMERA_VENDOR_RICOH: case ARV_CAMERA_VENDOR_XIMEA: case ARV_CAMERA_VENDOR_MATRIX_VISION: + case ARV_CAMERA_VENDOR_IMPERX: case ARV_CAMERA_VENDOR_UNKNOWN: if (local_error == NULL) { if (arv_camera_is_feature_available (camera, "AcquisitionFrameRateEnable", &local_error)) { @@ -1155,6 +1182,7 @@ arv_camera_get_frame_rate (ArvCamera *camera, GError **error) case ARV_CAMERA_VENDOR_BASLER: case ARV_CAMERA_VENDOR_XIMEA: case ARV_CAMERA_VENDOR_MATRIX_VISION: + case ARV_CAMERA_VENDOR_IMPERX: case ARV_CAMERA_VENDOR_UNKNOWN: return arv_camera_get_float (camera, priv->has_acquisition_frame_rate ? @@ -1232,6 +1260,7 @@ arv_camera_get_frame_rate_bounds (ArvCamera *camera, double *min, double *max, G case ARV_CAMERA_VENDOR_BASLER: case ARV_CAMERA_VENDOR_XIMEA: case ARV_CAMERA_VENDOR_MATRIX_VISION: + case ARV_CAMERA_VENDOR_IMPERX: case ARV_CAMERA_VENDOR_UNKNOWN: arv_camera_get_float_bounds (camera, priv->has_acquisition_frame_rate ? @@ -1512,6 +1541,7 @@ arv_camera_set_exposure_time (ArvCamera *camera, double exposure_time_us, GError case ARV_CAMERA_SERIES_XIMEA: arv_camera_set_integer (camera, "ExposureTime", exposure_time_us, &local_error); break; + case ARV_CAMERA_SERIES_IMPERX_CHEETAH: case ARV_CAMERA_SERIES_MATRIX_VISION: arv_camera_set_string (camera, "ExposureMode", "Timed", &local_error); if (local_error == NULL) @@ -2000,6 +2030,7 @@ arv_camera_is_frame_rate_available (ArvCamera *camera, GError **error) case ARV_CAMERA_VENDOR_BASLER: case ARV_CAMERA_VENDOR_XIMEA: case ARV_CAMERA_VENDOR_MATRIX_VISION: + case ARV_CAMERA_VENDOR_IMPERX: case ARV_CAMERA_VENDOR_UNKNOWN: return arv_camera_is_feature_available (camera, priv->has_acquisition_frame_rate ? @@ -2026,11 +2057,13 @@ arv_camera_is_exposure_time_available (ArvCamera *camera, GError **error) g_return_val_if_fail (ARV_IS_CAMERA (camera), FALSE); - switch (priv->vendor) { - case ARV_CAMERA_VENDOR_XIMEA: + switch (priv->series) { + case ARV_CAMERA_SERIES_XIMEA: return arv_camera_is_feature_available (camera, "ExposureTime", error); - case ARV_CAMERA_VENDOR_RICOH: + case ARV_CAMERA_SERIES_RICOH: return arv_camera_is_feature_available (camera, "ExposureTimeRaw", error); + case ARV_CAMERA_SERIES_IMPERX_CHEETAH: + return arv_camera_is_feature_available (camera, "ExposureMode", error); default: return arv_camera_is_feature_available (camera, priv->has_exposure_time ? "ExposureTime" : "ExposureTimeAbs", @@ -3668,6 +3701,12 @@ arv_camera_constructed (GObject *object) } else if (g_strcmp0 (vendor_name, "MATRIX VISION GmbH") == 0) { vendor = ARV_CAMERA_VENDOR_MATRIX_VISION; series = ARV_CAMERA_SERIES_MATRIX_VISION; + } else if (g_strcmp0 (vendor_name, "Imperx, Inc") == 0) { + vendor = ARV_CAMERA_VENDOR_IMPERX; + if (g_str_has_prefix (model_name, "POE-C")) + series = ARV_CAMERA_SERIES_IMPERX_CHEETAH; + else + series = ARV_CAMERA_SERIES_IMPERX_OTHER; } else { vendor = ARV_CAMERA_VENDOR_UNKNOWN; series = ARV_CAMERA_SERIES_UNKNOWN; diff --git a/src/arvcamera.h b/src/arvcamera.h index fb718640d..8eb5b98bf 100644 --- a/src/arvcamera.h +++ b/src/arvcamera.h @@ -47,6 +47,7 @@ ARV_API ArvCamera * arv_camera_new_with_device (ArvDevice *device, GError **erro ARV_API ArvDevice * arv_camera_get_device (ArvCamera *camera); ARV_API ArvStream * arv_camera_create_stream (ArvCamera *camera, ArvStreamCallback callback, void *user_data, GError **error); +ARV_API ArvStream * arv_camera_create_stream_full (ArvCamera *camera, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error); /* Device informations */ diff --git a/src/arvcameratest.c b/src/arvcameratest.c index edcaed02c..4a4f36102 100644 --- a/src/arvcameratest.c +++ b/src/arvcameratest.c @@ -16,6 +16,7 @@ static int arv_option_horizontal_binning = -1; static int arv_option_vertical_binning = -1; static double arv_option_exposure_time_us = -1; static int arv_option_gain = -1; +static char *arv_option_features = NULL; static gboolean arv_option_auto_socket_buffer = FALSE; static char *arv_option_packet_size_adjustment = NULL; static gboolean arv_option_no_packet_resend = FALSE; @@ -36,6 +37,7 @@ static char *arv_option_range_check = NULL; static char *arv_option_access_check = NULL; static int arv_option_duration_s = -1; static char *arv_option_uv_usb_mode = NULL; +static gboolean arv_option_show_version = FALSE; /* clang-format off */ static const GOptionEntry arv_option_entries[] = @@ -95,6 +97,11 @@ static const GOptionEntry arv_option_entries[] = &arv_option_auto_socket_buffer, "Auto socket buffer size", NULL }, + { + "features", '\0', 0, G_OPTION_ARG_STRING, + &arv_option_features, "Additional configuration as a space separated list of features", + NULL + }, { "packet-size-adjustment", 'j', 0, G_OPTION_ARG_STRING, &arv_option_packet_size_adjustment, "Packet size adjustment", @@ -184,22 +191,31 @@ static const GOptionEntry arv_option_entries[] = { "bandwidth-limit", 'b', 0, G_OPTION_ARG_INT, &arv_option_bandwidth_limit, "Desired USB3 Vision device bandwidth limit", - NULL + "" }, { "duration", '\0', 0, G_OPTION_ARG_INT, &arv_option_duration_s, "Test duration (s)", - NULL + "" }, { "debug", 'd', 0, G_OPTION_ARG_STRING, - &arv_option_debug_domains, NULL, + &arv_option_debug_domains, "Debug output selection", "{[:][,...]|help}" }, + { + "version", 'v', 0, G_OPTION_ARG_NONE, + &arv_option_show_version, "Show version", + NULL + }, { NULL } }; /* clang-format on */ +static const char +description_content[] = +"This tool configures a camera and starts video streaming, infinitely unless a duration is given."; + typedef struct { GMainLoop *main_loop; @@ -244,14 +260,16 @@ new_buffer_cb (ArvStream *stream, ApplicationData *data) gint64 integer_value; GError *error = NULL; - integer_value = arv_chunk_parser_get_integer_value (data->chunk_parser, buffer, data->chunks[i], &error); + integer_value = arv_chunk_parser_get_integer_value (data->chunk_parser, + buffer, data->chunks[i], &error); if (error == NULL) g_print ("%s = %" G_GINT64_FORMAT "\n", data->chunks[i], integer_value); else { double float_value; g_clear_error (&error); - float_value = arv_chunk_parser_get_float_value (data->chunk_parser, buffer, data->chunks[i], &error); + float_value = arv_chunk_parser_get_float_value (data->chunk_parser, + buffer, data->chunks[i], &error); if (error == NULL) g_print ("%s = %g\n", data->chunks[i], float_value); else @@ -347,6 +365,8 @@ main (int argc, char **argv) data.chunk_parser = NULL; context = g_option_context_new (NULL); + g_option_context_set_summary (context, "Small utility for basic device checks."); + g_option_context_set_description (context, description_content); g_option_context_add_main_entries (context, arv_option_entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { @@ -358,6 +378,14 @@ main (int argc, char **argv) g_option_context_free (context); + if (arv_option_show_version) { + printf ("%u.%u.%u\n", + arv_get_major_version (), + arv_get_minor_version (), + arv_get_micro_version ()); + return EXIT_SUCCESS; + } + if (arv_option_register_cache == NULL) register_cache_policy = ARV_REGISTER_CACHE_POLICY_DEFAULT; else if (g_strcmp0 (arv_option_register_cache, "disable") == 0) @@ -518,6 +546,9 @@ main (int argc, char **argv) arv_camera_gv_set_packet_size_adjustment (camera, adjustment); } + if (error == NULL && arv_option_features != NULL) + arv_device_set_features_from_string (arv_camera_get_device (camera), arv_option_features, &error); + if (error != NULL) { printf ("Failed to configure the device: %s\n", error->message); g_clear_error (&error); diff --git a/src/arvdevice.c b/src/arvdevice.c index 684af47ed..d1f5b112d 100644 --- a/src/arvdevice.c +++ b/src/arvdevice.c @@ -66,7 +66,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ArvDevice, arv_device, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, arv_device_initable_iface_init)) /** - * arv_device_create_stream: + * arv_device_create_stream: (skip) * @device: a #ArvDevice * @callback: (scope call): a frame processing callback * @user_data: (allow-none) (closure): user data for @callback @@ -82,10 +82,32 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ArvDevice, arv_device, G_TYPE_OBJECT, ArvStream * arv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GError **error) +{ + return arv_device_create_stream_full(device, callback, user_data, NULL, error); +} + +/** + * arv_device_create_stream_full: (rename-to arv_device_create_stream) + * @device: a #ArvDevice + * @callback: (scope notified): a frame processing callback + * @user_data: (allow-none) (closure): user data for @callback + * @destroy: a #GDestroyNotify placeholder, %NULL to ignore + * @error: a #GError placeholder, %NULL to ignore + * + * Creates a new #ArvStream for video stream handling. See + * @ArvStreamCallback for details regarding the callback function. + * + * Return value: (transfer full): a new #ArvStream. + * + * Since: 0.8.23 + */ + +ArvStream * +arv_device_create_stream_full (ArvDevice *device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error) { g_return_val_if_fail (ARV_IS_DEVICE (device), NULL); - return ARV_DEVICE_GET_CLASS (device)->create_stream (device, callback, user_data, error); + return ARV_DEVICE_GET_CLASS (device)->create_stream (device, callback, user_data, destroy, error); } /** @@ -923,20 +945,48 @@ arv_device_set_features_from_string (ArvDevice *device, const char *string, GErr ArvGcNode *feature; char *key = g_match_info_fetch_named (match_info, "Key"); char *value = g_match_info_fetch_named (match_info, "Value"); - - feature = arv_device_get_feature (device, key); - if (ARV_IS_GC_FEATURE_NODE (feature)) { - if (ARV_IS_GC_COMMAND (feature)) { - arv_device_execute_command (device, key, &local_error); - } else if (value != NULL) { - arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (feature), value, &local_error); - } else { - g_set_error (&local_error, ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_INVALID_PARAMETER, - "[%s] Require a parameter value to set", key); - } - } else - g_set_error (&local_error, ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_FEATURE_NOT_FOUND, - "[%s] Not found", key); + size_t key_length = key != NULL ? strlen (key) : 0; + + if (key_length > 4 && key[0] == 'R' && key[1] == '[' && key[key_length - 1] == ']') { + char *end; + gint64 address; + gint64 int_value; + + address = g_ascii_strtoll (&key[2], &end, 0); + if (end == NULL || end != key + key_length -1) { + g_set_error (&local_error, + ARV_DEVICE_ERROR, + ARV_DEVICE_ERROR_INVALID_PARAMETER, + "Invalid address in %s", key); + } else { + int_value = g_ascii_strtoll (value, &end, 0); + if (end == NULL || end[0] != '\0') { + g_set_error (&local_error, + ARV_DEVICE_ERROR, + ARV_DEVICE_ERROR_INVALID_PARAMETER, + "Invalid %s value for %s", value, key); + } else { + arv_device_write_register (device, address, int_value, &local_error); + } + } + } else { + feature = arv_device_get_feature (device, key); + if (ARV_IS_GC_FEATURE_NODE (feature)) { + if (ARV_IS_GC_COMMAND (feature)) { + arv_device_execute_command (device, key, &local_error); + } else if (value != NULL) { + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (feature), + value, &local_error); + } else { + g_set_error (&local_error, + ARV_DEVICE_ERROR, + ARV_DEVICE_ERROR_INVALID_PARAMETER, + "[%s] Require a parameter value to set", key); + } + } else + g_set_error (&local_error, ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_FEATURE_NOT_FOUND, + "[%s] Not found", key); + } g_free (key); g_free (value); diff --git a/src/arvdevice.h b/src/arvdevice.h index a19a214a6..73179ef49 100644 --- a/src/arvdevice.h +++ b/src/arvdevice.h @@ -76,7 +76,7 @@ ARV_API G_DECLARE_DERIVABLE_TYPE (ArvDevice, arv_device, ARV, DEVICE, GObject) struct _ArvDeviceClass { GObjectClass parent_class; - ArvStream * (*create_stream) (ArvDevice *device, ArvStreamCallback callback, void *user_data, GError **error); + ArvStream * (*create_stream) (ArvDevice *device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error); const char * (*get_genicam_xml) (ArvDevice *device, size_t *size); ArvGc * (*get_genicam) (ArvDevice *device); @@ -91,6 +91,7 @@ struct _ArvDeviceClass { }; ARV_API ArvStream * arv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GError **error); +ARV_API ArvStream * arv_device_create_stream_full (ArvDevice *device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error); ARV_API gboolean arv_device_read_memory (ArvDevice *device, guint64 address, guint32 size, void *buffer, GError **error); ARV_API gboolean arv_device_write_memory (ArvDevice *device, guint64 address, guint32 size, void *buffer, GError **error); diff --git a/src/arvfakecamera.c b/src/arvfakecamera.c index 3d8fda1d9..27032a500 100644 --- a/src/arvfakecamera.c +++ b/src/arvfakecamera.c @@ -530,7 +530,7 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, switch (pixel_format) { case ARV_PIXEL_FORMAT_MONO_8: - if (height * width <= buffer->priv->size) { + if (height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned char *pixel = &buffer->priv->data [y * width + x]; @@ -541,11 +541,12 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, *pixel = CLAMP (pixel_value, 0, 255); } } + buffer->priv->received_size = height * width; } break; case ARV_PIXEL_FORMAT_MONO_16: - if (2 * height * width <= buffer->priv->size) { + if (2 * height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned short *pixel = (unsigned short *)&buffer->priv->data [2*y * width + 2*x]; @@ -556,11 +557,12 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, *pixel = CLAMP (pixel_value, 0, 65535); } } + buffer->priv->received_size = 2 * height * width; } break; case ARV_PIXEL_FORMAT_BAYER_BG_8: - if (height * width <= buffer->priv->size) { + if (height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned int index; @@ -586,11 +588,12 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, } } } + buffer->priv->received_size = height * width; } break; case ARV_PIXEL_FORMAT_BAYER_GB_8: - if (height * width <= buffer->priv->size) { + if (height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned int index; @@ -616,11 +619,12 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, } } } + buffer->priv->received_size = height * width; } break; case ARV_PIXEL_FORMAT_BAYER_GR_8: - if (height * width <= buffer->priv->size) { + if (height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned int index; @@ -646,11 +650,12 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, } } } + buffer->priv->received_size = height * width; } break; case ARV_PIXEL_FORMAT_BAYER_RG_8: - if (height * width <= buffer->priv->size) { + if (height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned int index; @@ -676,11 +681,12 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, } } } + buffer->priv->received_size = height * width; } break; case ARV_PIXEL_FORMAT_RGB_8_PACKED: - if (3 * height * width <= buffer->priv->size) { + if (3 * height * width <= buffer->priv->allocated_size) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { unsigned char *pixel = &buffer->priv->data [3 * (y * width + x)]; @@ -696,6 +702,7 @@ arv_fake_camera_diagonal_ramp (ArvBuffer *buffer, void *fill_pattern_data, pixel[2] = jet_colormap [index].b; } } + buffer->priv->received_size = 3 * height * width; } break; @@ -760,7 +767,7 @@ arv_fake_camera_fill_buffer (ArvFakeCamera *camera, ArvBuffer *buffer, guint32 * height = _get_register (camera, ARV_FAKE_CAMERA_REGISTER_HEIGHT); payload = arv_fake_camera_get_payload (camera); - if (buffer->priv->size < payload) { + if (buffer->priv->allocated_size < payload) { buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; return; } diff --git a/src/arvfakedevice.c b/src/arvfakedevice.c index 3fbc0ebd0..25b675a82 100644 --- a/src/arvfakedevice.c +++ b/src/arvfakedevice.c @@ -59,9 +59,9 @@ G_DEFINE_TYPE_WITH_CODE (ArvFakeDevice, arv_fake_device, ARV_TYPE_DEVICE, G_ADD_ /* ArvDevice implemenation */ static ArvStream * -arv_fake_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GError **error) +arv_fake_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error) { - return arv_fake_stream_new (ARV_FAKE_DEVICE (device), callback, user_data, error); + return arv_fake_stream_new (ARV_FAKE_DEVICE (device), callback, user_data, destroy, error); } static const char * diff --git a/src/arvfakestream.c b/src/arvfakestream.c index 3f1f82a60..a853667db 100644 --- a/src/arvfakestream.c +++ b/src/arvfakestream.c @@ -85,13 +85,14 @@ arv_fake_stream_thread (void *data) arv_fake_camera_wait_for_next_frame (thread_data->fake_camera); buffer = arv_stream_pop_input_buffer (thread_data->stream); if (buffer != NULL) { + buffer->priv->received_size = 0; if (thread_data->callback != NULL) thread_data->callback (thread_data->callback_data, ARV_STREAM_CALLBACK_TYPE_START_BUFFER, NULL); arv_fake_camera_fill_buffer (thread_data->fake_camera, buffer, NULL); - thread_data->n_transferred_bytes += buffer->priv->size; + thread_data->n_transferred_bytes += buffer->priv->allocated_size; if (buffer->priv->status == ARV_BUFFER_STATUS_SUCCESS) thread_data->n_completed_buffers++; @@ -161,12 +162,13 @@ arv_fake_stream_stop_thread (ArvStream *stream) */ ArvStream * -arv_fake_stream_new (ArvFakeDevice *device, ArvStreamCallback callback, void *callback_data, GError **error) +arv_fake_stream_new (ArvFakeDevice *device, ArvStreamCallback callback, void *callback_data, GDestroyNotify destroy, GError **error) { return g_initable_new (ARV_TYPE_FAKE_STREAM, NULL, error, "device", device, "callback", callback, "callback-data", callback_data, + "destroy-notify", destroy, NULL); } diff --git a/src/arvfakestreamprivate.h b/src/arvfakestreamprivate.h index cf444f417..4e02df98b 100644 --- a/src/arvfakestreamprivate.h +++ b/src/arvfakestreamprivate.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS -ArvStream * arv_fake_stream_new (ArvFakeDevice *device, ArvStreamCallback callback, void *callback_data, GError **error); +ArvStream * arv_fake_stream_new (ArvFakeDevice *device, ArvStreamCallback callback, void *callback_data, GDestroyNotify destroy, GError **error); G_END_DECLS diff --git a/src/arvgc.h b/src/arvgc.h index 3b53b8d03..89943f7d4 100644 --- a/src/arvgc.h +++ b/src/arvgc.h @@ -51,7 +51,8 @@ typedef enum { ARV_GC_ERROR_READ_ONLY, ARV_GC_ERROR_SET_FROM_STRING_UNDEFINED, ARV_GC_ERROR_GET_AS_STRING_UNDEFINED, - ARV_GC_ERROR_INVALID_BIT_RANGE + ARV_GC_ERROR_INVALID_BIT_RANGE, + ARV_GC_ERROR_INVALID_SYNTAX } ArvGcError; /** diff --git a/src/arvgcfeaturenode.c b/src/arvgcfeaturenode.c index 2cd027418..c706d57b9 100644 --- a/src/arvgcfeaturenode.c +++ b/src/arvgcfeaturenode.c @@ -455,13 +455,47 @@ arv_gc_feature_node_set_value_from_string (ArvGcFeatureNode *self, const char *s if (ARV_IS_GC_ENUMERATION (self)) { arv_gc_enumeration_set_string_value (ARV_GC_ENUMERATION (self), string, &local_error); } else if (ARV_IS_GC_INTEGER (self)) { - arv_gc_integer_set_value (ARV_GC_INTEGER (self), g_ascii_strtoll (string, NULL, 0), &local_error); + gint64 value; + char *end = NULL; + + value = g_ascii_strtoll (string, &end, 0); + + if (end == NULL || end[0] != '\0') { + g_set_error (error, ARV_GC_ERROR, ARV_GC_ERROR_INVALID_SYNTAX, + "Invalid string for an integer feature (%s)", string); + return; + } + + arv_gc_integer_set_value (ARV_GC_INTEGER (self), value, &local_error); } else if (ARV_IS_GC_FLOAT (self)) { - arv_gc_float_set_value (ARV_GC_FLOAT (self), g_ascii_strtod (string, NULL), &local_error); + double value; + char *end = NULL; + + value = g_ascii_strtod (string, &end); + + if (end == NULL || end[0] != '\0') { + g_set_error (error, ARV_GC_ERROR, ARV_GC_ERROR_INVALID_SYNTAX, + "Invalid string for a float feature (%s)", string); + return; + } + + arv_gc_float_set_value (ARV_GC_FLOAT (self), value, &local_error); } else if (ARV_IS_GC_STRING (self)) { arv_gc_string_set_value (ARV_GC_STRING (self), string, &local_error); } else if (ARV_IS_GC_BOOLEAN (self)) { - arv_gc_boolean_set_value (ARV_GC_BOOLEAN (self), g_strcmp0 (string, "true") == 0 ? 1 : 0, &local_error); + gboolean value; + + if (g_ascii_strcasecmp (string, "false") == 0 || g_ascii_strcasecmp (string, "0") == 0) + value = FALSE; + else if (g_ascii_strcasecmp (string, "true") == 0 || g_ascii_strcasecmp (string, "1") == 0) + value = TRUE; + else { + g_set_error (error, ARV_GC_ERROR, ARV_GC_ERROR_INVALID_SYNTAX, + "Invalid string for a boolean feature (%s)", string); + return; + } + + arv_gc_boolean_set_value (ARV_GC_BOOLEAN (self), value, &local_error); } else { g_set_error (&local_error, ARV_GC_ERROR, ARV_GC_ERROR_SET_FROM_STRING_UNDEFINED, "Don't know how to set value from string"); diff --git a/src/arvgcport.c b/src/arvgcport.c index 430c910ac..f7b74dca9 100644 --- a/src/arvgcport.c +++ b/src/arvgcport.c @@ -43,6 +43,8 @@ typedef struct { static ArvGvLegacyInfos arv_gc_port_legacy_infos[] = { { .vendor_selection = "Imperx", .model_selection = "IpxGEVCamera"}, + { .vendor_selection = "PleoraTechnologiesInc", .model_selection = "NTxGigE"}, + { .vendor_selection = "KowaOptronics", .model_selection = "SC130ET3"}, }; typedef struct { diff --git a/src/arvgcpropertynode.c b/src/arvgcpropertynode.c index 6bd59f56e..5f7099aef 100644 --- a/src/arvgcpropertynode.c +++ b/src/arvgcpropertynode.c @@ -111,6 +111,8 @@ arv_gc_property_node_get_node_name (ArvDomNode *node) return "Constant"; case ARV_GC_PROPERTY_NODE_TYPE_ACCESS_MODE: return "AccessMode"; + case ARV_GC_PROPERTY_NODE_TYPE_IMPOSED_ACCESS_MODE: + return "ImposedAccessMode"; case ARV_GC_PROPERTY_NODE_TYPE_CACHABLE: return "Cachable"; case ARV_GC_PROPERTY_NODE_TYPE_POLLING_TIME: diff --git a/src/arvgcstructentrynode.c b/src/arvgcstructentrynode.c index 046ac8468..12d63c68d 100644 --- a/src/arvgcstructentrynode.c +++ b/src/arvgcstructentrynode.c @@ -141,11 +141,16 @@ static ArvGcAccessMode arv_gc_struct_entry_node_get_access_mode (ArvGcFeatureNode *gc_feature_node) { ArvGcStructEntryNode *self = ARV_GC_STRUCT_ENTRY_NODE(gc_feature_node); + ArvDomNode *struct_register; - if (self->access_mode == NULL) - return ARV_GC_ACCESS_MODE_RO; + if (ARV_IS_GC_PROPERTY_NODE(self->access_mode)) + return arv_gc_property_node_get_access_mode (self->access_mode, ARV_GC_ACCESS_MODE_RO); - return arv_gc_property_node_get_access_mode (self->access_mode, ARV_GC_ACCESS_MODE_RO); + struct_register = arv_dom_node_get_parent_node (ARV_DOM_NODE (gc_feature_node)); + if (ARV_IS_GC_REGISTER_NODE (struct_register)) + return arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (struct_register)); + + return ARV_GC_ACCESS_MODE_RO; } static void diff --git a/src/arvgvdevice.c b/src/arvgvdevice.c index 72d6c5a97..489416e94 100644 --- a/src/arvgvdevice.c +++ b/src/arvgvdevice.c @@ -611,7 +611,7 @@ test_packet_check (ArvDevice *device, else read_count = 0; /* Discard late packets, read_count should be equal to packet size minus IP and UDP headers */ - } while (n_events != 0 && read_count != (packet_size - sizeof (struct iphdr) - sizeof (struct udphdr))); + } while (n_events != 0 && read_count != (packet_size - ARV_GVSP_PACKET_UDP_OVERHEAD)); n_tries++; } while (n_events == 0 && n_tries < 3); @@ -654,12 +654,11 @@ auto_packet_size (ArvGvDevice *gv_device, gboolean exit_early, GError **error) inc = 1; packet_size = arv_device_get_integer_feature_value (device, "GevSCPSPacketSize", NULL); arv_device_get_integer_feature_bounds (device, "GevSCPSPacketSize", &minimum, &maximum, NULL); - max_size = MIN (65536, maximum); - min_size = MAX (ARV_GVSP_PACKET_PROTOCOL_OVERHEAD, minimum); + max_size = MIN (ARV_GVSP_MAXIMUM_PACKET_SIZE, maximum); + min_size = MAX (ARV_GVSP_MINIMUM_PACKET_SIZE, minimum); if (max_size < min_size || - inc > max_size - min_size || - inc > 16) { + inc > max_size - min_size) { arv_warning_device ("[GvDevice::auto_packet_size] Invalid GevSCPSPacketSize properties"); return arv_device_get_integer_feature_value (device, "GevSCPSPacketSize", error); } @@ -700,18 +699,18 @@ auto_packet_size (ArvGvDevice *gv_device, gboolean exit_early, GError **error) "(%" G_GINT64_FORMAT " bytes)", packet_size); } else { - guint current_size = CLAMP (packet_size, min_size, max_size); + GError *local_error = NULL; + guint current_size = packet_size; do { - current_size = ((current_size + inc - 1) / inc) * inc; + if (current_size == last_size || + min_size + inc >= max_size) + break; arv_info_device ("[GvDevice::auto_packet_size] Try packet size = %d", current_size); arv_device_set_integer_feature_value (device, "GevSCPSPacketSize", current_size, NULL); - current_size = arv_device_get_integer_feature_value (device, "GevSCPSPacketSize", NULL); - - if (current_size == last_size) - break; + current_size = arv_device_get_integer_feature_value (device, "GevSCPSPacketSize", &local_error); last_size = current_size; @@ -720,19 +719,26 @@ auto_packet_size (ArvGvDevice *gv_device, gboolean exit_early, GError **error) if (success) { packet_size = current_size; + if (current_size == max_size) + break; + min_size = current_size; - current_size = (max_size - min_size) / 2 + min_size; } else { max_size = current_size; - current_size = (max_size - min_size) / 2 + min_size; } - } while ((max_size - min_size) > 16); - arv_device_set_integer_feature_value (device, "GevSCPSPacketSize", packet_size, error); + current_size = min_size + (((max_size - min_size) / 2 + 1) / inc) * inc; + } while (TRUE); - arv_info_device ("[GvDevice::auto_packet_size] Packet size set to %" G_GINT64_FORMAT " bytes", - packet_size); - } + if (local_error == NULL) { + arv_device_set_integer_feature_value (device, "GevSCPSPacketSize", packet_size, error); + + arv_info_device ("[GvDevice::auto_packet_size] Packet size set to %" G_GINT64_FORMAT " bytes", + packet_size); + } else { + g_propagate_error (error, local_error); + } + } g_clear_pointer (&buffer, g_free); g_clear_object (&socket); @@ -1607,7 +1613,7 @@ arv_gv_device_load_genicam (ArvGvDevice *gv_device, GError **error) /* ArvDevice implemenation */ static ArvStream * -arv_gv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GError **error) +arv_gv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error) { ArvGvDevice *gv_device = ARV_GV_DEVICE (device); ArvGvDevicePrivate *priv = arv_gv_device_get_instance_private (gv_device); @@ -1645,7 +1651,7 @@ arv_gv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void } } - stream = arv_gv_stream_new (gv_device, callback, user_data, error); + stream = arv_gv_stream_new (gv_device, callback, user_data, destroy, error); if (!ARV_IS_STREAM (stream)) return NULL; diff --git a/src/arvgvspprivate.h b/src/arvgvspprivate.h index 3350f4048..676a633ee 100644 --- a/src/arvgvspprivate.h +++ b/src/arvgvspprivate.h @@ -167,6 +167,12 @@ typedef struct { guint8 header[]; } ArvGvspPacket; +/* Minimum ethernet frame size minus ethernet protocol overhead */ +#define ARV_GVSP_MINIMUM_PACKET_SIZE (64 - 14 - 4) +/* Maximum ethernet frame size minus ethernet protocol overhead */ +#define ARV_GVSP_MAXIMUM_PACKET_SIZE (65536 - 14 - 4) + /* IP + UDP */ +#define ARV_GVSP_PACKET_UDP_OVERHEAD (20 + 8) /* IP + UDP + GVSP headers */ #define ARV_GVSP_PACKET_PROTOCOL_OVERHEAD (20 + 8 + sizeof (ArvGvspPacket) + sizeof (ArvGvspHeader)) /* IP + UDP + GVSP extended headers */ diff --git a/src/arvgvstream.c b/src/arvgvstream.c index cb7781ee8..26226938c 100644 --- a/src/arvgvstream.c +++ b/src/arvgvstream.c @@ -25,6 +25,7 @@ * @short_description: GigEVision stream */ +#include #include #include #include @@ -98,6 +99,8 @@ typedef struct { ArvBuffer *buffer; guint64 frame_id; + gsize received_size; + gint32 last_valid_packet; guint64 first_packet_time_us; guint64 last_packet_time_us; @@ -156,7 +159,7 @@ struct _ArvGvStreamThreadData { guint64 n_failures; guint64 n_underruns; guint64 n_timeouts; - guint64 n_aborteds; + guint64 n_aborted; guint64 n_missing_frames; guint64 n_size_mismatch_errors; @@ -227,9 +230,9 @@ _update_socket (ArvGvStreamThreadData *thread_data, ArvBuffer *buffer) break; case ARV_GV_STREAM_SOCKET_BUFFER_AUTO: if (thread_data->socket_buffer_size <= 0) - buffer_size = buffer->priv->size; + buffer_size = buffer->priv->allocated_size; else - buffer_size = MIN (buffer->priv->size, thread_data->socket_buffer_size); + buffer_size = MIN (buffer->priv->allocated_size, thread_data->socket_buffer_size); break; } @@ -320,19 +323,21 @@ _process_data_block (ArvGvStreamThreadData *thread_data, ARV_GVSP_PACKET_PROTOCOL_OVERHEAD)); block_end = block_size + block_offset; - if (block_end > frame->buffer->priv->size) { + if (block_end > frame->buffer->priv->allocated_size) { arv_info_stream_thread ("[GvStream::process_data_block] %" G_GINTPTR_FORMAT " unexpected bytes in packet %u " " for frame %" G_GUINT64_FORMAT, - block_end - frame->buffer->priv->size, + block_end - frame->buffer->priv->allocated_size, packet_id, frame->frame_id); thread_data->n_size_mismatch_errors++; - block_end = frame->buffer->priv->size; + block_end = frame->buffer->priv->allocated_size; block_size = block_end - block_offset; } memcpy (((char *) frame->buffer->priv->data) + block_offset, arv_gvsp_packet_get_data (packet), block_size); + frame->received_size += block_size; + if (frame->packet_data[packet_id].resend_requested) { thread_data->n_resent_packets++; arv_debug_stream_thread ("[GvStream::process_data_block] Received resent packet %u for frame %" G_GUINT64_FORMAT, @@ -348,16 +353,24 @@ _process_data_trailer (ArvGvStreamThreadData *thread_data, if (frame->buffer->priv->status != ARV_BUFFER_STATUS_FILLING) return; - if (packet_id != frame->n_packets - 1) { + if (packet_id > frame->n_packets - 1) { frame->buffer->priv->status = ARV_BUFFER_STATUS_WRONG_PACKET_ID; - return; - } + return; + } + + /* Trailer packet received before expected, because the actual payload size is smaller than the buffer size */ + if (frame->n_packets != packet_id + 1) { + arv_debug_stream_thread ("[GvStream::process_data_trailer] Update expected number of packets (%u → %u)", + frame->n_packets, packet_id + 1); + frame->n_packets = packet_id + 1; + } if (frame->packet_data[packet_id].resend_requested) { thread_data->n_resent_packets++; - arv_debug_stream_thread ("[GvStream::process_data_trailer] Received resent packet %u for frame %" G_GUINT64_FORMAT, - packet_id, frame->frame_id); - } + arv_debug_stream_thread ("[GvStream::process_data_trailer] Received resent packet %u for frame %" + G_GUINT64_FORMAT, + packet_id, frame->frame_id); + } } static ArvGvStreamFrameData * @@ -428,7 +441,8 @@ _find_frame_data (ArvGvStreamThreadData *thread_data, frame->buffer = buffer; _update_socket (thread_data, frame->buffer); frame->buffer->priv->status = ARV_BUFFER_STATUS_FILLING; - n_packets = (frame->buffer->priv->size + block_size - 1) / block_size + 2; + frame->buffer->priv->received_size = 0; + n_packets = (frame->buffer->priv->allocated_size + block_size - 1) / block_size + 2; frame->first_packet_time_us = time_us; frame->last_packet_time_us = time_us; @@ -566,7 +580,7 @@ _close_frame (ArvGvStreamThreadData *thread_data, thread_data->n_timeouts++; if (frame->buffer->priv->status == ARV_BUFFER_STATUS_ABORTED) - thread_data->n_aborteds++; + thread_data->n_aborted++; if (frame->buffer->priv->status != ARV_BUFFER_STATUS_SUCCESS && frame->buffer->priv->status != ARV_BUFFER_STATUS_ABORTED) @@ -618,6 +632,7 @@ _check_frame_completion (ArvGvStreamThreadData *thread_data, if (can_close_frame && frame->last_valid_packet == frame->n_packets - 1) { frame->buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; + frame->buffer->priv->received_size = frame->received_size; arv_debug_stream_thread ("[GvStream::check_frame_completion] Completed frame %" G_GUINT64_FORMAT, frame->frame_id); _close_frame (thread_data, time_us, frame); @@ -793,9 +808,8 @@ _loop (ArvGvStreamThreadData *thread_data) ArvGvspPacket *packet_buffers; GPollFD poll_fd[2]; guint64 time_us; - int n_msgs; gboolean use_poll; - unsigned i; + int i; GInputVector packet_iv[ARV_GV_STREAM_NUM_BUFFERS] = { {NULL, 0}, }; GInputMessage packet_im[ARV_GV_STREAM_NUM_BUFFERS] = { {NULL, NULL, 0, 0, 0, NULL, NULL}, }; // we don't need to consider the IP and UDP header size @@ -843,24 +857,34 @@ _loop (ArvGvStreamThreadData *thread_data) } while (n_events < 0 && errsv == EINTR); if (poll_fd[0].revents != 0) { + GError *error = NULL; + int n_msgs; + arv_gpollfd_clear_one (&poll_fd[0], thread_data->socket); n_msgs = g_socket_receive_messages (thread_data->socket, packet_im, ARV_GV_STREAM_NUM_BUFFERS, G_SOCKET_MSG_NONE, NULL, - NULL); - time_us = g_get_monotonic_time (); - for (i = 0; i < n_msgs; i++) { - frame = _process_packet (thread_data, - packet_iv[i].buffer, - packet_im[i].bytes_received, - time_us); - _check_frame_completion (thread_data, time_us, frame); - } - } else { - time_us = g_get_monotonic_time (); - _check_frame_completion (thread_data, time_us, NULL); + &error); + + if (G_LIKELY(n_msgs > 0)) { + time_us = g_get_monotonic_time (); + for (i = 0; i < n_msgs; i++) { + frame = _process_packet (thread_data, + packet_iv[i].buffer, + packet_im[i].bytes_received, + time_us); + _check_frame_completion (thread_data, time_us, frame); + } + } else { + arv_warning_stream_thread ("[GvStream::loop] receive_messages failed: %s", + error != NULL ? error->message : "Unknown reason"); + g_clear_error (&error); + } + } else { + time_us = g_get_monotonic_time (); + _check_frame_completion (thread_data, time_us, NULL); } } while (!g_cancellable_is_cancelled (thread_data->cancellable)); @@ -1247,12 +1271,13 @@ arv_gv_stream_stop_thread (ArvStream *stream) */ ArvStream * -arv_gv_stream_new (ArvGvDevice *gv_device, ArvStreamCallback callback, void *callback_data, GError **error) +arv_gv_stream_new (ArvGvDevice *gv_device, ArvStreamCallback callback, void *callback_data, GDestroyNotify destroy, GError **error) { return g_initable_new (ARV_TYPE_GV_STREAM, NULL, error, "device", gv_device, "callback", callback, "callback-data", callback_data, + "destroy-notify", destroy, NULL); } @@ -1457,8 +1482,8 @@ arv_gv_stream_constructed (GObject *object) G_TYPE_UINT64, &priv->thread_data->n_underruns); arv_stream_declare_info (ARV_STREAM (gv_stream), "n_timeouts", G_TYPE_UINT64, &priv->thread_data->n_timeouts); - arv_stream_declare_info (ARV_STREAM (gv_stream), "n_aborteds", - G_TYPE_UINT64, &priv->thread_data->n_aborteds); + arv_stream_declare_info (ARV_STREAM (gv_stream), "n_aborted", + G_TYPE_UINT64, &priv->thread_data->n_aborted); arv_stream_declare_info (ARV_STREAM (gv_stream), "n_missing_frames", G_TYPE_UINT64, &priv->thread_data->n_missing_frames); arv_stream_declare_info (ARV_STREAM (gv_stream), "n_size_mismatch_errors", @@ -1517,8 +1542,8 @@ arv_gv_stream_finalize (GObject *object) thread_data->n_underruns); arv_info_stream ("[GvStream::finalize] n_timeouts = %" G_GUINT64_FORMAT, thread_data->n_timeouts); - arv_info_stream ("[GvStream::finalize] n_aborteds = %" G_GUINT64_FORMAT, - thread_data->n_aborteds); + arv_info_stream ("[GvStream::finalize] n_aborted = %" G_GUINT64_FORMAT, + thread_data->n_aborted); arv_info_stream ("[GvStream::finalize] n_missing_frames = %" G_GUINT64_FORMAT, thread_data->n_missing_frames); diff --git a/src/arvgvstreamprivate.h b/src/arvgvstreamprivate.h index b49fc71b7..1493d228d 100644 --- a/src/arvgvstreamprivate.h +++ b/src/arvgvstreamprivate.h @@ -35,7 +35,7 @@ G_BEGIN_DECLS #define ARV_GV_STREAM_FRAME_RETENTION_US_DEFAULT 100000 #define ARV_GV_STREAM_PACKET_REQUEST_RATIO_DEFAULT 0.25 -ArvStream * arv_gv_stream_new (ArvGvDevice *gv_device, ArvStreamCallback callback, void *callback_data, GError **error); +ArvStream * arv_gv_stream_new (ArvGvDevice *gv_device, ArvStreamCallback callback, void *callback_data, GDestroyNotify destroy, GError **error); G_END_DECLS diff --git a/src/arvmisc.c b/src/arvmisc.c index c9b4edaa0..273129b0c 100644 --- a/src/arvmisc.c +++ b/src/arvmisc.c @@ -746,9 +746,16 @@ ArvGstCapsInfos arv_gst_caps_infos[] = { ARV_PIXEL_FORMAT_RGB_8_PACKED, "video/x-raw, format=(string)RGB", "video/x-raw", "RGB", - "video/x-raw-rgb, format=(string)RGB, bpp=(int)24, depth=(int)24", + "video/x-raw-rgb, format=(string)RGB, bpp=(int)24, depth=(int)8", "video/x-raw-rgb", 24, 24, 0 }, + { + ARV_PIXEL_FORMAT_RGBA_8_PACKED, + "video/x-raw, format=(string)RGBA", + "video/x-raw", "RGBA", + "video/x-raw-rgba, format=(string)RGBA, bpp=(int)32, depth=(int)8", + "video/x-raw-rgba", 32, 8, 0 + }, { ARV_PIXEL_FORMAT_CUSTOM_YUV_422_YUYV_PACKED, "video/x-raw, format=(string)YUY2", diff --git a/src/arvstream.c b/src/arvstream.c index 65bf86512..09b156a5e 100644 --- a/src/arvstream.c +++ b/src/arvstream.c @@ -55,7 +55,8 @@ enum { ARV_STREAM_PROPERTY_EMIT_SIGNALS, ARV_STREAM_PROPERTY_DEVICE, ARV_STREAM_PROPERTY_CALLBACK, - ARV_STREAM_PROPERTY_CALLBACK_DATA + ARV_STREAM_PROPERTY_CALLBACK_DATA, + ARV_STREAM_PROPERTY_DESTROY_NOTIFY } ArvStreamProperties; typedef struct { @@ -67,6 +68,7 @@ typedef struct { ArvDevice *device; ArvStreamCallback callback; void *callback_data; + GDestroyNotify destroy_notify; GError *init_error; @@ -660,6 +662,9 @@ arv_stream_set_property (GObject * object, guint prop_id, case ARV_STREAM_PROPERTY_CALLBACK_DATA: priv->callback_data = g_value_get_pointer (value); break; + case ARV_STREAM_PROPERTY_DESTROY_NOTIFY: + priv->destroy_notify = g_value_get_pointer (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -759,6 +764,10 @@ arv_stream_finalize (GObject *object) g_ptr_array_foreach (priv->infos, (GFunc) arv_stream_info_free, NULL); g_clear_pointer (&priv->infos, g_ptr_array_unref); + if (priv->destroy_notify != NULL) { + priv->destroy_notify(priv->callback_data); + } + G_OBJECT_CLASS (arv_stream_parent_class)->finalize (object); } @@ -824,6 +833,13 @@ arv_stream_class_init (ArvStreamClass *node_class) "Stream callback data", "Optional user callback data", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property + (object_class, + ARV_STREAM_PROPERTY_DESTROY_NOTIFY, + g_param_spec_pointer ("destroy-notify", + "Destroy notify", + "Optional destroy notify", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static gboolean diff --git a/src/arvtest.c b/src/arvtest.c index 1cd0dd9dc..7df3711b8 100644 --- a/src/arvtest.c +++ b/src/arvtest.c @@ -947,6 +947,7 @@ static char *arv_option_debug_domains = NULL; static char *arv_option_uv_usb_mode = NULL; static gboolean arv_option_cache_check = FALSE; static gboolean arv_option_packet_socket = FALSE; +static gboolean arv_option_show_version = FALSE; static const GOptionEntry arv_option_entries[] = { @@ -990,10 +991,15 @@ static const GOptionEntry arv_option_entries[] = &arv_option_debug_domains, NULL, "{[:][,...]|help}" }, + { + "version", 'v', 0, G_OPTION_ARG_NONE, + &arv_option_show_version, "Show version", + NULL + }, { NULL } }; -static const char *summary = +static const char *description_content = "arv-test is an automated test utility that tries to exercise most of the\n" "Aravis functionalities. By default it runs all the tests on all the detected\n" "devices, but devices and tests can be selected using a glob pattern.\n\n" @@ -1010,7 +1016,8 @@ main (int argc, char **argv) ArvUvUsbMode usb_mode; context = g_option_context_new (NULL); - g_option_context_set_summary (context, summary); + g_option_context_set_summary (context, "Automated test utillity."); + g_option_context_set_description (context, description_content); g_option_context_add_main_entries (context, arv_option_entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { @@ -1021,6 +1028,15 @@ main (int argc, char **argv) } g_option_context_free (context); + + if (arv_option_show_version) { + printf ("%u.%u.%u\n", + arv_get_major_version (), + arv_get_minor_version (), + arv_get_micro_version ()); + return EXIT_SUCCESS; + } + if (!arv_debug_enable (arv_option_debug_domains)) { if (g_strcmp0 (arv_option_debug_domains, "help") != 0) printf ("Invalid debug selection\n"); diff --git a/src/arvtool.c b/src/arvtool.c index 7e4b6d2a3..7a208d478 100644 --- a/src/arvtool.c +++ b/src/arvtool.c @@ -75,7 +75,7 @@ static const GOptionEntry arv_option_entries[] = }, { "version", 'v', 0, G_OPTION_ARG_NONE, - &arv_option_show_version, "Show library version", + &arv_option_show_version, "Show version", NULL }, { NULL } @@ -90,7 +90,7 @@ description_content[] = " values: list all available feature values\n" " description [] ...: show the full feature description\n" " control [=] ...: read/write device features\n" -" network [=]: read/write network settings\n" +" network [=]...: read/write network settings\n" "\n" "If no command is given, this utility will list all the available devices.\n" "For the control command, direct access to device registers is provided using a R[address] syntax" diff --git a/src/arvuvdevice.c b/src/arvuvdevice.c index f7767b469..b2c76629b 100644 --- a/src/arvuvdevice.c +++ b/src/arvuvdevice.c @@ -167,10 +167,10 @@ arv_uv_device_bulk_transfer (ArvUvDevice *uv_device, ArvUvEndpointType endpoint_ } static ArvStream * -arv_uv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GError **error) +arv_uv_device_create_stream (ArvDevice *device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, GError **error) { ArvUvDevicePrivate *priv = arv_uv_device_get_instance_private (ARV_UV_DEVICE (device)); - return arv_uv_stream_new (ARV_UV_DEVICE (device), callback, user_data, priv->usb_mode, error); + return arv_uv_stream_new (ARV_UV_DEVICE (device), callback, user_data, destroy, priv->usb_mode, error); } static gboolean @@ -914,6 +914,15 @@ arv_uv_device_constructed (GObject *object) g_mutex_init (&priv->transfer_mutex); + result = libusb_init (&priv->usb); + if (result != 0) { + arv_device_take_init_error (ARV_DEVICE (uv_device), + g_error_new (ARV_DEVICE_ERROR, ARV_DEVICE_ERROR_PROTOCOL_ERROR, + "Failed to initialize USB library: %s", + libusb_error_name (result))); + return; + } + if (priv->vendor != NULL) arv_info_device ("[UvDevice::new] Vendor = %s", priv->vendor); if (priv->product != NULL) @@ -923,7 +932,6 @@ arv_uv_device_constructed (GObject *object) if (priv->guid != NULL) arv_info_device ("[UvDevice::new] GUID = %s", priv->guid); - libusb_init (&priv->usb); priv->packet_id = 65300; /* Start near the end of the circular counter */ priv->timeout_ms = 32; @@ -1023,7 +1031,8 @@ arv_uv_device_finalize (GObject *object) libusb_release_interface (priv->usb_device, priv->data_interface); libusb_close (priv->usb_device); } - libusb_exit (priv->usb); + if (priv->usb != NULL) + libusb_exit (priv->usb); g_mutex_clear (&priv->transfer_mutex); G_OBJECT_CLASS (arv_uv_device_parent_class)->finalize (object); diff --git a/src/arvuvinterface.c b/src/arvuvinterface.c index 68f884840..57dda3d65 100644 --- a/src/arvuvinterface.c +++ b/src/arvuvinterface.c @@ -173,11 +173,12 @@ _usb_device_to_device_ids (ArvUvInterface *uv_interface, libusb_device *device) gboolean control_protocol_found; gboolean data_protocol_found; int guid_index = -1; - int r, i, j; + int result, i, j; - r = libusb_get_device_descriptor (device, &desc); - if (r < 0) { - arv_warning_interface ("Failed to get device descriptor"); + result = libusb_get_device_descriptor (device, &desc); + if (result < 0) { + arv_warning_interface ("Failed to get device descriptor: %s", + libusb_error_name (result)); return NULL; } @@ -212,7 +213,8 @@ _usb_device_to_device_ids (ArvUvInterface *uv_interface, libusb_device *device) if (!control_protocol_found || !data_protocol_found) return NULL; - if (libusb_open (device, &device_handle) == LIBUSB_SUCCESS) { + result = libusb_open (device, &device_handle); + if (result == LIBUSB_SUCCESS) { ArvUvInterfaceDeviceInfos *device_infos; unsigned char *manufacturer; unsigned char *product; @@ -267,7 +269,8 @@ _usb_device_to_device_ids (ArvUvInterface *uv_interface, libusb_device *device) libusb_close (device_handle); } else - arv_warning_interface ("Failed to open USB device"); + arv_warning_interface ("Failed to open USB device: %s", + libusb_error_name (result)); return device_ids; } @@ -277,19 +280,22 @@ _discover (ArvUvInterface *uv_interface, GArray *device_ids) { libusb_device **devices; unsigned uv_count = 0; - ssize_t count; + ssize_t result; unsigned i; - count = libusb_get_device_list(uv_interface->priv->usb, &devices); - if (count < 0) { - arv_warning_interface ("[[UvInterface:_discover] Failed to get USB device list: %s", - libusb_error_name (count)); + if (uv_interface->priv->usb == NULL) + return; + + result = libusb_get_device_list(uv_interface->priv->usb, &devices); + if (result < 0) { + arv_warning_interface ("Failed to get USB device list: %s", + libusb_error_name (result)); return; } g_hash_table_remove_all (uv_interface->priv->devices); - for (i = 0; i < count; i++) { + for (i = 0; i < result; i++) { ArvInterfaceDeviceIds *ids; ids = _usb_device_to_device_ids (uv_interface, devices[i]); @@ -312,7 +318,7 @@ _discover (ArvUvInterface *uv_interface, GArray *device_ids) arv_info_interface ("Found %d USB3Vision device%s (among %" G_GSSIZE_FORMAT " USB device%s)", uv_count , uv_count > 1 ? "s" : "", - count, count > 1 ? "s" : ""); + result, result > 1 ? "s" : ""); libusb_free_device_list (devices, 1); } @@ -407,9 +413,15 @@ G_DEFINE_TYPE_WITH_CODE (ArvUvInterface, arv_uv_interface, ARV_TYPE_INTERFACE, G static void arv_uv_interface_init (ArvUvInterface *uv_interface) { + int result; + uv_interface->priv = arv_uv_interface_get_instance_private (uv_interface); - libusb_init (&uv_interface->priv->usb); + result = libusb_init (&uv_interface->priv->usb); + if (result != 0) + arv_warning_interface ("Failed to initialize USB library: %s", + libusb_error_name (result)); + uv_interface->priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) arv_uv_interface_device_infos_unref); } @@ -423,7 +435,8 @@ arv_uv_interface_finalize (GObject *object) G_OBJECT_CLASS (arv_uv_interface_parent_class)->finalize (object); - libusb_exit (uv_interface->priv->usb); + if (uv_interface->priv->usb != NULL) + libusb_exit (uv_interface->priv->usb); } static void diff --git a/src/arvuvstream.c b/src/arvuvstream.c index 5bf4d172f..a100465ec 100644 --- a/src/arvuvstream.c +++ b/src/arvuvstream.c @@ -50,6 +50,7 @@ typedef struct { guint64 n_completed_buffers; guint64 n_failures; guint64 n_underruns; + guint64 n_aborted; guint64 n_transferred_bytes; guint64 n_ignored_bytes; @@ -62,8 +63,11 @@ typedef struct { ArvStreamCallback callback; void *callback_data; + size_t expected_size; size_t leader_size; size_t payload_size; + guint32 payload_count; + size_t transfer1_size; size_t trailer_size; gboolean cancel; @@ -99,6 +103,7 @@ typedef struct { GCond* transfer_completed_event; size_t total_payload_transferred; + size_t expected_size; guint8 *leader_buffer, *trailer_buffer; @@ -109,6 +114,8 @@ typedef struct { gint *total_submitted_bytes; + gboolean is_aborting; + ArvStreamStatistics *statistics; } ArvUvStreamBufferContext; @@ -137,9 +144,12 @@ void arv_uv_stream_leader_cb (struct libusb_transfer *transfer) ArvUvspPacket *packet = (ArvUvspPacket*)transfer->buffer; if (ctx->buffer != NULL) { - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - arv_uvsp_packet_debug (packet, ARV_DEBUG_LEVEL_DEBUG); + if (ctx->is_aborting) { + ctx->buffer->priv->status = ARV_BUFFER_STATUS_ABORTED; + } else { + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + arv_uvsp_packet_debug (packet, ARV_DEBUG_LEVEL_DEBUG); if (arv_uvsp_packet_get_packet_type (packet) != ARV_UVSP_PACKET_TYPE_LEADER) { arv_warning_stream_thread ("Unexpected packet type (was expecting leader packet)"); @@ -161,9 +171,11 @@ void arv_uv_stream_leader_cb (struct libusb_transfer *transfer) ctx->buffer->priv->timestamp_ns = arv_uvsp_packet_get_timestamp (packet); break; default: - arv_warning_stream_thread ("Leader transfer failed: transfer->status = %d", transfer->status); + arv_warning_stream_thread ("Leader transfer failed: transfer->status = %d", + transfer->status); ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; break; + } } } @@ -179,14 +191,19 @@ void arv_uv_stream_payload_cb (struct libusb_transfer *transfer) ArvUvStreamBufferContext *ctx = transfer->user_data; if (ctx->buffer != NULL) { - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - ctx->total_payload_transferred += transfer->actual_length; - break; - default: - arv_warning_stream_thread ("Payload transfer failed: transfer->status = %d", transfer->status); - ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; - break; + if (ctx->is_aborting) { + ctx->buffer->priv->status = ARV_BUFFER_STATUS_ABORTED; + } else { + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + ctx->total_payload_transferred += transfer->actual_length; + break; + default: + arv_warning_stream_thread ("Payload transfer failed: transfer->status = %d", + transfer->status); + ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; + break; + } } } @@ -203,38 +220,47 @@ void arv_uv_stream_trailer_cb (struct libusb_transfer *transfer) ArvUvspPacket *packet = (ArvUvspPacket*)transfer->buffer; if (ctx->buffer != NULL) { - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - arv_uvsp_packet_debug (packet, ARV_DEBUG_LEVEL_DEBUG); + if (ctx->is_aborting) { + ctx->buffer->priv->status = ARV_BUFFER_STATUS_ABORTED; + ctx->statistics->n_aborted += 1; + } else { + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + arv_uvsp_packet_debug (packet, ARV_DEBUG_LEVEL_DEBUG); + + if (arv_uvsp_packet_get_packet_type (packet) != ARV_UVSP_PACKET_TYPE_TRAILER) { + arv_warning_stream_thread ("Unexpected packet type (was expecting trailer packet)"); + ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; + break; + } - if (arv_uvsp_packet_get_packet_type (packet) != ARV_UVSP_PACKET_TYPE_TRAILER) { - arv_warning_stream_thread ("Unexpected packet type (was expecting trailer packet)"); - ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; - break; - } + arv_debug_stream_thread ("Total payload: %zu bytes", ctx->total_payload_transferred); + if (ctx->total_payload_transferred != ctx->expected_size) { + arv_warning_stream_thread ("Unexpected total payload size (received %" + G_GSIZE_FORMAT " - expected %" G_GSIZE_FORMAT")", + ctx->total_payload_transferred, ctx->expected_size); + ctx->buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; + break; + } - arv_debug_stream_thread ("Total payload: %zu bytes", ctx->total_payload_transferred); - if (ctx->total_payload_transferred < ctx->buffer->priv->size) { - arv_warning_stream_thread ("Total payload smaller than expected"); + break; + default: + arv_warning_stream_thread ("Trailer transfer failed: transfer->status = %d", + transfer->status); ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; break; - } - - break; - default: - arv_warning_stream_thread ("Trailer transfer failed: transfer->status = %d", transfer->status); - ctx->buffer->priv->status = ARV_BUFFER_STATUS_MISSING_PACKETS; - break; - } + } - switch (ctx->buffer->priv->status) { - case ARV_BUFFER_STATUS_FILLING: - ctx->buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; - ctx->statistics->n_completed_buffers += 1; - break; - default: - ctx->statistics->n_failures += 1; - break; + switch (ctx->buffer->priv->status) { + case ARV_BUFFER_STATUS_FILLING: + ctx->buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; + ctx->buffer->priv->received_size = ctx->total_payload_transferred; + ctx->statistics->n_completed_buffers += 1; + break; + default: + ctx->statistics->n_failures += 1; + break; + } } arv_stream_push_output_buffer (ctx->stream, ctx->buffer); @@ -250,7 +276,7 @@ void arv_uv_stream_trailer_cb (struct libusb_transfer *transfer) static ArvUvStreamBufferContext* arv_uv_stream_buffer_context_new (ArvBuffer *buffer, ArvUvStreamThreadData *thread_data, gint *total_submitted_bytes) { - ArvUvStreamBufferContext* ctx = g_malloc (sizeof(ArvUvStreamBufferContext)); + ArvUvStreamBufferContext* ctx = g_malloc0 (sizeof(ArvUvStreamBufferContext)); int i; size_t offset = 0; @@ -267,11 +293,11 @@ arv_uv_stream_buffer_context_new (ArvBuffer *buffer, ArvUvStreamThreadData *thre arv_uv_stream_leader_cb, ctx, 0); - ctx->num_payload_transfers = (buffer->priv->size - 1) / thread_data->payload_size + 1; + ctx->num_payload_transfers = (buffer->priv->allocated_size - 1) / thread_data->payload_size + 1; ctx->payload_transfers = g_malloc (ctx->num_payload_transfers * sizeof(struct libusb_transfer*)); for (i = 0; i < ctx->num_payload_transfers; ++i) { - size_t size = MIN (thread_data->payload_size, buffer->priv->size - offset); + size_t size = MIN (thread_data->payload_size, buffer->priv->allocated_size - offset); ctx->payload_transfers[i] = libusb_alloc_transfer(0); @@ -364,7 +390,7 @@ _submit_transfer (ArvUvStreamBufferContext* ctx, struct libusb_transfer* transfe } static void -arv_uv_stream_buffer_context_submit (ArvUvStreamBufferContext* ctx, ArvBuffer *buffer, gboolean *cancel) +arv_uv_stream_buffer_context_submit (ArvUvStreamBufferContext* ctx, ArvBuffer *buffer, ArvUvStreamThreadData *thread_data) { int i; @@ -372,13 +398,15 @@ arv_uv_stream_buffer_context_submit (ArvUvStreamBufferContext* ctx, ArvBuffer *b ctx->total_payload_transferred = 0; buffer->priv->status = ARV_BUFFER_STATUS_FILLING; - _submit_transfer (ctx, ctx->leader_transfer, cancel); + ctx->expected_size = thread_data->expected_size; + + _submit_transfer (ctx, ctx->leader_transfer, &thread_data->cancel); for (i = 0; i < ctx->num_payload_transfers; ++i) { - _submit_transfer (ctx, ctx->payload_transfers[i], cancel); + _submit_transfer (ctx, ctx->payload_transfers[i], &thread_data->cancel); } - _submit_transfer (ctx, ctx->trailer_transfer, cancel); + _submit_transfer (ctx, ctx->trailer_transfer, &thread_data->cancel); } static void @@ -387,6 +415,8 @@ arv_uv_stream_buffer_context_cancel (gpointer key, gpointer value, gpointer user ArvUvStreamBufferContext* ctx = value; int i; + ctx->is_aborting = TRUE; + libusb_cancel_transfer (ctx->leader_transfer ); for (i = 0; i < ctx->num_payload_transfers; ++i) { @@ -441,7 +471,7 @@ arv_uv_stream_thread_async (void *data) g_hash_table_insert (ctx_lookup, buffer, ctx); } - arv_uv_stream_buffer_context_submit (ctx, buffer, &thread_data->cancel); + arv_uv_stream_buffer_context_submit (ctx, buffer, thread_data); } g_hash_table_foreach (ctx_lookup, arv_uv_stream_buffer_context_cancel, NULL); @@ -483,8 +513,8 @@ arv_uv_stream_thread_sync (void *data) if (buffer == NULL) size = ARV_UV_STREAM_MAXIMUM_TRANSFER_SIZE; else { - if (offset < buffer->priv->size) - size = MIN (thread_data->payload_size, buffer->priv->size - offset); + if (offset < buffer->priv->allocated_size) + size = MIN (thread_data->payload_size, buffer->priv->allocated_size - offset); else size = thread_data->trailer_size; } @@ -492,7 +522,7 @@ arv_uv_stream_thread_sync (void *data) /* Avoid unnecessary memory copy by transferring data directly to the image buffer */ if (buffer != NULL && buffer->priv->status == ARV_BUFFER_STATUS_FILLING && - offset + size <= buffer->priv->size) + offset + size <= buffer->priv->allocated_size) packet = (ArvUvspPacket *) (buffer->priv->data + offset); else packet = incoming_buffer; @@ -504,6 +534,8 @@ arv_uv_stream_thread_sync (void *data) if (error != NULL) { arv_warning_sp ("USB transfer error: %s", error->message); g_clear_error (&error); + } else if (transferred < 1) { + arv_warning_sp ("No data transferred"); } else { ArvUvspPacketType packet_type; @@ -528,6 +560,7 @@ arv_uv_stream_thread_sync (void *data) if (buffer != NULL) { buffer->priv->system_timestamp_ns = g_get_real_time () * 1000LL; buffer->priv->status = ARV_BUFFER_STATUS_FILLING; + buffer->priv->received_size = 0; buffer->priv->payload_type = arv_uvsp_packet_get_buffer_payload_type (packet); buffer->priv->chunk_endianness = G_LITTLE_ENDIAN; if (buffer->priv->payload_type == ARV_BUFFER_PAYLOAD_TYPE_IMAGE || @@ -554,63 +587,64 @@ arv_uv_stream_thread_sync (void *data) break; case ARV_UVSP_PACKET_TYPE_TRAILER: if (buffer != NULL) { - arv_debug_stream_thread ("Received %" G_GUINT64_FORMAT - " bytes - expected %zu", - offset, buffer->priv->size); - - /* If the image was incomplete, drop the frame and try again. */ - if (offset != buffer->priv->size) { - arv_info_stream_thread ("Incomplete image received, dropping " - "(received %" G_GUINT64_FORMAT - " / expected %" G_GSIZE_FORMAT ")", - offset, buffer->priv->size); - - buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; - arv_stream_push_output_buffer (thread_data->stream, buffer); - if (thread_data->callback != NULL) - thread_data->callback (thread_data->callback_data, - ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE, - buffer); - thread_data->statistics.n_failures++; - thread_data->statistics.n_ignored_bytes += transferred; - buffer = NULL; - } else { - buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; - arv_stream_push_output_buffer (thread_data->stream, buffer); - if (thread_data->callback != NULL) - thread_data->callback (thread_data->callback_data, - ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE, - buffer); + arv_debug_stream_thread ("Received %" G_GUINT64_FORMAT " bytes", + offset); + + if (offset != thread_data->expected_size) { + arv_info_stream_thread ("Incomplete image received, dropping " + "(received %" G_GUINT64_FORMAT + " / expected %" G_GSIZE_FORMAT ")", + offset, thread_data->expected_size); + + buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; + arv_stream_push_output_buffer (thread_data->stream, buffer); + if (thread_data->callback != NULL) + thread_data->callback (thread_data->callback_data, + ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE, + buffer); + thread_data->statistics.n_failures++; + thread_data->statistics.n_ignored_bytes += transferred; + buffer = NULL; + } else { + buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; + buffer->priv->received_size = offset; + arv_stream_push_output_buffer (thread_data->stream, buffer); + if (thread_data->callback != NULL) + thread_data->callback (thread_data->callback_data, + ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE, + buffer); thread_data->statistics.n_completed_buffers++; thread_data->statistics.n_transferred_bytes += transferred; buffer = NULL; } - } - break; - case ARV_UVSP_PACKET_TYPE_DATA: - if (buffer != NULL && buffer->priv->status == ARV_BUFFER_STATUS_FILLING) { - if (offset + transferred <= buffer->priv->size) { - if (packet == incoming_buffer) - memcpy (((char *) buffer->priv->data) + offset, packet, transferred); - offset += transferred; + } + break; + case ARV_UVSP_PACKET_TYPE_DATA: + if (buffer != NULL && buffer->priv->status == ARV_BUFFER_STATUS_FILLING) { + if (offset + transferred <= buffer->priv->allocated_size) { + if (packet == incoming_buffer) + memcpy (((char *) buffer->priv->data) + offset, + packet, transferred); + offset += transferred; thread_data->statistics.n_transferred_bytes += transferred; - } else { - buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; + } else { + buffer->priv->status = ARV_BUFFER_STATUS_SIZE_MISMATCH; thread_data->statistics.n_ignored_bytes += transferred; } - } else { - thread_data->statistics.n_ignored_bytes += transferred; + } else { + thread_data->statistics.n_ignored_bytes += transferred; } - break; - default: - arv_info_stream_thread ("Unknown packet type"); - break; - } - } - } + break; + default: + arv_info_stream_thread ("Unknown packet type"); + break; + } + } + } if (buffer != NULL) { buffer->priv->status = ARV_BUFFER_STATUS_ABORTED; + thread_data->statistics.n_aborted++; arv_stream_push_output_buffer (thread_data->stream, buffer); if (thread_data->callback != NULL) thread_data->callback (thread_data->callback_data, @@ -656,6 +690,8 @@ arv_uv_stream_start_thread (ArvStream *stream) guint32 si_payload_count; guint32 si_transfer1_size; guint32 si_transfer2_size; + guint32 si_leader_size; + guint32 si_trailer_size; guint32 si_control; guint32 alignment; guint32 aligned_maximum_transfer_size; @@ -693,27 +729,27 @@ arv_uv_stream_start_thread (ArvStream *stream) if (si_req_leader_size < 1) { arv_warning_stream ("Wrong SI_REQ_LEADER_SIZE value, using %d instead", aligned_maximum_transfer_size); - si_req_leader_size = aligned_maximum_transfer_size; + si_leader_size = aligned_maximum_transfer_size; } else { - si_req_leader_size = align (si_req_leader_size, alignment); + si_leader_size = align (si_req_leader_size, alignment); } if (si_req_trailer_size < 1) { arv_warning_stream ("Wrong SI_REQ_TRAILER_SIZE value, using %d instead", aligned_maximum_transfer_size); - si_req_trailer_size = aligned_maximum_transfer_size; + si_trailer_size = aligned_maximum_transfer_size; } else { - si_req_trailer_size = align (si_req_trailer_size, alignment); + si_trailer_size = align (si_req_trailer_size, alignment); } - si_payload_size = aligned_maximum_transfer_size; + si_payload_size = MIN(si_req_payload_size , aligned_maximum_transfer_size); si_payload_count= si_req_payload_size / si_payload_size; si_transfer1_size = align(si_req_payload_size % si_payload_size, alignment); si_transfer2_size = 0; arv_device_write_memory (device, sirm_offset + ARV_SIRM_MAX_LEADER_SIZE, - sizeof (si_req_leader_size), &si_req_leader_size, NULL); + sizeof (si_leader_size), &si_leader_size, NULL); arv_device_write_memory (device, sirm_offset + ARV_SIRM_MAX_TRAILER_SIZE, - sizeof (si_req_trailer_size), &si_req_trailer_size, NULL); + sizeof (si_trailer_size), &si_trailer_size, NULL); arv_device_write_memory (device, sirm_offset + ARV_SIRM_PAYLOAD_SIZE, sizeof (si_payload_size), &si_payload_size, NULL); arv_device_write_memory (device, sirm_offset + ARV_SIRM_PAYLOAD_COUNT, @@ -727,15 +763,18 @@ arv_uv_stream_start_thread (ArvStream *stream) arv_info_stream ("SIRM_PAYLOAD_COUNT = 0x%08x", si_payload_count); arv_info_stream ("SIRM_TRANSFER1_SIZE = 0x%08x", si_transfer1_size); arv_info_stream ("SIRM_TRANSFER2_SIZE = 0x%08x", si_transfer2_size); - arv_info_stream ("SIRM_MAX_LEADER_SIZE = 0x%08x", si_req_leader_size); - arv_info_stream ("SIRM_MAX_TRAILER_SIZE = 0x%08x", si_req_trailer_size); + arv_info_stream ("SIRM_MAX_LEADER_SIZE = 0x%08x", si_leader_size); + arv_info_stream ("SIRM_MAX_TRAILER_SIZE = 0x%08x", si_trailer_size); si_control = ARV_SIRM_CONTROL_STREAM_ENABLE; arv_device_write_memory (device, sirm_offset + ARV_SIRM_CONTROL, sizeof (si_control), &si_control, NULL); - thread_data->leader_size = si_req_leader_size; + thread_data->expected_size = si_req_payload_size; + thread_data->leader_size = si_leader_size; thread_data->payload_size = si_payload_size; - thread_data->trailer_size = si_req_trailer_size; + thread_data->payload_count = si_payload_count; + thread_data->transfer1_size = si_transfer1_size; + thread_data->trailer_size = si_trailer_size; thread_data->cancel = FALSE; switch (priv->usb_mode) { @@ -792,13 +831,14 @@ arv_uv_stream_stop_thread (ArvStream *stream) */ ArvStream * -arv_uv_stream_new (ArvUvDevice *uv_device, ArvStreamCallback callback, void *callback_data, +arv_uv_stream_new (ArvUvDevice *uv_device, ArvStreamCallback callback, void *callback_data, GDestroyNotify destroy, ArvUvUsbMode usb_mode, GError **error) { return g_initable_new (ARV_TYPE_UV_STREAM, NULL, error, "device", uv_device, "callback", callback, "callback-data", callback_data, + "destroy-notify", destroy, "usb-mode", usb_mode, NULL); } @@ -822,6 +862,7 @@ arv_uv_stream_constructed (GObject *object) thread_data->statistics.n_completed_buffers = 0; thread_data->statistics.n_failures = 0; thread_data->statistics.n_underruns = 0; + thread_data->statistics.n_aborted = 0; thread_data->statistics.n_transferred_bytes = 0; thread_data->statistics.n_ignored_bytes = 0; @@ -839,6 +880,8 @@ arv_uv_stream_constructed (GObject *object) G_TYPE_UINT64, &thread_data->statistics.n_failures); arv_stream_declare_info (ARV_STREAM (uv_stream), "n_underruns", G_TYPE_UINT64, &thread_data->statistics.n_underruns); + arv_stream_declare_info (ARV_STREAM (uv_stream), "n_aborted", + G_TYPE_UINT64, &thread_data->statistics.n_aborted); arv_stream_declare_info (ARV_STREAM (uv_stream), "n_transferred_bytes", G_TYPE_UINT64, &thread_data->statistics.n_transferred_bytes); arv_stream_declare_info (ARV_STREAM (uv_stream), "n_ignored_bytes", @@ -890,6 +933,8 @@ arv_uv_stream_finalize (GObject *object) thread_data->statistics.n_failures); arv_info_stream ("[UvStream::finalize] n_underruns = %" G_GUINT64_FORMAT, thread_data->statistics.n_underruns); + arv_info_stream ("[UvStream::finalize] n_aborted = %" G_GUINT64_FORMAT, + thread_data->statistics.n_aborted); arv_info_stream ("[UvStream::finalize] n_transferred_bytes = %" G_GUINT64_FORMAT, thread_data->statistics.n_transferred_bytes); diff --git a/src/arvuvstreamprivate.h b/src/arvuvstreamprivate.h index 625a37b52..337bc6a6b 100644 --- a/src/arvuvstreamprivate.h +++ b/src/arvuvstreamprivate.h @@ -33,7 +33,7 @@ G_BEGIN_DECLS -ArvStream * arv_uv_stream_new (ArvUvDevice *uv_device, ArvStreamCallback callback, void *user_data, +ArvStream * arv_uv_stream_new (ArvUvDevice *uv_device, ArvStreamCallback callback, void *user_data, GDestroyNotify destroy, ArvUvUsbMode usb_mode, GError **error); G_END_DECLS diff --git a/tests/arvroitest.c b/tests/arvroitest.c index b04b86f7b..6a262d8ab 100644 --- a/tests/arvroitest.c +++ b/tests/arvroitest.c @@ -35,6 +35,7 @@ new_buffer_cb (ArvStream *stream, ApplicationData *data) buffer = arv_stream_try_pop_buffer (stream); if (buffer != NULL) { + if (arv_buffer_get_status (buffer) == ARV_BUFFER_STATUS_SUCCESS) data->buffer_count++; @@ -80,17 +81,15 @@ static gboolean switch_roi (gpointer user_data) { ApplicationData *data = user_data; - gint payload; gint width; gint height; - guint i; - guint n_deleted; + guint n_deleted; arv_camera_stop_acquisition (data->camera, NULL); - n_deleted = arv_stream_stop_thread (data->stream, TRUE); + n_deleted = arv_stream_stop_thread (data->stream, FALSE); - g_assert (n_deleted == N_BUFFERS); + g_assert (n_deleted == 0); data->width += SIZE_INC; if (data->width > WIDTH_MAX) @@ -107,13 +106,7 @@ switch_roi (gpointer user_data) printf ("image size set to %dx%d\n", width, height); - - payload = arv_camera_get_payload (data->camera, NULL); - - for (i = 0; i < N_BUFFERS; i++) - arv_stream_push_buffer (data->stream, arv_buffer_new (payload, NULL)); - - arv_stream_start_thread (data->stream); + arv_stream_start_thread (data->stream); arv_camera_start_acquisition (data->camera, NULL); @@ -149,17 +142,19 @@ main (int argc, char **argv) if (ARV_IS_CAMERA (data.camera)) { void (*old_sigint_handler)(int); - gint payload; + gint max_payload; gint x, y, width, height; guint64 n_completed_buffers; guint64 n_failures; guint64 n_underruns; - arv_camera_set_region (data.camera, 0, 0, data.width, data.height, NULL); + arv_camera_set_region (data.camera, 0, 0, WIDTH_MAX, HEIGHT_MAX, NULL); + + max_payload = arv_camera_get_payload (data.camera, NULL); + arv_camera_set_frame_rate (data.camera, 20.0, NULL); arv_camera_get_region (data.camera, &x, &y, &width, &height, NULL); - - payload = arv_camera_get_payload (data.camera, NULL); + arv_camera_set_region (data.camera, 0, 0, data.width, data.height, NULL); printf ("vendor name = %s\n", arv_camera_get_vendor_name (data.camera, NULL)); printf ("model name = %s\n", arv_camera_get_model_name (data.camera, NULL)); @@ -176,7 +171,7 @@ main (int argc, char **argv) arv_stream_set_emit_signals (data.stream, TRUE); for (i = 0; i < N_BUFFERS; i++) - arv_stream_push_buffer (data.stream, arv_buffer_new (payload, NULL)); + arv_stream_push_buffer (data.stream, arv_buffer_new (max_payload, NULL)); arv_camera_set_acquisition_mode (data.camera, ARV_ACQUISITION_MODE_CONTINUOUS, NULL); arv_camera_start_acquisition (data.camera, NULL); diff --git a/tests/buffer.c b/tests/buffer.c index 1da3a9ef6..3a6fd8cae 100644 --- a/tests/buffer.c +++ b/tests/buffer.c @@ -15,7 +15,7 @@ simple_buffer_test (void) data = arv_buffer_get_data (buffer, &size); g_assert (data != NULL); - g_assert (size == 1024); + g_assert (size == 0); g_assert (arv_buffer_get_payload_type (buffer) == ARV_BUFFER_PAYLOAD_TYPE_UNKNOWN); g_assert (arv_buffer_get_status (buffer) == ARV_BUFFER_STATUS_CLEARED); @@ -65,7 +65,7 @@ full_buffer_test (void) data = arv_buffer_get_data (buffer, &size); g_assert (data != NULL); - g_assert (size == 1024); + g_assert (size == 0); g_assert (arv_buffer_get_payload_type (buffer) == ARV_BUFFER_PAYLOAD_TYPE_UNKNOWN); g_assert (arv_buffer_get_status (buffer) == ARV_BUFFER_STATUS_CLEARED); @@ -108,7 +108,7 @@ allocate (void) data = arv_buffer_get_data (buffer, &size); g_assert (data != NULL); - g_assert (size == 512); + g_assert (size == 0); g_object_unref (buffer); } diff --git a/tests/data/genicam.xml b/tests/data/genicam.xml index ec694826d..4d515a103 100644 --- a/tests/data/genicam.xml +++ b/tests/data/genicam.xml @@ -571,6 +571,76 @@ 0 + + + + RWRegister + RW + + + + RWRegister + RO + + + + RORegister + RW + + + + RORegister + RO + + + + RWStructEntry + RW + + + + RWStructEntry + RO + + + + ROStructEntry + RW + + + + ROStructEntry + RO + + + +
0x1100
+ 4 + RW + Device +
+ + +
0x1100
+ 4 + RO + Device +
+ + +
0x1100
+ 4 + RW + Device + + 0 + + + 1 + RO + +
+ diff --git a/tests/fake.py b/tests/fake.py index 86aa7fe9b..01fd5a633 100644 --- a/tests/fake.py +++ b/tests/fake.py @@ -30,7 +30,24 @@ [x,y,width,height] = camera.get_region () -stream = camera.create_stream (None, None) +callback_map = { + Aravis.StreamCallbackType.INIT: 0, + Aravis.StreamCallbackType.START_BUFFER: 0, + Aravis.StreamCallbackType.BUFFER_DONE: 0, + Aravis.StreamCallbackType.EXIT: 0, +} + + +test_user_data = [1, 2, 3] + +def callback(user_data, cb_type, buffer): + assert user_data == test_user_data + callback_map[cb_type] += 1 + if cb_type == Aravis.StreamCallbackType.BUFFER_DONE: + assert buffer is not None + + +stream = camera.create_stream (callback, test_user_data) for i in range(0,10): stream.push_buffer (Aravis.Buffer.new_allocate (payload)) @@ -45,6 +62,16 @@ camera.stop_acquisition () +# Explicitly delete the stream here. Otherwise it will likely be garbage collected only +# when the test application exits. This is to test that we receive a StreamCallbackType.EXIT +# event. +del stream + +assert callback_map[Aravis.StreamCallbackType.INIT] == 1 +assert callback_map[Aravis.StreamCallbackType.START_BUFFER] >= 20 +assert callback_map[Aravis.StreamCallbackType.BUFFER_DONE] == callback_map[Aravis.StreamCallbackType.START_BUFFER] +assert callback_map[Aravis.StreamCallbackType.EXIT] == 1 + buffer = camera.acquisition (0) data = buffer.get_data () diff --git a/tests/genicam.c b/tests/genicam.c index bd3bc8165..394c670bc 100644 --- a/tests/genicam.c +++ b/tests/genicam.c @@ -107,6 +107,24 @@ integer_test (void) v_string = arv_gc_feature_node_get_value_as_string (ARV_GC_FEATURE_NODE (node), NULL); g_assert_cmpstr (v_string, ==, "1"); + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "4", &error); + g_assert (error == NULL); + v_int64 = arv_gc_integer_get_value (ARV_GC_INTEGER (node), &error); + g_assert (error == NULL); + g_assert_cmpint (v_int64, ==, 4); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "0xf", &error); + g_assert (error == NULL); + v_int64 = arv_gc_integer_get_value (ARV_GC_INTEGER (node), &error); + g_assert (error == NULL); + g_assert_cmpint (v_int64, ==, 15); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "0.4", &error); + g_assert (error != NULL); + g_assert (error->domain == ARV_GC_ERROR); + g_assert (error->code == ARV_GC_ERROR_INVALID_SYNTAX); + g_clear_error (&error); + arv_gc_integer_set_value (ARV_GC_INTEGER (node), 2, NULL); v_int64 = arv_gc_integer_get_value (ARV_GC_INTEGER (node), NULL); g_assert_cmpint (v_int64, ==, 2); @@ -308,6 +326,53 @@ boolean_test (void) v_string = arv_gc_feature_node_get_value_as_string (ARV_GC_FEATURE_NODE (node), NULL); g_assert_cmpstr (v_string, ==, "false"); + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "True", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, TRUE); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "False", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, FALSE); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "true", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, TRUE); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "false", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, FALSE); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "1", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, TRUE); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "0", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, FALSE); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "what", &error); + g_assert (error != NULL); + g_assert (error->domain == ARV_GC_ERROR); + g_assert (error->code == ARV_GC_ERROR_INVALID_SYNTAX); + g_clear_error (&error); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "2", &error); + g_assert (error != NULL); + g_assert (error->domain == ARV_GC_ERROR); + g_assert (error->code == ARV_GC_ERROR_INVALID_SYNTAX); + g_clear_error (&error); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "0", &error); + g_assert (error == NULL); + v_boolean = arv_gc_boolean_get_value (ARV_GC_BOOLEAN (node), NULL); + g_assert_cmpint (v_boolean, ==, FALSE); + node = arv_gc_get_node (genicam, "P_RWBoolean"); g_assert (ARV_IS_GC_BOOLEAN (node)); @@ -367,6 +432,18 @@ float_test (void) v_string = arv_gc_feature_node_get_value_as_string (ARV_GC_FEATURE_NODE (node), NULL); g_assert_cmpstr (v_string, ==, "0.1"); + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "0.4", &error); + g_assert (error == NULL); + v_double = arv_gc_float_get_value (ARV_GC_FLOAT (node), &error); + g_assert (error == NULL); + g_assert_cmpfloat (v_double, ==, 0.4); + + arv_gc_feature_node_set_value_from_string (ARV_GC_FEATURE_NODE (node), "0.4.", &error); + g_assert (error != NULL); + g_assert (error->domain == ARV_GC_ERROR); + g_assert (error->code == ARV_GC_ERROR_INVALID_SYNTAX); + g_clear_error (&error); + arv_gc_float_set_value (ARV_GC_FLOAT (node), 0.2, NULL); v_double = arv_gc_float_get_value (ARV_GC_FLOAT (node), NULL); g_assert_cmpfloat (v_double, ==, 0.2); @@ -1019,7 +1096,7 @@ create_buffer_with_chunk_data (void) buffer = arv_buffer_new (size, NULL); buffer->priv->payload_type = ARV_BUFFER_PAYLOAD_TYPE_CHUNK_DATA; buffer->priv->status = ARV_BUFFER_STATUS_SUCCESS; - data = (char *) arv_buffer_get_data (buffer, &size); + data = (char *) arv_buffer_get_data (buffer, NULL); memset ((char *) data, '\0', size); @@ -1281,6 +1358,66 @@ lock_test (void) g_object_unref (device); } + +static void +access_mode_test (void) +{ + ArvDevice *device; + ArvGc *genicam; + ArvGcNode *node; + ArvGcAccessMode access_mode; + GError *error = NULL; + + device = arv_fake_device_new ("TEST0", &error); + g_assert (ARV_IS_FAKE_DEVICE (device)); + g_assert (error == NULL); + + genicam = arv_device_get_genicam (device); + g_assert (ARV_IS_GC (genicam)); + + node = arv_gc_get_node (genicam, "RWRegister_ImposedAccessModeRW"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RW); + + node = arv_gc_get_node (genicam, "RWRegister_ImposedAccessModeRO"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RO); + + node = arv_gc_get_node (genicam, "RORegister_ImposedAccessModeRW"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RO); + + node = arv_gc_get_node (genicam, "RORegister_ImposedAccessModeRO"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RO); + + node = arv_gc_get_node (genicam, "RWStructEntry_ImposedAccessModeRW"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RW); + + node = arv_gc_get_node (genicam, "RWStructEntry_ImposedAccessModeRO"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RO); + + node = arv_gc_get_node (genicam, "ROStructEntry_ImposedAccessModeRW"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RO); + + node = arv_gc_get_node (genicam, "ROStructEntry_ImposedAccessModeRO"); + g_assert (ARV_IS_GC_FEATURE_NODE (node)); + access_mode = arv_gc_feature_node_get_actual_access_mode (ARV_GC_FEATURE_NODE (node)); + g_assert_cmpint (access_mode, ==, ARV_GC_ACCESS_MODE_RO); + + g_object_unref (device); +} + int main (int argc, char *argv[]) { @@ -1306,6 +1443,7 @@ main (int argc, char *argv[]) g_test_add_func ("/genicam/visibility", visibility_test); g_test_add_func ("/genicam/category", category_test); g_test_add_func ("/genicam/lock", lock_test); + g_test_add_func ("/genicam/access-mode", access_mode_test); result = g_test_run(); diff --git a/tests/python/arv-stream-callback.py b/tests/python/arv-stream-callback.py new file mode 100644 index 000000000..cba57a8b8 --- /dev/null +++ b/tests/python/arv-stream-callback.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# If you have installed aravis in a non standard location, you may need +# to make GI_TYPELIB_PATH point to the correct location. For example: +# +# export GI_TYPELIB_PATH=$GI_TYPELIB_PATH:/opt/bin/lib/girepositry-1.0/ +# +# You may also have to give the path to libaravis.so, using LD_PRELOAD or +# LD_LIBRARY_PATH. + +import threading +import time + +import gi +# autopep8: off +gi.require_version('Aravis', '0.8') +from gi.repository import Aravis # noqa: E402 +# autopep8: on + +Aravis.enable_interface('Fake') + + +class UserData: + + def __init__(self) -> None: + self.stream = None + + +def callback(user_data, cb_type, buffer): + print(f'Callback[{threading.get_native_id()}] {cb_type.value_name} {buffer=}') + if buffer is not None: + # Fake some light computation here (like copying the buffer). Do not do heavy image processing here + # since it would block the acquisition thread. + time.sleep(0.01) + # Re-enqueue the buffer + user_data.stream.push_buffer(buffer) + + +print(f'Main thread[{threading.get_native_id()}]') +cam = Aravis.Camera.new('Fake_1') + +user_data = UserData() +stream = cam.create_stream(callback, user_data) +user_data.stream = stream + +payload = cam.get_payload() +stream.push_buffer(Aravis.Buffer.new_allocate(payload)) + +cam.start_acquisition() +time.sleep(1) +cam.stop_acquisition() diff --git a/viewer/main.c b/viewer/main.c index 326bf93c6..e43f84eda 100644 --- a/viewer/main.c +++ b/viewer/main.c @@ -42,6 +42,7 @@ static unsigned int arv_viewer_option_initial_packet_timeout = ARV_GV_STREAM_INI static unsigned int arv_viewer_option_packet_timeout = ARV_GV_STREAM_PACKET_TIMEOUT_US_DEFAULT / 1000; static unsigned int arv_viewer_option_frame_retention = ARV_GV_STREAM_FRAME_RETENTION_US_DEFAULT / 1000; static char *arv_option_uv_usb_mode = NULL; +static gboolean arv_option_show_version = FALSE; static const GOptionEntry arv_viewer_option_entries[] = { @@ -85,6 +86,11 @@ static const GOptionEntry arv_viewer_option_entries[] = &arv_viewer_option_debug_domains, NULL, "{[:][,...]|help}" }, + { + "version", 'v', 0, G_OPTION_ARG_NONE, + &arv_option_show_version, "Show version", + NULL + }, { NULL } }; @@ -127,6 +133,14 @@ main (int argc, char **argv) g_option_context_free (context); + if (arv_option_show_version) { + printf ("%u.%u.%u\n", + arv_get_major_version (), + arv_get_minor_version (), + arv_get_micro_version ()); + return EXIT_SUCCESS; + } + if (arv_option_register_cache == NULL) register_cache_policy = ARV_REGISTER_CACHE_POLICY_DEFAULT; else if (g_strcmp0 (arv_option_register_cache, "disable") == 0)