From 68a19a73681301c6712e10d55bc64324716dbd24 Mon Sep 17 00:00:00 2001
From: zhangmeng <775834166@qq.com>
Date: 星期三, 09 十月 2019 15:38:47 +0800
Subject: [PATCH] split scale

---
 gostream.go                    |   26 +
 cffmpeg.h                      |   14 
 csrc/ffmpeg/configure/conf.cpp |    2 
 goenc.go                       |   54 +++
 csrc/gpu-conv/CUDALERP.cu      |   95 +++++
 CMakeLists.txt                 |    8 
 csrc/gpu-conv/CUDALERP.h       |   54 +++
 csrc/wrapper.cpp               |  118 ++++++
 godec.go                       |   28 +
 csrc/worker/decoder.cpp        |  106 ++---
 csrc/wrapper.hpp               |   16 
 goffmpeg.go                    |  215 -----------
 csrc/worker/decoder.hpp        |   24 
 goconv.go                      |  100 +++++
 libcffmpeg.c                   |   37 +
 gojpeg.go                      |   36 ++
 csrc/cffmpeg.cpp               |   26 +
 gorec.go                       |   54 +++
 libcffmpeg.h                   |   29 +
 19 files changed, 725 insertions(+), 317 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5ef89c8..6e1e6b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,7 +22,12 @@
     ${CMAKE_SOURCE_DIR}/csrc/thirdparty/whereami
     ${CMAKE_SOURCE_DIR}/csrc/thirdparty/ffmpeg/include
     ${CMAKE_SOURCE_DIR}/csrc/thirdparty/gb28181/include
+    ${CMAKE_SOURCE_DIR}/csrc/gpu-conv
 )
+
+set(CUDA_TOOLKIT_ROOT_DIR /usr/local/cuda)
+include_directories(/usr/local/cuda/include)
+find_package(CUDA QUIET REQUIRED)
 
 link_directories(/usr/local/cuda/lib64 ${CMAKE_SOURCE_DIR}/csrc/thirdparty/gb28181/lib)
 
@@ -47,7 +52,8 @@
 
 file(GLOB_RECURSE FFMPEG_LIST ${CMAKE_SOURCE_DIR}/csrc/*.cpp)
 list(APPEND FFMPEG_LIST ${CMAKE_SOURCE_DIR}/csrc/thirdparty/whereami/whereami.c)
+file(GLOB_RECURSE CUDA_LIST ${CMAKE_SOURCE_DIR}/csrc/gpu-conv/*.cu)
 
-add_library(${BIN} SHARED ${FFMPEG_LIST})
+cuda_add_library(${BIN} SHARED ${FFMPEG_LIST} ${CUDA_LIST})
 
 target_link_libraries(${BIN} ${LINK_LIB} numa nppig nppicc nppc -lz pthread dl rtspclient StreamParse)
diff --git a/cffmpeg.h b/cffmpeg.h
index c794216..ccc21a6 100644
--- a/cffmpeg.h
+++ b/cffmpeg.h
@@ -15,7 +15,6 @@
 void c_ffmpeg_destroy(const cffmpeg h);
 void c_ffmpeg_run(const cffmpeg h, const char *input);
 
-void c_ffmpeg_scale(const cffmpeg h, const int wid, const int hei, const int flags);
 void c_ffmpeg_run_gb28181(const cffmpeg h);
 void c_ffmepg_use_cpu(const cffmpeg h);
 /////////passive api
@@ -24,10 +23,10 @@
 void c_ffmpeg_get_info_recorder(const cffmpeg h, int *index, char** recid, int *recidLen, char **fpath, int *pathLen);
 
 void c_ffmpeg_build_decoder(const cffmpeg h);
-void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int64_t *id);
+void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id);
 void* c_ffmpeg_get_avpacket(const cffmpeg h, int *size, int *key);
 
-//////test
+//////decoder
 void* c_ffmpeg_decode(const char *file, const int gb, int *wid, int *hei);
 
 // pic encoder
@@ -35,6 +34,15 @@
 void c_ffmpeg_destroy_encoder(void *h);
 int c_ffmpeg_encode(void *hdl, uint8_t *in, const int w, const int h, uint8_t **out, int *size, int *key);
 
+// conv cpu
+void *c_ffmpeg_create_conv(const int srcW, const int srcH, const int srcFormat,
+                          const int dstW, const int dstH, const int flag);
+void c_ffmpeg_destroy_conv(void *h);
+void *c_ffmpeg_conv(void *h, uint8_t *in);
+
+// gpu conv
+void* c_gpu_conv(uint8_t *in, const int w, const int h, const int dst_w, const int dst_h, int *length);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/csrc/cffmpeg.cpp b/csrc/cffmpeg.cpp
index 7b31f3f..9ade6f9 100644
--- a/csrc/cffmpeg.cpp
+++ b/csrc/cffmpeg.cpp
@@ -33,11 +33,6 @@
     s->RunStream(input);
 }
 
-void c_ffmpeg_scale(const cffmpeg h, const int wid, const int hei, const int flags){
-    Wrapper *s = (Wrapper*)h;
-    s->ScalePicture(wid, hei, flags);
-}
-
 void c_ffmpeg_run_gb28181(const cffmpeg h){
     Wrapper *s = (Wrapper*)h;
     s->GB28181();
@@ -90,10 +85,10 @@
     s->BuildDecoder();
 }
 
-void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int64_t *id){
+void* c_ffmpeg_get_pic_decoder(const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id){
     Wrapper *s = (Wrapper*)h;
     unsigned char *data = NULL;
-    s->GetPicDecoder(&data, wid, hei, id);
+    s->GetPicDecoder(&data, wid, hei, format, length, id);
     return data;
 }
 
@@ -121,3 +116,20 @@
 int c_ffmpeg_encode(void *hdl, uint8_t *in, const int w, const int h, uint8_t **out, int *size, int *key){
     return Encode(hdl, in, w, h, out, size, key);
 }
+
+void *c_ffmpeg_create_conv(const int srcW, const int srcH, const int srcFormat,
+                          const int dstW, const int dstH, const int flag){
+    return CreateConvertor(srcW, srcH, srcFormat, dstW, dstH, flag);
+}
+
+void *c_ffmpeg_conv(void *h, uint8_t *in){
+    return Convert(h, in);
+}
+
+void c_ffmpeg_destroy_conv(void *h){
+    DestoryConvertor(h);
+}
+
+void* c_gpu_conv(uint8_t *in, const int w, const int h, const int dst_w, const int dst_h, int *length){
+    return ConvertYUV2BGR(in, w, h, dst_w, dst_h, length);
+}
\ No newline at end of file
diff --git a/csrc/ffmpeg/configure/conf.cpp b/csrc/ffmpeg/configure/conf.cpp
index d836840..43e45ac 100644
--- a/csrc/ffmpeg/configure/conf.cpp
+++ b/csrc/ffmpeg/configure/conf.cpp
@@ -13,7 +13,7 @@
 	    av_register_all();
         avfilter_register_all();
         avformat_network_init();
-        av_log_set_level(AV_LOG_ERROR);
+        av_log_set_level(AV_LOG_VERBOSE);
 	}
 
 	std::string getAVErrorDesc(const int code){
diff --git a/csrc/gpu-conv/CUDALERP.cu b/csrc/gpu-conv/CUDALERP.cu
new file mode 100644
index 0000000..ee44fee
--- /dev/null
+++ b/csrc/gpu-conv/CUDALERP.cu
@@ -0,0 +1,95 @@
+/*******************************************************************
+*   CUDALERP.cu
+*   CUDALERP
+*
+*	Author: Kareem Omar
+*	kareem.omar@uah.edu
+*	https://github.com/komrad36
+*
+*	Last updated Jan 7, 2016
+*******************************************************************/
+//
+// The file CUDALERP.h exposes two extremely high performance GPU
+// resize operations,
+// CUDALERP (bilinear interpolation), and 
+// CUDANERP (nearest neighbor interpolation), for 8-bit unsigned
+// integer (i.e. grayscale) data.
+//
+// For 32-bit float data, see the CUDAFLERP project instead.
+//
+// CUDALERP offers superior accuracy to CUDA's built-in texture
+// interpolator at comparable performance. The accuracy if compiled
+// with -use-fast-math off is nearly equivalent to my CPU interpolator,
+// KLERP, while still being as fast as the built-in interpolation.
+// 
+// Particularly for large images, CUDALERP dramatically outperforms
+// even the highly tuned CPU AVX2 versions.
+// 
+// All functionality is contained in the header 'CUDALERP.h' and
+// the source file 'CUDALERP.cu' and has no external dependencies at all.
+// 
+// Note that these are intended for computer vision use(hence the speed)
+// and are designed for grayscale images.
+// 
+// The file 'main.cpp' is an example and speed test driver.
+//
+
+#include "CUDALERP.h"
+
+__global__ void
+#ifndef __INTELLISENSE__
+__launch_bounds__(256, 0)
+#endif
+CUDANERP_kernel(const cudaTextureObject_t d_img_tex, const float gxs, const float gys, uint8_t* __restrict const d_out, const int neww) {
+	uint32_t x = (blockIdx.x << 9) + (threadIdx.x << 1);
+	const uint32_t y = blockIdx.y;
+	const float fy = y*gys;
+#pragma unroll
+	for (int i = 0; i < 2; ++i, ++x) {
+		const float fx = x*gxs;
+		float res = 255.0f*tex2D<float>(d_img_tex, fx, fy);
+		if (x < neww) d_out[y*neww + x] = res;
+	}
+}
+
+__global__ void
+#ifndef __INTELLISENSE__
+__launch_bounds__(256, 0)
+#endif
+CUDALERP_kernel(const cudaTextureObject_t d_img_tex, const float gxs, const float gys, uint8_t* __restrict const d_out, const int neww) {
+	uint32_t x = (blockIdx.x << 9) + (threadIdx.x << 1);
+	const uint32_t y = blockIdx.y;
+	const float fy = (y + 0.5f)*gys - 0.5f;
+	const float wt_y = fy - floor(fy);
+	const float invwt_y = 1.0f - wt_y;
+#pragma unroll
+	for (int i = 0; i < 2; ++i, ++x) {
+		const float fx = (x + 0.5f)*gxs - 0.5f;
+		// less accurate and not really much (or any) faster
+		// -----------------
+		// const float res = tex2D<float>(d_img_tex, fx, fy);
+		// -----------------
+		const float4 f = tex2Dgather<float4>(d_img_tex, fx + 0.5f, fy + 0.5f);
+		const float wt_x = fx - floor(fx);
+		const float invwt_x = 1.0f - wt_x;
+		const float xa = invwt_x*f.w + wt_x*f.z;
+		const float xb = invwt_x*f.x + wt_x*f.y;
+		const float res = 255.0f*(invwt_y*xa + wt_y*xb) + 0.5f;
+		// -----------------
+		if (x < neww) d_out[y*neww + x] = res;
+	}
+}
+
+void CUDANERP(const cudaTextureObject_t d_img_tex, const int oldw, const int oldh, uint8_t* __restrict const d_out, const uint32_t neww, const uint32_t newh) {
+	const float gxs = static_cast<float>(oldw) / static_cast<float>(neww);
+	const float gys = static_cast<float>(oldh) / static_cast<float>(newh);
+	CUDANERP_kernel<<<{((neww - 1) >> 9) + 1, newh}, 256>>>(d_img_tex, gxs, gys, d_out, neww);
+	cudaDeviceSynchronize();
+}
+
+void CUDALERP(const cudaTextureObject_t d_img_tex, const int oldw, const int oldh, uint8_t* __restrict const d_out, const uint32_t neww, const uint32_t newh) {
+	const float gxs = static_cast<float>(oldw) / static_cast<float>(neww);
+	const float gys = static_cast<float>(oldh) / static_cast<float>(newh);
+	CUDALERP_kernel<<<{((neww - 1) >> 9) + 1, newh}, 256>>>(d_img_tex, gxs, gys, d_out, neww);
+	cudaDeviceSynchronize();
+}
diff --git a/csrc/gpu-conv/CUDALERP.h b/csrc/gpu-conv/CUDALERP.h
new file mode 100644
index 0000000..1645cb9
--- /dev/null
+++ b/csrc/gpu-conv/CUDALERP.h
@@ -0,0 +1,54 @@
+/*******************************************************************
+*   CUDALERP.h
+*   CUDALERP
+*
+*	Author: Kareem Omar
+*	kareem.omar@uah.edu
+*	https://github.com/komrad36
+*
+*	Last updated Jan 7, 2016
+*******************************************************************/
+//
+// The file CUDALERP.h exposes two extremely high performance GPU
+// resize operations,
+// CUDALERP (bilinear interpolation), and 
+// CUDANERP (nearest neighbor interpolation), for 8-bit unsigned
+// integer (i.e. grayscale) data.
+//
+// For 32-bit float data, see the CUDAFLERP project instead.
+//
+// CUDALERP offers superior accuracy to CUDA's built-in texture
+// interpolator at comparable performance. The accuracy if compiled
+// with -use-fast-math off is nearly equivalent to my CPU interpolator,
+// KLERP, while still being as fast as the built-in interpolation.
+// 
+// Particularly for large images, CUDALERP dramatically outperforms
+// even the highly tuned CPU AVX2 versions.
+// 
+// All functionality is contained in the header 'CUDALERP.h' and
+// the source file 'CUDALERP.cu' and has no external dependencies at all.
+// 
+// Note that these are intended for computer vision use(hence the speed)
+// and are designed for grayscale images.
+// 
+// The file 'main.cpp' is an example and speed test driver.
+//
+
+#pragma once
+
+#include "cuda_runtime.h"
+
+#include <cstdint>
+
+#ifdef __INTELLISENSE__
+#include <algorithm>
+#define asm(x)
+#include "device_launch_parameters.h"
+#define __CUDACC__
+#include "device_functions.h"
+#undef __CUDACC__
+#endif
+
+void CUDALERP(const cudaTextureObject_t d_img_tex, const int oldw, const int oldh, uint8_t* __restrict const d_out, const uint32_t neww, const uint32_t newh);
+
+void CUDANERP(const cudaTextureObject_t d_img_tex, const int oldw, const int oldh, uint8_t* __restrict const d_out, const uint32_t neww, const uint32_t newh);
diff --git a/csrc/worker/decoder.cpp b/csrc/worker/decoder.cpp
index ce5f631..67af0a1 100644
--- a/csrc/worker/decoder.cpp
+++ b/csrc/worker/decoder.cpp
@@ -17,27 +17,17 @@
 
 namespace cffmpeg_wrap
 {
-    decoder::decoder(ffwrapper::FormatIn *dec, const int w, const int h, const int f)
-    :conv_(NULL)
-    ,conv_w_(w)
-    ,conv_h_(h)
-    ,conv_flag_(f)
-    ,decRef_(dec)
+    decoder::decoder(ffwrapper::FormatIn *dec)
+    :decRef_(dec)
     {}
     
     decoder::~decoder(){
 
-        if (conv_){
-            delete conv_;
+        std::lock_guard<std::mutex> l(mutex_frm_);
+        for(auto i : list_frm_){
+            av_frame_free(&i.frm);
         }
-
-        {
-            std::lock_guard<std::mutex> l(mutex_pic_);
-            for(auto &i : list_pic_){
-                free(i.data);
-            }
-            list_pic_.clear();
-        }
+        list_frm_.clear();
     }
 
     int decoder::initDecoder(){
@@ -47,17 +37,6 @@
                 
             bool flag = true;
             flag = decRef_->openCodec(NULL);
-            auto dec_ctx = decRef_->getCodecContext();
-            if(conv_){
-                delete conv_;
-                conv_ = NULL;
-            }
-            conv_w_ = conv_w_ == 0 || conv_w_ > dec_ctx->width ? dec_ctx->width : conv_w_;
-            conv_h_ = conv_h_ == 0 || conv_h_ > dec_ctx->height ? dec_ctx->height : conv_h_;
-            AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24;
-            conv_ = new cvbridge(
-                    dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
-                    conv_w_, conv_h_, pix_fmt, conv_flag_);
 
             if (!flag){
                 logIt("FormatIn openCodec Failed!");
@@ -68,25 +47,15 @@
     }
 
     int decoder::saveFrame(AVFrame *frame, int64_t &id){
-        //缂撳瓨鏁版嵁
-        BGR24 pic;
-        AVFrame *frm = frame;
-        pic.w = conv_w_;
-        pic.h = conv_h_;
-        unsigned char *picData = (unsigned char*)malloc(pic.w * pic.h * 3);
-        conv_->copyPicture(picData, frm);
-        pic.data = picData;
-        pic.id = id;
-        std::lock_guard<std::mutex> l(mutex_pic_);
-        while(list_pic_.size() > 50){
+        while(list_frm_.size() > 50){
             for(int i = 0; i < 12; i++){
-                auto t = list_pic_.front();
-                free(t.data);
-                list_pic_.pop_front();
+                auto t = list_frm_.front();
+                av_frame_free(&t.frm);
+                list_frm_.pop_front();
             }
         }
-        list_pic_.emplace_back(pic);
-        return list_pic_.size();
+        list_frm_.push_back({frame,id});
+        return list_frm_.size();   
     }
 
     int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
@@ -94,7 +63,7 @@
         if (!data) return -1;
         if (!decRef_->isVideoPkt(&data->getAVPacket())) return -2;
         
-        if (!conv_){
+        if (decRef_->getCodecContext() == NULL){
             if (initDecoder() != 0) return -3;
         }
 
@@ -107,21 +76,50 @@
         if (ret == 0){
             saveFrame(frame, id);
         }
-        av_frame_free(&frame);
     }
 
-    void decoder::GetFrame(unsigned char **data, int *w, int *h, int64_t *id){
-        std::lock_guard<std::mutex> l(mutex_pic_);
-        if(list_pic_.empty()){
+    void decoder::GetFrame(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id){
+
+        AVFrame *frm = NULL;
+        {
+            std::lock_guard<std::mutex> l(mutex_frm_);
+            if(list_frm_.empty()){
+                *data = NULL;
+                *w = *h = 0;
+                *id = -1;
+                return;
+            }
+            auto p = list_frm_.front();
+            list_frm_.pop_front();
+            frm = p.frm;
+            *id = p.id;
+            *w = frm->width;
+            *h = frm->height;
+            *format = frm->format;
+        }
+
+        *length = avpicture_get_size((enum AVPixelFormat)frm->format, frm->width, frm->height);
+        if (*length <= 0){
+            logIt("get raw frame data error");
             *data = NULL;
-            *w = 0;
-            *h = 0;
+            *w = *h = 0;
+            *id = -1;
             return;
         }
-        auto p = list_pic_.front();
-        *data = p.data; *w = p.w; *h = p.h;
-        *id = p.id;
-        list_pic_.pop_front();
+
+        unsigned char *picData = (unsigned char*)malloc(*length);
+        auto ret = avpicture_layout((const AVPicture*)frm, (enum AVPixelFormat)frm->format, frm->width, frm->height, picData, *length);
+        av_frame_free(&frm);
+        
+        if (ret < 0){
+            *data = NULL;
+            *w = *h = 0;
+            *id = -1;
+            free(picData);
+            return;
+        }
+
+        *data = picData;
     }
 
 } // namespace cffmpeg_wrap
diff --git a/csrc/worker/decoder.hpp b/csrc/worker/decoder.hpp
index ae9fba2..94bbb03 100644
--- a/csrc/worker/decoder.hpp
+++ b/csrc/worker/decoder.hpp
@@ -10,44 +10,40 @@
 #include <condition_variable>
 
 struct AVFrame;
+struct AVCodecContext;
 
 namespace ffwrapper
 {
     class FormatIn;
-    class cvbridge;
     class CodedData;
 } // namespace ffwrapper
 
 namespace cffmpeg_wrap
 {
-    typedef struct _pic_bgr24{
-        unsigned char *data;
-        int w;
-        int h;
-
+    typedef struct _frm{
+        AVFrame *frm;
         int64_t id;
-    }BGR24;
+    }FRM;
 
     class decoder
     {
     private:
-        ffwrapper::cvbridge *conv_;
-        int conv_w_, conv_h_, conv_flag_;
 
         ffwrapper::FormatIn *decRef_;
 
-        std::list<BGR24> list_pic_;
-        std::mutex mutex_pic_;
-
+        std::list<FRM> list_frm_;
+        std::mutex mutex_frm_;
+        
     private:
         int initDecoder();
         int saveFrame(AVFrame *frame, int64_t &id);
     public: 
         void Start();
         int SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
-        void GetFrame(unsigned char **data, int *w, int *h, int64_t *id);
+        void GetFrame(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id);
+    
     public:
-        decoder(ffwrapper::FormatIn *dec, const int w, const int h, const int f);
+        explicit decoder(ffwrapper::FormatIn *dec);
         ~decoder();
     };
     
diff --git a/csrc/wrapper.cpp b/csrc/wrapper.cpp
index c03b54f..2643ce0 100644
--- a/csrc/wrapper.cpp
+++ b/csrc/wrapper.cpp
@@ -24,6 +24,8 @@
 #include "worker/decoder.hpp"
 #include "worker/rec.hpp"
 
+#include "CUDALERP.h"
+
 using namespace logif;
 using namespace ffwrapper;
 
@@ -40,9 +42,6 @@
 
     Wrapper::Wrapper()
     :input_url_("")
-    ,scale_w_(0)
-    ,scale_h_(0)
-    ,scale_f_(SWS_POINT)
     ,audio_(false)
     ,gb_(0)
     ,cpu_(0)
@@ -59,9 +58,6 @@
 
     Wrapper::Wrapper(const char *logfile)
     :input_url_("")
-    ,scale_w_(0)
-    ,scale_h_(0)
-    ,scale_f_(SWS_POINT)
     ,audio_(false)
     ,gb_(0)
     ,cpu_(0)
@@ -154,7 +150,7 @@
         stream_ = new stream(in, 3 * in->getFPS());
         // stream_->AudioSwitch(audio_);
 
-        decoder_ = new decoder(in, scale_w_, scale_h_, scale_f_);
+        decoder_ = new decoder(in);
 
         rec_->Load(in);
         if(fn_rec_lazy_) {
@@ -253,9 +249,9 @@
         run_dec_ = true;
     }
 
-    void Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id){
+    void Wrapper::GetPicDecoder(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id){
         if (decoder_){
-            decoder_->GetFrame(data, w, h, id);
+            decoder_->GetFrame(data, w, h, format, length, id);
         }
     }
     
@@ -427,5 +423,109 @@
         return flag;
     }
 
+///////////////////////////////////////////////////////////
+    typedef struct _conv
+    {
+        int srcW;
+        int srcH;
+        int srcF;
+        int dstW;
+        int dstH;
+        cvbridge *b;
+    }Conv;
+    
+    void *CreateConvertor(const int srcW, const int srcH, const int srcFormat,
+                          const int dstW, const int dstH, const int flag){
+        AVPixelFormat pix_fmt = AV_PIX_FMT_BGR24;
+        auto bridge = new cvbridge(
+                srcW, srcH, srcFormat,
+                dstW, dstH, pix_fmt, flag);
+        if (!bridge) return NULL;
+
+        Conv *c = (Conv*)malloc(sizeof(Conv));
+        c->b = bridge;
+        c->dstW = dstW;
+        c->dstH = dstH;
+        c->srcW = srcW;
+        c->srcH = srcH;
+        c->srcF = srcFormat;
+
+        return c;
+    }
+
+    uint8_t *Convert(void *h, uint8_t *src){
+        Conv *c = (Conv*)h;
+
+        auto b = c->b;
+
+        AVFrame *tmp_frm = av_frame_alloc();
+        tmp_frm->format = (AVPixelFormat)c->srcF;
+        tmp_frm->width = c->srcW;
+        tmp_frm->height = c->srcH;
+    
+        //create a AVPicture frame from the opencv Mat input image
+        int ret = avpicture_fill((AVPicture *)tmp_frm,
+                        (uint8_t *)src,
+                        (AVPixelFormat)tmp_frm->format,
+                        tmp_frm->width,
+                        tmp_frm->height);
+
+        unsigned char *picData = NULL;
+        if (ret > 0){
+            picData = (unsigned char*)malloc(c->dstW * c->dstH * 3);
+            b->copyPicture(picData, tmp_frm);
+        }
+        
+        av_frame_free(&tmp_frm);
+
+        return picData;
+    }
+
+    void DestoryConvertor(void *h){
+        Conv *c = (Conv*)h;
+        delete c->b;
+        free(c);
+    }
+
+
+    uint8_t* ConvertYUV2BGR(uint8_t *src, const int w, const int h, const int dst_w, const int dst_h, int *length){
+        return NULL;
+
+        // int oldw = w, oldh = h, neww = dst_w, newh = dst_h;
+        // 	// setting cache and shared modes
+	    // cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);
+	    // cudaDeviceSetSharedMemConfig(cudaSharedMemBankSizeFourByte);
+
+	    // // allocating and transferring image and binding to texture object
+	    // cudaChannelFormatDesc chandesc_img = cudaCreateChannelDesc(8, 0, 0, 0, cudaChannelFormatKindUnsigned);
+	    // cudaArray* d_img_arr;
+	    // cudaMallocArray(&d_img_arr, &chandesc_img, oldw, oldh, cudaArrayTextureGather);
+	    // cudaMemcpyToArray(d_img_arr, 0, 0, image, oldh * oldw, cudaMemcpyHostToDevice);
+	    // struct cudaResourceDesc resdesc_img;
+	    // memset(&resdesc_img, 0, sizeof(resdesc_img));
+	    // resdesc_img.resType = cudaResourceTypeArray;
+	    // resdesc_img.res.array.array = d_img_arr;
+	    // struct cudaTextureDesc texdesc_img;
+	    // memset(&texdesc_img, 0, sizeof(texdesc_img));
+	    // texdesc_img.addressMode[0] = cudaAddressModeClamp;
+	    // texdesc_img.addressMode[1] = cudaAddressModeClamp;
+	    // texdesc_img.readMode = cudaReadModeNormalizedFloat;
+	    // texdesc_img.filterMode = cudaFilterModePoint;
+	    // texdesc_img.normalizedCoords = 0;
+	    // cudaTextureObject_t d_img_tex = 0;
+	    // cudaCreateTextureObject(&d_img_tex, &resdesc_img, &texdesc_img, nullptr);
+
+	    // uint8_t* d_out = nullptr;
+	    // cudaMalloc(&d_out, total);
+
+	    // for (int i = 0; i < warmups; ++i) CUDALERP(d_img_tex, oldw, oldh, d_out, neww, newh);
+	    // auto start = high_resolution_clock::now();
+	    // for (int i = 0; i < runs; ++i) CUDALERP(d_img_tex, oldw, oldh, d_out, neww, newh);
+	    // auto end = high_resolution_clock::now();
+	    // auto sum = (end - start) / runs;
+
+	    // auto h_out = new uint8_t[neww * newh];
+	    // cudaMemcpy(h_out, d_out, total, cudaMemcpyDeviceToHost);
+    }
 }
 
diff --git a/csrc/wrapper.hpp b/csrc/wrapper.hpp
index af976e5..13d5f7d 100644
--- a/csrc/wrapper.hpp
+++ b/csrc/wrapper.hpp
@@ -44,23 +44,18 @@
         void BuildRecorder(const char* id,const char *dir, const int mind, const int maxd, const bool audio);
         int FireRecorder(const char* sid,const int64_t &id);
         void GetInfoRecorder(std::string &recID, int &index, std::string &path);
-        void ScalePicture(const int w, const int h, const int flags){
-            scale_w_ = w;
-            scale_h_ = h;
-            scale_f_ = flags;
-        }
+        
         void GB28181(){gb_ = 1;}
         void CPUDec(){cpu_ = 1;}
         void AudioSwitch(const bool a);
     public: //decoder
         void BuildDecoder();
-        void GetPicDecoder(unsigned char **data, int *w, int *h, int64_t *id);
+        void GetPicDecoder(unsigned char **data, int *w, int *h, int *format, int *length, int64_t *id);
     public: // push stream
         void GetPacket(unsigned char **pktData, int *size, int *key);
     private:
         // stream 鍙傛暟
         std::string input_url_;
-        int scale_w_, scale_h_, scale_f_;
         bool audio_;
         int gb_, cpu_;
         bool run_dec_;
@@ -80,10 +75,17 @@
     };
 
     uint8_t* Decode(const char *file, const int gb, int *w, int *h);
+
     void *CreateEncoder(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
     void DestroyEncoder(void *h);
     int Encode(void *hdl, uint8_t *in, const int w, const int h, uint8_t **out, int *size, int *key);
 
+    void *CreateConvertor(const int srcW, const int srcH, const int srcFormat,
+                          const int dstW, const int dstH, const int flag);
+    uint8_t *Convert(void *h, uint8_t *src);
+    void DestoryConvertor(void *h);
+
+    uint8_t* ConvertYUV2BGR(uint8_t *src, const int w, const int h, const int dst_w, const int dst_h, int *length);
 }
 
 #endif
\ No newline at end of file
diff --git a/goconv.go b/goconv.go
new file mode 100644
index 0000000..459b3dd
--- /dev/null
+++ b/goconv.go
@@ -0,0 +1,100 @@
+package goffmpeg
+
+/*
+#include <stdlib.h>
+#include "libcffmpeg.h"
+*/
+import "C"
+import "unsafe"
+
+const (
+	// ScaleNone self add no scale raw frame data
+	ScaleNone = 0
+	// ScaleFastBilinear SWS_FAST_BILINEAR
+	ScaleFastBilinear = 1
+	// ScaleBilinear SWS_BILINEAR
+	ScaleBilinear = 2
+	// ScaleBicubic SWS_BICUBIC
+	ScaleBicubic = 4
+	// ScaleX SWS_X
+	ScaleX = 8
+	// ScalePoint SWS_POINT
+	ScalePoint = 0x10
+	// ScaleArea SWS_AREA
+	ScaleArea = 0x20
+	// ScaleBicublin SWS_BICUBLIN
+	ScaleBicublin = 0x40
+	// ScaleGauss SWS_GAUSS
+	ScaleGauss = 0x80
+	// ScaleSinc SWS_SINC
+	ScaleSinc = 0x100
+	// ScaleLancZos SWS_LANCZOS
+	ScaleLancZos = 0x200
+	// ScaleSpline SWS_SPLINE
+	ScaleSpline = 0x400
+)
+
+// SrcFormat format
+const srcFormat = 23
+
+// GoConv conv
+type GoConv struct {
+	srcW int
+	srcH int
+	dstW int
+	dstH int
+
+	conv C.cconv
+}
+
+// NewConv new conv
+func NewConv(srcW, srcH, dstW, dstH, scaleFlag int) *GoConv {
+	c := C.wrap_fn_create_conv(C.int(srcW), C.int(srcH), C.int(srcFormat), C.int(dstW), C.int(dstH), C.int(scaleFlag))
+
+	if c == nil {
+		return nil
+	}
+
+	return &GoConv{
+		srcW,
+		srcH,
+		dstW,
+		dstH,
+		c,
+	}
+}
+
+// Free free
+func (c *GoConv) Free() {
+	if c.conv != nil {
+		C.wrap_fn_destroy_conv(c.conv)
+	}
+}
+
+// ConvToPicture conv to pic
+func (c *GoConv) ConvToPicture(src []byte) []byte {
+	if c.conv == nil {
+		return nil
+	}
+
+	cin := C.CBytes(src)
+	defer C.free(cin)
+
+	bgr := C.wrap_fn_conv(c.conv, (*C.uchar)(cin))
+	defer C.free(unsafe.Pointer(bgr))
+
+	if bgr != nil {
+		return C.GoBytes(bgr, C.int(c.dstW*c.dstH*3))
+	}
+
+	return nil
+}
+
+/////////////// for conv
+
+// ConvGPU conv gpu resize
+func ConvGPU(in []byte, w, h, dstW, dstH int) []byte {
+
+	return nil
+
+}
diff --git a/godec.go b/godec.go
new file mode 100644
index 0000000..a232618
--- /dev/null
+++ b/godec.go
@@ -0,0 +1,28 @@
+package goffmpeg
+
+/*
+#include <stdlib.h>
+#include "libcffmpeg.h"
+*/
+import "C"
+import "unsafe"
+
+// BuildDecoder build decoder
+func (h *GoFFMPEG) BuildDecoder() {
+	C.wrap_fn_decoder(h.ffmpeg)
+}
+
+// GetYUV get yuv data
+func (h *GoFFMPEG) GetYUV() ([]byte, int, int, int64) {
+	var fid C.long
+	var length C.int
+	var srcW, srcH, srcF C.int
+
+	p := C.wrap_fn_decoder_pic(h.ffmpeg, &srcW, &srcH, &srcF, &length, &fid)
+	if srcW == 0 || srcH == 0 {
+		return nil, 0, 0, 0
+	}
+	defer C.free(unsafe.Pointer(p))
+
+	return C.GoBytes(p, length), int(srcW), int(srcH), int64(fid)
+}
diff --git a/goenc.go b/goenc.go
new file mode 100644
index 0000000..3d00996
--- /dev/null
+++ b/goenc.go
@@ -0,0 +1,54 @@
+package goffmpeg
+
+/*
+#include <stdlib.h>
+#include "libcffmpeg.h"
+*/
+import "C"
+
+///////////////for encoder
+
+// GoEncoder encoder
+type GoEncoder struct {
+	enc C.cencoder
+}
+
+// NewEncoder encoder
+func NewEncoder(w, h, fps, br, sFlag, gi int) *GoEncoder {
+	if w <= 0 || h <= 0 {
+		return nil
+	}
+
+	return &GoEncoder{
+		enc: C.wrap_fn_create_encoder(C.int(w), C.int(h), C.int(fps), C.int(br), C.int(sFlag), C.int(gi)),
+	}
+}
+
+// Free free
+func (e *GoEncoder) Free() {
+	if e.enc != nil {
+		C.wrap_fn_destroy_encoder(e.enc)
+	}
+}
+
+// Encode pic
+func (e *GoEncoder) Encode(in []byte, w, h int) ([]byte, int, bool) {
+
+	var size C.int
+	var key C.int
+	cin := C.CBytes(in)
+	defer C.free(cin)
+
+	p := C.wrap_fn_encode(e.enc, cin, C.int(w), C.int(h), &size, &key)
+	defer C.free(p)
+	if p != nil && size > 0 {
+		b := C.GoBytes(p, size)
+
+		isKey := false
+		if key > 0 {
+			isKey = true
+		}
+		return b, int(size), isKey
+	}
+	return nil, 0, false
+}
diff --git a/goffmpeg.go b/goffmpeg.go
index d23bf80..dedb2bf 100644
--- a/goffmpeg.go
+++ b/goffmpeg.go
@@ -12,31 +12,6 @@
 	"unsafe"
 )
 
-const (
-	// ScaleFastBilinear SWS_FAST_BILINEAR
-	ScaleFastBilinear = 1
-	// ScaleBilinear SWS_BILINEAR
-	ScaleBilinear = 2
-	// ScaleBicubic SWS_BICUBIC
-	ScaleBicubic = 4
-	// ScaleX SWS_X
-	ScaleX = 8
-	// ScalePoint SWS_POINT
-	ScalePoint = 0x10
-	// ScaleArea SWS_AREA
-	ScaleArea = 0x20
-	// ScaleBicublin SWS_BICUBLIN
-	ScaleBicublin = 0x40
-	// ScaleGauss SWS_GAUSS
-	ScaleGauss = 0x80
-	// ScaleSinc SWS_SINC
-	ScaleSinc = 0x100
-	// ScaleLancZos SWS_LANCZOS
-	ScaleLancZos = 0x200
-	// ScaleSpline SWS_SPLINE
-	ScaleSpline = 0x400
-)
-
 var libcffmpeg C.libcffmpeg
 
 // InitFFmpeg init ffmepg
@@ -59,35 +34,23 @@
 	}
 }
 
-// Config config
-type Config struct {
-	Scale  int
-	Width  int
-	Height int
-	GB     bool
-	CPU    bool
-}
-
 // GoFFMPEG handle for c
 type GoFFMPEG struct {
 	ffmpeg C.cffmpeg
 }
 
 // New 2nd new
-func New(conf Config) *GoFFMPEG {
+func New(GB, CPU bool) *GoFFMPEG {
 
 	f := C.wrap_fn_create()
 
 	if f == nil {
 		return nil
 	}
-	if conf.Scale != 0 && conf.Width != 0 && conf.Height != 0 {
-		C.wrap_fn_scale(f, C.int(conf.Width), C.int(conf.Height), C.int(conf.Scale))
-	}
-	if conf.GB {
+	if GB {
 		C.wrap_fn_run_gb28181(f)
 	}
-	if conf.CPU {
+	if CPU {
 		C.wrap_fn_use_cpu(f)
 	}
 
@@ -97,21 +60,18 @@
 }
 
 // NewWithLog log
-func NewWithLog(conf Config, logfile string) *GoFFMPEG {
-	lf := C.CString(logfile)
+func NewWithLog(GB, CPU bool, ffmpegLog string) *GoFFMPEG {
+	lf := C.CString(ffmpegLog)
 	defer C.free(unsafe.Pointer(lf))
 
 	f := C.wrap_fn_create2(lf)
 	if f == nil {
 		return nil
 	}
-	if conf.Scale != 0 && conf.Width != 0 && conf.Height != 0 {
-		C.wrap_fn_scale(f, C.int(conf.Width), C.int(conf.Height), C.int(conf.Scale))
-	}
-	if conf.GB {
+	if GB {
 		C.wrap_fn_run_gb28181(f)
 	}
-	if conf.CPU {
+	if CPU {
 		C.wrap_fn_use_cpu(f)
 	}
 
@@ -122,7 +82,9 @@
 
 // Free free handle
 func (h *GoFFMPEG) Free() {
-	C.wrap_fn_destroy(h.ffmpeg)
+	if h.ffmpeg != nil {
+		C.wrap_fn_destroy(h.ffmpeg)
+	}
 }
 
 // Run ffmpeg
@@ -131,161 +93,4 @@
 	defer C.free(unsafe.Pointer(in))
 
 	C.wrap_fn_run(h.ffmpeg, in)
-}
-
-// FireRecorder fire recorder
-func (h *GoFFMPEG) FireRecorder(sid string, id int64) {
-	csid := C.CString(sid)
-	defer C.free(unsafe.Pointer(csid))
-	C.wrap_fn_fire_recorder(h.ffmpeg, csid, C.long(id))
-}
-
-// BuildRecorder build recorder
-func (h *GoFFMPEG) BuildRecorder(sid, output string, mind, maxd int, audio bool) {
-	out := C.CString(output)
-	defer C.free(unsafe.Pointer(out))
-	csid := C.CString(sid)
-	defer C.free(unsafe.Pointer(csid))
-
-	a := 0
-	if audio {
-		a = 1
-	}
-	C.wrap_fn_recorder(h.ffmpeg, csid, out, C.int(mind), C.int(maxd), C.int(a))
-}
-
-// GetInfoRecorder info
-func (h *GoFFMPEG) GetInfoRecorder() (string, int, string) {
-	var i C.int = -1
-
-	var id *C.char
-	var idl C.int
-
-	var p *C.char
-	var pl C.int
-
-	C.wrap_fn_info_recorder(h.ffmpeg, &i, &id, &idl, &p, &pl)
-	// if p == nil {
-	// 	return -1, ""
-	// }
-	gID := C.GoString(id)
-	C.free(unsafe.Pointer(id))
-	path := C.GoString(p)
-	C.free(unsafe.Pointer(p))
-
-	// fmt.Println("Go get info : ", path, " len: ", l)
-
-	return gID, int(i), path
-}
-
-// BuildDecoder build decoder
-func (h *GoFFMPEG) BuildDecoder() {
-	C.wrap_fn_decoder(h.ffmpeg)
-}
-
-// GetPicDecoder get pic from decoder
-func (h *GoFFMPEG) GetPicDecoder() ([]byte, int, int, int64) {
-	var width C.int
-	var height C.int
-	var fid C.long
-
-	p := C.wrap_fn_decoder_pic(h.ffmpeg, &width, &height, &fid)
-	if width == 0 && height == 0 {
-		return nil, 0, 0, 0
-	}
-	defer C.free(unsafe.Pointer(p))
-	d := C.GoBytes(p, width*height*3)
-	wid := int(width)
-	hei := int(height)
-	gfid := int64(fid)
-	return d, wid, hei, gfid
-}
-
-//GetAVPacket get AVPacket
-func (h *GoFFMPEG) GetAVPacket() ([]byte, int, int) {
-	var key C.int
-	var size C.int
-
-	p := C.wrap_fn_get_avpacket(h.ffmpeg, &size, &key)
-	if size <= 0 {
-		return nil, 0, -1
-	}
-	defer C.free(unsafe.Pointer(p))
-	d := C.GoBytes(p, size)
-	s := int(size)
-	k := int(key)
-
-	return d, s, k
-}
-
-/////////////// for decoder
-
-// Decode decode jpeg file
-// return val: -1 open error; -2, find stream error; -3, converter create error
-func Decode(input string, gb bool) ([]byte, int, int) {
-	in := C.CString(input)
-	defer C.free(unsafe.Pointer(in))
-
-	withGB := 0
-	if gb {
-		withGB = 1
-	}
-
-	var width C.int
-	var height C.int
-	p := C.wrap_fn_decode(in, C.int(withGB), &width, &height)
-	defer C.free(p)
-
-	if width > 0 && height > 0 {
-		data := C.GoBytes(p, width*height*3)
-		wid := int(width)
-		hei := int(height)
-		return data, wid, hei
-	}
-	return nil, int(width), int(height)
-}
-
-///////////////for encoder
-
-// GoEncoder encoder
-type GoEncoder struct {
-	enc C.cencoder
-}
-
-// NewEncoder encoder
-func NewEncoder(w, h, fps, br, sFlag, gi int) *GoEncoder {
-	if w <= 0 || h <= 0 {
-		return nil
-	}
-
-	return &GoEncoder{
-		enc: C.wrap_fn_create_encoder(C.int(w), C.int(h), C.int(fps), C.int(br), C.int(sFlag), C.int(gi)),
-	}
-}
-
-// Free free
-func (e *GoEncoder) Free() {
-	C.wrap_fn_destroy_encoder(e.enc)
-}
-
-// Encode pic
-func (e *GoEncoder) Encode(in []byte, w, h int) ([]byte, int, bool) {
-
-	var size C.int
-	var key C.int
-	cin := C.CBytes(in)
-	defer C.free(cin)
-
-	p := C.wrap_fn_encode(e.enc, cin, C.int(w), C.int(h), &size, &key)
-	defer C.free(p)
-	if p != nil && size > 0 {
-		b := C.GoBytes(p, size)
-
-		isKey := false
-		if key > 0 {
-			isKey = true
-		}
-		return b, int(size), isKey
-	}
-	return nil, 0, false
 }
diff --git a/gojpeg.go b/gojpeg.go
new file mode 100644
index 0000000..6cc855d
--- /dev/null
+++ b/gojpeg.go
@@ -0,0 +1,36 @@
+package goffmpeg
+
+/*
+#include <stdlib.h>
+#include "libcffmpeg.h"
+*/
+import "C"
+
+import "unsafe"
+
+/////////////// for decoder
+
+// Decode decode jpeg file
+// return val: -1 open error; -2, find stream error; -3, converter create error
+func Decode(input string, gb bool) ([]byte, int, int) {
+	in := C.CString(input)
+	defer C.free(unsafe.Pointer(in))
+
+	withGB := 0
+	if gb {
+		withGB = 1
+	}
+
+	var width C.int
+	var height C.int
+	p := C.wrap_fn_decode(in, C.int(withGB), &width, &height)
+	defer C.free(p)
+
+	if width > 0 && height > 0 {
+		data := C.GoBytes(p, width*height*3)
+		wid := int(width)
+		hei := int(height)
+		return data, wid, hei
+	}
+	return nil, int(width), int(height)
+}
diff --git a/gorec.go b/gorec.go
new file mode 100644
index 0000000..dcf0f5e
--- /dev/null
+++ b/gorec.go
@@ -0,0 +1,54 @@
+package goffmpeg
+
+/*
+#include <stdlib.h>
+#include "libcffmpeg.h"
+*/
+import "C"
+
+import "unsafe"
+
+// FireRecorder fire recorder
+func (h *GoFFMPEG) FireRecorder(sid string, id int64) {
+	csid := C.CString(sid)
+	defer C.free(unsafe.Pointer(csid))
+	C.wrap_fn_fire_recorder(h.ffmpeg, csid, C.long(id))
+}
+
+// BuildRecorder build recorder
+func (h *GoFFMPEG) BuildRecorder(sid, output string, mind, maxd int, audio bool) {
+	out := C.CString(output)
+	defer C.free(unsafe.Pointer(out))
+	csid := C.CString(sid)
+	defer C.free(unsafe.Pointer(csid))
+
+	a := 0
+	if audio {
+		a = 1
+	}
+	C.wrap_fn_recorder(h.ffmpeg, csid, out, C.int(mind), C.int(maxd), C.int(a))
+}
+
+// GetInfoRecorder info
+func (h *GoFFMPEG) GetInfoRecorder() (string, int, string) {
+	var i C.int = -1
+
+	var id *C.char
+	var idl C.int
+
+	var p *C.char
+	var pl C.int
+
+	C.wrap_fn_info_recorder(h.ffmpeg, &i, &id, &idl, &p, &pl)
+	// if p == nil {
+	// 	return -1, ""
+	// }
+	gID := C.GoString(id)
+	C.free(unsafe.Pointer(id))
+	path := C.GoString(p)
+	C.free(unsafe.Pointer(p))
+
+	// fmt.Println("Go get info : ", path, " len: ", l)
+
+	return gID, int(i), path
+}
diff --git a/gostream.go b/gostream.go
new file mode 100644
index 0000000..6345ebd
--- /dev/null
+++ b/gostream.go
@@ -0,0 +1,26 @@
+package goffmpeg
+
+/*
+#include <stdlib.h>
+#include "libcffmpeg.h"
+*/
+import "C"
+
+import "unsafe"
+
+//GetAVPacket get AVPacket
+func (h *GoFFMPEG) GetAVPacket() ([]byte, int, int) {
+	var key C.int
+	var size C.int
+
+	p := C.wrap_fn_get_avpacket(h.ffmpeg, &size, &key)
+	if size <= 0 {
+		return nil, 0, -1
+	}
+	defer C.free(unsafe.Pointer(p))
+	d := C.GoBytes(p, size)
+	s := int(size)
+	k := int(key)
+
+	return d, s, k
+}
diff --git a/libcffmpeg.c b/libcffmpeg.c
index 69fcbb9..2414a16 100644
--- a/libcffmpeg.c
+++ b/libcffmpeg.c
@@ -25,8 +25,6 @@
         release_if_err(fn_destroy, lib);
         fn_run = (lib_cffmpeg_run)dlsym(lib, "c_ffmpeg_run");
         release_if_err(fn_run, lib);
-        fn_scale = (lib_cffmpeg_scale)dlsym(lib, "c_ffmpeg_scale");
-        release_if_err(fn_scale, lib);
         fn_gb28181 = (lib_cffmpeg_gb28181)dlsym(lib, "c_ffmpeg_run_gb28181");
         release_if_err(fn_gb28181, lib);
         fn_cpu = (lib_cffmpeg_cpu)dlsym(lib, "c_ffmepg_use_cpu");
@@ -52,6 +50,16 @@
         release_if_err(fn_destroy_encoder, lib);
         fn_encode = (lib_cffmpeg_encode)dlsym(lib, "c_ffmpeg_encode");
         release_if_err(fn_encode, lib);
+
+        fn_create_conv = (lib_cffmpeg_create_conv)dlsym(lib, "c_ffmpeg_create_conv");
+        release_if_err(fn_create_conv, lib);
+        fn_destroy_conv = (lib_cffmpeg_destroy_conv)dlsym(lib, "c_ffmpeg_destroy_conv");
+        release_if_err(fn_destroy_conv, lib);
+        fn_conv = (lib_cffmpeg_conv)dlsym(lib, "c_ffmpeg_conv");
+        release_if_err(fn_conv, lib);
+
+        fn_gpu_conv = (lib_gpu_conv)dlsym(lib, "c_gpu_conv");
+        release_if_err(fn_gpu_conv, lib);
 
     }else{
         printf("dlopen - %s\n", dlerror());  
@@ -81,10 +89,6 @@
     fn_run(h, input);
 }
 
-void wrap_fn_scale(const cffmpeg h, const int wid, const int hei, const int flags){
-    fn_scale(h, wid, hei, flags);
-}
-
 void wrap_fn_run_gb28181(const cffmpeg h){
     fn_gb28181(h);
 }
@@ -109,8 +113,8 @@
     fn_decoder(h);
 }
 
-void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei, int64_t *id){
-    return fn_decoder_pic(h, wid, hei, id);
+void* wrap_fn_decoder_pic(const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id){
+    return fn_decoder_pic(h, wid, hei, format, length, id);
 }
 
 void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key){
@@ -120,6 +124,10 @@
 // return val: -1 open error; -2, find stream error; -3, converter create error
 void* wrap_fn_decode(const char* file, const int gb, int* wid, int* hei){
     return fn_decode(file, gb, wid, hei);
+}
+
+void* wran_fn_gpu_conv(void *in, const int w, const int h, const int dst_w, const int dst_h, int *length){
+    return fn_gpu_conv(in, w, h, dst_w, dst_h, length);
 }
 
 // for encoder
@@ -141,3 +149,16 @@
     *key = 0;
     return NULL;
 }
+
+// for conv
+cconv wrap_fn_create_conv(const int srcW, const int srcH, const int srcFormat,
+                          const int dstW, const int dstH, const int flag){
+    return fn_create_conv(srcW, srcH, srcFormat, dstW, dstH, flag);
+}
+
+void wrap_fn_destroy_conv(const cconv h){
+    fn_destroy_conv(h);
+}
+void* wrap_fn_conv(const cconv h, uint8_t *in){
+    return fn_conv(h, in);
+}
diff --git a/libcffmpeg.h b/libcffmpeg.h
index 5b43da3..44d82b2 100644
--- a/libcffmpeg.h
+++ b/libcffmpeg.h
@@ -14,22 +14,21 @@
 typedef cffmpeg(*lib_cffmpeg_create2)(const char*);
 typedef void (*lib_cffmpeg_destroy)(const cffmpeg);
 typedef void (*lib_cffmpeg_run)(const cffmpeg, const char*);
-typedef void (*lib_cffmpeg_scale)(const cffmpeg, const int, const int, const int);
 typedef void (*lib_cffmpeg_gb28181)(const cffmpeg);
 typedef void (*lib_cffmpeg_cpu)(const cffmpeg);
 typedef void (*lib_cffmpeg_recorder)(const cffmpeg, const char*, const char*, int, int, int);
 typedef void (*lib_cffmpeg_fire_recorder)(const cffmpeg, const char*, const int64_t);
 typedef void (*lib_cffmpeg_info_recorder)(const cffmpeg, int*, char**, int*, char**, int*);
 typedef void (*lib_cffmpeg_decoder)(const cffmpeg);
-typedef void*(*lib_cffmpeg_pic)(const cffmpeg, int*, int*, int64_t*);
+typedef void*(*lib_cffmpeg_pic)(const cffmpeg, int*, int*, int*, int*, int64_t*);
 typedef void*(*lib_cffmpeg_avpacket)(const cffmpeg, int*, int*);
 typedef void*(*lib_cffmpeg_decode)(const char*, const int, int*, int*);
+typedef void*(*lib_gpu_conv)(void*, const int, const int, const int, const int, int *);
 
 static lib_cffmpeg_create              fn_create = NULL;
 static lib_cffmpeg_create2             fn_create2 = NULL;
 static lib_cffmpeg_destroy             fn_destroy = NULL;
 static lib_cffmpeg_run                 fn_run = NULL;
-static lib_cffmpeg_scale               fn_scale = NULL;
 static lib_cffmpeg_gb28181             fn_gb28181 = NULL;
 static lib_cffmpeg_cpu                 fn_cpu = NULL;
 static lib_cffmpeg_recorder            fn_recorder = NULL;
@@ -39,6 +38,7 @@
 static lib_cffmpeg_pic                 fn_decoder_pic = NULL;
 static lib_cffmpeg_avpacket            fn_get_avpacket = NULL;
 static lib_cffmpeg_decode              fn_decode = NULL;
+static lib_gpu_conv                    fn_gpu_conv = NULL;
 
 typedef void* libcffmpeg;
 libcffmpeg init_libcffmpeg(const char *so_file);
@@ -48,21 +48,18 @@
 cffmpeg wrap_fn_create2(const char *logfile);
 void wrap_fn_destroy(const cffmpeg h);
 void wrap_fn_run(const cffmpeg h, const char* input);
-void wrap_fn_scale(const cffmpeg h, const int wid, const int hei, const int flags);
 void wrap_fn_run_gb28181(const cffmpeg h);
 void wrap_fn_use_cpu(const cffmpeg h);
 void wrap_fn_recorder(const cffmpeg h, const char* id, const char* dir, int mind, int maxd, int audio);
 void wrap_fn_fire_recorder(const cffmpeg h, const char *sid, const int64_t id);
 void wrap_fn_info_recorder(const cffmpeg, int* index, char** recid, int* recidLen, char** fpath, int* pathLen);
 void wrap_fn_decoder(const cffmpeg h);
-void* wrap_fn_decoder_pic(const cffmpeg h, int* wid, int* hei, int64_t *id);
+void* wrap_fn_decoder_pic(const cffmpeg h, int *wid, int *hei, int *format, int *length, int64_t *id);
 void* wrap_fn_get_avpacket(const cffmpeg h, int* size, int* key);
 void* wrap_fn_decode(const char* file, const int gb, int* wid, int* hei);
-
-
+void* wran_fn_gpu_conv(void *in, const int w, const int h, const int dst_w, const int dst_h, int *length);
 // for encoder
 typedef void* cencoder;
-
 typedef cencoder (*lib_cffmpeg_create_encoder)(const int w, const int h, const int fps, const int br, const int scale_flag, const int gi);
 typedef void (*lib_cffmpeg_destroy_encoder)(cencoder h);
 typedef int (*lib_cffmpeg_encode)(cencoder hdl, uint8_t *in, const int w, const int h, uint8_t **out, int *size, int *key);
@@ -75,6 +72,22 @@
 void wrap_fn_destroy_encoder(const cencoder h);
 void* wrap_fn_encode(cencoder hdl, void *in, const int w, const int h, int *out_size, int *key);
 
+
+// for conv
+typedef void *cconv;
+typedef cconv (*lib_cffmpeg_create_conv)(const int, const int, const int, const int, const int, const int);
+typedef void* (*lib_cffmpeg_conv)(const cconv, uint8_t *in);
+typedef void (*lib_cffmpeg_destroy_conv)(const cconv);
+
+static lib_cffmpeg_create_conv fn_create_conv = NULL;
+static lib_cffmpeg_destroy_conv fn_destroy_conv = NULL;
+static lib_cffmpeg_conv fn_conv = NULL;
+
+cconv wrap_fn_create_conv(const int srcW, const int srcH, const int srcFormat,
+                          const int dstW, const int dstH, const int flag);
+void wrap_fn_destroy_conv(const cconv h);
+void* wrap_fn_conv(const cconv h, uint8_t *in);
+
 #ifdef __cplusplus
 }
 #endif

--
Gitblit v1.8.0