Recherche avancée

Médias (1)

Mot : - Tags -/biographie

Autres articles (15)

  • Creating farms of unique websites

    13 avril 2011, par

    MediaSPIP platforms can be installed as a farm, with a single "core" hosted on a dedicated server and used by multiple websites.
    This allows (among other things) : implementation costs to be shared between several different projects / individuals rapid deployment of multiple unique sites creation of groups of like-minded sites, making it possible to browse media in a more controlled and selective environment than the major "open" (...)

  • Les autorisations surchargées par les plugins

    27 avril 2010, par

    Mediaspip core
    autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs

  • Gestion des droits de création et d’édition des objets

    8 février 2011, par

    Par défaut, beaucoup de fonctionnalités sont limitées aux administrateurs mais restent configurables indépendamment pour modifier leur statut minimal d’utilisation notamment : la rédaction de contenus sur le site modifiables dans la gestion des templates de formulaires ; l’ajout de notes aux articles ; l’ajout de légendes et d’annotations sur les images ;

Sur d’autres sites (3987)

  • ffmpeg x11grab to streamable format

    2 juin 2021, par Jintor

    2 FFMPEG process

    


    (1) generating a ffmpeg x11grab to a .mp4
(2) take the .mp4 and restream it simultaneously to multiple rtmp endpoints

    


    ISSUE the generated file in (1) have this error "moov atom not found"

    


    This is the command that generate (1) :

    


    ffmpeg -re -y -f x11grab -draw_mouse 0 -framerate 30 
-video_size $RESOLUTION -i :$DISPLAY_NUM -c:a aac -c:v libx264 
-movflags +faststart -preset ultrafast -crf 28 -refs 4 -qmin 4 
-pix_fmt yuv420p -filter:v fps=30 file.mp4


    


    in the (2) => when I try to ffmpeg -i file.mp4 output somewhere : I get "moov atom not found" so the (2) can't read or open (1).

    


    What I'm I missing

    


    in (1) -movflags +faststart doesn't seem to fix the issue

    


    ••••••• EDIT : more details on the context ••••••

    


    I'm using openvidu : webrtc with kurento and coturn.

    


    The record feature creates a .mp4 on the fly as the chat is going on.

    


    To start the recording, there is an API call i can make to my server and it automatically stops when all users leaves the chatroom OR do an other api call to stop. see composed video in this link https://docs.openvidu.io/en/2.17.0/advanced-features/recording/

    


    openvidu have also webhooks.

    


    My problem is not how to stop ffmpeg, but getting FFMPEG to encode while the mp4 or other is being generated "on the fly".

    


    There is 2 options :

    


    OPTION 1 : individual => 1 .webm per camare => this .webm ffmpeg can restream as hls or RTMP => it's working.

    


    OPTION 2 : ** but the issue is with "Composed" video => it's using ffmpeg to x11grab the session... but it's mp4 without moov ato, so ffmpeg don't do anything with this.

    


    see the composed.sh script here
https://github.com/OpenVidu/openvidu/blob/master/openvidu-server/docker/openvidu-recording/scripts/composed.sh

    


    ***************** EDIT 3 *************

    


    in the .sh this is the part that is creating the mp4

    


    ffmpeg -y -f alsa -i pulse -f x11grab -draw_mouse 0
-framerate $FRAMERATE -video_size $RESOLUTION -i :$DISPLAY_NUM
-c:a aac -c:v libx264 -preset ultrafast
-crf 28 -refs 4 -qmin 4 -pix_fmt yuv420p
-filter:v fps=$FRAMERATE "/recordings/$VIDEO_ID/$VIDEO_NAME.$VIDEO_FORMAT"

    


    How can I modify this to have better result example VP8 or VP9 with good quality .webm so that the ffpmeg second command(2) can encode it live...

    


    **** EDIT 4 ********

    


    I tried this it worked for 30 seconds and suddenly stopped

    


        &lt;./stop ffmpeg -y -f alsa -i pulse -f &#xA;x11grab -draw_mouse 0 -framerate $FRAMERATE &#xA;-video_size $RESOLUTION -i :$DISPLAY_NUM &#xA;-c:v libx264 -b:v 1396k -b:a 128k -ar 44100 -maxrate 1369k &#xA;-pix_fmt yuv420p -preset veryfast -tune zerolatency &#xA;-c:a aac -ac 2 -profile:v main -flags -global_header &#xA;-bufsize 969k -hls_time 1 -hls_list_size 0 -g 30 &#xA;-start_number 0 -streaming 1 -hls_playlist 1 &#xA;-lhls 1 -hls_playlist_type event -f hls "/recordings/$VIDEO_ID/$VIDEO_NAME".m3u8&#xA;&#xA;&#xA;N: [pulseaudio] main.c: Running in system mode, forcibly disabling SHM mode.&#xA;N: [pulseaudio] main.c: Running in system mode, forcibly disabling exit idle time.&#xA;Display in use -> :99&#xA;----------------------------------------&#xA;ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers&#xA;  built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)&#xA;  configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared&#xA;  libavutil      56. 31.100 / 56. 31.100&#xA;  libavcodec     58. 54.100 / 58. 54.100&#xA;  libavformat    58. 29.100 / 58. 29.100&#xA;  libavdevice    58.  8.100 / 58.  8.100&#xA;  libavfilter     7. 57.100 /  7. 57.100&#xA;  libavresample   4.  0.  0 /  4.  0.  0&#xA;  libswscale      5.  5.100 /  5.  5.100&#xA;  libswresample   3.  5.100 /  3.  5.100&#xA;  libpostproc    55.  5.100 / 55.  5.100&#xA;Guessed Channel Layout for Input Stream #0.0 : stereo&#xA;Input #0, alsa, from &#x27;pulse&#x27;:&#xA;  Duration: N/A, start: 1617150428.783763, bitrate: 1536 kb/s&#xA;    Stream #0:0: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s&#xA;[x11grab @ 0x55e88a4e8780] Stream #0: not enough frames to estimate rate; consider increasing probesize&#xA;Input #1, x11grab, from &#x27;:99&#x27;:&#xA;  Duration: N/A, start: 1617150428.837799, bitrate: N/A&#xA;    Stream #1:0: Video: rawvideo (BGR[0] / 0x524742), bgr0, 1920x1080, 30 fps, 1000k tbr, 1000k tbn, 1000k tbc&#xA;Stream mapping:&#xA;  Stream #1:0 -> #0:0 (rawvideo (native) -> h264 (libx264))&#xA;  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))&#xA;Press [q] to stop, [?] for help&#xA;[libx264 @ 0x55e88a4f70c0] max bitrate less than average bitrate, assuming CBR&#xA;[libx264 @ 0x55e88a4f70c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 AVX512&#xA;[libx264 @ 0x55e88a4f70c0] profile Main, level 4.0&#xA;[alsa @ 0x55e88a4c2e40] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619940.ts&#x27; for writing&#xA;Output #0, hls, to &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8&#x27;:&#xA;  Metadata:&#xA;    encoder         : Lavf58.29.100&#xA;    Stream #0:0: Video: h264 (libx264), yuv420p(progressive), 1920x1080, q=-1--1, 1396 kb/s, 30 fps, 90k tbn, 30 tbc&#xA;    Metadata:&#xA;      encoder         : Lavc58.54.100 libx264&#xA;    Side data:&#xA;      cpb: bitrate max/min/avg: 1369000/0/1396000 buffer size: 969000 vbv_delay: -1&#xA;    Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 128 kb/s&#xA;    Metadata:&#xA;      encoder         : Lavc58.54.100 aac&#xA;frame=   16 fps=0.0 q=21.0 size=N/A time=00:00:00.53 bitrate=N/A speed=1.06x    &#xA;frame=   31 fps= 31 q=16.0 size=N/A time=00:00:01.03 bitrate=N/A speed=1.02x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619941.ts&#x27; for writing&#xA;frame=   47 fps= 31 q=21.0 size=N/A time=00:00:01.56 bitrate=N/A speed=1.03x    &#xA;frame=   62 fps= 30 q=22.0 size=N/A time=00:00:02.06 bitrate=N/A speed=1.02x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619942.ts&#x27; for writing&#xA;frame=   77 fps= 30 q=24.0 size=N/A time=00:00:02.56 bitrate=N/A speed=1.01x    &#xA;frame=   92 fps= 30 q=22.0 size=N/A time=00:00:03.06 bitrate=N/A speed=0.999x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619943.ts&#x27; for writing&#xA;frame=  108 fps= 30 q=29.0 size=N/A time=00:00:03.60 bitrate=N/A speed=   1x    &#xA;frame=  124 fps= 30 q=21.0 size=N/A time=00:00:04.13 bitrate=N/A speed=1.01x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619944.ts&#x27; for writing&#xA;frame=  139 fps= 30 q=20.0 size=N/A time=00:00:04.63 bitrate=N/A speed=1.01x    &#xA;frame=  154 fps= 30 q=18.0 size=N/A time=00:00:05.13 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619945.ts&#x27; for writing&#xA;frame=  169 fps= 30 q=19.0 size=N/A time=00:00:05.63 bitrate=N/A speed=   1x    &#xA;frame=  185 fps= 30 q=19.0 size=N/A time=00:00:06.16 bitrate=N/A speed=1.01x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619946.ts&#x27; for writing&#xA;frame=  199 fps= 30 q=20.0 size=N/A time=00:00:06.63 bitrate=N/A speed=   1x    &#xA;frame=  215 fps= 30 q=19.0 size=N/A time=00:00:07.16 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619947.ts&#x27; for writing&#xA;frame=  230 fps= 30 q=19.0 size=N/A time=00:00:07.66 bitrate=N/A speed=   1x    &#xA;frame=  242 fps= 30 q=18.0 size=N/A time=00:00:08.06 bitrate=N/A speed=0.99x    &#xA;frame=  254 fps= 29 q=17.0 size=N/A time=00:00:08.46 bitrate=N/A speed=0.979x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619948.ts&#x27; for writing&#xA;frame=  276 fps= 30 q=17.0 size=N/A time=00:00:09.20 bitrate=N/A speed=1.01x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec133903625619949.ts&#x27; for writing&#xA;frame=  290 fps= 30 q=21.0 size=N/A time=00:00:09.66 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199410.ts&#x27; for writing&#xA;frame=  306 fps= 30 q=31.0 size=N/A time=00:00:10.20 bitrate=N/A speed=   1x    &#xA;frame=  322 fps= 30 q=21.0 size=N/A time=00:00:10.73 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199411.ts&#x27; for writing&#xA;frame=  337 fps= 30 q=21.0 size=N/A time=00:00:11.23 bitrate=N/A speed=   1x    &#xA;frame=  352 fps= 30 q=19.0 size=N/A time=00:00:11.73 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199412.ts&#x27; for writing&#xA;frame=  367 fps= 30 q=19.0 size=N/A time=00:00:12.23 bitrate=N/A speed=   1x    &#xA;frame=  382 fps= 30 q=18.0 size=N/A time=00:00:12.73 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199413.ts&#x27; for writing&#xA;frame=  397 fps= 30 q=18.0 size=N/A time=00:00:13.23 bitrate=N/A speed=   1x    &#xA;frame=  412 fps= 30 q=18.0 size=N/A time=00:00:13.73 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199414.ts&#x27; for writing&#xA;frame=  428 fps= 30 q=18.0 size=N/A time=00:00:14.26 bitrate=N/A speed=   1x    &#xA;frame=  443 fps= 30 q=17.0 size=N/A time=00:00:14.76 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199415.ts&#x27; for writing&#xA;frame=  458 fps= 30 q=18.0 size=N/A time=00:00:15.26 bitrate=N/A speed=   1x    &#xA;frame=  474 fps= 30 q=17.0 size=N/A time=00:00:15.80 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199416.ts&#x27; for writing&#xA;frame=  489 fps= 30 q=18.0 size=N/A time=00:00:16.30 bitrate=N/A speed=   1x    &#xA;frame=  504 fps= 30 q=17.0 size=N/A time=00:00:16.80 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199417.ts&#x27; for writing&#xA;frame=  520 fps= 30 q=20.0 size=N/A time=00:00:17.33 bitrate=N/A speed=   1x    &#xA;frame=  535 fps= 30 q=18.0 size=N/A time=00:00:17.83 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199418.ts&#x27; for writing&#xA;frame=  551 fps= 30 q=20.0 size=N/A time=00:00:18.36 bitrate=N/A speed=   1x    &#xA;frame=  566 fps= 30 q=19.0 size=N/A time=00:00:18.86 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199419.ts&#x27; for writing&#xA;frame=  581 fps= 30 q=20.0 size=N/A time=00:00:19.36 bitrate=N/A speed=   1x    &#xA;frame=  596 fps= 30 q=19.0 size=N/A time=00:00:19.86 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199420.ts&#x27; for writing&#xA;frame=  612 fps= 30 q=21.0 size=N/A time=00:00:20.40 bitrate=N/A speed=   1x    &#xA;frame=  626 fps= 30 q=20.0 size=N/A time=00:00:20.86 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199421.ts&#x27; for writing&#xA;frame=  641 fps= 30 q=21.0 size=N/A time=00:00:21.37 bitrate=N/A speed=   1x    &#xA;frame=  657 fps= 30 q=35.0 size=N/A time=00:00:21.90 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199422.ts&#x27; for writing&#xA;frame=  672 fps= 30 q=33.0 size=N/A time=00:00:22.40 bitrate=N/A speed=   1x    &#xA;frame=  687 fps= 30 q=23.0 size=N/A time=00:00:22.90 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199423.ts&#x27; for writing&#xA;frame=  703 fps= 30 q=23.0 size=N/A time=00:00:23.43 bitrate=N/A speed=   1x    &#xA;frame=  718 fps= 30 q=25.0 size=N/A time=00:00:23.93 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199424.ts&#x27; for writing&#xA;frame=  733 fps= 30 q=27.0 size=N/A time=00:00:24.44 bitrate=N/A speed=   1x    &#xA;frame=  749 fps= 30 q=26.0 size=N/A time=00:00:24.96 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199425.ts&#x27; for writing&#xA;frame=  764 fps= 30 q=28.0 size=N/A time=00:00:25.46 bitrate=N/A speed=   1x    &#xA;frame=  780 fps= 30 q=27.0 size=N/A time=00:00:26.00 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199426.ts&#x27; for writing&#xA;frame=  795 fps= 30 q=27.0 size=N/A time=00:00:26.50 bitrate=N/A speed=   1x    &#xA;frame=  810 fps= 30 q=26.0 size=N/A time=00:00:27.00 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec1339036256199427.ts&#x27; for writing&#xA;frame=  825 fps= 30 q=29.0 size=N/A time=00:00:27.50 bitrate=N/A speed=   1x    &#xA;[hls @ 0x55e88a4f3040] Opening &#x27;/recordings/13391978436095-2/rec13390362561994.m3u8.tmp&#x27; for writing&#xA;frame=  840 fps= 30 q=30.0 Lsize=N/A time=00:00:28.01 bitrate=N/A speed=   1x    &#xA;video:4635kB audio:404kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown&#xA;[libx264 @ 0x55e88a4f70c0] frame I:42    Avg QP:12.88  size: 28020&#xA;[libx264 @ 0x55e88a4f70c0] frame P:798   Avg QP:13.11  size:  4473&#xA;[libx264 @ 0x55e88a4f70c0] mb I  I16..4: 88.4%  0.0% 11.6%&#xA;[libx264 @ 0x55e88a4f70c0] mb P  I16..4:  6.6%  0.0%  0.4%  P16..4:  6.6%  1.9%  0.6%  0.0%  0.0%    skip:83.8%&#xA;[libx264 @ 0x55e88a4f70c0] coded y,uvDC,uvAC intra: 18.8% 20.1% 10.1% inter: 1.7% 2.4% 0.1%&#xA;[libx264 @ 0x55e88a4f70c0] i16 v,h,dc,p: 55% 30% 12%  4%&#xA;[libx264 @ 0x55e88a4f70c0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 29% 27% 31%  2%  3%  2%  2%  1%  2%&#xA;[libx264 @ 0x55e88a4f70c0] i8c dc,h,v,p: 77%  9% 12%  1%&#xA;[libx264 @ 0x55e88a4f70c0] Weighted P-Frames: Y:1.1% UV:0.1%&#xA;[libx264 @ 0x55e88a4f70c0] kb/s:1355.98&#xA;[aac @ 0x55e88a4f8440] Qavg: 40876.258&#xA;jq: error (at <stdin>:1): Cannot iterate over null (null)&#xA;jq: error (at <stdin>:1): Cannot iterate over null (null)&#xA;jq: error (at <stdin>:1): null (null) cannot be parsed as a number&#xA;jq: error (at <stdin>:1): null (null) cannot be parsed as a number&#xA;jq: error: syntax error, unexpected &#x27;|&#x27; (Unix shell quoting issues?) at , line 1:&#xA;.hasAudio=false | .hasVideo=false | .duration= | .size= | .status="failed"                                               &#xA;jq: 1 compile error&#xA;ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers&#xA;  built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)&#xA;  configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared&#xA;  libavutil      56. 31.100 / 56. 31.100&#xA;  libavcodec     58. 54.100 / 58. 54.100&#xA;  libavformat    58. 29.100 / 58. 29.100&#xA;  libavdevice    58.  8.100 / 58.  8.100&#xA;  libavfilter     7. 57.100 /  7. 57.100&#xA;  libavresample   4.  0.  0 /  4.  0.  0&#xA;  libswscale      5.  5.100 /  5.  5.100&#xA;  libswresample   3.  5.100 /  3.  5.100&#xA;  libpostproc    55.  5.100 / 55.  5.100&#xA;Invalid duration specification for ss: -i&#xA;</stdin></stdin></stdin></stdin>

    &#xA;

    ***** Edit 5 **********

    &#xA;

    no mather what format I choose, it stops after 20 to 30 secs.&#xA;the same line with .webm .mov .264 when it's not .mp4 ffmpeg seems to drop

    &#xA;

  • Why does my ffmpeg audio sound slower and deeper - sample rate mismatch

    4 septembre 2020, par yogesh zinzu

    ok so this is a discord bot to record voice chat&#xA;https://hatebin.com/hgjlazacri&#xA;Now the bot works perfectly fine but the issue is that the audio sounds a bit deeper and slower than normal.. Why does it happen ? how can I make the audio sound 1:1..

    &#xA;

    &#xD;&#xA;
    &#xD;&#xA;
    const Discord = require(&#x27;discord.js&#x27;);&#xA;const client = new Discord.Client();&#xA;const ffmpegInstaller = require(&#x27;@ffmpeg-installer/ffmpeg&#x27;);&#xA;const ffmpeg = require(&#x27;fluent-ffmpeg&#x27;);&#xA;ffmpeg.setFfmpegPath(ffmpegInstaller.path);&#xA;const fs = require(&#x27;fs-extra&#x27;)&#xA;const mergeStream = require(&#x27;merge-stream&#x27;);&#xA;const config = require(&#x27;./config.json&#x27;);&#xA;const { getAudioDurationInSeconds } = require(&#x27;get-audio-duration&#x27;);&#xA;const cp = require(&#x27;child_process&#x27;);&#xA;const path1 = require(&#x27;path&#x27;);&#xA;const Enmap = require(&#x27;enmap&#x27;);&#xA;const UserRecords = require("./models/userrecords.js")&#xA;const ServerRecords = require("./models/serverrecords.js")&#xA;let prefix = `$`&#xA;class Readable extends require(&#x27;stream&#x27;).Readable { _read() {} }&#xA;let recording = false;&#xA;let currently_recording = {};&#xA;let mp3Paths = [];&#xA;const silence_buffer = new Uint8Array(3840);&#xA;const express = require(&#x27;express&#x27;)&#xA;const app = express()&#xA;const port = 3000&#xA;const publicIP = require(&#x27;public-ip&#x27;)&#xA;const { program } = require(&#x27;commander&#x27;);&#xA;const { path } = require(&#x27;@ffmpeg-installer/ffmpeg&#x27;);&#xA;const version = &#x27;0.0.1&#x27;&#xA;program.version(version);&#xA;let debug = false&#xA;let runProd = false&#xA;let fqdn = "";&#xA;const mongoose = require("mongoose");&#xA;const MongoClient = require(&#x27;mongodb&#x27;).MongoClient;&#xA;mongoose.connect(&#x27;SECRRET&#x27;,{&#xA;  useNewUrlParser: true&#xA;}, function(err){&#xA;  if(err){&#xA;    console.log(err);&#xA;  }else{&#xA;    console.log("Database connection initiated");&#xA;  }&#xA;});&#xA;require("dotenv").config()&#xA;function bufferToStream(buffer) {&#xA;    let stream = new Readable();&#xA;    stream.push(buffer);&#xA;    return stream;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;client.commands = new Enmap();&#xA;&#xA;client.on(&#x27;ready&#x27;, async () => {&#xA;    console.log(`Logged in as ${client.user.tag}`);&#xA;&#xA;    let host = "localhost"&#xA;&#xA;    &#xA;&#xA;    let ip = await publicIP.v4();&#xA;&#xA;    let protocol = "http";&#xA;    if (!runProd) {&#xA;        host = "localhost"&#xA;    } else {&#xA;        host = `35.226.244.186`;&#xA;    }&#xA;    fqdn = `${protocol}://${host}:${port}`&#xA;    app.listen(port, `0.0.0.0`, () => {&#xA;        console.log(`Listening on port ${port} for ${host} at fqdn ${fqdn}`)&#xA;    })&#xA;});&#xA;let randomArr = []&#xA;let finalArrWithIds = []&#xA;let variable = 0&#xA;client.on(&#x27;message&#x27;, async message => {&#xA;    console.log(`fuck`);&#xA;    if(message.content === `$record`){&#xA;        mp3Paths = []&#xA;        finalArrWithIds = []&#xA;        let membersToScrape = Array.from(message.member.voice.channel.members.values());&#xA;        membersToScrape.forEach((member) => {&#xA;            if(member.id === `749250882830598235`) {&#xA;                console.log(`botid`);&#xA;            }&#xA;            else {&#xA;                finalArrWithIds.push(member.id)&#xA;            }&#xA;            &#xA;        })&#xA;        const randomNumber = Math.floor(Math.random() * 100)&#xA;        randomArr = []&#xA;        randomArr.push(randomNumber)&#xA;    }&#xA;   &#xA;    &#xA;    const generateSilentData = async (silentStream, memberID) => {&#xA;        console.log(`recordingnow`)&#xA;        while(recording) {&#xA;            if (!currently_recording[memberID]) {&#xA;                silentStream.push(silence_buffer);&#xA;            }&#xA;            await new Promise(r => setTimeout(r, 20));&#xA;        }&#xA;        return "done";&#xA;    }&#xA;    console.log(generateSilentData, `status`)&#xA;    function generateOutputFile(channelID, memberID) {&#xA;        const dir = `./recordings/${channelID}/${memberID}`;&#xA;        fs.ensureDirSync(dir);&#xA;        const fileName = `${dir}/${randomArr[0]}.aac`;&#xA;        console.log(`${fileName} ---------------------------`);&#xA;        return fs.createWriteStream(fileName);&#xA;    }&#xA;    &#xA;    if (!fs.existsSync("public")) {&#xA;        fs.mkdirSync("public");&#xA;    }&#xA;    app.use("/public", express.static("./public"));&#xA;  if (!message.guild) return;&#xA;&#xA;  if (message.content === config.prefix &#x2B; config.record_command) {&#xA;    if (recording) {&#xA;        message.reply("bot is already recording");&#xA;        return&#xA;    }&#xA;    if (message.member.voice.channel) {&#xA;        recording = true;&#xA;        const connection = await message.member.voice.channel.join();&#xA;        const dispatcher = connection.play(&#x27;./audio.mp3&#x27;);&#xA;&#xA;        connection.on(&#x27;speaking&#x27;, (user, speaking) => {&#xA;            if (speaking.has(&#x27;SPEAKING&#x27;)) {&#xA;                currently_recording[user.id] = true;&#xA;            } else {&#xA;                currently_recording[user.id] = false;&#xA;            }&#xA;        })&#xA;&#xA;&#xA;        let members = Array.from(message.member.voice.channel.members.values());&#xA;        members.forEach((member) => {&#xA;&#xA;            if (member.id != client.user.id) {&#xA;                let memberStream = connection.receiver.createStream(member, {mode : &#x27;pcm&#x27;, end : &#x27;manual&#x27;})&#xA;&#xA;                let outputFile = generateOutputFile(message.member.voice.channel.id, member.id);&#xA;                console.log(outputFile, `outputfile here`);&#xA;                mp3Paths.push(outputFile.path);&#xA;                    &#xA;&#xA;                silence_stream = bufferToStream(new Uint8Array(0));&#xA;                generateSilentData(silence_stream, member.id).then(data => console.log(data));&#xA;                let combinedStream = mergeStream(silence_stream, memberStream);&#xA;&#xA;                ffmpeg(combinedStream)&#xA;                    .inputFormat(&#x27;s32le&#x27;)&#xA;                    .audioFrequency(44100)&#xA;                    .audioChannels(2)&#xA;                    .on(&#x27;error&#x27;, (error) => {console.log(error)})&#xA;                    .audioCodec(&#x27;aac&#x27;)&#xA;                    .format(&#x27;adts&#x27;) &#xA;                    .pipe(outputFile)&#xA;                    &#xA;            }&#xA;        })&#xA;    } else {&#xA;      message.reply(&#x27;You need to join a voice channel first!&#x27;);&#xA;    }&#xA;  }&#xA;&#xA;  if (message.content === config.prefix &#x2B; config.stop_command) {&#xA;&#xA;    let date = new Date();&#xA;    let dd = String(date.getDate()).padStart(2, &#x27;0&#x27;);&#xA;    let mm = String(date.getMonth() &#x2B; 1).padStart(2, &#x27;0&#x27;); &#xA;    let yyyy = date.getFullYear();&#xA;    date = mm &#x2B; &#x27;/&#x27; &#x2B; dd &#x2B; &#x27;/&#x27; &#x2B; yyyy;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;    let currentVoiceChannel = message.member.voice.channel;&#xA;    if (currentVoiceChannel) {&#xA;        recording = false;&#xA;        await currentVoiceChannel.leave();&#xA;&#xA;        let mergedOutputFolder = &#x27;./recordings/&#x27; &#x2B; message.member.voice.channel.id &#x2B; `/${randomArr[0]}/`;&#xA;        fs.ensureDirSync(mergedOutputFolder);&#xA;        let file_name = `${randomArr[0]}` &#x2B; &#x27;.aac&#x27;;&#xA;        let mergedOutputFile = mergedOutputFolder &#x2B; file_name;&#xA;    &#xA;        &#xA;    let download_path = message.member.voice.channel.id &#x2B; `/${randomArr[0]}/` &#x2B; file_name;&#xA;&#xA;        let mixedOutput = new ffmpeg();&#xA;        console.log(mp3Paths, `mp3pathshere`);&#xA;        mp3Paths.forEach((mp3Path) => {&#xA;             mixedOutput.addInput(mp3Path);&#xA;            &#xA;        })&#xA;        console.log(mp3Paths);&#xA;        //mixedOutput.complexFilter(&#x27;amix=inputs=2:duration=longest&#x27;);&#xA;        mixedOutput.complexFilter(&#x27;amix=inputs=&#x27; &#x2B; mp3Paths.length &#x2B; &#x27;:duration=longest&#x27;);&#xA;        &#xA;        let processEmbed = new Discord.MessageEmbed().setTitle(`Audio Processing.`)&#xA;        processEmbed.addField(`Audio processing starting now..`, `Processing Audio`)&#xA;        processEmbed.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/748610998985818202/speaker.png`)&#xA;        processEmbed.setColor(` #00FFFF`)&#xA;        const processEmbedMsg = await message.channel.send(processEmbed)&#xA;        async function saveMp3(mixedData, outputMixed) {&#xA;            console.log(`${mixedData} MIXED `)&#xA;            &#xA;            &#xA;            &#xA;            return new Promise((resolve, reject) => {&#xA;                mixedData.on(&#x27;error&#x27;, reject).on(&#x27;progress&#x27;,&#xA;                async (progress) => {&#xA;                    &#xA;                    let processEmbedEdit = new Discord.MessageEmbed().setTitle(`Audio Processing.`)&#xA;                    processEmbedEdit.addField(`Processing: ${progress.targetSize} KB converted`, `Processing Audio`)&#xA;                    processEmbedEdit.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/748610998985818202/speaker.png`)&#xA;                    processEmbedEdit.setColor(` #00FFFF`)&#xA;                    processEmbedMsg.edit(processEmbedEdit)&#xA;                    console.log(&#x27;Processing: &#x27; &#x2B; progress.targetSize &#x2B; &#x27; KB converted&#x27;);&#xA;                }).on(&#x27;end&#x27;, () => {&#xA;                    console.log(&#x27;Processing finished !&#x27;);&#xA;                    resolve()&#xA;                }).saveToFile(outputMixed);&#xA;                console.log(`${outputMixed} IT IS HERE`);&#xA;            })&#xA;        }&#xA;        // mixedOutput.saveToFile(mergedOutputFile);&#xA;        await saveMp3(mixedOutput, mergedOutputFile);&#xA;        console.log(`${mixedOutput} IN HEREEEEEEE`);&#xA;        // We saved the recording, now copy the recording&#xA;        if (!fs.existsSync(`./public`)) {&#xA;            fs.mkdirSync(`./public`);&#xA;        }&#xA;        let sourceFile = `${__dirname}/recordings/${download_path}`&#xA;        console.log(`DOWNLOAD PATH HERE ${download_path}`)&#xA;        const guildName = message.guild.id;&#xA;        const serveExist = `/public/${guildName}`&#xA;        if (!fs.existsSync(`.${serveExist}`)) {&#xA;            fs.mkdirSync(`.${serveExist}`)&#xA;        }&#xA;        let destionationFile = `${__dirname}${serveExist}/${file_name}`&#xA;&#xA;        let errorThrown = false&#xA;        try {&#xA;            fs.copySync(sourceFile, destionationFile);&#xA;        } catch (err) {&#xA;            errorThrown = true&#xA;            await message.channel.send(`Error: ${err.message}`)&#xA;        }&#xA;        const usersWithTag = finalArrWithIds.map(user => `\n &lt;@${user}>`);&#xA;        let timeSpent = await getAudioDurationInSeconds(`public/${guildName}/${file_name}`)&#xA;        let timesSpentRound = Math.floor(timeSpent)&#xA;        let finalTimeSpent = timesSpentRound / 60&#xA;        let finalTimeForReal = Math.floor(finalTimeSpent)&#xA;        if(!errorThrown){&#xA;            //--------------------- server recording save START&#xA;            class GeneralRecords {&#xA;                constructor(generalLink, date, voice, time) {&#xA;                  this.generalLink = generalLink;&#xA;                  this.date = date;&#xA;                  this.note = `no note`;&#xA;                  this.voice = voice;&#xA;                  this.time = time&#xA;                }&#xA;              }&#xA;              let newGeneralRecordClassObject = new GeneralRecords(`${fqdn}/public/${guildName}/${file_name}`, date, usersWithTag, finalTimeForReal)&#xA;              let checkingServerRecord = await ServerRecords.exists({userid: `server`})&#xA;              if(checkingServerRecord === true){&#xA;                  existingServerRecord = await ServerRecords.findOne({userid: `server`})&#xA;                  existingServerRecord.content.push(newGeneralRecordClassObject)&#xA;                  await existingServerRecord.save()&#xA;              }&#xA;              if(checkingServerRecord === false){&#xA;                let serverRecord = new ServerRecords()&#xA;                serverRecord.userid = `server`&#xA;                serverRecord.content.push(newGeneralRecordClassObject)&#xA;                await serverRecord.save()&#xA;              }&#xA;              //--------------------- server recording save STOP&#xA;        }&#xA;        &#xA;        //--------------------- personal recording section START&#xA;        for( member of finalArrWithIds) {&#xA;&#xA;        let personal_download_path = message.member.voice.channel.id &#x2B; `/${member}/` &#x2B; file_name;&#xA;        let sourceFilePersonal = `${__dirname}/recordings/${personal_download_path}`&#xA;        let destionationFilePersonal = `${__dirname}${serveExist}/${member}/${file_name}`&#xA;        await fs.copySync(sourceFilePersonal, destionationFilePersonal);&#xA;        const user = client.users.cache.get(member);&#xA;        console.log(user, `user here`);&#xA;        try {&#xA;            ffmpeg.setFfmpegPath(ffmpegInstaller.path);&#xA;          &#xA;            ffmpeg(`public/${guildName}/${member}/${file_name}`)&#xA;             .audioFilters(&#x27;silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-90dB&#x27;)&#xA;             .output(`public/${guildName}/${member}/personal-${file_name}`)&#xA;             .on(`end`, function () {&#xA;               console.log(`DONE`);&#xA;             })&#xA;             .on(`error`, function (error) {&#xA;               console.log(`An error occured` &#x2B; error.message)&#xA;             })&#xA;             .run();&#xA;             &#xA;          }&#xA;          catch (error) {&#xA;          console.log(error)&#xA;          }&#xA;        &#xA;&#xA;        // ----------------- SAVING PERSONAL RECORDING TO DATABASE START&#xA;        class PersonalRecords {&#xA;            constructor(generalLink, personalLink, date, time) {&#xA;              this.generalLink = generalLink;&#xA;              this.personalLink = personalLink;&#xA;              this.date = date;&#xA;              this.note = `no note`;&#xA;              this.time = time;&#xA;            }&#xA;          }&#xA;          let timeSpentPersonal = await getAudioDurationInSeconds(`public/${guildName}/${file_name}`)&#xA;          let timesSpentRoundPersonal = Math.floor(timeSpentPersonal)&#xA;          let finalTimeSpentPersonal = timesSpentRoundPersonal / 60&#xA;          let finalTimeForRealPersonal = Math.floor(finalTimeSpentPersonal)&#xA;          let newPersonalRecordClassObject = new PersonalRecords(`${fqdn}/public/${guildName}/${file_name}`, `${fqdn}/public/${guildName}/${member}/personal-${file_name}`, date, finalTimeForRealPersonal)&#xA;&#xA;           let checkingUserRecord = await UserRecords.exists({userid: member})&#xA;              if(checkingUserRecord === true){&#xA;                  existingUserRecord = await UserRecords.findOne({userid: member})&#xA;                  existingUserRecord.content.push(newPersonalRecordClassObject)&#xA;                  await existingUserRecord.save()&#xA;              }&#xA;              if(checkingUserRecord === false){&#xA;                let newRecord = new UserRecords()&#xA;                newRecord.userid = member&#xA;                newRecord.content.push(newPersonalRecordClassObject)&#xA;                await newRecord.save()&#xA;              }&#xA;&#xA;&#xA;       &#xA;        // ----------------- SAVING PERSONAL RECORDING TO DATABASE END&#xA;       &#xA;&#xA;        const endPersonalEmbed = new Discord.MessageEmbed().setTitle(`Your performance was amazing ! Review it here :D`)&#xA;        endPersonalEmbed.setColor(&#x27;#9400D3&#x27;)&#xA;        endPersonalEmbed.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/745381641324724294/vinyl.png`)&#xA;        endPersonalEmbed.addField(`1
  • A Guide to Ethical Web Analytics in 2024

    17 juin 2024, par Erin

    User data is more valuable and sought after than ever. 

    Ninety-four percent of respondents in Cisco’s Data Privacy Benchmark Study said their customers wouldn’t buy from them if their data weren’t protected, with 95% saying privacy was a business imperative. 

    Unfortunately, the data collection practices of most businesses are far from acceptable and often put their customers’ privacy at risk. 

    But it doesn’t have to be this way. You can ethically collect valuable and insightful customer data—you just need the right tools.

    In this article, we show you what an ethical web analytics solution can look like, why Google Analytics is a problem and how you can collect data without risking your customers’ privacy.

    What is ethical web analytics ?

    Ethical web analytics put user privacy first. These platforms prioritise privacy and transparency by only collecting necessary data, avoiding implicit user identification and openly communicating data practices and tracking methods. 

    Ethical tools adhere to data protection laws like GDPR as standard (meaning businesses using these tools never have to worry about fines or disruptions). In other words, ethical web analytics refrain from exploiting and profiting from user behaviour and data. 

    Unfortunately, most traditional data solutions collect as much data as possible without users’ knowledge or consent.

    Why does digital privacy matter ?

    Digital privacy matters because companies have repeatedly proven they will collect and use data for financial gain. It also presents security risks. Unsecured user data can lead to identity theft, cyberattacks and harassment. 

    Big tech companies like Google and Meta are often to blame for all this. These companies collect millions of user data points — like age, gender, income, political beliefs and location. Worse still, they share this information with interested third parties.

    After public outrage over data breaches and other privacy scandals, consumers are taking active steps to disallow tracking where possible. IAPP’s Privacy and Consumer Trust Report finds that 68% of consumers across 19 countries are somewhat or very concerned about their digital privacy. 

    There’s no way around it : companies of all sizes and shapes need to consider how they handle and protect customers’ private information

    Why should you use an ethical web analytics tool ?

    When companies use ethical web analytics tools they can build customer trust, boost their brand reputation, improve data security practices and future proof their website tracking solution. 

    Boost brand reputation

    The fallout from a data privacy scandal can be severe. 

    Just look at what happened to Facebook during the Cambridge Analytica data scandal. The eponymous consulting firm harvested 50 million Facebook profiles and used that information to target people with political messages. Due to the instant public backlash, Facebook’s stock tanked, and use of the “delete Facebook” hashtag increased by 423% in the following days.

    That’s because consumers care about data privacy, according to Deloitte’s Connected Consumer Study :

    • Almost 90 percent agree they should be able to view and delete data companies collect 
    • 77 percent want the government to introduce stricter regulations
    • Half feel the benefits they get from online services outweigh data privacy concerns.

    If you can prove you buck the trend by collecting data using ethical methods, it can boost your brand’s reputation. 

    Build trust with customers

    At the same time, collecting data in an ethical way can help you build customer trust. You’ll go a long way to changing consumer perceptions, too. Almost half of consumers don’t like sharing data, and 57% believe companies sell their data. 

    This additional trust should generate a positive ROI for your business. According to Cisco’s Data Privacy Benchmark Study, the average company gains $180 for every $100 they invest in privacy. 

    Improve data security

    According to IBM’s Cost of a Data Breach report, the average cost of a data breach is nearly $4.5 million. This kind of scenario becomes much less likely when you use an ethical tool that collects less data overall and anonymises the data you do collect. 

    Futureproof your web analytics solution

    The obvious risk of not complying with privacy regulations is a fine — which can be up to €20 million, or 4% of worldwide annual revenue in the case of GDPR.

    It’s not just fines and penalties you risk if you fail to comply with privacy regulations like GDPR. For some companies, especially larger ones, the biggest risk of non-compliance with privacy regulations is the potential sudden need to abandon Google Analytics and switch to an ethical alternative.

    If Data Protection Authorities ban Google Analytics again, as has happened in Austria, France, and other countries, businesses will be forced to drop everything and make an immediate transition to a compliant web analytics solution.

    When an organisation’s entire marketing operation relies on data, migrating to a new solution can be incredibly painful and time-consuming. So, the sooner you switch to an ethical tool, the less of a headache the process will be. 

    The problem with Google Analytics

    Google Analytics (GA) is the most popular analytics platform in the world, but it’s a world away from being an ethical tool. Here’s why :

    You don’t have data ownership

    Google Analytics is attractive to businesses of all sizes because of its price. Everyone loves getting something for free, but there’s still a cost — your and your customers’ data.

    That’s because Google combines the data you collect with information from the millions of other websites it tracks to inform its advertising efforts. It may also use your data to train large language models like Gemini. 

    It has a rocky history with GDPR laws

    Google and EU regulators haven’t always got along. For example, the German Data Protection Authority is investigating 200,000 pending cases against websites using GA. The platform has also been banned and added back to the EU-US Data Privacy Framework several times over the past few years. 

    You can use GA to collect data about EU customers right now, but there’s no guarantee you’ll be able to do so in the future. 

    It requires a specific setup to remain compliant

    While you can currently use GA in a GDPR-compliant way — owing to its inclusion in the EU-US Data Privacy Framework — you have to set it up in a very specific way. That’s because the platform’s compliance depends on what data you collect, how you inform users and the level of consent you acquire. You’ll still need to include an extensive privacy policy on your website. 

    What does ethical web analytics look like ?

    An ethical web analytics solution should put user privacy first, ensure compliance with regulations like GDPR, give businesses 100% control of the data they collect and be completely transparent about data collection and storage practices. 

    What does ethical web tracking look like?

    100% data ownership

    You don’t fully control customer data when you use Google Analytics. The search giant uses your data for its own advertising purposes and may also use it to train large language models like Gemini. 

    When you choose an ethical web analytics alternative like Matomo, you can ensure you completely own your data.

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

    No credit card required

    Respects user privacy

    It’s possible to track and measure user behaviour without collecting personally identifiable information (PII). Just look at the ethical web analytics tools we’ve reviewed below. 

    These platforms respect user privacy and conform to strict privacy regulations like GDPR, CCPA and HIPAA by incorporating some or all of the following features :

    In Matomo’s case, it’s all of the above. Better still, you can check our privacy credentials yourself. Our software’s source code is open source on GitHub and accessible to anyone at any time. 

    Compliant with government regulations

    While Google’s history with data regulations is tumultuous, an ethical web analytics platform should follow even the strictest privacy laws, including GDPR, HIPAA, CCPA, LGPD and PECR.

    But why stop there ? Matomo has been approved by the French Data Protection Authority (CNIL) as one of the few web analytics tools that French sites can use to collect data without tracking consent. So you don’t need an annoying consent banner popping up on your website anymore. 

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

    No credit card required

    Complete transparency 

    Ethical web analytics tools will be upfront about their data collection practices, whether that’s in the U.S., EU, or on your own private servers. Look for a solution that refrains from collecting personally identifiable information, shows where data is stored, and lets you alter tracking methods to increase privacy even further. 

    Some solutions, like Matomo, will increase transparency further by providing open source software. Anyone can find our source code on GitHub to see exactly how our platform tracks and stores user data. This means our code is regularly examined and reviewed by a community of developers, making it more secure, too.

    Ethical web analytics solutions

    There are several options for an ethical web analytics tool. We list three of the best providers below. 

    Matomo

    Matomo is an open source web analytics tool and privacy-focused Google Analytics alternative used by over one million sites globally. 

    Screenshot example of the Matomo dashboard

    Matomo is fully compliant with prominent global privacy regulations like GDPR, CCPA and HIPAA, meaning you never have to worry about collecting consent when tracking user behaviour. 

    The data you collect is completely accurate since Matomo doesn’t use data sampling and is 100% yours. We don’t share data with third parties but can prove it. Our product source code is publicly available on GitHub. As a community-led project, you can download and install it yourself for free. 

    With Matomo, you get a full range of web analytics capabilities and behavioural analytics. That includes your standard metrics (think visitors, traffic sources, bounce rates, etc.), advanced features to analyse user behaviour like A/B Testing, Form Analytics, Heatmaps and Session Recordings. 

    Migrating to Matomo is easy. You can even import historical Google Analytics data to generate meaningful insights immediately. 

    Try Matomo for Free

    Get the web insights you need, without compromising data accuracy.

    No credit card required

    Fathom

    Fathom Analytics is a lightweight privacy-focused analytics solution that launched in 2018. It aims to be an easy-to-use Google Analytics alternative that doesn’t compromise privacy. 

    A screenshot of the Fathom website

    Like Matomo, Fathom complies with all major privacy regulations, including GDPR and CCPA. It also provides 100% accurate, unsampled reports and doesn’t share your data with third parties. 

    While Fathom provides fairly comprehensive analytics reports, it doesn’t have some of Matomo’s more advanced features. That includes e-commerce tracking, heatmaps, session recordings, and more. 

    Plausible

    Plausible Analytics is another open source Google Analytics alternative that was built and hosted in the EU. 

    A screenshot of the Plausible website

    Launched in 2019, Plausible is a newer player in the privacy-focused analytics market. Still, its ultra-lightweight script makes it an attractive option for organisations that prioritise speed over everything else. 

    Like Matomo and Fathom, Plausible is GDPR and CCPA-compliant by design. Nor is there any cap on the amount of data you collect or any debate over whether the data is accurate (Plausible doesn’t use data sampling) or who owns the data (you do). 

    Matomo makes it easy to migrate to an ethical web analytics alternative

    There’s no reason to put your users’ privacy at risk, especially when there are so many benefits to choosing an ethical tool. Whether you want to avoid fines, build trust with your customers, or simply know you’re doing the right thing, choosing a privacy-focused, ethical solution like Matomo is taking a massive step in the right direction. 

    Making the switch is easy, too. Matomo is one of the few options that lets you import historical Google Analytics data, so starting from scratch is unnecessary. 

    Get started today by trying Matomo for free for 21-days. No credit card required.