Recherche avancée

Médias (1)

Mot : - Tags -/book

Autres articles (52)

  • Support de tous types de médias

    10 avril 2011

    Contrairement à beaucoup de logiciels et autres plate-formes modernes de partage de documents, MediaSPIP a l’ambition de gérer un maximum de formats de documents différents qu’ils soient de type : images (png, gif, jpg, bmp et autres...) ; audio (MP3, Ogg, Wav et autres...) ; vidéo (Avi, MP4, Ogv, mpg, mov, wmv et autres...) ; contenu textuel, code ou autres (open office, microsoft office (tableur, présentation), web (html, css), LaTeX, Google Earth) (...)

  • 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 (...)

  • Support audio et vidéo HTML5

    10 avril 2011

    MediaSPIP utilise les balises HTML5 video et audio pour la lecture de documents multimedia en profitant des dernières innovations du W3C supportées par les navigateurs modernes.
    Pour les navigateurs plus anciens, le lecteur flash Flowplayer est utilisé.
    Le lecteur HTML5 utilisé a été spécifiquement créé pour MediaSPIP : il est complètement modifiable graphiquement pour correspondre à un thème choisi.
    Ces technologies permettent de distribuer vidéo et son à la fois sur des ordinateurs conventionnels (...)

Sur d’autres sites (5473)

  • How to increase conversions to meet your business goals

    8 septembre 2020, par Joselyn Khor — Analytics Tips, Marketing

     Through optimizing your messaging, content, or your page layouts, you can increase conversions by getting your visitors through a clear pathway to achieve your business goals.

    Conversion Rate Optimization

    When we talk about optimizing websites to improve and increase conversions, we’re really talking about conversion rate optimization (CRO).

    CRO is the process of learning what the most valuable content/aspect of your website is and how to best optimize this for your visitors to increase its chance to convert. It typically involves generating ideas for elements on your site or app that can be improved, learning which pathways visitors are most likely going to take to conversion and then validating those assumptions through A/B testing and multivariate testing to transform learning into actionable insights.

    Conversion Rate

    The conversion rate is expressed as a % and the goal for any business should be to increase the % of conversions for any given goal e.g. in February a website had 200 newsletter sign-ups from 1,000 visitors on its sign-up page, a conversion rate of 20%. CRO should be used to increase the sign-up rate from 20% to 25%, and then eventually from 25% to 30% and so on.

    CRO cheat sheet

    You need to consider your website or business’ objectives (bigger picture) as well as your website goals (smaller achievements). Whatever the aim of your website, it’s crucial for this to be your starting point. Figure out what you want your website to do and what you want visitors to get from it. When you do that, you’ll know what conversions to focus on.
    • Define your business/website’s objectives. Do you want the website to drive sales ? Is the website a hub to raise awareness for a charity ? Do you want to increase readership for your news site ?
    • Define what your conversion goals are. This helps you narrow your focus so you follow a path to meet your overall objectives. By defining these, you clarify for yourself the next actions you should take, such as wanting to funnel users through to a sign up landing page. Then you’ll need to optimize and test your sign up landing page. If conversions are low, then tweak it and measure the results until you find you’ve increased conversion rates.
    • Conversion goals can include :
      • Purchases in your ecommerce store
      • eBook downloads
      • Sign ups to your mailing list
      • Visitors successfully filling in a contact form
    • Figure out what your Key Performance Indicators (KPIs) are and the metrics you need to focus on to achieve them.

    1. Set goals

    “Make Sure Goals Are Clearly Understood. To prove the value of an analytics-focused company, any project you take on needs to have clear goals. If you don’t have a goal in mind you’ll fail. Everyone involved in the project needs to be aligned around the goals.”

    - Lean Analytics : Use Data to Build a Better Startup Faster

    A goal is the measure of a successful action that you want your visitors to take. The more goals you track, the more you can learn about behavioural changes as you implement and modify paths that lead to conversions over time.

    Matomo goal feature

    You’ll understand which channels and campaigns (SEO, PPC, newsletter, blogging etc.) are converting the best for your business, which cities/countries are most popular, what devices are working and how engaged your visitors are before converting. Learn more

    2. Set Heatmaps

    This is vital to show how your visitors are engaging with your website, blog pages, signup and sales pages. If you want to learn how your visitors really engage with your website to increase conversions, Heatmaps lets you see the results visually without any guesswork.

    Matomo's heatmaps feature

    By showing where your visitors try to click, move the mouse or how far down they’re scrolling on each page, you can effortlessly discover how your visitors truly engage with your most important web pages. Rather than guessing, rely on facts to prove if the changes you make actually improve your website or not. Learn more

    How to improve conversion rates with Heatmaps :

    • If you’ve got important information that will sell your service/product or bring you loyal followers, make sure it’s in the hot zones as shown in your heatmaps.
    • Try to rearrange parts of your pages to see if that increases engagement.
    • Make it easy for people to take important actions by having the CTA above-the-fold where 100% of visitors see it. Make sure you don’t clutter this section with too many messages or actions.
    • You can also identify areas to add links as heatmaps shows where people want to click.
    • Find what content is most popular on the page

    3. Session Recordings

    This is a conversion research technique where you learn what your users are trying to do and make sure your website is optimized to give them what they want. With Session Recordings you can playback all the interactions your visitors took on your website, such as clicks, mouse movements, scrolls, resizes, form interactions and page changes in a video. Truly understand how real visitors are using your website and what experiences they’re having.

    Also, by understanding what’s working you’re increasing the usability of your website, Session Recordings allow you to identify problem areas as well as where users are getting stuck. Learn more

    Session Recordings

    How to improve conversion rates with Session Recordings : For example, on a product landing page, you see your visitor highlighting specific words and putting it into search. With this you can observe what they’re trying to find and what they’re actually interested in. As you tweak the page to ensure what the visitor wants can be easily found, you’re taking steps to increase the chance for more conversions.

    4. A/B Testing

    Test anything and test anywhere to increase your conversions. Grow your website by comparing different versions of your landing pages to determine what works best for your users. Subtle tweaks across different versions of your landing pages can have a significant impact on converting incoming traffic.

    Matomo's a/b testing feature

    The changes for each landing page could be :

    • A different headline
    • Less copy vs more copy
    • Different calls-to-action
    • Colour schemes, forms, fonts, links, testimonials,
    • Or, it could be an entirely different page layout altogether.

    The idea is to see if either page A or page B (or C or D) was most successful in getting your visitors to the next step in the conversion funnel. Learn more

    How Matomo used A/B Testing : For our sign up page we tested three different CTAs and found how phrasing words differently could help improve conversion rates. Both “Start improving your websites” and “Start converting more users now” were stronger CTAs and converted 7% more than, “Start my free 30-day trial”.

    5. Form Analytics

    Form Analytics gives you powerful insights into how your visitors interact with your forms (like cart, sign-up and checkout forms).

    Form Analytics

    Online forms can come in thousands of different variations. It’s an area on your website that if not done right, could lead to you missing out on converting a large portion of your visitors. Rely on facts when you change your forms. Learn more

    How to improve conversion rates with Form Analytics : By proving whether your form is doing better when you change it and by how much. This lets you consistently increase form submission rates (conversions) on your website which is crucial to the success of your business.

    6. Funnels

    At a glance you will learn the steps (actions, events and pages) your users go through to the desired outcomes you want them to achieve whether it’s a sale, sign-up or any other particular goal you have defined.

    Funnels feature

    Looking at the entire conversion funnel and focusing on usability, you’ll be able to identify where your visitors are having problems, where they aren’t understanding the flow of your webpages and identify obstacles that get in the way of your users reaching that end goal. Learn more

    How to improve conversion rates with Funnels : Learn what makes your visitors take action (or what stops them) in progressing to the next step in the conversion funnel. At each step, you’ll discover what content/layout resonates with your visitors and you can optimize your website to have the greatest impact on your business.

    7. Behaviour

    This is one of the most important features to help you optimize your website for conversions. Learning visitor behaviour is a driving force to increase conversions. How ? It lets you identify where you could be taking action to increase conversions. You get to learn first-hand what content or feature on your site is or isn’t working for your visitors. 

    Behaviour feature

    Engagement is essential to help increase conversion rates. If your visitors aren’t interested in the content on your site, then there’s very little chance they’ll be interested in what you have to offer. Learn more

    How to improve conversion rates with Behaviour : Get started by reducing bounce rates on important pages, testing messaging on your most popular entry pages, testing on the highest exit pages to reduce visitors leaving the site, learning pathways through Users Flow and Transitions to see if users are taking pathways that lead them to conversions or are the journeys currently long or go in odd directions. Discover how your visitors are responding to your content. The happier your visitors are to stay on your site, the more likely they’ll be able to move through the journey to help you achieve the goals you’ve set for your site.

    Do privacy-focused industries need conversion optimization ?

    For industries that place extra emphasis on privacy and security, Matomo is a complete analytics tool that can cater for all your needs. You get the full benefits of a web analytics and conversion optimization platform as well as peace of mind knowing Matomo places emphasis on security/privacy and adheres strictly to GDPR.

    If you operate in a data sensitive industry like in government, healthcare, finance, education etc. you can rest assured knowing your user’s privacy is respected and that you will have 100% data ownership.

    Other conversion optimization metrics in Matomo to look at :

    Get a good indication that your conversion optimization efforts are working by knowing where to look and this starts by going through the metrics in your analytics. Below we list how you can make a start.

    “Best” metrics are hard to determine so you’ll need to ask yourself what you want your site to do. How do you want your users to behave or what kind of customer journey do you want them to have ?

    You can start with :

    • Decreasing abandonment rate
    • Decreasing bounce rate
    • Increasing interactions per visit
    • Reducing exit rates on pages that significantly impact your visitors to leave your site
    • Constantly test and learn what content resonates with your visitors
    • Look to advance more users through each stage of the conversion funnel
    • Improve your forms to increase submission rates
    • Always improve the conversion rate % for your goals e.g. if you currently have a 5% conversion rate for selling a product, aim for 10% ; if 30% of your visitors are downloading your e-book, then aim for 40%, then 50% and so on.

    Through optimizing your messaging, content or your page layouts, you will increase conversions by getting your visitors through a clear pathway to meet your website’s goal.

  • MOV to ACVHD conversion via Spring Boot and FFmpeg leads to file system error

    31 décembre 2024, par epicUsername

    I am experiencing an issue on a personal project that seeks to convert HEIC to JPG files and MOV files to AVCHD format. The HEIC to JPG conversion works, but the MOV to AVCHD does not, which is where my problems lie.

    


    The intent is to do this with Spring Boot and FFmpeg, using a simple interface done in WindowBuilder.

    


    The relevant bits are the pom file :

    


        <dependencies>&#xA;    &#xA;        &#xA;        <dependency>&#xA;            <groupid>jmagick</groupid>&#xA;            <artifactid>jmagick</artifactid>&#xA;            <version>6.6.9</version>&#xA;        </dependency>&#xA;&#xA;        &#xA;        <dependency>&#xA;            <groupid>net.java.dev.jna</groupid>&#xA;            <artifactid>jna</artifactid>&#xA;            <version>5.7.0</version> &#xA;        </dependency>&#xA;        <dependency>&#xA;            <groupid>net.java.dev.jna</groupid>&#xA;            <artifactid>jna-platform</artifactid>&#xA;            <version>5.7.0</version>&#xA;        </dependency>&#xA;        &#xA;        &#xA;&#xA;&#xA;        <dependency>&#xA;            <groupid>org.bytedeco</groupid>&#xA;            <artifactid>ffmpeg</artifactid>&#xA;            <version>7.1-1.5.11</version>&#xA;        </dependency>&#xA;        <dependency>&#xA;            <groupid>org.bytedeco</groupid>&#xA;            <artifactid>javacv</artifactid>&#xA;            <version>1.5.11</version>&#xA;        </dependency>&#xA;        <dependency>&#xA;            <groupid>org.bytedeco</groupid>&#xA;            <artifactid>ffmpeg-platform</artifactid>&#xA;            <version>7.1-1.5.11</version>&#xA;        </dependency>&#xA;        &#xA;        <dependency>&#xA;            <groupid>org.bytedeco</groupid>&#xA;            <artifactid>javacpp</artifactid>&#xA;            <version>1.5.11</version>&#xA;        </dependency>&#xA;    </dependencies>&#xA;&#xA;

    &#xA;

    and the main file with the event handling for the application, based on the interface :

    &#xA;

    package home.multimeida.mmconverter;&#xA;&#xA;imports...&#xA;&#xA;public class MMConverterInterface extends JFrame {&#xA;&#xA;    public static void main(String[] args) {&#xA;        &#xA;        &#xA;        try {&#xA;            System.setProperty("jna.library.path", "absolute/path/to/gstreamer/bin");&#xA;            // Gst.init("GStreamer Test");&#xA;            System.out.println("GStreamer initialized successfully.");&#xA;        } catch (Exception e) {&#xA;            e.printStackTrace();&#xA;            System.out.println("Failed to initialize GStreamer.");&#xA;        }&#xA;        EventQueue.invokeLater(new Runnable() {&#xA;            public void run() {&#xA;                try {&#xA;                    MMConverterInterface frame = new MMConverterInterface();&#xA;                    frame.setVisible(true);&#xA;                } catch (Exception e) {&#xA;                    e.printStackTrace();&#xA;                }&#xA;            }&#xA;        });&#xA;    }&#xA;&#xA;    /**&#xA;     * Create the frame.&#xA;     */&#xA;    public MMConverterInterface() {&#xA;        &#xA;        // convert button&#xA;        &#xA;        btnConvert.addActionListener(e -> {&#xA;            &#xA;            try {&#xA;                &#xA;                if (sourceFileLabel.getText().equals("No file chosen...") || destinationFolderLabel.getText().equals("No folder selected...")) {&#xA;                    JOptionPane.showMessageDialog(null, "Please select both an input file and a save location.", "Validation Error", JOptionPane.WARNING_MESSAGE);&#xA;                    return;&#xA;                }&#xA;                 &#xA;                File sourceFile = new File(sourceFileLabel.getText());&#xA;                File destinationFile;&#xA;                 &#xA;                if (rdbtnNewRadioButton.isSelected()) {&#xA;                    &#xA;                    System.out.println("Converting HEIC to JPG...");&#xA;                        &#xA;                    String outputFileName = sourceFile.getName().replaceFirst("[.][^.]&#x2B;$", ".jpg");&#xA;                    &#xA;                    // Call your conversion logic here&#xA;                    &#xA;                    destinationFile = new File(destinationFolderLabel.getText(), outputFileName);&#xA;                    &#xA;                    convertHeicToJpg(sourceFile, destinationFile);&#xA;                    &#xA;                } else if (rdbtnNewRadioButton_1.isSelected()) {&#xA;                    &#xA;                    if (sourceFileLabel.getText().equals("No file chosen...") || destinationFolderLabel.getText().equals("No folder selected...")) {&#xA;                        JOptionPane.showMessageDialog(null, "Please select both an input file and a save location.", "Validation Error", JOptionPane.WARNING_MESSAGE);&#xA;                        return;&#xA;                    }&#xA;                    &#xA;                     // Validate source file&#xA;                    if (!sourceFile.exists() || !sourceFile.canRead()) {&#xA;                        JOptionPane.showMessageDialog(null, "Source file does not exist or is not readable.", "File Error", JOptionPane.ERROR_MESSAGE);&#xA;                        return;&#xA;                    }&#xA;                    &#xA;                    // Validate destination folder&#xA;                    String destinationPath = destinationFolderLabel.getText();&#xA;                    if (destinationPath == null || destinationPath.isEmpty() || !(new File(destinationPath).isDirectory())) {&#xA;                        JOptionPane.showMessageDialog(null, "Invalid destination folder.", "File Error", JOptionPane.ERROR_MESSAGE);&#xA;                        return;&#xA;                    }&#xA;                    &#xA;                    System.out.println("Converting MOV to AVCHD...");&#xA;                    &#xA;                    String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());&#xA;&#xA;                    // Extract the file name without the extension&#xA;                    String baseName = sourceFile.getName().replaceFirst("[.][^.]&#x2B;$", "");&#xA;&#xA;                    // Sanitize the base name (replace invalid characters with &#x27;_&#x27;)&#xA;                    baseName = baseName.replaceAll("[^a-zA-Z0-9-_]", "_");&#xA;                    &#xA;                    String sanitizedFileName = baseName &#x2B; "_" &#x2B; currentDate;&#xA;                    sanitizedFileName = sanitizedFileName.replaceAll("[^a-zA-Z0-9._-]", "_"); // Allow alphanumeric, &#x27;-&#x27;, &#x27;_&#x27;, and &#x27;.&#x27;&#xA;&#xA;                    destinationFile = new File(destinationPath, sanitizedFileName);&#xA;                    &#xA;                    &#xA;                    /*&#xA;                    // Ensure the destination file is writable&#xA;                    if (!destinationFile.canWrite()) {&#xA;                        JOptionPane.showMessageDialog(null, "Output file is not writable.", "File Error", JOptionPane.ERROR_MESSAGE);&#xA;                        return;&#xA;                    }&#xA;                    */&#xA;                   &#xA;&#xA;                    convertMovToAvchd(sourceFile, destinationFile);&#xA;                    &#xA;                } else {&#xA;                    &#xA;                    JOptionPane.showMessageDialog(null, "Please select a conversion type.");&#xA;                    &#xA;                }&#xA;                &#xA;            } catch (Exception ex) {&#xA;                &#xA;                JOptionPane.showMessageDialog(null, "Error: " &#x2B; ex.getMessage(), "Conversion Error", JOptionPane.ERROR_MESSAGE);&#xA;                ex.printStackTrace();&#xA;            }&#xA;            &#xA;            &#xA;        });&#xA;        &#xA;        // cancel button:&#xA;        &#xA;        btnCancel.addActionListener(e -> {&#xA;            System.out.println("Operation canceled.");&#xA;            System.exit(0); // Close the application&#xA;        });&#xA;&#xA;    }&#xA;    &#xA;    public void convertMovToAvchd(File sourceFile, File destinationFile) {&#xA;        avutil.av_log_set_level(avutil.AV_LOG_DEBUG);&#xA;        &#xA;        &#xA;&#xA;        AVFormatContext inputFormatContext = null;&#xA;        AVFormatContext outputFormatContext = new AVFormatContext(null);&#xA;        AVCodecContext inputCodecContext = null;&#xA;        AVCodecContext outputCodecContext = null;&#xA;&#xA;        try {&#xA;            // Validate input file&#xA;            if (!sourceFile.exists() || !sourceFile.canRead()) {&#xA;                System.out.println("Source file does not exist or is not readable: " &#x2B; sourceFile.getAbsolutePath());&#xA;                return;&#xA;            }&#xA;            &#xA;            // Validate output file path using the validateFileCreation method&#xA;            if (!validateFileCreation(destinationFile)) {&#xA;                return; // Exit if destination file validation fails&#xA;            }&#xA;&#xA;            // Validate output file path&#xA;            if (destinationFile.getParentFile() == null || !destinationFile.getParentFile().exists()) {&#xA;                System.out.println("Output directory does not exist: " &#x2B; destinationFile.getParentFile());&#xA;                return;&#xA;            }&#xA;            if (!destinationFile.getParentFile().canWrite()) {&#xA;                System.out.println("Output directory is not writable: " &#x2B; destinationFile.getParentFile());&#xA;                return;&#xA;            }&#xA;&#xA;            // Open input file&#xA;            inputFormatContext = avformat.avformat_alloc_context();&#xA;            if (avformat.avformat_open_input(inputFormatContext, sourceFile.getAbsolutePath(), null, null) &lt; 0) {&#xA;                System.out.println("Failed to open input file: " &#x2B; sourceFile.getAbsolutePath());&#xA;                return;&#xA;            }&#xA;&#xA;            // Find stream information&#xA;            if (avformat.avformat_find_stream_info(inputFormatContext, (PointerPointer) null) &lt; 0) {&#xA;                System.out.println("Failed to retrieve input stream information.");&#xA;                return;&#xA;            }&#xA;&#xA;            // Find video stream&#xA;            int videoStreamIndex = avformat.av_find_best_stream(inputFormatContext, avutil.AVMEDIA_TYPE_VIDEO, -1, -1, (AVCodec) null, 0);&#xA;            if (videoStreamIndex &lt; 0) {&#xA;                System.out.println("Failed to find video stream in input file.");&#xA;                return;&#xA;            }&#xA;&#xA;            // Initialize input codec context&#xA;            inputCodecContext = avcodec.avcodec_alloc_context3(null);&#xA;            avcodec.avcodec_parameters_to_context(inputCodecContext, inputFormatContext.streams(videoStreamIndex).codecpar());&#xA;&#xA;            AVCodec decoder = avcodec.avcodec_find_decoder(inputCodecContext.codec_id());&#xA;            if (decoder == null || avcodec.avcodec_open2(inputCodecContext, decoder, (PointerPointer) null) &lt; 0) {&#xA;                System.out.println("Failed to open video decoder.");&#xA;                return;&#xA;            }&#xA;&#xA;            // Allocate output format context&#xA;            if (avformat.avformat_alloc_output_context2(outputFormatContext, null, "mpegts", destinationFile.getAbsolutePath()) &lt; 0) {&#xA;                System.out.println("Failed to allocate output format context.");&#xA;                return;&#xA;            }&#xA;&#xA;            // Initialize output codec&#xA;            AVCodec encoder = avcodec.avcodec_find_encoder_by_name("mpeg2video");&#xA;            if (encoder == null) {&#xA;                System.out.println("Failed to find MPEG2 video encoder.");&#xA;                return;&#xA;            }&#xA;&#xA;            outputCodecContext = avcodec.avcodec_alloc_context3(encoder);&#xA;            if (outputCodecContext == null) {&#xA;                System.out.println("Failed to allocate output codec context.");&#xA;                return;&#xA;            }&#xA;            &#xA;            if ((outputFormatContext.oformat().flags() &amp; avformat.AVFMT_GLOBALHEADER) != 0) {&#xA;                outputCodecContext.flags(outputCodecContext.flags() | avcodec.AV_CODEC_FLAG_GLOBAL_HEADER);&#xA;            }&#xA;&#xA;&#xA;            //outputCodecContext.codec_id(avcodec.AV_CODEC_ID_MPEG2VIDEO);&#xA;            outputCodecContext.codec_id(encoder.id());&#xA;            outputCodecContext.codec_type(avutil.AVMEDIA_TYPE_VIDEO);&#xA;            outputCodecContext.width(1920);&#xA;            outputCodecContext.height(1080);&#xA;            outputCodecContext.pix_fmt(avutil.AV_PIX_FMT_YUV420P);&#xA;            outputCodecContext.time_base(avutil.av_make_q(1, 25));&#xA;            outputCodecContext.bit_rate(4000000);&#xA;            outputCodecContext.gop_size(12);&#xA;&#xA;            if ((outputFormatContext.oformat().flags() &amp; avformat.AVFMT_GLOBALHEADER) != 0) {&#xA;                outputCodecContext.flags(outputCodecContext.flags() | avcodec.AV_CODEC_FLAG_GLOBAL_HEADER);&#xA;            }&#xA;&#xA;            &#xA;            &#xA;            if (avcodec.avcodec_open2(outputCodecContext, encoder, (PointerPointer) null) &lt; 0) {&#xA;                System.out.println("Failed to open video encoder.");&#xA;                return;&#xA;            }&#xA;&#xA;            // Create output stream&#xA;            AVStream videoStream = avformat.avformat_new_stream(outputFormatContext, encoder);&#xA;            if (videoStream == null) {&#xA;                System.out.println("Failed to create video stream.");&#xA;                return;&#xA;            }&#xA;&#xA;            avcodec.avcodec_parameters_from_context(videoStream.codecpar(), outputCodecContext);&#xA;            &#xA;            System.out.println("Destination file path before trying to open the file is: " &#x2B; destinationFile);&#xA;&#xA;            if ((outputFormatContext.oformat().flags() &amp; avformat.AVFMT_NOFILE) == 0) {&#xA;                // Ensure the output path has the correct extension&#xA;                String outputPath = destinationFile.getAbsolutePath().replace("\\", "/") &#x2B; ".avchd";&#xA;                System.out.println("Normalized output path: " &#x2B; outputPath);&#xA;&#xA;                // Try opening the output file&#xA;                int ret = avformat.avio_open(outputFormatContext.pb(), outputPath, avformat.AVIO_FLAG_WRITE);&#xA;                if (ret &lt; 0) {&#xA;                    BytePointer errorBuffer = new BytePointer(avutil.AV_ERROR_MAX_STRING_SIZE);&#xA;                    avutil.av_strerror(ret, errorBuffer, errorBuffer.capacity());&#xA;                    System.out.println("Failed to open output file: " &#x2B; errorBuffer.getString());&#xA;                    return;&#xA;                }&#xA;            }&#xA;&#xA;&#xA;            // Write header&#xA;            if (avformat.avformat_write_header(outputFormatContext, (PointerPointer) null) &lt; 0) {&#xA;                System.out.println("Failed to write header to output file.");&#xA;                return;&#xA;            }&#xA;&#xA;&#xA;            // Packet processing loop&#xA;            AVPacket packet = new AVPacket();&#xA;            while (avformat.av_read_frame(inputFormatContext, packet) >= 0) {&#xA;                if (packet.stream_index() == videoStreamIndex) {&#xA;                    if (avcodec.avcodec_send_packet(inputCodecContext, packet) >= 0) {&#xA;                        AVFrame frame = avutil.av_frame_alloc();&#xA;                        while (avcodec.avcodec_receive_frame(inputCodecContext, frame) >= 0) {&#xA;                            if (avcodec.avcodec_send_frame(outputCodecContext, frame) >= 0) {&#xA;                                AVPacket encodedPacket = new AVPacket();&#xA;                                while (avcodec.avcodec_receive_packet(outputCodecContext, encodedPacket) >= 0) {&#xA;                                    encodedPacket.stream_index(videoStream.index());&#xA;                                    avformat.av_interleaved_write_frame(outputFormatContext, encodedPacket);&#xA;                                    avcodec.av_packet_unref(encodedPacket);&#xA;                                }&#xA;                            }&#xA;                            avutil.av_frame_unref(frame);&#xA;                        }&#xA;                        avutil.av_frame_free(frame);&#xA;                    }&#xA;                }&#xA;                avcodec.av_packet_unref(packet);&#xA;            }&#xA;&#xA;            // Write trailer&#xA;            avformat.av_write_trailer(outputFormatContext);&#xA;            System.out.println("Conversion completed successfully.");&#xA;            &#xA;            if (avcodec.avcodec_send_frame(outputCodecContext, null) >= 0) {&#xA;                AVPacket encodedPacket = new AVPacket();&#xA;                while (avcodec.avcodec_receive_packet(outputCodecContext, encodedPacket) >= 0) {&#xA;                    encodedPacket.stream_index(videoStream.index());&#xA;                    avformat.av_interleaved_write_frame(outputFormatContext, encodedPacket);&#xA;                    avcodec.av_packet_unref(encodedPacket);&#xA;                }&#xA;            }&#xA;&#xA;        } catch (Exception e) {&#xA;            e.printStackTrace();&#xA;        } finally {&#xA;            // Cleanup&#xA;            avcodec.avcodec_free_context(inputCodecContext);&#xA;            avcodec.avcodec_free_context(outputCodecContext);&#xA;            avformat.avformat_close_input(inputFormatContext);&#xA;&#xA;            if (outputFormatContext != null &amp;&amp; outputFormatContext.pb() != null) {&#xA;                avformat.avio_closep(outputFormatContext.pb());&#xA;            }&#xA;            avformat.avformat_free_context(outputFormatContext);&#xA;        }&#xA;    }&#xA;    &#xA;    private boolean validateFileCreation(File destinationFile) {&#xA;        // Check if the parent directory exists and is writable&#xA;        File parentDir = destinationFile.getParentFile();&#xA;        if (parentDir == null || !parentDir.exists()) {&#xA;            System.out.println("Parent directory does not exist: " &#x2B; parentDir);&#xA;            return false;&#xA;        }&#xA;        if (!parentDir.canWrite()) {&#xA;            System.out.println("Cannot write to parent directory: " &#x2B; parentDir);&#xA;            return false;&#xA;        }&#xA;&#xA;        // Check if the file exists and is writable&#xA;        if (destinationFile.exists()) {&#xA;            if (!destinationFile.canWrite()) {&#xA;                System.out.println("Destination file is not writable: " &#x2B; destinationFile);&#xA;                return false;&#xA;            }&#xA;        } else {&#xA;            // If the file doesn&#x27;t exist, try to create it to verify writability&#xA;            try {&#xA;                if (!destinationFile.createNewFile()) {&#xA;                    System.out.println("Unable to create destination file: " &#x2B; destinationFile);&#xA;                    return false;&#xA;                }&#xA;                // Delete the file after successful creation to avoid residual files&#xA;                destinationFile.delete();&#xA;            } catch (IOException e) {&#xA;                System.out.println("File creation failed: " &#x2B; e.getMessage());&#xA;                return false;&#xA;            }&#xA;        }&#xA;&#xA;        return true;&#xA;    }&#xA;    &#xA;}&#xA;&#xA;&#xA;

    &#xA;

    A few caveats :

    &#xA;

      &#xA;
    1. I did explore FFmpeg and GStreamer for this project. GStreamer was inconclusive, with available version for it that were too old for use with my current state of STS4.27 and Java 17, even if this version of Java is under long-term support...

      &#xA;

    2. &#xA;

    3. I've used AI to tell me about the options and suggest ways to build this thing, since multimedia handling is very far away from my skillset. I don't have a good conceptual grasp of video formats and how they transfrom from one to another.

      &#xA;

    4. &#xA;

    &#xA;

    The issue, as I have identified it, occurs at these lines :

    &#xA;

     // Ensure the destination file is writable&#xA;                    if (!destinationFile.canWrite()) {&#xA;                        JOptionPane.showMessageDialog(null, "Output file is not writable.", "File Error", JOptionPane.ERROR_MESSAGE);&#xA;                        return;&#xA;                    }&#xA;

    &#xA;

    ^^ And this, while temporarily commented out for testing, it meant to compensate for an issue that occurs here in the conversion function :

    &#xA;

     if ((outputFormatContext.oformat().flags() &amp; avformat.AVFMT_NOFILE) == 0) {&#xA;                // Ensure the output path has the correct extension&#xA;                String outputPath = destinationFile.getAbsolutePath().replace("\\", "/") &#x2B; ".avchd";&#xA;                System.out.println("Normalized output path: " &#x2B; outputPath);&#xA;&#xA;                // Try opening the output file&#xA;                int ret = avformat.avio_open(outputFormatContext.pb(), outputPath, avformat.AVIO_FLAG_WRITE);&#xA;                if (ret &lt; 0) {&#xA;                    BytePointer errorBuffer = new BytePointer(avutil.AV_ERROR_MAX_STRING_SIZE);&#xA;                    avutil.av_strerror(ret, errorBuffer, errorBuffer.capacity());&#xA;                    System.out.println("Failed to open output file: " &#x2B; errorBuffer.getString());&#xA;                    return;&#xA;                }&#xA;            }&#xA;

    &#xA;

    The idea here is that the avio_open() function requires the use of the a valid file path that it can open to be able to write it.

    &#xA;

    Padadoxically, the file conversion seems to work, but the project crashes with a fatal error in the console :

    &#xA;

    Selected file: E:\TestConveresions\sample_960x540.mov&#xA;Save location: E:\TestConveresions&#xA;Converting MOV to AVCHD...&#xA;Destination file path before trying to open the file is: E:\TestConveresions\sample_960x540_20241231&#xA;Normalized output path: E:/TestConveresions/sample_960x540_20241231.avchd&#xA;#&#xA;# A fatal error has been detected by the Java Runtime Environment:&#xA;#&#xA;#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffcffb0868b, pid=11020, tid=14436&#xA;#&#xA;# JRE version: OpenJDK Runtime Environment Temurin-21.0.5&#x2B;11 (21.0.5&#x2B;11) (build 21.0.5&#x2B;11-LTS)&#xA;# Java VM: OpenJDK 64-Bit Server VM Temurin-21.0.5&#x2B;11 (21.0.5&#x2B;11-LTS, mixed mode, emulated-client, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64)&#xA;# Problematic frame:&#xA;# C  0x00007ffcffb0868b&#xA;#&#xA;# No core dump will be written. Minidumps are not enabled by default on client versions of Windows&#xA;#&#xA;# An error report file with more information is saved as:&#xA;# E:\STS4 Workspace\MMConverter\hs_err_pid11020.log&#xA;[80.882s][warning][os] Loading hsdis library failed&#xA;#&#xA;# If you would like to submit a bug report, please visit:&#xA;#   https://github.com/adoptium/adoptium-support/issues&#xA;# The crash happened outside the Java Virtual Machine in native code.&#xA;# See problematic frame for where to report the bug.&#xA;#&#xA;[AVFormatContext @ 000002528adcea40] Opening &#x27;E:\TestConveresions\sample_960x540.mov&#x27; for reading&#xA;[file @ 000002528ae51c40] Setting default whitelist &#x27;file,crypto,data&#x27;&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] ISO: File Type Major Brand: qt  &#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] Unknown dref type 0x206c7275 size 12&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] Processing st: 0, edit list 0 - media time: 2002, duration: 400410&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] Offset DTS by 2002 to make first pts zero.&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] Setting codecpar->delay to 2 for stream st: 0&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] Before avformat_find_stream_info() pos: 1320742 bytes read:38225 seeks:1 nb_streams:1&#xA;[h264 @ 000002528ae62780] nal_unit_type: 7(SPS), nal_ref_idc: 3&#xA;[h264 @ 000002528ae62780] Decoding VUI&#xA;[h264 @ 000002528ae62780] nal_unit_type: 8(PPS), nal_ref_idc: 3&#xA;[h264 @ 000002528ae62780] nal_unit_type: 7(SPS), nal_ref_idc: 3&#xA;[h264 @ 000002528ae62780] Decoding VUI&#xA;[h264 @ 000002528ae62780] nal_unit_type: 8(PPS), nal_ref_idc: 3&#xA;[h264 @ 000002528ae62780] nal_unit_type: 6(SEI), nal_ref_idc: 0&#xA;[h264 @ 000002528ae62780] nal_unit_type: 5(IDR), nal_ref_idc: 3&#xA;[h264 @ 000002528ae62780] Format yuv420p chosen by get_format().&#xA;[h264 @ 000002528ae62780] Reinit context to 960x544, pix_fmt: yuv420p&#xA;[h264 @ 000002528ae62780] no picture &#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] All info found&#xA;[mov,mp4,m4a,3gp,3g2,mj2 @ 000002528adcea40] After avformat_find_stream_info() pos: 51943 bytes read:90132 seeks:2 frames:1&#xA;[h264 @ 000002528ae62780] nal_unit_type: 7(SPS), nal_ref_idc: 3&#xA;[h264 @ 000002528ae62780] Decoding VUI&#xA;[h264 @ 000002528ae62780] nal_unit_type: 8(PPS), nal_ref_idc: 3&#xA;[mpeg2video @ 000002528ae8e700] intra_quant_bias = 96 inter_quant_bias = 0&#xA;&#xA;

    &#xA;

    If I refer to the error log, I get this. It is partial, as I'm not sure SO will take all of it (quite long), but still might have enough to be relevant :

    &#xA;

    Host: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz, 8 cores, 31G,  Windows 11 , 64 bit Build 26100 (10.0.26100.2454)&#xA;&#xA;&#xA;---------------  T H R E A D  ---------------&#xA;&#xA;Current thread (0x00000252d030b340):  JavaThread "AWT-EventQueue-0"        [_thread_in_native, id=14436, stack(0x000000a4e2b00000,0x000000a4e2c00000) (1024K)]&#xA;&#xA;Stack: [0x000000a4e2b00000,0x000000a4e2c00000],  sp=0x000000a4e2bfdf30,  free space=1015k&#xA;Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)&#xA;C  0x00007ffcffb0868b&#xA;&#xA;Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)&#xA;j  org.bytedeco.ffmpeg.global.avformat.avio_open(Lorg/bytedeco/ffmpeg/avformat/AVIOContext;Ljava/lang/String;I)I&#x2B;0&#xA;j  home.multimeida.mmconverter.MMConverterInterface.convertMovToAvchd(Ljava/io/File;Ljava/io/File;)V&#x2B;1120&#xA;j  home.multimeida.mmconverter.MMConverterInterface.lambda$2(Ljavax/swing/JRadioButton;Ljavax/swing/JRadioButton;Ljava/awt/event/ActionEvent;)V&#x2B;347&#xA;j  home.multimeida.mmconverter.MMConverterInterface$$Lambda&#x2B;0x000002528c0c7778.actionPerformed(Ljava/awt/event/ActionEvent;)V&#x2B;13&#xA;j  javax.swing.AbstractButton.fireActionPerformed(Ljava/awt/event/ActionEvent;)V&#x2B;84 java.desktop@21.0.5&#xA;j  javax.swing.AbstractButton$Handler.actionPerformed(Ljava/awt/event/ActionEvent;)V&#x2B;5 java.desktop@21.0.5&#xA;j  javax.swing.DefaultButtonModel.fireActionPerformed(Ljava/awt/event/ActionEvent;)V&#x2B;34 java.desktop@21.0.5&#xA;j  javax.swing.DefaultButtonModel.setPressed(Z)V&#x2B;117 java.desktop@21.0.5&#xA;j  javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Ljava/awt/event/MouseEvent;)V&#x2B;35 java.desktop@21.0.5&#xA;j  java.awt.Component.processMouseEvent(Ljava/awt/event/MouseEvent;)V&#x2B;64 java.desktop@21.0.5&#xA;j  javax.swing.JComponent.processMouseEvent(Ljava/awt/event/MouseEvent;)V&#x2B;23 java.desktop@21.0.5&#xA;J 2581 c1 java.awt.Component.processEvent(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (220 bytes) @ 0x00000252fa62719c [0x00000252fa627020&#x2B;0x000000000000017c]&#xA;J 2580 c1 java.awt.Container.processEvent(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (22 bytes) @ 0x00000252fa627d9c [0x00000252fa627cc0&#x2B;0x00000000000000dc]&#xA;J 2406 c1 java.awt.Component.dispatchEventImpl(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (785 bytes) @ 0x00000252fa670f14 [0x00000252fa670040&#x2B;0x0000000000000ed4]&#xA;J 2325 c1 java.awt.Container.dispatchEventImpl(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (129 bytes) @ 0x00000252fa64e93c [0x00000252fa64e8a0&#x2B;0x000000000000009c]&#xA;J 2608 c1 java.awt.LightweightDispatcher.retargetMouseEvent(Ljava/awt/Component;ILjava/awt/event/MouseEvent;)V java.desktop@21.0.5 (372 bytes) @ 0x00000252fa61c364 [0x00000252fa61b9e0&#x2B;0x0000000000000984]&#xA;J 2578 c1 java.awt.LightweightDispatcher.processMouseEvent(Ljava/awt/event/MouseEvent;)Z java.desktop@21.0.5 (268 bytes) @ 0x00000252fa628a54 [0x00000252fa6284c0&#x2B;0x0000000000000594]&#xA;J 2474 c1 java.awt.LightweightDispatcher.dispatchEvent(Ljava/awt/AWTEvent;)Z java.desktop@21.0.5 (73 bytes) @ 0x00000252fa699bbc [0x00000252fa699a60&#x2B;0x000000000000015c]&#xA;J 2325 c1 java.awt.Container.dispatchEventImpl(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (129 bytes) @ 0x00000252fa64e914 [0x00000252fa64e8a0&#x2B;0x0000000000000074]&#xA;J 2473 c1 java.awt.Window.dispatchEventImpl(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (23 bytes) @ 0x00000252fa699654 [0x00000252fa6994e0&#x2B;0x0000000000000174]&#xA;J 1838 c1 java.awt.EventQueue.dispatchEventImpl(Ljava/awt/AWTEvent;Ljava/lang/Object;)V java.desktop@21.0.5 (139 bytes) @ 0x00000252fa3bec64 [0x00000252fa3beb20&#x2B;0x0000000000000144]&#xA;J 1837 c1 java.awt.EventQueue$4.run()Ljava/lang/Void; java.desktop@21.0.5 (60 bytes) @ 0x00000252fa3c0504 [0x00000252fa3c0460&#x2B;0x00000000000000a4]&#xA;J 1836 c1 java.awt.EventQueue$4.run()Ljava/lang/Object; java.desktop@21.0.5 (5 bytes) @ 0x00000252fa3c0a04 [0x00000252fa3c09c0&#x2B;0x0000000000000044]&#xA;J 1778 c1 java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;Ljava/security/AccessControlContext;)Ljava/lang/Object; java.base@21.0.5 (22 bytes) @ 0x00000252fa4601d4 [0x00000252fa45ffa0&#x2B;0x0000000000000234]&#xA;J 1832 c1 java.awt.EventQueue.dispatchEvent(Ljava/awt/AWTEvent;)V java.desktop@21.0.5 (80 bytes) @ 0x00000252fa44f14c [0x00000252fa44eae0&#x2B;0x000000000000066c]&#xA;J 1846 c1 java.awt.EventDispatchThread.pumpOneEventForFilters(I)V java.desktop@21.0.5 (106 bytes) @ 0x00000252fa3ba544 [0x00000252fa3ba2e0&#x2B;0x0000000000000264]&#xA;j  java.awt.EventDispatchThread.pumpEventsForFilter(ILjava/awt/Conditional;Ljava/awt/EventFilter;)V&#x2B;35 java.desktop@21.0.5&#xA;j  java.awt.EventDispatchThread.pumpEventsForHierarchy(ILjava/awt/Conditional;Ljava/awt/Component;)V&#x2B;11 java.desktop@21.0.5&#xA;j  java.awt.EventDispatchThread.pumpEvents(ILjava/awt/Conditional;)V&#x2B;4 java.desktop@21.0.5&#xA;j  java.awt.EventDispatchThread.pumpEvents(Ljava/awt/Conditional;)V&#x2B;3 java.desktop@21.0.5&#xA;j  java.awt.EventDispatchThread.run()V&#x2B;9 java.desktop@21.0.5&#xA;v  ~StubRoutines::call_stub 0x00000252fa08100d&#xA;&#xA;siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), writing address 0x0000000000000000&#xA;&#xA;

    &#xA;

    If anyone has a perspective on this, it'd be appreciated.

    &#xA;

    The catch 22 in this project is that pre-creating the file is not a good idea, since avio_open has a purpose in-built method for that (I tried). Error checking everything about Java's File class in terms of setting pathways and creating and deleting files is not problematic. Likewise, permissions are all fine (Full Control in source and target folders) ; I've tested default C drive folders, which have restritions, to a separate volume and removable media, to no effect. Likewise, FFmpeg requires a forward slash, "/" in file paths, whereas Java does the backslash, generally. That's been handled with the replace method in the above conditioning, also to no effect.

    &#xA;

    The basic contradiction in the project seems to be that the error tries open a file that does not exist, with a valid source and destination file, and if I try to create a placeholder file wiht an acvhd extension at the event handling for the Convert button, it still errors out ; meanwhile, FFmpeg allegedly handles the file creation at its core, but requires a valid path to be passed ; I've tried with and without a filename, with and without an extension. I'm not able to resovle it.

    &#xA;

    The excessive error handling conditions are in an effort to isolate the problem, which I think I've done.

    &#xA;

    There also seems to be a compatibility between mpegts and acvhd, which is why I also had that format specified in the conversion function, without result.

    &#xA;

    I also have the idea to be able to do this without having to install any libraries locally or having to set path variables, which is an aspect that both GStreamer and FFmpeg have.

    &#xA;

    Nearest suggestion I've found is this : integrate ffmpeg with spring boot

    &#xA;

    AI remains hopeless for resolving this issue.

    &#xA;

  • Matomo analytics for wordpress

    15 octobre 2019, par Matomo Core Team — Community

    Self-hosting web analytics got a whole lot easier ! Introducing Matomo for WordPress

    Be the first to try it out ! Your feedback is much needed and appreciated

    Get a fully functioning Matomo (which is comparable to Google Analytics) in seconds ! How ? With the new Matomo Analytics for WordPress plugin. 

    Web analytics in WordPress has never been easier to get, or more powerful. Matomo Analytics for WordPress is the one-stop problem solver. It’ll save you time, money and give you the insights to help your website or business succeed. 

    Best of all, we get to further the goal of decentralising the internet. Our hope is for Matomo Analytics for WordPress to spread far and wide. We’re so excited that more and more people can now get their hands on this powerful, free, open-source analytics platform, in a few clicks !

    Download now and check it out !

    What do you get ?

    • No more signing up to third party analytics service (like Google)
    • No more sending away your valuable data to a third party service (like Google)
    • Easy setup – install with a few clicks, no tracking code installation or developer knowledge needed
    • 100% accurate data – no data sampling and no data limits 
    • Full data ownership – all data is stored on your servers and no one else can see your data
    • Privacy protection / GDPR compliance
    • Ecommerce tracking out-of-the-box (Woocommerce, Easy Digital Downloads, and MemberPress) and we’re keen to add many more over time
    • Powerful features – segmenting, comparing reports, different visualisations, real-time reports, visit logs and visitor profiles, Matomo Tag Manager, dashboards, data export, APIs, and many more
    • Compared to other WordPress solutions we don’t charge you extra for basic features that should work out-of-the-box
    • Just like Matomo On-Premise, Matomo Analytics for WordPress is free

    We need your feedback !

    We all know and love the versatility of WordPress – with over 55,000 plugins and all the different ways of hosting it. However, with this great versatility comes the potential for things to be missed, so we’re keen to hear your feedback.

    Thank you ! We really appreciate your help on this ❤️

    How do you get Matomo Analytics for WordPress ?

    Log in to your WordPress and go to “Plugins => Add New”, search for “Matomo Analytics – Ethical Stats. Powerful Insights”, click on “Install” and then “Activate”.

    All you need is at least WordPress 4.8 and PHP 7.0 or later. MySQL 5.1+ is recommended. 

    The source code is available at : https://github.com/matomo-org/wp-matomo/

    In perfect harmony : Matomo and WordPress

    Matomo Analytics for WordPress

    The idea for this started two years ago when we realised the similarities between the Matomo and WordPress project. 

    Not only from a technological point of view – where both are based on PHP and MySQL and can be extended using plugins – but also from a philosophical, license and values point of view. We both believe in privacy, security, data ownership, openness, transparency, having things working out-of-the-box, simplicity etc. 

    WordPress is currently used on approximately 30% of all websites. Many of them use the self-hosted open-source WordPress version. Giving everyone in this market the opportunity to easily get a powerful web analytics platform for free, means a lot to us. We believe WordPress users get a real choice besides the standard solution of Google Analytics, and it furthers our effort and goal of decentralising the internet. 

    We’re hoping more people will be empowered to protect user privacy, have access to a great free and open-source tool, and keep control of data in their own hands.

    We hope you feel the same. Help us spread the word to your friends and get them in on this awesome new project !

    Share on facebook
    Share on twitter
    Share on linkedin

    FAQs

    Isn’t there already a WP-Matomo plugin for WordPress available ?

    Yes, the existing WP-Matomo (WP-Piwik) plugin is an awesome plugin to connect your existing Matomo On-Premise or Matomo Cloud account with WordPress. The difference is that this new plugin installs Matomo Analytics fully in your WordPress. So you get the convenience of having a powerful analytics platform within your WordPress.

    We highly recommend you install this new plugin if you use WordPress and are not running Matomo yet. 

    If you are already using Matomo on our Cloud or On-Premise, we’d still highly recommend you use WP-Matomo (WP-Piwik). So that you get an easier way of inserting the tracking code into your WordPress site and get insights faster.

    I have a high traffic website, will it be an issue ?

    If you have a lot of traffic, we’d advise you to install Matomo On-Premise separately. There’s no specific traffic threshold we can give you on when it’s better to use Matomo On-Premise. It really depends on your server. 

    We reckon if you have more than 500,000 page views a month, you may want to think about using Matomo On-Premise with WP-Matomo instead, but this is just an estimate. In general, if the load on your server is already quite high, then it might be better to install Matomo on a separate server. See also recommended server sizing for running Matomo.

    How do I report a bug or request a new feature in Matomo for WordPress ?

    Please create an issue, on our repository whenever you find a bug or if you have any suggestion or ideas of improvement. We want to build an outstanding analytics experience for WordPress !

    Have another question you’re dying to ask ? The Matomo for WordPress FAQ page might have the answer you need. 

    Matomo Analytics for WordPress newsletter

    Get ahead of the crowd – signup to our exclusive Matomo for WordPress newsletter to get the latest updates on this exciting new project.

    &lt;script type=&quot;text/javascript&quot;&gt;<br />
    (function(global) {<br />
     function serialize(form){if(!form||form.nodeName!==&quot;FORM&quot;){return }var i,j,q=[];for(i=form.elements.length-1;i&gt;=0;i=i-1){if(form.elements[i].name===&quot;&quot;){continue}switch(form.elements[i].nodeName){case&quot;INPUT&quot;:switch(form.elements[i].type){case&quot;text&quot;:case&quot;hidden&quot;:case&quot;password&quot;:case&quot;button&quot;:case&quot;reset&quot;:case&quot;submit&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;checkbox&quot;:case&quot;radio&quot;:if(form.elements[i].checked){q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value))}break;case&quot;file&quot;:break}break;case&quot;TEXTAREA&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;SELECT&quot;:switch(form.elements[i].type){case&quot;select-one&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;select-multiple&quot;:for(j=form.elements[i].options.length-1;j&gt;=0;j=j-1){if(form.elements[i].options[j].selected){q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].options[j].value))}}break}break;case&quot;BUTTON&quot;:switch(form.elements[i].type){case&quot;reset&quot;:case&quot;submit&quot;:case&quot;button&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break}break}}return q.join(&quot;&amp;&quot;)};<br />
    <br />
    <br />
     function extend(destination, source) {<br />
       for (var prop in source) {<br />
         destination[prop] = source[prop];<br />
       }<br />
     }<br />
    <br />
     if (!Mimi) var Mimi = {};<br />
     if (!Mimi.Signups) Mimi.Signups = {};<br />
    <br />
     Mimi.Signups.EmbedValidation = function() {<br />
       this.initialize();<br />
    <br />
       var _this = this;<br />
       if (document.addEventListener) {<br />
         this.form.addEventListener('submit', function(e){<br />
           _this.onFormSubmit(e);<br />
         });<br />
       } else {<br />
         this.form.attachEvent('onsubmit', function(e){<br />
           _this.onFormSubmit(e);<br />
         });<br />
       }<br />
     };<br />
    <br />
     extend(Mimi.Signups.EmbedValidation.prototype, {<br />
       initialize: function() {<br />
         this.form         = document.getElementById('ema_signup_form');<br />
         this.submit       = document.getElementById('webform_submit_button');<br />
         this.callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());<br />
         this.validEmail   = /.+@.+\..+/<br />
       },<br />
    <br />
       onFormSubmit: function(e) {<br />
         e.preventDefault();<br />
    <br />
         this.validate();<br />
         if (this.isValid) {<br />
           this.submitForm();<br />
         } else {<br />
           this.revalidateOnChange();<br />
         }<br />
       },<br />
    <br />
       validate: function() {<br />
         this.isValid = true;<br />
         this.emailValidation();<br />
         this.fieldAndListValidation();<br />
         this.updateFormAfterValidation();<br />
       },<br />
    <br />
       emailValidation: function() {<br />
         var email = document.getElementById('signup_email');<br />
    <br />
         if (this.validEmail.test(email.value)) {<br />
           this.removeTextFieldError(email);<br />
         } else {<br />
           this.textFieldError(email);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       fieldAndListValidation: function() {<br />
         var fields = this.form.querySelectorAll('.mimi_field.required');<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           var field = fields[i],<br />
               type  = this.fieldType(field);<br />
           if (type === 'checkboxes' || type === 'radio_buttons' || type === 'age_check') {<br />
             this.checkboxAndRadioValidation(field);<br />
           } else {<br />
             this.textAndDropdownValidation(field, type);<br />
           }<br />
         }<br />
       },<br />
    <br />
       fieldType: function(field) {<br />
         var type = field.querySelectorAll('.field_type');<br />
    <br />
         if (type.length) {<br />
           return type[0].getAttribute('data-field-type');<br />
         } else if (field.className.indexOf('checkgroup') &gt;= 0) {<br />
           return 'checkboxes';<br />
         } else {<br />
           return 'text_field';<br />
         }<br />
       },<br />
    <br />
       checkboxAndRadioValidation: function(field) {<br />
         var inputs   = field.getElementsByTagName('input'),<br />
             selected = false;<br />
    <br />
         for (var i = 0; i &lt; inputs.length; ++i) {<br />
           var input = inputs[i];<br />
           if((input.type === 'checkbox' || input.type === 'radio') &amp;&amp; input.checked) {<br />
             selected = true;<br />
           }<br />
         }<br />
    <br />
         if (selected) {<br />
           field.className = field.className.replace(/ invalid/g, '');<br />
         } else {<br />
           if (field.className.indexOf('invalid') === -1) {<br />
             field.className += ' invalid';<br />
           }<br />
    <br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       textAndDropdownValidation: function(field, type) {<br />
         var inputs = field.getElementsByTagName('input');<br />
    <br />
         for (var i = 0; i &lt; inputs.length; ++i) {<br />
           var input = inputs[i];<br />
           if (input.name.indexOf('signup') &gt;= 0) {<br />
             if (type === 'text_field') {<br />
               this.textValidation(input);<br />
             } else {<br />
               this.dropdownValidation(field, input);<br />
             }<br />
           }<br />
         }<br />
         this.htmlEmbedDropdownValidation(field);<br />
       },<br />
    <br />
       textValidation: function(input) {<br />
         if (input.id === 'signup_email') return;<br />
    <br />
         if (input.value) {<br />
           this.removeTextFieldError(input);<br />
         } else {<br />
           this.textFieldError(input);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       dropdownValidation: function(field, input) {<br />
         if (input.value) {<br />
           field.className = field.className.replace(/ invalid/g, '');<br />
         } else {<br />
           if (field.className.indexOf('invalid') === -1) field.className += ' invalid';<br />
           this.onSelectCallback(input);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       htmlEmbedDropdownValidation: function(field) {<br />
         var dropdowns = field.querySelectorAll('.mimi_html_dropdown');<br />
         var _this = this;<br />
    <br />
         for (var i = 0; i &lt; dropdowns.length; ++i) {<br />
           var dropdown = dropdowns[i];<br />
    <br />
           if (dropdown.value) {<br />
             field.className = field.className.replace(/ invalid/g, '');<br />
           } else {<br />
             if (field.className.indexOf('invalid') === -1) field.className += ' invalid';<br />
             this.isValid = false;<br />
             dropdown.onchange = (function(){ _this.validate(); });<br />
           }<br />
         }<br />
       },<br />
    <br />
       textFieldError: function(input) {<br />
         input.className   = 'required invalid';<br />
         input.placeholder = input.getAttribute('data-required-field');<br />
       },<br />
    <br />
       removeTextFieldError: function(input) {<br />
         input.className   = 'required';<br />
         input.placeholder = '';<br />
       },<br />
    <br />
       onSelectCallback: function(input) {<br />
         if (typeof Widget === 'undefined' || !Widget.BasicDropdown) return;<br />
    <br />
         var dropdownEl = input.parentNode,<br />
             instances  = Widget.BasicDropdown.instances,<br />
             _this = this;<br />
    <br />
         for (var i = 0; i &lt; instances.length; ++i) {<br />
           var instance = instances[i];<br />
           if (instance.wrapperEl === dropdownEl) {<br />
             instance.onSelect = function(){ _this.validate() };<br />
           }<br />
         }<br />
       },<br />
    <br />
       updateFormAfterValidation: function() {<br />
         this.form.className   = this.setFormClassName();<br />
         this.submit.value     = this.submitButtonText();<br />
         this.submit.disabled  = !this.isValid;<br />
         this.submit.className = this.isValid ? 'submit' : 'disabled';<br />
       },<br />
    <br />
       setFormClassName: function() {<br />
         var name = this.form.className;<br />
    <br />
         if (this.isValid) {<br />
           return name.replace(/\s?mimi_invalid/, '');<br />
         } else {<br />
           if (name.indexOf('mimi_invalid') === -1) {<br />
             return name += ' mimi_invalid';<br />
           } else {<br />
             return name;<br />
           }<br />
         }<br />
       },<br />
    <br />
       submitButtonText: function() {<br />
         var invalidFields = document.querySelectorAll('.invalid'),<br />
             text;<br />
    <br />
         if (this.isValid || !invalidFields) {<br />
           text = this.submit.getAttribute('data-default-text');<br />
         } else {<br />
           if (invalidFields.length || invalidFields[0].className.indexOf('checkgroup') === -1) {<br />
             text = this.submit.getAttribute('data-invalid-text');<br />
           } else {<br />
             text = this.submit.getAttribute('data-choose-list');<br />
           }<br />
         }<br />
         return text;<br />
       },<br />
    <br />
       submitForm: function() {<br />
         this.formSubmitting();<br />
    <br />
         var _this = this;<br />
         window[this.callbackName] = function(response) {<br />
           delete window[this.callbackName];<br />
           document.body.removeChild(script);<br />
           _this.onSubmitCallback(response);<br />
         };<br />
    <br />
         var script = document.createElement('script');<br />
         script.src = this.formUrl('json');<br />
         document.body.appendChild(script);<br />
       },<br />
    <br />
       formUrl: function(format) {<br />
         var action  = this.form.action;<br />
         if (format === 'json') action += '.json';<br />
         return action + '?callback=' + this.callbackName + '&amp;' + serialize(this.form);<br />
       },<br />
    <br />
       formSubmitting: function() {<br />
         this.form.className  += ' mimi_submitting';<br />
         this.submit.value     = this.submit.getAttribute('data-submitting-text');<br />
         this.submit.disabled  = true;<br />
         this.submit.className = 'disabled';<br />
       },<br />
    <br />
       onSubmitCallback: function(response) {<br />
         if (response.success) {<br />
           this.onSubmitSuccess(response.result);<br />
         } else {<br />
           top.location.href = this.formUrl('html');<br />
         }<br />
       },<br />
    <br />
       onSubmitSuccess: function(result) {<br />
         if (result.has_redirect) {<br />
           top.location.href = result.redirect;<br />
         } else if(result.single_opt_in || !result.confirmation_html) {<br />
           this.disableForm();<br />
           this.updateSubmitButtonText(this.submit.getAttribute('data-thanks'));<br />
         } else {<br />
           this.showConfirmationText(result.confirmation_html);<br />
         }<br />
       },<br />
    <br />
       showConfirmationText: function(html) {<br />
         var fields = this.form.querySelectorAll('.mimi_field');<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           fields[i].style['display'] = 'none';<br />
         }<br />
    <br />
         (this.form.querySelectorAll('fieldset')[0] || this.form).innerHTML = html;<br />
       },<br />
    <br />
       disableForm: function() {<br />
         var elements = this.form.elements;<br />
         for (var i = 0; i &lt; elements.length; ++i) {<br />
           elements[i].disabled = true;<br />
         }<br />
       },<br />
    <br />
       updateSubmitButtonText: function(text) {<br />
         this.submit.value = text;<br />
       },<br />
    <br />
       revalidateOnChange: function() {<br />
         var fields = this.form.querySelectorAll(&quot;.mimi_field.required&quot;),<br />
             _this = this;<br />
    <br />
         var onTextFieldChange = function() {<br />
           if (this.getAttribute('name') === 'signup[email]') {<br />
             if (_this.validEmail.test(this.value)) _this.validate();<br />
           } else {<br />
             if (this.value.length === 1) _this.validate();<br />
           }<br />
         }<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           var inputs = fields[i].getElementsByTagName('input');<br />
           for (var j = 0; j &lt; inputs.length; ++j) {<br />
             if (this.fieldType(fields[i]) === 'text_field') {<br />
               inputs[j].onkeyup = onTextFieldChange;<br />
               inputs[j].onchange = onTextFieldChange; <br />
             } else {<br />
               inputs[j].onchange = function(){ _this.validate() };<br />
             }<br />
           }<br />
         }<br />
       }<br />
     });<br />
    <br />
     if (document.addEventListener) {<br />
       document.addEventListener(&quot;DOMContentLoaded&quot;, function() {<br />
         new Mimi.Signups.EmbedValidation();<br />
       });<br />
     }<br />
     else {<br />
       window.attachEvent('onload', function() {<br />
         new Mimi.Signups.EmbedValidation();<br />
       });<br />
     }<br />
    })(this);<br />
    &lt;/script&gt;