How to turn OpenCV_GPUMat into CUdeviceptr? - opencv

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.

Related

How to get stack trace for C/C++ program in CYGWIN environment?

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

ROS gpsd client Subscriber node (/fix)

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

How can I obtain the YUV components from the GPU device?

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.

Received throughput issue with saturated traffic

I am using NS3 (v3.13) Wi-Fi model in infrastructure topology configured as follows (simulation file attached):
Single AP (BSS)
Multiple STAs (stations)
Application duration = 10s
Saturated downlink traffic (OnOffApplication with OnTime=2s and OffTime=0) from AP to all STAs
Phy: 802.11a
Default YansWifiChannelHelper and YansWifiPhyHelper
Rate control: ConstantRateWifiManager
Mobility: ConstantPositionMobilityModel (STAs are positioned on a circle of 2 meters radius around the AP)
Although all is going well, for a high bitrate (saturated traffic), when the number of STAs per BSS increases a lot, some STAs don't receive any BYTE !!
Experiments:
OnOffApplication DataRate = 60Mb/s, Phy DataMode=OfdmRate54Mbps and 30 STAs, one STA receives packets with a bitrate of 7.2Mb/s and another with 15.3Mb/s (all other 28 STAs don't receive any BYTE)
OnOffApplication DataRate = 60Mb/s, DataMode=OfdmRate6Mbps and 30 STAs, one STA receives packets with a bitrate of 1.95Mb/s and another with 4.3Mb/s (all other 28 STAs don't receive any BYTE)
I think that the problem comes from the OnOff Application configurations; how should I configure it to simulate a full buffer downlink traffic?
Thanks in advance for any suggestion.
#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/flow-monitor-helper.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/applications-module.h"
#include "ns3/internet-module.h"
#include "ns3/gnuplot.h"
#include "ns3/constant-velocity-helper.h"
#include "ns3/integer.h"
#include "ns3/mpi-interface.h"
#include "math.h"
#include <iostream>
/**
* PARAMETERS
*/
#define StaNb 30
#define Distance 2
#define Duration 10
#define DataRate 90000000
#define PacketSize 1500
#define couleur(param) printf("\033[%sm",param)
using namespace ns3;
class Experiment {
public:
Experiment();
void CreateArchi(void);
void CreateApplis();
private:
Ptr<ListPositionAllocator> positionAllocAp;
Ptr<ListPositionAllocator> positionAllocSta;
Ptr<GridPositionAllocator> positionAllocStaCouloir;
Ptr<RandomDiscPositionAllocator> positionAllocStaAmphi;
std::vector<Ptr<ConstantPositionMobilityModel> > constant;
NodeContainer m_wifiAP, m_wifiQSta;
NetDeviceContainer m_APDevice;
NetDeviceContainer m_QStaDevice;
YansWifiChannelHelper m_channel;
Ptr<YansWifiChannel> channel;
YansWifiPhyHelper m_phyLayer_Sta, m_phyLayer_AP;
WifiHelper m_wifi;
QosWifiMacHelper m_macSta, m_macAP;
InternetStackHelper m_stack;
Ipv4InterfaceContainer m_StaInterface;
Ipv4InterfaceContainer m_ApInterface;
Ssid m_ssid;
};
Experiment::Experiment() {
positionAllocStaCouloir = CreateObject<GridPositionAllocator>();
positionAllocAp = CreateObject<ListPositionAllocator>();
positionAllocSta = CreateObject<ListPositionAllocator>();
positionAllocStaAmphi = CreateObject<RandomDiscPositionAllocator>();
m_wifi = WifiHelper::Default();
constant.resize(StaNb + 1);
for (int i = 0; i < StaNb + 1; i++) {
constant[i] = CreateObject<ConstantPositionMobilityModel>();
}
}
void Experiment::CreateArchi(void) {
m_wifiQSta.Create(StaNb);
m_wifiAP.Create(1);
m_ssid = Ssid("BSS_circle");
m_channel = YansWifiChannelHelper::Default();
channel = m_channel.Create();
m_wifi.SetStandard(WIFI_PHY_STANDARD_80211a);
m_wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager", "DataMode",
StringValue("OfdmRate6Mbps"));
m_phyLayer_Sta = YansWifiPhyHelper::Default();
m_phyLayer_AP = YansWifiPhyHelper::Default();
m_phyLayer_Sta.SetChannel(channel);
m_phyLayer_AP.SetChannel(channel);
positionAllocAp->Add(Vector3D(0.0, 0.0, 0.0));
MobilityHelper mobilityAp;
mobilityAp.SetPositionAllocator(positionAllocAp);
mobilityAp.SetMobilityModel("ns3::ConstantPositionMobilityModel");
mobilityAp.Install(m_wifiAP.Get(0));
constant[0]->SetPosition(Vector3D(0.0, 0.0, 0.0));
float deltaAngle = 2 * M_PI / StaNb;
float angle = 0.0;
double x = 0.0;
double y = 0.0;
for (int i = 0; i < StaNb; i++) {
x = cos(angle) * Distance;
y = sin(angle) * Distance;
positionAllocSta->Add(Vector3D(x, y, 0.0));
MobilityHelper mobilitySta;
mobilitySta.SetPositionAllocator(positionAllocSta);
mobilitySta.SetMobilityModel("ns3::ConstantPositionMobilityModel");
mobilitySta.Install(m_wifiQSta.Get(i));
constant[i]->SetPosition(Vector3D(x, y, 0.0));
angle += deltaAngle;
}
m_macSta = QosWifiMacHelper::Default();
m_macSta.SetType("ns3::StaWifiMac", "ActiveProbing", BooleanValue(true),
"Ssid", SsidValue(m_ssid));
m_macAP = QosWifiMacHelper::Default();
m_macAP.SetType("ns3::ApWifiMac", "Ssid", SsidValue(m_ssid),
"BeaconInterval", TimeValue(Time(std::string("100ms"))));
m_APDevice.Add(m_wifi.Install(m_phyLayer_AP, m_macAP, m_wifiAP));
for (int i = 0; i < StaNb; i++) {
m_QStaDevice.Add(
m_wifi.Install(m_phyLayer_Sta, m_macSta, m_wifiQSta.Get(i)));
}
m_stack.Install(m_wifiAP);
m_stack.Install(m_wifiQSta);
Ipv4AddressHelper address;
address.SetBase("192.168.1.0", "255.255.255.0");
m_ApInterface.Add(address.Assign(m_APDevice.Get(0)));
for (int i = 0; i < StaNb; i++) {
m_StaInterface.Add(address.Assign(m_QStaDevice.Get(i)));
}
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
}
void Experiment::CreateApplis() {
ApplicationContainer source;
OnOffHelper onoff("ns3::UdpSocketFactory", Address());
onoff.SetAttribute("OnTime", RandomVariableValue(ConstantVariable(2)));
onoff.SetAttribute("OffTime", RandomVariableValue(ConstantVariable(0)));
onoff.SetAttribute("DataRate", StringValue("500kb/s"));
for (int i = 0; i < StaNb; i++) {
AddressValue remoteAddress(
InetSocketAddress(m_StaInterface.GetAddress(i), 5010));
onoff.SetAttribute("Remote", remoteAddress);
source.Add(onoff.Install(m_wifiAP.Get(0)));
source.Start(Seconds(3.0));
source.Stop(Seconds(Duration));
}
ApplicationContainer sinks;
PacketSinkHelper packetSinkHelper("ns3::UdpSocketFactory",
Address(InetSocketAddress(Ipv4Address::GetAny(), 5010)));
for (int i = 0; i < StaNb; i++) {
sinks.Add(packetSinkHelper.Install(m_wifiQSta.Get(i)));
sinks.Start(Seconds(3.0));
sinks.Stop(Seconds(Duration));
}
}
int main(int argc, char *argv[]) {
Experiment exp = Experiment();
Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
StringValue("2346"));
exp.CreateArchi();
exp.CreateApplis();
FlowMonitorHelper flowmon;
Ptr<FlowMonitor> monitor = flowmon.InstallAll();
Simulator::Stop(Seconds(Duration));
Simulator::Run();
monitor->CheckForLostPackets();
Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier>(
flowmon.GetClassifier());
std::map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats();
int c = 0;
for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i =
stats.begin(); i != stats.end(); ++i) {
Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
std::cout << "Flux " << i->first << " (" << t.sourceAddress << " -> "
<< t.destinationAddress << ")\n";
std::cout << " Tx Bytes : " << i->second.txBytes << "\n";
std::cout << " Rx Bytes : " << i->second.rxBytes << "\n";
couleur("33");
std::cout << " Bitrate : "
<< i->second.rxBytes * 8.0
/ (i->second.timeLastRxPacket.GetSeconds()
- i->second.timeFirstRxPacket.GetSeconds())
/ 1000000 << " Mbps\n\n";
couleur("0");
if (i->second.rxBytes > 0)
c++;
}
std::cout << " Number of receiving nodes : " << c << "\n";
Simulator::Destroy();
}
I think the medium is too busy.
You need to tuning down onoff datarate e.g 1 mbps. Practically, full buffer 720p video only need no more than 1mbps
You may also check tracing using pcap, ascii or netanim too see either the packet dropping, packet never being send or bug in your code

HIDAPI in two threads

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!

Resources