Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package wf-recorder for openSUSE:Factory checked in at 2026-03-18 16:50:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/wf-recorder (Old) and /work/SRC/openSUSE:Factory/.wf-recorder.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "wf-recorder" Wed Mar 18 16:50:07 2026 rev:9 rq:1340786 version:0.6.0+git4 Changes: -------- --- /work/SRC/openSUSE:Factory/wf-recorder/wf-recorder.changes 2024-10-15 15:01:11.187624915 +0200 +++ /work/SRC/openSUSE:Factory/.wf-recorder.new.8177/wf-recorder.changes 2026-03-18 16:51:30.191537001 +0100 @@ -1,0 +2,44 @@ +Tue Mar 17 00:35:21 UTC 2026 - Mia Herkt <[email protected]> + +- Use RPM 4.20 declarative build system +- Use non-patented and lossless formats by default and print these + openSUSE-specific defaults in the program’s help output + 0001-Add-openSUSE-specific-defaults-to-help-output.patch +- Add fish-completion package +- Update to version 0.6.0+git4: + * Actually use parsed audio options when opening audio codec + gh#ammen99/wf-recorder#337 + * frame-writer: do not set output color range + gh#ammen99/wf-recorder#332 + * frame-writer: ensure compatibility with ffmpeg 8 + gh#ammen99/wf-recorder#326 + * Fix -y/--overwrite requiring an argument + gh#ammen99/wf-recorder#318 + * feat: add output listing capability + gh#ammen99/wf-recorder#317 + * Automatically transpose video based on output transform + gh#ammen99/wf-recorder#315 + * Document multiple codec parameters + gh#ammen99/wf-recorder#306 + * Update wf-recorder.1 + gh#ammen99/wf-recorder#302 + * Move 'selected region' status message to stderr + gh#ammen99/wf-recorder#303 + * frame-writer: WebM+Opus: Fix silent audio due to inconsistent + sample rate time base in PTS and packet rescaling + gh#ammen99/wf-recorder#298 + * Add fish shell completions + gh#ammen99/wf-recorder#295 + * fix build error if have_audio is false + gh#ammen99/wf-recorder#297 + * add support for RTP streaming + gh#ammen99/wf-recorder#296 + * frame-writer: Use superfast instead of ultrafast for libx264/5 + gh#ammen99/wf-recorder#280 + * Update wf-recorder.1: fix quote rendering in slurp call + gh#ammen99/wf-recorder#290 + * frame-writer: Call the correct function for loading + audio codec parameters + gh#ammen99/wf-recorder#292 + +------------------------------------------------------------------- Old: ---- wf-recorder-0.5.0+git1.obscpio wf-recorder-0.5.0+git1.tar.gz New: ---- 0001-Add-openSUSE-specific-defaults-to-help-output.patch wf-recorder-0.6.0+git4.obscpio ----------(New B)---------- New: openSUSE-specific defaults in the program’s help output 0001-Add-openSUSE-specific-defaults-to-help-output.patch - Add fish-completion package ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ wf-recorder.spec ++++++ --- /var/tmp/diff_new_pack.PcpROR/_old 2026-03-18 16:51:31.147577047 +0100 +++ /var/tmp/diff_new_pack.PcpROR/_new 2026-03-18 16:51:31.155577383 +0100 @@ -1,7 +1,7 @@ # # spec file for package wf-recorder # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # Copyright (c) 2018 Michael Aquilina # # All modifications and additions to the file contributed by third parties @@ -18,15 +18,15 @@ Name: wf-recorder -Version: 0.5.0+git1 +Version: 0.6.0+git4 Release: 0%{?dist} Summary: Utility program for screen recording of wlroots-based compositors License: MIT -Group: System/Management URL: https://github.com/ammen99/wf-recorder -Source0: %{name}-%{version}.tar.gz -BuildRequires: gcc -BuildRequires: gcc-c++ +Source0: %{name}-%{version}.tar.zst +Patch0: 0001-Add-openSUSE-specific-defaults-to-help-output.patch +BuildRequires: c++_compiler +BuildRequires: fish BuildRequires: meson >= 0.54.0 BuildRequires: pkgconfig BuildRequires: pkgconfig(gbm) @@ -36,29 +36,46 @@ BuildRequires: pkgconfig(libavformat) BuildRequires: pkgconfig(libavutil) BuildRequires: pkgconfig(libdrm) -BuildRequires: pkgconfig(libpipewire-0.3) +BuildRequires: pkgconfig(libpipewire-0.3) >= 1.0.5 BuildRequires: pkgconfig(libpulse-simple) BuildRequires: pkgconfig(libswresample) -BuildRequires: pkgconfig(wayland-client) +BuildRequires: pkgconfig(wayland-client) >= 1.20 BuildRequires: pkgconfig(wayland-protocols) >= 1.14 +BuildSystem: meson +# Since the only good non-patented video codec is AV1 and there are +# no fast software encoders for it, let’s just pick a fast lossless codec +# with support for GBR(A) and YUV444 pixel formats. +# FFv1 would offer more formats (e.g. high bit depths) and compression +# ratios similar to libx264 lossless, but it is much slower. +BuildOption: -Ddefault_codec=utvideo +BuildOption: -Ddefault_pixel_format=gbrp +# Opus would be perfectly fine, but we’re doing lossless video anyway, +# so let’s also pick a lossless audio codec. +BuildOption: -Ddefault_audio_codec=flac %description Utility program for screen recording of wlroots-based compositors (more specifically, those that support wlr-screencopy-v1 and xdg-output). -%prep -%setup -q +%package fish-completion +Summary: Fish Completion for %{name} +Requires: %{name} = %{version} +Supplements: (%{name} and fish) +BuildArch: noarch -%build -%meson -%meson_build +%description fish-completion +Fish command line completion support for %{name}. -%install -%meson_install +%prep +# https://github.com/openSUSE/obs-service-source_validator/issues/156 +%autosetup -C -p1 %files %license LICENSE %doc README.md -%attr(0755,root,root) /usr/bin/wf-recorder +%attr(0755,root,root) %{_bindir}/wf-recorder %{_mandir}/man?/%{name}* +%files fish-completion +%{_datadir}/fish/vendor_completions.d/%{name}.fish + ++++++ 0001-Add-openSUSE-specific-defaults-to-help-output.patch ++++++ >From e84c9a29ae9d33e747be9cb4cc522e58eb675fd8 Mon Sep 17 00:00:00 2001 From: Mia Herkt <[email protected]> Date: Tue, 17 Mar 2026 02:17:34 +0100 Subject: [PATCH] Add openSUSE-specific defaults to help output --- src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 8ff65f9..35b6a37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -911,6 +911,7 @@ Use Ctrl+C to stop.)"); -c, --codec Specifies the codec of the video. These can be found by using: ffmpeg -encoders To modify codec parameters, use -p <option_name>=<option_value> + openSUSE default: utvideo (lossless) -r, --framerate Changes framerate to constant framerate with a given value. @@ -940,6 +941,7 @@ Use Ctrl+C to stop.)"); -x, --pixel-format Set the output pixel format. These can be found by running: ffmpeg -pix_fmts + openSUSE default: gbrp (lowest recording overhead with utvideo) -g, --geometry Selects a specific part of the screen. The format is "x,y WxH". @@ -971,6 +973,7 @@ Use Ctrl+C to stop.)"); -C, --audio-codec Specifies the codec of the audio. These can be found by running: ffmpeg -encoders To modify codec parameters, use -P <option_name>=<option_value> + openSUSE default: flac (lossless) -X, --sample-format Set the output audio sample format. These can be found by running: ffmpeg -sample_fmts -- 2.53.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.PcpROR/_old 2026-03-18 16:51:31.355585761 +0100 +++ /var/tmp/diff_new_pack.PcpROR/_new 2026-03-18 16:51:31.379586766 +0100 @@ -1,20 +1,17 @@ <services> - <service name="obs_scm" mode="disabled"> + <service name="obs_scm" mode="manual"> <param name="scm">git</param> <param name="url">https://github.com/ammen99/wf-recorder.git</param> - <param name="revision">560bb92d3ddaeb31d7af77d22d01b0050b45bebe</param> <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@</param> <param name="versionrewrite-pattern">v(.*)</param> - <param name="versionrewrite-replacement">\1</param> <param name="changesgenerate">enable</param> - <param name="changesauthor">[email protected]</param> </service> - <service mode="disabled" name="tar" /> - <service mode="disabled" name="recompress"> + <service mode="buildtime" name="tar" /> + <service mode="buildtime" name="recompress"> <param name="file">*.tar</param> - <param name="compression">gz</param> + <param name="compression">zstd</param> </service> - <service mode="disabled" name="set_version"/> + <service mode="manual" name="set_version"/> </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.PcpROR/_old 2026-03-18 16:51:31.511592296 +0100 +++ /var/tmp/diff_new_pack.PcpROR/_new 2026-03-18 16:51:31.531593134 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/ammen99/wf-recorder.git</param> - <param name="changesrevision">560bb92d3ddaeb31d7af77d22d01b0050b45bebe</param></service></servicedata> + <param name="changesrevision">6b562c1b5f1a37d82d0c19bfb94d1af8b9b5c031</param></service></servicedata> (No newline at EOF) ++++++ wf-recorder-0.5.0+git1.obscpio -> wf-recorder-0.6.0+git4.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/README.md new/wf-recorder-0.6.0+git4/README.md --- old/wf-recorder-0.5.0+git1/README.md 2024-10-08 20:56:55.000000000 +0200 +++ new/wf-recorder-0.6.0+git4/README.md 2026-02-20 22:46:22.000000000 +0100 @@ -2,81 +2,30 @@ wf-recorder is a utility program for screen recording of `wlroots`-based compositors (more specifically, those that support `wlr-screencopy-v1` and `xdg-output`). Its dependencies are `ffmpeg`, `wayland-client` and `wayland-protocols`. -# installation +# Installation -[comment]: <> (List ordered alphabetically) - -## Alpine Linux - -wf-recorder is available in the community repositories: -``` -apk add wf-recorder -``` - -## Arch Linux - -Arch users can install wf-recorder from the Community repo. -``` -pacman -S wf-recorder -``` - -## Artix Linux +The following distributions are known to have packages: -Artix users can install wf-recorder from the official repos -``` -pacman -S wf-recorder -``` - -## Debian GNU/Linux - -Debian users can install wf-recorder from official repos -``` -apt install wf-recorder -``` - -## Fedora Linux - -Fedora users can install wf-recorder from the official repos -``` -sudo dnf install wf-recorder -``` - -## Gentoo Linux - -Gentoo users can install wf-recorder from the official (`::gentoo`) repository. - -## NixOS / Nix - -Users of the Nix package manager can add the `wf-recorder` package to their system configurations, or use `nix-shell` / `nix shell` / `nix run`: - -``` -nix-shell -p wf-recorder -# OR -nix shell nixpkgs#wf-recorder -# OR -nix run nixpkgs#wf-recorder -``` - -## Void Linux - -Void users can install wf-recorder from the official repos -``` -xbps-install -S wf-recorder -``` +[comment]: <> (List ordered alphabetically) +| Distribution | Installation | +| ------------ | ----------------------------- | +| Alpine | ```apk add wf-recorder``` | +| Arch / Artix | ```pacman -S wf-recorder``` | +| Debian | ```apt install wf-recorder``` | +| Fedora | ```dnf install wf-recorder``` | +| Gentoo | Available in the official `::gentoo` repository | +| NixOS / Nix | Add `wf-recoder` to configuration or run any of: `nix-shell -p wf-recorder`, `nix shell nixpkgs#wfrecorder`, `nix run nixpkgs#wf-recorder` | +| Void | ```xbps-install -S wf-recorder``` | ## From Source ### Install Dependencies -#### Ubuntu -``` -sudo apt install g++ meson libavutil-dev libavcodec-dev libavformat-dev libswscale-dev libpulse-dev -``` - -#### Fedora -``` -$ sudo dnf install gcc-c++ meson wayland-devel wayland-protocols-devel ffmpeg-free-devel pulseaudio-libs-devel -``` +| Distribution | Install dependencies packages | +| ------------ | --------------------- | +| Ubuntu | ```sudo apt install g++ meson libavutil-dev libavcodec-dev libavformat-dev libswscale-dev libpulse-dev``` | +| Fedora | ```sudo dnf install gcc-c++ meson wayland-devel wayland-protocols-devel ffmpeg-free-devel pulseaudio-libs-devel``` | +| Void | ```sudo xbps-install -S meson ninja gcc pkg-config scdoc wayland-devel wayland-protocols wayland-devel libgbm-devel libdrm-devel ffmpeg6-devel x264-devel pulseaudio-devel pipewire-devel``` | ### Download & Build ``` @@ -92,6 +41,7 @@ In its simplest form, run `wf-recorder` to start recording and use Ctrl+C to stop. This will create a file called `recording.mp4` in the current working directory using the default codec. Use `-f <filename>` to specify the output file. In case of multiple outputs, you'll first be prompted to select the output you want to record. If you know the output name beforehand, you can use the `-o <output name>` option. +To view all available output options, use the list flag `-L` or `--list-output` To select a specific part of the screen you can either use `-g <geometry>`, or use [slurp](https://github.com/emersion/slurp) for interactive selection of the screen area that will be recorded: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/completions/wf-recorder.fish new/wf-recorder-0.6.0+git4/completions/wf-recorder.fish --- old/wf-recorder-0.5.0+git1/completions/wf-recorder.fish 1970-01-01 01:00:00.000000000 +0100 +++ new/wf-recorder-0.6.0+git4/completions/wf-recorder.fish 2026-02-20 22:46:22.000000000 +0100 @@ -0,0 +1,26 @@ +complete -c wf-recorder --no-files + +complete -c wf-recorder -s a -l audio -d 'Starts recording the screen with audio' --arguments '(pactl list sources | grep Name | cut -d " " -f 2)' +complete -c wf-recorder -s c -l codec -d 'Specifies the codec of the video' --arguments '(ffmpeg -hide_banner -encoders | grep "^ V" | grep -F "(codec" | cut -c 9- | cut -d " " -f 1)' --exclusive +complete -c wf-recorder -s r -l framerate -d 'Changes framerate to constant framerate with a given value' --exclusive +complete -c wf-recorder -s d -l device -d 'Selects the device to use when encoding the video' --arguments '(find /dev/dri -type c)' --exclusive +complete -c wf-recorder -l no-dmabuf -d 'Disables GPU buffer usage, forcing CPU copy to avoid potential issues.' +complete -c wf-recorder -s D -l no-damage -d 'Disables damage-based recording, capturing frames continuously for a constant refresh rate.' +complete -c wf-recorder -s f -d 'Sets the output file name and format based on the given extension.' --require-parameter --force-files +complete -c wf-recorder -s m -l muxer -d 'Set the output format to a specific muxer' --arguments '(ffmpeg -hide_banner -muxers | grep "^ E" | cut -c 6- | cut -d " " -f 1 | tr "," "\n")' --exclusive +complete -c wf-recorder -s x -l pixel-format -d 'Set the output pixel format' --arguments '(ffmpeg -hide_banner -pix_fmts | tail -n +9 | cut -d " " -f 2)' --exclusive +complete -c wf-recorder -s g -l geometry -d 'Selects a specific part of the screen. The format is "x,y WxH".' --exclusive +complete -c wf-recorder -s h -l help -d 'Prints help' +complete -c wf-recorder -s v -l version -d 'Prints the version of wf-recorder' +complete -c wf-recorder -s l -l log -d 'Generates a log on the current terminal' +complete -c wf-recorder -s o -l output -d 'Specify the output where the video is to be recorded' --exclusive +complete -c wf-recorder -s p -l codec-param -d 'Change the codec parameters. (ex. -p <option_name>=<option_value>)' --exclusive +complete -c wf-recorder -s F -l filter -d 'Specify the ffmpeg filter string to use. (ex. -F scale_vaapi=format=nv12)' --exclusive +complete -c wf-recorder -s b -l bframes -d 'This option is used to set the maximum number of b-frames to be used' --exclusive +complete -c wf-recorder -s B -l buffrate -d 'This option is used to specify the buffers expected framerate' --exclusive +complete -c wf-recorder -l audio-backend -d 'Specifies the audio backend' --exclusive +complete -c wf-recorder -s C -l audio-codec -d 'Specifies the codec of the audio' --exclusive +complete -c wf-recorder -s X -l sample-format -d 'Set the output audio sample format' --arguments '(ffmpeg -hide_banner -sample_fmts | tail -n +2 | cut -d " " -f 1)' --exclusive +complete -c wf-recorder -s R -l sample-rate -d 'Changes the audio sample rate in HZ. (default: 48000)' --exclusive +complete -c wf-recorder -s P -l audio-codec-param -d 'Change the audio codec parameters. (ex.. -P <option_name>=<option_value>)' --exclusive +complete -c wf-recorder -s y -l overwrite -d 'Force overwriting the output file without prompting' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/manpage/wf-recorder.1 new/wf-recorder-0.6.0+git4/manpage/wf-recorder.1 --- old/wf-recorder-0.5.0+git1/manpage/wf-recorder.1 2024-10-08 20:56:55.000000000 +0200 +++ new/wf-recorder-0.6.0+git4/manpage/wf-recorder.1 2026-02-20 22:46:22.000000000 +0100 @@ -15,12 +15,13 @@ .Op Fl d, -device Ar encoding_device .Op Fl -no-dmabuf .Op Fl D, -no-damage -.Op Fl f Ar filename.ext +.Op Fl f, -file Ar filename.ext .Op Fl F Ar filter_string .Op Fl g, -geometry Ar geometry .Op Fl h, -help .Op Fl l, -log .Op Fl m, -muxer Ar muxer +.Op Fl L, -list-output .Op Fl o, -output Ar output .Op Fl p, -codec-param Op Ar option_param=option_value .Op Fl v, -version @@ -66,18 +67,18 @@ .It Fl b , -bframes Ar max_b_frames Sets the maximum number of B-Frames to use. .It Fl B , -buffrate Ar buffrate -Tells the encoder a prediction of what framerate to expect. +Tells the encoder a prediction of what framerate to expect. This preserves VFR and Solves FPS limit issue of some encoders (like svt-av1). Should be set to the same framerate as display. .Pp .It Fl c , -codec Ar output_codec Specifies the codec of the video. Supports GIF output as well. .Pp -To modify codec parameters, use +To change codec parameters, use .Fl p Ar option_name=option_value .Pp .It Fl r , -framerate Ar framerate -Sets hard constant framerate. Will duplicate frames to reach it. +Sets hard constant framerate. Will duplicate frames to reach it. This makes the resulting video CFR. Solves FPS limit issue of some encoders. .Pp .It Fl d , -device Ar encoding_device @@ -103,7 +104,7 @@ on, wf-recorder does not use this optimization and continuously records new frames, even if there are no updates on the screen. .Pp -.It Fl f Ar filename.ext +.It Fl f , -file Ar filename.ext By using the .Fl f option, the output file will have the name @@ -133,11 +134,16 @@ .It Fl m , -muxer Ar muxer Set the output format to a specific muxer instead of detecting it from the filename. .Pp +.It Fl L , -list-output +List the available outputs. +.Pp .It Fl o , -output Specify the output where the video is to be recorded. .Pp .It Fl p , -codec-param Op Ar option_name=option_value -Change the codec parameters. +Change a codec parameter. Can be used multiple times: +.Fl p Ar option_name_1=option_value_1 +.Fl p Ar option_name_2=option_value_2 .Pp .It Fl v , -version Print the version of wf-recorder. @@ -176,7 +182,7 @@ or use https://github.com/emersion/slurp for interactive selection of the screen area that will be recorded: -.Dl $ wf-recorder -g "$(slurp)" +.Dl $ wf-recorder -g \(dq$(slurp)\(dq .Pp You can record screen and sound simultaneously with .Dl $ wf-recorder --audio --file=recording_with_audio.mp4 @@ -191,9 +197,10 @@ .Ar codec use the .Fl c Ar codec -option. To modify codec parameters, +option. To change codec parameters, use the .Fl p -.Ar option_name=option_value. +option: +.Dl $ wf-recorder -c libx264 -p preset=slow -p crf=18 .Pp To set a specific output format, use the .Fl m, -muxer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/meson.build new/wf-recorder-0.6.0+git4/meson.build --- old/wf-recorder-0.5.0+git1/meson.build 2024-10-08 20:56:55.000000000 +0200 +++ new/wf-recorder-0.6.0+git4/meson.build 2026-02-20 22:46:22.000000000 +0100 @@ -2,7 +2,7 @@ 'wf-recorder', 'c', 'cpp', - version: '0.5.0', + version: '0.6.0', license: 'MIT', meson_version: '>=0.54.0', default_options: [ @@ -127,6 +127,9 @@ install_data('manpage/wf-recorder.1', install_dir : join_paths(get_option('prefix'), get_option('mandir'), 'man1')) +install_data('completions/wf-recorder.fish', install_dir : + join_paths(get_option('prefix'), 'share/fish/vendor_completions.d/')) + subdir('proto') dependencies = [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/src/frame-writer.cpp new/wf-recorder-0.6.0+git4/src/frame-writer.cpp --- old/wf-recorder-0.5.0+git1/src/frame-writer.cpp 2024-10-08 20:56:55.000000000 +0200 +++ new/wf-recorder-0.6.0+git4/src/frame-writer.cpp 2026-02-20 22:46:22.000000000 +0100 @@ -5,8 +5,7 @@ #include <iostream> #include "frame-writer.hpp" -#include <vector> -#include <queue> +#include <libavfilter/version.h> #include <cstring> #include <sstream> #include "averr.h" @@ -50,7 +49,7 @@ static const CodecOptions default_x264_options = { {"tune", "zerolatency"}, - {"preset", "ultrafast"}, + {"preset", "superfast"}, {"crf", "20"}, }; @@ -212,15 +211,65 @@ return best_format; } +static std::string transpose_from_transform(int32_t transform) +{ + switch (transform) + { + case WL_OUTPUT_TRANSFORM_90: + fprintf(stderr, "Transform: 90\n"); + return "transpose=" + std::to_string(1); + break; + case WL_OUTPUT_TRANSFORM_180: + fprintf(stderr, "Transform: 180\n"); + return "transpose=" + std::to_string(1) + ",transpose=" + std::to_string(1); + break; + case WL_OUTPUT_TRANSFORM_270: + fprintf(stderr, "Transform: 270\n"); + return "transpose=" + std::to_string(2); + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + fprintf(stderr, "Transform: FLIPPED\n"); + return "hflip"; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + fprintf(stderr, "Transform: FLIPPED_90\n"); + return "transpose=" + std::to_string(1) + ",hflip"; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + fprintf(stderr, "Transform: FLIPPED_180\n"); + return "vflip"; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + fprintf(stderr, "Transform: FLIPPED_270\n"); + return "transpose=" + std::to_string(2) + ",hflip"; + break; + case WL_OUTPUT_TRANSFORM_NORMAL: + default: + break; + } + return ""; +} + void FrameWriter::init_video_filters(const AVCodec *codec) { + if (params.transform != 0) { + if (params.video_filter != "null" && + params.video_filter.find("transpose") == std::string::npos && + params.video_filter.find("hflip") == std::string::npos && + params.video_filter.find("vflip") == std::string::npos) { + params.video_filter += "," + transpose_from_transform(params.transform); + } + else if (params.video_filter == "null"){ + params.video_filter = transpose_from_transform(params.transform); + } + } if (params.framerate != 0){ if (params.video_filter != "null" && params.video_filter.find("fps") == std::string::npos) { params.video_filter += ",fps=" + std::to_string(params.framerate); } else if (params.video_filter == "null"){ params.video_filter = "fps=" + std::to_string(params.framerate); - } + } } this->videoFilterGraph = avfilter_graph_alloc(); @@ -260,10 +309,10 @@ } buffer_filter_config << ":pixel_aspect=1/1"; - int err = avfilter_graph_create_filter(&this->videoFilterSourceCtx, source, - "Source", buffer_filter_config.str().c_str(), NULL, this->videoFilterGraph); - if (err < 0) { - std::cerr << "Cannot create video filter in: " << averr(err) << std::endl;; + this->videoFilterSourceCtx = avfilter_graph_alloc_filter(this->videoFilterGraph, + source, "Source"); + if (!this->videoFilterSourceCtx) { + std::cerr << "Cannot alloc video filter in." << std::endl;; exit(-1); } @@ -271,23 +320,31 @@ memset(p, 0, sizeof(*p)); p->format = AV_PIX_FMT_NONE; p->hw_frames_ctx = this->hw_frame_context_in; - err = av_buffersrc_parameters_set(this->videoFilterSourceCtx, p); + int err = av_buffersrc_parameters_set(this->videoFilterSourceCtx, p); av_free(p); if (err < 0) { std::cerr << "Cannot set hwcontext filter in: " << averr(err) << std::endl;; exit(-1); } - err = avfilter_graph_create_filter(&this->videoFilterSinkCtx, sink, "Sink", - NULL, NULL, this->videoFilterGraph); + err = avfilter_init_str(this->videoFilterSourceCtx, buffer_filter_config.str().c_str()); if (err < 0) { - std::cerr << "Cannot create video filter out: " << averr(err) << std::endl;; + std::cerr << "Cannot init filter in: " << averr(err) << std::endl;; + exit(-1); + } + + this->videoFilterSinkCtx = avfilter_graph_alloc_filter(this->videoFilterGraph, + sink, "Sink"); + if (!this->videoFilterSinkCtx) { + std::cerr << "Cannot alloc video filter out." << std::endl;; exit(-1); } // We also need to tell the sink which pixel formats are supported. // by the video encoder. codevIndicate to our sink pixel formats // are accepted by our codec. + // pixel_formats used to be called pix_fmts and was renamed in 10.6.100 +#if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(10, 6, 100) const AVPixelFormat picked_pix_fmt[] = { handle_buffersink_pix_fmt(codec), @@ -296,12 +353,22 @@ err = av_opt_set_int_list(this->videoFilterSinkCtx, "pix_fmts", picked_pix_fmt, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); +#else + err = av_opt_set(this->videoFilterSinkCtx, "pixel_formats", + av_get_pix_fmt_name(handle_buffersink_pix_fmt(codec)), AV_OPT_SEARCH_CHILDREN); +#endif if (err < 0) { std::cerr << "Failed to set pix_fmts: " << averr(err) << std::endl;; exit(-1); } + err = avfilter_init_dict(this->videoFilterSinkCtx, NULL); + if (err < 0) { + std::cerr << "Cannot init filter out: " << averr(err) << std::endl;; + exit(-1); + } + // Create the connections to the filter graph // // The in/out swap is not a mistake: @@ -403,9 +470,8 @@ videoCodecCtx->width = params.width; videoCodecCtx->height = params.height; videoCodecCtx->time_base = US_RATIONAL; - videoCodecCtx->color_range = AVCOL_RANGE_JPEG; if (params.framerate) { - std::cerr << "Framerate: " << params.framerate << std::endl; + std::cerr << "Framerate: " << params.framerate << std::endl; } if (params.bframes != -1) @@ -526,7 +592,7 @@ void FrameWriter::init_audio_stream() { AVDictionary *options = NULL; - load_codec_options(&options); + load_audio_codec_options(&options); const AVCodec* codec = avcodec_find_encoder_by_name(params.audio_codec.c_str()); if (!codec) @@ -558,13 +624,13 @@ audioCodecCtx->channels = av_get_channel_layout_nb_channels(audioCodecCtx->channel_layout); #endif audioCodecCtx->sample_rate = params.sample_rate; - audioCodecCtx->time_base = (AVRational) { 1, 1000 }; + audioCodecCtx->time_base = (AVRational) { 1, audioCodecCtx->sample_rate }; if (fmtCtx->oformat->flags & AVFMT_GLOBALHEADER) audioCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; int err; - if ((err = avcodec_open2(audioCodecCtx, codec, NULL)) < 0) + if ((err = avcodec_open2(audioCodecCtx, codec, &options)) < 0) { std::cerr << "(audio) avcodec_open2 failed " << err << std::endl; std::exit(-1); @@ -642,6 +708,9 @@ if (params.file.find("udp") == 0) return "mpegts"; + + if (params.file.find("rtp") == 0) + return "rtp_mpegts"; return NULL; } @@ -855,7 +924,7 @@ in = swr_next_pts(ctx, in); /* Convert from 1/(src_samplerate * dst_samplerate) to audio_dst_tb */ - return av_rescale_rnd(in, DST_RATE, d, AV_ROUND_NEAR_INF); + return av_rescale_rnd(in, sample_rate, d, AV_ROUND_NEAR_INF); } void FrameWriter::send_audio_pkt(AVFrame *frame) @@ -921,7 +990,7 @@ #ifdef HAVE_AUDIO else { - av_packet_rescale_ts(&pkt, (AVRational){ 1, 1000 }, audioStream->time_base); + av_packet_rescale_ts(&pkt, audioCodecCtx->time_base, audioStream->time_base); pkt.stream_index = audioStream->index; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/src/frame-writer.hpp new/wf-recorder-0.6.0+git4/src/frame-writer.hpp --- old/wf-recorder-0.5.0+git1/src/frame-writer.hpp 2024-10-08 20:56:55.000000000 +0200 +++ new/wf-recorder-0.6.0+git4/src/frame-writer.hpp 2026-02-20 22:46:22.000000000 +0100 @@ -9,6 +9,7 @@ #include <vector> #include <map> #include <atomic> +#include <wayland-client-protocol.h> #include "config.h" extern "C" @@ -29,8 +30,6 @@ #include <libavutil/hwcontext_drm.h> } -#include "config.h" - enum InputFormat { INPUT_FORMAT_BGR0, @@ -69,6 +68,7 @@ int framerate = 0; int sample_rate; int buffrate = 0; + int32_t transform = 0; int64_t audio_sync_offset; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wf-recorder-0.5.0+git1/src/main.cpp new/wf-recorder-0.6.0+git4/src/main.cpp --- old/wf-recorder-0.5.0+git1/src/main.cpp 2024-10-08 20:56:55.000000000 +0200 +++ new/wf-recorder-0.6.0+git4/src/main.cpp 2026-02-20 22:46:22.000000000 +0100 @@ -17,7 +17,6 @@ #include <sys/stat.h> #include <signal.h> #include <unistd.h> -#include <wayland-client-protocol.h> #include <gbm.h> #include <fcntl.h> #include <xf86drm.h> @@ -58,10 +57,72 @@ zxdg_output_v1 *zxdg_output; std::string name, description; int32_t x, y, width, height; + int32_t transform; }; std::list<wf_recorder_output> available_outputs; +static void +display_handle_geometry(void *data, + wl_output *, + int32_t, int32_t, + int32_t, + int32_t, + int32_t, + const char *, + const char *, + int32_t transform) +{ + wf_recorder_output *wo = (wf_recorder_output*) data; + + wo->transform = transform; +} + +static void +display_handle_mode(void *, + struct wl_output *, + uint32_t, + int32_t, + int32_t, + int32_t) +{ +} + +static void +display_handle_done(void *, wl_output *) +{ +} + +static void +display_handle_scale(void *, + wl_output *, + int32_t) +{ +} + +static void +display_handle_name(void *, + wl_output *, + const char *) +{ +} + +static void +display_handle_description(void *, + wl_output *, + const char *) +{ +} + +static const struct wl_output_listener output_listener = { + display_handle_geometry, + display_handle_mode, + display_handle_done, + display_handle_scale, + display_handle_name, + display_handle_description +}; + static void handle_xdg_output_logical_position(void*, zxdg_output_v1* zxdg_output, int32_t x, int32_t y) { @@ -466,10 +527,11 @@ if (strcmp(interface, wl_output_interface.name) == 0) { - auto output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 1); + auto output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 4); wf_recorder_output wro; wro.output = output; available_outputs.push_back(wro); + wl_output_add_listener(output, &output_listener, &available_outputs.back()); } else if (strcmp(interface, wl_shm_interface.name) == 0) { @@ -611,6 +673,7 @@ uint64_t sync_timestamp = 0; if (first_frame_ts.has_value()) { sync_timestamp = buffer.base_usec - first_frame_ts.value(); +#ifdef HAVE_AUDIO } else if (pr) { if (!pr->get_time_base() || pr->get_time_base() > buffer.base_usec) { drop = true; @@ -618,6 +681,7 @@ first_frame_ts = pr->get_time_base(); sync_timestamp = buffer.base_usec - first_frame_ts.value(); } +#endif } else { sync_timestamp = 0; first_frame_ts = buffer.base_usec; @@ -728,7 +792,6 @@ wl_display_roundtrip(display); } - static void load_output_info() { for (auto& wo : available_outputs) @@ -742,16 +805,23 @@ sync_wayland(); } -static wf_recorder_output* choose_interactive() +static void print_available_outputs() { - fprintf(stdout, "Please select an output from the list to capture (enter output no.):\n"); - int i = 1; for (auto& wo : available_outputs) { printf("%d. Name: %s Description: %s\n", i++, wo.name.c_str(), wo.description.c_str()); } +} + + + +static wf_recorder_output* choose_interactive() +{ + fprintf(stdout, "Please select an output from the list to capture (enter output no.):\n"); + + print_available_outputs(); printf("Enter output no.:"); fflush(stdout); @@ -879,6 +949,8 @@ -l, --log Generates a log on the current terminal. Debug purposes. + -L, --list-output List the available outputs. + -o, --output Specify the output where the video is to be recorded. -p, --codec-param Change the codec parameters. @@ -987,6 +1059,29 @@ } } +static void init_wayland_client() +{ + display = wl_display_connect(NULL); + if (display == NULL) + { + fprintf(stderr, "failed to create display: %m\n"); + exit(EXIT_FAILURE); + } + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + sync_wayland(); +} + +static void list_available_outputs() +{ + init_wayland_client(); + load_output_info(); + print_available_outputs(); + + exit(EXIT_SUCCESS); +} + + int main(int argc, char *argv[]) { FrameWriterParams params = FrameWriterParams(exit_main_loop); @@ -1029,11 +1124,12 @@ { "version", no_argument, NULL, 'v' }, { "no-damage", no_argument, NULL, 'D' }, { "overwrite", no_argument, NULL, 'y' }, + { "list-output", no_argument, NULL, 'L' }, { 0, 0, NULL, 0 } }; int c, i; - while((c = getopt_long(argc, argv, "o:f:m:g:c:p:r:x:C:P:R:X:d:b:B:la::hvDF:y", opts, &i)) != -1) + while((c = getopt_long(argc, argv, "o:f:m:g:c:p:r:x:C:P:R:X:d:b:B:la::hvDF:yL", opts, &i)) != -1) { switch(c) { @@ -1135,10 +1231,14 @@ force_overwrite = true; break; + case 'L': + list_available_outputs(); + break; +#ifdef HAVE_AUDIO case '*': audioParams.audio_backend = optarg; break; - +#endif default: printf("Unsupported command line argument %s\n", optarg); } @@ -1149,16 +1249,7 @@ return EXIT_FAILURE; } - display = wl_display_connect(NULL); - if (display == NULL) - { - fprintf(stderr, "failed to create display: %m\n"); - return EXIT_FAILURE; - } - - struct wl_registry *registry = wl_display_get_registry(display); - wl_registry_add_listener(registry, ®istry_listener, NULL); - sync_wayland(); + init_wayland_client(); if (params.codec.find("vaapi") != std::string::npos) { @@ -1265,6 +1356,8 @@ return EXIT_FAILURE; } + params.transform = chosen_output->transform; + if (selected_region.is_selected()) { if (!selected_region.contained_in({chosen_output->x, chosen_output->y, @@ -1274,9 +1367,13 @@ "inside the output\n"); selected_region = capture_region{}; } + } else + { + selected_region = capture_region{chosen_output->x, chosen_output->y, + chosen_output->width, chosen_output->height}; } - printf("selected region %d,%d %dx%d\n", selected_region.x, selected_region.y, selected_region.width, selected_region.height); + fprintf(stderr, "selected region %d,%d %dx%d\n", selected_region.x, selected_region.y, selected_region.width, selected_region.height); bool spawned_thread = false; std::thread writer_thread; ++++++ wf-recorder.obsinfo ++++++ --- /var/tmp/diff_new_pack.PcpROR/_old 2026-03-18 16:51:32.051614916 +0100 +++ /var/tmp/diff_new_pack.PcpROR/_new 2026-03-18 16:51:32.083616257 +0100 @@ -1,5 +1,5 @@ name: wf-recorder -version: 0.5.0+git1 -mtime: 1728413815 -commit: 560bb92d3ddaeb31d7af77d22d01b0050b45bebe +version: 0.6.0+git4 +mtime: 1771623982 +commit: 6b562c1b5f1a37d82d0c19bfb94d1af8b9b5c031
