DxDecoderWrap.cpp 8.02 KB
#include <chrono>

#include "DxDecoderWrap.h"
#include "ColorSpace.h"

#include "sfx_depend_inc.h"
#include "opencv2/opencv.hpp"

#include <iostream>

#ifndef SFX_STD_LOG_DONE
#define SFX_STD_LOG_DONE         "done"
#endif


static void CUDADecoder_Callback(const void * userPtr, void * buf, unsigned int size, int width, int height, unsigned long long timestamp){
	DxDecoderWrap* _this = (DxDecoderWrap*)userPtr;
	if(nullptr != _this){
		_this->DxCUDADecoderCallback(buf, size, width, height, timestamp);
	}
}

static int DecoderLog_Callback( const void * userPtr, DxLogLevel level, const char * log, unsigned int logLen ){
	DxDecoderWrap* _this = (DxDecoderWrap*)userPtr;
	if(nullptr != _this){
		_this->DxDecoderLogCallback(level, log, logLen);
	}
}

static long get_cur_time_ms() {
	chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro
		= chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
	return tpMicro.time_since_epoch().count();
}

DxDecoderWrap::DxDecoderWrap(  )
{
	m_pDec = nullptr;
	m_skip = 0;

	return;
}


int frame_nb = 0;

DxDecoderWrap::~DxDecoderWrap()
{
	DxCloseDecoder();

	std::cout << "总帧数" << frame_nb << std::endl;

	return;
}

bool DxDecoderWrap::isStream(string sVideoFileName) {
	string target = "file://";
	int pos = sVideoFileName.find(target);
	if (pos == 0) {
		int n = target.size();
		sVideoFileName = sVideoFileName.erase(pos, n);
	}else {
		// 非file 开头,直接判为视频流
		return true;
	}
	
	pos = sVideoFileName.find_first_of('?');
	if (pos != string::npos) {
		sVideoFileName = sVideoFileName.substr(0, pos);
	}

	bool bReal = false;
	FILE* fp=fopen(sVideoFileName.c_str(),"rb");
	if(fp!=nullptr) {
		bReal = false;
		fclose(fp);
	} else {
		bReal = true;
	}

	return bReal;
}

int DxDecoderWrap::DxOpenDecoder(const DxConfig& cfg)
{
	cout << "before check: " << cfg.uri << endl;

	//判断是否为实时流
	m_bReal = isStream(cfg.uri);

	cout << "before check: " << cfg.uri << endl;

	m_nums = 0;
	m_bPause = false;

	m_pDec = new SfxDecoder();
	if ( nullptr == m_pDec ) {
		return -1;
	}

	DxDecoderConfig m_cfg;
	m_cfg.userPtr = this;
	m_cfg.escbk = CUDADecoder_Callback;
	m_cfg.logcbk = DecoderLog_Callback;
	m_cfg.log_all = cfg.log_all;
	m_cfg.log_user_ptr = cfg.log_user_ptr;
	m_cfg.devId = cfg.devId;
	m_cfg.uri = cfg.uri;
	m_cfg.dec_name = cfg.name;

	m_skip = cfg.skip_frame;
	m_name = cfg.name;
	m_devId = cfg.devId;

	cout << "before open: " << m_cfg.uri << endl;

	bool bRet= m_pDec->OpenDecoder(m_cfg);
    if (bRet)
    {
		m_bRun = true;
		LOG_INFO("[{}][{}]- 解码器初始化成功", m_name.c_str(), m_cfg.uri);
		return 0;
    }
    
    // 创建失败,关闭解码器
	m_pDec->CloseDecoder();
    delete m_pDec;
	m_pDec = nullptr;

    LOG_ERROR("[{}][{}]- 解码器初始化失败!", m_name.c_str(), m_cfg.uri);
    return -1;
}

int DxDecoderWrap::DxCloseDecoder() {
	if (m_pDec)
	{
		m_pDec->CloseDecoder();
		delete m_pDec;
		m_pDec = nullptr;
	}

	m_queue_frames_mutex.lock();
	while (m_queue_frames.size() > 0) {
		DxGPUFrame decodedFrame = m_queue_frames.front();
		if (decodedFrame.frame) {
			cudaFree(decodedFrame.frame);
			decodedFrame.frame = nullptr;
		}
		m_queue_frames.pop();
	}
	m_queue_frames_mutex.unlock();
}

bool DxDecoderWrap::DxDecoderIsFinished() {
	if(m_pDec) {
		return m_pDec->isFinished();
	}

	return true;
}

int DxDecoderWrap::DxGetResolution( int &width, int &height ) {
	width = m_width;
	height = m_height;
}

bool DxDecoderWrap::DxFrameIsEmpty()
{
	m_queue_frames_mutex.lock();
	int count = m_queue_frames.size();
	m_queue_frames_mutex.unlock();

	return 0 == count;
}

int DxDecoderWrap::DxLockFrame(DxGPUFrame& frame)
{
	std::lock_guard<std::mutex> l(m_queue_frames_mutex);
	
	if(m_queue_frames.size() <= 0) {
		return -1;
	}
	frame = m_queue_frames.front();
	m_queue_frames.pop();

	return 0;
}

DxGPUFrame DxDecoderWrap::DxGetFrame()
{
	std::lock_guard<std::mutex> l(m_queue_frames_mutex);
	
	DxGPUFrame frame;
	if(m_queue_frames.size() <= 0) {
		return frame;
	}
	frame = m_queue_frames.front();
	m_queue_frames.pop();

	return frame;
}

int DxDecoderWrap::PauseDecoder()
{
	m_bPause = true;
	return 0;
}

int DxDecoderWrap::ResumeDecoder()
{
	m_bPause = false;
	return 0;
}

bool DxDecoderWrap::DxDecoderIsRun() const
{
	return m_bRun;
}

unsigned int DxDecoderWrap::DxGetFrameCount() {
	if(m_pDec) {
		return m_pDec->GetFrameCount();
	}
	return 1;
}

int DxDecoderWrap::DxDecoderLogCallback(DxLogLevel level, const char * log, unsigned int logLen )
{
	int index = 0;

	if ( DX_LOG_LEVEL_FATAL == level )
	{
		return 0;
	}
	
	if (DX_LOG_LEVEL_IMPORTANT == level) {
		if (0 == memcmp( log, SFX_STD_LOG_DONE, strlen(SFX_STD_LOG_DONE) + 1)) {
			m_bRun = false;
			return 0;
		}

		if (0 == memcmp( log, "progress ", strlen( "progress ") ) ) {
			//printf("%s\n", log); //打印进度 格式:progress 100
		}
	}

	if ( DX_LOG_LEVEL_CLEANUP == level ) {
		
		LOG_INFO( "{}", log );
		m_bRun = false;
	}

	return 0;
}

void DxDecoderWrap::DxCUDADecoderCallback( void * buf, unsigned int size, int width, int height, unsigned long long timestamp )
{
	if ( 0 == size ) {
		m_width = width;
		m_height = height;
		return;
	}
	
	m_nums++;

	while ( m_bRun ) {
		if ( m_bPause ) {
			if ( m_bReal ) {
				return;
			}
			std::this_thread::sleep_for(std::chrono::milliseconds(50));
			continue;
		}
		break;
	}

	if ( !m_bRun ) {
		return;
	}
	
	if ( m_skip > 0 ) {
		if ( m_nums % m_skip ) {
			return;
		}
	}

	while(m_bRun) {
		m_queue_frames_mutex.lock();
		if(m_queue_frames.size() < 3) {
			// 入队

			cudaSetDevice(m_devId);
			size_t  rgbSize = 3 * m_width * m_height * sizeof(unsigned char);
			unsigned char *pHwData = nullptr;
			cudaError_t cudaStatus = cudaMalloc((void **)&pHwData, rgbSize);
			if (cudaStatus != cudaSuccess) {
				m_queue_frames_mutex.unlock();
				LOG_ERROR("[{}]- cudaMalloc failed !!!", m_name.c_str());
				return ;
			}

			// Nv12ToColor24<BGR24>((unsigned char*)buf, m_width, pHwData, 3 * m_width, m_width, m_height, 0);


			cudaStatus = cudaMemcpy(pHwData, buf, rgbSize * sizeof(unsigned char), cudaMemcpyDeviceToDevice);


			// int rgb_size = 3 * m_width * m_height;
			// unsigned char* cpu_data = new unsigned char[rgb_size];
			// cudaStatus = cudaMemcpy(cpu_data, pHwData, rgb_size * sizeof(unsigned char), cudaMemcpyDeviceToHost);

			// // if (timestamp > 245  && timestamp < 255)
			// // {
			// // 	string file_name = "./nv12/"+to_string(timestamp) + ".txt";
			// // 	FILE* fp=fopen(file_name.c_str(),"wb");
			// // 	fwrite(cpu_data, rgb_size, 1, fp);
			// // 	fclose(fp);
			// // }

			// cv::Mat img(m_height, m_width, CV_8UC3, cpu_data);
			// cv::imwrite("test.jpg", img);
			// delete[] cpu_data;
			// cpu_data = nullptr;


			DxGPUFrame frame;
			frame.width = m_width;
			frame.height = m_height;
			frame.size = m_width;
			frame.frame = pHwData;
			frame.timestamp = timestamp;
			frame.dec_name = m_name;

			m_queue_frames.push(frame);
			m_queue_frames_mutex.unlock();

			frame_nb++;

			std::cout << "in queue " << frame_nb << std::endl;
			break;
		} else {
			m_queue_frames_mutex.unlock();
			if (m_bReal) {
				// 实时流不等待,直接弃帧
				return;
			}

			// std::cout << "waiting queue " << frame_nb << std::endl;
			std::this_thread::sleep_for(std::chrono::milliseconds(10));
		}
	}


	//int width = m_frames.width;
	//int height = m_frames.height;

	//size_t  rgbSize = 3 * width * height * sizeof(unsigned char);
	//unsigned char* pHwData = nullptr;
	//cudaStatus = cudaMalloc((void**)&pHwData, rgbSize);
	//if (cudaStatus != cudaSuccess) {
	//	//LOG_ERROR("[{}]- cudaMalloc failed !!!", m_name.c_str());
	//	return;
	//}

	//Nv12ToColor24<BGR24>((unsigned char*)m_frames.frames[m_frames.write].frame, width, pHwData, 3 * width, width, height, 0);


	//int rgb_size = 3 * width * height;
	//unsigned char* cpu_data = new unsigned char[rgb_size];
	//cudaStatus = cudaMemcpy(cpu_data, pHwData, rgb_size * sizeof(unsigned char), cudaMemcpyDeviceToHost);
	//cv::Mat img(height, width, CV_8UC3, cpu_data);
	////cv::imwrite("test.jpg", img);
	//cv::imshow("test", img);
	//cv::waitKey(1);
	//delete[] cpu_data;
	//cpu_data = nullptr;

	//cudaFree(pHwData);
}