本事实例是在英伟达官方实例上做的修改,可以将每一帧转换为图片区别为(YUV和RGB)用于智能识别
一直用ffmpeg解码h264视频流,有幸接触一下硬解码简单的做一下笔记
1.首先配置deepstream开发环境,必须要用ubuntu环境(需要P4,P40显卡)。
这里不再赘述,直接下载需要的sdk配置到临时环境变量即可
例:
export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64/:$LD_LIBRARY_PATH
2.运行官方sdk带的例子
直接自己新建makefile文件,用到了opencv库/cuda/deepstream/cudnn&tensorrt/videosdk等库
CC = g++ -std=c++11
CFLAGS = -I/usr/local/cuda-9.0/include -I../common
LDFLAGS = -L/usr/local/cuda-9.0/lib64 -L/home/TensorRT/targets/x86_64-linux-gnu/lib
LDFLAGS += -L/home/TensorRT/Bin -L/home/deepstream/lib -L. -L/usr/local/lib
LDFLAGS += -ldeepstream -lpthread -lcudart -lnvparsers -lnvinfer -lcudnn -lcublas -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_text -lopencv_calib3d -lopencv_freetype -lopencv_tracking
SRC = nvCuvidPerf.cpp
all:
$(CC) $(CFLAGS) $(SRC) $(LDFLAGS) -o dech264_to_rgb
clean:
rm -rf *.o dech264_to_rgb
3.跑通之后,就可以在官方案例中编写解码获取数据的程序
官方提供的回调函数如下:
typedef void (*DECODER_CALLBACK)(void *pUserData, DEC_OUTPUT *decOutput);
在官方案例的这个位置添加设置回调函数,红色字体是自定义的函数用于解码并获取需要的数据
//为woker提供profiers
#if 1
for (int i = 0; i < g_nChannels; ++i) {
g_vpDecProfilers.push_back(new DecodeProfiler);
//先设置毁掉在启动解码
pDeviceWorker->setDecCallback((void*)&strFiler, outputData, i);
pDeviceWorker->setDecodeProfiler(g_vpDecProfilers[i], i);
}
#endif
outputData, i);
pDeviceWorker->setDecodeProfiler(g_vpDecProfilers[i], i);
}
#endif
首先我们来获取YUV数据,只获取第400帧的数据,写成文件可以用YUVViewer这个程序打开查看,如果不是破解版的YUVViewer的话需要打开文件选择文件格式为YUV然后设置宽高图片才能显示
int g_nIndex = 0;
void outputData(void *pData, DEC_OUTPUT *pOutData)
{
if(pOutData->dpFrame_ == NULL)
printf("输出YUV数据为空\n");
//输出用户信息
//std::string strFiler = *(std::string*)pData;
//cout << strFiler.c_str() << endl;
//在这里是测试程序,所以我只解码一帧数据
g_nIndex++;
if(g_nIndex == 400)
{
LOG_DEBUG(logger, "开始写入数据");
uint8_t *pBuf;
pBuf = (uint8_t*)malloc(pOutData->frameSize_* sizeof(uint8_t));
memset((char*)pBuf, 128, pOutData->frameSize_);
cudaStream_t cst = pOutData->stream_;
cudaMemcpyAsync(pBuf, pOutData->dpFrame_, pOutData->frameSize_, cudaMemcpyDeviceToHost, cst);
int len = fwrite(pBuf, 1, pOutData->frameSize_, g_fp);
cout << len << endl;
}
g_nIndex++;
}
接下来我们在我们来解码获取RGB格式文件,由于哪里都找不到资料,根据自己的理解写出来的有不成功,所以一点一点蒙的,可以用
int g_nIndex = 0;
void outputData(void *pData, DEC_OUTPUT *pOutData)
{
if(pOutData->dpFrame_ == NULL)
printf("输出YUV数据为空\n");
g_nIndex++;
if(g_nIndex == 400)
{
LOG_DEBUG(logger, "开始写入数据");
uint8_t *pBuf;
pBuf = (uint8_t*)malloc(pOutData->frameSize_*4* sizeof(uint8_t));
memset((char*)pBuf, 128, pOutData->frameSize_);
//打印输出信息
uint8_t* devBuf;
cudaError_t cudaStatus = cudaMalloc((void**)&devBuf, pOutData->frameSize_*4*sizeof(uint8_t));
if(cudaStatus != cudaSuccess)
printf("申请空间失败\n");
cout << "开始转化文件" << endl;
//似乎转出来了,但是看不到图
//nv12_to_bgr_planar_batch(pOutData->dpFrame_, 1.5*pOutData->nWidthPixels_, (float*)devBuf, 3*pOutData->nWidthPixels_, pOutData->nWidthPixels_, pOutData->nHeightPixels_, 1, true, pOutData->stream_);
//很清晰的图片
nv12_to_bgra(pOutData->dpFrame_, pOutData->nWidthPixels_, devBuf, 4*pOutData->nWidthPixels_, pOutData->nWidthPixels_, pOutData->nHeightPixels_, pOutData->stream_);
//转成灰度图片,也是灰灰的一片
//nv12_to_gray_batch(pOutData->dpFrame_, 1.5*pOutData->nWidthPixels_, (float*)devBuf, 3*pOutData->nWidthPixels_, pOutData->nWidthPixels_, pOutData->nHeightPixels_, 1, pOutData->stream_);
cudaMemcpyAsync(pBuf, devBuf, pOutData->frameSize_*4*sizeof(uint8_t), cudaMemcpyDeviceToHost, pOutData->stream_);
//写入来一张倒着的图片很清晰
int len = fwrite(pBuf, 1, pOutData->frameSize_*4*sizeof(uint8_t), g_fp);
cout << "写入文件大小" << len << endl;
//使用opencv转化并显示图片
IplImage *pImg = cvCreateImage(cvSize(pOutData->nWidthPixels_, pOutData->nHeightPixels_), IPL_DEPTH_8U, 4);
memcpy(pImg->imageData, pBuf, pOutData->nWidthPixels_*pOutData->nHeightPixels_* 4);
cvNamedWindow("显示图片", 1);
cvShowImage("显示图片", pImg);
cvSaveImage("1.jpg", pImg);
cvReleaseImage(&pImg);
}
}
加QQ群一起交流学习音视频开发:476513431