Recherche avancée

Médias (91)

Autres articles (25)

  • Selection of projects using MediaSPIP

    2 mai 2011, par

    The examples below are representative elements of MediaSPIP specific uses for specific projects.
    MediaSPIP farm @ Infini
    The non profit organizationInfini develops hospitality activities, internet access point, training, realizing innovative projects in the field of information and communication technologies and Communication, and hosting of websites. It plays a unique and prominent role in the Brest (France) area, at the national level, among the half-dozen such association. Its members (...)

  • Keeping control of your media in your hands

    13 avril 2011, par

    The vocabulary used on this site and around MediaSPIP in general, aims to avoid reference to Web 2.0 and the companies that profit from media-sharing.
    While using MediaSPIP, you are invited to avoid using words like "Brand", "Cloud" and "Market".
    MediaSPIP is designed to facilitate the sharing of creative media online, while allowing authors to retain complete control of their work.
    MediaSPIP aims to be accessible to as many people as possible and development is based on expanding the (...)

  • Sélection de projets utilisant MediaSPIP

    29 avril 2011, par

    Les exemples cités ci-dessous sont des éléments représentatifs d’usages spécifiques de MediaSPIP pour certains projets.
    Vous pensez avoir un site "remarquable" réalisé avec MediaSPIP ? Faites le nous savoir ici.
    Ferme MediaSPIP @ Infini
    L’Association Infini développe des activités d’accueil, de point d’accès internet, de formation, de conduite de projets innovants dans le domaine des Technologies de l’Information et de la Communication, et l’hébergement de sites. Elle joue en la matière un rôle unique (...)

Sur d’autres sites (4428)

  • Resampling audio with FFMPEG LibAV

    22 septembre 2020, par FennecFix

    Well, since FFMPEG documentation and code examples are absolute garbage, I guess my only choise is to go here and aks.

    


    So what I'm trying to do is simply record audio from microphione and write it to the file. So I initialize my input and out formats, I get an audio packet decode it, resample, encode and write. But everytime I try to play and audio there's only a stub of data. It seems like for some reason it writes only a start packet. Which is still very strange and let me explain why :

    


    if((response = swr_config_frame(resampleContext, audioOutputFrame, frame) < 0)) qDebug() << "can't configure frame!" <<  av_make_error(response);

if((response = swr_convert_frame(resampleContext, audioOutputFrame, frame) < 0)) qDebug() << "can't resample frame!" <<  av_make_error(response);


    


    Here's the code I'm using to resample. My frame has data but swr_convert_frame writes empty data to audioOutputFrame

    


    How do I fix that ? FFMPEG literally driving me crazy.

    


    Here's the full code of my class

    


    VideoReader.h

    


    #ifndef VIDEOREADER_H&#xA;#define VIDEOREADER_H&#xA;&#xA;extern "C"&#xA;{&#xA;#include <libavcodec></libavcodec>avcodec.h>&#xA;#include <libavformat></libavformat>avformat.h>&#xA;#include <libswscale></libswscale>swscale.h>&#xA;#include <libavdevice></libavdevice>avdevice.h>&#xA;#include "libavutil/audio_fifo.h"&#xA;#include "libavformat/avio.h"&#xA;#include "libswresample/swresample.h"&#xA;#include &#xA;}&#xA;&#xA;#include <qstring>&#xA;#include <qelapsedtimer>&#xA;&#xA;class VideoReader&#xA;{&#xA;public:&#xA;    VideoReader();&#xA;&#xA;    bool open(const char* filename);&#xA;    bool fillFrame();&#xA;    bool readFrame(uint8_t *&amp;frameData);&#xA;    void close();&#xA;&#xA;    int width, height;&#xA;&#xA;private:&#xA;    bool configInput();&#xA;    bool configOutput(const char *filename);&#xA;    bool configResampler();&#xA;&#xA;    bool encode(AVFrame *frame, AVCodecContext *encoderContext, AVPacket *outputPacket, int streamIndex, QString type);&#xA;&#xA;    int audioStreamIndex = -1;&#xA;    int videoStreamIndex = -1;&#xA;&#xA;    int64_t videoStartPts = 0;&#xA;    int64_t audioStartPts = 0;&#xA;&#xA;    AVFormatContext* inputFormatContext = nullptr;&#xA;    AVFormatContext* outputFormatContext = nullptr;&#xA;&#xA;    AVCodecContext* videoDecoderContext = nullptr;&#xA;    AVCodecContext* videoEncoderContext = nullptr;&#xA;&#xA;    AVCodecContext* audioDecoderContext = nullptr;&#xA;    AVCodecContext* audioEncoderContext = nullptr;&#xA;&#xA;    AVFrame* videoInputFrame = nullptr;&#xA;    AVFrame* audioInputFrame = nullptr;&#xA;&#xA;    AVFrame* videoOutputFrame = nullptr;&#xA;    AVFrame* audioOutputFrame = nullptr;&#xA;&#xA;    AVPacket* inputPacket = nullptr;&#xA;&#xA;    AVPacket* videoOutputPacket = nullptr;&#xA;    AVPacket* audioOutputPacket = nullptr;&#xA;&#xA;    SwsContext* innerScaleContext = nullptr;&#xA;    SwsContext* outerScaleContext = nullptr;&#xA;&#xA;    SwrContext *resampleContext = nullptr;&#xA;};&#xA;&#xA;#endif // VIDEOREADER_H&#xA;</qelapsedtimer></qstring>

    &#xA;

    VideoReader.cpp

    &#xA;

    #include "VideoReader.h"&#xA;&#xA;#include <qdebug>&#xA;&#xA;static const char* av_make_error(int errnum)&#xA;{&#xA;    static char str[AV_ERROR_MAX_STRING_SIZE];&#xA;    memset(str, 0, sizeof(str));&#xA;    return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum);&#xA;}&#xA;&#xA;VideoReader::VideoReader()&#xA;{&#xA;&#xA;}&#xA;&#xA;bool VideoReader::open(const char *filename)&#xA;{&#xA;    if(!configInput()) return false;&#xA;    if(!configOutput(filename)) return false;&#xA;    if(!configResampler()) return false;&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;bool VideoReader::fillFrame()&#xA;{&#xA;    auto convertToYUV = [=](AVFrame* frame)&#xA;    {&#xA;        int response = 0;&#xA;&#xA;        if((response = sws_scale(outerScaleContext, frame->data, frame->linesize, 0, videoEncoderContext->height, videoOutputFrame->data, videoOutputFrame->linesize)) &lt; 0) qDebug() &lt;&lt; "can&#x27;t rescale" &lt;&lt; av_make_error(response);&#xA;    };&#xA;&#xA;    auto convertAudio = [this](AVFrame* frame)&#xA;    {&#xA;        int response = 0;&#xA;&#xA;        auto&amp; out = audioOutputFrame;&#xA;        qDebug() &lt;&lt; out->linesize[0] &lt;&lt; out->nb_samples;&#xA;        if((response = swr_convert_frame(resampleContext, audioOutputFrame, frame)) &lt; 0) qDebug() &lt;&lt; "can&#x27;t resample frame!" &lt;&lt; av_make_error(response);&#xA;        qDebug() &lt;&lt; "poop";&#xA;    };&#xA;&#xA;    auto decodeEncode = [=](AVPacket* inputPacket, AVFrame* inputFrame, AVCodecContext* decoderContext,&#xA;                            AVPacket* outputPacket, AVFrame* outputFrame, AVCodecContext* encoderContext,&#xA;                            std::function<void> convertFunc,&#xA;                            int streamIndex, int64_t startPts, QString type)&#xA;    {&#xA;        int response = avcodec_send_packet(decoderContext, inputPacket);&#xA;        if(response &lt; 0) { qDebug() &lt;&lt; "failed to send" &lt;&lt; type &lt;&lt; "packet!" &lt;&lt;  av_make_error(response); return false; }&#xA;&#xA;        response = avcodec_receive_frame(decoderContext, inputFrame);&#xA;        if(response == AVERROR(EAGAIN) || response == AVERROR_EOF) { av_packet_unref(inputPacket); return false; }&#xA;        else if (response &lt; 0) { qDebug() &lt;&lt; "failed to decode" &lt;&lt; type &lt;&lt; "frame!" &lt;&lt; response &lt;&lt; av_make_error(response); return false; }&#xA;&#xA;        if(encoderContext)&#xA;        {&#xA;            outputFrame->pts = inputPacket->pts - startPts;&#xA;&#xA;            convertFunc(inputFrame);&#xA;            if(!encode(outputFrame, encoderContext, outputPacket, streamIndex, type)) return false;&#xA;        }&#xA;&#xA;        av_packet_unref(inputPacket);&#xA;&#xA;        return true;&#xA;    };&#xA;&#xA;    while(av_read_frame(inputFormatContext, inputPacket) >= 0) //actually read packet&#xA;    {&#xA;        if(inputPacket->stream_index == videoStreamIndex)&#xA;        {&#xA;            if(!videoStartPts) videoStartPts = inputPacket->pts;&#xA;            if(decodeEncode(inputPacket, videoInputFrame, videoDecoderContext, videoOutputPacket, videoOutputFrame, videoEncoderContext, convertToYUV, videoStreamIndex, videoStartPts, "video")) break;&#xA;        }&#xA;        else if(inputPacket->stream_index == audioStreamIndex)&#xA;        {&#xA;            if(!audioStartPts) audioStartPts = inputPacket->pts;&#xA;            if(decodeEncode(inputPacket, audioInputFrame, audioDecoderContext, audioOutputPacket, audioOutputFrame, audioEncoderContext, convertAudio, audioStreamIndex, audioStartPts, "audio")) break;&#xA;        }&#xA;    }&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;bool VideoReader::readFrame(uint8_t *&amp;frameData)&#xA;{&#xA;    if(!fillFrame()) { qDebug() &lt;&lt; "readFrame method failed!"; return false; };&#xA;&#xA;    const int bytesPerPixel = 4;&#xA;&#xA;    uint8_t* destination[bytesPerPixel] = {frameData, NULL, NULL, NULL};&#xA;    int destinationLinesize[bytesPerPixel] = { videoInputFrame->width * bytesPerPixel,  0, 0, 0};&#xA;&#xA;    sws_scale(innerScaleContext, videoInputFrame->data, videoInputFrame->linesize, 0, videoInputFrame->height, destination, destinationLinesize);&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;void VideoReader::close()&#xA;{&#xA;    encode(NULL, videoEncoderContext, videoOutputPacket, videoStreamIndex, "video");&#xA;    encode(NULL, audioEncoderContext, audioOutputPacket, audioStreamIndex, "audio");&#xA;&#xA;    if(av_write_trailer(outputFormatContext) &lt; 0) { qDebug() &lt;&lt; "failed to write trailer"; };&#xA;&#xA;    avformat_close_input(&amp;outputFormatContext);&#xA;    avformat_free_context(outputFormatContext);&#xA;    avformat_close_input(&amp;inputFormatContext);&#xA;    avformat_free_context(inputFormatContext);&#xA;&#xA;    av_frame_free(&amp;videoInputFrame);&#xA;    av_frame_free(&amp;audioInputFrame);&#xA;&#xA;    av_frame_free(&amp;videoOutputFrame);&#xA;    av_frame_free(&amp;audioOutputFrame);&#xA;&#xA;    av_packet_free(&amp;inputPacket);&#xA;&#xA;    av_packet_free(&amp;videoOutputPacket);&#xA;    av_packet_free(&amp;audioOutputPacket);&#xA;&#xA;    avcodec_free_context(&amp;videoDecoderContext);&#xA;    avcodec_free_context(&amp;videoEncoderContext);&#xA;&#xA;    avcodec_free_context(&amp;audioDecoderContext);&#xA;    avcodec_free_context(&amp;audioEncoderContext);&#xA;&#xA;    sws_freeContext(innerScaleContext);&#xA;    sws_freeContext(outerScaleContext);&#xA;&#xA;    swr_free(&amp;resampleContext);&#xA;}&#xA;&#xA;bool VideoReader::configInput()&#xA;{&#xA;    avdevice_register_all();&#xA;&#xA;    inputFormatContext = avformat_alloc_context();&#xA;&#xA;    if(!inputFormatContext) { qDebug() &lt;&lt; "can&#x27;t create context!"; return false; }&#xA;&#xA;    const char* inputFormatName = "dshow";/*"gdigrab"*/&#xA;    AVInputFormat* inputFormat = av_find_input_format(inputFormatName);&#xA;&#xA;    if(!inputFormat){ qDebug() &lt;&lt; "Can&#x27;t find" &lt;&lt; inputFormatName; return false; }&#xA;&#xA;    AVDictionary* options = NULL;&#xA;    av_dict_set(&amp;options, "framerate", "30", 0);&#xA;    av_dict_set(&amp;options, "video_size", "1920x1080", 0);&#xA;&#xA;    if(avformat_open_input(&amp;inputFormatContext, "video=HD USB Camera:audio=Microphone (High Definition Audio Device)" /*"desktop"*/, inputFormat, &amp;options) != 0) { qDebug() &lt;&lt; "can&#x27;t open video file!"; return false; }&#xA;&#xA;    AVCodecParameters* videoCodecParams = nullptr;&#xA;    AVCodecParameters* audioCodecParams = nullptr;&#xA;    AVCodec* videoDecoder = nullptr;&#xA;    AVCodec* audioDecoder = nullptr;&#xA;&#xA;    for (uint i = 0; i &lt; inputFormatContext->nb_streams; &#x2B;&#x2B;i)&#xA;    {&#xA;        auto stream = inputFormatContext->streams[i];&#xA;        auto codecParams = stream->codecpar;&#xA;&#xA;        if(codecParams->codec_type == AVMEDIA_TYPE_AUDIO) { audioStreamIndex = i; audioDecoder = avcodec_find_decoder(codecParams->codec_id); audioCodecParams = codecParams; }&#xA;        if(codecParams->codec_type == AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; videoDecoder = avcodec_find_decoder(codecParams->codec_id); videoCodecParams = codecParams; }&#xA;&#xA;        if(audioStreamIndex != -1 &amp;&amp; videoStreamIndex != -1) break;&#xA;    }&#xA;&#xA;    if(audioStreamIndex == -1) { qDebug() &lt;&lt; "failed to find audio stream inside file"; return false; }&#xA;    if(videoStreamIndex == -1) { qDebug() &lt;&lt; "failed to find video stream inside file"; return false; }&#xA;&#xA;    auto configureCodecContext = [=](AVCodecContext*&amp; context, AVCodec* decoder, AVCodecParameters* params, AVFrame*&amp; frame, QString type)&#xA;    {&#xA;        context = avcodec_alloc_context3(decoder);&#xA;        if(!context) { qDebug() &lt;&lt; "failed to create" &lt;&lt; type &lt;&lt; "decoder context!"; return false; }&#xA;&#xA;        if(avcodec_parameters_to_context(context, params) &lt; 0) { qDebug() &lt;&lt; "can&#x27;t initialize input" &lt;&lt; type &lt;&lt; "decoder context"; return false; }&#xA;&#xA;        if(avcodec_open2(context, decoder, NULL) &lt; 0) { qDebug() &lt;&lt; "can&#x27;t open" &lt;&lt; type &lt;&lt; "decoder"; return false; }&#xA;&#xA;        frame = av_frame_alloc();&#xA;        if(!frame) { qDebug() &lt;&lt; "can&#x27;t allocate" &lt;&lt; type &lt;&lt; "frame"; return false; }&#xA;&#xA;        return true;&#xA;    };&#xA;&#xA;    if(!configureCodecContext(videoDecoderContext, videoDecoder, videoCodecParams, videoInputFrame, "video")) return false;&#xA;    if(!configureCodecContext(audioDecoderContext, audioDecoder, audioCodecParams, audioInputFrame, "audio")) return false;&#xA;&#xA;    audioDecoderContext->channel_layout = AV_CH_LAYOUT_STEREO;&#xA;    audioInputFrame->channel_layout = audioDecoderContext->channel_layout;&#xA;&#xA;    inputPacket = av_packet_alloc();&#xA;    if(!inputPacket) { qDebug() &lt;&lt; "can&#x27;t allocate input packet!";  return false; }&#xA;&#xA;    //first frame, needed fo initialization&#xA;    if(!fillFrame()) { qDebug() &lt;&lt; "Failed to fill frame on init!"; return false; };&#xA;&#xA;    width = videoDecoderContext->width;&#xA;    height = videoDecoderContext->height;&#xA;&#xA;    innerScaleContext = sws_getContext(width, height, videoDecoderContext->pix_fmt,&#xA;                                       width, height, AV_PIX_FMT_RGB0,&#xA;                                       SWS_FAST_BILINEAR,&#xA;                                       NULL,&#xA;                                       NULL,&#xA;                                       NULL);&#xA;&#xA;    outerScaleContext = sws_getContext(width, height, videoDecoderContext->pix_fmt,&#xA;                                       width, height, AV_PIX_FMT_YUV420P,&#xA;                                       SWS_FAST_BILINEAR,&#xA;                                       NULL,&#xA;                                       NULL,&#xA;                                       NULL);&#xA;&#xA;&#xA;    if(!innerScaleContext) { qDebug() &lt;&lt; "failed to initialize scaler context"; return false; }&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;bool VideoReader::configOutput(const char *filename)&#xA;{&#xA;    avformat_alloc_output_context2(&amp;outputFormatContext, NULL, NULL, filename);&#xA;    if(!outputFormatContext) { qDebug() &lt;&lt; "failed to create output context"; return false; }&#xA;&#xA;    AVOutputFormat* outputFormat = outputFormatContext->oformat;&#xA;&#xA;    auto prepareOutputContext = [=](AVCodecContext*&amp; encoderContext,&#xA;                                    std::function<void> configureContextFunc,&#xA;                                    std::function<void> configureFrameFunc,&#xA;                                    AVCodecID codecId, AVFrame*&amp; frame, AVPacket*&amp; packet, QString type)&#xA;    {&#xA;        auto stream = avformat_new_stream(outputFormatContext, NULL);&#xA;        if(!stream) { qDebug() &lt;&lt; "failed to allocate output" &lt;&lt; type &lt;&lt; "stream"; return false; }&#xA;&#xA;        AVCodec* encoder = avcodec_find_encoder(codecId);&#xA;        if(!encoder) { qDebug() &lt;&lt; "failed to find" &lt;&lt; type &lt;&lt; "encoder!"; return false; }&#xA;&#xA;        encoderContext = avcodec_alloc_context3(encoder);&#xA;        if(!encoderContext) { qDebug() &lt;&lt; "failed to create video encoder context!"; return false; }&#xA;&#xA;        configureContextFunc(encoderContext, encoder);&#xA;&#xA;        int result = avcodec_open2(encoderContext, encoder, NULL);&#xA;        if(result &lt; 0) { qDebug() &lt;&lt; "failed to open audio encoder" &lt;&lt; av_make_error(result); return false; }&#xA;        if(avcodec_parameters_from_context(stream->codecpar, encoderContext) &lt; 0) { qDebug() &lt;&lt; "failed to copy parameters to audio output stream"; return false; }&#xA;&#xA;        packet = av_packet_alloc();&#xA;        if(!packet) {qDebug() &lt;&lt; "failed allocate output" &lt;&lt; type &lt;&lt; "packet"; return false;}&#xA;&#xA;        frame = av_frame_alloc();&#xA;        if(!frame) { qDebug() &lt;&lt; "can&#x27;t allocate output" &lt;&lt; type &lt;&lt; "frame"; return false; }&#xA;&#xA;        configureFrameFunc(frame);&#xA;&#xA;        av_frame_get_buffer(frame, 0);&#xA;&#xA;        return true;&#xA;    };&#xA;&#xA;    auto configureAudioFrame = [=](AVFrame* frame)&#xA;    {&#xA;        frame->nb_samples = audioEncoderContext->frame_size;&#xA;        frame->format = audioEncoderContext->sample_fmt;&#xA;        frame->sample_rate = audioEncoderContext->sample_rate;&#xA;        frame->channel_layout = av_get_default_channel_layout(audioDecoderContext->channels);&#xA;    };&#xA;&#xA;    auto configureAudioEncoderContext = [=](AVCodecContext* encoderContext, AVCodec* encoder)&#xA;    {&#xA;        encoderContext->bit_rate = 64000;&#xA;        encoderContext->sample_fmt = encoder->sample_fmts[0];&#xA;        encoderContext->sample_rate = 44100;&#xA;        encoderContext->codec_type = AVMEDIA_TYPE_AUDIO;&#xA;        encoderContext->channel_layout = AV_CH_LAYOUT_STEREO;&#xA;        encoderContext->channels = av_get_channel_layout_nb_channels(encoderContext->channel_layout);&#xA;    };&#xA;&#xA;    auto configureVideoFrame = [=](AVFrame* frame)&#xA;    {&#xA;        frame->format = videoEncoderContext->pix_fmt;&#xA;        frame->width  = videoEncoderContext->width;&#xA;        frame->height = videoEncoderContext->height;&#xA;    };&#xA;&#xA;    auto configureVideoEncoderContext = [=](AVCodecContext* encoderContext, AVCodec* encoder)&#xA;    {&#xA;        encoderContext->width = videoDecoderContext->width;&#xA;        encoderContext->height = videoDecoderContext->height;&#xA;        encoderContext->pix_fmt = encoder->pix_fmts[0];&#xA;        encoderContext->gop_size = 10;&#xA;        encoderContext->max_b_frames = 1;&#xA;        encoderContext->framerate = AVRational{30, 1};&#xA;        encoderContext->time_base = AVRational{1, 30};&#xA;&#xA;        av_opt_set(encoderContext->priv_data, "preset", "ultrafast", 0);&#xA;        av_opt_set(encoderContext->priv_data, "tune", "zerolatency", 0);&#xA;    };&#xA;&#xA;    if(!prepareOutputContext(videoEncoderContext, configureVideoEncoderContext, configureVideoFrame, outputFormat->video_codec, videoOutputFrame, videoOutputPacket, "video")) return false;&#xA;    if(!prepareOutputContext(audioEncoderContext, configureAudioEncoderContext, configureAudioFrame, outputFormat->audio_codec, audioOutputFrame, audioOutputPacket, "audio")) return false;&#xA;&#xA;    if(outputFormat->flags &amp; AVFMT_GLOBALHEADER) outputFormat->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;&#xA;&#xA;    int result = 0;&#xA;    if(!(outputFormat->flags &amp; AVFMT_NOFILE))&#xA;        if((result = avio_open(&amp;outputFormatContext->pb, filename, AVIO_FLAG_WRITE)) &lt; 0)&#xA;            { qDebug() &lt;&lt; "failed to open file" &lt;&lt;  av_make_error(result); return false; }&#xA;&#xA;    result = avformat_write_header(outputFormatContext, NULL);&#xA;    if(result &lt; 0) {qDebug() &lt;&lt; "failed to write header!" &lt;&lt; av_make_error(result); return false; }&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;bool VideoReader::configResampler()&#xA;{&#xA;&#xA;    resampleContext = swr_alloc_set_opts(NULL,&#xA;                                         av_get_default_channel_layout(audioEncoderContext->channels),&#xA;                                         audioEncoderContext->sample_fmt,&#xA;                                         audioEncoderContext->sample_rate,&#xA;                                         av_get_default_channel_layout(audioDecoderContext->channels),&#xA;                                         audioDecoderContext->sample_fmt,&#xA;                                         audioDecoderContext->sample_rate,&#xA;                                         0, NULL);&#xA;    if (!resampleContext) { qDebug() &lt;&lt; "Could not allocate resample context"; return false; }&#xA;&#xA;    int error;&#xA;    if ((error = swr_init(resampleContext)) &lt; 0) { qDebug() &lt;&lt; "Could not open resample context"; swr_free(&amp;resampleContext); return false; }&#xA;&#xA;    return true;&#xA;}&#xA;&#xA;bool VideoReader::encode(AVFrame* frame, AVCodecContext* encoderContext, AVPacket* outputPacket, int streamIndex, QString type)&#xA;{&#xA;    int response;&#xA;&#xA;    response = avcodec_send_frame(encoderContext, frame);&#xA;    if(response &lt; 0) { qDebug() &lt;&lt; "failed to send" &lt;&lt; type &lt;&lt; "frame" &lt;&lt; av_make_error(response); return false; }&#xA;&#xA;    while(response >= 0)&#xA;    {&#xA;        response = avcodec_receive_packet(encoderContext, outputPacket);&#xA;        if(response == AVERROR(EAGAIN) || response == AVERROR_EOF) { av_packet_unref(outputPacket); continue; }&#xA;        else if (response &lt; 0) { qDebug() &lt;&lt; "failed to encode" &lt;&lt; type &lt;&lt; "frame!" &lt;&lt; response &lt;&lt; av_make_error(response); return false; }&#xA;&#xA;        outputPacket->stream_index = streamIndex;&#xA;&#xA;        AVStream *inStream = inputFormatContext->streams[streamIndex];&#xA;        AVStream *outStream = outputFormatContext->streams[streamIndex];&#xA;&#xA;        av_packet_rescale_ts(outputPacket, inStream->time_base, outStream->time_base);&#xA;&#xA;        if((response = av_interleaved_write_frame(outputFormatContext, outputPacket)) != 0) { qDebug() &lt;&lt; "Failed to write" &lt;&lt; type &lt;&lt; "packet!" &lt;&lt;  av_make_error(response); av_packet_unref(outputPacket); return false; }&#xA;&#xA;        av_packet_unref(outputPacket);&#xA;    }&#xA;&#xA;    return true;&#xA;}&#xA;</void></void></void></qdebug>

    &#xA;

    I could try to write down shorter example if needed

    &#xA;

  • CRO Program : Best Practices and KPIs to Track [2024]

    8 mai 2024, par Erin

    Driving traffic to your website is only one part of the equation ; the second part is getting those visitors to convert by completing a desired action — creating an account, signing up for a newsletter or completing a purchase. 

    But if you fail to optimise your website for conversions, you’ll have a hard time guiding visitors further down the funnel and turning them into customers.

    That’s where a CRO program (or conversion rate optimisation) can help. 

    This article will cover conversion rate optimisation best practices and outline key metrics and KPIs to start tracking to see an improvement in your conversion rates.

    What is a CRO program ? 

    In the simplest terms, a CRO program — also called a CRO plan — is a digital marketing strategy. It focuses on implementing different tactics that can lead to an increase in conversion rate and maximising revenue. 

    CRO concept with marketing icons

    One thing to remember is that the definition of “conversion” varies from business to business. The most obvious type of conversion would be a financial transaction or a completed form — but it comes down to what you consider a valuable action. 

    Many different actions can count as conversions, depending on your marketing goals. 

    Besides making a purchase, other common examples of key conversion moments include creating a new account, signing up for a free trial, booking a demo and subscribing to an email newsletter. 

    Another thing worth noting is that while the average conversion rate on e-commerce websites is 3.76%, it might fluctuate across different industries and device types. Case in point — desktop devices have higher conversion rates than mobile devices, clocking in at 4.79% and 3.32%, respectively. 

    So, in addition to defining your key conversion moments, you should also go over conversion insights relevant to your specific industry. 

    The importance of conversion rate optimisation 

    You’d be right to assume that the ultimate goal of a conversion rate optimisation process is to drive revenue through higher conversion rates — but don’t focus solely on the numbers. The core principle of a CRO program is improving the customer experience. Once you’ve achieved that, the increase in conversion rate will follow. 

    Illustration of conversion funnel optimisation

    According to a recent report, global conversion rate optimisation (CRO) software sales are expected to reach $3.7 billion by 2032 — up from $1.1 billion in 2021. 

    This growth indicates the increasing interest in strategies and tools that can help optimise the conversion funnel. Businesses are looking for ways to keep potential customers engaged and improve the average conversion rate — without necessarily increasing their spending. 

    Here are a few reasons why a CRO program deserves a spot in your broader digital marketing strategies : 

    • It can lower your cost per acquisition (CPA) : A CRO program is about optimising your conversion funnel by leveraging existing assets and website traffic rather than increasing your spending — which lowers the costs of acquiring new customers and, in turn, drives ROI. 
    • It can maximise customer lifetime value (CLV) : If you can turn one-time buyers into repeat customers, you’ll be one step closer to building a loyal user base and increasing your CLV. 
    • It can lead to increased sales and boost your revenue : Higher conversion rates typically mean higher revenue ; that’s arguably the most obvious benefit of implementing a CRO program
    • It improves the overall user experience : The goal is to make your site more accessible, easier to navigate and more engaging. Delivering the experience people want — and expect — when navigating your website is one of the core principles of a CRO program.
    • It helps you to get to know your customers better : You can’t meet your customers’ needs without taking the time to know them, create user personas and understand their preferences, pain points and conversion barriers they may be facing. 

    Conversion optimisation gives you a competitive edge in revenue and brand reputation. 

    5 CRO best practices 

    Illustration of different CRO elements

    Here are five conversion rate optimisation strategies and best practices that can make a real difference in the customer experience — and drive potential conversions. 

    Create a CRO roadmap in advance 

    First and foremost, you’ll need a well-defined “game plan” that aligns with and reflects your conversion goals. 

    A CRO roadmap is a detailed manual that outlines how to implement different elements of your CRO-related efforts. Marketing teams can refer to this step-by-step framework for test planning, prioritisation and resource allocation while optimising their marketing strategy. 

    While conversion rate optimisation can be a complex process — especially when you don’t know what to tackle first — we’ve found that there are three things you need to consider when setting the foundations of a successful CRO program : 

    • The “why” behind your website traffic : You’re likely using different online marketing strategies — from SEO to pay-per-click (PPC). So, it’s best to start by gathering channel-specific conversion insights through marketing attribution. Then identify which of these efforts have the biggest impact on your target audience. 
    • The so-called “conversion blockers” that tell you where and why visitors tend to leave without completing a desired action : Funnel analysis might reveal problematic pages — drop-off points where you tend to lose most of your visitors. 
    • Your “hooks” : User feedback can be of great help here ; you can learn a lot by simply asking your customers to fill out a quick online survey and tell you what motivated them to take action.

    Before working on that “game plan,” perform a pre-test analysis. 

    Matomo combines web analytics and user behaviour analytics with features like Heatmaps, Session Recordings, Form Analytics, Funnel Analytics, A/B Testing and User Flow. It can give you those initial benchmarks for measuring progress and a potential increase in conversion rate. 

    Validate your ideas with A/B and multivariate testing 

    Conversion rate optimisation is an iterative process. So, it shouldn’t come as a surprise that A/B testing variants of page layouts, CTAs, headlines, copy and other elements is a big part of it.

    Multivariate and A/B testing allows you to test a wide range of elements across your site and identify what works — and, more importantly, what doesn’t — in terms of driving conversions.

    On that note, Matomo’s A/B Testing feature can support your conversion rate optimisation process by identifying variants that perform better based on statistical significance. 

    Try Matomo for Free

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

    No credit card required

    Get to know your website visitors 

    Driving conversions comes down to understanding potential customer’s pain points and needs — and delivering an experience that positions you as the solution and gets them to take action. 

    Here are a few things that can help you understand your website visitors better : 

    • Collecting customer feedback through surveys and using it to identify main areas for improvement 
    • Creating detailed customer personas and optimising your website design and messaging based on your target audience’s pain points, needs and wants 
    • Using heatmaps — colour-coded data visualisation tools that illustrate user interactions — and scroll maps to get a comprehensive overview of online sessions and identify the most engaging elements and those that stand out as potential conversion barriers 

    Matomo’s Heatmaps can help you identify the most-clicked elements on the page and show how far users scroll — providing powerful user insights you can use to optimise these pages.

    Try Matomo for Free

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

    No credit card required

    Remove friction points 

    As we previously discussed, identifying friction points and barriers to conversion — issues that prevent visitors from converting — is one of the crucial aspects of developing a CRO plan. 

    Many different “conversion blockers” are worth looking into, including : 

    • Lengthy or otherwise complex checkout processes 
    • No guest checkout feature 
    • Device type, browser and OS compatibility issues 
    • Slow site speed and other technical issues
    • Lack of free shipping and limited payment methods 
    • Absence of social proof (customer reviews and testimonials) and trust badges

    Once you’ve identified what’s slowing down or completely discouraging users from reaching key conversion moments, take the time to address it. 

    Switch to text-based CTAs 

    Calls-to-action (CTAs) play a crucial role in guiding customers from interest to action. However, sometimes they fail to do their job — encouraging website visitors to proceed to the next step — effectively. 

    The most obvious reason is that your CTAs aren’t visually engaging or clear enough. In that case, you can try using action-oriented language and stronger visual elements and aligning the CTA copy with the context of the page. 

    But more often than not, the issue comes down to a phenomenon called “banner blindness” — the tendency of website visitors to ignore (either intentionally or unintentionally) elements on a page that resemble banner ads. 

    And if that’s what’s preventing visitors from converting, consider switching to text-based CTAs. 

    Conversion rate optimisation metrics and KPIs 

    At this point, you should know the outcomes you hope to achieve. Your next step should be to figure out how you’re going to measure and analyse results — and identify the changes that made the most impact on your conversion funnel. 

    After all, your CRO action plan should be based on data — assumptions and “gut feelings” will rarely lead to a notable increase in conversion rates

    Illustration of the conversion funnel

    That brings us to key performance indicators (KPIs) : 

    Tracking CRO metrics and website KPIs can help you understand the customer’s journey and path to purchase, identify opportunities for improving the user experience (UX) and determine how to optimise conversions.

    That said, you shouldn’t try to track every metric in the book ; think about your ultimate goal and identify the metrics and KPIs most relevant to your business. 

    We’ll assume that you’re already tracking macro- and micro-conversions. However, we’ve outlined a few additional key conversion rate optimisation metrics you should keep an eye on to make sure that your CRO program is performing as intended : 

    • Cost-per-conversion : By measuring how much you spend on each successful conversion — again, completed forms, sign-ups and sales all count as key conversion moments — you’ll be in a better position to assess the cost-effectiveness of your online marketing strategies.
    • Starter rate : This metric tells you the number of people who start filling out the form, after seeing it. This metric is particularly important for companies that rely on getting leads from forms. 
    • Average order value (AOV) : This metric is important for e-commerce sites to understand the value of their transactions. AOV calculates the average monetary value of each order.

    That’s not all ; you can also use a web analytics tool like Matomo to gain granular insights into visitors : 

    • Unique, new and returning visitors : Tracking the number of new and returning visitors your website gets within a given timeframe will help you understand your user base and determine if your content resonates with them. While you want a constant stream of new traffic, don’t overlook the importance of returning visitors ; they’re the foundation of a loyal customer base.
    • User flows : By analysing the user flows, you’ll have a visual representation of how visitors use your website, which will help you understand their journey and the specific path they take. 
    • Bounce rate : This metric tells you how many users viewed a single page on your site and ended up leaving before they took any kind of action. As such, it’s a clear indicator of how good your content, CTAs and website layout are at keeping users engaged.
    • Exit rate : Another key metric to track is the exit rate — the percentage of users who drop off at a specific page. High-exit pages usually lack important information and CTAs, cause frustration or otherwise fail to meet users’ expectations. Keep in mind that there’s a difference between bounce rate and exit rate — the latter involves users who viewed at least one other page. 

    There are many other user engagement metrics you should keep an eye on in addition to the ones mentioned above — including time on-page, actions per visit, scroll depth and traffic source. You’ll find all this information — and more — in Matomo’s Page Analytics Report

    Conclusion 

    Implementing a CRO program can be a time-consuming and iterative process. However, it’s vital for guiding your marketing efforts and making data-driven decisions that’ll ultimately help you drive growth and reach your business goals. 

    It’s best to start by identifying where your website visitors come from and what contributes to — or prevents them from — taking further action. But that’s easier said than done. You’ll need to leverage web analytics tools like Matomo to gather powerful user insights and monitor your website’s performance. 

    As an all-in-one, privacy-friendly web analytics solution, Matomo combines traditional web analytics and advanced behavioural analytics — delivering a consistent experience based on 100% accurate, unsampled data.

    Join the 1 million websites that have chosen Matomo as their web analytics platform. Start your 21-day free trial today — and see how Matomo can help you improve your website’s conversion rates. No credit card required.

  • Web Analytics Reports : 10 Key Types and How to Use Them

    29 janvier 2024, par Erin

    You can’t optimise your website to drive better results if you don’t know how visitors are engaging with your site.

    But how do you correctly analyse data and identify patterns ? With the right platform, you can use a wide range of web analytics reports to dive deep into the data.

    In this article, we’ll discuss what website analytics reports are, different types, why you need them, and how to use reports to find the insights you need.

    What is web analytics ?

    Website analytics is the process of gathering, processing, and analysing data that shows what users are doing when they visit your website. 

    You typically achieve this with web analytics tools by adding a tracking code that shares data with the analytics platform when someone visits the site.

    Illustration of how website analytics works

    The visitors trigger the tracking code, which collects data on how they act while on your site and then sends that information to the analytics platform. You can then see the data in your analytics solution and create reports based on this data.

    While there are a lot of web analytics solutions available, this article will specifically demonstrate reports using Matomo.

    What are web analytics reports ?

    Web analytics reports are analyses that focus on specific data points within your analytics platform. 

    For example, this channel report in Matomo shows the top referring channels of a website.

    Channel types report in Matomo analytics

    Your marketing team can use this report to determine which channels drive the best results. In the example above, organic search drives almost double the visits and actions of social campaigns. 

    If you’re investing the same amount of money, you’d want to move more of your budget from social to search.

    Why you need to get familiar with specific web analytics reports

    The default web analytics dashboard offers an overview of high-level trends in performance. However, it usually does not give you specific insights that can help you optimise your marketing campaigns.

    For example, you can see that your conversions are down month over month. But, at a glance, you do not understand why that is.

    To understand why, you need to go granular and wider — looking into qualifying data that separates different types of visitors from each other.

    Gartner predicts that 70% of organisations will focus on “small and wide” data by 2025 over “big data.” Most companies lack the data volume to simply let big data and algorithms handle the optimising.

    What you can do instead is dive deep into each visitor. Figure out how they engage with your site, and then you can adjust your campaigns and page content accordingly.

    Common types of web analytics reports

    There are dozens of different web analytics reports, but they usually fall into four separate categories :

    Diagram that illustrates the main types of web analytics reports
    • Referral sources : These reports show where your visitors come from. They range from channel reports — search, social media — to specific campaigns and ads.
    • Engagement (on-site actions) : These reports dive into what visitors are doing on your site. They break down clicks, scrolling, completed conversion goals, and more.
    • E-commerce performance : These reports show the performance of your e-commerce store. They’ll help you dive into the sales of individual products, trends in cart abandonment and more.
    • Demographics : These reports help you understand more about your visitors — where they’re visiting from, their browser language, device, and more.

    You can even combine insights across all four using audience segmentation and custom reports. (We’ll cover this in more detail later.)

    How to use 10 important website analytics reports

    The first step is to install the website analytics code on your website. (We include more detailed information in our guide on how to track website visitors.)

    Then, you need to wait until you have a few days (or, if you have limited traffic, a few weeks) of data. Without sufficient website visitor data, none of the reports will be meaningful.

    Visitor Overview report

    First, let’s take a look at the Visitor Overview report. It’s a general report that breaks down the visits over a given time period.

    Visitor overview report in Matomo

    What this report shows :

    • Trends in unique visits month over month
    • Basic engagement trends like the average visit length and bounce rate
    • The number of actions taken per page

    In general, this report is more of a high-level indicator you can use to explore certain areas more thoroughly. For example, if most of your traffic comes from organic traffic or social media, you can dive deeper into those channels.

    Try Matomo for Free

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

    No credit card required

    Location report

    Next up, we have the most basic type of demographic report — the Location report. It shows where your visitors tend to access your website from.

    Location report in Matomo

    What this report shows :

    • The country, state or city your visitors access your website from

    This report is most useful for identifying regional trends. You may notice that your site is growing in popularity in a country. You can take advantage of this by creating a regional campaign to double down on a high performing audience.

    Device report

    Next, we have the Device report, which breaks down your visitors’ devices.

    Device report in Matomo analytics

    What this report shows :

    • Overall device types used by your visitors
    • Specific device models used

    Today, most websites are responsive or use mobile-first design. So, just seeing that many people access your site through smartphones probably isn’t all that surprising.

    But you should ensure your responsive design doesn’t break down on popular devices. The design may not work effectively because many phones have different screen resolutions. 

    Users Flow report

    The Users Flow report dives deeper into visitor engagement — how your visitors act on your site. It shows common landing pages — the first page visitors land on — and how they usually navigate your site from there.

    Users flow report in Matomo analytics

    What this report shows :

    • Popular landing pages
    • How your visitors most commonly navigate your site

    You can use this report to determine which intermediary pages are crucial to keeping visitors engaged. For example, you can prioritise optimisation and rewriting for case study pages that don’t get a lot of direct search or campaign traffic.

    Improving this flow can improve conversion rates and the impact of your marketing efforts.

    Try Matomo for Free

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

    No credit card required

    Exit Pages report

    The Exit Pages report complements the Users Flow report well. It highlights the most common pages visitors leave your website from.

    Exit pages report in Matomo analytics

    What this report shows :

    • The most common exit pages on your website
    • The exit rates of these pages

    Pages with high exit rates fall into two categories. The first are pages where it makes sense that visitors leave, like a post-purchase thank-you page. The second are pages where you’d want your visitors to stay and keep flowing down the funnel. When the rates are unusually high on product pages, category pages, or case study pages, you may have found a problem.

    By combining insights from the Users Flow and Exit Pages reports, you can find valuable candidates for optimisation. This is a key aspect of effective conversion rate optimisation.

    Traffic Acquisition Channel report

    The Acquisition Channels report highlights the channels that drive the most visitors to your site.

    Acquisition report in Matomo analytics

    What this report shows :

    • Top referring traffic sources by channel type
    • The average time on site, bounce rates, and actions taken by the source

    Because of increasingly privacy-sensitive browsers and apps, the best way to reliably track traffic sources is to use campaign tracking URL. Matomo offers an easy-to-use campaign tracking URL builder to simplify this process.

    Search Engines and Keywords report

    The Search Engines and Keywords report shows which keywords are driving the most organic search traffic and from what search engines.

    Search engine keyword report in Matomo analytics

    What this report shows :

    • Search engine keywords that drive traffic
    • The different search engines that refer visitors

    One of the best ways to use this report is to identify low-hanging fruit. You want to find keywords driving some traffic where your page isn’t ranked in the top three results. If the keyword has high traffic potential, you should then work to optimise that page to rank higher and get more traffic. This technique is an efficient way to improve your SEO performance.

    Ecommerce Products report

    If you sell products directly on your website, the Ecommerce Products report is a lifesaver. It shows you exactly how all your products are performing.

    Ecommerce product report in Matomo analytics

    What this report shows :

    • How your products are selling
    • The average sale price (with coupons) and quantity

    This report could help an online retailer identify top-selling items, adjust pricing based on average sale prices, and strategically allocate resources to promote or restock high-performing products for maximum profitability.

    Try Matomo for Free

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

    No credit card required

    Ecommerce Log report

    If you want to explore every single ecommerce interaction, the Ecommerce Log report is for you. It breaks down the actions of visitors who add products to their cart in real time.

    Ecommerce log report in Matomo analytics

    What this report shows :

    • The full journey of completed purchases and abandoned carts
    • The exact actions your potential customers take and how long their journeys last

    If you suspect that the user experience of your online store isn’t perfect, this report helps you confirm or deny that suspicion. By closely examining individual interactions, you can identify common exit pages or other issues.