2. JPEG解码

2.1. 使用JPEG解码

要进行解码,需提供数据大小和指向文件数据的指针。解码后的图像会放在输出缓冲区中。

要使用mcJPEG库,请先调用初始化的辅助函数。

  1. 使用辅助函数 mcjpegCreateSimple()mcjpegCreateEx() 创建mcJPEG库句柄。

  2. 使用辅助函数 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

  3. 使用 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() 函数是线程安全的。

  4. mcjpegGetImageInfo() 函数的输出之一是 mcjpegChromaSubsampling_t,该参数为枚举类型,其枚举列表由从JPEG图像解析出的色度子采样属性组成。 更多信息,参见 2.2.8 mcJPEG色度子采样

  5. 使用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_tmcjpegImage_tmcStream_t 来设置 mcjpegDecode() 函数的输出行为。 可通过 mcStream_t 参数指示提交异步任务的流。

  6. 设置 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格式

  7. 如上所述, 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,来计算输出缓冲区所需的大小。

  8. 确保 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

  9. 最后,使用上述参数调用 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;
表 2.2 错误码描述

返回的错误(返回码)

描述

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_VERSIONMINOR_VERSIONPATCH_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_VERSIONMINOR_VERSIONPATCH_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

输入

主机

设备内存分配器。 mcjpegDevAllocator_t 结构体说明,参见 2.2.4 mcJPEG设备内存分配器接口。如果为NULL,则将使用默认的MXMACA运行时函数 mcMalloc()mcFree()

mcjpegPinnedAllocator_t *pinned_allocator

输入

主机

主机固页内存分配器。 mcjpegPinnedAllocator_t 结构体说明,参见 2.2.2 mcJPEG主机固页内存分配器接口。如果为NULL,则将使用默认的MXMACA运行时函数 mcMallocHost()mcFreeHost()

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