parent
e77bb5e392
commit
e991200a8e
|
@ -24,6 +24,7 @@
|
|||
ps.cl-cffi-gtk
|
||||
ps.sdl2
|
||||
ps.cl-opengl
|
||||
ps.cl-gobject-introspection
|
||||
]);
|
||||
in
|
||||
{
|
||||
|
@ -32,6 +33,9 @@
|
|||
WAYLAND_DISPLAY="wayland-1";
|
||||
EGL_PLATFORM="wayland";
|
||||
buildInputs = [
|
||||
pkgs.gst_all_1.gstreamer
|
||||
pkgs.gst_all_1.gst-plugins-base
|
||||
pkgs.gst_all_1.gst-plugins-good
|
||||
sbcl'
|
||||
];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
(load (sb-ext:posix-getenv "ASDF"))
|
||||
(asdf:load-system 'cl-cffi-gtk)
|
||||
(asdf:load-system 'cl-gobject-introspection)
|
||||
|
||||
(defpackage :tutorial-hello-world
|
||||
(:use :cl))
|
||||
|
||||
(in-package :tutorial-hello-world)
|
||||
|
||||
(gir:require-namespace "GLib")
|
||||
(defvar *gtk* (gir:require-namespace "Gtk" "3.0"))
|
||||
(gir:nget *gtk* "WindowType" :toplevel) ; get enum value
|
||||
|
||||
;; name wildly from
|
||||
;; https://stackoverflow.com/questions/36296165/python-bindings-for-gstreamer-how-to-import-typelib
|
||||
(defvar *gstreamer* (gir:require-namespace "Gst"))
|
||||
|
||||
;; overall capacities of this Glib bindings
|
||||
;; https://github.com/andy128k/cl-gobject-introspection
|
||||
|
||||
;; back to hello-world
|
||||
;; how'd i figure out what are the names to call, sad
|
||||
|
||||
(gir:nget *gstreamer* 'init )
|
||||
(gir:nget *gstreamer* 'parse-launch)
|
||||
(gir:nget *gstreamer* "State" :playing)
|
||||
(gir:nget *gstreamer* "Element" 'set-state)
|
||||
(gir:nget *gstreamer* "Element")
|
||||
|
||||
(progn
|
||||
(gir:invoke (*gstreamer* 'init) '())
|
||||
(let ((pipeline (gir:invoke (*gstreamer* 'parse-launch)
|
||||
"playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm"
|
||||
)))
|
||||
(gir:invoke (pipeline 'set-state)
|
||||
(gir:nget *gstreamer* "State" :playing))))
|
||||
|
||||
(defun tutorial-main ()
|
||||
(gir:invoke (*gstreamer* 'init) '())
|
||||
(let ((pipeline (gir:invoke (*gstreamer* 'parse-launch)
|
||||
"videotestsrc ! videoconvert ! autovideosink"
|
||||
;"playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm"
|
||||
)))
|
||||
(gir:invoke (pipeline 'set-state)
|
||||
(gir:nget *gstreamer* "State" :playing))
|
||||
;; (let* ((bus (gir:invoke (pipeline 'get-bus)))
|
||||
;; (msg (gir:invoke (bus 'timed-pop-filtered)
|
||||
;; (gir:nget *gstreamer* :clock-time-none)
|
||||
;; (list
|
||||
;; (gir:nget *gstreamer* "MessageType" :error)
|
||||
;; (gir:nget *gstreamer* "MessageType" :eos))))))
|
||||
(gir:invoke (pipeline 'set-state)
|
||||
(gir:nget *gstreamer* "State" :paused))))
|
||||
;; call
|
||||
|
||||
;; so, it's only uri stuff didn't work
|
||||
;; videotestsc worked
|
||||
;; and error i got was from trying to set :null ? but it should be correct enum
|
||||
;; oh well, ok
|
|
@ -0,0 +1,174 @@
|
|||
(load (sb-ext:posix-getenv "ASDF"))
|
||||
(asdf:load-system 'cl-cffi-gtk)
|
||||
|
||||
(defpackage :video-processor
|
||||
(:use :cl))
|
||||
|
||||
(in-package :video-processor)
|
||||
|
||||
(defun create-main-window ()
|
||||
(let ((window (gtk:gtk-window-new :toplevel)))
|
||||
(setf (gtk:gtk-window-title window) "Video Processor")
|
||||
(setf (gtk:gtk-window-default-size window) '(800 600))
|
||||
(g:g-signal-connect window "destroy"
|
||||
(lambda (widget)
|
||||
(declare (ignore widget))
|
||||
(gtk:leave-gtk-main)))
|
||||
window))
|
||||
|
||||
(defun create-drawing-area ()
|
||||
(let ((area (gtk:gtk-drawing-area-new)))
|
||||
(g:g-signal-connect area "draw"
|
||||
#'draw-callback)
|
||||
area))
|
||||
|
||||
|
||||
(defun draw-callback (widget cr)
|
||||
(declare (ignore widget))
|
||||
;; Clear the surface with a light gray color
|
||||
(let ((cr (gobject:pointer cr)))
|
||||
(cairo:cairo-set-source-rgb cr 0.9 0.9 0.9)
|
||||
(cairo:cairo-paint cr)
|
||||
|
||||
;; Draw a blue rectangle
|
||||
(cairo:cairo-set-source-rgb cr 0.0 0.0 1.0)
|
||||
(cairo:cairo-rectangle cr 50 50 200 100)
|
||||
(cairo:cairo-fill cr)
|
||||
|
||||
;; Draw some text
|
||||
(cairo:cairo-set-source-rgb cr 0.0 0.0 0.0)
|
||||
|
||||
|
||||
(cairo:cairo-select-font-face cr "Sans" :normal :normal)
|
||||
(cairo:cairo-set-font-size cr 40.0)
|
||||
(cairo:cairo-move-to cr 100 300)
|
||||
(cairo:cairo-show-text cr "Waiting for video...")))
|
||||
|
||||
(defun main ()
|
||||
(gtk:within-main-loop
|
||||
(let* ((window (create-main-window))
|
||||
(area (create-drawing-area)))
|
||||
(gtk:gtk-container-add window area)
|
||||
(gtk:gtk-widget-show-all window))))
|
||||
|
||||
(defun start-video-processing ()
|
||||
;; Initialize Pipewire connection here
|
||||
;; Start a thread to continuously read frames and trigger redraws
|
||||
)
|
||||
|
||||
;(main)
|
||||
;(start-video-processing)
|
||||
|
||||
;; ok, i can create a window
|
||||
|
||||
;; copying stuff with hopes that it will help to get frames from pipewire
|
||||
(cffi:define-foreign-library libpipewire
|
||||
(:unix (:or "/lib/x86_64-linux-gnu/libpipewire-0.3.so.0"
|
||||
"libpipewire-0.3.so.0"
|
||||
"libpipewire-0.3.so"))
|
||||
(t (:default "libpipewire-0.3")))
|
||||
|
||||
(cffi:use-foreign-library libpipewire)
|
||||
|
||||
;; Define constants
|
||||
(defconstant +pw-stream-flag-autoconnect+ 2)
|
||||
|
||||
(defun setup-pipewire ()
|
||||
(pw-init (cffi:null-pointer) (cffi:null-pointer))
|
||||
(let* ((loop (pw-loop-new))
|
||||
(context (pw-context-new loop (cffi:null-pointer) 0))
|
||||
(core (pw-context-connect context (cffi:null-pointer) 0))
|
||||
(stream (pw-stream-new core "my-stream" (cffi:null-pointer))))
|
||||
|
||||
;; Set up stream parameters
|
||||
(let ((params (pw-stream-get-properties stream)))
|
||||
(pw-properties-set params "media.type" "Audio")
|
||||
(pw-properties-set params "media.category" "Capture")
|
||||
(pw-properties-set params "media.role" "Music"))
|
||||
|
||||
;; Connect the stream
|
||||
(let ((stream-flags +pw-stream-flag-autoconnect+)
|
||||
(target 0)) ; Changed to 0 instead of null-pointer for target-id
|
||||
(pw-stream-connect stream "output" target stream-flags (cffi:null-pointer) 0))
|
||||
|
||||
;; Return the created objects
|
||||
(values loop context core stream)))
|
||||
|
||||
(defun setup-pipewire ()
|
||||
(pw-init (cffi:null-pointer) (cffi:null-pointer))
|
||||
(let* ((loop (pw-loop-new)))
|
||||
(unless loop
|
||||
(error "Failed to create Pipewire loop"))
|
||||
|
||||
(let ((context (pw-context-new loop (cffi:null-pointer) 0)))
|
||||
(unless context
|
||||
(error "Failed to create Pipewire context"))
|
||||
|
||||
(let ((core (pw-context-connect context (cffi:null-pointer) 0)))
|
||||
(unless core
|
||||
(error "Failed to connect Pipewire context"))
|
||||
|
||||
(let ((stream (pw-stream-new core "my-stream" (cffi:null-pointer))))
|
||||
(unless stream
|
||||
(error "Failed to create Pipewire stream"))
|
||||
|
||||
;; Set up stream parameters
|
||||
(let ((params (pw-stream-get-properties stream)))
|
||||
(unless params
|
||||
(error "Failed to get stream properties"))
|
||||
|
||||
(unless (= 0 (pw-properties-set params "media.type" "Audio"))
|
||||
(error "Failed to set media.type"))
|
||||
(unless (= 0 (pw-properties-set params "media.category" "Capture"))
|
||||
(error "Failed to set media.category"))
|
||||
(unless (= 0 (pw-properties-set params "media.role" "Music"))
|
||||
(error "Failed to set media.role"))
|
||||
|
||||
;; Connect the stream
|
||||
(let ((stream-flags +pw-stream-flag-autoconnect+)
|
||||
(target 0))
|
||||
(unless (>= (pw-stream-connect stream "output" target stream-flags (cffi:null-pointer) 0) 0)
|
||||
(error "Failed to connect stream"))
|
||||
|
||||
;; Return the created objects
|
||||
(values loop context core stream))))))))
|
||||
|
||||
;; Define necessary CFFI bindings
|
||||
(cffi:defcfun ("pw_init" pw-init) :void
|
||||
(argc :pointer)
|
||||
(argv :pointer))
|
||||
|
||||
(cffi:defcfun ("pw_loop_new" pw-loop-new) :pointer)
|
||||
|
||||
(cffi:defcfun ("pw_context_new" pw-context-new) :pointer
|
||||
(loop :pointer)
|
||||
(properties :pointer)
|
||||
(user-data-size :int))
|
||||
|
||||
(cffi:defcfun ("pw_context_connect" pw-context-connect) :pointer
|
||||
(context :pointer)
|
||||
(properties :pointer)
|
||||
(user-data-size :int))
|
||||
|
||||
(cffi:defcfun ("pw_stream_new" pw-stream-new) :pointer
|
||||
(core :pointer)
|
||||
(name :string)
|
||||
(properties :pointer))
|
||||
|
||||
(cffi:defcfun ("pw_stream_get_properties" pw-stream-get-properties) :pointer
|
||||
(stream :pointer))
|
||||
|
||||
(cffi:defcfun ("pw_properties_set" pw-properties-set) :int
|
||||
(properties :pointer)
|
||||
(key :string)
|
||||
(value :string))
|
||||
|
||||
(cffi:defcfun ("pw_stream_connect" pw-stream-connect) :int
|
||||
(stream :pointer)
|
||||
(direction :string)
|
||||
(target-id :int32)
|
||||
(flags :int)
|
||||
(params :pointer)
|
||||
(n-params :uint32))
|
||||
|
||||
(setup-pipewire)
|
57
notes.org
57
notes.org
|
@ -33,6 +33,8 @@ $ nix shell nixpkgs#kdePackages.qttools
|
|||
* 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
|
||||
|
@ -125,3 +127,58 @@ https://gitlab.gnome.org/-/snippets/19
|
|||
|
||||
** 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
|
||||
|
|
Loading…
Reference in New Issue