MAX_CARLINK_A270S/MXC_A27-PCB4.5-270T/app/carlink/common/carlink_video.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;
}