Recherche avancée

Médias (91)

Sur d’autres sites (97)

  • Unable to stream video file from MediaMTX media server to browser via WebRTC

    2 avril, par thegreatjedi

    I took over a repository at work. It's a working demo comprising a web server which receives video and camera feeds from a media server (built from the rtsp-simple-server Docker image) via a RTSP relay server and streams the feeds to the client, all deployed via Docker Compose.

    


    I'm trying to switch over to use WebRTC instead. rtsp-simple-server has upgraded into MediaMTX since the time the demo was created 2 years ago. This is the relevant section of the updated Docker Compose configuration :

    


      media-server:
    image: bluenviron/mediamtx:latest-ffmpeg
    expose:
      - 8889
    init: true
    ports:
      - 8889:8889
    restart: unless-stopped
    volumes:
      - type: bind
        source: ./demo/vids
        target: /vids
      - type: bind
        source: ./demo/mediamtx.yml
        target: /mediamtx.yml


    


    Relevant part of the MediaMTX custom configuration in mediamtx.yml :

    


    ###############################################
# Path settings

# Settings in "paths" are applied to specific paths, and the map key
# is the name of the path.
# Any setting in "pathDefaults" can be overridden here.
# It's possible to use regular expressions by using a tilde as prefix,
# for example "~^(test1|test2)$" will match both "test1" and "test2",
# for example "~^prefix" will match all paths that start with "prefix".
paths:
  # example:
  # my_camera:
  #   source: rtsp://my_camera
  ~^demo\d+$:
    runOnDemand: ffmpeg -re -stream_loop -1 -i /vids/$MTX_PATH.mp4 -c:v libvpx -b:v 0 -crf 18 -qmin 18 -qmax 18 -f webm http://localhost:8889/$MTX_PATH/whip

  # Settings under path "all_others" are applied to all paths that
  # do not match another entry.
  all_others:


    


    I've absolutely no experience with WebRTC. This is my first time hearing of this protocol, let alone working with it. From what I understand, I need to convert my demo mp4 videos (which were successfully streaming via RTSP in the previous implementation) to a compatible video codec, so I've opted for VP8.

    


    Before trying to stream the videos into my web server, I tested the stream directly in the browser (tried with both the latest versions of Chrome and Edge). I went to http://localhost:8889/demo0 (which should convert demo0.mp4 to VP8 and then stream it over WebRTC). The video player loaded in the browser but no video data was received and nothing played. After several seconds, the screen displayed "Error : bad status code 400, retrying in some seconds". In the browser console, it showed :

    


    Failed to load resource : the server responded with a status of 400 (Bad Request)

    


    Inside the MediaMTX container's runtime logs, this is what's displayed :

    


    2024-04-02 14:53:08 ffmpeg version 6.1.1 Copyright (c) 2000-2023 the FFmpeg developers
2024-04-02 14:53:08   built with gcc 13.2.1 (Alpine 13.2.1_git20231014) 20231014
2024-04-02 14:53:08   configuration: --prefix=/usr --disable-librtmp --disable-lzma --disable-static --disable-stripping --enable-avfilter --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libmp3lame --enable-libopenmpt --enable-libopus --enable-libplacebo --enable-libpulse --enable-librav1e --enable-librist --enable-libsoxr --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-lto=auto --enable-lv2 --enable-openssl --enable-pic --enable-postproc --enable-pthreads --enable-shared --enable-vaapi --enable-vdpau --enable-version3 --enable-vulkan --optflags=-O3 --enable-libjxl --enable-libsvtav1 --enable-libvpl
2024-04-02 14:53:08   libavutil      58. 29.100 / 58. 29.100
2024-04-02 14:53:08   libavcodec     60. 31.102 / 60. 31.102
2024-04-02 14:53:08   libavformat    60. 16.100 / 60. 16.100
2024-04-02 14:53:08   libavdevice    60.  3.100 / 60.  3.100
2024-04-02 14:53:08   libavfilter     9. 12.100 /  9. 12.100
2024-04-02 14:53:08   libswscale      7.  5.100 /  7.  5.100
2024-04-02 14:53:08   libswresample   5.  0.100 /  5.  0.100
2024-04-02 14:53:08   libpostproc    57.  3.100 / 57.  3.100
2024-04-02 14:53:08 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/vids/demo0.mp4':
2024-04-02 14:53:08   Metadata:
2024-04-02 14:53:08     major_brand     : isom
2024-04-02 14:53:08     minor_version   : 512
2024-04-02 14:53:08     compatible_brands: isomiso2mp41
2024-04-02 14:53:08     encoder         : Lavf58.76.100
2024-04-02 14:53:08   Duration: 00:00:03.47, start: 0.000000, bitrate: 1675 kb/s
2024-04-02 14:53:08   Stream #0:0[0x1](und): Video: mpeg1video (mp4v / 0x7634706D), yuv420p(tv, progressive), 640x360 [SAR 1:1 DAR 16:9], 104857 kb/s, 30 fps, 30 tbr, 90k tbn (default)
2024-04-02 14:53:08     Metadata:
2024-04-02 14:53:08       handler_name    : VideoHandler
2024-04-02 14:53:08       vendor_id       : [0][0][0][0]
2024-04-02 14:53:08     Side data:
2024-04-02 14:53:08       cpb: bitrate max/min/avg: 0/0/0 buffer size: 49152 vbv_delay: N/A
2024-04-02 14:53:08 Stream mapping:
2024-04-02 14:53:08   Stream #0:0 -> #0:0 (mpeg1video (native) -> vp8 (libvpx))
2024-04-02 14:53:08 Press [q] to stop, [?] for help
2024-04-02 14:53:08 [libvpx @ 0x7faa8591b8c0] v1.13.1
2024-04-02 14:53:08 [libvpx @ 0x7faa8591b8c0] Bitrate not specified for constrained quality mode, using default of 256kbit/sec
2024-04-02 14:53:08 Output #0, webm, to 'http://localhost:8889/demo0/whip':
2024-04-02 14:53:08   Metadata:
2024-04-02 14:53:08     major_brand     : isom
2024-04-02 14:53:08     minor_version   : 512
2024-04-02 14:53:08     compatible_brands: isomiso2mp41
2024-04-02 14:53:08     encoder         : Lavf60.16.100
2024-04-02 14:53:08   Stream #0:0(und): Video: vp8, yuv420p(tv, progressive), 640x360 [SAR 1:1 DAR 16:9], q=2-31, 256 kb/s, 30 fps, 1k tbn (default)
2024-04-02 14:53:08     Metadata:
2024-04-02 14:53:08       handler_name    : VideoHandler
2024-04-02 14:53:08       vendor_id       : [0][0][0][0]
2024-04-02 14:53:08       encoder         : Lavc60.31.102 libvpx
2024-04-02 14:53:08     Side data:
2024-04-02 14:53:08       cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
2024-04-02 14:53:18 2024/04/02 06:53:18 INF [path demo0] runOnDemand command stopped: timed out
2024-04-02 14:53:18 2024/04/02 06:53:18 INF [WebRTC] [session 0f460c76] closed: source of path 'demo0' has timed out
[out#0/webm @ 0x7faa859487c0] video:272kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.042856%
2024-04-02 14:53:18 frame=  315 fps= 32 q=18.0 Lsize=     275kB time=00:00:10.46 bitrate= 215.1kbits/s speed=1.05x    
2024-04-02 14:53:18 Exiting normally, received signal 2.


    


    I'm not sure what this is supposed to mean ? Why isn't the server able to stream this 3-second, 709kb video even once ? The browser connected to the server and the URL successfully, but no data was being transferred.

    


    Just in case, I decided to manually convert all of my mp4 files to webm using ffmpeg, and verified with Window's media player that the webm videos work. Then, I modified MediaMTX's configuration to stream the webm videos directly :

    


    paths:
  # example:
  # my_camera:
  #   source: rtsp://my_camera
  ~^demo\d+$:
    runOnDemand: ffmpeg -re -stream_loop -1 -i /vids/$MTX_PATH.webm -c copy -f webm http://localhost:8889/$MTX_PATH/whip


    


    However, the error persists :

    


    2024-04-02 15:03:58 ffmpeg version 6.1.1 Copyright (c) 2000-2023 the FFmpeg developers
2024-04-02 15:03:58   built with gcc 13.2.1 (Alpine 13.2.1_git20231014) 20231014
2024-04-02 15:03:58   configuration: --prefix=/usr --disable-librtmp --disable-lzma --disable-static --disable-stripping --enable-avfilter --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libmp3lame --enable-libopenmpt --enable-libopus --enable-libplacebo --enable-libpulse --enable-librav1e --enable-librist --enable-libsoxr --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-lto=auto --enable-lv2 --enable-openssl --enable-pic --enable-postproc --enable-pthreads --enable-shared --enable-vaapi --enable-vdpau --enable-version3 --enable-vulkan --optflags=-O3 --enable-libjxl --enable-libsvtav1 --enable-libvpl
2024-04-02 15:03:58   libavutil      58. 29.100 / 58. 29.100
2024-04-02 15:03:58   libavcodec     60. 31.102 / 60. 31.102
2024-04-02 15:03:58   libavformat    60. 16.100 / 60. 16.100
2024-04-02 15:03:58   libavdevice    60.  3.100 / 60.  3.100
2024-04-02 15:03:58   libavfilter     9. 12.100 /  9. 12.100
2024-04-02 15:03:58   libswscale      7.  5.100 /  7.  5.100
2024-04-02 15:03:58   libswresample   5.  0.100 /  5.  0.100
2024-04-02 15:03:58   libpostproc    57.  3.100 / 57.  3.100
2024-04-02 15:03:58 Input #0, matroska,webm, from '/vids/demo0.webm':
2024-04-02 15:03:58   Metadata:
2024-04-02 15:03:58     COMPATIBLE_BRANDS: isomiso2mp41
2024-04-02 15:03:58     MAJOR_BRAND     : isom
2024-04-02 15:03:58     MINOR_VERSION   : 512
2024-04-02 15:03:58     ENCODER         : Lavf60.16.100
2024-04-02 15:03:58   Duration: 00:00:03.47, start: 0.000000, bitrate: 217 kb/s
2024-04-02 15:03:58   Stream #0:0: Video: vp8, yuv420p(tv, progressive), 640x360, SAR 1:1 DAR 16:9, 30 fps, 30 tbr, 1k tbn (default)
2024-04-02 15:03:58     Metadata:
2024-04-02 15:03:58       HANDLER_NAME    : VideoHandler
2024-04-02 15:03:58       VENDOR_ID       : [0][0][0][0]
2024-04-02 15:03:58       ENCODER         : Lavc60.31.102 libvpx
2024-04-02 15:03:58       DURATION        : 00:00:03.466000000
2024-04-02 15:03:58 Output #0, webm, to 'http://localhost:8889/demo0/whip':
2024-04-02 15:03:58   Metadata:
2024-04-02 15:03:58     COMPATIBLE_BRANDS: isomiso2mp41
2024-04-02 15:03:58     MAJOR_BRAND     : isom
2024-04-02 15:03:58     MINOR_VERSION   : 512
2024-04-02 15:03:58     encoder         : Lavf60.16.100
2024-04-02 15:03:58   Stream #0:0: Video: vp8, yuv420p(tv, progressive), 640x360 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 30 tbr, 1k tbn (default)
2024-04-02 15:03:58     Metadata:
2024-04-02 15:03:58       HANDLER_NAME    : VideoHandler
2024-04-02 15:03:58       VENDOR_ID       : [0][0][0][0]
2024-04-02 15:03:58       ENCODER         : Lavc60.31.102 libvpx
2024-04-02 15:03:58       DURATION        : 00:00:03.466000000
2024-04-02 15:03:58 Stream mapping:
2024-04-02 15:03:58   Stream #0:0 -> #0:0 (copy)
2024-04-02 15:03:58 Press [q] to stop, [?] for help
2024-04-02 15:04:08 2024/04/02 07:04:08 INF [path demo0] runOnDemand command stopped: timed out
2024-04-02 15:04:08 2024/04/02 07:04:08 INF [WebRTC] [session 829664cb] closed: source of path 'demo0' has timed out
[out#0/webm @ 0x7f04b00515c0] video:281kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.023511%
2024-04-02 15:04:08 size=     284kB time=00:00:10.49 bitrate= 221.3kbits/s speed=1.05x    
2024-04-02 15:04:08 Exiting normally, received signal 2.


    


    This is the same when I try to stream my other videos (demo1.mp4, demo2.mp4 etc.). What am I doing wrong ?

    


  • I am converting images to video using ffmpeg in koltin but i am getting error

    28 mars, par Mohith_karthikeya

    i implement ffmpeg by using this gitbub by this reference :5
https://github.com/tanersener/mobile-ffmpeg in koltin
my code is :

    


    class BurstModeToVideo(&#xA;    private val context: Context,&#xA;    private val onVideoConverted: (File) -> Unit&#xA;) {&#xA;&#xA;    private val vibeDirectory = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "vibes")&#xA;    private val outputDirectory = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)&#xA;&#xA;    fun convertBitmapToJpeg(vibes: List<bitmap>) {&#xA;        if (!vibeDirectory.exists()) {&#xA;            vibeDirectory.mkdirs()&#xA;        }&#xA;&#xA;        vibes.forEachIndexed { index, vibe ->&#xA;            val fileName = "$index.jpg"&#xA;            val file = File(vibeDirectory, fileName)&#xA;            FileOutputStream(file).use { fos ->&#xA;                vibe.compress(Bitmap.CompressFormat.JPEG, 100, fos)&#xA;            }&#xA;        }&#xA;    }&#xA;&#xA;    private val callback = ExecuteCallback { _, returnCode ->&#xA;        if (returnCode == Config.RETURN_CODE_SUCCESS) {&#xA;            try {&#xA;                val tempFile = File("${outputDirectory?.absolutePath}/vibe.mp4")&#xA;                onVideoConverted(tempFile)&#xA;                Log.e(TAG, "FFmpeg output found $tempFile")&#xA;                Toast.makeText(context,"$tempFile",Toast.LENGTH_LONG).show()&#xA;                Log.e(TAG, "FFmpeg output found $")&#xA;            } catch (e: IOException) {&#xA;                Log.e(TAG, "Error handling FFmpeg output", e)&#xA;            }&#xA;        } else {&#xA;            Log.i(TAG, "Async command execution failed with returnCode=$returnCode.")&#xA;        }&#xA;    }&#xA;&#xA;    fun convertShotsToVideo() {&#xA;        if (!vibeDirectory.exists() || vibeDirectory.listFiles()?.isEmpty() == true) {&#xA;            Log.e(TAG, "No images to convert")&#xA;            return&#xA;        }&#xA;&#xA;        Log.d(TAG, "Images are stored in: ${vibeDirectory.absolutePath}")&#xA;&#xA;        val imageFiles = vibeDirectory.listFiles { file -> file.isFile &amp;&amp; file.extension.equals("jpg", ignoreCase = true) }&#xA;        if (imageFiles.isNullOrEmpty()) {&#xA;            Log.e(TAG, "No image files found in directory")&#xA;            return&#xA;        }&#xA;&#xA;        Log.d(TAG, "List of image files:")&#xA;        imageFiles.forEach { file ->&#xA;            Log.d(TAG, file.name)&#xA;        }&#xA;&#xA;        val cmd = "-i ${vibeDirectory.absolutePath}/%d.jpg -c:v mpeg4 -y ${outputDirectory?.absolutePath}/vibe.mp4"&#xA;&#xA;        FFmpevubeg.executeAsync(cmd, callback)&#xA;    }&#xA;&#xA;    companion object {&#xA;        private const val TAG = "BurstModeToVideo"&#xA;    }&#xA;}&#xA;</bitmap>

    &#xA;

    above function convert images from bimtap to jpeg files and then it converts to video by using ffmpeg. And i initialize this fun in mainactivity.kt and it goes here :

    &#xA;

    var vibe by remember {&#xA;        mutableStateOf(null)&#xA;    }&#xA;&#xA;    val burstModeToVideo = BurstModeToVideo(&#xA;        context,&#xA;        onVideoConverted = {&#xA;            vibe = it&#xA;        }&#xA;    )&#xA;coroutineScope.launch {&#xA;            withContext(Dispatchers.IO) {&#xA;                burstModeToVideo.convertBitmapToJpeg(vibesList)&#xA;                burstModeToVideo.convertShotsToVideo()&#xA;            }&#xA;        }&#xA;&#xA;VideoPlayer(vibe)&#xA;

    &#xA;

    now this vibe variable is used in videoPlayer function and it goes here :

    &#xA;

    @OptIn(UnstableApi::class)&#xA;@Composable&#xA;fun VideoPlayer(file: File) {&#xA;    val context = LocalContext.current&#xA;&#xA;    val exoPlayer = remember {&#xA;        ExoPlayer.Builder(context)&#xA;            .build()&#xA;            .apply {&#xA;                val defaultDataSourceFactory = DefaultDataSource.Factory(context)&#xA;                val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(&#xA;                    context,&#xA;                    defaultDataSourceFactory&#xA;                )&#xA;                this.repeatMode = ExoPlayer.REPEAT_MODE_ALL&#xA;                this.playWhenReady =  true&#xA;                val source = file.let {&#xA;                    ProgressiveMediaSource.Factory(dataSourceFactory)&#xA;                        .createMediaSource(MediaItem.fromUri(Uri.fromFile(file)))&#xA;                }&#xA;                this.setMediaSource(source)&#xA;                this.prepare()&#xA;                this.play()&#xA;                this.volume = 0f&#xA;            }&#xA;    }&#xA;&#xA;    DisposableEffect(Unit) {&#xA;        onDispose {&#xA;            exoPlayer.release()&#xA;        }&#xA;    }&#xA;&#xA;    AndroidView(&#xA;        factory = { ctx ->&#xA;            PlayerView(ctx).apply {&#xA;                useController = false&#xA;                resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM&#xA;                player = exoPlayer&#xA;            }&#xA;        },&#xA;        modifier = Modifier.fillMaxSize()&#xA;    )&#xA;}&#xA;

    &#xA;

    the error is :

    &#xA;

     MediaCodec will operate in async mode&#xA;2024-03-28 20:08:53.065 18946-27920 OplusCCodec             com.example.flenzey                  D  initiateShutdown [475]: (0xb400007656569fc0) keepComponentAllocated=0&#xA;2024-03-28 20:08:53.067 18946-27920 BpBinder                com.example.flenzey                  I  onLastStrongRef automatically unlinking death recipients: android.media.IResourceManagerService&#xA;2024-03-28 20:08:53.069 18946-27926 hw-BpHwBinder           com.example.flenzey                  I  onLastStrongRef automatically unlinking death recipients&#xA;2024-03-28 20:08:53.071 18946-27926 OplusCCodec             com.example.flenzey                  D  ~OplusCCodec [144]: (0xb400007656569fc0)&#xA;2024-03-28 20:08:53.077 18946-27889 MediaCodecRenderer      com.example.flenzey                  W  Failed to initialize decoder: c2.android.mpeg4.decoder&#xA;                                                                                                      java.lang.IllegalArgumentException&#xA;                                                                                                          at android.media.MediaCodec.native_configure(Native Method)&#xA;                                                                                                          at android.media.MediaCodec.configure(MediaCodec.java:2176)&#xA;                                                                                                          at android.media.MediaCodec.configure(MediaCodec.java:2092)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter.initialize(AsynchronousMediaCodecAdapter.java:174)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter.access$100(AsynchronousMediaCodecAdapter.java:54)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter$Factory.createAdapter(AsynchronousMediaCodecAdapter.java:119)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.DefaultMediaCodecAdapterFactory.createAdapter(DefaultMediaCodecAdapterFactory.java:117)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:1195)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1103)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:551)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1560)&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:1152)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:994)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:814)&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:940)&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1102)&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:541)&#xA;                                                                                                          at android.os.Handler.dispatchMessage(Handler.java:102)&#xA;                                                                                                          at android.os.Looper.loopOnce(Looper.java:238)&#xA;                                                                                                          at android.os.Looper.loop(Looper.java:349)&#xA;                                                                                                          at android.os.HandlerThread.run(HandlerThread.java:67)&#xA;2024-03-28 20:08:53.091 18946-27889 MediaCodecVideoRenderer com.example.flenzey                  E  Video codec error&#xA;                                                                                                      androidx.media3.exoplayer.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: c2.android.mpeg4.decoder, Format(1, null, null, video/mp4v-es, null, 22800180, null, [2448, 3264, 24.999998, ColorInfo(Unset color space, Unset color range, Unset color transfer, false, 8bit Luma, 8bit Chroma)], [-1, -1])&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1114)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:551)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1560)&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:1152)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:994)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:814)&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:940)&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1102)&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:541)&#xA;                                                                                                          at android.os.Handler.dispatchMessage(Handler.java:102)&#xA;                                                                                                          at android.os.Looper.loopOnce(Looper.java:238)&#xA;                                                                                                          at android.os.Looper.loop(Looper.java:349)&#xA;                                                                                                          at android.os.HandlerThread.run(HandlerThread.java:67)&#xA;                                                                                                      Caused by: java.lang.IllegalArgumentException&#xA;                                                                                                          at android.media.MediaCodec.native_configure(Native Method)&#xA;                                                                                                          at android.media.MediaCodec.configure(MediaCodec.java:2176)&#xA;                                                                                                          at android.media.MediaCodec.configure(MediaCodec.java:2092)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter.initialize(AsynchronousMediaCodecAdapter.java:174)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter.access$100(AsynchronousMediaCodecAdapter.java:54)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter$Factory.createAdapter(AsynchronousMediaCodecAdapter.java:119)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.DefaultMediaCodecAdapterFactory.createAdapter(DefaultMediaCodecAdapterFactory.java:117)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:1195)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1103)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:551)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1560)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:1152)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:994)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:814)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:940)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1102)&#xA0;&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:541)&#xA0;&#xA;                                                                                                          at android.os.Handler.dispatchMessage(Handler.java:102)&#xA0;&#xA;                                                                                                          at android.os.Looper.loopOnce(Looper.java:238)&#xA0;&#xA;                                                                                                          at android.os.Looper.loop(Looper.java:349)&#xA0;&#xA;                                                                                                          at android.os.HandlerThread.run(HandlerThread.java:67)&#xA0;&#xA;2024-03-28 20:08:53.092 18946-27889 MediaCodecInfo          com.example.flenzey                  D  NoSupport [sizeAndRate.support, 2448x3264@24.999998092651367] [c2.android.mpeg4.decoder, video/mp4v-es] [OP535DL1, CPH2381, OnePlus, 31]&#xA;2024-03-28 20:08:53.108 18946-27889 ExoPlayerImplInternal   com.example.flenzey                  E  Playback error&#xA;                                                                                                      androidx.media3.exoplayer.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(1, null, null, video/mp4v-es, null, 22800180, null, [2448, 3264, 24.999998, ColorInfo(Unset color space, Unset color range, Unset color transfer, false, 8bit Luma, 8bit Chroma)], [-1, -1]), format_supported=NO_EXCEEDS_CAPABILITIES&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:620)&#xA;                                                                                                          at android.os.Handler.dispatchMessage(Handler.java:102)&#xA;                                                                                                          at android.os.Looper.loopOnce(Looper.java:238)&#xA;                                                                                                          at android.os.Looper.loop(Looper.java:349)&#xA;                                                                                                          at android.os.HandlerThread.run(HandlerThread.java:67)&#xA;                                                                                                      Caused by: androidx.media3.exoplayer.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: c2.android.mpeg4.decoder, Format(1, null, null, video/mp4v-es, null, 22800180, null, [2448, 3264, 24.999998, ColorInfo(Unset color space, Unset color range, Unset color transfer, false, 8bit Luma, 8bit Chroma)], [-1, -1])&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1114)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:551)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1560)&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:1152)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:994)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:814)&#xA;                                                                                                          at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:940)&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1102)&#xA;                                                                                                          at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:541)&#xA;                                                                                                          at android.os.Handler.dispatchMessage(Handler.java:102)&#xA0;&#xA;                                                                                                          at android.os.Looper.loopOnce(Looper.java:238)&#xA0;&#xA;                                                                                                          at android.os.Looper.loop(Looper.java:349)&#xA0;&#xA;                                                                                                          at android.os.HandlerThread.run(HandlerThread.java:67)&#xA0;&#xA;                                                                                                      Caused by: java.lang.IllegalArgumentException&#xA;                                                                                                          at android.media.MediaCodec.native_configure(Native Method)&#xA;                                                                                                          at android.media.MediaCodec.configure(MediaCodec.java:2176)&#xA;                                                                                                          at android.media.MediaCodec.configure(MediaCodec.java:2092)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter.initialize(AsynchronousMediaCodecAdapter.java:174)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter.access$100(AsynchronousMediaCodecAdapter.java:54)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecAdapter$Factory.createAdapter(AsynchronousMediaCodecAdapter.java:119)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.DefaultMediaCodecAdapterFactory.createAdapter(DefaultMediaCodecAdapterFactory.java:117)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:1195)&#xA;                                                                                                          at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1103)&#xA;

    &#xA;

    can anybody solve it

    &#xA;

    i tried to implement but i don't how to solve it . please decode this and get me correct result.

    &#xA;

  • Incrementality Testing : Quick-Start Guide (With Calculations)

    26 mars, par Erin

    How do you know when a campaign is successful ? When you earn more revenue than last month ?

    Maybe.

    But how do you know how much of an impact a certain campaign or channel had on your sales ?

    With marketing attribution, you can determine credit for each sale.

    But if you want a deeper look, you need to understand the incremental impact of each channel and campaign.

    The way you do this ?

    Incrementality testing.

    In this guide, we break down what incrementality is, why it’s important and how to test it so you can double down on the activities driving the most growth.

    What is incrementality ?

    So, what exactly is incrementality ?

    Let’s say you just ran a marketing campaign for a new product. The launch was a success. Breakthrough numbers in your revenue. You used a variety of channels and activities to bring it all together.

    So, you launch a plan for next month’s campaign. But you don’t truly know what moved the needle.

    Did you just hit new highs because your audience is bigger ? And your brand is greater ?

    Or did the recent moves you made make a direct difference ?

    This is incrementality.

    What is incrementally in marketing?

    Incrementality is growth directly attributed to marketing efforts beyond the overall impact of your brand. By measuring and conducting incrementality testing, you can clearly see how much of a difference each activity or channel truly impacted business growth. 

    What is incrementality testing ?

    Incrementality testing allows marketers to gauge the effectiveness of a marketing tactic or strategy. It tells you if a particular marketing activity had a positive, negative or neutral impact on your business. 

    It also tells you the overall impact it can have on your key performance indicators (KPIs). 

    The result ?

    You can pinpoint the highest-performing moves and incorporate them into your marketing workflows. You also discard marketing strategies with negligible, neutral or even negative impacts. 

    For example, let’s say you think a B2B LinkedIn ads campaign will help you reach your product launch goals. An incrementality test can tell you if the introduction of this campaign will help you get to the desired outcome.

    How incrementality testing works

    Before diving into your testing phase, you must clearly identify your KPIs.

    Here are the top KPIs you should be tracking on your website :

    • Ad impressions
    • Website visits
    • Leads
    • Sales

    The exact KPIs will depend on your marketing goals. You’re ready to move forward once you know your key performance indicators.

    Here’s how incrementality testing works step-by-step :

    1. Define a test and control group

    The first step is to define a test group and control group. 

    • A test group is a segment of your target audience that’s exposed to the marketing campaign. 
    • A control group is a segment that isn’t. 

    Keep in mind that both groups have similar demographics and other relevant characteristics. 

    2. Execute your campaign

    The second step is to run the marketing campaign on the test group. This can be a Facebook ad, LinkedIn ad or email marketing campaign.

    It all depends on your goals and your primary channels.

    3. Measure outcomes

    The third step is to measure the campaign’s impact based on your KPIs. 

    Let’s say a brand wants to see if a certain marketing move increases its leads. The test can tell them the number of email sign-ups with and without the campaign. 

    4. Compare results

    Next, compare the test group results with the control group. The difference in outcomes tells you the impact of that campaign. You can then use this difference to inform your future marketing strategies. 

    With Matomo, you can easily track results from campaigns — like conversions. 

    Our platform lets you quickly see what channels are getting the best results so you can gain insights into incrementality and optimise your strategy.

    Try Matomo for Free

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

    No credit card required

    Why it’s important to conduct incrementality tests

    The digital marketing industry is constantly changing. Marketers need to stay on their toes to keep up. Incrementality tests help you stay on track.

    For example, let’s say you’re selling laptops. You can increase your warranty period to three years to see the impact on sales. An incrementality test will tell you if this move will boost your sales (and by how much).

    Now, let’s dive into the reasons why you need to consistently conduct incrementality tests :

    Determine the right tactics for success

    Identifying the best action to grow your business is a challenge every marketer faces.

    The best way to identify marketing tactics is by conducting incrementality testing. These tactics are bound to work since data back them. As a result, you can optimise your marketing budget and maximise your ROIs. 

    It lets you run multiple tests to identify the most impactful strategy between :

    • An email marketing strategy
    • A social media strategy 
    • A PPC ad

    For instance, an incrementality test might suggest email marketing will be more cost-effective than an ad campaign. What you can do is :

    • Expose the test group to the email marketing campaign and then compare the results with the control group
    • Expose the test group to the ad campaign and then compare its results with the control group

    Then, you can calculate the difference in results between the two marketing campaigns. This lets you focus on the strategy with a better ROI or ROAS potential. 

    Accurate data

    Marketing data is powerful. But getting accurate data can be challenging. With incrementality testing, you get to know the true impact of a marketing campaign. 

    Plus, with this testing strategy, you don’t have to waste your marketing budget. 

    With Matomo, you get 100% accurate data on all website activities. 

    Unlike Google Analytics, Matomo doesn’t rely on inaccurate data sampling — limiting the amount of data analysed.

    Try Matomo for Free

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

    No credit card required

    Get the most out of your marketing investment

    Every business owner wants to maximise their return on investment. The ROI you get mainly depends on the marketing strategy. 

    For instance, email marketing offers an ROI of about 40:1 with some sources even reporting as high as 72:1.

    Incrementality testing helps you make informed investment decisions. With it, you can pinpoint the tactics that are most likely to bring the highest return. You can then focus your resources on them. It also helps you stay away from low-performing strategies. 

    Increase revenue

    It’s safe to say that the goal behind every marketing effort is a revenue boost. The higher your revenue, the more profits you generate. However, for many marketers, it’s an uphill battle. 

    With incrementality testing, you can boost your revenue by focusing your efforts in the right direction. 

    Get more traffic

    Incrementality testing tells you if a particular strategy can help you drive more traffic. You can use it to get more high-quality leads to your website or landing pages and double down on high-traffic strategies to increase those leads.

    How to test incrementality

    How to test incrementality.

    Developing an implementation plan is crucial to generate accurate insights from an incrementality test. Incrementality testing is like running a science experience. You need to go through several stages. Each stage is important for generating accurate results. 

    Here’s how you test incrementality :

    Define your goals

    Get clarity on what you want to achieve with this campaign. Which KPIs do you want to test ? Is it the return on your overall investment (ROI), return on ad spend (ROAS) or something else ?

    Segment your audience

    Selecting the right audience segment is crucial to getting accurate insights with an incrementality test. Decide the demographics and psychographics of the audience you want to target. Then, divide this audience segment into two sub-parts :

    • Test group (people you’ll expose to the marketing campaign)
    • Control group (people who won’t be exposed to the campaign)

    These groups are a part of the larger segment. This means people in both groups will have similar attributes. 

    Launch the test at the right time

    Before the launch, decide on the length of the test. Ideally, it should be at least one week. Don’t run any other campaigns in this window, as it can interfere with the results. 

    Analyse the data and take action

    Once the campaign is over, measure the results from both groups. Compare the data to identify incremental lift in your selected KPIs. 

    Let’s say you want to see if this campaign can boost your sales. Check to see if the test group responded differently than the control group. If the sales equal your desired outcome, you have a winning strategy. 

    Not all incrementality tests result in a positive incremental lift ; Some can be neutral, indicating that the campaign didn’t have any effect. Some can even indicate a negative lift, which means your core group performed better than the test group. 

    Lastly, take action based on the test findings. 

    Incrementality test examples 

    You can use incrementality testing to identify gaps and growth opportunities in your strategy. 

    Here’s an example :

    Let’s say a company runs an incrementality test on a YouTube marketing strategy for sales. The results indicate that the ROI was only $0.10, as the company makes $1.10 for every $1.00 spent. This alarms the marketing department and helps them optimise the campaign for a higher ROI. 

    Here’s another practical example :

    Let’s say a retail business wanted to test the effectiveness of its ad campaign. So, the retailer optimises its ad campaign after conducting an incrementality test on a test and control group. As a result, they experienced a 34% incremental increase in sales.

    How to calculate incrementality in marketing

    Once you’ve aggregated the data, it’s time to calculate. There are two ways to calculate incrementality :

    Incremental profit 

    The first one is incremental profit. It tells you how much profit you can generate with a strategy (If any). With it, you get the actual value of a marketing campaign. 

    It’s calculated with the following formula :

    Test group profit – control group profit = incremental profit 

    For example, let’s say you’re exposing a test group to a paid ads campaign. And it generates a profit of $3,000. On the other hand, the control group generated a $2,000 profit. 

    In this case, your incremental profit will be $1,000 ($3,000 – $2,000). 

    However, if the paid ads campaign generates a $2,000 profit, the incremental profit would be zero. Essentially, you’re generating the same profit as before, which means the campaign doesn’t work. Similarly, a marketing strategy is no good if it generates lower profits than the control group. 

    Incremental lift

    Incremental lift measures the difference in the conversions you generate with each group. 

    Here’s the formula :

    (Test – Control)/Control x 100 = Lift

    So, let’s say the test group and control group generated 2,000 and 1,000 conversions, respectively. 

    The incremental lift you’ll get from this incrementality test would be :

    (2,000 – 1,000)/1,000 x 100 = 100

    This turns out to be a 100% incremental lift.

    How to track incrementality with Matomo

    Incrementality testing lets you use a practical approach to identify the best marketing path for your business.

    It helps you develop a hyper-focused approach that gives you access to accurate and practical data. 

    With these insights, you can confidently move forward to maximise your ROI since it helps you focus on high-performing tactics. 

    The result is more revenue and profit for your business. 

    Plus, all you need to do is identify your target audience, divide them into two groups and run your test. Then, the results will be compared to determine if the marketing strategy offers any value. 

    Conducting incrementality tests may take time and expertise. 

    But, thanks to Matomo, you can leverage accurate insights for your incrementality tests to ensure you make the right decisions to grow your business.

    See for yourself why over 1 million websites choose Matomo. Try it free for 21-days now. No credit card required.