373 lines
9.9 KiB
C
373 lines
9.9 KiB
C
|
#include <string.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
#include "carlink_video.h"
|
||
|
#include "mfcapi.h"
|
||
|
#include "lcd.h"
|
||
|
#include "pxp.h"
|
||
|
#include "cp15/cp15.h"
|
||
|
#include "timer.h"
|
||
|
#include "task.h"
|
||
|
#include "semphr.h"
|
||
|
#include "os_adapt.h"
|
||
|
#include "ff_stdio.h"
|
||
|
|
||
|
static List_t frame_free_list;
|
||
|
static List_t frame_ready_list;
|
||
|
static video_frame_s h264_frame_fifos[H264_FRAME_FIFO_COUNT];
|
||
|
static char* h264_buf = NULL;
|
||
|
static SemaphoreHandle_t frame_list_mutex = NULL;
|
||
|
static TaskHandle_t dec_h264_handle;
|
||
|
static QueueHandle_t h264_frame_queue;
|
||
|
static uint8_t g_init_flag = 0;
|
||
|
static uint8_t g_video_start = 0;
|
||
|
static int g_disp_x = 0, g_disp_y = 0, g_disp_width = LCD_WIDTH, g_disp_height = LCD_HEIGHT;
|
||
|
static int g_video_width = LCD_WIDTH, g_video_height = LCD_HEIGHT, g_video_fps = 30;
|
||
|
static int g_hide_carlink_flag = 0;
|
||
|
|
||
|
static int g_active_video_x = 0, g_active_video_y = 0;
|
||
|
|
||
|
void set_carlink_active_video_info(int x, int y)//for android auto
|
||
|
{
|
||
|
g_active_video_x = x;
|
||
|
g_active_video_y = y;
|
||
|
}
|
||
|
|
||
|
|
||
|
void set_carlink_video_info(int w, int h, int fps)
|
||
|
{
|
||
|
g_video_width = w;
|
||
|
g_video_height = h;
|
||
|
g_video_fps = fps;
|
||
|
}
|
||
|
|
||
|
int get_carlink_video_width()
|
||
|
{
|
||
|
return g_video_width;
|
||
|
}
|
||
|
|
||
|
int get_carlink_video_height()
|
||
|
{
|
||
|
return g_video_height;
|
||
|
}
|
||
|
|
||
|
int get_carlink_video_fps()
|
||
|
{
|
||
|
return g_video_fps;
|
||
|
}
|
||
|
|
||
|
void set_carlink_display_info(int x, int y, int w, int h)
|
||
|
{
|
||
|
g_disp_x = x;
|
||
|
g_disp_y = y;
|
||
|
g_disp_width = w;
|
||
|
g_disp_height = h;
|
||
|
}
|
||
|
|
||
|
static void h264_frame_list_reset()
|
||
|
{
|
||
|
video_frame_s *buffer;
|
||
|
int i;
|
||
|
|
||
|
buffer = (video_frame_s *)h264_frame_fifos;
|
||
|
vListInitialise(&frame_free_list);
|
||
|
vListInitialise(&frame_ready_list);
|
||
|
for(i = 0; i < H264_FRAME_FIFO_COUNT; i++) {
|
||
|
buffer->buf = (char *)(((unsigned int)h264_buf + i * H264_FRAME_BUF_SIZE));
|
||
|
buffer->cur = buffer->buf;
|
||
|
buffer->frame_id = i;
|
||
|
buffer->len = 0;
|
||
|
vListInitialiseItem(&buffer->entry);
|
||
|
vListInsertEnd(&frame_free_list, &buffer->entry);
|
||
|
listSET_LIST_ITEM_OWNER(&buffer->entry, buffer);
|
||
|
buffer++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int h264_frame_buf_init(void)
|
||
|
{
|
||
|
h264_buf = pvPortMalloc(H264_FRAME_FIFO_COUNT * H264_FRAME_BUF_SIZE );
|
||
|
if (h264_buf == NULL) {
|
||
|
printf("malloc jpeg buf failed\r\n");
|
||
|
return -1;
|
||
|
}
|
||
|
h264_frame_list_reset();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void h264_dec_ctx_init()
|
||
|
{
|
||
|
g_video_start = 0;
|
||
|
xQueueSend(h264_frame_queue, NULL, 0);
|
||
|
}
|
||
|
|
||
|
void set_carlink_display_state(int on)
|
||
|
{
|
||
|
g_hide_carlink_flag = on;
|
||
|
xQueueSend(h264_frame_queue, NULL, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void set_carlink_display_state_irq(int on)
|
||
|
{
|
||
|
g_hide_carlink_flag = on;
|
||
|
|
||
|
xQueueSendFromISR(h264_frame_queue, NULL, 0);
|
||
|
}
|
||
|
|
||
|
video_frame_s* get_h264_frame_buf()
|
||
|
{
|
||
|
video_frame_s* frame = NULL;
|
||
|
ListItem_t* item = NULL;
|
||
|
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
|
||
|
if (g_video_start && !listLIST_IS_EMPTY(&frame_free_list)) {
|
||
|
frame = list_first_entry(&frame_free_list);
|
||
|
item = listGET_HEAD_ENTRY(&frame_free_list);
|
||
|
uxListRemove(item);
|
||
|
}
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
return frame;
|
||
|
}
|
||
|
|
||
|
|
||
|
void notify_h264_frame_ready(video_frame_s** frame)
|
||
|
{
|
||
|
//ListItem_t* item = NULL;
|
||
|
video_frame_s * tmp = *frame;
|
||
|
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
|
||
|
if (NULL != tmp) {
|
||
|
vListInsertEnd(&frame_ready_list, &tmp->entry);
|
||
|
}
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
|
||
|
xQueueSend(h264_frame_queue, NULL, 0);
|
||
|
}
|
||
|
|
||
|
void set_h264_frame_free(video_frame_s* frame)
|
||
|
{
|
||
|
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
|
||
|
if (g_video_start) {
|
||
|
frame->cur = frame->buf;
|
||
|
frame->len = 0;
|
||
|
vListInsertEnd(&frame_free_list, &frame->entry);
|
||
|
}
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
}
|
||
|
uint8_t map_flag = 0;
|
||
|
static void h264_decode_proc(void *pvParameters)
|
||
|
{
|
||
|
MFCHandle *handle = NULL;
|
||
|
DWLLinearMem_t inBuf;
|
||
|
OutFrameBuffer outBuf = {0};
|
||
|
int ret = -1, i;
|
||
|
uint32_t align_width, align_height;
|
||
|
uint32_t yaddr, uaddr, vaddr, dstaddr;
|
||
|
video_frame_s* frame = NULL;
|
||
|
uint32_t ts = get_timer(0), show_ts = 0, video_ts = 0;
|
||
|
int32_t delta_ts = 0;;
|
||
|
int carlink_lcd_take = 0;
|
||
|
ListItem_t* item = NULL;
|
||
|
//FF_FILE *fp = ff_fopen("/usb/ey.h264", "w+");
|
||
|
|
||
|
handle = mfc_init(RAW_STRM_TYPE_H264_NOREORDER);
|
||
|
if(!handle) {
|
||
|
printf("%s, mfc_init failed.\r\n", __func__);
|
||
|
goto exit;
|
||
|
}
|
||
|
g_video_start = 1;
|
||
|
while(1) {
|
||
|
if (xQueueReceive(h264_frame_queue, NULL, portMAX_DELAY) != pdPASS) {
|
||
|
printf("%s xQueueReceive err!\r\n", __func__);
|
||
|
continue;
|
||
|
}
|
||
|
if (g_video_start == 0) {
|
||
|
printf("dec uninit\r\n");
|
||
|
if (carlink_lcd_take) {
|
||
|
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
|
||
|
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||
|
vVideoDisplayBufGive();
|
||
|
ark_lcd_osd_enable(LCD_UI_LAYER, 1);
|
||
|
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||
|
carlink_lcd_take = 0;
|
||
|
}
|
||
|
mfc_uninit(handle);
|
||
|
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
|
||
|
h264_frame_list_reset();
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
xQueueReset(h264_frame_queue);
|
||
|
handle = mfc_init(RAW_STRM_TYPE_H264_NOREORDER);
|
||
|
if(!handle) {
|
||
|
printf("%s, mfc_reinit failed.\r\n", __func__);
|
||
|
continue;
|
||
|
}
|
||
|
g_video_start = 1;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (g_hide_carlink_flag == 0) {
|
||
|
if(map_flag)
|
||
|
map_flag = 0;
|
||
|
printf("Exit navigation =========\r\n ");
|
||
|
Set_sys_wifi_state(0);
|
||
|
//printf("start carplay or andrord auto .\r\n");
|
||
|
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
|
||
|
ark_lcd_osd_enable(LCD_UI_LAYER, 1);
|
||
|
}
|
||
|
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
|
||
|
if (!listLIST_IS_EMPTY(&frame_ready_list)) {
|
||
|
frame = list_first_entry(&frame_ready_list);
|
||
|
item = listGET_HEAD_ENTRY(&frame_ready_list);
|
||
|
uxListRemove(item);
|
||
|
} else {
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
continue;
|
||
|
}
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
|
||
|
memset(&outBuf, 0, sizeof(OutFrameBuffer));
|
||
|
inBuf.busAddress = (u32)frame->cur;
|
||
|
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
|
||
|
inBuf.size = frame->len;
|
||
|
CP15_clean_dcache_for_dma(inBuf.busAddress, inBuf.busAddress + inBuf.size);
|
||
|
ts = get_timer(0);
|
||
|
//printf("start dec...\r\n");
|
||
|
ret = mfc_decode(handle, &inBuf, &outBuf);
|
||
|
//ret = 0;
|
||
|
//if (NULL != fp)
|
||
|
// ret = ff_fwrite((void*)inBuf.virtualAddress, 1, inBuf.size, fp);
|
||
|
|
||
|
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
|
||
|
frame->cur = frame->buf;
|
||
|
frame->len = 0;
|
||
|
vListInsertEnd(&frame_free_list, &frame->entry);
|
||
|
xSemaphoreGive(frame_list_mutex);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
printf("h264 decode fail.\n");
|
||
|
continue;
|
||
|
}//printf("dec num:%d use:%d ms\r\n", outBuf.num, (get_timer(0) - ts) / 1000);
|
||
|
//continue;
|
||
|
|
||
|
for(i = 0; i < outBuf.num; i++) {
|
||
|
int active_offset = 0;
|
||
|
align_width = outBuf.frameWidth;
|
||
|
align_height = outBuf.frameHeight;
|
||
|
|
||
|
if(!(align_width && align_height))
|
||
|
continue;
|
||
|
active_offset = g_active_video_y * align_width;
|
||
|
yaddr = outBuf.buffer[i].yBusAddress + active_offset + g_active_video_x;
|
||
|
uaddr = outBuf.buffer[i].yBusAddress + align_width * align_height + active_offset / 2 + g_active_video_x;
|
||
|
vaddr = 0;//yaddr + align_width * align_height * 5/4;
|
||
|
|
||
|
if (carlink_lcd_take == 0) {
|
||
|
carlink_lcd_take = 1;
|
||
|
xVideoDisplayBufTake(portMAX_DELAY);
|
||
|
}
|
||
|
if (carlink_lcd_take) {
|
||
|
LcdOsdInfo info = {0};
|
||
|
|
||
|
if (0 == g_hide_carlink_flag)
|
||
|
continue;
|
||
|
|
||
|
show_ts = get_timer(0);
|
||
|
|
||
|
info.format = LCD_OSD_FORAMT_YUV420; //set default format.
|
||
|
if ((info.format == LCD_OSD_FORAMT_RGB565) || \
|
||
|
(g_disp_width != g_video_width) || (g_disp_height != g_video_height)) {
|
||
|
uint32_t pxp_width, pxp_height;
|
||
|
int pxp_out_fmt = PXP_OUT_FMT_YUV2P420;
|
||
|
|
||
|
if(info.format == LCD_OSD_FORAMT_RGB565)
|
||
|
pxp_out_fmt = PXP_OUT_FMT_RGB565;
|
||
|
|
||
|
//align_width = ((outBuf.frameWidth + 0xf) & (~0xf));
|
||
|
if (outBuf.frameWidth != g_video_width)
|
||
|
align_width = g_video_width;
|
||
|
else
|
||
|
align_width = outBuf.frameWidth ;
|
||
|
if (outBuf.frameHeight != g_video_height)
|
||
|
align_height = g_video_height;
|
||
|
else
|
||
|
align_height = outBuf.frameHeight;
|
||
|
|
||
|
pxp_width = g_disp_width;
|
||
|
pxp_height = g_disp_height;
|
||
|
dstaddr = ulVideoDisplayBufGet();
|
||
|
|
||
|
pxp_scaler_rotate(yaddr, uaddr, vaddr, PXP_SRC_FMT_YUV2P420, align_width, align_height,
|
||
|
dstaddr, dstaddr + pxp_width * pxp_height, pxp_out_fmt, pxp_width, pxp_height, LCD_ROTATE_ANGLE);
|
||
|
info.yaddr = dstaddr;
|
||
|
info.uaddr = dstaddr + pxp_width * pxp_height;
|
||
|
info.vaddr = 0;
|
||
|
} else {
|
||
|
info.yaddr = yaddr;
|
||
|
info.uaddr = uaddr;
|
||
|
info.vaddr = vaddr;
|
||
|
}
|
||
|
info.x = g_disp_x;
|
||
|
info.y = g_disp_y;
|
||
|
info.width = g_disp_width;
|
||
|
info.height = g_disp_height;
|
||
|
if (g_active_video_x != 0)
|
||
|
info.stride = outBuf.frameWidth;
|
||
|
|
||
|
if (info.format == LCD_OSD_FORAMT_YUV420)
|
||
|
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
|
||
|
|
||
|
if (!ark_lcd_get_osd_info_atomic_isactive(LCD_VIDEO_LAYER)) {
|
||
|
ark_lcd_wait_for_vsync();
|
||
|
}
|
||
|
|
||
|
ark_lcd_set_osd_info_atomic(LCD_VIDEO_LAYER, &info);
|
||
|
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
|
||
|
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||
|
Set_sys_wifi_state(1);
|
||
|
// ark_lcd_osd_enable(LCD_UI_LAYER, 0);
|
||
|
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||
|
vVideoDisplayBufRender(dstaddr);
|
||
|
if (outBuf.num > 1) {// for apple h264
|
||
|
video_ts = (1000 / g_video_fps);
|
||
|
show_ts = (get_timer(0) - show_ts) / 1000;
|
||
|
delta_ts = ((int32_t)video_ts - (int32_t)show_ts) -3;
|
||
|
//printf("delay %d ms\r\n", delta_ts);
|
||
|
if (delta_ts > 0)
|
||
|
vTaskDelay(pdMS_TO_TICKS(delta_ts));
|
||
|
}
|
||
|
if(!map_flag){
|
||
|
// printf("###############################################.\r\n");
|
||
|
request_UI("maps:");
|
||
|
map_flag = 1;
|
||
|
// printf("###############################################.\r\n");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
//printf("all use:%d ms dec:%ld ms all ts:%ld ms\r\n", (get_timer(0) - ts) / 1000, dec_ts, (get_timer(0) - all_ts) / 1000);
|
||
|
//all_ts = get_timer(0);
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
if (NULL != handle)
|
||
|
mfc_uninit(handle);
|
||
|
|
||
|
vTaskDelete(NULL);
|
||
|
}
|
||
|
|
||
|
int carlink_ey_video_init()
|
||
|
{
|
||
|
int ret = -1;
|
||
|
|
||
|
if (g_init_flag ==1) {
|
||
|
return 0;
|
||
|
}
|
||
|
g_init_flag = 1;
|
||
|
ret = h264_frame_buf_init();
|
||
|
frame_list_mutex = xSemaphoreCreateMutex();
|
||
|
//h264_frame_queue = xQueueCreate(H264_FRAME_FIFO_COUNT, sizeof(uint32_t));
|
||
|
h264_frame_queue = xQueueCreate(1, 0);
|
||
|
ret = xTaskCreate(h264_decode_proc, "h264_decode_proc", 2048 * 4, NULL, configMAX_PRIORITIES - 3, &dec_h264_handle);
|
||
|
return ret;
|
||
|
}
|