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);
}
}
}