JPEGE

This section describes the API call sequence of JPEGE, and sample code is also provided to help you better understand the process.

The JPEG encoder (JPEGE) encodes YUV images into .jpg images. For details about the JPEGE function and restrictions, see DVPP Media Acceleration Library.

API Call Sequence

Figure 1 Process of calling the JPEGE image encoding function
The current system supports encoding YUV images into JPEG images. The key APIs are described as follows:
  1. Initialize resources.
    1. Call aclInit to initialize the system.
    2. Call aclrtSetDevice to specify the compute device.
    3. Call the hi_mpi_sys_init interface to initialize the media data processing system.
    4. Call the hi_mpi_venc_create_chn function to create a channel.

      After a channel is created, you can set the advanced encoding parameters as required, such as the scenario mode and advanced parameters of the stream controller. For details, see the API description in hi_mpi_venc_set_jpeg_param~hi_mpi_venc_compact_jpeg_tables.

    5. Call hi_mpi_venc_get_fd to convert the channel ID into a file descriptor.
    6. Call the hi_mpi_sys_create_epoll function to create a DVPP epoll instance.

      Note: In Ctrl CPU open form mode, to be compatible with earlier versions, the method of calling the select or poll function of the Linux OS in the application of an earlier version is still available when the encoding is complete. You are advised to use the API call sequence shown in the preceding figure to ensure the evolution of later versions.

    7. Call the hi_mpi_sys_ctl_epoll function to add the file descriptor of the encoding channel to the epoll instance. The epoll instance processes the file descriptor.

      Skip this step if the select or poll function is used.

  2. Encode images.
    1. Call the hi_mpi_venc_start_chn function to notify the channel to start encoding.
    2. Call the hi_mpi_dvpp_malloc API to allocate memory for storing the input data on the device.
    3. Start a user-mode thread and call the hi_mpi_sys_wait_epoll function to wait until the encoding is complete.
    4. Then, you can call the hi_mpi_venc_send_frame function to send the stream to be encoded.
    5. Once the encoding is complete, the hi_mpi_sys_wait_epoll, select, or poll function returns. You can call the hi_mpi_venc_query_status API to query the encoding status and then call the hi_mpi_venc_get_stream API to obtain the encoding result.
    6. Note that you need to call the hi_mpi_venc_release_stream function to release the buffer after the encoding result data is used. Otherwise, no more encoding task can be performed because the encoding buffer is used up.
    7. Call the hi_mpi_dvpp_free interface to release the input buffer.
    8. If you do not need to send images to the destination channel for encoding, you need to call the hi_mpi_venc_stop_chn function to notify the channel not to receive new input images.
  3. Destroy allocations.
    1. Call the hi_mpi_sys_ctl_epoll function to delete the file descriptor of the encoding channel from the epoll instance.
    2. After encoding is complete, you need to call hi_mpi_venc_destroy_chn to release the encoding channel and internal memory resources.
    3. Call the hi_mpi_sys_close_epoll function to destroy the DVPP epoll instance.
    4. Deinitialize the media data processing system by calling hi_mpi_sys_exit.
    5. Call aclrtResetDevice to reset the device and free the resources on the device.
    6. Call aclFinalize to deinitialize the system and free the resources used by the acl API in the process.

Sample Code

The following is a code example of the key steps of JPEGE image encoding. It is for reference only and cannot be directly copied for compilation and running. After APIs are called, you need to add exception handling branches and record error logs and info logs.

You can click jpege_sample to obtain the sample.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 1. Initialize the media data processing system.
int32_t ret = hi_mpi_sys_init();

// 2. Create a channel.
hi_venc_chn chn = 0;
hi_venc_chn_attr attr{};
attr.venc_attr.type = HI_PT_JPEG;
attr.venc_attr.profile = 0;
attr.venc_attr.max_pic_width = 128;
attr.venc_attr.max_pic_height = 128;
attr.venc_attr.pic_width = 128;
attr.venc_attr.pic_height = 128;
attr.venc_attr.buf_size = 2 * 1024 * 1024;
attr.venc_attr.is_by_frame = HI_TRUE;
attr.venc_attr.jpeg_attr.dcf_en = HI_FALSE;
attr.venc_attr.jpeg_attr.recv_mode = HI_VENC_PIC_RECV_SINGLE;
attr.venc_attr.jpeg_attr.mpf_cfg.large_thumbnail_num = 0;
ret = hi_mpi_venc_create_chn(chn, &attr);

// 3. Instruct the encoder to start receiving input data.
hi_venc_start_param recv_param{};
recv_param.recv_pic_num = -1;
ret = hi_mpi_venc_start_chn(chn, &recv_param);

// 4. Send the input data.
// 4.1 Allocate input buffer.
uint8_t* inputAddr = nullptr;
int32_t inputSize = 128 * 128 * 3 / 2;
ret = hi_mpi_dvpp_malloc(0, &inputAddr, inputSize);
// Read the input data into the memory. The user-defined function JpegeReadYuvFile is implemented by the user.
JpegeReadYuvFile(streamName, inputAddr, inputSize);

// 4.2 Send the input data and start encoding.
hi_video_frame_info frame{};
frame.mod_id = HI_ID_VENC;
frame.v_frame.width = 128;
frame.v_frame.height = 128;
frame.v_frame.field = HI_VIDEO_FIELD_FRAME;
frame.v_frame.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
frame.v_frame.video_format = HI_VIDEO_FORMAT_LINEAR;
frame.v_frame.compress_mode = HI_COMPRESS_MODE_NONE;
frame.v_frame.dynamic_range = HI_DYNAMIC_RANGE_SDR8;
frame.v_frame.color_gamut = HI_COLOR_GAMUT_BT709;
frame.v_frame.width_stride[0] = 128;
frame.v_frame.width_stride[1] = 128;
frame.v_frame.width_stride[2] = 128;
frame.v_frame.virt_addr[0] = inputAddr;
frame.v_frame.virt_addr[1] = (hi_void *)((uintptr_t)frame.v_frame.virt_addr[0] + 128 * 128);
frame.v_frame.frame_flag = 0;
frame.v_frame.time_ref = 0;
frame.v_frame.pts = 0;
ret = hi_mpi_venc_send_frame(chn, &frame, 0);

// 5. Obtain the encoding result.
//5.1 Create an epoll instance.
int32_t epollFd = 0;
int32_t fd = hi_mpi_venc_get_fd(chn);
ret = hi_mpi_sys_create_epoll(10, &epollFd);

hi_dvpp_epoll_event event;
event.events = HI_DVPP_EPOLL_IN;
event.data = (void*)(unsigned long)(fd);
ret = hi_mpi_sys_ctl_epoll(epollFd, HI_DVPP_EPOLL_CTL_ADD, fd, &event);

int32_t eventCount = 0;
// Before the encoding is complete, timeout occurs. The next step is not performed until the encoding is complete.
ret = hi_mpi_sys_wait_epoll(epollFd, event, 3, 1000, &eventCount);

// 5.2 Obtain the encoding result.
hi_venc_chn_status stat;
ret = hi_mpi_venc_query_status(chn, &stat);
hi_venc_stream stream;
stream.pack_cnt = stat.cur_packs;
stream.pack = new hi_venc_pack[stream.pack_cnt];
ret = hi_mpi_venc_get_stream(chn, &stream, 1000);

// 5.3 Obtain the encoded output stream data in the memory pointed to by stream.pack[0].addr.
......

// 6. Free the input buffer and release the output streams.
ret = hi_mpi_dvpp_free(inputAddr);
ret = hi_mpi_venc_release_stream(chn, &stream);
delete[] stream.pack;

// 7. Notify the encoder to stop receiving input data.
ret = hi_mpi_venc_stop_chn(chn);
ret = hi_mpi_sys_ctl_epoll(epollFd, HI_DVPP_EPOLL_CTL_DEL, fd, NULL);
ret = hi_mpi_sys_close_epoll(epollFd);

// 8. Destroy the channel.
ret = hi_mpi_venc_destroy_chn(chn);

// 9. Deinitialize the media data processing system.
ret = hi_mpi_sys_exit();

....