【音视频开发(四)】---RGB转YUV 颜色空间转换

Android的MediaCodec编码,默认要求输入是原始视频图像格式,一般为YUV420,例如NV12, NV21。但算法库输出默认的颜色为RGB或者BGR,需要进行转化。而如果使用循环单纯用CPU转换是比较慢的,这里使用OpenCV来进行转换,OpenCV虽然也是用了CPU,但是他内部做了并行计算的优化是比较快的,例如NEON/SSE等。
 

头文件:


#include "Flow.h"
#include <thread>
#include "DmSyncQueue.h"
#include "InputData.h"

#include <atomic>

using namespace  std;

class Rgb2YuvCv : public Flow {

public:
    Rgb2YuvCv();
    ~Rgb2YuvCv();
    void Init(int width, int height, int buffNumber=10);
    void PushData(const unsigned char *data, int size, int copy, int flag=0);
    void ReleaseOuputData(); //当外部使用完缓冲工区时释放
    void UnInit();
private:
    void Loop();

    int imageW;
    int imageH;

    int mMaxBufferNumber;
    int mBufferHead;
    int mBufferTail;
    atomic<int> mBufferSize;
    unsigned char **mOutputBuffer;
};

初始化:


void Rgb2YuvCv::Init(int width, int height, int buffNumber)
{

    run = true;
    imageW = width;
    imageH = height;
    mMaxBufferNumber = buffNumber;

    mInputDataList = new DmSyncQueue<InputData_t>(mMaxBufferNumber);
    mOutputDataList = new DmSyncQueue<InputData_t>(mMaxBufferNumber);

   
    mOutputBuffer =  new unsigned char* [mMaxBufferNumber+1];
    for (int i = 0; i < mMaxBufferNumber+1; i++) {
        mOutputBuffer[i] = new unsigned char [imageW * imageH * 3];
    }

    mBufferHead = 0;
    mBufferTail = 0;
    mBufferSize.store(mMaxBufferNumber);
    mLoopThread = new std::thread(&Rgb2YuvCv::Loop, this);
}
void Rgb2YuvCv::UnInit()
{
    run = false;
    if(mLoopThread) mLoopThread->join();

    for (int i = 0; i < mMaxBufferNumber+1; i++) {
        delete [] mOutputBuffer[i] ;
    }
    delete [] mOutputBuffer ;

    SAFE_DELETE(mInputDataList);
    SAFE_DELETE(mOutputDataList);
}

数据的输入或者释放:

void Rgb2YuvCv::PushData(const unsigned char *data, int size, int copy, int flag)
{
    InputData_t input;
    if (size <= 0 ) return;
    if (copy) {
        unsigned char *newdata = new unsigned char[size];
        memcpy(newdata, data, size);
        data = newdata;
    }
    input.dataPtr = data;
    input.size = size;
    input.needRealeaseMemory = copy;
    input.flag = flag;
    mInputDataList->Put(input);
}

void Rgb2YuvCv::ReleaseOuputData()
{
    mBufferTail = (mBufferTail + 1) % mMaxBufferNumber;
    mBufferSize++;
}

图像数据转换工作线程:


void Rgb2YuvCv::Loop()
{
    unsigned char *buffer ;
    while(run) {
        if(mBufferSize.load() == 0) {
            usleep(1000);
            continue;
        }
        InputData_t input;
        if(mInputStreamDataList == NULL) {
            if(!mInputDataList->Take(input)) continue;
        } else {
            if(!mInputStreamDataList->Take(input)) continue;
        }
        buffer = mOutputBuffer[mBufferHead];
        //DM_NATIVE_ERR_PRINT("-------- Rgb2YuvCv %dx%d size= %p %d %p--------\n",imageW,imageH, input.dataPtr, input.size, buffer);

        //转码
        cv::Mat yuvImg(imageH*1.5, imageW,CV_8UC1, (void *)buffer);
        // rgbImg.data = buffer;
        cv::Mat rgbImg(imageH, imageW, CV_8UC3,  (void *)input.dataPtr);
        // yuvImg.data = yuvImg.data;

        mBufferHead = (mBufferHead + 1) % mMaxBufferNumber;
        mBufferSize--;

        //memcpy(yuvImg.data, *iter, decoder.mYUVSize);
        //DM_NATIVE_ERR_PRINT("-------- cvtColor start--------\n");
        cv::cvtColor(rgbImg, yuvImg , CV_RGB2YUV_I420);
        //DM_NATIVE_ERR_PRINT("-------- cvtColor done--------\n");
        InputData_t output;
        output.dataPtr = buffer;
        output.size = imageH * imageW * 1.5;
        output.flag = input.flag;
        output.needRealeaseMemory = false;
        DM_NATIVE_DEBUG_PRINT("-------- Rgb2YuvCv %dx%d size= %p %d %p flag=%d--------\n",imageW,imageH, input.dataPtr, input.size, buffer, output.flag);
        mOutputDataList->Put(output);
        CALLBACK_InputDataFinished(input);
        if (input.needRealeaseMemory) {
            SAFE_DELETE_ARRAY(input.dataPtr);
        }
    }
}

上一篇:Qt移植到ARN


下一篇:Docker-安装GitLab