This commit is contained in:
刘可亮
2024-09-03 11:16:08 +08:00
parent cf270df8d6
commit 803cac77d5
2931 changed files with 614364 additions and 31222 deletions

View File

@@ -0,0 +1,360 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: jpeg encoder
*/
#include <stdio.h>
#include <string.h>
#include "ve.h"
#include "ve_buffer.h"
#include "put_bits.h"
#include "jpeg_tables.h"
#include "jpeg_enc_ctx.h"
#include "mpp_mem.h"
#include "mpp_log.h"
static s32 __mjpeg_encode_init(struct mpp_encoder *ctx, struct encode_config *config)
{
if (!ctx || !config)
return -1;
struct jpeg_ctx *impl = (struct jpeg_ctx *)ctx;
impl->ve_fd = ve_open_device();
if (impl->ve_fd < 0) {
loge("ve open failed");
return -1;
}
impl->config.quality = config->quality;
impl->regs_base = ve_get_reg_base();
impl->alloc = ve_buffer_allocator_create(VE_BUFFER_TYPE_DMA);
mjpeg_build_huffman_codes(impl->huff_size_dc_luminance,
impl->huff_code_dc_luminance,
avpriv_mjpeg_bits_dc_luminance,
avpriv_mjpeg_val_dc);
mjpeg_build_huffman_codes(impl->huff_size_dc_chrominance,
impl->huff_code_dc_chrominance,
avpriv_mjpeg_bits_dc_chrominance,
avpriv_mjpeg_val_dc);
mjpeg_build_huffman_codes(impl->huff_size_ac_luminance,
impl->huff_code_ac_luminance,
avpriv_mjpeg_bits_ac_luminance,
avpriv_mjpeg_val_ac_luminance);
mjpeg_build_huffman_codes(impl->huff_size_ac_chrominance,
impl->huff_code_ac_chrominance,
avpriv_mjpeg_bits_ac_chrominance,
avpriv_mjpeg_val_ac_chrominance);
return 0;
}
s32 __mjpeg_encode_destroy(struct mpp_encoder *ctx)
{
if (!ctx)
return -1;
struct jpeg_ctx *impl = (struct jpeg_ctx *)ctx;
ve_close_device();
ve_buffer_allocator_destroy(impl->alloc);
mpp_free(impl);
return 0;
}
/* table_class: 0 = DC coef, 1 = AC coefs */
static int put_huffman_table(struct put_bit_ctx *p, int table_class, int table_id,
const uint8_t *bits_table, const uint8_t *value_table)
{
int n, i;
put_bits(p, 4, table_class);
put_bits(p, 4, table_id);
n = 0;
for (i = 1; i <= 16; i++) {
n += bits_table[i];
put_bits(p, 8, bits_table[i]);
}
for (i = 0; i < n; i++)
put_bits(p, 8, value_table[i]);
return n + 17;
}
static inline void put_marker(struct put_bit_ctx *p, enum JpegMarker code)
{
put_bits(p, 8, 0xff);
put_bits(p, 8, code);
}
static void jpeg_table_header(struct jpeg_ctx* s, struct put_bit_ctx *p)
{
int i, j, size;
uint8_t *ptr;
/* quant matrixes */
put_marker(p, DQT);
put_bits(p, 16, 2 + 2 * (1 + 64));
put_bits(p, 4, 0); /* 8 bit precision */
put_bits(p, 4, 0); /* table 0 */
for (i = 0; i < 64; i++) {
j = zigzag_direct[i];
put_bits(p, 8, s->luma_quant_table[j]);
}
put_bits(p, 4, 0); /* 8 bit precision */
put_bits(p, 4, 1); /* table 1 */
for (i = 0; i < 64; i++) {
j = zigzag_direct[i];
put_bits(p, 8, s->chroma_quant_table[j]);
}
/* huffman table */
put_marker(p, DHT);
flush_put_bits(p);
ptr = put_bits_ptr(p);
put_bits(p, 16, 0); /* patched later */
size = 2;
size += put_huffman_table(p, 0, 0, avpriv_mjpeg_bits_dc_luminance,
avpriv_mjpeg_val_dc);
size += put_huffman_table(p, 0, 1, avpriv_mjpeg_bits_dc_chrominance,
avpriv_mjpeg_val_dc);
size += put_huffman_table(p, 1, 0, avpriv_mjpeg_bits_ac_luminance,
avpriv_mjpeg_val_ac_luminance);
size += put_huffman_table(p, 1, 1, avpriv_mjpeg_bits_ac_chrominance,
avpriv_mjpeg_val_ac_chrominance);
ptr[0] = (size >> 8) & 0xff;
ptr[1] = (size) & 0xff;
}
static void jpeg_encode_pic_header(struct jpeg_ctx* s)
{
put_marker(&s->pb, SOI);
jpeg_table_header(s, &s->pb);
put_marker(&s->pb, SOF0);
int len = 2 + 1 + 2 + 2 + 1 + 3 * s->comp_num;
put_bits(&s->pb, 16, len);
put_bits(&s->pb, 8, 8); /* precision 8 bits/component */
if (s->cur_frame->buf.crop_en) {
put_bits(&s->pb, 16, s->cur_frame->buf.crop.height);
put_bits(&s->pb, 16, s->cur_frame->buf.crop.width);
} else {
put_bits(&s->pb, 16, s->height);
put_bits(&s->pb, 16, s->width);
}
put_bits(&s->pb, 8, s->comp_num); /* 3 or 4 components */
/* Y component */
put_bits(&s->pb, 8, 1); /* component number */
put_bits(&s->pb, 4, s->h_count[0]); /* H factor */
put_bits(&s->pb, 4, s->v_count[0]); /* V factor */
put_bits(&s->pb, 8, 0); /* select quant table */
if (s->comp_num > 1) {
/* Cb */
put_bits(&s->pb, 8, 2); /* component number */
put_bits(&s->pb, 4, s->h_count[1]); /* H factor */
put_bits(&s->pb, 4, s->v_count[1]); /* V factor */
put_bits(&s->pb, 8, 1); /* select quant table */
/* Cr */
put_bits(&s->pb, 8, 3); /* component number */
put_bits(&s->pb, 4, s->h_count[2]); /* H factor */
put_bits(&s->pb, 4, s->v_count[2]); /* V factor */
put_bits(&s->pb, 8, 1); /* select quant table */
}
logi("offset: %d", put_bits_count(&s->pb) / 8);
// the start address of VE must be 8 bytes aligned,
// we cannot pad 0x00 here, because some customer app
// cannot compatible this case.
// So we use COM marker.
int pad = (put_bits_count(&s->pb) / 8) % 8;
if (pad) {
pad = 8 - pad;
if (pad < 4) {
pad += 8;
}
put_marker(&s->pb, COM);
put_bits(&s->pb, 16, pad-2); // length
pad -= 4;
while (pad--) {
put_bits(&s->pb, 8, 0);
}
}
flush_put_bits(&s->pb);
s->header_offset = put_bits_count(&s->pb) / 8;
}
static void jpeg_init_hvcount(struct jpeg_ctx* s)
{
s->h_count[1] = s->h_count[2] = 1;
s->v_count[1] = s->v_count[2] = 1;
s->comp_num = 3;
s->uv_interleave = 0;
if (s->cur_frame->buf.format == MPP_FMT_YUV400) {
s->h_count[0] = s->v_count[0] = 1;
s->comp_num = 1;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV444P) {
s->h_count[0] = s->v_count[0] = 1;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV420P ||
s->cur_frame->buf.format == MPP_FMT_NV12) {
s->h_count[0] = s->v_count[0] = 2;
s->uv_interleave = s->cur_frame->buf.format != MPP_FMT_YUV420P;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV422P) {
s->h_count[0] = 2;
s->v_count[0] = 1;
} else {
loge("not supprt this format: %d", s->cur_frame->buf.format);
}
}
static void set_quality(struct jpeg_ctx* s)
{
int i;
if (s->quality <= 0)
s->quality = 1;
if (s->quality > 100)
s->quality = 100;
// 1. quality = 1, produce "worst" quality, 5000*std_quant_table
// 2. quality = 50, produce "good" quality, std_quant_table
// 3. quality =100, produce "best" quality, the value of table are all 1
if (s->quality < 50) {
s->quality = 5000 / s->quality;
} else {
s->quality = 200 - s->quality * 2;
}
for (i=0; i<64; i++) {
s->luma_quant_table[i] = (std_luminance_quant_tbl[i] * s->quality + 50) / 100;
if (s->luma_quant_table[i] <= 0)
s->luma_quant_table[i] = 1;
if (s->luma_quant_table[i] > 255)
s->luma_quant_table[i] = 255;
s->chroma_quant_table[i] = (std_chrominance_quant_tbl[i] * s->quality + 50) / 100;
if (s->chroma_quant_table[i] <= 0)
s->chroma_quant_table[i] = 1;
if (s->chroma_quant_table[i] > 255)
s->chroma_quant_table[i] = 255;
}
}
int __mpp_encode_jpeg(struct mpp_encoder *ctx, struct mpp_frame* frame, struct mpp_packet* packet)
{
if (!ctx)
return -1;
struct jpeg_ctx *s = (struct jpeg_ctx *)ctx;
int ret = 0;
int i;
int comp = 3;
if (frame->buf.format == MPP_FMT_NV12) {
comp = 2;
} else if (frame->buf.format == MPP_FMT_YUV420P
|| frame->buf.format == MPP_FMT_YUV422P) {
comp = 3;
} else if (frame->buf.format == MPP_FMT_YUV400) {
comp = 1;
} else {
loge("unsupport format, %d", frame->buf.format);
return -1;
}
s->width = frame->buf.size.width;
s->height = frame->buf.size.height;
s->quality = s->config.quality;
s->y_stride = frame->buf.stride[0];
set_quality(s);
s->stream_num = packet->size / 256;
s->bitstream_vir_addr = (unsigned char *)(unsigned long)packet->phy_addr;
s->bitstream_phy_addr = packet->phy_addr;
s->cur_frame = frame;
init_put_bits(&s->pb, s->bitstream_vir_addr, packet->size);
for (i=0; i<comp; i++) {
s->phy_addr[i] = frame->buf.phy_addr[i];
}
jpeg_init_hvcount(s);
jpeg_encode_pic_header(s);
// we should flush (s->header_offset + 64) bytes, because
// flush_put_bits will write some data of SOS
ve_buffer_sync_range(NULL, s->bitstream_vir_addr, s->header_offset + 64, CACHE_CLEAN);
if (jpeg_hw_encode(s) < 0) {
loge("encode failed");
ret = -1;
goto out;
}
if (s->encode_data_len > packet->size) {
loge("buf len(%d) is too small, we need (%d) bytes",
packet->size, s->encode_data_len + s->header_offset);
ret = -1;
goto out;
}
packet->len = s->encode_data_len;
ve_buffer_sync_range(NULL, s->bitstream_vir_addr, s->encode_data_len, CACHE_INVALID);
out:
return ret;
}
int __mjpeg_encode_control(struct mpp_encoder *ctx, int cmd, void *param)
{
// TODO
return 0;
}
int __mjpeg_encode_reset(struct mpp_encoder *ctx)
{
// TODO
return 0;
}
struct enc_ops mjpeg_encoder = {
.name = "mjpeg",
.init = __mjpeg_encode_init,
.destory = __mjpeg_encode_destroy,
.encode = __mpp_encode_jpeg,
.control = __mjpeg_encode_control,
.reset = __mjpeg_encode_reset,
};
struct mpp_encoder* create_jpeg_encoder()
{
struct jpeg_ctx *s = (struct jpeg_ctx*)mpp_alloc(sizeof(struct jpeg_ctx));
if(s == NULL) {
loge("malloc jpeg_ctx failed");
return NULL;
}
memset(s, 0, sizeof(struct jpeg_ctx));
s->encoder.ops = &mjpeg_encoder;
return &s->encoder;
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: jpeg enc context
*/
#ifndef JPEG_ENC_CTX_H
#define JPEG_ENC_CTX_H
#include <unistd.h>
#include "put_bits.h"
#include "jpeg_tables.h"
#include "mpp_codec.h"
#define QUANT_FIXED_POINT_BITS 19
#define ALIGN_4K(x) (((x) + 4095) & ~(4095))
/* JPEG marker codes */
enum JpegMarker {
/* start of frame */
SOF0 = 0xc0, /* baseline */
SOF1 = 0xc1, /* extended sequential, huffman */
SOF2 = 0xc2, /* progressive, huffman */
SOF3 = 0xc3, /* lossless, huffman */
SOF5 = 0xc5, /* differential sequential, huffman */
SOF6 = 0xc6, /* differential progressive, huffman */
SOF7 = 0xc7, /* differential lossless, huffman */
JPG = 0xc8, /* reserved for JPEG extension */
SOF9 = 0xc9, /* extended sequential, arithmetic */
SOF10 = 0xca, /* progressive, arithmetic */
SOF11 = 0xcb, /* lossless, arithmetic */
SOF13 = 0xcd, /* differential sequential, arithmetic */
SOF14 = 0xce, /* differential progressive, arithmetic */
SOF15 = 0xcf, /* differential lossless, arithmetic */
DHT = 0xc4, /* define huffman tables */
DAC = 0xcc, /* define arithmetic-coding conditioning */
/* restart with modulo 8 count "m" */
RST0 = 0xd0,
RST1 = 0xd1,
RST2 = 0xd2,
RST3 = 0xd3,
RST4 = 0xd4,
RST5 = 0xd5,
RST6 = 0xd6,
RST7 = 0xd7,
SOI = 0xd8, /* start of image */
EOI = 0xd9, /* end of image */
SOS = 0xda, /* start of scan */
DQT = 0xdb, /* define quantization tables */
DNL = 0xdc, /* define number of lines */
DRI = 0xdd, /* define restart interval */
DHP = 0xde, /* define hierarchical progression */
EXP = 0xdf, /* expand reference components */
APP0 = 0xe0,
APP1 = 0xe1,
APP2 = 0xe2,
APP3 = 0xe3,
APP4 = 0xe4,
APP5 = 0xe5,
APP6 = 0xe6,
APP7 = 0xe7,
APP8 = 0xe8,
APP9 = 0xe9,
APP10 = 0xea,
APP11 = 0xeb,
APP12 = 0xec,
APP13 = 0xed,
APP14 = 0xee,
APP15 = 0xef,
JPG0 = 0xf0,
JPG1 = 0xf1,
JPG2 = 0xf2,
JPG3 = 0xf3,
JPG4 = 0xf4,
JPG5 = 0xf5,
JPG6 = 0xf6,
SOF48 = 0xf7, ///< JPEG-LS
LSE = 0xf8, ///< JPEG-LS extension parameters
JPG9 = 0xf9,
JPG10 = 0xfa,
JPG11 = 0xfb,
JPG12 = 0xfc,
JPG13 = 0xfd,
COM = 0xfe, /* comment */
TEM = 0x01, /* temporary private use for arithmetic coding */
/* 0x02 -> 0xbf reserved */
};
struct jpeg_ctx {
struct mpp_encoder encoder;
unsigned int luma_quant_table[64];
unsigned int chroma_quant_table[64];
uint8_t huff_size_dc_luminance[12]; ///< DC luminance Huffman table size.
uint16_t huff_code_dc_luminance[12]; ///< DC luminance Huffman table codes.
uint8_t huff_size_dc_chrominance[12]; ///< DC chrominance Huffman table size.
uint16_t huff_code_dc_chrominance[12]; ///< DC chrominance Huffman table codes.
uint8_t huff_size_ac_luminance[256]; ///< AC luminance Huffman table size.
uint16_t huff_code_ac_luminance[256]; ///< AC luminance Huffman table codes.
uint8_t huff_size_ac_chrominance[256]; ///< AC chrominance Huffman table size.
uint16_t huff_code_ac_chrominance[256]; ///< AC chrominance Huffman table codes.
int uv_interleave;
int h_count[4];
int v_count[4];
int comp_num;
int width;
int height;
int y_stride;
int quality;
int header_offset;
struct mpp_frame* cur_frame;
unsigned int phy_addr[3];
int encode_data_len;
int ve_fd;
unsigned long regs_base;
struct ve_buffer_allocator *alloc;
unsigned char* bitstream_vir_addr;
unsigned int bitstream_phy_addr;
int stream_num;
struct put_bit_ctx pb;
struct encode_config config;
};
int jpeg_hw_encode(struct jpeg_ctx *s);
#endif

View File

@@ -0,0 +1,244 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: jpeg encoder hal
*/
#include <stdlib.h>
#include "ve_top_register.h"
#include "jpeg_register.h"
#include "mpp_log.h"
#include "ve_buffer.h"
#include "ve.h"
#include "jpeg_enc_ctx.h"
static void config_ve_top_reg(struct jpeg_ctx *s)
{
logd("config mjpeg reg");
write_reg_u32(s->regs_base + VE_CLK_REG, 1);
write_reg_u32(s->regs_base + VE_RST_REG, RST_JPG_PIC_MODULE);
while (1) {
uint32_t val = read_reg_u32(s->regs_base + VE_RST_REG);
if ((val >> 16) == 0)
break;
}
write_reg_u32(s->regs_base + VE_INIT_REG, 1);
write_reg_u32(s->regs_base + VE_IRQ_REG, 1);
write_reg_u32(s->regs_base + VE_JPG_EN_REG, 1);
}
static void config_header_info(struct jpeg_ctx *s)
{
uint32_t val = 0;
write_reg_u32(s->regs_base + JPG_START_POS_REG, 0);
write_reg_u32(s->regs_base + JPG_CTRL_REG, (3 << 12) | (3 << 8) | (3 << 3));
int width_align = (s->width + 15) & (~15);
val = s->height | (width_align << 16);
write_reg_u32(s->regs_base + JPG_SIZE_REG, val);
int total_blks = s->h_count[0] * s->v_count[0] +
s->h_count[1] * s->v_count[1] + s->h_count[2] * s->v_count[2];
val = s->v_count[2] | (s->h_count[2] << 2) |
(s->v_count[1] << 4) | (s->h_count[1] << 6) |
(s->v_count[0] << 8) | (s->h_count[0] << 10) |
(s->comp_num << 12) | (total_blks << 16);
write_reg_u32(s->regs_base + JPG_MCU_INFO_REG, val);
val = 12 / total_blks;
write_reg_u32(s->regs_base + JPG_HANDLE_NUM_REG, val);
write_reg_u32(s->regs_base + JPG_UV_REG, s->uv_interleave);
write_reg_u32(s->regs_base + JPG_FRAME_IDX_REG, 0);
write_reg_u32(s->regs_base + JPG_RST_INTERVAL_REG, 0);
write_reg_u32(s->regs_base + JPG_INTRRUPT_EN_REG, 0);
}
static void config_picture_info_register(struct jpeg_ctx *s)
{
uint32_t val = 0;
uint32_t color_mode = 0;
if (s->cur_frame->buf.format == MPP_FMT_YUV420P || s->cur_frame->buf.format == MPP_FMT_NV12) {
color_mode = 0;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV444P) {
color_mode = 3;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV400) {
color_mode = 4;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV422P) {
color_mode = 1;
} else {
loge("not supprt this format(%d)", s->cur_frame->buf.format);
}
val = s->y_stride | (s->uv_interleave << 16) | (color_mode << 17);
write_reg_u32(s->regs_base + PIC_INFO_START_REG, val);
val = s->height | (s->y_stride << 16);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 4, val);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 8, s->phy_addr[0]);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 12, s->phy_addr[1]);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 16, s->phy_addr[2]);
}
/*
quant matrix store in zigzag order
*/
static void ve_config_quant_matrix(struct jpeg_ctx *s)
{
int i, j;
uint32_t val;
unsigned int* quant_tab[3] = { s->luma_quant_table, s->chroma_quant_table, s->chroma_quant_table };
for (int comp = 0; comp < 3; comp++) {
write_reg_u32(s->regs_base + JPG_QMAT_INFO_REG, (comp << 6) | 3);
write_reg_u32(s->regs_base + JPG_QMAT_ADDR_REG, comp << 6);
for (i = 0; i < 64; i++) {
j = zigzag_direct[i];
// qmatrix should be (1<<19)/q
val = (1 << QUANT_FIXED_POINT_BITS) / quant_tab[comp][j];
write_reg_u32(s->regs_base + JPG_QMAT_VAL_REG, val);
}
}
write_reg_u32(s->regs_base + JPG_QMAT_INFO_REG, 0);
}
/*
huffman table include 4 tables: DC_Luma\DC_Chroma\AC_LUMA\AC_Chroma
internal SRAM in VE is 544x20bit
20bit data: [19:16]: code_length-1; [15:0]: code word
address of the 4 tables:
Luma_AC: 0-255
Chroma_AC: 256-511
Luma_DC: 512-528
Chroma_DC: 528-544
*/
static void ve_config_huffman_table(struct jpeg_ctx *s)
{
int i;
uint32_t val;
write_reg_u32(s->regs_base + JPG_HUFF_INFO_REG, 3);
write_reg_u32(s->regs_base + JPG_HUFF_ADDR_REG, 0);
// luma ac
for (i = 0; i < 256; i++) {
val = ((s->huff_size_ac_luminance[i] - 1) << 16) | s->huff_code_ac_luminance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// chroma ac
for (i = 0; i < 256; i++) {
val = ((s->huff_size_ac_chrominance[i] - 1) << 16) | s->huff_code_ac_chrominance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// luma dc
for (i = 0; i < 12; i++) {
val = ((s->huff_size_dc_luminance[i] - 1) << 16) | s->huff_code_dc_luminance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// chroma dc
write_reg_u32(s->regs_base + JPG_HUFF_INFO_REG, 3);
write_reg_u32(s->regs_base + JPG_HUFF_ADDR_REG, 528);
for (i = 0; i < 12; i++) {
val = ((s->huff_size_dc_chrominance[i] - 1) << 16) | s->huff_code_dc_chrominance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// clear
write_reg_u32(s->regs_base + JPG_HUFF_INFO_REG, 0);
}
static void ve_config_stream_register(struct jpeg_ctx *s)
{
int head_offset = s->header_offset;
int stream_num = s->stream_num;
// end addr of output stream
unsigned int align_256_addr = s->bitstream_phy_addr + stream_num * 256;
write_reg_u32(s->regs_base + JPG_STREAM_END_ADDR_REG, align_256_addr);
// base addr of output stream
write_reg_u32(s->regs_base + JPG_BAS_ADDR_REG, s->bitstream_phy_addr + head_offset);
// start addr of output stream
write_reg_u32(s->regs_base + JPG_STREAM_START_ADDR_REG, s->bitstream_phy_addr + head_offset);
write_reg_u32(s->regs_base + JPG_STREAM_WRITE_PTR_REG, s->bitstream_phy_addr + head_offset);
write_reg_u32(s->regs_base + JPG_STREAM_READ_PTR_REG, s->bitstream_phy_addr + head_offset);
// current stream pos
write_reg_u32(s->regs_base + JPG_CUR_POS_REG, 0);
write_reg_u32(s->regs_base + JPG_DATA_CNT_REG, 64);
write_reg_u32(s->regs_base + JPG_MEM_EA_REG, 0x7f);
write_reg_u32(s->regs_base + JPG_MEM_IA_REG, 0x40);
write_reg_u32(s->regs_base + JPG_MEM_HA_REG, 0x40);
write_reg_u32(s->regs_base + JPG_BITREQ_EN_REG, 1);
}
int jpeg_hw_encode(struct jpeg_ctx *s)
{
int ret = 0;
uint32_t status;
ve_get_client();
// 1. config ve top
config_ve_top_reg(s);
// 2. config jpeg header
config_header_info(s);
// 3. config picture info
config_picture_info_register(s);
// 4. config quant/huffman table
ve_config_quant_matrix(s);
ve_config_huffman_table(s);
// 5. config bitstream
ve_config_stream_register(s);
write_reg_u32(s->regs_base + JPG_STATUS_REG, 0xf);
write_reg_u32(s->regs_base + JPG_START_REG, 1);
if (ve_wait((unsigned int*)&status) < 0) {
loge("ve wait irq timeout");
logi("read JPG_STATUS_REG %x", read_reg_u32(s->regs_base + JPG_STATUS_REG));
ve_reset();
ret = -1;
goto out;
}
if(status > 1) {
loge("status error");
ve_reset();
ret = -1;
goto out;
}
uint32_t cycles = 0;
cycles = read_reg_u32(s->regs_base + JPG_CYCLES_REG);
uint32_t end_addr = 0;
end_addr = read_reg_u32(s->regs_base + JPG_STREAM_WRITE_PTR_REG);
s->encode_data_len = end_addr - s->bitstream_phy_addr;
logi("cycles: %"PRIu32", data len: %d", cycles, s->encode_data_len);
// disable jpeg module
write_reg_u32(s->regs_base + VE_JPG_EN_REG, 0);
out:
ve_put_client();
return ret;
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: jpeg tables
*/
#include <unistd.h>
#include <stdint.h>
/****************** Quant Table *************************/
/* These are the sample quantization tables given in JPEG spec section K.1.
* The spec says that the values given produce "good" quality, and
* when divided by 2, "very good" quality.
*/
const unsigned char std_luminance_quant_tbl[64] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
const unsigned char std_chrominance_quant_tbl[64] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
uint8_t zigzag_direct[64] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
/****************** Huffman Table *************************/
/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
/* IMPORTANT: these are only valid for 8-bit data precision! */
const uint8_t avpriv_mjpeg_bits_dc_luminance[17] =
{ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
const uint8_t avpriv_mjpeg_val_dc[12] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
const uint8_t avpriv_mjpeg_bits_dc_chrominance[17] =
{ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
const uint8_t avpriv_mjpeg_bits_ac_luminance[17] =
{ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
const uint8_t avpriv_mjpeg_val_ac_luminance[] =
{ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
const uint8_t avpriv_mjpeg_bits_ac_chrominance[17] =
{ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
const uint8_t avpriv_mjpeg_val_ac_chrominance[] =
{ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
/* isn't this function nicer than the one in the libjpeg ? */
void mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code,
const uint8_t *bits_table,
const uint8_t *val_table)
{
int i, j, k,nb, code, sym;
/* Some badly encoded files [1] map 2 different codes to symbol 0.
Only the first one is valid, so we zero-initialize this here and
make sure we only set it once (the first time) in the loop below.
[1]: Embedded JPEGs in "X7 RAW" and "X7 CinemaDNG" samples here:
https://www.dji.com/gr/zenmuse-x7/info#downloads
*/
huff_size[0] = 0;
k = 0;
code = 0;
for(i=1;i<=16;i++) {
nb = bits_table[i];
for(j=0;j<nb;j++) {
sym = val_table[k++];
if (sym != 0 || huff_size[sym] == 0) { /* see comment above */
huff_size[sym] = i;
huff_code[sym] = code;
}
code++;
}
code <<= 1;
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: jpeg tables
*/
#ifndef JPEG_TABLES_H
#define JPEG_TABLES_H
#include <stdint.h>
extern const unsigned char std_luminance_quant_tbl[];
extern const unsigned char std_chrominance_quant_tbl[];
extern const uint8_t avpriv_mjpeg_bits_dc_luminance[];
extern const uint8_t avpriv_mjpeg_val_dc[];
extern const uint8_t avpriv_mjpeg_bits_dc_chrominance[];
extern const uint8_t avpriv_mjpeg_bits_ac_luminance[];
extern const uint8_t avpriv_mjpeg_val_ac_luminance[];
extern const uint8_t avpriv_mjpeg_bits_ac_chrominance[];
extern const uint8_t avpriv_mjpeg_val_ac_chrominance[];
extern uint8_t zigzag_direct[64];
void mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code,
const uint8_t *bits_table,
const uint8_t *val_table);
#endif

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: put bits
*/
#ifndef __PUT_BITS_H_
#define __PUT_BITS_H_
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include "mpp_log.h"
static const int BUF_BITS = 8 * sizeof(uint32_t);
struct put_bit_ctx {
uint32_t bit_buf;
int bit_left;
uint8_t *buf, *buf_ptr, *buf_end;
int size_in_bits;
};
static inline void init_put_bits(struct put_bit_ctx *s, uint8_t *buffer, int buffer_size)
{
if (buffer_size < 0) {
buffer_size = 0;
buffer = NULL;
return;
}
s->size_in_bits = 8 * buffer_size;
s->buf = buffer;
s->buf_end = s->buf + buffer_size;
s->buf_ptr = s->buf;
s->bit_left = BUF_BITS;
s->bit_buf = 0;
}
static inline int put_bits_count(struct put_bit_ctx *s)
{
return (s->buf_ptr - s->buf) * 8 + BUF_BITS - s->bit_left;
}
static inline int put_bits_left(struct put_bit_ctx* s)
{
return (s->buf_end - s->buf_ptr) * 8 - BUF_BITS + s->bit_left;
}
#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff))
#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16))
#define AV_WLBUF(p, v) (*((uint64_t *)(p)) = (v))
#define AV_WBBUF(p, v) (*((uint64_t *)(p)) = (v))
static inline void put_bits_no_assert(struct put_bit_ctx* s, int n, uint32_t value)
{
uint32_t bit_buf;
int bit_left;
bit_buf = s->bit_buf;
bit_left = s->bit_left;
if (n < bit_left) {
bit_buf = (bit_buf << n) | value;
bit_left -= n;
} else {
bit_buf <<= bit_left;
bit_buf |= value >> (n - bit_left);
if (s->buf_end - s->buf_ptr >= sizeof(uint32_t)) {
AV_WBBUF(s->buf_ptr, AV_BSWAP32C(bit_buf));
s->buf_ptr += sizeof(uint32_t);
} else {
loge("Internal error, put_bits buffer too small\n");
mpp_assert(0);
}
bit_left += BUF_BITS - n;
bit_buf = value;
}
s->bit_buf = bit_buf;
s->bit_left = bit_left;
}
/**
* Write up to 31 bits into a bitstream.
* Use put_bits32 to write 32 bits.
*/
static inline void put_bits(struct put_bit_ctx *s, int n, uint32_t value)
{
if(n <= 31 && value < (1UL << n)) {
put_bits_no_assert(s, n, value);
} else {
loge("put bits fail, n: %d, val: 0x%"PRIx32"", n, value);
}
}
static unsigned av_mod_uintp2_c(unsigned a, unsigned p)
{
return a & ((1U << p) - 1);
}
static inline void put_sbits(struct put_bit_ctx *pb, int n, int32_t value)
{
if (n < 0 || n > 31) {
loge("put_sbits error");
return;
}
put_bits(pb, n, av_mod_uintp2_c(value, n));
}
/**
* Pad the end of the output stream with zeros.
*/
static inline void flush_put_bits(struct put_bit_ctx *s)
{
if (s->bit_left < BUF_BITS)
s->bit_buf <<= s->bit_left;
while (s->bit_left < BUF_BITS) {
mpp_assert(s->buf_ptr < s->buf_end);
*s->buf_ptr++ = s->bit_buf >> (BUF_BITS - 8);
s->bit_buf <<= 8;
s->bit_left += 8;
}
s->bit_left = BUF_BITS;
s->bit_buf = 0;
}
static inline uint8_t *put_bits_ptr(struct put_bit_ctx *s)
{
return s->buf_ptr;
}
static inline void skip_put_bytes(struct put_bit_ctx *s, int n)
{
mpp_assert((put_bits_count(s) & 7) == 0);
mpp_assert(s->bit_left == BUF_BITS);
mpp_assert(n <= s->buf_end - s->buf_ptr);
s->buf_ptr += n;
}
#endif