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 functions and restrictions, see JPEGE Functions and Restrictions.

API Call Sequence

If a YUV image needs to be encoded into a JPEG image during app development, ensure that your app contains the code logic for such image encoding. For details about the API call sequence, see API Call Sequence.

Figure 1 API call sequence
The current system supports encoding YUV images into JPEG images. The key APIs are described as follows:
  1. Initialize resources.
    1. Call hi_mpi_sys_init to initialize the media data processing system.
    2. Call hi_mpi_venc_create_chn to create a channel.

      After creating a channel, you can set advanced encoding parameters such as the scene mode and stream controller as required. For details, see hi_mpi_venc_set_jpeg_param to hi_mpi_venc_compact_jpeg_tables.

    3. Call hi_mpi_venc_get_fd to obtain the file descriptor corresponding to the channel ID.
    4. Call hi_mpi_sys_create_epoll to create a DVPP epoll instance.
    5. Call hi_mpi_sys_ctl_epoll to add the file descriptor corresponding to the encoding channel to the epoll instance.

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

  2. Encode images.
    1. Call hi_mpi_venc_start_chn to notify the channel to start encoding.
    2. Call hi_mpi_dvpp_malloc to allocate the device buffer to store the input data.
    3. Start a user-mode thread and call hi_mpi_sys_wait_epoll to wait for the epoll instance to complete encoding.
    4. Call hi_mpi_venc_send_frame to feed your stream to the encoder.
    5. Once the encoding is complete, the hi_mpi_sys_wait_epoll, select, or poll function returns a value. Call hi_mpi_venc_query_status to query the encoding status and call hi_mpi_venc_get_stream to obtain the encoding result.
    6. Call hi_mpi_venc_release_stream to free the buffer in time when the encoding result is no longer needed. Otherwise, no more encoding task can be performed because the encoding buffer is used up.
    7. Call hi_mpi_dvpp_free to free the input buffer.
    8. When the source images have been completely fed, call hi_mpi_venc_stop_chn to stop the channel from receiving new images.
  3. Destroy resources.
    1. Call hi_mpi_sys_ctl_epoll to delete the encoding channel file descriptor from the epoll instance.
    2. After all encoding tasks are complete, call hi_mpi_venc_destroy_chn to destroy the encoding channel and free the memory.
    3. Call hi_mpi_sys_close_epoll to destroy the DVPP epoll instance.
    4. Call hi_mpi_sys_exit to deinitialize the media data processing system.
The output buffer can be managed by DVPP internally or by users.
  • Managed by DVPP: Call hi_mpi_venc_send_frame to send source images for encoding.

    When creating a channel by calling hi_mpi_venc_create_chn, you must properly set hi_venc_chn_attr.venc_attr.buf_size. For details about the parameter description, see hi_venc_attr.

    In this mode, the JPEG header of the output data does not contain the COM comment field, and the data length is smaller. However, you need to copy the output data from the buffer returned by DVPP to the specified memory.

  • Managed by users: Call hi_mpi_venc_send_jpege_frame to send source images for encoding.

    When creating a channel by calling hi_mpi_venc_create_chn, set hi_venc_chn_attr.venc_attr.buf_size to 0 (for details about the parameter description, see hi_venc_attr). Call hi_mpi_venc_get_jpege_predicted_size to predict the output buffer size and call hi_mpi_dvpp_malloc or hi_mpi_dvpp_free to allocate or free the output buffer.

    In this mode, the output buffer address is set when hi_mpi_venc_send_jpege_frame is called. The output data is directly stored in the buffer set by the user. Compared with the other mode, this mode does not require you to copy the output data from the buffer returned by DVPP to the specified memory. However, the JPEG header of the output data may contain the COM comment field (whose length ranges from 4 bytes to 19 bytes), and thus the data length is larger.

Sample Code

You can view the complete code in Media Data Processing V2 (JPEGE).

This section focuses on the code logic for encoding JPEGE images. For details about how to perform initialization and deinitialization, see Initialization and Deinitialization. For details about how to allocate and deallocate runtime resources, see Runtime Resource Allocation and Deallocation.

After APIs are called, add an exception handling branch, and record error logs and warning logs. The following is a code snippet of key steps only, which is not ready to be built or run.

  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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 1. Perform initialization.

// 2. Allocate runtime resources.

// 3. Initialize the media data processing system.
int32_t ret = hi_mpi_sys_init();

// 4. 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);

// 5. Notify 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);

// 6. Send the input data.
// 6.1 Allocate input buffer.
uint8_t* inputAddr = nullptr;
int32_t inputSize = 128 * 128 * 3 / 2;
ret = hi_mpi_dvpp_malloc(0, &inputAddr, inputSize);

// If the run mode is ACL_HOST, allocate the host buffer, load the input image data into the host buffer, and call aclrtMemcpy to transfer the host image data to the device. After the data transfer is complete, free the host buffer in a timely manner. In other modes, directly load the input image data into the device buffer.
// runMode indicates the running mode of the software stack, which can be obtained through aclrtGetRunMode.
if (runMode == ACL_HOST) {
    void* hostInputAddr = nullptr;
    //Allocate the host buffer.
    aclRet = aclrtMallocHost(&hostInputAddr, inputSize);
    // Load the input data into the buffer. The function JpegeReadYuvFile is implemented by the user.
    JpegeReadYuvFile(streamName, hostInputAddr, inputSize);
    // Transfer data.
    aclRet = aclrtMemcpy(inputAddr, inputSize, hostInputAddr, inputSize, ACL_MEMCPY_HOST_TO_DEVICE);
    // Free the buffer in a timely manner after data transfer is complete.
    aclrtFreeHost(hostInputAddr );
    hostInputAddr = nullptr;
} else {
    // Load the input data into the buffer. The function JpegeReadYuvFile is implemented by the user.
    JpegeReadYuvFile(streamName, inputAddr, inputSize);
}

// 6.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);

// 7. Obtain the encoding result.
// 7.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);

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

//7.3 If the run mode is ACL_HOST and the host needs to use the encoded streams, allocate the host buffer and call aclrtMemcpy to transfer the output streams from the device to the host. In other modes, directly use the encoded streams.
if (g_runMode == ACL_HOST) {
    void* hostOutputAddr = nullptr;
    aclRet = aclrtMallocHost(&hostOutputAddr, outputSize);
    aclRet = aclrtMemcpy(hostOutputAddr, outputSize, stream.pack[0].addr, outputSize, ACL_MEMCPY_DEVICE_TO_HOST);
    // ......
    // After data is used, free the buffer in a timely manner.
    aclrtFreeHost(hostOutputAddr);
    hostOutputAddr = nullptr;
} else {
    // You can directly use the encoded streams, which are stored in the buffer specified by stream.pack[0].addr.
    // ......
}

// 8. 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;

// 9. 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);

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

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

// 12. Deallocate runtime resources.

// 13. Perform deinitialization.

// ....