Skip to content

Commit

Permalink
adding video compression (h264)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsobhani committed Dec 13, 2023
1 parent 89a5a2a commit 2539c92
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 3 deletions.
6 changes: 4 additions & 2 deletions ADApp/ADSrc/Codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ static std::string codecName[] = {
"jpeg",
"blosc",
"lz4",
"bslz4"
"bslz4",
"h264"
};

typedef enum {
NDCODEC_NONE,
NDCODEC_JPEG,
NDCODEC_BLOSC,
NDCODEC_LZ4,
NDCODEC_BSLZ4
NDCODEC_BSLZ4,
NDCODEC_H264
} NDCodecCompressor_t;

typedef struct Codec_t {
Expand Down
20 changes: 20 additions & 0 deletions ADApp/Db/NDCodec.template
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ record(mbbo, "$(P)$(R)Compressor")
field(THVL, "3")
field(FRST, "BSLZ4")
field(FRVL, "4")
field(FVST, "H264")
field(FVVL, "5")
info(autosaveFields, "VAL")
}

Expand All @@ -61,6 +63,8 @@ record(mbbi, "$(P)$(R)Compressor_RBV")
field(THVL, "3")
field(FRST, "BSLZ4")
field(FRVL, "4")
field(FVST, "H264")
field(FVVL, "5")
field(SCAN, "I/O Intr")
}

Expand Down Expand Up @@ -217,3 +221,19 @@ record(waveform, "$(P)$(R)CodecError")
field(FTVL, "CHAR")
field(NELM, "256")
}

# Sets group of picture size. A value of 1 is effectively frame-level compression. Set to higher values for true video compression.
record(ao, "$(P)$(R)GOPSize")
{
field(DTYP, "asynInt32")
field(OUT, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))GOP_SIZE")
}

# Sets the quantizer (qmin and qmax) to value written to PV.
# One can effectively adjust quality this way, with 1 being the least lossy, and higher numbers lossier
record(ao, "$(P)$(R)QMinMax")
{
field(DTYP, "asynInt32")
field(OUT, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))QMINMAX")
}

14 changes: 14 additions & 0 deletions ADApp/commonDriverMakefile
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,20 @@ ifeq ($(WITH_BLOSC),YES)
endif
endif

ifeq ($(WITH_VC),YES)
ifeq ($(VC_EXTERNAL),NO)
PROD_LIBS += videoCompression
else
ifdef VC_LIB
VC_DIR = $(VC_LIB)
PROD_LIBS += videoCompression
else
PROD_SYS_LIBS += videoCompression
endif
endif
endif


ifeq ($(WITH_SZIP),YES)
ifeq ($(SZIP_EXTERNAL),NO)
PROD_LIBS += szip
Expand Down
14 changes: 14 additions & 0 deletions ADApp/commonLibraryMakefile
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,20 @@ ifeq ($(WITH_BLOSC),YES)
endif
endif

ifeq ($(WITH_VC),YES)
ifeq ($(VC_EXTERNAL),NO)
PROD_LIBS += videoCompression
else
ifdef VC_LIB
VC_DIR = $(VC_LIB)
PROD_LIBS += videoCompression
else
PROD_SYS_LIBS += videoCompression
endif
endif
endif


ifeq ($(WITH_SZIP),YES)
ifeq ($(SZIP_EXTERNAL),NO)
LIB_LIBS += szip
Expand Down
5 changes: 5 additions & 0 deletions ADApp/pluginSrc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ ifeq ($(WITH_BITSHUFFLE), YES)
USR_CXXFLAGS += -DHAVE_BITSHUFFLE
endif

ifeq ($(WITH_VC), YES)
#INC += video_compression.h
USR_CXXFLAGS += -DHAVE_VC
endif

ifdef BLOSC_INCLUDE
USR_INCLUDES += $(addprefix -I, $(BLOSC_INCLUDE))
endif
Expand Down
84 changes: 83 additions & 1 deletion ADApp/pluginSrc/NDPluginCodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,6 @@ NDArray *compressLZ4(NDArray *input, NDCodecStatus_t *status, char *errorMessage
return output;
}


NDArray *decompressLZ4(NDArray *input, NDCodecStatus_t *status, char *errorMessage)
{
// Sanity check
Expand Down Expand Up @@ -635,6 +634,70 @@ NDArray *decompressBSLZ4(NDArray *input, NDCodecStatus_t *status, char *errorMes

#endif // ifdef HAVE_BITSHUFFLE

#ifdef HAVE_VC
#include <video_compression.h>
//extern int H264_compress_default(const char*, char*, int, int, int);
NDArray *compressH264(NDArray *input, NDCodecStatus_t *status, char *errorMessage)
{
//printf("inside compressH264\n");
if (!input->codec.empty()) {
sprintf(errorMessage, "Array is already compressed");
*status = NDCODEC_WARNING;
return NULL;
}

switch (input->dataType) {
case NDInt8:
case NDUInt8:
//case NDInt16:
//case NDUInt16:
break;
default:
sprintf(errorMessage, "H264 only supports 8-bit data");
*status = NDCODEC_ERROR;
//goto failure;
return NULL;
}



NDArrayInfo_t info;
input->getInfo(&info);
int outputSize = LZ4_compressBound((int)info.totalBytes);
NDArray *output = allocArray(input, -1, outputSize);

if (!output) {
sprintf(errorMessage, "Failed to allocate H264 output array");
*status = NDCODEC_ERROR;
return NULL;
}

//int compSize = LZ4_compress_default((const char*)input->pData, (char*)output->pData, (int)info.totalBytes, outputSize);
int x_size = input->dims[0].size;
int y_size = input->dims[1].size;

//printf("x_size %d y_size %d\n", x_size, y_size);
//printf("before H264 compress default\n");
//int compSize = H264_compress_default((const char*)input->pData, (char*)output->pData, (int)x_size, (int)y_size, outputSize);
int compSize = H264_compress((const char*)input->pData, (char*)output->pData, (int)x_size, (int)y_size);

if (compSize <= 0) {
output->release();
sprintf(errorMessage, "Internal H264 error");
*status = NDCODEC_ERROR;
return NULL;
}

output->codec.name = codecName[NDCODEC_H264];
output->compressedSize = compSize;
//printf("before return output\n");

return output;
}
#endif



/** Callback function that is called by the NDArray driver with new NDArray data.
* Does JPEG or Blosc compression on the array.
* If compression is None or fails the input array is passed on without
Expand Down Expand Up @@ -717,6 +780,14 @@ void NDPluginCodec::processCallbacks(NDArray *pArray)
break;
}

case NDCODEC_H264: {
//commenting out unlock for now - crashes when changing AVCodecContext parameters while acquiring
//unlock();
result = compressH264(pArray, &codecStatus, errorMessage);
//lock();
break;
}

}

if (result && result != pArray) {
Expand Down Expand Up @@ -807,8 +878,17 @@ asynStatus NDPluginCodec::writeInt32(asynUser *pasynUser, epicsInt32 value)
value = 1;
} else if (function < FIRST_NDCODEC_PARAM) {
status = NDPluginDriver::writeInt32(pasynUser, value);
} else if (function == NDCodecGOPSize) {
printf("setting GOP Size...\n");
set_gop_size(value);
} else if (function == NDCodecQMinMax) {
//lock();
printf("setting qmin and qmax...\n");
set_q_min_max(value);
//unlock();
}


/* Set the parameter in the parameter library. */
status = (asynStatus) setIntegerParam(function, value);

Expand Down Expand Up @@ -877,6 +957,8 @@ NDPluginCodec::NDPluginCodec(const char *portName, int queueSize, int blockingCa
createParam(NDCodecBloscCLevelString, asynParamInt32, &NDCodecBloscCLevel);
createParam(NDCodecBloscShuffleString, asynParamInt32, &NDCodecBloscShuffle);
createParam(NDCodecBloscNumThreadsString, asynParamInt32, &NDCodecBloscNumThreads);
createParam(NDCodecGOPSizeString, asynParamInt32, &NDCodecGOPSize);
createParam(NDCodecQMinMaxString, asynParamInt32, &NDCodecQMinMax);

/* Set the plugin type string */
setStringParam(NDPluginDriverPluginType, "NDPluginCodec");
Expand Down
4 changes: 4 additions & 0 deletions ADApp/pluginSrc/NDPluginCodec.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#define NDCodecBloscCLevelString "BLOSC_CLEVEL" /* (int r/w) Blosc compression level */
#define NDCodecBloscShuffleString "BLOSC_SHUFFLE" /* (bool r/w) Should Blosc apply shuffling? */
#define NDCodecBloscNumThreadsString "BLOSC_NUMTHREADS" /* (int r/w) Number of threads to be used by Blosc */
#define NDCodecGOPSizeString "GOP_SIZE" /* (int r/w) Group of pictures size for H264 */
#define NDCodecQMinMaxString "QMINMAX" /* (int r/w) Sets min and max values for quantizer for H264 */

/** Compress/decompress NDArrays according to available codecs.
* This plugin is a source of NDArray callbacks, passing the (possibly
Expand Down Expand Up @@ -87,6 +89,8 @@ class NDPLUGIN_API NDPluginCodec : public NDPluginDriver {
int NDCodecBloscCLevel;
int NDCodecBloscShuffle;
int NDCodecBloscNumThreads;
int NDCodecGOPSize;
int NDCodecQMinMax;

};

Expand Down

0 comments on commit 2539c92

Please sign in to comment.