初始化解码器:
void VideoDecoder::Init(int width, int height, int buffNumber)
{
DM_NATIVE_PRINT("VideoDecoder::Init Start... %dx%d", width, height);
imageW = width;
imageH = height;
//带解码图像队列个数
mMaxBufferNumber = buffNumber;
mInputDataList = new DmSyncQueue<InputData_t>(buffNumber);
mOutputDataList = new DmSyncQueue<InputData_t>(buffNumber);
//解码器为H264解码类型
const char* mine = "video/avc";
//创建解码器
mMediaCodec = AMediaCodec_createDecoderByType(mine);
AMediaFormat* videoFormat = AMediaFormat_new();
AMediaFormat_setString(videoFormat, "mime", mine);
AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_WIDTH, width); // 视频宽度
AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_HEIGHT, height); // 视频高度
//设置PPS和SPS
if (videoCsd0 != NULL) {
AMediaFormat_setBuffer(videoFormat, "csd-0", videoCsd0, videoCsd0Size);
DM_NATIVE_PRINT(" videoCsd0 = %d\n", videoCsd0Size);
}
if (videoCsd1 != NULL) {
AMediaFormat_setBuffer(videoFormat, "csd-1", videoCsd1, videoCsd1Size);
DM_NATIVE_PRINT(" videoCsd1 = %d\n", videoCsd1Size);
}
//不需要设置图像格式
//AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, 21);
//配置解码器
media_status_t status = AMediaCodec_configure(mMediaCodec, videoFormat, NULL, NULL, 0);
if (status != AMEDIA_OK)
{
DM_NATIVE_ERR_PRINT("AMediaCodec_configure() failed with error %i for format %u", (int)status, 21);
} else {
//开始解码器状态机
status = AMediaCodec_start(mMediaCodec);
if (status != AMEDIA_OK)
{
DM_NATIVE_ERR_PRINT("AMediaCodec_start: Could not start decoder.");
}
run = true;
//创建解码线程
mLoopThread = new std::thread(&VideoDecoder::Loop, this);
}
//释放解码格式
AMediaFormat_delete(videoFormat);
DM_NATIVE_PRINT("VideoDecoder::Init Done");
}
解码器图像解码
解码线程:
void VideoDecoder::Loop()
{
while(run) {
Decode();
}
}
解码过程:
void VideoDecoder::Decode()
{
#ifndef WIN32
//获取带解码的数据
InputData_t input;
//static uint64_t m = 0;
if (mMediaCodec == NULL)
{
return;
}
if(mInputStreamDataList == NULL) {
if(!mInputDataList->Take(input)) return;
} else {
if(!mInputStreamDataList->Take(input)) return;
}
ssize_t oBufidx = -1;
size_t bufsize = 0;
AMediaCodecBufferInfo info;
uint8_t *buf = NULL;
ssize_t iBufidx = -1;
/*First put our H264 bitstream into the decoder*/
do
{
//获取解码器空闲的输入队列索引
iBufidx = AMediaCodec_dequeueInputBuffer(mMediaCodec, TIMEOUT_US);
//DM_NATIVE_DEBUG_PRINT("decoder iBufidx %d %d", iBufidx, mInputDataList.size());
if (iBufidx >= 0)
{
//获取输入队列的缓冲区
buf = AMediaCodec_getInputBuffer(mMediaCodec, iBufidx, &bufsize);
if (buf)
{
bufsize = input.size;
//填充缓冲工区
memcpy(buf, input.dataPtr, bufsize);
//DM_NATIVE_DEBUG_PRINT("Decoder iBufidx %d size=%d %02X%02X%02X%02X%02X %p", iBufidx, bufsize, buf[0],buf[1],buf[2],buf[3],buf[4], buf);
}
// DM_NATIVE_DEBUG_PRINT("Decoder iBufidx %d size=%d %02X%02X%02X%02X%02X %p", iBufidx, bufsize, input.dataPtr[0],input.dataPtr[1],input.dataPtr[2],input.dataPtr[3],input.dataPtr[4], buf);
//提交解码器解码
AMediaCodec_queueInputBuffer(mMediaCodec, iBufidx, 0, bufsize, GetTimestampUs(), 0);
//AMediaCodec_queueInputBuffer(mMediaCodec, iBufidx, 0, bufsize,m++, 0);
//释放用户图像输入队列的内存
CALLBACK_InputDataFinished(input);
if (input.needRealeaseMemory) {
SAFE_DELETE_ARRAY(input.dataPtr);
}
}
else if (iBufidx == -1)
{
break;
}
//继续查看用户队列是否还有待解码的数据
if (!mInputDataList->IsEmpty()) {
if(!mInputDataList->Take(input)) break;
} else {
break;
}
}while (true);
//等待解码器结果输出
/*secondly try to get decoded frames from the decoder, this is performed every tick*/
oBufidx = AMediaCodec_dequeueOutputBuffer(mMediaCodec, &info, 500);
//DM_NATIVE_DEBUG_PRINT("Decoder oBufidx %d", oBufidx);
while (oBufidx >= 0)
{
AMediaFormat *format;
int color = 0;
//获取解码器输出的队列缓冲区
uint8_t *buf = AMediaCodec_getOutputBuffer(mMediaCodec, oBufidx, &bufsize);
if (buf == NULL)
{
DM_NATIVE_ERR_PRINT("MediaCodecH264Dec: AMediaCodec_getOutputBuffer() returned NULL");
//continue;
}
else
{
int width = 0, height = 0;
//获取解码器解码的格式
format = AMediaCodec_getOutputFormat(mMediaCodec);
if (format != NULL)
{
AMediaFormat_getInt32(format, "width", &width);
AMediaFormat_getInt32(format, "height", &height);
AMediaFormat_getInt32(format, "color-format", &color);
AMediaFormat_delete(format);
//DM_NATIVE_DEBUG_PRINT("width=%d height=%d color=%d", width, height, color);
} else {
DM_NATIVE_ERR_PRINT("MediaCodecH264Dec: AMediaCodec_getOutputFormat() returned NULL");
}
if (width != 0 && height != 0)
{
//if (color == 21)
if (true)
{
//DM_NATIVE_DEBUG_PRINT("12121212");
#if 1
//将解码器的图像数据从缓冲区拷贝出来,并输送至下一个环节
mYUVSize = width * height * 3 / 2;
//NV12
unsigned char* outNV12 = new unsigned char[mYUVSize];
memcpy(outNV12, buf, mYUVSize);
//mOutputNV12List.push_back(outNV12);
InputData_t output;
output.dataPtr = outNV12;
output.size = mYUVSize;
output.needRealeaseMemory = true;
mOutputDataList->Put(output);
#endif
}
else
{
DM_NATIVE_DEBUG_PRINT("unknown format");
}
}
else
{
DM_NATIVE_DEBUG_PRINT("MediaCodecH264Dec: width and height are not known !");
}
}
//释放解码器的输出缓冲区
AMediaCodec_releaseOutputBuffer(mMediaCodec, oBufidx, false);
//继续查看是否有数据已经解码完成
oBufidx = AMediaCodec_dequeueOutputBuffer(mMediaCodec, &info, 500);
//DM_NATIVE_DEBUG_PRINT("Decoder oBufidx- %d", oBufidx);
}
if (oBufidx == AMEDIA_ERROR_UNKNOWN)
{
DM_NATIVE_DEBUG_PRINT("MediaCodecH264Dec: AMediaCodec_dequeueOutputBuffer() had an exception");
}
#endif // !WIN32
}
其他辅助函数:
获取时间戳:
static uint64_t GetTimestampUs() {
static uint64_t start_uptime = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
uint64_t timestamp = (tv.tv_sec * 1000000ul + tv.tv_usec);
if(start_uptime == 0) start_uptime = timestamp;
timestamp-=start_uptime;
//DM_NATIVE_PRINT("uptime:: %lld", timestamp);
return timestamp;
}
解码图像数据入队,提交到解码器:
void VideoDecoder::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 = (unsigned char *)data;
input.size = size;
input.needRealeaseMemory = copy;
input.flag = flag;
mInputDataList->Put(input);
}
去初始化:
void VideoEncoder::UnInit()
{
run = false;
if(mLoopThread) mLoopThread->join();
if(mMediaCodec) { AMediaCodec_stop(mMediaCodec); AMediaCodec_delete(mMediaCodec); }
SAFE_DELETE(mInputDataList);
SAFE_DELETE(mOutputDataList);
SAFE_DELETE(videoCfgData);
}
头文件:
#include "Flow.h"
#include <vector>
#include <thread>
#include <media/NdkMediaCodec.h>
#include "DmSyncQueue.h"
#include "InputData.h"
using namespace std;
class VideoDecoder : public Flow {
public:
VideoDecoder();
~VideoDecoder();
void SetVideoCsdInfo(uint8_t *csd0, int csd0Size, uint8_t *csd1, int csd1Size)
{
videoCsd0 = csd0;
videoCsd0Size = csd0Size;
videoCsd1 = csd1;
videoCsd1Size = csd1Size;
}
void Init(int width, int height, int buffNumber=10);
void UnInit();
void PushData(const unsigned char *data, int size, int copy, int flag=0);
//vector <unsigned char *> mOutputNV12List;
private:
AMediaCodec *mMediaCodec;
void Loop();
void Decode();
int mYUVSize;
uint8_t *videoCsd0;
int videoCsd0Size;
uint8_t *videoCsd1;
int videoCsd1Size;
};