Last Updated on : 2024-06-25 03:42:35download
This topic describes the complete process of IPC video capture, including video input (VI), video encoding (VENC) initialization, and video streaming.
VI refers to the process of capturing encoded video data. The common video specifications for the IPC:
The following figure shows the data stream for the FH8636 platform.
The following figure shows the data stream for the T31 platform.
Some platforms have sensor drivers. For example, the sensor driver for the Anyka platform is loaded during file system initialization.
insmod /drv/ak_ion.ko
insmod /drv/ak_uio.ko
insmod /drv/ak_pcm.ko
insmod /drv/ak_i2c.ko
if [ -e /drv/sensor_sc2336.ko ]; then
insmod /drv/ak_isp.ko
insmod /drv/sensor_sc2336.ko
fi
if [ -e /drv/sensor_sc3336.ko ]; then
insmod /drv/ak_isp.ko internal_pclk=100000000
insmod /drv/sensor_sc3336.ko
fi
The kernel’s board support package (BSP) on the Anyka platform handles media memory allocation.
Some platforms do not have sensor drivers, such as the Fullhan platform. The code includes the register sequence of the sensor.
#Allocate memory
insmod /drv/vmm.ko mmz=anonymous,0,0xA2600000,26624K anony=1
#0xA2600000 = 0xA0000000 + 0x2600000, 0x2600000 = 38 MB, indicating the system memory. 26624 KB = 26 MB, indicating the size of the media memory zone.
#Load driver
insmod /drv/media_process.ko
insmod /drv/isp.ko
insmod /drv/enc.ko
insmod /drv/jpeg.ko
insmod /drv/bgm.ko
insmod /drv/nna.ko
How the driver is loaded varies by platform. You only need to focus on initializing the sensor’s register sequence.
Configure the basic properties of the sensor, including the sensor’s length and width, sensor name, default flipping, and ISP image style.
Configure the properties of the encoder. For more information, see the example in this topic.
As shown in the feature description, there is a coupling between streams. For example, if a substream and QR code scanning use the same channel of the vision processing unit (VPU), their resolutions should both be set to 640 x 360 px.
Video streams can be input actively and passively.
Only one method of VI can be applied to a single chip platform. By default, active input is adopted unless otherwise specified.
Passive VI follows the same logic as active VI, except that the callbacks are registered before tal_venc_init
. The application layer does not need to call the tal_venc_get_frame
to request streaming. The underlying layer starts a thread automatically and calls put_cb
to send videos.
// vi and isp
typedef struct{
CHAR_T conf[128]; // isp conf path
CHAR_T conf1[128]; // isp conf1 path
CHAR_T conf2[128]; // isp conf2 path
CHAR_T conf3[128]; // isp conf3 path
CHAR_T version[32]; // version num
CHAR_T name[16]; // isp sensor num
TKL_ISP_DN_SWITCH_CONFIG_T isp_dn_switch_config; // ADN switch config
TKL_VI_SENSOR_CBUS_TYPE_E sensor_type; // sensor control bus type
INT32_T addr; // sensor address
INT32_T width;
INT32_T height;
TKL_ISP_FIG_STYLE_CONFIG_T isp_fig_style_day; // isp fig style in day
TKL_ISP_FIG_STYLE_CONFIG_T isp_fig_style_night; // isp fig style in night
INT32_T fps; // sensor fps
}TKL_VI_ISP_CONFIG_T;
typedef struct {
INT32_T enable; // 1,enable,0,disable
TKL_VI_CHN_E chn; // video input channel
INT32_T mirror; // mirror defaults
INT32_T filp; // filp defaults
TKL_VI_ISP_CONFIG_T isp; // isp config
VOID *pdata; // reserver data
} TKL_VI_CONFIG_T;
// venc
typedef enum
{
TKL_VIDEO_PB_FRAME = 0,
TKL_VIDEO_I_FRAME,
TKL_VIDEO_TS_FRAME,
TKL_AUDIO_FRAME,
TKL_CMD_FRAME,
TKL_MEDIA_FRAME_MAX,
}TKL_MEDIA_FRAME_TYPE_E;
typedef enum
{
TKL_CODEC_VIDEO_MPEG4 = 0,
TKL_CODEC_VIDEO_H263,
TKL_CODEC_VIDEO_H264,
TKL_CODEC_VIDEO_MJPEG,
TKL_CODEC_VIDEO_H265,
TKL_CODEC_VIDEO_YUV420,
TKL_CODEC_VIDEO_YUV422,
TKL_CODEC_VIDEO_MAX = 99,
TKL_CODEC_AUDIO_ADPCM,
TKL_CODEC_AUDIO_PCM,
TKL_CODEC_AUDIO_AAC_RAW,
TKL_CODEC_AUDIO_AAC_ADTS,
TKL_CODEC_AUDIO_AAC_LATM,
TKL_CODEC_AUDIO_G711U,
TKL_CODEC_AUDIO_G711A,
TKL_CODEC_AUDIO_G726,
TKL_CODEC_AUDIO_SPEEX,
TKL_CODEC_AUDIO_MP3,
TKL_CODEC_AUDIO_MAX = 199,
TKL_CODEC_TYPE_MAX
}TKL_MEDIA_CODEC_TYPE_E;
typedef struct
{
UINT_T left; // The x-coordinate displayed in the top left corner of the OSD.
UINT_T top; // The y-coordinate displayed in the top left corner of the OSD.
UINT_T font_w; // The width of the font displayed on the OSD.
UINT_T font_h; // The height of the font displayed on the OSD.
}TKL_VENC_OSD_CONFIG_T; // Configure the OSD property.
typedef struct {
UINT_T enable; // 1,enable,0,disable
TKL_VENC_CHN_E chn; // video encode channel
TKL_VENC_TYPE_E type; // stream work type
TKL_MEDIA_CODEC_TYPE_E codectype; // codec type
UINT_T fps; // fps
UINT_T gop; // I Frame interval
UINT_T bitrate; // bitrate,kbps
UINT_T width;
UINT_T height;
UINT_T min_qp;
UINT_T max_qp;
TKL_VENC_DATA_TRANS_MODE_E trans_mode;
TKL_VENC_PUT_CB put_cb;
TKL_VENC_OSD_CONFIG_T osd;
} TKL_VENC_CONFIG_T;
#define TAL_VI_CONFIG_T TKL_VI_CONFIG_T
#define TAL_VI_HARDWARE_SOURCE_T TKL_VI_HARDWARE_SOURCE_T
typedef enum {
TAL_VI_CMD_MIRROR_FLIP,
TAL_VI_CMD_ANTIFLICKER,
TAL_VI_CMD_ILLUMIN,
TAL_VI_CMD_DAYMODE,
TAL_VI_CMD_SENSOR_REG,
} TAL_VI_CMD_E;
typedef enum {
TAL_VENC_CMD_OSD, // osd
TAL_VENC_CMD_IDR, // set IDR
TAL_VENC_CMD_STREAM_BUFF, // Set the circular cache area of the video memory pool. For example, set two 30K memory
// pools for storage
TAL_VENC_CMD_START, // venc start
TAL_VENC_CMD_STOP, // venc stop
} TAL_VENC_CMD_E;
typedef struct {
INT32_T enable;
INT32_T is_dls;
} TKL_VENC_OSD_T;
typedef struct {
TKL_MEDIA_FRAME_TYPE_E frametype; // bitrate,kbps
TKL_MEDIA_CODEC_TYPE_E codectype; // codec type
CHAR_T *pbuf; // frame buffer
UINT_T buf_size; // buffer size
UINT_T used_size; // used buffer size
UINT_T width; // frame width
UINT_T height; // frame height
UINT64_T pts; // sdk pts
UINT64_T timestamp; // system utc time, unit: ms
UINT_T seq; // frame sequence number
UINT_T fragment; // frame sequence's fragment
BYTE_T seq_error; // frame sequence is error
BYTE_T fragment_is_last; // frame sequence's fragment is last fragment
} TKL_VENC_FRAME_T; // video frame
#define TAL_VENC_FRAME_T TKL_VENC_FRAME_T
typedef INT_T (*TKL_VENC_PUT_CB)(TKL_VENC_FRAME_T *pframe);
The IPC only supports 1-channel VI currently, so count
is 1.
/**
* @brief vi init
*
* @param[in] pconfig: vi config
* @param[in] count: count of pconfig
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_vi_init(TAL_VI_CONFIG_T *pconfig, INT32_T count);
/**
* @brief vi set
*
* @param[in] chn: vi chn
* @param[in] cmd: cmd
* @param[in] parg: parg
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_vi_set(INT32_T chn, TAL_VI_CMD_E cmd, VOID *parg);
/**
* @brief vi get
*
* @param[in] chn: vi chn
* @param[in] cmd: cmd
* @param[out] parg: parg
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_vi_get(INT32_T chn, TAL_VI_CMD_E cmd, VOID *parg);
/**
* @brief vi uninit
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_vi_uninit(VOID);
The IPC only supports 1-channel VI currently, so specify vi_chn
as 0.
/**
* @brief video encode init
*
* @param[in] vi_chn: vi channel number
* @param[in] pconfig: venc config
* @param[in] count: count of pconfig
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_venc_init(INT32_T vi_chn, TAL_VENC_CONFIG_T *pconfig, INT32_T count);
/**
* @brief video set
*
* @param[in] vi_chn: vi channel number
* @param[in] venc_chn: venc chn
* @param[in] cmd: cmd
* @param[in] parg: parg
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_venc_set(INT32_T vi_chn, INT32_T venc_chn, TAL_VENC_CMD_E cmd, VOID *parg);
/**
* @brief video get
*
* @param[in] vi_chn: vi channel number
* @param[in] venc_chn: venc chn
* @param[in] cmd: cmd
* @param[out] parg: parg
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_venc_get(INT32_T vi_chn, INT32_T venc_chn, TAL_VENC_CMD_E cmd, VOID *parg);
/**
* @brief video encode get frame
*
* @param[in] vi_chn: vi channel number
* @param[in] venc_chn: venc channel number
* @param[out] pframe: output frame
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_venc_get_frame(INT32_T vi_chn, INT32_T venc_chn, TAL_VENC_FRAME_T *pframe);
/**
* @brief video encode uninit
*
* @param[in] vi_chn: vi channel number
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_venc_uninit(INT32_T vi_chn);
// Configure and initialize the VI parameter:
TAL_VI_CONFIG_T *pvi = NULL;
// The IPC has only one VI channel currently.
pvi = &gMediaInfo.vi[0];
pvi->enable = true;
pvi->chn = TKL_VI_0;
pvi->mirror = ISP_SENSOR_MIRROR; // The initial flipping.
pvi->filp = ISP_SENSOR_FILP;
memcpy(pvi->isp.conf, ISP_SENSOR_CONF, sizeof(pvi->isp.conf)); // ISP configuration file
memcpy(pvi->isp.version, ISP_FW_VERSION, sizeof(pvi->isp.version));
memcpy(pvi->isp.name, ISP_SENSOR_NAME, sizeof(pvi->isp.name));
pvi->isp.width = ISP_SENSOR_WIDTH;
pvi->isp.height = ISP_SENSOR_HEIGHT;
memcpy(&pvi->isp.isp_dn_switch_config, &g_Tuya_DN_SWITCH_CONFIG_DAY, sizeof(pvi->isp.isp_dn_switch_config));
...
ret = tal_vi_init(pinfo->vi, 1);
...
// Configure the VENC parameter.
S_DSP_MEDIA_INFO gMediaInfo = {
/* Mainstream */
.venc[E_DSP_MEDIA_VIDEO_MAIN].enable = 1,
.venc[E_DSP_MEDIA_VIDEO_MAIN].chn = TKL_VENC_0,
.venc[E_DSP_MEDIA_VIDEO_MAIN].type = TKL_VENC_MAIN,
.venc[E_DSP_MEDIA_VIDEO_MAIN].fps = 20,
.venc[E_DSP_MEDIA_VIDEO_MAIN].gop = 40,
.venc[E_DSP_MEDIA_VIDEO_MAIN].bitrate = 1024,
.venc[E_DSP_MEDIA_VIDEO_MAIN].width = 1920,
.venc[E_DSP_MEDIA_VIDEO_MAIN].height = 1080,
.venc[E_DSP_MEDIA_VIDEO_MAIN].codectype = 4,
.venc[E_DSP_MEDIA_VIDEO_MAIN].min_qp = 26,
.venc[E_DSP_MEDIA_VIDEO_MAIN].max_qp = 48,
/* Substream */
.venc[E_DSP_MEDIA_VIDEO_SUB].enable = 1,
.venc[E_DSP_MEDIA_VIDEO_SUB].chn = TKL_VENC_1,
.venc[E_DSP_MEDIA_VIDEO_SUB].type = TKL_VENC_SUB,
.venc[E_DSP_MEDIA_VIDEO_SUB].fps = 20,
.venc[E_DSP_MEDIA_VIDEO_SUB].gop = 40,
.venc[E_DSP_MEDIA_VIDEO_SUB].bitrate = 512,
.venc[E_DSP_MEDIA_VIDEO_SUB].width = 640,
.venc[E_DSP_MEDIA_VIDEO_SUB].height = 360,
.venc[E_DSP_MEDIA_VIDEO_SUB].codectype = 2,
.venc[E_DSP_MEDIA_VIDEO_SUB].min_qp = 26,
.venc[E_DSP_MEDIA_VIDEO_SUB].max_qp = 48,
/* The third stream, reserved */
.venc[E_DSP_MEDIA_VIDEO_3RD].enable = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].chn = TKL_VENC_2,
.venc[E_DSP_MEDIA_VIDEO_3RD].type = TKL_VENC_3RD,
.venc[E_DSP_MEDIA_VIDEO_3RD].fps = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].gop = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].bitrate = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].width = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].height = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].codectype = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].min_qp = 0,
.venc[E_DSP_MEDIA_VIDEO_3RD].max_qp = 0,
/* The fourth stream, reserved */
.venc[E_DSP_MEDIA_VIDEO_4TH].enable = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].chn = TKL_VENC_3,
.venc[E_DSP_MEDIA_VIDEO_4TH].type = TKL_VENC_4TH,
.venc[E_DSP_MEDIA_VIDEO_4TH].fps = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].gop = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].bitrate = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].width = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].height = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].codectype = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].min_qp = 0,
.venc[E_DSP_MEDIA_VIDEO_4TH].max_qp = 0,
/* Image capture */
.venc[E_DSP_MEDIA_VIDEO_SNAP].enable = 1,
.venc[E_DSP_MEDIA_VIDEO_SNAP].chn = TKL_VENC_4,
.venc[E_DSP_MEDIA_VIDEO_SNAP].type = TKL_VENC_SNAP,
.venc[E_DSP_MEDIA_VIDEO_SNAP].fps = 20,
.venc[E_DSP_MEDIA_VIDEO_SNAP].gop = 40,
.venc[E_DSP_MEDIA_VIDEO_SNAP].bitrate = 512,
.venc[E_DSP_MEDIA_VIDEO_SNAP].width = 640,
.venc[E_DSP_MEDIA_VIDEO_SNAP].height = 360,
.venc[E_DSP_MEDIA_VIDEO_SNAP].codectype = 3,
.venc[E_DSP_MEDIA_VIDEO_SNAP].min_qp = 15,
.venc[E_DSP_MEDIA_VIDEO_SNAP].max_qp = 15,
/* Motion detection */
.venc[E_DSP_MEDIA_VIDEO_MD].enable = 1,
.venc[E_DSP_MEDIA_VIDEO_MD].chn = TKL_VENC_5,
.venc[E_DSP_MEDIA_VIDEO_MD].type = TKL_VENC_MD,
.venc[E_DSP_MEDIA_VIDEO_MD].fps = 20,
.venc[E_DSP_MEDIA_VIDEO_MD].gop = 40,
.venc[E_DSP_MEDIA_VIDEO_MD].bitrate = 512,
.venc[E_DSP_MEDIA_VIDEO_MD].width = 320,
.venc[E_DSP_MEDIA_VIDEO_MD].height = 180,
.venc[E_DSP_MEDIA_VIDEO_MD].codectype = 5,
/* Human shape */
.venc[E_DSP_MEDIA_VIDEO_HD].enable = 1,
.venc[E_DSP_MEDIA_VIDEO_HD].chn = TKL_VENC_6,
.venc[E_DSP_MEDIA_VIDEO_HD].type = TKL_VENC_HD,
.venc[E_DSP_MEDIA_VIDEO_HD].fps = 20,
.venc[E_DSP_MEDIA_VIDEO_HD].gop = 40,
.venc[E_DSP_MEDIA_VIDEO_HD].bitrate = 512,
.venc[E_DSP_MEDIA_VIDEO_HD].width = 512,
.venc[E_DSP_MEDIA_VIDEO_HD].height = 288,
.venc[E_DSP_MEDIA_VIDEO_HD].codectype = 5,
/* QR code */
.venc[E_DSP_MEDIA_VIDEO_QR].enable = 1,
.venc[E_DSP_MEDIA_VIDEO_QR].chn = TKL_VENC_7,
.venc[E_DSP_MEDIA_VIDEO_QR].type = TKL_VENC_QR,
.venc[E_DSP_MEDIA_VIDEO_QR].fps =25,
.venc[E_DSP_MEDIA_VIDEO_QR].gop = 50,
.venc[E_DSP_MEDIA_VIDEO_QR].bitrate = 512,
.venc[E_DSP_MEDIA_VIDEO_QR].width = 640,
.venc[E_DSP_MEDIA_VIDEO_QR].height = 360,
.venc[E_DSP_MEDIA_VIDEO_QR].codectype = 5,
// Initialize VENC:
ret = tal_venc_init(0, pinfo->venc, 8);
...
// Active input of the mainstream. It is recommended to allocate 300 KB to the mainstream:
TAL_VENC_FRAME_T frame = {0};
frame.pbuf = (UCHAR_T *)malloc(300*1024);
frame.buf_size = 300*1024;
ret = tal_venc_get_frame(0, 0, &frame)
...
// Get substream:
frame.pbuf = (UCHAR_T *)malloc(100*1024);
frame.buf_size = 100*1024;
ret = tal_venc_get_frame(0, 1, &frame)
// Image capture
frame.pbuf = (UCHAR_T *)malloc(150*1024);
frame.buf_size = 150*1024;
ret = tal_venc_get_frame(0, TKL_VENC_SNAP, &frame)
...
// Turn on/off OSD
TKL_VENC_OSD_T osd = {0};
osd.enable = 1; // On/off
osd.is_dls = 0; // Specifies if daylight saving time is in effect.
ret = tal_venc_set(0, 0, TAL_VENC_CMD_OSD, &osd);
...
// Set flipping
TKL_VI_MIRROR_FLIP_E val = TKL_VI_MIRROR_FLIP_NONE;
ret =tal_vi_set(0, TAL_VI_CMD_MIRROR_FLIP, &val);
...
val = TKL_VI_MIRROR_FLIP;
ret = tal_vi_set(0, TAL_VI_CMD_MIRROR_FLIP, &val);
Is this page helpful?
YesFeedbackIs this page helpful?
YesFeedback