Recherche avancée

Médias (91)

Autres articles (80)

  • Le profil des utilisateurs

    12 avril 2011, par

    Chaque utilisateur dispose d’une page de profil lui permettant de modifier ses informations personnelle. Dans le menu de haut de page par défaut, un élément de menu est automatiquement créé à l’initialisation de MediaSPIP, visible uniquement si le visiteur est identifié sur le site.
    L’utilisateur a accès à la modification de profil depuis sa page auteur, un lien dans la navigation "Modifier votre profil" est (...)

  • Configurer la prise en compte des langues

    15 novembre 2010, par

    Accéder à la configuration et ajouter des langues prises en compte
    Afin de configurer la prise en compte de nouvelles langues, il est nécessaire de se rendre dans la partie "Administrer" du site.
    De là, dans le menu de navigation, vous pouvez accéder à une partie "Gestion des langues" permettant d’activer la prise en compte de nouvelles langues.
    Chaque nouvelle langue ajoutée reste désactivable tant qu’aucun objet n’est créé dans cette langue. Dans ce cas, elle devient grisée dans la configuration et (...)

  • Personnaliser les catégories

    21 juin 2013, par

    Formulaire de création d’une catégorie
    Pour ceux qui connaissent bien SPIP, une catégorie peut être assimilée à une rubrique.
    Dans le cas d’un document de type catégorie, les champs proposés par défaut sont : Texte
    On peut modifier ce formulaire dans la partie :
    Administration > Configuration des masques de formulaire.
    Dans le cas d’un document de type média, les champs non affichés par défaut sont : Descriptif rapide
    Par ailleurs, c’est dans cette partie configuration qu’on peut indiquer le (...)

Sur d’autres sites (13059)

  • Decoding MediaRecorder produced webm stream

    15 août 2019, par sgmg

    I am trying to decode a video stream from the browser using the ffmpeg API. The stream is produced by the webcam and recorded with MediaRecorder as webm format. What I ultimately need is a vector of opencv cv::Mat objects for further processing.

    I have written a C++ webserver using the uWebsocket library. The video stream is sent via websocket from the browser to the server once per second. On the server, I append the received data to my custom buffer and decode it with the ffmpeg API.

    If I just save the data on the disk and later I play it with a media player, it works fine. So, whatever the browser sends is a valid video.

    I do not think that I correctly understand how should the custom IO behave with network streaming as nothing seems to be working.

    The custom buffer :

    struct Buffer
       {
           std::vector data;
           int currentPos = 0;
       };

    The readAVBuffer method for custom IO

    int MediaDecoder::readAVBuffer(void* opaque, uint8_t* buf, int buf_size)
    {
       MediaDecoder::Buffer* mbuf = (MediaDecoder::Buffer*)opaque;
       int count = 0;
       for(int i=0;icurrentPos;
           if(index >= (int)mbuf->data.size())
           {
               break;
           }
           count++;
           buf[i] = mbuf->data.at(index);
       }
       if(count > 0) mbuf->currentPos+=count;

       std::cout << "read : "<currentPos<<", buff size:"<data.size() << std::endl;
       if(count <= 0) return AVERROR(EAGAIN); //is this error that should be returned? It cannot be EOF since we're not done yet, most likely
       return count;
    }

    The big decode method, that’s supposed to return whatever frames it could read

    std::vector MediaDecoder::decode(const char* data, size_t length)
    {
       std::vector frames;
       //add data to the buffer
       for(size_t i=0;i/do not invoke the decoders until we have 1MB of data
       if(((buf.data.size() - buf.currentPos) < 1*1024*1024) && !initializedCodecs) return frames;

       std::cout << "decoding data length "</initialize ffmpeg objects. Custom I/O, format, decoder, etc.
       {      
           //these are just members of the class
           avioCtxPtr = std::unique_ptr(
                       avio_alloc_context((uint8_t*)av_malloc(4096),4096,0,&buf,&readAVBuffer,nullptr,nullptr),
                       avio_context_deleter());
           if(!avioCtxPtr)
           {
               std::cerr << "Could not create IO buffer" << std::endl;
               return frames;
           }                

           fmt_ctx = std::unique_ptr(avformat_alloc_context(),
                                                                             avformat_context_deleter());
           fmt_ctx->pb = avioCtxPtr.get();
           fmt_ctx->flags |= AVFMT_FLAG_CUSTOM_IO ;
           //fmt_ctx->max_analyze_duration = 2 * AV_TIME_BASE; // read 2 seconds of data
           {
               AVFormatContext *fmtCtxRaw = fmt_ctx.get();            
               if (avformat_open_input(&fmtCtxRaw, "", nullptr, nullptr) < 0) {
                   std::cerr << "Could not open movie" << std::endl;
                   return frames;
               }
           }
           if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
               std::cerr << "Could not find stream information" << std::endl;
               return frames;
           }
           if((video_stream_idx = av_find_best_stream(fmt_ctx.get(), AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0)) < 0)
           {
               std::cerr << "Could not find video stream" << std::endl;
               return frames;
           }
           AVStream *video_stream = fmt_ctx->streams[video_stream_idx];
           AVCodec *dec = avcodec_find_decoder(video_stream->codecpar->codec_id);

           video_dec_ctx = std::unique_ptr (avcodec_alloc_context3(dec),
                                                                                 avcodec_context_deleter());
           if (!video_dec_ctx)
           {
               std::cerr << "Failed to allocate the video codec context" << std::endl;
               return frames;
           }
           avcodec_parameters_to_context(video_dec_ctx.get(),video_stream->codecpar);
           video_dec_ctx->thread_count = 1;
          /* video_dec_ctx->max_b_frames = 0;
           video_dec_ctx->frame_skip_threshold = 10;*/

           AVDictionary *opts = nullptr;
           av_dict_set(&opts, "refcounted_frames", "1", 0);
           av_dict_set(&opts, "deadline", "1", 0);
           av_dict_set(&opts, "auto-alt-ref", "0", 0);
           av_dict_set(&opts, "lag-in-frames", "1", 0);
           av_dict_set(&opts, "rc_lookahead", "1", 0);
           av_dict_set(&opts, "drop_frame", "1", 0);
           av_dict_set(&opts, "error-resilient", "1", 0);

           int width = video_dec_ctx->width;
           videoHeight = video_dec_ctx->height;

           if(avcodec_open2(video_dec_ctx.get(), dec, &opts) < 0)
           {
               std::cerr << "Failed to open the video codec context" << std::endl;
               return frames;
           }

           AVPixelFormat  pFormat = AV_PIX_FMT_BGR24;
           img_convert_ctx = std::unique_ptr(sws_getContext(width, videoHeight,
                                            video_dec_ctx->pix_fmt,   width, videoHeight, pFormat,
                                            SWS_BICUBIC, nullptr, nullptr,nullptr),swscontext_deleter());

           frame = std::unique_ptr(av_frame_alloc(),avframe_deleter());
           frameRGB = std::unique_ptr(av_frame_alloc(),avframe_deleter());


           int numBytes = av_image_get_buffer_size(pFormat, width, videoHeight,32 /*https://stackoverflow.com/questions/35678041/what-is-linesize-alignment-meaning*/);
           std::unique_ptr imageBuffer((uint8_t *) av_malloc(numBytes*sizeof(uint8_t)),avbuffer_deleter());
           av_image_fill_arrays(frameRGB->data,frameRGB->linesize,imageBuffer.get(),pFormat,width,videoHeight,32);
           frameRGB->width = width;
           frameRGB->height = videoHeight;

           initializedCodecs = true;
       }    
       AVPacket pkt;
       av_init_packet(&pkt);
       pkt.data = nullptr;
       pkt.size = 0;

       int read_frame_return = 0;
       while ( (read_frame_return=av_read_frame(fmt_ctx.get(), &pkt)) >= 0)
       {
           readFrame(&frames,&pkt,video_dec_ctx.get(),frame.get(),img_convert_ctx.get(),
                     videoHeight,frameRGB.get());
           //if(cancelled) break;
       }
       avioCtxPtr->eof_reached = 0;
       avioCtxPtr->error = 0;


       //flush
      // readFrame(frames.get(),nullptr,video_dec_ctx.get(),frame.get(),
        //         img_convert_ctx.get(),videoHeight,frameRGB.get());

       avioCtxPtr->eof_reached = 0;
       avioCtxPtr->error = 0;

       if(frames->size() <= 0)
       {
           std::cout << "buffer pos: "<code>

    What I would expect to happen would be for a continuous extraction of cv::Mat frames as I feed it more and more data. What actually happens is that after the the buffer is fully read I see :

    [matroska,webm @ 0x507b450] Read error at pos. 1278266 (0x13813a)
    [matroska,webm @ 0x507b450] Seek to desired resync point failed. Seeking to earliest point available instead.

    And then no more bytes are read from the buffer even if later I increase the size of it.

    There is something terribly wrong I’m doing here and I don’t understand what.

  • Parsing The Clue Chronicles

    30 décembre 2018, par Multimedia Mike — Game Hacking

    A long time ago, I procured a 1999 game called Clue Chronicles : Fatal Illusion, based on the classic board game Clue, a.k.a. Cluedo. At the time, I was big into collecting old, unloved PC games so that I could research obscure multimedia formats.



    Surveying the 3 CD-ROMs contained in the box packaging revealed only Smacker (SMK) videos for full motion video which was nothing new to me or the multimedia hacking community at the time. Studying the mix of data formats present on the discs, I found a selection of straightforward formats such as WAV for audio and BMP for still images. I generally find myself more fascinated by how computer games are constructed rather than by playing them, and this mix of files has always triggered a strong “I could implement a new engine for this !” feeling in me, perhaps as part of the ScummVM project which already provides the core infrastructure for reimplementing engines for 2D adventure games.

    Tying all of the assets together is a custom high-level programming language. I have touched on this before in a blog post over a decade ago. The scripts are in a series of files bearing the extension .ini (usually reserved for configuration scripts, but we’ll let that slide). A representative sample of such a script can be found here :

    clue-chronicles-scarlet-1.txt

    What Is This Language ?
    At the time I first analyzed this language, I was still primarily a C/C++-minded programmer, with a decent amount of Perl experience as a high level language, and had just started to explore Python. I assessed this language to be “mildly object oriented with C++-type comments (‘//’) and reliant upon a number of implicit library functions”. Other people saw other properties. When I look at it nowadays, it reminds me a bit more of JavaScript than C++. I think it’s sort of a Rorschach test for programming languages.

    Strangely, I sort of had this fear that I would put a lot of effort into figuring out how to parse out the language only for someone to come along and point out that it’s a well-known yet academic language that already has a great deal of supporting code and libraries available as open source. Google for “spanish dolphins far side comic” for an illustration of the feeling this would leave me with.

    It doesn’t matter in the end. Even if such libraries exist, how easy would they be to integrate into something like ScummVM ? Time to focus on a workable approach to understanding and processing the format.

    Problem Scope
    So I set about to see if I can write a program to parse the language seen in these INI files. Some questions :

    1. How large is the corpus of data that I need to be sure to support ?
    2. What parsing approach should I take ?
    3. What is the exact language format ?
    4. Other hidden challenges ?

    To figure out how large the data corpus is, I counted all of the INI files on all of the discs. There are 138 unique INI files between the 3 discs. However, there are 146 unique INI files after installation. This leads to a hidden challenge described a bit later.

    What parsing approach should I take ? I worried a bit too much that I might not be doing this the “right” way. I’m trying to ignore doubts like this, like how “SQL Shame” blocked me on a task for a little while a few years ago as I concerned myself that I might not be using the purest, most elegant approach to the problem. I know I covered language parsing a lot time ago in university computer science education and there is a lot of academic literature to the matter. But sometimes, you just have to charge in and experiment and prototype and see what falls out. In doing so, I expect to have a better understanding of the problems that need to solved and the right questions to ask, not unlike that time that I wrote a continuous integration system from scratch because I didn’t actually know that “continuous integration” was the keyword I needed.

    Next, what is the exact language format ? I realized that parsing the language isn’t the first and foremost problem here– I need to know exactly what the language is. I need to know what the grammar are keywords are. In essence, I need to reverse engineer the language before I write a proper parser for it. I guess that fits in nicely with the historical aim of this blog (reverse engineering).

    Now, about the hidden challenges– I mentioned that there are 8 more INI files after the game installs itself. Okay, so what’s the big deal ? For some reason, all of the INI files are in plaintext on the CD-ROM but get compressed (apparently, according to file size ratios) when installed to the hard drive. This includes those 8 extra INI files. I thought to look inside the CAB installation archive file on the CD-ROM and the files were there… but all in compressed form. I suspect that one of the files forms the “root” of the program and is the launching point for the game.

    Parsing Approach
    I took a stab at parsing an INI file. My approach was to first perform lexical analysis on the file and create a list of 4 types : symbols, numbers, strings, and language elements ([]{}()=., :). Apparently, this is the kind of thing that Lex/Flex are good at. This prototyping tool is written in Python, but when I port this to ScummVM, it might be useful to call upon the services of Lex/Flex, or another lexical analyzer, for there are many. I have a feeling it will be easier to use better tools when I understand the full structure of the language based on the data available.

    The purpose of this tool is to explore all the possibilities of the existing corpus of INI files. To that end, I ran all 138 of the plaintext files through it, collected all of the symbols, and massaged the results, assuming that the symbols that occurred most frequently are probably core language features. These are all the symbols which occur more than 1000 times among all the scripts :

       6248 false
       5734 looping
       4390 scripts
       3877 layer
       3423 sequentialscript
       3408 setactive
       3360 file
       3257 thescreen
       3239 true
       3008 autoplay
       2914 offset
       2599 transparent
       2441 text
       2361 caption
       2276 add
       2205 ge
       2197 smackanimation
       2196 graphicscript
       2196 graphic
       1977 setstate
       1642 state
       1611 skippable
       1576 desc
       1413 delayscript
       1298 script
       1267 seconds
       1019 rect
    

    About That Compression
    I have sorted out at least these few details of the compression :

    bytes 0-3    "COMP" (a pretty strong sign that this is, in fact, compressed data)
    bytes 4-11   unknown
    bytes 12-15  size of uncompressed data
    bytes 16-19  size of compressed data (filesize - 20)
    bytes 20-    compressed payload
    

    The compression ratios are on the same order of gzip. I was hoping that it was stock zlib data. However, I have been unable to prove this. I wrote a Python script that scrubbed through the first 100 bytes of payload data and tried to get Python’s zlib.decompress to initialize– no luck. It’s frustrating to know that I’ll have to reverse engineer a compression algorithm that deals with just 8 total text files if I want to see this effort through to fruition.

    Update, January 15, 2019
    Some folks expressed interest in trying to sort out the details of the compression format. So I have posted a followup in which I post some samples and go into deeper details about things I have tried :

    Reverse Engineering Clue Chronicles Compression

    The post Parsing The Clue Chronicles first appeared on Breaking Eggs And Making Omelettes.

  • How to make your plugin configurable – Introducing the Piwik Platform

    18 septembre 2014, par Thomas Steur — Development

    This is the next post of our blog series where we introduce the capabilities of the Piwik platform (our previous post was How to add new pages and menu items to Piwik). This time you will learn how to define settings for your plugin. For this tutorial you will need to have basic knowledge of PHP.

    What can I do with settings ?

    The Settings API offers you a simple way to make your plugin configurable within the Admin interface of Piwik without having to deal with HTML, JavaScript, CSS or CSRF tokens. There are many things you can do with settings, for instance let users configure :

    • connection infos to a third party system such as a WordPress installation.
    • select a metric to be displayed in your widget
    • select a refresh interval for your widget
    • which menu items, reports or widgets should be displayed
    • and much more

    Getting started

    In this series of posts, we assume that you have already set up your development environment. If not, visit the Piwik Developer Zone where you’ll find the tutorial Setting up Piwik.

    To summarize the things you have to do to get setup :

    • Install Piwik (for instance via git).
    • Activate the developer mode : ./console development:enable --full.
    • Generate a plugin : ./console generate:plugin --name="MySettingsPlugin". There should now be a folder plugins/MySettingsPlugin.
    • And activate the created plugin under Settings => Plugins.

    Let’s start creating settings

    We start by using the Piwik Console to create a settings template :

    ./console generate:settings

    The command will ask you to enter the name of the plugin the settings should belong to. I will simply use the above chosen plugin name “MySettingsPlugin”. There should now be a file plugins/MySettingsPlugin/Settings.php which contains already some examples to get you started easily. To see the settings in action go to Settings => Plugin settings in your Piwik installation.

    Adding one or more settings

    Settings are added in the init() method of the settings class by calling the method addSetting() and passing an instance of a UserSetting or SystemSetting object. How to create a setting is explained in the next chapter.

    Customising a setting

    To create a setting you have to define a name along some options. For instance which input field should be displayed, what type of value you expect, a validator and more. Depending on the input field we might automatically validate the values for you. For example if you define available values for a select field then we make sure to validate and store only a valid value which provides good security out of the box.

    For a list of possible properties have a look at the SystemSetting and UserSetting API reference.

    class Settings extends \Piwik\Plugin\Settings
    {
       public $refreshInterval;

       protected function init()
       {
           $this->setIntroduction('Here you can specify the settings for this plugin.');

           $this->createRefreshIntervalSetting();
       }

       private function createRefreshIntervalSetting()
       {
           $this->refreshInterval = new UserSetting('refreshInterval', 'Refresh Interval');
           $this->refreshInterval->type = static::TYPE_INT;
           $this->refreshInterval->uiControlType = static::CONTROL_TEXT;
           $this->refreshInterval->uiControlAttributes = array('size' => 3);
           $this->refreshInterval->description = 'How often the value should be updated';
           $this->refreshInterval->inlineHelp = 'Enter a number which is >= 15';
           $this->refreshInterval->defaultValue = '30';
           $this->refreshInterval->validate = function ($value, $setting) {
               if ($value < 15) {
                   throw new \Exception('Value is invalid');
               }
           };

           $this->addSetting($this->refreshInterval);
       }
    }

    In this example you can see some of those properties. Here we create a setting named “refreshInterval” with the display name “Refresh Interval”. We want the setting value to be an integer and the user should enter this value in a text input field having the size 3. There is a description, an inline help and a default value of 30. The validate function makes sure to accept only integers that are at least 15, otherwise an error in the UI will be shown.

    You do not always have to specify a PHP type and a uiControlType. For instance if you specify a PHP type boolean we automatically display a checkbox by default. Similarly if you specify to display a checkbox we assume that you want a boolean value.

    Accessing settings values

    You can access the value of a setting in a widget, in a controller, in a report or anywhere you want. To access the value create an instance of your settings class and get the value like this :

    $settings = new Settings();
    $interval = $settings->refreshInterval->getValue()

    Type of settings

    The Piwik platform differentiates between UserSetting and SystemSetting. User settings can be configured by any logged in user and each user can configure the setting independently. The Piwik platform makes sure that settings are stored per user and that a user cannot see another users configuration.

    A system setting applies to all of your users. It can be configured only by a user who has super user access. By default, the value can be read only by a super user as well but often you want to have it readable by anyone or at least by logged in users. If you set a setting readable the value will still be only displayed to super users but you will always be able to access the value in the background.

    Imagine you are building a widget that fetches data from a third party system where you need to configure an API URL and token. While no regular user should see the value of both settings, the value should still be readable by any logged in user. Otherwise when logged in users cannot read the setting value then the data cannot be fetched in the background when this user wants to see the content of the widget. Solve this by making the setting readable by the current user :

    $setting->readableByCurrentUser = !Piwik::isUserIsAnonymous();

    Publishing your Plugin on the Marketplace

    In case you want to share your settings or your plugin with other Piwik users you can do this by pushing your plugin to a public GitHub repository and creating a tag. Easy as that. Read more about how to distribute a plugin.

    Advanced features

    Isn’t it easy to create settings for plugins ? We never even created a file ! The Settings API already offers many possibilities but it might not yet be as flexible as your use case requires. So let us know in case you are missing something and we hope to add this feature at some point in the future.

    If you have any feedback regarding our APIs or our guides in the Developer Zone feel free to send it to us.