GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* g_uvc.h -- USB Video Class Gadget driver API
*
* Copyright (C) 2009-2010 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#ifndef __LINUX_USB_G_UVC_H
#define __LINUX_USB_G_UVC_H
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/usb/ch9.h>
#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0)
#define UVC_EVENT_CONNECT (V4L2_EVENT_PRIVATE_START + 0)
#define UVC_EVENT_DISCONNECT (V4L2_EVENT_PRIVATE_START + 1)
#define UVC_EVENT_STREAMON (V4L2_EVENT_PRIVATE_START + 2)
#define UVC_EVENT_STREAMOFF (V4L2_EVENT_PRIVATE_START + 3)
#define UVC_EVENT_SETUP (V4L2_EVENT_PRIVATE_START + 4)
#define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5)
#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5)
struct uvc_request_data {
__s32 length;
__u8 data[60];
};
struct uvc_event {
union {
enum usb_device_speed speed;
struct usb_ctrlrequest req;
struct uvc_request_data data;
};
};
#define UVCIOC_SEND_RESPONSE _IOW('U', 1, struct uvc_request_data)
#endif /* __LINUX_USB_G_UVC_H */
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __UVC_ADAPTER_H__
#define __UVC_ADAPTER_H__
/* For Requests */
/* 和内核中的定义一致 */
/* For VideoControl Requests */
#define UVC_VC_INTERFACE_ID 0x00
#define UVC_CAMERA_TERMINAL_ID 0x01
#define UVC_PROCESSING_UNIT_ID 0x02
#define UVC_SELECTOR_UNIT_ID 0x03
#define UVC_OUTPUT_TERMINAL_ID 0x05
#define UVC_EXTENSION_UNIT_H264_ID 0x0A
#define UVC_EXTENSION_UNIT_CAMERA_ID 0x11
#define UVC_EXTENSION_UNIT_VENDOR1_ID 0x0B
/* For VideoStreaming Requests*/
#define UVC_VS_INTERFACE_ID 0x01
/* Requests Error Code */
#define UVC_REC_NO_ERROR 0x00
#define UVC_REC_NO_READY 0x01
#define UVC_REC_WRONG_STATE 0x02
#define UVC_REC_POWER 0x03
#define UVC_REC_OUT_OF_RANGE 0x04
#define UVC_REC_INVALID_UNIT 0x05
#define UVC_REC_INVALID_CONTROL 0x06
#define UVC_REC_INVALID_REQUEST 0x07
#define UVC_REC_UNKNOW 0xFF
/* Stream Error Code */
/* CTRL id */
#define XUID_SET_RESET 0x01
#define XUID_SET_STREAM 0x02
#define XUID_SET_RESOLUTION 0x03
#define XUID_SET_IFRAME 0x04
#define XUID_SET_BITRATE 0x05
#define XUID_UPDATE_SYSTEM 0x06
/* VENDOR1 CTRL id */
#define XUID_VENDOR_01 0x01
#define XUID_VENDOR_02 0x02
#define XUID_VENDOR_03 0x03
#define XUID_VENDOR_04 0x04
#define XUID_VENDOR_05 0x05
#define XUID_VENDOR_06 0x06
#define XUID_VENDOR_07 0x07
#define XUID_VENDOR_08 0x08
#define XUID_VENDOR_09 0x09
#define XUID_VENDOR_10 0x0A
// ...
//#define XUID_VENDOR_32 0x20
/* */
#define MASK_INTF_ID(usb_ctrl) ((usb_ctrl)->wIndex & 0xFF)
#define MASK_ENTITY_ID(usb_ctrl) (((usb_ctrl)->wIndex & 0xFF00) >> 8)
#define MASK_CS_CODE(usb_ctrl) ((usb_ctrl)->wValue >> 8)
#define MASK_REQ_CODE(usb_ctrl) ((usb_ctrl)->bRequest)
void uvc_requests_infos(struct usb_ctrlrequest* ctrl);
#endif
+502
View File
@@ -0,0 +1,502 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uvc_formats.h"
#include "config_svc.h"
#include "uvc_log.h"
#define FORMAT_NV12 "nv12"
#define FORMAT_NV21 "nv21"
#define FORMAT_YUYV "yuyv"
#define FORMAT_H264 "h264"
#define FORMAT_H265 "h265"
#define FORMAT_MJPEG "mjpeg"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define v4l2_fourcc(a, b, c, d)\
((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
#define V4L2_PIX_FMT_H265 v4l2_fourcc('H', '2', '6', '5') /* H265 with start codes */
struct node {
void* data;
struct node* row;
struct node* column;
};
static struct node g_formats_list_head = {
.data = NULL,
.row = NULL,
.column = NULL,
};
static int g_malloc_count = 0;
static char* fcc_to_string(int fcc)
{
switch (fcc) {
case V4L2_PIX_FMT_YUYV:
return "yuyv";
case V4L2_PIX_FMT_NV21:
return "nv21";
case V4L2_PIX_FMT_NV12:
return "nv12";
case V4L2_PIX_FMT_MJPEG:
return "mjpeg";
case V4L2_PIX_FMT_H264:
return "h264";
case V4L2_PIX_FMT_H265:
return "h265";
default:
return "Unknow";
}
}
static int string_to_fcc(char* str)
{
if (memcmp(str, FORMAT_YUYV, strlen(str)) == 0) {
return V4L2_PIX_FMT_YUYV;
}
if (memcmp(str, FORMAT_NV21, strlen(str)) == 0) {
return V4L2_PIX_FMT_NV21;
}
if (memcmp(str, FORMAT_NV12, strlen(str)) == 0) {
return V4L2_PIX_FMT_NV12;
}
if (memcmp(str, FORMAT_MJPEG, strlen(str)) == 0) {
return V4L2_PIX_FMT_MJPEG;
}
if (memcmp(str, FORMAT_H264, strlen(str)) == 0) {
return V4L2_PIX_FMT_H264;
}
if (memcmp(str, FORMAT_H265, strlen(str)) == 0) {
return V4L2_PIX_FMT_H265;
}
return 0;
}
static void show_formats_info(void)
{
int i, j;
struct node* list_head = &g_formats_list_head;
struct node* fmt_n = NULL;
struct node* frm_n = NULL;
struct uvc_format_info* fmt_info = NULL;
struct uvc_frame_info* frm_info = NULL;
printf("\n");
printf("Formats info:\n");
fmt_n = list_head->row;
i = 1;
while (fmt_n) {
fmt_info = (struct uvc_format_info*)fmt_n->data;
printf("\tFormat %d: %s\n", i, fcc_to_string(fmt_info->fcc));
frm_n = fmt_n->column;
j = 1;
while (frm_n) {
frm_info = (struct uvc_frame_info*)frm_n->data;
printf("\tFrame %d: \t%d x %d \t@ %d.\n",
j, frm_info->width, frm_info->height, frm_info->intervals[0]);
frm_n = frm_n->column;
j++;
}
fmt_n = fmt_n->row;
i++;
printf("\n");
}
}
static struct node* new_node(void* data)
{
struct node* new = malloc(sizeof(struct node));
if (new == NULL) {
uvc_loge("Out of memory\n");
} else {
g_malloc_count++;
new->data = data;
new->row = NULL;
new->column = NULL;
}
return new;
}
static struct node* new_format(int fcc)
{
struct node* new_fmt = NULL;
struct uvc_format_info* fmt = malloc(sizeof(struct uvc_format_info));
if (fmt == NULL) {
uvc_loge("Out of memory.\n");
} else {
g_malloc_count++;
fmt->fcc = fcc;
fmt->frames = NULL;
fmt->frm_nums = 0;
new_fmt = new_node(fmt);
if (new_fmt == NULL) {
free(fmt);
g_malloc_count--;
fmt = NULL;
}
}
return new_fmt;
}
static struct node* new_frame(int w, int h, int interval)
{
struct node* new_frm = NULL;
struct uvc_frame_info* frm = malloc(sizeof(struct uvc_frame_info));
if (frm == NULL) {
uvc_loge("Out of memory.\n");
} else {
g_malloc_count++;
memset(frm, 0, sizeof(struct uvc_frame_info));
frm->width = w;
frm->height = h;
frm->intervals[0] = interval;
new_frm = new_node(frm);
if (new_frm == NULL) {
free(frm);
g_malloc_count--;
frm = NULL;
}
}
return new_frm;
}
static void add_format_tail(struct node* list_head, struct node* new_fmt)
{
struct node* cur = list_head;
while (cur->row) {
cur = cur->row;
}
cur->row = new_fmt;
}
static void add_frame_tail(struct node* list_head, int fcc, struct node* new_frm)
{
struct node* frm = NULL;
struct node* fmt = list_head->row;
struct uvc_format_info* fmt_info = NULL;
while (fmt) {
fmt_info = (struct uvc_format_info*)fmt->data;
if (fmt_info->fcc == fcc) {
fmt_info->frm_nums++;
break;
} else {
fmt = fmt->row;
}
}
if (fmt == NULL) {
uvc_loge("Not found format: %d.\n", fcc);
return;
}
frm = fmt;
while (frm->column) {
frm = frm->column;
}
frm->column = new_frm;
}
static void add_format(struct node* list_head, int fcc)
{
struct node* new_fmt = new_format(fcc);
add_format_tail(list_head, new_fmt);
}
static void add_frame(struct node* list_head, int fcc, struct uvc_frame_info frm)
{
struct node* new_frm = new_frame(frm.width, frm.height, frm.intervals[0]);
add_frame_tail(list_head, fcc, new_frm);
}
static char* parser_sub(char* in, char* out, char k)
{
char* tmp = in;
while (1) {
if (*tmp == '\0') {
tmp = NULL;
break;
} else if (*tmp == k) {
/* step k */
tmp++;
break;
} else {
*out++ = *tmp++;
}
}
*out = '\0';
return tmp;
}
static char* parser_format(char* str, char* format)
{
char k = ',';
return parser_sub(str, format, k);
}
static char* parser_frame(char* formats, char* frame)
{
char k = ',';
return parser_sub(formats, frame, k);
}
static int frame_interval(int fps)
{
return ((1000 * 10000) / fps);
}
static void parser_whf(char* frame, struct uvc_frame_info* frm_info)
{
int i;
char param[16];
char* tmp = frame;
char k = '-';
/* width */
bzero(param, sizeof(param));
tmp = parser_sub(tmp, param, k);
frm_info->width = atoi(param);
/* height */
bzero(param, sizeof(param));
tmp = parser_sub(tmp, param, k);
frm_info->height = atoi(param);
/* fps */
i = 0;
do {
bzero(param, sizeof(param));
tmp = parser_sub(tmp, param, k);
if (i == ARRAY_SIZE(frm_info->intervals)) {
break;
}
frm_info->intervals[i++] = frame_interval(atoi(param));
} while (tmp != NULL);
}
static int init_format(char* key)
{
int rc, fcc;
char str[256];
char frame[256];
char format[16];
char stream[32] = "stream:";
char* tmp = NULL;
struct uvc_frame_info frm_info= {0};
strcat(stream, key);
bzero(str, sizeof(str));
rc = get_config_string(stream, str, sizeof(str));
if (rc < 0) {
uvc_logd("Not found %s\n", stream);
return -1;
}
tmp = (char*)str;
bzero(format, sizeof(format));
tmp = parser_format(tmp, format);
if (tmp == NULL) {
uvc_loge("parser_format fail\n");
return 0;
}
uvc_logd("Format %s: %s\n", format, tmp);
fcc = string_to_fcc(format);
add_format(&g_formats_list_head, fcc);
do {
bzero(frame, sizeof(frame));
tmp = parser_frame(tmp, frame);
parser_whf(frame, &frm_info);
add_frame(&g_formats_list_head, fcc, frm_info);
} while (tmp != NULL);
return 0;
}
static int frame_min(int* fmt_index, int* frm_index)
{
*fmt_index = 1;
*frm_index = 1;
uvc_logd("Format min {format %d, frame %d}\n", *fmt_index, *frm_index);
return 0;
}
static int frame_max(int* fmt_index, int* frm_index)
{
struct node* list_head = &g_formats_list_head;
struct node* tmp = list_head;
int index;
index = 0;
while (tmp->row) {
tmp = tmp->row;
index++;
}
*fmt_index = index;
index = 0;
while (tmp->column) {
tmp = tmp->column;
index++;
}
*frm_index = index;
uvc_logd("Format max {format %d, frame %d}\n", *fmt_index, *frm_index);
return 0;
}
int find_frame(int* fmt_index, int* frm_index, int* fcc, struct uvc_frame_info* frame)
{
struct node* list_head = &g_formats_list_head;
struct node* tmp = list_head;
struct uvc_format_info* fmt = NULL;
struct uvc_frame_info* frm = NULL;
int index;
if (list_head->row == NULL) {
uvc_loge("UVC formats is not initialized.\n");
return -1;
}
if (*fmt_index == 0) {
frame_min(fmt_index, frm_index);
} else if (*fmt_index < 0) {
frame_max(fmt_index, frm_index);
}
if (frame == NULL || fcc == NULL) {
return 0;
}
/* Find format */
index = *fmt_index;
while (index-- && tmp) {
tmp = tmp->row;
}
if (tmp == NULL) {
uvc_logw("Not found {format %d , frame %d }, Use {format 1, frame 1}\n", *fmt_index, *frm_index);
show_formats_info();
fflush(stdout);
*fmt_index = 1;
*frm_index = 1;
return find_frame(fmt_index, frm_index, fcc, frame);
}
fmt = (struct uvc_format_info*)tmp->data;
*fcc = fmt->fcc;
/* Find frame */
index = *frm_index;
while (index-- && tmp) {
tmp = tmp->column;
}
if (tmp == NULL) {
uvc_logw("Not found {format %d, frame %d}, Use {format %d, frame 1}\n", *fmt_index, *frm_index, *fmt_index);
show_formats_info();
fflush(stdout);
*frm_index = 1;
return find_frame(fmt_index, frm_index, fcc, frame);
}
frm = (struct uvc_frame_info*)tmp->data;
memcpy(frame, frm, sizeof(struct uvc_frame_info));
uvc_logd("Find {format %d, frame %d} : %s, %dx%d @ %d\n", *fmt_index, *frm_index,
fcc_to_string(*fcc), frame->width, frame->height, frame->intervals[0]);
return 0;
}
void uvc_formats_init(void)
{
int i, ret;
char key[16];
i = 0;
do {
bzero(key, sizeof(key));
i++;
snprintf(key, sizeof(key), "fmt%d", i);
ret = init_format(key);
} while (ret == 0);
}
void uvc_formats_deinit(void)
{
struct node* list_head = &g_formats_list_head;
struct node* row = list_head->row;
struct node* tmp = NULL;
struct node* column = NULL;
while (row) {
list_head->row = row->row;
/* release resources */
column = row;
while (column) {
tmp = column->column;
free(column->data);
g_malloc_count--;
free(column);
g_malloc_count--;
column = tmp;
}
row = list_head->row;
}
if (g_malloc_count) {
uvc_logw("Resource leakage.\n");
} else {
uvc_logi("Release resources ok.\n");
}
}
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
/*
* uvc formats
*/
#ifndef __UVC_FORMATS_H__
#define __UVC_FORMATS_H__
#include <linux/videodev2.h>
#if 1
struct uvc_frame_info {
unsigned int width;
unsigned int height;
unsigned int intervals[8];
};
struct uvc_format_info {
unsigned int fcc;
unsigned int frm_nums;
const struct uvc_frame_info* frames;
};
void uvc_formats_init(void);
void uvc_formats_deinit(void);
int find_frame(int* fmt_index, int* frm_index, int* fcc, struct uvc_frame_info* frame);
#else
struct uvc_frame_info {
unsigned int width;
unsigned int height;
unsigned int intervals[8];
};
struct uvc_format_info {
unsigned int fcc;
const struct uvc_frame_info* frames;
};
static const struct uvc_frame_info uvc_frames_yuv[] = {
{ 640, 360, {333333, 0 }, },
{ 1280, 720, {333333, 0 }, },
{ 1920, 1080, {333333, 0 }, },
{ 3840, 2160, {333333, 0 }, },
{ 0, 0, { 0, }, },
};
static const struct uvc_frame_info uvc_frames_mjpeg[] = {
{ 640, 360, {333333, 0 }, },
{ 1280, 720, {333333, 0 }, },
{ 1920, 1080, {333333, 0 }, },
{ 3840, 2160, {333333, 0 }, },
{ 0, 0, { 0, }, },
};
static const struct uvc_frame_info uvc_frames_h264[] = {
{ 640, 360, {333333, 0 }, },
{ 1280, 720, {333333, 0 }, },
{ 1920, 1080, {333333, 0 }, },
{ 3840, 2160, {333333, 0 }, },
{ 0, 0, { 0, }, },
};
static const struct uvc_format_info uvc_formats[] = {
{V4L2_PIX_FMT_YUYV, uvc_frames_yuv},
{V4L2_PIX_FMT_MJPEG, uvc_frames_mjpeg},
{V4L2_PIX_FMT_H264, uvc_frames_h264},
};
#endif
#endif
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __UVC_HAL_H__
#define __UVC_HAL_H__
#include <stdint.h>
#include <linux/usb/g_uvc.h>
#include <linux/usb/video.h>
typedef struct uvc_probe_t {
unsigned char set;
unsigned char get;
unsigned char max;
unsigned char min;
} uvc_probe_t;
struct uvc_device {
int fd;
int streaming;
unsigned int req;
unsigned int control;
unsigned int unit_id;
unsigned int interface_id;
unsigned int fcc;
unsigned int width;
unsigned int height;
unsigned int fps;
unsigned int bulk;
unsigned int bulk_size;
unsigned int nbufs;
unsigned int imgsize;
unsigned int max_payload_size;
unsigned char color;
/* USB speed specific */
int mult;
int burst;
int maxpkt;
enum usb_device_speed speed;
uvc_probe_t probe_status;
struct uvc_streaming_control probe;
struct uvc_streaming_control commit;
struct uvc_request_data request_error_code;
};
int open_uvc_device();
int close_uvc_device();
int run_uvc_device();
int run_uvc_data();
#endif //__UVC_HAL_H__
+292
View File
@@ -0,0 +1,292 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <linux/videodev2.h>
#include <linux/usb/ch9.h>
#include <linux/usb/video.h>
#include "uvc_log.h"
#include "uvc_adapter.h"
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* +++++++++++++++++++ Requests infos +++++++++++++++++++++++++++
*/
/* 4.2.2.1 Camera Terminal Control Requests */
static char* vc_camera_terminal_cs(unsigned char cs_code)
{
switch (cs_code) {
case UVC_CT_SCANNING_MODE_CONTROL:
return "Sanning Mode";
case UVC_CT_AE_MODE_CONTROL:
return "Auto-Exposure Mode";
case UVC_CT_AE_PRIORITY_CONTROL:
return "Auto-Exposure Priority";
case UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
return "Exposure Time(Absolute)";
case UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL:
return "Exposure Time(Relative)";
case UVC_CT_FOCUS_ABSOLUTE_CONTROL:
return "Focus(Absolute)";
case UVC_CT_FOCUS_RELATIVE_CONTROL:
return "Focus(Relative)";
case UVC_CT_FOCUS_AUTO_CONTROL:
return "Focus(Auto)";
case UVC_CT_IRIS_ABSOLUTE_CONTROL:
return "Iris(Absolute)";
case UVC_CT_IRIS_RELATIVE_CONTROL:
return "Iris(Relative)";
case UVC_CT_ZOOM_ABSOLUTE_CONTROL:
return "Zoom(Absolute)";
case UVC_CT_ZOOM_RELATIVE_CONTROL:
return "Zoom(Relative)";
case UVC_CT_PANTILT_ABSOLUTE_CONTROL:
return "PanTilt(Absolute)";
case UVC_CT_PANTILT_RELATIVE_CONTROL:
return "PanTilt(Relative)";
case UVC_CT_ROLL_ABSOLUTE_CONTROL:
return "Roll(Absolute)";
case UVC_CT_ROLL_RELATIVE_CONTROL:
return "Roll(Relative)";
case UVC_CT_PRIVACY_CONTROL:
return "Privacy Shutter";
case UVC_CT_CONTROL_UNDEFINED:
default:
return "Invalid control";
}
}
/* 4.2.2.2 Selector Unit Control Requests */
static char* vc_selector_unit_cs(unsigned char cs_code)
{
switch (cs_code) {
case UVC_SU_INPUT_SELECT_CONTROL:
return "Selector Unit";
case UVC_SU_CONTROL_UNDEFINED:
default:
return "Invalid control";
}
}
/* 4.2.2.3 Processing Unit Control Requests */
static char* vc_processing_unit_cs(unsigned char cs_code)
{
switch (cs_code) {
case UVC_PU_BACKLIGHT_COMPENSATION_CONTROL:
return "Backlight compensation";
case UVC_PU_BRIGHTNESS_CONTROL:
return "Brightness";
case UVC_PU_CONTRAST_CONTROL:
return "Contrast";
case UVC_PU_GAIN_CONTROL:
return "Gain";
case UVC_PU_POWER_LINE_FREQUENCY_CONTROL:
return "Power Line Frequency";
case UVC_PU_HUE_CONTROL:
return "Hue";
case UVC_PU_HUE_AUTO_CONTROL:
return "Hue,Auto";
case UVC_PU_SATURATION_CONTROL:
return "Saturation";
case UVC_PU_SHARPNESS_CONTROL:
return "Sharpness";
case UVC_PU_GAMMA_CONTROL:
return "Gamma";
case UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL:
return "White Balance Temperature";
case UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
return "White Balance Temperature,Auto";
case UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL:
return "White Balance Component";
case UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL:
return "White Balance Component,Auto";
case UVC_PU_DIGITAL_MULTIPLIER_CONTROL:
return "Digital Multiplier";
case UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL:
return "Digital Multiplier Limit";
case UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL:
return "Analog Video Standard";
case UVC_PU_ANALOG_LOCK_STATUS_CONTROL:
return "Analog Video Lock Status";
case UVC_PU_CONTROL_UNDEFINED:
default:
return "Invalid control";
}
}
/* 4.2.2.4 Extension Unit Control Requests */
static char* vc_extension_unit_h264_cs(unsigned char cs_code)
{
return "Invalid control";
}
/* 4.2.1 Intercace Control Requests */
static char* vc_interface_cs(unsigned char cs_code)
{
switch (cs_code) {
case UVC_VC_VIDEO_POWER_MODE_CONTROL:
return "Device Power Mode";
case UVC_VC_REQUEST_ERROR_CODE_CONTROL:
return "Request Error Code Control";
case UVC_VC_CONTROL_UNDEFINED:
default:
return "Invalid control";
}
}
/* 4.3.1 Interface Control Requests */
static char* vs_interface_cs(unsigned char cs_code)
{
switch (cs_code) {
case UVC_VS_PROBE_CONTROL:
return "Video Probe";
case UVC_VS_COMMIT_CONTROL:
return "Video Commit";
case UVC_VS_STILL_PROBE_CONTROL:
return "Video Still Probe";
case UVC_VS_STILL_COMMIT_CONTROL:
return "Video Still Commit";
case UVC_VS_STILL_IMAGE_TRIGGER_CONTROL:
return "Still Image Trigger";
case UVC_VS_STREAM_ERROR_CODE_CONTROL:
return "Stream Error Code";
case UVC_VS_GENERATE_KEY_FRAME_CONTROL:
return "Generate Key Frame";
case UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL:
return "Update Frame Segment";
case UVC_VS_SYNC_DELAY_CONTROL:
return "Sync Delay";
case UVC_VS_CONTROL_UNDEFINED:
default:
return "Invalid control";
}
}
/* 4.2.2 Unit and Terminal Control Requests */
static char* vc_entity_name(unsigned char entity_id)
{
switch (entity_id) {
case UVC_CAMERA_TERMINAL_ID:
return "Camera Terminal";
case UVC_PROCESSING_UNIT_ID:
return "Processing Unit";
case UVC_OUTPUT_TERMINAL_ID:
return "Output Terminal";
case UVC_SELECTOR_UNIT_ID:
return "Selector Unit";
case UVC_EXTENSION_UNIT_H264_ID:
return "Extension Unit H264";
default:
return "Invalid Unit";
}
}
static char* control_entity_cs(unsigned char entity_id, unsigned char cs_code)
{
switch (entity_id) {
case UVC_CAMERA_TERMINAL_ID:
return vc_camera_terminal_cs(cs_code);
case UVC_PROCESSING_UNIT_ID:
return vc_processing_unit_cs(cs_code);
case UVC_OUTPUT_TERMINAL_ID:
return "Unsupported unit";
case UVC_SELECTOR_UNIT_ID:
return vc_selector_unit_cs(cs_code);
case UVC_EXTENSION_UNIT_H264_ID:
return vc_extension_unit_h264_cs(cs_code);
default:
return "Invalid unit";
}
}
/* 4.2.1 Intercace Control Requests */
/* 4.3.1 Interface Control Requests */
static char* control_interface_name(unsigned char interface_id)
{
switch (interface_id) {
case UVC_VS_INTERFACE_ID:
return "VS Interface";
case UVC_VC_INTERFACE_ID:
return "VC Interface";
default:
return "Invalid Interface";
}
}
static char* control_interface_cs(unsigned char interface_id, unsigned char cs_code)
{
switch (interface_id) {
case UVC_VC_INTERFACE_ID:
return vc_interface_cs(cs_code);
case UVC_VS_INTERFACE_ID:
return vs_interface_cs(cs_code);
default:
return "Invalid Interface";
}
}
/* 4.1 Requests Layout */
static char* request_name(unsigned char req_id)
{
switch (req_id) {
case UVC_SET_CUR:
return "Set Cur";
case UVC_GET_CUR:
return "Get Cur";
case UVC_GET_MIN:
return "Get Min";
case UVC_GET_MAX:
return "Get Max";
case UVC_GET_RES:
return "Get Res";
case UVC_GET_LEN:
return "Get Len";
case UVC_GET_INFO:
return "Get Info";
case UVC_GET_DEF:
return "Get Def";
case UVC_RC_UNDEFINED:
default:
return "Invalid request";
}
}
/* +++++++++++++++++++ Requests infos +++++++++++++++++++++++++++
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
/* Requests Debug */
/*
* Node: f_uvc.c 中定义 entity_id,各entity的ID不会为0;
* f_uvc.c 中定义 video control interface 为 0;
* f_uvc.c 中定义 video streaming interface 为1;
*/
void uvc_requests_infos(struct usb_ctrlrequest* ctrl)
{
// unit_id != 0, video Control
unsigned char entity_id = MASK_ENTITY_ID(ctrl);
// interface_id == 0 : video control interface
// interface_id == 1 : video streaming interface
unsigned char interface_id = MASK_INTF_ID(ctrl);
unsigned char cs_code = MASK_CS_CODE(ctrl);
unsigned char req_id = MASK_REQ_CODE(ctrl);
uvc_logd("reqeust type : INTERFACE.\n");
uvc_logd("class-specific : 0x%02x(%s).\n",
interface_id, interface_id ? "Video Streaming" : "Video Control");
if (entity_id) {
uvc_logd("entity id : 0x%02x(%s)\n", entity_id, vc_entity_name(entity_id));
uvc_logd("control selector : 0x%02x(%s)\n", cs_code, control_entity_cs(entity_id, cs_code));
} else {
uvc_logd("interface : 0x%02x(%s)\n", interface_id, control_interface_name(interface_id));
uvc_logd("control selector : 0x%02x(%s)\n", cs_code, control_interface_cs(interface_id, cs_code));
}
uvc_logd("requests : 0x%02x(%s)\n",req_id, request_name(req_id));
}
+265
View File
@@ -0,0 +1,265 @@
#include <stdio.h>
#include <string.h>
#define MARK_SOI 0xFFD8
#define MARK_APP0 0xFFE0
#define MARK_DQT 0xFFDB
#define MARK_SOF0 0xFFC0
#define MARK_DHT 0xFFC4
#define MARK_SOS 0xFFDA
#define MARK_DRI 0xFFDD
#define MARK_DOI 0xFFD9
#define SPLIT_DHT 1
/* 7205 7606, There are 3 quantitative tables (DQT0 DQT1 DQT2)
* 7203 7206, There are 2 quantitative tables (DQT0 DQT1) */
#define REMOVE_DQT2 0
#define REMOVE_DRI 1
/*
* Delete DRI field in JPEG, delete quantization table 2 (DQT2), split Huffman table.
*/
void memcpy_jpeg_user(unsigned char* src_buffer, unsigned int src_len,
unsigned char* dest_buffer, unsigned int dest_length, unsigned int* dest_offset)
{
unsigned int mark, sec_len;
unsigned int copy_size;
unsigned int src_off = 0;
unsigned int dst_len = dest_length;
unsigned int dst_off = *dest_offset;
unsigned char* src_buf = src_buffer;
unsigned char* dst_buf = (dest_buffer + dst_off);
while ((src_len - src_off) > 0) {
mark = ((src_buf[0] << 8) | src_buf[1]);
sec_len = ((src_buf[2] << 8) | src_buf[3]);
switch (mark) {
case MARK_SOI:
//printf("MARK_SOI\n");
/* copy SOI */
copy_size = 2;
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += 2;
src_off += 2;
dst_buf += copy_size;
dst_off += copy_size;
break;
case MARK_APP0:
/* copy APP0 */
//printf("MARK_APP0\n");
copy_size = (2 + sec_len);
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
break;
case MARK_DQT:
//printf("MARK_DQT\n");
copy_size = (2 + sec_len);
#if REMOVE_DQT2
/* Delete the third quantification table */
/* After JPEG encoding on the Xmdeia platform, there are 3 quantization tables,
* while some decoding platforms only support 2 quantization tables.*/
if ((dst_len - dst_off) > copy_size) {
/* copy DQT0 and refactoring DQT */
dst_buf[0] = 0xFF;
dst_buf[1] = 0xDB;
dst_buf[2] = 0x00;
dst_buf[3] = 0x43;
dst_buf[4] = 0x00; /* DQT0 */
dst_buf += 5;
dst_off += 5;
src_buf += 5;
memcpy(dst_buf, src_buf, 0x40); /* 0x40: DQT0 size */
dst_buf += 0x40;
dst_off += 0x40;
src_buf += 0x40;
/* copy DQT1 and refactoring DQT*/
dst_buf[0] = 0xFF;
dst_buf[1] = 0xDB;
dst_buf[2] = 0x00;
dst_buf[3] = 0x43;
dst_buf[4] = 0x01; /* DQT1 */
dst_buf += 5;
dst_off += 5;
src_buf += 1;
memcpy(dst_buf, src_buf, 0x40); /* 0x40: DQT1 size */
dst_buf += 0x40;
dst_off += 0x40;
src_buf += 0x40;
#if 0
/* remove DQT2 */
src_buf += 0x41;
src_off += (2 + sec_len);
#endif
} else {
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
}
#else
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
#endif
break;
case MARK_SOF0:
//printf("MARK_SOF0\n");
copy_size = (2 + sec_len);
#if 0
/* copy SOF0 and refactoring DQT */
if ((dst_len - dst_off) > copy_size) {
memcpy(dst_buf, src_buf, copy_size);
dst_buf[copy_size - 1] = 0x01; /* refactoring DQT info */
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
} else {
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
}
#else
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
#endif
break;
case MARK_DHT:
/* copy DHT*/
//printf("MARK_DHT\n");
copy_size = (2 + sec_len);
#if SPLIT_DHT
/* Split Huffman table */
/* The Huffman table encoded by JPEG on the XMedia platform consists of four sets in a single DHT.
* Some decoding platforms do not support this and need to split it into four sets */
if ((dst_len - dst_off) > copy_size) {
/* copy DHT0 */
dst_buf[0] = 0xFF;
dst_buf[1] = 0xC4;
dst_buf[2] = 0x00;
dst_buf[3] = 0x1F;
dst_buf += 4;
dst_off += 4;
src_buf += 4;
copy_size = 0x1F - 2;
memcpy(dst_buf, src_buf, copy_size);
dst_buf += copy_size;
dst_off += copy_size;
src_buf += copy_size;
/* copy DHT1 */
dst_buf[0] = 0xFF;
dst_buf[1] = 0xC4;
dst_buf[2] = 0x00;
dst_buf[3] = 0xB5;
dst_buf += 4;
dst_off += 4;
copy_size = 0xB5 - 2;
memcpy(dst_buf, src_buf, copy_size);
dst_buf += copy_size;
dst_off += copy_size;
src_buf += copy_size;
/* copy DHT2 */
dst_buf[0] = 0xFF;
dst_buf[1] = 0xC4;
dst_buf[2] = 0x00;
dst_buf[3] = 0x1F;
dst_buf += 4;
dst_off += 4;
copy_size = 0x1F - 2;
memcpy(dst_buf, src_buf, copy_size);
dst_buf += copy_size;
dst_off += copy_size;
src_buf += copy_size;
/* copy DHT3 */
dst_buf[0] = 0xFF;
dst_buf[1] = 0xC4;
dst_buf[2] = 0x00;
dst_buf[3] = 0xB5;
dst_buf += 4;
dst_off += 4;
copy_size = 0xB5 - 2;
memcpy(dst_buf, src_buf, copy_size);
dst_buf += copy_size;
dst_off += copy_size;
src_buf += copy_size;
src_off += (2 + sec_len);
} else {
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
}
#else
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
#endif
break;
case MARK_DRI:
//printf("MARK_DRI\n");
copy_size = (2 + sec_len);
#if REMOVE_DRI
/* remove DRI */
src_buf += copy_size;
src_off += copy_size;
#else
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
src_buf += (2 + sec_len);
src_off += (2 + sec_len);
dst_buf += copy_size;
dst_off += copy_size;
#endif
break;
case MARK_SOS:
/* copy SOS */
//printf("MARK_SOS\n");
case MARK_DOI:
/* copy DOI */
default:
/* copy data */
copy_size = src_len - src_off;
copy_size = ((dst_len - dst_off) > copy_size) ? copy_size : (dst_len - dst_off);
memcpy(dst_buf, src_buf, copy_size);
dst_off += copy_size;
*dest_offset = dst_off;
return;
}
}
*dest_offset = dst_off;
}
@@ -0,0 +1,199 @@
#include <stdio.h>
#include <string.h>
/* 序号 字段 字节 说明
* 0 标识码 2 0xFFE1 ~ 0xFFEF
* 1 数据长度 2 字段长度,不包括标识码,但包括本字段。JPEG标志定义,解码器可以根据长度跳过此标识段
* 2 视频信息 1 码流格式, H264:0x01
* 3 视频帧率 1 每秒帧数,如25表示25FPS
* 4 保留信息 6 预留字段,默认都为0x00
* 5 视频数据长度 2 视频数据字段长度,包括本字段
* 6 视频数据 n 视频数据字节数 = (视频数据长度 - 2)
*
* 说明:每个字段(0xFFEX)仅支持填充(65535 - 12)字节数据。该封装协议支持最大填充(65523 * 15)字节数据
*/
#define PROCOTOL_HEAD_SIZE 14
#define SECTIONS_NUMS 9
#define SECTIONS_SIZE (65535 - 12)
#define APP1 0xFFE7
static unsigned char* fill_protocol_head(unsigned char* out, unsigned short id, unsigned char fps, unsigned short video_len)
{
unsigned char* pout = out;
unsigned short val;
// Identification code
val = id;
*pout++ = (unsigned char)((val >> 8) & 0xFF);
*pout++ = (unsigned char)(val & 0xFF);
// Data length
val = 12 + video_len;
*pout++ = (unsigned char)((val >> 8) & 0xFF);
*pout++ = (unsigned char)(val & 0xFF);
// Video information
*pout++ = (unsigned char)0x01; // 0x01: H264
// FPS
*pout++ = fps;
// Reserve
memset(pout, 0, 6);
pout += 6;
// Video data length
val = video_len + 2;
*pout++ = (unsigned char)((val >> 8) & 0xFF);
*pout++ = (unsigned char)(val & 0xFF);
return pout;
}
static unsigned int merge_h264_to_jpeg(unsigned char* out, unsigned char* frame_h264,
unsigned int size_h264, unsigned short fps)
{
unsigned int size;
unsigned short i;
unsigned char* pout = out;
unsigned char* psrc = frame_h264;
unsigned short id = (unsigned short)APP1;
unsigned short sec_size = SECTIONS_SIZE;
unsigned short sections = size_h264 / sec_size;
unsigned short remaining = size_h264 % sec_size;
size = 0;
for (i = 0; i < sections; i++) {
pout = fill_protocol_head(pout, id, fps, sec_size);
// fill frame data
memcpy(pout, psrc, sec_size);
pout += sec_size;
psrc += sec_size;
id += 1;
size += (sec_size + PROCOTOL_HEAD_SIZE);
}
if (remaining) {
pout = fill_protocol_head(pout, id, fps, remaining);
// fill frame data
memcpy(pout, psrc, remaining);
pout += remaining;
id += 1;
size += (remaining + PROCOTOL_HEAD_SIZE);
}
//printf("merge h264 size(%u) to jpeg ok.\n", size);
return size;
}
static unsigned char* refactoring_jpeg(unsigned char* frame_jpeg, unsigned int size_jpeg, unsigned int len_jpeg, unsigned int size_h264)
{
unsigned char* ph264_start = NULL;
unsigned char* pjpeg_old = NULL;
unsigned char* pjpeg_new = NULL;
unsigned int size;
unsigned int move_size;
unsigned int h264_pack_size, total_pack_size;
unsigned int sections_num;
sections_num = (size_h264 / SECTIONS_SIZE);
if (size_h264 % SECTIONS_SIZE) {
sections_num += 1;
}
h264_pack_size = (sections_num * PROCOTOL_HEAD_SIZE) + size_h264;
total_pack_size = h264_pack_size + size_jpeg;
if ((total_pack_size > len_jpeg) || (sections_num > SECTIONS_NUMS)) {
printf("[ERROR] H264 frame is too large, I will drop it!\n");
return NULL;
}
ph264_start = frame_jpeg;
// skip 0xFFD8 and 0xFFE0
ph264_start += 4;
// skip APP0 字段
size = (ph264_start[0] << 8) & 0xFF00;
size += (ph264_start[1] & 0xFF);
ph264_start += size;
// Move the data after 'APP0 field' and leave space for H264
pjpeg_old = ph264_start;
pjpeg_new = (pjpeg_old + h264_pack_size);
move_size = size_jpeg - 4 - size;
memmove(pjpeg_new, pjpeg_old, move_size);
return ph264_start;
}
/* @brief Package a frame of H264 into mjpeg
*
* @param [in, out] frame_jpeg Mjpeg frame buffer address
* @param [in] size_jpeg Mjpeg frame size
* @param [in] len_jpeg Mjpeg frame buffer size
* @param [in] frame_h264 H264 frame buffer address
* @param [in] size_h264 H264 frame size
* @param [in] fps H264 FPS
*
* @return The total length of valid data in frame_jpeg.
*/
unsigned int pack_h264_to_jpeg(unsigned char* frame_jpeg, unsigned int size_jpeg, unsigned int len_jpeg,
unsigned char* frame_h264, unsigned int size_h264, unsigned int fps)
{
unsigned int ret, total_size;
unsigned char* ph264 = NULL;
total_size = size_jpeg;
ph264 = refactoring_jpeg(frame_jpeg, size_jpeg, len_jpeg, size_h264);
if (ph264 == NULL) {
return total_size;
}
ret = merge_h264_to_jpeg(ph264, frame_h264, size_h264, (unsigned short)fps);
total_size += ret;
return total_size;
}
#if 0
static void dexdump(const unsigned char* str, unsigned int size)
{
unsigned int i;
for (i = 0; i < size; i++) {
printf("0x%02X, ", str[i]);
}
printf("\n");
}
int main(unsigned int argc, unsigned char* argv[])
{
unsigned char frame_jpeg[2048] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46,
0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0xC5,
0x00, 0x28, 0x1C, 0x1E, 0x23, 0x1E, 0x19, 0x28,
0x23, 0x21, 0x23, 0x2D, 0x2B, 0x28, 0x30, 0x3C};
unsigned char frame_h264[61];
unsigned char i;
unsigned int size;
for (i = 0; i < sizeof(frame_h264); i++) {
frame_h264[i] = i;
}
size = pack_h264_to_jpeg(frame_jpeg, 40, 1024, frame_h264, sizeof(frame_h264), 15);
dexdump(frame_jpeg, size);
return 0;
}
#endif
+321
View File
@@ -0,0 +1,321 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "video_stream.h"
#include "sample_video.h"
#include "sample_video_yuv.h"
#include "sample_video_mjpeg.h"
#include "sample_video_h264.h"
#include "sample_video_mjpeg_h264.h"
#include "venc_log.h"
#include "frame_cache.h"
#define XMEDIA_ACCESS_ENABLE 1
#define EMBEDDING_H24_IN_MJPEG 0
#if !XMEDIA_ACCESS_ENABLE
#define STREAM_FILE_PATH "./stream.bin"
#endif
#define v4l2_fourcc(a, b, c, d) \
((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */
#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */
#define V4L2_PIX_FMT_H265 v4l2_fourcc('H', '2', '6', '5') /* H265 with start codes */
static int g_start = 0;
static struct encoder_property g_encoder_property;
static xmedia_payload_type format_v4l2_to_mpp(uint32_t fcc)
{
xmedia_payload_type t;
switch (fcc) {
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_MJPEG:
t = PT_MJPEG;
break;
case V4L2_PIX_FMT_H264:
t = PT_H264;
break;
case V4L2_PIX_FMT_H265:
t = PT_H265;
break;
default:
t = PT_MJPEG;
break;
}
return t;
}
static void pic_format_convert(xmedia_payload_type *format)
{
*format = format_v4l2_to_mpp(g_encoder_property.format);
}
static void pic_size_convert(xmedia_video_size *wh)
{
wh->width = g_encoder_property.width;
wh->height = g_encoder_property.height;
}
void get_user_format(xmedia_payload_type *format, xmedia_video_size *wh, unsigned int *framerate)
{
if (wh != NULL) {
pic_size_convert(wh);
}
if (format != NULL) {
pic_format_convert(format);
}
if (framerate != NULL) {
*framerate = g_encoder_property.fps;
}
}
/*******************************************************
* Processing Unit Operation Functions
*******************************************************/
/* Processing Unit Operation Functions End */
/*******************************************************
* Input Terminal Operation Functions
*******************************************************/
/* Input Terminal Operation Functions End */
/*******************************************************
* Stream Control Operation Functions
*******************************************************/
static int sample_video_stream_set_idr(void)
{
return 0;
}
static int sample_video_stream_init(void)
{
return 0;
}
static int sample_video_stream_deinit(void)
{
return 0;
}
#if !XMEDIA_ACCESS_ENABLE
static int g_stop = 0;
static pthread_t send_pid = -1;
static void* send_process(void* args)
{
FILE *fp = fopen(STREAM_FILE_PATH, "r");
uvc_cache_t *uvc_cache = NULL;
frame_node_t *fnode = NULL;
g_stop = 0;
while (!g_stop && fp != NULL) {
uvc_cache = uvc_cache_get();
if (uvc_cache) {
get_node_from_queue(uvc_cache->free_queue, &fnode);
}
if (!fnode) {
usleep(100000);
} else {
fseek(fp, 0L, SEEK_SET);
fnode->used = fread((char*)fnode->mem, 1, fnode->length, fp);
venc_logi("send %d\n", fnode->used);
put_node_to_queue(uvc_cache->ok_queue, fnode);
}
}
fclose(fp);
return NULL;
}
static void start_send_file(int fcc)
{
pthread_create(&send_pid, NULL, &send_process, NULL);
}
static void stop_send_file(int fcc)
{
g_stop = 1;
if (send_pid != -1) {
pthread_join(send_pid, NULL);
}
}
#endif
static int sample_video_stream_startup(void)
{
int fcc = g_encoder_property.format;
venc_logi("sample stream startup.\n");
g_start = 1;
#if !XMEDIA_ACCESS_ENABLE
start_send_file(fcc);
#else
switch (fcc) {
case V4L2_PIX_FMT_MJPEG:
#if !EMBEDDING_H24_IN_MJPEG
sample_mjpeg_init();
sample_mjpeg_startup();
#else
sample_mjpeg_h264_init();
sample_mjpeg_h264_startup();
#endif
break;
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_H265:
sample_h264_init();
sample_h264_startup();
break;
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
sample_yuv_init();
sample_yuv_startup(fcc);
break;
default:
venc_loge("Unsupported stream type.\n");
return -1;
}
#endif
venc_logi("sample stream startup ok.\n");
return 0;
}
static int sample_video_stream_shutdown(void)
{
int fcc = g_encoder_property.format;
if (!g_start) {
return 0;
}
#if !XMEDIA_ACCESS_ENABLE
stop_send_file(fcc);
#else
switch (fcc) {
case V4L2_PIX_FMT_MJPEG:
#if !EMBEDDING_H24_IN_MJPEG
sample_mjpeg_shutdown();
#else
sample_mjpeg_h264_shutdown();
#endif
break;
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_H265:
sample_h264_shutdown();
break;
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
sample_yuv_shutdown();
break;
default:
venc_loge("Unsupported stream type.\n");
return -1;
}
#endif
g_start = 0;
return 0;
}
static int sample_video_stream_set_property(struct encoder_property *p)
{
g_encoder_property = *p;
return 0;
}
/* Stream Control Operation Functions End */
static struct stream_control_ops venc_sc_ops = {
.init = &sample_video_stream_init,
.deinit = &sample_video_stream_deinit,
.startup = &sample_video_stream_startup,
.shutdown = &sample_video_stream_shutdown,
.set_idr = &sample_video_stream_set_idr,
.set_property = &sample_video_stream_set_property,
};
static struct processing_unit_ops venc_pu_ops = {
/* get */
.brightness_get = NULL,
.contrast_get = NULL,
.hue_get = NULL,
.power_line_frequency_get = NULL,
.saturation_get = NULL,
.white_balance_temperature_auto_get = NULL,
.white_balance_temperature_get = NULL,
/* set */
.brightness_set = NULL,
.contrast_set = NULL,
.hue_set = NULL,
.power_line_frequency_set = NULL,
.saturation_set = NULL,
.white_balance_temperature_auto_set = NULL,
.white_balance_temperature_set = NULL,
};
static struct input_terminal_ops venc_it_ops = {
/* get */
.exposure_ansolute_time_get = NULL,
.exposure_auto_mode_get = NULL,
/* set */
.exposure_ansolute_time_set = NULL,
.exposure_auto_mode_set = NULL,
};
//static struct extension_unit_ops venc_xu_ops;
void video_stream_register(void)
{
stream_register_mpi_ops(&venc_sc_ops, &venc_pu_ops, &venc_it_ops, NULL);
}
void video_stream_unregister(void)
{
stream_register_mpi_ops(NULL, NULL, NULL, NULL);
}
@@ -0,0 +1,22 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __SAMPLE_VIDEO_H__
#define __SAMPLE_VIDEO_H__
#include "sample_comm.h"
struct encoder_property {
unsigned int format;
unsigned int width;
unsigned int height;
unsigned int fps;
};
void video_stream_register(void);
void video_stream_unregister(void);
void get_user_format(xmedia_payload_type *format, xmedia_video_size *wh, unsigned int *framerate);
#endif
@@ -0,0 +1,851 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "sample_comm.h"
#include "sample_comm_venc.h"
#include "sample_comm_vpss.h"
#include "sample_comm_vi.h"
#include "sample_comm_sys.h"
#include "sample_comm_isp.h"
#include "video_stream.h"
#include "sample_video.h"
#include "sample_video_dual.h"
#include "venc_log.h"
#include "frame_cache.h"
static int g_start = 0;
static pthread_t g_recv_pid;
static sample_venc_getstream_para g_st_param;
//common
struct dual_comm {
sample_comm_sensor_type sensor_type;
sample_comm_video_param video_param;
};
// vi config
struct dual_vi {
xmedia_s32 vi_dev; /* 0:单板SENSOR0; 2:单板SENSOR2 */
xmedia_s32 vi_chn;
xmedia_s32 vi_pipe;
sample_vi_config vi_cfg;
};
// isp config
struct dual_isp {
sample_isp_param isp_param;
};
// vpss config
struct dual_vpss {
xmedia_s32 vpss_pipe;
xmedia_s32 vpss_ichn;
xmedia_s32 vpss_ochn;
sample_vpss_config vpss_cfg;
};
// venc config
struct dual_venc {
xmedia_s32 venc_chn;
sample_venc_config venc_cfg;
};
struct dual_stream {
xmedia_s32 stream_id;
struct dual_comm comm;
struct dual_vi vi;
struct dual_isp isp;
struct dual_vpss vpss;
struct dual_venc venc;
};
#define STREAM_NUMS 4
static struct dual_stream g_stream[STREAM_NUMS];
static void sample_dual_config_comm(struct dual_comm* comm, sample_comm_sensor_type sns_type)
{
comm->sensor_type = sns_type;
comm->video_param.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
comm->video_param.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420;
comm->video_param.data_width = XMEDIA_VIDEO_DATA_WIDTH_8;
comm->video_param.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
}
static void sample_dual_config_vi(struct dual_vi* vi,
xmedia_s32 vi_chn,
xmedia_s32 vi_dev,
xmedia_s32 vi_pipe,
sample_comm_sensor_type sns_type)
{
vi->vi_chn = vi_chn;
vi->vi_dev = vi_dev;
vi->vi_pipe = vi_pipe;
vi->vi_cfg.dev_info[vi_dev].dev_no = vi_dev;
vi->vi_cfg.dev_info[vi_dev].dev_en = XMEDIA_TRUE;
vi->vi_cfg.dev_info[vi_dev].sensor_type = sns_type;
vi->vi_cfg.pipe_info[vi_pipe].pipe_no = vi_pipe;
vi->vi_cfg.pipe_info[vi_pipe].pipe_en = XMEDIA_TRUE;
vi->vi_cfg.pipe_info[vi_pipe].chn_info[vi_chn].chn_no = vi_chn;
vi->vi_cfg.pipe_info[vi_pipe].chn_info[vi_chn].chn_en = XMEDIA_TRUE;
vi->vi_cfg.dev_bind_pipe[vi_dev].pipe[0] = vi_pipe;
vi->vi_cfg.dev_bind_pipe[vi_dev].pipe[1] = -1;
}
static void sample_dual_config_isp(struct dual_isp* isp,
xmedia_s32 vi_pipe,
sample_comm_sensor_type sns_type)
{
xmedia_u32 framerate = 0;
vi_sensor_info sensor_info = {0};
sample_comm_vi_get_sensor_info(sns_type, &sensor_info);
sample_comm_vi_get_framerate_by_sensor(sns_type, &framerate);
// isp config init
isp->isp_param.isp_info[vi_pipe].isp_config.fps = framerate;
isp->isp_param.isp_info[vi_pipe].isp_config.mode_config.work_mode = XMEDIA_ISP_WORK_MODE_MASTER;
isp->isp_param.isp_info[vi_pipe].isp_config.mode_config.master_mode.blend_stat_enable = XMEDIA_FALSE;
isp->isp_param.isp_info[vi_pipe].isp_config.mode_config.master_mode.slave_num = 0;
isp->isp_param.isp_info[vi_pipe].isp_config.pixel_fmt = sensor_info.pixel_format;
isp->isp_param.isp_info[vi_pipe].isp_config.size.height = sensor_info.height;
isp->isp_param.isp_info[vi_pipe].isp_config.size.width = sensor_info.width;
isp->isp_param.isp_info[vi_pipe].isp_config.wdr_mode = sensor_info.wdr_mode;
// isp pipe init
isp->isp_param.pipe[vi_pipe] = vi_pipe;
isp->isp_param.isp_info[vi_pipe].flip = XMEDIA_FALSE;
isp->isp_param.isp_info[vi_pipe].mirror = XMEDIA_FALSE;
isp->isp_param.isp_info[vi_pipe].isp_pipe_en = XMEDIA_TRUE;
isp->isp_param.isp_info[vi_pipe].isp_sensor_en = XMEDIA_TRUE;
isp->isp_param.isp_info[vi_pipe].sensor_type = sns_type;
}
static void sample_dual_config_vpss(struct dual_vpss* vpss,
xmedia_s32 vpss_pipe,
xmedia_s32 vpss_ichn,
xmedia_s32 vpss_ochn)
{
vpss->vpss_pipe = vpss_pipe;
vpss->vpss_ichn = vpss_ichn;
vpss->vpss_ochn = vpss_ochn;
//vpss->vpss_cfg = ;
}
static void sample_dual_config_venc(struct dual_venc* venc,
xmedia_s32 venc_chnl)
{
venc->venc_chn = venc_chnl;
venc->venc_cfg.chn_info[venc_chnl].venc_en = XMEDIA_TRUE;
venc->venc_cfg.chn_info[venc_chnl].venc_chn = venc_chnl;
venc->venc_cfg.chn_info[venc_chnl].payload_type = PT_H264;
venc->venc_cfg.chn_info[venc_chnl].rc_mode = VENC_RC_MODE_H264CBR;
}
static void sammple_dual_stream_config(void)
{
xmedia_s32 id;
xmedia_s32 vi_dev[STREAM_NUMS] = {0, 0, 2, 2};
xmedia_s32 vi_pipe[STREAM_NUMS] = {0, 0, 1, 1};
xmedia_s32 vi_chn[STREAM_NUMS] = {0, 0, 0, 0};
xmedia_s32 vpss_pipe[STREAM_NUMS] = {0, 0, 1, 1};
xmedia_s32 vpss_ichn[STREAM_NUMS] = {0, 0, 0, 0};
xmedia_s32 vpss_ochn[STREAM_NUMS] = {0, 1, 0, 1};
xmedia_s32 venc_chnl[STREAM_NUMS] = {0, 1, 2, 3};
sample_comm_sensor_type sns_type[STREAM_NUMS] = {SENSOR0_TYPE, SENSOR0_TYPE, SENSOR1_TYPE, SENSOR1_TYPE};
for (id = 0; id < STREAM_NUMS; id++) {
g_stream[id].stream_id = id;
sample_dual_config_comm(&g_stream[id].comm, sns_type[id]);
sample_dual_config_vi(&g_stream[id].vi, vi_chn[id], vi_dev[id], vi_pipe[id], sns_type[id]);
sample_dual_config_isp(&g_stream[id].isp, vi_pipe[id], sns_type[id]);
sample_dual_config_vpss(&g_stream[id].vpss, vpss_pipe[id], vpss_ichn[id], vpss_ochn[id]);
sample_dual_config_venc(&g_stream[id].venc, venc_chnl[id]);
}
}
static int sample_dual_sys_init(void)
{
xmedia_s32 ret;
xmedia_s32 id;
xmedia_s32 blk_size, pool_id;
xmedia_s32 vi_pipe;
sample_comm_sensor_type sensor_type;
vi_sensor_info sensor_info = {0};
xmedia_video_size pic_size = {0};
sample_sys_config sys_config = {0};
sample_comm_video_param* video_param = NULL;
func_entry();
sammple_dual_stream_config();
pool_id = 0;
for (id = 0; id < STREAM_NUMS; id++) {
sensor_type = g_stream[id].comm.sensor_type;
sample_comm_vi_get_sensor_info(sensor_type, &sensor_info);
// sys init
vi_pipe = g_stream[id].vi.vi_pipe;
sys_config.sys_conf.pipe_mode[vi_pipe].vicap_viproc_mode = XMEDIA_WORK_MODE_OFFLINE;
sys_config.sys_conf.pipe_mode[vi_pipe].viproc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
sys_config.sys_conf.pipe_mode[vi_pipe].gdc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
venc_logd("resolution: w(%d) x h(%d).\n", pic_size.width, pic_size.height);
video_param = &g_stream[id].comm.video_param;
blk_size = sample_comm_sys_get_buffer_size(pic_size,
video_param->video_fmt,
sensor_info.pixel_format,
sensor_info.bit_width,
video_param->compress_mode);
sys_config.vb_conf.common_pool[pool_id].block_size = blk_size;
sys_config.vb_conf.common_pool[pool_id].block_cnt = 5;
venc_logd("allocate cache pool %d: size(%d) x cnt(%d)\n", pool_id, blk_size, 5);
pool_id++;
blk_size = sample_comm_sys_get_buffer_size(pic_size,
video_param->video_fmt,
video_param->pixel_fmt,
video_param->data_width,
video_param->compress_mode);
sys_config.vb_conf.common_pool[pool_id].block_size = blk_size;
sys_config.vb_conf.common_pool[pool_id].block_cnt = 5;
venc_logd("allocate cache pool %d: size(%d) x cnt(%d)\n", pool_id, blk_size, 5);
pool_id++;
}
sys_config.vb_conf.supplement_config = (1 << 0);
sys_config.vb_conf.supplement_config |= (1 << 1);
ret = sample_comm_sys_init(&sys_config);
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_sys_init failed!\n");
return ret;
}
//in online-online mode,vi and vpss must be reset at the same time
ret = sample_comm_vi_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vi_init failed!\n");
return ret;
}
ret = sample_comm_vpss_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vpss_init failed!\n");
return ret;
}
ret = sample_comm_venc_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_venc_init failed!\n");
return ret;
}
func_success();
return XMEDIA_SUCCESS;
}
static int sample_dual_sys_deinit(void)
{
sample_comm_venc_exit();
sample_comm_vpss_exit();
sample_comm_vi_exit();
sample_comm_sys_exit();
return XMEDIA_SUCCESS;
}
static FILE* fp[4] = {NULL, NULL, NULL, NULL};
char filename[4][32] = {
{"stream_dev.h264"},
{"stream_1.h264"},
{"stream_2.h264"},
{"stream_3.h264"}
};
struct dual_head {
unsigned int id;
unsigned int stream_offset;
unsigned int stream_size;
unsigned char reserve[4];
};
void save_stream(char* stream, int length)
{
int w_actl = 0;
int recv_size = length;
unsigned int offset, size;
unsigned int id = 0;
unsigned char* tmp = (unsigned char*)stream;
struct dual_head* stream_head = NULL;
while (recv_size > 0) {
stream_head = (struct dual_head*)stream;
id = stream_head->id;
offset = stream_head->stream_offset;
size = stream_head->stream_size;
if (id >= STREAM_NUMS) {
printf("Error: Invalid stream id.\n");
return ;
}
//printf("id(%u), off(%u), size(%u)\n", id, offset, size);
tmp += offset;
if (fp[id] != NULL) {
w_actl = fwrite(tmp, 1, size, fp[id]);
}
if (w_actl != size) {
//printf("Warning: exp(%d) != acl(%d).", size, w_actl);
}
tmp += size;
recv_size -= (offset + size);
}
}
static int sample_dual_save_data(xmedia_venc_stream* pst_stream, int id)
{
int i = 0;
xmedia_venc_pack *pst_data = NULL;
unsigned char *s = NULL;
unsigned int data_len = 0;
unsigned int copy_size = 0;
struct dual_head head = {0};
uvc_cache_t *uvc_cache = uvc_cache_get();
frame_node_t *fnode = NULL;
if (uvc_cache) {
get_node_from_queue(uvc_cache->free_queue, &fnode);
}
if (!fnode) {
venc_logd("drop frame.\n");
return XMEDIA_SUCCESS;
}
fnode->used = sizeof(struct dual_head);
head.id = id;
head.stream_offset = sizeof(struct dual_head);
head.stream_size = 0;
for (i = 0; i < pst_stream->pack_count; ++i) {
pst_data = &pst_stream->pack[i];
s = pst_data->vir_addr + pst_data->offset;
data_len = pst_data->len - pst_data->offset;
copy_size = data_len < (fnode->length - fnode->used) ? data_len : (fnode->length - fnode->used);
if (copy_size > 0) {
memcpy(fnode->mem + fnode->used, s, copy_size);
fnode->used += copy_size;
head.stream_size += copy_size;
}
if (data_len > copy_size) {
venc_logw("fnode->length = %u\n", fnode->length);
venc_logw("WARN: missing pack. exp(%u) != act(%u)\n", data_len, copy_size);
}
}
memcpy(fnode->mem, (void*)&head, sizeof(struct dual_head));
//fwrite((char*)(fnode->mem), 1, 16, fp[0]);
if (fp[id] != NULL) {
//fwrite((char*)(fnode->mem + head.stream_offset), 1, head.stream_size, fp[id]);
//save_stream((char*)fnode->mem, fnode->used);
}
venc_logd("send size(%u)\n", fnode->used);
put_node_to_queue(uvc_cache->ok_queue, fnode);
return XMEDIA_SUCCESS;
}
static int sample_dual_save_stream(xmedia_payload_type en_type, xmedia_venc_stream *pst_stream, int id)
{
xmedia_s32 ret = XMEDIA_FAILURE;
if (PT_H264 == en_type) {
ret = sample_dual_save_data(pst_stream, id);
}
return ret;
}
static void* sample_dual_stream_proc(void* arg)
{
xmedia_s32 i;
xmedia_s32 ret = XMEDIA_FAILURE;
xmedia_venc_chn_attr venc_chn_attr;
xmedia_payload_type payload_type[VENC_MAX_CHN_NUM];
sample_venc_getstream_para *param = (sample_venc_getstream_para*)arg;
xmedia_s32 chn_cnt = param->cnt;
struct timeval time_out;
xmedia_venc_stream venc_stream;
xmedia_venc_chn_status stat;
xmedia_u32 venc_mask = 0;
if (chn_cnt >= VENC_MAX_CHN_NUM) {
venc_loge("input venc chn count invaild\n");
return XMEDIA_NULL;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_get_chn_attr(param->venc_chn[i], &venc_chn_attr);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_get_chn_attr chn[%d] failed with %#x!\n", param->venc_chn[i], ret);
return XMEDIA_NULL;
}
payload_type[i] = venc_chn_attr.venc_attr.en_type;
venc_mask |= 1 << param->venc_chn[i];
if (fp[i] == NULL) {
fp[i] = fopen((char*)filename[i], "w+");
}
}
venc_logi("Dual start.\n");
while (param->thread_start) {
time_out.tv_sec = 2;
time_out.tv_usec = 0;
ret = xmedia_venc_select(venc_mask, &time_out);
if (ret == XMEDIA_ERRCODE_INVALID_PARAM || ret == XMEDIA_FAILURE) {
venc_loge("select err\n");
break;
} else if (ret == XMEDIA_ERRCODE_TIMEOUT) {
param->stream_timeout_cnt++;
venc_logd("get venc stream time out, continue. \n");
continue;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_query_status(param->venc_chn[i], &stat);
if (XMEDIA_SUCCESS != ret) {
venc_logd("xmedia_venc_query_status chn[%d] failed with %#x!\n", i, ret);
break;
}
if (0 == stat.cur_packs) {
continue;
}
memset(&venc_stream, 0, sizeof(venc_stream));
venc_stream.pack = (xmedia_venc_pack*)malloc(sizeof(xmedia_venc_pack) * stat.cur_packs);
if (XMEDIA_NULL == venc_stream.pack) {
venc_logd("malloc stream pack failed!\n");
break;
}
venc_stream.pack_count = stat.cur_packs;
ret = xmedia_venc_get_stream(param->venc_chn[i], &venc_stream, XMEDIA_TRUE);
if (XMEDIA_SUCCESS != ret) {
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
venc_loge("xmedia_venc_get_stream failed with %#x!\n", ret);
break;
}
sample_dual_save_stream(payload_type[i], &venc_stream, i);
ret = xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_release_stream failed!\n");
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
break;
}
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
}
}
for (i = 0; i < 4; i++) {
if (fp[i] != NULL) {
fclose(fp[i]);
}
fp[i] = NULL;
}
venc_logi("Dual stream exit.\n");
return NULL;
}
static int sample_dual_start_get_stream()
{
int i, rc;
g_st_param.cnt = STREAM_NUMS;
g_st_param.thread_start = XMEDIA_TRUE;
for (i = 0; i < STREAM_NUMS; i++) {
g_st_param.venc_chn[i] = g_stream[i].venc.venc_chn;
}
rc = pthread_create(&g_recv_pid, NULL, sample_dual_stream_proc, (void*)&g_st_param);
if (rc < 0) {
venc_loge("Create sample_dual_stream_proc failed.\n");
return -1;
}
return 0;
}
static int sample_dual_stop_get_stream(void)
{
if (XMEDIA_TRUE == g_st_param.thread_start) {
g_st_param.thread_start = XMEDIA_FALSE;
pthread_join(g_recv_pid, 0);
}
venc_logi("stop get Dual stream ok.\n");
return 0;
}
static int sample_dual_normalp_classic(void)
{
xmedia_s32 id;
xmedia_s32 ret = XMEDIA_SUCCESS;
xmedia_u32 framerate = 0;
xmedia_video_size pic_size = {0};
xmedia_video_size vpss_ochn_size = {0};
//xmedia_isp_config isp_config = {0};
xmedia_payload_type en_payload = PT_H264;
vi_sensor_info sensor_info = {0};
xmedia_s32 venc_chn_0, venc_chn_1;
xmedia_s32 vi_pipe, vi_chn;
xmedia_s32 vpss_pipe, vpss_ichn, vpss_ochn_0, vpss_ochn_1;
sample_comm_sensor_type sensor_type;
sample_isp_param* isp_param = NULL;
sample_vi_config* vi_config = NULL;
sample_vpss_config* vpss_config = NULL;
sample_venc_config* venc_config = NULL;
sample_comm_video_param* video_param = NULL;
for (id = 0; id < STREAM_NUMS; id++) {
#if 0
g_vi_config.dev_info[g_vi_dev].dev_en = XMEDIA_TRUE;
g_vi_config.dev_info[g_vi_dev].dev_no = g_vi_dev;
g_vi_config.dev_info[g_vi_dev].sensor_type = g_sensor_type;
g_vi_config.pipe_info[g_vi_pipe].pipe_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].pipe_no = g_vi_pipe;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_no = g_vi_chn;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[0] = g_vi_pipe;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[1] = -1;
#endif
sensor_type = g_stream[id].comm.sensor_type;
sample_comm_vi_get_sensor_info(sensor_type, &sensor_info);
sample_comm_vi_get_framerate_by_sensor(sensor_type, &framerate);
pic_size.height = sensor_info.height;
pic_size.width = sensor_info.width;
#if 0
isp_config.fps = framerate;
isp_config.mode_config.work_mode = XMEDIA_ISP_WORK_MODE_MASTER;
isp_config.mode_config.master_mode.blend_stat_enable = XMEDIA_FALSE;
isp_config.mode_config.master_mode.slave_num = 0;
isp_config.pixel_fmt = sensor_info.pixel_format;
isp_config.size.height = sensor_info.height;
isp_config.size.width = sensor_info.width;
isp_config.wdr_mode = sensor_info.wdr_mode;
// isp pipe init
g_isp_param.pipe[g_vi_pipe] = g_vi_pipe;
g_isp_param.isp_info[g_vi_pipe].sensor_type = g_sensor_type;
g_isp_param.isp_info[g_vi_pipe].flip = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].mirror = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].isp_pipe_en = XMEDIA_TRUE;
g_isp_param.isp_info[g_vi_pipe].isp_sensor_en = XMEDIA_TRUE;
memcpy(&(g_isp_param.isp_info[g_vi_pipe].isp_config), &isp_config, sizeof(xmedia_isp_config));
#endif
// isp init
isp_param = &g_stream[id].isp.isp_param;
vi_config = &g_stream[id].vi.vi_cfg;
ret = sample_comm_isp_init(isp_param, vi_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] isp init failed!\n", id);
}
// vi start
vi_config = &g_stream[id].vi.vi_cfg;
video_param = &g_stream[id].comm.video_param;
ret = sample_comm_vi_start(vi_config, video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] start vi failed!\n", id);
}
// isp start
isp_param = &g_stream[id].isp.isp_param;
ret = sample_comm_isp_start(isp_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] start isp failed!\n", id);
}
// vpss config
vpss_pipe = g_stream[id].vpss.vpss_pipe;
vpss_ichn = g_stream[id].vpss.vpss_ichn;
vpss_ochn_0 = g_stream[id].vpss.vpss_ochn;
vpss_ochn_1 = g_stream[id + 1].vpss.vpss_ochn;
vpss_config = &g_stream[id].vpss.vpss_cfg;
video_param = &g_stream[id].comm.video_param;
ret = sample_comm_vpss_get_default_pipe_cfg(&vpss_config->pipe_info[vpss_pipe].pipe_config,
pic_size,
video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] get default pipe cfg failed !\n", id);
}
get_user_format(&en_payload, &pic_size, NULL);
vpss_ochn_size.width = pic_size.width;
vpss_ochn_size.height = pic_size.height;
vpss_config->pipe_info[vpss_pipe].pipe_en = XMEDIA_TRUE;
vpss_config->pipe_info[vpss_pipe].pipe_no = vpss_pipe;
#if 0
vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn].chn_no = vpss_ochn;
vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn].chn_en = XMEDIA_TRUE;
#else
vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn_0].chn_no = vpss_ochn_0;
vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn_0].chn_en = XMEDIA_TRUE;
vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn_1].chn_no = vpss_ochn_1;
vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn_1].chn_en = XMEDIA_TRUE;
#endif
#if 0
ret = sample_comm_vpss_get_default_ochn_cfg(
&vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn].chn_config,
vpss_ochn_size,
video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] get default pipe cfg failed !\n", id);
}
#else
ret = sample_comm_vpss_get_default_ochn_cfg(
&vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn_0].chn_config,
vpss_ochn_size,
video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] get default pipe cfg failed !\n", id);
}
ret = sample_comm_vpss_get_default_ochn_cfg(
&vpss_config->pipe_info[vpss_pipe].chn_info[vpss_ochn_1].chn_config,
vpss_ochn_size,
video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] get default pipe cfg failed !\n", id + 1);
}
#endif
// vpss start
ret = sample_comm_vpss_start(vpss_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] vpss start failed !\n", id);
}
vi_chn = g_stream[id].vi.vi_chn;
vi_pipe = g_stream[id].vi.vi_pipe;
vpss_ichn = g_stream[id].vpss.vpss_ichn;
vpss_pipe = g_stream[id].vpss.vpss_pipe;
ret = sample_comm_sys_vi_bind_vpss(vi_pipe, vi_chn, vpss_pipe, vpss_ichn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] vi bind vpss failed !\n", id);
}
//venc init
venc_chn_0 = g_stream[id].venc.venc_chn;
venc_config = &g_stream[id].venc.venc_cfg;
venc_config->chn_info[venc_chn_0].venc_chn = venc_chn_0;
venc_config->chn_info[venc_chn_0].venc_en = XMEDIA_TRUE;
venc_config->chn_info[venc_chn_0].payload_type = en_payload;
venc_config->chn_info[venc_chn_0].rc_mode = VENC_RC_MODE_H264CBR;
sample_comm_venc_get_default_chn_info(vpss_ochn_size,
framerate,
&venc_config->chn_info[venc_chn_0]);
ret = sample_comm_venc_start(venc_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] venc start failed !\n", id);
}
venc_chn_1 = g_stream[id + 1].venc.venc_chn;
venc_config = &g_stream[id + 1].venc.venc_cfg;
venc_config->chn_info[venc_chn_1].venc_chn = venc_chn_1;
venc_config->chn_info[venc_chn_1].venc_en = XMEDIA_TRUE;
venc_config->chn_info[venc_chn_1].payload_type = en_payload;
venc_config->chn_info[venc_chn_1].rc_mode = VENC_RC_MODE_H264CBR;
sample_comm_venc_get_default_chn_info(vpss_ochn_size,
framerate,
&venc_config->chn_info[venc_chn_1]);
ret = sample_comm_venc_start(venc_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] venc start failed !\n", id);
}
ret = sample_comm_sys_vpss_bind_venc(vpss_pipe, vpss_ochn_0, venc_chn_0);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] vpss bind venc failed !\n", id);
}
ret = sample_comm_sys_vpss_bind_venc(vpss_pipe, vpss_ochn_1, venc_chn_1);
if (ret != XMEDIA_SUCCESS) {
venc_loge("stream[%d] vpss bind venc failed !\n", id);
}
id++;
}
return 0;
}
/*******************************************************
* Processing Unit Operation Functions
*******************************************************/
/* Processing Unit Operation Functions End */
/*******************************************************
* Input Terminal Operation Functions
*******************************************************/
/* Input Terminal Operation Functions End */
/*******************************************************
* Stream Control Operation Functions
*******************************************************/
int sample_dual_set_idr(void)
{
return 0;
}
int sample_dual_init(void)
{
sample_dual_sys_init();
return 0;
}
int sample_dual_startup(void)
{
venc_logi("Dual stream startup.\n");
g_start = 1;
if (sample_dual_normalp_classic() < 0) {
return -1;
}
sample_dual_start_get_stream();
venc_logi("Dual stream startup ok.\n");
return 0;
}
int sample_dual_shutdown(void)
{
xmedia_s32 id;
xmedia_s32 vi_pipe, vi_chn;
xmedia_s32 vpss_pipe, vpss_ichn, vpss_ochn_0, vpss_ochn_1;
xmedia_s32 venc_chn_0, venc_chn_1;
sample_venc_config* venc_config = NULL;
sample_vpss_config* vpss_config = NULL;
sample_isp_param* isp_param = NULL;
sample_vi_config* vi_config = NULL;
if (!g_start) {
return 0;
}
sample_dual_stop_get_stream();
for (id = 0; id < STREAM_NUMS; id++) {
venc_config = &g_stream[id].venc.venc_cfg;
sample_comm_venc_stop(venc_config);
venc_config = &g_stream[id + 1].venc.venc_cfg;
sample_comm_venc_stop(venc_config);
vpss_pipe = g_stream[id].vpss.vpss_pipe;
vpss_ichn = g_stream[id].vpss.vpss_ichn;
vpss_ochn_0 = g_stream[id].vpss.vpss_ochn;
vpss_ochn_1 = g_stream[id + 1].vpss.vpss_ochn;
venc_chn_0 = g_stream[id].venc.venc_chn;
venc_chn_1 = g_stream[id + 1].venc.venc_chn;
sample_comm_sys_vpss_unbind_venc(vpss_pipe, vpss_ochn_0, venc_chn_0);
sample_comm_sys_vpss_unbind_venc(vpss_pipe, vpss_ochn_1, venc_chn_1);
vi_pipe = g_stream[id].vi.vi_pipe;
vi_chn = g_stream[id].vi.vi_chn;
sample_comm_sys_vi_unbind_vpss(vi_pipe, vi_chn, vpss_pipe, vpss_ichn);
vpss_config = &g_stream[id].vpss.vpss_cfg;
sample_comm_vpss_stop(vpss_config);
isp_param = &g_stream[id].isp.isp_param;
sample_comm_isp_stop(isp_param);
vi_config = &g_stream[id].vi.vi_cfg;
sample_comm_vi_stop(vi_config);
sample_comm_isp_exit(isp_param);
id++;
}
sample_dual_sys_deinit();
g_start = 0;
return 0;
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __SAMPLE_VIDEO_DUAL_H__
#define __SAMPLE_VIDEO_DUAL_H__
int sample_dual_set_idr(void);
int sample_dual_init(void);
int sample_dual_startup(void);
int sample_dual_shutdown(void);
#endif
@@ -0,0 +1,561 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "sample_comm.h"
#include "sample_comm_venc.h"
#include "sample_comm_vpss.h"
#include "sample_comm_vi.h"
#include "sample_comm_sys.h"
#include "sample_comm_isp.h"
#include "video_stream.h"
#include "sample_video.h"
#include "sample_video_h264.h"
#include "venc_log.h"
#include "frame_cache.h"
static int g_start = 0;
static pthread_t g_recv_pid;
static sample_venc_getstream_para g_st_param;
//common
static sample_comm_sensor_type g_sensor_type = SENSOR0_TYPE;
static sample_comm_video_param g_video_param = {0};
// vi config
static xmedia_s32 g_vi_dev = 0; /* 0:单板SENSOR0; 2:单板SENSOR2 */
static xmedia_s32 g_vi_chn = 0;
static xmedia_s32 g_vi_pipe = 0;
static sample_vi_config g_vi_config = {0};
// isp config
static sample_isp_param g_isp_param = {0};
// vpss config
static xmedia_s32 g_vpss_pipe = 0;
static xmedia_s32 g_vpss_ichn = 0;
static xmedia_s32 g_vpss_ochn = 0;
static sample_vpss_config g_vpss_config = {0};
// venc config
static xmedia_s32 g_venc_chn = 0;
static sample_venc_config g_venc_config = {0};
static int sample_h264_sys_init(int sensor_type)
{
xmedia_s32 ret, idx;
xmedia_s32 blk_size = 0;
vi_sensor_info sensor_info = {0};
xmedia_video_size pic_size = {0};
sample_sys_config sys_config = {0};
func_entry();
g_video_param.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
g_video_param.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420;
g_video_param.data_width = XMEDIA_VIDEO_DATA_WIDTH_8;
g_video_param.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
sample_comm_vi_get_sensor_info(sensor_type, &sensor_info);
// sys init
sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].gdc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
idx = 0;
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode == XMEDIA_WORK_MODE_OFFLINE) {
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, sensor_info.pixel_format,
sensor_info.bit_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 2;
idx++;
}
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode == XMEDIA_WORK_MODE_OFFLINE) {
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
idx++;
}
get_user_format(NULL, &pic_size, NULL);
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
idx++;
sys_config.vb_conf.supplement_config = (1 << 0);
sys_config.vb_conf.supplement_config |= (1 << 1);
ret = sample_comm_sys_init(&sys_config);
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_sys_init failed!\n");
return ret;
}
//in online-online mode,vi and vpss must be reset at the same time
ret = sample_comm_vi_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vi_init failed!\n");
return ret;
}
ret = sample_comm_vpss_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vpss_init failed!\n");
return ret;
}
ret = sample_comm_venc_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_venc_init failed!\n");
return ret;
}
func_success();
return XMEDIA_SUCCESS;
}
static int sample_h264_sys_deinit(void)
{
sample_comm_venc_exit();
sample_comm_vpss_exit();
sample_comm_vi_exit();
sample_comm_sys_exit();
return XMEDIA_SUCCESS;
}
static int sample_h264_save_data(xmedia_venc_stream* pst_stream)
{
int i = 0;
xmedia_venc_pack *pst_data = NULL;
unsigned char *s = NULL;
unsigned int data_len = 0;
unsigned int copy_size = 0;
uvc_cache_t *uvc_cache = uvc_cache_get();
frame_node_t *fnode = NULL;
if (uvc_cache) {
get_node_from_queue(uvc_cache->free_queue, &fnode);
}
if (!fnode) {
venc_logd("drop frame.\n");
return XMEDIA_SUCCESS;
}
fnode->used = 0;
for (i = 0; i < pst_stream->pack_count; ++i) {
pst_data = &pst_stream->pack[i];
s = pst_data->vir_addr + pst_data->offset;
data_len = pst_data->len - pst_data->offset;
copy_size = data_len < (fnode->length - fnode->used) ? data_len : (fnode->length - fnode->used);
if (copy_size > 0) {
memcpy(fnode->mem + fnode->used, s, copy_size);
fnode->used += copy_size;
}
if (data_len > copy_size) {
venc_logw("WARN: missing pack, exp(%d) != act(%d)\n", data_len, copy_size);
}
}
venc_logd("send size(%u)\n", fnode->used);
put_node_to_queue(uvc_cache->ok_queue, fnode);
return XMEDIA_SUCCESS;
}
static int sample_h264_save_stream(xmedia_payload_type en_type, xmedia_venc_stream *pst_stream)
{
xmedia_s32 ret = XMEDIA_FAILURE;
ret = sample_h264_save_data(pst_stream);
return ret;
}
void* sample_h264_stream_proc(void* arg)
{
sample_venc_getstream_para *param = (sample_venc_getstream_para*)arg;
xmedia_s32 chn_cnt = param->cnt;
xmedia_s32 i;
xmedia_s32 ret = XMEDIA_FAILURE;
xmedia_venc_chn_attr venc_chn_attr;
xmedia_payload_type payload_type[VENC_MAX_CHN_NUM];
struct timeval time_out;
xmedia_venc_stream venc_stream;
xmedia_venc_chn_status stat;
xmedia_u32 venc_mask = 0;
if (chn_cnt >= VENC_MAX_CHN_NUM) {
venc_loge("input venc chn count invaild\n");
return XMEDIA_NULL;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_get_chn_attr(param->venc_chn[i], &venc_chn_attr);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_get_chn_attr chn[%d] failed with %#x!\n", param->venc_chn[i], ret);
return XMEDIA_NULL;
}
payload_type[i] = venc_chn_attr.venc_attr.en_type;
venc_mask |= 1 << param->venc_chn[i];
}
venc_logi("H264 start.\n");
while (param->thread_start) {
time_out.tv_sec = 2;
time_out.tv_usec = 0;
ret = xmedia_venc_select(venc_mask, &time_out);
if (ret == XMEDIA_ERRCODE_INVALID_PARAM || ret == XMEDIA_FAILURE) {
venc_loge("select err\n");
break;
} else if (ret == XMEDIA_ERRCODE_TIMEOUT) {
param->stream_timeout_cnt++;
venc_logd("get venc stream time out, continue. \n");
continue;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_query_status(param->venc_chn[i], &stat);
if (XMEDIA_SUCCESS != ret) {
venc_logd("xmedia_venc_query_status chn[%d] failed with %#x!\n", i, ret);
break;
}
if (0 == stat.cur_packs) {
continue;
}
memset(&venc_stream, 0, sizeof(venc_stream));
venc_stream.pack = (xmedia_venc_pack*)malloc(sizeof(xmedia_venc_pack) * stat.cur_packs);
if (XMEDIA_NULL == venc_stream.pack) {
venc_logd("malloc stream pack failed!\n");
break;
}
venc_stream.pack_count = stat.cur_packs;
ret = xmedia_venc_get_stream(param->venc_chn[i], &venc_stream, XMEDIA_TRUE);
if (XMEDIA_SUCCESS != ret) {
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
venc_loge("xmedia_venc_get_stream failed with %#x!\n", ret);
break;
}
sample_h264_save_stream(payload_type[i], &venc_stream);
ret = xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_release_stream failed!\n");
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
break;
}
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
}
}
venc_logi("H264 stream exit.\n");
return NULL;
}
static int sample_h264_start_get_stream(int venc_chn, int cnt)
{
int i, rc;
g_st_param.cnt = cnt;
g_st_param.thread_start = XMEDIA_TRUE;
for (i = 0; i < cnt; i++) {
g_st_param.venc_chn[i] = venc_chn;
}
rc = pthread_create(&g_recv_pid, NULL, sample_h264_stream_proc, (void*)&g_st_param);
if (rc < 0) {
venc_loge("Create sample_h264_stream_proc failed.\n");
return -1;
}
return 0;
}
static int sample_h264_stop_get_stream(void)
{
if (XMEDIA_TRUE == g_st_param.thread_start) {
g_st_param.thread_start = XMEDIA_FALSE;
pthread_join(g_recv_pid, 0);
}
venc_logi("stop get H264 stream ok.\n");
return 0;
}
static int sample_h264_normalp_classic(void)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
xmedia_u32 framerate = 0, fps_user = 0;
xmedia_video_size pic_size = {0};
xmedia_video_size vpss_ochn_size = {0};
xmedia_isp_config isp_config = {0};
xmedia_payload_type en_payload = PT_H264;
vi_sensor_info sensor_info = {0};
g_vi_config.dev_info[g_vi_dev].dev_en = XMEDIA_TRUE;
g_vi_config.dev_info[g_vi_dev].dev_no = g_vi_dev;
g_vi_config.dev_info[g_vi_dev].sensor_type = g_sensor_type;
g_vi_config.pipe_info[g_vi_pipe].pipe_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].pipe_no = g_vi_pipe;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_no = g_vi_chn;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[0] = g_vi_pipe;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[1] = -1;
sample_comm_vi_get_sensor_info(g_sensor_type, &sensor_info);
sample_comm_vi_get_framerate_by_sensor(g_sensor_type, &framerate);
get_user_format(NULL, NULL, &fps_user);
if (fps_user > framerate) {
venc_logw("User framerate(%d) > sensor framerate(%d), used sensor framerate\n", fps_user, framerate);
} else {
framerate = fps_user;
}
isp_config.fps = framerate;
isp_config.mode_config.work_mode = XMEDIA_ISP_WORK_MODE_MASTER;
isp_config.mode_config.master_mode.blend_stat_enable = XMEDIA_FALSE;
isp_config.mode_config.master_mode.slave_num = 0;
isp_config.pixel_fmt = sensor_info.pixel_format;
isp_config.size.height = sensor_info.height;
isp_config.size.width = sensor_info.width;
pic_size.height = sensor_info.height;
pic_size.width = sensor_info.width;
isp_config.wdr_mode = sensor_info.wdr_mode;
// isp pipe init
g_isp_param.pipe[g_vi_pipe] = g_vi_pipe;
g_isp_param.isp_info[g_vi_pipe].sensor_type = g_sensor_type;
g_isp_param.isp_info[g_vi_pipe].flip = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].mirror = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].isp_pipe_en = XMEDIA_TRUE;
g_isp_param.isp_info[g_vi_pipe].isp_sensor_en = XMEDIA_TRUE;
memcpy(&(g_isp_param.isp_info[g_vi_pipe].isp_config), &isp_config, sizeof(xmedia_isp_config));
// isp init
ret = sample_comm_isp_init(&g_isp_param, &g_vi_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("isp init failed!\n");
goto exit0;
}
// vi start
ret = sample_comm_vi_start(&g_vi_config, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start vi failed!\n");
goto exit1;
}
// isp start
ret = sample_comm_isp_start(&g_isp_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start isp failed!\n");
goto exit2;
}
// vpss config
ret = sample_comm_vpss_get_default_pipe_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].pipe_config, pic_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
get_user_format(&en_payload, &pic_size, NULL);
vpss_ochn_size.width = pic_size.width;
vpss_ochn_size.height = pic_size.height;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_no = g_vpss_pipe;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_no = g_vpss_ochn;
ret = sample_comm_vpss_get_default_ochn_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_config,
vpss_ochn_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
// vpss start
ret = sample_comm_vpss_start(&g_vpss_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss start failed !\n");
goto exit2;
}
ret = sample_comm_sys_vi_bind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vi bind vpss failed !\n");
goto exit3;
}
//venc init
g_venc_config.chn_info[g_venc_chn].venc_en = XMEDIA_TRUE;
g_venc_config.chn_info[g_venc_chn].venc_chn = g_venc_chn;
g_venc_config.chn_info[g_venc_chn].payload_type = en_payload;
if (en_payload == PT_H264)
g_venc_config.chn_info[g_venc_chn].rc_mode = VENC_RC_MODE_H264CBR;
else if (en_payload == PT_H265)
g_venc_config.chn_info[g_venc_chn].rc_mode = VENC_RC_MODE_H265CBR;
sample_comm_venc_get_default_chn_info(vpss_ochn_size, framerate, &g_venc_config.chn_info[g_venc_chn]);
ret = sample_comm_venc_start(&g_venc_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("venc start failed !\n");
goto exit4;
}
ret = sample_comm_sys_vpss_bind_venc(g_vpss_pipe, g_vpss_ochn, g_venc_chn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss bind venc failed !\n");
goto exit5;
}
return 0;
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn, g_venc_chn);
exit5:
sample_comm_venc_stop(&g_venc_config);
exit4:
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
exit3:
sample_comm_vpss_stop(&g_vpss_config);
exit2:
sample_comm_isp_stop(&g_isp_param);
exit1:
sample_comm_vi_stop(&g_vi_config);
exit0:
sample_comm_isp_exit(&g_isp_param);
sample_h264_sys_deinit();
return -1;
}
/*******************************************************
* Processing Unit Operation Functions
*******************************************************/
/* Processing Unit Operation Functions End */
/*******************************************************
* Input Terminal Operation Functions
*******************************************************/
/* Input Terminal Operation Functions End */
/*******************************************************
* Stream Control Operation Functions
*******************************************************/
int sample_h264_set_idr(void)
{
return 0;
}
int sample_h264_init(void)
{
g_sensor_type = SENSOR0_TYPE;
sample_h264_sys_init(g_sensor_type);
return 0;
}
int sample_h264_startup(void)
{
venc_logi("H264 stream startup.\n");
g_start = 1;
if (sample_h264_normalp_classic() < 0) {
return -1;
}
sample_h264_start_get_stream(g_venc_chn, 1);
venc_logi("H264 stream startup ok.\n");
return 0;
}
int sample_h264_shutdown(void)
{
if (!g_start) {
return 0;
}
sample_h264_stop_get_stream();
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn, g_venc_chn);
sample_comm_venc_stop(&g_venc_config);
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
sample_comm_vpss_stop(&g_vpss_config);
sample_comm_isp_stop(&g_isp_param);
sample_comm_vi_stop(&g_vi_config);
sample_comm_isp_exit(&g_isp_param);
sample_h264_sys_deinit();
g_start = 0;
return 0;
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __SAMPLE_VIDEO_H264_H__
#define __SAMPLE_VIDEO_H264_H__
int sample_h264_set_idr(void);
int sample_h264_init(void);
int sample_h264_startup(void);
int sample_h264_shutdown(void);
#endif
@@ -0,0 +1,559 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "sample_comm.h"
#include "sample_comm_venc.h"
#include "sample_comm_vpss.h"
#include "sample_comm_vi.h"
#include "sample_comm_sys.h"
#include "sample_comm_isp.h"
#include "video_stream.h"
#include "sample_video.h"
#include "sample_video_mjpeg.h"
#include "venc_log.h"
#include "frame_cache.h"
static int g_start = 0;
static pthread_t g_recv_pid;
static sample_venc_getstream_para g_st_param;
//common
static sample_comm_sensor_type g_sensor_type = SENSOR0_TYPE;
static sample_comm_video_param g_video_param = {0};
// vi config
static xmedia_s32 g_vi_dev = 0; /* 0:单板SENSOR0; 2:单板SENSOR2 */
static xmedia_s32 g_vi_chn = 0;
static xmedia_s32 g_vi_pipe = 0;
static sample_vi_config g_vi_config = {0};
// isp config
static sample_isp_param g_isp_param = {0};
// vpss config
static xmedia_s32 g_vpss_pipe = 0;
static xmedia_s32 g_vpss_ichn = 0;
static xmedia_s32 g_vpss_ochn = 0;
static sample_vpss_config g_vpss_config = {0};
// venc config
static xmedia_s32 g_venc_chn = 0;
static sample_venc_config g_venc_config = {0};
static int sample_mjpeg_sys_init(int sensor_type)
{
xmedia_s32 ret, idx;
xmedia_s32 blk_size = 0;
vi_sensor_info sensor_info = {0};
xmedia_video_size pic_size = {0};
sample_sys_config sys_config = {0};
func_entry();
g_video_param.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
g_video_param.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420;
g_video_param.data_width = XMEDIA_VIDEO_DATA_WIDTH_8;
g_video_param.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
sample_comm_vi_get_sensor_info(sensor_type, &sensor_info);
// sys init
sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].gdc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
sys_config.vb_conf.max_pool_cnt = 25;
idx = 0;
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode == XMEDIA_WORK_MODE_OFFLINE) {
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, sensor_info.pixel_format,
sensor_info.bit_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 2;
idx++;
}
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode == XMEDIA_WORK_MODE_OFFLINE) {
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
idx++;
}
get_user_format(NULL, &pic_size, NULL);
venc_logi("user resolution: %d(w) x %d(h)\n", pic_size.width, pic_size.height);
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
sys_config.vb_conf.supplement_config = (1 << 0);
sys_config.vb_conf.supplement_config |= (1 << 1);
ret = sample_comm_sys_init(&sys_config);
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_sys_init failed!\n");
return ret;
}
//in online-online mode,vi and vpss must be reset at the same time
ret = sample_comm_vi_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vi_init failed!\n");
return ret;
}
ret = sample_comm_vpss_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vpss_init failed!\n");
return ret;
}
ret = sample_comm_venc_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_venc_init failed!\n");
return ret;
}
func_success();
return XMEDIA_SUCCESS;
}
static int sample_mjpeg_sys_deinit(void)
{
sample_comm_venc_exit();
sample_comm_vpss_exit();
sample_comm_vi_exit();
sample_comm_sys_exit();
return XMEDIA_SUCCESS;
}
static int sample_mjpeg_save_data(xmedia_venc_stream* pst_stream)
{
int i = 0;
xmedia_venc_pack *pst_data = NULL;
unsigned char *s = NULL;
unsigned int data_len = 0;
unsigned int copy_size = 0;
uvc_cache_t *uvc_cache = uvc_cache_get();
frame_node_t *fnode = NULL;
if (uvc_cache) {
get_node_from_queue(uvc_cache->free_queue, &fnode);
}
if (!fnode) {
venc_logd("drop frame.\n");
return XMEDIA_SUCCESS;
}
fnode->used = 0;
for (i = 0; i < pst_stream->pack_count; ++i) {
pst_data = &pst_stream->pack[i];
s = pst_data->vir_addr + pst_data->offset;
data_len = pst_data->len - pst_data->offset;
copy_size = data_len < (fnode->length - fnode->used) ? data_len : (fnode->length - fnode->used);
if (copy_size > 0) {
memcpy(fnode->mem + fnode->used, s, copy_size);
fnode->used += copy_size;
}
if (data_len > copy_size) {
venc_logw("WARN: missing pack, exp(%d) != act(%d)\n", data_len, copy_size);
}
}
venc_logd("send size(%u)\n", fnode->used);
put_node_to_queue(uvc_cache->ok_queue, fnode);
return XMEDIA_SUCCESS;
}
static int sample_mjpeg_save_stream(xmedia_payload_type en_type, xmedia_venc_stream *pst_stream)
{
xmedia_s32 ret = XMEDIA_FAILURE;
if (PT_MJPEG == en_type) {
ret = sample_mjpeg_save_data(pst_stream);
}
return ret;
}
void* sample_mjpeg_stream_proc(void* arg)
{
sample_venc_getstream_para *param = (sample_venc_getstream_para*)arg;
xmedia_s32 chn_cnt = param->cnt;
xmedia_s32 i;
xmedia_s32 ret = XMEDIA_FAILURE;
xmedia_venc_chn_attr venc_chn_attr;
xmedia_payload_type payload_type[VENC_MAX_CHN_NUM];
struct timeval time_out;
xmedia_venc_stream venc_stream;
xmedia_venc_chn_status stat;
xmedia_u32 venc_mask = 0;
if (chn_cnt >= VENC_MAX_CHN_NUM) {
venc_loge("input venc chn count invaild\n");
return XMEDIA_NULL;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_get_chn_attr(param->venc_chn[i], &venc_chn_attr);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_get_chn_attr chn[%d] failed with %#x!\n", param->venc_chn[i], ret);
return XMEDIA_NULL;
}
payload_type[i] = venc_chn_attr.venc_attr.en_type;
venc_mask |= 1 << param->venc_chn[i];
}
venc_logi("mjpeg start.\n");
while (param->thread_start) {
time_out.tv_sec = 2;
time_out.tv_usec = 0;
ret = xmedia_venc_select(venc_mask, &time_out);
if (ret == XMEDIA_ERRCODE_INVALID_PARAM || ret == XMEDIA_FAILURE) {
venc_loge("select err\n");
break;
} else if (ret == XMEDIA_ERRCODE_TIMEOUT) {
param->stream_timeout_cnt++;
venc_logd("get venc stream time out, continue. \n");
continue;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_query_status(param->venc_chn[i], &stat);
if (XMEDIA_SUCCESS != ret) {
venc_logd("xmedia_venc_query_status chn[%d] failed with %#x!\n", i, ret);
break;
}
if (0 == stat.cur_packs) {
continue;
}
memset(&venc_stream, 0, sizeof(venc_stream));
venc_stream.pack = (xmedia_venc_pack*)malloc(sizeof(xmedia_venc_pack) * stat.cur_packs);
if (XMEDIA_NULL == venc_stream.pack) {
venc_logd("malloc stream pack failed!\n");
break;
}
venc_stream.pack_count = stat.cur_packs;
ret = xmedia_venc_get_stream(param->venc_chn[i], &venc_stream, XMEDIA_TRUE);
if (XMEDIA_SUCCESS != ret) {
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
venc_loge("xmedia_venc_get_stream failed with %#x!\n", ret);
break;
}
sample_mjpeg_save_stream(payload_type[i], &venc_stream);
ret = xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_release_stream failed!\n");
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
break;
}
free(venc_stream.pack);
venc_stream.pack = XMEDIA_NULL;
}
}
venc_logi("mjpeg stream exit.\n");
return NULL;
}
static int sample_mjpeg_start_get_stream(int venc_chn, int cnt)
{
int i, rc;
g_st_param.cnt = cnt;
g_st_param.thread_start = XMEDIA_TRUE;
for (i = 0; i < cnt; i++) {
g_st_param.venc_chn[i] = venc_chn;
}
rc = pthread_create(&g_recv_pid, NULL, sample_mjpeg_stream_proc, (void*)&g_st_param);
if (rc < 0) {
venc_loge("Create sample_mjpeg_stream_proc failed.\n");
return -1;
}
return 0;
}
static int sample_mjpeg_stop_get_stream(void)
{
if (XMEDIA_TRUE == g_st_param.thread_start) {
g_st_param.thread_start = XMEDIA_FALSE;
pthread_join(g_recv_pid, 0);
}
venc_logi("stop get mjpeg stream ok.\n");
return 0;
}
static int sample_mjpeg_normalp_classic(void)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
xmedia_u32 framerate = 0, fps_user = 0;
xmedia_video_size pic_size = {0};
xmedia_video_size vpss_ochn_size = {0};
xmedia_isp_config isp_config = {0};
xmedia_payload_type en_payload = PT_MJPEG;
vi_sensor_info sensor_info = {0};
g_vi_config.dev_info[g_vi_dev].dev_en = XMEDIA_TRUE;
g_vi_config.dev_info[g_vi_dev].dev_no = g_vi_dev;
g_vi_config.dev_info[g_vi_dev].sensor_type = g_sensor_type;
g_vi_config.pipe_info[g_vi_pipe].pipe_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].pipe_no = g_vi_pipe;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_no = g_vi_chn;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[0] = g_vi_pipe;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[1] = -1;
sample_comm_vi_get_sensor_info(g_sensor_type, &sensor_info);
sample_comm_vi_get_framerate_by_sensor(g_sensor_type, &framerate);
get_user_format(NULL, NULL, &fps_user);
if (fps_user > framerate) {
venc_logw("User framerate(%d) > sensor framerate(%d), used sensor framerate\n", fps_user, framerate);
} else {
framerate = fps_user;
}
isp_config.fps = framerate;
isp_config.mode_config.work_mode = XMEDIA_ISP_WORK_MODE_MASTER;
isp_config.mode_config.master_mode.blend_stat_enable = XMEDIA_FALSE;
isp_config.mode_config.master_mode.slave_num = 0;
isp_config.pixel_fmt = sensor_info.pixel_format;
isp_config.size.height = sensor_info.height;
isp_config.size.width = sensor_info.width;
pic_size.height = sensor_info.height;
pic_size.width = sensor_info.width;
isp_config.wdr_mode = sensor_info.wdr_mode;
// isp pipe init
g_isp_param.pipe[g_vi_pipe] = g_vi_pipe;
g_isp_param.isp_info[g_vi_pipe].sensor_type = g_sensor_type;
g_isp_param.isp_info[g_vi_pipe].flip = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].mirror = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].isp_pipe_en = XMEDIA_TRUE;
g_isp_param.isp_info[g_vi_pipe].isp_sensor_en = XMEDIA_TRUE;
memcpy(&(g_isp_param.isp_info[g_vi_pipe].isp_config), &isp_config, sizeof(xmedia_isp_config));
// isp init
ret = sample_comm_isp_init(&g_isp_param, &g_vi_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("isp init failed!\n");
goto exit0;
}
// vi start
ret = sample_comm_vi_start(&g_vi_config, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start vi failed!\n");
goto exit1;
}
// isp start
ret = sample_comm_isp_start(&g_isp_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start isp failed!\n");
goto exit2;
}
// vpss config
ret = sample_comm_vpss_get_default_pipe_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].pipe_config, pic_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
get_user_format(&en_payload, &pic_size, NULL);
vpss_ochn_size.width = pic_size.width;
vpss_ochn_size.height = pic_size.height;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_no = g_vpss_pipe;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_no = g_vpss_ochn;
ret = sample_comm_vpss_get_default_ochn_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_config,
vpss_ochn_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
// vpss start
ret = sample_comm_vpss_start(&g_vpss_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss start failed !\n");
goto exit2;
}
ret = sample_comm_sys_vi_bind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vi bind vpss failed !\n");
goto exit3;
}
//venc init
g_venc_config.chn_info[g_venc_chn].venc_en = XMEDIA_TRUE;
g_venc_config.chn_info[g_venc_chn].venc_chn = g_venc_chn;
g_venc_config.chn_info[g_venc_chn].payload_type = en_payload;
g_venc_config.chn_info[g_venc_chn].rc_mode = VENC_RC_MODE_MJPEGFIXQP;
//g_venc_config.chn_info[g_venc_chn].rc_mode = VENC_RC_MODE_MJPEGCBR;
sample_comm_venc_get_default_chn_info(vpss_ochn_size, framerate, &g_venc_config.chn_info[g_venc_chn]);
ret = sample_comm_venc_start(&g_venc_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("venc start failed !\n");
goto exit4;
}
ret = sample_comm_sys_vpss_bind_venc(g_vpss_pipe, g_vpss_ochn, g_venc_chn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss bind venc failed !\n");
goto exit5;
}
return 0;
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn, g_venc_chn);
exit5:
sample_comm_venc_stop(&g_venc_config);
exit4:
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
exit3:
sample_comm_vpss_stop(&g_vpss_config);
exit2:
sample_comm_isp_stop(&g_isp_param);
exit1:
sample_comm_vi_stop(&g_vi_config);
exit0:
sample_comm_isp_exit(&g_isp_param);
sample_mjpeg_sys_deinit();
return -1;
}
/*******************************************************
* Processing Unit Operation Functions
*******************************************************/
/* Processing Unit Operation Functions End */
/*******************************************************
* Input Terminal Operation Functions
*******************************************************/
/* Input Terminal Operation Functions End */
/*******************************************************
* Stream Control Operation Functions
*******************************************************/
int sample_mjpeg_set_idr(void)
{
return 0;
}
int sample_mjpeg_init(void)
{
g_sensor_type = SENSOR0_TYPE;
sample_mjpeg_sys_init(g_sensor_type);
return 0;
}
int sample_mjpeg_startup(void)
{
venc_logi("Mjpeg stream startup.\n");
g_start = 1;
if (sample_mjpeg_normalp_classic() < 0) {
return -1;
}
sample_mjpeg_start_get_stream(g_venc_chn, 1);
venc_logi("Mjpeg stream startup ok.\n");
return 0;
}
int sample_mjpeg_shutdown(void)
{
if (!g_start) {
return 0;
}
sample_mjpeg_stop_get_stream();
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn, g_venc_chn);
sample_comm_venc_stop(&g_venc_config);
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
sample_comm_vpss_stop(&g_vpss_config);
sample_comm_isp_stop(&g_isp_param);
sample_comm_vi_stop(&g_vi_config);
sample_comm_isp_exit(&g_isp_param);
sample_mjpeg_sys_deinit();
g_start = 0;
return 0;
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __SAMPLE_VIDEO_MJPEG_H__
#define __SAMPLE_VIDEO_MJPEG_H__
int sample_mjpeg_set_idr(void);
int sample_mjpeg_init(void);
int sample_mjpeg_startup(void);
int sample_mjpeg_shutdown(void);
#endif
@@ -0,0 +1,655 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "sample_comm.h"
#include "sample_comm_venc.h"
#include "sample_comm_vpss.h"
#include "sample_comm_vi.h"
#include "sample_comm_sys.h"
#include "sample_comm_isp.h"
#include "video_stream.h"
#include "sample_video.h"
#include "sample_video_mjpeg.h"
#include "venc_log.h"
#include "frame_cache.h"
#include "debug.h"
extern unsigned int pack_h264_to_jpeg(unsigned char* frame_jpeg, unsigned int size_jpeg, unsigned int len_jpeg,
unsigned char* frame_h264, unsigned int size_h264, unsigned int fps);
static int g_start = 0;
static pthread_t g_recv_pid;
static sample_venc_getstream_para g_st_param;
//common
static sample_comm_sensor_type g_sensor_type = SENSOR0_TYPE;
static sample_comm_video_param g_video_param = {0};
// vi config
static xmedia_s32 g_vi_dev = 0; /* 0:单板SENSOR0; 2:单板SENSOR2 */
static xmedia_s32 g_vi_chn = 0;
static xmedia_s32 g_vi_pipe = 0;
static sample_vi_config g_vi_config = {0};
// isp config
static sample_isp_param g_isp_param = {0};
// vpss config
static xmedia_s32 g_vpss_pipe = 0;
static xmedia_s32 g_vpss_ichn = 0;
static xmedia_s32 g_vpss_ochn_0 = 0;
static xmedia_s32 g_vpss_ochn_1 = 1;
static sample_vpss_config g_vpss_config = {0};
// venc config
static xmedia_s32 g_venc_chn_0 = 0;
static xmedia_s32 g_venc_chn_1 = 1;
static sample_venc_config g_venc_config = {0};
static int sample_mjpeg_h264_sys_init(int sensor_type)
{
xmedia_s32 ret, idx;
xmedia_s32 blk_size = 0;
vi_sensor_info sensor_info = {0};
xmedia_video_size pic_size = {0};
sample_sys_config sys_config = {0};
func_entry();
g_video_param.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
g_video_param.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420;
g_video_param.data_width = XMEDIA_VIDEO_DATA_WIDTH_8;
g_video_param.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
sample_comm_vi_get_sensor_info(sensor_type, &sensor_info);
// sys init
sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].gdc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
idx = 0;
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode == XMEDIA_WORK_MODE_OFFLINE) {
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, sensor_info.pixel_format,
sensor_info.bit_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 2;
idx++;
}
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode == XMEDIA_WORK_MODE_OFFLINE) {
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
idx++;
}
get_user_format(NULL, &pic_size, NULL);
venc_logi("user resolution: %d(w) x %d(h)\n", pic_size.width, pic_size.height);
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 6;
sys_config.vb_conf.supplement_config = 1;
ret = sample_comm_sys_init(&sys_config);
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_sys_init failed!\n");
return ret;
}
//in online-online mode,vi and vpss must be reset at the same time
ret = sample_comm_vi_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vi_init failed!\n");
return ret;
}
ret = sample_comm_vpss_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vpss_init failed!\n");
return ret;
}
ret = sample_comm_venc_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_venc_init failed!\n");
return ret;
}
func_success();
return XMEDIA_SUCCESS;
}
static int sample_mjpeg_h264_sys_deinit(void)
{
sample_comm_venc_exit();
sample_comm_vpss_exit();
sample_comm_vi_exit();
sample_comm_sys_exit();
return XMEDIA_SUCCESS;
}
extern void memcpy_jpeg_user(unsigned char* src_buffer, unsigned int src_len,
unsigned char* dest_buffer, unsigned int dest_length, unsigned int* dest_offset);
static int sample_copy_frame(xmedia_venc_stream* pst_stream, char* dst_buf, int buf_len, int buf_used, int type)
{
int i = 0;
xmedia_venc_pack *pst_data = NULL;
unsigned char *s = NULL;
unsigned int data_len = 0;
unsigned int copy_size = 0;
for (i = 0; i < pst_stream->pack_count; ++i) {
pst_data = &pst_stream->pack[i];
s = pst_data->vir_addr + pst_data->offset;
data_len = pst_data->len - pst_data->offset;
copy_size = data_len < (buf_len - buf_used) ? data_len : (buf_len - buf_used);
if (copy_size > 0) {
if (type == PT_MJPEG) {
memcpy_jpeg_user(s, data_len, (unsigned char*)dst_buf, buf_len, (unsigned int *)&buf_used);
} else {
memcpy(dst_buf + buf_used, s, copy_size);
buf_used += copy_size;
}
}
if (data_len > copy_size) {
venc_logw("WARN: missing pack.\n");
}
}
return buf_used;
}
static char* g_h264 = NULL;
#define H264_BUFF_LEN 0x80000
extern unsigned int pack_h264_to_jpeg(unsigned char* frame_jpeg, unsigned int size_jpeg, unsigned int len_jpeg,
unsigned char* frame_h264, unsigned int size_h264, unsigned int fps);
static void sample_save_h264(xmedia_venc_stream* pst_stream, frame_node_t* fnode)
{
int ret;
if (fnode->used == 0) {
venc_loge("Not found mjpeg frame, drop current frame\n");
return;
}
memset(g_h264, 0, H264_BUFF_LEN);
ret = sample_copy_frame(pst_stream, g_h264, H264_BUFF_LEN, 0, PT_H264);
venc_logd("h264_size = %d, fnode->used = %u, fnode->length = %d\n", ret, fnode->used, fnode->length);
debug_dump_frame((char*)g_h264, ret, "frame.h264");
debug_dump_frame((char*)fnode->mem, fnode->used, "frame.mjpeg");
ret = pack_h264_to_jpeg((unsigned char*)fnode->mem, fnode->used, fnode->length,
(unsigned char*)g_h264, ret, 30);
debug_dump_frame((char*)fnode->mem, ret, "frame_mjpeg_h264h.bin");
fnode->used = ret;
}
static void sample_save_mjpeg(xmedia_venc_stream* pst_stream, frame_node_t* fnode)
{
int ret;
ret = sample_copy_frame(pst_stream, (char*)fnode->mem, fnode->length, fnode->used, PT_MJPEG);
fnode->used = ret;
}
static void sample_mjpeg_h264_save_stream(xmedia_payload_type en_type, xmedia_venc_stream *pst_stream, frame_node_t* fnode)
{
if (PT_MJPEG == en_type) {
sample_save_mjpeg(pst_stream, fnode);
} else if (PT_H264 == en_type){
sample_save_h264(pst_stream, fnode);
}
}
void* sample_mjpeg_h264_stream_proc(void* arg)
{
sample_venc_getstream_para *param = (sample_venc_getstream_para*)arg;
xmedia_s32 chn_cnt = param->cnt;
xmedia_s32 i;
xmedia_s32 ret = XMEDIA_FAILURE;
xmedia_venc_chn_attr venc_chn_attr;
xmedia_payload_type payload_type[VENC_MAX_CHN_NUM];
struct timeval time_out;
void *venc_pack = NULL;
xmedia_venc_stream venc_stream;
xmedia_venc_chn_status stat;
xmedia_u32 venc_mask = 0;
uvc_cache_t *uvc_cache = uvc_cache_get();
frame_node_t *fnode = NULL;
if (chn_cnt >= VENC_MAX_CHN_NUM) {
venc_loge("input venc chn count invaild\n");
return XMEDIA_NULL;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_get_chn_attr(param->venc_chn[i], &venc_chn_attr);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_get_chn_attr chn[%d] failed with %#x!\n", param->venc_chn[i], ret);
return XMEDIA_NULL;
}
payload_type[i] = venc_chn_attr.venc_attr.en_type;
venc_mask |= 1 << param->venc_chn[i];
}
venc_pack = malloc(sizeof(xmedia_venc_pack) * 5);
if (venc_pack == NULL) {
venc_loge("Failed to malloc venc pack\n");
return NULL;
}
g_h264 = (char*)malloc(H264_BUFF_LEN);
if (g_h264 == NULL) {
venc_loge("Failed to malloc\n");
free(venc_pack);
return NULL;
}
venc_logi("mjpeg and h264 start.\n");
while (param->thread_start) {
time_out.tv_sec = 2;
time_out.tv_usec = 0;
ret = xmedia_venc_select(venc_mask, &time_out);
if (ret == XMEDIA_ERRCODE_INVALID_PARAM || ret == XMEDIA_FAILURE) {
venc_loge("select err\n");
break;
} else if (ret == XMEDIA_ERRCODE_TIMEOUT) {
param->stream_timeout_cnt++;
venc_logd("get venc stream time out, continue. \n");
continue;
}
if (uvc_cache) {
get_node_from_queue(uvc_cache->free_queue, &fnode);
}
if (!fnode) {
//venc_logw("drop frame.\n");
} else {
fnode->used = 0;
}
for (i = 0; i < chn_cnt; ++i) {
if (param->venc_chn[i] < 0) {
continue;
}
ret = xmedia_venc_query_status(param->venc_chn[i], &stat);
if (XMEDIA_SUCCESS != ret) {
venc_logd("xmedia_venc_query_status chn[%d] failed with %#x!\n", i, ret);
break;
}
if (0 == stat.cur_packs) {
break;
}
memset(&venc_stream, 0, sizeof(venc_stream));
venc_stream.pack = (xmedia_venc_pack*)venc_pack;
if (XMEDIA_NULL == venc_stream.pack) {
venc_logd("malloc stream pack failed!\n");
break;
}
venc_stream.pack_count = stat.cur_packs;
ret = xmedia_venc_get_stream(param->venc_chn[i], &venc_stream, XMEDIA_TRUE);
if (XMEDIA_SUCCESS != ret) {
venc_stream.pack = XMEDIA_NULL;
xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
venc_loge("xmedia_venc_get_stream failed with %#x!\n", ret);
break;
}
if (fnode != NULL) {
sample_mjpeg_h264_save_stream(payload_type[i], &venc_stream, fnode);
}
ret = xmedia_venc_release_stream(param->venc_chn[i], &venc_stream);
if (XMEDIA_SUCCESS != ret) {
venc_loge("xmedia_venc_release_stream failed!\n");
venc_stream.pack = XMEDIA_NULL;
break;
}
venc_stream.pack = XMEDIA_NULL;
}
if (fnode != NULL) {
venc_logd("send size(%u)\n", fnode->used);
if (fnode->used) {
put_node_to_queue(uvc_cache->ok_queue, fnode);
} else {
put_node_to_queue(uvc_cache->free_queue, fnode);
}
}
}
free(venc_pack);
free(g_h264);
venc_logi("mjpeg and stream exit.\n");
return NULL;
}
static int sample_mjpeg_h264_start_get_stream(void)
{
int i, rc, cnt;
cnt = 2;
g_st_param.cnt = cnt;
g_st_param.thread_start = XMEDIA_TRUE;
for (i = 0; i < cnt; i++) {
g_st_param.venc_chn[i] = i; // g_venc_chn_0, g_venc_chn_1
}
rc = pthread_create(&g_recv_pid, NULL, sample_mjpeg_h264_stream_proc, (void*)&g_st_param);
if (rc < 0) {
venc_loge("Create sample_mjpeg_h264_stream_proc failed.\n");
return -1;
}
return 0;
}
static int sample_mjpeg_h264_stop_get_stream(void)
{
if (XMEDIA_TRUE == g_st_param.thread_start) {
g_st_param.thread_start = XMEDIA_FALSE;
pthread_join(g_recv_pid, 0);
}
venc_logi("stop get mjpeg stream ok.\n");
return 0;
}
static int sample_mjpeg_h264_normalp_classic(void)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
xmedia_u32 framerate = 0, fps_user = 0;
xmedia_video_size pic_size = {0};
xmedia_video_size vpss_ochn_size = {0};
xmedia_isp_config isp_config = {0};
xmedia_payload_type en_payload = PT_MJPEG;
vi_sensor_info sensor_info = {0};
g_vi_config.dev_info[g_vi_dev].dev_en = XMEDIA_TRUE;
g_vi_config.dev_info[g_vi_dev].dev_no = g_vi_dev;
g_vi_config.dev_info[g_vi_dev].sensor_type = g_sensor_type;
g_vi_config.pipe_info[g_vi_pipe].pipe_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].pipe_no = g_vi_pipe;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_no = g_vi_chn;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[0] = g_vi_pipe;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[1] = -1;
sample_comm_vi_get_sensor_info(g_sensor_type, &sensor_info);
sample_comm_vi_get_framerate_by_sensor(g_sensor_type, &framerate);
get_user_format(NULL, NULL, &fps_user);
if (fps_user > framerate) {
venc_logw("User framerate(%d) > sensor framerate(%d), used sensor framerate\n", fps_user, framerate);
} else {
framerate = fps_user;
}
isp_config.fps = framerate;
isp_config.mode_config.work_mode = XMEDIA_ISP_WORK_MODE_MASTER;
isp_config.mode_config.master_mode.blend_stat_enable = XMEDIA_FALSE;
isp_config.mode_config.master_mode.slave_num = 0;
isp_config.pixel_fmt = sensor_info.pixel_format;
isp_config.size.height = sensor_info.height;
isp_config.size.width = sensor_info.width;
pic_size.height = sensor_info.height;
pic_size.width = sensor_info.width;
isp_config.wdr_mode = sensor_info.wdr_mode;
// isp pipe init
g_isp_param.pipe[g_vi_pipe] = g_vi_pipe;
g_isp_param.isp_info[g_vi_pipe].sensor_type = g_sensor_type;
g_isp_param.isp_info[g_vi_pipe].flip = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].mirror = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].isp_pipe_en = XMEDIA_TRUE;
g_isp_param.isp_info[g_vi_pipe].isp_sensor_en = XMEDIA_TRUE;
memcpy(&(g_isp_param.isp_info[g_vi_pipe].isp_config), &isp_config, sizeof(xmedia_isp_config));
// isp init
ret = sample_comm_isp_init(&g_isp_param, &g_vi_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("isp init failed!\n");
goto exit0;
}
// vi start
ret = sample_comm_vi_start(&g_vi_config, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start vi failed!\n");
goto exit1;
}
// isp start
ret = sample_comm_isp_start(&g_isp_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start isp failed!\n");
goto exit2;
}
// vpss config
ret = sample_comm_vpss_get_default_pipe_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].pipe_config, pic_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
get_user_format(&en_payload, &pic_size, NULL);
vpss_ochn_size.width = pic_size.width;
vpss_ochn_size.height = pic_size.height;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_no = g_vpss_pipe;
// vpss out channel 0
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn_0].chn_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn_0].chn_no = g_vpss_ochn_0;
ret = sample_comm_vpss_get_default_ochn_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn_0].chn_config,
vpss_ochn_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
// vpss out channel 1
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn_1].chn_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn_1].chn_no = g_vpss_ochn_1;
ret = sample_comm_vpss_get_default_ochn_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn_1].chn_config,
vpss_ochn_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
// vpss start
ret = sample_comm_vpss_start(&g_vpss_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss start failed !\n");
goto exit2;
}
ret = sample_comm_sys_vi_bind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vi bind vpss failed !\n");
goto exit3;
}
//venc channel 0 init
g_venc_config.chn_info[g_venc_chn_0].venc_en = XMEDIA_TRUE;
g_venc_config.chn_info[g_venc_chn_0].venc_chn = g_venc_chn_0;
g_venc_config.chn_info[g_venc_chn_0].payload_type = PT_MJPEG;
//g_venc_config.chn_info[g_venc_chn_0].rc_mode = VENC_RC_MODE_MJPEGFIXQP;
g_venc_config.chn_info[g_venc_chn_0].rc_mode = VENC_RC_MODE_MJPEGCBR;
sample_comm_venc_get_default_chn_info(vpss_ochn_size, framerate, &g_venc_config.chn_info[g_venc_chn_0]);
//venc channel 1 init
g_venc_config.chn_info[g_venc_chn_1].venc_en = XMEDIA_TRUE;
g_venc_config.chn_info[g_venc_chn_1].venc_chn = g_venc_chn_1;
g_venc_config.chn_info[g_venc_chn_1].payload_type = PT_H264;
g_venc_config.chn_info[g_venc_chn_1].rc_mode = VENC_RC_MODE_H264CBR;
sample_comm_venc_get_default_chn_info(vpss_ochn_size, framerate, &g_venc_config.chn_info[g_venc_chn_1]);
ret = sample_comm_venc_start(&g_venc_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("venc start failed !\n");
goto exit4;
}
ret = sample_comm_sys_vpss_bind_venc(g_vpss_pipe, g_vpss_ochn_0, g_venc_chn_0);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss bind venc failed !\n");
goto exit5;
}
ret = sample_comm_sys_vpss_bind_venc(g_vpss_pipe, g_vpss_ochn_1, g_venc_chn_1);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss bind venc failed !\n");
goto exit5;
}
return 0;
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn_0, g_venc_chn_0);
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn_1, g_venc_chn_1);
exit5:
sample_comm_venc_stop(&g_venc_config);
exit4:
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
exit3:
sample_comm_vpss_stop(&g_vpss_config);
exit2:
sample_comm_isp_stop(&g_isp_param);
exit1:
sample_comm_vi_stop(&g_vi_config);
exit0:
sample_comm_isp_exit(&g_isp_param);
sample_mjpeg_h264_sys_deinit();
return -1;
}
/*******************************************************
* Processing Unit Operation Functions
*******************************************************/
/* Processing Unit Operation Functions End */
/*******************************************************
* Input Terminal Operation Functions
*******************************************************/
/* Input Terminal Operation Functions End */
/*******************************************************
* Stream Control Operation Functions
*******************************************************/
int sample_mjpeg_h264_set_idr(void)
{
return 0;
}
int sample_mjpeg_h264_init(void)
{
g_sensor_type = SENSOR0_TYPE;
sample_mjpeg_h264_sys_init(g_sensor_type);
return 0;
}
int sample_mjpeg_h264_startup(void)
{
venc_logi("Mjpeg stream startup.\n");
g_start = 1;
if (sample_mjpeg_h264_normalp_classic() < 0) {
return -1;
}
sample_mjpeg_h264_start_get_stream();
venc_logi("Mjpeg stream startup ok.\n");
return 0;
}
int sample_mjpeg_h264_shutdown(void)
{
if (!g_start) {
return 0;
}
sample_mjpeg_h264_stop_get_stream();
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn_0, g_venc_chn_0);
sample_comm_sys_vpss_unbind_venc(g_vpss_pipe, g_vpss_ochn_1, g_venc_chn_1);
sample_comm_venc_stop(&g_venc_config);
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
sample_comm_vpss_stop(&g_vpss_config);
sample_comm_isp_stop(&g_isp_param);
sample_comm_vi_stop(&g_vi_config);
sample_comm_isp_exit(&g_isp_param);
sample_mjpeg_h264_sys_deinit();
g_start = 0;
return 0;
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __SAMPLE_VIDEO_MJPEG_H264_H__
#define __SAMPLE_VIDEO_MJPEG_H264_H__
int sample_mjpeg_h264_set_idr(void);
int sample_mjpeg_h264_init(void);
int sample_mjpeg_h264_startup(void);
int sample_mjpeg_h264_shutdown(void);
#endif
@@ -0,0 +1,842 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "sample_comm.h"
#include "sample_comm_vpss.h"
#include "sample_comm_vi.h"
#include "sample_comm_sys.h"
#include "sample_comm_isp.h"
#include "xmedia_sys.h"
#include "xmedia_mmz.h"
#include "xmedia_vb.h"
#include "xmedia_vpss.h"
#include "xmedia_vgs.h"
#include "video_stream.h"
#include "sample_video.h"
#include "sample_video_yuv.h"
#include "venc_log.h"
#include "frame_cache.h"
#include "debug.h"
#define v4l2_fourcc(a, b, c, d) \
((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YUV 4:2:0 */
static int g_tag_fmt = V4L2_PIX_FMT_YUYV;
static pthread_t g_recv_pid;
static int g_start = 0;
static int g_recv = 0;
static xmedia_u32 g_vpss_depth_flag = 0;
//static xmedia_u32 g_vpss_ori_depth = 0;
//common
static sample_comm_sensor_type g_sensor_type = SENSOR0_TYPE;
static sample_comm_video_param g_video_param = {0};
// vi config
static xmedia_s32 g_vi_dev = 0; /* 0:单板SENSOR0; 2:单板SENSOR2 */
static xmedia_s32 g_vi_chn = 0;
static xmedia_s32 g_vi_pipe = 0;
static xmedia_u32 g_vgs_pool_id = 0;
static sample_vi_config g_vi_config = {0};
// isp config
static sample_isp_param g_isp_param = {0};
// vpss config
static xmedia_s32 g_vpss_pipe = 0;
static xmedia_s32 g_vpss_ichn = 0;
static xmedia_s32 g_vpss_ochn = 0;
static sample_vpss_config g_vpss_config = {0};
static xmedia_video_frame_info g_vpss_frame_info = {0};
static int sample_yuv_create_yuyv_pool(void)
{
xmedia_vb_pool_config pool_config;
vi_sensor_info sensor_info = {0};
sample_comm_vi_get_sensor_info(g_sensor_type, &sensor_info);
pool_config.block_cnt = 1;
pool_config.block_size = sensor_info.width * sensor_info.height * 2;
pool_config.map_mode = XMEDIA_VB_MAP_MODE_NONE;
g_vgs_pool_id = xmedia_vb_create_pool(&pool_config);
if (g_vgs_pool_id == -1) {
venc_logd("resolution: w(%d) x h(%d).\n", sensor_info.width, sensor_info.height);
return XMEDIA_FAILURE;
}
return XMEDIA_SUCCESS;
}
static int vgs_nv12_to_yuyv(xmedia_video_frame_info* vpss_frame, xmedia_video_frame_info* scale_frame)
{
xmedia_s32 ret;
xmedia_vgs_frame_info task_info;
xmedia_s32 job_handle;
xmedia_handle vb_handle;
vi_sensor_info sensor_info = {0};
xmedia_vb_base_info base_info = {0};
xmedia_vb_cal_cfg vb_cal_cfg = {0};
sample_comm_vi_get_sensor_info(g_sensor_type, &sensor_info);
base_info.width = vpss_frame->frame.width;
base_info.height = vpss_frame->frame.height;
base_info.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YUYV_PACKAGE_422; //XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_422;
base_info.bit_width = vpss_frame->frame.bit_width;
base_info.cmp_mode = vpss_frame->frame.compress_mode;
base_info.align = 8;
xmedia_vb_get_buffer_config(&base_info, &vb_cal_cfg);
vb_handle = xmedia_vb_get_block(g_vgs_pool_id, sensor_info.width * sensor_info.height * 2, XMEDIA_NULL);
if (vb_handle == VB_INVALID_HANDLE) {
SAMPLE_PRT("xmedia_vb_get_block(size:%d) failed!\n", sensor_info.width * sensor_info.height * 2);
return XMEDIA_FAILURE;
}
ret = xmedia_vgs_init();
if (ret != XMEDIA_SUCCESS) {
venc_loge("vgs init failed\n");
return ret;
}
ret = xmedia_vgs_create_job(&job_handle);
if (ret != XMEDIA_SUCCESS) {
venc_loge("create vgs job failed\n");
xmedia_vgs_exit();
goto EXIT1;
}
memset(scale_frame, 0, sizeof(xmedia_video_frame_info));
scale_frame->pool_id = g_vgs_pool_id;
scale_frame->frame.width = vpss_frame->frame.width;
scale_frame->frame.height = vpss_frame->frame.height;
scale_frame->frame.dynamic_range = XMEDIA_VIDEO_DYNAMIC_RANGE_SDR;
scale_frame->frame.color_info.color_gamut = XMEDIA_VIDEO_COLOR_GAMUT_BT709;
scale_frame->frame.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YUYV_PACKAGE_422; //XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_422; XMEDIA_VIDEO_PIXEL_FMT_YUYV_PACKAGE_422
scale_frame->frame.pts = vpss_frame->frame.pts;
scale_frame->frame.compress_mode = vpss_frame->frame.compress_mode;
scale_frame->frame.video_fmt = vpss_frame->frame.video_fmt;
scale_frame->frame.bit_width = vpss_frame->frame.bit_width;
scale_frame->mod_id = MOD_ID_USER;
scale_frame->frame.addr.y_head_phy_addr = xmedia_vb_handle_to_phy_addr(vb_handle);
scale_frame->frame.addr.c_head_phy_addr = scale_frame->frame.addr.y_head_phy_addr + vb_cal_cfg.head_y_size;
scale_frame->frame.stride.y_head_stride = vb_cal_cfg.head_y_stride;
scale_frame->frame.stride.c_head_stride = vb_cal_cfg.head_c_stride;
scale_frame->frame.addr.y_phy_addr = scale_frame->frame.addr.y_head_phy_addr + vb_cal_cfg.head_size;
scale_frame->frame.addr.c_phy_addr = scale_frame->frame.addr.y_head_phy_addr + vb_cal_cfg.main_y_size;
scale_frame->frame.stride.y_stride = vb_cal_cfg.main_stride;
scale_frame->frame.stride.c_stride = vb_cal_cfg.main_stride;
memcpy(&task_info.img_in, vpss_frame, sizeof(xmedia_video_frame_info));
memcpy(&task_info.img_out, scale_frame, sizeof(xmedia_video_frame_info));
ret = xmedia_vgs_add_task_scale(job_handle, &task_info, XMEDIA_VIDEO_SCALE_MODE_NORMAL);
if(ret != XMEDIA_SUCCESS) {
xmedia_vgs_cancel_job(job_handle);
SAMPLE_PRT("xmedia_vgs_add_task_scale failed!\n");
goto EXIT2;
}
ret = xmedia_vgs_submit_job(job_handle);
if (ret != XMEDIA_SUCCESS) {
venc_loge("submit vgs job failed\n");
goto EXIT2;
}
ret = xmedia_vgs_wait_job(job_handle, 2000);
if (ret != XMEDIA_SUCCESS) {
venc_loge("wait vgs job failed\n");
goto EXIT1;
}
xmedia_vgs_exit();
return XMEDIA_SUCCESS;
EXIT2:
xmedia_vgs_cancel_job(job_handle);
EXIT1:
xmedia_vgs_exit();
return XMEDIA_FAILURE;
}
static int sample_yuv_sys_init(int sensor_type)
{
xmedia_s32 ret, idx;
xmedia_s32 blk_size = 0;
vi_sensor_info sensor_info = {0};
xmedia_video_size pic_size = {0};
sample_sys_config sys_config = {0};
func_entry();
g_video_param.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
g_video_param.pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420; /* NV21 */
g_video_param.data_width = XMEDIA_VIDEO_DATA_WIDTH_8;
g_video_param.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
sample_comm_vi_get_sensor_info(sensor_type, &sensor_info);
// sys init
sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode = XMEDIA_WORK_MODE_ONLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
sys_config.sys_conf.pipe_mode[g_vi_pipe].gdc_vpss_mode = XMEDIA_WORK_MODE_OFFLINE;
sys_config.vb_conf.max_pool_cnt = 25;
pic_size.width = sensor_info.width;
pic_size.height = sensor_info.height;
venc_logd("sensor resolution: w(%d) x h(%d).\n", pic_size.width, pic_size.height);
idx = 0;
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].vicap_viproc_mode == XMEDIA_WORK_MODE_OFFLINE) {
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, sensor_info.pixel_format,
sensor_info.bit_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 2;
idx++;
}
if (sys_config.sys_conf.pipe_mode[g_vi_pipe].viproc_vpss_mode == XMEDIA_WORK_MODE_OFFLINE) {
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
idx++;
}
get_user_format(NULL, &pic_size, NULL);
venc_logi("user resolution: %d(w) x %d(h)\n", pic_size.width, pic_size.height);
blk_size = sample_comm_sys_get_buffer_size(pic_size, g_video_param.video_fmt, g_video_param.pixel_fmt,
g_video_param.data_width, g_video_param.compress_mode);
sys_config.vb_conf.common_pool[idx].block_size = blk_size;
sys_config.vb_conf.common_pool[idx].block_cnt = 3;
sys_config.vb_conf.supplement_config = 1;
ret = sample_comm_sys_init(&sys_config);
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_sys_init failed!\n");
return ret;
}
//in online-online mode,vi and vpss must be reset at the same time
ret = sample_comm_vi_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vi_init failed!\n");
return ret;
}
ret = sample_comm_vpss_init();
if(ret != XMEDIA_SUCCESS) {
venc_loge("sample_comm_vpss_init failed!\n");
return ret;
}
func_success();
return XMEDIA_SUCCESS;
}
static int sample_yuv_sys_deinit(void)
{
sample_comm_vpss_exit();
sample_comm_vi_exit();
sample_comm_sys_exit();
return XMEDIA_SUCCESS;
}
static xmedia_s32 vpss_ochn_dump_transform_format(xmedia_video_frame_info *frame_in,
xmedia_video_frame_info *tmp_frame, xmedia_video_frame_info *frame_out)
{
xmedia_s32 ret;
xmedia_vgs_frame_info task_info;
xmedia_s32 job_handle;
ret = xmedia_vgs_init();
if (ret != XMEDIA_SUCCESS) {
venc_loge("vgs init failed\n");
return ret;
}
ret = xmedia_vgs_create_job(&job_handle);
if (ret != XMEDIA_SUCCESS) {
venc_loge("create vgs job failed\n");
xmedia_vgs_exit();
goto EXIT1;
}
if (frame_in->frame.video_fmt == XMEDIA_VIDEO_FMT_TILE_16x4) {
memcpy(&task_info.img_in, frame_in, sizeof(xmedia_video_frame_info));
memcpy(&task_info.img_out, tmp_frame, sizeof(xmedia_video_frame_info));
ret = xmedia_vgs_add_task_rotation(job_handle, &task_info, XMEDIA_VIDEO_ROTATION_0);
if (ret != XMEDIA_SUCCESS) {
venc_loge("add vgs task failed\n");
goto EXIT2;
}
}
memcpy(&task_info.img_in, tmp_frame, sizeof(xmedia_video_frame_info));
memcpy(&task_info.img_out, frame_out, sizeof(xmedia_video_frame_info));
ret = xmedia_vgs_add_task_rotation(job_handle, &task_info, XMEDIA_VIDEO_ROTATION_0);
if (ret != XMEDIA_SUCCESS) {
venc_loge("add vgs task failed\n");
goto EXIT2;
}
ret = xmedia_vgs_submit_job(job_handle);
if (ret != XMEDIA_SUCCESS) {
venc_loge("submit vgs job failed\n");
goto EXIT2;
}
ret = xmedia_vgs_wait_job(job_handle, 2000);
if (ret != XMEDIA_SUCCESS) {
venc_loge("wait vgs job failed\n");
goto EXIT1;
}
xmedia_vgs_exit();
return XMEDIA_SUCCESS;
EXIT2:
xmedia_vgs_cancel_job(job_handle);
EXIT1:
xmedia_vgs_exit();
return XMEDIA_FAILURE;
}
static int nv21_to_nv21(unsigned char* src_nv21, unsigned int width, unsigned int height,
unsigned char* nv21, unsigned int nv21_len)
{
int copy_size;
copy_size = width * height * 3 / 2;
if (copy_size > nv21_len) {
return 0;
}
memcpy(nv21, src_nv21, copy_size);
return copy_size;
}
static int nv21_to_yuyv(unsigned char* nv21, unsigned int width, unsigned int height,
unsigned char* yuyv, unsigned int yuyv_len)
{
int copy_size;
copy_size = width * height * 2;
if (copy_size > yuyv_len) {
return 0;
}
memcpy(yuyv, nv21, copy_size);
return copy_size;
}
static void sample_yuv_save_data(unsigned char* yuv, unsigned int src_fmt,
unsigned int width, unsigned int height)
{
unsigned int copy_size = 0;
uvc_cache_t *uvc_cache = uvc_cache_get();
frame_node_t *fnode = NULL;
if (uvc_cache) {
get_node_from_queue(uvc_cache->free_queue, &fnode);
}
if (!fnode) {
venc_logd("drop frame.\n");
return;
}
switch (g_tag_fmt) {
case V4L2_PIX_FMT_YUYV:
copy_size = nv21_to_yuyv(yuv, width, height, fnode->mem, fnode->length);
break;
case V4L2_PIX_FMT_NV21:
copy_size = nv21_to_nv21(yuv, width, height, fnode->mem, fnode->length);
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
default:
venc_logw("send default format NV21.\n");
copy_size = nv21_to_nv21(yuv, width, height, fnode->mem, fnode->length);
break;
}
if (copy_size == 0) {
venc_loge("cache size is to small.\n");
}
fnode->used = copy_size;
venc_logd("send size(%u)\n", fnode->used);
put_node_to_queue(uvc_cache->ok_queue, fnode);
}
//static int flag = 0;
static void sample_yuv_save_frame(xmedia_video_frame_info vpss_frame)
{
char* virt_addr_y;
xmedia_u64 phy_addr;
xmedia_u32 size;
xmedia_char* page_addr[2];
xmedia_video_frame *video_frame = &vpss_frame.frame;
xmedia_video_pixel_format pixel_fmt = video_frame->pixel_fmt;
xmedia_video_frame_info scale_frame;
if (g_tag_fmt == V4L2_PIX_FMT_YUYV) {
vgs_nv12_to_yuyv(&vpss_frame, &scale_frame);
}
if (video_frame->compress_mode != XMEDIA_VIDEO_COMPRESS_MODE_NONE) {
video_frame->stride.y_stride = video_frame->width;
video_frame->stride.c_stride = video_frame->width;
}
if ((pixel_fmt == XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_420) ||
(pixel_fmt == XMEDIA_VIDEO_PIXEL_FMT_YUV_SEMIPLANAR_420)) {
size = video_frame->stride.y_stride * video_frame->height * 3 / 2;
} else if (pixel_fmt == XMEDIA_VIDEO_PIXEL_FMT_YUV_400) {
size = video_frame->stride.y_stride * video_frame->height;
} else {
size = video_frame->stride.y_stride * video_frame->height * 3 / 2;
}
if (g_tag_fmt == V4L2_PIX_FMT_YUYV) {
phy_addr = scale_frame.frame.addr.y_phy_addr;
size = video_frame->stride.y_stride * video_frame->height * 2;
pixel_fmt = XMEDIA_VIDEO_PIXEL_FMT_YUYV_PACKAGE_422; //XMEDIA_VIDEO_PIXEL_FMT_YVU_SEMIPLANAR_422;
} else {
phy_addr = video_frame->addr.y_phy_addr;
}
page_addr[0] = (xmedia_char*)xmedia_mmz_map(phy_addr, size, XMEDIA_FALSE);
if (XMEDIA_NULL == page_addr[0]) {
venc_loge("xmedia_mmz_map failed.\n");
return;
}
virt_addr_y = page_addr[0];
debug_dump_frame((char*)virt_addr_y, size, "frame_vpss.yuv");
sample_yuv_save_data((unsigned char*)virt_addr_y, pixel_fmt,
video_frame->stride.y_stride, video_frame->height);
xmedia_mmz_unmap(page_addr[0]);
page_addr[0] = XMEDIA_NULL;
if (g_tag_fmt == V4L2_PIX_FMT_YUYV) {
xmedia_vb_release_block(xmedia_vb_phy_addr_to_handle(scale_frame.frame.addr.y_head_phy_addr));
}
}
void* sample_yuv_stream_proc(void* arg)
{
int ret;
xmedia_vb_base_info base_info;
xmedia_vb_cal_cfg cal_cfg;
xmedia_s32 millisec = -1;
xmedia_handle vb_handle = VB_INVALID_HANDLE;
xmedia_handle tmp_handle = VB_INVALID_HANDLE;
xmedia_video_frame_info tmp_frame = {0};
xmedia_video_frame_info frame_out = {0};
g_vpss_depth_flag = 1;
while (g_recv) {
memset(&g_vpss_frame_info, 0, sizeof(xmedia_video_frame_info));
g_vpss_frame_info.pool_id = VB_INVALID_POOLID;
ret = xmedia_vpss_acquire_ochn_frame(g_vpss_pipe, g_vpss_ochn, &g_vpss_frame_info, millisec);
if (ret != XMEDIA_SUCCESS) {
venc_logi("piipe(%d) ochn(%d) get frame failed!\n", g_vpss_pipe, g_vpss_ochn);
usleep(1000);
continue;
}
venc_logd("pipe(%d) ochn(%d) video_fmt(%d) save frame!\n", g_vpss_pipe, g_vpss_ochn,
g_vpss_frame_info.frame.video_fmt);
if (g_vpss_frame_info.frame.video_fmt != XMEDIA_VIDEO_FMT_LINEAR) {
memset(&base_info, 0, sizeof(xmedia_vb_base_info));
base_info.align = 0;
base_info.bit_width = g_vpss_frame_info.frame.bit_width;
base_info.cmp_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
base_info.width = g_vpss_frame_info.frame.width;
base_info.height = g_vpss_frame_info.frame.height;
base_info.pixel_fmt = g_vpss_frame_info.frame.pixel_fmt;
if (g_vpss_frame_info.frame.video_fmt == XMEDIA_VIDEO_FMT_TILE_16x4) {
base_info.video_fmt = XMEDIA_VIDEO_FMT_TILE_64x4;
ret = xmedia_vb_get_buffer_config(&base_info, &cal_cfg);
if (ret != XMEDIA_SUCCESS) {
venc_logw("get buffer config failed with 0x%x\n", ret);
continue;
}
tmp_handle = xmedia_vb_get_block(-1, cal_cfg.vb_size, NULL);
if (tmp_handle == VB_INVALID_HANDLE) {
venc_logw("get block failed\n");
continue;
}
memcpy(&tmp_frame, &g_vpss_frame_info, sizeof(xmedia_video_frame_info));
tmp_frame.pool_id = xmedia_vb_handle_to_pool_id(tmp_handle);
tmp_frame.frame.addr.y_phy_addr = xmedia_vb_handle_to_phy_addr(tmp_handle);
tmp_frame.frame.addr.y_head_phy_addr = tmp_frame.frame.addr.y_phy_addr;
tmp_frame.frame.addr.c_phy_addr = tmp_frame.frame.addr.y_phy_addr + cal_cfg.main_y_size;
tmp_frame.frame.stride.y_stride = cal_cfg.main_stride;
tmp_frame.frame.stride.c_stride = cal_cfg.main_stride;
tmp_frame.frame.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
tmp_frame.frame.video_fmt = XMEDIA_VIDEO_FMT_TILE_64x4;
} else {
memcpy(&tmp_frame, &g_vpss_frame_info, sizeof(xmedia_video_frame_info));
}
base_info.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
ret = xmedia_vb_get_buffer_config(&base_info, &cal_cfg);
if (ret != XMEDIA_SUCCESS) {
if (tmp_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(tmp_handle);
tmp_handle = VB_INVALID_HANDLE;
}
venc_logw("get buffer config failed with 0x%x\n", ret);
continue;
}
vb_handle = xmedia_vb_get_block(-1, cal_cfg.vb_size, NULL);
if (vb_handle == VB_INVALID_HANDLE) {
if (tmp_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(tmp_handle);
tmp_handle = VB_INVALID_HANDLE;
}
venc_logw("get block failed\n");
continue;
}
memcpy(&frame_out, &tmp_frame, sizeof(xmedia_video_frame_info));
frame_out.pool_id = xmedia_vb_handle_to_pool_id(vb_handle);
frame_out.frame.addr.y_phy_addr = xmedia_vb_handle_to_phy_addr(vb_handle);
frame_out.frame.addr.y_head_phy_addr = frame_out.frame.addr.y_phy_addr;
frame_out.frame.addr.c_phy_addr = frame_out.frame.addr.y_phy_addr + cal_cfg.main_y_size;
frame_out.frame.stride.y_stride = cal_cfg.main_stride;
frame_out.frame.stride.c_stride = cal_cfg.main_stride;
frame_out.frame.compress_mode = XMEDIA_VIDEO_COMPRESS_MODE_NONE;
frame_out.frame.video_fmt = XMEDIA_VIDEO_FMT_LINEAR;
ret = vpss_ochn_dump_transform_format(&g_vpss_frame_info, &tmp_frame, &frame_out);
if (ret != XMEDIA_SUCCESS) {
if (tmp_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(tmp_handle);
tmp_handle = VB_INVALID_HANDLE;
}
if (vb_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(vb_handle);
vb_handle = VB_INVALID_HANDLE;
}
venc_logw("pipe %d ochn %d vpss_ochn_dump_transform_format failed\n", g_vpss_pipe, g_vpss_ochn);
continue;
}
} else {
memcpy(&frame_out, &g_vpss_frame_info, sizeof(xmedia_video_frame_info));
}
sample_yuv_save_frame(frame_out);
if (tmp_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(tmp_handle);
tmp_handle = VB_INVALID_HANDLE;
}
if (vb_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(vb_handle);
vb_handle = VB_INVALID_HANDLE;
}
ret = xmedia_vpss_release_ochn_frame(g_vpss_pipe, g_vpss_ochn, &g_vpss_frame_info);
if (ret != XMEDIA_SUCCESS) {
printf("pipe(%d) ochn(%d) release frame failed!\n", g_vpss_pipe, g_vpss_ochn);
}
}
g_vpss_frame_info.pool_id = VB_INVALID_POOLID;
if (tmp_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(tmp_handle);
tmp_handle = VB_INVALID_HANDLE;
}
if (vb_handle != VB_INVALID_HANDLE) {
xmedia_vb_release_block(vb_handle);
vb_handle = VB_INVALID_HANDLE;
}
return NULL;
}
static int sample_yuv_start_get_stream(int venc_chn, int cnt)
{
int rc;
g_recv = 1;
rc = pthread_create(&g_recv_pid, NULL, sample_yuv_stream_proc, NULL);
if (rc < 0) {
venc_loge("Create sample_yuv_stream_proc failed.\n");
return -1;
}
return 0;
}
static int sample_yuv_stop_get_stream(void)
{
if (g_recv == 1) {
g_recv = 0;
pthread_join(g_recv_pid, 0);
}
return 0;
}
static int sample_yuv_normalp_classic(void)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
xmedia_u32 framerate = 0, fps_user = 0;
xmedia_video_size pic_size = {0};
xmedia_video_size vpss_ochn_size = {0};
xmedia_isp_config isp_config = {0};
xmedia_payload_type en_payload = PT_MJPEG;
vi_sensor_info sensor_info = {0};
g_vi_config.dev_info[g_vi_dev].dev_en = XMEDIA_TRUE;
g_vi_config.dev_info[g_vi_dev].dev_no = g_vi_dev;
g_vi_config.dev_info[g_vi_dev].sensor_type = g_sensor_type;
g_vi_config.pipe_info[g_vi_pipe].pipe_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].pipe_no = g_vi_pipe;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_en = XMEDIA_TRUE;
g_vi_config.pipe_info[g_vi_pipe].chn_info[g_vi_chn].chn_no = g_vi_chn;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[0] = g_vi_pipe;
g_vi_config.dev_bind_pipe[g_vi_dev].pipe[1] = -1;
sample_comm_vi_get_sensor_info(g_sensor_type, &sensor_info);
sample_comm_vi_get_framerate_by_sensor(g_sensor_type, &framerate);
get_user_format(NULL, NULL, &fps_user);
if (fps_user > framerate) {
venc_logw("User framerate(%d) > sensor framerate(%d), used sensor framerate\n", fps_user, framerate);
} else {
framerate = fps_user;
}
venc_logi("isp framerate(%d)\n", framerate);
isp_config.fps = framerate;
isp_config.mode_config.work_mode = XMEDIA_ISP_WORK_MODE_MASTER;
isp_config.mode_config.master_mode.blend_stat_enable = XMEDIA_FALSE;
isp_config.mode_config.master_mode.slave_num = 0;
isp_config.pixel_fmt = sensor_info.pixel_format;
isp_config.size.height = sensor_info.height;
isp_config.size.width = sensor_info.width;
pic_size.height = sensor_info.height;
pic_size.width = sensor_info.width;
isp_config.wdr_mode = sensor_info.wdr_mode;
// isp pipe init
g_isp_param.pipe[g_vi_pipe] = g_vi_pipe;
g_isp_param.isp_info[g_vi_pipe].sensor_type = g_sensor_type;
g_isp_param.isp_info[g_vi_pipe].flip = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].mirror = XMEDIA_FALSE;
g_isp_param.isp_info[g_vi_pipe].isp_pipe_en = XMEDIA_TRUE;
g_isp_param.isp_info[g_vi_pipe].isp_sensor_en = XMEDIA_TRUE;
memcpy(&(g_isp_param.isp_info[g_vi_pipe].isp_config), &isp_config, sizeof(xmedia_isp_config));
// isp init
ret = sample_comm_isp_init(&g_isp_param, &g_vi_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("isp init failed!\n");
goto exit0;
}
// vi start
ret = sample_comm_vi_start(&g_vi_config, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start vi failed!\n");
goto exit1;
}
// isp start
ret = sample_comm_isp_start(&g_isp_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("start isp failed!\n");
goto exit2;
}
// vpss config
ret = sample_comm_vpss_get_default_pipe_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].pipe_config, pic_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
get_user_format(&en_payload, &pic_size, NULL);
#if 0
vpss_ochn_size.width = sensor_info.width;
vpss_ochn_size.height = sensor_info.height;
#else
vpss_ochn_size.width = pic_size.width;
vpss_ochn_size.height = pic_size.height;
#endif
g_vpss_config.pipe_info[g_vpss_pipe].pipe_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].pipe_no = g_vpss_pipe;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_en = XMEDIA_TRUE;
g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_no = g_vpss_ochn;
ret = sample_comm_vpss_get_default_ochn_cfg(&g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn].chn_config,
vpss_ochn_size, &g_video_param);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
#if 0
ret = sample_comm_vpss_set_ochn_wrap(&g_vpss_config.pipe_info[g_vpss_pipe].chn_info[g_vpss_ochn]);
if (ret != XMEDIA_SUCCESS) {
venc_loge("get default pipe cfg failed !\n");
goto exit2;
}
#endif
// vpss start
ret = sample_comm_vpss_start(&g_vpss_config);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vpss start failed !\n");
goto exit2;
}
ret = sample_comm_sys_vi_bind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
if (ret != XMEDIA_SUCCESS) {
venc_loge("vi bind vpss failed !\n");
goto exit3;
}
return 0;
exit3:
sample_comm_vpss_stop(&g_vpss_config);
exit2:
sample_comm_isp_stop(&g_isp_param);
exit1:
sample_comm_vi_stop(&g_vi_config);
exit0:
sample_comm_isp_exit(&g_isp_param);
sample_yuv_sys_deinit();
return -1;
}
/*******************************************************
* Processing Unit Operation Functions
*******************************************************/
/* Processing Unit Operation Functions End */
/*******************************************************
* Input Terminal Operation Functions
*******************************************************/
/* Input Terminal Operation Functions End */
/*******************************************************
* Stream Control Operation Functions
*******************************************************/
int sample_yuv_set_idr(void)
{
return 0;
}
int sample_yuv_init(void)
{
g_sensor_type = SENSOR0_TYPE;
sample_yuv_sys_init(g_sensor_type);
return 0;
}
int sample_yuv_startup(int fmt)
{
g_start = 1;
if (sample_yuv_normalp_classic() < 0) {
return -1;
}
g_tag_fmt = fmt;
if (g_tag_fmt == V4L2_PIX_FMT_YUYV) {
sample_yuv_create_yuyv_pool();
}
sample_yuv_start_get_stream(g_vpss_ochn, 1);
return 0;
}
int sample_yuv_shutdown(void)
{
if (!g_start) {
return 0;
}
sample_yuv_stop_get_stream();
sample_comm_sys_vi_unbind_vpss(g_vi_pipe, g_vi_chn, g_vpss_pipe, g_vpss_ichn);
sample_comm_vpss_stop(&g_vpss_config);
sample_comm_isp_stop(&g_isp_param);
sample_comm_vi_stop(&g_vi_config);
sample_comm_isp_exit(&g_isp_param);
sample_yuv_sys_deinit();
g_start = 0;
return 0;
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __SAMPLE_VIDEO_YUV_H__
#define __SAMPLE_VIDEO_YUV_H__
int sample_yuv_set_idr(void);
int sample_yuv_init(void);
int sample_yuv_startup(int fmt);
int sample_yuv_shutdown(void);
#endif
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __STREAM_H__
#define __STREAM_H__
#include "uvc_hal.h"
#include "sample_video.h"
//USB_Video_Payload_H_264_1.0 3.3
#define UVCX_PICTURE_TYPE_CONTROL 0x09
// H264 extension unit id, must same as to driver
#define UNIT_XU_H264 10
// CAMERA
#define UNIT_XU_CAMERA (0x11)
// VENDOR
#define UNIT_XU_VENDOR 11
typedef struct stream_control_ops {
int (*init)(void);
int (*deinit)(void);
int (*startup)(void);
int (*shutdown)(void);
int (*set_idr)(void);
int (*set_property)(struct encoder_property *p);
} stream_control_ops_st;
typedef struct processing_unit_ops {
uint16_t (*brightness_get)(void);
uint16_t (*contrast_get)(void);
uint16_t (*hue_get)(void);
uint8_t (*power_line_frequency_get)(void);
uint16_t (*saturation_get)(void);
uint8_t (*white_balance_temperature_auto_get)(void);
uint16_t (*white_balance_temperature_get)(void);
void (*brightness_set)(uint16_t v);
void (*contrast_set)(uint16_t v);
void (*hue_set)(uint16_t v);
void (*power_line_frequency_set)(uint8_t v);
void (*saturation_set)(uint16_t v);
void (*white_balance_temperature_auto_set)(uint8_t v);
void (*white_balance_temperature_set)(uint16_t v);
} processing_unit_ops_st;
typedef struct input_terminal_ops {
uint32_t (*exposure_ansolute_time_get)(void);
uint8_t (*exposure_auto_mode_get)(void);
void (*exposure_ansolute_time_set)(uint32_t v);
void (*exposure_auto_mode_set)(uint8_t v);
} input_terminal_ops_st;
typedef struct extension_unit_ops {
/*todo eu-h264 ops*/
/*todo eu-camera ops*/
} extension_unit_ops_st;
typedef struct stream
{
struct stream_control_ops *mpi_sc_ops;
struct processing_unit_ops *mpi_pu_ops;
struct input_terminal_ops *mpi_it_ops;
struct extension_unit_ops *mpi_eu_ops;
int streaming;
int exposure_auto_stall;
int brightness_stall;
} stream;
/* media control functions */
extern int stream_register_mpi_ops(struct stream_control_ops *sc_ops,
struct processing_unit_ops *pu_ops,
struct input_terminal_ops *it_ops,
struct extension_unit_ops *eu_ops);
extern int video_stream_set_enc_property(struct encoder_property *p);
extern int video_stream_init(void);
extern int video_stream_deinit(void);
extern int video_stream_shutdown(void);
extern int video_stream_startup(void);
extern int video_stream_set_enc_idr(void);
extern unsigned int stream_pu_get_brightness(void);
extern void stream_pu_set_brightness(unsigned int val);
extern unsigned int stream_pu_get_contrast(void);
extern void stream_pu_set_contrast(unsigned int val);
extern void stream_event_pu_setup(struct uvc_device *dev,
uint8_t req,
uint8_t unit_id,
uint8_t cs,
struct uvc_request_data* resp);
extern void stream_event_it_setup(struct uvc_device *dev,
uint8_t req,
uint8_t unit_id,
uint8_t cs,
struct uvc_request_data *resp);
extern void stream_event_eu_h264_setup(uint8_t req,
uint8_t unit_id,
uint8_t cs,
struct uvc_request_data *resp);
extern void stream_event_eu_camera_setup(uint8_t req,
uint8_t unit_id,
uint8_t cs,
struct uvc_request_data *resp);
extern void stream_event_eu_vendor1_setup(struct uvc_device *dev,
uint8_t req,
uint8_t unit_id,
uint8_t cs,
struct uvc_request_data *resp);
extern void stream_event_eu_h264_data(int unit_id, int control, struct uvc_request_data *data);
extern void stream_event_pu_data(int unit_id, int control, struct uvc_request_data *data);
extern void stream_event_it_data(int unit_id, int control, struct uvc_request_data *data);
extern void stream_event_eu_camera_data(int unit_id, int control, struct uvc_request_data *data);
extern void stream_event_eu_vendor1_data(int unit_id, int control, struct uvc_request_data *data);
#endif //__STREAM_H__
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include "uvc.h"
#include "uvc_hal.h"
#include "video_stream.h"
#include "uvc_log.h"
extern void video_stream_register(void);
static int g_uvc_run = 0;
static int __uvc_init(void)
{
video_stream_register();
video_stream_init();
return 0;
}
static int __uvc_deinit(void)
{
video_stream_deinit();
video_stream_unregister();
return 0;
}
static int __uvc_open(void)
{
return open_uvc_device();
}
static int __uvc_close(void)
{
return close_uvc_device();
}
static pthread_t g_pid_stream;
static pthread_t g_pid_contrl;
static void *uvc_stream_process(void *args)
{
uvc_logt("UVC stream process start.\n");
while (g_uvc_run) {
run_uvc_data();
}
uvc_logt("UVC stream process exit.\n");
return NULL;
}
static void *uvc_contrl_process(void *args)
{
uvc_logt("UVC contrl process start.\n");
while (g_uvc_run) {
run_uvc_device();
}
uvc_logt("UVC contrl process exit.\n");
return NULL;
}
static int __uvc_run(void)
{
int err;
g_uvc_run = 1;
uvc_logt("UVC run entry.\n");
err = pthread_create(&g_pid_stream, NULL, &uvc_stream_process, NULL);
if (err != 0) {
uvc_loge("Create uvc_stream_process failed.\n");
}
err = pthread_create(&g_pid_contrl, NULL, &uvc_contrl_process, NULL);
if (err != 0) {
uvc_loge("Create uvc_contrl_process failed.\n");
}
uvc_logt("UVC run ok.\n");
return 0;
}
static int __uvc_stop(void)
{
uvc_logt("UVC stop entry.\n");
g_uvc_run = 0;
pthread_join(g_pid_contrl, NULL);
pthread_join(g_pid_stream, NULL);
uvc_logt("UVC stop ok.\n");
return 0;
}
/* ---------------------------------------------------------------------- */
static uvc_t __uvc = {
.init = &__uvc_init,
.deinit = &__uvc_deinit,
.open = &__uvc_open,
.close = &__uvc_close,
.run = &__uvc_run,
.stop = &__uvc_stop,
};
uvc_t *get_uvc()
{
return &__uvc;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __UVC_LOG_H__
#define __UVC_LOG_H__
#include "log_base.h"
#undef TAG
#define TAG "UVC"
#define uvc_loge LOGE
#define uvc_logw LOGW
#define uvc_logi LOGI
#define uvc_logt LOGT
#define uvc_logd LOGD
#define func_entry() uvc_logd("entry\n")
#define func_success() uvc_logd("success\n")
#define func_fail() uvc_loge("failed\n")
#define check_null_goto(ptr, tag) do { \
if ((ptr) == NULL) { \
uvc_loge("invalid param.\n"); \
goto tag; \
} \
} while (0)
#endif