SoroMoon
Posts: 3
Joined: Tue Aug 29, 2017 1:14 pm

Image_fx doesn't apply filter

Tue Aug 29, 2017 1:21 pm

I try to understand how to works the component "image_fx", and I found only one exemple. But unfortunately it doesn't work and I don't understand why, is there a supplementary flag to add, is it these code the problem, ... I am lost !! Someone have others examples with image_fx please ?


here is the code (and the link : https://gist.github.com/jvcleave/afb745c686b8456f5007)

Code: Select all

/*
Copyright (c) 2012, Broadcom Europe Ltd
Copyright (c) 2012, OtherCrashOverride
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions 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.
    * Neither the name of the copyright holder nor the
      names of its contributors may 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 COPYRIGHT HOLDER 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.
*/

// Video decode demo using OpenMAX IL though the ilcient helper library

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bcm_host.h"
#include "ilclient.h"

#define OMX_INIT_STRUCTURE(a) \
memset(&(a), 0, sizeof(a)); \
(a).nSize = sizeof(a); \
(a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
(a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
(a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
(a).nVersion.s.nStep = OMX_VERSION_STEP

static OMX_BUFFERHEADERTYPE* eglBuffer = NULL;
static COMPONENT_T* egl_render = NULL;
static COMPONENT_T* image_fx = NULL;
int frameCounter = 0;
static void* eglImage = 0;
OMX_IMAGEFILTERTYPE imageFilters[25];
void my_fill_buffer_done(void* data, COMPONENT_T* comp)
{
    
    if(frameCounter+1<25)
    {
        frameCounter++;
    }else
    {
        frameCounter=0;
    }
    OMX_CONFIG_IMAGEFILTERTYPE imagefilterConfig;
    OMX_INIT_STRUCTURE(imagefilterConfig); 
    imagefilterConfig.nPortIndex = 191;
    imagefilterConfig.eImageFilter = OMX_ImageFilterNegative;//imageFilters[frameCounter];
    
    OMX_SetConfig(ILC_GET_HANDLE(image_fx), OMX_IndexConfigCommonImageFilter, &imagefilterConfig);
    printf("frameCounter: %d \n", frameCounter);
  if (OMX_FillThisBuffer(ilclient_get_handle(egl_render), eglBuffer) != OMX_ErrorNone)
   {
      printf("OMX_FillThisBuffer failed in callback\n");
      exit(1);
   }
}


// Modified function prototype to work with pthreads
void *video_decode_test(void* arg)
{
   const char* filename = "/opt/vc/src/hello_pi/hello_video/test.h264";
   eglImage = arg;

   if (eglImage == 0)
   {
      printf("eglImage is null.\n");
      exit(1);
   }
    imageFilters[0] = OMX_ImageFilterNone;
    imageFilters[1] = OMX_ImageFilterNoise;
    imageFilters[2] = OMX_ImageFilterEmboss;
    imageFilters[3] = OMX_ImageFilterNegative;
    imageFilters[4] = OMX_ImageFilterSketch;
    imageFilters[5] = OMX_ImageFilterOilPaint;
    imageFilters[6] = OMX_ImageFilterHatch;
    imageFilters[7] = OMX_ImageFilterGpen;
    imageFilters[8] = OMX_ImageFilterAntialias;
    imageFilters[9] = OMX_ImageFilterDeRing;
    imageFilters[10] = OMX_ImageFilterSolarize;
    imageFilters[11] = OMX_ImageFilterWatercolor;
    imageFilters[12] = OMX_ImageFilterPastel;
    imageFilters[13] = OMX_ImageFilterSharpen;
    imageFilters[14] = OMX_ImageFilterFilm;
    imageFilters[15] = OMX_ImageFilterBlur;
    imageFilters[16] = OMX_ImageFilterSaturation;
    imageFilters[17] = OMX_ImageFilterDeInterlaceLineDouble;
    imageFilters[18] = OMX_ImageFilterDeInterlaceAdvanced;
    imageFilters[19] = OMX_ImageFilterColourSwap;
    imageFilters[20] = OMX_ImageFilterWashedOut;
    imageFilters[21] = OMX_ImageFilterColourPoint;
    imageFilters[22] = OMX_ImageFilterPosterise;
    imageFilters[23] = OMX_ImageFilterColourBalance;
    imageFilters[24] = OMX_ImageFilterCartoon;
   OMX_VIDEO_PARAM_PORTFORMATTYPE format;
   OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
    COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *clock = NULL;
   COMPONENT_T *list[6];
   TUNNEL_T tunnel[5];
   ILCLIENT_T *client;
   FILE *in;
   int status = 0;
   unsigned int data_len = 0;
    
   memset(list, 0, sizeof(list));
   memset(tunnel, 0, sizeof(tunnel));

   if((in = fopen(filename, "rb")) == NULL)
      return (void *)-2;

   if((client = ilclient_init()) == NULL)
   {
      fclose(in);
      return (void *)-3;
   }

   if(OMX_Init() != OMX_ErrorNone)
   {
      ilclient_destroy(client);
      fclose(in);
      return (void *)-4;
   }

   // callback
   ilclient_set_fill_buffer_done_callback(client, my_fill_buffer_done, 0);

   // create video_decode
   if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
      status = -14;
   list[0] = video_decode;

    // create image_fx
    if(ilclient_create_component(client, &image_fx, "image_fx", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
        status = -14;
    list[1] = image_fx;
    
    
   // create egl_render
   if(status == 0 && ilclient_create_component(client, &egl_render, "egl_render", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_OUTPUT_BUFFERS) != 0)
      status = -14;
   list[2] = egl_render;

   // create clock
   if(status == 0 && ilclient_create_component(client, &clock, "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
      status = -14;
   list[3] = clock;

   memset(&cstate, 0, sizeof(cstate)); 
   cstate.nSize = sizeof(cstate);
   cstate.nVersion.nVersion = OMX_VERSION;
   cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
   cstate.nWaitMask = 1;
   if(clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
      status = -13;

   // create video_scheduler
   if(status == 0 && ilclient_create_component(client, &video_scheduler, "video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
      status = -14;
   list[4] = video_scheduler;

    
    set_tunnel(tunnel, video_decode, 131, image_fx, 190);
    set_tunnel(tunnel+1, image_fx, 191, video_scheduler, 10);
    set_tunnel(tunnel+2, video_scheduler, 11, egl_render, 220);
    set_tunnel(tunnel+3, clock, 80, video_scheduler, 12);
    

   // setup clock tunnel first
   if(status == 0 && ilclient_setup_tunnel(tunnel+3, 0, 0) != 0)
      status = -15;
   else
      ilclient_change_component_state(clock, OMX_StateExecuting);

   if(status == 0)
      ilclient_change_component_state(video_decode, OMX_StateIdle);

   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
   format.nVersion.nVersion = OMX_VERSION;
   format.nPortIndex = 130;
   format.eCompressionFormat = OMX_VIDEO_CodingAVC;

   if(status == 0 &&
      OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
      ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0)
   {
      OMX_BUFFERHEADERTYPE *buf;
      int port_settings_changed = 0;
      int first_packet = 1;

#if 1
       OMX_PARAM_U32TYPE extra_buffers;
       OMX_INIT_STRUCTURE(extra_buffers);
       extra_buffers.nU32 = 5;
       
     
       if (OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamBrcmExtraBuffers, &extra_buffers) != OMX_ErrorNone)
       {
           printf("OMX_IndexParamBrcmExtraBuffers failed.\n");
           exit(1);
       }
#endif
      ilclient_change_component_state(video_decode, OMX_StateExecuting);

      while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
      {
         // feed data and wait until we get port settings changed
         unsigned char *dest = buf->pBuffer;

         // loop if at end
         if (feof(in))
            rewind(in);

         data_len += fread(dest, 1, buf->nAllocLen-data_len, in);

         if(port_settings_changed == 0 &&
            ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
             (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
                                                       ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
         {
            port_settings_changed = 1;

            if(ilclient_setup_tunnel(tunnel, 0, 0) != 0)
            {
               status = -7;
               break;
            }

            ilclient_change_component_state(video_scheduler, OMX_StateExecuting);

             // now setup tunnel to image_fx
             if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0)
             {
                 status = -192;
                 break;
             }
             
             // Set image_fx to executing
             ilclient_change_component_state(image_fx, OMX_StateExecuting);
             
            // now setup tunnel to egl_render
            if(ilclient_setup_tunnel(tunnel+2, 0, 1000) != 0)
            {
               status = -12;
               break;
            }

            // Set egl_render to idle
            ilclient_change_component_state(egl_render, OMX_StateIdle);

            // Enable the output port and tell egl_render to use the texture as a buffer
            //ilclient_enable_port(egl_render, 221); THIS BLOCKS SO CANT BE USED
            if (OMX_SendCommand(ILC_GET_HANDLE(egl_render), OMX_CommandPortEnable, 221, NULL) != OMX_ErrorNone)
            {
               printf("OMX_CommandPortEnable failed.\n");
               exit(1);
            }

            if (OMX_UseEGLImage(ILC_GET_HANDLE(egl_render), &eglBuffer, 221, NULL, eglImage) != OMX_ErrorNone)
            {
               printf("OMX_UseEGLImage failed.\n");
               exit(1);
            }

            // Set egl_render to executing
            ilclient_change_component_state(egl_render, OMX_StateExecuting);


            // Request egl_render to write data to the texture buffer
            if(OMX_FillThisBuffer(ILC_GET_HANDLE(egl_render), eglBuffer) != OMX_ErrorNone)
            {
               printf("OMX_FillThisBuffer failed.\n");
               exit(1);
            }
             
            OMX_CONFIG_IMAGEFILTERTYPE imagefilterConfig;
            OMX_INIT_STRUCTURE(imagefilterConfig); 
            imagefilterConfig.nPortIndex = 191;
            imagefilterConfig.eImageFilter = OMX_ImageFilterNegative;
             
            OMX_SetConfig(ILC_GET_HANDLE(image_fx), OMX_IndexConfigCommonImageFilter, &imagefilterConfig);
            printf("test\n");
             
         }
         if(!data_len)
            break;

         buf->nFilledLen = data_len;
         data_len = 0;

         buf->nOffset = 0;
         if(first_packet)
         {
            buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
            first_packet = 0;
         }
         else
            buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;

         if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
         {
            status = -6;
            break;
         } 
      }

      buf->nFilledLen = 0;
      buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;

      if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
         status = -20;

      // need to flush the renderer to allow video_decode to disable its input port
      ilclient_flush_tunnels(tunnel, 0);

      ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
   }

   fclose(in); 

   ilclient_disable_tunnel(tunnel);
   ilclient_disable_tunnel(tunnel+1);
   ilclient_disable_tunnel(tunnel+2);
    ilclient_disable_tunnel(tunnel+3);
   ilclient_teardown_tunnels(tunnel);

   ilclient_state_transition(list, OMX_StateIdle);
   ilclient_state_transition(list, OMX_StateLoaded);

   
    ilclient_cleanup_components(list);

#if 0
    //unwinding ilclient_cleanup_components but nothing prints?
    int i;
    OMX_ERRORTYPE error;
    
    i=0;
    while (list[i])
    {
        ilclient_return_events(list[i]);
        i++;
    }
    error = OMX_FreeHandle(ILC_GET_HANDLE(video_decode));
    if(error == OMX_ErrorNone)
    {
        printf("video_decode component FREED \n");
    }else
    {
        printf("video_decode component FREE FAIL\n");
    }
    error = OMX_FreeHandle(ILC_GET_HANDLE(video_scheduler));
    if(error == OMX_ErrorNone)
    {
        printf("video_scheduler component FREED\n");
    }
    else
    {
        printf("video_decode component FREE FAIL\n");
        
    }
    error = OMX_FreeHandle(ILC_GET_HANDLE(clock));
    if(error == OMX_ErrorNone)
    {
        printf("clock component FREED\n");
    }
    else
    {
        printf("clock component FREE FAIL\n");
        
    }
    error = OMX_FreeHandle(ILC_GET_HANDLE(image_fx));
    if(error == OMX_ErrorNone)
    {
        printf("image_fx component FREED\n");
    }else
    {
        printf("image_fx component FREE FAIL\n");
        
    }
    ilclient_cleanup_components(list); 
#endif
   OMX_Deinit();
   ilclient_destroy(client);
   return (void *)status;
}

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 18178
Joined: Sat Jul 30, 2011 7:41 pm

Re: Image_fx doesn't apply filter

Tue Aug 29, 2017 2:02 pm

Try raspistill - that has an effects mode and uses this component (via mmal). Note that some effects I was never able to get working, but a lot do.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Please direct all questions to the forum, I do not do support via PM.

SoroMoon
Posts: 3
Joined: Tue Aug 29, 2017 1:14 pm

Re: Image_fx doesn't apply filter

Tue Aug 29, 2017 2:27 pm

Hello, thanks four answer.

I do some research about your suggestion, but component from mmal is it compatible with openMax (especially with egl_render, i have some projects in my mind I want to do) ?


thanks.

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 18178
Joined: Sat Jul 30, 2011 7:41 pm

Re: Image_fx doesn't apply filter

Tue Aug 29, 2017 2:38 pm

The mmal component uses the image_fx component under the skin, so if it works in mmal, it should work in OpenMAX. But you cannot mix mmal and OpenMax.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Please direct all questions to the forum, I do not do support via PM.

SoroMoon
Posts: 3
Joined: Tue Aug 29, 2017 1:14 pm

Re: Image_fx doesn't apply filter

Tue Aug 29, 2017 4:12 pm

Hmm it will be difficult, I don't have a camera ... I will try to find a solution, thank you very much.

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 4593
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Image_fx doesn't apply filter

Tue Aug 29, 2017 8:24 pm

James is sort of right. Raspistill does allow the use of the image effects plugins, but built in to the camera component rather than image_fx.

omxplayer and Kodi use image_fx for deinterlacing.

A couple of things:
- check the return value from the OMX_SetConfig(OMX_IndexConfigCommonImageFilter) call.
- test with others of the image effects. video_decode when tunnelled produces a native image format that isn't supported by all the image effects. viewtopic.php?f=43&t=83353&start=25#p590941 was the last report as to which worked, and it appears to include negative as one that works in both video and stills mode, so I would expect it to work via video_decode/image_fx.
- alternatively set OMX_IndexParamBrcmDisableProprietaryTunnels to OMX_TRUE on the video_decode output port. That forces video decode to convert from the native format to standard planar, and that should be supported by all the effects.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
Please don't send PMs asking for support - use the forum.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

Return to “OpenMAX”

Who is online

Users browsing this forum: No registered users and 3 guests