The following program shows the flow of a transcoder from the NVIDIA's NVTranscoder project from the Video_Codec_SDK_8.0.14.
The decoder output each frame with NV12 format.
However, for my coding part, the frame I received only get the Y component channel, how can I get all the YUV components channel?
Besides, how can I write back the CUdeviceptr after some processing?
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <stdio.h>
#include <string.h>
#include "dynlink_cuda.h" // <cuda.h>
#include "VideoDecoder.h"
#include "VideoEncoder.h"
#include "../common/inc/nvUtils.h"
#include <opencv2/opencv.hpp>
#include "opencv2/gpu/gpu.hpp"
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
using namespace cv;
#ifdef _WIN32
DWORD WINAPI DecodeProc(LPVOID lpParameter)
{
CudaDecoder* pDecoder = (CudaDecoder*)lpParameter;
pDecoder->Start();
return 0;
}
#else
void* DecodeProc(void *arg)
{
CudaDecoder* pDecoder = (CudaDecoder*)arg;
pDecoder->Start();
return NULL;
}
#endif
int MatchFPS(const float fpsRatio, int decodedFrames, int encodedFrames)
{
if (fpsRatio < 1.f) {
// need to drop frame
if (decodedFrames * fpsRatio < (encodedFrames + 1)) {
return -1;
}
}
else if (fpsRatio > 1.f) {
// need to duplicate frame
int duplicate = 0;
while (decodedFrames*fpsRatio > encodedFrames + duplicate + 1) {
duplicate++;
}
return duplicate;
}
return 0;
}
void PrintHelp()
{
printf("Usage : NvTranscoder \n"
"-i <string> Specify input .h264 file\n"
"-o <string> Specify output bitstream file\n"
"\n### Optional parameters ###\n"
"-size <int int> Specify output resolution <width height>\n"
"-codec <integer> Specify the codec \n"
" 0: H264\n"
" 1: HEVC\n"
"-preset <string> Specify the preset for encoder settings\n"
" hq : nvenc HQ \n"
" hp : nvenc HP \n"
" lowLatencyHP : nvenc low latency HP \n"
" lowLatencyHQ : nvenc low latency HQ \n"
" lossless : nvenc Lossless HP \n"
"-fps <integer> Specify encoding frame rate\n"
"-goplength <integer> Specify gop length\n"
"-numB <integer> Specify number of B frames\n"
"-bitrate <integer> Specify the encoding average bitrate\n"
"-vbvMaxBitrate <integer> Specify the vbv max bitrate\n"
"-vbvSize <integer> Specify the encoding vbv/hrd buffer size\n"
"-rcmode <integer> Specify the rate control mode\n"
" 0: Constant QP mode\n"
" 1: Variable bitrate mode\n"
" 2: Constant bitrate mode\n"
" 8: low-delay CBR, high quality\n"
" 16: CBR, high quality (slower)\n"
" 32: VBR, high quality (slower)\n"
"-qp <integer> Specify qp for Constant QP mode\n"
"-i_qfactor <float> Specify qscale difference between I-frames and P-frames\n"
"-b_qfactor <float> Specify qscale difference between P-frames and B-frames\n"
"-i_qoffset <float> Specify qscale offset between I-frames and P-frames\n"
"-b_qoffset <float> Specify qscale offset between P-frames and B-frames\n"
"-deviceID <integer> Specify the GPU device on which encoding will take place\n"
"-help Prints Help Information\n\n"
);
}
int main(int argc, char* argv[])
{
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
typedef HMODULE CUDADRIVER;
#else
typedef void *CUDADRIVER;
#endif
CUDADRIVER hHandleDriver = 0;
__cu(cuInit(0, __CUDA_API_VERSION, hHandleDriver));
__cu(cuvidInit(0));
EncodeConfig encodeConfig = { 0 };
encodeConfig.endFrameIdx = INT_MAX;
encodeConfig.bitrate = 5000000;
encodeConfig.rcMode = NV_ENC_PARAMS_RC_CONSTQP;
encodeConfig.gopLength = NVENC_INFINITE_GOPLENGTH;
encodeConfig.codec = NV_ENC_H264;
encodeConfig.fps = 0;
encodeConfig.qp = 28;
encodeConfig.i_quant_factor = DEFAULT_I_QFACTOR;
encodeConfig.b_quant_factor = DEFAULT_B_QFACTOR;
encodeConfig.i_quant_offset = DEFAULT_I_QOFFSET;
encodeConfig.b_quant_offset = DEFAULT_B_QOFFSET;
encodeConfig.presetGUID = NV_ENC_PRESET_DEFAULT_GUID;
encodeConfig.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
NVENCSTATUS nvStatus = CNvHWEncoder::ParseArguments(&encodeConfig, argc, argv);
if (nvStatus != NV_ENC_SUCCESS)
{
PrintHelp();
return 1;
}
if (!encodeConfig.inputFileName || !encodeConfig.outputFileName)
{
PrintHelp();
return 1;
}
encodeConfig.fOutput = fopen(encodeConfig.outputFileName, "wb");
if (encodeConfig.fOutput == NULL)
{
PRINTERR("Failed to create \"%s\"\n", encodeConfig.outputFileName);
return 1;
}
//init cuda
CUcontext cudaCtx;
CUdevice device;
__cu(cuDeviceGet(&device, encodeConfig.deviceID));
__cu(cuCtxCreate(&cudaCtx, CU_CTX_SCHED_AUTO, device));
CUcontext curCtx;
CUvideoctxlock ctxLock;
__cu(cuCtxPopCurrent(&curCtx));
__cu(cuvidCtxLockCreate(&ctxLock, curCtx));
CudaDecoder* pDecoder = new CudaDecoder;
FrameQueue* pFrameQueue = new CUVIDFrameQueue(ctxLock);
pDecoder->InitVideoDecoder(encodeConfig.inputFileName, ctxLock, pFrameQueue, encodeConfig.width, encodeConfig.height);
int decodedW, decodedH, decodedFRN, decodedFRD, isProgressive;
pDecoder->GetCodecParam(&decodedW, &decodedH, &decodedFRN, &decodedFRD, &isProgressive);
if (decodedFRN <= 0 || decodedFRD <= 0) {
decodedFRN = 30;
decodedFRD = 1;
}
if(encodeConfig.width <= 0 || encodeConfig.height <= 0) {
encodeConfig.width = decodedW;
encodeConfig.height = decodedH;
}
float fpsRatio = 1.f;
if (encodeConfig.fps <= 0) {
encodeConfig.fps = decodedFRN / decodedFRD;
}
else {
fpsRatio = (float)encodeConfig.fps * decodedFRD / decodedFRN;
}
encodeConfig.pictureStruct = (isProgressive ? NV_ENC_PIC_STRUCT_FRAME : 0);
pFrameQueue->init(encodeConfig.width, encodeConfig.height);
VideoEncoder* pEncoder = new VideoEncoder(ctxLock);
assert(pEncoder->GetHWEncoder());
nvStatus = pEncoder->GetHWEncoder()->Initialize(cudaCtx, NV_ENC_DEVICE_TYPE_CUDA);
if (nvStatus != NV_ENC_SUCCESS)
return 1;
encodeConfig.presetGUID = pEncoder->GetHWEncoder()->GetPresetGUID(encodeConfig.encoderPreset, encodeConfig.codec);
printf("Encoding input : \"%s\"\n", encodeConfig.inputFileName);
printf(" output : \"%s\"\n", encodeConfig.outputFileName);
printf(" codec : \"%s\"\n", encodeConfig.codec == NV_ENC_HEVC ? "HEVC" : "H264");
printf(" size : %dx%d\n", encodeConfig.width, encodeConfig.height);
printf(" bitrate : %d bits/sec\n", encodeConfig.bitrate);
printf(" vbvMaxBitrate : %d bits/sec\n", encodeConfig.vbvMaxBitrate);
printf(" vbvSize : %d bits\n", encodeConfig.vbvSize);
printf(" fps : %d frames/sec\n", encodeConfig.fps);
printf(" rcMode : %s\n", encodeConfig.rcMode == NV_ENC_PARAMS_RC_CONSTQP ? "CONSTQP" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_VBR ? "VBR" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_CBR ? "CBR" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_VBR_MINQP ? "VBR MINQP (deprecated)" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ ? "CBR_LOWDELAY_HQ" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_CBR_HQ ? "CBR_HQ" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_VBR_HQ ? "VBR_HQ" : "UNKNOWN");
if (encodeConfig.gopLength == NVENC_INFINITE_GOPLENGTH)
printf(" goplength : INFINITE GOP \n");
else
printf(" goplength : %d \n", encodeConfig.gopLength);
printf(" B frames : %d \n", encodeConfig.numB);
printf(" QP : %d \n", encodeConfig.qp);
printf(" preset : %s\n", (encodeConfig.presetGUID == NV_ENC_PRESET_LOW_LATENCY_HQ_GUID) ? "LOW_LATENCY_HQ" :
(encodeConfig.presetGUID == NV_ENC_PRESET_LOW_LATENCY_HP_GUID) ? "LOW_LATENCY_HP" :
(encodeConfig.presetGUID == NV_ENC_PRESET_HQ_GUID) ? "HQ_PRESET" :
(encodeConfig.presetGUID == NV_ENC_PRESET_HP_GUID) ? "HP_PRESET" :
(encodeConfig.presetGUID == NV_ENC_PRESET_LOSSLESS_HP_GUID) ? "LOSSLESS_HP" : "LOW_LATENCY_DEFAULT");
printf("\n");
nvStatus = pEncoder->GetHWEncoder()->CreateEncoder(&encodeConfig);
if (nvStatus != NV_ENC_SUCCESS)
return 1;
nvStatus = pEncoder->AllocateIOBuffers(&encodeConfig);
if (nvStatus != NV_ENC_SUCCESS)
return 1;
unsigned long long lStart, lEnd, lFreq;
NvQueryPerformanceCounter(&lStart);
//start decoding thread
#ifdef _WIN32
HANDLE decodeThread = CreateThread(NULL, 0, DecodeProc, (LPVOID)pDecoder, 0, NULL);
#else
pthread_t pid;
pthread_create(&pid, NULL, DecodeProc, (void*)pDecoder);
#endif
//start encoding thread
int frmProcessed = 0;
int frmActual = 0;
while(!(pFrameQueue->isEndOfDecode() && pFrameQueue->isEmpty()) ) {
CUVIDPARSERDISPINFO pInfo;
if(pFrameQueue->dequeue(&pInfo)) {
CUdeviceptr dMappedFrame = 0;
unsigned int pitch;
CUVIDPROCPARAMS oVPP = { 0 };
oVPP.progressive_frame = pInfo.progressive_frame;
oVPP.second_field = 0;
oVPP.top_field_first = pInfo.top_field_first;
oVPP.unpaired_field = (pInfo.progressive_frame == 1 || pInfo.repeat_first_field <= 1);
cuvidMapVideoFrame(pDecoder->GetDecoder(), pInfo.picture_index, &dMappedFrame, &pitch, &oVPP);
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
gpu::GpuMat dimg(cv::Size(decodedW, decodedH), CV_8UC1, (void*)(dMappedFrame), pitch);
gpu::GpuMat blurImg;
gpu::GaussianBlur(dimg, blurImg, cv::Size(5, 5), 0);
cv::Mat img;
dimg.download(img);
cvtColor(img, img, CV_YUV2RGB_NV12);
cv::imshow("Decoded Frame", img);
imwrite("C:\\test\\video1.bmp", img);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
EncodeFrameConfig stEncodeConfig = { 0 };
NV_ENC_PIC_STRUCT picType = (pInfo.progressive_frame || pInfo.repeat_first_field >= 2 ? NV_ENC_PIC_STRUCT_FRAME :
(pInfo.top_field_first ? NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM : NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP));
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
stEncodeConfig.dptr = (CUdeviceptr)img.data; //dMappedFrame;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stEncodeConfig.pitch = pitch;
stEncodeConfig.width = encodeConfig.width;
stEncodeConfig.height = encodeConfig.height;
int dropOrDuplicate = MatchFPS(fpsRatio, frmProcessed, frmActual);
for (int i = 0; i <= dropOrDuplicate; i++) {
pEncoder->EncodeFrame(&stEncodeConfig, picType);
frmActual++;
}
frmProcessed++;
//cuvidUnmapVideoFrame(pDecoder->GetDecoder(), dMappedFrame);
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
cuvidUnmapVideoFrame(pDecoder->GetDecoder(), (CUdeviceptr)img.data);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pFrameQueue->releaseFrame(&pInfo);
}
}
pEncoder->EncodeFrame(NULL, NV_ENC_PIC_STRUCT_FRAME, true);
#ifdef _WIN32
WaitForSingleObject(decodeThread, INFINITE);
#else
pthread_join(pid, NULL);
#endif
if (pEncoder->GetEncodedFrames() > 0)
{
NvQueryPerformanceCounter(&lEnd);
NvQueryPerformanceFrequency(&lFreq);
double elapsedTime = (double)(lEnd - lStart)/(double)lFreq;
printf("Total time: %fms, Decoded Frames: %d, Encoded Frames: %d, Average FPS: %f\n",
elapsedTime * 1000,
pDecoder->m_decodedFrames,
pEncoder->GetEncodedFrames(),
(float)pEncoder->GetEncodedFrames() / elapsedTime);
}
pEncoder->Deinitialize();
delete pDecoder;
delete pEncoder;
delete pFrameQueue;
cuvidCtxLockDestroy(ctxLock);
__cu(cuCtxDestroy(cudaCtx));
return 0;
}
The Y block is at the position 0, the U block is at position width*height and the V block is at the position width*height+(width*height)/4.
cv::cuda::GpuMat dimg(cv::Size(decodedW,decodedH+(decodedH/2)),CV_8UC1,(void*)(dMappedFrame), pitch);
dimg.download(img);
cv::cvtColor(img, img, cv::COLOR_YUV2BGR_NV12);
cv::imshow("frame", img);
cv::waitKey(1);
Further reading here.
Related
I'm using nftw(file tree walk) for traversing a dir(which has sub-directories and files). I've passed a directory using CLI function. Now I need to store the leaf files and dirs(empty dirs) into a linked list and print them out. I've create a function for nftw called as disp & passed it to nftw so that it'll print out some info about the files. The linked list stores the info of file produced by stat & for printing the linked Linked list printll function is used.
For files I can check that typeflag == FTW_F and then enter the following but how do I check empty directories in nftw and add them to the linked list?
I've tried the following
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <ftw.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct node{
long ino; //Inode number
long f_size; //file size
long a_tm; //Access time
long m_tm; //Modify time
long c_tm; //change time
struct node *next;
}node;
node *tmp = NULL;
static node *head = NULL;
void printll(node *head);
//display function
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
//Function to create linked list
static int linked(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
/* ------------------Main---------------------*/
int main(int argc, char *argv[]){
int flags = 0;
if(argc > 2 && strchr(argv[2], 'd') != NULL)
flags |= FTW_DEPTH;
printf("File_type\tF_size\t\tPath\t\t\t\t\t\t\tInode\n");
if(nftw((argc < 2) ? "." : argv[1], disp, 20, flags) == -1) {
perror("nftw");
return -1;
}
printf("\n");
// nftw((argc < 2) ? "." : argv[1], linked, 20, flags);
printll(tmp);
exit(EXIT_SUCCESS);
}
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw){
printf("%-3s\t\t%7jd\t\t%-40s\t\t%ld\n",
(typeflag == FTW_D) ? "d" : (typeflag == FTW_F) ? "f": "???",
s->st_size, fpath, s->st_ino);
struct dirent *r;
if(typeflag == FTW_F){ //How to check empty dirs here?
if(head == NULL){
head = malloc(sizeof(node));
head->ino = s->st_ino;
head->f_size = s->st_size;
head->a_tm = s->st_atime;
head->m_tm = s->st_mtime;
head->c_tm = s->st_ctime;
head->next = NULL;
tmp = head;
} else if(head != NULL) {
if(tmp != NULL){
node *ptr = malloc(sizeof(node));
ptr->ino = s->st_ino;
ptr->f_size = s->st_size;
ptr->a_tm = s->st_atime;
ptr->m_tm = s->st_mtime;
ptr->c_tm = s->st_ctime;
ptr->next = NULL;
tmp->next = ptr;
tmp = tmp->next;
}
}
while(tmp != NULL){
printf("%ld\n", tmp->ino);
printf("%ld\n", tmp->f_size);
printf("%ld\n", tmp->a_tm);
printf("%ld\n", tmp->m_tm);
printf("%ld\n", tmp->c_tm);
tmp = tmp->next;
}
}
return 0;
}
void printll(node *head){
node *ptr;
if(head == NULL)
printf("The linked list is NULL\n");
ptr = head;
while(ptr != NULL){
printf("%ld\n", ptr->ino);
printf("%ld\n", ptr->f_size);
printf("%ld\n", ptr->a_tm);
printf("%ld\n", ptr->m_tm);
printf("%ld\n", ptr->c_tm);
ptr = ptr->next;
}
}
Here's the code for creaiting the linked list using ftw
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <libgen.h>
#include <ftw.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct node{
long ino;
long f_size;
long a_tm;
long m_tm;
long c_tm;
struct node *next;
}node;
node *c, *tmp = NULL, *loc;
static node *head = NULL;
void printll(node *head); //printing of linked list
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
static int linked(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
void add_at_end(node *p);
/* ------------------Main---------------------*/
int main(int argc, char *argv[]){
int flags = 0;
if(argc > 2 && strchr(argv[2], 'd') != NULL)
flags |= FTW_DEPTH;
printf("File_type\tF_size\t\tPath\t\t\t\t\t\t\tInode\n");
if(nftw((argc < 2) ? "." : argv[1], disp, 20, flags) == -1) {
perror("nftw");
return -1;
}
nftw((argc < 2) ? "." : argv[1], linked, 20, flags);
printf("\n");
printll(tmp);
int num, fd;
char f_name[100], dest[100], str_ent[100];
char c, dl;
struct stat fb;
while(1){
printf("1. Add a file\n");
printf("2. Delete a file\n");
printf("3. Add a directory\n");
printf("4. Delete a directory\n");
printf("Enter the operation num to perform\n");
scanf(" %d", &num);
switch(num){
case 1:
printf("File Name: ");
scanf("%s", f_name);
printf("Destination: ");
scanf("%s", dest);
strcat(dest, f_name);
open(dest, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
printf("File %s is successfully added.\n", f_name);
printf("Do you want to write to this file (Y/N)? \n");
scanf(" %c", &c);
if(c == 'y' || c == 'Y'){
FILE *f;
f = fopen(dest, "w");
printf("How many lines do you want to enter: ");
scanf("%d", &num);
printf("Enter content\n");
for(int i = 0; i < num+1; i++){
fgets(str_ent, sizeof str_ent, stdin);
fputs(str_ent, f);
}
printf("The content you entered is written to the file\n");
fclose(f);
stat(dest, &fb);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
node *b;
b = tmp;
while(b->next != NULL)
b = b->next;
b->next = loc;
printf("File added to linked list successfully\n");
break;
} else if( c == 'n' || c == 'N'){
stat(dest, &fb);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
node *b;
b = tmp;
while(b->next != NULL)
b = b->next;
b->next = loc;
printf("File added to linked list successfully\n");
free(loc);
break;
}
case 2:
printf("File Name: ");
scanf("%s", f_name);
printf("Destination: ");
scanf("%s", dest);
strcat(dest, f_name);
stat(dest, &fb);
printf("The inode for removed file is: %ld\n", fb.st_ino);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
if(loc->ino == tmp->ino){
tmp = tmp->next;
printf("The node is shifted to next and break is here\n");
break;
} else {
node *bu, *cu;
bu = tmp; //tmp
cu = tmp; //tmp2
while(cu->ino != loc->ino){
bu = cu;
cu = cu->next;
}
bu->next = cu->next;
free(cu);
cu = NULL;
unlink(dest);
printf("File %s has been removed & linked list it updated.\n", f_name);
break;
}
case 3:
printf("Dir Name: ");
scanf("%s", f_name);
printf("\nDestination: ");
scanf("%s", dest);
strcat(dest, f_name);
mkdir(dest, 00700);
stat(dest, &fb);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
printf("Directory %s successfully added at %s\n", f_name, dest);
break;
case 4:
printf("Dir Name: ");
scanf("%s", f_name);
printf("Destination: ");
scanf("%s", dest);
rmdir(dest);
printf("The directory has been deleted successfully\n");
break;
default:
printf("Operation doesn't exits\n");
exit(0);
}
printf("Do you want to continue with file operations (Y/N)? ");
scanf(" %c", &c);
if(c == 'y' || c == 'Y')
continue;
else
break;
}
while(1){
printf("Do you want to print Director structure OR Linked List (D/L)? ");
scanf(" %c", &dl);
if(dl == 'd' || dl == 'D')
nftw((argc < 2) ? "." : argv[1], disp, 20, flags);
if(dl == 'l' || dl == 'L')
printll(tmp);
printf("Do you want to continue the print? ");
scanf(" %c", &c);
if(c == 'y' || c == 'Y')
continue;
else
break;
}
free(tmp);
exit(EXIT_SUCCESS);
}
/* ----------------Main exit--------------------*/
/* ----------------Display Dir tree structure --------------------*/
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw){
printf("%-3s\t\t%7jd\t\t%-40s\t\t%ld\n",
(typeflag == FTW_D) ? "d" : (typeflag == FTW_F) ? "f": "???",
s->st_size, fpath, s->st_ino);
return 0;
}
/* ----------------xx-xx-------------------*/
/* -----------------Linked list function ----------------- */
static int linked(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw){
struct dirent *r;
DIR *d;
int files = 0;
if(typeflag == FTW_D){
d= opendir(fpath);
while((r = readdir(d)) != NULL)
files++;
}
if(typeflag == FTW_F || files == 2){
if(head == NULL){
head = malloc(sizeof(node));
head->ino = s->st_ino;
head->f_size = s->st_size;
head->a_tm = s->st_atime;
head->m_tm = s->st_mtime;
head->c_tm = s->st_ctime;
head->next = NULL;
tmp = head;
} else if(head != NULL) {
node *c = (struct node *)malloc(sizeof(node));
c->ino = s->st_ino;
c->f_size = s->st_size;
c->a_tm = s->st_atime;
c->m_tm = s->st_mtime;
c->c_tm = s->st_ctime;
c->next = NULL;
add_at_end(c);
}
}
return 0;
}
/* ------------------xx-------xx--------------------------- */
/* ---------------function to add at end ---------------- */
void add_at_end(node *p){
node *c2 = (struct node *)malloc(sizeof(node));
c2 = tmp;
while(c2->next != NULL)
c2 = c2->next;
c2->next = p;
}
/* --------------------------x--x-------------------------*/
/* -----------------------Printing linked list ------------------------- */
void printll(node *head){
node *ptr;
if(head == NULL)
printf("The linked list is NULL\n");
ptr = head;
while(ptr != NULL){
printf("%ld\n", ptr->ino);
printf("%ld\n", ptr->f_size);
printf("%ld\n", ptr->a_tm);
printf("%ld\n", ptr->m_tm);
printf("%ld\n", ptr->c_tm);
ptr = ptr->next;
printf("\n");
}
}
/* ------------------------x---x--------------------------------------- */
How to get stack trace for C/C++ program in CYGWIN environment ?
** I was looking for a back trace mechanism, I've compiled some of the solutions found here and made it a small program for quick reference.
My Answers with a code snippet:
#if defined(__CYGWIN__)
#include <Windows.h>
#include <dbghelp.h>
#include <psdk_inc/_dbg_common.h>
#include <cxxabi.h>
#include <cstring>
class Error // Windows version
{
private:
void *stacktrace[MAX_STACKTRACE_SIZE];
size_t stacktrace_size;
public:
const char* message;
Error(const char* m)
: message(m)
, stacktrace_size(0)
{
// Capture the stack, when error is 'hit'
stacktrace_size = CaptureStackBackTrace(0, MAX_STACKTRACE_SIZE, stacktrace, nullptr);
}
void print_backtrace(ostream& out) const
{
SYMBOL_INFO * symbol;
HANDLE process;
size_t length;
process = GetCurrentProcess();
SymInitialize(process, nullptr, TRUE);
symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
length = strlen (symbol->Name);
std::string result;
char tempStr[255] = {0};
for (int i = 0; i < stacktrace_size; i++)
{
int status = 0;
// '_' is missing in symbol->Name , hence prefix it and concat with symbol->Name
char prefixed_symbol [256] = "_" ;
SymFromAddr(process, (DWORD64)(stacktrace[i]), 0, symbol);
auto backtrace_line = string(symbol->Name);
if (backtrace_line.size() == 0) continue;
// https://en.wikipedia.org/wiki/Name_mangling
// Prefix '_' with symbol name, so that __cxa_demangle does the job correctly
// $ c++filt -n _Z9test_ringI12SmallIntegerIhEEvRK4RingIT_E
strcat (prefixed_symbol, symbol->Name);
char * demangled_name = abi::__cxa_demangle(prefixed_symbol, nullptr, nullptr, &status);
if(status < 0)
{
sprintf(tempStr, "%i: %s - 0x%0X\n", stacktrace_size-i-1, symbol->Name, symbol->Address);
// out << symbol->Name << endl;
}
else
{
sprintf(tempStr, "%i: %s - 0x%0X\n", stacktrace_size - i - 1, demangled_name, symbol->Address);
// out << demangled_name << endl;
}
// Append the extracted info to the result
result += tempStr;
// Free the HEAP allocation made by __cxa_demangle
free((void*)demangled_name);
// Restore the prefix '_' string
prefixed_symbol [1] = '\0';
}
std::cout << result << std::endl;
free(symbol);
}
};
int main ()
{
try {
do_something ();
if (false == status) throw Error("SystemError");
}
catch (const Error &error)
{
cout << "NotImplementedError(\"" << error.message << "\")" << endl;
error.print_backtrace(cout);
return 1;
}
#endif
Command Line Option:
// Use -limagehlp to link the library
g++ -std=c++20 main.cpp -limagehlp
I want to write subscriber node for ROS GPSD client which is publishing GPS coordinates on topic "/fix". I don't know exactly what would be the right code and what changes I have to make in CMakeList.txt and package.xml. Below is the code
#include <ros/ros.h>
#include <sensor_msgs/NavSatStatus.h>
#include <sensor_msgs/NavSatFix.h>
using namespace gps_common;
void callback(const sensor_msgs::NavSatFixConstPtr& fix) {
if (fix->status.status == sensor_msgs::NavSatStatus::STATUS_NO_FIX) {
ROS_INFO("No fix.");
return;
}
if (fix->header.stamp == ros::Time(0)) {
return;
}
printf("\n Latitude = %f and Logitude = %f ",fix->latitude, fix->logitude);
}
int main (int argc, char **argv) {
ros::init(argc, argv, "gps_collect");
ros::NodeHandle node;
ros::Subscriber fix_sub = node.subscribe("fix", 10, callback);
ros::spin();
return 0;
}
I have this code working which is in C. Source: https://github.com/felipegutierrez/raspberryExplore/blob/master/src/gps/gpsClient.c
#include <gps.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "gpsClient.h"
int runGpsStreamClient() {
int rc;
int count = 0;
clock_t t;
struct gps_data_t gps_data;
t = clock();
if ((rc = gps_open("localhost", "2947", &gps_data)) == -1) {
printf("code: %d, reason: %s\n", rc, gps_errstr(rc));
return EXIT_FAILURE;
}
t = clock() - t;
double time_taken = ((double) t) / CLOCKS_PER_SEC; // in seconds
printf("gps_open() took %f seconds to execute \n", time_taken);
t = clock();
gps_stream(&gps_data, WATCH_ENABLE | WATCH_JSON, NULL);
t = clock() - t;
time_taken = ((double) t) / CLOCKS_PER_SEC; // in seconds
printf("gps_stream() took %f seconds to execute \n", time_taken);
while (count < 60) {
/* wait for 1 second to receive data */
if (gps_waiting(&gps_data, 1000000)) {
/* read data */
if ((rc = gps_read(&gps_data)) == -1) {
printf(
"error occurred reading gps data. code: %d, reason: %s\n",
rc, gps_errstr(rc));
} else {
/* Display data from the GPS receiver. */
double lat = gps_data.fix.latitude;
double lon = gps_data.fix.longitude;
double alt = gps_data.fix.altitude;
double speed = gps_data.fix.speed;
double climb = gps_data.fix.climb;
double t = gps_data.fix.time; // EDIT: Replaced tv.tv_sec with gps_data.fix.time
int status = gps_data.status;
int mode = gps_data.fix.mode;
/**
* MODE_NOT_SEEN 0 mode update not seen yet
* MODE_NO_FIX 1 none
* MODE_2D 2 good for latitude/longitude
* MODE_3D 3 good for altitude/climb too
*/
printf("status: %d - ", status);
printf("mode: %d - ", mode);
printf("latitude: %f - ", lat);
printf("longitude: %f - ", lon);
printf("altitude: %f - ", alt);
printf("speed: %f - ", speed);
printf("vertical speed: %f - ", climb);
printf("timestamp: %f - ", t);
printf("%d:%d:%d", (int) (t / 3600), (int) (t / 60), (int) t);
if ((status == STATUS_FIX)
&& (mode == MODE_2D || mode == MODE_3D)
&& !isnan(lat) && !isnan(lon)) {
//gettimeofday(&tv, NULL); EDIT: tv.tv_sec isn't actually the timestamp!
printf(" =) GPS data correctly received\n");
} else {
printf(" =( NO GPS data received\n");
}
}
} else {
printf("Timeout to retrieve data from gpsd.");
}
count++;
sleep(1);
}
/* When you are done... */
gps_stream(&gps_data, WATCH_DISABLE, NULL);
gps_close(&gps_data);
return EXIT_SUCCESS;
}
I was modiying the NVTranscoder project from the Video_Codec_SDK_8.0.14 in order to adding some signal processing works into the video frames.
However, I encounter some problems when I turn the GPUMat into CUdeviceptr.
I was wondering how can I turn the GPUMat into CUdeviceptr. After I performed the blurring function where I have emphasized as below, I want to turn the processed mat into a CUdeviceptr.
Besides, the part converting the CUdeviceptr into GPUmat is also wrong, as it shows the gpuInput cannot read memory.
Besides, can anyone point out some problems of my implementation?
The code is as follows:
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <stdio.h>
#include <string.h>
#include "dynlink_cuda.h" // <cuda.h>
#include "VideoDecoder.h"
#include "VideoEncoder.h"
#include "../common/inc/nvUtils.h"
#include <opencv2/opencv.hpp>
#include "opencv2/gpu/gpu.hpp"
using namespace cv;
#ifdef _WIN32
DWORD WINAPI DecodeProc(LPVOID lpParameter)
{
CudaDecoder* pDecoder = (CudaDecoder*)lpParameter;
pDecoder->Start();
return 0;
}
#else
void* DecodeProc(void *arg)
{
CudaDecoder* pDecoder = (CudaDecoder*)arg;
pDecoder->Start();
return NULL;
}
#endif
int MatchFPS(const float fpsRatio, int decodedFrames, int encodedFrames)
{
if (fpsRatio < 1.f) {
// need to drop frame
if (decodedFrames * fpsRatio < (encodedFrames + 1)) {
return -1;
}
}
else if (fpsRatio > 1.f) {
// need to duplicate frame
int duplicate = 0;
while (decodedFrames*fpsRatio > encodedFrames + duplicate + 1) {
duplicate++;
}
return duplicate;
}
return 0;
}
void PrintHelp()
{
printf("Usage : NvTranscoder \n"
"-i <string> Specify input .h264 file\n"
"-o <string> Specify output bitstream file\n"
"\n### Optional parameters ###\n"
"-size <int int> Specify output resolution <width height>\n"
"-codec <integer> Specify the codec \n"
" 0: H264\n"
" 1: HEVC\n"
"-preset <string> Specify the preset for encoder settings\n"
" hq : nvenc HQ \n"
" hp : nvenc HP \n"
" lowLatencyHP : nvenc low latency HP \n"
" lowLatencyHQ : nvenc low latency HQ \n"
" lossless : nvenc Lossless HP \n"
"-fps <integer> Specify encoding frame rate\n"
"-goplength <integer> Specify gop length\n"
"-numB <integer> Specify number of B frames\n"
"-bitrate <integer> Specify the encoding average bitrate\n"
"-vbvMaxBitrate <integer> Specify the vbv max bitrate\n"
"-vbvSize <integer> Specify the encoding vbv/hrd buffer size\n"
"-rcmode <integer> Specify the rate control mode\n"
" 0: Constant QP mode\n"
" 1: Variable bitrate mode\n"
" 2: Constant bitrate mode\n"
" 8: low-delay CBR, high quality\n"
" 16: CBR, high quality (slower)\n"
" 32: VBR, high quality (slower)\n"
"-qp <integer> Specify qp for Constant QP mode\n"
"-i_qfactor <float> Specify qscale difference between I-frames and P-frames\n"
"-b_qfactor <float> Specify qscale difference between P-frames and B-frames\n"
"-i_qoffset <float> Specify qscale offset between I-frames and P-frames\n"
"-b_qoffset <float> Specify qscale offset between P-frames and B-frames\n"
"-deviceID <integer> Specify the GPU device on which encoding will take place\n"
"-help Prints Help Information\n\n"
);
}
int main(int argc, char* argv[])
{
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
typedef HMODULE CUDADRIVER;
#else
typedef void *CUDADRIVER;
#endif
CUDADRIVER hHandleDriver = 0;
__cu(cuInit(0, __CUDA_API_VERSION, hHandleDriver));
__cu(cuvidInit(0));
EncodeConfig encodeConfig = { 0 };
encodeConfig.endFrameIdx = INT_MAX;
encodeConfig.bitrate = 5000000;
encodeConfig.rcMode = NV_ENC_PARAMS_RC_CONSTQP;
encodeConfig.gopLength = NVENC_INFINITE_GOPLENGTH;
encodeConfig.codec = NV_ENC_H264;
encodeConfig.fps = 0;
encodeConfig.qp = 28;
encodeConfig.i_quant_factor = DEFAULT_I_QFACTOR;
encodeConfig.b_quant_factor = DEFAULT_B_QFACTOR;
encodeConfig.i_quant_offset = DEFAULT_I_QOFFSET;
encodeConfig.b_quant_offset = DEFAULT_B_QOFFSET;
encodeConfig.presetGUID = NV_ENC_PRESET_DEFAULT_GUID;
encodeConfig.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
NVENCSTATUS nvStatus = CNvHWEncoder::ParseArguments(&encodeConfig, argc, argv);
if (nvStatus != NV_ENC_SUCCESS)
{
PrintHelp();
return 1;
}
if (!encodeConfig.inputFileName || !encodeConfig.outputFileName)
{
PrintHelp();
return 1;
}
encodeConfig.fOutput = fopen(encodeConfig.outputFileName, "wb");
if (encodeConfig.fOutput == NULL)
{
PRINTERR("Failed to create \"%s\"\n", encodeConfig.outputFileName);
return 1;
}
//init cuda
CUcontext cudaCtx;
CUdevice device;
__cu(cuDeviceGet(&device, encodeConfig.deviceID));
__cu(cuCtxCreate(&cudaCtx, CU_CTX_SCHED_AUTO, device));
CUcontext curCtx;
CUvideoctxlock ctxLock;
__cu(cuCtxPopCurrent(&curCtx));
__cu(cuvidCtxLockCreate(&ctxLock, curCtx));
CudaDecoder* pDecoder = new CudaDecoder;
FrameQueue* pFrameQueue = new CUVIDFrameQueue(ctxLock);
pDecoder->InitVideoDecoder(encodeConfig.inputFileName, ctxLock, pFrameQueue, encodeConfig.width, encodeConfig.height);
int decodedW, decodedH, decodedFRN, decodedFRD, isProgressive;
pDecoder->GetCodecParam(&decodedW, &decodedH, &decodedFRN, &decodedFRD, &isProgressive);
if (decodedFRN <= 0 || decodedFRD <= 0) {
decodedFRN = 30;
decodedFRD = 1;
}
if(encodeConfig.width <= 0 || encodeConfig.height <= 0) {
encodeConfig.width = decodedW;
encodeConfig.height = decodedH;
}
float fpsRatio = 1.f;
if (encodeConfig.fps <= 0) {
encodeConfig.fps = decodedFRN / decodedFRD;
}
else {
fpsRatio = (float)encodeConfig.fps * decodedFRD / decodedFRN;
}
encodeConfig.pictureStruct = (isProgressive ? NV_ENC_PIC_STRUCT_FRAME : 0);
pFrameQueue->init(encodeConfig.width, encodeConfig.height);
VideoEncoder* pEncoder = new VideoEncoder(ctxLock);
assert(pEncoder->GetHWEncoder());
nvStatus = pEncoder->GetHWEncoder()->Initialize(cudaCtx, NV_ENC_DEVICE_TYPE_CUDA);
if (nvStatus != NV_ENC_SUCCESS)
return 1;
encodeConfig.presetGUID = pEncoder->GetHWEncoder()->GetPresetGUID(encodeConfig.encoderPreset, encodeConfig.codec);
printf("Encoding input : \"%s\"\n", encodeConfig.inputFileName);
printf(" output : \"%s\"\n", encodeConfig.outputFileName);
printf(" codec : \"%s\"\n", encodeConfig.codec == NV_ENC_HEVC ? "HEVC" : "H264");
printf(" size : %dx%d\n", encodeConfig.width, encodeConfig.height);
printf(" bitrate : %d bits/sec\n", encodeConfig.bitrate);
printf(" vbvMaxBitrate : %d bits/sec\n", encodeConfig.vbvMaxBitrate);
printf(" vbvSize : %d bits\n", encodeConfig.vbvSize);
printf(" fps : %d frames/sec\n", encodeConfig.fps);
printf(" rcMode : %s\n", encodeConfig.rcMode == NV_ENC_PARAMS_RC_CONSTQP ? "CONSTQP" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_VBR ? "VBR" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_CBR ? "CBR" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_VBR_MINQP ? "VBR MINQP (deprecated)" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ ? "CBR_LOWDELAY_HQ" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_CBR_HQ ? "CBR_HQ" :
encodeConfig.rcMode == NV_ENC_PARAMS_RC_VBR_HQ ? "VBR_HQ" : "UNKNOWN");
if (encodeConfig.gopLength == NVENC_INFINITE_GOPLENGTH)
printf(" goplength : INFINITE GOP \n");
else
printf(" goplength : %d \n", encodeConfig.gopLength);
printf(" B frames : %d \n", encodeConfig.numB);
printf(" QP : %d \n", encodeConfig.qp);
printf(" preset : %s\n", (encodeConfig.presetGUID == NV_ENC_PRESET_LOW_LATENCY_HQ_GUID) ? "LOW_LATENCY_HQ" :
(encodeConfig.presetGUID == NV_ENC_PRESET_LOW_LATENCY_HP_GUID) ? "LOW_LATENCY_HP" :
(encodeConfig.presetGUID == NV_ENC_PRESET_HQ_GUID) ? "HQ_PRESET" :
(encodeConfig.presetGUID == NV_ENC_PRESET_HP_GUID) ? "HP_PRESET" :
(encodeConfig.presetGUID == NV_ENC_PRESET_LOSSLESS_HP_GUID) ? "LOSSLESS_HP" : "LOW_LATENCY_DEFAULT");
printf("\n");
nvStatus = pEncoder->GetHWEncoder()->CreateEncoder(&encodeConfig);
if (nvStatus != NV_ENC_SUCCESS)
return 1;
nvStatus = pEncoder->AllocateIOBuffers(&encodeConfig);
if (nvStatus != NV_ENC_SUCCESS)
return 1;
unsigned long long lStart, lEnd, lFreq;
NvQueryPerformanceCounter(&lStart);
//start decoding thread
#ifdef _WIN32
HANDLE decodeThread = CreateThread(NULL, 0, DecodeProc, (LPVOID)pDecoder, 0, NULL);
#else
pthread_t pid;
pthread_create(&pid, NULL, DecodeProc, (void*)pDecoder);
#endif
//start encoding thread
int frmProcessed = 0;
int frmActual = 0;
while(!(pFrameQueue->isEndOfDecode() && pFrameQueue->isEmpty()) ) {
CUVIDPARSERDISPINFO pInfo;
if(pFrameQueue->dequeue(&pInfo)) {
CUdeviceptr dMappedFrame = 0;
unsigned int pitch;
CUVIDPROCPARAMS oVPP = { 0 };
oVPP.progressive_frame = pInfo.progressive_frame;
oVPP.second_field = 0;
oVPP.top_field_first = pInfo.top_field_first;
oVPP.unpaired_field = (pInfo.progressive_frame == 1 || pInfo.repeat_first_field <= 1);
cuvidMapVideoFrame(pDecoder->GetDecoder(), pInfo.picture_index, &dMappedFrame, &pitch, &oVPP);
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
gpu::GpuMat gpuInput = gpu::GpuMat(decodedH, decodedW, CV_8UC3, (void*)dMappedFrame, pitch);
gpu::GpuMat d_dst;
gpu::GpuMat d_buf;
gpu::GaussianBlur(gpuInput, d_dst, cv::Size(3, 3), 0);
cv::Mat result;
d_dst.download(result);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
EncodeFrameConfig stEncodeConfig = { 0 };
NV_ENC_PIC_STRUCT picType = (pInfo.progressive_frame || pInfo.repeat_first_field >= 2 ? NV_ENC_PIC_STRUCT_FRAME :
(pInfo.top_field_first ? NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM : NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP));
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
stEncodeConfig.dptr = result.data;//dMappedFrame;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stEncodeConfig.pitch = pitch;
stEncodeConfig.width = encodeConfig.width;
stEncodeConfig.height = encodeConfig.height;
int dropOrDuplicate = MatchFPS(fpsRatio, frmProcessed, frmActual);
for (int i = 0; i <= dropOrDuplicate; i++) {
pEncoder->EncodeFrame(&stEncodeConfig, picType);
frmActual++;
}
frmProcessed++;
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
cuvidUnmapVideoFrame(pDecoder->GetDecoder(), dMappedFrame);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pFrameQueue->releaseFrame(&pInfo);
}
}
pEncoder->EncodeFrame(NULL, NV_ENC_PIC_STRUCT_FRAME, true);
#ifdef _WIN32
WaitForSingleObject(decodeThread, INFINITE);
#else
pthread_join(pid, NULL);
#endif
if (pEncoder->GetEncodedFrames() > 0)
{
NvQueryPerformanceCounter(&lEnd);
NvQueryPerformanceFrequency(&lFreq);
double elapsedTime = (double)(lEnd - lStart)/(double)lFreq;
printf("Total time: %fms, Decoded Frames: %d, Encoded Frames: %d, Average FPS: %f\n",
elapsedTime * 1000,
pDecoder->m_decodedFrames,
pEncoder->GetEncodedFrames(),
(float)pEncoder->GetEncodedFrames() / elapsedTime);
}
pEncoder->Deinitialize();
delete pDecoder;
delete pEncoder;
delete pFrameQueue;
cuvidCtxLockDestroy(ctxLock);
__cu(cuCtxDestroy(cudaCtx));
return 0;
}
I run the argument "-i C:\test\input.h264 -o C:\test\output.h264 -size 352 288"
The decoded frame is in NV12 format.
What is your exactly the cuda error code returned ? can you check for cuda Errors and post it : this post will help you
Is the member dptr waiting for a device pointer and you are giving a pointer on data stored on the host (cv::Mat instead of cv::cuda::GpuMat)?
can you try this
stEncodeConfig.dptr = dst.data;
As I pointed out in the comments of your linked post, the decoded frame is in raw format (i.e YUV etc). You're providing CV_8UC3 image format which is incorrect.
To test whether GpuMat is being created from CUdeviceptr:
cv::cuda::GpuMat dimg(cv::Size(decodedW, decodedH),CV_8UC1, (void*)(dMappedFrame),pitch);
cv::Mat img;
dimg.download(img);
cv::imshow("Decoded Frame", img);
cv::waitKey(1);
For further details, see this link.
According to https://github.com/signal11/hidapi/issues/72 HIDAPI ought to be thread safe on Linux machines. However, I can't get it working at all. This is what I do:
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
#include "hidapi.h"
hid_device *handle;
static void *TaskCode(void *argument)
{
int res;
//hid_device *handle;
unsigned char buf[64];
// res = hid_init();
// if( res == -1 )
// {
// return (void*)1;
// }
//
// handle = hid_open(0x0911, 0x251c, NULL);
// if( handle == NULL )
// {
// return (void*)2;
// }
printf( "while 2\n");
while( 1 )
{
memset( buf, 64, 0 );
res = hid_read(handle, buf, 0);
if( res == -1 )
{
return (void*)3;
}
printf( "received %d bytes\n", res);
for (int i = 0; i < res; i++)
printf("Byte %d: %02x ", i+1, buf[i]);
//printf( "%02x ", buf[0]);
fflush(stdout);
}
return (void*)0;
}
int main(int argc, char* argv[])
{
int res;
//hid_device *handle;
unsigned char buf[65];
res = hid_init();
if( res == -1 )
{
return 1;
}
handle = hid_open(0x0911, 0x251c, NULL);
if( handle == NULL )
{
return 2;
}
hid_set_nonblocking( handle, 0 );
pthread_t thread;
int rc = pthread_create(&thread, NULL, TaskCode, NULL);
printf( "while 1\n");
while(1)
{
int a = getchar();
if( a == 'a')
{
// Get Device Type (cmd 0x82). The first byte is the report number (0x0).
buf[0] = 0x0;
buf[1] = 0x82;
res = hid_write(handle, buf, 65);
if( res != -1 )
printf( "write ok, transferred %d bytes\n", res );
else
{
printf( "write error\n" );
char* str = hid_error(handle);
printf( "error: %s\n", str );
return 1;
}
}
else if( a== 'b')
break;
}
void* trc;
rc = pthread_join(thread, &trc);
printf( "rc code: %d\n", (int)trc );
// Finalize the hidapi library
res = hid_exit();
return 0;
}
If I don't use the global handle, I get 'write error' every time. If I do, as in the example, formally everything works but hid_read always returns 0 bytes... Of course, if I do simple hid_write() followed by hid_read(), I'll get the correct reply to the command 0x82 as intended. I'm really lost here, am I overlooking something?
EDIT: to clarify, zero bytes return also for everything, incl. buttons on mouse etc. So it seems to work but the data buffer is always zero bytes.
Shame on me, a dumb mistake. The code should be:
memset( buf, 0, 64 );
res = hid_read(handle, buf, 64);
and then it works. Should sleep more and write less!