diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2012-03-21 12:26:48 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2012-03-21 12:26:48 +0100 |
commit | 1f7af39943aabb7cb9223510609b5d1ef11d7bf5 (patch) | |
tree | a6e70d3a7f1ba1355ded5a43d18aeb4c52d4ba31 | |
parent | ca03e2cda42c1da6272526a2fcc7436e5b7d72a6 (diff) | |
download | gst-plugins-fsl-vpu-1f7af39943aabb7cb9223510609b5d1ef11d7bf5.tar.gz gst-plugins-fsl-vpu-1f7af39943aabb7cb9223510609b5d1ef11d7bf5.tar.xz |
module: Add mjpeg encoding support
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | module/imx-vpu.c | 232 | ||||
-rw-r--r-- | module/imx-vpu.h | 6 |
2 files changed, 233 insertions, 5 deletions
diff --git a/module/imx-vpu.c b/module/imx-vpu.c index 37fe8bf..68dbd47 100644 --- a/module/imx-vpu.c +++ b/module/imx-vpu.c @@ -39,12 +39,14 @@ #include <mach/hardware.h> #include <mach/iram.h> +#include "imx-vpu-jpegtable.h" #include "imx-vpu.h" #define VPU_IOC_MAGIC 'V' #define VPU_IOC_ROTATE_MIRROR _IO(VPU_IOC_MAGIC, 7) #define VPU_IOC_CODEC _IO(VPU_IOC_MAGIC, 8) +#define VPU_IOC_MJPEG_QUALITY _IO(VPU_IOC_MAGIC, 9) #define VPU_NUM_INSTANCE 4 @@ -67,6 +69,9 @@ #define VPU_MAX_BITRATE 32767 +#define VPU_HUFTABLE_SIZE 432 +#define VPU_QMATTABLE_SIZE 192 + #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0) static inline dma_addr_t vb2_dma_contig_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no) @@ -113,18 +118,18 @@ enum { #define STD_MPEG4 0 #define STD_H263 1 #define STD_AVC 2 +#define STD_MJPG 3 static int vpu_v1_codecs[VPU_CODEC_MAX] = { [VPU_CODEC_AVC_DEC] = 2, [VPU_CODEC_VC1_DEC] = -1, [VPU_CODEC_MP2_DEC] = -1, - [VPU_CODEC_MP4_DEC] = 0, [VPU_CODEC_DV3_DEC] = -1, [VPU_CODEC_RV_DEC] = -1, - [VPU_CODEC_MJPG_DEC] = -1, + [VPU_CODEC_MJPG_DEC] = 0x82, [VPU_CODEC_AVC_ENC] = 3, [VPU_CODEC_MP4_ENC] = 1, - [VPU_CODEC_MJPG_ENC] = -1, + [VPU_CODEC_MJPG_ENC] = 0x83, }; static int vpu_v2_codecs[VPU_CODEC_MAX] = { @@ -301,6 +306,10 @@ struct vpu_instance { int standard; unsigned int readofs, fifo_in, fifo_out; + u32 *mjpg_huf_table; + u32 *mjpg_q_mat_table; + int mjpg_quality; + /* statistic */ uint64_t encoding_time_max; uint64_t encoding_time_total; @@ -526,7 +535,7 @@ static int vpu_alloc_fb_v1(struct vpu_instance *instance) struct vpu *vpu = instance->vpu; int i, ret = 0; int size = (instance->width * instance->height * 3) / 2; - unsigned long *para_buf = instance->para_buf; + u32 *para_buf = instance->para_buf; for (i = 0; i < instance->num_fb; i++) { struct memalloc_record *rec = &instance->rec[i]; @@ -627,13 +636,189 @@ static int encode_header(struct vpu_instance *instance, int headertype) memcpy(header + instance->headersize, instance->bitstream_buf, headersize); - print_hex_dump(KERN_INFO, "header: ", DUMP_PREFIX_ADDRESS, 16, 1, instance->bitstream_buf, headersize, 0); + print_hex_dump(KERN_INFO, "header: ", DUMP_PREFIX_ADDRESS, 16, 1, + instance->bitstream_buf, headersize, 0); instance->header = header; instance->headersize += headersize; return 0; } + +static void vpu_calc_mjpeg_quant_tables(struct vpu_instance *instance, + int quality) +{ + int i; + unsigned int temp, new_quality; + + if (quality > 100) + quality = 100; + if (quality < 5) + quality = 5; + + /* re-calculate the Q-matrix */ + if (quality > 50) + new_quality = 5000 / quality; + else + new_quality = 200 - 2 * quality; + + pr_info("quality = %d %d", quality, new_quality); + + /* recalculate luma Quantification table */ + for (i = 0; i< 64; i++) { + temp = ((unsigned int)lumaQ2[i] * new_quality + 50) / 100; + if (temp <= 0) + temp = 1; + if (temp > 255) + temp = 255; + lumaQ2[i] = (unsigned char)temp; + } + + pr_info("Luma Quant Table is \n"); + for (i = 0; i < 64; i += 8) { + pr_info("0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, \n", + lumaQ2[i], lumaQ2[i + 1], lumaQ2[i + 2], lumaQ2[i + 3], + lumaQ2[i + 4], lumaQ2[i + 5], lumaQ2[i + 6], lumaQ2[i + 7]); + } + + /* chromaB Quantification Table */ + for (i = 0; i< 64; i++) { + temp = ((unsigned int)chromaBQ2[i] * new_quality + 50) / 100; + if (temp <= 0) + temp = 1; + if (temp > 255) + temp = 255; + chromaBQ2[i] = (unsigned char)temp; + } + + pr_info("chromaB Quantification Table is \n"); + for(i = 0; i < 64; i = i+8) { + pr_info("0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, \n", + chromaBQ2[i], chromaBQ2[i + 1], chromaBQ2[i + 2], chromaBQ2[i + 3], + chromaBQ2[i + 4], chromaBQ2[i + 5], chromaBQ2[i + 6], chromaBQ2[i + 7]); + } + + /* chromaR Quantification Table */ + for (i = 0; i< 64; i++) { + temp = ((unsigned int)chromaRQ2[i] * new_quality + 50) / 100; + if (temp <= 0) + temp = 1; + if (temp > 255) + temp = 255; + chromaRQ2[i] = (unsigned char)temp; + } + + pr_info("chromaR Quantification Table is \n"); + for (i = 0; i < 64; i += 8) { + pr_info("0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, \n", + chromaRQ2[i], chromaRQ2[i + 1], chromaRQ2[i + 2], chromaRQ2[i + 3], + chromaRQ2[i + 4], chromaRQ2[i + 5], chromaRQ2[i + 6], chromaRQ2[i + 7]); + } +} + +static int vpu_generate_jpeg_tables(struct vpu_instance *instance, + int quality) +{ + u8 *q_mat_table; + u8 *huf_table; + int i; + + huf_table = kzalloc(VPU_HUFTABLE_SIZE, GFP_KERNEL); + q_mat_table = kzalloc(VPU_QMATTABLE_SIZE, GFP_KERNEL); + + if (!huf_table || !q_mat_table) { + kfree(huf_table); + kfree(q_mat_table); + return -ENOMEM; + } + + for (i = 0; i < 16; i += 4) { + huf_table[i] = lumaDcBits[i + 3]; + huf_table[i + 1] = lumaDcBits[i + 2]; + huf_table[i + 2] = lumaDcBits[i + 1]; + huf_table[i + 3] = lumaDcBits[i]; + } + + for (i = 16; i < 32 ; i += 4) { + huf_table[i] = lumaDcValue[i + 3 - 16]; + huf_table[i + 1] = lumaDcValue[i + 2 - 16]; + huf_table[i + 2] = lumaDcValue[i + 1 - 16]; + huf_table[i + 3] = lumaDcValue[i - 16]; + } + + for (i = 32; i < 48; i += 4) { + huf_table[i] = lumaAcBits[i + 3 - 32]; + huf_table[i + 1] = lumaAcBits[i + 2 - 32]; + huf_table[i + 2] = lumaAcBits[i + 1 - 32]; + huf_table[i + 3] = lumaAcBits[i - 32]; + } + + for (i = 48; i < 216; i += 4) { + huf_table[i] = lumaAcValue[i + 3 - 48]; + huf_table[i + 1] = lumaAcValue[i + 2 - 48]; + huf_table[i + 2] = lumaAcValue[i + 1 - 48]; + huf_table[i + 3] = lumaAcValue[i - 48]; + } + + for (i = 216; i < 232; i += 4) { + huf_table[i] = chromaDcBits[i + 3 - 216]; + huf_table[i + 1] = chromaDcBits[i + 2 - 216]; + huf_table[i + 2] = chromaDcBits[i + 1 - 216]; + huf_table[i + 3] = chromaDcBits[i - 216]; + } + + for (i = 232; i < 248; i += 4) { + huf_table[i] = chromaDcValue[i + 3 - 232]; + huf_table[i + 1] = chromaDcValue[i + 2 - 232]; + huf_table[i + 2] = chromaDcValue[i + 1 - 232]; + huf_table[i + 3] = chromaDcValue[i - 232]; + } + + for (i = 248; i < 264; i += 4) { + huf_table[i] = chromaAcBits[i + 3 - 248]; + huf_table[i + 1] = chromaAcBits[i + 2 - 248]; + huf_table[i + 2] = chromaAcBits[i + 1 - 248]; + huf_table[i + 3] = chromaAcBits[i - 248]; + } + + for (i = 264; i < 432; i += 4) { + huf_table[i] = chromaAcValue[i + 3 - 264]; + huf_table[i + 1] = chromaAcValue[i + 2 - 264]; + huf_table[i + 2] = chromaAcValue[i + 1 - 264]; + huf_table[i + 3] = chromaAcValue[i - 264]; + } + + /* according to the bitrate, recalculate the quant table */ + vpu_calc_mjpeg_quant_tables(instance, quality); + + /* Rearrange and insert pre-defined Q-matrix to deticated variable. */ + for (i = 0; i < 64; i += 4) { + q_mat_table[i] = lumaQ2[i + 3]; + q_mat_table[i + 1] = lumaQ2[i + 2]; + q_mat_table[i + 2] = lumaQ2[i + 1]; + q_mat_table[i + 3] = lumaQ2[i]; + } + + for (i = 64; i < 128; i += 4) { + q_mat_table[i] = chromaBQ2[i + 3 - 64]; + q_mat_table[i + 1] = chromaBQ2[i + 2 - 64]; + q_mat_table[i + 2] = chromaBQ2[i + 1 - 64]; + q_mat_table[i + 3] = chromaBQ2[i - 64]; + } + + for (i = 128; i < 192; i += 4) { + q_mat_table[i] = chromaRQ2[i + 3 - 128]; + q_mat_table[i + 1] = chromaRQ2[i + 2 - 128]; + q_mat_table[i + 2] = chromaRQ2[i + 1 - 128]; + q_mat_table[i + 3] = chromaRQ2[i - 128]; + } + + instance->mjpg_huf_table = (void *)huf_table; + instance->mjpg_q_mat_table = (void *)q_mat_table; + + return 0; +} + #define VPU_DEFAULT_MPEG4_QP 15 #define VPU_DEFAULT_H264_QP 35 @@ -651,6 +836,8 @@ static int noinline vpu_enc_get_initial_info(struct vpu_instance *instance) u32 sliceReport = 0; u32 mbReport = 0; u32 rcIntraQp = 0; + u32 *table_buf, *para_buf; + int i; switch (instance->standard) { case STD_MPEG4: @@ -660,6 +847,9 @@ static int noinline vpu_enc_get_initial_info(struct vpu_instance *instance) case STD_AVC: instance->format = VPU_CODEC_AVC_ENC; break; + case STD_MJPG: + instance->format = VPU_CODEC_MJPG_ENC; + break; default: return -EINVAL; }; @@ -731,6 +921,31 @@ static int noinline vpu_enc_get_initial_info(struct vpu_instance *instance) (avc_chromaQpOffset & 31); vpu_write(vpu, CMD_ENC_SEQ_264_PARA, data); rcIntraQp = VPU_DEFAULT_H264_QP; + } else if (instance->standard == STD_MJPG) { + vpu_write(vpu, CMD_ENC_SEQ_JPG_PARA, 0); + vpu_write(vpu, CMD_ENC_SEQ_JPG_RST_INTERVAL, 60); + vpu_write(vpu, CMD_ENC_SEQ_JPG_THUMB_EN, 0); + vpu_write(vpu, CMD_ENC_SEQ_JPG_THUMB_SIZE, 0); + vpu_write(vpu, CMD_ENC_SEQ_JPG_THUMB_OFFSET, 0); + + vpu_generate_jpeg_tables(instance, instance->mjpg_quality); + + para_buf = instance->para_buf; + table_buf = (u32 *)instance->mjpg_huf_table; + + for (i = 0; i < 108; i += 2) { + para_buf[i + 1] = *table_buf; + para_buf[i] = *(table_buf + 1); + table_buf += 2; + } + + table_buf = (u32 *)instance->mjpg_q_mat_table; + + for (i = 0; i < 48; i += 2) { + para_buf[i + 129] = *table_buf; + para_buf[i + 128] = *(table_buf + 1); + table_buf += 2; + } } data = 4000 << 2 | /* slice size */ @@ -1339,11 +1554,18 @@ static long vpu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case STD_AVC: instance->standard = std; break; + case STD_MJPG: + instance->standard = std; + instance->mjpg_quality = 50; + break; default: ret = -EINVAL; break; } break; + case VPU_IOC_MJPEG_QUALITY: + instance->mjpg_quality = (u32)arg; + break; default: ret = video_ioctl2(file, cmd, arg); break; diff --git a/module/imx-vpu.h b/module/imx-vpu.h index d2de056..d36d8b6 100644 --- a/module/imx-vpu.h +++ b/module/imx-vpu.h @@ -125,6 +125,12 @@ #define CMD_ENC_SEQ_RC_QP_MAX 0x1C8 #define RET_ENC_SEQ_SUCCESS 0x1C0 +#define CMD_ENC_SEQ_JPG_PARA 0x198 +#define CMD_ENC_SEQ_JPG_RST_INTERVAL 0x19C +#define CMD_ENC_SEQ_JPG_THUMB_EN 0x1A0 +#define CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1A4 +#define CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1A8 + /*-------------------------------------------------------------------------- * [ENC PARA CHANGE] COMMAND : *------------------------------------------------------------------------*/ |