mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-29 01:06:56 +00:00
V1.0.6
This commit is contained in:
360
packages/artinchip/mpp/ve/encoder/jpeg/jpeg_enc.c
Normal file
360
packages/artinchip/mpp/ve/encoder/jpeg/jpeg_enc.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user