Recherche avancée

Médias (0)

Mot : - Tags -/albums

Aucun média correspondant à vos critères n’est disponible sur le site.

Autres articles (97)

  • MediaSPIP 0.1 Beta version

    25 avril 2011, par

    MediaSPIP 0.1 beta is the first version of MediaSPIP proclaimed as "usable".
    The zip file provided here only contains the sources of MediaSPIP in its standalone version.
    To get a working installation, you must manually install all-software dependencies on the server.
    If you want to use this archive for an installation in "farm mode", you will also need to proceed to other manual (...)

  • HTML5 audio and video support

    13 avril 2011, par

    MediaSPIP uses HTML5 video and audio tags to play multimedia files, taking advantage of the latest W3C innovations supported by modern browsers.
    The MediaSPIP player used has been created specifically for MediaSPIP and can be easily adapted to fit in with a specific theme.
    For older browsers the Flowplayer flash fallback is used.
    MediaSPIP allows for media playback on major mobile platforms with the above (...)

  • ANNEXE : Les plugins utilisés spécifiquement pour la ferme

    5 mars 2010, par

    Le site central/maître de la ferme a besoin d’utiliser plusieurs plugins supplémentaires vis à vis des canaux pour son bon fonctionnement. le plugin Gestion de la mutualisation ; le plugin inscription3 pour gérer les inscriptions et les demandes de création d’instance de mutualisation dès l’inscription des utilisateurs ; le plugin verifier qui fournit une API de vérification des champs (utilisé par inscription3) ; le plugin champs extras v2 nécessité par inscription3 (...)

Sur d’autres sites (12784)

  • FFmpeg encoding produces slightly incompatible MKV/MP4 container

    11 juin 2018, par james2048

    I’ve been using the FFmpeg libraries to read and write media files using the C API.

    So far, reading seems to be pretty straightforward. I am able to read frames which I can then process, convert to RGB, process, and then convert back to YUV420 to be encoded.

    The encoded files play back with VLC media player fine, and Windows Media Player if I have a codec pack installed. However, they do behave strangely : the stock Windows 10 player won’t play them, same for Adobe Premiere. Also thumbnailers don’t work on it.
    Basically it seems like nothing other than VLC or FFmpeg itself can play/process the file. I have seen this with both MP4 and MKV, so it is not a format-specific issue.

    The problems go away once you remux the file with FFmpeg, for example "ffmpeg -i input.mkv -c copy output.mkv". Everything can play the file correctly.
    Also, the "remuxing.c" sample from the official samples works as well, with the same library version and compilers that I’m using (Visual Studio 2017, FFmpeg compiled with MinGW). It will fix the file and make it playable in all software.

    I’m not sure what could be causing this. I also don’t understand what the remuxing "fixed". It must be a container issue as the frames aren’t touched by remuxing.
    I have analysed the output MKVs with FFprobe -show_packets. It seems to have budged the packet timestamps a little constant factor, and the output stream now has
    is_avc=true and nal_length_size=4 instead of is_avc=false and nal_length_size=0, but apart from that the files are identical.

    Now here’s the output of FFprobe with the 3 last test packets, stream info and format info for both streams. As you can see, they are identical except for a couple of field. But something in here must have been "fixed" during remuxing to make it work.

    [PACKET]
    codec_type=video
    stream_index=0
    pts=59050
    pts_time=59.050000
    dts=58890
    dts_time=58.890000
    duration=1
    duration_time=0.001000
    convergence_duration=N/A
    convergence_duration_time=N/A
    size=427
    pos=277358
    flags=__
    [/PACKET]
    [PACKET]
    codec_type=video
    stream_index=0
    pts=58970
    pts_time=58.970000
    dts=58970
    dts_time=58.970000
    duration=1
    duration_time=0.001000
    convergence_duration=N/A
    convergence_duration_time=N/A
    size=205
    pos=277792
    flags=__
    [/PACKET]
    [PACKET]
    codec_type=video
    stream_index=0
    pts=59130
    pts_time=59.130000
    dts=59050
    dts_time=59.050000
    duration=1
    duration_time=0.001000
    convergence_duration=N/A
    convergence_duration_time=N/A
    size=268
    pos=278004
    flags=__
    [/PACKET]
    [STREAM]
    index=0
    codec_name=h264
    codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
    profile=Main
    codec_type=video
    codec_time_base=1/2000
    codec_tag_string=[0][0][0][0]
    codec_tag=0x0000
    width=720
    height=576
    coded_width=720
    coded_height=576
    has_b_frames=2
    sample_aspect_ratio=N/A
    display_aspect_ratio=N/A
    pix_fmt=yuv420p
    level=50
    color_range=unknown
    color_space=unknown
    color_transfer=unknown
    color_primaries=unknown
    chroma_location=left
    field_order=progressive
    timecode=N/A
    refs=1
    is_avc=false
    nal_length_size=0
    id=N/A
    r_frame_rate=299/12
    avg_frame_rate=1000/1
    time_base=1/1000
    start_pts=0
    start_time=0.000000
    duration_ts=N/A
    duration=N/A
    bit_rate=N/A
    max_bit_rate=N/A
    bits_per_raw_sample=8
    nb_frames=N/A
    nb_read_frames=N/A
    nb_read_packets=737
    DISPOSITION:default=1
    DISPOSITION:dub=0
    DISPOSITION:original=0
    DISPOSITION:comment=0
    DISPOSITION:lyrics=0
    DISPOSITION:karaoke=0
    DISPOSITION:forced=0
    DISPOSITION:hearing_impaired=0
    DISPOSITION:visual_impaired=0
    DISPOSITION:clean_effects=0
    DISPOSITION:attached_pic=0
    DISPOSITION:timed_thumbnails=0
    TAG:DURATION=00:00:59.211000000
    [/STREAM]
    [FORMAT]
    filename=testEncLeft.mkv
    nb_streams=1
    nb_programs=0
    format_name=matroska,webm
    format_long_name=Matroska / WebM
    start_time=0.000000
    duration=59.211000
    size=278349
    bit_rate=37607
    probe_score=100
    TAG:COMMENT=Slickline Player Export
    TAG:ENCODER=Lavf57.83.100
    [/FORMAT]

    And the info after remuxing, which works :

    [PACKET]
    codec_type=video
    stream_index=0
    pts=59050
    pts_time=59.050000
    dts=58890
    dts_time=58.890000
    duration=1
    duration_time=0.001000
    convergence_duration=N/A
    convergence_duration_time=N/A
    size=427
    pos=277418
    flags=__
    [/PACKET]
    [PACKET]
    codec_type=video
    stream_index=0
    pts=58970
    pts_time=58.970000
    dts=58970
    dts_time=58.970000
    duration=1
    duration_time=0.001000
    convergence_duration=N/A
    convergence_duration_time=N/A
    size=205
    pos=277852
    flags=__
    [/PACKET]
    [PACKET]
    codec_type=video
    stream_index=0
    pts=59130
    pts_time=59.130000
    dts=59050
    dts_time=59.050000
    duration=1
    duration_time=0.001000
    convergence_duration=N/A
    convergence_duration_time=N/A
    size=268
    pos=278064
    flags=__
    [/PACKET]
    [STREAM]
    index=0
    codec_name=h264
    codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
    profile=Main
    codec_type=video
    codec_time_base=1/2000
    codec_tag_string=[0][0][0][0]
    codec_tag=0x0000
    width=720
    height=576
    coded_width=720
    coded_height=576
    has_b_frames=2
    sample_aspect_ratio=N/A
    display_aspect_ratio=N/A
    pix_fmt=yuv420p
    level=50
    color_range=unknown
    color_space=unknown
    color_transfer=unknown
    color_primaries=unknown
    chroma_location=left
    field_order=progressive
    timecode=N/A
    refs=1
    is_avc=true
    nal_length_size=4
    id=N/A
    r_frame_rate=299/12
    avg_frame_rate=1000/1
    time_base=1/1000
    start_pts=0
    start_time=0.000000
    duration_ts=N/A
    duration=N/A
    bit_rate=N/A
    max_bit_rate=N/A
    bits_per_raw_sample=8
    nb_frames=N/A
    nb_read_frames=N/A
    nb_read_packets=737
    DISPOSITION:default=1
    DISPOSITION:dub=0
    DISPOSITION:original=0
    DISPOSITION:comment=0
    DISPOSITION:lyrics=0
    DISPOSITION:karaoke=0
    DISPOSITION:forced=0
    DISPOSITION:hearing_impaired=0
    DISPOSITION:visual_impaired=0
    DISPOSITION:clean_effects=0
    DISPOSITION:attached_pic=0
    DISPOSITION:timed_thumbnails=0
    TAG:DURATION=00:00:59.212000000
    [/STREAM]
    [FORMAT]
    filename=fixedLeft.mkv
    nb_streams=1
    nb_programs=0
    format_name=matroska,webm
    format_long_name=Matroska / WebM
    start_time=0.000000
    duration=59.212000
    size=278409
    bit_rate=37615
    probe_score=100
    TAG:COMMENT=Slickline Player Export
    TAG:ENCODER=Lavf58.12.100
    [/FORMAT]

    Here is how I’m setting up the output context, for reference : it’s pretty standard, following the sample code.

    int ret;

    avformat_alloc_output_context2(&outputFormatCtx, nullptr, nullptr, outFilePath.c_str());

    av_dict_set(&outputFormatCtx->metadata, "comment", "FFmpeg Export", 0);

    if (!outputFormatCtx)
    {
       LOG_AND_THROW("Could not allocate output context");
    }

    outputVideoStream = avformat_new_stream(outputFormatCtx, nullptr);
    outputVideoStream->time_base = AVRational{ 1, AV_TIME_BASE }; // Stream timebase will be used by codec

    if (!outputVideoStream)
    {
       LOG_AND_THROW("Failed allocating output stream");
    }

    // defaults to "libx264"
    AVCodec *outCodec = avcodec_find_encoder_by_name(selectedCodecName.c_str());

    if (!outCodec)
    {
       LOG_AND_THROW("Failed finding output codec");
    }

    AVDictionary *opts = nullptr;

    if (selectedCodecName == "libx264")
    {
       opts = getX264CodecOptions();
    }

    encoderCtx = avcodec_alloc_context3(outCodec);

    if (!encoderCtx)
    {
       LOG_AND_THROW("Failed to allocate the encoder context");
    }

    encoderCtx->width = width;
    encoderCtx->height = height;
    encoderCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    // time base for the frames we will provide to the encoder
    encoderCtx->time_base = AVRational{ 1, AV_TIME_BASE };
    // convert framerate from double to rational
    encoderCtx->framerate = AVRational{ (int)(frameRate * AV_TIME_BASE), AV_TIME_BASE};

    // Match encoderCtx time base for the stream
    outputVideoStream->time_base = encoderCtx->time_base;

    ret = avcodec_open2(encoderCtx, outCodec, &opts);

    if (ret < 0)
    {
       LOG_AND_THROW_PARAM("Cannot open video encoder for stream: %d", ret);
    }

    // Fill in some params for MP4 stream, details about encoder
    ret = avcodec_parameters_from_context(outputVideoStream->codecpar, encoderCtx);

    if (ret < 0)
    {
       LOG_AND_THROW_PARAM("Failed to copy encoder parameters to output stream: %d", ret);
    }

    if (outputFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
    {
       encoderCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }

    av_dump_format(outputFormatCtx, 0, filePath.c_str(), 1);

    // End of encoder settings, setting up MP4
    if (!(outputFormatCtx->oformat->flags & AVFMT_NOFILE))
    {
       ret = avio_open(&outputFormatCtx->pb, outFilePath.c_str(), AVIO_FLAG_WRITE);

       if (ret < 0)
       {
           LOG_AND_THROW_PARAMSTR("Could not open output file '%s'", outFilePath.c_str());
       }
    }

    ret = avformat_write_header(outputFormatCtx, nullptr);

    if (ret < 0)
    {
       LOG_AND_THROW_PARAM("Error occurred when opening output file for writing: %d", ret);
    }

    Can anyone help me figure out why the container is not playing properly ?

    Thanks in advance.

    -James

  • How to generate a fixed duration and fps for a video using FFmpeg C++ libraries ? [closed]

    4 novembre 2024, par BlueSky Light Programmer

    I'm following the mux official example to write a C++ class that generates a video with a fixed duration (5s) and a fixed fps (60). For some reason, the duration of the output video is 3-4 seconds, although I call the function to write frames 300 times and set the fps to 60.

    


    Can you take a look at the code below and spot what I'm doing wrong ?

    


    #include "ffmpeg.h"&#xA;&#xA;#include <iostream>&#xA;&#xA;static int writeFrame(AVFormatContext *fmt_ctx, AVCodecContext *c,&#xA;                      AVStream *st, AVFrame *frame, AVPacket *pkt);&#xA;&#xA;static void addStream(OutputStream *ost, AVFormatContext *formatContext,&#xA;                      const AVCodec **codec, enum AVCodecID codec_id,&#xA;                      int width, int height, int fps);&#xA;&#xA;static AVFrame *allocFrame(enum AVPixelFormat pix_fmt, int width, int height);&#xA;&#xA;static void openVideo(AVFormatContext *formatContext, const AVCodec *codec,&#xA;                      OutputStream *ost, AVDictionary *opt_arg);&#xA;&#xA;static AVFrame *getVideoFrame(OutputStream *ost,&#xA;                              const std::vector<glubyte>&amp; pixels,&#xA;                              int duration);&#xA;&#xA;static int writeVideoFrame(AVFormatContext *formatContext,&#xA;                           OutputStream *ost,&#xA;                           const std::vector<glubyte>&amp; pixels,&#xA;                           int duration);&#xA;&#xA;static void closeStream(AVFormatContext *formatContext, OutputStream *ost);&#xA;&#xA;static void fillRGBImage(AVFrame *frame, int width, int height,&#xA;                         const std::vector<glubyte>&amp; pixels);&#xA;&#xA;#ifdef av_err2str&#xA;#undef av_err2str&#xA;#include <string>&#xA;av_always_inline std::string av_err2string(int errnum) {&#xA;  char str[AV_ERROR_MAX_STRING_SIZE];&#xA;  return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum);&#xA;}&#xA;#define av_err2str(err) av_err2string(err).c_str()&#xA;#endif  // av_err2str&#xA;&#xA;FFmpeg::FFmpeg(int width, int height, int fps, const char *fileName)&#xA;: videoStream{ 0 }&#xA;, formatContext{ nullptr } {&#xA;  const AVOutputFormat *outputFormat;&#xA;  const AVCodec *videoCodec{ nullptr };&#xA;  AVDictionary *opt{ nullptr };&#xA;  int ret{ 0 };&#xA;&#xA;  av_dict_set(&amp;opt, "crf", "17", 0);&#xA;&#xA;  /* Allocate the output media context. */&#xA;  avformat_alloc_output_context2(&amp;this->formatContext, nullptr, nullptr, fileName);&#xA;  if (!this->formatContext) {&#xA;    std::cout &lt;&lt; "Could not deduce output format from file extension: using MPEG." &lt;&lt; std::endl;&#xA;    avformat_alloc_output_context2(&amp;this->formatContext, nullptr, "mpeg", fileName);&#xA;  &#xA;    if (!formatContext)&#xA;      exit(-14);&#xA;  }&#xA;&#xA;  outputFormat = this->formatContext->oformat;&#xA;&#xA;  /* Add the video stream using the default format codecs&#xA;   * and initialize the codecs. */&#xA;  if (outputFormat->video_codec == AV_CODEC_ID_NONE) {&#xA;    std::cout &lt;&lt; "The output format doesn&#x27;t have a default codec video." &lt;&lt; std::endl;&#xA;    exit(-15);&#xA;  }&#xA;&#xA;  addStream(&#xA;    &amp;this->videoStream,&#xA;    this->formatContext,&#xA;    &amp;videoCodec,&#xA;    outputFormat->video_codec,&#xA;    width,&#xA;    height,&#xA;    fps&#xA;  );&#xA;  openVideo(this->formatContext, videoCodec, &amp;this->videoStream, opt);&#xA;  av_dump_format(this->formatContext, 0, fileName, 1);&#xA;  &#xA;  /* open the output file, if needed */&#xA;  if (!(outputFormat->flags &amp; AVFMT_NOFILE)) {&#xA;    ret = avio_open(&amp;this->formatContext->pb, fileName, AVIO_FLAG_WRITE);&#xA;    if (ret &lt; 0) {&#xA;      std::cout &lt;&lt; "Could not open &#x27;" &lt;&lt; fileName &lt;&lt; "&#x27;: " &lt;&lt; std::string{ av_err2str(ret) } &lt;&lt; std::endl;&#xA;      exit(-16);&#xA;    }&#xA;  }&#xA;&#xA;  /* Write the stream header, if any. */&#xA;  ret = avformat_write_header(this->formatContext, &amp;opt);&#xA;  if (ret &lt; 0) {&#xA;    std::cout &lt;&lt; "Error occurred when opening output file: " &lt;&lt; av_err2str(ret) &lt;&lt; std::endl;&#xA;    exit(-17);&#xA;  }&#xA;&#xA;  av_dict_free(&amp;opt);&#xA;}&#xA;&#xA;FFmpeg::~FFmpeg() {&#xA;  if (this->formatContext) {&#xA;    /* Close codec. */&#xA;    closeStream(this->formatContext, &amp;this->videoStream);&#xA;&#xA;    if (!(this->formatContext->oformat->flags &amp; AVFMT_NOFILE)) {&#xA;      /* Close the output file. */&#xA;      avio_closep(&amp;this->formatContext->pb);&#xA;    }&#xA;&#xA;    /* free the stream */&#xA;    avformat_free_context(this->formatContext);&#xA;  }&#xA;}&#xA;&#xA;void FFmpeg::Record(&#xA;  const std::vector<glubyte>&amp; pixels,&#xA;  unsigned frameIndex,&#xA;  int duration,&#xA;  bool isLastIndex&#xA;) {&#xA;  static bool encodeVideo{ true };&#xA;  if (encodeVideo)&#xA;    encodeVideo = !writeVideoFrame(this->formatContext,&#xA;                                   &amp;this->videoStream,&#xA;                                   pixels,&#xA;                                   duration);&#xA;&#xA;  if (isLastIndex) {&#xA;    av_write_trailer(this->formatContext);&#xA;    encodeVideo = false;&#xA;  }&#xA;}&#xA;&#xA;int writeFrame(AVFormatContext *fmt_ctx, AVCodecContext *c,&#xA;               AVStream *st, AVFrame *frame, AVPacket *pkt) {&#xA;  int ret;&#xA;&#xA;  // send the frame to the encoder&#xA;  ret = avcodec_send_frame(c, frame);&#xA;  if (ret &lt; 0) {&#xA;    std::cout &lt;&lt; "Error sending a frame to the encoder: " &lt;&lt; av_err2str(ret) &lt;&lt; std::endl;&#xA;    exit(-2);&#xA;  }&#xA;&#xA;  while (ret >= 0) {&#xA;    ret = avcodec_receive_packet(c, pkt);&#xA;    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)&#xA;      break;&#xA;    else if (ret &lt; 0) {&#xA;      std::cout &lt;&lt; "Error encoding a frame: " &lt;&lt; av_err2str(ret) &lt;&lt; std::endl;&#xA;      exit(-3);&#xA;    }&#xA;&#xA;    /* rescale output packet timestamp values from codec to stream timebase */&#xA;    av_packet_rescale_ts(pkt, c->time_base, st->time_base);&#xA;    pkt->stream_index = st->index;&#xA;&#xA;    /* Write the compressed frame to the media file. */&#xA;    ret = av_interleaved_write_frame(fmt_ctx, pkt);&#xA;    /* pkt is now blank (av_interleaved_write_frame() takes ownership of&#xA;     * its contents and resets pkt), so that no unreferencing is necessary.&#xA;     * This would be different if one used av_write_frame(). */&#xA;    if (ret &lt; 0) {&#xA;      std::cout &lt;&lt; "Error while writing output packet: " &lt;&lt; av_err2str(ret) &lt;&lt; std::endl;&#xA;      exit(-4);&#xA;    }&#xA;  }&#xA;&#xA;  return ret == AVERROR_EOF ? 1 : 0;&#xA;}&#xA;&#xA;void addStream(OutputStream *ost, AVFormatContext *formatContext,&#xA;               const AVCodec **codec, enum AVCodecID codec_id,&#xA;               int width, int height, int fps) {&#xA;  AVCodecContext *c;&#xA;  int i;&#xA;&#xA;  /* find the encoder */&#xA;  *codec = avcodec_find_encoder(codec_id);&#xA;  if (!(*codec)) {&#xA;    std::cout &lt;&lt; "Could not find encoder for " &lt;&lt; avcodec_get_name(codec_id) &lt;&lt; "." &lt;&lt; std::endl;&#xA;    exit(-5);&#xA;  }&#xA;&#xA;  ost->tmpPkt = av_packet_alloc();&#xA;  if (!ost->tmpPkt) {&#xA;    std::cout &lt;&lt; "Could not allocate AVPacket." &lt;&lt; std::endl;&#xA;    exit(-6);&#xA;  }&#xA;&#xA;  ost->st = avformat_new_stream(formatContext, nullptr);&#xA;  if (!ost->st) {&#xA;    std::cout &lt;&lt; "Could not allocate stream." &lt;&lt; std::endl;&#xA;    exit(-7);&#xA;  }&#xA;&#xA;  ost->st->id = formatContext->nb_streams-1;&#xA;  c = avcodec_alloc_context3(*codec);&#xA;  if (!c) {&#xA;    std::cout &lt;&lt; "Could not alloc an encoding context." &lt;&lt; std::endl;&#xA;    exit(-8);&#xA;  }&#xA;  ost->enc = c;&#xA;&#xA;  switch ((*codec)->type) {&#xA;  case AVMEDIA_TYPE_VIDEO:&#xA;    c->codec_id = codec_id;&#xA;    c->bit_rate = 6000000;&#xA;    /* Resolution must be a multiple of two. */&#xA;    c->width    = width;&#xA;    c->height   = height;&#xA;    /* timebase: This is the fundamental unit of time (in seconds) in terms&#xA;      * of which frame timestamps are represented. For fixed-fps content,&#xA;      * timebase should be 1/framerate and timestamp increments should be&#xA;      * identical to 1. */&#xA;    ost->st->time_base = { 1, fps };&#xA;    c->time_base       = ost->st->time_base;&#xA;    c->framerate       = { fps, 1 };&#xA;&#xA;    c->gop_size      = 0; /* emit one intra frame every twelve frames at most */&#xA;    c->pix_fmt       = AV_PIX_FMT_YUV420P;&#xA;    if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {&#xA;      /* just for testing, we also add B-frames */&#xA;      c->max_b_frames = 2;&#xA;    }&#xA;    if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {&#xA;      /* Needed to avoid using macroblocks in which some coeffs overflow.&#xA;      *  This does not happen with normal video, it just happens here as&#xA;      *  the motion of the chroma plane does not match the luma plane.*/&#xA;      c->mb_decision = 2;&#xA;    }&#xA;    break;&#xA;&#xA;  default:&#xA;    break;&#xA;  }&#xA;&#xA;  /* Some formats want stream headers to be separate. */&#xA;  if (formatContext->oformat->flags &amp; AVFMT_GLOBALHEADER)&#xA;    c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;&#xA;}&#xA;&#xA;AVFrame *allocFrame(enum AVPixelFormat pix_fmt, int width, int height) {&#xA;  AVFrame *frame{ av_frame_alloc() };&#xA;  int ret;&#xA;&#xA;  if (!frame)&#xA;    return nullptr;&#xA;&#xA;  frame->format = pix_fmt;&#xA;  frame->width  = width;&#xA;  frame->height = height;&#xA;&#xA;  /* allocate the buffers for the frame data */&#xA;  ret = av_frame_get_buffer(frame, 0);&#xA;  if (ret &lt; 0) {&#xA;    std::cout &lt;&lt; "Could not allocate frame data." &lt;&lt; std::endl;&#xA;    exit(-8);&#xA;  }&#xA;&#xA;  return frame;&#xA;}&#xA;&#xA;void openVideo(AVFormatContext *formatContext, const AVCodec *codec,&#xA;               OutputStream *ost, AVDictionary *opt_arg) {&#xA;  int ret;&#xA;  AVCodecContext *c{ ost->enc };&#xA;  AVDictionary *opt{ nullptr };&#xA;&#xA;  av_dict_copy(&amp;opt, opt_arg, 0);&#xA;&#xA;  /* open the codec */&#xA;  ret = avcodec_open2(c, codec, &amp;opt);&#xA;  av_dict_free(&amp;opt);&#xA;  if (ret &lt; 0) {&#xA;    std::cout &lt;&lt; "Could not open video codec: " &lt;&lt; av_err2str(ret) &lt;&lt; std::endl;&#xA;    exit(-9);&#xA;  }&#xA;&#xA;  /* Allocate and init a re-usable frame. */&#xA;  ost->frame = allocFrame(c->pix_fmt, c->width, c->height);&#xA;  if (!ost->frame) {&#xA;    std::cout &lt;&lt; "Could not allocate video frame." &lt;&lt; std::endl;&#xA;    exit(-10);&#xA;  }&#xA;&#xA;  /* If the output format is not RGB24, then a temporary RGB24&#xA;   * picture is needed too. It is then converted to the required&#xA;   * output format. */&#xA;  ost->tmpFrame = nullptr;&#xA;  if (c->pix_fmt != AV_PIX_FMT_RGB24) {&#xA;    ost->tmpFrame = allocFrame(AV_PIX_FMT_RGB24, c->width, c->height);&#xA;    if (!ost->tmpFrame) {&#xA;      std::cout &lt;&lt; "Could not allocate temporary video frame." &lt;&lt; std::endl;&#xA;      exit(-11);&#xA;    }&#xA;  }&#xA;&#xA;  /* Copy the stream parameters to the muxer. */&#xA;  ret = avcodec_parameters_from_context(ost->st->codecpar, c);&#xA;  if (ret &lt; 0) {&#xA;    std::cout &lt;&lt; "Could not copy the stream parameters." &lt;&lt; std::endl;&#xA;    exit(-12);&#xA;  }&#xA;}&#xA;&#xA;AVFrame *getVideoFrame(OutputStream *ost,&#xA;                       const std::vector<glubyte>&amp; pixels,&#xA;                       int duration) {&#xA;  AVCodecContext *c{ ost->enc };&#xA;&#xA;  /* check if we want to generate more frames */&#xA;  if (av_compare_ts(ost->nextPts, c->time_base,&#xA;                    duration, { 1, 1 }) > 0) {&#xA;    return nullptr;&#xA;  }&#xA;&#xA;  /* when we pass a frame to the encoder, it may keep a reference to it&#xA;    * internally; make sure we do not overwrite it here */&#xA;  if (av_frame_make_writable(ost->frame) &lt; 0) {&#xA;    std::cout &lt;&lt; "It wasn&#x27;t possible to make frame writable." &lt;&lt; std::endl;&#xA;    exit(-12);&#xA;  }&#xA;&#xA;  if (c->pix_fmt != AV_PIX_FMT_RGB24) {&#xA;      /* as we only generate a YUV420P picture, we must convert it&#xA;        * to the codec pixel format if needed */&#xA;      if (!ost->swsContext) {&#xA;        ost->swsContext = sws_getContext(c->width, c->height,&#xA;                                         AV_PIX_FMT_RGB24,&#xA;                                         c->width, c->height,&#xA;                                         c->pix_fmt,&#xA;                                         SWS_BICUBIC, nullptr, nullptr, nullptr);&#xA;        if (!ost->swsContext) {&#xA;          std::cout &lt;&lt; "Could not initialize the conversion context." &lt;&lt; std::endl;&#xA;          exit(-13);&#xA;        }&#xA;      }&#xA;&#xA;      fillRGBImage(ost->tmpFrame, c->width, c->height, pixels);&#xA;      sws_scale(ost->swsContext, (const uint8_t * const *) ost->tmpFrame->data,&#xA;                ost->tmpFrame->linesize, 0, c->height, ost->frame->data,&#xA;                ost->frame->linesize);&#xA;  } else&#xA;    fillRGBImage(ost->frame, c->width, c->height, pixels);&#xA;&#xA;  ost->frame->pts = ost->nextPts&#x2B;&#x2B;;&#xA;&#xA;  return ost->frame;&#xA;}&#xA;&#xA;int writeVideoFrame(AVFormatContext *formatContext,&#xA;                    OutputStream *ost,&#xA;                    const std::vector<glubyte>&amp; pixels,&#xA;                    int duration) {&#xA;  return writeFrame(formatContext,&#xA;                    ost->enc,&#xA;                    ost->st,&#xA;                    getVideoFrame(ost, pixels, duration),&#xA;                    ost->tmpPkt);&#xA;}&#xA;&#xA;void closeStream(AVFormatContext *formatContext, OutputStream *ost) {&#xA;  avcodec_free_context(&amp;ost->enc);&#xA;  av_frame_free(&amp;ost->frame);&#xA;  av_frame_free(&amp;ost->tmpFrame);&#xA;  av_packet_free(&amp;ost->tmpPkt);&#xA;  sws_freeContext(ost->swsContext);&#xA;}&#xA;&#xA;static void fillRGBImage(AVFrame *frame, int width, int height,&#xA;                         const std::vector<glubyte>&amp; pixels) {&#xA;  // Copy pixel data into the frame&#xA;  int inputLineSize{ 3 * width };  // 3 bytes per pixel for RGB&#xA;  for (int y{ 0 }; y &lt; height; &#x2B;&#x2B;y) {&#xA;    memcpy(frame->data[0] &#x2B; y * frame->linesize[0],&#xA;           pixels.data() &#x2B; y * inputLineSize,&#xA;           inputLineSize);&#xA;  }&#xA;}&#xA;</glubyte></glubyte></glubyte></glubyte></string></glubyte></glubyte></glubyte></iostream>

    &#xA;

  • Exceeded GA’s 10M hits data limit, now what ?

    21 juin 2019, par Joselyn Khor

    Exceeded GA’s 10M hits data limit, now what ? Matomo has the answers

    “Your data volume (1XXM hits) exceeds the limit of 10M hits per month as outlined in our Terms of Service. If you continue to exceed the limit, we will stop processing new data on XXX 21, 2019. Learn more about possible solutions.”

    Yikes. Alarm bells were ringing when a Google Analytics free user came to us faced with this notice. Let’s call him ‘Mark’. Mark had reached the limits on the data he could collect through Google Analytics and was shocked by the limited options available to fix the problem, without blowing the budget. The thoughts racing through his head were :

    • “What happens to all my data ?”
    • “What if Google starts charging USD150K now ?”

    Then he came across Matomo and decided to get in touch with our support team …

    “Can you fix this issue ?” he asked us.

    “Absolutely !” we said.

    We’ll get back to helping Mark in a minute. For now let’s go over why this was such a dilemma for him.

    In order to resolve this data limits issue, one of the solutions was for him to upgrade to Google Analytics 360, which meant shelling out USD150,000 per year for their 1 billion hits per month option. Going from free to USD150,000 was too much of a stretch for a growing company.

    “Your data volume (1XXM hits) exceeds the limit of 10M hits per month …”, what did this message mean ?

    With the free version, Mark could collect up to 10 million “hits” per month, per account. Going over meant Google Analytics could stop collecting any more data for free as outlined in their Terms.

    Google Analytics’ Terms of Service (2018, sec. 2) states, “Subject to Section 15, the Service is provided without charge to You for up to 10 million Hits per month per account.”[1]

    In general, what’s a "hit" ?

    Data being sent to Google Analytics. It can be a transaction, event, social interaction or pageview - these all produce what Google calls a “hit”.

    Google Analytics data limits
    Google Analytics Terms of Service

    And their Analytics Help Data Limits (n.d.) support page makes clear that : “If a property sends more hits per month to Analytics than allowed by the Analytics Terms of Service, there is no assurance that the excess hits will be processed. If the property’s hit volume exceeds this limit, a warning may be displayed in the user interface and you may be prevented from accessing reports.”[2]

    Google Analytics data collection limit
    Google Analytics’ data limits support page

    Possible solutions

    So the possible solutions given by Google Analytics’ Data Limits support page were (also shown in image below) :

    • To pay USD150K to upgrade to Google Analytics 360
    • To send fewer hits by setting up sampling
    • Or choose the slightly less relevant option to upgrade mobile app tracking to Google Analytics for Firebase.

    Without the means to pay, the free version was fast becoming inaccessible for Mark as he was facing a future where he risked no longer having access to up-to-date data used in his business’ reporting.

    Mark was facing a problem that potentially didn’t have a cost-effective solution.

    Google Analytics data limits
    Google Analytics’ data limits support page

    So what can you really do about it ?

    This is where we can help provide some assistance. If you’re reading this article, we’ll assume you can relate to Mark and share with you the advice on options we gave him.

    Options :

    One option posed by Google is for you to send fewer hits by auditing your data collection processes

    If you really don’t have the budget, you’ll need to reassess your data collection priorities and go over your strategies to see what is necessary to track, and what isn’t.

    • Make sure you know what you’re tracking and why. Look at what websites are being tracked by Google and into what properties.
    • Go through what data you’re tracking and decide what is or isn’t of value.
    • Set up data sampling, this however, will lead to inaccurate data.

    From here you can start to course correct. If you’ve found data you’re not using for analysis, get rid of these events/pageviews in your Google Analytics.

    But the limitations here are that eventually, you’re going to run out of irrelevant metrics and everything you’re tracking will be essential. So you’ll hit another brick wall and return to the same situation.

    Option 2 Ignore and continue using the free version of Google Analytics

    With this option, you’ll have to bear the business risks involved by basing decisions off of analytics reports that may or may not be updated. In this case, you may still get contacted about exceeding the limits. As the free service is provided for only up to 10 million hits, once you’ve gone over them, you’re violating what’s stipulated in the Terms of Service. 

    There’s also the warning that “… you may be prevented from accessing reports” (Data limits, n.d.). So while we may not know for certain what Google Analytics will do, in this case it may be better to be safe rather than sorry by acting quickly to resolve it. 

    Option 3 The Matomo solution. Upgrade to a web analytics platform that can handle your demanding data requirements

    Save money while continuing to gain valuable insights by moving over to Matomo Analytics (recommended)

    This is where you can save up to USD130,000 a year. As well as that, the transition from Google Analytics to the Matomo Cloud is a seamless experience as setup and maintenance is taken care of by our experts.

    For example, you can get up to 15M pageviews for USD1,612.50/month (or USD19,350/year) on the Essentials plan.

    Or even 25M pageviews for USD2400/month (or USD24000/year) on the Business plan – which offers additional web analytics and conversion optimization resources.

    Matomo Cloud is a great option if you’re looking for a secure, cost-effective and powerful analytics solution. You also get what Google Analytics could never offer you : full control and ownership of your own data and privacy. 

    No need to worry about losing your Google Analytics data because …

    Now you can import your historic Google Analytics data directly into your Matomo with the Google Analytics Importer tool. Simply follow the step-by-step guide to get started for free.

    Along with savings you can get :

    • A solution for the data limits issue forever. You choose the right plan to suit your data needs and adapt as you continue growing
    • 100% accurate data (no data sampling)
    • 100% data ownership of all your information without signing away your data to a third party
    • Powerful web analytics and conversion optimization features
    • Matomo Tag Manager
    • Easy setup
    • Support from Matomo’s specialists

    Learn more about Matomo Cloud pricing.

    Or go for Matomo On-Premise

    If you have the in-house infrastructure to support self-hosting Matomo on your own servers then there’s also the option of Matomo On-Premise. Here you’ll get full security knowing the data is on your own servers. 

    Setup will also require technical knowledge. There will also be costs associated with acquiring your own servers, and keeping up with regular maintenance and updates. With On-Premise you get maximum flexibility, with no data limits whatsoever. But if you’re coming over from Google Analytics and don’t have the infrastructure and team to host On-Premise, the Matomo Cloud could be right for you.

    Learn more about Matomo On-Premise.

    Where do you go from here ?

    Getting 10 millions hits per month is no small feat, it’s actually pretty fantastic. But if it means having to shell out USD150,000 just to be able to continue with Google Analytics, we feel your problem could be fixed with Matomo Cloud. You could then put the rest of the money you save to better use.

    If you choose Matomo, you now have the option to : 

    • Raise your data limits for a fraction of Google Analytics 360’s price
    • Get a comprehensive range of analytics features for the most impactful insights to ensure your website continues excelling
    • Get data that’s not sampled – meaning 100% accuracy in your reports
    • Migrate your data easily with the help of Matomo’s support team

    We’ll have you covered. 

    By sharing with you the options and advice we gave to Mark, we hope you’ll be able to find a solution that makes your life easier and solves the issue of data restrictions forever.

    The team at Matomo is here to help you every step of the way to ensure a stress-free transition from Google Analytics if that is what works best for you.

    For next steps, why not check out our pricing page to see what could suit your needs !

    References :

    [1] Terms of Service. (2018, July 24). In Google Analytics Terms of Service. Retrieved June 12, 2019, from https://www.google.com/analytics/terms/us.html

    [2] Data limits. (n.d.). In Analytics Help Data limits. Retrieved June 12, 2019, from https://support.google.com/analytics/answer/1070983?hl=en