amvdec_ports: adds the feature of the amvdec ports are based on v4l2.[2/2]

PD#153299:
1. amports has v4l for video decoding implemented upstream.
2. Only the decoding of h264 has been implemented at the moment.
3. the maximun resolution supports 1080p currently.
4. it is nv12 that the canvas data format of the decoder output.
5. the detailed description can be referred to wiki.
wiki: Media/The_V4L2_Amvdec_Ports_Instructions

Change-Id: I6fdff300a4b5bd715b8612be966a8734cd522555
Signed-off-by: Nanxin Qin <nanxin.qin@amlogic.com>
This commit is contained in:
Nanxin Qin
2017-12-11 11:03:15 +08:00
committed by Dongjin Kim
parent 69d9c4ed74
commit f1dec43592
38 changed files with 6174 additions and 25 deletions

View File

@@ -2,3 +2,4 @@ obj-y += common/
obj-y += frame_provider/
obj-y += frame_sink/
obj-y += stream_input/
obj-y += amvdec_ports/

View File

@@ -0,0 +1,11 @@
obj-m += amvdec_ports.o
amvdec_ports-objs += aml_vcodec_dec_drv.o
amvdec_ports-objs += aml_vcodec_dec.o
amvdec_ports-objs += aml_vcodec_dec_pm.o
amvdec_ports-objs += aml_vcodec_util.o
amvdec_ports-objs += aml_vcodec_adapt.o
amvdec_ports-objs += aml_vcodec_vfm.o
amvdec_ports-objs += vdec_drv_if.o
amvdec_ports-objs += decoder/vdec_h264_if.o
amvdec_ports-objs += decoder/h264_parse.o
amvdec_ports-objs += decoder/h264_stream.o

View File

@@ -0,0 +1,719 @@
#include <linux/types.h>
#include <linux/amlogic/media/utils/amstream.h>
#include <linux/amlogic/media/utils/vformat.h>
#include <linux/amlogic/media/utils/aformat.h>
#include <linux/amlogic/media/frame_sync/tsync.h>
#include <linux/amlogic/media/frame_sync/ptsserv.h>
#include <linux/amlogic/media/frame_sync/timestamp.h>
#include <linux/amlogic/media/utils/amports_config.h>
#include <linux/amlogic/media/frame_sync/tsync_pcr.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include <linux/amlogic/media/codec_mm/configs.h>
#include <linux/amlogic/media/utils/vformat.h>
#include <linux/amlogic/media/utils/aformat.h>
#include <linux/amlogic/media/registers/register.h>
#include "../stream_input/amports/adec.h"
#include "../stream_input/parser/streambuf.h"
#include "../stream_input/parser/streambuf_reg.h"
#include "../stream_input/parser/tsdemux.h"
#include "../stream_input/parser/psparser.h"
#include "../stream_input/parser/esparser.h"
#include "../frame_provider/decoder/utils/vdec.h"
#include "../common/media_clock/switch/amports_gate.h"
#include <linux/delay.h>
#include "aml_vcodec_adapt.h"
#include <linux/crc32.h>
#define DEFAULT_VIDEO_BUFFER_SIZE (1024 * 1024 * 3)
#define DEFAULT_VIDEO_BUFFER_SIZE_4K (1024 * 1024 * 6)
#define DEFAULT_VIDEO_BUFFER_SIZE_TVP (1024 * 1024 * 10)
#define DEFAULT_VIDEO_BUFFER_SIZE_4K_TVP (1024 * 1024 * 15)
#define DEFAULT_AUDIO_BUFFER_SIZE (1024*768*2)
#define DEFAULT_SUBTITLE_BUFFER_SIZE (1024*256)
#define PTS_OUTSIDE (1)
#define SYNC_OUTSIDE (2)
#define USE_V4L_PORTS (0x80)
//#define DATA_DEBUG
static int def_4k_vstreambuf_sizeM =
(DEFAULT_VIDEO_BUFFER_SIZE_4K >> 20);
static int def_vstreambuf_sizeM =
(DEFAULT_VIDEO_BUFFER_SIZE >> 20);
static int slow_input = 0;
static int use_bufferlevelx10000 = 10000;
static unsigned int amstream_buf_num = BUF_MAX_NUM;
static struct stream_buf_s bufs[BUF_MAX_NUM] = {
{
.reg_base = VLD_MEM_VIFIFO_REG_BASE,
.type = BUF_TYPE_VIDEO,
.buf_start = 0,
.buf_size = DEFAULT_VIDEO_BUFFER_SIZE,
.default_buf_size = DEFAULT_VIDEO_BUFFER_SIZE,
.first_tstamp = INVALID_PTS
},
{
.reg_base = AIU_MEM_AIFIFO_REG_BASE,
.type = BUF_TYPE_AUDIO,
.buf_start = 0,
.buf_size = DEFAULT_AUDIO_BUFFER_SIZE,
.default_buf_size = DEFAULT_AUDIO_BUFFER_SIZE,
.first_tstamp = INVALID_PTS
},
{
.reg_base = 0,
.type = BUF_TYPE_SUBTITLE,
.buf_start = 0,
.buf_size = DEFAULT_SUBTITLE_BUFFER_SIZE,
.default_buf_size = DEFAULT_SUBTITLE_BUFFER_SIZE,
.first_tstamp = INVALID_PTS
},
{
.reg_base = 0,
.type = BUF_TYPE_USERDATA,
.buf_start = 0,
.buf_size = 0,
.first_tstamp = INVALID_PTS
},
{
.reg_base = HEVC_STREAM_REG_BASE,
.type = BUF_TYPE_HEVC,
.buf_start = 0,
.buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K,
.default_buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K,
.first_tstamp = INVALID_PTS
},
};
struct vdec_adapt_config {
struct vdec_s *vdec;
struct stream_port_s port;
struct dec_sysinfo dec_prop;
};
struct vdec_adapt_config g_cfg;
static void set_cfg_info(struct aml_vdec_adapt *vdec)
{
unsigned long sync_mode = (PTS_OUTSIDE | SYNC_OUTSIDE | USE_V4L_PORTS);
g_cfg.port.type |= (PORT_TYPE_VIDEO | PORT_TYPE_ES);
g_cfg.port.flag |= PORT_FLAG_VFORMAT;
g_cfg.dec_prop.format = VFORMAT_H264;
g_cfg.dec_prop.width = 1920;
g_cfg.dec_prop.height = 1080;
g_cfg.dec_prop.rate = 3200;
g_cfg.dec_prop.param = (void *)sync_mode;
}
static void set_system_info(struct vdec_s *vdec)
{
vdec->sys_info = &g_cfg.dec_prop;
vdec->sys_info_store = g_cfg.dec_prop;
}
static void set_vdec_mode(struct vdec_s *vdec)
{
//vdec->type = VDEC_TYPE_SINGLE;
vdec->type = VDEC_TYPE_FRAME_BLOCK;
}
static void set_vdec_vfm(struct vdec_s *vdec)
{
vdec->frame_base_video_path = FRAME_BASE_PATH_V4L_VIDEO;
}
static int enable_hardware(void)
{
struct stream_port_s *port = &g_cfg.port;
if (get_cpu_type() < MESON_CPU_MAJOR_ID_M6)
return -1;
amports_switch_gate("demux", 1);
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8)
amports_switch_gate("parser_top", 1);
if (port->type & PORT_TYPE_VIDEO) {
amports_switch_gate("vdec", 1);
if (has_hevc_vdec()) {
if (port->type & (PORT_TYPE_MPTS | PORT_TYPE_HEVC)) {
amports_switch_gate("clk_hevc_mux", 1);
vdec_poweron(VDEC_HEVC);
}
if ((port->type & PORT_TYPE_HEVC) == 0) {
amports_switch_gate("clk_vdec_mux", 1);
vdec_poweron(VDEC_1);
}
} else {
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
amports_switch_gate("clk_vdec_mux", 1);
vdec_poweron(VDEC_1);
}
}
}
return 0;
}
static int disable_hardware(void)
{
struct stream_port_s *port = &g_cfg.port;
if (get_cpu_type() < MESON_CPU_MAJOR_ID_M6)
return -1;
if ((port->type & PORT_TYPE_VIDEO)
&& get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) {
#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
if (has_hevc_vdec())
vdec_poweroff(VDEC_HEVC);
vdec_poweroff(VDEC_1);
#else
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXLX
&& port->vformat == VFORMAT_H264
&& bufs[BUF_TYPE_VIDEO].for_4k)
vdec_poweroff(VDEC_HEVC);
if ((port->vformat == VFORMAT_HEVC
|| port->vformat == VFORMAT_VP9))
vdec_poweroff(VDEC_HEVC);
else
vdec_poweroff(VDEC_1);
#endif
amports_switch_gate("vdec", 0);
}
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8)
amports_switch_gate("parser_top", 0);
amports_switch_gate("demux", 0);
return 0;
}
static int reset_canuse_buferlevel(int levelx10000)
{
int i;
struct stream_buf_s *p = NULL;
if (levelx10000 >= 0 && levelx10000 <= 10000)
use_bufferlevelx10000 = levelx10000;
else
use_bufferlevelx10000 = 10000;
for (i = 0; i < amstream_buf_num; i++) {
p = &bufs[i];
p->canusebuf_size = ((p->buf_size / 1024) *
use_bufferlevelx10000 / 10000) * 1024;
p->canusebuf_size += 1023;
p->canusebuf_size &= ~1023;
if (p->canusebuf_size > p->buf_size)
p->canusebuf_size = p->buf_size;
}
return 0;
}
static void change_vbufsize(struct vdec_s *vdec,
struct stream_buf_s *pvbuf)
{
if (pvbuf->buf_start != 0) {
pr_info("streambuf is alloced before\n");
return;
}
if (pvbuf->for_4k) {
pvbuf->buf_size = def_4k_vstreambuf_sizeM * SZ_1M;
if (vdec->port_flag & PORT_FLAG_DRM)
pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_4K_TVP;
if ((pvbuf->buf_size > 30 * SZ_1M)
&& (codec_mm_get_total_size() < 220 * SZ_1M)) {
/*if less than 250M, used 20M for 4K & 265*/
pvbuf->buf_size = pvbuf->buf_size >> 1;
}
} else if (pvbuf->buf_size > def_vstreambuf_sizeM * SZ_1M) {
if (vdec->port_flag & PORT_FLAG_DRM)
pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
} else {
pvbuf->buf_size = def_vstreambuf_sizeM * SZ_1M;
if (vdec->port_flag & PORT_FLAG_DRM)
pvbuf->buf_size = DEFAULT_VIDEO_BUFFER_SIZE_TVP;
}
reset_canuse_buferlevel(10000);
}
static void user_buffer_init(void)
{
struct stream_buf_s *pubuf = &bufs[BUF_TYPE_USERDATA];
pubuf->buf_size = 0;
pubuf->buf_start = 0;
pubuf->buf_wp = 0;
pubuf->buf_rp = 0;
}
static void audio_component_release(struct stream_port_s *port,
struct stream_buf_s *pbuf, int release_num)
{
switch (release_num) {
default:
case 0:
case 4:
esparser_release(pbuf);
case 3:
adec_release(port->vformat);
case 2:
stbuf_release(pbuf, false);
case 1:
;
}
}
static int audio_component_init(struct stream_port_s *port,
struct stream_buf_s *pbuf)
{
int r;
if ((port->flag & PORT_FLAG_AFORMAT) == 0) {
pr_err("aformat not set\n");
return 0;
}
r = stbuf_init(pbuf, NULL, false);
if (r < 0)
return r;
r = adec_init(port);
if (r < 0) {
audio_component_release(port, pbuf, 2);
return r;
}
if (port->type & PORT_TYPE_ES) {
r = esparser_init(pbuf, NULL);
if (r < 0) {
audio_component_release(port, pbuf, 3);
return r;
}
}
pbuf->flag |= BUF_FLAG_IN_USE;
return 0;
}
static void video_component_release(struct stream_port_s *port,
struct stream_buf_s *pbuf, int release_num)
{
struct vdec_adapt_config *cfg
= container_of(port, struct vdec_adapt_config, port);
struct vdec_s *vdec = cfg->vdec;
struct vdec_s *slave = NULL;
bool is_multidec = !vdec_single(vdec);
switch (release_num) {
default:
case 0:
case 4: {
if ((port->type & PORT_TYPE_FRAME) == 0)
esparser_release(pbuf);
}
case 3: {
if (vdec->slave)
slave = vdec->slave;
vdec_release(vdec);
if (slave)
vdec_release(slave);
vdec = NULL;
}
case 2: {
if ((port->type & PORT_TYPE_FRAME) == 0)
stbuf_release(pbuf, is_multidec);
}
case 1:
;
}
}
static int video_component_init(struct stream_port_s *port,
struct stream_buf_s *pbuf)
{
int ret = -1;
struct vdec_adapt_config *cfg
= container_of(port, struct vdec_adapt_config, port);
struct vdec_s *vdec = cfg->vdec;
if ((vdec->port_flag & PORT_FLAG_VFORMAT) == 0) {
pr_err("vformat not set\n");
return -EPERM;
}
if ((vdec->sys_info->height * vdec->sys_info->width) > 1920 * 1088
|| port->vformat == VFORMAT_H264_4K2K) {
pbuf->for_4k = 1;
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXLX
&& port->vformat == VFORMAT_H264)
vdec_poweron(VDEC_HEVC);
} else
pbuf->for_4k = 0;
if (port->type & PORT_TYPE_FRAME) {
ret = vdec_init(vdec, pbuf->for_4k);
if (ret < 0) {
pr_err("video_component_init %d, failed\n", __LINE__);
video_component_release(port, pbuf, 2);
return ret;
}
return 0;
}
change_vbufsize(vdec, pbuf);
if (has_hevc_vdec()) {
if (port->type & PORT_TYPE_MPTS) {
if (pbuf->type == BUF_TYPE_HEVC)
vdec_poweroff(VDEC_1);
else
vdec_poweroff(VDEC_HEVC);
}
}
ret = stbuf_init(pbuf, vdec, false);
if (ret < 0) {
pr_err("video_component_init %d, stbuf_init failed\n", __LINE__);
return ret;
}
/* todo: set path based on port flag */
ret = vdec_init(vdec, pbuf->for_4k);
if (ret < 0) {
pr_err("video_component_init %d, vdec_init failed\n", __LINE__);
video_component_release(port, pbuf, 2);
return ret;
}
if (vdec_dual(vdec)) {
ret = vdec_init(vdec->slave, pbuf->for_4k);
if (ret < 0) {
pr_err("video_component_init %d, vdec_init failed\n",
__LINE__);
video_component_release(port, pbuf, 2);
return ret;
}
}
if (port->type & PORT_TYPE_ES) {
ret = esparser_init(pbuf, vdec);
if (ret < 0) {
video_component_release(port, pbuf, 3);
pr_err("esparser_init() failed\n");
return ret;
}
}
pbuf->flag |= BUF_FLAG_IN_USE;
vdec_connect(vdec);
return 0;
}
static int vdec_ports_release(struct stream_port_s *port)
{
struct vdec_adapt_config *cfg
= container_of(port, struct vdec_adapt_config, port);
struct vdec_s *vdec = cfg->vdec;
struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO];
struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
//struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
struct vdec_s *slave = NULL;
if (has_hevc_vdec()) {
if (port->vformat == VFORMAT_HEVC
|| port->vformat == VFORMAT_VP9)
pvbuf = &bufs[BUF_TYPE_HEVC];
}
if (port->type & PORT_TYPE_MPTS) {
tsync_pcr_stop();
tsdemux_release();
}
if (port->type & PORT_TYPE_MPPS)
psparser_release();
if (port->type & PORT_TYPE_VIDEO)
video_component_release(port, pvbuf, 0);
if (port->type & PORT_TYPE_AUDIO)
audio_component_release(port, pabuf, 0);
if (port->type & PORT_TYPE_SUB)
//sub_port_release(port, psbuf);
if (vdec) {
if (vdec->slave)
slave = vdec->slave;
vdec_release(vdec);
if (slave)
vdec_release(slave);
vdec = NULL;
}
port->pcr_inited = 0;
port->flag = 0;
return 0;
}
static int vdec_ports_init(struct aml_vdec_adapt *vdec_adapt)
{
int ret = -1;
struct stream_buf_s *pvbuf = &bufs[BUF_TYPE_VIDEO];
struct stream_buf_s *pabuf = &bufs[BUF_TYPE_AUDIO];
//struct stream_buf_s *psbuf = &bufs[BUF_TYPE_SUBTITLE];
struct stream_port_s *port = &g_cfg.port;
struct vdec_s *vdec = NULL;
/* create the vdec instance.*/
vdec = vdec_create(port, NULL);
if (IS_ERR_OR_NULL(vdec))
return -1;
/* set v4l2 ctx */
vdec->private = vdec_adapt->ctx;
g_cfg.vdec = vdec;
/* set video format and sys info */
vdec_set_format(vdec, g_cfg.dec_prop.format); //set by ioctl ???
set_system_info(vdec);
set_vdec_mode(vdec);
set_vdec_vfm(vdec);
stbuf_fetch_init();
user_buffer_init();
if ((port->type & PORT_TYPE_AUDIO)
&& (port->flag & PORT_FLAG_AFORMAT)) {
ret = audio_component_init(port, pabuf);
if (ret < 0) {
pr_err("audio_component_init failed\n");
goto error1;
}
}
if ((port->type & PORT_TYPE_VIDEO)
&& (vdec->port_flag & PORT_FLAG_VFORMAT)) {
pvbuf->for_4k = 0;
if (has_hevc_vdec()) {
if (port->vformat == VFORMAT_HEVC
|| port->vformat == VFORMAT_VP9)
pvbuf = &bufs[BUF_TYPE_HEVC];
}
ret = video_component_init(port, pvbuf);
if (ret < 0) {
pr_err("video_component_init failed\n");
goto error2;
}
}
/* connect vdec at the end after all HW initialization */
if ((port->type & PORT_TYPE_VIDEO)
&& (vdec->port_flag & PORT_FLAG_VFORMAT))
vdec_connect(vdec);
return 0;
//error3:
//video_component_release(port, pvbuf, 0);
error2:
audio_component_release(port, pabuf, 0);
error1:
return ret;
}
int video_decoder_init(struct aml_vdec_adapt *vdec)
{
int ret = -1;
/* sets configure data */
set_cfg_info(vdec);
/* init hw and gate*/
ret = enable_hardware();
if (ret < 0) {
pr_info("enable hw fail.\n");
goto out;
}
/* init the buffer work space and connect vdec.*/
ret = vdec_ports_init(vdec);
if (ret < 0) {
pr_info("vdec ports init fail.\n");
goto out;
}
out:
return ret;
}
int video_decoder_release(struct aml_vdec_adapt *vdec)
{
int ret = -1;
struct stream_port_s *port = &g_cfg.port;
ret = vdec_ports_release(port);
if (ret < 0) {
pr_info("vdec ports release fail.\n");
goto out;
}
/* disable gates */
ret = disable_hardware();
if (ret < 0) {
pr_info("disable hw fail.\n");
goto out;
}
out:
return ret;
}
int vdec_vbuf_write(struct file *file, const char *buf, unsigned int count)
{
int ret = -1;
int try_cnt = 100;
struct stream_port_s *port = &g_cfg.port;
struct vdec_s *vdec = g_cfg.vdec;
struct stream_buf_s *pbuf = NULL;
if (has_hevc_vdec()) {
pbuf = (port->type & PORT_TYPE_HEVC) ? &bufs[BUF_TYPE_HEVC] :
&bufs[BUF_TYPE_VIDEO];
} else
pbuf = &bufs[BUF_TYPE_VIDEO];
/*if (!(port_get_inited(priv))) {
r = video_decoder_init(priv);
if (r < 0)
return r;
}*/
do {
if (vdec->port_flag & PORT_FLAG_DRM)
ret = drm_write(file, pbuf, buf, count);
else
ret = esparser_write(file, pbuf, buf, count);
} while (ret == -EAGAIN && try_cnt--);
if (slow_input) {
pr_info("slow_input: es codec write size %x\n", ret);
msleep(10);
}
#ifdef DATA_DEBUG
/* dump to file */
//dump_write(vbuf, size);
//pr_info("vbuf: %p, size: %u, ret: %d\n", vbuf, size, ret);
#endif
return ret;
}
int is_need_to_buf(void)
{
struct vdec_s *vdec = g_cfg.vdec;
if (vdec->input.have_frame_num > 8)
return 0;
else
return 1;
}
int vdec_vframe_write(struct file *file, const char *buf,
unsigned int count, unsigned long int timestamp)
{
int ret = -1;
int try_cnt = 10;
struct vdec_s *vdec = g_cfg.vdec;
/* set timestamp */
vdec_set_timestamp(vdec, timestamp);
do {
ret = vdec_write_vframe(vdec, buf, count);
if (ret == -EAGAIN) {
vdec_input_level(&vdec->input);
msleep(20);
}
} while (ret == -EAGAIN && try_cnt--);
if (slow_input) {
pr_info("slow_input: frame codec write size %d\n", ret);
msleep(30);
}
#ifdef DATA_DEBUG
/* dump to file */
dump_write(buf, count);
#endif
aml_v4l2_debug(1, "vdec_vframe_write, vbuf: %p, size: %u, ret: %d, crc: %x\n",
buf, count, ret, crc32(0, buf, count));
return ret;
}
void aml_decoder_flush(void)
{
struct vdec_s *vdec = g_cfg.vdec;
if (vdec)
vdec_set_eos(vdec, true);
}
void aml_codec_reset(void)
{
struct vdec_s *vdec = g_cfg.vdec;
if (vdec) {
vdec_set_eos(vdec, false);
vdec_reset(vdec);
}
}
bool is_decoder_ready(void)
{
struct vdec_s *vdec = g_cfg.vdec;
int state = VDEC_STATUS_UNINITIALIZED;
if (vdec) {
state = vdec_get_status(vdec);
if (state == VDEC_STATUS_CONNECTED
|| state == VDEC_STATUS_ACTIVE)
return true;
}
return false;
}

View File

@@ -0,0 +1,40 @@
#ifndef VDEC_ADAPT_H
#define VDEC_ADAPT_H
#include <linux/amlogic/media/utils/vformat.h>
#include "aml_vcodec_drv.h"
struct aml_vdec_adapt {
enum vformat_e id;
void *vsi;
int32_t failure;
uint32_t inst_addr;
unsigned int signaled;
struct aml_vcodec_ctx *ctx;
struct platform_device *dev;
wait_queue_head_t wq;
struct file *filp;
//ipi_handler_t handler;
};
int video_decoder_init(struct aml_vdec_adapt *vdec);
int video_decoder_release(struct aml_vdec_adapt *vdec);
int vdec_vbuf_write(struct file *file, const char *buf, unsigned int count);
int vdec_vframe_write(struct file *file, const char *buf,
unsigned int count, unsigned long int pts);
int is_need_to_buf(void);
void aml_decoder_flush(void);
void aml_codec_reset(void);
extern void dump_write(const char __user *buf, size_t count);
bool is_decoder_ready(void);
#endif /* VDEC_ADAPT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
#ifndef _AML_VCODEC_DEC_H_
#define _AML_VCODEC_DEC_H_
#include <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#define VCODEC_CAPABILITY_4K_DISABLED 0x10
#define VCODEC_DEC_4K_CODED_WIDTH 4096U
#define VCODEC_DEC_4K_CODED_HEIGHT 2304U
#define AML_VDEC_MAX_W 2048U
#define AML_VDEC_MAX_H 1088U
#define AML_VDEC_IRQ_STATUS_DEC_SUCCESS 0x10000
#define V4L2_BUF_FLAG_LAST 0x00100000
/**
* struct vdec_fb - decoder frame buffer
* @base_y : Y plane memory info
* @base_c : C plane memory info
* @status : frame buffer status (vdec_fb_status)
*/
struct vdec_fb {
unsigned long vf_handle;
struct aml_vcodec_mem base_y;
struct aml_vcodec_mem base_c;
unsigned int status;
};
/**
* struct aml_video_dec_buf - Private data related to each VB2 buffer.
* @b: VB2 buffer
* @list: link list
* @used: Capture buffer contain decoded frame data and keep in
* codec data structure
* @ready_to_display: Capture buffer not display yet
* @queued_in_vb2: Capture buffer is queue in vb2
* @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2
* queue yet
* @lastframe: Intput buffer is last buffer - EOS
* @error: An unrecoverable error occurs on this buffer.
* @frame_buffer: Decode status, and buffer information of Capture buffer
*
* Note : These status information help us track and debug buffer state
*/
struct aml_video_dec_buf {
struct vb2_v4l2_buffer vb;
struct list_head list;
struct vdec_fb frame_buffer;
struct codec_mm_s *mem[2];
bool used;
bool ready_to_display;
bool queued_in_vb2;
bool queued_in_v4l2;
bool lastframe;
bool error;
};
extern const struct v4l2_ioctl_ops aml_vdec_ioctl_ops;
extern const struct v4l2_m2m_ops aml_vdec_m2m_ops;
/*
* aml_vdec_lock/aml_vdec_unlock are for ctx instance to
* get/release lock before/after access decoder hw.
* aml_vdec_lock get decoder hw lock and set curr_ctx
* to ctx instance that get lock
*/
void aml_vdec_unlock(struct aml_vcodec_ctx *ctx);
void aml_vdec_lock(struct aml_vcodec_ctx *ctx);
int aml_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
void aml_vcodec_dec_set_default_params(struct aml_vcodec_ctx *ctx);
void aml_vcodec_dec_release(struct aml_vcodec_ctx *ctx);
int aml_vcodec_dec_ctrls_setup(struct aml_vcodec_ctx *ctx);
void vdec_device_vf_run(struct aml_vcodec_ctx *ctx);
#endif /* _AML_VCODEC_DEC_H_ */

View File

@@ -0,0 +1,332 @@
#define DEBUG
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-contig.h>
#include "aml_vcodec_drv.h"
#include "aml_vcodec_dec.h"
#include "aml_vcodec_dec_pm.h"
//#include "aml_vcodec_intr.h"
#include "aml_vcodec_util.h"
#include "aml_vcodec_vfm.h"
#define VDEC_HW_ACTIVE 0x10
#define VDEC_IRQ_CFG 0x11
#define VDEC_IRQ_CLR 0x10
#define VDEC_IRQ_CFG_REG 0xa4
module_param(aml_v4l2_dbg_level, int, 0644);
module_param(aml_vcodec_dbg, bool, 0644);
static int fops_vcodec_open(struct file *file)
{
struct aml_vcodec_dev *dev = video_drvdata(file);
struct aml_vcodec_ctx *ctx = NULL;
struct aml_video_dec_buf *aml_buf = NULL;
int ret = 0;
struct vb2_queue *src_vq;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
aml_buf = kzalloc(sizeof(*aml_buf), GFP_KERNEL);
if (!aml_buf) {
kfree(ctx);
return -ENOMEM;
}
mutex_lock(&dev->dev_mutex);
ctx->empty_flush_buf = aml_buf;
ctx->id = dev->id_counter++;
v4l2_fh_init(&ctx->fh, video_devdata(file));
file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh);
INIT_LIST_HEAD(&ctx->list);
dev->filp = file;
ctx->dev = dev;
init_waitqueue_head(&ctx->queue);
mutex_init(&ctx->lock);
sema_init(&ctx->sem, 1);
init_waitqueue_head(&ctx->wq);
ctx->type = AML_INST_DECODER;
ret = aml_vcodec_dec_ctrls_setup(ctx);
if (ret) {
aml_v4l2_err("Failed to setup mt vcodec controls\n");
goto err_ctrls_setup;
}
ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
&aml_vcodec_dec_queue_init);
if (IS_ERR((__force void *)ctx->m2m_ctx)) {
ret = PTR_ERR((__force void *)ctx->m2m_ctx);
aml_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)\n", ret);
goto err_m2m_ctx_init;
}
src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq;
ctx->empty_flush_buf->lastframe = true;
aml_vcodec_dec_set_default_params(ctx);
list_add(&ctx->list, &dev->ctx_list);
mutex_unlock(&dev->dev_mutex);
pr_info("[%d] %s decoder\n", ctx->id, dev_name(&dev->plat_dev->dev));
return ret;
/* Deinit when failure occurred */
//err_load_fw:
v4l2_m2m_ctx_release(ctx->m2m_ctx);
err_m2m_ctx_init:
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
err_ctrls_setup:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
kfree(ctx->empty_flush_buf);
kfree(ctx);
mutex_unlock(&dev->dev_mutex);
return ret;
}
static int fops_vcodec_release(struct file *file)
{
struct aml_vcodec_dev *dev = video_drvdata(file);
struct aml_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
pr_info("[%d] release decoder\n", ctx->id);
mutex_lock(&dev->dev_mutex);
/*
* Call v4l2_m2m_ctx_release before aml_vcodec_dec_release. First, it
* makes sure the worker thread is not running after vdec_if_deinit.
* Second, the decoder will be flushed and all the buffers will be
* returned in stop_streaming.
*/
v4l2_m2m_ctx_release(ctx->m2m_ctx);
aml_vcodec_dec_release(ctx);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
list_del_init(&ctx->list);
kfree(ctx->empty_flush_buf);
kfree(ctx);
mutex_unlock(&dev->dev_mutex);
return 0;
}
static const struct v4l2_file_operations aml_vcodec_fops = {
.owner = THIS_MODULE,
.open = fops_vcodec_open,
.release = fops_vcodec_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = v4l2_m2m_fop_mmap,
};
static int aml_vcodec_probe(struct platform_device *pdev)
{
struct aml_vcodec_dev *dev;
struct video_device *vfd_dec;
int ret = 0;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
INIT_LIST_HEAD(&dev->ctx_list);
dev->plat_dev = pdev;
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
return ret;
}
mutex_init(&dev->dec_mutex);
mutex_init(&dev->dev_mutex);
spin_lock_init(&dev->irqlock);
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
"[/AML_V4L2_VDEC]");
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret) {
aml_v4l2_err("v4l2_device_register err=%d\n", ret);
goto err_res;
}
init_waitqueue_head(&dev->queue);
vfd_dec = video_device_alloc();
if (!vfd_dec) {
aml_v4l2_err("Failed to allocate video device\n");
ret = -ENOMEM;
goto err_dec_alloc;
}
vfd_dec->fops = &aml_vcodec_fops;
vfd_dec->ioctl_ops = &aml_vdec_ioctl_ops;
vfd_dec->release = video_device_release;
vfd_dec->lock = &dev->dev_mutex;
vfd_dec->v4l2_dev = &dev->v4l2_dev;
vfd_dec->vfl_dir = VFL_DIR_M2M;
vfd_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
V4L2_CAP_STREAMING;
snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s",
AML_VCODEC_DEC_NAME);
video_set_drvdata(vfd_dec, dev);
dev->vfd_dec = vfd_dec;
platform_set_drvdata(pdev, dev);
dev->m2m_dev_dec = v4l2_m2m_init(&aml_vdec_m2m_ops);
if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
aml_v4l2_err("Failed to init mem2mem dec device\n");
ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
goto err_dec_mem_init;
}
dev->decode_workqueue =
alloc_ordered_workqueue(AML_VCODEC_DEC_NAME,
WQ_MEM_RECLAIM | WQ_FREEZABLE);
if (!dev->decode_workqueue) {
aml_v4l2_err("Failed to create decode workqueue\n");
ret = -EINVAL;
goto err_event_workq;
}
dev->decode_workqueue_vf =
alloc_ordered_workqueue("aml-vcodec-dec-vf",
WQ_MEM_RECLAIM | WQ_FREEZABLE);
if (!dev->decode_workqueue_vf) {
aml_v4l2_err("Failed to create decode workqueue\n");
ret = -EINVAL;
destroy_workqueue(dev->decode_workqueue);
goto err_event_workq;
}
dev->reset_workqueue =
alloc_ordered_workqueue("aml-vcodec-reset",
WQ_MEM_RECLAIM | WQ_FREEZABLE);
if (!dev->decode_workqueue_vf) {
aml_v4l2_err("Failed to create decode workqueue\n");
ret = -EINVAL;
destroy_workqueue(dev->decode_workqueue_vf);
destroy_workqueue(dev->decode_workqueue);
goto err_event_workq;
}
//dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 26);
if (ret) {
pr_err("Failed to register video device\n");
goto err_dec_reg;
}
pr_info("decoder registered as /dev/video%d\n", vfd_dec->num);
return 0;
err_dec_reg:
destroy_workqueue(dev->reset_workqueue);
destroy_workqueue(dev->decode_workqueue_vf);
destroy_workqueue(dev->decode_workqueue);
err_event_workq:
v4l2_m2m_release(dev->m2m_dev_dec);
err_dec_mem_init:
video_unregister_device(vfd_dec);
err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_res:
return ret;
}
static const struct of_device_id aml_vcodec_match[] = {
{.compatible = "amlogic, vcodec-dec",},
{},
};
MODULE_DEVICE_TABLE(of, aml_vcodec_match);
static int aml_vcodec_dec_remove(struct platform_device *pdev)
{
struct aml_vcodec_dev *dev = platform_get_drvdata(pdev);
flush_workqueue(dev->decode_workqueue_vf);
destroy_workqueue(dev->decode_workqueue_vf);
flush_workqueue(dev->decode_workqueue);
destroy_workqueue(dev->decode_workqueue);
if (dev->m2m_dev_dec)
v4l2_m2m_release(dev->m2m_dev_dec);
if (dev->vfd_dec)
video_unregister_device(dev->vfd_dec);
v4l2_device_unregister(&dev->v4l2_dev);
return 0;
}
/*static void aml_vcodec_dev_release(struct device *dev)
{
}*/
static struct platform_driver aml_vcodec_dec_driver = {
.probe = aml_vcodec_probe,
.remove = aml_vcodec_dec_remove,
.driver = {
.name = AML_VCODEC_DEC_NAME,
.of_match_table = aml_vcodec_match,
},
};
/*
static struct platform_device aml_vcodec_dec_device = {
.name = AML_VCODEC_DEC_NAME,
.dev.release = aml_vcodec_dev_release,
};*/
module_platform_driver(aml_vcodec_dec_driver);
/*
static int __init amvdec_ports_init(void)
{
int ret;
ret = platform_device_register(&aml_vcodec_dec_device);
if (ret)
return ret;
ret = platform_driver_register(&aml_vcodec_dec_driver);
if (ret)
platform_device_unregister(&aml_vcodec_dec_device);
return ret;
}
static void __exit amvdec_ports_exit(void)
{
platform_driver_unregister(&aml_vcodec_dec_driver);
platform_device_unregister(&aml_vcodec_dec_device);
}
module_init(amvdec_ports_init);
module_exit(amvdec_ports_exit);
*/
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("AML video codec V4L2 decoder driver");

View File

@@ -0,0 +1,187 @@
#include <linux/clk.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include "aml_vcodec_dec_pm.h"
#include "aml_vcodec_util.h"
//#include "aml_vpu.h"
int aml_vcodec_init_dec_pm(struct aml_vcodec_dev *amldev)
{
struct device_node *node;
struct platform_device *pdev;
struct aml_vcodec_pm *pm;
int ret = 0;
pdev = amldev->plat_dev;
pm = &amldev->pm;
pm->amldev = amldev;
node = of_parse_phandle(pdev->dev.of_node, "larb", 0);
if (!node) {
aml_v4l2_err("of_parse_phandle larb fail!");
return -1;
}
pdev = of_find_device_by_node(node);
if (WARN_ON(!pdev)) {
of_node_put(node);
return -1;
}
pm->larbvdec = &pdev->dev;
pdev = amldev->plat_dev;
pm->dev = &pdev->dev;
pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll");
if (IS_ERR(pm->vcodecpll)) {
aml_v4l2_err("devm_clk_get vcodecpll fail");
ret = PTR_ERR(pm->vcodecpll);
}
pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2");
if (IS_ERR(pm->univpll_d2)) {
aml_v4l2_err("devm_clk_get univpll_d2 fail");
ret = PTR_ERR(pm->univpll_d2);
}
pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel");
if (IS_ERR(pm->clk_cci400_sel)) {
aml_v4l2_err("devm_clk_get clk_cci400_sel fail");
ret = PTR_ERR(pm->clk_cci400_sel);
}
pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel");
if (IS_ERR(pm->vdec_sel)) {
aml_v4l2_err("devm_clk_get vdec_sel fail");
ret = PTR_ERR(pm->vdec_sel);
}
pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll");
if (IS_ERR(pm->vdecpll)) {
aml_v4l2_err("devm_clk_get vdecpll fail");
ret = PTR_ERR(pm->vdecpll);
}
pm->vencpll = devm_clk_get(&pdev->dev, "vencpll");
if (IS_ERR(pm->vencpll)) {
aml_v4l2_err("devm_clk_get vencpll fail");
ret = PTR_ERR(pm->vencpll);
}
pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
if (IS_ERR(pm->venc_lt_sel)) {
aml_v4l2_err("devm_clk_get venc_lt_sel fail");
ret = PTR_ERR(pm->venc_lt_sel);
}
pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src");
if (IS_ERR(pm->vdec_bus_clk_src)) {
aml_v4l2_err("devm_clk_get vdec_bus_clk_src");
ret = PTR_ERR(pm->vdec_bus_clk_src);
}
pm_runtime_enable(&pdev->dev);
return ret;
}
void aml_vcodec_release_dec_pm(struct aml_vcodec_dev *dev)
{
pm_runtime_disable(dev->pm.dev);
}
void aml_vcodec_dec_pw_on(struct aml_vcodec_pm *pm)
{
int ret;
ret = pm_runtime_get_sync(pm->dev);
if (ret)
aml_v4l2_err("pm_runtime_get_sync fail %d", ret);
}
void aml_vcodec_dec_pw_off(struct aml_vcodec_pm *pm)
{
int ret;
ret = pm_runtime_put_sync(pm->dev);
if (ret)
aml_v4l2_err("pm_runtime_put_sync fail %d", ret);
}
void aml_vcodec_dec_clock_on(struct aml_vcodec_pm *pm)
{
int ret;
ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000);
if (ret)
aml_v4l2_err("clk_set_rate vcodecpll fail %d", ret);
ret = clk_set_rate(pm->vencpll, 800 * 1000000);
if (ret)
aml_v4l2_err("clk_set_rate vencpll fail %d", ret);
ret = clk_prepare_enable(pm->vcodecpll);
if (ret)
aml_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret);
ret = clk_prepare_enable(pm->vencpll);
if (ret)
aml_v4l2_err("clk_prepare_enable vencpll fail %d", ret);
ret = clk_prepare_enable(pm->vdec_bus_clk_src);
if (ret)
aml_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d",
ret);
ret = clk_prepare_enable(pm->venc_lt_sel);
if (ret)
aml_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret);
ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src);
if (ret)
aml_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d",
ret);
ret = clk_prepare_enable(pm->univpll_d2);
if (ret)
aml_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret);
ret = clk_prepare_enable(pm->clk_cci400_sel);
if (ret)
aml_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret);
ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2);
if (ret)
aml_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d",
ret);
ret = clk_prepare_enable(pm->vdecpll);
if (ret)
aml_v4l2_err("clk_prepare_enable vdecpll fail %d", ret);
ret = clk_prepare_enable(pm->vdec_sel);
if (ret)
aml_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret);
ret = clk_set_parent(pm->vdec_sel, pm->vdecpll);
if (ret)
aml_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret);
//ret = aml_smi_larb_get(pm->larbvdec);
if (ret)
aml_v4l2_err("aml_smi_larb_get larbvdec fail %d", ret);
}
void aml_vcodec_dec_clock_off(struct aml_vcodec_pm *pm)
{
//aml_smi_larb_put(pm->larbvdec);
clk_disable_unprepare(pm->vdec_sel);
clk_disable_unprepare(pm->vdecpll);
clk_disable_unprepare(pm->univpll_d2);
clk_disable_unprepare(pm->clk_cci400_sel);
clk_disable_unprepare(pm->venc_lt_sel);
clk_disable_unprepare(pm->vdec_bus_clk_src);
clk_disable_unprepare(pm->vencpll);
clk_disable_unprepare(pm->vcodecpll);
}

View File

@@ -0,0 +1,15 @@
#ifndef _AML_VCODEC_DEC_PM_H_
#define _AML_VCODEC_DEC_PM_H_
#include "aml_vcodec_drv.h"
int aml_vcodec_init_dec_pm(struct aml_vcodec_dev *dev);
void aml_vcodec_release_dec_pm(struct aml_vcodec_dev *dev);
void aml_vcodec_dec_pw_on(struct aml_vcodec_pm *pm);
void aml_vcodec_dec_pw_off(struct aml_vcodec_pm *pm);
void aml_vcodec_dec_clock_on(struct aml_vcodec_pm *pm);
void aml_vcodec_dec_clock_off(struct aml_vcodec_pm *pm);
#endif /* _AML_VCODEC_DEC_PM_H_ */

View File

@@ -0,0 +1,385 @@
#ifndef _AML_VCODEC_DRV_H_
#define _AML_VCODEC_DRV_H_
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include "aml_vcodec_util.h"
#define AML_VCODEC_DRV_NAME "aml_vcodec_drv"
#define AML_VCODEC_DEC_NAME "aml-vcodec-dec"
#define AML_VCODEC_ENC_NAME "aml-vcodec-enc"
#define AML_PLATFORM_STR "platform:mt8173"
#define AML_VCODEC_MAX_PLANES 3
#define AML_V4L2_BENCHMARK 0
#define WAIT_INTR_TIMEOUT_MS 1000
/**
* enum aml_hw_reg_idx - AML hw register base index
*/
enum aml_hw_reg_idx {
VDEC_SYS,
VDEC_MISC,
VDEC_LD,
VDEC_TOP,
VDEC_CM,
VDEC_AD,
VDEC_AV,
VDEC_PP,
VDEC_HWD,
VDEC_HWQ,
VDEC_HWB,
VDEC_HWG,
NUM_MAX_VDEC_REG_BASE,
/* h264 encoder */
VENC_SYS = NUM_MAX_VDEC_REG_BASE,
/* vp8 encoder */
VENC_LT_SYS,
NUM_MAX_VCODEC_REG_BASE
};
/**
* enum aml_instance_type - The type of an AML Vcodec instance.
*/
enum aml_instance_type {
AML_INST_DECODER = 0,
AML_INST_ENCODER = 1,
};
/**
* enum aml_instance_state - The state of an AML Vcodec instance.
* @AML_STATE_FREE - default state when instance is created
* @AML_STATE_INIT - vcodec instance is initialized
* @AML_STATE_HEADER - vdec had sps/pps header parsed or venc
* had sps/pps header encoded
* @AML_STATE_FLUSH - vdec is flushing. Only used by decoder
* @AML_STATE_ABORT - vcodec should be aborted
*/
enum aml_instance_state {
AML_STATE_FREE = 0,
AML_STATE_INIT = 1,
AML_STATE_HEADER = 2,
AML_STATE_FLUSH = 3,
AML_STATE_ABORT = 4,
AML_STATE_RESET = 5,
};
/**
* struct aml_encode_param - General encoding parameters type
*/
enum aml_encode_param {
AML_ENCODE_PARAM_NONE = 0,
AML_ENCODE_PARAM_BITRATE = (1 << 0),
AML_ENCODE_PARAM_FRAMERATE = (1 << 1),
AML_ENCODE_PARAM_INTRA_PERIOD = (1 << 2),
AML_ENCODE_PARAM_FORCE_INTRA = (1 << 3),
AML_ENCODE_PARAM_GOP_SIZE = (1 << 4),
};
enum aml_fmt_type {
AML_FMT_DEC = 0,
AML_FMT_ENC = 1,
AML_FMT_FRAME = 2,
};
/**
* struct aml_video_fmt - Structure used to store information about pixelformats
*/
struct aml_video_fmt {
u32 fourcc;
enum aml_fmt_type type;
u32 num_planes;
};
/**
* struct aml_codec_framesizes - Structure used to store information about
* framesizes
*/
struct aml_codec_framesizes {
u32 fourcc;
struct v4l2_frmsize_stepwise stepwise;
};
/**
* struct aml_q_type - Type of queue
*/
enum aml_q_type {
AML_Q_DATA_SRC = 0,
AML_Q_DATA_DST = 1,
};
/**
* struct aml_q_data - Structure used to store information about queue
*/
struct aml_q_data {
unsigned int visible_width;
unsigned int visible_height;
unsigned int coded_width;
unsigned int coded_height;
enum v4l2_field field;
unsigned int bytesperline[AML_VCODEC_MAX_PLANES];
unsigned int sizeimage[AML_VCODEC_MAX_PLANES];
struct aml_video_fmt *fmt;
};
/**
* struct aml_enc_params - General encoding parameters
* @bitrate: target bitrate in bits per second
* @num_b_frame: number of b frames between p-frame
* @rc_frame: frame based rate control
* @rc_mb: macroblock based rate control
* @seq_hdr_mode: H.264 sequence header is encoded separately or joined
* with the first frame
* @intra_period: I frame period
* @gop_size: group of picture size, it's used as the intra frame period
* @framerate_num: frame rate numerator. ex: framerate_num=30 and
* framerate_denom=1 menas FPS is 30
* @framerate_denom: frame rate denominator. ex: framerate_num=30 and
* framerate_denom=1 menas FPS is 30
* @h264_max_qp: Max value for H.264 quantization parameter
* @h264_profile: V4L2 defined H.264 profile
* @h264_level: V4L2 defined H.264 level
* @force_intra: force/insert intra frame
*/
struct aml_enc_params {
unsigned int bitrate;
unsigned int num_b_frame;
unsigned int rc_frame;
unsigned int rc_mb;
unsigned int seq_hdr_mode;
unsigned int intra_period;
unsigned int gop_size;
unsigned int framerate_num;
unsigned int framerate_denom;
unsigned int h264_max_qp;
unsigned int h264_profile;
unsigned int h264_level;
unsigned int force_intra;
};
/**
* struct aml_vcodec_pm - Power management data structure
*/
struct aml_vcodec_pm {
struct clk *vdec_bus_clk_src;
struct clk *vencpll;
struct clk *vcodecpll;
struct clk *univpll_d2;
struct clk *clk_cci400_sel;
struct clk *vdecpll;
struct clk *vdec_sel;
struct clk *vencpll_d2;
struct clk *venc_sel;
struct clk *univpll1_d2;
struct clk *venc_lt_sel;
struct device *larbvdec;
struct device *larbvenc;
struct device *larbvenclt;
struct device *dev;
struct aml_vcodec_dev *amldev;
};
/**
* struct vdec_pic_info - picture size information
* @pic_w: picture width
* @pic_h: picture height
* @buf_w: picture buffer width (64 aligned up from pic_w)
* @buf_h: picture buffer heiht (64 aligned up from pic_h)
* @y_bs_sz: Y bitstream size
* @c_bs_sz: CbCr bitstream size
* @y_len_sz: additional size required to store decompress information for y
* plane
* @c_len_sz: additional size required to store decompress information for cbcr
* plane
* E.g. suppose picture size is 176x144,
* buffer size will be aligned to 176x160.
*/
struct vdec_pic_info {
unsigned int pic_w;
unsigned int pic_h;
unsigned int buf_w;
unsigned int buf_h;
unsigned int y_bs_sz;
unsigned int c_bs_sz;
unsigned int y_len_sz;
unsigned int c_len_sz;
};
/**
* struct aml_vcodec_ctx - Context (instance) private data.
*
* @type: type of the instance - decoder or encoder
* @dev: pointer to the aml_vcodec_dev of the device
* @list: link to ctx_list of aml_vcodec_dev
* @fh: struct v4l2_fh
* @m2m_ctx: pointer to the v4l2_m2m_ctx of the context
* @q_data: store information of input and output queue
* of the context
* @id: index of the context that this structure describes
* @state: state of the context
* @param_change: indicate encode parameter type
* @enc_params: encoding parameters
* @dec_if: hooked decoder driver interface
* @enc_if: hoooked encoder driver interface
* @drv_handle: driver handle for specific decode/encode instance
*
* @picinfo: store picture info after header parsing
* @dpb_size: store dpb count after header parsing
* @int_cond: variable used by the waitqueue
* @int_type: type of the last interrupt
* @queue: waitqueue that can be used to wait for this context to
* finish
* @irq_status: irq status
*
* @ctrl_hdl: handler for v4l2 framework
* @decode_work: worker for the decoding
* @encode_work: worker for the encoding
* @last_decoded_picinfo: pic information get from latest decode
* @empty_flush_buf: a fake size-0 capture buffer that indicates flush
*
* @colorspace: enum v4l2_colorspace; supplemental to pixelformat
* @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
* @quantization: enum v4l2_quantization, colorspace quantization
* @xfer_func: enum v4l2_xfer_func, colorspace transfer function
* @lock: protect variables accessed by V4L2 threads and worker thread such as
* aml_video_dec_buf.
*/
struct aml_vcodec_ctx {
enum aml_instance_type type;
struct aml_vcodec_dev *dev;
struct list_head list;
struct v4l2_fh fh;
struct v4l2_m2m_ctx *m2m_ctx;
struct aml_q_data q_data[2];
int id;
enum aml_instance_state state;
enum aml_encode_param param_change;
struct aml_enc_params enc_params;
const struct vdec_common_if *dec_if;
const struct venc_common_if *enc_if;
unsigned long drv_handle;
struct vdec_pic_info picinfo;
int dpb_size;
int int_cond;
int int_type;
wait_queue_head_t queue;
unsigned int irq_status;
struct v4l2_ctrl_handler ctrl_hdl;
struct work_struct decode_work;
struct work_struct decode_work_vf;
struct work_struct encode_work;
struct work_struct reset_work;
struct vdec_pic_info last_decoded_picinfo;
struct aml_video_dec_buf *empty_flush_buf;
enum v4l2_colorspace colorspace;
enum v4l2_ycbcr_encoding ycbcr_enc;
enum v4l2_quantization quantization;
enum v4l2_xfer_func xfer_func;
int decoded_frame_cnt;
struct mutex lock;
struct semaphore sem;
wait_queue_head_t wq;
bool has_receive_eos;
};
/**
* struct aml_vcodec_dev - driver data
* @v4l2_dev: V4L2 device to register video devices for.
* @vfd_dec: Video device for decoder
* @vfd_enc: Video device for encoder.
*
* @m2m_dev_dec: m2m device for decoder
* @m2m_dev_enc: m2m device for encoder.
* @plat_dev: platform device
* @vpu_plat_dev: aml vpu platform device
* @alloc_ctx: VB2 allocator context
* (for allocations without kernel mapping).
* @ctx_list: list of struct aml_vcodec_ctx
* @irqlock: protect data access by irq handler and work thread
* @curr_ctx: The context that is waiting for codec hardware
*
* @reg_base: Mapped address of AML Vcodec registers.
*
* @id_counter: used to identify current opened instance
*
* @encode_workqueue: encode work queue
*
* @int_cond: used to identify interrupt condition happen
* @int_type: used to identify what kind of interrupt condition happen
* @dev_mutex: video_device lock
* @queue: waitqueue for waiting for completion of device commands
*
* @dec_irq: decoder irq resource
* @enc_irq: h264 encoder irq resource
* @enc_lt_irq: vp8 encoder irq resource
*
* @dec_mutex: decoder hardware lock
* @enc_mutex: encoder hardware lock.
*
* @pm: power management control
* @dec_capability: used to identify decode capability, ex: 4k
* @enc_capability: used to identify encode capability
*/
struct aml_vcodec_dev {
struct v4l2_device v4l2_dev;
struct video_device *vfd_dec;
struct video_device *vfd_enc;
struct file *filp;
struct v4l2_m2m_dev *m2m_dev_dec;
struct v4l2_m2m_dev *m2m_dev_enc;
struct platform_device *plat_dev;
struct platform_device *vpu_plat_dev;//??
struct vb2_alloc_ctx *alloc_ctx;//??
struct list_head ctx_list;
spinlock_t irqlock;
struct aml_vcodec_ctx *curr_ctx;
void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
unsigned long id_counter;
struct workqueue_struct *decode_workqueue;
struct workqueue_struct *decode_workqueue_vf;
struct workqueue_struct *encode_workqueue;
struct workqueue_struct *reset_workqueue;
int int_cond;
int int_type;
struct mutex dev_mutex;
wait_queue_head_t queue;
int dec_irq;
int enc_irq;
int enc_lt_irq;
struct mutex dec_mutex;
struct mutex enc_mutex;
struct aml_vcodec_pm pm;
unsigned int dec_capability;
unsigned int enc_capability;
};
static inline struct aml_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
{
return container_of(fh, struct aml_vcodec_ctx, fh);
}
static inline struct aml_vcodec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
{
return container_of(ctrl->handler, struct aml_vcodec_ctx, ctrl_hdl);
}
#endif /* _AML_VCODEC_DRV_H_ */

View File

@@ -0,0 +1,103 @@
#include <linux/module.h>
#include "aml_vcodec_drv.h"
#include "aml_vcodec_util.h"
//#include "aml_vpu.h"
/* For encoder, this will enable logs in venc/*/
bool aml_vcodec_dbg;
EXPORT_SYMBOL(aml_vcodec_dbg);
/* The log level of v4l2 encoder or decoder driver.
* That is, files under aml-vcodec/.
*/
int aml_v4l2_dbg_level;
EXPORT_SYMBOL(aml_v4l2_dbg_level);
void __iomem *aml_vcodec_get_reg_addr(struct aml_vcodec_ctx *data,
unsigned int reg_idx)
{
struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data;
if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) {
aml_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
return NULL;
}
return ctx->dev->reg_base[reg_idx];
}
EXPORT_SYMBOL(aml_vcodec_get_reg_addr);
int aml_vcodec_mem_alloc(struct aml_vcodec_ctx *data,
struct aml_vcodec_mem *mem)
{
unsigned long size = mem->size;
struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data;
struct device *dev = &ctx->dev->plat_dev->dev;
//mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
mem->va = codec_mm_dma_alloc_coherent(dev_name(dev), size,
&mem->dma_addr, GFP_KERNEL, 0);
if (!mem->va) {
aml_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev),
size);
return -ENOMEM;
}
memset(mem->va, 0, size);
aml_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va);
aml_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id,
(unsigned long)mem->dma_addr);
aml_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size);
return 0;
}
EXPORT_SYMBOL(aml_vcodec_mem_alloc);
void aml_vcodec_mem_free(struct aml_vcodec_ctx *data,
struct aml_vcodec_mem *mem)
{
unsigned long size = mem->size;
struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)data;
struct device *dev = &ctx->dev->plat_dev->dev;
if (!mem->va) {
aml_v4l2_err("%s dma_free size=%ld failed!", dev_name(dev),
size);
return;
}
aml_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va);
aml_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id,
(unsigned long)mem->dma_addr);
aml_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size);
dma_free_coherent(dev, size, mem->va, mem->dma_addr);
mem->va = NULL;
mem->dma_addr = 0;
mem->size = 0;
}
EXPORT_SYMBOL(aml_vcodec_mem_free);
void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev,
struct aml_vcodec_ctx *ctx)
{
unsigned long flags;
spin_lock_irqsave(&dev->irqlock, flags);
dev->curr_ctx = ctx;
spin_unlock_irqrestore(&dev->irqlock, flags);
}
EXPORT_SYMBOL(aml_vcodec_set_curr_ctx);
struct aml_vcodec_ctx *aml_vcodec_get_curr_ctx(struct aml_vcodec_dev *dev)
{
unsigned long flags;
struct aml_vcodec_ctx *ctx;
spin_lock_irqsave(&dev->irqlock, flags);
ctx = dev->curr_ctx;
spin_unlock_irqrestore(&dev->irqlock, flags);
return ctx;
}
EXPORT_SYMBOL(aml_vcodec_get_curr_ctx);

View File

@@ -0,0 +1,77 @@
#ifndef _AML_VCODEC_UTIL_H_
#define _AML_VCODEC_UTIL_H_
#include <linux/types.h>
#include <linux/dma-direction.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#define DEBUG
struct aml_vcodec_mem {
size_t size;
void *va;
dma_addr_t dma_addr;
unsigned int bytes_used;
};
struct aml_vcodec_ctx;
struct aml_vcodec_dev;
extern int aml_v4l2_dbg_level;
extern bool aml_vcodec_dbg;
#if defined(DEBUG)
#define aml_v4l2_debug(level, fmt, args...) \
do { \
if (aml_v4l2_dbg_level >= level) \
pr_info("[AML_V4L2] level=%d %s(),%d: " fmt "\n",\
level, __func__, __LINE__, ##args); \
} while (0)
#define aml_v4l2_debug_enter() aml_v4l2_debug(3, "+")
#define aml_v4l2_debug_leave() aml_v4l2_debug(3, "-")
#define aml_vcodec_debug(h, fmt, args...) \
do { \
if (aml_vcodec_dbg) \
pr_info("[AML_VCODEC][%d]: %s() " fmt "\n", \
((struct aml_vcodec_ctx *)h->ctx)->id, \
__func__, ##args); \
} while (0)
#define aml_vcodec_debug_enter(h) aml_vcodec_debug(h, "+")
#define aml_vcodec_debug_leave(h) aml_vcodec_debug(h, "-")
#else
#define aml_v4l2_debug(level, fmt, args...)
#define aml_v4l2_debug_enter()
#define aml_v4l2_debug_leave()
#define aml_vcodec_debug(h, fmt, args...)
#define aml_vcodec_debug_enter(h)
#define aml_vcodec_debug_leave(h)
#endif
#define aml_v4l2_err(fmt, args...) \
pr_err("[AML_V4L2][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \
##args)
#define aml_vcodec_err(h, fmt, args...) \
pr_err("[AML_VCODEC][ERROR][%d]: %s() " fmt "\n", \
((struct aml_vcodec_ctx *)h->ctx)->id, __func__, ##args)
void __iomem *aml_vcodec_get_reg_addr(struct aml_vcodec_ctx *data,
unsigned int reg_idx);
int aml_vcodec_mem_alloc(struct aml_vcodec_ctx *data,
struct aml_vcodec_mem *mem);
void aml_vcodec_mem_free(struct aml_vcodec_ctx *data,
struct aml_vcodec_mem *mem);
void aml_vcodec_set_curr_ctx(struct aml_vcodec_dev *dev,
struct aml_vcodec_ctx *ctx);
struct aml_vcodec_ctx *aml_vcodec_get_curr_ctx(struct aml_vcodec_dev *dev);
#endif /* _AML_VCODEC_UTIL_H_ */

View File

@@ -0,0 +1,179 @@
#include "aml_vcodec_vfm.h"
#include "aml_vcodec_vfq.h"
#include "aml_vcodec_util.h"
#include <media/v4l2-mem2mem.h>
#define RECEIVER_NAME "v4l2-video"
#define PROVIDER_NAME "v4l2-video"
static struct vframe_s *vdec_vf_peek(void *op_arg)
{
struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
return vfq_peek(&vfm->vf_que);
}
static struct vframe_s *vdec_vf_get(void *op_arg)
{
struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
return vfq_pop(&vfm->vf_que);
}
static void vdec_vf_put(struct vframe_s *vf, void *op_arg)
{
struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
vf_put(vf, vfm->recv_name);
vf_notify_provider(vfm->recv_name, VFRAME_EVENT_RECEIVER_PUT, NULL);
}
static int vdec_event_cb(int type, void *data, void *private_data)
{
if (type & VFRAME_EVENT_RECEIVER_PUT) {
} else if (type & VFRAME_EVENT_RECEIVER_GET) {
} else if (type & VFRAME_EVENT_RECEIVER_FRAME_WAIT) {
}
return 0;
}
static int vdec_vf_states(struct vframe_states *states, void *op_arg)
{
struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)op_arg;
states->vf_pool_size = POOL_SIZE;
states->buf_recycle_num = 0;
states->buf_free_num = POOL_SIZE - vfq_level(&vfm->vf_que);
states->buf_avail_num = vfq_level(&vfm->vf_que);
return 0;
}
void video_vf_put(struct vdec_fb *fb)
{
struct vframe_provider_s *vfp = vf_get_provider(RECEIVER_NAME);
struct vframe_s *vf = (struct vframe_s *)fb->vf_handle;
aml_v4l2_debug(4, "%s() [%d], vfp: %p, vf: %p, cnt: %d\n",
__FUNCTION__, __LINE__, vfp, vf, atomic_read(&vf->use_cnt));
if (vfp && vf && atomic_dec_and_test(&vf->use_cnt))
vf_put(vf, RECEIVER_NAME);
}
static const struct vframe_operations_s vf_provider = {
.peek = vdec_vf_peek,
.get = vdec_vf_get,
.put = vdec_vf_put,
.event_cb = vdec_event_cb,
.vf_states = vdec_vf_states,
};
static int video_receiver_event_fun(int type, void *data, void *private_data)
{
int ret = 0;
struct vframe_states states;
struct vcodec_vfm_s *vfm = (struct vcodec_vfm_s *)private_data;
aml_v4l2_debug(4, "%s() [%d], type: %d, vfm: %p\n",
__FUNCTION__, __LINE__, type, vfm);
switch (type) {
case VFRAME_EVENT_PROVIDER_UNREG: {
if (vf_get_receiver(vfm->prov_name)) {
aml_v4l2_debug(4, "%s() [%d] unreg %s provider.\n",
__FUNCTION__, __LINE__, vfm->prov_name);
vf_unreg_provider(&vfm->vf_prov);
}
vfq_init(&vfm->vf_que, POOL_SIZE + 1, &vfm->pool[0]);
break;
}
case VFRAME_EVENT_PROVIDER_START: {
if (vf_get_receiver(vfm->prov_name)) {
aml_v4l2_debug(4, "%s() [%d] reg %s provider.\n",
__FUNCTION__, __LINE__, vfm->prov_name);
vf_provider_init(&vfm->vf_prov, vfm->prov_name,
&vf_provider, vfm);
vf_reg_provider(&vfm->vf_prov);
vf_notify_receiver(vfm->prov_name,
VFRAME_EVENT_PROVIDER_START, NULL);
}
vfq_init(&vfm->vf_que, POOL_SIZE + 1, &vfm->pool[0]);
break;
}
case VFRAME_EVENT_PROVIDER_QUREY_STATE: {
vdec_vf_states(&states, vfm);
if (states.buf_avail_num > 0)
ret = RECEIVER_ACTIVE;
break;
}
case VFRAME_EVENT_PROVIDER_VFRAME_READY: {
if (vfq_level(&vfm->vf_que) > POOL_SIZE - 1)
ret = -1;
if (!vf_peek(vfm->recv_name))
ret = -1;
vfm->vf = vf_get(vfm->recv_name);
if (!vfm->vf)
ret = -1;
vfq_push(&vfm->vf_que, vfm->vf);
/*vf_notify_receiver(vfm->prov_name,
VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);*/
/* schedule capture work. */
vdec_device_vf_run(vfm->ctx);
aml_v4l2_debug(1, "%s() [%d] VFRAME_EVENT_PROVIDER_VFRAME_READY.\n",
__FUNCTION__, __LINE__);
break;
}
default:
aml_v4l2_debug(4, "the vf event is %d .", type);
}
return ret;
}
static const struct vframe_receiver_op_s vf_receiver = {
.event_cb = video_receiver_event_fun
};
struct vframe_s *peek_video_frame(struct vcodec_vfm_s *vfm)
{
return vfq_peek(&vfm->vf_que);
}
struct vframe_s *get_video_frame(struct vcodec_vfm_s *vfm)
{
return vfq_pop(&vfm->vf_que);
}
int vcodec_vfm_init(struct vcodec_vfm_s *vfm)
{
memcpy(vfm->recv_name, RECEIVER_NAME, sizeof(RECEIVER_NAME));
memcpy(vfm->prov_name, PROVIDER_NAME, sizeof(PROVIDER_NAME));
vf_receiver_init(&vfm->vf_recv, vfm->recv_name, &vf_receiver, vfm);
vf_reg_receiver(&vfm->vf_recv);
return 0;
}
void vcodec_vfm_release(struct vcodec_vfm_s *vfm)
{
vf_unreg_receiver(&vfm->vf_recv);
vf_unreg_provider(&vfm->vf_prov);
}

View File

@@ -0,0 +1,37 @@
#ifndef __AML_VCODEC_VFM_H_
#define __AML_VCODEC_VFM_H_
#include "aml_vcodec_vfq.h"
#include "aml_vcodec_drv.h"
#include "aml_vcodec_dec.h"
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
#define VF_NAME_SIZE (32)
#define POOL_SIZE (16)
struct vcodec_vfm_s {
struct aml_vcodec_ctx *ctx;
struct vfq_s vf_que;
struct vframe_s *vf;
struct vframe_s *pool[POOL_SIZE + 1];
char recv_name[VF_NAME_SIZE];
char prov_name[VF_NAME_SIZE];
struct vframe_provider_s vf_prov;
struct vframe_receiver_s vf_recv;
};
int vcodec_vfm_init(struct vcodec_vfm_s *vfm);
void vcodec_vfm_release(struct vcodec_vfm_s *vfm);
struct vframe_s *peek_video_frame(struct vcodec_vfm_s *vfm);
struct vframe_s *get_video_frame(struct vcodec_vfm_s *vfm);
int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_fb **out_fb);
int put_fb_to_queue(struct aml_vcodec_ctx *ctx, struct vdec_fb *in_fb);
void video_vf_put(struct vdec_fb *fb);
#endif /* __AML_VCODEC_VFM_H_ */

View File

@@ -0,0 +1,93 @@
#ifndef __AML_VCODEC_VFQ_H_
#define __AML_VCODEC_VFQ_H_
#include <linux/types.h>
#include <asm/barrier.h>
struct vfq_s {
int rp;
int wp;
int size;
int pre_rp;
int pre_wp;
struct vframe_s **pool;
};
static inline void vfq_lookup_start(struct vfq_s *q)
{
q->pre_rp = q->rp;
q->pre_wp = q->wp;
}
static inline void vfq_lookup_end(struct vfq_s *q)
{
q->rp = q->pre_rp;
q->wp = q->pre_wp;
}
static inline void vfq_init(struct vfq_s *q, u32 size, struct vframe_s **pool)
{
q->rp = q->wp = 0;
q->size = size;
q->pool = pool;
}
static inline bool vfq_empty(struct vfq_s *q)
{
return q->rp == q->wp;
}
static inline void vfq_push(struct vfq_s *q, struct vframe_s *vf)
{
int wp = q->wp;
/*ToDo*/
smp_mb();
q->pool[wp] = vf;
/*ToDo*/
smp_wmb();
q->wp = (wp == (q->size - 1)) ? 0 : (wp + 1);
}
static inline struct vframe_s *vfq_pop(struct vfq_s *q)
{
struct vframe_s *vf;
int rp;
if (vfq_empty(q))
return NULL;
rp = q->rp;
/*ToDo*/
smp_rmb();
vf = q->pool[rp];
/*ToDo*/
smp_mb();
q->rp = (rp == (q->size - 1)) ? 0 : (rp + 1);
return vf;
}
static inline struct vframe_s *vfq_peek(struct vfq_s *q)
{
return (vfq_empty(q)) ? NULL : q->pool[q->rp];
}
static inline int vfq_level(struct vfq_s *q)
{
int level = q->wp - q->rp;
if (level < 0)
level += q->size;
return level;
}
#endif /* __AML_VCODEC_VFQ_H_ */

View File

@@ -0,0 +1,389 @@
/*
* drivers/amlogic/media_modules/amvdec_ports/decoder/h264_parse.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/kernel.h>
#include "h264_parse.h"
#include "h264_stream.h"
static unsigned char h264_exp_golomb_bits[256] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
};
static unsigned char ZZ_SCAN[16] = {
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
};
static unsigned char ZZ_SCAN8[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
};
unsigned int h264_u(struct h264_stream_t *s, unsigned int n)
{
//if (n % 8 == 0) {
// return h264_stream_read_bytes(s, n / 8);
//}
return h264_stream_read_bits(s, n);
}
unsigned int h264_ue(struct h264_stream_t *s)
{
unsigned int bits, read;
unsigned char coded;
bits = 0;
while (true) {
if (h264_stream_bytes_remaining(s) < 1) {
read = h264_stream_peek_bits(s, s->bit_pos) <<
(8 - s->bit_pos);
break;
}
read = h264_stream_peek_bits(s, 8);
if (bits > 16)
break;
if (read)
break;
h264_stream_read_bits(s, 8);
bits += 8;
}
coded = h264_exp_golomb_bits[read];
h264_stream_read_bits(s, coded);
bits += coded;
return h264_stream_read_bits(s, bits + 1) - 1;
}
int h264_se(struct h264_stream_t *s)
{
unsigned int ret;
ret = h264_ue(s);
if (!(ret & 0x1)) {
ret >>= 1;
return (int)(-ret);
}
return (ret + 1) >> 1;
}
void h264_f(struct h264_stream_t *s, unsigned int n, unsigned int pattern)
{
unsigned int val = h264_u(s, n);
if (val != pattern) {
pr_err("fixed-pattern doesn't match. expected: %x actual: %x\n",
pattern, (unsigned int)val);
return;
}
}
void h264_rbsp_trailing_bits(struct h264_stream_t *s)
{
h264_f(s, 1, 1);
h264_f(s, s->bit_pos, 0);
}
// syntax for scaling list matrix values
void Scaling_List(int *scalingList, int sizeOfScalingList,
bool *UseDefaultScalingMatrix, struct h264_stream_t *s)
{
int j, scanj;
int delta_scale, lastScale, nextScale;
lastScale = 8;
nextScale = 8;
for (j = 0; j < sizeOfScalingList; j++) {
scanj = (sizeOfScalingList == 16) ? ZZ_SCAN[j] : ZZ_SCAN8[j];
if (nextScale != 0) {
delta_scale = h264_ue(s);
nextScale = (lastScale + delta_scale + 256) % 256;
*UseDefaultScalingMatrix =
(bool) (scanj == 0 && nextScale == 0);
}
scalingList[scanj] = (nextScale == 0) ? lastScale : nextScale;
lastScale = scalingList[scanj];
}
}
void h264_sps_parse(struct h264_stream_t *s, struct h264_SPS_t *sps)
{
unsigned int i, n_ScalingList;
sps->profile_idc = h264_u(s, 8);
if ((sps->profile_idc != BASELINE) &&
(sps->profile_idc != MAIN) &&
(sps->profile_idc != EXTENDED) &&
(sps->profile_idc != FREXT_HP) &&
(sps->profile_idc != FREXT_Hi10P) &&
(sps->profile_idc != FREXT_Hi422) &&
(sps->profile_idc != FREXT_Hi444) &&
(sps->profile_idc != FREXT_CAVLC444)
&& (sps->profile_idc != MVC_HIGH)
&& (sps->profile_idc != STEREO_HIGH)) {
pr_err("Invalid Profile IDC (%d) encountered.\n",
sps->profile_idc);
return;
}
sps->constrained_set0_flag = h264_u(s, 1);
sps->constrained_set1_flag = h264_u(s, 1);
sps->constrained_set2_flag = h264_u(s, 1);
h264_u(s, 5); // reserved_zero_5bits
sps->level_idc = h264_u(s, 8);
sps->seq_parameter_set_id = h264_ue(s);
// Fidelity Range Extensions stuff
sps->chroma_format_idc = 1;
sps->bit_depth_luma_minus8 = 0;
sps->bit_depth_chroma_minus8 = 0;
sps->lossless_qpprime_flag = 0;
sps->separate_colour_plane_flag = 0;
if ((sps->profile_idc == FREXT_HP) ||
(sps->profile_idc == FREXT_Hi10P) ||
(sps->profile_idc == FREXT_Hi422) ||
(sps->profile_idc == FREXT_Hi444) ||
(sps->profile_idc == FREXT_CAVLC444)) {
sps->chroma_format_idc = h264_ue(s);
if (sps->chroma_format_idc == YUV444)
sps->separate_colour_plane_flag = h264_u(s, 1);
sps->bit_depth_luma_minus8 = h264_ue(s);
sps->bit_depth_chroma_minus8 = h264_ue(s);
//checking;
if ((sps->bit_depth_luma_minus8 + 8 > sizeof(unsigned short) * 8) ||
(sps->bit_depth_chroma_minus8 + 8 > sizeof(unsigned short) * 8)) {
pr_err("Source picture has higher bit depth than imgpel data type.\n");
pr_err("Please recompile with larger data type for imgpel.\n");
}
sps->lossless_qpprime_flag = h264_u(s, 1);
sps->seq_scaling_matrix_present_flag = h264_u(s, 1);
if (sps->seq_scaling_matrix_present_flag) {
n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12;
for (i = 0; i < n_ScalingList; i++) {
sps->seq_scaling_list_present_flag[i] = h264_u(s, 1);
if (sps->seq_scaling_list_present_flag[i]) {
if (i < 6)
Scaling_List(sps->ScalingList4x4[i], 16,
&sps->UseDefaultScalingMatrix4x4Flag[i], s);
else
Scaling_List(sps->ScalingList8x8[i - 6],
64, &sps->UseDefaultScalingMatrix8x8Flag[i - 6], s);
}
}
}
}
sps->log2_max_frame_num_minus4 = h264_ue(s);
sps->pic_order_cnt_type = h264_ue(s);
if (sps->pic_order_cnt_type == 0) {
sps->log2_max_pic_order_cnt_lsb_minus4 = h264_ue(s);
} else if (sps->pic_order_cnt_type == 1) {
sps->delta_pic_order_always_zero_flag = h264_se(s);
sps->offset_for_non_ref_pic = h264_se(s);
sps->offset_for_top_to_bottom_field = h264_se(s);
sps->num_ref_frames_in_poc_cycle = h264_se(s);
for (i = 0; i < sps->num_ref_frames_in_poc_cycle; ++i)
sps->offset_for_ref_frame[i] = h264_se(s);
}
sps->num_ref_frames = h264_ue(s);
sps->gaps_in_frame_num_value_allowed_flag = h264_u(s, 1);
sps->pic_width_in_mbs_minus1 = h264_ue(s);
sps->pic_height_in_map_units_minus1 = h264_ue(s);
sps->frame_mbs_only_flag = h264_u(s, 1);
if (!sps->frame_mbs_only_flag)
sps->mb_adaptive_frame_field_flag = h264_u(s, 1);
sps->direct_8x8_inference_flag = h264_u(s, 1);
sps->frame_cropping_flag = h264_u(s, 1);
if (sps->frame_cropping_flag) {
sps->frame_crop_left_offset = h264_ue(s);
sps->frame_crop_right_offset = h264_ue(s);
sps->frame_crop_top_offset = h264_ue(s);
sps->frame_crop_bottom_offset = h264_ue(s);
}
sps->vui_parameters_present_flag = h264_u(s, 1);
//if (sps->vui_parameters_present_flag) {
// sps->vui_parameters = h264_vui_parameters(s);
//}
h264_rbsp_trailing_bits(s);
}
void h264_pps_parse(struct h264_stream_t *s, struct h264_PPS_t *pps)
{
pps->pic_parameter_set_id = h264_ue(s);
pps->seq_parameter_set_id = h264_ue(s);
pps->entropy_coding_mode_flag = h264_u(s, 1);
pps->pic_order_present_flag = h264_u(s, 1);
pps->num_slice_groups_minus1 = h264_ue(s);
if (pps->num_slice_groups_minus1 > 0) {
pps->slice_group_map_type = h264_ue(s);
if (pps->slice_group_map_type == 0) {
pps->run_length_minus1 = h264_ue(s);
} else if (pps->slice_group_map_type == 2) {
pps->top_left = h264_ue(s);
pps->bottom_right = h264_ue(s);
} else if (pps->slice_group_map_type == 3 ||
pps->slice_group_map_type == 4 ||
pps->slice_group_map_type == 5) {
pps->slice_group_change_direction_flag = h264_u(s, 1);
pps->slice_group_change_rate_minus1 = h264_ue(s);
} else if (pps->slice_group_map_type == 6) {
pps->pic_size_in_map_units_minus1 = h264_ue(s);
pps->slice_group_id = h264_ue(s);
}
}
pps->num_ref_idx_l0_active_minus1 = h264_ue(s);
pps->num_ref_idx_l1_active_minus1 = h264_ue(s);
pps->weighted_pred_flag = h264_u(s, 1);
pps->weighted_bipred_idc = h264_u(s, 2);
pps->pic_init_qp_minus26 = h264_se(s);
pps->pic_init_qs_minus26 = h264_se(s);
pps->chroma_qp_index_offset = h264_se(s);
pps->deblocking_filter_control_present_flag = h264_u(s, 1);
pps->constrained_intra_pred_flag = h264_u(s, 1);
pps->redundant_pic_cnt_present_flag = h264_u(s, 1);
h264_rbsp_trailing_bits(s);
}
void h264_sps_info(struct h264_SPS_t *sps)
{
int i;
pr_info("sequence_parameter_set {\n");
pr_info(" profile_idc: %d\n", sps->profile_idc);
pr_info(" constraint_set0_flag: %d\n", sps->constrained_set0_flag);
pr_info(" constraint_set1_flag: %d\n", sps->constrained_set1_flag);
pr_info(" constraint_set2_flag: %d\n", sps->constrained_set2_flag);
pr_info(" level_idc: %d\n", sps->level_idc);
pr_info(" seq_parameter_set_id: %d\n", sps->seq_parameter_set_id);
pr_info(" log2_max_frame_num_minus4: %d\n",
sps->log2_max_frame_num_minus4);
pr_info(" pic_order_cnt_type: %d\n", sps->pic_order_cnt_type);
if (sps->pic_order_cnt_type == 0) {
pr_info(" log2_max_pic_order_cnt_lsb_minus4: %d\n",
sps->log2_max_pic_order_cnt_lsb_minus4);
} else if (sps->pic_order_cnt_type == 1) {
pr_info(" delta_pic_order_always_zero_flag: %d\n",
sps->delta_pic_order_always_zero_flag);
pr_info(" offset_for_non_ref_pic: %d\n",
sps->offset_for_non_ref_pic);
pr_info(" offset_for_top_to_bottom_field: %d\n",
sps->offset_for_top_to_bottom_field);
pr_info(" num_ref_frames_in_pic_order_cnt_cycle: %d\n",
sps->num_ref_frames_in_poc_cycle);
for (i = 0; i < sps->num_ref_frames_in_poc_cycle; ++i) {
pr_info(" offset_for_ref_frame[%d]: %d\n", i,
sps->offset_for_ref_frame[i]);
}
}
pr_info(" num_ref_frames: %d\n", sps->num_ref_frames);
pr_info(" gaps_in_frame_num_value_allowed_flag: %d\n",
sps->gaps_in_frame_num_value_allowed_flag);
pr_info(" pic_width_in_mbs_minus1: %d\n",
sps->pic_width_in_mbs_minus1);
pr_info(" pic_height_in_map_units_minus1: %d\n",
sps->pic_height_in_map_units_minus1);
pr_info(" frame_mbs_only_flag: %d\n",
sps->frame_mbs_only_flag);
pr_info(" mb_adaptive_frame_field_flag: %d\n",
sps->mb_adaptive_frame_field_flag);
pr_info(" direct_8x8_inference_flag: %d\n",
sps->direct_8x8_inference_flag);
pr_info(" frame_cropping_flag: %d\n",
sps->frame_cropping_flag);
if (sps->frame_cropping_flag) {
pr_info(" frame_crop_left_offset: %d\n",
sps->frame_crop_left_offset);
pr_info(" frame_crop_right_offset: %d\n",
sps->frame_crop_right_offset);
pr_info(" frame_crop_top_offset: %d\n",
sps->frame_crop_top_offset);
pr_info(" frame_crop_bottom_offset: %d\n",
sps->frame_crop_bottom_offset);
}
pr_info(" vui_parameters_present_flag: %d\n",
sps->vui_parameters_present_flag);
//if (sps->vui_parameters_present_flag) {
// h264_print_vui_parameters(sps->vui_parameters);
//}
pr_info(" }\n");
}
void h264_pps_info(struct h264_PPS_t *pps)
{
pr_info("pic_parameter_set {\n");
pr_info(" pic_parameter_set_id: %d\n",
pps->pic_parameter_set_id);
pr_info(" seq_parameter_set_id: %d\n",
pps->seq_parameter_set_id);
pr_info(" entropy_coding_mode_flag: %d\n",
pps->entropy_coding_mode_flag);
pr_info(" pic_order_present_flag: %d\n",
pps->pic_order_present_flag);
pr_info(" num_slice_groups_minus1: %d\n",
pps->num_slice_groups_minus1);
// FIXME: Code for slice groups is missing here.
pr_info(" num_ref_idx_l0_active_minus1: %d\n",
pps->num_ref_idx_l0_active_minus1);
pr_info(" num_ref_idx_l1_active_minus1: %d\n",
pps->num_ref_idx_l1_active_minus1);
pr_info(" weighted_pred_flag: %d\n", pps->weighted_pred_flag);
pr_info(" weighted_bipred_idc: %d\n", pps->weighted_bipred_idc);
pr_info(" pic_init_qp_minus26: %d\n", pps->pic_init_qp_minus26);
pr_info(" pic_init_qs_minus26: %d\n", pps->pic_init_qs_minus26);
pr_info(" chroma_qp_index_offset: %d\n",
pps->chroma_qp_index_offset);
pr_info(" deblocking_filter_control_present_flag: %d\n",
pps->deblocking_filter_control_present_flag);
pr_info(" constrained_intra_pred_flag: %d\n",
pps->constrained_intra_pred_flag);
pr_info(" redundant_pic_cnt_present_flag: %d\n",
pps->redundant_pic_cnt_present_flag);
pr_info(" }\n");
}

View File

@@ -0,0 +1,141 @@
/*
* drivers/amlogic/media_modules/amvdec_ports/decoder/h264_parse.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef _H264_PARSE_H
#define _H264_PARSE_H
#include "h264_stream.h"
enum color_model {
CM_UNKNOWN = -1,
CM_YUV = 0,
CM_RGB = 1,
CM_XYZ = 2
};
enum color_format {
CF_UNKNOWN = -1, //!< Unknown color format
YUV400 = 0, //!< Monochrome
YUV420 = 1, //!< 4:2:0
YUV422 = 2, //!< 4:2:2
YUV444 = 3 //!< 4:4:4
};
enum pixel_format {
PF_UNKNOWN = -1, //!< Unknown color ordering
UYVY = 0, //!< UYVY
YUY2 = 1, //!< YUY2
YUYV = 1, //!< YUYV
YVYU = 2, //!< YVYU
BGR = 3, //!< BGR
V210 = 4 //!< Video Clarity 422 format (10 bits)
};
//AVC Profile IDC definitions
enum profile_idc{
NO_PROFILE = 0, //!< disable profile checking for experimental coding (enables FRExt, but disables MV)
FREXT_CAVLC444 = 44, //!< YUV 4:4:4/14 "CAVLC 4:4:4"
BASELINE = 66, //!< YUV 4:2:0/8 "Baseline"
MAIN = 77, //!< YUV 4:2:0/8 "Main"
EXTENDED = 88, //!< YUV 4:2:0/8 "Extended"
FREXT_HP = 100, //!< YUV 4:2:0/8 "High"
FREXT_Hi10P = 110, //!< YUV 4:2:0/10 "High 10"
FREXT_Hi422 = 122, //!< YUV 4:2:2/10 "High 4:2:2"
FREXT_Hi444 = 244, //!< YUV 4:4:4/14 "High 4:4:4"
MVC_HIGH = 118, //!< YUV 4:2:0/8 "Multiview High"
STEREO_HIGH = 128 //!< YUV 4:2:0/8 "Stereo High"
};
/* sequence parameter set */
struct h264_SPS_t {
bool vailid;
unsigned int profile_idc;
bool constrained_set0_flag;
bool constrained_set1_flag;
bool constrained_set2_flag;
bool constrained_set3_flag;
unsigned int level_idc;
unsigned int seq_parameter_set_id;
unsigned int chroma_format_idc;
bool seq_scaling_matrix_present_flag;
int seq_scaling_list_present_flag[12];
int ScalingList4x4[6][16];
int ScalingList8x8[6][64];
bool UseDefaultScalingMatrix4x4Flag[6];
bool UseDefaultScalingMatrix8x8Flag[6];
unsigned int bit_depth_luma_minus8;
unsigned int bit_depth_chroma_minus8;
unsigned int log2_max_frame_num_minus4;
unsigned int pic_order_cnt_type;
unsigned int log2_max_pic_order_cnt_lsb_minus4;
bool delta_pic_order_always_zero_flag;
int offset_for_non_ref_pic;
int offset_for_top_to_bottom_field;
unsigned int num_ref_frames_in_poc_cycle;
int offset_for_ref_frame[255];
int num_ref_frames;
bool gaps_in_frame_num_value_allowed_flag;
unsigned int pic_width_in_mbs_minus1;
unsigned int pic_height_in_map_units_minus1;
bool frame_mbs_only_flag;
bool mb_adaptive_frame_field_flag;
bool direct_8x8_inference_flag;
bool frame_cropping_flag;
unsigned int frame_crop_left_offset;
unsigned int frame_crop_right_offset;
unsigned int frame_crop_top_offset;
unsigned int frame_crop_bottom_offset;
bool vui_parameters_present_flag;
//h264_vui_parameters_t *vui_parameters;
unsigned separate_colour_plane_flag;
int lossless_qpprime_flag;
};
/* pic parameter set */
struct h264_PPS_t {
int pic_parameter_set_id;
int seq_parameter_set_id;
int entropy_coding_mode_flag;
int pic_order_present_flag;
int num_slice_groups_minus1;
int slice_group_map_type;
int run_length_minus1;
int top_left;
int bottom_right;
int slice_group_change_direction_flag;
int slice_group_change_rate_minus1;
int pic_size_in_map_units_minus1;
int slice_group_id;
int num_ref_idx_l0_active_minus1;
int num_ref_idx_l1_active_minus1;
int weighted_pred_flag;
int weighted_bipred_idc;
int pic_init_qp_minus26;
int pic_init_qs_minus26;
int chroma_qp_index_offset;
int deblocking_filter_control_present_flag;
int constrained_intra_pred_flag;
int redundant_pic_cnt_present_flag;
};
void h264_sps_parse(struct h264_stream_t *s, struct h264_SPS_t *sps);
void h264_pps_parse(struct h264_stream_t *s, struct h264_PPS_t *pps);
void h264_sps_info(struct h264_SPS_t *sps);
void h264_pps_info(struct h264_PPS_t *pps);
#endif //_H264_PARSE_H

View File

@@ -0,0 +1,111 @@
/*
* drivers/amlogic/media_modules/amvdec_ports/decoder/h264_stream.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/mm.h>
#include <linux/slab.h>
#include "h264_stream.h"
void h264_stream_set(struct h264_stream_t *s, unsigned char *data, int size)
{
s->data = data;
s->size = size;
s->bit_pos = 7;
s->byte_pos = 0;
}
unsigned int h264_stream_read_bits(struct h264_stream_t *s, unsigned int n)
{
unsigned int ret = 0;
unsigned char b = 0;
int i;
if (n == 0)
return 0;
for (i = 0; i < n; ++i) {
if (h264_stream_bits_remaining(s) == 0)
ret <<= n - i - 1;
b = s->data[s->byte_pos];
if (n - i <= 32)
ret = ret << 1 | BITAT(b, s->bit_pos);
if (s->bit_pos == 0) {
s->bit_pos = 7;
s->byte_pos++;
} else
s->bit_pos--;
}
return ret;
}
unsigned int h264_stream_peek_bits(struct h264_stream_t *s, unsigned int n)
{
int prev_bit_pos = s->bit_pos;
int prev_byte_pos = s->byte_pos;
unsigned int ret = h264_stream_read_bits(s, n);
s->bit_pos = prev_bit_pos;
s->byte_pos = prev_byte_pos;
return ret;
}
unsigned int h264_stream_read_bytes(struct h264_stream_t *s, unsigned int n)
{
unsigned int ret = 0;
int i;
if (n == 0)
return 0;
for (i = 0; i < n; ++i) {
if (h264_stream_bytes_remaining(s) == 0) {
ret <<= (n - i - 1) * 8;
break;
}
if (n - i <= 4)
ret = ret << 8 | s->data[s->byte_pos];
s->byte_pos++;
}
return ret;
}
unsigned int h264_stream_peek_bytes(struct h264_stream_t *s, unsigned int n)
{
int prev_byte_pos = s->byte_pos;
unsigned int ret = h264_stream_read_bytes(s, n);
s->byte_pos = prev_byte_pos;
return ret;
}
int h264_stream_bits_remaining(struct h264_stream_t *s)
{
return (s->size - s->byte_pos) * 8 + s->bit_pos;
}
int h264_stream_bytes_remaining(struct h264_stream_t *s)
{
return s->size - s->byte_pos;
}

View File

@@ -0,0 +1,39 @@
/*
* drivers/amlogic/media_modules/amvdec_ports/decoder/h264_stream.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef _H264_STREAM_H
#define _H264_STREAM_H
#include "utils.h"
struct h264_stream_t {
unsigned char *data;
unsigned int size;
int bit_pos;
int byte_pos;
};
void h264_stream_set(struct h264_stream_t *s, unsigned char *data, int size);
unsigned int h264_stream_read_bits(struct h264_stream_t *s, unsigned int n);
unsigned int h264_stream_peek_bits(struct h264_stream_t *s, unsigned int n);
unsigned int h264_stream_read_bytes(struct h264_stream_t *s, unsigned int n);
unsigned int h264_stream_peek_bytes(struct h264_stream_t *s, unsigned int n);
int h264_stream_bits_remaining(struct h264_stream_t *s);
int h264_stream_bytes_remaining(struct h264_stream_t *s);
#endif //_H264_STREAM_H

View File

@@ -0,0 +1,31 @@
/*
* drivers/amlogic/media_modules/amvdec_ports/decoder/utils.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef _UTILS_H
#define _UTILS_H
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define CLAMP(x, low, high) \
(((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#define BITAT(x, n) ((x & (1 << n)) == (1 << n))
typedef unsigned char uint8_t;
typedef int int32_t;
typedef unsigned int uint32_t;
#endif //_UTILS_H

View File

@@ -0,0 +1,698 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include "../vdec_drv_if.h"
#include "../aml_vcodec_util.h"
#include "../aml_vcodec_dec.h"
//#include "../aml_vcodec_intr.h"
#include "../aml_vcodec_adapt.h"
#include "../vdec_drv_base.h"
#include "../aml_vcodec_vfm.h"
#include "h264_stream.h"
#include "h264_parse.h"
/* h264 NALU type */
#define NAL_NON_IDR_SLICE 0x01
#define NAL_IDR_SLICE 0x05
#define NAL_H264_SEI 0x06
#define NAL_H264_SPS 0x07
#define NAL_H264_PPS 0x08
#define NAL_TYPE(value) ((value) & 0x1F)
#define BUF_PREDICTION_SZ (64 * 1024)//(32 * 1024)
#define MB_UNIT_LEN 16
/* motion vector size (bytes) for every macro block */
#define HW_MB_STORE_SZ 64
#define H264_MAX_FB_NUM 17
#define HDR_PARSING_BUF_SZ 1024
/**
* struct h264_fb - h264 decode frame buffer information
* @vdec_fb_va : virtual address of struct vdec_fb
* @y_fb_dma : dma address of Y frame buffer (luma)
* @c_fb_dma : dma address of C frame buffer (chroma)
* @poc : picture order count of frame buffer
* @reserved : for 8 bytes alignment
*/
struct h264_fb {
uint64_t vdec_fb_va;
uint64_t y_fb_dma;
uint64_t c_fb_dma;
int32_t poc;
uint32_t reserved;
};
/**
* struct h264_ring_fb_list - ring frame buffer list
* @fb_list : frame buffer arrary
* @read_idx : read index
* @write_idx : write index
* @count : buffer count in list
*/
struct h264_ring_fb_list {
struct h264_fb fb_list[H264_MAX_FB_NUM];
unsigned int read_idx;
unsigned int write_idx;
unsigned int count;
unsigned int reserved;
};
/**
* struct vdec_h264_dec_info - decode information
* @dpb_sz : decoding picture buffer size
* @resolution_changed : resoltion change happen
* @realloc_mv_buf : flag to notify driver to re-allocate mv buffer
* @reserved : for 8 bytes alignment
* @bs_dma : Input bit-stream buffer dma address
* @y_fb_dma : Y frame buffer dma address
* @c_fb_dma : C frame buffer dma address
* @vdec_fb_va : VDEC frame buffer struct virtual address
*/
struct vdec_h264_dec_info {
uint32_t dpb_sz;
uint32_t resolution_changed;
uint32_t realloc_mv_buf;
uint32_t reserved;
uint64_t bs_dma;
uint64_t y_fb_dma;
uint64_t c_fb_dma;
uint64_t vdec_fb_va;
};
/**
* struct vdec_h264_vsi - shared memory for decode information exchange
* between VPU and Host.
* The memory is allocated by VPU then mapping to Host
* in vpu_dec_init() and freed in vpu_dec_deinit()
* by VPU.
* AP-W/R : AP is writer/reader on this item
* VPU-W/R: VPU is write/reader on this item
* @hdr_buf : Header parsing buffer (AP-W, VPU-R)
* @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R)
* @mv_buf_dma : HW working motion vector buffer dma address (AP-W, VPU-R)
* @list_free : free frame buffer ring list (AP-W/R, VPU-W)
* @list_disp : display frame buffer ring list (AP-R, VPU-W)
* @dec : decode information (AP-R, VPU-W)
* @pic : picture information (AP-R, VPU-W)
* @crop : crop information (AP-R, VPU-W)
*/
struct vdec_h264_vsi {
unsigned char hdr_buf[HDR_PARSING_BUF_SZ];
int sps_size;
int pps_size;
int sei_size;
int head_offset;
uint64_t pred_buf_dma;
uint64_t mv_buf_dma[H264_MAX_FB_NUM];
struct h264_ring_fb_list list_free;
struct h264_ring_fb_list list_disp;
struct vdec_h264_dec_info dec;
struct vdec_pic_info pic;
struct v4l2_rect crop;
};
/**
* struct vdec_h264_inst - h264 decoder instance
* @num_nalu : how many nalus be decoded
* @ctx : point to aml_vcodec_ctx
* @pred_buf : HW working predication buffer
* @mv_buf : HW working motion vector buffer
* @vpu : VPU instance
* @vsi : VPU shared information
*/
struct vdec_h264_inst {
unsigned int num_nalu;
struct aml_vcodec_ctx *ctx;
struct aml_vcodec_mem pred_buf;
struct aml_vcodec_mem mv_buf[H264_MAX_FB_NUM];
//struct vdec_vpu_inst vpu;
struct aml_vdec_adapt vdec;
struct vdec_h264_vsi *vsi;
struct vcodec_vfm_s vfm;
};
static DEFINE_MUTEX(mutex);
#define DUMP_FILE_NAME "/data/dump/dump.tmp"
static struct file *filp;
static loff_t file_pos;
void dump_write(const char __user *buf, size_t count)
{
mm_segment_t old_fs;
if (!filp)
return;
old_fs = get_fs();
set_fs(KERNEL_DS);
if (count != vfs_write(filp, buf, count, &file_pos))
pr_err("Failed to write file\n");
set_fs(old_fs);
}
void dump_init(void)
{
filp = filp_open(DUMP_FILE_NAME, O_CREAT | O_RDWR, 0644);
if (IS_ERR(filp)) {
pr_err("open dump file failed\n");
filp = NULL;
}
}
void dump_deinit(void)
{
if (filp) {
filp_close(filp, current->files);
filp = NULL;
file_pos = 0;
}
}
static void get_pic_info(struct vdec_h264_inst *inst,
struct vdec_pic_info *pic)
{
*pic = inst->vsi->pic;
aml_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
aml_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
}
static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr)
{
cr->left = inst->vsi->crop.left;
cr->top = inst->vsi->crop.top;
cr->width = inst->vsi->crop.width;
cr->height = inst->vsi->crop.height;
aml_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d",
cr->left, cr->top, cr->width, cr->height);
}
static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz)
{
*dpb_sz = inst->vsi->dec.dpb_sz;
aml_vcodec_debug(inst, "sz=%d", *dpb_sz);
}
static int find_start_code(unsigned char *data, unsigned int data_sz)
{
if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1)
return 3;
if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 &&
data[3] == 1)
return 4;
return -1;
}
static int vdec_h264_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec)
{
struct vdec_h264_inst *inst = NULL;
int err = -1;
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
if (!inst)
return -ENOMEM;
inst->ctx = ctx;
inst->vdec.id = VFORMAT_H264;
inst->vdec.dev = ctx->dev->vpu_plat_dev;
inst->vdec.filp = ctx->dev->filp;
inst->vdec.ctx = ctx;
inst->vfm.ctx = ctx;
vcodec_vfm_init(&inst->vfm);
//inst->vpu.handler = vpu_dec_ipi_handler;
err = video_decoder_init(&inst->vdec);
if (err) {
aml_vcodec_err(inst, "vdec_h264 init err=%d", err);
//goto error_free_inst;
}
//inst->vsi = (struct vdec_h264_vsi *)inst->vpu.vsi;
//probe info from the decoder hw debug_tmp
inst->vsi = kzalloc(sizeof(struct vdec_h264_vsi), GFP_KERNEL);
//debug_tmp
inst->vsi->pic.pic_w = 1920;
inst->vsi->pic.pic_h = 1088;
inst->vsi->pic.buf_w = 1920;
inst->vsi->pic.buf_h = 1088;
inst->vsi->pic.y_bs_sz = 0;
inst->vsi->pic.y_len_sz = (1920 * 1088);
inst->vsi->pic.c_bs_sz = 0;
inst->vsi->pic.c_len_sz = (1920 * 1088 / 2);
//err = allocate_predication_buf(inst);
//if (err)
//goto error_deinit;
aml_vcodec_debug(inst, "H264 Instance >> %p", inst);
*h_vdec = (unsigned long)inst;
dump_init();
return 0;
//error_deinit:
//vpu_dec_deinit(&inst->vpu);
//error_free_inst:
kfree(inst->vsi);
kfree(inst);
return err;
}
static int refer_buffer_num(int level_idc, int poc_cnt,
int mb_width, int mb_height)
{
int max_ref_num = 27;
int size, size_margin = 7;
int pic_size = mb_width * mb_height * 384;
switch (level_idc) {
case 9:
size = 152064;
break;
case 10:
size = 152064;
break;
case 11:
size = 345600;
break;
case 12:
size = 912384;
break;
case 13:
size = 912384;
break;
case 20:
size = 912384;
break;
case 21:
size = 1824768;
break;
case 22:
size = 3110400;
break;
case 30:
size = 3110400;
break;
case 31:
size = 6912000;
break;
case 32:
size = 7864320;
break;
case 40:
size = 12582912;
break;
case 41:
size = 12582912;
break;
case 42:
size = 13369344;
break;
case 50:
size = 42393600;
break;
case 51:
case 52:
default:
size = 70778880;
break;
}
size /= pic_size;
size = size + size_margin; /* need more buffers */
if (poc_cnt > size)
size = poc_cnt;
if (size > max_ref_num)
size = max_ref_num;
return size;
}
static void fill_vdec_params(struct h264_SPS_t *sps, struct vdec_h264_vsi *vsi)
{
struct vdec_pic_info *pic = &vsi->pic;
struct vdec_h264_dec_info *dec = &vsi->dec;
struct v4l2_rect *rect = &vsi->crop;
unsigned int mb_w, mb_h, width, height;
unsigned int crop_unit_x = 0, crop_unit_y = 0;
unsigned int poc_cnt = 0;
mb_w = sps->pic_width_in_mbs_minus1 + 1;
mb_h = sps->pic_height_in_map_units_minus1 + 1;
width = mb_w << 4; // 16
height = (2 - sps->frame_mbs_only_flag) * (mb_h << 4);
if (sps->frame_cropping_flag) {
if (0 == sps->chroma_format_idc) {// monochrome
crop_unit_x = 1;
crop_unit_y = 2 - sps->frame_mbs_only_flag;
} else if (1 == sps->chroma_format_idc) {// 4:2:0
crop_unit_x = 2;
crop_unit_y = 2 * (2 - sps->frame_mbs_only_flag);
} else if (2 == sps->chroma_format_idc) {// 4:2:2
crop_unit_x = 2;
crop_unit_y = 2 - sps->frame_mbs_only_flag;
} else {// 3 == sps.chroma_format_idc // 4:4:4
crop_unit_x = 1;
crop_unit_y = 2 - sps->frame_mbs_only_flag;
}
}
width -= crop_unit_x * (sps->frame_crop_left_offset +
sps->frame_crop_right_offset);
height -= crop_unit_y * (sps->frame_crop_top_offset +
sps->frame_crop_bottom_offset);
/* fill image size that be used for EGL. */
pic->pic_w = width;
pic->pic_h = height;
/* calc visible ares. */
rect->left = 0;
rect->top = 0;
rect->width = pic->pic_w;
rect->height = pic->pic_h;
/* config canvas size that be used for decoder. */
pic->buf_w = ALIGN(mb_w, 4) << 4;
pic->buf_h = ALIGN(mb_h, 4) << 4;
pic->y_len_sz = pic->buf_w * pic->buf_h;
pic->c_len_sz = pic->y_len_sz >> 1;
/* calc DPB size */
poc_cnt = sps->pic_order_cnt_type;
if (!poc_cnt)
poc_cnt = (sps->log2_max_pic_order_cnt_lsb_minus4 + 4) << 1;
dec->dpb_sz = refer_buffer_num(sps->level_idc, poc_cnt, mb_w, mb_h);
pr_info("the stream infos, width: %d, height: %d, dpb: %d\n",
pic->pic_w, pic->pic_h, dec->dpb_sz);
}
static int vdec_h264_probe(unsigned long h_vdec,
struct aml_vcodec_mem *bs, void *out)
{
struct vdec_h264_inst *inst =
(struct vdec_h264_inst *)h_vdec;
struct h264_stream_t s;
struct h264_SPS_t *sps;
unsigned int nal_type, nal_idx;
int real_data_pos, real_data_size;
unsigned char *buf = (unsigned char *)bs->va;
unsigned int size = bs->size;
nal_idx = find_start_code(buf, size);
if (nal_idx < 0)
return -1;
nal_type = NAL_TYPE(buf[nal_idx]);
if (nal_type != NAL_H264_SPS)
return -1;
/* start code plus nal type. */
real_data_pos = nal_idx + 1;
real_data_size = size - real_data_pos;
sps = kzalloc(sizeof(struct h264_SPS_t), GFP_KERNEL);
if (IS_ERR_OR_NULL(sps))
return -ENOMEM;
h264_stream_set(&s, &buf[real_data_pos], real_data_size);
h264_sps_parse(&s, sps);
//h264_sps_info(sps);
fill_vdec_params(sps, inst->vsi);
kfree(sps);
return 0;
}
static void vdec_h264_deinit(unsigned long h_vdec)
{
struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
mutex_lock(&mutex);
aml_vcodec_debug_enter(inst);
video_decoder_release(&inst->vdec);
vcodec_vfm_release(&inst->vfm);
dump_deinit();
kfree(inst->vsi);
kfree(inst);
inst = NULL;
mutex_unlock(&mutex);
}
static int vdec_h264_get_fb(struct vdec_h264_inst *inst, struct vdec_fb **out)
{
return get_fb_from_queue(inst->ctx, out);
}
static void vdec_h264_get_vf(struct vdec_h264_inst *inst, struct vdec_fb **out)
{
struct vframe_s *vf = NULL;
struct vdec_fb *fb = NULL;
aml_vcodec_debug(inst, "%s() [%d], vfm: %p\n",
__FUNCTION__, __LINE__, &inst->vfm);
vf = peek_video_frame(&inst->vfm);
if (!vf) {
aml_vcodec_debug(inst, "there is no vframe.\n");
*out = NULL;
return;
}
vf = get_video_frame(&inst->vfm);
if (!vf) {
aml_vcodec_debug(inst, "the vframe is avalid.\n");
*out = NULL;
return;
}
atomic_set(&vf->use_cnt, 1);
aml_vcodec_debug(inst, "%s() [%d], vf: %p, v4l_mem_handle: %lx\n",
__FUNCTION__, __LINE__, vf, vf->v4l_mem_handle);
fb = (struct vdec_fb *)vf->v4l_mem_handle;
fb->vf_handle = (unsigned long)vf;
fb->status = FB_ST_DISPLAY;
*out = fb;
//dump_write(fb->base_y.va, fb->base_y.bytes_used);
//dump_write(fb->base_c.va, fb->base_c.bytes_used);
aml_vcodec_debug(inst, "%s() [%d], va: %p, phy: %x, size: %lu\n",
__FUNCTION__, __LINE__, fb->base_y.va,
(unsigned int)virt_to_phys(fb->base_y.va), fb->base_y.size);
aml_vcodec_debug(inst, "%s() [%d], va: %p, phy: %x, size: %lu\n",
__FUNCTION__, __LINE__, fb->base_c.va,
(unsigned int)virt_to_phys(fb->base_c.va), fb->base_c.size);
}
static int vdec_h264_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs,
unsigned long int timestamp, bool *res_chg)
{
struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
struct aml_vdec_adapt *vdec = &inst->vdec;
int nal_start_idx = 0;
int err = 0;
unsigned int nal_start;
unsigned int nal_type;
unsigned char *buf;
unsigned int buf_sz;
int ret = 0;
/* bs NULL means flush decoder */
if (bs == NULL)
return 0;//vpu_dec_reset(vpu);
buf = (unsigned char *)bs->va;
buf_sz = bs->size;
nal_start_idx = find_start_code(buf, buf_sz);
if (nal_start_idx < 0)
goto err_free_fb_out;
nal_start = buf[nal_start_idx];
nal_type = NAL_TYPE(buf[nal_start_idx]);
aml_v4l2_debug(1, "NALU type: %d, size: %u\n", nal_type, buf_sz);
if (nal_type == NAL_H264_SPS) {
if (buf_sz > HDR_PARSING_BUF_SZ) {
err = -EILSEQ;
goto err_free_fb_out;
}
inst->vsi->sps_size = buf_sz;
memcpy(inst->vsi->hdr_buf + inst->vsi->head_offset, buf, buf_sz);
inst->vsi->head_offset += inst->vsi->sps_size;
} else if (nal_type == NAL_H264_PPS) {
//buf_sz -= nal_start_idx;
if (buf_sz > HDR_PARSING_BUF_SZ) {
err = -EILSEQ;
goto err_free_fb_out;
}
inst->vsi->pps_size = buf_sz;
memcpy(inst->vsi->hdr_buf + inst->vsi->head_offset, buf, buf_sz);
inst->vsi->head_offset += inst->vsi->pps_size;
} else if (nal_type == NAL_H264_SEI) {
if (buf_sz > HDR_PARSING_BUF_SZ) {
err = -EILSEQ;
goto err_free_fb_out;
}
inst->vsi->sei_size = buf_sz;
memcpy(inst->vsi->hdr_buf + inst->vsi->head_offset, buf, buf_sz);
inst->vsi->head_offset += inst->vsi->sei_size;
} else {
char *write_buf = vmalloc(inst->vsi->head_offset + buf_sz);
memcpy(write_buf, inst->vsi->hdr_buf, inst->vsi->head_offset);
memcpy(write_buf + inst->vsi->head_offset, buf, buf_sz);
ret = vdec_vframe_write(vdec->filp, write_buf,
inst->vsi->head_offset + buf_sz, timestamp);
aml_vcodec_debug(inst,
"%s() [%d], buf: %p, buf size: %u, write to: %d\n",
__FUNCTION__, __LINE__, write_buf,
inst->vsi->head_offset + buf_sz, ret);
inst->vsi->head_offset = 0;
inst->vsi->sps_size = 0;
inst->vsi->pps_size = 0;
inst->vsi->sei_size = 0;
vfree(write_buf);
}
//err = vpu_dec_start(vpu, data, 2);
if (err)
goto err_free_fb_out;
#if 0
*res_chg = inst->vsi->dec.resolution_changed;
if (*res_chg) {
struct vdec_pic_info pic;
aml_vcodec_debug(inst, "- resolution changed -");
get_pic_info(inst, &pic);
if (inst->vsi->dec.realloc_mv_buf) {
err = alloc_mv_buf(inst, &pic);
if (err)
goto err_free_fb_out;
}
}
#endif
if (nal_type == NAL_NON_IDR_SLICE || nal_type == NAL_IDR_SLICE) {
/* wait decoder done interrupt */
//err = aml_vcodec_wait_for_done_ctx(inst->ctx, aml_INST_IRQ_RECEIVED, WAIT_INTR_TIMEOUT_MS);
if (err)
goto err_free_fb_out;
//vpu_dec_end(vpu);
}
aml_vcodec_debug(inst, "\n - NALU[%d] type=%d -\n", inst->num_nalu,
nal_type);
return ret;
err_free_fb_out:
//put_fb_to_free(inst, fb);
aml_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err);
return err;
}
static int vdec_h264_get_param(unsigned long h_vdec,
enum vdec_get_param_type type, void *out)
{
int ret = 0;
struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
mutex_lock(&mutex);
if (!inst) {
pr_err("the h264 inst of dec is void.\n");
mutex_unlock(&mutex);
return -1;
}
switch (type) {
case GET_PARAM_DISP_FRAME_BUFFER:
//vdec_h264_get_fb(inst, &inst->vsi->list_disp, true, out);
vdec_h264_get_vf(inst, out);
break;
case GET_PARAM_FREE_FRAME_BUFFER:
ret = vdec_h264_get_fb(inst, out);
break;
case GET_PARAM_PIC_INFO:
get_pic_info(inst, out);
break;
case GET_PARAM_DPB_SIZE:
get_dpb_size(inst, out);
break;
case GET_PARAM_CROP_INFO:
get_crop_info(inst, out);
break;
default:
aml_vcodec_err(inst, "invalid get parameter type=%d", type);
return -EINVAL;
}
mutex_unlock(&mutex);
return ret;
}
static struct vdec_common_if vdec_h264_if = {
vdec_h264_init,
vdec_h264_probe,
vdec_h264_decode,
vdec_h264_get_param,
vdec_h264_deinit,
};
struct vdec_common_if *get_h264_dec_comm_if(void);
struct vdec_common_if *get_h264_dec_comm_if(void)
{
return &vdec_h264_if;
}

View File

@@ -0,0 +1,23 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := vcode_m2m
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := vcodec_m2m_test.c
LOCAL_ARM_MODE := arm
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
$(ANDROID_BUILD_TOP)/vendor/amlogic/external/ffmpeg
LOCAL_SHARED_LIBRARIES := \
libamffmpeg
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_PREBUILT_LIBS:= \
# libavcodec:ffmpeg/lib/libavcodec.so \
include $(BUILD_MULTI_PREBUILT)

View File

@@ -0,0 +1,273 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#define INBUF_SIZE (4096)
#define DUMP_DIR "/mnt/video_frames"
typedef struct VcodecCtx {
AVFormatContext *fmt_ctx;
AVStream *stream;
int nb_streams;
int vst_idx;
char *filename;
pthread_t tid;
pthread_mutex_t pthread_mutex;
pthread_cond_t pthread_cond;
} VcodecCtx;
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
char *filename)
{
FILE *f;
int i;
printf("wrap: %d, xsize: %d, ysize: %d, filename: %s\n", wrap, xsize, ysize, filename);
f = fopen(filename,"w+");
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
fclose(f);
}
static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt,
const char *filename)
{
char buf[1024];
int ret;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
return;
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding, ret: %s\n", av_err2str(ret));
break;
}
//fprintf(stderr, "saving frame %3d\n", dec_ctx->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to free it */
snprintf(buf, sizeof(buf), "%s/frame-%d", filename, dec_ctx->frame_number);
pgm_save(frame->data[0], frame->linesize[0],
frame->width, frame->height, buf);
}
}
static void* read_thread(void *arg)
{
int ret, err;
AVFormatContext *ic = NULL;
AVCodecContext *dec_ctx = NULL;
AVStream *stream = NULL;
AVCodec *codec = NULL;
AVPacket pkt1, *pkt = &pkt1;
AVFrame *frame = NULL;
int vst_idx = 0;
int has_video = 0;
unsigned int st_idx = 0;
VcodecCtx *vctx = arg;
printf("entry read thread, tid: %ld.\n", vctx->tid);
ic = avformat_alloc_context();
if (!ic) {
fprintf(stderr, "Could not allocate avformat context.\n");
return NULL;
}
err = avformat_open_input(&ic, vctx->filename, NULL, NULL);
if (err < 0) {
fprintf(stderr, "Could not open avformat input.\n");
return NULL;
}
err = avformat_find_stream_info(ic, NULL);
if (err < 0) {
fprintf(stderr, "find stream info err.\n");
return NULL;
}
for (st_idx = 0; st_idx < ic->nb_streams; st_idx++) {
AVStream *st = ic->streams[st_idx];
enum AVMediaType type = st->codecpar->codec_type;
st->discard = AVDISCARD_ALL;
if (type == AVMEDIA_TYPE_VIDEO) {
st->discard = AVDISCARD_NONE;
vctx->vst_idx = st_idx;
has_video = 1;
break;
}
}
if (!has_video) {
fprintf(stderr, "no video stream.\n");
return NULL;
}
stream = ic->streams[vctx->vst_idx];
//codec = avcodec_find_decoder(stream->codecpar->codec_id);
codec = avcodec_find_decoder_by_name("h264_v4l2m2m");
if (!codec) {
fprintf(stderr, "Unsupported codec with id %d for input stream %d\n",
stream->codecpar->codec_id, stream->index);
return NULL;
}
dec_ctx = avcodec_alloc_context3(codec);
if (!dec_ctx) {
fprintf(stderr, "Could not allocate video codec context\n");
return NULL;
}
err = avcodec_parameters_to_context(dec_ctx, stream->codecpar);
if (err < 0) {
fprintf(stderr, "Could not set paras to context\n");
return NULL;
}
av_codec_set_pkt_timebase(dec_ctx, stream->time_base);
dec_ctx->framerate = stream->avg_frame_rate;
if (avcodec_open2(dec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec for input stream %d\n",
stream->index);
return NULL;
}
printf("fmt ctx: %p, stream: %p, video st idx: %d, num: %d\n",
ic, stream, vst_idx, ic->nb_streams);
printf("format: %s\n",ic->iformat->name);
ic->flags |= AVFMT_FLAG_GENPTS;
ic->debug = 0xff;
//if (ic->pb)
// ic->pb->eof_reached = 0;
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
return NULL;
}
for (;;) {
ret = av_read_frame(ic, pkt);
if (ret < 0) {
if (ret == AVERROR_EOF || avio_feof(ic->pb)) {
printf("read data end, ret: %d.\n", ret);
break;
}
if (ic->pb && ic->pb->error)
break;
printf("read data fail, ret: %d.\n", ret);
continue;
}
if (pkt->stream_index == vctx->vst_idx) {
//packet_queue_put(&is->audioq, pkt);
printf("read video data size: %d.\n", pkt->size);
if (pkt->size)
decode(dec_ctx, frame, pkt, DUMP_DIR);
} else
av_packet_unref(pkt);
}
/* flush the decoder */
decode(dec_ctx, frame, NULL, DUMP_DIR);
avcodec_free_context(&dec_ctx);
av_frame_free(&frame);
if (ic)
avformat_close_input(&ic);
printf("read thread exit.\n");
pthread_mutex_lock(&vctx->pthread_mutex);
pthread_cond_signal(&vctx->pthread_cond);
pthread_mutex_unlock(&vctx->pthread_mutex);
return NULL;
}
static int open_input_file(const char *filename)
{
int ret;
VcodecCtx *vctx;
pthread_t pid = pthread_self();
vctx = av_mallocz(sizeof(VcodecCtx));
if (!vctx)
return -1;
vctx->filename = av_strdup(filename);
if (!vctx->filename)
return -1;
pthread_mutex_init(&vctx->pthread_mutex, NULL);
pthread_cond_init(&vctx->pthread_cond, NULL);
ret = pthread_create(&vctx->tid, NULL, read_thread, (void *)vctx);
if (ret == 0) {
pthread_setname_np(pid, "read_thread");
pthread_mutex_lock(&vctx->pthread_mutex);
pthread_cond_wait(&vctx->pthread_cond, &vctx->pthread_mutex);
pthread_mutex_unlock(&vctx->pthread_mutex);
}
printf("creat the read thread, ret: %d.\n", ret);
return 0;
}
int main(int argc, char **argv)
{
int ret;
const char *filename, *outfilename;
if (argc < 2) {
fprintf(stderr, "Usage: %s <input file>\n ==> %s/frame-123\n", argv[0], DUMP_DIR);
exit(0);
}
filename = argv[1];
outfilename = argv[2];
mkdir(DUMP_DIR, 0664);
/*set debug level*/
//av_log_set_level(AV_LOG_DEBUG);
av_register_all();
ret = open_input_file(filename);
if (ret < 0) {
fprintf(stderr, "open input file fail.\n");
goto out;
}
out:
return ret < 0;
}

View File

@@ -0,0 +1,45 @@
#ifndef _VDEC_DRV_BASE_
#define _VDEC_DRV_BASE_
#include "aml_vcodec_drv.h"
#include "vdec_drv_if.h"
struct vdec_common_if {
/**
* (*init)() - initialize decode driver
* @ctx : [in] aml v4l2 context
* @h_vdec : [out] driver handle
*/
int (*init)(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec);
int (*probe)(unsigned long h_vdec,
struct aml_vcodec_mem *bs, void *out);
/**
* (*decode)() - trigger decode
* @h_vdec : [in] driver handle
* @bs : [in] input bitstream
* @fb : [in] frame buffer to store decoded frame
* @res_chg : [out] resolution change happen
*/
int (*decode)(unsigned long h_vdec, struct aml_vcodec_mem *bs,
unsigned long int pts, bool *res_chg);
/**
* (*get_param)() - get driver's parameter
* @h_vdec : [in] driver handle
* @type : [in] input parameter type
* @out : [out] buffer to store query result
*/
int (*get_param)(unsigned long h_vdec,
enum vdec_get_param_type type, void *out);
/**
* (*deinit)() - deinitialize driver.
* @h_vdec : [in] driver handle to be deinit
*/
void (*deinit)(unsigned long h_vdec);
};
#endif

View File

@@ -0,0 +1,119 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "vdec_drv_if.h"
#include "aml_vcodec_dec.h"
#include "vdec_drv_base.h"
#include "aml_vcodec_dec_pm.h"
//#include "aml_vpu.h"
const struct vdec_common_if *get_h264_dec_comm_if(void);
const struct vdec_common_if *get_vp8_dec_comm_if(void);
const struct vdec_common_if *get_vp9_dec_comm_if(void);
int vdec_if_init(struct aml_vcodec_ctx *ctx, unsigned int fourcc)
{
int ret = 0;
switch (fourcc) {
case V4L2_PIX_FMT_H264:
ctx->dec_if = get_h264_dec_comm_if();
break;
/*case V4L2_PIX_FMT_VP8:
ctx->dec_if = get_vp8_dec_comm_if();
break;
case V4L2_PIX_FMT_VP9:
ctx->dec_if = get_vp9_dec_comm_if();
break;*/
default:
return -EINVAL;
}
aml_vdec_lock(ctx);
//aml_vcodec_dec_clock_on(&ctx->dev->pm);//debug_tmp
ret = ctx->dec_if->init(ctx, &ctx->drv_handle);
//aml_vcodec_dec_clock_off(&ctx->dev->pm);
aml_vdec_unlock(ctx);
return ret;
}
int vdec_if_probe(struct aml_vcodec_ctx *ctx,
struct aml_vcodec_mem *bs, void *out)
{
int ret = 0;
aml_vdec_lock(ctx);
ret = ctx->dec_if->probe(ctx->drv_handle, bs, out);
aml_vdec_unlock(ctx);
return ret;
}
int vdec_if_decode(struct aml_vcodec_ctx *ctx, struct aml_vcodec_mem *bs,
unsigned long int timestamp, bool *res_chg)
{
int ret = 0;
if (bs) {
if ((bs->dma_addr & 63) != 0) {
aml_v4l2_err("bs dma_addr should 64 byte align");
return -EINVAL;
}
}
/*if (fb) {
if (((fb->base_y.dma_addr & 511) != 0) ||
((fb->base_c.dma_addr & 511) != 0)) {
aml_v4l2_err("frame buffer dma_addr should 512 byte align");
return -EINVAL;
}
}*/
if (ctx->drv_handle == 0)
return -EIO;
aml_vdec_lock(ctx);
aml_vcodec_set_curr_ctx(ctx->dev, ctx);
//aml_vcodec_dec_clock_on(&ctx->dev->pm);//debug_tmp
enable_irq(ctx->dev->dec_irq);
ret = ctx->dec_if->decode(ctx->drv_handle, bs, timestamp, res_chg);
//disable_irq(ctx->dev->dec_irq);
//aml_vcodec_dec_clock_off(&ctx->dev->pm);
aml_vcodec_set_curr_ctx(ctx->dev, NULL);
aml_vdec_unlock(ctx);
return ret;
}
int vdec_if_get_param(struct aml_vcodec_ctx *ctx,
enum vdec_get_param_type type, void *out)
{
int ret = 0;
if (ctx->drv_handle == 0)
return -EIO;
aml_vdec_lock(ctx);
ret = ctx->dec_if->get_param(ctx->drv_handle, type, out);
aml_vdec_unlock(ctx);
return ret;
}
void vdec_if_deinit(struct aml_vcodec_ctx *ctx)
{
if (ctx->drv_handle == 0)
return;
aml_vdec_lock(ctx);
//aml_vcodec_dec_clock_on(&ctx->dev->pm);
ctx->dec_if->deinit(ctx->drv_handle);
//aml_vcodec_dec_clock_off(&ctx->dev->pm);
aml_vdec_unlock(ctx);
ctx->drv_handle = 0;
}

View File

@@ -0,0 +1,91 @@
#ifndef _VDEC_DRV_IF_H_
#define _VDEC_DRV_IF_H_
#include "aml_vcodec_drv.h"
#include "aml_vcodec_dec.h"
#include "aml_vcodec_util.h"
/**
* struct vdec_fb_status - decoder frame buffer status
* @FB_ST_NORMAL : initial state
* @FB_ST_DISPLAY : frmae buffer is ready to be displayed
* @FB_ST_FREE : frame buffer is not used by decoder any more
*/
enum vdec_fb_status {
FB_ST_NORMAL = 0,
FB_ST_DISPLAY = (1 << 0),
FB_ST_FREE = (1 << 1)
};
/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
* the caller does not own the returned buffer. The buffer will not be
* released before vdec_if_deinit.
* GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer,
* struct vdec_fb**
* GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb**
* GET_PARAM_PIC_INFO : get picture info, struct vdec_pic_info*
* GET_PARAM_CROP_INFO : get crop info, struct v4l2_crop*
* GET_PARAM_DPB_SIZE : get dpb size, unsigned int*
*/
enum vdec_get_param_type {
GET_PARAM_DISP_FRAME_BUFFER,
GET_PARAM_FREE_FRAME_BUFFER,
GET_PARAM_PIC_INFO,
GET_PARAM_CROP_INFO,
GET_PARAM_DPB_SIZE
};
/**
* struct vdec_fb_node - decoder frame buffer node
* @list : list to hold this node
* @fb : point to frame buffer (vdec_fb), fb could point to frame buffer and
* working buffer this is for maintain buffers in different state
*/
struct vdec_fb_node {
struct list_head list;
struct vdec_fb *fb;
};
/**
* vdec_if_init() - initialize decode driver
* @ctx : [in] v4l2 context
* @fourcc : [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9..
*/
int vdec_if_init(struct aml_vcodec_ctx *ctx, unsigned int fourcc);
int vdec_if_probe(struct aml_vcodec_ctx *ctx,
struct aml_vcodec_mem *bs, void *out);
/**
* vdec_if_deinit() - deinitialize decode driver
* @ctx : [in] v4l2 context
*
*/
void vdec_if_deinit(struct aml_vcodec_ctx *ctx);
/**
* vdec_if_decode() - trigger decode
* @ctx : [in] v4l2 context
* @bs : [in] input bitstream
* @fb : [in] frame buffer to store decoded frame, when null menas parse
* header only
* @res_chg : [out] resolution change happens if current bs have different
* picture width/height
* Note: To flush the decoder when reaching EOF, set input bitstream as NULL.
*
* Return: 0 on success. -EIO on unrecoverable error.
*/
int vdec_if_decode(struct aml_vcodec_ctx *ctx, struct aml_vcodec_mem *bs,
unsigned long int timestamp, bool *res_chg);
/**
* vdec_if_get_param() - get driver's parameter
* @ctx : [in] v4l2 context
* @type : [in] input parameter type
* @out : [out] buffer to store query result
*/
int vdec_if_get_param(struct aml_vcodec_ctx *ctx, enum vdec_get_param_type type,
void *out);
#endif

View File

@@ -1657,6 +1657,7 @@ static void insert_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb,
fs->pts = p->pts;
fs->pts64 = p->pts64;
fs->timestamp = p->timestamp;
}
void reset_frame_store(struct h264_dpb_stru *p_H264_Dpb,

View File

@@ -19,6 +19,7 @@
#define RRINT_FLAG_RPM 0x0400
#define DEBUG_DISABLE_RUNREADY_RMBUF 0x0800
#define PRINT_FLAG_DUMP_BUFSPEC 0x1000
#define PRINT_FLAG_V4L_DETAIL 0x8000
#define DISABLE_ERROR_HANDLE 0x10000
#define DEBUG_DUMP_STAT 0x80000
@@ -646,6 +647,7 @@ struct StorablePicture {
u32 pts;
u64 pts64;
u64 timestamp;
unsigned char data_flag;
};
@@ -709,6 +711,7 @@ struct FrameStore {
u32 pts;
u64 pts64;
u64 timestamp;
};

View File

@@ -57,6 +57,7 @@
#include <linux/amlogic/tee.h>
#include <linux/uaccess.h>
#include "../utils/config_parser.h"
#include "../../../amvdec_ports/vdec_drv_base.h"
#undef pr_info
#define pr_info printk
@@ -765,6 +766,8 @@ struct vdec_h264_hw_s {
struct mh264_ud_record_wait_node_t free_nodes[MAX_FREE_USERDATA_NODES];
int wait_for_udr_send;
#endif
bool is_used_v4l;
void *v4l2_ctx;
};
static u32 again_threshold = 0x40;
@@ -812,7 +815,6 @@ static void h264_clear_dpb(struct vdec_h264_hw_s *hw);
#define MAX_FRAME_4K_NUM 0x1200
#define FRAME_MMU_MAP_SIZE (MAX_FRAME_4K_NUM * 4)
/* 0:linear 1:32x32 2:64x32 ; m8baby test1902 */
static u32 mem_map_mode = H265_MEM_MAP_MODE;
@@ -1551,23 +1553,113 @@ static int alloc_one_buf_spec(struct vdec_h264_hw_s *hw, int i)
return 0;
}
static int v4l_get_fb(struct aml_vcodec_ctx *ctx, struct vdec_fb **out)
{
int ret = 0;
ret = ctx->dec_if->get_param(ctx->drv_handle,
GET_PARAM_FREE_FRAME_BUFFER, out);
if (ret)
pr_err("get frame buffer failed.\n");
return ret;
}
static int alloc_one_buf_spec_from_queue(struct vdec_h264_hw_s *hw, int idx)
{
int ret = 0;
struct buffer_spec_s *bs = &hw->buffer_spec[idx];
struct canvas_config_s *y_canvas_cfg = NULL;
struct canvas_config_s *c_canvas_cfg = NULL;
struct vdec_fb *fb = NULL;
unsigned int y_addr, c_addr;
int buf_size = (hw->mb_total << 8) + (hw->mb_total << 7);
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], buf size: %d\n", __FUNCTION__, __LINE__, buf_size);
if (IS_ERR_OR_NULL(hw->v4l2_ctx)) {
pr_err("the v4l context has err.\n");
return -1;
}
if (bs->cma_alloc_addr)
return 0;
ret = v4l_get_fb(hw->v4l2_ctx, &fb);
if (ret) {
pr_err("get fb fail.\n");
return ret;
}
bs->cma_alloc_addr = (unsigned long)fb;
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], cma alloc addr: 0x%x\n",
__FUNCTION__, __LINE__, bs->cma_alloc_addr);
y_addr = virt_to_phys(fb->base_y.va);
c_addr = virt_to_phys(fb->base_c.va);
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], y_addr: %x, va: %p\n",
__FUNCTION__, __LINE__, y_addr, fb->base_y.va);
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], c_addr: %x, va: %p\n",
__FUNCTION__, __LINE__, c_addr, fb->base_c.va);
bs->y_addr = y_addr;
bs->u_addr = c_addr;
bs->v_addr = c_addr;
y_canvas_cfg = &bs->canvas_config[0];
c_canvas_cfg = &bs->canvas_config[1];
y_canvas_cfg->phy_addr = y_addr;
y_canvas_cfg->width = hw->mb_width << 4;
y_canvas_cfg->height = hw->mb_height << 4;
y_canvas_cfg->block_mode = CANVAS_BLKMODE_LINEAR;
fb->base_y.bytes_used = y_canvas_cfg->width * y_canvas_cfg->height;
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], y_w: %d, y_h: %d\n", __FUNCTION__, __LINE__,
y_canvas_cfg->width,y_canvas_cfg->height);
c_canvas_cfg->phy_addr = c_addr;
c_canvas_cfg->width = hw->mb_width << 4;
c_canvas_cfg->height = hw->mb_height << 3;
c_canvas_cfg->block_mode = CANVAS_BLKMODE_LINEAR;
fb->base_c.bytes_used = c_canvas_cfg->width * c_canvas_cfg->height;
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], c_w: %d, c_h: %d\n", __FUNCTION__, __LINE__,
c_canvas_cfg->width, c_canvas_cfg->height);
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s, alloc buf for bufspec%d\n", __FUNCTION__, idx);
return ret;
}
static void config_decode_canvas(struct vdec_h264_hw_s *hw, int i)
{
canvas_config(hw->buffer_spec[i].
canvas_config_ex(hw->buffer_spec[i].
y_canvas_index,
hw->buffer_spec[i].y_addr,
hw->mb_width << 4,
hw->mb_height << 4,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_32X32);
hw->is_used_v4l ? CANVAS_BLKMODE_LINEAR :
CANVAS_BLKMODE_32X32,
hw->is_used_v4l ? 7 : 0);
canvas_config(hw->buffer_spec[i].
canvas_config_ex(hw->buffer_spec[i].
u_canvas_index,
hw->buffer_spec[i].u_addr,
hw->mb_width << 4,
hw->mb_height << 3,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_32X32);
hw->is_used_v4l ? CANVAS_BLKMODE_LINEAR :
CANVAS_BLKMODE_32X32,
hw->is_used_v4l ? 7 : 0);
WRITE_VREG(ANC0_CANVAS_ADDR + hw->buffer_spec[i].canvas_pos,
spec2canvas(&hw->buffer_spec[i]));
}
@@ -1773,9 +1865,11 @@ static void dealloc_buf_specs(struct vdec_h264_hw_s *hw,
if (!hw->mmu_enable) {
if (hw->buffer_spec[i].cma_alloc_addr) {
decoder_bmmu_box_free_idx(
hw->bmmu_box,
i);
if (!hw->is_used_v4l) {
decoder_bmmu_box_free_idx(
hw->bmmu_box,
i);
}
spin_lock_irqsave
(&hw->bufspec_lock, flags);
hw->buffer_spec[i].cma_alloc_addr = 0;
@@ -1837,7 +1931,10 @@ unsigned char have_free_buf_spec(struct vdec_s *vdec)
dealloc_buf_specs(hw, 0);
if (max_alloc_buf_count == 0 ||
allocated_count < max_alloc_buf_count) {
if (alloc_one_buf_spec(hw, index) >= 0)
if (hw->is_used_v4l) {
if (alloc_one_buf_spec_from_queue(hw, index) >= 0)
ret = 1;
} else if (alloc_one_buf_spec(hw, index) >= 0)
ret = 1;
}
mutex_unlock(&vmh264_mutex);
@@ -1995,7 +2092,17 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
vf->duration_pulldown = 0;
vf->pts = frame->pts;
vf->pts_us64 = frame->pts64;
vf->timestamp = frame->timestamp;
vf->index = VF_INDEX(frame->index, buffer_index);
if (hw->is_used_v4l) {
vf->v4l_mem_handle
= hw->buffer_spec[buffer_index].cma_alloc_addr;
dpb_print(DECODE_ID(hw), PRINT_FLAG_V4L_DETAIL,
"%s() [%d], v4l mem handle: 0x%x\n",
__FUNCTION__, __LINE__, vf->v4l_mem_handle);
}
if (hw->mmu_enable) {
if (hw->double_write_mode & 0x10) {
/* double write only */
@@ -2040,6 +2147,7 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
VIDTYPE_COMPRESS | VIDTYPE_VIU_FIELD;
vf->canvas0Addr = vf->canvas1Addr = 0;
}
vf->bitdepth =
BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
@@ -2106,6 +2214,38 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame)
return 0;
}
int notify_v4l_eos(struct vdec_s *vdec)
{
struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
struct vframe_s *vf = NULL;
struct vdec_fb *fb = NULL;
if (hw->is_used_v4l && hw->eos) {
if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) {
dpb_print(DECODE_ID(hw), PRINT_FLAG_ERROR,
"%s fatal error, no available buffer slot.\n",
__func__);
return -1;
}
if (v4l_get_fb(hw->v4l2_ctx, &fb)) {
pr_err("get fb fail.\n");
return -1;
}
vf->timestamp = ULONG_MAX;
vf->v4l_mem_handle = (unsigned long)fb;
vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L;
kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
pr_info("264 EOS notify \n");
vf_notify_receiver(vdec->vf_provider_name,
VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL);
}
return 0;
}
/******************
* Hardware config
*/
@@ -3070,6 +3210,7 @@ static void vh264_vf_put(struct vframe_s *vf, void *op_arg)
struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private;
int buf_spec_num;
int frame_index;
if (vf == (&hw->vframe_dummy))
return;
if (vf->index == -1) {
@@ -3477,10 +3618,17 @@ static int vh264_set_params(struct vdec_h264_hw_s *hw,
if (!hw->mmu_enable) {
config_buf_specs(vdec);
i = get_buf_spec_by_canvas_pos(hw, 0);
if (alloc_one_buf_spec(hw, i) >= 0)
config_decode_canvas(hw, i);
else
ret = -1;
if (hw->is_used_v4l) {
ret = alloc_one_buf_spec_from_queue(hw, i);
if (!ret)
config_decode_canvas(hw, i);
} else {
if (alloc_one_buf_spec(hw, i) >= 0)
config_decode_canvas(hw, i);
else
ret = -1;
}
} else {
if (hw->double_write_mode) {
config_buf_specs_ex(vdec);
@@ -3548,11 +3696,22 @@ static int vh264_set_params(struct vdec_h264_hw_s *hw,
if (!hw->mmu_enable) {
mutex_lock(&vmh264_mutex);
if (ret >= 0 && hw->decode_pic_count == 0) {
int buf_cnt;
/* h264_reconfig: alloc later*/
for (j = 1; j < hw->dpb.mDPB.size; j++) {
buf_cnt = hw->dpb.mDPB.size;
for (j = 1; j < buf_cnt; j++) {
i = get_buf_spec_by_canvas_pos(hw, j);
if (alloc_one_buf_spec(hw, i) < 0)
if (hw->is_used_v4l &&
alloc_one_buf_spec_from_queue
(hw, i) < 0) {
if (j++ != buf_cnt)
ret = -1;
break;
} else if (alloc_one_buf_spec(hw, i) < 0)
break;
config_decode_canvas(hw, i);
}
}
@@ -4212,6 +4371,8 @@ pic_done_proc:
hw->chunk->pts;
p_H264_Dpb->mVideo.dec_picture->pts64 =
hw->chunk->pts64;
p_H264_Dpb->mVideo.dec_picture->timestamp =
hw->chunk->timestamp;
#ifdef MH264_USERDATA_ENABLE
vmh264_udc_fill_vpts(hw,
p_H264_Dpb->mSlice.slice_type,
@@ -5110,11 +5271,17 @@ static void vh264_local_init(struct vdec_h264_hw_s *hw)
hw->frame_dur = 96000/30;
}
pr_info
("H264 sysinfo: %dx%d duration=%d, pts_outside=%d\n",
hw->frame_width, hw->frame_height, hw->frame_dur, hw->pts_outside);
pr_debug("sync_outside=%d, use_idr_framerate=%d\n",
hw->sync_outside, hw->use_idr_framerate);
hw->is_used_v4l = (((unsigned long)
hw->vh264_amstream_dec_info.param & 0x80) >> 7);
if (hw->is_used_v4l)
mem_map_mode = CANVAS_BLKMODE_LINEAR;
pr_info("H264 sysinfo: %dx%d duration=%d, pts_outside=%d\n",
hw->frame_width, hw->frame_height, hw->frame_dur, hw->pts_outside);
pr_debug("sync_outside=%d, use_idr_framerate=%d, is_used_v4l: %d\n",
hw->sync_outside, hw->use_idr_framerate, hw->is_used_v4l);
if (i_only_flag & 0x100)
hw->i_only = i_only_flag & 0xff;
@@ -6300,7 +6467,10 @@ result_done:
amhevc_stop();
hw->eos = 1;
flush_dpb(p_H264_Dpb);
if (hw->is_used_v4l)
notify_v4l_eos(hw_to_vdec(hw));
vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
vdec_clean_input(vdec);
} else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) {
dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
"%s: force exit\n",
@@ -6619,7 +6789,27 @@ static void run(struct vdec_s *vdec, unsigned long mask,
static void reset(struct vdec_s *vdec)
{
pr_info("ammvdec_h264: reset.\n");
struct vdec_h264_hw_s *hw =
(struct vdec_h264_hw_s *)vdec->private;
cancel_work_sync(&hw->work);
cancel_work_sync(&hw->notify_work);
cancel_work_sync(&hw->user_data_work);
if (hw->stat & STAT_VDEC_RUN) {
amhevc_stop();
hw->stat &= ~STAT_VDEC_RUN;
}
if (hw->stat & STAT_TIMER_ARM) {
del_timer_sync(&hw->check_timer);
hw->stat &= ~STAT_TIMER_ARM;
}
hw->eos = 0;
hw->decode_pic_count = 0;
hw->dec_result = DEC_RESULT_NONE;
reset_process_time(hw);
h264_reset_bufmgr(vdec);
dpb_print(DECODE_ID(hw), 0, "%s\n", __func__);
}
static void h264_reconfig(struct vdec_h264_hw_s *hw)
@@ -6856,6 +7046,10 @@ static int ammvdec_h264_probe(struct platform_device *pdev)
}
hw->id = pdev->id;
hw->platform_dev = pdev;
/* the ctx from v4l2 driver. */
hw->v4l2_ctx = pdata->private;
platform_set_drvdata(pdev, pdata);
hw->mmu_enable = 0;
@@ -7057,6 +7251,7 @@ static int ammvdec_h264_remove(struct platform_device *pdev)
vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED);
ammvdec_h264_mmu_release(hw);
h264_free_hw_stru(&pdev->dev, (void *)hw);
return 0;
}
@@ -7138,7 +7333,6 @@ static void __exit ammvdec_h264_driver_remove_module(void)
}
/****************************************/
module_param(h264_debug_flag, uint, 0664);
MODULE_PARM_DESC(h264_debug_flag, "\n ammvdec_h264 h264_debug_flag\n");

View File

@@ -526,6 +526,13 @@ int vdec_set_pts(struct vdec_s *vdec, u32 pts)
}
EXPORT_SYMBOL(vdec_set_pts);
void vdec_set_timestamp(struct vdec_s *vdec, u64 timestamp)
{
vdec->timestamp = timestamp;
vdec->timestamp_valid = true;
}
EXPORT_SYMBOL(vdec_set_timestamp);
int vdec_set_pts64(struct vdec_s *vdec, u64 pts64)
{
vdec->pts64 = pts64;
@@ -537,6 +544,12 @@ int vdec_set_pts64(struct vdec_s *vdec, u64 pts64)
}
EXPORT_SYMBOL(vdec_set_pts64);
int vdec_get_status(struct vdec_s *vdec)
{
return vdec->status;
}
EXPORT_SYMBOL(vdec_get_status);
void vdec_set_status(struct vdec_s *vdec, int status)
{
//trace_vdec_set_status(vdec, status);/*DEBUG_TMP*/
@@ -1554,6 +1567,11 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k)
"ppmgr amlvideo.1 amvide2");
snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
"vdec-map-%d", vdec->id);
} else if (p->frame_base_video_path == FRAME_BASE_PATH_V4L_VIDEO) {
snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
"%s %s", vdec->vf_provider_name, "v4l2-video");
snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
"vdec-map-%d", vdec->id);
}
if (vfm_map_add(vdec->vfm_map_id,
@@ -1710,6 +1728,11 @@ int vdec_reset(struct vdec_s *vdec)
vdec_input_release(&vdec->input);
vdec_input_init(&vdec->input, vdec);
vdec_input_prepare_bufs(&vdec->input, vdec->sys_info->width,
vdec->sys_info->height);
vf_reg_provider(&vdec->vframe_provider);
vf_notify_receiver(vdec->vf_provider_name,
VFRAME_EVENT_PROVIDER_START, vdec);

View File

@@ -175,6 +175,8 @@ struct vdec_s {
u32 pts;
u64 pts64;
bool pts_valid;
u64 timestamp;
bool timestamp_valid;
int flag;
int sched;
int need_more_data;
@@ -417,4 +419,8 @@ int vdec_get_debug_flags(void);
unsigned char is_mult_inc(unsigned int);
int vdec_get_status(struct vdec_s *vdec);
void vdec_set_timestamp(struct vdec_s *vdec, u64 timestamp);
#endif /* VDEC_H */

View File

@@ -47,7 +47,7 @@
#define EXTRA_PADDING_SIZE (16 * SZ_1K) /*HEVC_PADDING_SIZE*/
#define MEM_NAME "VFRAME_INPUT"
static int vdec_input_get_duration_u64(struct vdec_input_s *input);
//static int vdec_input_get_duration_u64(struct vdec_input_s *input);
static struct vframe_block_list_s *
vdec_input_alloc_new_block(struct vdec_input_s *input);
@@ -551,7 +551,7 @@ static struct vframe_block_list_s *
}
return block;
}
static int vdec_input_get_duration_u64(struct vdec_input_s *input)
int vdec_input_get_duration_u64(struct vdec_input_s *input)
{
int duration = (input->last_inpts_u64 - input->last_comsumed_pts_u64);
if (input->last_in_nopts_cnt > 0 &&
@@ -571,6 +571,8 @@ static int vdec_input_get_duration_u64(struct vdec_input_s *input)
duration = 0;
return duration;
}
EXPORT_SYMBOL(vdec_input_get_duration_u64);
/*
ret >= 13: have enough buffer, blocked add more buffers
*/
@@ -758,6 +760,10 @@ int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
chunk->pts = vdec->pts;
chunk->pts64 = vdec->pts64;
}
if (vdec->timestamp_valid)
chunk->timestamp = vdec->timestamp;
if (vdec->pts_valid &&
input->last_inpts_u64 > 0 &&
input->last_in_nopts_cnt == 0) {

View File

@@ -49,6 +49,8 @@ struct vframe_chunk_s {
u32 pading_size;
u64 pts64;
bool pts_valid;
u64 timestamp;
bool timestamp_valid;
u64 sequence;
struct vframe_block_list_s *block;
};
@@ -161,4 +163,6 @@ int vdec_input_dump_chunks(struct vdec_input_s *input,
int vdec_input_dump_blocks(struct vdec_input_s *input,
char *bufs, int size);
int vdec_input_get_duration_u64(struct vdec_input_s *input);
#endif /* VDEC_INPUT_H */

View File

@@ -230,6 +230,7 @@ s32 adec_init(struct stream_port_s *port)
astream_dev->format = NULL;
return 0;
}
EXPORT_SYMBOL(adec_init);
s32 adec_release(enum aformat_e vf)
{
@@ -242,6 +243,7 @@ s32 adec_release(enum aformat_e vf)
return 0;
}
EXPORT_SYMBOL(adec_release);
int amstream_adec_show_fun(const char *trigger, int id, char *sbuf, int size)
{

View File

@@ -609,6 +609,7 @@ Err_1:
mutex_unlock(&esparser_mutex);
return r;
}
EXPORT_SYMBOL(esparser_init);
void esparser_audio_reset_s(struct stream_buf_s *buf)
{
@@ -714,6 +715,7 @@ void esparser_release(struct stream_buf_s *buf)
buf->flag &= ~BUF_FLAG_PARSER;
pts_stop(pts_type);
}
EXPORT_SYMBOL(esparser_release);
ssize_t drm_write(struct file *file, struct stream_buf_s *stbuf,
const char __user *buf, size_t count)
@@ -821,6 +823,8 @@ ssize_t drm_write(struct file *file, struct stream_buf_s *stbuf,
return re_count;
}
EXPORT_SYMBOL(drm_write);
/*
*flags:
*1:phy
@@ -914,7 +918,7 @@ ssize_t esparser_write(struct file *file,
}
return esparser_write_ex(file, stbuf, buf, count, 0);
}
EXPORT_SYMBOL(esparser_write);
void esparser_sub_reset(void)
{

View File

@@ -1025,6 +1025,7 @@ void psparser_release(void)
pr_info("psparser release subtitle info\n");
#endif
}
EXPORT_SYMBOL(psparser_release);
ssize_t psparser_write(struct file *file,
struct stream_buf_s *vbuf,

View File

@@ -183,6 +183,7 @@ int stbuf_fetch_init(void)
}
return 0;
}
EXPORT_SYMBOL(stbuf_fetch_init);
void stbuf_fetch_release(void)
{
@@ -362,6 +363,7 @@ s32 stbuf_init(struct stream_buf_s *buf, struct vdec_s *vdec, bool is_multi)
MEM_CTRL_EMPTY_EN);
return 0;
}
EXPORT_SYMBOL(stbuf_init);
void stbuf_vdec2_init(struct stream_buf_s *buf)
{
@@ -425,6 +427,7 @@ void stbuf_release(struct stream_buf_s *buf, bool is_multi)
}
buf->flag &= ~BUF_FLAG_IN_USE;
}
EXPORT_SYMBOL(stbuf_release);
u32 stbuf_sub_rp_get(void)
{

View File

@@ -747,6 +747,7 @@ void tsdemux_release(void)
amports_switch_gate("demux", 0);
}
EXPORT_SYMBOL(tsdemux_release);
static int limited_delay_check(struct file *file,
struct stream_buf_s *vbuf,