635 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
			
		
		
	
	
			635 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
| * [2024-06-28 Fri]
 | |
| ** well, i'm setting up sbcl and sly?
 | |
| because i imagine using Common Lisp for my attempt at building screen
 | |
| sharing for the XR glasses
 | |
| 
 | |
| for the cool runtime access, right?
 | |
| ** well, just flake shell and (use-package sly) is enough
 | |
| for .lisp files to get stuff
 | |
| 
 | |
| yes, i'm still using C-M-f and stuff to move around sexps but things are fine
 | |
| 
 | |
| so, what's next?
 | |
| well, this is nice high level description
 | |
| dbus
 | |
| https://www.freedesktop.org/wiki/Software/dbus/
 | |
| 
 | |
| and here's something to start usage
 | |
| https://blog.macrolet.net/posts/DBus-and-PolicyKit-from-Common-Lisp.html
 | |
| from https://github.com/death/dbus
 | |
| 
 | |
| and even lots of examples, but i think i will need a big book on Common Lisp to learn new things?
 | |
| * [2024-06-29 Sat]
 | |
| ** going through the dbus guide, sounds neat
 | |
| https://develop.kde.org/docs/features/d-bus/introduction_to_dbus/
 | |
| 
 | |
| that qdbus and qdbus-viewer are in
 | |
| #+begin_src bash
 | |
| $ nix shell nixpkgs#kdePackages.qttools
 | |
| #+end_src
 | |
| 
 | |
| ** now let's read about calling methods
 | |
| 
 | |
| * the receiving of the signals
 | |
| 
 | |
| * all the different tabs i had
 | |
| ** overall freedesktop portal dbus api docs
 | |
| https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-org.freedesktop.portal.ScreenCast
 | |
| 
 | |
| ** searching github for 'get-managed-objects usage
 | |
| https://github.com/search?q=get-managed-objects&type=code
 | |
| 
 | |
| ** searchin github for 'define-singlan-handler usage examples
 | |
| https://github.com/search?q=dbus%3Adefine-dbus-signal-handler&type=code
 | |
| 
 | |
| ** example in cl-notify of calling a method 'with-introspected-object
 | |
| https://github.com/Lautaro-Garcia/cl-notify/blob/main/src/dbus-protocol.lisp#L27
 | |
| #+begin_src lisp
 | |
|   (defmacro with-dbus-method-inovaction ((result-var method &rest args) &body body)
 | |
|   (alexandria:with-gensyms (bus notifications-object)
 | |
|     `(dbus:with-open-bus (,bus (dbus:session-server-addresses))
 | |
|        (dbus:with-introspected-object (,notifications-object ,bus "/org/freedesktop/Notifications" "org.freedesktop.Notifications")
 | |
|          (let ((,result-var (,notifications-object "org.freedesktop.Notifications" ,method ,@args)))
 | |
|           ,@body)))))
 | |
| #+end_src
 | |
| 
 | |
| ** example in cl-notify of working with signals
 | |
| https://github.com/Lautaro-Garcia/cl-notify/blob/main/src/signals.lisp
 | |
| 
 | |
| they register single handler, and add callbacks dynamically & call
 | |
| them from the registered function
 | |
| 
 | |
| ** dbus library example for publishing objects
 | |
| https://github.com/death/dbus/blob/master/examples/publish.lisp
 | |
| 
 | |
| ** my request for help with interactive async calls
 | |
| https://github.com/death/dbus/issues/31
 | |
| 
 | |
| ** old ticket on dbus repo about enabling introspection
 | |
| https://github.com/death/dbus/issues/23
 | |
| 
 | |
| ** example of signal-handler in stumpwm-thingy
 | |
| https://github.com/lokedhs/stumpwm-dbus/blob/9cf0b52876111e777da27a42e3c81269b97c0005/src/pidgin.lisp#L16
 | |
| 
 | |
| ** ref for symbold in dbus package
 | |
| https://quickref.common-lisp.net/dbus.html#The-dbus_002fconnections-system
 | |
| 
 | |
| ** blog article with basics of usage
 | |
| https://blog.macrolet.net/posts/DBus-and-PolicyKit-from-Common-Lisp.html
 | |
| 
 | |
| ** big article about iolib
 | |
| https://pages.cs.wisc.edu/~psilord/blog/data/iolib-tutorial/tutorial.html
 | |
| 
 | |
| it's the one that's used to create multiplexer for communication
 | |
| i tried to figure out what it means to have event-loops
 | |
| 
 | |
| ** docs on dbus Screenshots portal
 | |
| https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Screenshot.html
 | |
| 
 | |
| the methods and stuff
 | |
| 
 | |
| ** docs on dbus type system
 | |
| https://dbus.freedesktop.org/doc/dbus-specification.html#type-system
 | |
| 
 | |
| i.e how to understand types of methods and properties
 | |
| 
 | |
| #+begin_src lisp
 | |
|   CL-USER> (dbus:sigexp "xsaysas")
 | |
| (:INT64 :STRING (:ARRAY :BYTE) :STRING (:ARRAY :STRING))
 | |
| #+end_src
 | |
| 
 | |
| function signature explanation can show what should lisp types be
 | |
| https://github.com/death/dbus/issues/17#issuecomment-418920440
 | |
| 
 | |
| ** example of flameshot how they get Screenshot via dbus
 | |
| https://github.com/flameshot-org/flameshot/blob/c1dac52231024174faa68a29577129ebca125dff/src/utils/screengrabber.cpp#L59
 | |
| 
 | |
| ** dbus methods for Notification
 | |
| https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html#signals
 | |
| 
 | |
| 
 | |
| ** dbus methods of ScreenCast
 | |
| https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.ScreenCast.html
 | |
| how to start them etc
 | |
| 
 | |
| ** dbus spec on Request & Response for the async methods
 | |
| https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Request.html#org-freedesktop-portal-request
 | |
| 
 | |
| ** repo for xdg-portal for wayland
 | |
| https://github.com/emersion/xdg-desktop-portal-wlr
 | |
| 
 | |
| ** the python snippet to check that ScreenCast via xdg-portal works
 | |
| https://gitlab.gnome.org/-/snippets/19
 | |
| 
 | |
| * [2024-07-20 Sat]
 | |
| 
 | |
| ** and now i want to try to get display of stuff into gtk window, i guess
 | |
| 
 | |
| ** doc about cl bindings to gtk3
 | |
| https://www.crategus.com/books/cl-gtk/gtk-tutorial.html#example-window-simple-c
 | |
| 
 | |
| ** well, i guess i could go and try to read guide on pipewire with C examples
 | |
| https://docs.pipewire.org/page_tutorial.html
 | |
| this is tutorial for the system
 | |
| 
 | |
| and here is example program that maybe does similar thing
 | |
| https://docs.pipewire.org/video-play_8c-example.html
 | |
| 
 | |
| * [2024-07-28 Sun]
 | |
| 
 | |
| ** ok, now i'm trying to get frames from the pipewire 'out' node
 | |
| and one option i'm exploring is gstreamer
 | |
| 
 | |
| which is a framework for creating applications that stream video / audio
 | |
| with some kind of ability to define \ declare pipeline and then start
 | |
| and then use api somehow
 | |
| 
 | |
| there's c api, and gobject accessibility layer
 | |
| so either c to common lisp, or gobject common lisp thingy maybe exist
 | |
| 
 | |
| ** reading docs
 | |
| https://gstreamer.freedesktop.org/documentation/frequently-asked-questions/using.html?gi-language=c
 | |
| 
 | |
| added via
 | |
| gst_all_1.gstreamer
 | |
| 
 | |
| ** more readin
 | |
| gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink
 | |
| this is test for how it's installed
 | |
| 
 | |
| needed to add plugins
 | |
| 
 | |
| https://nixos.wiki/wiki/GStreamer
 | |
| 
 | |
| ** i guess i can try to go with the tutorials?
 | |
| https://gstreamer.freedesktop.org/documentation/tutorials/index.html?gi-language=c
 | |
| 
 | |
| but with common lisp over gobject?
 | |
| i think i'm already using this in the gtk bindings  playground? maybe not
 | |
| https://cl-gtk2.common-lisp.dev/doc/gobject/Creating-GObjects-classes-and-implementing-GInterfaces.html
 | |
| #+begin_quote
 | |
| GObject binding at the moment provides only limited scenarios of creating GObject classes.
 | |
| #+end_quote
 | |
| 
 | |
| ** and there's something
 | |
| https://github.com/BohongHuang/cl-gobject-introspection-wrapper
 | |
| 
 | |
| which is based on older
 | |
| 
 | |
| https://github.com/andy128k/cl-gobject-introspection
 | |
| 
 | |
| https://search.nixos.org/packages?channel=unstable&from=0&size=50&sort=relevance&type=packages&query=gobject
 | |
| 
 | |
| 
 | |
| they are packaged in nix, this is just unbelievable how much is done by humanity, omg
 | |
| 
 | |
| * [2024-08-15 Thu]
 | |
| 
 | |
| ** getting back after a long while.
 | |
| so, i was at the creating a window, not knowing how to stream video from pipewire out node
 | |
| so. what to do, huh
 | |
| i think gtk3 bindings library was separate from gobject and glib
 | |
| 
 | |
| but maybe it doesn't matter?
 | |
| or maybe i should figure out glib bindings and use gtk3 though it?
 | |
| 
 | |
| ** well, there's something simple with opening a window
 | |
| [[file:gtk-playground.lisp::defun example-window-simple (]]
 | |
| 
 | |
| ** and something extra simple with gstreamer opening separate window for test video source
 | |
| [[file:gstreamer/tutorial-hello-world.lisp]]
 | |
| 
 | |
| ** maybe try to open gstreamer window with screen share?
 | |
| 
 | |
| ok, when i try example of pipewire window on screenshare source
 | |
| i get error that pipewiresrc is not found
 | |
| and that's right, i used system-wide gst-launch-1.0
 | |
| and when i tried with one in flake shell - it also didn't work
 | |
| 
 | |
| so. tried removing all from shell env, then not found namespace Gst
 | |
| (defvar *gstreamer* (gir:require-namespace "Gst"))
 | |
| 
 | |
| so. yeah. maybe i need to install dev headers or something?
 | |
| 
 | |
| ** so. for moving the video around. chatgpt recommended something named 'videobox'
 | |
| 
 | |
| like i can declare it in the pipeline and then get reference to it and use to set video coordinates, huh?
 | |
| https://gstreamer.freedesktop.org/documentation/videobox/index.html?gi-language=python
 | |
| the thing exists but i have zero idea whether it's accessible in a way that's recommended
 | |
| #+begin_src lisp
 | |
| (defun for-screencast ()
 | |
|   (gir:invoke (*gstreamer* 'init) '())
 | |
|   (let* ((pipeline (gir:invoke (*gstreamer* 'parse-launch)
 | |
|                                 "pipewiresrc path=49 ! videoconvert ! videobox top=0 left=0 right=0 bottom=0 ! videoconvert ! autovideosink"
 | |
|                                 ))
 | |
|          (videobox (gir:invoke (pipeline 'get-element-by-name) "videobox")))
 | |
|     ;; Set the initial state to playing
 | |
|     (gir:invoke (pipeline 'set-state) (gir:nget *gstreamer* "State" :playing))
 | |
|     
 | |
|     ;; Function to move the video
 | |
|     (defun move-video (top left)
 | |
|       (gir:invoke (videobox 'set-property) 'top top)
 | |
|       (gir:invoke (videobox 'set-property) 'left left))
 | |
| 
 | |
|     ;; Example: Move the video 10 pixels down and 20 pixels to the right
 | |
|     (move-video 10 20)))
 | |
| #+end_src
 | |
| 
 | |
| and similar advice from claude, huh
 | |
| #+begin_src lisp
 | |
| (defun for-screencast ()
 | |
|   (gir:invoke (*gstreamer* 'init) '())
 | |
|   (let* ((pipeline (gir:invoke (*gstreamer* 'parse-launch)
 | |
|                                "pipewiresrc path=49 ! videoconvert ! videobox name=move ! videoscale ! autovideosink"))
 | |
|          (move-element (gir:invoke (pipeline 'get-by-name) "move")))
 | |
|     (gir:invoke (pipeline 'set-state) (gir:nget *gstreamer* "State" :playing))
 | |
|     (values pipeline move-element)))
 | |
| 
 | |
| (defun move-video (move-element left top)
 | |
|   (gir:set-property move-element "left" left)
 | |
|   (gir:set-property move-element "top" top))
 | |
| 
 | |
| ;; Usage:
 | |
| (multiple-value-bind (pipeline move-element) (for-screencast)
 | |
|   ;; Move video 50 pixels to the right and 30 pixels down
 | |
|   (move-video move-element 50 30)
 | |
|   ;; Your main loop or other logic here
 | |
|   )
 | |
| #+end_src
 | |
| 
 | |
| let's try this out
 | |
| 
 | |
| * [2024-08-16 Fri]
 | |
| 
 | |
| ** new day of the vacation
 | |
| the experiment with moving the video, right?
 | |
| 
 | |
| could it be that both examples are fake? i don't seem to find both 'get-element things
 | |
| 
 | |
| trying to find anything about dynamism in gstreamer
 | |
| https://coaxion.net/blog/2014/01/gstreamer-dynamic-pipelines/
 | |
| looks like this is about changing elements of the pipeline
 | |
| 
 | |
| and it's possible that parameters of the pipeline elements (pads?) are also static
 | |
| 
 | |
| ** options for transforming frames?
 | |
| *** videotransform : A combination of scaling, 90-degree-step rotation,
 | |
| https://github.com/Freescale/gstreamer-imx/blob/master/README.md
 | |
| horizontal/vertical flipping, and color space conversion
 | |
| operations. These elements are able to render video overlay
 | |
| compositions from GstVideoOverlayCompositionMeta data. They also
 | |
| implement the GstVideoDirection interface and have a "video-direction"
 | |
| property that handles rotation and flipping. Through this property, it
 | |
| is possible to configure these elements to auto-rotate images
 | |
| according to the information in image-orientation tags.
 | |
| *** glimagesink
 | |
| https://gstreamer.freedesktop.org/documentation/opengl/glimagesink.html?gi-language=python
 | |
| gst-launch-1.0 -v videotestsrc ! video/x-raw ! glimagesink
 | |
| has error
 | |
| ERROR: from element /GstPipeline:pipeline0/GstGLImageSinkBin:glimagesinkbin0/GstGLImageSink:sink: Failed to create EGLDisplay from native display
 | |
| Additional debug info:
 | |
| ../ext/gl/gstglimagesink.c(1136): _ensure_gl_setup (): /GstPipeline:pipeline0/GstGLImageSinkBin:glimagesinkbin0/GstGLImageSink:sink
 | |
| ERROR: pipeline doesn't want to preroll.
 | |
| 
 | |
| so maybe opengl is not available? how to check?
 | |
| *** gltransformation
 | |
| https://gstreamer.freedesktop.org/documentation/opengl/gltransformation.html?gi-language=python
 | |
| 
 | |
| here examples seem to be for images, not video
 | |
| and same error, let's figure out the opengl check
 | |
| ** somewhat categorized things?
 | |
| * [2024-08-21 Wed]
 | |
| ** visiting sister, returning back
 | |
| last time i got stuck on video displaying frozen when i tried to add appsink
 | |
| 
 | |
| just re-checking my basic gstreamer pipeline and screencast start - thing works
 | |
| but i want to clean it up i guess, to allow for simpler retries?
 | |
| ** so, for the appsnk there are signals
 | |
| https://gstreamer.freedesktop.org/documentation/app/appsink.html?gi-language=python#appsink::new-sample
 | |
| 
 | |
|  new-sample
 | |
| 
 | |
| #+begin_src python
 | |
| def new_sample_callback (appsink, udata):
 | |
|     #python callback for the 'new-sample' signal
 | |
| #+end_src
 | |
| 
 | |
| Signal that a new sample is available.
 | |
| 
 | |
| but how do i connect to a callback from common lisp and gobject introspection
 | |
| https://github.com/andy128k/cl-gobject-introspection
 | |
| does the gitlab repo has info on callbacks?
 | |
| 
 | |
| can't seem to call method 'pull-sample'
 | |
| maybe article will help?
 | |
| https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=python#grabbing-data-with-appsink
 | |
| 
 | |
| well, this looks like method on gst namespace? "gst_app_sink_pull_sample()"
 | |
| https://gstreamer.freedesktop.org/documentation/applib/gstappsink.html?gi-language=python#gst_app_sink_pull_sample
 | |
| 
 | |
| there's article for python bindings
 | |
| https://lifestyletransfer.com/how-to-use-gstreamer-appsink-in-python/
 | |
| * [2024-08-22 Thu]
 | |
| ** hey, i think this is progress
 | |
| i am able to call appsink 'pull-sample after all (for some reason, i don't know what i was doing differently)
 | |
| 
 | |
| new error:
 | |
| >>> got to process sample with #<STRUCT-INSTANCE {10128D02F3}>
 | |
| but in the code for processing of the sample some type errors
 | |
| 
 | |
| Backtrace:
 | |
|  0: ((:METHOD GIR::THIS-OF (T)) T) [fast-method]
 | |
|  1: (GIR:PROPERTY T DATA)
 | |
|  2: (PROCESS-FRAME #<GIR::STRUCT-INSTANCE {100BCDAB73}>)
 | |
|  3: ((LAMBDA (APPSINK) :IN START-PROCESSING) #<GIR::OBJECT-INSTANCE {100BBE02D3}>)
 | |
| 
 | |
| ok, but when i have struct instance, how do i introspect it?
 | |
| ** let's just go and read documentation for the type that's returned from pull-sample, sure
 | |
| also there's that python code, right?
 | |
| doc 1: get sample on appsink https://people.freedesktop.org/~tsaunier/documentation/gst-plugins-base-app-1.0/gstappsink.html?gi-language=c#gst_app_sink_pull_sample
 | |
| doc 2: GstSample class https://people.freedesktop.org/~tsaunier/documentation/gstreamer-1.0/gstsample.html?gi-language=c#GstSample
 | |
| 
 | |
| so on GstSample everything is taken as results of funciton calls? let's try that
 | |
| 
 | |
| well, maybe i don't need get-info on sample, it returns null, maybe i need it on buffer?
 | |
| doc 3: get-buffer on sample  https://people.freedesktop.org/~tsaunier/documentation/gstreamer-1.0/gstsample.html?gi-language=python#gst_sample_get_buffer
 | |
| doc 4: buffer class info https://people.freedesktop.org/~tsaunier/documentation/gstreamer-1.0/gstbuffer.html?gi-language=python#gst_buffer_peek_memory
 | |
| 
 | |
| ** i'm recommended to look into GstBuffer.map
 | |
| https://people.freedesktop.org/~tsaunier/documentation/gstreamer-1.0/gstbuffer.html?gi-language=python#gst_buffer_map
 | |
| 
 | |
| it returns some https://people.freedesktop.org/~tsaunier/documentation/gstreamer-1.0/gstmemory.html?gi-language=python#GstMapInfo
 | |
| 
 | |
| ** struggling, searching for answers
 | |
| https://github.com/andy128k/cl-gobject-introspection/issues/73#issuecomment-755316735
 | |
| Examples of inspection of a repository can be found in test files.
 | |
| 
 | |
| https://github.com/andy128k/cl-gobject-introspection/blob/master/test/test1.lisp
 | |
| 
 | |
| and i mean it's possible that referencing members of a structure is not implemented?
 | |
| 
 | |
| so, huh
 | |
| using internal functions
 | |
| #+begin_src lisp
 | |
| (data (gir:fields-dict-of (gir:struct-class-of map-info)))  
 | |
| #+end_src
 | |
| i see
 | |
| >>>> and data has size NIL and buf ((memory . #<FIELD-INFO {100FEB4083}>)
 | |
|                                     (flags . #<FIELD-INFO {100FEB4153}>)
 | |
|                                     (data . #<FIELD-INFO {100FEB4223}>)
 | |
|                                     (size . #<FIELD-INFO {100FEB42F3}>)
 | |
|                                     (maxsize . #<FIELD-INFO {100FEB43C3}>)
 | |
|                                     (user_data . #<FIELD-INFO {100FEB4493}>)
 | |
|                                     (_gst_reserved
 | |
|                                      . #<FIELD-INFO {100FEB4563}>))
 | |
| ; Evaluation aborted on T
 | |
| CAPTURING-FRAMES>
 | |
| 
 | |
| so. there are data and size fields.
 | |
| 
 | |
| maybe i can try with 
 | |
| 
 | |
| ** well, for some reason data is not avaiable?
 | |
| (let* ((buffer (gir:invoke (sample 'get-buffer)))
 | |
|          (info (gir:invoke (sample 'get-info)))
 | |
| 			(caps (gir:invoke (sample 'get-caps)))
 | |
| 			(caps-struct (gir:invoke (caps 'get-structure) 0))
 | |
| 			(width (gir:invoke ((gir:invoke (caps-struct 'get-value) "width") 'get-int)))
 | |
| 			(height (gir:invoke ((gir:invoke (caps-struct 'get-value) "height") 'get-int)))
 | |
| 			(buf-size (gir:invoke (buffer 'get-size)))
 | |
| 			(data-copy (gir:invoke (buffer 'extract-dup) 0 buf-size)))
 | |
| 	 (format t ">>>> at buffer got size ~A and tried to copy ~A~%" buf-size data-copy)
 | |
| 	 ;; ok, we have buffer, let's try to get copy
 | |
| 	 
 | |
| 	 ;; (multiple-value-bind (found map-info) (gir:invoke (buffer 'map) (gir:nget *gstreamer* "MapFlags" :read))
 | |
| 	 ;; 	(format t ">>>> the buffer has offset ~A~%" (gir:field buffer 'offset))
 | |
| 	 ;; 	(format t ">>>> what's in struct? ~A~%" (gir:invoke (caps-struct 'to-string)))
 | |
| 	 ;; 	(format t ">>>> the fields are width ~A, height ~A~%" width height)
 | |
| 	 ;; 	(format t ">>>> and map result are ~A and ~A~%" found map-info)
 | |
| 	 ;; 	(when found
 | |
| 	 ;; 	  (let ((data (gir:field map-info 'memory))
 | |
| 	 ;; 			  (size (gir:field map-info 'size)))
 | |
| 	 ;; 		 (format t ">>>> and struct info? ~A~%" map-info)
 | |
| 	 ;; 		 (gir:invoke (buffer 'unmap) map-info)
 | |
| 	 ;; 		 (format t ">>>> and data has size ~A and memory is ~A~%" size (or data "empty data")))))
 | |
| 	 )
 | |
| 
 | |
| data-copy is NIL
 | |
| yep. mda.
 | |
| 
 | |
| ** well, trying to copy as in python example didn't work either
 | |
| 			(buf-size (gir:invoke (buffer 'get-size)))
 | |
| 			(data-copy (gir:invoke (buffer 'extract-dup) 0 buf-size))
 | |
| 
 | |
| https://github.com/jackersson/gst-python-tutorials/blob/master/launch_pipeline/run_appsink.py#L49
 | |
| 
 | |
| yeah, it's possible that gir library doesn't work well? even if on c level all is ok?
 | |
| 
 | |
| * [2024-08-23 Fri]
 | |
| 
 | |
| ** well, problem is in trying to read gir:map-c-array
 | |
| it gets length nil and fails
 | |
| 
 | |
| GIR::MAP-C-ARRAY
 | |
| 
 | |
| so what i'm using:
 | |
| https://github.com/andy128k/cl-gobject-introspection
 | |
| and there's wrapper around it
 | |
| https://github.com/bohonghuang/cl-gobject-introspection-wrapper
 | |
| 
 | |
| but there is also
 | |
| https://github.com/kat-co/gir2cl
 | |
| maybe it will work?
 | |
| or maybe i'll figure out what's up
 | |
| 
 | |
| ** well, trying to check available slots on that array type
 | |
| (mapcar #'c2mop:slot-definition-name (c2mop:class-slots (class-of c-array-type)))
 | |
| => (PARAM-TYPE FIXED-SIZE ZERO-TERMINATED? LENGTH)
 | |
| 
 | |
| and how do i get their values? if i don't know name of the :reader ?
 | |
| ( from article on https://riptutorial.com/common-lisp/example/9826/obtain-the-slot-names-of-a-class )
 | |
| 
 | |
| but yeah. huh. 
 | |
| 
 | |
| ** let's write up the problem?
 | |
| I'm trying to use gstreamer - a framework for video\audio pipelines with gobject api
 | |
| 
 | |
| the hope is to use their 'appsink' to get video frame data into the program i'm writing
 | |
| https://people.freedesktop.org/~tsaunier/documentation/gstreamer-1.0/gstbuffer.html?gi-language=python#gst_buffer_map
 | |
| 
 | |
| i'll link the code in case it will be needed for replication,
 | |
| right now it seems that by doing gir calls i've successfully set up pipeline
 | |
| and receiving callbacks with the buffers
 | |
| 
 | |
| the problem i get is when i try to access 'data
 | |
| and it seems to come from GIR:MAP-C-ARRAY
 | |
| where length of the parameter c-array-type is NIL
 | |
| 
 | |
| in #'map-c-array it comes by calling
 | |
| #+begin_src lisp
 | |
| (defun c-array-length (c-array-type)
 | |
|   (with-slots (param-type fixed-size zero-terminated? length)
 | |
|       c-array-type
 | |
|     (if fixed-size
 | |
| 	(if (and length (< length fixed-size))
 | |
| 	    length
 | |
| 	    fixed-size)
 | |
| 	(if length
 | |
| 	    (+ length (if zero-terminated? 1 0))))))
 | |
| #+end_src
 | |
| 
 | |
| and manually checking slots of the 'c-array-type
 | |
| it has NIL in length
 | |
| 
 | |
| right now I don't know whether it's a problem on the side of cl-gobject-introspection
 | |
| in how it's initializing the c-array-type
 | |
| or maybe it's somehow problem on the side of the gstreamer library,
 | |
| that provides bad responses, i'll try to use other languages \ libraries
 | |
| 
 | |
| but could also really use some help in figuring this out
 | |
| 
 | |
| fuller log:
 | |
| #+begin_src
 | |
| The value
 | |
|   NIL
 | |
| is not of type
 | |
|   REAL
 | |
|    [Condition of type TYPE-ERROR]
 | |
| 
 | |
| Restarts:
 | |
|  0: [ABORT] abort thread (#<FOREIGN-THREAD tid=127655 "callback" RUNNING {10131D8033}>)
 | |
| 
 | |
| Backtrace:
 | |
|  0: (SB-KERNEL:TWO-ARG->= 0 NIL)
 | |
|  1: (GIR::MAP-C-ARRAY #<FUNCTION (LAMBDA (GIR::POS) :IN GIR::MEM-GET) {10131D9CBB}> #.(SB-SYS:INT-SAP #X7F1EC80EBBD8) #<GIR::C-ARRAY-TYPE {10131E0FA3}>)
 | |
|       Locals:
 | |
|         ARRAY = #.(SB-SYS:INT-SAP #X7F1EC80EBBD8)
 | |
|         C-ARRAY-TYPE = #<GIR::C-ARRAY-TYPE {10131E0FA3}>
 | |
|         FUNC = #<FUNCTION (LAMBDA (GIR::POS) :IN GIR::MEM-GET) {10131D9CBB}>
 | |
|         I = 0
 | |
|         LENGTH = NIL
 | |
|         PARAM-SIZE = 1
 | |
|         POS = #.(SB-SYS:INT-SAP #X7F1EC80EBBD8)
 | |
|  2: ((:METHOD GIR::MEM-GET (T GIR::POINTER-TYPE)) #.(SB-SYS:INT-SAP #X7F1F97F7FFF8) #<GIR::POINTER-TYPE {10131E0FF3}>) [fast-method]
 | |
|       Locals:
 | |
|         GIR::POS = #.(SB-SYS:INT-SAP #X7F1F97F7FFF8)
 | |
|         TYPE = #<GIR::POINTER-TYPE {10131E0FF3}>
 | |
|  3: (GIR.FIELD:GET #.(SB-SYS:INT-SAP #X7F1ECC0036F0) #<GIR:FIELD-INFO {10087D1133}>)
 | |
|  4: (PROCESS-FRAME #<GIR::STRUCT-INSTANCE {10131E02D3}>)
 | |
|  5: ((LAMBDA (APPSINK) :IN START-PROCESSING) #<GIR::OBJECT-INSTANCE {10131E01B3}>)
 | |
|  6: ((LAMBDA (GIR::CLOSURE RETURN GIR::N-VALUES GIR::PARAMS GIR::HINT GIR::DATA) :IN "/nix/store/hijk9y2lcv24s3a5kv56cyxqcn3frgs4-source-patched/src/signal.lisp") #.(SB-SYS:INT-SAP #X7F1FCC470B30) #.(SB-S..
 | |
|  7: ((LAMBDA (SB-ALIEN::ARGS-POINTER SB-ALIEN::RESULT-POINTER FUNCTION) :IN "/nix/store/hijk9y2lcv24s3a5kv56cyxqcn3frgs4-source-patched/src/signal.lisp") #<unavailable argument> #<unavailable argument> #<..
 | |
|  8: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 | |
|  9: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::RUN))
 | |
| 10: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 | |
| 11: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::RUN))
 | |
| 12: (SB-THREAD::RUN)
 | |
| 13: (SB-THREAD::ENTER-FOREIGN-CALLBACK 87 69885224809132 69885224809124)
 | |
| 14: ("foreign function: call_into_lisp_")
 | |
| 15: ("foreign function: funcall3")
 | |
| 16: ("foreign function: callback_wrapper_trampoline")
 | |
| 17: ("foreign function: #x501053AB")
 | |
|  --more--
 | |
| 
 | |
| #+end_src
 | |
| 
 | |
| the source:
 | |
| #+begin_src lisp
 | |
| ;(load (sb-ext:posix-getenv "ASDF"))
 | |
| (asdf:load-system 'cl-cffi-gtk)
 | |
| (asdf:load-system 'cl-gobject-introspection)
 | |
| 
 | |
| (defpackage :capturing-frames
 | |
| 				(:use :cl))
 | |
| 
 | |
| (in-package :capturing-frames)
 | |
| 
 | |
| (defvar *gstreamer* (gir:require-namespace "Gst"))
 | |
| ;(defvar *gstapp* (gir:require-namespace "GstApp"))
 | |
| 
 | |
| (defun cast-with-videobox (&optional stream-num)
 | |
|   (gir:invoke (*gstreamer* 'init) '())
 | |
|   (let* ((pipeline (gir:invoke (*gstreamer* "Pipeline" 'new) "video-pipeline"))
 | |
|          (source (gir:invoke (*gstreamer* "ElementFactory" 'make) (if stream-num
 | |
| 																							"pipewiresrc"
 | |
| 																							"videotestsrc") "source"))
 | |
|          (convert (gir:invoke (*gstreamer* "ElementFactory" 'make) "videoconvert" "convert"))
 | |
| 			(tee (gir:invoke (*gstreamer* "ElementFactory" 'make) "tee" "tee"))
 | |
| 			(queue1 (gir:invoke (*gstreamer* "ElementFactory" 'make) "queue" "queue1"))
 | |
|          (queue2 (gir:invoke (*gstreamer* "ElementFactory" 'make) "queue" "queue2"))
 | |
|          (sink (gir:invoke (*gstreamer* "ElementFactory" 'make) "autovideosink" "sink"))
 | |
| 			(appsink (gir:invoke (*gstreamer* "ElementFactory" 'make) "appsink" "appsink"))
 | |
| 			)
 | |
| 	 (when stream-num
 | |
| 		;; Set pipewiresrc properties, such as the path
 | |
| 		(setf (gir:property source 'path) (format nil "~A" stream-num)))
 | |
| 
 | |
| 	 ;; Add and link elements in the pipeline
 | |
|     (gir:invoke (pipeline 'add) source)
 | |
|     (gir:invoke (pipeline 'add) convert)
 | |
| 	 (gir:invoke (pipeline 'add) tee)
 | |
| 	 (gir:invoke (pipeline 'add) queue1)
 | |
| 	 (gir:invoke (pipeline 'add) queue2)
 | |
| 	 (gir:invoke (pipeline 'add) sink)
 | |
| 	 (gir:invoke (pipeline 'add) appsink)
 | |
|     
 | |
|     (gir:invoke (source 'link) convert)
 | |
| 	 (gir:invoke (convert 'link) tee)
 | |
| 	 (gir:invoke (tee 'link) queue1)
 | |
| 	 (gir:invoke (tee 'link) queue2)
 | |
|     (gir:invoke (queue1 'link) sink)
 | |
| 	 (gir:invoke (queue2 'link) appsink)
 | |
| 
 | |
|     ;; Configure appsink
 | |
| 	 (setf (gir:property appsink "emit-signals") t
 | |
| 			 (gir:property appsink "max-buffers") 1
 | |
| 			 (gir:property appsink "drop") t)
 | |
|     	 
 | |
| 	 (gir:invoke (pipeline 'set-state) (gir:nget *gstreamer* "State" :playing))
 | |
| 	 	 
 | |
| 	 (values pipeline appsink)))
 | |
| 
 | |
| (defun process-frame (sample)
 | |
|   (format t ">>> got to process sample with ~A~%" sample)
 | |
|   (let* ((buffer (gir:invoke (sample 'get-buffer)))
 | |
|          (info (gir:invoke (sample 'get-info)))
 | |
| 			(caps (gir:invoke (sample 'get-caps)))
 | |
| 			(caps-struct (gir:invoke (caps 'get-structure) 0))
 | |
| 			(width (gir:invoke ((gir:invoke (caps-struct 'get-value) "width") 'get-int)))
 | |
| 			(height (gir:invoke ((gir:invoke (caps-struct 'get-value) "height") 'get-int))))
 | |
| 	 
 | |
| 	 (multiple-value-bind (found map-info) (gir:invoke (buffer 'map) (gir:nget *gstreamer* "MapFlags" :read))
 | |
| 		(format t ">>>> the buffer has offset ~A~%" (gir:field buffer 'offset))
 | |
| 		(format t ">>>> what's in struct? ~A~%" (gir:invoke (caps-struct 'to-string)))
 | |
| 		(format t ">>>> the fields are width ~A, height ~A~%" width height)
 | |
| 		(format t ">>>> and map result are ~A and ~A~%" found map-info)
 | |
| 		(when found
 | |
| 		  (let ((data (gir:field map-info 'data))
 | |
| 				  (size (gir:field map-info 'size)))
 | |
| 			 (format t ">>>> and struct info? ~A~%" map-info)
 | |
| 			 (gir:invoke (buffer 'unmap) map-info)
 | |
| 			 (format t ">>>> and data has size ~A and data is ~A~%" size (or data "empty data")))))))
 | |
| 
 | |
| (defun start-processing (appsink)
 | |
|   (gir:connect appsink "new-sample"
 | |
|                (lambda (appsink)
 | |
| 					  (format t ">> got printed object ~A~%" appsink)
 | |
| 					  (format t ">> got printed class ~A~%" (gir:gir-class-of appsink))
 | |
| 					  (format t ">> trying to get method on sink ~A~%" (gir:nget appsink 'pull-sample))
 | |
| 					  (let ((sample (gir:invoke (appsink 'pull-sample))))
 | |
|                    (when sample
 | |
|                      (process-frame sample)))
 | |
| 
 | |
| 					  
 | |
|                  (gir:nget *gstreamer* "FlowReturn" :ok))))
 | |
| 
 | |
| (defun try-run ()
 | |
|   (multiple-value-bind (pipeline appsink) (cast-with-videobox)
 | |
| 	 (format t "got appsink ~A" appsink)
 | |
| 	 (start-processing appsink)
 | |
| 	 (loop
 | |
| 		(sleep 1))))
 | |
| 
 | |
| ;(try-run)  
 | |
| #+end_src
 |