Browse Source

Add Multimedia Feature:
1. add starfive private packages: v4l2_test, pp_test, sf-gst-omx, sf-omx-il, stfisp_setfile, wave511, wave521
v4l2_test: used to test v4l2 device
pp_test: used to switch format and resolution for framebuffer framework
sf-gst-omx: from gst-omx and compatible with the omx-il library
sf-omx-il: starfive openmax il library for VPU hardware decode
stfisp_setfile: this is the host build package, used to generate the isp registrer setting bin for v4l2 framework
wave511: this is chip&media decode hardware wave511 vendor code building
wave521: this is chip&media encode hardware wave521 vendor code building

2. Add the following gstreamer patch:
add patch to support gstreamer plugin fbdevsink NV12 format
add patch to support gst-play take priority to decoding h264/h265 with gst-omx plugin

Signed-off-by: sw.multimedia <sw.multimedia@starfivetech.com>
Signed-off-by: andy.hu <andy.hu@starfivetech.com>
Signed-off-by: michael.yan <michael.yan@starfivetech.com>
Signed-off-by: david.li <david.li@starfivetech.com>
Signed-off-by: Curry Zhang <curry.zhang@starfivetech.com>
Signed-off-by: keithzhao <keith.zhao@starfivetech.com>

sw.multimedia 2 years ago
parent
commit
fce6b25d98
35 changed files with 5501 additions and 0 deletions
  1. 4 0
      package/Config.in
  2. 1 0
      package/Config.in.host
  3. 72 0
      package/gstreamer1/gst1-plugins-bad/0001-add-I420.patch
  4. 89 0
      package/gstreamer1/gst1-plugins-base/0001-quit-when-pipeline-interrupted.patch
  5. 7 0
      package/starfive/Config.in
  6. 7 0
      package/starfive/pp_test/Config.in
  7. 586 0
      package/starfive/pp_test/pp_test.c
  8. 17 0
      package/starfive/pp_test/pp_test.mk
  9. 69 0
      package/starfive/sf-gst-omx/0001-add-starfive-support.patch
  10. 70 0
      package/starfive/sf-gst-omx/0002-Fix-gst-omx-Enable-the-gst-omx-VPU-decoding-and-enco.patch
  11. 50 0
      package/starfive/sf-gst-omx/0003-add-video-scale-support.patch
  12. 19 0
      package/starfive/sf-gst-omx/0004-rank-257-for-sf-codecs.patch
  13. 11 0
      package/starfive/sf-gst-omx/Config.in
  14. 3 0
      package/starfive/sf-gst-omx/sf-gst-omx.hash
  15. 36 0
      package/starfive/sf-gst-omx/sf-gst-omx.mk
  16. 7 0
      package/starfive/sf-omx-il/Config.in
  17. 42 0
      package/starfive/sf-omx-il/sf-omx-il.mk
  18. 1 0
      package/starfive/starfive.mk
  19. 4 0
      package/starfive/stfisp_setfile/Config.in.host
  20. 900 0
      package/starfive/stfisp_setfile/stfisp_setfile.c
  21. 18 0
      package/starfive/stfisp_setfile/stfisp_setfile.mk
  22. 18 0
      package/starfive/v4l2_test/Config.in
  23. 92 0
      package/starfive/v4l2_test/config.h
  24. 812 0
      package/starfive/v4l2_test/convert.c
  25. 20 0
      package/starfive/v4l2_test/convert.h
  26. 283 0
      package/starfive/v4l2_test/pipeline_setting.sh
  27. 172 0
      package/starfive/v4l2_test/string.c
  28. 1763 0
      package/starfive/v4l2_test/v4l2_test.c
  29. 29 0
      package/starfive/v4l2_test/v4l2_test.mk
  30. 126 0
      package/starfive/v4l2_test/yuv.c
  31. 10 0
      package/starfive/v4l2_test/yuv.h
  32. 6 0
      package/starfive/wave511/Config.in
  33. 75 0
      package/starfive/wave511/wave511.mk
  34. 8 0
      package/starfive/wave521/Config.in
  35. 74 0
      package/starfive/wave521/wave521.mk

+ 4 - 0
package/Config.in

@@ -2477,4 +2477,8 @@ menu "Text editors and viewers"
 	source "package/vim/Config.in"
 endmenu
 
+menu "starfive packages"
+	source "package/starfive/Config.in"
+endmenu
+
 endmenu

+ 1 - 0
package/Config.in.host

@@ -90,5 +90,6 @@ menu "Host utilities"
 	source "package/xorriso/Config.in.host"
 	source "package/zip/Config.in.host"
 	source "package/zstd/Config.in.host"
+	source "package/starfive/stfisp_setfile/Config.in.host"
 
 endmenu

+ 72 - 0
package/gstreamer1/gst1-plugins-bad/0001-add-I420.patch

@@ -0,0 +1,72 @@
+--- a/sys/fbdev/gstfbdevsink.c	2021-07-06 16:02:46.304928800 +0800
++++ b/sys/fbdev/gstfbdevsink.c	2021-07-06 16:02:11.593693100 +0800
+@@ -73,7 +73,7 @@
+ static GstStateChangeReturn gst_fbdevsink_change_state (GstElement * element,
+     GstStateChange transition);
+ 
+-#define VIDEO_CAPS "{ RGB, BGR, BGRx, xBGR, RGB, RGBx, xRGB, RGB15, RGB16 }"
++#define VIDEO_CAPS "{ RGB, BGR, BGRx, xBGR, RGB, RGBx, xRGB, RGB15, RGB16, I420, NV12, NV21 }"
+ 
+ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+     GST_PAD_SINK,
+@@ -133,7 +133,10 @@
+   /* FIXME: locking */
+   if (!fbdevsink->framebuffer)
+     goto done;
+-
++  if (fbdevsink->varinfo.grayscale == 1) {
++    format = GST_VIDEO_FORMAT_NV12;
++    goto common;
++  }
+   bpp = fbdevsink->varinfo.bits_per_pixel;
+ 
+   rmask = ((1 << fbdevsink->varinfo.red.length) - 1)
+@@ -182,6 +185,8 @@
+   if (format == GST_VIDEO_FORMAT_UNKNOWN)
+     goto unknown_format;
+ 
++common:
++
+   caps = gst_caps_make_writable (caps);
+   gst_caps_set_simple (caps, "format", G_TYPE_STRING,
+       gst_video_format_to_string (format), NULL);
+@@ -272,12 +277,33 @@
+   if (!gst_buffer_map (buf, &map, GST_MAP_READ))
+     return GST_FLOW_ERROR;
+ 
+-  for (i = 0; i < fbdevsink->lines; i++) {
+-    memcpy (fbdevsink->framebuffer
+-        + (i + fbdevsink->cy) * fbdevsink->fixinfo.line_length
+-        + fbdevsink->cx * fbdevsink->bytespp,
+-        map.data + i * fbdevsink->width * fbdevsink->bytespp,
+-        fbdevsink->linelen);
++  if (fbdevsink->varinfo.grayscale == 1) {
++    int screen_offset = fbdevsink->varinfo.xres * fbdevsink->varinfo.yres;
++    int buffer_offset = fbdevsink->height * fbdevsink->width;
++
++    for (i = 0; i < fbdevsink->lines; i++) {
++      memcpy (fbdevsink->framebuffer
++          + (i + fbdevsink->cy) * fbdevsink->varinfo.xres
++          + fbdevsink->cx * 1,
++          map.data + i * fbdevsink->width * 1,
++          fbdevsink->width);
++    }
++
++    for (i = 0; i < fbdevsink->lines/2; i++) {
++      memcpy (fbdevsink->framebuffer + screen_offset
++          + (i + fbdevsink->cy/2) * fbdevsink->varinfo.xres
++          + fbdevsink->cx * 1,
++          map.data + buffer_offset + i * fbdevsink->width * 1,
++          fbdevsink->width);
++    }  
++  } else {
++    for (i = 0; i < fbdevsink->lines; i++) {
++      memcpy (fbdevsink->framebuffer
++          + (i + fbdevsink->cy) * fbdevsink->fixinfo.line_length
++          + fbdevsink->cx * fbdevsink->bytespp,
++          map.data + i * fbdevsink->width * fbdevsink->bytespp,
++          fbdevsink->linelen);
++    } 
+   }
+ 
+   gst_buffer_unmap (buf, &map);

+ 89 - 0
package/gstreamer1/gst1-plugins-base/0001-quit-when-pipeline-interrupted.patch

@@ -0,0 +1,89 @@
+diff -Naur a/tools/gst-play.c b/tools/gst-play.c
+--- a/tools/gst-play.c	2021-08-23 21:24:52.832142074 +0800
++++ b/tools/gst-play.c	2021-08-23 19:27:34.292506541 +0800
+@@ -104,6 +104,32 @@
+   gdouble rate;
+ } GstPlay;
+ 
++#if defined(G_OS_UNIX)
++static guint signal_watch_intr_id;
++#endif
++
++#if defined(G_OS_UNIX)
++/* As the interrupt handler is dispatched from GMainContext as a GSourceFunc
++ * handler, we can react to this by posting a message. */
++static gboolean
++intr_handler (gpointer user_data)
++{
++  GstElement *pipeline = (GstElement *) user_data;
++  GstPlay *play =  (GstPlay *) user_data;
++  gst_print ("handling interrupt.\n");
++
++  /* post an application specific message */
++  gst_element_post_message (GST_ELEMENT (play->playbin),
++      gst_message_new_application (GST_OBJECT (play->playbin),
++          gst_structure_new ("GstLaunchInterrupt",
++              "message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
++
++  /* remove signal handler */
++  signal_watch_intr_id = 0;
++  return G_SOURCE_REMOVE;
++}
++#endif /* G_OS_UNIX */
++
+ static gboolean quiet = FALSE;
+ static gboolean instant_rate_changes = FALSE;
+ 
+@@ -594,6 +620,24 @@
+       }
+       break;
+     }
++    case GST_MESSAGE_APPLICATION:{
++        const GstStructure *s;
++
++        s = gst_message_get_structure (msg);
++
++        if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
++          /* this application message is posted when we caught an interrupt and
++           * we need to stop the pipeline. */
++
++            gst_print (_("Interrupt: GST_MESSAGE_APPLICATION ...\n"));
++            if (play->desired_state == GST_STATE_PLAYING){
++               gst_print (_("Interrupt: Stopping pipeline ...\n"));
++               g_main_loop_quit (play->loop);  
++            }
++
++        }
++        break;
++      }
+     default:
+       if (gst_is_missing_plugin_message (msg)) {
+         gchar *desc;
+@@ -1622,6 +1666,12 @@
+     }
+   }
+ 
++#ifdef G_OS_UNIX
++    gst_print("g_source_remove signal_watch_intr_id \n");
++    signal_watch_intr_id =
++        g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, play);
++#endif
++
+   /* play */
+   do_play (play);
+ 
+@@ -1632,6 +1682,14 @@
+   g_free (video_sink);
+ 
+   gst_print ("\n");
++
++#ifdef G_OS_UNIX
++    if (signal_watch_intr_id > 0){
++      gst_print("g_source_remove signal_watch_intr_id \n");
++      g_source_remove (signal_watch_intr_id);
++    }
++#endif
++
+   gst_deinit ();
+   return 0;
+ }

+ 7 - 0
package/starfive/Config.in

@@ -0,0 +1,7 @@
+# starfive packages
+source "package/starfive/wave511/Config.in"
+source "package/starfive/wave521/Config.in"
+source "package/starfive/sf-gst-omx/Config.in"
+source "package/starfive/sf-omx-il/Config.in"
+source "package/starfive/v4l2_test/Config.in"
+source "package/starfive/pp_test/Config.in"

+ 7 - 0
package/starfive/pp_test/Config.in

@@ -0,0 +1,7 @@
+config BR2_PACKAGE_PP_TEST
+	bool "pp_test"
+
+	help
+	  pp test control format of src
+
+

+ 586 - 0
package/starfive/pp_test/pp_test.c

@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <stdbool.h>
+#include <asm/types.h>
+#include <linux/videodev2.h>
+// #include "jpeglib.h"
+// #include <libv4l2.h>
+#include <signal.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <linux/fb.h>
+
+enum COLOR_FORMAT{
+    COLOR_YUV422_UYVY = 0,  // 00={Y1,V0,Y0,U0}
+    COLOR_YUV422_VYUY = 1,  // 01={Y1,U0,Y0,V0}
+    COLOR_YUV422_YUYV = 2,  // 10={V0,Y1,U0,Y0}
+    COLOR_YUV422_YVYU = 3,  // 11={U0,Y1,V0,Y0}
+
+    COLOR_YUV420P,          // 4
+    COLOR_YUV420_NV21,      // 5
+    COLOR_YUV420_NV12,      // 6
+
+    COLOR_RGB888_ARGB,      // 7
+    COLOR_RGB888_ABGR,      // 8
+    COLOR_RGB888_RGBA,      // 9
+    COLOR_RGB888_BGRA,      // 10
+    COLOR_RGB565,           // 11
+};
+
+struct pp_video_mode {
+    enum COLOR_FORMAT format;
+    unsigned int height;
+    unsigned int width;
+    unsigned int addr;
+};
+
+struct pp_mode {
+    char pp_id;
+    bool bus_out;    /*out to ddr*/
+    bool fifo_out;    /*out to lcdc*/
+    bool inited;
+    struct pp_video_mode src;
+    struct pp_video_mode dst;
+};
+
+#define FBIOPAN_GET_PP_MODE    0x4609
+#define FBIOPAN_SET_PP_MODE    0x460a
+
+static unsigned char *g_fb_buf = NULL;
+static int g_fb_fd = -1;
+
+long g_screensize = 1920 * 1080 * 2;
+//static unsigned char jpegQuality = 70;
+struct fb_var_screeninfo g_vinfo;
+struct fb_fix_screeninfo g_finfo;
+
+static const char short_options[] = "f:";
+
+static const struct option long_options[] = {
+    { "format",     required_argument,      NULL,        'f' },
+    { 0, 0, 0, 0 }
+};
+
+/**
+    print usage information
+*/
+static void usage(FILE* fp, int argc, char** argv)
+{
+    fprintf(fp,
+        "Usage: %s [options]\n\n"
+        "Options:\n"
+        "-f | --format        image format RGB/Yuv\n"
+        "",
+        argv[0]);
+}
+
+/**
+    Write image to jpeg file.
+    \param img image to write
+*/
+int write_file (char * filename,unsigned char *image_buffer, int size)
+{
+    /*  More stuff */
+    FILE * outfile;               /*  target file */
+    if ((outfile = fopen(filename, "w+")) == NULL) {
+        fprintf(stderr, "can't open %s\n", filename);
+        return -1;
+    }
+    fwrite(image_buffer, size, 1, outfile);
+    fclose(outfile);
+    return 0 ;
+}
+
+//Y' = 0.257*R' + 0.504*G' + 0.098*B' + 16
+static int Rgb2Y(int r0, int g0, int b0)
+{
+    // float y0 = 0.257f*r0 + 0.504f*g0 + 0.098f*b0 + 16.0f;
+    // int y0 = (257*r0 + 504*g0 + 98*b0)/1000 + 16;
+    // Y = (77*R + 150*G + 29*B)>>8;
+    int y0 = (77*r0+150*g0+29*b0) >> 8;
+    return y0;
+}
+
+//U equals Cb'
+//Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
+static int Rgb2U(int r0, int g0, int b0)
+{
+    // float u0 = -0.148f*r0 - 0.291f*g0 + 0.439f*b0 + 128.0f;
+    // int u0 = (-148*r0 - 291*g0 + 439*b0)/1000 + 128;
+    // U = ((-44*R  - 87*G  + 131*B)>>8) + 128;
+    int u0 = ((-44*r0  - 87*g0  + 131*b0)>>8) + 128;
+    return u0;
+}
+
+//V equals Cr'
+//Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
+static int Rgb2V(int r0, int g0, int b0)
+{
+    // float v0 = 0.439f*r0 - 0.368f*g0 - 0.071f*b0 + 128.0f;
+    // int v0 = (439*r0 - 368*g0 - 71*b0)/1000 + 128;
+    // V = ((131*R - 110*G - 21*B)>>8) + 128 ;
+    int v0 = ((131*r0 - 110*g0 - 21*b0)>>8) + 128;
+    return v0;
+}
+
+//Convert two rows from RGB to two Y rows, and one row of interleaved U,V.
+//I0 and I1 points two sequential source rows.
+//I0 -> rgbrgbrgbrgbrgbrgb...
+//I1 -> rgbrgbrgbrgbrgbrgb...
+//Y0 and Y1 points two sequential destination rows of Y plane.
+//Y0 -> yyyyyy
+//Y1 -> yyyyyy
+//UV0 points destination rows of interleaved UV plane.
+//UV0 -> uvuvuv
+static void Rgb2NV12TwoRows(const unsigned char I0[],
+                            const unsigned char I1[],
+                            int step,
+                            const int image_width,
+                            unsigned char Y0[],
+                            unsigned char Y1[],
+                            unsigned char UV0[],
+                            int is_nv21)
+{
+    int x;  //Column index
+
+    //Process 4 source pixels per iteration (2 pixels of row I0 and 2 pixels of row I1).
+    for (x = 0; x < image_width; x += 2) {
+        //Load R,G,B elements from first row (and convert to int).
+        unsigned char b00 = (I0[x*step + 0] & 0x1F) << 3;
+        unsigned char g00 = ((I0[x*step + 1] & 0x7) << 3 | I0[x*step + 0] >> 5) << 2;
+        unsigned char r00 = I0[x*step + 1] & (~0x7);
+
+        //Load next R,G,B elements from first row (and convert to int).
+        unsigned char b01 = (I0[x*step + step+0] & 0x1F) << 3;
+        unsigned char g01 = ((I0[x*step + step+1] & 0x7) << 3 | I0[x*step + step+0] >> 5) << 2;
+        unsigned char r01 = I0[x*step + step+1] & (~0x7);
+
+        //Load R,G,B elements from second row (and convert to int).
+        unsigned char b10 = (I1[x*step + 0] & 0x1F) << 3;
+        unsigned char g10 = ((I1[x*step + 1] & 0x7) << 3 | I1[x*step + 0] >> 5) << 2;
+        unsigned char r10 = I1[x*step + 1] & (~0x7);
+
+        //Load next R,G,B elements from second row (and convert to int).
+        unsigned char b11 = (I1[x*step + step+0] & 0x1F) << 3;
+        unsigned char g11 = ((I1[x*step + step+1] & 0x7) << 3 | I1[x*step + step+0] >> 5) << 2;
+        unsigned char r11 = I1[x*step + step+1] & (~0x7);
+
+        //Calculate 4 Y elements.
+        unsigned char y00 = Rgb2Y(r00, g00, b00);
+        unsigned char y01 = Rgb2Y(r01, g01, b01);
+        unsigned char y10 = Rgb2Y(r10, g10, b10);
+        unsigned char y11 = Rgb2Y(r11, g11, b11);
+
+        //Calculate 4 U elements.
+        unsigned char u00 = Rgb2U(r00, g00, b00);
+        unsigned char u01 = Rgb2U(r01, g01, b01);
+        unsigned char u10 = Rgb2U(r10, g10, b10);
+        unsigned char u11 = Rgb2U(r11, g11, b11);
+
+        //Calculate 4 V elements.
+        unsigned char v00 = Rgb2V(r00, g00, b00);
+        unsigned char v01 = Rgb2V(r01, g01, b01);
+        unsigned char v10 = Rgb2V(r10, g10, b10);
+        unsigned char v11 = Rgb2V(r11, g11, b11);
+
+        //Calculate destination U element: average of 2x2 "original" U elements.
+        unsigned char u0 = (u00 + u01 + u10 + u11)/4;
+
+        //Calculate destination V element: average of 2x2 "original" V elements.
+        unsigned char v0 = (v00 + v01 + v10 + v11)/4;
+
+        //Store 4 Y elements (two in first row and two in second row).
+        Y0[x + 0]    = y00;
+        Y0[x + 1]    = y01;
+        Y1[x + 0]    = y10;
+        Y1[x + 1]    = y11;
+
+        if (is_nv21) {
+            // //Store destination U element.
+            UV0[x + 0]    = v0;
+
+            // //Store destination V element (next to stored U element).
+            UV0[x + 1]    = u0;
+        } else {
+            // //Store destination U element.
+            UV0[x + 0]    = u0;
+
+            // //Store destination V element (next to stored U element).
+            UV0[x + 1]    = v0;
+        }
+    }
+}
+
+//Convert image I from pixel ordered RGB to NV12 format.
+//I - Input image in pixel ordered RGB format
+//image_width - Number of columns of I
+//image_height - Number of rows of I
+//J - Destination "image" in NV12 format.
+
+//I is pixel ordered RGB color format (size in bytes is image_width*image_height*3):
+//RGBRGBRGBRGBRGBRGB
+//RGBRGBRGBRGBRGBRGB
+//RGBRGBRGBRGBRGBRGB
+//RGBRGBRGBRGBRGBRGB
+//
+//J is in NV12 format (size in bytes is image_width*image_height*3/2):
+//YYYYYY
+//YYYYYY
+//UVUVUV
+//Each element of destination U is average of 2x2 "original" U elements
+//Each element of destination V is average of 2x2 "original" V elements
+//
+//Limitations:
+//1. image_width must be a multiple of 2.
+//2. image_height must be a multiple of 2.
+//3. I and J must be two separate arrays (in place computation is not supported).
+void Rgb2NV12(const unsigned char I[], int step,
+              const int image_width,
+              const int image_height,
+              unsigned char J[],
+              int is_nv21)
+{
+    //In NV12 format, UV plane starts below Y plane.
+    // unsigned char *UV = &J[image_width*image_height];
+    unsigned char *UV = J;
+
+    //I0 and I1 points two sequential source rows.
+    const unsigned char *I0;  //I0 -> rgbrgbrgbrgbrgbrgb...
+    const unsigned char *I1;  //I1 -> rgbrgbrgbrgbrgbrgb...
+
+    //Y0 and Y1 points two sequential destination rows of Y plane.
+    unsigned char *Y0;    //Y0 -> yyyyyy
+    unsigned char *Y1;    //Y1 -> yyyyyy
+
+    //UV0 points destination rows of interleaved UV plane.
+    unsigned char *UV0; //UV0 -> uvuvuv
+
+    int y;  //Row index
+    int width, height;
+    int x_offset, y_offset;
+
+    width = image_width > g_vinfo.xres ? g_vinfo.xres : image_width;
+    height = image_height > g_vinfo.yres ? g_vinfo.yres : image_height;
+    x_offset = (g_vinfo.xres - width) / 2;
+    y_offset = (g_vinfo.yres - height) / 2;
+
+    //In each iteration: process two rows of Y plane, and one row of interleaved UV plane.
+    for (y = 0; y < height; y += 2)
+    {
+        I0 = &I[y*image_width*step];        //Input row width is image_width*3 bytes (each pixel is R,G,B).
+        I1 = &I[(y+1)*image_width*step];
+
+        Y0 = &J[(y+y_offset)*g_vinfo.xres+x_offset];            //Output Y row width is image_width bytes (one Y element per pixel).
+        Y1 = &J[(y+1+y_offset)*g_vinfo.xres+x_offset];
+
+        UV0 = &UV[g_vinfo.xres*g_vinfo.yres+((y+y_offset)/2*g_vinfo.xres/2+x_offset/2)*2];    //Output UV row - width is same as Y row width.
+
+        //Process two source rows into: Two Y destination row, and one destination interleaved U,V row.
+        Rgb2NV12TwoRows(I0,
+                        I1,
+                        step,
+                        width,
+                        Y0,
+                        Y1,
+                        UV0,
+                        is_nv21);
+    }
+}
+
+int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21)
+{
+    unsigned char *tmp = malloc(g_screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timespec ts_start, ts_end;
+
+    printf("convert rgb565 to %s\n", is_nv21 ? "nv21" : "nv12");
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+    Rgb2NV12(inBuf, 2, imgWidth, imgHeight, tmp, is_nv21);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
+    printf("%s: convert use %dms\n", __func__, end_timems - start_timems);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+    memcpy(outBuf, tmp, g_screensize);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
+    printf("%s: use %dms\n", __func__, end_timems - start_timems);
+
+    free(tmp);
+    return 0;
+}
+
+int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod)
+{
+    int rows ,cols;
+    unsigned char *RGB565data, *RGBdata;
+    int RGBpos;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(g_screensize);
+
+    printf("%s, %d\n", __func__, __LINE__);
+
+    width = imgWidth > g_vinfo.xres ? g_vinfo.xres : imgWidth;
+    height = imgHeight > g_vinfo.yres ? g_vinfo.yres : imgHeight;
+    x_offset = (g_vinfo.xres - width) / 2;
+    y_offset = (g_vinfo.yres - height) / 2;
+
+    RGB565data = inBuf;
+    RGBdata = tmp;
+
+    if (imgWidth == g_vinfo.xres) {
+        RGBpos = (y_offset * g_vinfo.xres + x_offset) * 2;
+        memcpy(&tmp[RGBpos], inBuf, imgWidth * height * 2);
+        memcpy(&outBuf[RGBpos], &tmp[RGBpos], imgWidth * height * 2);
+        // memcpy(&outBuf[RGBpos], inBuf, imgWidth * height * 2);
+        free(tmp);
+        return 0;
+    }
+
+    RGBpos = 0;
+    for(rows = 0; rows < imgHeight; rows++)
+    {
+        RGBdata = tmp + ((rows + y_offset) * g_vinfo.xres + x_offset) * g_vinfo.bits_per_pixel / 8;
+        RGBpos = rows * imgWidth * 2;
+        if (g_vinfo.bits_per_pixel == 16) {   // RGB565
+            memcpy(RGBdata, &RGB565data[RGBpos], imgWidth * 2);
+        } else {
+            for(cols = 0; cols < imgWidth; cols++)
+            {
+                *(RGBdata ++) = RGB565data[RGBpos] & 0x1F;
+                *(RGBdata ++) = (RGB565data[RGBpos + 1] & 0x7) << 3 | RGB565data[RGBpos] >> 5;
+                *(RGBdata ++) = RGB565data[RGBpos + 1] >> 3;
+                if (g_vinfo.bits_per_pixel == 32) {   // RGB888
+                    *(RGBdata ++) = 0xFF;
+                }
+                RGBpos += 2;
+            }
+        }
+    }
+
+    memcpy(outBuf, tmp, g_screensize);
+    free(tmp);
+    return 0;
+}
+
+static void deviceInit(void)
+{
+    g_fb_fd = open("/dev/fb0", O_RDWR);
+    if (g_fb_fd == -1) {
+        printf("Error: cannot open framebuffer device.\n");
+        exit (EXIT_FAILURE);
+    }
+
+    // Get fixed screen information
+    if (-1 == ioctl(g_fb_fd, FBIOGET_FSCREENINFO, &g_finfo)) {
+        printf("Error reading fixed information.\n");
+        exit (EXIT_FAILURE);
+    }
+
+    // Get variable screen information
+    if (-1 == ioctl(g_fb_fd, FBIOGET_VSCREENINFO, &g_vinfo)) {
+        printf("Error reading variable information.\n");
+        exit (EXIT_FAILURE);
+    }
+
+    printf("g_vinfo.xres = %d, g_vinfo.yres = %d, grayscale = %d\n", g_vinfo.xres, g_vinfo.yres, g_vinfo.grayscale);
+    printf("g_vinfo.xoffset = %d, g_vinfo.yoffset = %d\n", g_vinfo.xoffset, g_vinfo.yoffset);
+    printf("g_vinfo.bits_per_pixel = %d, g_finfo.line_length = %d\n", g_vinfo.bits_per_pixel, g_finfo.line_length);
+
+    g_screensize = g_vinfo.xres * g_vinfo.yres * g_vinfo.bits_per_pixel / 8;
+    //mmap framebuffer
+    g_fb_buf = (unsigned char *)mmap(NULL, g_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fb_fd, 0);
+    if (g_fb_buf == (void *)(-1)) {
+        printf("Error: failed to map framebuffer device to memory.\n");
+        exit (EXIT_FAILURE) ;
+    }
+    memset(g_fb_buf, 0x00, g_screensize);
+}
+
+static void deviceUninit(void)
+{
+    if (-1 == munmap((void *)g_fb_buf, g_screensize)) {
+        printf(" Error: framebuffer device munmap() failed.\n");
+        exit (EXIT_FAILURE) ;
+    }
+    close(g_fb_fd);
+}
+
+int main(int argc, char **argv)
+{
+    struct pp_mode pp_info[3];
+    int stfbc_fd = -1;
+    int format = 0;
+    int i, j;
+    unsigned char *rgb565demo_buffer = NULL;
+    int pixformat = COLOR_YUV420_NV21;  // or COLOR_RGB565
+
+    for (;;) {
+        int index, c = 0;
+        c = getopt_long(argc, argv, short_options, long_options, &index);
+        if (-1 == c) {
+            break;
+        }
+
+        switch (c) {
+        case 0: /* getopt_long() flag */
+            break;
+
+        case 'f':
+            printf("format: %s\n", optarg);
+            format = atoi(optarg);
+            switch (format) {
+            case  0:
+                pixformat = COLOR_RGB565;
+                break;
+            case  1:
+                pixformat = COLOR_RGB888_ARGB;
+                break;
+            case  2:
+                pixformat = COLOR_YUV420P;
+                break;
+            case  3:
+                pixformat = COLOR_YUV422_YUYV;
+                break;
+            case  4:
+                pixformat = COLOR_YUV420_NV21;
+                break;
+            case  5:
+                pixformat = COLOR_YUV420_NV12;
+                break;
+            case  6:
+                pixformat = COLOR_YUV422_YVYU;
+                break;
+            default:
+                pixformat = COLOR_RGB565;
+                break;
+            }
+            break;
+
+        default:
+            usage(stderr, argc, argv);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    stfbc_fd = open("/dev/stfbcdev", O_RDWR);
+    if (stfbc_fd == -1) {
+        printf("Error: cannot open framebuffer device./n");
+        exit (EXIT_FAILURE);
+    }
+
+    if (-1 == ioctl(stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) {
+        printf("Error reading variable information./n");
+        exit (EXIT_FAILURE);
+    }
+    printf(" get pp format :%d,%d\n",pp_info[1].src.format,__LINE__);
+
+    pp_info[1].src.format = pixformat;
+
+    if (-1 == ioctl(stfbc_fd, FBIOPAN_SET_PP_MODE, &pp_info[0])) {
+        printf("Error reading variable information./n");
+        exit (EXIT_FAILURE);
+    }
+
+    if (-1 == ioctl(stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) {
+        printf("Error reading variable information./n");
+        exit (EXIT_FAILURE);
+    }
+    printf(" get pp format :%d,%d\n",pp_info[1].src.format,__LINE__);
+    pixformat = pp_info[1].src.format;
+
+    deviceInit();
+
+    rgb565demo_buffer = malloc(g_screensize);
+    if (!rgb565demo_buffer) {
+        exit (EXIT_FAILURE);
+    }
+
+    unsigned char *dst = NULL;
+    dst = malloc(g_screensize);
+    if (!dst) {
+        exit (EXIT_FAILURE);
+    }
+
+    // init rgb raw data
+    for (j = 0; j < g_vinfo.yres/4; j++)
+        for (i = 0; i < g_vinfo.xres; i++) {
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)] = 0b00000000;
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)+1] = 0b11111000;
+        }
+    for (j = g_vinfo.yres/4; j < g_vinfo.yres/2; j++)
+        for (i = 0; i < g_vinfo.xres; i++) {
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)] = 0b11100000;
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)+1] = 0b00000111;
+    }
+
+    for (j = g_vinfo.yres/2; j < g_vinfo.yres * 3/4; j++)
+        for (i = 0; i < g_vinfo.xres; i++) {
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)] = 0b00011111;
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)+1] = 0b00000000;
+        }
+    for (j = g_vinfo.yres * 3/4; j < g_vinfo.yres; j++)
+        for (i = 0; i < g_vinfo.xres; i++) {
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)] = 0b11111111;
+            rgb565demo_buffer[2*(j*g_vinfo.xres+i)+1] = 0b11111111;
+        }
+    switch (pixformat) {
+    case COLOR_RGB565:
+        convert_rgb565_to_rgb(rgb565demo_buffer, g_fb_buf, g_vinfo.xres, g_vinfo.yres, 1);
+        convert_rgb565_to_rgb(rgb565demo_buffer, dst, g_vinfo.xres, g_vinfo.yres, 1);
+        write_file("test_format-rgb565.raw", dst, g_screensize);
+        break;
+    case COLOR_RGB888_ARGB:
+        break;
+    case COLOR_YUV420P:
+        break;
+    case COLOR_YUV422_YUYV:
+        break;
+    case COLOR_YUV420_NV21:
+        convert_rgb565_to_nv12(rgb565demo_buffer, g_fb_buf, g_vinfo.xres, g_vinfo.yres, 1);
+        convert_rgb565_to_nv12(rgb565demo_buffer, dst, g_vinfo.xres, g_vinfo.yres, 1);
+        write_file("test_format-nv21.raw", dst, g_screensize);
+        break;
+    case COLOR_YUV420_NV12:
+        convert_rgb565_to_nv12(rgb565demo_buffer, g_fb_buf, g_vinfo.xres, g_vinfo.yres, 0);
+        convert_rgb565_to_nv12(rgb565demo_buffer, dst, g_vinfo.xres, g_vinfo.yres, 0);
+        write_file("test_format-nv12.raw", dst, g_screensize);
+        break;
+    case COLOR_YUV422_YVYU:
+        break;
+    default:
+        break;
+    }
+
+    write_file("test_rgb565.raw", rgb565demo_buffer, g_screensize);
+    free(rgb565demo_buffer);
+    free(dst);
+    sleep(10);
+    deviceUninit();
+    return 0;
+}

+ 17 - 0
package/starfive/pp_test/pp_test.mk

@@ -0,0 +1,17 @@
+################################################################################
+#
+# pptest
+#
+################################################################################
+
+define PP_TEST_BUILD_CMDS
+	cp package/starfive/pp_test/pp_test.c $(@D)/
+	(cd $(@D); $(TARGET_CC) -Wall -O2 pp_test.c -o pp_test)
+endef
+
+define PP_TEST_INSTALL_TARGET_CMDS
+	install -m 0755 -D $(@D)/pp_test $(TARGET_DIR)/usr/bin/pp_test
+endef
+
+$(eval $(generic-package))
+

+ 69 - 0
package/starfive/sf-gst-omx/0001-add-starfive-support.patch

@@ -0,0 +1,69 @@
+diff --git a/config/meson.build b/config/meson.build
+index 1068c6d..7f8abe9 100755
+--- a/config/meson.build
++++ b/config/meson.build
+@@ -6,6 +6,8 @@ elif omx_target == 'zynqultrascaleplus'
+   sub = 'zynqultrascaleplus'
+ elif omx_target == 'tizonia'
+   sub = 'tizonia'
++ elif omx_target == 'stf'
++  sub = 'stf'
+ else
+   # No config file defined for the 'generic' target
+   sub = ''
+diff --git a/config/stf/gstomx.conf b/config/stf/gstomx.conf
+new file mode 100644
+index 0000000..b4cdebb
+--- /dev/null
++++ b/config/stf/gstomx.conf
+@@ -0,0 +1,17 @@
++[omxh265dec]
++type-name=GstOMXH265Dec
++core-name=/usr/lib/libsf-omx-il.so
++component-name=sf.dec.decoder.h265
++in-port-index=0
++out-port-index=1
++rank=0
++hacks=pass-profile-to-decoder;pass-color-format-to-decoder;ensure-buffer-count-actual
++
++[omxh264dec]
++type-name=GstOMXH264Dec
++core-name=/usr/lib/libsf-omx-il.so
++component-name=sf.dec.decoder.h264
++in-port-index=0
++out-port-index=1
++rank=1
++hacks=pass-profile-to-decoder;pass-color-format-to-decoder;ensure-buffer-count-actual
+diff --git a/config/stf/meson.build b/config/stf/meson.build
+new file mode 100644
+index 0000000..dc99c08
+--- /dev/null
++++ b/config/stf/meson.build
+@@ -0,0 +1 @@
++install_data (['gstomx.conf'], install_dir : omx_conf_dir)
+diff --git a/meson.build b/meson.build
+index 32c7fa7..aeda56a 100755
+--- a/meson.build
++++ b/meson.build
+@@ -216,6 +216,8 @@ elif omx_target == 'tizonia'
+   tizil_includedir = tizil_dep.get_pkgconfig_variable('includedir')
+   gst_omx_args += ['-I' + tizil_includedir + '/tizonia']
+   omx_inc = []
++elif omx_target == 'stf'
++  warning('stf selected')
+ else
+   error ('Unsupported omx target specified. Use the -Dtarget option')
+ endif
+diff --git a/meson_options.txt b/meson_options.txt
+index e18beb2..4fc6139 100755
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -1,7 +1,7 @@
+ option('header_path', type : 'string', value : '',
+     description : 'An extra include directory to find the OpenMax headers')
+ option('target', type : 'combo',
+-    choices : ['none', 'generic', 'rpi', 'bellagio', 'tizonia', 'zynqultrascaleplus'], value : 'none',
++    choices : ['none', 'generic', 'rpi', 'bellagio', 'tizonia', 'zynqultrascaleplus', 'stf'], value : 'none',
+     description : 'The OMX platform to target')
+ option('struct_packing', type : 'combo',
+     choices : ['0', '1', '2', '4', '8'], value : '0',

+ 70 - 0
package/starfive/sf-gst-omx/0002-Fix-gst-omx-Enable-the-gst-omx-VPU-decoding-and-enco.patch

@@ -0,0 +1,70 @@
+From 810800c303965e5cb0cf135210667c003f050ee0 Mon Sep 17 00:00:00 2001
+From: "andy.hu" <andy.hu@starfive.com>
+Date: Tue, 10 Aug 2021 19:18:00 +0800
+Subject: [PATCH] Fix(gst-omx): Enable the gst-omx VPU decoding and encoding
+ support h264 High L5.2
+
+---
+
+diff --git a/meson.build b/meson.build
+index aeda56a..48121ab 100644
+--- a/meson.build
++++ b/meson.build
+@@ -217,6 +217,7 @@ elif omx_target == 'tizonia'
+   gst_omx_args += ['-I' + tizil_includedir + '/tizonia']
+   omx_inc = []
+ elif omx_target == 'stf'
++  cdata.set('USE_OMX_TARGET_STARFIVE', 1)
+   warning('stf selected')
+ else
+   error ('Unsupported omx target specified. Use the -Dtarget option')
+diff --git a/omx/gstomxh264enc.c b/omx/gstomxh264enc.c
+index 51d84a8..875f974 100644
+--- a/omx/gstomxh264enc.c
++++ b/omx/gstomxh264enc.c
+@@ -824,6 +824,11 @@ gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
+       case OMX_VIDEO_AVCLevel51:
+         level = "5.1";
+         break;
++#ifdef USE_OMX_TARGET_STARFIVE
++      case OMX_VIDEO_AVCLevel52:
++        level = "5.2";
++        break;
++#else
+ #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+       case OMX_ALG_VIDEO_AVCLevel52:
+         level = "5.2";
+@@ -837,6 +842,7 @@ gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port,
+       case OMX_ALG_VIDEO_AVCLevel62:
+         level = "6.2";
+         break;
++#endif
+ #endif
+       default:
+         g_assert_not_reached ();
+diff --git a/omx/gstomxh264utils.c b/omx/gstomxh264utils.c
+index ba29211..a6e95e3 100644
+--- a/omx/gstomxh264utils.c
++++ b/omx/gstomxh264utils.c
+@@ -115,6 +115,10 @@ gst_omx_h264_utils_get_level_from_str (const gchar * level)
+     return OMX_VIDEO_AVCLevel5;
+   } else if (g_str_equal (level, "5.1")) {
+     return OMX_VIDEO_AVCLevel51;
++#ifdef USE_OMX_TARGET_STARFIVE
++  } else if (g_str_equal (level, "5.2")) {
++    return OMX_VIDEO_AVCLevel52;
++#else
+ #ifdef USE_OMX_TARGET_ZYNQ_USCALE_PLUS
+   } else if (g_str_equal (level, "5.2")) {
+     return (OMX_VIDEO_AVCLEVELTYPE) OMX_ALG_VIDEO_AVCLevel52;
+@@ -124,6 +128,7 @@ gst_omx_h264_utils_get_level_from_str (const gchar * level)
+     return (OMX_VIDEO_AVCLEVELTYPE) OMX_ALG_VIDEO_AVCLevel61;
+   } else if (g_str_equal (level, "6.2")) {
+     return (OMX_VIDEO_AVCLEVELTYPE) OMX_ALG_VIDEO_AVCLevel62;
++#endif
+ #endif
+   }
+
+-- 
+2.17.1
+

+ 50 - 0
package/starfive/sf-gst-omx/0003-add-video-scale-support.patch

@@ -0,0 +1,50 @@
+--- a/omx/gstomxvideodec.c	2020-10-26 19:17:03.000000000 +0800
++++ b/omx/gstomxvideodec.c	2021-08-16 16:23:08.082113380 +0800
+@@ -2185,6 +2185,7 @@
+ gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
+ {
+   OMX_VIDEO_PARAM_PORTFORMATTYPE param;
++  OMX_PARAM_PORTDEFINITIONTYPE port_def;
+   OMX_ERRORTYPE err;
+   GstCaps *comp_supported_caps;
+   GList *negotiation_map = NULL, *l;
+@@ -2192,6 +2193,7 @@
+   GstVideoFormat format;
+   GstStructure *s;
+   const gchar *format_str;
++  gint width, height;
+ 
+   GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream");
+ 
+@@ -2281,6 +2283,31 @@
+         gst_omx_error_to_string (err), err);
+   }
+ 
++  if (gst_structure_get_int(s, "width", &width) && gst_structure_get_int(s, "height", &height))
++  {
++    GST_OMX_INIT_STRUCT (&port_def);
++    port_def.nPortIndex = self->dec_out_port->index;
++    err = gst_omx_component_get_parameter (self->dec,
++        OMX_IndexParamPortDefinition, &port_def);
++    if (err != OMX_ErrorNone) {
++      GST_ERROR_OBJECT (self, "Failed to get video port definition: %s (0x%08x)",
++          gst_omx_error_to_string (err), err);
++      return FALSE;
++    }
++
++    port_def.format.video.nFrameHeight = height;
++    port_def.format.video.nFrameWidth = width;
++
++    err =
++      gst_omx_component_set_parameter (self->dec,
++      OMX_IndexParamPortDefinition, &port_def);
++    if (err != OMX_ErrorNone) {
++      GST_ERROR_OBJECT (self, "Failed to set video port definition: %s (0x%08x)",
++          gst_omx_error_to_string (err), err);
++      return FALSE;
++    }
++  }
++
+   gst_caps_unref (intersection);
+   return (err == OMX_ErrorNone);
+ }

+ 19 - 0
package/starfive/sf-gst-omx/0004-rank-257-for-sf-codecs.patch

@@ -0,0 +1,19 @@
+diff -Naur a/config/stf/gstomx.conf b/config/stf/gstomx.conf
+--- a/config/stf/gstomx.conf	2021-08-23 16:04:48.928905742 +0800
++++ b/config/stf/gstomx.conf	2021-08-23 16:03:38.590578856 +0800
+@@ -4,7 +4,7 @@
+ component-name=sf.dec.decoder.h265
+ in-port-index=0
+ out-port-index=1
+-rank=0
++rank=257
+ hacks=pass-profile-to-decoder;pass-color-format-to-decoder;ensure-buffer-count-actual
+ 
+ [omxh264dec]
+@@ -13,5 +13,5 @@
+ component-name=sf.dec.decoder.h264
+ in-port-index=0
+ out-port-index=1
+-rank=1
++rank=257
+ hacks=pass-profile-to-decoder;pass-color-format-to-decoder;ensure-buffer-count-actual

+ 11 - 0
package/starfive/sf-gst-omx/Config.in

@@ -0,0 +1,11 @@
+config SF_PACKAGE_GST_OMX
+	bool "sf-gst-omx"
+	depends on BR2_PACKAGE_SF_OMX_IL
+	select BR2_PACKAGE_GST1_PLUGINS_BASE
+	help
+	  GStreamer plug-in to use OpenMAX API.
+
+	  https://cgit.freedesktop.org/gstreamer/gst-omx
+
+comment "gst-omx requires a OpenMAX implementation"
+	depends on !BR2_PACKAGE_SF_OMX_IL

+ 3 - 0
package/starfive/sf-gst-omx/sf-gst-omx.hash

@@ -0,0 +1,3 @@
+# From https://gstreamer.freedesktop.org/src/gst-omx/gst-omx-1.18.1.tar.xz.sha256sum
+sha256  42a8e0f9518b94655981ede441638f9f9395f4b1b9a4b329f068ee793975a965  gst-omx-1.18.1.tar.xz
+sha256  dc626520dcd53a22f727af3ee42c770e56c97a64fe3adb063799d8ab032fe551  COPYING

+ 36 - 0
package/starfive/sf-gst-omx/sf-gst-omx.mk

@@ -0,0 +1,36 @@
+################################################################################
+#
+# sf-gst-omx
+#
+################################################################################
+
+SF_GST_OMX_VERSION = 1.18.1
+SF_GST_OMX_SOURCE = gst-omx-$(GST_OMX_VERSION).tar.xz
+SF_GST_OMX_SITE = https://gstreamer.freedesktop.org/src/gst-omx
+
+SF_GST_OMX_LICENSE = LGPL-2.1
+SF_GST_OMX_LICENSE_FILES = COPYING
+
+SF_GST_OMX_CONF_OPTS = \
+	-Dexamples=disabled \
+	-Dtests=disabled \
+	-Dtools=disabled \
+	-Ddoc=disabled
+
+
+SF_GST_OMX_VARIANT = stf
+SF_GST_OMX_CONF_OPTS += -Dheader_path=$(STAGING_DIR)/usr/include/omx-il
+
+SF_GST_OMX_CONF_OPTS += -Dtarget=$(SF_GST_OMX_VARIANT)
+
+SF_GST_OMX_DEPENDENCIES = gstreamer1 gst1-plugins-base sf-omx-il
+
+# adjust library paths to where buildroot installs them
+define SF_GST_OMX_FIXUP_CONFIG_PATHS
+	find $(@D)/config -name gstomx.conf | \
+		xargs $(SED) 's|/usr/local|/usr|g' -e 's|/opt/vc|/usr|g'
+endef
+
+SF_GST_OMX_POST_PATCH_HOOKS += SF_GST_OMX_FIXUP_CONFIG_PATHS
+
+$(eval $(meson-package))

+ 7 - 0
package/starfive/sf-omx-il/Config.in

@@ -0,0 +1,7 @@
+comment "wave511 package"
+
+config BR2_PACKAGE_SF_OMX_IL
+	bool "sf-omx-il"
+	depends on BR2_PACKAGE_WAVE511 && BR2_PACKAGE_WAVE521
+	help
+	  sf-omx-il package

+ 42 - 0
package/starfive/sf-omx-il/sf-omx-il.mk

@@ -0,0 +1,42 @@
+################################################################################
+#
+# OMX_IL
+#
+################################################################################
+
+
+SF_OMX_IL_VERSION:=1.0.0
+SF_OMX_IL_SITE=$(TOPDIR)/../soft_3rdpart/omx-il
+SF_OMX_IL_SITE_METHOD=local
+SF_OMX_IL_INSTALL_STAGING = YES
+
+SF_OMX_IL_DEPENDENCIES=wave511 wave521
+define SF_OMX_IL_BUILD_CMDS
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D)
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) wave521-test
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) wave511-test
+endef
+
+define SF_OMX_IL_CLEAN_CMDS
+
+endef
+
+define SF_OMX_IL_INSTALL_TARGET_CMDS
+	$(INSTALL) -m 0644 $(@D)/libsf-omx-il.so $(TARGET_DIR)/usr/lib/libsf-omx-il.so
+	$(INSTALL) -d $(@D)/include/khronos $(TARGET_DIR)/usr/include/omx-il
+	$(INSTALL) -m 0644 $(@D)/include/khronos/* $(TARGET_DIR)/usr/include/omx-il
+	$(INSTALL) -m 0777 $(@D)/wave521test $(TARGET_DIR)/root/wave521test
+endef
+
+define SF_OMX_IL_INSTALL_STAGING_CMDS
+	$(INSTALL) -m 0644 $(@D)/libsf-omx-il.so $(STAGING_DIR)/usr/lib/libsf-omx-il.so
+	$(INSTALL) -d $(@D)/include/khronos $(STAGING_DIR)/usr/include/omx-il
+	$(INSTALL) -m 0644 $(@D)/include/khronos/* $(STAGING_DIR)/usr/include/omx-il
+endef
+
+define SF_OMX_IL_UNINSTALL_TARGET_CMDS
+
+endef
+
+$(eval $(generic-package))
+

+ 1 - 0
package/starfive/starfive.mk

@@ -0,0 +1 @@
+include $(sort $(wildcard package/starfive/*/*.mk))

+ 4 - 0
package/starfive/stfisp_setfile/Config.in.host

@@ -0,0 +1,4 @@
+config BR2_PACKAGE_HOST_STFISP_SETFILE
+	bool "host generate isp fw"
+	help
+	  stfisp_setfile is a tool to generate ISP fw image

+ 900 - 0
package/starfive/stfisp_setfile/stfisp_setfile.c

@@ -0,0 +1,900 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+
+#ifndef VERSION
+#define VERSION "v0.0.1"
+#endif
+
+#define OV4689_SETFILE      "ov4689_stf_isp_fw.bin"
+#define OV4689_DUMP_SETFILE "ov4689_stf_isp_fw_dump.bin"
+#define SC2235_SETFILE      "sc2235_stf_isp_fw.bin"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+typedef unsigned int u32;
+
+typedef struct {
+    u32 addr;
+    u32 val;
+    u32 mask;
+    u32 delay_ms;
+} regval_t;
+
+struct reg_table {
+    const regval_t *regval;
+    int regval_num;
+};
+
+// 0x11BB, 0 1 0 1 2 3 2 3, R Gr R Gr Gb B Gb B
+static const regval_t isp_sc2235_reg_config_list[] = {
+    {0x00000014, 0x00000008, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000030, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000010, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000AC4, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004D, 0, 0},
+    {0x00000E44, 0x00000096, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001DA, 0, 0},
+    {0x00000E50, 0x000001B6, 0, 0},
+    {0x00000E54, 0x00000070, 0, 0},
+    {0x00000E58, 0x0000009D, 0, 0},
+    {0x00000E5C, 0x0000017C, 0, 0},
+    {0x00000E60, 0x000001E6, 0, 0},
+    {0x00000010, 0x00000000, 0, 0},
+    {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
+    {0x00000044, 0x00000000, 0, 0},
+    {0x00000008, 0x00010005, 0, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010004, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+
+// 0x11BB, 0 1 0 1 2 3 2 3, R Gr R Gr Gb B Gb B
+#if 0
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00F000F0, 0, 0},
+    {0x000002C4, 0x00F000F0, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00B000B0, 0, 0},
+    {0x000002DC, 0x00B000B0, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+#else
+/*   isp v3   
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x009D009D, 0, 0},
+    {0x000002C4, 0x009D009D, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00AF00AF, 0, 0},
+    {0x000002DC, 0x00AF00AF, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+*/
+
+
+//   20210802 v02
+/*
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x009D009D, 0, 0},
+    {0x000002C4, 0x009D009D, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00AF00AF, 0, 0},
+    {0x000002DC, 0x00AF00AF, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+*/
+// gammaoff_v01 
+/*
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00A500A5, 0, 0},
+    {0x000002C4, 0x00A500A5, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00A800A8, 0, 0},
+    {0x000002DC, 0x00A800A8, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+*/
+//gamaon_v01
+/*
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00A500A5, 0, 0},
+    {0x000002C4, 0x00A500A5, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00A800A8, 0, 0},
+    {0x000002DC, 0x00A800A8, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};*/
+//v02 gama off
+
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00C000C0, 0, 0},
+    {0x000002C4, 0x00C000C0, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00C400C4, 0, 0},
+    {0x000002DC, 0x00C400C4, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+
+//gama on v2
+/*
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00C000C0, 0, 0},
+    {0x000002C4, 0x00C000C0, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00C400C4, 0, 0},
+    {0x000002DC, 0x00C400C4, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+*/
+/* //isp  dump raw data
+static const regval_t isp_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000024, 0xfb000000, 0, 0}, // Buffer size = 3179520
+    {0x00000028, 0x00030B80, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00800080, 0, 0},
+    {0x000002C4, 0x00800080, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00800080, 0, 0},
+    {0x000002DC, 0x00800080, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+   // {0x00000010, 0x00000080, 0, 0},
+   {0x00000010, 0x00080080, 0, 0},
+    {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+
+};
+*/
+#endif
+static const regval_t isp_dump_1080p_reg_config_list[] = {
+    {0x00000014, 0x0000000D,0,0},
+    // {0x00000018, 0x000011BB,0,0},
+    {0x00000A1C, 0x00000032,0,0},
+    // {0x0000001C, 0x00000000,0,0},
+    // {0x00000020, 0x0437077F,0,0},
+    // {0x00000A0C, 0x04380780,0,0},
+    // {0x00000A80, 0xF9000000,0,0},
+    // {0x00000A84, 0xF91FA400,0,0},
+    {0x00000A88, 0x00000780,0,0},
+    // {0x00000024, 0xFB000000, 0, 0},// Buffer size = 3179520
+    {0x00000028, 0x00030B80, 0, 0},
+    {0x00000A8C, 0x00000000,0,0},
+    {0x00000A90, 0x00000000,0,0},
+    {0x00000E40, 0x0000004C,0,0},
+    {0x00000E44, 0x00000097,0,0},
+    {0x00000E48, 0x0000001D,0,0},
+    {0x00000E4C, 0x000001D5,0,0},
+    {0x00000E50, 0x000001AC,0,0},
+    {0x00000E54, 0x00000080,0,0},
+    {0x00000E58, 0x00000080,0,0},
+    {0x00000E5C, 0x00000194,0,0},
+    {0x00000E60, 0x000001EC,0,0},
+    {0x00000280, 0x00000000,0,0},
+    {0x00000284, 0x00000000,0,0},
+    {0x00000288, 0x00000000,0,0},
+    {0x0000028C, 0x00000000,0,0},
+    {0x00000290, 0x00000000,0,0},
+    {0x00000294, 0x00000000,0,0},
+    {0x00000298, 0x00000000,0,0},
+    {0x0000029C, 0x00000000,0,0},
+    {0x000002A0, 0x00000000,0,0},
+    {0x000002A4, 0x00000000,0,0},
+    {0x000002A8, 0x00000000,0,0},
+    {0x000002AC, 0x00000000,0,0},
+    {0x000002B0, 0x00000000,0,0},
+    {0x000002B4, 0x00000000,0,0},
+    {0x000002B8, 0x00000000,0,0},
+    {0x000002BC, 0x00000000,0,0},
+    {0x000002C0, 0x00800080, 0, 0},
+    {0x000002C4, 0x00800080, 0, 0},
+    {0x000002C8, 0x00800080,0,0},
+    {0x000002CC, 0x00800080,0,0},
+    {0x000002D0, 0x00800080,0,0},
+    {0x000002D4, 0x00800080,0,0},
+    {0x000002D8, 0x00800080, 0, 0},
+    {0x000002DC, 0x00800080, 0, 0},
+    {0x00000E00, 0x24000000,0,0},
+    {0x00000E04, 0x159500A5,0,0},
+    {0x00000E08, 0x0F9900EE,0,0},
+    {0x00000E0C, 0x0CE40127,0,0},
+    {0x00000E10, 0x0B410157,0,0},
+    {0x00000E14, 0x0A210181,0,0},
+    {0x00000E18, 0x094B01A8,0,0},
+    {0x00000E1C, 0x08A401CC,0,0},
+    {0x00000E20, 0x081D01EE,0,0},
+    {0x00000E24, 0x06B20263,0,0},
+    {0x00000E28, 0x05D802C7,0,0},
+    {0x00000E2C, 0x05420320,0,0},
+    {0x00000E30, 0x04D30370,0,0},
+    {0x00000E34, 0x047C03BB,0,0},
+    {0x00000E38, 0x043703FF,0,0},
+    {0x00000010, 0x00080080, 0, 0},
+    {0x00000A08, 0x10000032,0xFFFFFFF,0},
+    {0x00000A00, 0x00120002,0,0},
+    {0x00000A00, 0x00120000,0,0},
+    {0x00000A50, 0x00000002,0,0},
+    {0x00000A00, 0x00120001,0,0},
+    {0x00000008, 0x00010000,0,0},
+    {0x00000008, 0x0002000A,0,0},
+    {0x00000000, 0x00000001,0,0},
+};
+
+static const regval_t isp_imx219_reg_config_list[] = {
+    {0x00000014, 0x0000000D, 0, 0},
+    // {0x00000018, 0x000011BB, 0, 0},
+    {0x00000A1C, 0x00000032, 0, 0},
+    // {0x0000001C, 0x00000000, 0, 0},
+    // {0x00000020, 0x0437077F, 0, 0},
+    // {0x00000A0C, 0x04380780, 0, 0},
+    // {0x00000A80, 0xF9000000, 0, 0},
+    // {0x00000A84, 0xF91FA400, 0, 0},
+    // {0x00000A88, 0x00000780, 0, 0},
+    {0x00000A8C, 0x00000000, 0, 0},
+    {0x00000A90, 0x00000000, 0, 0},
+    {0x00000E40, 0x0000004C, 0, 0},
+    {0x00000E44, 0x00000097, 0, 0},
+    {0x00000E48, 0x0000001D, 0, 0},
+    {0x00000E4C, 0x000001D5, 0, 0},
+    {0x00000E50, 0x000001AC, 0, 0},
+    {0x00000E54, 0x00000080, 0, 0},
+    {0x00000E58, 0x00000080, 0, 0},
+    {0x00000E5C, 0x00000194, 0, 0},
+    {0x00000E60, 0x000001EC, 0, 0},
+    {0x00000280, 0x00000000, 0, 0},
+    {0x00000284, 0x00000000, 0, 0},
+    {0x00000288, 0x00000000, 0, 0},
+    {0x0000028C, 0x00000000, 0, 0},
+    {0x00000290, 0x00000000, 0, 0},
+    {0x00000294, 0x00000000, 0, 0},
+    {0x00000298, 0x00000000, 0, 0},
+    {0x0000029C, 0x00000000, 0, 0},
+    {0x000002A0, 0x00000000, 0, 0},
+    {0x000002A4, 0x00000000, 0, 0},
+    {0x000002A8, 0x00000000, 0, 0},
+    {0x000002AC, 0x00000000, 0, 0},
+    {0x000002B0, 0x00000000, 0, 0},
+    {0x000002B4, 0x00000000, 0, 0},
+    {0x000002B8, 0x00000000, 0, 0},
+    {0x000002BC, 0x00000000, 0, 0},
+    {0x000002C0, 0x00F000F0, 0, 0},
+    {0x000002C4, 0x00F000F0, 0, 0},
+    {0x000002C8, 0x00800080, 0, 0},
+    {0x000002CC, 0x00800080, 0, 0},
+    {0x000002D0, 0x00800080, 0, 0},
+    {0x000002D4, 0x00800080, 0, 0},
+    {0x000002D8, 0x00B000B0, 0, 0},
+    {0x000002DC, 0x00B000B0, 0, 0},
+    {0x00000E00, 0x24000000, 0, 0},
+    {0x00000E04, 0x159500A5, 0, 0},
+    {0x00000E08, 0x0F9900EE, 0, 0},
+    {0x00000E0C, 0x0CE40127, 0, 0},
+    {0x00000E10, 0x0B410157, 0, 0},
+    {0x00000E14, 0x0A210181, 0, 0},
+    {0x00000E18, 0x094B01A8, 0, 0},
+    {0x00000E1C, 0x08A401CC, 0, 0},
+    {0x00000E20, 0x081D01EE, 0, 0},
+    {0x00000E24, 0x06B20263, 0, 0},
+    {0x00000E28, 0x05D802C7, 0, 0},
+    {0x00000E2C, 0x05420320, 0, 0},
+    {0x00000E30, 0x04D30370, 0, 0},
+    {0x00000E34, 0x047C03BB, 0, 0},
+    {0x00000E38, 0x043703FF, 0, 0},
+    {0x00000010, 0x00000080, 0, 0},
+    {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+    {0x00000A00, 0x00120002, 0, 0},
+    {0x00000A00, 0x00120000, 0, 0},
+    {0x00000A50, 0x00000002, 0, 0},
+    {0x00000A00, 0x00120001, 0, 0},
+    {0x00000008, 0x00010000, 0, 0},
+    {0x00000008, 0x0002000A, 0, 0},
+    {0x00000000, 0x00000001, 0, 0},
+};
+
+const struct reg_table isp_1920_1080_settings[] = {
+    {isp_1080p_reg_config_list,
+    ARRAY_SIZE(isp_1080p_reg_config_list)},
+};
+
+const struct reg_table isp_dump_1920_1080_settings[] = {
+    {isp_dump_1080p_reg_config_list,
+    ARRAY_SIZE(isp_dump_1080p_reg_config_list)},
+};
+
+const struct reg_table isp_sc2235_settings[] = {
+    {isp_sc2235_reg_config_list,
+    ARRAY_SIZE(isp_sc2235_reg_config_list)},
+};
+
+/**
+    print usage information
+*/
+static void usage(FILE* fp, int argc, char** argv)
+{
+    fprintf(fp,
+        "Usage: %s [options]\n\n"
+        "Options:\n"
+        "-i | --input        Set input filename\n"
+        "-o | --output       Set output filename\n"
+        "-h | --help         Print this message\n"
+        "-v | --version      Print version\n"
+        "",
+        argv[0]);
+    }
+
+static const char short_options [] = "hv";
+
+static const struct option
+long_options [] = {
+    { "help",      no_argument,            NULL,        'h' },
+    { "version",   no_argument,            NULL,        'v' },
+    { 0, 0, 0, 0 }
+};
+
+int write_file (char * filename, unsigned char *image_buffer, int size)
+{
+    FILE * outfile;               /*  target file */
+    if ((outfile = fopen(filename, "w+")) == NULL) {
+        fprintf(stderr, "can't open %s\n", filename);
+        return -1;
+    }
+
+    fwrite(image_buffer, size * sizeof(regval_t), 1, outfile);
+    fwrite(&size, sizeof(int), 1, outfile);
+
+    fclose(outfile);
+    return 0 ;
+}
+
+int main(int argc, char **argv)
+{
+    for (;;) {
+        int index, c = 0;
+        c = getopt_long(argc, argv, short_options, long_options, &index);
+        if (-1 == c)
+            break;
+
+        switch (c) {
+        case 0: /* getopt_long() flag */
+            break;
+
+        case 'h':
+            // print help
+            usage(stdout, argc, argv);
+            exit(EXIT_SUCCESS);
+
+        case 'v':
+            printf("Version: %s\n", VERSION);
+            exit(EXIT_SUCCESS);
+            break;
+
+        default:
+            usage(stderr, argc, argv);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    printf("isp_1920_1080_settings size: %d, sizeof(regval_t): %lu, sizeof(int): %lu\n",
+            isp_1920_1080_settings->regval_num, sizeof(regval_t), sizeof(int));
+    write_file(OV4689_SETFILE, (unsigned char *)isp_1920_1080_settings->regval,
+            isp_1920_1080_settings->regval_num);
+
+    printf("isp_dump_1920_1080_settings size: %d, sizeof(regval_t): %lu, sizeof(int): %lu\n",
+            isp_dump_1920_1080_settings->regval_num, sizeof(regval_t), sizeof(int));
+    write_file(OV4689_DUMP_SETFILE, (unsigned char *)isp_dump_1920_1080_settings->regval,
+            isp_dump_1920_1080_settings->regval_num);
+
+    printf("isp_sc2235_settings size: %d, sizeof(regval_t): %lu\n",
+            isp_sc2235_settings->regval_num, sizeof(regval_t));
+    write_file(SC2235_SETFILE, (unsigned char *)isp_sc2235_settings->regval,
+            isp_sc2235_settings->regval_num);
+    return 0;
+}

+ 18 - 0
package/starfive/stfisp_setfile/stfisp_setfile.mk

@@ -0,0 +1,18 @@
+################################################################################
+#
+# stfisp_setfile 
+#
+################################################################################
+
+STFISP_SETFILE_LICENSE = GPL-2.0+
+
+define HOST_STFISP_SETFILE_BUILD_CMDS
+	cp package/starfive/stfisp_setfile/stfisp_setfile.c $(@D)/
+	(cd $(@D); $(HOSTCC) -Wall -O2 stfisp_setfile.c -o stfisp_setfile; ./stfisp_setfile)
+	install -m 0755 -D $(@D)/ov4689_stf_isp_fw.bin $(TARGET_DIR)/lib/firmware/stf_isp0_fw.bin
+	install -m 0755 -D $(@D)/ov4689_stf_isp_fw_dump.bin $(TARGET_DIR)/lib/firmware/stf_isp0_fw_dump.bin
+	install -m 0755 -D $(@D)/sc2235_stf_isp_fw.bin $(TARGET_DIR)/lib/firmware/stf_isp1_fw.bin
+endef
+
+$(eval $(host-generic-package))
+

+ 18 - 0
package/starfive/v4l2_test/Config.in

@@ -0,0 +1,18 @@
+config BR2_PACKAGE_V4L2_TEST
+	bool "v4l2_test"
+	depends on BR2_TOOLCHAIN_HAS_THREADS # libv4l
+	depends on BR2_USE_MMU # libv4l
+	depends on !BR2_STATIC_LIBS # libv4l
+	depends on BR2_INSTALL_LIBSTDCPP # libv4l
+	depends on BR2_TOOLCHAIN_HEADERS_AT_LEAST_3_0 # libv4l
+	select BR2_PACKAGE_JPEG
+	select BR2_PACKAGE_LIBV4L
+	help
+	  Utility for v4l2test JPEGs form V4L2 devices. This tool is
+	  similar to v4l2grab available from libv4l contrib directory,
+	  but provides additional features such as JPEG output.
+
+comment "v4l2_test needs a toolchain w/ threads, dynamic library, C++ and headers >= 3.0"
+	depends on BR2_USE_MMU
+	depends on !BR2_TOOLCHAIN_HAS_THREADS || BR2_STATIC_LIBS \
+		|| !BR2_INSTALL_LIBSTDCPP || !BR2_TOOLCHAIN_HEADERS_AT_LEAST_3_0

+ 92 - 0
package/starfive/v4l2_test/config.h

@@ -0,0 +1,92 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+#undef HAVE_LIBJPEG
+
+/* Define to 1 if you have the `v4l2' library (-lv4l2). */
+#undef HAVE_LIBV4L2
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t

+ 812 - 0
package/starfive/v4l2_test/convert.c

@@ -0,0 +1,812 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <signal.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <linux/fb.h>
+
+extern struct fb_var_screeninfo vinfo;
+extern struct fb_fix_screeninfo finfo;
+extern int screensize;
+
+int yuyv_resize(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight)
+{
+    int rows;
+    unsigned char *YUVindata, *YUVoutdata;    /* YUV and RGB pointer */
+    int YUVinpos;    /* Y U V offset */
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timeval ts_start, ts_end;
+
+    if (!tmp)
+        return -1;
+
+    gettimeofday(&ts_start, NULL);
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    YUVindata = inBuf;
+    YUVoutdata = tmp;
+
+    if (imgWidth == vinfo.xres) {
+        YUVinpos = (y_offset * vinfo.xres + x_offset) * 2;
+        memcpy(&tmp[YUVinpos], inBuf, imgWidth * height * 2);
+        memcpy(&outBuf[YUVinpos], &tmp[YUVinpos], imgWidth * height * 2);
+        // memcpy(&outBuf[YUVinpos], inBuf, imgWidth * height * 2);
+        gettimeofday(&ts_end, NULL);
+        start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
+        end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
+        // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
+        free(tmp);
+        return 0;
+    }
+
+    /* two bytes for one pixels */
+    for(rows = 0; rows < height; rows++)
+    {
+        // vinfo.xres, vinfo.yres vinfo.bits_per_pixel
+        YUVoutdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * 2;
+        YUVinpos = rows * imgWidth * 2;
+
+        memcpy(YUVoutdata, &YUVindata[YUVinpos], imgWidth * 2);
+    }
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
+    end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
+    // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
+
+    gettimeofday(&ts_start, NULL);
+
+    memcpy(outBuf, tmp, screensize);
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
+    // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
+
+    free(tmp);
+    return 0;
+
+}
+
+int convert_yuyv_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_yuyv)
+{
+    int rows, cols;
+    unsigned char *nv12data, *YUVdata;
+    int Ypos;
+    int fb_Ypos, fb_Upos, fb_Vpos;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timeval ts_start, ts_end;
+
+    if (!tmp)
+        return -1;
+
+    gettimeofday(&ts_start, NULL);
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    YUVdata = inBuf;
+    nv12data = tmp;
+
+    /* two bytes for every pixels */
+    for(rows = 0; rows < height; rows++)
+    {
+        // vinfo.xres, vinfo.yres vinfo.bits_per_pixel
+        fb_Ypos = ((rows + y_offset) * vinfo.xres + x_offset);
+        fb_Upos = ((rows + y_offset) / 2 * vinfo.xres / 2 + x_offset / 2) * 2;
+        fb_Upos = vinfo.xres * vinfo.yres + fb_Upos;
+        fb_Vpos = fb_Upos + 1;
+
+        Ypos = rows * imgWidth * 2;
+
+        for (cols = 0; cols < width; cols += 2) {
+            nv12data[fb_Ypos+cols] = YUVdata[Ypos+cols*2];
+            nv12data[fb_Ypos+cols+1] = YUVdata[Ypos+cols*2+2];
+            nv12data[fb_Upos+cols] = YUVdata[Ypos+cols*2+1];
+            nv12data[fb_Vpos+cols] = YUVdata[Ypos+cols*2+3];
+        }
+    }
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
+    end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
+    // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
+
+    gettimeofday(&ts_start, NULL);
+
+    memcpy(outBuf, tmp, screensize);
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
+    // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
+
+    free(tmp);
+    return 0;
+}
+
+int convert_nv21_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21)
+{
+    int rows, cols;
+    unsigned char *nv12data, *nv21data;
+    int Ypos, Upos, Vpos;
+    int fb_Ypos, fb_Upos, fb_Vpos;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timeval ts_start, ts_end;
+
+    if (!tmp)
+        return -1;
+
+    gettimeofday(&ts_start, NULL);
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    nv21data = inBuf;
+    nv12data = tmp;
+
+    if (imgWidth == vinfo.xres) {
+        fb_Ypos = y_offset * vinfo.xres + x_offset;
+        fb_Upos = (y_offset / 2 * vinfo.xres / 2 + x_offset / 2) * 2;
+        fb_Upos = vinfo.xres * vinfo.yres + fb_Upos;
+        Upos = imgWidth * imgHeight;
+        memcpy(&tmp[fb_Ypos], inBuf, imgWidth * height);
+        memcpy(&tmp[fb_Upos], &inBuf[Upos], imgWidth * height / 2);
+        memcpy(&outBuf[fb_Ypos], &tmp[fb_Ypos], imgWidth * height * 2);
+        memcpy(&outBuf[fb_Upos], &tmp[fb_Upos], imgWidth * height / 2);
+        // memcpy(&outBuf[fb_Ypos], inBuf, imgWidth * height);
+        // memcpy(&outBuf[fb_Upos], inBuf, imgWidth * height / 2);
+        free(tmp);
+        return 0;
+    }
+
+    /* two bytes for every pixels */
+    for(rows = 0; rows < height; rows+=2)
+    {
+        // vinfo.xres, vinfo.yres vinfo.bits_per_pixel
+        fb_Ypos = ((rows + y_offset) * vinfo.xres + x_offset);
+        fb_Upos = ((rows + y_offset) / 2 * vinfo.xres / 2 + x_offset / 2) * 2;
+        fb_Upos = vinfo.xres * vinfo.yres + fb_Upos;
+        fb_Vpos = fb_Upos + 1;
+
+        Ypos = rows * imgWidth;
+        Upos = imgWidth * imgHeight + Ypos / 2;
+        Vpos = Upos + 1;
+        memcpy(&nv12data[fb_Ypos], &nv21data[Ypos], width);
+        memcpy(&nv12data[fb_Ypos+vinfo.xres], &nv21data[Ypos+imgWidth], width);
+
+        if (is_nv21) {
+            for (cols = 0; cols < width; cols += 2) {
+                nv12data[fb_Upos+cols] = nv21data[Vpos+cols];
+                nv12data[fb_Vpos+cols] = nv21data[Upos+cols];
+            }
+        } else
+            memcpy(&nv12data[fb_Upos], &nv21data[Upos], width);
+    }
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
+    end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
+    // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
+
+    gettimeofday(&ts_start, NULL);
+
+    memcpy(outBuf, tmp, screensize);
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
+    // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
+
+    free(tmp);
+    return 0;
+}
+
+int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21)
+{
+    int rows ,cols;
+    int y, u, v, r, g, b;
+    unsigned char *YUVdata, *RGBdata;
+    int Ypos, Upos, Vpos;
+    unsigned int i = 0;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timeval ts_start, ts_end;
+
+    if (!tmp)
+        return -1;
+
+    gettimeofday(&ts_start, NULL);
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    YUVdata = inBuf;
+    RGBdata = tmp;
+
+    /* two bytes for every pixels */
+    for(rows = 0; rows < height; rows++)
+    {
+        // vinfo.xres, vinfo.yres vinfo.bits_per_pixel
+        RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8;
+
+        Ypos = rows * imgWidth;
+        Vpos = Upos = imgWidth * imgHeight + Ypos / 2;
+        if (is_nv21)
+            Vpos = Upos + 1;
+        else
+            Upos = Vpos + 1;
+        i = 0;
+
+        for (cols = 0; cols < width; cols++)
+        {
+            y = YUVdata[Ypos];
+            u = YUVdata[Upos] - 128;
+            v = YUVdata[Vpos] - 128;
+
+            r = y + v + ((v * 103) >> 8);
+            g = y - ((u * 88) >> 8) - ((v * 183) >> 8);
+            b = y + u + ((u * 198) >> 8);
+
+            r = r > 255 ? 255 : (r < 0 ? 0 : r);
+            g = g > 255 ? 255 : (g < 0 ? 0 : g);
+            b = b > 255 ? 255 : (b < 0 ? 0 : b);
+
+            /* low -> high r g b */
+            if (vinfo.bits_per_pixel == 16) {   // RGB565
+                *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3));   /* g low 5bit,b high 5bit */
+                *(RGBdata ++) = ((r & 0xf8) | (g >> 5));    /* r high 5bit,g high 3bit */
+            } else if (vinfo.bits_per_pixel == 24) {   // RGB888
+                *(RGBdata ++) = b;
+                *(RGBdata ++) = g;
+                *(RGBdata ++) = r;
+            } else { // RGB8888
+                *(RGBdata ++) = b;
+                *(RGBdata ++) = g;
+                *(RGBdata ++) = r;
+                *(RGBdata ++) = 0xFF;
+            }
+            Ypos++;
+            i++;
+            /* every 4 time y to update 1 time uv */
+            if(!(i & 0x03))
+            {
+                Vpos = Upos = imgWidth * imgHeight + Ypos/2;
+                if (is_nv21)
+                    Vpos = Upos + 1;
+                else
+                    Upos = Vpos + 1;
+            }
+        }
+    }
+
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
+    end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
+    // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
+
+    gettimeofday(&ts_start, NULL);
+
+#if 1
+    memcpy(outBuf, tmp, screensize);
+#else
+    int *p_outBuf, *p_tmp;
+    int size = screensize/4;
+    p_outBuf = outBuf;
+    p_tmp = tmp;
+
+    for (i = 0; i < size; i++)
+        p_outBuf[i] = p_tmp[i];
+#endif
+    gettimeofday(&ts_end, NULL);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
+    // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
+
+    free(tmp);
+    return 0;
+}
+
+//Y' = 0.257*R' + 0.504*G' + 0.098*B' + 16
+static int Rgb2Y(int r0, int g0, int b0)
+{
+    // float y0 = 0.257f*r0 + 0.504f*g0 + 0.098f*b0 + 16.0f;
+    // int y0 = (257*r0 + 504*g0 + 98*b0)/1000 + 16;
+    // Y = (77*R + 150*G + 29*B)>>8;
+    int y0 = (77*r0+150*g0+29*b0) >> 8;
+    return y0;
+}
+
+//U equals Cb'
+//Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
+static int Rgb2U(int r0, int g0, int b0)
+{
+    // float u0 = -0.148f*r0 - 0.291f*g0 + 0.439f*b0 + 128.0f;
+    // int u0 = (-148*r0 - 291*g0 + 439*b0)/1000 + 128;
+    // U = ((-44*R  - 87*G  + 131*B)>>8) + 128;
+    int u0 = ((-44*r0  - 87*g0  + 131*b0)>>8) + 128;
+    return u0;
+}
+
+//V equals Cr'
+//Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
+static int Rgb2V(int r0, int g0, int b0)
+{
+    // float v0 = 0.439f*r0 - 0.368f*g0 - 0.071f*b0 + 128.0f;
+    // int v0 = (439*r0 - 368*g0 - 71*b0)/1000 + 128;
+    // V = ((131*R - 110*G - 21*B)>>8) + 128 ;
+    int v0 = ((131*r0 - 110*g0 - 21*b0)>>8) + 128;
+    return v0;
+}
+
+//Convert two rows from RGB to two Y rows, and one row of interleaved U,V.
+//I0 and I1 points two sequential source rows.
+//I0 -> rgbrgbrgbrgbrgbrgb...
+//I1 -> rgbrgbrgbrgbrgbrgb...
+//Y0 and Y1 points two sequential destination rows of Y plane.
+//Y0 -> yyyyyy
+//Y1 -> yyyyyy
+//UV0 points destination rows of interleaved UV plane.
+//UV0 -> uvuvuv
+static void Rgb2NV12TwoRows(const unsigned char I0[],
+                            const unsigned char I1[],
+                            int step,
+                            const int image_width,
+                            unsigned char Y0[],
+                            unsigned char Y1[],
+                            unsigned char UV0[])
+{
+    int x;  //Column index
+
+    //Process 4 source pixels per iteration (2 pixels of row I0 and 2 pixels of row I1).
+    for (x = 0; x < image_width; x += 2)
+    {
+        //Load R,G,B elements from first row (and convert to int).
+        unsigned char b00 = (I0[x*step + 0] & 0x1F) << 3;
+        unsigned char g00 = ((I0[x*step + 1] & 0x7) << 3 | I0[x*step + 0] >> 5) << 2;
+        unsigned char r00 = I0[x*step + 1] & (~0x7);
+
+        //Load next R,G,B elements from first row (and convert to int).
+        unsigned char b01 = (I0[x*step + step+0] & 0x1F) << 3;
+        unsigned char g01 = ((I0[x*step + step+1] & 0x7) << 3 | I0[x*step + step+0] >> 5) << 2;
+        unsigned char r01 = I0[x*step + step+1] & (~0x7);
+
+        //Load R,G,B elements from second row (and convert to int).
+        unsigned char b10 = (I1[x*step + 0] & 0x1F) << 3;
+        unsigned char g10 = ((I1[x*step + 1] & 0x7) << 3 | I1[x*step + 0] >> 5) << 2;
+        unsigned char r10 = I1[x*step + 1] & (~0x7);
+
+        //Load next R,G,B elements from second row (and convert to int).
+        unsigned char b11 = (I1[x*step + step+0] & 0x1F) << 3;
+        unsigned char g11 = ((I1[x*step + step+1] & 0x7) << 3 | I1[x*step + step+0] >> 5) << 2;
+        unsigned char r11 = I1[x*step + step+1] & (~0x7);
+
+        //Calculate 4 Y elements.
+        unsigned char y00 = Rgb2Y(r00, g00, b00);
+        unsigned char y01 = Rgb2Y(r01, g01, b01);
+        unsigned char y10 = Rgb2Y(r10, g10, b10);
+        unsigned char y11 = Rgb2Y(r11, g11, b11);
+
+        //Calculate 4 U elements.
+        unsigned char u00 = Rgb2U(r00, g00, b00);
+        unsigned char u01 = Rgb2U(r01, g01, b01);
+        unsigned char u10 = Rgb2U(r10, g10, b10);
+        unsigned char u11 = Rgb2U(r11, g11, b11);
+
+        //Calculate 4 V elements.
+        unsigned char v00 = Rgb2V(r00, g00, b00);
+        unsigned char v01 = Rgb2V(r01, g01, b01);
+        unsigned char v10 = Rgb2V(r10, g10, b10);
+        unsigned char v11 = Rgb2V(r11, g11, b11);
+
+        //Calculate destination U element: average of 2x2 "original" U elements.
+        unsigned char u0 = (u00 + u01 + u10 + u11)/4;
+
+        //Calculate destination V element: average of 2x2 "original" V elements.
+        unsigned char v0 = (v00 + v01 + v10 + v11)/4;
+
+        //Store 4 Y elements (two in first row and two in second row).
+        Y0[x + 0]    = y00;
+        Y0[x + 1]    = y01;
+        Y1[x + 0]    = y10;
+        Y1[x + 1]    = y11;
+
+        // //Store destination U element.
+        UV0[x + 0]    = u0;
+
+        // //Store destination V element (next to stored U element).
+        UV0[x + 1]    = v0;
+    }
+}
+
+//Convert image I from pixel ordered RGB to NV12 format.
+//I - Input image in pixel ordered RGB format
+//image_width - Number of columns of I
+//image_height - Number of rows of I
+//J - Destination "image" in NV12 format.
+
+//I is pixel ordered RGB color format (size in bytes is image_width*image_height*3):
+//RGBRGBRGBRGBRGBRGB
+//RGBRGBRGBRGBRGBRGB
+//RGBRGBRGBRGBRGBRGB
+//RGBRGBRGBRGBRGBRGB
+//
+//J is in NV12 format (size in bytes is image_width*image_height*3/2):
+//YYYYYY
+//YYYYYY
+//UVUVUV
+//Each element of destination U is average of 2x2 "original" U elements
+//Each element of destination V is average of 2x2 "original" V elements
+//
+//Limitations:
+//1. image_width must be a multiple of 2.
+//2. image_height must be a multiple of 2.
+//3. I and J must be two separate arrays (in place computation is not supported).
+void Rgb2NV12(const unsigned char I[], int step,
+              const int image_width,
+              const int image_height,
+              unsigned char J[])
+{
+    //In NV12 format, UV plane starts below Y plane.
+    // unsigned char *UV = &J[image_width*image_height];
+    unsigned char *UV = J;
+
+    //I0 and I1 points two sequential source rows.
+    const unsigned char *I0;  //I0 -> rgbrgbrgbrgbrgbrgb...
+    const unsigned char *I1;  //I1 -> rgbrgbrgbrgbrgbrgb...
+
+    //Y0 and Y1 points two sequential destination rows of Y plane.
+    unsigned char *Y0;    //Y0 -> yyyyyy
+    unsigned char *Y1;    //Y1 -> yyyyyy
+
+    //UV0 points destination rows of interleaved UV plane.
+    unsigned char *UV0; //UV0 -> uvuvuv
+
+    int y;  //Row index
+    int width, height;
+    int x_offset, y_offset;
+
+    width = image_width > vinfo.xres ? vinfo.xres : image_width;
+    height = image_height > vinfo.yres ? vinfo.yres : image_height;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    //In each iteration: process two rows of Y plane, and one row of interleaved UV plane.
+    for (y = 0; y < height; y += 2)
+    {
+        I0 = &I[y*image_width*step];        //Input row width is image_width*3 bytes (each pixel is R,G,B).
+        I1 = &I[(y+1)*image_width*step];
+
+        Y0 = &J[(y+y_offset)*vinfo.xres+x_offset];            //Output Y row width is image_width bytes (one Y element per pixel).
+        Y1 = &J[(y+1+y_offset)*vinfo.xres+x_offset];
+
+        UV0 = &UV[vinfo.xres*vinfo.yres+((y+y_offset)/2*vinfo.xres/2+x_offset/2)*2];    //Output UV row - width is same as Y row width.
+
+        //Process two source rows into: Two Y destination row, and one destination interleaved U,V row.
+        Rgb2NV12TwoRows(I0,
+                        I1,
+                        step,
+                        width,
+                        Y0,
+                        Y1,
+                        UV0);
+    }
+}
+
+int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21)
+{
+    unsigned char *tmp = malloc(screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timespec ts_start, ts_end;
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+    Rgb2NV12(inBuf, 2, imgWidth, imgHeight, tmp);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
+    // printf("%s: convert use %dms\n", __func__, end_timems - start_timems);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+    memcpy(outBuf, tmp, screensize);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
+    // printf("%s: use %dms\n", __func__, end_timems - start_timems);
+
+    free(tmp);
+    return 0;
+}
+
+int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod)
+{
+    int rows ,cols;
+    int y, u, v, r, g, b;
+    unsigned char *YUVdata, *RGBdata;
+    int Ypos, Upos, Vpos;
+    unsigned int i = 0;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+    unsigned int start_timems;
+    unsigned int end_timems;
+    struct timespec ts_start, ts_end;
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    YUVdata = inBuf;
+    RGBdata = tmp;
+
+    /* two bytes for every pixels */
+    for(rows = 0; rows < height; rows++)
+    {
+        // vinfo.xres, vinfo.yres vinfo.bits_per_pixel
+        RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8;
+
+        Ypos = rows * imgWidth * 2;
+        Upos = Ypos + 1;
+        Vpos = Upos + 2;
+        i = 0;
+
+        for(cols = 0; cols < width; cols++)
+        {
+            y = YUVdata[Ypos];
+            u = YUVdata[Upos] - 128;
+            v = YUVdata[Vpos] - 128;
+
+            r = y + v + ((v * 103) >> 8);
+            g = y - ((u * 88) >> 8) - ((v * 183) >> 8);
+            b = y + u + ((u * 198) >> 8);
+
+            r = r > 255 ? 255 : (r < 0 ? 0 : r);
+            g = g > 255 ? 255 : (g < 0 ? 0 : g);
+            b = b > 255 ? 255 : (b < 0 ? 0 : b);
+
+            /* low -> high r g b */
+            if (vinfo.bits_per_pixel == 16) {   // RGB565
+                *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3));    /* g low 5bits,b high 5bits */
+                *(RGBdata ++) = ((r & 0xf8) | (g >> 5));    /* r high 5bits, g high 3bits */
+            } else if (vinfo.bits_per_pixel == 24) {   // RGB888
+                *(RGBdata ++) = b;
+                *(RGBdata ++) = g;
+                *(RGBdata ++) = r;
+            } else { // RGB8888
+                *(RGBdata ++) = b;
+                *(RGBdata ++) = g;
+                *(RGBdata ++) = r;
+                *(RGBdata ++) = 0xFF;
+            }
+            /* two bytes contain 1 y */
+            Ypos += 2;
+            //Ypos++;
+            i++;
+            /* every 2 y to update 1 uv */
+            if(!(i & 0x01))
+            {
+                Upos = Ypos + 1;
+                Vpos = Upos + 2;
+            }
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
+    // printf("%s: convert use %dms\n", __func__, end_timems - start_timems);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+    memcpy(outBuf, tmp, screensize);
+
+    clock_gettime(CLOCK_MONOTONIC, &ts_end);
+    start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
+    end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
+    // printf("%s: use %dms\n", __func__, end_timems - start_timems);
+
+    free(tmp);
+    return 0;
+}
+
+int convert_yuv444_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod)
+{
+    int rows ,cols;
+    int y, u, v, r, g, b;
+    unsigned char *YUVdata, *RGBdata;
+    int Ypos;
+    unsigned char *tmp = malloc(screensize);
+
+    YUVdata = inBuf;
+    RGBdata = tmp;
+    /*  YUV */
+    Ypos = 0;
+
+    for(rows = 0; rows < imgHeight; rows++)
+    {
+        for(cols = 0; cols < imgWidth; cols++)
+        {
+            y = YUVdata[Ypos];
+            u = YUVdata[Ypos + 1] - 128;
+            v = YUVdata[Ypos + 2] - 128;
+
+            r = y + v + ((v * 103) >> 8);
+            g = y - ((u * 88) >> 8) - ((v * 183) >> 8);
+            b = y + u + ((u * 198) >> 8);
+
+            r = r > 255 ? 255 : (r < 0 ? 0 : r);
+            g = g > 255 ? 255 : (g < 0 ? 0 : g);
+            b = b > 255 ? 255 : (b < 0 ? 0 : b);
+
+            /* low -> high r g b */
+            if (vinfo.bits_per_pixel == 16) {   // RGB565
+                *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3));    /* g low 5bits,b high 5bits */
+                *(RGBdata ++) = ((r & 0xf8) | (g >> 5));    /* r high 5bits,g high 3bits */
+            } else if (vinfo.bits_per_pixel == 24) {   // RGB888
+                *(RGBdata ++) = b;
+                *(RGBdata ++) = g;
+                *(RGBdata ++) = r;
+            } else { // RGB8888
+                *(RGBdata ++) = b;
+                *(RGBdata ++) = g;
+                *(RGBdata ++) = r;
+                *(RGBdata ++) = 0xFF;
+            }
+            Ypos += 3;
+        }
+    }
+
+    memcpy(outBuf, tmp, screensize);
+    free(tmp);
+    return 0;
+}
+
+int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod)
+{
+    int rows ,cols;
+    unsigned char *RGB565data, *RGBdata;
+    int RGBpos;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    RGB565data = inBuf;
+    RGBdata = tmp;
+
+    if (imgWidth == vinfo.xres) {
+        RGBpos = (y_offset * vinfo.xres + x_offset) * 2;
+        memcpy(&tmp[RGBpos], inBuf, imgWidth * height * 2);
+        memcpy(&outBuf[RGBpos], &tmp[RGBpos], imgWidth * height * 2);
+        // memcpy(&outBuf[RGBpos], inBuf, imgWidth * height * 2);
+        free(tmp);
+        return 0;
+    }
+
+    RGBpos = 0;
+    for(rows = 0; rows < imgHeight; rows++)
+    {
+        RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8;
+        RGBpos = rows * imgWidth * 2;
+        if (vinfo.bits_per_pixel == 16) {   // RGB565
+            memcpy(RGBdata, &RGB565data[RGBpos], imgWidth * 2);
+        } else {
+            for(cols = 0; cols < imgWidth; cols++)
+            {
+                *(RGBdata ++) = RGB565data[RGBpos] & 0x1F;
+                *(RGBdata ++) = (RGB565data[RGBpos + 1] & 0x7) << 3 | RGB565data[RGBpos] >> 5;
+                *(RGBdata ++) = RGB565data[RGBpos + 1] >> 3;
+                if (vinfo.bits_per_pixel == 32) {   // RGB888
+                    *(RGBdata ++) = 0xFF;
+                }
+                RGBpos += 2;
+            }
+        }
+    }
+
+    memcpy(outBuf, tmp, screensize);
+    free(tmp);
+    return 0;
+}
+
+int convert_rgb888_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod)
+{
+    int rows ,cols;
+    unsigned char *RGB888data, *RGBdata;
+    int RGBpos;
+    int width, height;
+    int x_offset, y_offset;
+    unsigned char *tmp = malloc(screensize);
+    unsigned char r, g, b;
+
+    width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth;
+    height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight;
+    x_offset = (vinfo.xres - width) / 2;
+    y_offset = (vinfo.yres - height) / 2;
+
+    RGB888data = inBuf;
+    RGBdata = tmp;
+
+    RGBpos = 0;
+    for(rows = 0; rows < imgHeight; rows++)
+    {
+        RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8;
+        RGBpos = rows * imgWidth * 3;
+        if (vinfo.bits_per_pixel == 24) {   // RGB888
+            memcpy(RGBdata, &RGB888data[RGBpos], imgWidth * 3);
+        } else {
+            for(cols = 0; cols < imgWidth; cols++)
+            {
+                if (vinfo.bits_per_pixel == 16) {   // RGB565
+                    b = RGB888data[RGBpos];
+                    g = RGB888data[RGBpos + 1];
+                    r = RGB888data[RGBpos + 2];
+                    *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3));    /* g low 5bits,b high 5bits */
+                    *(RGBdata ++) = ((r & 0xf8) | (g >> 5));    /* r high 5bits,g high 3bits */
+                } else {   // RGB8888
+                    *(RGBdata ++) = RGB888data[RGBpos];
+                    *(RGBdata ++) = RGB888data[RGBpos + 1];
+                    *(RGBdata ++) = RGB888data[RGBpos + 2];
+                    *(RGBdata ++) = 0xFF;
+                }
+                RGBpos += 3;
+            }
+        }
+    }
+
+    memcpy(outBuf, tmp, screensize);
+    free(tmp);
+    return 0;
+}

+ 20 - 0
package/starfive/v4l2_test/convert.h

@@ -0,0 +1,20 @@
+
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#ifndef _CONVERT_H_
+#define _CONVERT_H_
+
+extern int yuyv_resize(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight);
+
+extern int convert_yuyv_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_yuyv);
+extern int convert_nv21_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21);
+extern int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21);
+extern int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21);
+extern int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod);
+extern int convert_yuv444_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod);
+extern int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod);
+extern int convert_rgb888_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod);
+
+#endif // _CONVERT_H_

+ 283 - 0
package/starfive/v4l2_test/pipeline_setting.sh

@@ -0,0 +1,283 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2021 StarFive Technology Co., Ltd.
+#
+
+USAGE="Usage: media-ctl-pipeline interface_type sensor_type {start|stop}"
+
+echo "Pipeline $1 $2 $3"
+
+case $1 in
+	dvp)
+		case $3 in
+			start)
+				# media-ctl -vl "'sc2235 1-0030':0 -> 'stf_dvp0':0 [1]"
+				# media-ctl -vl "'ov5640 1-003c':0 -> 'stf_dvp0':0 [1]"
+				case $2 in
+					VIN)
+						echo "DVP vin enable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_vin0_wr':0 [1]"
+						# media-ctl -vl "'stf_vin0_wr':1 -> 'stf_vin0_wr_video0':0 [1]"
+						;;
+					ISP0)
+						echo "DVP ISP0 enable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [1]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]"
+						;;
+					ISP0RAW)
+						echo "DVP ISP0RAW enable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [1]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]"
+						;;
+					ISP1)
+						echo "DVP ISP1 enable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [1]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]"
+						;;
+					ISP1RAW)
+						echo "DVP ISP1RAW enable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [1]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]"
+						;;
+					*)
+						echo $USAGE
+						exit 1
+						;;
+				esac
+				;;
+			stop)
+				# media-ctl -vl "'sc2235 1-0030':0 -> 'stf_dvp0':0 [0]"
+				# media-ctl -vl "'ov5640 1-003c':0 -> 'stf_dvp0':0 [0]"
+				case $2 in
+					VIN)
+						echo "DVP vin disable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_vin0_wr':0 [0]"
+						# media-ctl -vl "'stf_vin0_wr':1 -> 'stf_vin0_wr_video0':0 [0]"
+						;;
+					ISP0)
+						echo "DVP ISP0 disable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [0]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]"
+						;;
+					ISP0RAW)
+						echo "DVP ISP0RAW disable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [0]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]"
+						;;
+					ISP1)
+						echo "DVP ISP1 disable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [0]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]"
+						;;
+					ISP1RAW)
+						echo "DVP ISP1RAW disable pipeline:"
+						media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [0]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]"
+						;;
+					*)
+						echo $USAGE
+						exit 1
+						;;
+				esac
+				;;
+			*)
+				echo $USAGE
+				exit 1
+				;;
+		esac
+		;;
+	csiphy0)
+		case $3 in
+			start)
+				# media-ctl -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [1]"
+				case $2 in
+					VIN)
+						echo "csiphy0 CSIRX0 vin enable pipeline:"
+						;;
+					ISP0)
+						echo "csiphy0 CSIRX0 ISP0 enable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [1]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]"
+						;;
+					ISP0RAW)
+						echo "csiphy0 CSIRX0 ISP0RAW enable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [1]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]"
+						;;
+					ISP1)
+						echo "csiphy0 CSIRX0 ISP1 enable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [1]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]"
+						;;
+					ISP1RAW)
+						echo "csiphy0 CSIRX0 ISP1RAW enable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [1]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]"
+						;;
+
+					*)
+						echo $USAGE
+						exit 1
+						;;
+				esac
+				;;
+			stop)
+				# media-ctl -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [0]"
+				case $2 in
+					VIN)
+						echo "csiphy0 CSIRX0 vin disable pipeline:"
+						;;
+					ISP0)
+						echo "csiphy0 CSIRX0 ISP0 disable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [0]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]"
+						;;
+					ISP0RAW)
+						echo "csiphy0 CSIRX0 ISP0RAW disable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [0]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]"
+						;;
+					ISP1)
+						echo "csiphy0 CSIRX0 ISP1 disable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [0]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]"
+						;;
+					ISP1RAW)
+						echo "csiphy0 CSIRX0 ISP1RAW disable pipeline:"
+						media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]"
+						media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [0]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]"
+						;;
+
+					*)
+						echo $USAGE
+						exit 1
+						;;
+				esac
+				;;
+			*)
+				echo $USAGE
+				exit 1
+				;;
+		esac
+		;;
+	csiphy1)
+		case $3 in
+			start)
+				# media-ctl -vl "'ov4689 2-0036':0 -> 'stf_csiphy1':0 [1]"
+				case $2 in
+					VIN)
+						echo "csiphy1 CSIRX0 vin enable pipeline:"
+						;;
+					ISP0)
+						echo "csiphy1 CSIRX1 ISP0 enable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [1]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]"
+						;;
+					ISP0RAW)
+						echo "csiphy1 CSIRX1 ISP0RAW enable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [1]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]"
+						;;
+					ISP1)
+						echo "csiphy1 CSIRX1 ISP1 enable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [1]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]"
+						;;
+					ISP1RAW)
+						echo "csiphy1 CSIRX1 ISP1RAW enable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [1]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]"
+						;;
+
+					*)
+						echo $USAGE
+						exit 1
+						;;
+				esac
+				;;
+			stop)
+				# media-ctl -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [0]"
+				case $2 in
+					VIN)
+						echo "csiphy1 CSIRX0 vin disable pipeline:"
+						;;
+					ISP0)
+						echo "csiphy1 CSIRX1 ISP0 disable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [0]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]"
+						;;
+					ISP0RAW)
+						echo "csiphy1 CSIRX1 ISP0RAW disable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [0]"
+						media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]"
+						;;
+					ISP1)
+						echo "csiphy1 CSIRX1 ISP1 disable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [0]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]"
+						;;
+					ISP1RAW)
+						echo "csiphy1 CSIRX1 ISP1RAW disable pipeline:"
+						media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]"
+						media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [0]"
+						media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]"
+						# media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]"
+						;;
+					*)
+						echo $USAGE
+						exit 1
+						;;
+				esac
+				;;
+			*)
+				echo $USAGE
+				exit 1
+				;;
+		esac
+		;;
+	*)
+		echo $USAGE
+		exit 1
+		;;
+esac
+
+exit 0;

+ 172 - 0
package/starfive/v4l2_test/string.c

@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * arch/riscv/lib/string.c
+ *
+ * Copyright (C) 2021 Matteo Croce
+ *
+ * string functions optimized for 64 bit hardware which doesn't
+ * handle unaligned memory accesses efficiently.
+ *
+ * May be freely distributed as part of Linux.
+ */
+
+#include <stddef.h>
+#include <linux/types.h>
+#include <linux/module.h>
+
+#define BITS_PER_LONG 64
+
+typedef unsigned long uintptr_t;
+
+typedef __u64 u64;
+typedef __s64 s64;
+
+typedef __u32 u32;
+typedef __s32 s32;
+
+typedef __u16 u16;
+typedef __s16 s16;
+
+typedef __u8  u8;
+typedef __s8  s8;
+
+union types {
+	u8 *u8;
+	u16 *u16;
+	u32 *u32;
+	u64 *u64;
+	unsigned long *ulong;
+	uintptr_t ptr;
+};
+
+union ctypes {
+	const u8 *u8;
+	const u16 *u16;
+	const u32 *u32;
+	const u64 *u64;
+	unsigned long *ulong;
+	uintptr_t ptr;
+};
+
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+void *memcpy(void *dest, const void *src, size_t count)
+{
+	static const void *labels[] = {
+		&&u64, &&u8, &&u16, &&u8,
+		&&u32, &&u8, &&u16, &&u8,
+	};
+	union types d = { .u8 = dest };
+	union ctypes s = { .u8 = src };
+#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
+	int distance = 0;
+#else
+	const int mask = BITS_PER_LONG / 8 - 1;
+	int distance = (src - dest) & 7;
+
+	for (; count && d.ptr & s.ptr & mask; count--)
+		*d.u8++ = *s.u8++;
+#endif
+
+	goto *labels[distance];
+
+u64:
+#if BITS_PER_LONG == 64
+	for (; count >= 8; count -= 8)
+		*d.u64++ = *s.u64++;
+#endif
+
+u32:
+	for (; count >= 4; count -= 4)
+		*d.u32++ = *s.u32++;
+
+u16:
+	for (; count >= 2; count -= 2)
+		*d.u16++ = *s.u16++;
+
+u8:
+	while (count--)
+		*d.u8++ = *s.u8++;
+
+	return dest;
+}
+EXPORT_SYMBOL(memcpy);
+
+void *__memcpy(void *dest, const void *src, size_t count)
+{
+	return memcpy(dest, src, count);
+}
+EXPORT_SYMBOL(__memcpy);
+
+/**
+ * memmove - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * Unlike memcpy(), memmove() copes with overlapping areas.
+ */
+void *memmove(void *dest, const void *src, size_t count)
+{
+	if (dest < src || src + count <= dest)
+		return memcpy(dest, src, count);
+
+	if (dest > src) {
+		const char *s = src + count;
+		char *tmp = dest + count;
+
+		while (count--)
+			*--tmp = *--s;
+	}
+	return dest;
+}
+EXPORT_SYMBOL(memmove);
+
+void *__memmove(void *dest, const void *src, size_t count)
+{
+	return memmove(dest, src, count);
+}
+EXPORT_SYMBOL(__memmove);
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
+ */
+void *memset(void *s, int c, size_t count)
+{
+	const int bytes_long = BITS_PER_LONG / 8;
+	u8 cc[] = { [0 ... bytes_long-1] = c };
+	union ctypes src = { .u8 = cc };
+	union types dest = { .u8 = s };
+
+#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS
+	for (; count && dest.ptr % bytes_long; count--)
+		*dest.u8++ = c;
+#endif
+
+	for (; count >= bytes_long; count -= bytes_long)
+		*dest.ulong++ = *src.ulong;
+
+	while (count--)
+		*dest.u8++ = c;
+
+	return s;
+}
+EXPORT_SYMBOL(memset);
+
+void *__memset(void *s, int c, size_t count)
+{
+	return memset(s, c, count);
+}
+EXPORT_SYMBOL(__memset);

+ 1763 - 0
package/starfive/v4l2_test/v4l2_test.c

@@ -0,0 +1,1763 @@
+/***************************************************************************
+ *   v4l2grab Version 0.3                                                  *
+ *   Copyright (C) 2012 by Tobias Müller                                   *
+ *   Tobias_Mueller@twam.info                                              *
+ *                                                                         *
+ *   based on V4L2 Specification, Appendix B: Video Capture Example        *
+ *   (http://v4l2spec.bytesex.org/spec/capture-example.html)               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+ /**************************************************************************
+ *   Modification History                                                  *
+ *                                                                         *
+ *   Matthew Witherwax      21AUG2013                                      *
+ *      Added ability to change frame interval (ie. frame rate/fps)        *
+ * Martin Savc              7JUL2015
+ *      Added support for continuous capture using SIGINT to stop.
+ ***************************************************************************/
+
+// compile with all three access methods
+#if !defined(IO_READ) && !defined(IO_MMAP) && !defined(IO_USERPTR)
+#define IO_READ
+#define IO_MMAP
+#define IO_USERPTR
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <linux/videodev2.h>
+#include <jpeglib.h>
+#include <libv4l2.h>
+#include <signal.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <linux/fb.h>
+#include <stdbool.h>
+
+#include "config.h"
+#include "yuv.h"
+#include "convert.h"
+
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+
+#ifndef VERSION
+#define VERSION "v0.0.1"
+#endif
+
+#define FILENAME_MAX_LEN     30
+struct stfisp_fw_info {
+    char filename[FILENAME_MAX_LEN];
+};
+
+struct v4l2_subdev_frame_size_enum {
+    __u32 index;
+    __u32 pad;
+    __u32 code;
+    __u32 min_width;
+    __u32 max_width;
+    __u32 min_height;
+    __u32 max_height;
+    __u32 which;
+    __u32 reserved[8];
+};
+
+
+#define VIDIOC_STFISP_LOAD_FW \
+        _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct stfisp_fw_info)
+
+#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
+        _IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
+#define MEDIA_BUS_FMT_SRGGB10_1X10  0x300f
+
+#define FBIOPAN_GET_PP_MODE        0x4609
+#define FBIOPAN_SET_PP_MODE        0x460a
+
+enum COLOR_FORMAT{
+    COLOR_YUV422_UYVY = 0,  // 00={Y1,V0,Y0,U0}
+    COLOR_YUV422_VYUY = 1,  // 01={Y1,U0,Y0,V0}
+    COLOR_YUV422_YUYV = 2,  // 10={V0,Y1,U0,Y0}
+    COLOR_YUV422_YVYU = 3,  // 11={U0,Y1,V0,Y0}
+
+    COLOR_YUV420P,          // 4
+    COLOR_YUV420_NV21,      // 5
+    COLOR_YUV420_NV12,      // 6
+
+    COLOR_RGB888_ARGB,      // 7
+    COLOR_RGB888_ABGR,      // 8
+    COLOR_RGB888_RGBA,      // 9
+    COLOR_RGB888_BGRA,      // 10
+    COLOR_RGB565,           // 11
+};
+
+struct pp_video_mode {
+    enum COLOR_FORMAT format;
+    unsigned int height;
+    unsigned int width;
+    unsigned int addr;
+};
+
+struct pp_mode {
+    char pp_id;
+    bool bus_out;        /*out to ddr*/
+    bool fifo_out;        /*out to lcdc*/
+    bool inited;
+    struct pp_video_mode src;
+    struct pp_video_mode dst;
+};
+
+#if defined(IO_MMAP) || defined(IO_USERPTR)
+// minimum number of buffer to request in VIDIOC_REQBUFS call
+#define VIDIOC_REQBUFS_COUNT 5
+#endif
+
+typedef enum {
+#ifdef IO_READ
+        IO_METHOD_READ,
+#endif
+#ifdef IO_MMAP
+        IO_METHOD_MMAP,
+#endif
+#ifdef IO_USERPTR
+        IO_METHOD_USERPTR,
+#endif
+} io_method;
+
+struct buffer {
+    void *                  start;
+    size_t                  length;
+};
+
+static io_method        g_io_mthd   = IO_METHOD_MMAP;
+static int              g_fd        = -1;
+static int              g_fb_fd     = -1;
+static int              g_stfbc_fd  = -1;
+struct buffer *         g_buffers     = NULL;
+static unsigned int     n_buffers   = 0;
+struct fb_var_screeninfo g_vinfo;
+struct fb_fix_screeninfo g_finfo;
+static unsigned char *g_fb_buf = NULL;
+long g_screensize = 1920 * 1080 * 2;
+long g_imagesize  = 1920 * 1080 * 2;
+// global settings
+static unsigned int format= V4L2_PIX_FMT_RGB565;
+static int pixformat = COLOR_RGB565;
+static unsigned int width = 1920;
+static unsigned int height = 1080;
+static unsigned int left = 0;
+static unsigned int up = 0;
+static unsigned int right = 0;
+static unsigned int down = 0;
+static unsigned int crop_flag = 0;
+//static int istride = 1280;
+static unsigned int fps = 30;
+static unsigned int test_fps = 0;
+static int continuous = 0;
+static unsigned char jpegQuality = 70;
+static char* jpegFilename = NULL;
+static char* deviceName = "/dev/video0";
+static unsigned int fps_count = 0;
+static struct v4l2_subdev_frame_size_enum frame_size;
+//static const char* const continuousFilenameFmt = "%s_%010"PRIu32"_%"PRId64".jpg";
+
+inline int clip(int value, int min, int max) {
+    return (value > max ? max : value < min ? min : value);
+}
+
+static int v4l2fmt_to_fbfmt(unsigned int format)
+{
+    int pixformat = COLOR_RGB565;
+
+    switch (format) {
+    case V4L2_PIX_FMT_RGB565:
+        pixformat = COLOR_RGB565;
+        break;
+    case V4L2_PIX_FMT_RGB24:
+        pixformat = COLOR_RGB888_ARGB;
+        break;
+    case V4L2_PIX_FMT_YUV420:
+        pixformat = COLOR_YUV420P;
+        break;
+    case V4L2_PIX_FMT_YUYV:
+        pixformat = COLOR_YUV422_YUYV;
+        break;
+    case V4L2_PIX_FMT_NV21:
+        pixformat = COLOR_YUV420_NV21;
+        break;
+    case V4L2_PIX_FMT_NV12:
+        pixformat = COLOR_YUV420_NV12;
+        break;
+    case V4L2_PIX_FMT_YVYU:
+        pixformat = COLOR_YUV422_YVYU;
+        break;
+    default:
+        pixformat = COLOR_RGB565;
+        break;
+    }
+
+    return pixformat;
+}
+
+void test_float_1()
+{
+    int count = 1920 * 1080 * 2;
+    float r, g, b;
+    float y = 10, u = 20, v = 30;
+    int int_r, int_g, int_b;
+    int int_y = 10, int_u = 20, int_v = 30;
+    struct timeval tv1, tv2, tv3;
+    long long elapse = 0;
+    int i;
+
+    gettimeofday(&tv1, NULL);
+    while (count--) {
+        b = 1.164 * (y - 16) + 2.018 * (u - 128);
+        g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128);
+        r = 1.164 * (y - 16) + 1.596 * (v - 128);
+
+        y ++;
+        u ++;
+        v ++;
+    }
+    gettimeofday(&tv2, NULL);
+    elapse = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000;
+    printf("elapse: %lldms, out: r=%f, g=%f, b=%f\n",
+            elapse ,r, g, b);
+
+    count = 1920 * 1080 * 2;
+    gettimeofday(&tv1, NULL);
+    while (count--) {
+        int_b = 1164 * (y - 16) + 2018 * (u - 128);
+        int_g = 1164 * (y - 16) - 813 * (v - 128) - 391 * (u - 128);
+        int_r = 1164 * (y - 16) + 1596 * (v - 128);
+
+        int_y ++;
+        int_u ++;
+        int_v ++;
+    }
+    gettimeofday(&tv2, NULL);
+    elapse = (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec);
+    printf("elapse: %lldus, out: r=%d, g=%d, b=%d\n",
+            elapse , int_r, int_g, int_b);
+
+    count = 1920 * 1080 * 2;
+    unsigned char* arraybuf = NULL;
+    arraybuf = (unsigned char*)malloc(count);
+    if (!arraybuf) {
+        printf("arraybuf malloc error\n");
+        return;
+    }
+
+    unsigned char* arraybuf2 = NULL;
+    arraybuf2 = (unsigned char*)malloc(count);
+    if (!arraybuf2) {
+        printf("arraybuf2 malloc error\n");
+        return;
+    }
+
+    gettimeofday(&tv1, NULL);
+
+    for (i = 0; i < count; i++) {
+        arraybuf[i] = i + 1;
+    }
+
+    gettimeofday(&tv2, NULL);
+
+    memcpy(arraybuf2, arraybuf, count);
+
+    gettimeofday(&tv3, NULL);
+
+    elapse = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000;
+    printf("for() elapse: %lldms\n", elapse);
+
+    elapse = (tv3.tv_sec - tv2.tv_sec) * 1000000 + (tv3.tv_usec - tv2.tv_usec);
+    printf("memcpy() run elapse: %lldus\n", elapse);
+
+    convert_nv21_to_rgb(arraybuf, arraybuf2, 1920, 1080, 1);
+
+    free(arraybuf);
+    free(arraybuf2);
+}
+
+/**
+SIGINT interput handler
+*/
+void StopContCapture(int sig_id) {
+    printf("stoping continuous capture\n");
+    continuous = 0;
+}
+
+void InstallSIGINTHandler() {
+    struct sigaction sa;
+    CLEAR(sa);
+
+    sa.sa_handler = StopContCapture;
+    if(sigaction(SIGINT, &sa, 0) != 0)
+    {
+        fprintf(stderr,"could not install SIGINT handler, continuous capture disabled");
+        continuous = 0;
+    }
+}
+
+/**
+    Print error message and terminate programm with EXIT_FAILURE return code.
+
+    \param s error message to print
+*/
+static void errno_exit(const char* s)
+{
+    fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
+    exit(EXIT_FAILURE);
+}
+
+/**
+    Do ioctl and retry if error was EINTR ("A signal was caught during the ioctl() operation."). Parameters are the same as on ioctl.
+
+    \param fd file descriptor
+    \param request request
+    \param argp argument
+    \returns result from ioctl
+*/
+static int xioctl(int fd, int request, void* argp)
+{
+    int r;
+
+    do r = v4l2_ioctl(fd, request, argp);
+    while (-1 == r && EINTR == errno);
+
+    return r;
+}
+
+/**
+    Write image to jpeg file.
+
+    \param img image to write
+*/
+int write_file (char * filename,unsigned char *image_buffer, int size)
+{
+    /*  More stuff */
+
+    FILE * outfile;               /*  target file */
+
+    if ((outfile = fopen(filename, "w+")) == NULL) {
+
+        fprintf(stderr, "can't open %s\n", filename);
+
+        return -1;
+
+    }
+    fwrite(image_buffer, size, 1, outfile);
+
+    fclose(outfile);
+    return 0 ;
+}
+
+int write_JPEG_file (char * filename,unsigned char *image_buffer, int image_width, int image_height, int quality )
+
+{
+
+    struct jpeg_compress_struct cinfo;
+
+    struct jpeg_error_mgr jerr;
+
+    /*  More stuff */
+
+    FILE * outfile;               /*  target file */
+
+    JSAMPROW row_pointer[1];      /*  pointer to JSAMPLE row[s] */
+
+    int row_stride;               /*  physical row width in image buffer */
+
+
+
+    /*  Step 1: allocate and initialize JPEG compression object */
+
+    cinfo.err = jpeg_std_error(&jerr);
+
+    /*  Now we can initialize the JPEG compression object. */
+
+    jpeg_create_compress(&cinfo);
+
+
+
+    /*  Step 2: specify data destination (eg, a file) */
+
+    /*  Note: steps 2 and 3 can be done in either order. */
+
+
+
+    if ((outfile = fopen(filename, "w+")) == NULL) {
+
+        fprintf(stderr, "can't open %s\n", filename);
+
+        return -1;
+
+    }
+
+    jpeg_stdio_dest(&cinfo, outfile);
+
+
+
+    /*  Step 3: set parameters for compression */
+
+    cinfo.image_width = image_width;      /*  image width and height, in pixels */
+
+    cinfo.image_height = image_height;
+
+    cinfo.input_components = 3;           /*  # of color components per pixel */
+
+    cinfo.in_color_space = JCS_RGB;       /*  colorspace of input image */
+
+
+
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, quality, TRUE /*  limit to baseline-JPEG values */);
+
+
+
+    /*  Step 4: Start compressor */
+
+
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+
+
+    /*  Step 5: while (scan lines remain to be written) */
+
+    row_stride = image_width * 3; /*  JSAMPLEs per row in image_buffer */
+
+
+
+    while (cinfo.next_scanline < cinfo.image_height) {
+
+        row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+
+        (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+
+    }
+
+
+
+    /*  Step 6: Finish compression */
+
+
+
+    jpeg_finish_compress(&cinfo);
+
+    /*  After finish_compress, we can close the output file. */
+
+    fclose(outfile);
+
+
+
+    /*  Step 7: release JPEG compression object */
+
+
+
+    /*  This is an important step since it will release a good deal of memory. */
+
+    jpeg_destroy_compress(&cinfo);
+
+
+
+    /*  And we're done! */
+
+    return 0 ;
+
+}
+
+static void jpegWrite(unsigned char* img, char* jpegFilename)
+{
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+
+    JSAMPROW row_pointer[1];
+    FILE *outfile = fopen( jpegFilename, "wb" );
+
+    // try to open file for saving
+    if (!outfile) {
+        errno_exit("jpeg");
+    }
+
+    // create jpeg data
+    cinfo.err = jpeg_std_error( &jerr );
+    jpeg_create_compress(&cinfo);
+    jpeg_stdio_dest(&cinfo, outfile);
+
+    // set image parameters
+    cinfo.image_width = width;
+    cinfo.image_height = height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    // set jpeg compression parameters to default
+    jpeg_set_defaults(&cinfo);
+    // and then adjust quality setting
+    jpeg_set_quality(&cinfo, jpegQuality, TRUE);
+
+    // start compress
+    jpeg_start_compress(&cinfo, TRUE);
+
+    // feed data
+    while (cinfo.next_scanline < cinfo.image_height) {
+        row_pointer[0] = &img[cinfo.next_scanline * cinfo.image_width *  cinfo.input_components];
+        jpeg_write_scanlines(&cinfo, row_pointer, 1);
+    }
+
+    // finish compression
+    jpeg_finish_compress(&cinfo);
+
+    // destroy jpeg data
+    jpeg_destroy_compress(&cinfo);
+
+    // close output file
+    fclose(outfile);
+}
+
+/**
+    process image read
+*/
+static void imageProcess(const void* p, struct timeval timestamp)
+{
+    //timestamp.tv_sec
+    //timestamp.tv_usec
+    unsigned char* src = (unsigned char*)p;
+    unsigned char* dst = malloc(width*height*3*sizeof(char));
+    static int count = 0;
+
+    if (test_fps)
+        return;
+
+    // write jpeg
+    char filename[512];
+    switch (format) {
+        case V4L2_PIX_FMT_YUV420:
+            if (jpegFilename) {
+                // sprintf(filename, "%d-yuv420-%s", count, jpegFilename);
+                // YUV420toYUV444(width, height, src, dst);
+                // jpegWrite(dst, filename);
+                sprintf(filename, "raw-%d-yuv420-%s", count, jpegFilename);
+                write_file(filename, src, g_imagesize);
+                count++;
+            }
+            break;
+        case V4L2_PIX_FMT_YUYV:
+        case V4L2_PIX_FMT_YVYU:
+            if (jpegFilename) {
+                // sprintf(filename, "%d-yuv422-%s", count, jpegFilename);
+                // YUV422toYUV444(width, height, src, dst);
+                // jpegWrite(dst, filename);
+                sprintf(filename, "raw-%d-yuv422-%s", count, jpegFilename);
+                write_file(filename, src, g_imagesize);
+                count++;
+            }
+            if (pixformat == v4l2fmt_to_fbfmt(format)) {
+                yuyv_resize(src, g_fb_buf, width, height);
+            } else if (g_vinfo.grayscale) {
+                convert_yuyv_to_nv12(src, g_fb_buf, width, height, 1);
+            } else {
+                convert_yuyv_to_rgb(src, g_fb_buf, width, height, 0);
+            }
+            break;
+        case V4L2_PIX_FMT_NV21:
+            if (jpegFilename) {
+                // sprintf(filename, "%d-nv21-%s", count, jpegFilename);
+                // YUV420NV21toYUV444(width, height, src, dst);
+                // jpegWrite(dst, filename);
+                sprintf(filename, "raw-%d-nv21-%s", count, jpegFilename);
+                write_file(filename, src, g_imagesize);
+                count++;
+            }
+            if (pixformat == v4l2fmt_to_fbfmt(format))
+                convert_nv21_to_nv12(src, g_fb_buf, width, height, 0);
+            else if (g_vinfo.grayscale)
+                convert_nv21_to_nv12(src, g_fb_buf, width, height, 1);
+            else
+                convert_nv21_to_rgb(src, g_fb_buf, width, height, 1);
+            break;
+        case V4L2_PIX_FMT_NV12:
+            if (jpegFilename) {
+                // sprintf(filename, "%d-nv12-%s", count, jpegFilename);
+                // YUV420NV12toYUV444(width, height, src, dst);
+                // jpegWrite(dst, filename);
+                sprintf(filename, "raw-%d-nv12-%s", count, jpegFilename);
+                write_file(filename, src, g_imagesize);
+                count++;
+            }
+            if (pixformat == v4l2fmt_to_fbfmt(format))
+                convert_nv21_to_nv12(src, g_fb_buf, width, height, 0);
+            else if (g_vinfo.grayscale)
+                convert_nv21_to_nv12(src, g_fb_buf, width, height, 0);
+            else
+                convert_nv21_to_rgb(src, g_fb_buf, width, height, 0);
+            break;
+        case V4L2_PIX_FMT_RGB24:
+            if (jpegFilename) {
+                // sprintf(filename, "%d-rgb-%s", count, jpegFilename);
+                // RGB565toRGB888(width, height, src, dst);
+                // write_JPEG_file(filename, src, width, height, jpegQuality);
+                sprintf(filename, "raw-%d-rgb-%s", count, jpegFilename);
+                write_file(filename, src, g_imagesize);
+                count++;
+            }
+            convert_rgb888_to_rgb(src, g_fb_buf, width, height, 0);
+            break;
+        case V4L2_PIX_FMT_RGB565:
+            if (jpegFilename) {
+                // sprintf(filename, "%d-rgb565-%s", count, jpegFilename);
+                // RGB565toRGB888(width, height, src, dst);
+                // write_JPEG_file(filename, dst, width, height, jpegQuality);
+                sprintf(filename, "raw-%d-rgb565-%s", count, jpegFilename);
+                write_file(filename, src, g_imagesize);
+                count++;
+            }
+            if (pixformat == v4l2fmt_to_fbfmt(format))
+                convert_rgb565_to_rgb(src, g_fb_buf, width, height, 0);
+            else if (g_vinfo.grayscale)
+                convert_rgb565_to_nv12(src, g_fb_buf, width, height, 0);
+            else
+                convert_rgb565_to_rgb(src, g_fb_buf, width, height, 0);
+            break;
+        case V4L2_PIX_FMT_SRGGB12:
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-RGGB12-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-RGGB12.raw", count);
+            write_file(filename, src, g_imagesize);
+            RAW12toRAW16(width, height, src, dst);
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-RGGB16-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-RGGB16.raw", count);
+            write_file(filename, dst, width * height * 2);
+            count++;
+            break;
+        case V4L2_PIX_FMT_SGRBG12:
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-GRBG12-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-GRBG12.raw", count);
+            write_file(filename, src, g_imagesize);
+            RAW12toRAW16(width, height, src, dst);
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-GRBG16-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-GRBG16.raw", count);
+            write_file(filename, dst, width * height * 2);
+            count++;
+            break;
+        case V4L2_PIX_FMT_SGBRG12:
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-GBRG12-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-GBRG12.raw", count);
+            write_file(filename, src, g_imagesize);
+            RAW12toRAW16(width, height, src, dst);
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-GBRG16-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-GBRG16.raw", count);
+            write_file(filename, dst, width * height * 2);
+            count++;
+            break;
+        case V4L2_PIX_FMT_SBGGR12:
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-BGGR12-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-BGGR12.raw", count);
+            write_file(filename, src, g_imagesize);
+            RAW12toRAW16(width, height, src, dst);
+            if (jpegFilename)
+                sprintf(filename, "raw-%d-BGGR16-%s", count, jpegFilename);
+            else
+                sprintf(filename, "raw-%d-BGGR16.raw", count);
+            write_file(filename, dst, width * height * 2);
+            count++;
+            break;
+        default:
+            printf("unknow format\n");
+            break;
+    }
+
+    // free temporary image
+    free(dst);
+}
+
+/**
+    read single frame
+*/
+static int frameRead(void)
+{
+    struct v4l2_buffer buf;
+#ifdef IO_USERPTR
+    unsigned int i;
+#endif
+
+    switch (g_io_mthd) {
+#ifdef IO_READ
+        case IO_METHOD_READ:
+            if (-1 == v4l2_read(g_fd, g_buffers[0].start, g_buffers[0].length)) {
+                switch (errno) {
+                    case EAGAIN:
+                        return 0;
+
+                    case EIO:
+                        // Could ignore EIO, see spec.
+                        // fall through
+
+                    default:
+                        errno_exit("read");
+                }
+            }
+
+            struct timespec ts;
+            struct timeval timestamp;
+            clock_gettime(CLOCK_MONOTONIC,&ts);
+            timestamp.tv_sec = ts.tv_sec;
+            timestamp.tv_usec = ts.tv_nsec/1000;
+
+            imageProcess(g_buffers[0].start,timestamp);
+            break;
+#endif
+
+#ifdef IO_MMAP
+        case IO_METHOD_MMAP:
+            CLEAR(buf);
+
+            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+            buf.memory = V4L2_MEMORY_MMAP;
+
+            if (-1 == xioctl(g_fd, VIDIOC_DQBUF, &buf)) {
+                switch (errno) {
+                    case EAGAIN:
+                        return 0;
+
+                    case EIO:
+                        // Could ignore EIO, see spec
+                        // fall through
+
+                    default:
+                        errno_exit("VIDIOC_DQBUF");
+                }
+            }
+
+            assert(buf.index < n_buffers);
+
+            imageProcess(g_buffers[buf.index].start, buf.timestamp);
+            if (-1 == xioctl(g_fd, VIDIOC_QBUF, &buf))
+                errno_exit("VIDIOC_QBUF");
+
+            break;
+#endif
+
+#ifdef IO_USERPTR
+            case IO_METHOD_USERPTR:
+                CLEAR (buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_USERPTR;
+
+                if (-1 == xioctl(g_fd, VIDIOC_DQBUF, &buf)) {
+                    switch (errno) {
+                    case EAGAIN:
+                        return 0;
+
+                    case EIO:
+                        // Could ignore EIO, see spec.
+                        // fall through
+
+                    default:
+                        errno_exit("VIDIOC_DQBUF");
+                    }
+                }
+
+                for (i = 0; i < n_buffers; ++i) {
+                    if (buf.m.userptr == (unsigned long)g_buffers[i].start 
+                            && buf.length == g_buffers[i].length) {
+                        break;
+                    }
+                }
+                assert (i < n_buffers);
+
+                imageProcess((void *)buf.m.userptr, buf.timestamp);
+
+                if (-1 == xioctl(g_fd, VIDIOC_QBUF, &buf))
+                    errno_exit("VIDIOC_QBUF");
+                break;
+#endif
+    }
+
+    static unsigned int start_timems;
+    unsigned int time_ms, tmp_ms;
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    tmp_ms = ts.tv_sec * 1000 + ts.tv_nsec/1000000;
+    time_ms = tmp_ms - start_timems;
+    start_timems = tmp_ms;
+
+    if (!(++fps_count%5)) {
+        fps_count = 0;
+        printf("%s format = 0x%x\n", __func__, format);
+        printf("fps: %d\n", 1000/time_ms);
+    }
+
+    return 1;
+}
+
+/**
+    mainloop: read frames and process them
+*/
+static void mainLoop(void)
+{
+    int count, i;
+    unsigned int numberOfTimeouts;
+
+    numberOfTimeouts = 0;
+    count = 3;
+
+    while (count-- > 0) {
+        for (i = 0; i < 1; i++) {
+            fd_set fds;
+            struct timeval tv;
+            int r;
+
+            FD_ZERO(&fds);
+            FD_SET(g_fd, &fds);
+
+            /* Timeout. */
+            tv.tv_sec = 1;
+            tv.tv_usec = 0;
+
+            r = select(g_fd + 1, &fds, NULL, NULL, &tv);
+
+            if (-1 == r) {
+                if (EINTR == errno)
+                    continue;
+
+                errno_exit("select");
+            }
+
+            if (0 == r) {
+                if (numberOfTimeouts <= 0) {
+                    // count++;
+                } else {
+                    fprintf(stderr, "select timeout\n");
+                    exit(EXIT_FAILURE);
+                }
+            }
+            if(continuous == 1) {
+                count = 3;
+            }
+
+            if (frameRead())
+                break;
+
+            /* EAGAIN - continue select loop. */
+        }
+    }
+}
+
+/**
+    stop capturing
+*/
+static void captureStop(void)
+{
+    enum v4l2_buf_type type;
+
+    switch (g_io_mthd) {
+#ifdef IO_READ
+        case IO_METHOD_READ:
+            /* Nothing to do. */
+            break;
+#endif
+
+#ifdef IO_MMAP
+        case IO_METHOD_MMAP:
+#endif
+#ifdef IO_USERPTR
+        case IO_METHOD_USERPTR:
+#endif
+#if defined(IO_MMAP) || defined(IO_USERPTR)
+            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+            if (-1 == xioctl(g_fd, VIDIOC_STREAMOFF, &type))
+            errno_exit("VIDIOC_STREAMOFF");
+
+            break;
+#endif
+    }
+}
+
+/**
+  start capturing
+*/
+static void captureStart(void)
+{
+    unsigned int i;
+    enum v4l2_buf_type type;
+
+    switch (g_io_mthd) {
+#ifdef IO_READ
+        case IO_METHOD_READ:
+            /* Nothing to do. */
+            break;
+#endif
+
+#ifdef IO_MMAP
+        case IO_METHOD_MMAP:
+            for (i = 0; i < n_buffers; ++i) {
+                struct v4l2_buffer buf;
+
+                CLEAR(buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_MMAP;
+                buf.index = i;
+
+                if (-1 == xioctl(g_fd, VIDIOC_QBUF, &buf))
+                    errno_exit("VIDIOC_QBUF");
+                }
+
+            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+            if (-1 == xioctl(g_fd, VIDIOC_STREAMON, &type))
+                errno_exit("VIDIOC_STREAMON");
+
+            break;
+#endif
+
+#ifdef IO_USERPTR
+        case IO_METHOD_USERPTR:
+            for (i = 0; i < n_buffers; ++i) {
+                struct v4l2_buffer buf;
+
+            CLEAR (buf);
+
+            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+            buf.memory = V4L2_MEMORY_USERPTR;
+            buf.index = i;
+            buf.m.userptr = (unsigned long) g_buffers[i].start;
+            buf.length = g_buffers[i].length;
+
+            if (-1 == xioctl(g_fd, VIDIOC_QBUF, &buf))
+                errno_exit("VIDIOC_QBUF");
+            }
+
+            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+            if (-1 == xioctl(g_fd, VIDIOC_STREAMON, &type))
+                errno_exit("VIDIOC_STREAMON");
+
+            break;
+#endif
+    }
+}
+
+static void deviceUninit(void)
+{
+    unsigned int i;
+
+    switch (g_io_mthd) {
+#ifdef IO_READ
+        case IO_METHOD_READ:
+            free(g_buffers[0].start);
+            break;
+#endif
+
+#ifdef IO_MMAP
+        case IO_METHOD_MMAP:
+            for (i = 0; i < n_buffers; ++i)
+                if (-1 == v4l2_munmap(g_buffers[i].start, g_buffers[i].length))
+                    errno_exit("munmap");
+            break;
+#endif
+
+#ifdef IO_USERPTR
+        case IO_METHOD_USERPTR:
+            for (i = 0; i < n_buffers; ++i)
+                free(g_buffers[i].start);
+            break;
+#endif
+    }
+
+    free(g_buffers);
+
+    if (!test_fps) {
+        if (-1 == munmap((void *)g_fb_buf, g_screensize)) {
+            printf(" Error: framebuffer device munmap() failed.\n");
+            exit (EXIT_FAILURE) ;
+        }
+    }
+}
+
+#ifdef IO_READ
+static void readInit(unsigned int buffer_size)
+{
+    g_buffers = calloc(1, sizeof(*g_buffers));
+
+    if (!g_buffers) {
+        fprintf(stderr, "Out of memory\n");
+        exit(EXIT_FAILURE);
+    }
+
+    g_buffers[0].length = buffer_size;
+    g_buffers[0].start = malloc(buffer_size);
+
+    if (!g_buffers[0].start) {
+        fprintf (stderr, "Out of memory\n");
+        exit(EXIT_FAILURE);
+    }
+}
+#endif
+
+#ifdef IO_MMAP
+static void mmapInit(void)
+{
+    struct v4l2_requestbuffers req;
+
+    CLEAR(req);
+
+    req.count = VIDIOC_REQBUFS_COUNT;
+    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    req.memory = V4L2_MEMORY_MMAP;
+
+    if (-1 == xioctl(g_fd, VIDIOC_REQBUFS, &req)) {
+        if (EINVAL == errno) {
+            fprintf(stderr, "%s does not support memory mapping\n", deviceName);
+            exit(EXIT_FAILURE);
+        } else {
+            errno_exit("VIDIOC_REQBUFS");
+        }
+    }
+
+    if (req.count < 2) {
+        fprintf(stderr, "Insufficient buffer memory on %s\n", deviceName);
+        exit(EXIT_FAILURE);
+    }
+
+    g_buffers = calloc(req.count, sizeof(*g_buffers));
+
+    if (!g_buffers) {
+        fprintf(stderr, "Out of memory\n");
+        exit(EXIT_FAILURE);
+    }
+
+    for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
+        struct v4l2_buffer buf;
+
+        CLEAR(buf);
+
+        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        buf.memory = V4L2_MEMORY_MMAP;
+        buf.index = n_buffers;
+
+        if (-1 == xioctl(g_fd, VIDIOC_QUERYBUF, &buf))
+            errno_exit("VIDIOC_QUERYBUF");
+
+        g_buffers[n_buffers].length = buf.length;
+        g_buffers[n_buffers].start = v4l2_mmap(NULL, /* start anywhere */
+                buf.length, PROT_READ | PROT_WRITE, /* required */
+                MAP_SHARED, /* recommended */
+                g_fd, buf.m.offset);
+
+        if (MAP_FAILED == g_buffers[n_buffers].start)
+            errno_exit("mmap");
+        g_imagesize = buf.length;
+    }
+}
+#endif
+
+#ifdef IO_USERPTR
+static void userptrInit(unsigned int buffer_size)
+{
+    struct v4l2_requestbuffers req;
+    unsigned int page_size;
+
+    page_size = getpagesize();
+    buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
+
+    CLEAR(req);
+
+    req.count = VIDIOC_REQBUFS_COUNT;
+    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    req.memory = V4L2_MEMORY_USERPTR;
+
+    if (-1 == xioctl(g_fd, VIDIOC_REQBUFS, &req)) {
+        if (EINVAL == errno) {
+            fprintf(stderr, "%s does not support user pointer i/o\n", deviceName);
+            exit(EXIT_FAILURE);
+        } else {
+            errno_exit("VIDIOC_REQBUFS");
+        }
+    }
+
+    g_buffers = calloc(4, sizeof(*g_buffers));
+
+    if (!g_buffers) {
+        fprintf(stderr, "Out of memory\n");
+        exit(EXIT_FAILURE);
+    }
+
+    for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
+        g_buffers[n_buffers].length = buffer_size;
+        g_buffers[n_buffers].start = memalign(/* boundary */ page_size, buffer_size);
+
+        if (!g_buffers[n_buffers].start) {
+            fprintf(stderr, "Out of memory\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+#endif
+
+/**
+    initialize device
+*/
+static void deviceInit(void)
+{
+    struct v4l2_capability cap;
+    struct v4l2_cropcap cropcap;
+    struct v4l2_crop crop;
+    struct v4l2_format fmt;
+    struct v4l2_streamparm frameint;
+    //struct v4l2_streamparm frameget;
+    unsigned int min;
+
+    if (-1 == xioctl(g_fd, VIDIOC_QUERYCAP, &cap)) {
+        if (EINVAL == errno) {
+            fprintf(stderr, "%s is no V4L2 device\n",deviceName);
+            exit(EXIT_FAILURE);
+        } else {
+            errno_exit("VIDIOC_QUERYCAP");
+        }
+    }
+
+    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
+        fprintf(stderr, "%s is no video capture device\n",deviceName);
+        exit(EXIT_FAILURE);
+    }
+
+    switch (g_io_mthd) {
+#ifdef IO_READ
+        case IO_METHOD_READ:
+            if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
+                fprintf(stderr, "%s does not support read i/o\n",deviceName);
+                exit(EXIT_FAILURE);
+            }
+            break;
+#endif
+
+#ifdef IO_MMAP
+        case IO_METHOD_MMAP:
+#endif
+#ifdef IO_USERPTR
+        case IO_METHOD_USERPTR:
+#endif
+#if defined(IO_MMAP) || defined(IO_USERPTR)
+                  if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
+                fprintf(stderr, "%s does not support streaming i/o\n",deviceName);
+                exit(EXIT_FAILURE);
+            }
+            break;
+#endif
+    }
+
+    /* Select video input, video standard and tune here. */
+    CLEAR(cropcap);
+
+    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+    if (0 == xioctl(g_fd, VIDIOC_CROPCAP, &cropcap)) {
+        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        crop.c = cropcap.defrect; /* reset to default */
+
+        if (-1 == xioctl(g_fd, VIDIOC_S_CROP, &crop)) {
+            switch (errno) {
+                case EINVAL:
+                    /* Cropping not supported. */
+                    break;
+                default:
+                    /* Errors ignored. */
+                    break;
+            }
+        }
+    } else {
+        /* Errors ignored. */
+    }
+
+    CLEAR(fmt);
+
+    // v4l2_format
+    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    fmt.fmt.pix.width = width;
+    fmt.fmt.pix.height = height;
+    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+    fmt.fmt.pix.pixelformat = format;
+
+    /* If the user has set the fps to -1, don't try to set the frame interval */
+    if (fps != -1)
+    {
+        CLEAR(frameint);
+
+        /* Attempt to set the frame interval. */
+        frameint.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        frameint.parm.capture.timeperframe.numerator = 1;
+        frameint.parm.capture.timeperframe.denominator = fps;
+        if (-1 == xioctl(g_fd, VIDIOC_S_PARM, &frameint))
+            fprintf(stderr,"Unable to set frame interval.\n");
+        fprintf(stderr,"set frame interval = %d.\n", frameint.parm.capture.timeperframe.denominator);
+    }
+
+    if (-1 == xioctl(g_fd, VIDIOC_S_FMT, &fmt))
+        errno_exit("VIDIOC_S_FMT");
+
+    if (crop_flag) {
+        struct v4l2_selection sel_crop = {
+            V4L2_BUF_TYPE_VIDEO_CAPTURE,
+            V4L2_SEL_TGT_CROP,
+            0,
+            { left, up, right, down }
+        };
+        struct v4l2_selection get_crop = {
+            V4L2_BUF_TYPE_VIDEO_CAPTURE,
+            V4L2_SEL_TGT_CROP,
+        };
+
+        fprintf(stderr, "sel_crop.left = %d, %d, %d, %d\n",
+            sel_crop.r.left, sel_crop.r.top, sel_crop.r.width, sel_crop.r.height);
+        if (-1 == xioctl(g_fd, VIDIOC_S_SELECTION, &sel_crop)) {
+            fprintf(stderr,"S_SELECTION Failed.\n");
+        }
+
+        fprintf(stderr, "sel_crop.left = %d, %d, %d, %d\n",
+            sel_crop.r.left, sel_crop.r.top, sel_crop.r.width, sel_crop.r.height);
+        if (-1 == xioctl(g_fd, VIDIOC_G_SELECTION, &get_crop)) {
+            fprintf(stderr,"G_SELECTION Failed.\n");
+        }
+
+        fprintf(stderr, "get_crop.left = %d, %d, %d, %d\n",
+            get_crop.r.left, get_crop.r.top, get_crop.r.width, get_crop.r.height);
+        if (memcmp(&sel_crop, &get_crop, sizeof(sel_crop))) {
+            fprintf(stderr,"set/get selection diff.\n");
+        }
+
+        memset(&fmt, 0, sizeof(struct v4l2_format));
+        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        fmt.fmt.pix.field = V4L2_FIELD_ANY;
+
+        if (-1 == ioctl(g_fd, VIDIOC_G_FMT, &fmt))
+            errno_exit("VIDIOC_G_FMT");
+    }
+
+    //if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) {
+    //if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) {
+    if (fmt.fmt.pix.pixelformat != format) {
+        fprintf(stderr,"Libv4l didn't accept format. Can't proceed.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Note VIDIOC_S_FMT may change width and height. */
+    if (width != fmt.fmt.pix.width) {
+        width = fmt.fmt.pix.width;
+        fprintf(stderr,"Image width set to %i by device %s.\n", width, deviceName);
+    }
+
+    if (height != fmt.fmt.pix.height) {
+        height = fmt.fmt.pix.height;
+        fprintf(stderr,"Image height set to %i by device %s.\n", height, deviceName);
+    }
+
+    /* Buggy driver paranoia. */
+    min = fmt.fmt.pix.width * 2;
+    if (fmt.fmt.pix.bytesperline < min)
+        fmt.fmt.pix.bytesperline = min;
+    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
+    if (fmt.fmt.pix.sizeimage < min)
+        fmt.fmt.pix.sizeimage = min;
+
+    switch (g_io_mthd) {
+#ifdef IO_READ
+        case IO_METHOD_READ:
+            readInit(fmt.fmt.pix.sizeimage);
+            break;
+#endif
+
+#ifdef IO_MMAP
+        case IO_METHOD_MMAP:
+            mmapInit();
+            break;
+#endif
+
+#ifdef IO_USERPTR
+        case IO_METHOD_USERPTR:
+            userptrInit(fmt.fmt.pix.sizeimage);
+            break;
+#endif
+    }
+
+    if (!test_fps) {
+        struct pp_mode pp_info[3];
+
+        pixformat = v4l2fmt_to_fbfmt(format);
+        if (-1 == ioctl(g_stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) {
+            printf("Error reading variable information.\n");
+            exit (EXIT_FAILURE);
+        }
+        printf("get pp format :%d, %d\n", pp_info[1].src.format, __LINE__);
+
+        pp_info[1].src.format = pixformat;
+
+        if (-1 == ioctl(g_stfbc_fd, FBIOPAN_SET_PP_MODE, &pp_info[0])) {
+            printf("Error reading variable information.\n");
+            exit (EXIT_FAILURE);
+        }
+
+        if (-1 == ioctl(g_stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) {
+            printf("Error reading variable information.\n");
+            exit (EXIT_FAILURE);
+        }
+        printf("get pp format :%d, %d\n", pp_info[1].src.format, __LINE__);
+        pixformat = pp_info[1].src.format;
+
+        // Get fixed screen information
+        if (-1 == xioctl(g_fb_fd, FBIOGET_FSCREENINFO, &g_finfo)) {
+            printf("Error reading fixed information.\n");
+            exit (EXIT_FAILURE);
+        }
+
+        // Get variable screen information
+        if (-1 == xioctl(g_fb_fd, FBIOGET_VSCREENINFO, &g_vinfo)) {
+            printf("Error reading variable information.\n");
+            exit (EXIT_FAILURE);
+        }
+
+        printf("g_vinfo.xres = %d, g_vinfo.yres = %d, grayscale = %d\n", g_vinfo.xres, g_vinfo.yres, g_vinfo.grayscale);
+        printf("g_vinfo.xoffset = %d, g_vinfo.yoffset = %d\n", g_vinfo.xoffset, g_vinfo.yoffset);
+        printf("g_vinfo.bits_per_pixel = %d, g_finfo.line_length = %d\n", g_vinfo.bits_per_pixel, g_finfo.line_length);
+
+        // if (ioctl(g_fb_fd, FBIOPUT_VSCREENINFO, &g_vinfo) < 0) {
+        //     printf("FBIOPUT_VSCREENINFO.\n");
+        //     exit (EXIT_FAILURE);
+        // }
+
+        // printf("g_vinfo.bits_per_pixel = %d, g_finfo.line_length = %d\n", g_vinfo.bits_per_pixel, g_finfo.line_length);
+        g_screensize = g_vinfo.xres * g_vinfo.yres * g_vinfo.bits_per_pixel / 8;
+        // g_screensize = g_vinfo.xres * g_vinfo.yres * 32 / 8;
+        //mmap framebuffer
+        g_fb_buf = (unsigned char *)mmap(NULL, g_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fb_fd, 0);
+        if (g_fb_buf == (void *)(-1)) {
+            printf("Error: failed to map framebuffer device to memory.\n");
+            exit (EXIT_FAILURE) ;
+        }
+        memset(g_fb_buf, 0x00, g_screensize);
+    }
+}
+
+/**
+    close device
+*/
+static void deviceClose(void)
+{
+    if (-1 == v4l2_close(g_fd))
+        errno_exit("close");
+
+    g_fd = -1;
+    if (!test_fps) {
+        close(g_fb_fd);
+        close(g_stfbc_fd);
+    }
+}
+
+/**
+    open device
+*/
+static void deviceOpen(void)
+{
+    struct stat st;
+    //struct v4l2_capability cap;
+
+    // stat file
+    if (-1 == stat(deviceName, &st)) {
+        fprintf(stderr, "Cannot identify '%s': %d, %s\n", deviceName, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    // check if its device
+    if (!S_ISCHR(st.st_mode)) {
+        fprintf(stderr, "%s is no device\n", deviceName);
+        exit(EXIT_FAILURE);
+    }
+
+    // open device
+    g_fd = v4l2_open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
+    // g_fd = v4l2_open(deviceName, O_RDWR, 0);
+
+    // check if opening was successfull
+    if (-1 == g_fd) {
+        fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    //open framebuffer
+    if (!test_fps) {
+        g_fb_fd = open("/dev/fb0", O_RDWR);
+        if (g_fb_fd == -1) {
+            printf("Error: cannot open framebuffer device.\n");
+            exit (EXIT_FAILURE);
+        }
+        g_stfbc_fd = open("/dev/stfbcdev", O_RDWR);
+        if (g_stfbc_fd == -1) {
+            printf("Error: cannot open stfbcdev device.\n");
+            exit (EXIT_FAILURE);
+        }
+    }
+}
+
+void loadfw_start(char *filename)
+{
+    struct stfisp_fw_info fw_info = {0};
+
+    // open device
+    g_fd = open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
+
+    // check if opening was successfull
+    if (-1 == g_fd) {
+        fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    if (filename && (strlen(filename) < FILENAME_MAX_LEN))
+            memcpy(fw_info.filename, filename, strlen(filename) + 1);
+
+    fprintf(stderr, "VIDIOC_STFISP_LOAD_FW = 0x%lx, filename = %s, size = %lu\n",
+                    VIDIOC_STFISP_LOAD_FW, fw_info.filename, sizeof(struct stfisp_fw_info));
+    if (-1 == ioctl(g_fd, VIDIOC_STFISP_LOAD_FW, &fw_info)) {
+        if (EINVAL == errno) {
+            fprintf(stderr, "%s is no V4L2 device\n",deviceName);
+            exit(EXIT_FAILURE);
+        } else {
+            errno_exit("VIDIOC_STFISP_LOAD_FW");
+        }
+    }
+}
+
+void sensor_image_size_info(void)
+{
+    unsigned int i = 0;
+    fprintf(stderr, "go in sensor_image_size_info....\n");
+    // open device
+    g_fd = open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
+
+    // check if opening was successfull
+    if (-1 == g_fd) {
+        fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    for (i = 0; i < 4; i++)
+    {
+        frame_size.index = i;
+        frame_size.code = MEDIA_BUS_FMT_SRGGB10_1X10;
+        if (-1 == ioctl(g_fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frame_size)) {
+            errno_exit("VIDIOC_SIZE_INFO");
+        }
+
+        printf("image_size: width[%d] = %d, height[%d] = %d \n",
+                    i, frame_size.min_width, i, frame_size.min_height);
+    }
+}
+
+/**
+    print usage information
+*/
+static void usage(FILE* fp, int argc, char** argv)
+{
+    fprintf(fp,
+        "Usage: %s [options]\n\n"
+        "Options:\n"
+        "-d | --device name   Video device name [/dev/video0]\n"
+        "-h | --help          Print this message\n"
+        "-o | --output        Set JPEG output filename\n"
+        "-q | --quality       Set JPEG quality (0-100)\n"
+        "-m | --mmap          Use memory mapped buffer\n"
+        "-r | --read          Use read() calls\n"
+        "-u | --userptr       Use application allocated buffer\n"
+        "-W | --width         Set image width\n"
+        "-H | --height        Set image height\n"
+        "-X | --left          Set image x start\n"
+        "-Y | --up            Set image y start\n"
+        "-R | --right         Set image x width\n"
+        "-D | --down          Set image y height\n"
+        "-I | --interval      Set frame interval (fps) (-1 to skip)\n"
+        "-c | --continuous    Do continous capture, stop with SIGINT.\n"
+        "-v | --version       Print version\n"
+        "-f | --format        image format\n"
+        "                0:V4L2_PIX_FMT_RGB565\n"
+        "                1:V4L2_PIX_FMT_RGB24\n"
+        "                2:V4L2_PIX_FMT_YUV420\n"
+        "                3:V4L2_PIX_FMT_YUYV\n"
+        "                4:V4L2_PIX_FMT_NV21\n"
+        "                5:V4L2_PIX_FMT_NV12\n"
+        "                6:V4L2_PIX_FMT_YVYU\n"
+        "                7:V4L2_PIX_FMT_SRGGB12\n"
+        "                8:V4L2_PIX_FMT_SGRBG12\n"
+        "                9:V4L2_PIX_FMT_SGBRG12\n"
+        "                10:V4L2_PIX_FMT_SBGGR12\n"
+        "                default:V4L2_PIX_FMT_RGB565\n"
+        "-t | --testfps       test fps\n"
+        "-l | --loadfw        load stfisp fw image\n"
+        "-s | --g_imagesize     print image size\n"
+        "",
+        argv[0]);
+    }
+
+static const char short_options [] = "d:ho:q:mruW:H:I:vcf:tX:Y:R:D:l:s";
+
+static const struct option
+long_options [] = {
+    { "device",     required_argument,      NULL,           'd' },
+    { "help",       no_argument,            NULL,           'h' },
+    { "output",     required_argument,      NULL,           'o' },
+    { "quality",    required_argument,      NULL,           'q' },
+    { "mmap",       no_argument,            NULL,           'm' },
+    { "read",       no_argument,            NULL,           'r' },
+    { "userptr",    no_argument,            NULL,           'u' },
+    { "width",      required_argument,      NULL,           'W' },
+    { "height",     required_argument,      NULL,           'H' },
+    { "left",      required_argument,      NULL,           'X' },
+    { "up",       required_argument,      NULL,            'Y' },
+    { "right",       required_argument,      NULL,         'R' },
+    { "down",       required_argument,      NULL,          'D' },
+    { "interval",   required_argument,      NULL,           'I' },
+    { "version",    no_argument,            NULL,        'v' },
+    { "continuous", no_argument,            NULL,        'c' },
+    { "format",     required_argument,      NULL,        'f' },
+    { "testfps",    no_argument,            NULL,        't' },
+    { "loadfw",     required_argument,      NULL,        'l' },
+    { "g_imagesize",  no_argument,            NULL,        's' },
+    { 0, 0, 0, 0 }
+};
+
+int main(int argc, char **argv)
+{
+    for (;;) {
+        int index, c = 0;
+
+        c = getopt_long(argc, argv, short_options, long_options, &index);
+
+        if (-1 == c)
+            break;
+
+        switch (c) {
+            case 0: /* getopt_long() flag */
+                break;
+
+            case 'd':
+                deviceName = optarg;
+                break;
+
+            case 'h':
+                // print help
+                usage(stdout, argc, argv);
+                exit(EXIT_SUCCESS);
+
+            case 'o':
+                // set jpeg filename
+                jpegFilename = optarg;
+                break;
+
+            case 'q':
+                // set jpeg quality
+                jpegQuality = atoi(optarg);
+                break;
+
+            case 'm':
+#ifdef IO_MMAP
+                g_io_mthd = IO_METHOD_MMAP;
+#else
+                fprintf(stderr, "You didn't compile for mmap support.\n");
+                exit(EXIT_FAILURE);
+#endif
+                break;
+
+            case 'r':
+#ifdef IO_READ
+                g_io_mthd = IO_METHOD_READ;
+#else
+                fprintf(stderr, "You didn't compile for read support.\n");
+                exit(EXIT_FAILURE);
+#endif
+                break;
+
+            case 'u':
+#ifdef IO_USERPTR
+                g_io_mthd = IO_METHOD_USERPTR;
+#else
+                fprintf(stderr, "You didn't compile for userptr support.\n");
+                exit(EXIT_FAILURE);
+#endif
+                break;
+
+            case 'W':
+                // set width
+                width = atoi(optarg);
+                break;
+
+            case 'H':
+                // set height
+                height = atoi(optarg);
+                break;
+
+            case 'X':
+                // set x start
+                left = atoi(optarg);
+                crop_flag = 1;
+                break;
+
+            case 'Y':
+                // set y start
+                up = atoi(optarg);
+                crop_flag = 1;
+                break;
+
+            case 'R':
+                // set x width
+                right = atoi(optarg);
+                crop_flag = 1;
+                break;
+
+            case 'D':
+                // set y height
+                down = atoi(optarg);
+                crop_flag = 1;
+                break;
+
+            case 'I':
+                // set fps
+                fps = atoi(optarg);
+                break;
+
+            case 'c':
+                // set flag for continuous capture, interuptible by sigint
+                continuous = 1;
+                InstallSIGINTHandler();
+                break;
+
+
+            case 'v':
+                printf("Version: %s\n", VERSION);
+                exit(EXIT_SUCCESS);
+                break;
+
+            case 'f':
+                printf("format: %s\n", optarg);
+                format = atoi(optarg);
+                switch (format) {
+                    case  0:
+                        format = V4L2_PIX_FMT_RGB565;
+                        break;
+                    case  1:
+                        format = V4L2_PIX_FMT_RGB24;
+                        break;
+                    case  2:
+                        format = V4L2_PIX_FMT_YUV420;
+                        break;
+                    case  3:
+                        format = V4L2_PIX_FMT_YUYV;
+                        break;
+                    case  4:
+                        format = V4L2_PIX_FMT_NV21;
+                        break;
+                    case  5:
+                        format = V4L2_PIX_FMT_NV12;
+                        break;
+                    case  6:
+                        format = V4L2_PIX_FMT_YVYU;
+                        break;
+                    case  7:
+                        format = V4L2_PIX_FMT_SRGGB12;
+                        break;
+                    case  8:
+                        format = V4L2_PIX_FMT_SGRBG12;
+                        break;
+                    case  9:
+                        format = V4L2_PIX_FMT_SGBRG12;
+                        break;
+                    case  10:
+                        format = V4L2_PIX_FMT_SBGGR12;
+                        break;
+                    default:
+                        format = V4L2_PIX_FMT_RGB565;
+                        break;
+                }
+                break;
+
+            case 't':
+                test_fps = 1;
+                break;
+            case 'l':
+                loadfw_start(optarg);
+                exit(EXIT_SUCCESS);
+                break;
+            case 's':
+                sensor_image_size_info();
+                exit(EXIT_SUCCESS);
+                break;
+            default:
+                usage(stderr, argc, argv);
+                exit(EXIT_FAILURE);
+        }
+    }
+
+    // open and initialize device
+    deviceOpen();
+    deviceInit();
+
+    test_float_1();
+    // start capturing
+    captureStart();
+
+    // process frames
+    mainLoop();
+
+    // stop capturing
+    captureStop();
+
+    // close device
+    deviceUninit();
+    deviceClose();
+
+    exit(EXIT_SUCCESS);
+
+    return 0;
+}

+ 29 - 0
package/starfive/v4l2_test/v4l2_test.mk

@@ -0,0 +1,29 @@
+################################################################################
+#
+# v4l2test
+#
+################################################################################
+
+V4L2_TEST_LICENSE = GPL-2.0+
+
+define V4L2_TEST_BUILD_CMDS
+	cp package/starfive/v4l2_test/v4l2_test.c $(@D)/
+	cp package/starfive/v4l2_test/yuv.c $(@D)/
+	cp package/starfive/v4l2_test/yuv.h $(@D)/
+	cp package/starfive/v4l2_test/convert.c $(@D)/
+	cp package/starfive/v4l2_test/convert.h $(@D)/
+	cp package/starfive/v4l2_test/config.h $(@D)/
+	cp package/starfive/v4l2_test/string.c $(@D)/
+	cp package/starfive/v4l2_test/pipeline_setting.sh $(@D)/
+	(cd $(@D); $(TARGET_CC) -Wall -O2 v4l2_test.c yuv.c convert.c string.c -l v4l2 -l jpeg -o v4l2test)
+	#(cd $(@D); $(TARGET_CC) -Wall -O2 v4l2_test.c -o v4l2test)
+endef
+
+define V4L2_TEST_INSTALL_TARGET_CMDS
+	install -m 0755 -D $(@D)/v4l2test $(TARGET_DIR)/usr/bin/v4l2test
+	install -m 0755 -D $(@D)/pipeline_setting.sh $(TARGET_DIR)/usr/bin/pipeline_setting.sh
+endef
+
+V4L2_TEST_DEPENDENCIES = jpeg libv4l
+$(eval $(generic-package))
+

+ 126 - 0
package/starfive/v4l2_test/yuv.c

@@ -0,0 +1,126 @@
+/***************************************************************************
+ *   Copyright (C) 2012 by Tobias Müller                                   *
+ *   Tobias_Mueller@twam.info                                              *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/**
+	Convert from YUV420 format to YUV444.
+
+	\param width width of image
+	\param height height of image
+	\param src source
+	\param dst destination
+*/
+
+void YUV420toYUV444(int width, int height, unsigned char* src, unsigned char* dst) {
+	int line, column;
+	unsigned char *py, *pu, *pv;
+	unsigned char *tmp = dst;
+
+	// In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr.
+	// Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels.
+	unsigned char *base_py = src;
+	unsigned char *base_pu = src+(height*width);
+	unsigned char *base_pv = src+(height*width)+(height*width)/4;
+
+	for (line = 0; line < height; ++line) {
+		for (column = 0; column < width; ++column) {
+			py = base_py+(line*width)+column;
+			pu = base_pu+(line/2*width/2)+column/2;
+			pv = base_pv+(line/2*width/2)+column/2;
+
+			*tmp++ = *py;
+			*tmp++ = *pu;
+			*tmp++ = *pv;
+		}
+	}
+}
+
+void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char* dst) {
+	int line, column;
+	unsigned char *py, *pu, *pv;
+	unsigned char *tmp = dst;
+
+	// In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr.
+	// Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels.
+	unsigned char *base_py = src;
+	unsigned char *base_pu = src+(height*width);
+	unsigned char *base_pv = src+(height*width);
+
+	for (line = 0; line < height; ++line) {
+		for (column = 0; column < width; ++column) {
+			py = base_py+(line*width)+column;
+			pu = base_pu+((line/2*width/2)+column/2)*2+1;
+			pv = base_pv+((line/2*width/2)+column/2)*2;
+
+			*tmp++ = *py;
+			*tmp++ = *pu;
+			*tmp++ = *pv;
+		}
+	}
+}
+
+void YUV422toYUV444(int width, int height, unsigned char* src, unsigned char* dst) {
+	int line, column;
+	unsigned char *py, *pu, *pv;
+	unsigned char *tmp = dst;
+
+	// In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr.
+	// Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels.
+	unsigned char *base_py = src;
+	//unsigned char *base_pu = src+(height*width);
+	//unsigned char *base_pv = src+(height*width)+(height*width)/2;
+
+	for (line = 0; line < height; ++line) {
+		for (column = 0; column < width; ++column) {
+			py = base_py+((line*width)+column)*2;
+			pu = base_py+((line*width)+column)*2 + 1;
+			pv = base_py+((line*width)+column)*2 + 1;
+
+			*tmp++ = *py;
+			*tmp++ = *pu;
+			*tmp++ = *pv;
+		}
+	}
+}
+
+void RGB565toRGB888(int width, int height, unsigned char* src, unsigned char* dst)
+{
+	unsigned short *pix = (unsigned short *)src;
+	unsigned int i;
+	for (i = 0 ; i < width * height; i++)
+	{
+		*dst++ = (*(pix+i) & 0b1111100000000000) >> 8;
+		*dst++ = (*(pix+i) & 0b11111100000) >> 3 ;
+		*dst++ = (*(pix+i) & 0b11111) << 3;
+	}
+}
+
+void RAW12toRAW16(int width, int height, unsigned char* src, unsigned char* dst)
+{
+	unsigned char *p_src = src;
+	unsigned short *p_dst = (unsigned short *)dst;
+	unsigned int i, j;
+	for (i = 0 ; i < height; i++) {
+		p_src = src + (((width * 12 / 8 + 8 * 16 - 1) / (8 * 16)) * 128) * i;
+		for (j = 0 ; j < width * 12 / 8; j += 3) {
+			*p_dst++ = ((*(p_src + j)) | ((*(p_src + j + 1) & 0xF) << 8)) << 4;
+			*p_dst++ = ((*(p_src + j + 2) << 4) | ((*(p_src + j + 1)) >> 4)) << 4;
+		}
+	}
+}

+ 10 - 0
package/starfive/v4l2_test/yuv.h

@@ -0,0 +1,10 @@
+#ifndef _YUV_H_
+#define _YUV_H_
+
+void YUV420toYUV444(int width, int height, unsigned char* src, unsigned char* dst);
+void YUV422toYUV444(int width, int height, unsigned char* src, unsigned char* dst);
+void RGB565toRGB888(int width, int height, unsigned char* src, unsigned char* dst);
+void RAW12toRAW16(int width, int height, unsigned char* src, unsigned char* dst);
+void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char* dst);
+
+#endif

+ 6 - 0
package/starfive/wave511/Config.in

@@ -0,0 +1,6 @@
+comment "wave511 package"
+
+config BR2_PACKAGE_WAVE511
+	bool "wave511"
+	help
+	  wave511 package

+ 75 - 0
package/starfive/wave511/wave511.mk

@@ -0,0 +1,75 @@
+################################################################################
+#
+# wave511
+#
+################################################################################
+
+
+WAVE511_VERSION:=1.0.0
+WAVE511_SITE=$(TOPDIR)/../soft_3rdpart/wave511/code
+WAVE511_SITE_METHOD=local
+WAVE511_INSTALL_STAGING = YES
+
+export KERNELDIR=$(TOPDIR)/../work/linux
+	
+define WAVE511_BUILD_CMDS
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) -f $(@D)/WaveDecDriver_buildroot.mak
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) -f $(@D)/WaveDecode_buildroot.mak
+endef
+
+define WAVE511_CLEAN_CMDS
+
+endef
+
+define WAVE511_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0644 $(@D)/vdi/linux/driver/vdec.ko $(TARGET_DIR)/root/wave511/vdec.ko
+	$(INSTALL) -D -m 0777 $(@D)/vdi/linux/driver/load.sh $(TARGET_DIR)/root/wave511/vdec_load.sh
+	$(INSTALL) -D -m 0777 $(@D)/vdi/linux/driver/unload.sh $(TARGET_DIR)/root/wave511/vdec_unload.sh
+	$(INSTALL) -D -m 0644 $(WAVE511_SITE)/../firmware/chagall.bin $(TARGET_DIR)/lib/firmware/chagall.bin
+	$(INSTALL) -D -m 0644 $(@D)/libsfdec.so $(TARGET_DIR)/usr/lib/libsfdec.so
+endef
+
+
+define WAVE511_INSTALL_STAGING_CMDS
+	mkdir -p $(STAGING_DIR)/usr/include/wave511
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_list_decoder.h                           $(STAGING_DIR)/usr/include/wave511/sample_v2/component_list_decoder.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_list_encoder.h                           $(STAGING_DIR)/usr/include/wave511/sample_v2/component_list_encoder.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/pbu.h                                  $(STAGING_DIR)/usr/include/wave511/sample_v2/helper/misc/pbu.h 
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/header_struct.h                        $(STAGING_DIR)/usr/include/wave511/sample_v2/helper/misc/header_struct.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/json_output.h                          $(STAGING_DIR)/usr/include/wave511/sample_v2/helper/misc/json_output.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/debug.h                                $(STAGING_DIR)/usr/include/wave511/sample_v2/helper/misc/debug.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/bw_monitor.h                           $(STAGING_DIR)/usr/include/wave511/sample_v2/helper/misc/bw_monitor.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/main_helper.h                               $(STAGING_DIR)/usr/include/wave511/sample_v2/helper/main_helper.h 
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/component.h                              $(STAGING_DIR)/usr/include/wave511/sample_v2/component/component.h 
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/cnm_app_internal.h                       $(STAGING_DIR)/usr/include/wave511/sample_v2/component/cnm_app_internal.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/cnm_app.h                                $(STAGING_DIR)/usr/include/wave511/sample_v2/component/cnm_app.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/component_list.h                         $(STAGING_DIR)/usr/include/wave511/sample_v2/component/component_list.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_list_all.h                               $(STAGING_DIR)/usr/include/wave511/sample_v2/component_list_all.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_encoder/encoder_listener.h               $(STAGING_DIR)/usr/include/wave511/sample_v2/component_encoder/encoder_listener.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_decoder/decoder_listener.h               $(STAGING_DIR)/usr/include/wave511/sample_v2/component_decoder/decoder_listener.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/vdi_osal.h                                               $(STAGING_DIR)/usr/include/wave511/vdi/vdi_osal.h                        
+	$(INSTALL) -D -m 0644 $(@D)/vdi/linux/driver/vmm.h                                       $(STAGING_DIR)/usr/include/wave511/vdi/linux/driver/vmm.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/linux/driver/vpu.h                                       $(STAGING_DIR)/usr/include/wave511/vdi/linux/driver/vpu.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/mm.h                                                     $(STAGING_DIR)/usr/include/wave511/vdi/mm.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/vdi.h                                                    $(STAGING_DIR)/usr/include/wave511/vdi/vdi.h 
+	$(INSTALL) -D -m 0644 $(@D)/config.h                                                     $(STAGING_DIR)/usr/include/wave511/config.h   
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/product.h                                             $(STAGING_DIR)/usr/include/wave511/vpuapi/product.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/coda9/coda9_vpuconfig.h                               $(STAGING_DIR)/usr/include/wave511/vpuapi/coda9/coda9_vpuconfig.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/coda9/coda9.h                                         $(STAGING_DIR)/usr/include/wave511/vpuapi/coda9/coda9.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/coda9/coda9_regdefine.h                               $(STAGING_DIR)/usr/include/wave511/vpuapi/coda9/coda9_regdefine.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuapi.h                                              $(STAGING_DIR)/usr/include/wave511/vpuapi/vpuapi.h   
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuconfig.h                                           $(STAGING_DIR)/usr/include/wave511/vpuapi/vpuconfig.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/wave/wave5.h                                          $(STAGING_DIR)/usr/include/wave511/vpuapi/wave/wave5.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/wave/wave5_regdefine.h                                $(STAGING_DIR)/usr/include/wave511/vpuapi/wave/wave5_regdefine.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuerror.h                                            $(STAGING_DIR)/usr/include/wave511/vpuapi/vpuerror.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vputypes.h                                            $(STAGING_DIR)/usr/include/wave511/vpuapi/vputypes.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuapifunc.h                                          $(STAGING_DIR)/usr/include/wave511/vpuapi/vpuapifunc.h   
+endef
+
+define WAVE511_UNINSTALL_TARGET_CMDS
+	rm -rf $(TARGET_DIR)/root/vdec.ko
+	rm -rf $(TARGET_DIR)/root/vdec_load.sh
+	rm -rf $(TARGET_DIR)/root/vdec_unload.sh
+endef
+
+$(eval $(generic-package))

+ 8 - 0
package/starfive/wave521/Config.in

@@ -0,0 +1,8 @@
+comment "wave521 package"
+
+config BR2_PACKAGE_WAVE521
+	bool "wave521"
+	depends on BR2_KERNEL_HEADERS_CUSTOM_GIT
+	help
+	  wave521 package
+	  

+ 74 - 0
package/starfive/wave521/wave521.mk

@@ -0,0 +1,74 @@
+################################################################################
+#
+# wave521
+#
+################################################################################
+
+WAVE521_VERSION:=1.0.0
+WAVE521_SITE=$(TOPDIR)/../soft_3rdpart/wave521/code
+WAVE521_SITE_METHOD=local
+WAVE521_INSTALL_STAGING = YES
+
+export KERNELDIR=$(TOPDIR)/../work/linux
+	
+define WAVE521_BUILD_CMDS
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) -f $(@D)/WaveEncDriver_buildroot.mak
+	$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) -f $(@D)/WaveEncoder_buildroot.mak
+endef
+
+define WAVE521_CLEAN_CMDS
+
+endef
+
+define WAVE521_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0644 $(@D)/vdi/linux/driver/venc.ko $(TARGET_DIR)/root/wave521/venc.ko
+	$(INSTALL) -D -m 0777 $(@D)/vdi/linux/driver/load.sh $(TARGET_DIR)/root/wave521/venc_load.sh
+	$(INSTALL) -D -m 0777 $(@D)/vdi/linux/driver/unload.sh $(TARGET_DIR)/root/wave521/venc_unload.sh
+	$(INSTALL) -D -m 0644 $(WAVE521_SITE)/../firmware/chagall.bin $(TARGET_DIR)/root/wave521/chagall.bin
+	$(INSTALL) -D -m 0644 $(@D)/libsfenc.so $(TARGET_DIR)/usr/lib/libsfenc.so
+endef
+
+
+define WAVE521_INSTALL_STAGING_CMDS
+	mkdir -p $(STAGING_DIR)/usr/include/wave521
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_list_decoder.h                           $(STAGING_DIR)/usr/include/wave521/sample_v2/component_list_decoder.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_list_encoder.h                           $(STAGING_DIR)/usr/include/wave521/sample_v2/component_list_encoder.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/pbu.h                                  $(STAGING_DIR)/usr/include/wave521/sample_v2/helper/misc/pbu.h 
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/header_struct.h                        $(STAGING_DIR)/usr/include/wave521/sample_v2/helper/misc/header_struct.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/json_output.h                          $(STAGING_DIR)/usr/include/wave521/sample_v2/helper/misc/json_output.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/debug.h                                $(STAGING_DIR)/usr/include/wave521/sample_v2/helper/misc/debug.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/misc/bw_monitor.h                           $(STAGING_DIR)/usr/include/wave521/sample_v2/helper/misc/bw_monitor.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/helper/main_helper.h                               $(STAGING_DIR)/usr/include/wave521/sample_v2/helper/main_helper.h 
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/component.h                              $(STAGING_DIR)/usr/include/wave521/sample_v2/component/component.h 
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/cnm_app_internal.h                       $(STAGING_DIR)/usr/include/wave521/sample_v2/component/cnm_app_internal.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/cnm_app.h                                $(STAGING_DIR)/usr/include/wave521/sample_v2/component/cnm_app.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component/component_list.h                         $(STAGING_DIR)/usr/include/wave521/sample_v2/component/component_list.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_list_all.h                               $(STAGING_DIR)/usr/include/wave521/sample_v2/component_list_all.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_encoder/encoder_listener.h               $(STAGING_DIR)/usr/include/wave521/sample_v2/component_encoder/encoder_listener.h
+	$(INSTALL) -D -m 0644 $(@D)/sample_v2/component_decoder/decoder_listener.h               $(STAGING_DIR)/usr/include/wave521/sample_v2/component_decoder/decoder_listener.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/vdi_osal.h                                               $(STAGING_DIR)/usr/include/wave521/vdi/vdi_osal.h                        
+	$(INSTALL) -D -m 0644 $(@D)/vdi/linux/driver/vmm.h                                       $(STAGING_DIR)/usr/include/wave521/vdi/linux/driver/vmm.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/linux/driver/vpu.h                                       $(STAGING_DIR)/usr/include/wave521/vdi/linux/driver/vpu.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/mm.h                                                     $(STAGING_DIR)/usr/include/wave521/vdi/mm.h
+	$(INSTALL) -D -m 0644 $(@D)/vdi/vdi.h                                                    $(STAGING_DIR)/usr/include/wave521/vdi/vdi.h 
+	$(INSTALL) -D -m 0644 $(@D)/config.h                                                     $(STAGING_DIR)/usr/include/wave521/config.h   
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/product.h                                             $(STAGING_DIR)/usr/include/wave521/vpuapi/product.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/coda9/coda9_vpuconfig.h                               $(STAGING_DIR)/usr/include/wave521/vpuapi/coda9/coda9_vpuconfig.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/coda9/coda9.h                                         $(STAGING_DIR)/usr/include/wave521/vpuapi/coda9/coda9.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/coda9/coda9_regdefine.h                               $(STAGING_DIR)/usr/include/wave521/vpuapi/coda9/coda9_regdefine.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuapi.h                                              $(STAGING_DIR)/usr/include/wave521/vpuapi/vpuapi.h   
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuconfig.h                                           $(STAGING_DIR)/usr/include/wave521/vpuapi/vpuconfig.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/wave/wave5.h                                          $(STAGING_DIR)/usr/include/wave521/vpuapi/wave/wave5.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/wave/wave5_regdefine.h                                $(STAGING_DIR)/usr/include/wave521/vpuapi/wave/wave5_regdefine.h  
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuerror.h                                            $(STAGING_DIR)/usr/include/wave521/vpuapi/vpuerror.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vputypes.h                                            $(STAGING_DIR)/usr/include/wave521/vpuapi/vputypes.h 
+	$(INSTALL) -D -m 0644 $(@D)/vpuapi/vpuapifunc.h                                          $(STAGING_DIR)/usr/include/wave521/vpuapi/vpuapifunc.h   
+endef
+
+define WAVE521_UNINSTALL_TARGET_CMDS
+	rm -rf $(TARGET_DIR)/root/venc.ko
+	rm -rf $(TARGET_DIR)/root/venc_load.sh
+	rm -rf $(TARGET_DIR)/root/venc_unload.sh
+endef
+
+$(eval $(generic-package))