<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2008, 2011, <NAME>, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

/*!
 * \file cap_gstreamer.cpp
 * \author <NAME> <<EMAIL>>
 *         Max-Planck-Institut Informatik
 * \author <NAME> <<EMAIL>>
 *
 * \brief Use GStreamer to read/write video
 */
#include "precomp.hpp"
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/gstbuffer.h>
#include <gst/video/video.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#include <gst/riff/riff-media.h>
#include <gst/pbutils/missing-plugins.h>

#define VERSION_NUM(major, minor, micro) (major * 1000000 + minor * 1000 + micro)
#define FULL_GST_VERSION VERSION_NUM(GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO)

#if FULL_GST_VERSION >= VERSION_NUM(0,10,32)
#include <gst/pbutils/encoding-profile.h>
//#include <gst/base/gsttypefindhelper.h>
#endif


#ifdef NDEBUG
#define CV_WARN(message)
#else
#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
#endif

#if GST_VERSION_MAJOR == 0
#define COLOR_ELEM "ffmpegcolorspace"
#define COLOR_ELEM_NAME "ffmpegcsp"
#elif FULL_GST_VERSION < VERSION_NUM(1,5,0)
#define COLOR_ELEM "videoconvert"
#define COLOR_ELEM_NAME COLOR_ELEM
#else
#define COLOR_ELEM "autovideoconvert"
#define COLOR_ELEM_NAME COLOR_ELEM
#endif

#if defined(_WIN32) || defined(_WIN64)
#if defined(__MINGW32__)
inline char *realpath(const char *path, char *resolved_path)
{
    return _fullpath(resolved_path,path,PATH_MAX);
}
#endif
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#include <sys/stat.h>
#endif

void toFraction(double decimal, double &numerator, double &denominator);
void handleMessage(GstElement * pipeline);


static cv::Mutex gst_initializer_mutex;

/*!
 * \brief The gst_initializer class
 * Initializes gstreamer once in the whole process
 */
class gst_initializer
{
public:
    static void init()
    {
        gst_initializer_mutex.lock();
        static gst_initializer init;
        gst_initializer_mutex.unlock();
    }
private:
    gst_initializer()
    {
        gst_init(NULL, NULL);
//        gst_debug_set_active(1);
//        gst_debug_set_colored(1);
//        gst_debug_set_default_threshold(GST_LEVEL_INFO);
    }
};

/*!
 * \brief The CvCapture_GStreamer class
 * Use GStreamer to capture video
 */
class CvCapture_GStreamer : public CvCapture
{
public:
    CvCapture_GStreamer() { init(); }
    virtual ~CvCapture_GStreamer() { close(); }

    virtual bool open( int type, const char* filename );
    virtual void close();

    virtual double getProperty(int) const;
    virtual bool setProperty(int, double);
    virtual bool grabFrame();
    virtual IplImage* retrieveFrame(int);

protected:
    void init();
    bool reopen();
    bool isPipelinePlaying();
    void startPipeline();
    void stopPipeline();
    void restartPipeline();
    void setFilter(const char* prop, int type, int v1, int v2 = 0);
    void removeFilter(const char *filter);
    static void newPad(GstElement *myelement,
                       GstPad     *pad,
                       gpointer    data);
    GstElement*   pipeline;
    GstElement*   uridecodebin;
    GstElement*   v4l2src;
    GstElement*   color;
    GstElement*   sink;
#if GST_VERSION_MAJOR > 0
    GstSample*    sample;
#endif
    GstBuffer*    buffer;
    GstCaps*      caps;
    IplImage*     frame;
    gint64        duration;
    gint          width;
    gint          height;
    double        fps;

    bool          isPosFramesSupported;
    bool          isPosFramesEmulated;
    gint64        emulatedFrameNumber;
};

/*!
 * \brief CvCapture_GStreamer::init
 * inits the class
 */
void CvCapture_GStreamer::init()
{
    pipeline = NULL;
    uridecodebin = NULL;
    v4l2src = NULL;
    color = NULL;
    sink = NULL;
#if GST_VERSION_MAJOR > 0
    sample = NULL;
#endif
    buffer = NULL;
    caps = NULL;
    frame = NULL;
    duration = -1;
    width = -1;
    height = -1;
    fps = -1;

    isPosFramesSupported = false;
    isPosFramesEmulated = false;
    emulatedFrameNumber = -1;
}

/*!
 * \brief CvCapture_GStreamer::close
 * Closes the pipeline and destroys all instances
 */
void CvCapture_GStreamer::close()
{
    if (isPipelinePlaying())
        this->stopPipeline();

    if(pipeline) {
        gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
        gst_object_unref(GST_OBJECT(pipeline));
        pipeline = NULL;
    }

    duration = -1;
    width = -1;
    height = -1;
    fps = -1;
    isPosFramesSupported = false;
    isPosFramesEmulated = false;
    emulatedFrameNumber = -1;
}

/*!
 * \brief CvCapture_GStreamer::grabFrame
 * \return
 * Grabs a sample from the pipeline, awaiting consumation by retreiveFrame.
 * The pipeline is started if it was not running yet
 */
bool CvCapture_GStreamer::grabFrame()
{
    if(!pipeline)
        return false;

    // start the pipeline if it was not in playing state yet
    if(!this->isPipelinePlaying())
        this->startPipeline();

    // bail out if EOS
    if(gst_app_sink_is_eos(GST_APP_SINK(sink)))
        return false;

#if GST_VERSION_MAJOR == 0
    if(buffer)
        gst_buffer_unref(buffer);

    buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink));
#else
    if(sample)
        gst_sample_unref(sample);

    sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));

    if(!sample)
        return false;

    buffer = gst_sample_get_buffer(sample);
#endif

    if(!buffer)
        return false;

    if (isPosFramesEmulated)
        emulatedFrameNumber++;

    return true;
}

/*!
 * \brief CvCapture_GStreamer::retrieveFrame
 * \return IplImage pointer. [Transfer Full]
 *  Retreive the previously grabbed buffer, and wrap it in an IPLImage structure
 */
IplImage * CvCapture_GStreamer::retrieveFrame(int)
{
    if(!buffer)
        return 0;

    //construct a frame header if we did not have any yet
    if(!frame)
    {
#if GST_VERSION_MAJOR == 0
        GstCaps* buffer_caps = gst_buffer_get_caps(buffer);
#else
        GstCaps* buffer_caps = gst_sample_get_caps(sample);
#endif
        // bail out in no caps
        assert(gst_caps_get_size(buffer_caps) == 1);
        GstStructure* structure = gst_caps_get_structure(buffer_caps, 0);

        // bail out if width or height are 0
        if(!gst_structure_get_int(structure, "width", &width) ||
                !gst_structure_get_int(structure, "height", &height))
        {
            gst_caps_unref(buffer_caps);
            return 0;
        }

        int depth = 3;
        bool height_extend = false;

#if GST_VERSION_MAJOR > 0
        depth = 0;
        const gchar* name = gst_structure_get_name(structure);
        const gchar* format = gst_structure_get_string(structure, "format");

        if (!name)
            return 0;

        // we support 11 types of data:
        //     video/x-raw, format=BGR   -> 8bit, 3 channels
        //     video/x-raw, format=GRAY8 -> 8bit, 1 channel
        //     video/x-raw, format=UYVY  -> 8bit, 2 channel
        //     video/x-raw, format=YUY2  -> 8bit, 2 channel
        //     video/x-raw, format=YVYU  -> 8bit, 2 channel
        //     video/x-raw, format=NV12  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-raw, format=NV21  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-raw, format=YV12  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-raw, format=I420  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-bayer             -> 8bit, 1 channel
        //     image/jpeg                -> 8bit, mjpeg: buffer_size x 1 x 1
        // bayer data is never decoded, the user is responsible for that
        // everything is 8 bit, so we just test the caps for bit depth

        if (strcasecmp(name, "video/x-raw") == 0)
        {
            if (!format)
                return 0;

            if (strcasecmp(format, "BGR") == 0) {
                depth = 3;
            }
            else if( (strcasecmp(format, "UYVY") == 0) || (strcasecmp(format, "YUY2") == 0) || (strcasecmp(format, "YVYU") == 0) ){
                depth = 2;
            }
            else if( (strcasecmp(format, "NV12") == 0) || (strcasecmp(format, "NV21") == 0) || (strcasecmp(format, "YV12") == 0) || (strcasecmp(format, "I420") == 0) ){
                depth = 1;
                height_extend = true;
            }
            else if(strcasecmp(format, "GRAY8") == 0){
                depth = 1;
            }
        }
        else if (strcasecmp(name, "video/x-bayer") == 0)
        {
            depth = 1;
        } else if(strcasecmp(name, "image/jpeg") == 0) {
            depth = 1;
            // the correct size will be set once the first frame arrives
        }
#endif
        if (depth > 0) {
            if(height_extend){
                frame = cvCreateImageHeader(cvSize(width, height*3/2), IPL_DEPTH_8U, depth);
            }else{
                frame = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, depth);
            }
        } else {
            gst_caps_unref(buffer_caps);
            return 0;
        }

        gst_caps_unref(buffer_caps);
    }

    // gstreamer expects us to handle the memory at this point
    // so we can just wrap the raw buffer and be done with it
#if GST_VERSION_MAJOR == 0
    frame->imageData = (char *)GST_BUFFER_DATA(buffer);
#else
    // info.data ptr is valid until next grabFrame where the associated sample is unref'd
    GstMapInfo info = GstMapInfo();
    gboolean success = gst_buffer_map(buffer,&info, (GstMapFlags)GST_MAP_READ);

    // with MJPEG streams frame size can change arbitrarily
    if(int(info.size) != frame->imageSize) {
        cvReleaseImageHeader(&frame);
        frame = cvCreateImageHeader(cvSize(info.size, 1), IPL_DEPTH_8U, 1);
    }

    if (!success){<commit_msg>videoio: improve condition for MJPEG gstreamer sink<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2008, 2011, <NAME>, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

/*!
 * \file cap_gstreamer.cpp
 * \author <NAME> <<EMAIL>>
 *         Max-Planck-Institut Informatik
 * \author <NAME> <<EMAIL>>
 *
 * \brief Use GStreamer to read/write video
 */
#include "precomp.hpp"
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/gstbuffer.h>
#include <gst/video/video.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#include <gst/riff/riff-media.h>
#include <gst/pbutils/missing-plugins.h>

#define VERSION_NUM(major, minor, micro) (major * 1000000 + minor * 1000 + micro)
#define FULL_GST_VERSION VERSION_NUM(GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO)

#if FULL_GST_VERSION >= VERSION_NUM(0,10,32)
#include <gst/pbutils/encoding-profile.h>
//#include <gst/base/gsttypefindhelper.h>
#endif


#ifdef NDEBUG
#define CV_WARN(message)
#else
#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
#endif

#if GST_VERSION_MAJOR == 0
#define COLOR_ELEM "ffmpegcolorspace"
#define COLOR_ELEM_NAME "ffmpegcsp"
#elif FULL_GST_VERSION < VERSION_NUM(1,5,0)
#define COLOR_ELEM "videoconvert"
#define COLOR_ELEM_NAME COLOR_ELEM
#else
#define COLOR_ELEM "autovideoconvert"
#define COLOR_ELEM_NAME COLOR_ELEM
#endif

#if defined(_WIN32) || defined(_WIN64)
#if defined(__MINGW32__)
inline char *realpath(const char *path, char *resolved_path)
{
    return _fullpath(resolved_path,path,PATH_MAX);
}
#endif
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#include <sys/stat.h>
#endif

void toFraction(double decimal, double &numerator, double &denominator);
void handleMessage(GstElement * pipeline);


static cv::Mutex gst_initializer_mutex;

/*!
 * \brief The gst_initializer class
 * Initializes gstreamer once in the whole process
 */
class gst_initializer
{
public:
    static void init()
    {
        gst_initializer_mutex.lock();
        static gst_initializer init;
        gst_initializer_mutex.unlock();
    }
private:
    gst_initializer()
    {
        gst_init(NULL, NULL);
//        gst_debug_set_active(1);
//        gst_debug_set_colored(1);
//        gst_debug_set_default_threshold(GST_LEVEL_INFO);
    }
};

/*!
 * \brief The CvCapture_GStreamer class
 * Use GStreamer to capture video
 */
class CvCapture_GStreamer : public CvCapture
{
public:
    CvCapture_GStreamer() { init(); }
    virtual ~CvCapture_GStreamer() { close(); }

    virtual bool open( int type, const char* filename );
    virtual void close();

    virtual double getProperty(int) const;
    virtual bool setProperty(int, double);
    virtual bool grabFrame();
    virtual IplImage* retrieveFrame(int);

protected:
    void init();
    bool reopen();
    bool isPipelinePlaying();
    void startPipeline();
    void stopPipeline();
    void restartPipeline();
    void setFilter(const char* prop, int type, int v1, int v2 = 0);
    void removeFilter(const char *filter);
    static void newPad(GstElement *myelement,
                       GstPad     *pad,
                       gpointer    data);
    GstElement*   pipeline;
    GstElement*   uridecodebin;
    GstElement*   v4l2src;
    GstElement*   color;
    GstElement*   sink;
#if GST_VERSION_MAJOR > 0
    GstSample*    sample;
#endif
    GstBuffer*    buffer;
    GstCaps*      caps;
    IplImage*     frame;
    gint64        duration;
    gint          width;
    gint          height;
    double        fps;

    bool          isPosFramesSupported;
    bool          isPosFramesEmulated;
    gint64        emulatedFrameNumber;

    bool          isOutputByteBuffer;
};

/*!
 * \brief CvCapture_GStreamer::init
 * inits the class
 */
void CvCapture_GStreamer::init()
{
    pipeline = NULL;
    uridecodebin = NULL;
    v4l2src = NULL;
    color = NULL;
    sink = NULL;
#if GST_VERSION_MAJOR > 0
    sample = NULL;
#endif
    buffer = NULL;
    caps = NULL;
    frame = NULL;
    duration = -1;
    width = -1;
    height = -1;
    fps = -1;

    isPosFramesSupported = false;
    isPosFramesEmulated = false;
    emulatedFrameNumber = -1;

    isOutputByteBuffer = false;
}

/*!
 * \brief CvCapture_GStreamer::close
 * Closes the pipeline and destroys all instances
 */
void CvCapture_GStreamer::close()
{
    if (isPipelinePlaying())
        this->stopPipeline();

    if(pipeline) {
        gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
        gst_object_unref(GST_OBJECT(pipeline));
        pipeline = NULL;
    }

    duration = -1;
    width = -1;
    height = -1;
    fps = -1;
    isPosFramesSupported = false;
    isPosFramesEmulated = false;
    emulatedFrameNumber = -1;
}

/*!
 * \brief CvCapture_GStreamer::grabFrame
 * \return
 * Grabs a sample from the pipeline, awaiting consumation by retreiveFrame.
 * The pipeline is started if it was not running yet
 */
bool CvCapture_GStreamer::grabFrame()
{
    if(!pipeline)
        return false;

    // start the pipeline if it was not in playing state yet
    if(!this->isPipelinePlaying())
        this->startPipeline();

    // bail out if EOS
    if(gst_app_sink_is_eos(GST_APP_SINK(sink)))
        return false;

#if GST_VERSION_MAJOR == 0
    if(buffer)
        gst_buffer_unref(buffer);

    buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink));
#else
    if(sample)
        gst_sample_unref(sample);

    sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));

    if(!sample)
        return false;

    buffer = gst_sample_get_buffer(sample);
#endif

    if(!buffer)
        return false;

    if (isPosFramesEmulated)
        emulatedFrameNumber++;

    return true;
}

/*!
 * \brief CvCapture_GStreamer::retrieveFrame
 * \return IplImage pointer. [Transfer Full]
 *  Retreive the previously grabbed buffer, and wrap it in an IPLImage structure
 */
IplImage * CvCapture_GStreamer::retrieveFrame(int)
{
    if(!buffer)
        return 0;

    //construct a frame header if we did not have any yet
    if(!frame)
    {
#if GST_VERSION_MAJOR == 0
        GstCaps* buffer_caps = gst_buffer_get_caps(buffer);
#else
        GstCaps* buffer_caps = gst_sample_get_caps(sample);
#endif
        // bail out in no caps
        assert(gst_caps_get_size(buffer_caps) == 1);
        GstStructure* structure = gst_caps_get_structure(buffer_caps, 0);

        // bail out if width or height are 0
        if(!gst_structure_get_int(structure, "width", &width) ||
                !gst_structure_get_int(structure, "height", &height))
        {
            gst_caps_unref(buffer_caps);
            return 0;
        }

        int depth = 3;
        bool height_extend = false;

#if GST_VERSION_MAJOR > 0
        depth = 0;
        const gchar* name = gst_structure_get_name(structure);
        const gchar* format = gst_structure_get_string(structure, "format");

        if (!name)
            return 0;

        // we support 11 types of data:
        //     video/x-raw, format=BGR   -> 8bit, 3 channels
        //     video/x-raw, format=GRAY8 -> 8bit, 1 channel
        //     video/x-raw, format=UYVY  -> 8bit, 2 channel
        //     video/x-raw, format=YUY2  -> 8bit, 2 channel
        //     video/x-raw, format=YVYU  -> 8bit, 2 channel
        //     video/x-raw, format=NV12  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-raw, format=NV21  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-raw, format=YV12  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-raw, format=I420  -> 8bit, 1 channel (height is 1.5x larger than true height)
        //     video/x-bayer             -> 8bit, 1 channel
        //     image/jpeg                -> 8bit, mjpeg: buffer_size x 1 x 1
        // bayer data is never decoded, the user is responsible for that
        // everything is 8 bit, so we just test the caps for bit depth

        if (strcasecmp(name, "video/x-raw") == 0)
        {
            if (!format)
                return 0;

            if (strcasecmp(format, "BGR") == 0) {
                depth = 3;
            }
            else if( (strcasecmp(format, "UYVY") == 0) || (strcasecmp(format, "YUY2") == 0) || (strcasecmp(format, "YVYU") == 0) ){
                depth = 2;
            }
            else if( (strcasecmp(format, "NV12") == 0) || (strcasecmp(format, "NV21") == 0) || (strcasecmp(format, "YV12") == 0) || (strcasecmp(format, "I420") == 0) ){
                depth = 1;
                height_extend = true;
            }
            else if(strcasecmp(format, "GRAY8") == 0){
                depth = 1;
            }
        }
        else if (strcasecmp(name, "video/x-bayer") == 0)
        {
            depth = 1;
        } else if(strcasecmp(name, "image/jpeg") == 0) {
            depth = 1;
            // the correct size will be set once the first frame arrives
            isOutputByteBuffer = true;
        }
#endif
        if (depth > 0) {
            if(height_extend){
                frame = cvCreateImageHeader(cvSize(width, height*3/2), IPL_DEPTH_8U, depth);
            }else{
                frame = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, depth);
            }
        } else {
            gst_caps_unref(buffer_caps);
            return 0;
        }

        gst_caps_unref(buffer_caps);
    }

    // gstreamer expects us to handle the memory at this point
    // so we can just wrap the raw buffer and be done with it
#if GST_VERSION_MAJOR == 0
    frame->imageData = (char *)GST_BUFFER_DATA(buffer);
#else
    // info.data ptr is valid until next grabFrame where the associated sample is unref'd
    GstMapInfo info = GstMapInfo();
    gboolean success = gst_buffer_map(buffer,&info, (GstMapFlags)GST_MAP_READ);

    // with MJPEG streams frame size can change arbitrarily
    if (isOutputByteBuffer && (size_t)info.size != (size_t)frame->imageSize)
    {
        cvReleaseImageHeader(&frame);
        frame = cvCreateImageHeader(cvSize(info.size, 1), IPL_DEPTH_8U, 1);
    }

    if (!success){
{'fraction_non_alphanumeric': 0.11090342679127727, 'fraction_numerical': 0.012876427829698858, 'mean_word_length': 2.59934220361788, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3503203', 'n_tokens_mistral': 7948, 'n_tokens_neox': 7569, 'n_words': 2195}