2. JPEG解码
2.1. 使用JPEG解码
要进行解码,需提供数据大小和指向文件数据的指针。解码后的图像会放在输出缓冲区中。
要使用mcJPEG库,请先调用初始化的辅助函数。
使用辅助函数
mcjpegCreateSimple()或mcjpegCreateEx()创建mcJPEG库句柄。使用辅助函数
mcjpegJpegStateCreate()创建JPEG状态。mcJPEG库中提供以下辅助函数:
mcjpegStatus_t mcjpegGetProperty(libraryPropertyType type, int *value);mcjpegStatus_t mcjpegCreate(mcjpegBackend_t backend, mcjpegHandle_t *handle, mcjpeg_dev_allocator allocator);mcjpegStatus_t mcjpegCreateSimple(mcjpegHandle_t *handle);mcjpegStatus_t mcjpegCreateEx(mcjpegBackend_t backend, mcjpegDevAllocator_t *dev_allocator, mcjpegPinnedAllocator_t *pinned_allocator, unsigned int flags, mcjpegHandle_t *handle);mcjpegStatus_t mcjpegDestroy(mcjpegHandle_t handle);mcjpegStatus_t mcjpegJpegStateCreate(mcjpegHandle_t handle, mcjpegJpegState_t *jpeg_handle);mcjpegStatus_t mcjpegJpegStateDestroy(mcjpegJpegState handle);
其他辅助函数,如
mcjpegSet*()和mcjpegGet*(),可用于按句柄配置库功能。更多信息,参见 2.3 mcJPEG解码API。使用
mcjpegGetImageInfo()函数解析JPEG图像的宽度和高度。以下为
mcjpegGetImageInfo()函数的签名mcjpegStatus_t mcjpegGetImageInfo( mcjpegHandle_t handle, const unsigned char *data, size_t length, int *nComponents, mcjpegChromaSubsampling_t *subsampling, int *widths, int *heights);
对于要解码的每个图像,将JPEG数据指针和数据长度传递给上述函数。
mcjpegGetImageInfo()函数是线程安全的。mcjpegGetImageInfo()函数的输出之一是mcjpegChromaSubsampling_t,该参数为枚举类型,其枚举列表由从JPEG图像解析出的色度子采样属性组成。 更多信息,参见 2.2.8 mcJPEG色度子采样。使用mcJPEG库中的
mcjpegDecode()函数对JPEG图像进行解码。此函数的签名如下所示:mcjpegStatus_t mcjpegDecode( mcjpegHandle_t handle, mcjpegJpegState_t jpeg_handle, const unsigned char *data, size_t length, mcjpegOutputFormat_t output_format, mcjpegImage_t *destination, mcStream_t stream);
在上述
mcjpegDecode()函数中,可以使用参数mcjpegOutputFormat_t,mcjpegImage_t和mcStream_t来设置mcjpegDecode()函数的输出行为。 可通过mcStream_t参数指示提交异步任务的流。设置
mcjpegOutputFormat_t参数。mcjpegOutputFormat_t的参数设置可参见下表:表 2.1 mcjpegOutputFormat_t的参数描述 Output_format
含义
MCJPEG_OUTPUT_UNCHANGED
返回编码JPEG的原始图像格式,不做任何转换
MCJPEG_OUTPUT_RGB
转换为planar RGB
MCJPEG_OUTPUT_BGR
转换为planar BGR
MCJPEG_OUTPUT_RGBI
转换为交错排布的RGB
MCJPEG_OUTPUT_BGRI
转换为交错排布的BGR
MCJPEG_OUTPUT_Y
仅返回Y分量
MCJPEG_OUTPUT_YUV
返回YUV planar格式
如上所述,
mcjpegGetImageInfo()函数的一个重要优点是能利用从输入的JPEG图像解析到的图像信息为解码操作分配适当的GPU内存。mcjpegGetImageInfo()函数返回宽度、高度和nComponents参数。mcjpegStatus_t mcjpegGetImageInfo( mcjpegHandle_t handle, const unsigned char *data, size_t length, int *nComponents, mcjpegChromaSubsampling_t *subsampling, int *widths, int *heights);
用户可以使用获取到的参数:宽度,高度和
nComponents,来计算输出缓冲区所需的大小。确保
mcjpegImage_t结构体中填充了已分配缓冲区的指针和行距(pitch)。包含输出指针的mcjpegImage_t结构体定义如下。typedef struct { unsigned char *channel[MCJPEG_MAX_COMPONENT]; size_t pitch[MCJPEG_MAX_COMPONENT]; } mcjpegImage_t;
JPEG库在当前版本中支持的最大分量数为
MCJPEG_MAX_COMPONENT。最后,使用上述参数调用
mcjpegDecode()函数时,mcjpegDecode()函数将解码数据填充到输出缓冲区。
2.2. mcJPEG类型声明
2.2.1. mcJPEG解码后端
typedef enum {
MCJPEG_BACKEND_DEFAULT = 0,
MCJPEG_BACKEND_HYBRID = 1,
MCJPEG_BACKEND_GPU_HYBRID = 2,
MCJPEG_BACKEND_HARDWARE = 3,
MCJPEG_BACKEND_GPU_HYBRID_DEVICE = 4,
MCJPEG_BACKEND_HARDWARE_DEVICE = 5
} mcjpegBackend_t;
mcjpegBackend_t 枚举用于选择解码后端。
备注
目前仅支持 MCJPEG_BACKEND_DEFAULT。
2.2.2. mcJPEG主机固页内存分配器接口
typedef int (*tPinnedMalloc)(void**, size_t, unsigned int flags);
typedef int (*tPinnedFree)(void*);
typedef struct {
tPinnedMalloc pinned_malloc;
tPinnedFree pinned_free;
} mcjpegPinnedAllocator_t;
当在 mcjpegCreateEx() 函数中将 mcjpegPinnedAllocator_t *allocator 参数设置为指向上述 mcjpegPinnedAllocator_t 结构体的指针时,此结构体将用于分配和释放主机固页内存,以便将数据复制到设备或从设备复制数据。
内存分配和内存释放函数的函数原型类似于 mcMallocHost() 和 mcFreeHost() 函数。如果成功,它们将返回0,否则将返回非零。
但是,如果在 mcjpegCreateEx() 函数中将 mcjpegPinnedAllocator_t *allocator 参数设置为NULL,则将使用默认的内存分配函数 mcMallocHost() 和 mcFreeHost()。
使用 mcjpegCreate() 或 mcjpegCreateSimple() 函数创建库句柄时,将使用默认的内存分配器。
2.2.3. mcJPEG图像
typedef struct {
unsigned char *channel[MCJPEG_MAX_COMPONENT];
size_t pitch[MCJPEG_MAX_COMPONENT];
} mcjpegImage_t;
mcjpegImage_t 结构体用于填充已分配缓冲区的指针和行距。 mcjpegImage_t 结构体包含输出指针。
MCJPEG_MAX_COMPONENT:mcJPEG库支持的最大分量数。
2.2.4. mcJPEG设备内存分配器接口
typedef int (*tDevMalloc)(void**, size_t);
typedef int (*tDevFree)(void*);
typedef struct {
tDevMalloc dev_malloc;
tDevFree dev_free;
} mcjpegDevAllocator_t;
用户可以指定库使用自己的设备内存分配器。
内存分配和内存释放函数的函数原型类似于 mcMalloc() 和 mcFree() 函数。
如果成功,它们将返回0,否则将返回非零。
应该为 mcjpegCreate() 函数提供一个指向具有正确填充字段的 mcjpegDevAllocator_t 结构体的指针。
也可设置为NULL,在这种情况下,将使用默认的内存分配函数 mcMalloc() 和 mcFree()。
当在 mcjpegCreate() 或 mcjpegCreateEx() 函数中将 mcjpegDevAllocator_t *allocator 参数设置为指向上述 mcjpegDevAllocator_t 结构体的指针时,此结构体用于分配和释放设备内存。
但是,如果在 mcjpegCreate() 或 mcjpegCreateEx() 函数中将 mcjpegDevAllocator_t *allocator 参数设置为NULL,则将使用默认的内存分配函数 mcMalloc() 和 mcFree()。
使用 mcjpegCreateSimple() 函数创建库句柄时,将使用默认的设备内存分配器。
2.2.5. mcJPEG解码状态句柄
struct mcjpegJpegState;
typedef struct mcjpegJpegState* mcjpegJpegState_t;
mcjpegJpegState 结构体存储临时JPEG信息。在使用之前,应先初始化。此JPEG状态句柄可以重复使用。
2.2.6. mcJPEG库句柄
struct mcjpegHandle;
typedef struct mcjpegHandle* mcjpegHandle_t;
库句柄在使用前应先初始化,库句柄是线程安全的,可由多个线程同时使用。
2.2.7. mcJPEG API返回码
mcJPEG API遵循以下返回码及其指示符:
typedef enum {
MCJPEG_STATUS_SUCCESS = 0,
MCJPEG_STATUS_NOT_INITIALIZED = 1,
MCJPEG_STATUS_INVALID_PARAMETER = 2,
MCJPEG_STATUS_JPEG_NOT_SUPPORTED = 4,
MCJPEG_STATUS_ALLOCATOR_FAILURE = 5,
MCJPEG_STATUS_EXECUTION_FAILED = 6,
MCJPEG_STATUS_ARCH_MISMATCH = 7,
MCJPEG_STATUS_INTERNAL_ERROR=8,
MCJPEG_STATUS_IMPLEMENTATION_NOT_SUPPORTED = 9
} mcjpegStatus_t;
返回的错误(返回码) |
描述 |
|---|---|
MCJPEG_STATUS_SUCCESS (0) |
API调用已成功完成。请注意,许多调用是异步的,且某些错误可能只在同步后才会出现 |
MCJPEG_STATUS_NOT_INITIALIZED (1) |
库句柄未初始化 |
MCJPEG_STATUS_INVALID_PARAMETER (2) |
传递了错误的参数。例如,输入数据为空指针 |
MCJPEG_STATUS_BAD_JPEG (3) |
无法解析JPEG流。需确认编码的JPEG流及其大小参数是否正确 |
MCJPEG_STATUS_JPEG_NOT_SUPPORTED (4) |
尝试对mcJPEG库不支持的JPEG流进行解码 |
MCJPEG_STATUS_ALLOCATOR_FAILURE (5) |
内存分配失败 |
MCJPEG_STATUS_EXECUTION_FAILED (6) |
执行出错 |
MCJPEG_STATUS_ARCH_MISMATCH (7) |
设备不足以满足提供的输入参数集(后端,编码流参数,输出格式等输入参数) |
MCJPEG_STATUS_INTERNAL_ERROR (8) |
执行设备任务时出错 |
MCJPEG_STATUS_IMPLEMENTATION_NOT_SUPPORTED (9) |
功能尚未实现 |
MCJPEG_STATUS_INCOMPLETE_BITSTREAM (10) |
比特流输入数据不完整 |
2.2.8. mcJPEG色度子采样
mcjpegGetImageInfo() API的输出之一是mcjpegChromaSubsampling_t。
该参数为枚举类型,其枚举列表由从编码的JPEG图像中解析到的色度子采样属性组成。 mcjpegGetImageInfo() 函数目前支持以下色度子采样类型:
typedef enum {
MCJPEG_CSS_444,
MCJPEG_CSS_422,
MCJPEG_CSS_420,
MCJPEG_CSS_440,
MCJPEG_CSS_411,
MCJPEG_CSS_410,
MCJPEG_CSS_GRAY,
MCJPEG_CSS_410V,
MCJPEG_CSS_UNKNOWN
} mcjpegChromaSubsampling_t;
2.3. mcJPEG解码API
2.3.1. mcjpegGetProperty()
获取mcJPEG库的主版本号、次版本号或补丁级别的数值。
签名
mcjpegStatus_t mcjpegGetProperty(
libraryPropertyType type,
int *value);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
libraryPropertyType type |
输入 |
主机 |
支持的libraryPropertyType值之一,即MAJOR_VERSION、MINOR_VERSION或PATCH_LEVEL |
int *value |
输出 |
主机 |
请求的特定libraryPropertyType所对应的数值 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.2. mcjpegGetMacartProperty()
获取用于构建mcJPEG库的MXMACA软件包的主版本号、次版本号或补丁级别的数值。 有关mcJPEG库的信息,请参见 2.3.1 mcjpegGetProperty()。
签名
mcjpegStatus_t mcjpegGetMacartProperty(
libraryPropertyType type,
int *value);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
libraryPropertyType type |
输入 |
主机 |
支持的libraryPropertyType值之一,即MAJOR_VERSION、MINOR_VERSION或PATCH_LEVEL |
int *value |
输出 |
主机 |
请求的特定libraryPropertyType所对应的数值 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.3. mcjpegCreateSimple()
使用库默认的编解码器实现和内存分配器分配和初始化库句柄。
签名
mcjpegStatus_t mcjpegCreateSimple(mcjpegHandle_t *handle);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegHandle_t *handle |
输入/输出 |
主机 |
库句柄 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.4. mcjpegCreateEx()
使用提供的参数分配和初始化库句柄。
签名
mcjpegStatus_t mcjpegCreateEx(
mcjpegBackend_t backend,
mcjpegDevAllocator_t *dev_allocator,
mcjpegPinnedAllocator_t *pinned_allocator,
unsigned int flags,
mcjpegHandle_t *handle);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegBackend_t backend |
输入 |
主机 |
后端参数。如果为DEFAULT,则将自动选择其中一个底层算法 |
mcjpegDevAllocator_t *dev_allocator |
输入 |
主机 |
设备内存分配器。 |
mcjpegPinnedAllocator_t *pinned_allocator |
输入 |
主机 |
主机固页内存分配器。 |
unsigned int flags |
输入 |
主机 |
初始化库时,可以附加额外的控制标志。当前仅支持 MCJPEG_FLAGS_DEFAULT |
mcjpegHandle_t *handle |
输入/输出 |
主机 |
库句柄 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.5. mcjpegDestroy()
销毁库句柄
签名
mcjpegStatus_t mcjpegDestroy(mcjpegHandle_t handle);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegHandle_t handle |
输入/输出 |
主机 |
要销毁的库句柄 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.6. mcjpegGetHardwareDecoderInfo()
获取硬件解码器详细信息,如引擎数量和每个引擎中可用的核心数量。
签名
mcjpegStatus_t mcjpegGetHardwareDecoderInfo(
mcjpegHandle_t handle,
unsigned int* num_engines,
unsigned int* num_cores_per_engine);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegHandle_t handle |
输入 |
主机 |
库句柄 |
unsigned int* num_engines |
输入/输出 |
主机 |
可用于解码的引擎数量。返回值0表示硬件解码器不可用 |
unsigned int* num_cores_per_engine |
输入/输出 |
主机 |
每个引擎的核心数量。返回值0表示硬件解码器不可用 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.7. mcjpegJpegStateCreate()
分配和初始化JPEG处理所需的内部结构体。
签名
mcjpegStatus_t mcjpegJpegStateCreate(
mcjpegHandle_t handle,
mcjpegJpegState_t *jpeg_handle);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegHandle_t handle |
输入 |
主机 |
库句柄 |
mcjpegJpegState_t *jpeg_handle |
输入/输出 |
主机 |
解码状态句柄 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.8. mcjpegJpegStateDestroy()
销毁解码状态内部结构。
签名
mcjpegStatus_t mcjpegJpegStateDestroy(mcjpegJpegState handle);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegJpegState handle |
输入/输出 |
主机 |
解码状态句柄 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.3.9. mcjpegGetImageInfo()
解析JPEG头部,获取图像的基本信息。
签名
mcjpegStatus_t mcjpegGetImageInfo(
mcjpegHandle_t handle,
const unsigned char *data,
size_t length,
int *nComponents,
mcjpegChromaSubsampling_t *subsampling,
int *widths,
int *heights);
参数
参数 |
输入/输出 |
内存 |
描述 |
|---|---|---|---|
mcjpegHandle_t handle |
输入 |
主机 |
库句柄 |
const unsigned char *data |
输入 |
主机 |
此指针指向编码数据 |
size_t length |
输入 |
主机 |
编码数据的大小,以字节为单位 |
int *nComponents |
输出 |
主机 |
图像的component数目 |
int *widths |
输出 |
主机 |
此指针指向数组第一个元素,数组大小为MCJPEG_MAX_COMPONENT,其中将保存每个通道的宽度(最多MCJPEG_MAX_COMPONENT个)。如果通道未编码,则相应的值为零 |
int *heights |
输出 |
主机 |
此指针指向数组第一个元素,数组大小为MCJPEG_MAX_COMPONENT,其中将保存每个通道的高度(最多MCJPEG_MAX_COMPONENT个)。如果通道未编码,则相应的值为零 |
返回值
mcjpegStatus_t - 错误码,详情参见 2.2.7 mcJPEG API返回码。
2.4. mcJPEG解码示例
mcSetDevice(0);
//创建mcjpeg的库句柄
mcjpegHandle_t mcjpegHandle;
mcjpegCreateSimple(&mcjpegHandle);
//创建mcjpeg解码的状态
mcjpegJpegState_t mcjpegState;
mcjpegJpegStateCreate(mcjpegHandle,&mcjpegState);
//获取要解码图像的基本信息
//假设data指针指向要解码的图像数据
//size是数据长度
int widths[MCJPEG_MAX_COMPONENT];
int heights[MCJPEG_MAX_COMPONENT];
int channels;
mcjpegChromaSubsampling_t subsampling;
mcjpegGetImageInfo(mcjpegHandle,data,size,&channels,&subsampling,widths,heights);
//分配用以保存解码数据的设备内存
unsigned char * pBuffer = NULL;
mcMalloc(&pBuffer, widths[0] * heights[0] * MCJPEG_MAX_COMPONENT);
mcjpegImage_t imgdesc =
{
{
pBuffer,
pBuffer + widths[0]*heights[0],
pBuffer + widths[0]*heights[0]*2,
pBuffer + widths[0]*heights[0]*3
},
{
(unsigned int)widths[0],
(unsigned int)widths[0],
(unsigned int)widths[0],
(unsigned int)widths[0]
}
};
//创建用于解码的流
mcStream_t stream;
mcStreamCreateWithFlags(&stream,mcStreamNonBlocking);
//进行解码
mcjpegDecode(mcjpegHandle,mcjpegState,data,size,MCJPEG_OUTPUT_YUV,&imgdesc,stream);
mcStreamSynchronize(stream);
//到现在为止,我们在imgdesc结构体中获取解码的图像数据
//在此处添加代码以使用图像数据
//不要忘记释放资源
mcFree(pBuffer);
mcjpegJpegStateDestroy(mcjpegState);
mcjpegDestroy(mcjpegHandle);
mcStreamDestroy(stream);