Browse Source

[base]: commit a base verison for project

base version offer a simple process from mpp decode
to drm disaply.

Signed-off-by: sliver.chen <sliver.chen@rock-chips.com>
sliver.chen 7 years ago
commit
a923f96b26
16 changed files with 1895 additions and 0 deletions
  1. 16 0
      CMakeLists.txt
  2. 30 0
      README.md
  3. 82 0
      main.cpp
  4. 458 0
      mpp/Codec.cpp
  5. 87 0
      mpp/Codec.h
  6. BIN
      res/Tennis1080p.h264
  7. 184 0
      rkdrm/bo.c
  8. 63 0
      rkdrm/bo.h
  9. 233 0
      rkdrm/dev.c
  10. 74 0
      rkdrm/dev.h
  11. 235 0
      rkdrm/modeset.c
  12. 33 0
      rkdrm/modeset.h
  13. 292 0
      rkrga/RGA.cpp
  14. 44 0
      rkrga/RGA.h
  15. 35 0
      thread/Thread.cpp
  16. 29 0
      thread/Thread.h

+ 16 - 0
CMakeLists.txt

@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(mpp_linux_demo)
+
+set(CMAKE_CXX_STANDARD 11)
+
+set(SOURCE_FILES main.cpp
+        mpp/Codec.cpp
+        thread/Thread.cpp
+        rkrga/RGA.cpp
+        rkdrm/bo.c
+        rkdrm/dev.c
+        rkdrm/modeset.c)
+
+add_executable(mpp_linux_demo ${SOURCE_FILES})
+target_link_libraries(mpp_linux_demo mpp pthread drm)

+ 30 - 0
README.md

@@ -0,0 +1,30 @@
+# MPP_LINUX_C++
+a demo shows that how to use mpp on linux
+
+project architecture
+
+├── build   --build directory
+├── CMakeLists.txt      --cmake script
+├── main.cpp            --main program
+├── mpp                 --mpp abstract interface
+├── README.md           --doc
+├── res                 --res directory
+├── rkdrm               --drm interface(abount display)
+├── rkrga               --rga interface(about format and resolution conversion)
+└── thread              --thread abstract interface(use posix)
+
+## make & test
+first please modify CMakeLists.txt to specified c and c++ compiler.
+just do that
+    set(CMAKE_C_COMPILER "enter your toolchain gcc path)
+    set(CMAKE_CXX_coMPILER "enter your toolchain g++ path")
+
+cmake version >= 2.8 is required
+root:cd build
+root:make
+root:./mpp_linux_demo
+
+## how you will see
+on your device screen,you will see that local avc file
+is displayed.
+

+ 82 - 0
main.cpp

@@ -0,0 +1,82 @@
+/*
+ * linux mpp c++ performance avaluation.
+ * base in mpp & rga & sdl.
+ * cfg info writed in params[6].
+ */
+
+#include <iostream>
+#include "rkrga/RGA.h"
+#include "mpp/Codec.h"
+#include "thread/Thread.h"
+
+extern "C" {
+#include <stdlib.h>
+#include <signal.h>
+#include "rk_mpi.h"
+}
+
+#define dbg(fmt,...)\
+            do {\
+                printf(fmt,##__VA_ARGS__);\
+            } while(0)
+
+using namespace std;
+
+struct param {
+    int display;
+    int width;
+    int height;
+    string input;
+    string output;
+    MppCodingType type;
+};
+
+/*
+ * specified res file info here
+ */
+param params[1] = {
+    {1, 1920, 1080, "../res/Tennis1080p.h264", "../res/Tennis1080p.yuv", MPP_VIDEO_CodingAVC},
+};
+
+void *thread_exec(void *args) {
+    int ret = 0;
+    param *arg = (param *)args;
+    double *retRate = new double;
+
+    Codec *ctx = new Codec();
+    ret = ctx->init(arg->input.c_str(), arg->output.c_str(), arg->type,
+                    arg->width, arg->height, arg->display);
+    if (ret < 0) {
+        cout << "failed to init codec" << endl;
+        return NULL;
+    }
+
+    ret = ctx->decode();
+    if (ret <0)
+        cout << "codec decode exec failed" << endl;
+    else
+        cout << "codec decode exec success id:" << endl;
+
+    ctx->deinit();
+    delete ctx;
+
+    return NULL;
+}
+
+void stop(int signo) {
+    cout << "mpp_linux_demo exit";
+    _exit(0);
+}
+
+int main() {
+    int ret = 0;
+    signal(SIGINT, stop);
+
+    Thread *tFirst = new Thread(thread_exec, &params[0], NULL);
+    tFirst->init();
+
+    tFirst->run();
+
+    delete(tFirst);
+    return 0;
+}

+ 458 - 0
mpp/Codec.cpp

@@ -0,0 +1,458 @@
+//
+// Created by root on 17-11-1.
+//
+
+#include "Codec.h"
+
+#define cxx_log(fmt,...)\
+            do {\
+                printf(fmt,##__VA_ARGS__);\
+            } while(0)
+
+using namespace std;
+
+Codec::Codec() : mFps(0),
+                 mEos(0),
+                 mID(0),
+                 mDisPlay(0),
+                 mFrmCnt(0),
+                 mFrmRate(0.0),
+                 mFin(NULL),
+                 mFout(NULL),
+                 mPktBuf(NULL),
+                 mCtx(NULL),
+                 mApi(NULL),
+                 mPkt(NULL),
+                 mFrmGrp(NULL)
+{
+
+}
+
+Codec::~Codec() {
+    if (mPkt) {
+        mpp_packet_deinit(&mPkt);
+        mPkt = NULL;
+    }
+
+    if (mCtx) {
+        mpp_destroy(mCtx);
+        mCtx = NULL;
+    }
+
+    if (mPktBuf) {
+        delete(mPktBuf);
+        mPktBuf = NULL;
+    }
+
+    if (mBuffer) {
+        mpp_buffer_put(mBuffer);
+        mBuffer = NULL;
+    }
+
+    if (mFrmGrp) {
+        mpp_buffer_group_put(mFrmGrp);
+        mFrmGrp = NULL;
+    }
+
+    if (mFin) {
+        fclose(mFin);
+        mFin = NULL;
+    }
+
+    if (mFout) {
+        fclose(mFout);
+        mFout = NULL;
+    }
+
+    if (mRGA) {
+        delete(mRGA);
+        mRGA = NULL;
+    }
+}
+
+int Codec::init(const char *file_input,
+                const char *file_output, MppCodingType type,
+                int src_w, int src_h, int display) {
+    int ret = 0;
+    int x, y, i;
+    RK_U32 need_split = 1;
+    MpiCmd mpi_cmd = MPP_CMD_BASE;
+    MppParam param = NULL;
+
+    mDisPlay = display;
+    srcW = src_w;
+    srcH = src_h;
+
+    mFin = fopen(file_input, "rb");
+    if (!mFin) {
+        cxx_log("failed to open input file %s.\n", file_input);
+        return -1;
+    }
+
+    mFout = fopen(file_output, "wb+");
+    if (!mFout) {
+        cxx_log("failed to open output file %s.\n", file_output);
+        return -2;
+    }
+
+    mPktBuf = new char[PKT_SIZE];
+    if (!mPktBuf) {
+        cxx_log("failed to malloc mPktBuf.\n");
+        return -3;
+    }
+
+    ret = mpp_packet_init(&mPkt, mPktBuf, PKT_SIZE);
+    if (ret) {
+        cxx_log("failed to exec mpp_packet_init ret %d", ret);
+        return -4;
+    }
+
+    ret = mpp_create(&mCtx, &mApi);
+    if (ret != MPP_OK) {
+        cxx_log("failed to exec mpp_create ret %d", ret);
+        return -5;
+    }
+
+    mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE;
+    param = &need_split;
+    ret = mApi->control(mCtx, mpi_cmd, param);
+    if (ret != MPP_OK) {
+        cxx_log("failed to control MPP_DEC_SET_PARSER_SPLIT_MODE.\n");
+        return  -6;
+    }
+
+    ret = mpp_init(mCtx, MPP_CTX_DEC, type);
+    if (ret != MPP_OK) {
+        cxx_log("failed to exec mpp_init.\n");
+        return -7;
+    }
+#if 0
+    mRGA = new RGA();
+    ret = mRGA->init(srcW, srcH, dstW, dstH);
+    if (ret < 0) {
+        cxx_log("failed to exec mRGA->init %d.\n", ret);
+        return -8;
+    }
+#endif
+    mDev = create_sp_dev();
+    if (!mDev) {
+        cxx_log("failed to exec create_sp_dev.\n");
+        return -10;
+    }
+
+    ret = initialize_screens(mDev);
+    if (ret != 0) {
+        cxx_log("failed to exec initialize_screens.\n");
+        return -11;
+    }
+
+    mPlanes = (sp_plane **)calloc(mDev->num_planes, sizeof(*mPlanes));
+    if (!mPlanes) {
+        cxx_log("failed to calloc mPlanes.\n");
+        return -12;
+    }
+
+    mCrtc = &mDev->crtcs[0];
+    for (i = 0; i < mCrtc->num_planes; i++) {
+        mPlanes[i] = get_sp_plane(mDev, mCrtc);
+        if (is_supported_format(mPlanes[i], DRM_FORMAT_NV12))
+            mTestPlane = mPlanes[i];
+    }
+
+    if (!mTestPlane) {
+        cxx_log("failed to get mTestPlane.\n");
+        return -13;
+    }
+
+    return 0;
+}
+
+static RK_S64 get_time() {
+    struct timeval tv_date;
+    gettimeofday(&tv_date, NULL);
+    return (RK_S64)tv_date.tv_sec * 1000000 + (RK_S64)tv_date.tv_usec;
+}
+
+int Codec::dump_mpp_frame_to_file(MppFrame frame, FILE *fp)
+{
+    RK_U32 width = 0;
+    RK_U32 height = 0;
+    RK_U32 h_stride = 0;
+    RK_U32 v_stride = 0;
+    MppFrameFormat fmt = MPP_FMT_YUV420SP;
+    MppBuffer buffer = NULL;
+    RK_U8 *base = NULL;
+
+    if (!fp || !frame)
+        return -1;
+
+    width = mpp_frame_get_width(frame);
+    height = mpp_frame_get_height(frame);
+    h_stride = mpp_frame_get_hor_stride(frame);
+    v_stride = mpp_frame_get_ver_stride(frame);
+    fmt = mpp_frame_get_fmt(frame);
+    buffer = mpp_frame_get_buffer(frame);
+
+    if(!buffer)
+        return -2;
+
+    base = (RK_U8 *)mpp_buffer_get_ptr(buffer);
+    {
+        RK_U32 i;
+        RK_U8 *base_y = base;
+        RK_U8 *base_u = base + h_stride * v_stride;
+        RK_U8 *base_v = base_u + h_stride * v_stride / 4;
+
+        for (i = 0; i < height; i++, base_y += h_stride)
+            fwrite(base_y, 1, width, fp);
+        for (i = 0; i < height / 2; i++, base_u += h_stride / 2)
+            fwrite(base_u, 1, width / 2, fp);
+        for (i = 0; i < height / 2; i++, base_v += h_stride / 2)
+            fwrite(base_v, 1, width / 2, fp);
+    }
+
+    return 0;
+}
+
+int Codec::drm_show_frmae(MppFrame frame) {
+    sp_bo *bo;
+    uint32_t handles[4], pitches[4], offsets[4];
+    int width, height;
+    int frm_size, ret, fd, err;
+
+    err = mpp_frame_get_errinfo(frame) |
+          mpp_frame_get_discard(frame);
+    if (err) {
+        cxx_log("get err info %d discard %d,go back.\n",
+                mpp_frame_get_errinfo(frame),
+                mpp_frame_get_discard(frame));
+        return -1;
+    }
+
+
+    width = mpp_frame_get_width(frame);
+    height = mpp_frame_get_height(frame);
+    width = CODEC_ALIGN(width, 16);
+    height = CODEC_ALIGN(height, 16);
+    frm_size = width * height * 3 / 2;
+    fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));
+
+    bo = (struct sp_bo *)calloc(1, sizeof(struct sp_bo));
+    if (!bo) {
+        cxx_log("failed to calloc bo.\n");
+        return -2;
+    }
+
+    drmPrimeFDToHandle(mDev->fd, fd, &bo->handle);
+    bo->dev = mDev;
+    bo->width = width;
+    bo->height = height;
+    bo->depth = 16;
+    bo->bpp = 32;
+    bo->format = DRM_FORMAT_NV12;
+    bo->flags = 0;
+
+    handles[0] = bo->handle;
+    pitches[0] = width;
+    offsets[0] = 0;
+    handles[1] = bo->handle;
+    pitches[1] = width;
+    offsets[1] = width * height;
+    ret = drmModeAddFB2(mDev->fd, bo->width, bo->height,
+                        bo->format, handles, pitches, offsets,
+                        &bo->fb_id, bo->flags);
+    if (ret != 0) {
+        cxx_log("failed to exec drmModeAddFb2.\n");
+        return -3;
+    }
+
+    ret = drmModeSetPlane(mDev->fd, mTestPlane->plane->plane_id,
+                          mCrtc->crtc->crtc_id, bo->fb_id, 0, 0, 0,
+                          mCrtc->crtc->mode.hdisplay,
+                          mCrtc->crtc->mode.vdisplay,
+                          0, 0, bo->width << 16, bo->height << 16);
+    if (ret) {
+        cxx_log("failed to exec drmModeSetPlane.\n");
+        return -3;
+    }
+
+    if (mTestPlane->bo) {
+        if (mTestPlane->bo->fb_id) {
+            ret = drmModeRmFB(mDev->fd, mTestPlane->bo->fb_id);
+            if (ret)
+                cxx_log("failed to exec drmModeRmFB.\n");
+        }
+        if (mTestPlane->bo->handle) {
+            struct drm_gem_close req = {
+                    .handle = mTestPlane->bo->handle,
+            };
+
+            drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
+        }
+        free(mTestPlane->bo);
+    }
+    mTestPlane->bo = bo;
+
+    return 0;
+}
+
+int Codec::decode_one_pkt(char *buf, int size, MppFrame *srcFrm, MppFrame *dstFrm) {
+    int ret = 0;
+    RK_U32 pkt_done = 0;
+
+    mpp_packet_write(mPkt, 0, buf, size);
+    mpp_packet_set_pos(mPkt, buf);
+    mpp_packet_set_length(mPkt, size);
+
+    if (mEos)
+        mpp_packet_set_eos(mPkt);
+
+    do {
+        RK_S32 times = 5;
+
+        if (!pkt_done) {
+            ret = mApi->decode_put_packet(mCtx, mPkt);
+            if (ret == MPP_OK)
+                pkt_done = 1;
+        }
+
+        do {
+            RK_S32 get_frm = 0;
+            RK_U32 frm_eos = 0;
+
+            try_again:
+                ret = mApi->decode_get_frame(mCtx, srcFrm);
+                if (ret == MPP_ERR_TIMEOUT) {
+                    if (times > 0) {
+                        times--;
+                        usleep(2000);
+                        goto try_again;
+                    }
+                    cxx_log("decode_get_frame failed too much time.\n");
+                }
+
+                if (ret != MPP_OK) {
+                    cxx_log("decode_get_frame failed ret %d.\n", ret);
+                    break;
+                }
+
+                if (*srcFrm) {
+                    if (mpp_frame_get_info_change(*srcFrm)) {
+                        RK_U32 width = mpp_frame_get_width(*srcFrm);
+                        RK_U32 height = mpp_frame_get_height(*srcFrm);
+                        RK_U32 hor_stride = mpp_frame_get_hor_stride(*srcFrm);
+                        RK_U32 ver_stride = mpp_frame_get_ver_stride(*srcFrm);
+
+                        cxx_log("decode_get_frame get info changed found.\n");
+                        cxx_log("decoder require buffer w:h [%d:%d] stride [%d:%d]",
+                                width, height, hor_stride, ver_stride);
+
+                        ret = mpp_buffer_group_get_internal(&mFrmGrp, MPP_BUFFER_TYPE_DRM);
+                        if (ret) {
+                            cxx_log("get mpp buffer group failed ret %d.\n", ret);
+                            break;
+                        }
+
+                        mApi->control(mCtx, MPP_DEC_SET_EXT_BUF_GROUP, mFrmGrp);
+                        mApi->control(mCtx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
+                    } else {
+                        cxx_log("decode_get_frame ID:%d get srcFrm %d.\n", mID, mFrmCnt++);
+                        if (mDisPlay) {
+                            drm_show_frmae(*srcFrm);
+                            if (mFout) {
+                                /*
+                                 * note that write file will leads to IO block
+                                 * so if you want to test frame rate,don't wirte
+                                 * it.
+                                 */
+                                //dump_mpp_frame_to_file(*srcFrm, mFout);
+                            }
+                        }
+                    }
+                    frm_eos = mpp_frame_get_eos(*srcFrm);
+                    mpp_frame_deinit(srcFrm);
+                    *srcFrm = NULL;
+                    get_frm = 1;
+                }
+
+                if (mEos && pkt_done && !frm_eos) {
+                    usleep(10000);
+                    continue;
+                }
+
+                if (frm_eos) {
+                    cxx_log("found last frame.\n");
+                    break;
+                }
+
+                if (get_frm)
+                    continue;
+                break;
+        } while (1);
+
+        if (pkt_done)
+            break;
+        usleep(50000);
+    } while (1);
+
+    return 0;
+}
+
+int Codec::decode() {
+    MppFrame srcFrm;
+    MppFrame dstFrm;
+    double timeDiff;
+    int ret = 0;
+    int hor_stride = CODEC_ALIGN(dstW, 16);
+    int ver_srride = CODEC_ALIGN(dstH, 16);
+
+    ret = mpp_frame_init(&dstFrm);
+    if (ret) {
+        cxx_log("failed to exec mpp_frame_init %d.\n", ret);
+        return -1;
+    }
+
+    mpp_buffer_get(mFrmGrp, &mBuffer, hor_stride * ver_srride * 3 / 2);
+    mpp_frame_set_width(dstFrm, dstW);
+    mpp_frame_set_height(dstFrm, dstH);
+    mpp_frame_set_hor_stride(dstFrm, hor_stride);
+    mpp_frame_set_ver_stride(dstFrm, ver_srride);
+    mpp_frame_set_fmt(dstFrm, MPP_FMT_YUV420P);
+    mpp_frame_set_buffer(dstFrm, mBuffer);
+
+    mTimeS = get_time();
+    while (!mEos) {
+        size_t read_size = fread(mPktBuf, 1, PKT_SIZE, mFin);
+        if (read_size != PKT_SIZE || feof(mFin)) {
+            cxx_log("found last packet.\n");
+            mEos = 1;
+        }
+
+        mpp_frame_set_eos(dstFrm, mEos);
+
+        ret = decode_one_pkt(mPktBuf, read_size, &srcFrm, &dstFrm);
+        if (ret < 0) {
+            cxx_log("failed to exec decode.\n");
+            return -2;
+        }
+    }
+    mpp_frame_deinit(&dstFrm);
+
+    mTimeE = get_time();
+    timeDiff = double(mTimeE - mTimeS)/1000;
+    mFrmRate = (mFrmCnt * 1000) / timeDiff;
+    cxx_log("decode frames %d using %.2fms frm rate:%.2f.\n", mFrmCnt,
+            timeDiff, mFrmRate);
+
+    return 0;
+}
+
+int Codec::deinit() {
+    int ret = 0;
+
+    ret = mApi->reset(mCtx);
+    if (ret != MPP_OK) {
+        cxx_log("failed to exec mApi->reset.\n");
+        return -1;
+    }
+}

+ 87 - 0
mpp/Codec.h

@@ -0,0 +1,87 @@
+//
+// Created by root on 17-11-1.
+//
+
+#ifndef MPP_LINUX_C_CODEC_H
+#define MPP_LINUX_C_CODEC_H
+
+#include <iostream>
+#include "../rkrga/RGA.h"
+
+extern "C" {
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "vpu.h"
+#include "rk_mpi.h"
+#include "rk_type.h"
+#include "vpu_api.h"
+#include "mpp_err.h"
+#include "mpp_task.h"
+#include "mpp_meta.h"
+#include "mpp_frame.h"
+#include "mpp_buffer.h"
+#include "mpp_packet.h"
+#include "rk_mpi_cmd.h"
+
+#include "../rkdrm/bo.h"
+#include "../rkdrm/dev.h"
+#include "../rkdrm/modeset.h"
+};
+
+#define PKT_SIZE    SZ_4K
+#define CODEC_ALIGN(x, a)   (((x)+(a)-1)&~((a)-1))
+
+class Codec {
+public:
+    Codec();
+    ~Codec();
+    int init(const char *file_input,
+             const char *file_output, MppCodingType type,
+             int src_w, int src_h, int display);
+    int deinit();
+    int decode_one_pkt(char *buf, int size, MppFrame *srcFrm, MppFrame *dstFrm);
+    int decode();
+    int dump_mpp_frame_to_file(MppFrame frame, FILE *fp);
+    int drm_show_frmae(MppFrame frame);
+
+    double get_frm_rate() {
+        return mFrmRate;
+    }
+private:
+    int mFps;
+    int mEos;
+    int mID;
+    int mDisPlay;
+    int mFrmCnt;
+    int srcW;
+    int srcH;
+    int dstW;
+    int dstH;
+
+    RK_S64 mTimeS;
+    RK_S64 mTimeE;
+    RK_S64 mTimeDiff;
+    double mFrmRate;
+
+    FILE *mFin;
+    FILE *mFout;
+    char *mPktBuf;
+
+    MppCtx mCtx;
+    MppApi *mApi;
+    MppPacket mPkt;
+    MppBuffer mBuffer;
+    MppBufferGroup mFrmGrp;
+
+    RGA *mRGA;
+
+    sp_dev *mDev;
+    sp_plane **mPlanes;
+    sp_crtc *mCrtc;
+    sp_plane *mTestPlane;
+};
+
+
+#endif //MPP_LINUX_C_CODEC_H

BIN
res/Tennis1080p.h264


+ 184 - 0
rkdrm/bo.c

@@ -0,0 +1,184 @@
+/*
+ * Copyright 2016 Rockchip Electronics S.LSI Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+#include "bo.h"
+
+void fill_bo(struct sp_bo* bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
+{
+    draw_rect(bo, 0, 0, bo->width, bo->height, a, r, g, b);
+}
+
+void draw_rect(struct sp_bo* bo, uint32_t x, uint32_t y, uint32_t width,
+               uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
+{
+    uint32_t i, j, xmax = x + width, ymax = y + height;
+
+    if (xmax > bo->width)
+        xmax = bo->width;
+    if (ymax > bo->height)
+        ymax = bo->height;
+
+    for (i = y; i < ymax; i++) {
+        uint8_t* row = (uint8_t*)bo->map_addr + i * bo->pitch;
+
+        for (j = x; j < xmax; j++) {
+            uint8_t* pixel = row + j * 4;
+
+            if (bo->format == DRM_FORMAT_ARGB8888 || bo->format == DRM_FORMAT_XRGB8888) {
+                pixel[0] = b;
+                pixel[1] = g;
+                pixel[2] = r;
+                pixel[3] = a;
+            } else if (bo->format == DRM_FORMAT_RGBA8888) {
+                pixel[0] = r;
+                pixel[1] = g;
+                pixel[2] = b;
+                pixel[3] = a;
+            }
+        }
+    }
+}
+
+int add_fb_sp_bo(struct sp_bo* bo, uint32_t format)
+{
+    int ret;
+    uint32_t handles[4], pitches[4], offsets[4];
+
+    handles[0] = bo->handle;
+    pitches[0] = bo->pitch;
+    offsets[0] = 0;
+
+    if(format == DRM_FORMAT_NV12 || format == DRM_FORMAT_NV16) {
+        handles[1] = bo->handle;
+        pitches[0] = bo->width;
+        pitches[1] = bo->width;
+        offsets[1] = bo->width * bo->height;
+    }
+
+    ret = drmModeAddFB2(bo->dev->fd, bo->width, bo->height,
+                        format, handles, pitches, offsets,
+                        &bo->fb_id, bo->flags);
+    if (ret) {
+        printf("failed to create fb ret=%d\n", ret);
+        return ret;
+    }
+    return 0;
+}
+
+static int map_sp_bo(struct sp_bo* bo)
+{
+    int ret;
+    struct drm_mode_map_dumb md;
+
+    if (bo->map_addr)
+        return 0;
+
+    md.handle = bo->handle;
+    ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &md);
+    if (ret) {
+        printf("failed to map sp_bo ret=%d\n", ret);
+        return ret;
+    }
+
+    bo->map_addr = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                        bo->dev->fd, md.offset);
+    if (bo->map_addr == MAP_FAILED) {
+        printf("failed to map bo ret=%d\n", -errno);
+        return -errno;
+    }
+    return 0;
+}
+
+struct sp_bo* create_sp_bo(struct sp_dev* dev, uint32_t width, uint32_t height,
+                           uint32_t depth, uint32_t bpp, uint32_t format, uint32_t flags)
+{
+    int ret;
+    struct drm_mode_create_dumb cd;
+    struct sp_bo* bo;
+
+    memset(&cd, 0, sizeof(cd));
+
+    bo = (struct sp_bo *) calloc(1, sizeof(*bo));
+    if (!bo)
+        return NULL;
+
+    cd.height = height;
+    cd.width = width;
+    cd.bpp = bpp;
+    cd.flags = flags;
+
+    ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &cd);
+    if (ret) {
+        printf("failed to create sp_bo %d\n", ret);
+        goto err;
+    }
+
+    bo->dev = dev;
+    bo->width = width;
+    bo->height = height;
+    bo->depth = depth;
+    bo->bpp = bpp;
+    bo->format = format;
+    bo->flags = flags;
+
+    bo->handle = cd.handle;
+    bo->pitch = cd.pitch;
+    bo->size = cd.size;
+
+    ret = add_fb_sp_bo(bo, format);
+    if (ret) {
+        printf("failed to add fb ret=%d\n", ret);
+        goto err;
+    }
+
+    ret = map_sp_bo(bo);
+    if (ret) {
+        printf("failed to map bo ret=%d\n", ret);
+        goto err;
+    }
+
+    return bo;
+
+    err:
+    free_sp_bo(bo);
+    return NULL;
+}
+
+void free_sp_bo(struct sp_bo* bo)
+{
+    int ret;
+    struct drm_mode_destroy_dumb dd;
+
+    if (!bo)
+        return;
+
+    if (bo->map_addr)
+        munmap(bo->map_addr, bo->size);
+
+    if (bo->fb_id) {
+        ret = drmModeRmFB(bo->dev->fd, bo->fb_id);
+        if (ret)
+            printf("Failed to rmfb ret=%d!\n", ret);
+    }
+
+    if (bo->handle) {
+        dd.handle = bo->handle;
+        ret = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dd);
+        if (ret)
+            printf("Failed to destroy buffer ret=%d\n", ret);
+    }
+
+    free(bo);
+}

+ 63 - 0
rkdrm/bo.h

@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 Rockchip Electronics S.LSI Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef MPP_LINUX_C_BO_H
+#define MPP_LINUX_C_BO_H
+
+#include <drm/drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+#include "dev.h"
+
+#undef USE_ATOMIC_API
+struct sp_dev;
+
+struct sp_bo {
+    struct sp_dev *dev;
+
+    uint32_t width;
+    uint32_t height;
+    uint32_t depth;
+    uint32_t bpp;
+    uint32_t format;
+    uint32_t flags;
+
+    uint32_t fb_id;
+    uint32_t handle;
+    void *map_addr;
+    uint32_t pitch;
+    uint32_t size;
+};
+
+int add_fb_sp_bo(struct sp_bo *bo, uint32_t format);
+struct sp_bo* create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
+                           uint32_t depth, uint32_t bpp, uint32_t format, uint32_t flags);
+
+void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
+void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
+               uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
+
+void free_sp_bo(struct sp_bo *bo);
+
+#endif //MPP_LINUX_C_BO_H

+ 233 - 0
rkdrm/dev.c

@@ -0,0 +1,233 @@
+/*
+ * Copyright 2016 Rockchip Electronics S.LSI Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+#include "dev.h"
+
+#if 0 //def USE_ATOMIC_API
+static uint32_t get_prop_id(struct sp_dev *dev,
+			    drmModeObjectPropertiesPtr props, const char *name){
+	drmModePropertyPtr p;
+	uint32_t i, prop_id = 0; /* Property ID should always be > 0 */
+
+	for (i = 0; !prop_id && i < props->count_props; i++) {
+		p = drmModeGetProperty(dev->fd, props->props[i]);
+		if (!strcmp(p->name, name))
+		prop_id = p->prop_id;
+		drmModeFreeProperty(p);
+	}
+	if (!prop_id)
+	printf("Could not find %s property\n", name);
+	return prop_id;
+}
+#endif
+
+int is_supported_format(struct sp_plane* plane, uint32_t format)
+{
+    uint32_t i;
+
+    for (i = 0; i < plane->plane->count_formats; i++) {
+        if (plane->plane->formats[i] == format)
+            return 1;
+    }
+    return 0;
+}
+
+static int get_supported_format(struct sp_plane* plane, uint32_t* format)
+{
+    uint32_t i;
+
+    for (i = 0; i < plane->plane->count_formats; i++) {
+        if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 || plane->plane->formats[i] == DRM_FORMAT_ARGB8888 || plane->plane->formats[i] == DRM_FORMAT_RGBA8888) {
+            *format = plane->plane->formats[i];
+            return 0;
+        }
+    }
+    printf("No suitable formats found!\n");
+    return -ENOENT;
+}
+
+struct sp_dev* create_sp_dev(void)
+{
+    struct sp_dev* dev;
+    int ret, fd, i, j;
+    drmModeRes* r = NULL;
+    drmModePlaneRes* pr = NULL;
+
+    fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+    if (fd < 0) {
+        printf("failed to open card0\n");
+        return NULL;
+    }
+
+    dev = (struct sp_dev*)calloc(1, sizeof(*dev));
+    if (!dev) {
+        printf("failed to allocate dev\n");
+        return NULL;
+    }
+
+    dev->fd = fd;
+
+    ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+    if (ret) {
+        printf("failed to set client cap atomic\n");
+        goto err;
+    }
+    ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+    if (ret) {
+        printf("failed to set client cap\n");
+        goto err;
+    }
+
+    r = drmModeGetResources(dev->fd);
+    if (!r) {
+        printf("failed to get r\n");
+        goto err;
+    }
+
+    dev->num_connectors = r->count_connectors;
+    dev->connectors = (drmModeConnectorPtr*)calloc(dev->num_connectors, sizeof(*dev->connectors));
+    if (!dev->connectors) {
+        printf("failed to allocate connectors\n");
+        goto err;
+    }
+    for (i = 0; i < dev->num_connectors; i++) {
+        dev->connectors[i] = drmModeGetConnector(dev->fd,
+                                                 r->connectors[i]);
+        if (!dev->connectors[i]) {
+            printf("failed to get connector %d\n", i);
+            goto err;
+        }
+    }
+
+    dev->num_encoders = r->count_encoders;
+    dev->encoders = (drmModeEncoderPtr*)calloc(dev->num_encoders, sizeof(*dev->encoders));
+    if (!dev->encoders) {
+        printf("failed to allocate encoders\n");
+        goto err;
+    }
+    for (i = 0; i < dev->num_encoders; i++) {
+        dev->encoders[i] = drmModeGetEncoder(dev->fd, r->encoders[i]);
+        if (!dev->encoders[i]) {
+            printf("failed to get encoder %d\n", i);
+            goto err;
+        }
+    }
+
+    dev->num_crtcs = r->count_crtcs;
+    dev->crtcs = (struct sp_crtc*)calloc(dev->num_crtcs, sizeof(struct sp_crtc));
+    if (!dev->crtcs) {
+        printf("failed to allocate crtcs\n");
+        goto err;
+    }
+    for (i = 0; i < dev->num_crtcs; i++) {
+        dev->crtcs[i].crtc = drmModeGetCrtc(dev->fd, r->crtcs[i]);
+        if (!dev->crtcs[i].crtc) {
+            printf("failed to get crtc %d\n", i);
+            goto err;
+        }
+        dev->crtcs[i].scanout = NULL;
+        dev->crtcs[i].pipe = i;
+        dev->crtcs[i].num_planes = 0;
+    }
+
+    pr = drmModeGetPlaneResources(dev->fd);
+    if (!pr) {
+        printf("failed to get plane resources\n");
+        goto err;
+    }
+    dev->num_planes = pr->count_planes;
+    dev->planes = (struct sp_plane*)calloc(dev->num_planes, sizeof(struct sp_plane));
+    for (i = 0; i < dev->num_planes; i++) {
+        drmModeObjectPropertiesPtr props;
+        struct sp_plane* plane = &dev->planes[i];
+
+        plane->dev = dev;
+        plane->plane = drmModeGetPlane(dev->fd, pr->planes[i]);
+        if (!plane->plane) {
+            printf("failed to get plane %d\n", i);
+            goto err;
+        }
+        plane->bo = NULL;
+        plane->in_use = 0;
+
+        ret = get_supported_format(plane, &plane->format);
+        if (ret) {
+            printf("failed to get supported format: %d\n", ret);
+            goto err;
+        }
+
+        for (j = 0; j < dev->num_crtcs; j++) {
+            if (plane->plane->possible_crtcs & (1 << j))
+                dev->crtcs[j].num_planes++;
+        }
+    }
+
+    if (pr)
+        drmModeFreePlaneResources(pr);
+    if (r)
+        drmModeFreeResources(r);
+
+    return dev;
+    err:
+    if (pr)
+        drmModeFreePlaneResources(pr);
+    if (r)
+        drmModeFreeResources(r);
+    destroy_sp_dev(dev);
+    return NULL;
+}
+
+void destroy_sp_dev(struct sp_dev* dev)
+{
+    int i;
+
+    if (dev->planes) {
+        for (i = 0; i < dev->num_planes; i++) {
+            if (dev->planes[i].in_use)
+                put_sp_plane(&dev->planes[i]);
+            if (dev->planes[i].plane)
+                drmModeFreePlane(dev->planes[i].plane);
+            if (dev->planes[i].bo)
+                free_sp_bo(dev->planes[i].bo);
+        }
+        free(dev->planes);
+    }
+    if (dev->crtcs) {
+        for (i = 0; i < dev->num_crtcs; i++) {
+            if (dev->crtcs[i].crtc)
+                drmModeFreeCrtc(dev->crtcs[i].crtc);
+            if (dev->crtcs[i].scanout)
+                free_sp_bo(dev->crtcs[i].scanout);
+        }
+        free(dev->crtcs);
+    }
+    if (dev->encoders) {
+        for (i = 0; i < dev->num_encoders; i++) {
+            if (dev->encoders[i])
+                drmModeFreeEncoder(dev->encoders[i]);
+        }
+        free(dev->encoders);
+    }
+    if (dev->connectors) {
+        for (i = 0; i < dev->num_connectors; i++) {
+            if (dev->connectors[i])
+                drmModeFreeConnector(dev->connectors[i]);
+        }
+        free(dev->connectors);
+    }
+
+    close(dev->fd);
+    free(dev);
+}

+ 74 - 0
rkdrm/dev.h

@@ -0,0 +1,74 @@
+//
+// Created by root on 17-11-7.
+//
+
+#ifndef MPP_LINUX_C_DEV_H
+#define MPP_LINUX_C_DEV_H
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <drm/drm.h>
+#include <drm/drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "bo.h"
+#include "modeset.h"
+
+struct sp_bo;
+struct sp_dev;
+
+struct sp_plane {
+    struct sp_dev *dev;
+    drmModePlanePtr plane;
+    struct sp_bo *bo;
+    int in_use;
+    uint32_t format;
+
+    /* Property ID's */
+    uint32_t crtc_pid;
+    uint32_t fb_pid;
+    uint32_t zpos_pid;
+    uint32_t crtc_x_pid;
+    uint32_t crtc_y_pid;
+    uint32_t crtc_w_pid;
+    uint32_t crtc_h_pid;
+    uint32_t src_x_pid;
+    uint32_t src_y_pid;
+    uint32_t src_w_pid;
+    uint32_t src_h_pid;
+};
+
+struct sp_crtc {
+    drmModeCrtcPtr crtc;
+    int pipe;
+    int num_planes;
+    struct sp_bo *scanout;
+};
+
+struct sp_dev {
+    int fd;
+
+    int num_connectors;
+    drmModeConnectorPtr *connectors;
+
+    int num_encoders;
+    drmModeEncoderPtr *encoders;
+
+    int num_crtcs;
+    struct sp_crtc *crtcs;
+
+    int num_planes;
+    struct sp_plane *planes;
+};
+
+int is_supported_format(struct sp_plane *plane, uint32_t format);
+struct sp_dev* create_sp_dev(void);
+void destroy_sp_dev(struct sp_dev *dev);
+
+#endif //MPP_LINUX_C_DEV_H

+ 235 - 0
rkdrm/modeset.c

@@ -0,0 +1,235 @@
+//
+// Created by root on 17-11-7.
+//
+
+/*
+ * Copyright 2016 Rockchip Electronics S.LSI Co. LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+#include "modeset.h"
+
+int initialize_screens(struct sp_dev *dev) {
+    int ret, i, j;
+
+    for (i = 0; i < dev->num_connectors; i++) {
+        drmModeConnectorPtr c = dev->connectors[i];
+        drmModeModeInfoPtr m = NULL;
+        drmModeEncoderPtr e = NULL;
+        struct sp_crtc *cr = NULL;
+
+        if (c->connection != DRM_MODE_CONNECTED)
+            continue;
+
+        if (!c->count_modes) {
+            printf("connector has no modes, skipping\n");
+            continue;
+        }
+
+        /* Take the first unless there's a preferred mode */
+        m = &c->modes[0];
+        for (j = 0; j < c->count_modes; j++) {
+            drmModeModeInfoPtr tmp_m = &c->modes[j];
+
+            if (!(tmp_m->type & DRM_MODE_TYPE_PREFERRED))
+                continue;
+
+            m = tmp_m;
+            break;
+        }
+
+        if (!c->encoder_id) {
+            /*
+             * default drm encoder not attached connector, just
+             * select the first one.
+             */
+            if (dev->num_encoders) {
+                e = dev->encoders[0];
+                c->encoder_id = e->encoder_id;
+            } else {
+                printf("no encoder attached to the connector\n");
+                continue;
+            }
+        }
+
+        for (j = 0; j < dev->num_encoders; j++) {
+            e = dev->encoders[j];
+            if (e->encoder_id == c->encoder_id)
+                break;
+        }
+        if (j == dev->num_encoders) {
+            printf("could not find encoder for the connector\n");
+            continue;
+        }
+
+        if (!e->crtc_id) {
+            /*
+             * default drm crtc not attached encoder, just
+             * select the first one.
+             */
+            if (dev->num_crtcs) {
+                cr = &dev->crtcs[j];
+                e->crtc_id = cr->crtc->crtc_id;
+            } else {
+                printf("no crtc attached to the encoder\n");
+                continue;
+            }
+        }
+
+        for (j = 0; j < dev->num_crtcs; j++) {
+            cr = &dev->crtcs[j];
+
+            if (cr->crtc->crtc_id == e->crtc_id)
+                break;
+        }
+        if (j == dev->num_crtcs) {
+            printf("could not find crtc for the encoder\n");
+            continue;
+        }
+        if (cr->scanout) {
+            printf("crtc already in use\n");
+            continue;
+        }
+
+        /* XXX: Hardcoding the format here... :| */
+        cr->scanout = create_sp_bo(dev, m->hdisplay, m->vdisplay,
+                                   24, 32, DRM_FORMAT_XRGB8888, 0);
+        if (!cr->scanout) {
+            printf("failed to create new scanout bo\n");
+            continue;
+        }
+
+        fill_bo(cr->scanout, 0xFF, 0x0, 0x0, 0x0);
+
+        ret = drmModeSetCrtc(dev->fd, cr->crtc->crtc_id,
+                             cr->scanout->fb_id, 0, 0, &c->connector_id,
+                             1, m);
+        if (ret) {
+            printf("failed to set crtc mode ret=%d\n", ret);
+            continue;
+        }
+        cr->crtc = drmModeGetCrtc(dev->fd, cr->crtc->crtc_id);
+        /*
+         * Todo:
+         * I don't know why crtc mode is empty, just copy PREFERRED mode
+         * for it.
+         */
+        memcpy(&cr->crtc->mode, m, sizeof(*m));
+    }
+    return 0;
+}
+
+struct sp_plane* get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc) {
+    int i;
+
+    for (i = 0; i < dev->num_planes; i++) {
+        struct sp_plane *p = &dev->planes[i];
+
+        if (p->in_use)
+            continue;
+
+        if (!(p->plane->possible_crtcs & (1 << crtc->pipe)))
+            continue;
+
+        p->in_use = 1;
+        return p;
+    }
+    return NULL;
+}
+
+void put_sp_plane(struct sp_plane *plane) {
+    drmModePlanePtr p;
+
+    /* Get the latest plane information (most notably the crtc_id) */
+    p = drmModeGetPlane(plane->dev->fd, plane->plane->plane_id);
+    if (p)
+        plane->plane = p;
+
+    if (plane->plane->crtc_id)
+        drmModeSetPlane(plane->dev->fd, plane->plane->plane_id,
+                        plane->plane->crtc_id, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0, 0);
+
+    if (plane->bo) {
+        free_sp_bo(plane->bo);
+        plane->bo = NULL;
+    }
+    plane->in_use = 0;
+}
+
+int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane,
+                 struct sp_crtc *crtc, int x, int y) {
+    int ret;
+    uint32_t w, h;
+
+    w = plane->bo->width;
+    h = plane->bo->height;
+
+    if ((w + x) > crtc->crtc->mode.hdisplay)
+        w = crtc->crtc->mode.hdisplay - x;
+    if ((h + y) > crtc->crtc->mode.vdisplay)
+        h = crtc->crtc->mode.vdisplay - y;
+
+    ret = drmModeSetPlane(dev->fd, plane->plane->plane_id,
+                          crtc->crtc->crtc_id, plane->bo->fb_id, 0, x, y, w, h,
+                          0, 0, w << 16, h << 16);
+    if (ret) {
+        printf("failed to set plane to crtc ret=%d\n", ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+#ifdef USE_ATOMIC_API
+int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane,
+		      drmModePropertySetPtr pset, struct sp_crtc *crtc, int x, int y) {
+	int ret;
+	uint32_t w, h;
+
+	w = plane->bo->width;
+	h = plane->bo->height;
+
+	if ((w + x) > crtc->crtc->mode.hdisplay)
+		w = crtc->crtc->mode.hdisplay - x;
+	if ((h + y) > crtc->crtc->mode.vdisplay)
+		h = crtc->crtc->mode.vdisplay - y;
+
+	ret = drmModePropertySetAdd(pset, plane->plane->plane_id,
+				    plane->crtc_pid, crtc->crtc->crtc_id)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->fb_pid, plane->bo->fb_id)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->crtc_x_pid, x)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->crtc_y_pid, y)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->crtc_w_pid, w)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->crtc_h_pid, h)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->src_x_pid, 0)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->src_y_pid, 0)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->src_w_pid, w << 16)
+		|| drmModePropertySetAdd(pset, plane->plane->plane_id,
+					 plane->src_h_pid, h << 16);
+	if (ret) {
+		printf("failed to add properties to the set\n");
+		return -1;
+	}
+
+	return ret;
+}
+#endif

+ 33 - 0
rkdrm/modeset.h

@@ -0,0 +1,33 @@
+//
+// Created by root on 17-11-7.
+//
+
+#ifndef MPP_LINUX_C_MODESET_H
+#define MPP_LINUX_C_MODESET_H
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm/drm_fourcc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bo.h"
+#include "dev.h"
+
+struct sp_dev;
+struct sp_crtc;
+
+int initialize_screens(struct sp_dev *dev);
+
+struct sp_plane* get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc);
+void put_sp_plane(struct sp_plane *plane);
+
+int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane,
+                 struct sp_crtc *crtc, int x, int y);
+
+#ifdef USE_ATOMIC_API
+int set_sp_plane_pset(struct sp_dev *dev, struct sp_plane *plane,
+		      drmModePropertySetPtr pset, struct sp_crtc *crtc, int x, int y);
+#endif
+
+#endif //MPP_LINUX_C_MODESET_H

+ 292 - 0
rkrga/RGA.cpp

@@ -0,0 +1,292 @@
+//
+// Created by root on 17-11-2.
+//
+
+#include <linux/videodev2.h>
+#include "RGA.h"
+
+#define rga_log(fmt,...)\
+            do {\
+                printf(fmt,##__VA_ARGS__);\
+            } while(0)
+
+RGA::RGA() : mFd(0),
+             mDstH(0),
+             mDstW(0),
+             mSrcW(0),
+             mSrcH(0),
+             mSrcLen(0)
+{
+
+}
+
+RGA::~RGA() {
+
+}
+
+int RGA::chk_dev_cap() {
+    struct v4l2_capability cap = {0};
+    int ret = 0;
+
+    ret = ioctl(mFd, VIDIOC_QUERYCAP, &cap);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_QUERYCAP.\n");
+        return -1;
+    }
+
+    if (!(cap.capabilities & V4L2_CAP_VIDEO_M2M)) {
+        rga_log("dev don't support VIDEO_M2M.\n");
+        return -2;
+    }
+
+    if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
+        rga_log("dev don't support V4L2_CAP_STREAMING.\n");
+        return -3;
+    }
+
+    return 0;
+}
+
+int RGA::set_src_fmt() {
+    struct v4l2_format fmt;
+    int ret = 0;
+
+    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+    fmt.fmt.pix.width  = RGA_ALIGN(mSrcW, 16);
+    fmt.fmt.pix.height = RGA_ALIGN(mSrcH, 16);
+    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+    fmt.fmt.pix.field = V4L2_FIELD_ANY;
+
+    ret = ioctl(mFd, VIDIOC_S_FMT, &fmt);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIO_S_FMT.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+int RGA::set_dst_fmt() {
+    struct v4l2_format fmt;
+    int ret = 0;
+
+    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    fmt.fmt.pix.width  = RGA_ALIGN(mDstW, 16);
+    fmt.fmt.pix.height = RGA_ALIGN(mDstH, 16);
+#ifdef USE_SDL
+    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+#else
+    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+#endif
+    fmt.fmt.pix.field = V4L2_FIELD_ANY;
+
+    ret = ioctl(mFd, VIDIOC_S_FMT, &fmt);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_S_FMT.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+int RGA::open_dev_strm() {
+    enum v4l2_buf_type type;
+    int ret = 0;
+
+    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    ret = ioctl(mFd, VIDIOC_STREAMON, &type);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_STREAMON for %d %s.\n",
+                errno, strerror(errno));
+        return -1;
+    }
+
+    type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+    ret = ioctl(mFd, VIDIOC_STREAMON, &type);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_STREAMON for %d %s.\n",
+                errno, strerror(errno));
+        return -2;
+    }
+
+    return 0;
+}
+
+int RGA::src_buf_map() {
+    struct v4l2_buffer buf;
+    struct v4l2_requestbuffers reqbuf;
+    int nb_src_bufs;
+    int ret = 0;
+    int i = 0;
+
+    memset(&reqbuf, 0, sizeof(reqbuf));
+    reqbuf.count = 5;
+    reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+    reqbuf.memory = V4L2_MEMORY_DMABUF;
+
+    ret = ioctl(mFd, VIDIOC_REQBUFS, &reqbuf);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_REQBUFS for %d %s.\n", errno, strerror(errno));
+        return -1;
+    }
+
+    nb_src_bufs = reqbuf.count;
+    rga_log("get dma buffer nb:%d.\n", nb_src_bufs);
+    for (i = 0; i < nb_src_bufs; i++) {
+        buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+        buf.memory = V4L2_MEMORY_DMABUF;
+        buf.index = i;
+
+        ret = ioctl(mFd, VIDIOC_QUERYBUF, &buf);
+        if (ret != 0) {
+            rga_log("failed to ioctl VIDIOC_QUERYBUF.\n");
+            return -2;
+        }
+
+    }
+    mSrcLen = buf.length;
+
+    return 0;
+}
+
+int RGA::dst_buf_map() {
+    struct v4l2_buffer buf;
+    struct v4l2_requestbuffers reqbuf;
+    int ret = 0;
+    int nb_dst_bufs;
+    int i = 0;
+
+    memset(&reqbuf, 0, sizeof(reqbuf));
+    reqbuf.count = 5;
+    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    reqbuf.memory = V4L2_MEMORY_DMABUF;
+
+    ret = ioctl(mFd, VIDIOC_REQBUFS, &reqbuf);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_REQBUFS for %d %s.\n", errno, strerror(errno));
+        return -1;
+    }
+
+    nb_dst_bufs = reqbuf.count;
+    rga_log("get dma buffer nb:%d.\n", nb_dst_bufs);
+    for (i = 0; i < nb_dst_bufs; i++) {
+        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        buf.memory = V4L2_MEMORY_DMABUF;
+        buf.index = i;
+
+        ret = ioctl(mFd, VIDIOC_QUERYBUF, &buf);
+        if (ret != 0) {
+            rga_log("failed to ioctl VIDIOC_QUERYBUF.\n");
+            return -2;
+        }
+
+    }
+
+    return 0;
+}
+
+int RGA::init(int srcW, int srcH, int dstW, int dstH) {
+    int ret = 0;
+
+    mSrcW = srcW;
+    mSrcH = srcH;
+    mDstW = dstW;
+    mDstH = dstH;
+
+    mFd = open(RK_RGA_DEV, O_RDWR);
+    if (mFd < 0) {
+        rga_log("failed to open rga dev %s.\n", RK_RGA_DEV);
+        return -1;
+    }
+
+    ret = chk_dev_cap();
+    if (ret < 0) {
+        rga_log("failed to exec chk_dev_cap %d.\n", ret);
+        return -2;
+    }
+
+    ret = set_src_fmt();
+    if (ret < 0) {
+        rga_log("failed to exec set_src_fmt %d.\n", ret);
+        return -3;
+    }
+
+    ret = set_dst_fmt();
+    if (ret < 0) {
+        rga_log("failed to exec set_dst_fmt %d.\n", ret);
+        return -4;
+    }
+
+    ret = src_buf_map();
+    if (ret < 0) {
+        rga_log("failed to exec src_buf_map %d.\n", ret);
+        return -5;
+    }
+
+    ret = dst_buf_map();
+    if (ret < 0) {
+        rga_log("failed to exec dst_buf_map %d.\n", ret);
+        return -6;
+    }
+
+
+    ret = open_dev_strm();
+    if (ret < 0) {
+        rga_log("failed to exec open_dev_strm %d.\n", ret);
+        return -7;
+    }
+
+    return 0;
+}
+
+int RGA::swscale(int srcFrmFd, int dstFrmFd) {
+    struct v4l2_buffer buf = {0};
+    int ret = 0;
+
+    memset(&buf, 0, sizeof(buf));
+    buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+    buf.memory = V4L2_MEMORY_DMABUF;
+    buf.bytesused = mSrcLen;
+    buf.index = 0;
+    buf.m.fd = srcFrmFd;
+    ret = ioctl(mFd, VIDIOC_QBUF, &buf);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_QBUF for %d %s.\n",
+                errno, strerror(errno));
+        return -1;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buf.memory = V4L2_MEMORY_DMABUF;
+    buf.index = 0;
+    buf.m.fd = dstFrmFd;
+    ret = ioctl(mFd, VIDIOC_QBUF, &buf);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_QBUF for %d %s.\n",
+                errno, strerror(errno));
+        return -2;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+    buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+    buf.memory = V4L2_MEMORY_DMABUF;
+    ret = ioctl(mFd, VIDIOC_DQBUF, &buf);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_DQBUF for %d %s.\n",
+                errno, strerror(errno));
+        return -3;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buf.memory = V4L2_MEMORY_DMABUF;
+    ret = ioctl(mFd, VIDIOC_DQBUF, &buf);
+    if (ret != 0) {
+        rga_log("failed to ioctl VIDIOC_DQBUF for %d %s.\n",
+                errno, strerror(errno));
+        return -4;
+    }
+
+    return 0;
+}

+ 44 - 0
rkrga/RGA.h

@@ -0,0 +1,44 @@
+//
+// Created by root on 17-11-2.
+//
+
+#ifndef MPP_LINUX_C_RGA_H
+#define MPP_LINUX_C_RGA_H
+
+#define RK_RGA_DEV	"/dev/v4l/by-path/platform-ff680000.rga-video-index0"
+
+extern "C" {
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+};
+
+#define RGA_ALIGN(x, a)   (((x)+(a)-1)&~((a)-1))
+
+class RGA {
+public:
+    RGA();
+    ~RGA();
+    int init(int srcW, int srcH, int dstW, int dstH);
+    int swscale(int srcFrmFd, int dstFrmFd);
+private:
+    int chk_dev_cap();
+    int set_src_fmt();
+    int set_dst_fmt();
+    int open_dev_strm();
+    int dst_buf_map();
+    int src_buf_map();
+
+    int mFd;
+    int mSrcW;
+    int mSrcH;
+    int mDstW;
+    int mDstH;
+    int mSrcLen;
+};
+
+
+#endif //MPP_LINUX_C_RGA_H

+ 35 - 0
thread/Thread.cpp

@@ -0,0 +1,35 @@
+//
+// Created by root on 17-11-1.
+//
+
+#include "Thread.h"
+
+#define thread_dbg(fmt,...)\
+            do {\
+                printf(fmt,##__VA_ARGS__);\
+            } while(0)
+
+Thread::Thread(func func, void *args, void **ret) {
+    mFun = func;
+    mArgs = args;
+    mRet = ret;
+}
+
+Thread::~Thread() {
+
+}
+
+int Thread::init() {
+    int ret = 0;
+
+    ret = pthread_create(&mHandle, NULL, mFun, mArgs);
+    if (ret < 0) {
+        thread_dbg("failed to create thread %d.\n", mHandle);
+        return -1;
+    }
+}
+
+void Thread::run() {
+    pthread_join(mHandle, mRet);
+    //pthread_detach(mHandle);
+}

+ 29 - 0
thread/Thread.h

@@ -0,0 +1,29 @@
+//
+// Created by root on 17-11-1.
+//
+
+#ifndef MPP_LINUX_C_THREAD_H
+#define MPP_LINUX_C_THREAD_H
+
+extern "C" {
+#include <stdio.h>
+#include <pthread.h>
+};
+
+typedef void *(*func)(void *);
+
+class Thread {
+public:
+    Thread(func fun, void *args, void **ret);
+    ~Thread();
+    int init();
+    void run();
+private:
+    pthread_t mHandle;
+    void *mArgs;
+    void **mRet;
+    void *(*mFun)(void *args);
+};
+
+
+#endif //MPP_LINUX_C_THREAD_H