1429 lines
44 KiB
C
1429 lines
44 KiB
C
#include "basic_include.h"
|
||
|
||
#include "lib/multimedia/msi.h"
|
||
|
||
#include "stream_define.h"
|
||
#include "lib/video/h264/h264_drv.h"
|
||
#include "osal/work.h"
|
||
#include "lib/video/dvp/jpeg/jpg.h"
|
||
#include "hal/h264.h"
|
||
#include "lib/heap/av_heap.h"
|
||
#include "lib/heap/av_psram_heap.h"
|
||
#include "lib/heap/av_heap.h"
|
||
#include "lib/heap/av_psram_heap.h"
|
||
#include "gen420_hardware_msi.h"
|
||
#include "user_work/user_work.h"
|
||
#include "hal/scale.h"
|
||
|
||
extern uint32 get_h264_srcID(void *d);
|
||
extern uint8_t get_vpp_w_h(uint16_t *w, uint16_t *h);
|
||
extern uint8_t get_vpp1_w_h(uint16_t *w, uint16_t *h);
|
||
extern uint32 get_h264_w_h(void *d, uint16_t *w, uint16_t *h);
|
||
extern uint8_t get_vpp_scale_w_h(uint16_t *w, uint16_t *h);
|
||
extern void set_vpp_scale_w_h(uint8_t en, uint16_t w, uint16_t h);
|
||
#ifndef SAVE_COUNT
|
||
#define SAVE_COUNT 4
|
||
#endif
|
||
|
||
#define USE_WORK 1
|
||
#define MAX_BYTES 0
|
||
|
||
#if VIDEO_YUV_RANGE_TYPE
|
||
|
||
#undef MAX_BYTES
|
||
#define MAX_BITS 160
|
||
#define MAX_BYTES (MAX_BITS / 8)
|
||
|
||
// 位缓冲区结构体
|
||
typedef struct
|
||
{
|
||
uint8_t data[MAX_BYTES]; // 存储数据的字节数组
|
||
int current_bit_pos; // 当前位位置(0-127)
|
||
} BitBuffer;
|
||
|
||
// 初始化位缓冲区
|
||
void bit_buffer_init(BitBuffer *buffer)
|
||
{
|
||
// memset(buffer->data, 0, sizeof(buffer->data));
|
||
buffer->current_bit_pos = 0;
|
||
}
|
||
|
||
// 设置位缓冲区
|
||
void bit_buffer_set(BitBuffer *buffer, uint8_t data)
|
||
{
|
||
buffer->data[buffer->current_bit_pos / 8] = data;
|
||
buffer->current_bit_pos += 8;
|
||
}
|
||
|
||
// 二进制bit左移拼接函数
|
||
// 输入:buffer - 位缓冲区指针
|
||
// bits - 要添加的二进制数据(最多16位)
|
||
// bit_count - 二进制位数(1-16)
|
||
// padding - 是否补零到8的倍数(1:是,0:否)
|
||
// 返回值:成功添加的位数
|
||
int bit_buffer_append(BitBuffer *buffer, uint16_t bits, int bit_count, int padding)
|
||
{
|
||
if (bit_count < 1 || bit_count > 16)
|
||
{
|
||
os_printf(KERN_ERR "err:bit_count must 1-16\n");
|
||
return 0;
|
||
}
|
||
|
||
if (buffer->current_bit_pos + bit_count > MAX_BITS)
|
||
{
|
||
printf(KERN_ERR "warning:buff full\n");
|
||
bit_count = MAX_BITS - buffer->current_bit_pos;
|
||
if (bit_count <= 0)
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// 确保只取bit_count位
|
||
bits &= (1 << bit_count) - 1;
|
||
|
||
// 逐个bit添加
|
||
for (int i = bit_count - 1; i >= 0; i--)
|
||
{
|
||
int current_byte = buffer->current_bit_pos / 8;
|
||
int current_bit_in_byte = 7 - (buffer->current_bit_pos % 8); // 从高位到低位
|
||
|
||
// 获取当前bit的值
|
||
uint8_t bit_value = (bits >> i) & 1;
|
||
|
||
// 设置对应的bit位
|
||
if (bit_value)
|
||
{
|
||
buffer->data[current_byte] |= (1 << current_bit_in_byte);
|
||
}
|
||
else
|
||
{
|
||
buffer->data[current_byte] &= ~(1 << current_bit_in_byte);
|
||
}
|
||
|
||
buffer->current_bit_pos++;
|
||
}
|
||
|
||
// 如果需要补零到8的倍数
|
||
if (padding)
|
||
{
|
||
int remainder = buffer->current_bit_pos % 8;
|
||
if (remainder != 0)
|
||
{
|
||
int bits_to_pad = 8 - remainder;
|
||
|
||
if (buffer->current_bit_pos + bits_to_pad > MAX_BITS)
|
||
{
|
||
// printf("warning:buff full when fill zero\n");
|
||
bits_to_pad = MAX_BITS - buffer->current_bit_pos;
|
||
}
|
||
|
||
for (int i = 0; i < bits_to_pad; i++)
|
||
{
|
||
int current_byte = buffer->current_bit_pos / 8;
|
||
int current_bit_in_byte = 7 - (buffer->current_bit_pos % 8);
|
||
|
||
// 补零
|
||
buffer->data[current_byte] &= ~(1 << current_bit_in_byte);
|
||
buffer->current_bit_pos++;
|
||
}
|
||
|
||
// printf("fill zero %d bit,make byte align\n", bits_to_pad);
|
||
}
|
||
}
|
||
|
||
return bit_count;
|
||
}
|
||
|
||
// 打印缓冲区内容(十六进制格式)
|
||
void bit_buffer_print_hex(const BitBuffer *buffer)
|
||
{
|
||
int bytes_used = (buffer->current_bit_pos + 7) / 8;
|
||
for (int i = 0; i < bytes_used; i++)
|
||
{
|
||
os_printf("buff[%02d]:%02x\n", i, buffer->data[i]);
|
||
}
|
||
}
|
||
|
||
// 获取当前已使用的字节数
|
||
int bit_buffer_get_used_bytes(const BitBuffer *buffer)
|
||
{
|
||
return (buffer->current_bit_pos + 7) / 8;
|
||
}
|
||
|
||
// 指数哥伦布编码
|
||
uint8_t len_exp = 0;
|
||
uint8_t len_pre = 0;
|
||
uint8_t len_suf = 0;
|
||
uint16 exp_out = 0;
|
||
void ue_se_enc(uint16 in_data)
|
||
{
|
||
len_exp = 0;
|
||
len_pre = 0;
|
||
len_suf = 0;
|
||
exp_out = 0;
|
||
|
||
if ((in_data & 0x1e0) != 0)
|
||
{
|
||
if ((in_data & 0x100) != 0)
|
||
{
|
||
len_exp = 14;
|
||
len_pre = 7;
|
||
len_suf = 8;
|
||
}
|
||
else if ((in_data & 0x080) != 0)
|
||
{
|
||
len_exp = 14;
|
||
len_pre = 6;
|
||
len_suf = 7;
|
||
}
|
||
else if ((in_data & 0x040) != 0)
|
||
{
|
||
len_exp = 12;
|
||
len_pre = 5;
|
||
len_suf = 6;
|
||
}
|
||
else
|
||
{
|
||
len_exp = 10;
|
||
len_pre = 4;
|
||
len_suf = 5;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((in_data & 0x010) != 0)
|
||
{
|
||
len_exp = 8;
|
||
len_pre = 3;
|
||
len_suf = 4;
|
||
}
|
||
else if ((in_data & 0x008) != 0)
|
||
{
|
||
len_exp = 6;
|
||
len_pre = 2;
|
||
len_suf = 3;
|
||
}
|
||
else if ((in_data & 0x004) != 0)
|
||
{
|
||
len_exp = 4;
|
||
len_pre = 1;
|
||
len_suf = 2;
|
||
}
|
||
else if ((in_data & 0x002) != 0)
|
||
{
|
||
len_exp = 2;
|
||
len_pre = 0;
|
||
len_suf = 1;
|
||
}
|
||
else
|
||
{
|
||
len_exp = 0;
|
||
len_pre = 0;
|
||
len_suf = 1;
|
||
}
|
||
}
|
||
len_exp += 1;
|
||
len_pre += 1;
|
||
len_suf += 1;
|
||
exp_out = (in_data & 0x1ff);
|
||
}
|
||
// main 1920 1080
|
||
void h264_sps_gen_test(BitBuffer *buffer, uint16_t wrap_w, uint16_t wrap_h, uint8_t fr)
|
||
{
|
||
uint8_t level_idc = 52; // h264 0x50
|
||
uint16 img_x = wrap_w / 16;
|
||
uint16 img_y = (wrap_h + 0xf) / 16;
|
||
uint8_t crop_en = 0;
|
||
uint8_t crop_y = (img_y * 16 - wrap_h) / 2;
|
||
uint8_t full_range = fr;
|
||
|
||
if (crop_y)
|
||
{
|
||
crop_en = 1;
|
||
}
|
||
|
||
bit_buffer_init(buffer);
|
||
// fixed
|
||
bit_buffer_set(buffer, 0x00);
|
||
bit_buffer_set(buffer, 0x00);
|
||
bit_buffer_set(buffer, 0x00);
|
||
bit_buffer_set(buffer, 0x01);
|
||
bit_buffer_set(buffer, 0x67);
|
||
bit_buffer_set(buffer, 0x4d);
|
||
bit_buffer_set(buffer, 0x00);
|
||
bit_buffer_set(buffer, level_idc);
|
||
bit_buffer_set(buffer, 0x96);
|
||
bit_buffer_set(buffer, 0x54);
|
||
// img width
|
||
ue_se_enc(img_x);
|
||
bit_buffer_append(buffer, 0x0000, len_pre, 0);
|
||
bit_buffer_append(buffer, exp_out, len_suf, 0);
|
||
// img height
|
||
ue_se_enc(img_y);
|
||
bit_buffer_append(buffer, 0x0000, len_pre, 0);
|
||
bit_buffer_append(buffer, exp_out, len_suf, 0);
|
||
// other
|
||
bit_buffer_append(buffer, 0x0003, 2, 0);
|
||
// img crop
|
||
if (crop_en)
|
||
{
|
||
bit_buffer_append(buffer, 0x000f, 4, 0);
|
||
ue_se_enc((crop_y + 1));
|
||
bit_buffer_append(buffer, exp_out, len_exp, 0);
|
||
}
|
||
else
|
||
{
|
||
bit_buffer_append(buffer, 0x0000, 1, 0);
|
||
}
|
||
// full range
|
||
if (full_range)
|
||
{
|
||
bit_buffer_append(buffer, 0x4880, 15, 0);
|
||
}
|
||
else
|
||
{
|
||
bit_buffer_append(buffer, 0x0000, 1, 0);
|
||
}
|
||
// byte align
|
||
bit_buffer_append(buffer, 0x0001, 1, 1);
|
||
// bit_buffer_print_hex(buffer);
|
||
}
|
||
#endif
|
||
enum video_app_h264_enum
|
||
{
|
||
VIDEO_APP_H264_EXIT = BIT(0),
|
||
VIDEO_APP_H264_STOP = BIT(1),
|
||
};
|
||
|
||
// data申请空间函数
|
||
#define STREAM_MALLOC av_psram_malloc
|
||
#define STREAM_FREE av_psram_free
|
||
#define STREAM_ZALLOC av_psram_zalloc
|
||
|
||
// 结构体申请空间函数
|
||
#ifdef MORE_SRAM
|
||
#define STREAM_LIBC_MALLOC av_psram_malloc
|
||
#define STREAM_LIBC_FREE av_psram_free
|
||
#define STREAM_LIBC_ZALLOC av_psram_zalloc
|
||
#else
|
||
#define STREAM_LIBC_MALLOC av_malloc
|
||
#define STREAM_LIBC_FREE av_free
|
||
#define STREAM_LIBC_ZALLOC av_zalloc
|
||
#endif
|
||
|
||
#define MAX_VIDEO_APP_264 64
|
||
|
||
// 获取nal的size,从0开始搜索,返回的是的nal头的size,offset相对于头的偏移(通过多次调用,可以用于计算nal_size)
|
||
// 返回0代表搜索不到nal的头
|
||
static uint8_t get_nal_size(uint8_t *buf, uint32_t size, uint32_t *offset)
|
||
{
|
||
uint32_t pos = 0;
|
||
while ((size - pos) > 3)
|
||
{
|
||
if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 1)
|
||
{
|
||
*offset = pos;
|
||
return 3;
|
||
}
|
||
|
||
if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 0 && buf[pos + 3] == 1)
|
||
{
|
||
*offset = pos;
|
||
return 4;
|
||
}
|
||
|
||
pos++;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// 只是获取pps和sps的nalsize
|
||
static uint8_t *get_sps_pps_nal_size(uint8_t *buf, uint32_t size, uint32_t *nal_size, uint8_t *head_size)
|
||
{
|
||
uint32_t offset;
|
||
uint8_t nal_head_size = get_nal_size(buf, size, &offset);
|
||
uint8_t nal_type;
|
||
uint8_t *ret_buf = NULL;
|
||
// 找到头部,检查类型
|
||
if (nal_head_size && offset + nal_head_size < size)
|
||
{
|
||
nal_type = buf[nal_head_size + offset] & 0x1f;
|
||
|
||
// 找到sps和pps就返回长度和偏移(相对buf的偏移)
|
||
if (nal_type == 7 || nal_type == 8)
|
||
{
|
||
// 查找下一个nal
|
||
nal_head_size = get_nal_size(buf + offset + nal_head_size, size - (offset + nal_head_size), nal_size);
|
||
// os_printf("nal_head_size:%d\tnal_size:%d\n",nal_head_size,*nal_size);
|
||
if (nal_head_size)
|
||
{
|
||
// 偏移到nal的头部
|
||
|
||
ret_buf = buf + offset;
|
||
// 返回nal的头size
|
||
*head_size = nal_head_size;
|
||
}
|
||
}
|
||
}
|
||
|
||
return ret_buf;
|
||
}
|
||
|
||
uint8_t *skip_sps(uint8_t *next_nal_buf, uint32_t size, uint32_t *skip_size)
|
||
{
|
||
uint8_t sps_times = 0;
|
||
uint8_t nal_head_size;
|
||
uint32_t nal_size;
|
||
uint8_t pps_sps_size = 0;
|
||
uint8_t *sps_pps_buf = NULL;
|
||
while (sps_times < 1)
|
||
{
|
||
sps_pps_buf = get_sps_pps_nal_size(next_nal_buf, 64, &nal_size, &nal_head_size);
|
||
if (sps_pps_buf && (sps_pps_buf[nal_head_size] & 0x1f) == 7)
|
||
{
|
||
pps_sps_size += (nal_size + nal_head_size);
|
||
next_nal_buf = sps_pps_buf + nal_size + nal_head_size;
|
||
}
|
||
// 不匹配,就不再去获取pps或者sps了
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
// os_printf("sps_pps_buf[nal_head_size]& 0x1f):%d\n",sps_pps_buf[nal_head_size]& 0x1f);
|
||
sps_times++;
|
||
}
|
||
if (skip_size)
|
||
{
|
||
*skip_size = pps_sps_size;
|
||
}
|
||
|
||
return next_nal_buf;
|
||
}
|
||
|
||
#if USE_WORK == 0
|
||
struct video_h264_msi_s
|
||
{
|
||
// struct os_work work;
|
||
struct os_task task;
|
||
struct os_event evt;
|
||
struct msi *msi;
|
||
struct h264_device *h264_dev;
|
||
uint16_t filter_type;
|
||
uint16_t sub_stream_en;
|
||
struct fbpool tx_pool;
|
||
};
|
||
|
||
/********************************************************************************************
|
||
* I帧和P帧对应的位置图,主要通过寻找nal,定位pps和sps的起始位置并且记录
|
||
* 实际内容也会记录,到终端可以采取是否直接读取结构体的pps和sps(尽量从结构体读取)
|
||
*
|
||
*
|
||
* 00 00 00 01 67 xx xx xx 00 00 00 01 68 xx xx xx 00 00 00 01 65 xx xx xx I帧
|
||
* sps_buf pps_buf start_len
|
||
*
|
||
*
|
||
*
|
||
*
|
||
*
|
||
* 00 00 00 01 61 xx xx xx P帧
|
||
* start_len
|
||
*******************************************************************************************/
|
||
|
||
static int8_t h264_output_msi(struct list_head *get_f, struct video_h264_msi_s *video_h264)
|
||
{
|
||
int ret = RET_ERR;
|
||
uint32_t node_len;
|
||
uint32_t h264_len;
|
||
uint32_t h264_len_tmp;
|
||
uint32_t cp_len;
|
||
uint32_t cp_offset;
|
||
uint8_t *tmp_buf;
|
||
uint32_t timestamp;
|
||
uint8_t which;
|
||
uint8_t srcID;
|
||
|
||
uint8_t h264_type_frame;
|
||
node_len = get_h264_node_len_new((void *) get_f);
|
||
h264_len = get_h264_len(get_f);
|
||
timestamp = get_h264_timestamp(get_f);
|
||
h264_type_frame = get_h264_type(get_f); // 获取是否为I帧还是P帧
|
||
which = get_h264_which(get_f);
|
||
srcID = get_h264_srcID(get_f);
|
||
uint8_t count = get_h264_loop_num(get_f);
|
||
struct framebuff *fb = NULL;
|
||
if (!h264_len)
|
||
{
|
||
goto h264_output_msi_end;
|
||
}
|
||
fb = fbpool_get(&video_h264->tx_pool, 0, video_h264->msi);
|
||
if (fb)
|
||
{
|
||
// 先去msi寻找是否有空闲节点,如果有,才需要拷贝,否则就丢弃
|
||
uint8_t *h264_buf = (uint8_t *) STREAM_MALLOC(h264_len + SAVE_COUNT);
|
||
if (!h264_buf)
|
||
{
|
||
msi_delete_fb(NULL, fb);
|
||
goto h264_output_msi_end;
|
||
}
|
||
// 拷贝264的数据
|
||
h264_len_tmp = h264_len;
|
||
cp_offset = 0;
|
||
while (h264_buf)
|
||
{
|
||
// 图片节点提取
|
||
if (list_empty(get_f) || h264_len_tmp == 0)
|
||
{
|
||
break;
|
||
}
|
||
if (h264_len_tmp > node_len)
|
||
{
|
||
cp_len = node_len;
|
||
}
|
||
else
|
||
{
|
||
cp_len = h264_len_tmp;
|
||
}
|
||
h264_len_tmp -= cp_len;
|
||
tmp_buf = get_h264_first_buf(get_f);
|
||
hw_memcpy0(h264_buf + cp_offset, get_h264_first_buf(get_f), cp_len);
|
||
del_h264_first_node(get_f);
|
||
cp_offset += cp_len;
|
||
}
|
||
|
||
// 264末尾加一个序号
|
||
if (SAVE_COUNT > 0)
|
||
{
|
||
os_sprintf(h264_buf + h264_len, "%03d", count & 0xff);
|
||
h264_buf[h264_len + 3] = '#';
|
||
}
|
||
sys_dcache_clean_range((uint32_t *) h264_buf, h264_len + SAVE_COUNT);
|
||
|
||
fb->data = (uint8_t *) h264_buf;
|
||
fb->len = h264_len + SAVE_COUNT;
|
||
fb->mtype = F_H264;
|
||
fb->stype = which + FSTYPE_H264_VPP_DATA0; // 基于stype某个值
|
||
fb->time = timestamp;
|
||
fb->srcID = srcID;
|
||
// I帧
|
||
if (h264_type_frame == 1)
|
||
{
|
||
// 先去读取sps和pps的长度
|
||
uint8_t nal_head_size;
|
||
uint32_t nal_size;
|
||
uint8_t *sps_pps_buf = fb->data;
|
||
|
||
uint8_t *pps_buf = NULL;
|
||
uint8_t *sps_buf = NULL;
|
||
uint8_t pps_len = 0, sps_len = 0;
|
||
uint8_t pps_sps_times = 0;
|
||
uint8_t *next_nal_buf = fb->data;
|
||
|
||
// 读取sps和pps,仅仅读取两次,没有就退出
|
||
while (sps_pps_buf && pps_sps_times < 2)
|
||
{
|
||
sps_pps_buf = get_sps_pps_nal_size(next_nal_buf, 64, &nal_size, &nal_head_size);
|
||
if (sps_pps_buf && (sps_pps_buf[nal_head_size] & 0x1f) == 7)
|
||
{
|
||
sps_buf = sps_pps_buf + nal_head_size;
|
||
sps_len = nal_size;
|
||
next_nal_buf = sps_pps_buf + nal_size + nal_head_size;
|
||
}
|
||
else if (sps_pps_buf && (sps_pps_buf[nal_head_size] & 0x1f) == 8)
|
||
{
|
||
pps_buf = sps_pps_buf + nal_head_size;
|
||
pps_len = nal_size;
|
||
next_nal_buf = sps_pps_buf + nal_size + nal_head_size;
|
||
}
|
||
// 不匹配,就不再去获取pps或者sps了
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
// os_printf("sps_pps_buf[nal_head_size]& 0x1f):%d\n",sps_pps_buf[nal_head_size]& 0x1f);
|
||
pps_sps_times++;
|
||
}
|
||
|
||
struct fb_h264_s *priv = (struct fb_h264_s *) STREAM_LIBC_ZALLOC(sizeof(struct fb_h264_s));
|
||
|
||
// 寻找一下nal头有多少字节
|
||
uint32_t pos;
|
||
uint8_t h264_nal_size = get_nal_size(next_nal_buf, 16, &pos);
|
||
|
||
priv->pps = pps_buf;
|
||
priv->pps_len = pps_len;
|
||
priv->sps = sps_buf;
|
||
priv->sps_len = sps_len;
|
||
fb->priv = (void *) priv;
|
||
priv->type = 1;
|
||
priv->count = count;
|
||
priv->start_len = next_nal_buf - fb->data + pos + h264_nal_size;
|
||
// os_printf("priv->start_len:%d\ttype:%d\n",priv->start_len,fb->data[priv->start_len]&0x1f);
|
||
// os_printf("pps:%d\tsps:%d\n",pps_buf[0]&0x1f,sps_buf[0]&0x1f);
|
||
}
|
||
else
|
||
{
|
||
struct fb_h264_s *priv = (struct fb_h264_s *) STREAM_LIBC_ZALLOC(sizeof(struct fb_h264_s));
|
||
uint32_t pos;
|
||
uint8_t h264_nal_size = get_nal_size(fb->data, 16, &pos);
|
||
priv->type = 2;
|
||
fb->priv = (void *) priv;
|
||
priv->count = count;
|
||
priv->start_len = pos + h264_nal_size;
|
||
}
|
||
//_os_printf("H%d", h264_type_frame);
|
||
// 在msi_output_fb后,不要继续调用其他和msi有关的东西,因为有可能在这个之后,会释放对应的内存
|
||
msi_output_fb(video_h264->msi, fb);
|
||
ret = RET_OK;
|
||
}
|
||
h264_output_msi_end:
|
||
return ret;
|
||
}
|
||
|
||
static int32 h264_msi_thread(void *d)
|
||
{
|
||
struct video_h264_msi_s *video_h264 = (struct video_h264_msi_s *) d;
|
||
uint32_t flags;
|
||
// uint8_t which;
|
||
uint32_t stop_flag = 0;
|
||
msi_get(video_h264->msi);
|
||
while (1)
|
||
{
|
||
// 如果需要退出,则直接退出线程
|
||
os_event_wait(&video_h264->evt, VIDEO_APP_H264_STOP, &stop_flag, OS_EVENT_WMODE_OR, 0);
|
||
if (stop_flag & VIDEO_APP_H264_STOP)
|
||
{
|
||
break;
|
||
}
|
||
flags = disable_irq();
|
||
struct list_head *get_f = (void *) get_h264_frame();
|
||
enable_irq(flags);
|
||
|
||
if (get_f)
|
||
{
|
||
h264_output_msi(get_f, video_h264);
|
||
del_h264_frame(get_f);
|
||
}
|
||
else
|
||
{
|
||
os_sleep_ms(1);
|
||
}
|
||
}
|
||
// 设置退出标志
|
||
os_event_set(&video_h264->evt, VIDEO_APP_H264_EXIT, NULL);
|
||
// 释放对应的msi(不是open的),实际是这个时候才会真正释放
|
||
msi_put(video_h264->msi);
|
||
return 0;
|
||
}
|
||
|
||
static int32_t h264_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
||
{
|
||
int32_t ret = RET_OK;
|
||
struct video_h264_msi_s *video_h264 = (struct video_h264_msi_s *) msi->priv;
|
||
switch (cmd_id)
|
||
{
|
||
case MSI_CMD_POST_DESTROY:
|
||
{
|
||
|
||
h264_mem_init(0, 0, 0, 0, 0);
|
||
fbpool_destroy(&video_h264->tx_pool);
|
||
// 等待线程退出
|
||
os_event_wait(&video_h264->evt, VIDEO_APP_H264_EXIT, NULL, OS_EVENT_WMODE_CLEAR, -1);
|
||
os_event_del(&video_h264->evt);
|
||
STREAM_LIBC_FREE(video_h264);
|
||
}
|
||
break;
|
||
|
||
case MSI_CMD_PRE_DESTROY:
|
||
{
|
||
// os_work_cancle2(&video_h264->work, 1);
|
||
os_event_set(&video_h264->evt, VIDEO_APP_H264_STOP, NULL);
|
||
h264_close(video_h264->h264_dev);
|
||
if (video_h264->sub_stream_en)
|
||
{
|
||
unregister_gen420_queue(GEN420_QUEUE_H264);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case MSI_CMD_FREE_FB:
|
||
{
|
||
struct framebuff *fb = (struct framebuff *) param1;
|
||
if (fb->data)
|
||
{
|
||
STREAM_FREE(fb->data);
|
||
fb->data = NULL;
|
||
}
|
||
if (fb->priv)
|
||
{
|
||
STREAM_LIBC_FREE(fb->priv);
|
||
fb->priv = NULL;
|
||
}
|
||
fbpool_put(&video_h264->tx_pool, fb);
|
||
// 不需要内核去释放fb
|
||
ret = RET_OK + 1;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
struct msi *h264_msi_init_with_mode(uint32_t drv1_from, uint32_t drv1_w, uint32_t drv1_h, uint32_t drv2_from, uint32_t drv2_w, uint32_t drv2_h)
|
||
{
|
||
int ret = 0;
|
||
struct msi *msi = msi_new(S_H264, 0, NULL);
|
||
struct video_h264_msi_s *video_h264 = (struct video_h264_msi_s *) msi->priv;
|
||
|
||
if (!video_h264)
|
||
{
|
||
video_h264 = (struct video_h264_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct video_h264_msi_s));
|
||
msi->priv = (void *) video_h264;
|
||
msi->enable = 1;
|
||
msi->action = h264_msi_action;
|
||
video_h264->msi = msi;
|
||
fbpool_init(&video_h264->tx_pool, MAX_VIDEO_APP_264);
|
||
os_event_init(&video_h264->evt);
|
||
|
||
video_h264->h264_dev = (struct h264_device *) dev_get(HG_H264_DEVID);
|
||
if (video_h264->h264_dev)
|
||
{
|
||
if (drv1_from == GEN420_DATA || drv2_from == GEN420_DATA)
|
||
{
|
||
extern int32_t h264_gen420_kick();
|
||
uint32_t gen_w = drv1_from == GEN420_DATA ? drv1_w : drv2_w;
|
||
uint32_t gen_h = drv1_from == GEN420_DATA ? drv1_h : drv2_h;
|
||
ret = register_gen420_queue(GEN420_QUEUE_H264, gen_w, gen_h, h264_gen420_kick, NULL, (uint32) NULL);
|
||
if (!ret)
|
||
{
|
||
video_h264->sub_stream_en = 1;
|
||
}
|
||
else
|
||
{
|
||
video_h264->sub_stream_en = 0;
|
||
|
||
if (drv1_from == GEN420_DATA)
|
||
{
|
||
drv1_from = 0;
|
||
drv1_w = 0;
|
||
drv1_h = 0;
|
||
}
|
||
|
||
if (drv2_from == GEN420_DATA)
|
||
{
|
||
drv2_from = 0;
|
||
drv2_w = 0;
|
||
drv2_h = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 自己适应w和h
|
||
if (drv1_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
|
||
if (drv2_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv2_w, &drv2_h);
|
||
}
|
||
else if (drv2_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv2_w, &drv2_h);
|
||
}
|
||
|
||
h264_set_oe_select(video_h264->h264_dev, 0, 0);
|
||
h264_enc(drv1_from, drv1_w, drv1_h, drv2_from, drv2_w, drv2_h);
|
||
h264_open(video_h264->h264_dev);
|
||
h264_set_sw_ready(video_h264->h264_dev);
|
||
}
|
||
// 启动workqueue
|
||
// 创建一个任务去做h264的工作
|
||
OS_TASK_INIT("video_h264", &video_h264->task, h264_msi_thread, (void *) video_h264, OS_TASK_PRIORITY_ABOVE_NORMAL, NULL, 1024);
|
||
// OS_WORK_INIT(&video_h264->work, h264_msi_work, 0);
|
||
// os_run_work_delay(&video_h264->work, 1);
|
||
}
|
||
return msi;
|
||
}
|
||
|
||
struct msi *h264_msi_init_with_mode_for_264wq(uint32_t drv1_from, uint32_t drv1_w, uint32_t drv1_h)
|
||
{
|
||
int ret = 0;
|
||
struct msi *msi = msi_new(S_H264, 0, NULL);
|
||
struct video_h264_msi_s *video_h264 = (struct video_h264_msi_s *) msi->priv;
|
||
|
||
if (!video_h264)
|
||
{
|
||
video_h264 = (struct video_h264_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct video_h264_msi_s));
|
||
msi->priv = (void *) video_h264;
|
||
msi->enable = 1;
|
||
msi->action = h264_msi_action;
|
||
video_h264->msi = msi;
|
||
fbpool_init(&video_h264->tx_pool, MAX_VIDEO_APP_264);
|
||
os_event_init(&video_h264->evt);
|
||
|
||
video_h264->h264_dev = (struct h264_device *) dev_get(HG_H264_DEVID);
|
||
if (video_h264->h264_dev)
|
||
{
|
||
if (drv1_from == GEN420_DATA)
|
||
{
|
||
extern int32_t h264_gen420_kick();
|
||
uint32_t gen_w = drv1_w;
|
||
uint32_t gen_h = drv1_h;
|
||
ret = register_gen420_queue(GEN420_QUEUE_H264, gen_w, gen_h, h264_gen420_kick, NULL, (uint32) NULL);
|
||
if (!ret)
|
||
{
|
||
video_h264->sub_stream_en = 1;
|
||
}
|
||
else
|
||
{
|
||
video_h264->sub_stream_en = 0;
|
||
|
||
if (drv1_from == GEN420_DATA)
|
||
{
|
||
drv1_from = 0;
|
||
drv1_w = 0;
|
||
drv1_h = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 自己适应w和h
|
||
if (drv1_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
|
||
h264_set_oe_select(video_h264->h264_dev, 0, 0);
|
||
h264_enc(drv1_from, drv1_w, drv1_h, -1, 0, 0);
|
||
// h264_open(video_h264->h264_dev);
|
||
}
|
||
// 启动workqueue
|
||
// 创建一个任务去做h264的工作
|
||
OS_TASK_INIT("video_h264", &video_h264->task, h264_msi_thread, (void *) video_h264, OS_TASK_PRIORITY_ABOVE_NORMAL, NULL, 1024);
|
||
// OS_WORK_INIT(&video_h264->work, h264_msi_work, 0);
|
||
// os_run_work_delay(&video_h264->work, 1);
|
||
}
|
||
return msi;
|
||
}
|
||
#else
|
||
struct video_h264_msi_s
|
||
{
|
||
struct os_work work;
|
||
struct os_event evt;
|
||
struct msi *msi;
|
||
struct h264_device *h264_dev;
|
||
uint16_t filter_type;
|
||
uint16_t sub_stream_en;
|
||
|
||
uint8_t drv1_from;
|
||
uint8_t drv2_from;
|
||
struct fbpool tx_pool;
|
||
};
|
||
|
||
#if VIDEO_YUV_RANGE_TYPE
|
||
uint8_t h264_dec_sps_src_param(uint32 w, uint32 h, uint8_t *buf)
|
||
{
|
||
BitBuffer buffer;
|
||
// uint32 itk;
|
||
buffer.current_bit_pos = 0;
|
||
h264_sps_gen_test(&buffer, w, h, 0);
|
||
memcpy(buf, buffer.data, buffer.current_bit_pos / 8);
|
||
return buffer.current_bit_pos / 8;
|
||
}
|
||
#endif
|
||
/********************************************************************************************
|
||
* I帧和P帧对应的位置图,主要通过寻找nal,定位pps和sps的起始位置并且记录
|
||
* 实际内容也会记录,到终端可以采取是否直接读取结构体的pps和sps(尽量从结构体读取)
|
||
*
|
||
*
|
||
* 00 00 00 01 67 xx xx xx 00 00 00 01 68 xx xx xx 00 00 00 01 65 xx xx xx I帧
|
||
* sps_buf pps_buf start_len
|
||
*
|
||
*
|
||
*
|
||
*
|
||
*
|
||
* 00 00 00 01 61 xx xx xx P帧
|
||
* start_len
|
||
*******************************************************************************************/
|
||
|
||
static int8_t h264_output_msi(struct list_head *get_f, struct video_h264_msi_s *video_h264)
|
||
{
|
||
int ret = RET_ERR;
|
||
uint32_t node_len;
|
||
uint32_t h264_len;
|
||
uint32_t h264_len_tmp;
|
||
uint32_t cp_len;
|
||
uint32_t cp_offset;
|
||
uint8_t *tmp_buf;
|
||
uint32_t timestamp;
|
||
uint8_t which;
|
||
uint8_t srcID;
|
||
uint16_t w, h;
|
||
uint8_t h264_type_frame;
|
||
node_len = get_h264_node_len_new((void *) get_f);
|
||
h264_len = get_h264_len(get_f);
|
||
timestamp = get_h264_timestamp(get_f);
|
||
h264_type_frame = get_h264_type(get_f); // 获取是否为I帧还是P帧
|
||
which = get_h264_which(get_f);
|
||
srcID = get_h264_srcID(get_f);
|
||
uint8_t count = get_h264_loop_num(get_f);
|
||
struct framebuff *fb = NULL;
|
||
get_h264_w_h((void *) get_f, &w, &h);
|
||
|
||
// 新的sps和pps的buf
|
||
|
||
if (!h264_len)
|
||
{
|
||
goto h264_output_msi_end;
|
||
}
|
||
#if VIDEO_YUV_RANGE_TYPE == 1
|
||
|
||
BitBuffer buffer;
|
||
// os_printf("h264_type_frame:%d\n", h264_type_frame);
|
||
// 如果是I帧,就重新生成一下对应的sps和pps
|
||
if (h264_type_frame == 1)
|
||
{
|
||
buffer.current_bit_pos = 0;
|
||
h264_sps_gen_test(&buffer, w, h, 1);
|
||
}
|
||
#endif
|
||
fb = fbpool_get(&video_h264->tx_pool, 0, video_h264->msi);
|
||
if (fb)
|
||
{
|
||
// 先去msi寻找是否有空闲节点,如果有,才需要拷贝,否则就丢弃
|
||
// MAX_BYTES是重新生成的sps和pps的最大空间
|
||
uint8_t *h264_buf = (uint8_t *) STREAM_MALLOC(h264_len + SAVE_COUNT + MAX_BYTES);
|
||
if (!h264_buf)
|
||
{
|
||
msi_delete_fb(NULL, fb);
|
||
goto h264_output_msi_end;
|
||
}
|
||
uint32_t reserve_len = 0;
|
||
|
||
#if VIDEO_YUV_RANGE_TYPE == 1
|
||
uint32_t skip_size;
|
||
if (h264_type_frame == 1)
|
||
{
|
||
uint8_t *new_sps_pps_buf = get_h264_first_buf(get_f);
|
||
|
||
skip_sps(new_sps_pps_buf, 128, &skip_size);
|
||
if (skip_size)
|
||
{
|
||
reserve_len = bit_buffer_get_used_bytes(&buffer) - skip_size;
|
||
}
|
||
}
|
||
|
||
#endif
|
||
// 拷贝264的数据
|
||
h264_len_tmp = h264_len;
|
||
// 设置预留的长度
|
||
cp_offset = reserve_len;
|
||
while (h264_buf)
|
||
{
|
||
// 图片节点提取
|
||
if (list_empty(get_f) || h264_len_tmp == 0)
|
||
{
|
||
break;
|
||
}
|
||
if (h264_len_tmp > node_len)
|
||
{
|
||
cp_len = node_len;
|
||
}
|
||
else
|
||
{
|
||
cp_len = h264_len_tmp;
|
||
}
|
||
h264_len_tmp -= cp_len;
|
||
tmp_buf = get_h264_first_buf(get_f);
|
||
hw_memcpy0(h264_buf + cp_offset, get_h264_first_buf(get_f), cp_len);
|
||
del_h264_first_node(get_f);
|
||
cp_offset += cp_len;
|
||
}
|
||
|
||
#if VIDEO_YUV_RANGE_TYPE == 1
|
||
// skip_size代表找到sps,替换新的sps
|
||
if (h264_type_frame == 1 && skip_size)
|
||
{
|
||
os_memcpy(h264_buf, buffer.data, bit_buffer_get_used_bytes(&buffer));
|
||
}
|
||
#endif
|
||
|
||
// 264末尾加一个序号
|
||
if (SAVE_COUNT > 0)
|
||
{
|
||
os_sprintf((char *) h264_buf + h264_len + reserve_len, "%03d", count & 0xff);
|
||
h264_buf[h264_len + reserve_len + 3] = '#';
|
||
}
|
||
sys_dcache_clean_range((uint32_t *) h264_buf, h264_len + SAVE_COUNT + reserve_len);
|
||
|
||
fb->data = (uint8_t *) h264_buf;
|
||
fb->len = h264_len + SAVE_COUNT + reserve_len;
|
||
fb->mtype = F_H264;
|
||
fb->stype = which + FSTYPE_H264_VPP_DATA0; // 基于stype某个值
|
||
fb->time = timestamp;
|
||
fb->srcID = srcID;
|
||
// I帧
|
||
if (h264_type_frame == 1)
|
||
{
|
||
// 先去读取sps和pps的长度
|
||
uint8_t nal_head_size;
|
||
uint32_t nal_size;
|
||
uint8_t *sps_pps_buf = fb->data;
|
||
|
||
uint8_t *pps_buf = NULL;
|
||
uint8_t *sps_buf = NULL;
|
||
uint8_t pps_len = 0, sps_len = 0;
|
||
uint8_t pps_sps_times = 0;
|
||
uint8_t *next_nal_buf = fb->data;
|
||
|
||
// 读取sps和pps,仅仅读取两次,没有就退出
|
||
while (sps_pps_buf && pps_sps_times < 2)
|
||
{
|
||
sps_pps_buf = get_sps_pps_nal_size(next_nal_buf, 64, &nal_size, &nal_head_size);
|
||
if (sps_pps_buf && (sps_pps_buf[nal_head_size] & 0x1f) == 7)
|
||
{
|
||
sps_buf = sps_pps_buf + nal_head_size;
|
||
sps_len = nal_size;
|
||
next_nal_buf = sps_pps_buf + nal_size + nal_head_size;
|
||
}
|
||
else if (sps_pps_buf && (sps_pps_buf[nal_head_size] & 0x1f) == 8)
|
||
{
|
||
pps_buf = sps_pps_buf + nal_head_size;
|
||
pps_len = nal_size;
|
||
next_nal_buf = sps_pps_buf + nal_size + nal_head_size;
|
||
}
|
||
// 不匹配,就不再去获取pps或者sps了
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
// os_printf("sps_pps_buf[nal_head_size]& 0x1f):%d\n",sps_pps_buf[nal_head_size]& 0x1f);
|
||
pps_sps_times++;
|
||
}
|
||
|
||
struct fb_h264_s *priv = (struct fb_h264_s *) STREAM_LIBC_ZALLOC(sizeof(struct fb_h264_s));
|
||
|
||
// 寻找一下nal头有多少字节
|
||
uint32_t pos;
|
||
uint8_t h264_nal_size = get_nal_size(next_nal_buf, 16, &pos);
|
||
|
||
priv->pps = pps_buf;
|
||
priv->pps_len = pps_len;
|
||
priv->sps = sps_buf;
|
||
priv->sps_len = sps_len;
|
||
fb->priv = (void *) priv;
|
||
priv->type = 1;
|
||
priv->count = count;
|
||
priv->start_len = next_nal_buf - fb->data + pos + h264_nal_size;
|
||
priv->w = w;
|
||
priv->h = h;
|
||
// os_printf("priv->start_len:%d\ttype:%d\n",priv->start_len,fb->data[priv->start_len]&0x1f);
|
||
// os_printf("pps:%d\tsps:%d\n",pps_buf[0]&0x1f,sps_buf[0]&0x1f);
|
||
}
|
||
else
|
||
{
|
||
struct fb_h264_s *priv = (struct fb_h264_s *) STREAM_LIBC_ZALLOC(sizeof(struct fb_h264_s));
|
||
uint32_t pos;
|
||
uint8_t h264_nal_size = get_nal_size(fb->data, 16, &pos);
|
||
priv->type = 2;
|
||
fb->priv = (void *) priv;
|
||
priv->count = count;
|
||
priv->start_len = pos + h264_nal_size;
|
||
priv->w = w;
|
||
priv->h = h;
|
||
}
|
||
//_os_printf("H%d", h264_type_frame);
|
||
// 在msi_output_fb后,不要继续调用其他和msi有关的东西,因为有可能在这个之后,会释放对应的内存
|
||
msi_output_fb(video_h264->msi, fb);
|
||
ret = RET_OK;
|
||
}
|
||
h264_output_msi_end:
|
||
return ret;
|
||
}
|
||
|
||
static int32 h264_msi_work(struct os_work *work)
|
||
{
|
||
struct video_h264_msi_s *video_h264 = (struct video_h264_msi_s *) work;
|
||
uint32_t flags;
|
||
h264_msi_work_again:
|
||
flags = disable_irq();
|
||
struct list_head *get_f = (void *) get_h264_frame();
|
||
enable_irq(flags);
|
||
if (get_f)
|
||
{
|
||
h264_output_msi(get_f, video_h264);
|
||
del_h264_frame(get_f);
|
||
goto h264_msi_work_again;
|
||
}
|
||
os_run_work_delay(work, 1);
|
||
// os_event_set(&video_h264->evt, VIDEO_APP_H264_EXIT, NULL);
|
||
return 0;
|
||
}
|
||
|
||
static int32_t h264_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
||
{
|
||
int32_t ret = RET_OK;
|
||
struct video_h264_msi_s *video_h264 = (struct video_h264_msi_s *) msi->priv;
|
||
switch (cmd_id)
|
||
{
|
||
case MSI_CMD_POST_DESTROY:
|
||
{
|
||
|
||
h264_mem_init(0, 0, 0, 0, 0);
|
||
fbpool_destroy(&video_h264->tx_pool);
|
||
// 等待线程退出
|
||
// os_event_wait(&video_h264->evt, VIDEO_APP_H264_EXIT, NULL, OS_EVENT_WMODE_CLEAR, -1);
|
||
os_event_del(&video_h264->evt);
|
||
STREAM_LIBC_FREE(video_h264);
|
||
}
|
||
break;
|
||
|
||
case MSI_CMD_PRE_DESTROY:
|
||
{
|
||
os_work_cancle2(&video_h264->work, 1);
|
||
h264_close(video_h264->h264_dev);
|
||
if (video_h264->sub_stream_en)
|
||
{
|
||
unregister_gen420_queue(GEN420_QUEUE_H264);
|
||
}
|
||
|
||
uint8_t scale1 = 0;
|
||
// 把检查数据源是否为scale1,如果是scale1,同时把scale1一起关闭了
|
||
if (video_h264->drv1_from == SCALER_DATA)
|
||
{
|
||
scale1 = 1;
|
||
}
|
||
|
||
if (video_h264->drv2_from == SCALER_DATA)
|
||
{
|
||
scale1 = 1;
|
||
}
|
||
if (scale1)
|
||
{
|
||
struct scale_device *scale_dev = (struct scale_device *) dev_get(HG_SCALE1_DEVID);
|
||
// 关闭scale1
|
||
scale_close(scale_dev);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case MSI_CMD_FREE_FB:
|
||
{
|
||
struct framebuff *fb = (struct framebuff *) param1;
|
||
if (fb->data)
|
||
{
|
||
STREAM_FREE(fb->data);
|
||
fb->data = NULL;
|
||
}
|
||
if (fb->priv)
|
||
{
|
||
STREAM_LIBC_FREE(fb->priv);
|
||
fb->priv = NULL;
|
||
}
|
||
fbpool_put(&video_h264->tx_pool, fb);
|
||
// 不需要内核去释放fb
|
||
ret = RET_OK + 1;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
struct msi *h264_msi_init_with_mode(uint32_t drv1_from, uint16_t drv1_w, uint16_t drv1_h, uint16_t drv2_from, uint16_t drv2_w, uint16_t drv2_h)
|
||
{
|
||
int ret = 0;
|
||
uint8_t isnew;
|
||
struct msi *msi = msi_new(S_H264, 0, &isnew);
|
||
struct video_h264_msi_s *video_h264;
|
||
|
||
if (msi && isnew)
|
||
{
|
||
video_h264 = (struct video_h264_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct video_h264_msi_s));
|
||
ASSERT(video_h264);
|
||
msi->priv = (void *) video_h264;
|
||
msi->enable = 1;
|
||
|
||
video_h264->h264_dev = (struct h264_device *) dev_get(HG_H264_DEVID);
|
||
if (video_h264->h264_dev)
|
||
{
|
||
|
||
if (drv1_from == GEN420_DATA || drv2_from == GEN420_DATA)
|
||
{
|
||
extern int32_t h264_gen420_kick();
|
||
uint32_t gen_w = drv1_from == GEN420_DATA ? drv1_w : drv2_w;
|
||
uint32_t gen_h = drv1_from == GEN420_DATA ? drv1_h : drv2_h;
|
||
ret = register_gen420_queue(GEN420_QUEUE_H264, gen_w, gen_h, h264_gen420_kick, NULL, (uint32) NULL);
|
||
if (!ret)
|
||
{
|
||
video_h264->sub_stream_en = 1;
|
||
}
|
||
else
|
||
{
|
||
video_h264->sub_stream_en = 0;
|
||
|
||
if (drv1_from == GEN420_DATA)
|
||
{
|
||
drv1_from = 0;
|
||
drv1_w = 0;
|
||
drv1_h = 0;
|
||
}
|
||
|
||
if (drv2_from == GEN420_DATA)
|
||
{
|
||
drv2_from = 0;
|
||
drv2_w = 0;
|
||
drv2_h = 0;
|
||
}
|
||
}
|
||
}
|
||
// 自己适应w和h
|
||
if (drv1_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == SCALER_DATA)
|
||
{
|
||
ret = get_vpp_scale_w_h(&drv1_w, &drv1_h);
|
||
if (!ret)
|
||
{
|
||
set_vpp_scale_w_h(1, drv1_w, drv1_h);
|
||
}
|
||
else
|
||
{
|
||
drv1_from = ~0;
|
||
}
|
||
}
|
||
|
||
if (drv2_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv2_w, &drv2_h);
|
||
}
|
||
else if (drv2_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv2_w, &drv2_h);
|
||
}
|
||
else if (drv2_from == SCALER_DATA)
|
||
{
|
||
ret = get_vpp_scale_w_h(&drv2_w, &drv2_h);
|
||
if (!ret)
|
||
{
|
||
set_vpp_scale_w_h(1, drv2_w, drv2_h);
|
||
}
|
||
else
|
||
{
|
||
drv2_from = ~0;
|
||
}
|
||
}
|
||
|
||
video_h264->drv1_from = drv1_from;
|
||
video_h264->drv2_from = drv2_from;
|
||
h264_set_oe_select(video_h264->h264_dev, 0, 0);
|
||
ret = h264_enc(drv1_from, drv1_w, drv1_h, drv2_from, drv2_w, drv2_h);
|
||
|
||
if (ret)
|
||
{
|
||
if (video_h264)
|
||
{
|
||
STREAM_LIBC_FREE(video_h264);
|
||
}
|
||
msi_destroy(msi);
|
||
msi = NULL;
|
||
goto h264_msi_init_with_mode_end;
|
||
}
|
||
else
|
||
{
|
||
h264_open(video_h264->h264_dev);
|
||
h264_set_sw_ready(video_h264->h264_dev);
|
||
msi->action = h264_msi_action;
|
||
video_h264->msi = msi;
|
||
fbpool_init(&video_h264->tx_pool, MAX_VIDEO_APP_264);
|
||
os_event_init(&video_h264->evt);
|
||
}
|
||
}
|
||
// 启动workqueue
|
||
// 创建一个任务去做h264的工作
|
||
// OS_TASK_INIT("video_h264", &video_h264->task, h264_msi_thread, (void*)video_h264, OS_TASK_PRIORITY_ABOVE_NORMAL, NULL, 1024);
|
||
OS_WORK_INIT(&video_h264->work, h264_msi_work, 0);
|
||
os_run_work_delay(&video_h264->work, 1);
|
||
}
|
||
h264_msi_init_with_mode_end:
|
||
return msi;
|
||
}
|
||
|
||
struct msi *h264_msi_init_with_timeLapse(uint32_t drv1_from, uint16_t drv1_w, uint16_t drv1_h, uint32_t timer)
|
||
{
|
||
int ret = 0;
|
||
uint8_t isnew = 0;
|
||
struct msi *msi = msi_new(S_H264, 0, &isnew);
|
||
struct video_h264_msi_s *video_h264;
|
||
|
||
if (msi && isnew)
|
||
{
|
||
video_h264 = (struct video_h264_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct video_h264_msi_s));
|
||
ASSERT(video_h264);
|
||
msi->priv = (void *) video_h264;
|
||
msi->enable = 1;
|
||
|
||
video_h264->h264_dev = (struct h264_device *) dev_get(HG_H264_DEVID);
|
||
if (video_h264->h264_dev)
|
||
{
|
||
// 自己适应w和h
|
||
if (drv1_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == SCALER_DATA)
|
||
{
|
||
ret = get_vpp_scale_w_h(&drv1_w, &drv1_h);
|
||
if (!ret)
|
||
{
|
||
set_vpp_scale_w_h(1, drv1_w, drv1_h);
|
||
}
|
||
else
|
||
{
|
||
drv1_from = ~0;
|
||
}
|
||
}
|
||
|
||
video_h264->drv1_from = drv1_from;
|
||
video_h264->drv2_from = ~0;
|
||
h264_set_oe_select(video_h264->h264_dev, 0, 0);
|
||
ret = h264_enc_with_timeLapse(drv1_from, drv1_w, drv1_h, timer);
|
||
|
||
if (ret)
|
||
{
|
||
if (video_h264)
|
||
{
|
||
STREAM_LIBC_FREE(video_h264);
|
||
}
|
||
msi_destroy(msi);
|
||
msi = NULL;
|
||
goto h264_msi_init_with_mode_end;
|
||
}
|
||
else
|
||
{
|
||
h264_open(video_h264->h264_dev);
|
||
h264_set_sw_ready(video_h264->h264_dev);
|
||
msi->action = h264_msi_action;
|
||
video_h264->msi = msi;
|
||
fbpool_init(&video_h264->tx_pool, MAX_VIDEO_APP_264);
|
||
os_event_init(&video_h264->evt);
|
||
}
|
||
}
|
||
// 启动workqueue
|
||
// 创建一个任务去做h264的工作
|
||
// OS_TASK_INIT("video_h264", &video_h264->task, h264_msi_thread, (void*)video_h264, OS_TASK_PRIORITY_ABOVE_NORMAL, NULL, 1024);
|
||
OS_WORK_INIT(&video_h264->work, h264_msi_work, 0);
|
||
os_run_work_delay(&video_h264->work, 1);
|
||
}
|
||
h264_msi_init_with_mode_end:
|
||
return msi;
|
||
}
|
||
|
||
struct msi *h264_msi_init_with_mode_for_264wq(uint32_t drv1_from, uint16_t drv1_w, uint16_t drv1_h)
|
||
{
|
||
int ret = 0;
|
||
uint8_t isnew;
|
||
struct msi *msi = msi_new(S_H264, 0, &isnew);
|
||
struct video_h264_msi_s *video_h264;
|
||
|
||
if (msi && isnew)
|
||
{
|
||
video_h264 = (struct video_h264_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct video_h264_msi_s));
|
||
ASSERT(video_h264);
|
||
msi->priv = (void *) video_h264;
|
||
msi->enable = 1;
|
||
|
||
video_h264->h264_dev = (struct h264_device *) dev_get(HG_H264_DEVID);
|
||
if (video_h264->h264_dev)
|
||
{
|
||
if (drv1_from == GEN420_DATA)
|
||
{
|
||
extern int32_t h264_gen420_kick();
|
||
uint32_t gen_w = drv1_w;
|
||
uint32_t gen_h = drv1_h;
|
||
ret = register_gen420_queue(GEN420_QUEUE_H264, gen_w, gen_h, h264_gen420_kick, NULL, (uint32) NULL);
|
||
if (!ret)
|
||
{
|
||
video_h264->sub_stream_en = 1;
|
||
}
|
||
else
|
||
{
|
||
video_h264->sub_stream_en = 0;
|
||
|
||
if (drv1_from == GEN420_DATA)
|
||
{
|
||
drv1_from = 0;
|
||
drv1_w = 0;
|
||
drv1_h = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 自己适应w和h
|
||
if (drv1_from == VPP_DATA0)
|
||
{
|
||
get_vpp_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
else if (drv1_from == VPP_DATA1)
|
||
{
|
||
get_vpp1_w_h(&drv1_w, &drv1_h);
|
||
}
|
||
|
||
h264_set_oe_select(video_h264->h264_dev, 0, 0);
|
||
ret = h264_enc(drv1_from, drv1_w, drv1_h, -1, 0, 0);
|
||
|
||
if (ret)
|
||
{
|
||
if (video_h264)
|
||
{
|
||
STREAM_LIBC_FREE(video_h264);
|
||
}
|
||
msi_destroy(msi);
|
||
msi = NULL;
|
||
goto h264_msi_init_with_mode_end;
|
||
}
|
||
else
|
||
{
|
||
h264_open(video_h264->h264_dev);
|
||
msi->action = h264_msi_action;
|
||
video_h264->msi = msi;
|
||
fbpool_init(&video_h264->tx_pool, MAX_VIDEO_APP_264);
|
||
os_event_init(&video_h264->evt);
|
||
}
|
||
}
|
||
// 启动workqueue
|
||
// 创建一个任务去做h264的工作
|
||
// OS_TASK_INIT("video_h264", &video_h264->task, h264_msi_thread, (void*)video_h264, OS_TASK_PRIORITY_ABOVE_NORMAL, NULL, 1024);
|
||
OS_WORK_INIT(&video_h264->work, h264_msi_work, 0);
|
||
os_run_work_delay(&video_h264->work, 1);
|
||
}
|
||
h264_msi_init_with_mode_end:
|
||
return msi;
|
||
}
|
||
#endif
|