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
+17
View File
@@ -0,0 +1,17 @@
ifeq ($(CFG_XMEDIA_EXPORT_FLAG),)
SDK_DIR := $(shell cd $(CURDIR)/../.. && /bin/pwd)
endif
include $(SDK_DIR)/build/base.mk
include $(SAMPLE_DIR)/sample_base.mk
LIB_NAME := liblive_rtsp
SDK_USR_CFLAGS += $(SAMPLE_CFLAGS) $(SAMPLE_LIBS) $(SAMPLE_INCLUDES)
SRCS := $(wildcard ./common/*.c)
SRCS += $(wildcard ./liveserver/*.c)
SRCS += $(wildcard ./livestream/*.c)
SRCS += $(wildcard ./mbuffer/*.c)
include $(SDK_DIR)/build/sdk_lib_rules.mk
+173
View File
@@ -0,0 +1,173 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdarg.h>
#include "xcam_log.h"
#define COLOR_NONE "\033[m"
#define COLOR_RED "\033[0;32;31m"
#define COLOR_YELLOW "\033[1;33m"
#define XCAM_LOG_MAX_PREFIX 64
#define XCAM_LOG_MAX_PER_CONTENT 256
typedef struct {
xcam_log_attr attr;
xcam_u8 *log_buffer;
} xcam_log_global;
static pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
static xcam_log_global *g_xcam_log = XCAM_NULL;
#define XCAM_LOG_MUTEX_LOCK() \
do { \
(void)pthread_mutex_lock(&g_log_mutex); \
} while (0)
#define XCAM_LOG_MUTEX_UNLOCK() \
do { \
(void)pthread_mutex_unlock(&g_log_mutex); \
} while (0)
static xcam_void do_logout(xcam_char *prefix, xcam_char *content)
{
printf("%s%s", prefix, content);
printf("%s", COLOR_NONE);
return;
}
xcam_s32 xcam_log_init(xcam_void)
{
xcam_s32 ret = XCAM_SUCCESS;
XCAM_LOG_MUTEX_LOCK();
// already inited
if (g_xcam_log != XCAM_NULL) {
ret = XCAM_SUCCESS;
goto __err_unlock__;
}
g_xcam_log = (xcam_log_global *)malloc(sizeof(xcam_log_global));
if (g_xcam_log == XCAM_NULL) {
ret = XCAM_FAILURE;
goto __err_unlock__;
}
memset(g_xcam_log, 0x0, sizeof(xcam_log_global));
g_xcam_log->attr.mode = XCAM_LOG_MODE_PRINTF;
g_xcam_log->attr.level = XCAM_LOG_LEVEL_ERR;
XCAM_LOG_MUTEX_UNLOCK();
return XCAM_SUCCESS;
__err_unlock__:
XCAM_LOG_MUTEX_UNLOCK();
return ret;
}
xcam_void xcam_log_deinit(xcam_void)
{
XCAM_LOG_MUTEX_LOCK();
// already deinited
if (g_xcam_log == XCAM_NULL) {
XCAM_LOG_MUTEX_UNLOCK();
return;
}
free(g_xcam_log);
g_xcam_log = XCAM_NULL;
XCAM_LOG_MUTEX_UNLOCK();
return;
}
xcam_s32 xcam_log_set_attr(xcam_log_attr *attr)
{
XCAM_LOG_MUTEX_LOCK();
if (g_xcam_log == XCAM_NULL) {
XCAM_LOG_MUTEX_UNLOCK();
return XCAM_FAILURE;
}
memcpy(&g_xcam_log->attr, attr, sizeof(xcam_log_attr));
XCAM_LOG_MUTEX_UNLOCK();
return XCAM_SUCCESS;
}
xcam_s32 xcam_log_get_attr(xcam_log_attr *attr)
{
XCAM_LOG_MUTEX_LOCK();
if (g_xcam_log == XCAM_NULL) {
XCAM_LOG_MUTEX_UNLOCK();
return XCAM_FAILURE;
}
memcpy(attr, &g_xcam_log->attr, sizeof(xcam_log_attr));
XCAM_LOG_MUTEX_UNLOCK();
return XCAM_SUCCESS;
}
xcam_void xcam_log_output(const xcam_char *module, xcam_log_level level, const xcam_char *func, xcam_u32 line, const xcam_char *format, ...)
{
xcam_char prefix[XCAM_LOG_MAX_PREFIX] = {0};
xcam_char content[XCAM_LOG_MAX_PER_CONTENT] = {0};
va_list args;
if (!g_xcam_log || level > g_xcam_log->attr.level) {
return;
}
switch (level) {
case XCAM_LOG_LEVEL_DBG:
snprintf(prefix, 64, "%s[%s-DEBUG][%s-%u]: ", COLOR_NONE, module, func, line);
break;
case XCAM_LOG_LEVEL_INFO:
snprintf(prefix, 64, "%s[%s-INFO][%s-%u]: ", COLOR_NONE, module, func, line);
break;
case XCAM_LOG_LEVEL_WARN:
snprintf(prefix, 64, "%s[%s-WARN][%s-%u]: ", COLOR_YELLOW, module, func, line);
break;
case XCAM_LOG_LEVEL_ERR:
snprintf(prefix, 64, "%s[%s-ERROR][%s-%u]: ", COLOR_RED, module, func, line);
break;
case XCAM_LOG_LEVEL_FATAL:
snprintf(prefix, 64, "%s[%s-FATAL][%s-%u]: ", COLOR_RED, module, func, line);
break;
default:
return;
}
va_start(args, format);
vsnprintf(content, XCAM_LOG_MAX_PER_CONTENT, format, args);
// if the content is too long, ensure it has an end.
if (content[XCAM_LOG_MAX_PER_CONTENT - 1] != '\0') {
content[XCAM_LOG_MAX_PER_CONTENT - 5] = '.';
content[XCAM_LOG_MAX_PER_CONTENT - 4] = '.';
content[XCAM_LOG_MAX_PER_CONTENT - 3] = '.';
content[XCAM_LOG_MAX_PER_CONTENT - 2] = '\n';
content[XCAM_LOG_MAX_PER_CONTENT - 1] = '\0';
}
va_end(args);
do_logout(prefix, content);
return;
}
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef __LIST_H__
#define __LIST_H__
#ifndef _LINUX_LIST_H
#define INIT_LIST_HEAD(ptr) \
do { \
(ptr)->next = (ptr); \
(ptr)->prev = (ptr); \
} while (0)
#define LIST_HEAD_INIT(name) { &(name), &(name) }
struct list_head {
struct list_head *next, *prev;
};
static inline void __list_add(struct list_head * _new, struct list_head * prev, struct list_head * next)
{
next->prev = _new;
_new->next = next;
_new->prev = prev;
prev->next = _new;
}
static inline void list_add(struct list_head *_new, struct list_head *head)
{
__list_add(_new, head, head->next);
}
static inline void list_add_tail(struct list_head *_new, struct list_head *head)
{
__list_add(_new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
static inline int list_empty(struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
{
__list_splice(list, head);
}
}
static inline void list_splice_init(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
{
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
#define list_entry(ptr, type, member) \
((type *)((uintptr_t)(ptr)-((unsigned long)(&((type *)1)->member) - 1)))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define get_first_item(attached, type, member) \
((type *)((char *)((attached)->next)-(unsigned long)(&((type *)0)->member)))
#endif
#endif
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef __XCAM_COMMON_H__
#define __XCAM_COMMON_H__
#include <stdlib.h>
#include "xcam_type.h"
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif
typedef enum {
/* common */
XCAM_MOD_COMMON = 0x0,
XCAM_MOD_LOG = 0x1,
/* middleware */
XCAM_MOD_EVTHUB = 0x100,
XCAM_MOD_MBUF = 0x101,
XCAM_MOD_STORAGE = 0x102,
XCAM_MOD_TIMER = 0x103,
XCAM_MOD_MSGHANDLE = 0x104,
XCAM_MOD_BARCODE = 0x105,
XCAM_MOD_DCF = 0x106,
XCAM_MOD_DTCF = 0x107,
XCAM_MOD_TS = 0x108,
XCAM_MOD_MP4 = 0x109,
XCAM_MOD_EXIF = 0x10A,
XCAM_MOD_FSTOOL = 0x10B,
XCAM_MOD_RECORD = 0x10C,
XCAM_MOD_LIVESTREAM = 0x10D,
XCAM_MOD_STATEMACHINE = 0x10E,
XCAM_MOD_SYSLINK = 0x110,
XCAM_MOD_MAPI = 0x111,
XCAM_MOD_RTSP = 0x112,
/* product wrapper layer */
XCAM_MOD_FLASH = 0x200,
XCAM_MOD_CONFACCESS = 0x201,
XCAM_MOD_DEVMNG = 0x202,
XCAM_MOD_FILEMNG = 0x203,
XCAM_MOD_FILETRANS = 0x204,
XCAM_MOD_DEVHAL = 0x205,
XCAM_MOD_LIVESERVER = 0x206,
XCAM_MOD_MEDIA = 0x207,
XCAM_MOD_NETSERV = 0x208,
XCAM_MOD_PHOTOMNG = 0x209,
XCAM_MOD_PLAYBACK = 0x20A,
XCAM_MOD_PM = 0x20B,
XCAM_MOD_QUEUE = 0x20C,
XCAM_MOD_RAWCAP = 0x20D,
XCAM_MOD_RECORDMNG = 0x20E,
XCAM_MOD_SCENCEAUTO = 0x210,
XCAM_MOD_STORAGEMNG = 0x211,
XCAM_MOD_SYSCTL = 0x212,
XCAM_MOD_TIMEDTASK = 0x213,
XCAM_MOD_TIMESTAMP = 0x214,
XCAM_MOD_UPGRADE = 0x215,
XCAM_MOD_USBMNG = 0x216,
XCAM_MOD_VIDANALISIS = 0x217,
XCAM_MOD_VIDPROCESS = 0x218,
XCAM_MOD_UTILS = 0X219,
/* application */
XCAM_MOD_APPLICATION = 0x300,
XCAM_MOD_MAX
} xcam_mod_id;
#define XCAM_BUILD_ERRNO(module, errno) ((xcam_u32)((0x80000000L) | ((module) << 16) | (errno)))
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _XCAM_LIVESERVER_H_
#define _XCAM_LIVESERVER_H_
#include "xcam_define.h"
#include "xcam_log.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
/* name pattern that used in webserver distrib link */
#define XCAM_LIVESERVER_CONN_CNT_MIN 1
#define XCAM_LIVESERVER_CONN_CNT_MAX 32
enum {
ERR_CODE_INVALID_PARAM = 0x10,
ERR_CODE_NOT_INIT = 0x11,
ERR_CODE_WAS_INITED = 0x12,
ERR_CODE_ALREADY_EXISTED = 0x13,
ERR_CODE_NOT_FIND = 0x14,
ERR_CODE_NO_FREE_RESOURCE = 0x15,
ERR_CODE_BUTT
};
/* general error code */
#define XCAM_LIVESERVER_ERR_ILLEGAL_PARAM XCAM_BUILD_ERRNO(XCAM_MOD_LIVESERVER, ERR_CODE_INVALID_PARAM)
#define XCAM_LIVESERVER_ERR_NOT_INIT XCAM_BUILD_ERRNO(XCAM_MOD_LIVESERVER, ERR_CODE_NOT_INIT)
#define XCAM_LIVESERVER_ERR_WAS_INITED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESERVER, ERR_CODE_WAS_INITED)
#define XCAM_LIVESERVER_ERR_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESERVER, ERR_CODE_ALREADY_EXISTED)
#define XCAM_LIVESERVER_ERR_NOT_FIND XCAM_BUILD_ERRNO(XCAM_MOD_LIVESERVER, ERR_CODE_NOT_FIND)
#define XCAM_LIVESERVER_ERR_NO_FREE_RESOURCE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESERVER, ERR_CODE_NO_FREE_RESOURCE)
#define LOG_LIVESERVER_INFO(fmt...) XCAM_LOG_INFO_PRINT("liveserver", fmt);
#define LOG_LIVESERVER_WARN(fmt...) XCAM_LOG_WARN_PRINT("liveserver", fmt);
#define LOG_LIVESERVER_ERROR(fmt...) XCAM_LOG_ERR_PRINT("liveserver", fmt);
#define LOG_LIVESERVER_FATAL(fmt...) XCAM_LOG_FATAL_PRINT("liveserver", fmt);
#define PATTERN_NAME_LEN 16
typedef struct {
xcam_s32 max_conn_num;
xcam_u16 listen_port;
xcam_char pattern_name[PATTERN_NAME_LEN];
} xcam_liveserver_init_param;
xcam_s32 xcam_liveserver_add_stream(xcam_handle venc_handle, xcam_track_video_source_info *video_src_info,
xcam_handle aenc_handle, xcam_track_audio_source_info *audio_src_info,
const xcam_char* stream_name,
func_xcam_track_source_request_key_frame func_request_key_frame);
xcam_s32 xcam_liveserver_remove_stream(const xcam_char* stream_name);
xcam_s32 xcam_liveserver_remove_all_stream(xcam_void);
xcam_bool xcam_liveserver_is_init(xcam_void);
xcam_s32 xcam_liveserver_init(const xcam_liveserver_init_param param);
xcam_s32 xcam_liveserver_deinit(xcam_void);
xcam_s32 xcam_liveserver_send_video_data(xcam_handle venc_handle, xcam_livestream_rtsp_data *rtsp_data);
xcam_s32 xcam_liveserver_send_audio_data(xcam_handle aenc_handle, xcam_livestream_rtsp_data *rtsp_data);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif /* _XCAM_LIVESERVER_H_ */
@@ -0,0 +1,150 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _XCAM_LIVESTREAM_RTSP_SERVER_H_
#define _XCAM_LIVESTREAM_RTSP_SERVER_H_
#include "xcam_track_source.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
typedef struct server_state_listener {
/**
* @brief report of server internal error.
* @param[in] listener :listener obj
* @param[in] errid : server error id
* @param[in] msg : string server error message info
*/
xcam_void (*func_server_error)(struct server_state_listener* listener, xcam_s32 errid, xcam_char* msg);
/**
* @brief reporting client connected.
* @param[in] listener : listener obj
* @param[in] ipaddr : string connected client ipaddress
*/
xcam_void (*func_client_connect)(struct server_state_listener* listener, xcam_char* ipaddr);
/**
* @brief reporting client disconnected.
* @param[in] listener : listener obj
* @param[in] ipaddr : string disconnected client ipaddress
*/
xcam_void (*func_client_disconnect)(const struct server_state_listener* listener, const xcam_char* ipaddr);
/** handle for statelistener, do not change, used internal*/
xcam_void* handle;
} xcam_server_state_listener;
#define RTSPSVR_FRAME_MAX_BLOCK (8)
/** RTSP config object type*/
typedef struct {
xcam_s32 packet_len; /**< length of the send packet [500,5000]recommend 1500 unit:byte*/
xcam_s32 max_conn_num; /**< max connect client num[1,32]*/
xcam_s32 listen_port; /**< listen port of rtspserver[1,65535] normal 554*/
xcam_s32 max_payload; /**< max payloadtype num in mbuffer[1,254] normal 2*/
xcam_s32 timeout; /**<set the timeout of connect <0 for not use timeout unit: s*/
} xcam_livestream_rtsp_config;
typedef struct {
xcam_u8* data_ptr[RTSPSVR_FRAME_MAX_BLOCK]; /**< data address */
xcam_u32 data_len[RTSPSVR_FRAME_MAX_BLOCK]; /**< length of frame data */
xcam_u64 pts_us; /**< timestamp of frame unit:us*/
xcam_u32 seq_num; /**< frame sequence number */
xcam_u32 block_cnt;/**< block count for one frame*/
xcam_bool is_key_frame; /**< key frame flag */
} xcam_livestream_rtsp_data;
typedef struct {
xcam_track_source_handle video_src_handle;
xcam_track_source_handle audio_src_handle;
} xcam_livestream_rtsp_source;
/**
* @brief create server instance.
* @param[in,out] handle xcam_void* : return rtspserver handle
* @param[in] ptr_rtsp_config xcam_livestream_rtsp_config : rtsp config info
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_create(xcam_void** handle, xcam_livestream_rtsp_config* ptr_rtsp_config);
/**
* @brief destroy server instance.
* @param[in] handle xcam_void* : rtspserver handle
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_destroy(xcam_void* handle);
/**
* @brief make server running, could handle client connecting and request.
* @param[in] handle xcam_void* : rtspserver handle
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_start(xcam_void* handle);
/**
* @brief make server stoped, deny client connecting and request.
* @param[in] handle xcam_void* : rtspserver handle
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_stop(xcam_void* handle);
/**
* @brief add media source to server, client could use specified URL \n
* related with stream connect to this source.
* @param[in] handle xcam_void* : rtspserver handle
* @param[in] stream_name string : stream Name related with this mediaStream,max length 128
* @param[in] buf_size XM_U32: size of allocate mbuffer[216K,50M] suggest frame size*5 unit:byte
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_add_media_stream(xcam_void* handle, xcam_livestream_rtsp_source* stream_src,
xcam_char* stream_name, xcam_u32 buf_size);
/**
* @brief remove media source from server, client connecting with \n
* specified URL related with this stream will receive failing
* @param[in] handle xcam_void* : rtspserver handle
* @param[in] track_src xcam_track_source_handle : Source of outputing MediaInfo and \n
* @param[in] ptr_data xcam_livestream_rtsp_data : Media data \n
* VideoStream&AudioStream
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_write_frame(xcam_void* handle,
xcam_track_source_handle track_src, const xcam_livestream_rtsp_data* ptr_data);
/**
* @brief remove media source from server, client connecting with \n
* specified URL related with this stream will receive failing
* @param[in] handle xcam_void* : rtspserver handle
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_remove_media_stream(xcam_void* handle, const xcam_char* stream_name);
/**
* @brief setting listener for listenning client connect&disconnect, server internal error.
* @param[in] handle xcam_void* : rtspserver handle
* @param[in] ptr_listener xcam_server_state_listener : input listener object
* @return 0 success
* @return err num failure
*/
xcam_s32 xcam_livestream_rtsp_server_set_listener(xcam_void* handle, xcam_server_state_listener* ptr_listener);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif /*_XCAM_LIVESTREAM_RTSP_SERVER_H_*/
+93
View File
@@ -0,0 +1,93 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef __XCAM_LOG_H__
#define __XCAM_LOG_H__
#include "xcam_type.h"
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif
typedef enum {
XCAM_LOG_LEVEL_FATAL = 0,
XCAM_LOG_LEVEL_ERR = 1,
XCAM_LOG_LEVEL_WARN = 2,
XCAM_LOG_LEVEL_INFO = 3,
XCAM_LOG_LEVEL_DBG = 4
} xcam_log_level;
typedef enum {
XCAM_LOG_MODE_PRINTF,
XCAM_LOG_MODE_FILE
} xcam_log_mode;
typedef struct {
xcam_log_level level;
xcam_log_mode mode;
xcam_u32 log_buffer_size;
} xcam_log_attr;
#define XCAM_LOG_TRACE(module, level, format...) \
do { \
xcam_log_output(module, level, __FUNCTION__, __LINE__, format); \
} while (0)
// use this config macro to optimize code size
#ifndef CONFIG_XCAM_LOG_LEVEL
#define CONFIG_XCAM_LOG_LEVEL 4
#endif
#if (CONFIG_XCAM_LOG_LEVEL == XCAM_LOG_LEVEL_FATAL)
#define XCAM_LOG_FATAL_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_FATAL, format)
#define XCAM_LOG_ERR_PRINT(module, format...)
#define XCAM_LOG_WARN_PRINT(module, format...)
#define XCAM_LOG_INFO_PRINT(module, format...)
#define XCAM_LOG_DBG_PRINT(module, format...)
#elif (CONFIG_XCAM_LOG_LEVEL == XCAM_LOG_LEVEL_ERR)
#define XCAM_LOG_FATAL_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_FATAL, format)
#define XCAM_LOG_ERR_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_ERR, format)
#define XCAM_LOG_WARN_PRINT(module, format...)
#define XCAM_LOG_INFO_PRINT(module, format...)
#define XCAM_LOG_DBG_PRINT(module, format...)
#elif (CONFIG_XCAM_LOG_LEVEL == XCAM_LOG_LEVEL_WARN)
#define XCAM_LOG_FATAL_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_FATAL, format)
#define XCAM_LOG_ERR_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_ERR, format)
#define XCAM_LOG_WARN_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_WARN, format)
#define XCAM_LOG_INFO_PRINT(module, format...)
#define XCAM_LOG_DBG_PRINT(module, format...)
#elif (CONFIG_XCAM_LOG_LEVEL == XCAM_LOG_LEVEL_INFO)
#define XCAM_LOG_FATAL_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_FATAL, format)
#define XCAM_LOG_ERR_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_ERR, format)
#define XCAM_LOG_WARN_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_WARN, format)
#define XCAM_LOG_INFO_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_INFO, format)
#define XCAM_LOG_DBG_PRINT(module, format...)
#else
#define XCAM_LOG_FATAL_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_FATAL, format)
#define XCAM_LOG_ERR_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_ERR, format)
#define XCAM_LOG_WARN_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_WARN, format)
#define XCAM_LOG_INFO_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_INFO, format)
#define XCAM_LOG_DBG_PRINT(module, format...) XCAM_LOG_TRACE(module, XCAM_LOG_LEVEL_DBG, format)
#endif
xcam_s32 xcam_log_init(xcam_void);
xcam_void xcam_log_deinit(xcam_void);
xcam_s32 xcam_log_set_attr(xcam_log_attr *attr);
xcam_s32 xcam_log_get_attr(xcam_log_attr *attr);
xcam_void xcam_log_output(const xcam_char *module, xcam_log_level level, const xcam_char *func, xcam_u32 line, const xcam_char *format, ...);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
+170
View File
@@ -0,0 +1,170 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef __XCAM_MBUF_H__
#define __XCAM_MBUF_H__
#include "xcam_type.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define XCAM_MBUF_MAX_PACK (8)
#define XCAM_MBUF_PAYLOAD_TYPE_ALL (0xFFFE)
#define XCAM_MBUF_PAYLOAD_TYPE_INVALID (0xFFFF)
/* error number */
#define XCAM_ERR_MBUF_BASE XCAM_FAILURE
#define XCAM_ERR_MBUF_MUTEX_INIT_FAILED (XCAM_ERR_MBUF_BASE - 1)
#define XCAM_ERR_MBUF_PARAM_INVALID (XCAM_ERR_MBUF_BASE - 2)
#define XCAM_ERR_MBUF_ALLOC_FAILED (XCAM_ERR_MBUF_BASE - 3)
#define XCAM_ERR_MBUF_ADDR_NULL (XCAM_ERR_MBUF_BASE - 4)
#define XCAM_ERR_MBUF_NO_MEMORY (XCAM_ERR_MBUF_BASE - 5)
#define XCAM_ERR_MBUF_BUFFER_FULL (XCAM_ERR_MBUF_BASE - 6)
#define XCAM_ERR_MBUF_BUFFER_EMPTY (XCAM_ERR_MBUF_BASE - 7)
#define XCAM_ERR_MBUF_FREE_ERR (XCAM_ERR_MBUF_BASE - 8)
#define XCAM_ERR_MBUF_GET_BUF_FAILED (XCAM_ERR_MBUF_BASE - 9)
#define XCAM_ERR_MBUF_PUT_BUF_FAILED (XCAM_ERR_MBUF_BASE - 10)
#define XCAM_ERR_MBUF_READ_FAILED (XCAM_ERR_MBUF_BASE - 11)
#define XCAM_ERR_MBUF_BUSY (XCAM_ERR_MBUF_BASE - 12)
#define XCAM_ERR_MBUF_PAYLOAD_CHECK_ERR (XCAM_ERR_MBUF_BASE - 13)
#define XCAM_ERR_MBUF_NOT_REGISTERED (XCAM_ERR_MBUF_BASE - 14)
#define XCAM_ERR_MBUF_RELEASE_FAILED (XCAM_ERR_MBUF_BASE - 15)
/* mbuffer config */
typedef struct cam_mbuf_cfg_s {
xcam_u32 buf_size; /* memory size of mbuffer */
xcam_s32 payload_count; /* max patload type num in mbuffer */
} xcam_mbuf_cfg;
/* mbuffer pack info */
typedef struct cam_mbuf_pack_info_s {
xcam_u64 pts; /* timestamp if the frame */
xcam_u32 seq; /* sequence num of the frame */
xcam_u16 payload_type; /* mbuffer data payload type 0~0xFFF0,0xFFFE:all,0xFFFF:invalid */
xcam_u8 key_frame; /* whether keyframe or not */
xcam_u8 pack_count; /* pack_count < XCAM_MBUF_MAX_PACK*/
xcam_u8 *pack_addr[XCAM_MBUF_MAX_PACK]; /* start address of the data block */
xcam_u32 pack_size[XCAM_MBUF_MAX_PACK]; /* len of the block data agree with pAdder */
} xcam_mbuf_pack_info;
/*
* Create the instant of mbuf, allocate buf.
* param[in] xcam_mbuf_cfg *mbuf_cfg: property of buffer
* param[out] xcam_void **handle: mbuf handle
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_ERR_MBUF_ALLOC_FAILED buffer malloc failed
* XCAM_ERR_MBUF_MUTEX_INIT_FAILED
*/
xcam_s32 xcam_mbuf_get_buffer(xcam_handle **handle, xcam_mbuf_cfg *mbuf_cfg);
/*
* Realse mbuffer.
* param[in] xcam_void *handle: mbuf handle
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
*/
xcam_s32 xcam_mbuf_release_buffer(xcam_handle *handle);
/*
* register MBUF payload type, for example 0 for video 1 for audio.
* param[in] xcam_void * handle: mbuf handle
* param[in] xcam_u16 payload_type: payload type
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_FAILURE regiter space is full
*/
xcam_s32 xcam_mbuf_register_payload(xcam_handle *handle, xcam_u16 payload_type);
/*
* unregister MBUF payload type.
* param[in] xcam_void * handle: mbuf handle
* param[in] xcam_u16 payload_type: payload type
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_FAILURE
*/
xcam_s32 xcam_mbuf_unregister_payload(xcam_handle *handle, xcam_u16 payload_type);
/*
* Set read/write status of mbuf, according to the payload type.
* param[in] xcam_void * handle: muf handle
* param[in] xcam_u16 payload_type: payload type
* param[in] xcam_bool enable_read : enable read ptr or not
* param[in] xcam_bool enable_write: enable write ptr or not
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_FAILURE payload not found
*/
xcam_s32 xcam_mbuf_set_rw_enable(xcam_handle *handle, xcam_u16 payload_type, xcam_bool enable_read, xcam_bool enable_write);
/*
* Get the read/write status of mbuffer, according to the payload type.
* param[in] xcam_void *handle: the handle of mbuf
* param[in] xcam_u16 payload_type: payload type
* param[in] xcam_bool *enable_read : enable read ptr or not
* param[in] xcam_bool *enable_write: enable write ptr or not
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_ERR_MBUF_NOT_REGISTERED
*/
xcam_s32 xcam_mbuf_get_rw_enable(xcam_handle *handle, xcam_u16 payload_type, xcam_bool *enable_read, xcam_bool *enable_write);
/*
* Write package into mbuf
* param[in] xcam_void * handle: mbuf handle
* param[in] xcam_mbuf_pack_info *pack_info pack info data
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID,XCAM_ERR_MBUF_GET_BUF_FAILED,XCAM_ERR_MBUF_PUT_BUF_FAILED
* XCAM_ERR_MBUF_FULL,XCAM_ERR_MBUF_BUSY,
* XCAM_ERR_MBUF_BUSY
*/
xcam_s32 xcam_mbuf_write_pack(xcam_handle *handle, const xcam_mbuf_pack_info *pack_info);
/*
* Read data from mbuf
* param[in] xcam_void * handle: mbuf handle
* param[in] xcam_u16 payload_type payload type
* param[out] xcam_mbuf_pack_info *pack_info read out pack info
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_ERR_MBUF_BUFFER_EMPTY
* XCAM_ERR_MBUF_PAYLOAD_CHECK_ERR no such data of the giving payload type
*/
xcam_s32 xcam_mbuf_read_pack(xcam_handle *handle, xcam_u16 payload_type, xcam_mbuf_pack_info *pack_info);
/*
* Forward the read ptr for the payload type data
* param[in] xcam_void * handle: mbuf handle
* param[in] xcam_u16 payload_type: payload type
* param[out] xcam_u32 step: moving steps for the read ptr,1 for move one package after
* return XCAM_SUCCESS success
* XCAM_ERR_MBUF_PARAM_INVALID illegal params
* XCAM_ERR_MBUF_RELEASE_FAILED
*/
xcam_s32 xcam_mbuf_forward(xcam_handle *handle, xcam_u16 payload_type, xcam_u32 step);
/*
* Print the debug info
*/
xcam_s32 xcam_mbuf_debug(xcam_handle *handle, xcam_u16 payload_type);
/*
* Get package data offset
*/
xcam_s32 xcam_mbuf_get_package_data_offset(xcam_handle *handle, const xcam_mbuf_pack_info *pack_info, xcam_u32 *offset);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* __XCAM_MBUF_H__ */
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _XCAM_TRACK_SOURCE_H_
#define _XCAM_TRACK_SOURCE_H_
#include "xcam_type.h"
typedef enum {
XCAM_TRACK_SOURCE_TYPE_PRIV = 0,
XCAM_TRACK_SOURCE_TYPE_VIDEO,
XCAM_TRACK_SOURCE_TYPE_AUDIO,
XCAM_TRACK_SOURCE_TYPE_BUTT
} xcam_track_source_type;
typedef enum {
XCAM_TRACK_VIDEO_CODEC_H264 = 96,
XCAM_TRACK_VIDEO_CODEC_H265 = 98,
XCAM_TRACK_VIDEO_CODEC_MJPEG = 102,
XCAM_TRACK_VIDEO_CODEC_BUTT
} xcam_track_video_codec;
typedef enum {
XCAM_TRACK_AUDIO_CODEC_G711U = 0, /* G.711 U */
XCAM_TRACK_AUDIO_CODEC_G711A = 8, /* G.711 A */
XCAM_TRACK_AUDIO_CODEC_LPCM = 23, /* LPCM see cam_common.h file from sdk */
XCAM_TRACK_AUDIO_CODEC_G726 = 97, /* G.726 */
XCAM_TRACK_AUDIO_CODEC_AMR = 101, /* AMR encoder format */
XCAM_TRACK_AUDIO_CODEC_ADPCM = 104, /* ADPCM */
XCAM_TRACK_AUDIO_CODEC_AAC = 105,
XCAM_TRACK_AUDIO_CODEC_WAV = 108, /* WAV encoder */
XCAM_TRACK_AUDIO_CODEC_MP3 = 109,
XCAM_TRACK_AUDIO_CODEC_BUTT
} xcam_track_audio_codec;
typedef struct {
xcam_track_video_codec codec_type;
xcam_u32 width;
xcam_u32 height;
xcam_u32 bit_rate;
xcam_float frame_rate;
xcam_u32 gop;
xcam_float speed;
} xcam_track_video_source_info;
typedef struct {
xcam_track_audio_codec codec_type;
xcam_u32 chn_cnt;
xcam_u32 sample_rate;
xcam_u32 avg_bytes_per_sec;
xcam_u32 samples_per_frame;
xcam_u16 sample_bit_width;
} xcam_track_audio_source_info;
typedef struct {
xcam_u32 private_data;
xcam_float frame_rate;
xcam_u32 bytes_per_sec;
xcam_bool is_strict_sync;
} xcam_track_private_source_info;
typedef struct cam_track_source* xcam_track_source_handle;
typedef xcam_s32 (*func_xcam_track_source_request_key_frame)(xcam_handle venc_handle, xcam_void* param);
typedef struct cam_track_source {
intptr_t private_handle; // venc or aenc handle
func_xcam_track_source_request_key_frame func_request_key_frame;
xcam_track_source_type track_type;
union {
xcam_track_video_source_info video_info; /** video track info */
xcam_track_audio_source_info audio_info; /** audio track info */
xcam_track_private_source_info priv_info; /** private track info */
} track_source_attr;
} xcam_track_source;
#endif // _XCAM_TRACK_SOURCE_H_
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef __XCAM_TYPE_H__
#define __XCAM_TYPE_H__
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif
typedef enum {
XCAM_FALSE = 0,
XCAM_TRUE = 1,
} xcam_bool;
#ifndef NULL
#define NULL 0L
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define XCAM_NULL 0L
#define XCAM_SUCCESS 0
#define XCAM_FAILURE (-1)
typedef unsigned char xcam_uchar;
typedef unsigned char xcam_u8;
typedef unsigned short xcam_u16;
typedef unsigned int xcam_u32;
typedef unsigned long long xcam_u64;
typedef unsigned long xcam_ulong;
typedef char xcam_char;
typedef signed char xcam_s8;
typedef short xcam_s16;
typedef int xcam_s32;
typedef long long xcam_s64;
typedef long xcam_slong;
typedef float xcam_float;
typedef double xcam_double;
typedef void xcam_void;
typedef unsigned long xcam_size_t;
typedef unsigned long xcam_length_t;
typedef xcam_u32 xcam_handle;
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif
+489
View File
@@ -0,0 +1,489 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <string.h>
#include <stdio.h>
#include "xcam_type.h"
#include "xcam_track_source.h"
#include "xcam_livestream_rtsp_server.h"
#include "xcam_liveserver.h"
#define LIVESVR_RTSP_PACKET_LEN 1500 /* packet length, value[500,5000], recommend 1500, unit:byte */
#define LIVESVR_RTSP_DEF_LISTEN_PORT 554 /* value[1,65535], normal 554 */
#define LIVESVR_RTSP_MAX_PAYLOAD_CNT 8 /* max payload num in mbuffer, value[1,254] */
#define LIVESVR_RTSP_TIMEOUT_SEC -1 /* <0: not use timeout, unit:s */
#define LIVESVR_RTSP_MAX_STREAM_CNT 4
#define LIVESVR_VIDEO_MBUFFER_FRAME 5
#define LIVESVR_PATH_MAX 64
#define LIVESVR_AUDIO_MBUFFER_SIZE (16 << 10) /* 16K */
#define RTSP_MIN_MBUFFER_SIZE (216 << 10) /* 216K */
#define RTSP_MAX_MBUFFER_SIZE (3 << 20) /* 3M */
#define LIVESVR_DEF_PATTERN_NAME "livestream"
#define INVALID_TRACK (-1)
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
typedef struct {
xcam_bool is_used;
xcam_char stream_name[LIVESVR_PATH_MAX];
xcam_track_source track_video_src;
xcam_track_source track_audio_src;
} xcam_liveserver_rtsp_stream_ctx;
typedef struct {
xcam_bool is_initialized;
xcam_void* rtspserv_obj;
xcam_liveserver_rtsp_stream_ctx rtsp_stream_ctx[LIVESVR_RTSP_MAX_STREAM_CNT];
xcam_char pattern_path[PATTERN_NAME_LEN];
} xcam_liveserver_context;
static xcam_liveserver_context g_xcam_liveserver_ctx;
static xcam_void client_connect_callback(xcam_server_state_listener* listener, xcam_char* ipaddr)
{
if (listener == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Null pointer [listener]!\n");
}
if (ipaddr == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Null pointer [ipaddr]!\n");
return;
}
LOG_LIVESERVER_INFO("client connect, ipaddr(%s).\n", ipaddr);
return;
}
static xcam_void client_disconnect_callback(const xcam_server_state_listener* listener, const xcam_char* ipaddr)
{
if (listener == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Null pointer [listener]!\n");
}
if (ipaddr == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Null pointer [ipaddr]!\n");
return;
}
LOG_LIVESERVER_INFO("client disconnect, ipaddr(%s)!\n", ipaddr);
return;
}
static xcam_void server_error_callback(xcam_server_state_listener* listener, xcam_s32 err_id, xcam_char* err_msg)
{
if (listener == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Null pointer [listener]!\n");
}
if (err_msg == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Null pointer [err_msg]!\n");
return;
}
LOG_LIVESERVER_INFO("server error, err_id(%d) err_msg(%s)!\n", err_id, err_msg);
return;
}
static xcam_s32 init_rtsp_server(const xcam_s32 max_conn_num, const xcam_u16 lsn_port)
{
xcam_server_state_listener listener;
xcam_livestream_rtsp_config rtsp_cfg;
xcam_s32 ret;
rtsp_cfg.listen_port = (xcam_s32)lsn_port;
rtsp_cfg.max_conn_num = max_conn_num;
rtsp_cfg.max_payload = LIVESVR_RTSP_MAX_PAYLOAD_CNT;
rtsp_cfg.packet_len = LIVESVR_RTSP_PACKET_LEN;
rtsp_cfg.timeout = LIVESVR_RTSP_TIMEOUT_SEC;
ret = xcam_livestream_rtsp_server_create(&g_xcam_liveserver_ctx.rtspserv_obj, &rtsp_cfg);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Create rtsp server failed, ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
listener.func_client_connect = client_connect_callback;
listener.func_client_disconnect = client_disconnect_callback;
listener.func_server_error = server_error_callback;
ret = xcam_livestream_rtsp_server_set_listener(g_xcam_liveserver_ctx.rtspserv_obj, &listener);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Set rtsp server listener failed, ret:0x%x!\n", ret);
(xcam_void)xcam_livestream_rtsp_server_destroy(g_xcam_liveserver_ctx.rtspserv_obj);
return XCAM_FAILURE;
}
LOG_LIVESERVER_INFO("Start rtsp server, listen port[%u] max conn count[%d]!\n",
lsn_port, max_conn_num);
ret = xcam_livestream_rtsp_server_start(g_xcam_liveserver_ctx.rtspserv_obj);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Start rtsp server failed, ret:0x%x!\n", ret);
(xcam_void)xcam_livestream_rtsp_server_destroy(g_xcam_liveserver_ctx.rtspserv_obj);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
static xcam_void deinit_rtsp_server(xcam_void)
{
xcam_s32 ret;
ret = xcam_livestream_rtsp_server_stop(g_xcam_liveserver_ctx.rtspserv_obj);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("rtsp server stop failed, ret:0x%X!\n", ret);
}
ret = xcam_livestream_rtsp_server_destroy(g_xcam_liveserver_ctx.rtspserv_obj);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("rtsp server destroy failed, ret:0x%X!\n", ret);
}
}
static xcam_s32 get_available_stream_context(const xcam_char* stream_name, xcam_liveserver_rtsp_stream_ctx** stream_ctx)
{
xcam_u32 idx;
for (idx = 0; idx < LIVESVR_RTSP_MAX_STREAM_CNT; ++idx) {
if (g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].is_used) {
if (strncmp(g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].stream_name, stream_name, LIVESVR_PATH_MAX) == 0) {
LOG_LIVESERVER_ERROR("stream_name[%s] already exists!\n", stream_name);
return XCAM_LIVESERVER_ERR_EXISTED;
}
}
}
for (idx = 0; idx < LIVESVR_RTSP_MAX_STREAM_CNT; ++idx) {
if (!g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].is_used) {
*stream_ctx = &g_xcam_liveserver_ctx.rtsp_stream_ctx[idx];
break;
}
}
if (*stream_ctx == XCAM_NULL) {
LOG_LIVESERVER_ERROR("Beyond max stream count!\n");
return XCAM_LIVESERVER_ERR_NO_FREE_RESOURCE;
}
return XCAM_SUCCESS;
}
static xcam_s32 get_rtsp_stream_context(xcam_handle venc_handle, xcam_track_video_source_info *video_src_info,
xcam_handle aenc_handle, xcam_track_audio_source_info *audio_src_info,
const xcam_char* stream_name, xcam_liveserver_rtsp_stream_ctx* stream_ctx)
{
xcam_s32 ret;
if (venc_handle != (xcam_handle)INVALID_TRACK) {
memcpy(&stream_ctx->track_video_src.track_source_attr.video_info, video_src_info,
sizeof(xcam_track_video_source_info));
stream_ctx->track_video_src.private_handle = venc_handle;
stream_ctx->track_video_src.track_type = XCAM_TRACK_SOURCE_TYPE_VIDEO;
} else {
stream_ctx->track_video_src.private_handle = INVALID_TRACK;
}
if (aenc_handle != (xcam_handle)INVALID_TRACK) {
memcpy(&stream_ctx->track_audio_src.track_source_attr.audio_info, audio_src_info,
sizeof(xcam_track_audio_source_info));
stream_ctx->track_audio_src.private_handle = aenc_handle;
stream_ctx->track_audio_src.track_type = XCAM_TRACK_SOURCE_TYPE_AUDIO;
} else {
stream_ctx->track_audio_src.private_handle = INVALID_TRACK;
}
ret = snprintf(stream_ctx->stream_name, LIVESVR_PATH_MAX - 1, "%s", stream_name);
if (ret < 0) {
LOG_LIVESERVER_ERROR("snprintf failed, ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
static xcam_void get_rtsp_source(xcam_liveserver_rtsp_stream_ctx* stream_ctx,
xcam_livestream_rtsp_source* rtsp_src)
{
if (stream_ctx->track_video_src.private_handle != INVALID_TRACK) {
rtsp_src->video_src_handle = &stream_ctx->track_video_src;
} else {
rtsp_src->video_src_handle = XCAM_NULL;
}
if (stream_ctx->track_audio_src.private_handle != INVALID_TRACK) {
rtsp_src->audio_src_handle = &stream_ctx->track_audio_src;
} else {
rtsp_src->audio_src_handle = XCAM_NULL;
}
}
static xcam_void get_mbuffer_size(const xcam_liveserver_rtsp_stream_ctx* stream_ctx, xcam_u32* mbuf_size)
{
*mbuf_size = RTSP_MIN_MBUFFER_SIZE;
if (stream_ctx->track_video_src.private_handle != INVALID_TRACK) {
*mbuf_size += (stream_ctx->track_video_src.track_source_attr.video_info.bit_rate /
stream_ctx->track_video_src.track_source_attr.video_info.frame_rate * LIVESVR_VIDEO_MBUFFER_FRAME);
}
if (stream_ctx->track_audio_src.private_handle != INVALID_TRACK) {
*mbuf_size += LIVESVR_AUDIO_MBUFFER_SIZE;
}
*mbuf_size = MAX(*mbuf_size, RTSP_MIN_MBUFFER_SIZE);
*mbuf_size = MIN(*mbuf_size, RTSP_MAX_MBUFFER_SIZE);
}
xcam_s32 xcam_liveserver_send_video_data(xcam_handle venc_handle, xcam_livestream_rtsp_data *rtsp_data)
{
if (rtsp_data == XCAM_NULL) {
LOG_LIVESERVER_ERROR("NuLL pointer [aenc_data]\n");
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
xcam_track_source_handle track_video = &(g_xcam_liveserver_ctx.rtsp_stream_ctx[venc_handle].track_video_src);
xcam_s32 ret;
ret = xcam_livestream_rtsp_server_write_frame(g_xcam_liveserver_ctx.rtspserv_obj,
(xcam_track_source_handle)track_video, rtsp_data);
return ret;
}
xcam_s32 xcam_liveserver_send_audio_data(xcam_handle aenc_handle, xcam_livestream_rtsp_data *rtsp_data)
{
if (rtsp_data == XCAM_NULL) {
LOG_LIVESERVER_ERROR("NuLL pointer [aenc_data]\n");
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
xcam_track_source_handle track_audio = &(g_xcam_liveserver_ctx.rtsp_stream_ctx[aenc_handle].track_audio_src);
xcam_s32 ret;
ret = xcam_livestream_rtsp_server_write_frame(g_xcam_liveserver_ctx.rtspserv_obj,
(xcam_track_source_handle)track_audio, rtsp_data);
return ret;
}
// xcam_livestream_rtsp_data rtsp_data;
// xcam_u32 offset = 0;
// rtsp_data.data_ptr[0] = aenc_data->pStream + offset;
// rtsp_data.data_len[0] = aenc_data->u32Len - offset;
// rtsp_data.pts_us = aenc_data->u64TimeStamp;
// rtsp_data.seq_num = aenc_data->u32Seq;
// rtsp_data.block_cnt = 1;
// rtsp_data.is_key_frame = XCAM_FALSE;
xcam_s32 xcam_liveserver_add_stream(xcam_handle venc_handle, xcam_track_video_source_info *video_src_info,
xcam_handle aenc_handle, xcam_track_audio_source_info *audio_src_info,
const xcam_char* stream_name,
func_xcam_track_source_request_key_frame func_request_key_frame)
{
xcam_liveserver_rtsp_stream_ctx* stream_ctx = XCAM_NULL;
xcam_char stream_path[LIVESVR_PATH_MAX];
xcam_livestream_rtsp_source rtsp_src;
xcam_u32 mbuf_size;
xcam_s32 ret;
if (!g_xcam_liveserver_ctx.is_initialized) {
LOG_LIVESERVER_ERROR("liveserver is not inited yet!\n");
return XCAM_LIVESERVER_ERR_NOT_INIT;
}
if (stream_name == XCAM_NULL) {
LOG_LIVESERVER_ERROR("NuLL pointer [stream_name]!\n");
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
if ((venc_handle == (xcam_handle)INVALID_TRACK)
&& (aenc_handle == (xcam_handle)INVALID_TRACK)) {
LOG_LIVESERVER_ERROR("venc_handle[%d] aenc_handle[%d] is invalid!\n", venc_handle, aenc_handle);
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
if (strlen(stream_name) == 0) {
LOG_LIVESERVER_ERROR("stream_name is null!\n");
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
ret = get_available_stream_context(stream_name, &stream_ctx);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Get one available stream context failed, ret:0x%x!\n", ret);
return ret;
}
memset(&stream_ctx->track_video_src, 0x0, sizeof(xcam_track_source));
memset(&stream_ctx->track_audio_src, 0x0, sizeof(xcam_track_source));
ret = get_rtsp_stream_context(venc_handle, video_src_info, aenc_handle, audio_src_info, stream_name, stream_ctx);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Get specific stream context failed, ret:0x%x!\n", ret);
return ret;
}
if (venc_handle != (xcam_handle)INVALID_TRACK && func_request_key_frame) {
stream_ctx->track_video_src.func_request_key_frame = func_request_key_frame;
}
get_rtsp_source(stream_ctx, &rtsp_src);
get_mbuffer_size(stream_ctx, &mbuf_size);
ret = snprintf(stream_path, LIVESVR_PATH_MAX - 1, "%s/%s", g_xcam_liveserver_ctx.pattern_path, stream_name);
if (ret < 0) {
LOG_LIVESERVER_ERROR("snprintf failed, ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
LOG_LIVESERVER_INFO("Add stream_path[%s] venc_hdl[%d] aenc_hdl[%d] mbuf_size[%u byte]!\n",
stream_path, venc_handle, aenc_handle, mbuf_size);
ret = xcam_livestream_rtsp_server_add_media_stream(g_xcam_liveserver_ctx.rtspserv_obj, &rtsp_src, stream_path, mbuf_size);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Add media stream failed, ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
stream_ctx->is_used = XCAM_TRUE;
return XCAM_SUCCESS;
}
xcam_s32 xcam_liveserver_remove_stream(const xcam_char* stream_name)
{
xcam_s32 ret;
xcam_s32 idx;
if (g_xcam_liveserver_ctx.is_initialized == XCAM_FALSE) {
LOG_LIVESERVER_ERROR("liveserver is not init yet!\n");
return XCAM_LIVESERVER_ERR_NOT_INIT;
}
if (stream_name == XCAM_NULL) {
LOG_LIVESERVER_ERROR("NuLL pointer [stream_name]!\n");
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
if (strlen(stream_name) == 0) {
LOG_LIVESERVER_ERROR("valid length of stream_name is 0!\n");
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
for (idx = 0; idx < LIVESVR_RTSP_MAX_STREAM_CNT; ++idx) {
if ( (g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].is_used == XCAM_TRUE)
&& (strncmp(g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].stream_name,
stream_name, LIVESVR_PATH_MAX) == 0) ) {
xcam_char stream_path[LIVESVR_PATH_MAX];
memset(stream_path, '\0', sizeof(stream_path));
ret = snprintf(stream_path, LIVESVR_PATH_MAX - 1, "%s/%s", g_xcam_liveserver_ctx.pattern_path, stream_name);
if (ret < 0) {
LOG_LIVESERVER_ERROR("snprintf failed, ret:0x%x.\n", ret);
return XCAM_FAILURE;
}
ret = xcam_livestream_rtsp_server_remove_media_stream(g_xcam_liveserver_ctx.rtspserv_obj, (const xcam_char*)stream_path);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Remove media stream failed, ret:0x%x.\n", ret);
return XCAM_FAILURE;
}
g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].is_used = XCAM_FALSE;
return XCAM_SUCCESS;
}
}
LOG_LIVESERVER_ERROR("could not find stream[%s].\n", stream_name);
return XCAM_LIVESERVER_ERR_NOT_FIND;
}
xcam_s32 xcam_liveserver_remove_all_stream(xcam_void)
{
xcam_s32 ret;
xcam_s32 idx;
if (!g_xcam_liveserver_ctx.is_initialized) {
LOG_LIVESERVER_ERROR("liveserver is not init yet!\n");
return XCAM_LIVESERVER_ERR_NOT_INIT;
}
for (idx = 0; idx < LIVESVR_RTSP_MAX_STREAM_CNT; ++idx) {
if (g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].is_used == XCAM_TRUE) {
xcam_char stream_path[LIVESVR_PATH_MAX];
memset(stream_path, '\0', sizeof(stream_path));
ret = snprintf(stream_path, LIVESVR_PATH_MAX - 1, "%s/%s",
g_xcam_liveserver_ctx.pattern_path,
g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].stream_name);
if (ret < 0) {
LOG_LIVESERVER_ERROR("snprintf failed, ret:0x%x!\n", ret);
continue;
}
ret = xcam_livestream_rtsp_server_remove_media_stream(g_xcam_liveserver_ctx.rtspserv_obj, stream_path);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("remove media stream failed, ret:0x%x!\n", ret);
}
g_xcam_liveserver_ctx.rtsp_stream_ctx[idx].is_used = XCAM_FALSE;
}
}
return XCAM_SUCCESS;
}
xcam_bool xcam_liveserver_is_init(xcam_void)
{
return g_xcam_liveserver_ctx.is_initialized;
}
xcam_s32 xcam_liveserver_init(const xcam_liveserver_init_param param)
{
if (g_xcam_liveserver_ctx.is_initialized) {
LOG_LIVESERVER_ERROR("Liveserver had been initialized!\n");
return XCAM_LIVESERVER_ERR_WAS_INITED;
}
if ((param.max_conn_num < XCAM_LIVESERVER_CONN_CNT_MIN)
|| (param.max_conn_num > XCAM_LIVESERVER_CONN_CNT_MAX)) {
LOG_LIVESERVER_ERROR("max conn num[%d] is beyond range[%d, %d]!\n", param.max_conn_num,
XCAM_LIVESERVER_CONN_CNT_MIN, XCAM_LIVESERVER_CONN_CNT_MAX);
return XCAM_LIVESERVER_ERR_ILLEGAL_PARAM;
}
xcam_u16 serv_port = param.listen_port;
if (serv_port == 0) {
serv_port = LIVESVR_RTSP_DEF_LISTEN_PORT;
LOG_LIVESERVER_INFO("Use default listen port(%u)!\n", serv_port);
}
memset(&g_xcam_liveserver_ctx, 0x0, sizeof(xcam_liveserver_context));
xcam_s32 ret = init_rtsp_server(param.max_conn_num, serv_port);
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Init rtsp server failed, ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
if (strlen(param.pattern_name) > 0) {
strncpy(g_xcam_liveserver_ctx.pattern_path, param.pattern_name, PATTERN_NAME_LEN);
} else {
LOG_LIVESERVER_INFO("Use default pattern name(%s)!\n", LIVESVR_DEF_PATTERN_NAME);
strncpy(g_xcam_liveserver_ctx.pattern_path, LIVESVR_DEF_PATTERN_NAME, PATTERN_NAME_LEN);
}
g_xcam_liveserver_ctx.is_initialized = XCAM_TRUE;
return XCAM_SUCCESS;
}
xcam_s32 xcam_liveserver_deinit(xcam_void)
{
xcam_s32 ret;
if (!g_xcam_liveserver_ctx.is_initialized) {
LOG_LIVESERVER_ERROR("liveserver is not init yet!\n");
return XCAM_LIVESERVER_ERR_NOT_INIT;
}
ret = xcam_liveserver_remove_all_stream();
if (ret != XCAM_SUCCESS) {
LOG_LIVESERVER_ERROR("Remove all stream failed, ret:0x%x!\n", ret);
}
deinit_rtsp_server();
g_xcam_liveserver_ctx.is_initialized = XCAM_FALSE;
return XCAM_SUCCESS;
}
+335
View File
@@ -0,0 +1,335 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdlib.h>
#include "livestream_comm.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#ifndef UNUSED
#define UNUSED(x) (void)x
#endif
#define IP_MAX_LEN (16)
static xcam_u8 g_basis64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static xcam_u8 g_basis64_index[128] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff
};
#define CHAR64(c) (((c) > 127) ? 0xff : g_basis64_index[(c)]) /* define CHAR64(c) */
xcam_s32 livestream_comm_format_date(xcam_char* date_buf, xcam_s32 buf_size)
{
if (XCAM_NULL == date_buf) {
LOG_LIVESTREAM_ERROR("Null pointer [date_buf]!\n");
return XCAM_FAILURE;
}
if (buf_size <= 0) {
LOG_LIVESTREAM_ERROR("Param buf_size(%d) is invalid!\n", buf_size);
return XCAM_FAILURE;
}
xcam_char buffer[MAX_DATE_LEN] = {0};
struct tm* ptime = XCAM_NULL;
time_t tt;
tt = time(XCAM_NULL);
ptime = gmtime(&tt);
if (XCAM_NULL == ptime) {
LOG_LIVESTREAM_ERROR("gmtime fail!\n");
return XCAM_FAILURE;
}
memset(buffer, '\0', sizeof(buffer));
if (strftime(buffer, sizeof(buffer), "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", ptime) > 0) {
strncpy(date_buf, buffer, buf_size);
return XCAM_SUCCESS;
}
return XCAM_FAILURE;
}
xcam_void livestream_comm_random_num(xcam_u32* buf_ssrc)
{
FILE* fp_file = fopen("/dev/urandom", "r");
if (XCAM_NULL == fp_file) {
LOG_LIVESTREAM_ERROR("Open /dev/urandom failed and errno is %d!\n", errno);
return;
}
if (1 != fread(buf_ssrc, sizeof(xcam_u32), 1, fp_file)) {
LOG_LIVESTREAM_ERROR("Read /dev/urandom failed and errno is %d!\n", errno);
}
fclose(fp_file);
return;
}
xcam_void livestream_comm_random_id(xcam_char* buf_ssrc, xcam_s32 length)
{
xcam_u32* tmpid;
xcam_s32 i;
FILE* file;
file = fopen("/dev/urandom", "r");
if (XCAM_NULL == file) {
LOG_LIVESTREAM_ERROR("Open /dev/urandom failed and errno is %d!\n", errno);
return;
}
if (buf_ssrc == XCAM_NULL) {
fclose(file);
LOG_LIVESTREAM_ERROR("Null pointer [buf_ssrc]!\n");
return;
}
tmpid = (xcam_u32 *)malloc(sizeof(xcam_u32));
if (tmpid == XCAM_NULL) {
fclose(file);
LOG_LIVESTREAM_ERROR("Dynamic alloc for random id fail!\n");
return;
}
memset(tmpid, 0x00, sizeof(xcam_u32));
for (i = 0; i < length; ++i) {
if (fread(tmpid, sizeof(xcam_u32), 1, file) != 1) {
LOG_LIVESTREAM_ERROR("Read /dev/urandom failed and errno is %d!\n", errno);
fclose(file);
free(tmpid);
tmpid = XCAM_NULL;
return;
} else {
buf_ssrc[i] = (*tmpid % 10) + '0';
}
}
buf_ssrc[length] = 0;
fclose(file);
free(tmpid);
tmpid = XCAM_NULL;
}
xcam_s32 livestream_comm_base64_encode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len)
{
xcam_s32 i = 0;
xcam_s32 j = 0;
xcam_s32 pad;
UNUSED(output_len);
if (input_str == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("Null pointer [input_str]!\n");
return XCAM_FAILURE;
}
if (output_str == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("Null pointer [output_str]!\n");
return XCAM_FAILURE;
}
while (i < input_len) {
pad = 3 - (input_len - i);
if (pad == 2) {
output_str[j ] = g_basis64_string[input_str[i] >> 2];
output_str[j + 1] = g_basis64_string[(input_str[i] & 0x03) << 4];
output_str[j + 2] = '=';
output_str[j + 3] = '=';
} else if (pad == 1) {
output_str[j ] = g_basis64_string[input_str[i] >> 2];
output_str[j + 1] = g_basis64_string[((input_str[i] & 0x03) << 4) | ((input_str[i + 1] & 0xf0) >> 4)];
output_str[j + 2] = g_basis64_string[(input_str[i + 1] & 0x0f) << 2];
output_str[j + 3] = '=';
} else {
output_str[j ] = g_basis64_string[input_str[i] >> 2];
output_str[j + 1] = g_basis64_string[((input_str[i] & 0x03) << 4) | ((input_str[i + 1] & 0xf0) >> 4)];
output_str[j + 2] = g_basis64_string[((input_str[i + 1] & 0x0f) << 2) | ((input_str[i + 2] & 0xc0) >> 6)];
output_str[j + 3] = g_basis64_string[input_str[i + 2] & 0x3f];
}
i += 3;
j += 4;
}
return j;
}
xcam_s32 livestream_comm_base64_decode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len)
{
xcam_s32 i = 0;
xcam_s32 j = 0;
xcam_s32 pad;
xcam_u8 temp[4];
UNUSED(output_len);
if (output_str == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("Null pointer [output_str]!\n");
return XCAM_FAILURE;
}
while ((i + 3) < input_len) {
pad = 0;
temp[0] = CHAR64(input_str[i ]);
if (temp[0] == 0xff) {
pad ++;
}
temp[1] = CHAR64(input_str[i + 1]);
if (temp[1] == 0xff) {
pad ++;
}
temp[2] = CHAR64(input_str[i + 2]);
if (temp[2] == 0xff) {
pad ++;
}
temp[3] = CHAR64(input_str[i + 3]);
if (temp[3] == 0xff) {
pad ++;
}
if (pad == 2) {
output_str[j++] = (temp[0] << 2) | ((temp[1] & 0x30) >> 4);
output_str[j] = (temp[1] & 0x0f) << 4;
} else if (pad == 1) {
output_str[j++] = (temp[0] << 2) | ((temp[1] & 0x30) >> 4);
output_str[j++] = ((temp[1] & 0x0f) << 4) | ((temp[2] & 0x3c) >> 2);
output_str[j] = (temp[2] & 0x03) << 6;
} else {
output_str[j++] = (temp[0] << 2) | ((temp[1] & 0x30) >> 4);
output_str[j++] = ((temp[1] & 0x0f) << 4) | ((temp[2] & 0x3c) >> 2);
output_str[j++] = ((temp[2] & 0x03) << 6) | (temp[3] & 0x3f);
}
i += 4;
}
return j;
}
xcam_s32 livestream_comm_close_socket(xcam_s32* sockfd)
{
if (sockfd == XCAM_NULL) {
return XCAM_FAILURE;
}
if (*sockfd >= 0) {
close(*sockfd);
*sockfd = INVALID_SOCKET;
return XCAM_SUCCESS;
}
return XCAM_FAILURE;
}
xcam_s32 livestream_comm_get_peer_ip_port(xcam_s32 sockfd, xcam_char* ip, xcam_u16* port)
{
xcam_char* ptr_temp = XCAM_NULL;
socklen_t name_len = 0;
struct sockaddr_in addr;
name_len = sizeof(struct sockaddr_in);
if (0 != getpeername(sockfd, (struct sockaddr*)&addr, &name_len)) {
return XCAM_FAILURE;
}
*port = (xcam_u16)ntohs(addr.sin_port);
ptr_temp = inet_ntoa(addr.sin_addr);
if (XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("ip address inet_ntoa error!\n");
return XCAM_FAILURE;
}
if (snprintf(ip, IP_MAX_LEN - 1, "%s", ptr_temp) < 0) {
LOG_LIVESTREAM_ERROR("string print ip fail!\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_comm_get_peer_sockaddr(xcam_char* ip, xcam_u16 port, struct sockaddr_in* sock_addr)
{
if (XCAM_NULL == sock_addr) {
LOG_LIVESTREAM_ERROR("param sock_addr is null!\n");
return XCAM_FAILURE;
}
sock_addr->sin_family = AF_INET;
sock_addr->sin_port = htons(port);
memset(&(sock_addr->sin_zero), '\0', sizeof(sock_addr->sin_zero));
if (0 == inet_aton(ip, (struct in_addr*) & (sock_addr->sin_addr.s_addr))) {
LOG_LIVESTREAM_ERROR("inet_aton fail!\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_comm_get_host_ipaddr(xcam_s32 sockfd, xcam_char* ip)
{
xcam_char* ptr_temp = XCAM_NULL;
xcam_s32 name_len = 0;
struct sockaddr_in addr;
name_len = sizeof(struct sockaddr);
if (0 != getsockname(sockfd, (struct sockaddr*)&addr, (socklen_t*)&name_len)) {
return XCAM_FAILURE;
}
ptr_temp = inet_ntoa(addr.sin_addr);
if (XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("inet_ntoa fail!\n");
return XCAM_FAILURE;
}
if (snprintf(ip, IP_MAX_LEN - 1, "%s", ptr_temp) < 0) {
LOG_LIVESTREAM_ERROR("string print ip address error\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_comm_open_udp_socket(xcam_u16 port)
{
struct sockaddr_in addr = {0};
xcam_s32 fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
LOG_LIVESTREAM_ERROR("socket udp fail!\n");
return XCAM_FAILURE;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
memset(&(addr.sin_zero), '\0', sizeof(addr.sin_zero));
if (bind(fd, (struct sockaddr*)&addr, sizeof (addr))) {
LOG_LIVESTREAM_ERROR("bind udp socket fail %s!\n", strerror(errno));
close(fd);
return XCAM_FAILURE;
}
return fd;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_COMMON_H_
#define _LIVESTREAM_COMMON_H_
#include <netinet/in.h>
#include <sys/types.h>
#include <stdio.h>
#include <limits.h>
#include <pthread.h>
#include <time.h>
#include "xcam_type.h"
#include "xcam_log.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define LOG_LIVESTREAM_INFO(fmt...) XCAM_LOG_INFO_PRINT("livestream", fmt);
#define LOG_LIVESTREAM_WARN(fmt...) XCAM_LOG_WARN_PRINT("livestream", fmt);
#define LOG_LIVESTREAM_ERROR(fmt...) XCAM_LOG_ERR_PRINT("livestream", fmt);
#define LOG_LIVESTREAM_FATAL(fmt...) XCAM_LOG_FATAL_PRINT("livestream", fmt);
#define MAX_DATE_LEN (200)
#define MIN_SEND_PORT (5000)
#define MAX_SEND_PORT (6000)
#define INVALID_SOCKET (-1)
xcam_s32 livestream_comm_format_date(xcam_char* date_buf, xcam_s32 buf_size);
xcam_void livestream_comm_random_num(xcam_u32* buf_ssrc);
xcam_void livestream_comm_random_id(xcam_char* buf_ssrc, xcam_s32 length);
xcam_s32 livestream_comm_base64_encode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len);
xcam_s32 livestream_comm_base64_decode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len);
xcam_s32 livestream_comm_get_peer_ip_port(xcam_s32 sockfd, xcam_char* ip, xcam_u16* port);
xcam_s32 livestream_comm_get_peer_sockaddr(xcam_char* ip, xcam_u16 port, struct sockaddr_in* sock_addr);
xcam_s32 livestream_comm_get_host_ipaddr(xcam_s32 sockfd, xcam_char* ip);
xcam_s32 livestream_comm_open_udp_socket(xcam_u16 port);
xcam_s32 livestream_comm_close_socket(xcam_s32* sockfd);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_COMMON_H_*/
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_ERRNO_H_
#define _LIVESTREAM_ERRNO_H_
#include "xcam_define.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
typedef enum {
/*general error code*/
ERR_CODE_NULL_PTR = 0x30,
ERR_CODE_INVALID_HANDLE = 0x31,
ERR_CODE_INVALID_PARAM = 0x32,
ERR_CODE_MALLOC_FAILED = 0x33,
ERR_CODE_HANDLE_INVALID = 0x40, /**<rtspserver handle invalid*/
ERR_CODE_INVALID_ARG = 0x41, /**<param is null or invalid*/
ERR_CODE_MALLOC_FAIL = 0x42, /**<malloc memory fail*/
ERR_CODE_CREATE_FAIL = 0x43, /**<create rtspserverfail*/
ERR_CODE_DESTORY_FAIL = 0x44, /**<destory rtspserver fail*/
ERR_CODE_START_FAIL = 0x45, /**<start rtspserverfail*/
ERR_CODE_STOP_FAIL = 0x46, /**<stop rtspserver fail*/
ERR_CODE_REACH_MAX_CONNECT = 0x47, /**<rtspserver reach the max clients connect*/
ERR_CODE_CREATE_AGAIN = 0x48, /**<rtspserver have been created*/
ERR_CODE_NOT_CREATE = 0x49, /**<rtspserver have been created*/
/*stream related error code*/
ERR_CODE_STREAM_REMOVE_FAIL = 0x50, /**<remove stream fail*/
ERR_CODE_STREAM_ADD_FAIL = 0x51, /**<add stream fail*/
ERR_CODE_STREAM_EXISTED = 0x52, /**<add stream existed*/
ERR_CODE_STREAM_NOT_EXIST = 0x53, /**<remove or find stream not existed*/
ERR_CODE_STREAM_REMOVE_SESS_FAIL = 0x54, /**<remove stream related session fail*/
ERR_CODE_STREAM_ADD_SESS_FAIL = 0x55, /**<add a session for stream fail*/
/*mbuffer related error code */
ERR_CODE_INIT_MBUF_FAIL = 0x56, /**<init mbuffer fail*/
ERR_CODE_DEL_MBUF_FAIL = 0x57, /**<deinit mbuffer fail*/
/*listener related error code*/
ERR_CODE_CREATE_LISTENER_FAIL = 0x60, /**<create listener fail*/
ERR_CODE_DESTROY_LISTENER_FAIL = 0x61, /**<destroy listener fail*/
ERR_CODE_START_LISTENER_FAIL = 0x62, /**<start listener fail*/
ERR_CODE_STOP_LISTENER_FAIL = 0x63, /**<stop listener fail*/
ERR_CODE_START_LISTENER_AGAIN = 0x64, /**<start the listener again*/
ERR_CODE_STOP_LISTENER_NOT_STARTED = 0x65, /**<stop the listener not started*/
/*sess related error code */
ERR_CODE_SESS_HANDLE_INVALID = 0x70, /**<session handle invalidt*/
ERR_CODE_SESS_CONNECT_FAIL = 0x71, /**<session connect fail*/
ERR_CODE_SESS_CREATE_FAIL = 0x72, /**<create sess fail*/
ERR_CODE_SESS_DESTROY_FAIL = 0x73, /**<destroy sess fail*/
ERR_CODE_SESS_START_FAIL = 0x74, /**<start sess fail*/
ERR_CODE_SESS_STOP_FAIL = 0x75, /**<stop sess fail*/
ERR_CODE_SESS_SET_FAIL = 0x76, /**<set sess fail*/
ERR_CODE_SESS_EXISTED = 0x77, /**<sess already existed*/
ERR_CODE_SESS_NOT_EXISTED = 0x78, /**<sess not existed*/
ERR_CODE_SESS_BAD_REQUEST = 0x79, /**<bad request*/
ERR_CODE_SESS_STREAM_NOT_FOUND = 0x7a, /**<stream not found*/
ERR_CODE_SESS_UNSUPPORT_TRANSPORT = 0x7b, /**<unsuport transtype*/
ERR_CODE_SESS_SEND_FAIL = 0x7c, /**<send fail*/
ERR_CODE_SESS_UNSUPPORT_MEDIATYPE = 0x7d, /**<unsuport mediatype*/
ERR_CODE_SESS_NO_DATA = 0x7e, /**<read no data*/
/*rtp error code*/
ERR_CODE_RTP_DESTROY_FAIL = 0x80, /**<create rtp fail*/
ERR_CODE_RTP_CREATE_FAIL = 0x81, /**<destory rtp fail*/
ERR_CODE_RTP_TRANS_MODE = 0x82, /**<not support trans mode*/
ERR_CODE_RTP_PACKET_TYPE = 0x83, /**<not support pack type*/
ERR_CODE_RTP_TRANS_SEND = 0x84, /**<rtp trans send error*/
/*rtcp error code*/
ERR_CODE_RTCP_DESTROY_FAIL = 0x85, /**<create rtcp fail*/
ERR_CODE_RTCP_CREATE_FAIL = 0x86, /**<destory rtcp fail*/
/*write frame error code*/
ERR_CODE_WRITE_FRAME_FAIL = 0x87, /**<write frame fail*/
ERR_CODE_MBUF_FULL = 0x88, /**<buff full fail*/
ERR_CODE_BUTT = 0xFF
} rtspserver_err_code;
/*general error code*/
#define LIVESTREAM_ERRNO_NULL_PTR XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_NULL_PTR)
#define LIVESTREAM_ERRNO_HANDLE_INVALID XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_INVALID_HANDLE)
#define LIVESTREAM_ERRNO_ILLEGAL_PARAM XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_INVALID_PARAM)
#define LIVESTREAM_ERRNO_MALLOC_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_MALLOC_FAILED)
#define LIVESTREAM_ERRNO_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_CREATE_FAIL)
#define LIVESTREAM_ERRNO_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_DESTORY_FAIL)
#define LIVESTREAM_ERRNO_START_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_START_FAIL)
#define LIVESTREAM_ERRNO_STOP_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STOP_FAIL)
#define LIVESTREAM_ERRNO_REACH_MAX_CONNECT XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_REACH_MAX_CONNECT)
#define LIVESTREAM_ERRNO_CREATE_AGAIN XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_CREATE_AGAIN)
#define LIVESTREAM_ERRNO_NOT_CREATE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_NOT_CREATE)
/*stream related error code*/
#define LIVESTREAM_ERRNO_STREAM_REMOVE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_REMOVE_FAIL)
#define LIVESTREAM_ERRNO_STREAM_ADD_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_ADD_FAIL)
#define LIVESTREAM_ERRNO_STREAM_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_EXISTED)
#define LIVESTREAM_ERRNO_STREAM_NOT_EXIST XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_NOT_EXIST)
#define LIVESTREAM_ERRNO_STREAM_REMOVE_SESS_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_REMOVE_SESS_FAIL)
#define LIVESTREAM_ERRNO_STREAM_ADD_SESS_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_ADD_SESS_FAIL)
/*mbuffer related error code*/
#define LIVESTREAM_ERRNO_INIT_MBUF_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_INIT_MBUF_FAIL)
#define LIVESTREAM_ERRNO_DEL_MBUF_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_DEL_MBUF_FAIL)
/*listener related error code*/
#define LIVESTREAM_ERRNO_CREATE_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_CREATE_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_DESTROY_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_DESTROY_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_START_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_START_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_STOP_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STOP_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_START_LISTENER_AGAIN XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_START_LISTENER_AGAIN)
#define LIVESTREAM_ERRNO_STOP_LISTENER_NOT_STARTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STOP_LISTENER_NOT_STARTED)
/*sess related error code */
#define LIVESTREAM_ERRNO_SESS_HANDLE_INVALID XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_HANDLE_INVALID)
#define LIVESTREAM_ERRNO_SESS_CONNECT_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_CONNECT_FAIL)
#define LIVESTREAM_ERRNO_SESS_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_CREATE_FAIL)
#define LIVESTREAM_ERRNO_SESS_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_DESTROY_FAIL)
#define LIVESTREAM_ERRNO_SESS_START_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_START_FAIL)
#define LIVESTREAM_ERRNO_SESS_STOP_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_STOP_FAIL)
#define LIVESTREAM_ERRNO_SESS_SET_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_SET_FAIL)
#define LIVESTREAM_ERRNO_SESS_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_EXISTED)
#define LIVESTREAM_ERRNO_SESS_NOT_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_NOT_EXISTED)
#define LIVESTREAM_ERRNO_SESS_BAD_REQUEST XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_BAD_REQUEST)
#define LIVESTREAM_ERRNO_SESS_STREAM_NOT_FOUND XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_STREAM_NOT_FOUND)
#define LIVESTREAM_ERRNO_SESS_UNSUPPORT_TRANSPORT XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_UNSUPPORT_TRANSPORT)
#define LIVESTREAM_ERRNO_SESS_SEND_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_SEND_FAIL)
#define LIVESTREAM_ERRNO_SESS_UNSUPPORT_MEDIATYPE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_UNSUPPORT_MEDIATYPE)
#define LIVESTREAM_ERRNO_SESS_NO_DATA XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_NO_DATA)
/*rtp error code*/
#define LIVESTREAM_ERRNO_RTP_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_DESTROY_FAIL)
#define LIVESTREAM_ERRNO_RTP_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_CREATE_FAIL)
#define LIVESTREAM_ERRNO_RTP_TRANS_MODE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_TRANS_MODE)
#define LIVESTREAM_ERRNO_RTP_PACKET_TYPE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_PACKET_TYPE)
#define LIVESTREAM_ERRNO_RTP_TRANS_SEND XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_TRANS_SEND)
/*rtcp error code*/
#define LIVESTREAM_ERRNO_RTCP_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTCP_DESTROY_FAIL)
#define LIVESTREAM_ERRNO_RTCP_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTCP_CREATE_FAIL)
/*write frame error code*/
#define LIVESTREAM_ERRNO_WRITE_FRAME XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_WRITE_FRAME_FAIL)
#define LIVESTREAM_ERRNO_MBUF_FULL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_MBUF_FULL)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* _LIVESTREAM_ERRNO_H_ */
+432
View File
@@ -0,0 +1,432 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include "livestream_comm.h"
#include "livestream_listener.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define KEEPALIVE_IDLE_SECONDS (3)
#define LISTEN_PORT_NUM_MIN 0
#define LISTEN_PORT_NUM_MAX 65535
#define LISTEN_TIMEOUT_SEC (0)
#define LISTEN_TIMEOUT_USEC (10000)
#define MAX_RECV_BUFFER (1024)
#define DEFAULT_MAX_FD_NUM (32)
typedef struct {
pthread_t listen_thread;
xcam_s32 listen_sock;
xcam_u16 listen_port;
/*state of the listener */
xcam_bool is_listening;
xcam_char first_msg_buff[MAX_RECV_BUFFER];
xcam_s32 client_sock_list[DEFAULT_MAX_FD_NUM];
client_connect_hook connect_callback;
xcam_void* callback_object;
} listener_context;
static xcam_s32 listener_set_nonblock(xcam_s32 sockfd)
{
xcam_u32 flags = 0;
xcam_s32 ret;
flags = (xcam_u32)fcntl(sockfd, F_GETFL, 0);
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
if (ret < 0) {
return ret;
}
return XCAM_SUCCESS;
}
static xcam_s32 listener_set_keepalive(xcam_s32 sockfd, xcam_s32 keepalive,
xcam_s32 keepidle, xcam_s32 keepinterval, xcam_s32 keepcount)
{
xcam_s32 ret;
ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive));
if (ret < 0) {
return ret;
}
ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle, sizeof(keepidle));
if (ret < 0) {
return ret;
}
ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval, sizeof(keepinterval));
if (ret < 0) {
return ret;
}
ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount, sizeof(keepcount));
if (ret < 0) {
return ret;
}
return XCAM_SUCCESS;
}
static xcam_s32 listener_add_fd(listener_context* listener_ctx, xcam_s32 sockfd)
{
xcam_s32 i = 0;
for (i = 0; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] == INVALID_SOCKET) {
listener_ctx->client_sock_list[i] = sockfd;
return XCAM_SUCCESS;
}
}
return XCAM_FAILURE;
}
static xcam_s32 listener_del_fd(listener_context* listener_ctx, xcam_s32 sockfd)
{
xcam_s32 i = 0;
for (i = 0; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] == sockfd) {
listener_ctx->client_sock_list[i] = INVALID_SOCKET;
return XCAM_SUCCESS;
}
}
return XCAM_FAILURE;
}
static xcam_s32 listener_close_client_fd(listener_context* listener_ctx)
{
xcam_s32 i = 0;
for (; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] != INVALID_SOCKET) {
close(listener_ctx->client_sock_list[i]);
listener_ctx->client_sock_list[i] = INVALID_SOCKET;
}
}
return XCAM_SUCCESS;
}
static xcam_s32 listener_update_max_fd(const listener_context* listener_ctx, xcam_s32* ptr_maxfd_num)
{
xcam_s32 maxfd_num = -1;
xcam_s32 i = 0;
for (; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] != INVALID_SOCKET
&& listener_ctx->client_sock_list[i] > maxfd_num) {
maxfd_num = listener_ctx->client_sock_list[i];
}
}
if (listener_ctx->listen_sock > maxfd_num) {
maxfd_num = listener_ctx->listen_sock;
}
*ptr_maxfd_num = maxfd_num + 1;
return XCAM_SUCCESS;
}
static xcam_bool listener_check_fd(listener_context* listener_ctx, fd_set* ptr_fdset, xcam_s32* ptr_sockfd)
{
xcam_s32 i = 0;
for (; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] != INVALID_SOCKET) {
xcam_s32 fd = listener_ctx->client_sock_list[i];
if (FD_ISSET(fd, ptr_fdset)) {
*ptr_sockfd = fd;
return XCAM_TRUE;
}
}
}
return XCAM_FALSE;
}
static xcam_s32 listener_create_socket(xcam_s32 listen_port, xcam_s32* listen_sockfd)
{
struct timeval timeout = {KEEPALIVE_IDLE_SECONDS, 0};
struct sockaddr_in svr_addr = {0};
xcam_s32 sockfd = INVALID_SOCKET; /*temp listen socket*/
xcam_s32 opt_value = 1;
xcam_s32 ret = 0;
/* 1. Create socket as block mode and listen for accept new connection.*/
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
LOG_LIVESTREAM_ERROR("Create listen sockfd failed! \n");
return XCAM_FAILURE;
}
/*2. set sock option*/
if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof(xcam_s32))) {
close(sockfd);
LOG_LIVESTREAM_ERROR("set socket option SO_REUSEADDR error.\n");
return XCAM_FAILURE;
}
if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(struct timeval))) {
close(sockfd);
LOG_LIVESTREAM_ERROR("set socket option SO_SNDTIMEO error.\n");
return XCAM_FAILURE;
}
if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(struct timeval))) {
close(sockfd);
LOG_LIVESTREAM_ERROR("set socket option SO_RCVTIMEO error.\n");
return XCAM_FAILURE;
}
xcam_s32 keepalive = 1;
xcam_s32 keepidle = KEEPALIVE_IDLE_SECONDS;
xcam_s32 keepinterval = 1;
xcam_s32 keepcount = 3;
ret = listener_set_keepalive(sockfd, keepalive, keepidle, keepinterval, keepcount);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("SetKeepAlive error=%d\n", ret);
}
/*3. bind socket */
svr_addr.sin_family = AF_INET;
svr_addr.sin_port = htons(listen_port);
svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(svr_addr.sin_zero), '\0', sizeof(svr_addr.sin_zero));
if (bind(sockfd, (struct sockaddr*)&svr_addr, sizeof(struct sockaddr)) != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("bind fail error:%s\n", strerror(errno));
close(sockfd);
return XCAM_FAILURE;
}
/*4. listen on port*/
ret = listen(sockfd, DEFAULT_MAX_FD_NUM);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("socket listen error.\n");
close(sockfd);
return XCAM_FAILURE;
}
*listen_sockfd = sockfd;
return XCAM_SUCCESS;
}
/*main func of listen thread */
static xcam_void* listener_thread_process(void* args)
{
listener_context* listener_ctx = (listener_context*)args;
struct sockaddr_in accept_addr; /*socket addr of accepted client connect*/
struct timeval timeout_val; /* Timeout value */
xcam_s32 maxfd_num = 0; /*max socket number of read set*/
xcam_s32 accept_sock = INVALID_SOCKET; /*accepted client connect socket */
xcam_s32 sockaddr_len = 0;
xcam_s32 recv_bytes = 0;
xcam_s32 ret = XCAM_SUCCESS;
fd_set read_active_fds;
fd_set read_fds;
memset(&timeout_val, 0, sizeof(struct timeval));
memset(&accept_addr, 0, sizeof(struct sockaddr_in));
ret = listener_create_socket(listener_ctx->listen_port, &listener_ctx->listen_sock);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("create listener sockfd failed error:%d \n", ret);
return XCAM_NULL;
}
prctl(PR_SET_NAME, (unsigned long)"NetlistenProc", 0, 0, 0);
LOG_LIVESTREAM_INFO("start listener! \n");
/*init read fds and set http lisen sock into read set*/
FD_ZERO(&read_fds);
FD_ZERO(&read_active_fds);
maxfd_num = listener_ctx->listen_sock + 1;
FD_SET(listener_ctx->listen_sock, &read_active_fds);
while (listener_ctx->is_listening) {
timeout_val.tv_sec = LISTEN_TIMEOUT_SEC;
timeout_val.tv_usec = LISTEN_TIMEOUT_USEC;
memcpy(&read_fds, &read_active_fds, sizeof(fd_set));
/*jude if there is new connect or first message come through already connected link */
ret = select(maxfd_num, &read_fds, NULL, NULL, &timeout_val);
if (ret < 0) {
if (EINTR == errno || EAGAIN == errno) {
/*to do: interrupt or try again*/
continue;
}
LOG_LIVESTREAM_ERROR("select error! ret:%x,errno:%d,err:%s\n", ret, errno, strerror(errno));
break;
} else if (0 == ret) {
/*to do :select timeout over proset*/
continue;
}
if (FD_ISSET(listener_ctx->listen_sock, &read_fds)) {
/*accept new connect*/
sockaddr_len = sizeof(accept_addr);
accept_sock = accept(listener_ctx->listen_sock, (struct sockaddr*)&accept_addr, (socklen_t*)&sockaddr_len);
if (accept_sock < 0) {
LOG_LIVESTREAM_ERROR("accept conn error=%s \r\n", strerror(errno));
continue;
}
// TCP socket may block in many situations, e.g. wifi disconnected
// so we use nonblock socket and enable TCP keep alive.
ret = listener_set_nonblock(accept_sock);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("SetNonblock error=%d\n", ret);
}
ret = listener_set_keepalive(accept_sock, 1, KEEPALIVE_IDLE_SECONDS, 1, 3);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("SetKeepAlive error=%d\n", ret);
}
LOG_LIVESTREAM_INFO("a new connect has occured fd=%d.\n", accept_sock);
/*add new connection link into readfds*/
if (accept_sock + 1 > maxfd_num) {
maxfd_num = accept_sock + 1;
}
FD_SET(accept_sock , &read_active_fds);
listener_add_fd(listener_ctx, accept_sock);
} else {
xcam_s32 clientSockfd = INVALID_SOCKET;
if (listener_check_fd(listener_ctx, &read_fds, &clientSockfd)) {
memset(listener_ctx->first_msg_buff, 0, MAX_RECV_BUFFER);
recv_bytes = recv(clientSockfd, listener_ctx->first_msg_buff, MAX_RECV_BUFFER-1, 0);
FD_CLR(clientSockfd, &read_active_fds);
listener_del_fd(listener_ctx, clientSockfd);
/*updat Max read Fds Num*/
listener_update_max_fd(listener_ctx, &maxfd_num);
if (recv_bytes <= 0) {
LOG_LIVESTREAM_ERROR("recv data from error=%s\n", strerror(errno));
livestream_comm_close_socket(&clientSockfd);
continue;
}
/*callback to user*/
if (listener_ctx->connect_callback) {
listener_ctx->connect_callback(listener_ctx->callback_object,
clientSockfd, listener_ctx->first_msg_buff, recv_bytes);
}
}
}
} /*end of while*/
/*close the client fd before connect*/
listener_close_client_fd(listener_ctx);
/*close the listen socket*/
livestream_comm_close_socket(&listener_ctx->listen_sock);
LOG_LIVESTREAM_INFO("stop listener! \n");
return XCAM_NULL;
}
xcam_s32 livestream_listener_create(xcam_s32 listen_port, xcam_void** ptr_handle)
{
/* malloc listen server manage struct*/
listener_context* listener_ctx;
xcam_s32 i = 0;
if (listen_port <= LISTEN_PORT_NUM_MIN || listen_port > LISTEN_PORT_NUM_MAX) {
LOG_LIVESTREAM_ERROR("invalid listen port\n");
return XCAM_FAILURE;
}
listener_ctx = (listener_context*)malloc(sizeof(listener_context));
if (!listener_ctx) {
LOG_LIVESTREAM_ERROR("dynamic alloc for lisn server error.\r\n");
return XCAM_FAILURE;
}
memset(listener_ctx, 0x00, sizeof(listener_context));
for (; i < DEFAULT_MAX_FD_NUM; i++) {
listener_ctx->client_sock_list[i] = INVALID_SOCKET;
}
listener_ctx->listen_port = listen_port;
*ptr_handle = (xcam_void*)listener_ctx;
return XCAM_SUCCESS;
}
/*stop the lisen svr*/
xcam_s32 livestream_listener_destroy(xcam_void* handle)
{
listener_context* listener_ctx = (listener_context*)handle;
xcam_s32 ret;
ret = livestream_listener_stop(handle);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("livestream_listener_stop failed :%d \n", ret);
return ret;
}
if (listener_ctx) {
free(listener_ctx);
listener_ctx = NULL;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_listener_start(xcam_void* handle)
{
listener_context* listener_ctx;
xcam_s32 ret;
listener_ctx = (listener_context*)handle;
if (XCAM_TRUE == listener_ctx->is_listening) {
LOG_LIVESTREAM_ERROR("network listener already started in listening\n");
return XCAM_FAILURE;
}
listener_ctx->is_listening = XCAM_TRUE;
ret = pthread_create(&(listener_ctx->listen_thread), NULL, listener_thread_process, (xcam_void*)listener_ctx);
return ret;
}
xcam_s32 livestream_listener_stop(xcam_void* handle)
{
listener_context* listener_ctx = (listener_context*)handle;
xcam_s32 ret = XCAM_SUCCESS;
if (!listener_ctx) {
return XCAM_FAILURE;
}
/*set the listen svr stop flag*/
if (listener_ctx->is_listening) {
listener_ctx->is_listening = XCAM_FALSE;
ret = pthread_join(listener_ctx->listen_thread, NULL);
if (ret != 0) {
LOG_LIVESTREAM_ERROR("destroy network listener thread error!\n");
return ret;
}
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_listener_register_callback(xcam_void* handle,
client_connect_hook connection_func, xcam_void* object)
{
listener_context* listener_ctx = (listener_context*)handle;
listener_ctx->connect_callback = connection_func;
listener_ctx->callback_object = object;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_LISTENER_H_
#define _LIVESTREAM_LISTENER_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
typedef xcam_s32 (*client_connect_hook)(xcam_void* object, xcam_s32 link_fd,
xcam_char* msg_buff, xcam_u32 msg_len);
xcam_s32 livestream_listener_create(xcam_s32 listen_port, xcam_void** ptr_handle);
xcam_s32 livestream_listener_destroy(xcam_void* handle);
xcam_s32 livestream_listener_start(xcam_void* handle);
xcam_s32 livestream_listener_stop(xcam_void* handle);
xcam_s32 livestream_listener_register_callback(xcam_void* handle,
client_connect_hook connection_func, xcam_void* object);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /* _LIVESTREAM_LISTENER_H_ */
+219
View File
@@ -0,0 +1,219 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "livestream_comm.h"
#include "livestream_mbuffer.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define UNUSED(x) (void)x
#define MAX_WAIT_COUNT (100)
#define DEFAULT_MBUFFER_SIZE (1280 * 720)
static xcam_s32 mbuffer_enable(xcam_void* handle, xcam_u8 payload_type)
{
xcam_s32 ret;
ret = xcam_mbuf_register_payload(handle, payload_type);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf register payload fail! handle:%p payload_type:%d\n",
handle, payload_type);
return ret;
}
ret = xcam_mbuf_set_rw_enable(handle, payload_type, XCAM_TRUE, XCAM_TRUE);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf set r/w enable fail, ret=%d!\n", ret);
if (XCAM_SUCCESS != xcam_mbuf_unregister_payload(handle, payload_type)) {
LOG_LIVESTREAM_ERROR("mbuf unregister payload_type:%d fail!\n", payload_type);
}
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_write_frame(xcam_void* handle, const xcam_mbuf_pack_info* pack_info)
{
if (pack_info != XCAM_NULL) {
return xcam_mbuf_write_pack(handle, pack_info);
}
return XCAM_FAILURE;
}
xcam_s32 livestream_mbuffer_create(const xcam_void* argv, xcam_void** buf_handle,
xcam_u32 buf_size, xcam_s32 max_payload)
{
xcam_s32 ret = XCAM_SUCCESS;
xcam_mbuf_cfg mbuf_cfg;
xcam_handle *handle;
mbuf_cfg.payload_count = max_payload;
mbuf_cfg.buf_size = buf_size;
if (mbuf_cfg.buf_size == 0) {
mbuf_cfg.buf_size = DEFAULT_MBUFFER_SIZE;
}
ret = xcam_mbuf_get_buffer(&handle, &mbuf_cfg);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("mbuf get buffer failed ret: %d\n", ret);
return XCAM_FAILURE;
}
*buf_handle = handle;
LOG_LIVESTREAM_INFO("mbuffer create success, size:%d payload_count:%d.\n",
mbuf_cfg.buf_size, mbuf_cfg.payload_count);
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_destroy(xcam_void* argv, xcam_void* handle)
{
xcam_s32 ret;
ret = xcam_mbuf_release_buffer(handle);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Release mbuf failed ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_register(xcam_void* handle, xcam_u8 media_type)
{
xcam_s32 ret;
ret = mbuffer_enable(handle, media_type);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf enable failed ret:0x%x!\n", ret);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_unregister(xcam_void* handle, xcam_u8 media_type)
{
xcam_s32 ret = XCAM_SUCCESS;
ret = xcam_mbuf_unregister_payload(handle, media_type);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf unregister fail, media type:%d ret:%d!\n", media_type, ret);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_read(xcam_void* handle, xcam_void** paddr, xcam_u32* plen,
xcam_u64* ppts, livestream_mbuffer_data_type* out_type, xcam_bool* bkey_flag)
{
xcam_mbuf_pack_info pack_info;
xcam_s32 ret = XCAM_FAILURE;
xcam_u32 i = 0;
pack_info.key_frame = XCAM_FALSE;
pack_info.seq = 0;
pack_info.pts = 0;
pack_info.payload_type = 0;
pack_info.pack_count = 0;
if (paddr == XCAM_NULL || plen == XCAM_NULL || ppts == XCAM_NULL
|| out_type == XCAM_NULL || bkey_flag == XCAM_NULL) {
return ret;
}
for (i = 0; i < XCAM_MBUF_MAX_PACK; i++) {
pack_info.pack_addr[i] = XCAM_NULL;
pack_info.pack_size[i] = 0;
}
*plen = 0;
ret = xcam_mbuf_read_pack(handle, XCAM_MBUF_PAYLOAD_TYPE_ALL, &pack_info);
if (XCAM_SUCCESS == ret) {
*paddr = pack_info.pack_addr[0];
for (i = 0; i < pack_info.pack_count; i++) {
*plen += pack_info.pack_size[i];
}
*ppts = pack_info.pts;
*bkey_flag = pack_info.key_frame;
switch (pack_info.payload_type) {
case BUF_PAYLOAD_H264:
case BUF_PAYLOAD_H265:
*out_type = MBUFFER_DATA_VIDEO;
break;
case BUF_PAYLOAD_G711U:
case BUF_PAYLOAD_G711A:
case BUF_PAYLOAD_G726:
case BUF_PAYLOAD_AAC:
case BUF_PAYLOAD_MP3:
*out_type = MBUFFER_DATA_AUDIO;
break;
default:
*out_type = MBUFFER_DATA_DATA;
break;
}
}
return ret;
}
xcam_s32 livestream_mbuffer_set(xcam_void* handle, xcam_u32 step)
{
xcam_s32 ret;
ret = xcam_mbuf_forward(handle, XCAM_MBUF_PAYLOAD_TYPE_ALL, step);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf forward fail, ret=%d!\n", ret);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_pts(xcam_void* handle, xcam_u8 payload_type, xcam_u64* ppts)
{
xcam_s32 ret = XCAM_FAILURE;
xcam_s32 count = 0;
xcam_u32 i = 0;
xcam_mbuf_pack_info pack_info;
pack_info.key_frame = XCAM_FALSE;
pack_info.seq = 0;
pack_info.pts = 0;
pack_info.payload_type = 0;
pack_info.pack_count = 0;
for (i = 0; i < XCAM_MBUF_MAX_PACK; i++) {
pack_info.pack_addr[i] = XCAM_NULL;
pack_info.pack_size[i] = 0;
}
while (XCAM_SUCCESS != ret && count < MAX_WAIT_COUNT) {
ret = xcam_mbuf_read_pack(handle, payload_type, &pack_info);
if (XCAM_SUCCESS == ret) {
*ppts = pack_info.pts;
xcam_mbuf_forward(handle, XCAM_MBUF_PAYLOAD_TYPE_ALL, 0);
break;
}
usleep(10 * 1000);
count++;
}
return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_MBUFFER_H_
#define _LIVESTREAM_MBUFFER_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#include "xcam_mbuf.h"
#include "pthread.h"
typedef enum {
MBUFFER_DATA_VIDEO = 1,
MBUFFER_DATA_AUDIO,
MBUFFER_DATA_DATA,
MBUFFER_DATA_BUTT
} livestream_mbuffer_data_type;
typedef struct {
pthread_mutex_t mutex; /* lock for mbuffer write pos */
} livestream_mbuffer_info;
enum {
BUF_PAYLOAD_G711U = 0, /**< G.711 Mu */
BUF_PAYLOAD_G711A = 8, /**< G.711 A */
BUF_PAYLOAD_G726 = 97, /**< G.726 */
BUF_PAYLOAD_H264 = 96, /**< H264 */
BUF_PAYLOAD_H265 = 98, /**< H265 */
BUF_PAYLOAD_ADPCM = 104, /**< ADPCM */
BUF_PAYLOAD_AAC = 105, /**< AAC encoder */
BUF_PAYLOAD_MP3 = 109, /**< MP3 encoder */
BUF_PAYLOAD_BUTT /**< invalid */
};
xcam_s32 livestream_mbuffer_write_frame(xcam_void* handle, const xcam_mbuf_pack_info* pack_info);
xcam_s32 livestream_mbuffer_create(const xcam_void* argv, xcam_void** buf_handle,
xcam_u32 buf_size, xcam_s32 max_payload);
xcam_s32 livestream_mbuffer_destroy(xcam_void* argv, xcam_void* handle);
xcam_s32 livestream_mbuffer_register(xcam_void* handle, xcam_u8 media_type);
xcam_s32 livestream_mbuffer_unregister(xcam_void* handle, xcam_u8 media_type);
xcam_s32 livestream_mbuffer_read(xcam_void* handle, xcam_void** paddr, xcam_u32* plen,
xcam_u64* ppts, livestream_mbuffer_data_type* type, xcam_bool* ptr_bkey_flag);
xcam_s32 livestream_mbuffer_set(xcam_void* handle, xcam_u32 step);
xcam_s32 livestream_mbuffer_pts(xcam_void* handle, xcam_u8 payload_type, xcam_u64* ppts);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /* _LIVESTREAM_MBUFFER_H_ */
@@ -0,0 +1,96 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_rtcp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
xcam_s32 livestream_rtcp_session_start_udp(livestream_rtcp_session* rtcp_session)
{
xcam_s32 sockfd = 0;
/*send rtcp socket*/
sockfd = livestream_comm_open_udp_socket(rtcp_session->server_rtcp_port);
if (INVALID_SOCKET == sockfd) {
LOG_LIVESTREAM_ERROR("open udp socket failed from port:%d.\n", rtcp_session->server_rtcp_port);
return XCAM_FAILURE;
}
rtcp_session->rtcp_send_sock = sockfd;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtcp_session_stop_udp(livestream_rtcp_session* rtcp_session)
{
if (XCAM_NULL == rtcp_session) {
LOG_LIVESTREAM_ERROR("param rtcp_session is null\n");
return XCAM_FAILURE;
}
livestream_comm_close_socket(&rtcp_session->rtcp_send_sock);
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtcp_session_create(livestream_rtcp_session** pptr_session, xcam_s32 packet_len)
{
if (packet_len <= 0) {
LOG_LIVESTREAM_ERROR("rtcp_session packlen less than 0! \n");
return XCAM_FAILURE;
}
livestream_rtcp_session* rtcp_session;
rtcp_session = (livestream_rtcp_session*)malloc(sizeof(livestream_rtcp_session));
if (!rtcp_session) {
LOG_LIVESTREAM_ERROR("dynamic alloc for rtcp session failed\n");
return XCAM_FAILURE;
}
memset(rtcp_session, 0x00, sizeof(livestream_rtcp_session));
rtcp_session->pack_buff = (xcam_char*)malloc(packet_len);
if (!rtcp_session->pack_buff) {
LOG_LIVESTREAM_ERROR("dynamic alloc for pack_buff failed\n");
free(rtcp_session);
rtcp_session = XCAM_NULL;
return XCAM_FAILURE;
}
memset(rtcp_session->pack_buff, 0x00, packet_len);
*pptr_session = rtcp_session;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtcp_session_destroy(livestream_rtcp_session* rtcp_session)
{
if (XCAM_NULL == rtcp_session) {
LOG_LIVESTREAM_ERROR("param rtcp_session is null !\n");
return XCAM_FAILURE;
}
if (rtcp_session->pack_buff) {
free(rtcp_session->pack_buff);
rtcp_session->pack_buff = XCAM_NULL;
}
free(rtcp_session);
rtcp_session = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
@@ -0,0 +1,38 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTCP_SESSION_H_
#define _LIVESTREAM_RTCP_SESSION_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
typedef struct {
xcam_s32 rtcp_send_sock;
xcam_s32 client_rtcp_port;
xcam_s32 server_rtcp_port;
xcam_u32 seq_num;
xcam_u32 data_len;
xcam_s32 packet_len;
xcam_char* pack_buff;
} livestream_rtcp_session;
xcam_s32 livestream_rtcp_session_start_udp(livestream_rtcp_session* rtcp_session);
xcam_s32 livestream_rtcp_session_stop_udp(livestream_rtcp_session* rtcp_session);
xcam_s32 livestream_rtcp_session_create(livestream_rtcp_session** rtcp_session, xcam_s32 packet_len);
xcam_s32 livestream_rtcp_session_destroy(livestream_rtcp_session* rtcp_session);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTCP_SESSION_H_*/
+980
View File
@@ -0,0 +1,980 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_mbuffer.h"
#include "livestream_rtp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
/* audio specific header len is 4, see rfc2550*/
static const xcam_u32 g_audio_specific_header_len = 4;
/* increase 128 bytes when current rtp packet buf is over full */
static const xcam_u32 g_rtp_packet_buf_step_len = 128;
#define RTP_VERSION 2
#define RTP_DEFAULT_SSRC 41030
#define RTP_TRANS_TIMEVAL_SEC (5)
#define RTP_TRANS_TIMEVAL_USEC (0)
#define RTP_TRANS_STREAM_VIDEO (0)
#define RTP_TRANS_STREAM_AUDIO (1)
#define RTP_TRANS_STREAM_DATA (2)
#define RTP_TRANS_STREAM_MAX (3)
static xcam_void rtp_packet_hdr(xcam_char* pack_addr, xcam_u32 timestamp, xcam_u32 marker,
rtp_payload_type payload_type, xcam_u32 ssrc, xcam_u16 last_sn)
{
rtp_pack_hdr* rtp_hdr = NULL;
rtp_hdr = (rtp_pack_hdr*)pack_addr;
RTP_HDR_SET_VERSION(rtp_hdr, RTP_VERSION);
RTP_HDR_SET_P(rtp_hdr, 0); /*no padding*/
RTP_HDR_SET_X(rtp_hdr, 0); /*no extension*/
RTP_HDR_SET_CC(rtp_hdr, 0); /*0 CSRC*/
RTP_HDR_SET_M(rtp_hdr, marker);
RTP_HDR_SET_PT(rtp_hdr, payload_type);
RTP_HDR_SET_SEQNO(rtp_hdr, htons(last_sn));
RTP_HDR_SET_TS(rtp_hdr, htonl(timestamp));
RTP_HDR_SET_SSRC(rtp_hdr, htonl(ssrc));
return;
}
static xcam_s32 rtp_send_to_sockfd(xcam_s32 write_sock, const xcam_char* buffer,
xcam_u32 data_len, const struct sockaddr_in* peer_sock_addr)
{
const xcam_char* buffer_pos = NULL;
struct timeval timeout_val;
xcam_u32 rem_size = 0;
xcam_s32 err_num = 0;
xcam_s32 size = 0;
xcam_s32 ret = 0;
fd_set write_fds;
memset(&timeout_val, 0, sizeof(struct timeval));
rem_size = data_len;
buffer_pos = buffer;
while (rem_size > 0) {
FD_ZERO(&write_fds);
FD_SET(write_sock, &write_fds);
timeout_val.tv_sec = RTP_TRANS_TIMEVAL_SEC;
timeout_val.tv_usec = RTP_TRANS_TIMEVAL_USEC;
/*judge if it can send */
ret = select(write_sock + 1, NULL, &write_fds, NULL, &timeout_val);
/*select found over time or error happend*/
if (0 == ret) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data timeout,errno=%d,%s\n",
errno, strerror(err_num));
return XCAM_FAILURE;
} else if (0 > ret) {
if (EINTR == errno || EAGAIN == errno) {
LOG_LIVESTREAM_ERROR("select error: %s\n", strerror(errno));
continue;
}
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data, select error: %s", strerror(err_num));
return XCAM_FAILURE;
}
if (!FD_ISSET(write_sock, &write_fds)) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data error: write fd not in fdset! error:%s\n",
strerror(err_num));
return XCAM_FAILURE;
}
/*select ok and fd isset ok*/
if (peer_sock_addr == NULL) {
size = send(write_sock, buffer_pos, rem_size, MSG_DONTWAIT);
} else {
size = sendto(write_sock, buffer_pos, rem_size, 0,
(struct sockaddr*)peer_sock_addr, sizeof(struct sockaddr));
}
if (size < 0) {
/*if it is not eagain error, means can not send*/
if (errno != EINTR && errno != EAGAIN) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media data(%u Byte) error: %s\n", data_len, strerror(err_num));
return XCAM_FAILURE;
}
/*it is eagain error, means can try again*/
continue;
}
rem_size -= size;
buffer_pos += size;
}
return XCAM_SUCCESS;
}
static xcam_void rtp_rtsp_itlv_packet(xcam_char* ptr_pack_addr, xcam_s32 channel,
xcam_u32 pack_len, xcam_u32 timestamp, xcam_u32 marker,
rtp_payload_type payload_type, xcam_u32 ssrc, xcam_u16 last_sn)
{
rtsp_itleaved_hdr* ptr_rtsp_itlv_hdr = XCAM_NULL;
ptr_rtsp_itlv_hdr = (rtsp_itleaved_hdr*)ptr_pack_addr;
ptr_rtsp_itlv_hdr->daollar = '$';
ptr_rtsp_itlv_hdr->chn_id = channel;
/* rtsp payload len represent the later packet lengthpacket len = rtp head + data len */
ptr_rtsp_itlv_hdr->payload_len = htons((xcam_u16)(pack_len - sizeof(rtsp_itleaved_hdr) + sizeof(rtp_pack_hdr)));
/* packet rtp packet */
rtp_packet_hdr((xcam_char*)(&(ptr_rtsp_itlv_hdr->rtp_head)), timestamp, marker, payload_type, ssrc, last_sn);
return;
}
/*
FU-A
FU indicator
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU header
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
Type Packet Type name
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264
24 STAP-A Single-time aggregation packet
25 STAP-B Single-time aggregation packet
26 MTAP16 Multi-time aggregation packet
27 MTAP24 Multi-time aggregation packet
28 FU-A Fragmentation unit
29 FU-B Fragmentation unit
30-31 undefined -
*/
static xcam_s32 rtp_fu_package_header(xcam_char* ptr_header, xcam_u8* ptr_message,
xcam_u8 start, xcam_u8 end)
{
xcam_s32 head_len = 0;
xcam_u8 nal_type;
xcam_u8 nri;
if (XCAM_NULL == ptr_header || XCAM_NULL == ptr_message) {
LOG_LIVESTREAM_ERROR("ptr_header=%p ptr_message=%p\n", ptr_header, ptr_message);
fflush(stdout);
return XCAM_FAILURE;
}
if ((1 == start && 1 == end) || start > 1 || end > 1) {
LOG_LIVESTREAM_ERROR("start=%d, end=%d\n", start, end);
fflush(stdout);
return XCAM_FAILURE;
}
if ((*ptr_message != 0 || *(ptr_message + 1) != 0 || *(ptr_message + 2) != 0 || *(ptr_message + 3) != 1)
&& (*ptr_message != 0 || *(ptr_message + 1) != 0 || *(ptr_message + 2) != 1)) {
LOG_LIVESTREAM_ERROR("this package is not have NALU!\n");
fflush(stdout);
return XCAM_FAILURE;
}
if (*ptr_message == 0 && *(ptr_message + 1) == 0 && *(ptr_message + 2) == 0 && *(ptr_message + 3) == 1) {
head_len = 4;
} else if (*ptr_message == 0 && *(ptr_message + 1) == 0 && *(ptr_message + 2) == 1) {
head_len = 3;
} else {
fflush(stdout);
return XCAM_FAILURE;
}
nri = (ptr_message[head_len] & 0x60) >> 5;
nal_type = ptr_message[head_len] & 0x1F;
*ptr_header = 0;
*ptr_header = nri << 5 | 0x1c;/*NAL is 0x1c=28means FUA*/
*(ptr_header + 1) = 0;
*(ptr_header + 1) = start << 7 | end << 6 | nal_type;
return XCAM_SUCCESS;
}
static xcam_s32 rtp_session_start_tcp_itlv(livestream_rtp_session* rtp_session)
{
if ( RTP_SESSION_STATE_READY == rtp_session->session_state ) {
rtp_session->session_state = RTP_SESSION_STATE_PLAY;
} else if ( RTP_SESSION_STATE_PLAY == rtp_session->session_state) {
/*do nothing*/
} else {
LOG_LIVESTREAM_ERROR("start video error: video is in not ready state.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
static xcam_s32 rtp_session_start_udp(livestream_rtp_session* rtp_session)
{
xcam_s32 temp_sock = 0;
if (RTP_SESSION_STATE_READY == rtp_session->session_state) {
/*send rtp socket*/
temp_sock = livestream_comm_open_udp_socket(rtp_session->server_rtp_port);
if (-1 == temp_sock) {
LOG_LIVESTREAM_ERROR("error:get socket from port%d.\n", rtp_session->server_rtp_port);
return XCAM_FAILURE;
}
rtp_session->rtp_send_sock = temp_sock;
livestream_comm_get_peer_sockaddr(rtp_session->client_ip, rtp_session->client_rtp_port, &(rtp_session->client_sockaddr));
rtp_session->session_state = RTP_SESSION_STATE_PLAY;
} else if ( RTP_SESSION_STATE_PLAY == rtp_session->session_state) {
/*do nothing*/
} else {
LOG_LIVESTREAM_ERROR("start video error: video is in not ready state.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_update_seq_num(livestream_rtp_session* rtp_session, xcam_u32 seq_num)
{
/*check the appointed task exit or not*/
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("get RTP rtp_session NULL.\n");
return XCAM_FAILURE;
}
rtp_session->seq_num = seq_num;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_get_packet_and_send_param(livestream_rtp_session* rtp_session, xcam_s32* ptr_write_sock,
struct sockaddr_in* ptr_peer_sockaddr, xcam_u32* ptr_last_sn,
rtp_pack_type* ptr_pack_type, xcam_u32* ptr_ssrc)
{
xcam_s32 ret = 0;
rtp_trans_mode trans_mode = RTP_TRANS_BUTT;
trans_mode = rtp_session->media_trans_mode;
/*1 get packet type*/
/*if stream waiting packet is video and vidieo is in playing state,
stream can be packeted*/
/*packet the stream according to different packet type */
*ptr_pack_type = rtp_session->pack_type;
*ptr_ssrc = rtp_session->ssrc;
if (RTP_TRANS_TCP_ITLV == trans_mode) {
*ptr_write_sock = rtp_session->rtp_send_sock;
*ptr_last_sn = rtp_session->seq_num;
} else if (RTP_TRANS_UDP == trans_mode) { /*the branch must be udp transport*/
*ptr_write_sock = rtp_session->rtp_send_sock;
memcpy(ptr_peer_sockaddr, &(rtp_session->client_sockaddr), sizeof(struct sockaddr_in));
*ptr_last_sn = rtp_session->seq_num;
} else if (RTP_TRANS_BROADCAST == trans_mode) {
*ptr_write_sock = rtp_session->rtp_send_sock;
memcpy(ptr_peer_sockaddr, &(rtp_session->client_sockaddr), sizeof(struct sockaddr_in));
*ptr_last_sn = rtp_session->seq_num;
} else {
LOG_LIVESTREAM_ERROR("unsupport trans type in send trans_mode:%d.\n", trans_mode);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_send_data_in_rtsp_itlv(livestream_rtp_session* rtp_session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type rtp_type, xcam_u32* seq_num, xcam_u32 ssrc,
xcam_s32 write_sock, struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len)
{
xcam_char* tmp_pack_buf = rtp_session->pack_buffer;
const xcam_u8* pack_data_addr = data_addr;
xcam_u32 pack_payload_len = packet_len;
xcam_u32 current_seq_num = *seq_num;
xcam_u32 rtp_send_len = 0;
xcam_u32 package_len = 0;
xcam_u32 send_len = 0;
xcam_s32 channel = 0;
xcam_u8 marker = 0;
xcam_s32 ret = 0;
if (pack_data_addr == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("param pack_data_addr is null\n");
return XCAM_FAILURE;
}
if (rtp_type == RTP_PT_H264) {
/*juege the slice data head length*/
xcam_u32 slice_head_len = 0;
/*H264 slice data header length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
channel = rtp_session->itlv_client_media_chnid;
/*when the frame data length is less than the packetsize 1500*/
if (data_len - (slice_head_len - 1) + sizeof(rtsp_itleaved_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*payload data should cut the 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr),
pack_data_addr + slice_head_len - 1, send_len);
/*form the rtp itlv head */
if (0x65 == (xcam_u8)data_addr[slice_head_len - 1] || 0x61 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
} else {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
}
/*send the rtp packet */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data length is larger than the packetsize 1500 */
/*need to cut the frame into several rtp packets*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtsp_itleaved_hdr) + 2 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtsp_itleaved_hdr) - 2;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr ) + 2;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len;
pack_data_addr += slice_head_len;
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) , (xcam_u8*)data_addr, 1, 0);
} else if ((package_len + send_len) < data_len) { /*in the middle packages*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ), (xcam_u8*)data_addr, 0, 0);
marker = 0;
} else { /*the last package*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ), (xcam_u8*)data_addr, 0, 1);
marker = 1;
}
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP FU Head pack error %d\n", ret);
return XCAM_FAILURE;
}
/*copy the data */
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 2,
pack_data_addr, send_len);
/*form rtp itlv head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len; /*update the ptr to the frame data*/
package_len += send_len; /*update the send data length*/
}
}
} else if (RTP_PT_H265 == rtp_type) {
/*juege the slice data head length*/
xcam_u32 slice_head_len = 0;
/*H265 slice data header length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
int nal_type = (data_addr[slice_head_len - 1] >> 1) & 0x3F;
channel = rtp_session->itlv_client_media_chnid;
/*when the frame data length is less than the packetsize 1500 */
if (data_len - (slice_head_len - 1) + sizeof(rtsp_itleaved_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*payload data should cut the 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr),
pack_data_addr + slice_head_len - 1, send_len);
if (0x26 == (xcam_u8)data_addr[slice_head_len - 1] || 0x02 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
} else {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
}
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data length is larger than the packetsize 1500 */
tmp_pack_buf[sizeof(rtsp_itleaved_hdr)] = 49 << 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 1] = 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] = nal_type;
/*need to cut the frame into several rtp packets*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtsp_itleaved_hdr) + 3 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtsp_itleaved_hdr) - 3;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr ) + 3;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len + 1;
pack_data_addr += slice_head_len + 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] |= 1 << 7;
} else if ((package_len + send_len) < data_len) { /* in the middle packages*/
marker = 0;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] &= ~(1 << 7);
} else { /*the last package*/
marker = 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] &= ~(1 << 7);
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] |= 1 << 6;
}
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 3, pack_data_addr, send_len);
/*form rtp itlv head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len; /*update the ptr to the frame data*/
package_len += send_len; /*update the send data length*/
}
}
} else if (RTP_PT_PCMA == rtp_type || RTP_PT_PCMU == rtp_type || RTP_PT_G726 == rtp_type) {
/*audio do not cut into packets*/
if (data_len >= (pack_payload_len - sizeof( rtsp_itleaved_hdr ))) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
channel = rtp_session->itlv_client_media_chnid;
send_len = data_len;
rtp_send_len = send_len + sizeof(rtsp_itleaved_hdr);
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr), pack_data_addr, send_len);
/*form the rtp head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
/*send the audio data*/
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP audio send error\n");
return ret;
}
} else if (RTP_PT_AAC == rtp_type) {
if ((data_len - 7) >= (pack_payload_len - sizeof( rtsp_itleaved_hdr ) - 4)) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
channel = rtp_session->itlv_client_media_chnid;
/*payload data should cut the first 7 bytes ADTS header */
send_len = data_len - 7 + 4;
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*add 4 bytes au header*/
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr )) = 0x00;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 1) = 0x10;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 2) = ((data_len - 7) & 0x1fe0) >> 5;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 3) = ((data_len - 7) & 0x1f) << 3;
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 4,
pack_data_addr + 7, data_len - 7);
/*add rtp head */
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (rtp_type == RTP_PT_MPA) {
if (data_len >= (pack_payload_len - sizeof(rtsp_itleaved_hdr) - g_audio_specific_header_len)) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + g_rtp_packet_buf_step_len));
if (rtp_session->pack_buffer == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
send_len = data_len + g_audio_specific_header_len;
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
xcam_u32 *audioSpecHeader = (xcam_u32 *)(tmp_pack_buf + sizeof(rtsp_itleaved_hdr));
*audioSpecHeader = 0;/* MBZ is reserved, and frag offset is 0, so audio specific header is 0 */
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr) + g_audio_specific_header_len,
pack_data_addr, data_len);
marker = 1; /* mpa maker should be 1, see rfc2550 */
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else {
/*media type do not support*/
LOG_LIVESTREAM_ERROR("unsupport stream type:%d\n", rtp_type);
return XCAM_FAILURE;
}
*seq_num = current_seq_num; /*update the seq when send several packet inside*/
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_send_data_in_rtp(livestream_rtp_session* session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type package_type, xcam_u32* seq_num,
xcam_u32 ssrc, xcam_s32 write_sock, const struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len)
{
xcam_char* tmp_pack_buf = session->pack_buffer;
const xcam_u8* pack_data_addr = data_addr;
xcam_u32 pack_payload_len = packet_len;
xcam_u32 current_seq_num = *seq_num;
xcam_u32 package_len = 0;
xcam_u32 rtp_send_len = 0;
xcam_u32 send_len = 0;
xcam_u8 marker = 0;
xcam_s32 ret = 0;
if (RTP_PT_H264 == package_type) {
xcam_u32 slice_head_len = 0;
/*H264 head length */
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
/*datalen less than packet length*/
if (data_len - (slice_head_len - 1) + sizeof(rtp_pack_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
/*payload data cut the first 4 bytres head ::00 00 00 01*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ),
pack_data_addr + slice_head_len - 1, send_len);
/*add rtp head*/
if (0x65 == (xcam_u8)data_addr[slice_head_len - 1] || 0x61 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
} else {
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
}
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data is larger than packet length*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtp_pack_hdr) + 2 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtp_pack_hdr) - 2;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtp_pack_hdr ) + 2;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len;
pack_data_addr += slice_head_len;
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ) , (xcam_u8*)data_addr, 1, 0);
} else if ((pack_payload_len == rtp_send_len) && ((package_len + send_len) < data_len)) { // in the middle packages
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ), (xcam_u8*)data_addr, 0, 0);
marker = 0;
} else { /*the last package*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ), (xcam_u8*)data_addr, 0, 1);
marker = 1;
}
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP FU Head pack error %d\n", ret);
return XCAM_FAILURE;
}
/*cp the data*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 2, pack_data_addr, send_len);
/*add the rtp head*/
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len;
package_len += send_len;
}
}
} else if (RTP_PT_H265 == package_type) {
xcam_u32 slice_head_len = 0;
/*H265 slice head length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H265 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
xcam_s32 nal_type = (data_addr[slice_head_len - 1] >> 1) & 0x3F;
/*frame date less than the packet length*/
if (data_len - (slice_head_len - 1) + sizeof(rtp_pack_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
/*payload should cut the first 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ),
pack_data_addr + slice_head_len - 1, send_len);
/*rtpͷ*/
if (0x26 == (xcam_u8)data_addr[slice_head_len - 1] || 0x02 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
} else {
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
}
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame date is larger than packet length*/
tmp_pack_buf[sizeof(rtp_pack_hdr)] = 49 << 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 1] = 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] = nal_type;
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtp_pack_hdr) + 3 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtp_pack_hdr) - 3;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtp_pack_hdr ) + 3;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len + 1;
pack_data_addr += slice_head_len + 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] |= 1 << 7;
} else if ((pack_payload_len == rtp_send_len) && ((package_len + send_len) < data_len)) { // in the middle packages
marker = 0;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] &= ~(1 << 7);
} else { /*the last package*/
marker = 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] &= ~(1 << 7);
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] |= 1 << 6;
}
/*copy the data */
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 3,
pack_data_addr, send_len);
/*add the rtp head */
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len;
package_len += send_len;
}
}
} else if (RTP_PT_PCMA == package_type || RTP_PT_PCMU == package_type || RTP_PT_G726 == package_type) {
/*audio not cut */
if (data_len >= (pack_payload_len - sizeof( rtp_pack_hdr ))) {
if (session->pack_buffer) {
free(session->pack_buffer );
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
send_len = data_len;
rtp_send_len = send_len + sizeof(rtp_pack_hdr);
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ), pack_data_addr, send_len);
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (RTP_PT_AAC == package_type) {
if ((data_len - 7) >= (pack_payload_len - sizeof(rtp_pack_hdr) - 4)) {
if (session->pack_buffer) {
free(session->pack_buffer);
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc( (data_len + 128));
if (XCAM_NULL == session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
/*payload cut the first 7 BYTES ADTS head*/
send_len = data_len - 7 + 4;
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
if (tmp_pack_buf == XCAM_NULL) {
return XCAM_FAILURE;
}
/*add 4 bytes au header*/
*(tmp_pack_buf + sizeof( rtp_pack_hdr )) = 0x00;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 1) = 0x10;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 2) = ((data_len - 7) & 0x1fe0) >> 5;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 3) = ((data_len - 7) & 0x1f) << 3;
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 4, pack_data_addr + 7, data_len - 7);
/*add rtp head */
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (package_type == RTP_PT_MPA) {
if (data_len >= (pack_payload_len - sizeof(rtp_pack_hdr) - g_audio_specific_header_len)) {
if (session->pack_buffer) {
free(session->pack_buffer);
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc((data_len + g_rtp_packet_buf_step_len));
if (session->pack_buffer == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
send_len = data_len + g_audio_specific_header_len;
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
xcam_u32 *audioSpecHeader = (xcam_u32 *)(tmp_pack_buf + sizeof(rtp_pack_hdr));
*audioSpecHeader = 0;/* MBZ is reserved, and frag offset is 0, so audio specific header is 0 */
memcpy(tmp_pack_buf + sizeof(rtp_pack_hdr) + g_audio_specific_header_len,
pack_data_addr, data_len);
marker = 1; /* mpa maker should be 1, see rfc2550 */
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else {
/*not support type */
LOG_LIVESTREAM_ERROR("unsupport stream type:%d\n", package_type);
return XCAM_FAILURE;
}
*seq_num = current_seq_num; /*update the seq num */
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_start(livestream_rtp_session* rtp_session)
{
xcam_s32 s32Ret = XCAM_SUCCESS;
if (XCAM_NULL == rtp_session) {
return XCAM_FAILURE;
}
/*if it is tcp trans type */
if (RTP_TRANS_TCP_ITLV == rtp_session->media_trans_mode) {
/*do not need create the socke while tcp_itlv cause the data trans sock is the same with session sock*/
s32Ret = rtp_session_start_tcp_itlv(rtp_session);
if (XCAM_SUCCESS != s32Ret) {
LOG_LIVESTREAM_ERROR("start task rtp_session_start_tcp_itlv fail %d.\n", s32Ret);
return s32Ret;
}
} else if (RTP_TRANS_UDP == rtp_session->media_trans_mode) {
/*if it is udp trans type, record corresponding info*/
s32Ret = rtp_session_start_udp(rtp_session);
if (XCAM_SUCCESS != s32Ret) {
LOG_LIVESTREAM_ERROR("start task rtp_session_start_udp fail %d.\n", s32Ret);
return s32Ret;
}
} else if (RTP_TRANS_TCP == rtp_session->media_trans_mode) {
/*if it is tcp trans type, record corresponding info*/
/*to do :add the part for tcp trans*/
LOG_LIVESTREAM_ERROR("start rtpSession error: not support tcp trans now.\n");
return XCAM_FAILURE;
} else {
LOG_LIVESTREAM_ERROR("start rtpSession error: unrecognized trans now.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_stop(livestream_rtp_session* rtp_session)
{
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("Stop rtpSession error.\n");
return XCAM_FAILURE;
}
/*set all meida state as init*/
rtp_session->session_state = RTP_SESSION_STATE_STOP;
/*if it is tcp trans type*/
if (RTP_TRANS_TCP_ITLV == rtp_session->media_trans_mode) {
/*do nothing*/
} else if (RTP_TRANS_UDP == rtp_session->media_trans_mode) {
/*if it is udp trans type, record corresponding info*/
livestream_comm_close_socket(&rtp_session->rtp_send_sock);
} else if (RTP_TRANS_BROADCAST == rtp_session->media_trans_mode) {
/*if it is broadcast trans type, record corresponding info*/
livestream_comm_close_socket(&rtp_session->rtp_send_sock);
} else {
LOG_LIVESTREAM_ERROR(
"top trans task error: not unrecognized trans type %d.\n", rtp_session->media_trans_mode);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_create(livestream_rtp_session** pptr_session, xcam_s32 packet_len)
{
livestream_rtp_session* ptr_rtp_session = XCAM_NULL;
if (packet_len <= 0) {
LOG_LIVESTREAM_ERROR("ptr_rtp_session packlen less than 0\n");
return XCAM_FAILURE;
}
ptr_rtp_session = (livestream_rtp_session*)malloc(sizeof(livestream_rtp_session));
if (!ptr_rtp_session) {
LOG_LIVESTREAM_ERROR("dynamic alloc for ptr_rtp_session failed\n");
return XCAM_FAILURE;
}
memset(ptr_rtp_session, 0x00, sizeof(livestream_rtp_session));
ptr_rtp_session->pack_buffer = (xcam_char*)malloc(packet_len);
if (!ptr_rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc for pack_buffer failed\n");
free(ptr_rtp_session);
ptr_rtp_session = XCAM_NULL;
return XCAM_FAILURE;
}
memset(ptr_rtp_session->pack_buffer, 0x00, packet_len);
*pptr_session = ptr_rtp_session;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_destroy(livestream_rtp_session* rtp_session)
{
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("param rtp_session is null !\n");
return XCAM_FAILURE;
}
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
free(rtp_session);
rtp_session = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTP_SESSION_H_
#define _LIVESTREAM_RTP_SESSION_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
/*RTP Payload type define rfc3551*/
typedef enum {
RTP_PT_PCMU = 0, /* mu-law G.711Mu*/
RTP_PT_GSM = 3, /* GSM */
RTP_PT_G723 = 4, /* G.723 */
RTP_PT_PCMA = 8, /* a-law G.711A*/
RTP_PT_G722 = 9, /* G.722 */
RTP_PT_L16_STEREO = 10, /* linear 16, 44.1khz, 2 channel */
RTP_PT_L16_MONO = 11, /* linear 16, 44.1khz, 1 channel */
RTP_PT_MPA = 14, /* mpeg audio */
RTP_PT_JPEG = 26, /* jpeg */
RTP_PT_H261 = 31, /* h.261 */
RTP_PT_MPV = 32, /* mpeg video */
RTP_PT_MP2T = 33, /* mpeg2 TS stream */
RTP_PT_H263 = 34, /* old H263 encapsulation */
/*96-127 dynamic*/
RTP_PT_H264 = 96, /* xmedia define as h.264 */
RTP_PT_G726 = 97, /* xmedia define as G.726 */
RTP_PT_H265 = 98, /* xmedia define as h.265 */
RTP_PT_DATA = 100, /* xmedia define as md alarm data*/
RTP_PT_AMR = 101, /* xmedia define as AMR*/
RTP_PT_MJPEG = 102, /* xmedia define as MJPEG */
RTP_PT_YUV = 103, /* xmedia define as YUV*/
RTP_PT_ADPCM = 104, /* xmedia define as ADPCM */
RTP_PT_AAC = 105, /* xmedia define as AAC */
RTP_PT_SEC = 106, /* xmedia define as SEC*/
RTP_PT_RED = 107, /* xmedia define as RED */
RTP_PT_INVALID = 128
} rtp_payload_type;
typedef enum {
PACK_TYPE_RAW = 0,
PACK_TYPE_RTP,
PACK_TYPE_RTP_STAP,
PACK_TYPE_RTP_FUA,
PACK_TYPE_RTSP_ITLV,
PACK_TYPE_XM_ITLV,
PACK_TYPE_RTSP_O_HTTP,
PACK_TYPE_BUTT
} rtp_pack_type;
typedef enum {
RTP_TRANS_UDP = 0,
RTP_TRANS_UDP_ITLV,
RTP_TRANS_TCP,
RTP_TRANS_TCP_ITLV,
RTP_TRANS_BROADCAST,
RTP_TRANS_BUTT
} rtp_trans_mode;
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif
/* total 12Bytes */
typedef struct {
#if (BYTE_ORDER == LITTLE_ENDIAN)
/* byte 0 */
xcam_u16 cc : 4; /* CSRC count */
xcam_u16 x : 1; /* header extension flag */
xcam_u16 p : 1; /* padding flag */
xcam_u16 version : 2; /* protocol version */
/* byte 1 */
xcam_u16 pt : 7; /* payload type */
xcam_u16 marker : 1; /* marker bit */
#elif (BYTE_ORDER == BIG_ENDIAN)
/* byte 0 */
xcam_u16 version : 2; /* protocol version */
xcam_u16 p : 1; /* padding flag */
xcam_u16 x : 1; /* header extension flag */
xcam_u16 cc : 4; /* CSRC count */
/*byte 1*/
xcam_u16 marker : 1; /* marker bit */
xcam_u16 pt : 7; /* payload type */
#else
#error YOU MUST DEFINE BYTE_ORDER == LITTLE_ENDIAN OR BIG_ENDIAN !
#endif
/* bytes 2, 3 */
xcam_u16 seqno : 16; /* sequence number */
/* bytes 4-7 */
xcam_u32 ts; /* timestamp in ms */
/* bytes 8-11 */
xcam_u32 ssrc; /* synchronization source */
} rtp_pack_hdr;
/*rtp field packet*/
#define RTP_HDR_SET_VERSION(HDR, val) ((HDR)->version = val)
#define RTP_HDR_SET_P(HDR, val) ((HDR)->p = val)
#define RTP_HDR_SET_X(HDR, val) ((HDR)->x = val)
#define RTP_HDR_SET_CC(HDR, val) ((HDR)->cc = val)
#define RTP_HDR_SET_M(HDR, val) ((HDR)->marker = val)
#define RTP_HDR_SET_PT(HDR, val) ((HDR)->pt = val)
#define RTP_HDR_SET_SEQNO(HDR, _sn) ((HDR)->seqno = (_sn))
#define RTP_HDR_SET_TS(HDR, _ts) ((HDR)->ts = (_ts))
#define RTP_HDR_SET_SSRC(HDR, _ssrc) ((HDR)->ssrc = _ssrc)
#define RTP_TRANS_IP_MAX_LEN (32)
/*rtsp interleaved packet*/
typedef struct {
xcam_u8 daollar; /*8, $:dollar sign(24 decimal)*/
xcam_u8 chn_id; /*8, channel id*/
xcam_u16 payload_len; /*16, payload length*/
rtp_pack_hdr rtp_head; /*rtp head*/
} rtsp_itleaved_hdr;
typedef enum {
RTP_SESSION_STATE_INIT = 0,
RTP_SESSION_STATE_READY = 1,
RTP_SESSION_STATE_PLAY = 2,
RTP_SESSION_STATE_STOP = 3,
RTP_SESSION_STATE_BUTT
} xcam_rtp_session_state;
typedef struct {
rtp_pack_type pack_type;
rtp_trans_mode media_trans_mode;
xcam_s32 rtp_send_sock;
xcam_s32 client_rtp_port;
xcam_s32 server_rtp_port;
xcam_u32 seq_num;
xcam_u32 ssrc;
xcam_u32 data_len;
xcam_char* pack_buffer;
xcam_u32 itlv_client_media_chnid;
xcam_u32 itlv_client_adapt_chnid;
xcam_rtp_session_state session_state;
xcam_char client_ip[RTP_TRANS_IP_MAX_LEN];
struct sockaddr_in client_sockaddr;
} livestream_rtp_session;
xcam_s32 livestream_rtp_session_update_seq_num(livestream_rtp_session* rtp_session, xcam_u32 seq_num);
xcam_s32 livestream_rtp_session_get_packet_and_send_param(livestream_rtp_session* rtp_session, xcam_s32* ptr_write_sock,
struct sockaddr_in* ptr_peer_sockaddr, xcam_u32* ptr_last_sn,
rtp_pack_type* ptr_pack_type, xcam_u32* ptr_ssrc);
xcam_s32 livestream_rtp_session_send_data_in_rtsp_itlv(livestream_rtp_session* rtp_session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type rtp_type, xcam_u32* seq_num, xcam_u32 ssrc,
xcam_s32 write_sock, struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len);
xcam_s32 livestream_rtp_session_send_data_in_rtp(livestream_rtp_session* session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type package_type, xcam_u32* seq_num,
xcam_u32 ssrc, xcam_s32 write_sock, const struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len);
xcam_s32 livestream_rtp_session_start(livestream_rtp_session* rtp_session);
xcam_s32 livestream_rtp_session_stop(livestream_rtp_session* rtp_session);
xcam_s32 livestream_rtp_session_create(livestream_rtp_session** rtp_session, xcam_s32 packet_len);
xcam_s32 livestream_rtp_session_destroy(livestream_rtp_session* rtp_session);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTP_SESSION_H_*/
@@ -0,0 +1,332 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <string.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_rtsp_message.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define RTSP_INVALID_STATUS_STR "Invalid Status"
#define RTSP_INVALID_STATUS_CODE (-1)
typedef struct {
xcam_char* status_str;
xcam_s32 status_code;
} rtsp_msg_status;
static rtsp_msg_status g_rtsp_status[] = {
{"Continue", 100},
{"OK", 200},
{"Created", 201},
{"Accepted", 202},
{"Non-Authoritative Information", 203},
{"No Content", 204},
{"Reset Content", 205},
{"Partial Content", 206},
{"Multiple Choices", 300},
{"Moved Permanently", 301},
{"Moved Temporarily", 302},
{"Bad Request", 400},
{"Unauthorized", 401},
{"Payment Required", 402},
{"Forbidden", 403},
{"Stream Not Found", 404},
{"Method Not Allowed", 405},
{"Not Acceptable", 406},
{"Proxy Authentication Required", 407},
{"Request Time-out", 408},
{"Conflict", 409},
{"Gone", 410},
{"Length Required", 411},
{"Precondition Failed", 412},
{"Request Entity Too Large", 413},
{"Request-URI Too Large", 414},
{"Unsupported Media Type", 415},
{"Over Supported connection ", 416},
{"Bad Extension", 420},
{"Invalid Parameter", 450},
{"Parameter Not Understood", 451},
{"Conference Not Found", 452},
{"Not Enough Bandwidth", 453},
{"Session Not Found", 454},
{"Method Not Valid In This State", 455},
{"Header Field Not Valid for Resource", 456},
{"Invalid Range", 457},
{"Parameter Is Read-Only", 458},
{"Unsupported Transport", 461},
{"Internal Server Error", 500},
{"Not Implemented", 501},
{"Bad Gateway", 502},
{"Service Unavailable", 503},
{"Gateway Time-out", 504},
{"RTSP Version Not Supported", 505},
{"Option not support", 551},
{"Extended Error:", 911},
{0, RTSP_INVALID_STATUS_CODE}
};
/*response header example
RTSP/1.0 200 OK
Server: Streaming Media Server/1.0.0(Jul 30 2015)
Cseq: 1
Public: OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN
*/
static xcam_bool msg_parser_is_response(const xcam_char* request)
{
xcam_char version[RTSP_VER_MAX_LEN] = {0};
xcam_u32 stat = 0;
xcam_s32 cnt = 0;
memset(version, '\0', sizeof(version));
cnt = sscanf(request, " %31s %d", version, &stat);
version[RTSP_VER_MAX_LEN - 1] = '\0';
if (strncasecmp(version, "RTSP/", strlen("RTSP/"))
|| cnt < RTSP_SCANF_RET_TWO || 0 == stat) {
return XCAM_FALSE; /* not a response message */
}
return XCAM_TRUE;
}
xcam_bool livestream_rtsp_message_check_request(const xcam_char* request)
{
livestream_rtsp_request_method method;
xcam_s32 ret = XCAM_SUCCESS;
/* check for request message. */
if (msg_parser_is_response(request)) {
LOG_LIVESTREAM_INFO("msg formate error, not request, just rtsp response\n");
return XCAM_FALSE;
}
/* not a response message, check for method request. */
ret = livestream_rtsp_message_parse_method(request, &method);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_INFO("method=%s requested was invalid. Message discarded.\n", request);
return XCAM_FALSE;
}
return XCAM_TRUE;
}
xcam_void livestream_rtsp_message_get_response(xcam_s32 status_code, xcam_s32 cseq,
xcam_char* reply_buf, xcam_u32 buf_len)
{
xcam_char status_str[MAX_DATE_LEN] = {0};
xcam_char buffer[MAX_DATE_LEN] = {0};
int ret;
memset(status_str, '\0', sizeof(status_str));
livestream_rtsp_message_status_code_to_str(status_code, status_str, sizeof(status_str)-1);
memset(buffer, '\0', sizeof(buffer));
livestream_comm_format_date(buffer, sizeof(buffer)-1);
ret = snprintf(reply_buf, buf_len - 1,
"%s %d %s\r\n"
"CSeq: %d\r\n"
"Cache-Control: no-cache\r\n"
"Server: %s\r\n"
"%s\r\n",
RTSP_VER_STR,
status_code,
status_str,
cseq,
RTSP_SERVER_DESCRIPTION,
buffer);
if (ret < 0) {
LOG_LIVESTREAM_ERROR("string print reply_buf error\n");
return;
}
return;
}
/*OPTIONS rtsp://ip:554/12 RTSP/1.0
CSeq: 1
Authorization: Basic Og==
User-Agent: Streaming Media Client/1.0.0(May 23 2016)*/
xcam_s32 livestream_rtsp_message_get_stream_name(const xcam_char* request, xcam_char* stream_name, xcam_u32 buf_len)
{
xcam_char method[RTSP_METHOD_MAX_LEN] = {0};
xcam_char url[RTSP_URL_MAX_LEN] = {0};
xcam_char* tmp_ptr = XCAM_NULL;
xcam_s32 cnt = 0;
cnt = sscanf(request, " %15s %255s", method, url);
if (cnt != RTSP_SCANF_RET_TWO) {
LOG_LIVESTREAM_ERROR("rtsp req format error\n");
return XCAM_FAILURE;
}
method[RTSP_METHOD_MAX_LEN - 1] = '\0';
url[RTSP_URL_MAX_LEN - 1] = '\0';
tmp_ptr = strcasestr(url, "rtsp://");
if (XCAM_NULL == tmp_ptr) {
LOG_LIVESTREAM_ERROR("rtsp req format error, url do not have rtsp://\n");
return XCAM_FAILURE;
}
tmp_ptr += strlen("rtsp://");
tmp_ptr = strchr(tmp_ptr, '/');
if (!tmp_ptr) {
LOG_LIVESTREAM_ERROR("rtsp req url do not have stream name\n");
return XCAM_FAILURE;
}
strncpy(stream_name, tmp_ptr + 1, buf_len - 1);
stream_name[buf_len - 1] = '\0';
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_get_cseq( const xcam_char* request, xcam_s32* ptr_cseq)
{
xcam_char* ptr_temp = XCAM_NULL;
ptr_temp = strcasestr(request, RTSP_HEADER_CSEQ);
if (XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("there no Cseq in req str\n");
return XCAM_FAILURE;
} else {
if (sscanf(ptr_temp, "%*s %d", ptr_cseq) != RTSP_SCANF_RET_ONE) {
return XCAM_FAILURE;
}
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_get_session_id(const xcam_char* ptr_msg_str, xcam_char* ptr_sess_id,
xcam_u32 sess_id_size)
{
xcam_char* ptr_temp = XCAM_NULL;
if (sess_id_size == 0) {
LOG_LIVESTREAM_ERROR("sessid buf size is 0\n");
return XCAM_FAILURE;
}
/*get sessionid*/
ptr_temp = strcasestr(ptr_msg_str, RTSP_HEADER_SESSION);
if ( XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("there no sessid in req str\n");
return XCAM_FAILURE;
} else {
if (sscanf(ptr_temp, "%*s %15s", ptr_sess_id) != RTSP_SCANF_RET_ONE) {
return XCAM_FAILURE;
}
}
ptr_sess_id[sess_id_size - 1] = '\0';
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_parse_method(const xcam_char* request,
livestream_rtsp_request_method* ptr_method)
{
xcam_char method[RTSP_METHOD_MAX_LEN] = {0};
if (RTSP_SCANF_RET_ONE != sscanf(request, "%15[^ ]", method)) {
return XCAM_FAILURE;
}
method[RTSP_METHOD_MAX_LEN - 1] = '\0';
if (0 == strncmp(method, RTSP_METHOD_DESCRIBE, strlen(RTSP_METHOD_DESCRIBE))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_DISCRIBLE;
} else if (0 == strncmp(method, RTSP_METHOD_SETUP, strlen(RTSP_METHOD_SETUP))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_SETUP;
} else if (0 == strncmp(method, RTSP_METHOD_PLAY, strlen(RTSP_METHOD_PLAY))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_PLAY;
} else if (0 == strncmp(method, RTSP_METHOD_TEARDOWN, strlen(RTSP_METHOD_TEARDOWN))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_TEARDOWN;
} else if (0 == strncmp(method, RTSP_METHOD_OPTIONS, strlen(RTSP_METHOD_OPTIONS))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_OPTIONS;
} else if (0 == strncmp(method, RTSP_METHOD_PAUSE, strlen(RTSP_METHOD_PAUSE))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_PAUSE;
} else if (0 == strncmp(method, RTSP_METHOD_GET_PARAMETER, strlen(RTSP_METHOD_GET_PARAMETER))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_GET_PARAM;
} else {
LOG_LIVESTREAM_INFO("not supported rtsp request method maybe rtcp in tcp_itlv\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_status_code_to_str(xcam_s32 code, xcam_char *out_buf_status,
xcam_s32 buf_len)
{
if (out_buf_status == XCAM_NULL || buf_len <= 0) {
LOG_LIVESTREAM_ERROR("Invalid param %d.\n", code);
return XCAM_FAILURE;
}
rtsp_msg_status* ptr;
for (ptr = g_rtsp_status; ptr->status_code != RTSP_INVALID_STATUS_CODE; ptr++) {
if (ptr->status_code == code) {
strncpy(out_buf_status, ptr->status_str, buf_len);
return XCAM_SUCCESS;
}
}
LOG_LIVESTREAM_ERROR("Invalid status code %d.\n", code);
strncpy(out_buf_status, RTSP_INVALID_STATUS_STR, buf_len);
return XCAM_FAILURE;
}
xcam_u32 livestream_rtsp_message_get_aac_config(xcam_u32 sample_rate, xcam_u32 chan_num)
{
xcam_u32 config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_16000;
if (chan_num == RTSP_AUDIO_SINGLE_CHN) {
switch (sample_rate) {
case LIVESTREAM_AUDIO_SAMPLE_RATE_8000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_8000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_16000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_16000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_32000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_32000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_48000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_48000;
break;
default:
break;
}
} else if (chan_num == RTSP_AUDIO_DOUBLE_CHN) {
switch (sample_rate) {
case LIVESTREAM_AUDIO_SAMPLE_RATE_8000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_8000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_16000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_16000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_32000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_32000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_48000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_48000;
break;
default:
break;
}
} else {
LOG_LIVESTREAM_ERROR("Invalid audio channel %d\n", chan_num);
}
return config_num;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
@@ -0,0 +1,168 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTSP_MESSAGE_H_
#define _LIVESTREAM_RTSP_MESSAGE_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define RTSP_VER_MAX_LEN (32)
#define RTSP_METHOD_MAX_LEN (16)
#define RTSP_URL_MAX_LEN (256)
#define RTSP_MAX_ONLINE_USER (16)
#define RTSP_IPADDE_LEN (16)
#define RTSP_TIME_LEN (32)
#define RTSP_SPS_MAX_LEN (128)
#define RTSP_PPS_MAX_LEN (128)
#define RTSP_VPS_MAX_LEN (128)
#define RTSP_SESSID_MAX_LEN (16)
#define RTSP_PASSWORD_MAX_LEN (256)
#define RTSP_USERNAME_MAX_LEN (256)
#define RTSP_AGENTBUF_MAX_LEN (128)
#define RTSP_LINE_MAX_LEN (256)
#define RTSP_TRASH_MAX_LEN (256)
#define RTSP_RANGE_MAX_LEN (64)
#define RTSP_OBJ_MAX_LEN (256)
#define RTSP_UNCARE_MAX_LEN (256)
#define RTSP_IP_MAX_LEN (16)
#define RTSP_COOK_MAX_LEN (64)
#define RTSP_CHAR_MAX_LEN (32)
#define RTSP_MAX_PROTOCOL_BUFFER (1024)
#define RTSP_SCANF_RET_ONE (1)
#define RTSP_SCANF_RET_TWO (2)
#define RTSP_SCANF_RET_THREE (3)
#define RTSP_AUDIO_SINGLE_CHN (1)
#define RTSP_AUDIO_DOUBLE_CHN (2)
#define RTSP_MAX_STREAMNAME_LEN (128)
#define XMRTSP_VER_STR "RTSP/1.0"
#define RTSP_LR "\r"
#define RTSP_LF "\n"
#define RTSP_LRLF "\r\n"
#define RTSP_SERVER_DESCRIPTION "XCAM RTSP Streaming Media Server/1.0.0"
#define RTSP_METHOD_OPTIONS "OPTIONS"
#define RTSP_METHOD_DESCRIBE "DESCRIBE"
#define RTSP_METHOD_SETUP "SETUP"
#define RTSP_METHOD_PLAY "PLAY"
#define RTSP_METHOD_PAUSE "PAUSE"
#define RTSP_METHOD_TEARDOWN "TEARDOWN"
#define RTSP_METHOD_GET_PARAMETER "GET_PARAMETER"
/* message header keywords */
#define RTSP_HEADER_CONTENTLENGTH "Content-Length"
#define RTSP_HEADER_ACCEPT "Accept"
#define RTSP_HEADER_CONTENTTYPE "Content-Type"
#define RTSP_HEADER_DATE "Date"
#define RTSP_HEADER_CSEQ "CSeq"
#define RTSP_HEADER_SESSION "Session"
#define RTSP_HEADER_TRANSPORT "Transport"
#define RTSP_VER_STR "RTSP/1.0"
#define RTSP_TRACK_ID "trackID="
#define RTSP_SDP_CONTENT_TYPE "application/sdp"
#define RTSP_SUPPORTED_CMD_LIST "OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN, GET_PARAMETER"
#define RTSP_STATUS_CODE_CONTINUE (100)
#define RTSP_STATUS_CODE_OK (200)
#define RTSP_STATUS_CODE_ACCEPTED (202)
#define RTSP_STATUS_CODE_BAD_REQUEST (400)
#define RTSP_STATUS_CODE_UNAUTHORIZED (401)
#define RTSP_STATUS_CODE_STREAM_NOT_FOUND (404)
#define RTSP_STATUS_CODE_METHOD_NOT_ALLOWED (405)
#define RTSP_STATUS_CODE_OVER_SUPPORTED_CONNECTION (416)
#define RTSP_STATUS_CODE_SESSION_NOT_FOUND (454)
#define RTSP_STATUS_CODE_UNSUPPORT_TRANSPORT (461)
#define RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR (500)
#define RTSP_STATUS_CODE_SERVICE_UNAVAILIABLE (503)
#define RTSP_STATUS_CODE_OPTION_UNSUPPORT (551)
typedef enum {
/* method codes */
LIVESTREAM_RTSP_REQ_METHOD_OPTIONS = 0,
LIVESTREAM_RTSP_REQ_METHOD_DISCRIBLE = 1,
LIVESTREAM_RTSP_REQ_METHOD_SETUP = 2,
LIVESTREAM_RTSP_REQ_METHOD_PLAY = 3,
LIVESTREAM_RTSP_REQ_METHOD_PAUSE = 4,
LIVESTREAM_RTSP_REQ_METHOD_TEARDOWN = 5,
LIVESTREAM_RTSP_REQ_METHOD_GET_PARAM = 6,
LIVESTREAM_RTSP_REQ_METHOD_SET_PARAM = 7,
LIVESTREAM_RTSP_REQ_METHOD_BUTT
} livestream_rtsp_request_method;
/** audio sample rate*/
typedef enum {
LIVESTREAM_AUDIO_SAMPLE_RATE_8000 = 8000, /* 8K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_11025 = 11025, /* 11.025K Sample rate*/
LIVESTREAM_AUDIO_SAMPLE_RATE_16000 = 16000, /* 16K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_22050 = 22050, /* 22.050K Sample rate*/
LIVESTREAM_AUDIO_SAMPLE_RATE_24000 = 24000, /* 24K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_32000 = 32000, /* 32K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_44100 = 44100, /* 44.1K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_48000 = 48000, /* 48K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_BUTT
} livestream_audio_sample_rate;
/**
aac low profile
8k single chn 1588 double chn 1590
16k single chn 1408 double chn 1410
22.05K single chn 1388 double chn 1390
24K single chn 1308 double chn 1310
32k single chn 1288 double chn 1290
44.1k single chn 1208 double chn 1210
48k single chn 1188 double chn 1190
*/
typedef enum {
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_8000 = 1588, /**< 8K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_16000 = 1408, /* *<16K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_22050 = 1388, /**<22.050K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_24000 = 1308, /* *<24K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_32000 = 1288, /**< 32K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_44100 = 1208, /**< 44.1K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_48000 = 1188, /* *<48K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_BUTT
} livestream_audio_singlechn_confignum;
typedef enum {
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_8000 = 1590, /**< 8K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_16000 = 1410, /**<16K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_22050 = 1390, /**< 22.050K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_24000 = 1310, /**<24K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_32000 = 1290, /* *<32K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_44100 = 1210, /* *<44.1K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_48000 = 1190, /* *<48K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_BUTT
} livestream_audio_doublechn_confignum;
xcam_bool livestream_rtsp_message_check_request(const xcam_char* request);
xcam_void livestream_rtsp_message_get_response(xcam_s32 stat_code, xcam_s32 cseq,
xcam_char* reply_buf, xcam_u32 buf_len);
xcam_s32 livestream_rtsp_message_get_stream_name(const xcam_char* request,
xcam_char* stream_name, xcam_u32 buf_len);
xcam_s32 livestream_rtsp_message_get_cseq( const xcam_char* request, xcam_s32* ptr_cseq);
xcam_s32 livestream_rtsp_message_get_session_id(const xcam_char* ptr_msg_str, xcam_char* ptr_sess_id,
xcam_u32 sess_id_size);
xcam_s32 livestream_rtsp_message_parse_method(const xcam_char* request, livestream_rtsp_request_method* ptr_method);
xcam_s32 livestream_rtsp_message_status_code_to_str(xcam_s32 code, xcam_char *out_buf_status,
xcam_s32 buf_len);
xcam_u32 livestream_rtsp_message_get_aac_config(xcam_u32 sample_rate, xcam_u32 chan_num);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTSP_MESSAGE_H_*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,206 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTSP_SESSION_H_
#define _LIVESTREAM_RTSP_SESSION_H_
#include <pthread.h>
#include "list.h"
#include "xcam_livestream_rtsp_server.h"
#include "xcam_track_source.h"
#include "livestream_rtsp_message.h"
#include "livestream_rtp_session.h"
#include "livestream_rtcp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define RTSP_TRACKID_VIDEO (0)
#define RTSP_TRACKID_AUDIO (1)
#define RTSP_INVALID_TRACK_ID (-1)
#define RTSP_INVALID_THREAD_ID (pthread_t)(-1)
#define RTSP_MAX_NALBASE_LEN (256)
#define CHECK_WAIT_MAX_NUM (600)
#define MAX_NAL_PARAM_LEN (128) /** max len for nal param*/
#define CHECK_WAIT_TIMEOUT (10 * 1000)
#define CHECK_WAIT_I_FRAME_COUNT (100)
#define RTSPSVR_CHECK_NULL_ERROR(condition) \
do { \
if(condition == XCAM_NULL) { \
LOG_LIVESTREAM_ERROR("pointer is null\n"); \
return LIVESTREAM_ERRNO_NULL_PTR; \
}\
} while(0)
typedef enum {
LIVESTREAM_RTSP_SESSION_STATE_INIT = 0,
LIVESTREAM_RTSP_SESSION_STATE_READY,
LIVESTREAM_RTSP_SESSION_STATE_PLAY,
LIVESTREAM_RTSP_SESSION_STATE_STOP,
LIVESTREAM_RTSP_SESSION_STATE_BUTT
} livestream_rtsp_session_state;
typedef enum {
AVC_SEI = 0x06,
AVC_IDR = 0x05,
AVC_SPS = 0x07,
AVC_PPS = 0x08,
} livestream_rtsp_avc_nalu;
typedef enum {
HEVC_PSLICE = 0x01,
HEVC_IDR = 0x13,
HEVC_SPS = 0x21,
HEVC_PPS = 0x22,
HEVC_VPS = 0x20,
HEVC_SEI = 0x27
} livestream_rtsp_hevc_nalu;
typedef struct {
livestream_rtp_session* rtp_session;
livestream_rtcp_session* rtcp_session;
pthread_mutex_t mutex_get_port;
xcam_s32 track_id;
xcam_char rtsp_url[RTSP_URL_MAX_LEN];
} livestream_rtsp_media_session;
typedef struct {
/*used to maintain link list*/
struct list_head list_ptr;
xcam_char name[RTSP_MAX_STREAMNAME_LEN];
xcam_track_source_handle video_stream;
xcam_track_source_handle audio_stream;
xcam_u32 buf_size;
xcam_u32 video_start_cnt;
xcam_u32 audio_start_cnt;
} livestream_media_stream_node;
typedef struct {
struct list_head stream_list;
pthread_mutex_t stream_list_lock;
struct list_head session_list;
pthread_mutex_t session_list_lock;
xcam_server_state_listener state_listener;
xcam_s32 max_conn_num;
xcam_s32 user_num;
xcam_s32 stream_num;
xcam_s32 listen_port;
xcam_s32 packet_len;
xcam_u32 buf_size;
xcam_s32 max_payload;
xcam_s32 timeout;
xcam_void* net_listener;
xcam_bool is_started;
} livestream_rtsp_server_ctx;
/** nal param buffer struct*/
typedef struct {
xcam_u8 data_buf[MAX_NAL_PARAM_LEN];/**< nal data buf */
xcam_u32 data_len;/**< nal data len */
} nal_param_buffer;
typedef struct {
xcam_bool video_enable;
xcam_bool audio_enable;
xcam_void* mbuf_handle;
livestream_mbuffer_info mbuf_info;
xcam_track_video_source_info video_source_info;
xcam_track_audio_source_info audio_source_info;
nal_param_buffer sps_buf;
nal_param_buffer pps_buf;
nal_param_buffer vps_buf;
xcam_u64 video_start_pts; /**< start timestamp of frame */
xcam_u64 audio_start_pts; /**< start timestamp of frame */
} livestream_rtsp_media_info;
struct rtsp_stream_session;
typedef struct {
xcam_s32 (*session_destroy_func)(xcam_void* object, struct rtsp_stream_session* rtsp_session);
} livestream_rtsp_session_listener;
typedef struct rtsp_stream_session {
/*for the management of the list */
struct list_head list_ptr;
xcam_track_source_handle video_stream;
xcam_track_source_handle audio_stream;
livestream_rtsp_session_listener session_listener;
xcam_void* listener_object;
xcam_void* rtspsvr_handle; // rtspserver handle
pthread_t session_thdid;
xcam_s32 session_sockfd;
livestream_rtsp_session_state session_state;
pthread_mutex_t state_lock;
xcam_s32 cur_request_seq;
xcam_char recv_buf[RTSP_MAX_PROTOCOL_BUFFER];
xcam_char response_buf[RTSP_MAX_PROTOCOL_BUFFER];
xcam_char stream_name[RTSP_MAX_STREAMNAME_LEN];
xcam_char url[RTSP_URL_MAX_LEN];
xcam_char client_ip[RTSP_IP_MAX_LEN];
xcam_char host_ip[RTSP_IP_MAX_LEN];
xcam_u32 recv_len;
xcam_char session_id[RTSP_SESSID_MAX_LEN];
xcam_s32 packet_len;
xcam_u32 buf_size;
xcam_s32 max_payload;
xcam_s32 timeout;
xcam_u64 start_pts;
xcam_u64 last_pts;
livestream_rtsp_media_info media_info;
livestream_rtsp_media_session video_session;
livestream_rtsp_media_session audio_session;
xcam_bool is_get_key_frame;
xcam_u16 client_rtsp_port;
xcam_u32 channel_id;
} livestream_rtsp_stream_session;
/*newly add for supporting teardown one track and multi packets*/
#define RTSP_RTCP_HEADER_LENGTH (4)
#define RTSP_RTCP_BYTES_LENGTH (4)
#define RTSP_RTCP_PACKRT_TYPE_SR (200)
#define RTSP_RTCP_PACKRT_TYPE_RR (201)
#define RTSP_RTCP_PACKRT_TYPE_SDES (202)
#define RTSP_RTCP_PACKRT_TYPE_BYE (203)
#define RTSP_RTCP_PACKRT_TYPE_APP (204)
#define RTSP_RESPONSE_PACKET_LENGTH (4)
#define RTSP_RESPONSE_PACKRT_FIRST_BYTE (36)
#define RTSP_RESPONSE_PACKRT_THIRD_BYTE (0)
xcam_s32 livestream_rtsp_session_create(livestream_rtsp_stream_session** pptr_session, xcam_s32 sockfd);
xcam_s32 livestream_rtsp_session_destroy(livestream_rtsp_stream_session* rtsp_session);
xcam_void livestream_rtsp_session_set_media_source(livestream_rtsp_stream_session* rtsp_session,
xcam_track_source_handle vid_stream, xcam_track_source_handle aud_stream,
const xcam_char* stream_name);
xcam_s32 livestream_rtsp_session_set_listener(livestream_rtsp_stream_session* rtsp_session,
const livestream_rtsp_session_listener* listener, xcam_void* object);
xcam_void livestream_rtsp_session_get_client_ipaddr(livestream_rtsp_stream_session* rtsp_session,
xcam_char* buffer, xcam_s32 buf_len);
xcam_s32 livestream_rtsp_session_client_connect(livestream_rtsp_stream_session* rtsp_session,
xcam_char* client_request, xcam_u32 request_len);
xcam_s32 livestream_rtsp_session_send(xcam_s32 writ_sock, xcam_char* ptr_buff, xcam_u32 data_len);
xcam_s32 livestream_rtsp_session_stop(livestream_rtsp_stream_session* rtsp_session);
xcam_s32 livestream_rtsp_session_write_frame(livestream_rtsp_stream_session* rtsp_session,
xcam_track_source_handle track_src, const xcam_livestream_rtsp_data* stream_data);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTSP_SESSION_H_*/
@@ -0,0 +1,970 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "livestream_errno.h"
#include "livestream_comm.h"
#include "livestream_listener.h"
#include "livestream_mbuffer.h"
#include "livestream_rtsp_session.h"
#include "livestream_rtsp_message.h"
#include "xcam_livestream_rtsp_server.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define RTSP_MAX_CONN_NUM (32)
#define RTSP_MAX_LISTEN_PORT (65535)
#define RTSP_MIN_BUFFER_SIZE (216*1024)
#define RTSP_MAX_BUFFER_SIZE (50*1024*1024)
#define RTSP_MAX_PAYLOAD_TYPE (254)
#define RTSP_MAX_PACKET_LEN (5000)
#define RTSP_MIN_PACKET_LEN (500)
#define RTSP_MAX_STREAM_NUM (8)
#define RTSP_KEEPALIVE_SECONDS_MIN (6)
static livestream_rtsp_server_ctx* g_server_ctx = XCAM_NULL;
static xcam_bool is_audio_codec_support(xcam_track_audio_codec codec)
{
if (codec == XCAM_TRACK_AUDIO_CODEC_AAC || codec == XCAM_TRACK_AUDIO_CODEC_G711A ||
codec == XCAM_TRACK_AUDIO_CODEC_G711U || codec == XCAM_TRACK_AUDIO_CODEC_G726 ||
codec == XCAM_TRACK_AUDIO_CODEC_ADPCM || codec == XCAM_TRACK_AUDIO_CODEC_MP3) {
return XCAM_TRUE;
}
LOG_LIVESTREAM_ERROR("Unsupport audio type: %d\n", codec);
return XCAM_FALSE;
}
static xcam_s32 check_frame_data(const xcam_livestream_rtsp_data* ptr_frame_data)
{
xcam_s32 ret = XCAM_SUCCESS;
xcam_u32 blk_idx = 0;
RTSPSVR_CHECK_NULL_ERROR(ptr_frame_data);
if (0 == ptr_frame_data->block_cnt
|| ptr_frame_data->block_cnt > RTSPSVR_FRAME_MAX_BLOCK) {
LOG_LIVESTREAM_ERROR("Illegal block count: %u!\n", ptr_frame_data->block_cnt);
ret = LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
for (blk_idx = 0; blk_idx < ptr_frame_data->block_cnt; blk_idx++) {
RTSPSVR_CHECK_NULL_ERROR(ptr_frame_data->data_ptr[blk_idx]);
if (0 == ptr_frame_data->data_len[blk_idx]) {
LOG_LIVESTREAM_ERROR("Illegal frame data len: 0!\n");
ret = LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
}
return ret;
}
static xcam_s32 check_stream_data(xcam_track_source_handle ptr_track_src, const xcam_livestream_rtsp_data* ptr_data)
{
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_TRACK_SOURCE_TYPE_VIDEO == ptr_track_src->track_type) {
if (XCAM_TRACK_VIDEO_CODEC_H264 != ptr_track_src->track_source_attr.video_info.codec_type
&& XCAM_TRACK_VIDEO_CODEC_H265 != ptr_track_src->track_source_attr.video_info.codec_type) {
LOG_LIVESTREAM_ERROR("not support video type :%d \n", ptr_track_src->track_source_attr.video_info.codec_type);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
} else if (XCAM_TRACK_SOURCE_TYPE_AUDIO == ptr_track_src->track_type) {
if (is_audio_codec_support(ptr_track_src->track_source_attr.audio_info.codec_type) == XCAM_FALSE) {
LOG_LIVESTREAM_ERROR("stream data illegal\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
} else {
LOG_LIVESTREAM_ERROR("source track type illegal \n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
ret = check_frame_data(ptr_data);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("Check frame data fail!\n");
return ret;
}
return XCAM_SUCCESS;
}
static xcam_s32 set_rtsp_config(livestream_rtsp_stream_session* stream_session,
livestream_rtsp_server_ctx* server_ctx)
{
RTSPSVR_CHECK_NULL_ERROR(stream_session);
RTSPSVR_CHECK_NULL_ERROR(server_ctx);
stream_session->max_payload = server_ctx->max_payload;
stream_session->timeout = server_ctx->timeout;
stream_session->packet_len = server_ctx->packet_len;
stream_session->rtspsvr_handle = (xcam_void*)server_ctx;
return XCAM_SUCCESS;
}
static xcam_s32 check_rtsp_config(xcam_livestream_rtsp_config* rtsp_config)
{
if (rtsp_config->packet_len < RTSP_MIN_PACKET_LEN
|| rtsp_config->packet_len > RTSP_MAX_PACKET_LEN) {
LOG_LIVESTREAM_ERROR("param packet_len not in the range min:%d- max:%d!\n",
RTSP_MIN_PACKET_LEN, RTSP_MAX_PACKET_LEN);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->max_conn_num <= 0
|| rtsp_config->max_conn_num > RTSP_MAX_CONN_NUM) {
LOG_LIVESTREAM_ERROR("param max_conn_num not in the range max:%d!\n", RTSP_MAX_CONN_NUM);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->listen_port <= 0
|| rtsp_config->listen_port > RTSP_MAX_LISTEN_PORT) {
LOG_LIVESTREAM_ERROR("param listen port not in the range max:%d!\n", RTSP_MAX_LISTEN_PORT);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->max_payload <= 0
|| rtsp_config->max_payload > RTSP_MAX_PAYLOAD_TYPE) {
LOG_LIVESTREAM_ERROR("param max_payload not in the range max:%d!\n", RTSP_MAX_PAYLOAD_TYPE);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->timeout >= 0
&& rtsp_config->timeout < RTSP_KEEPALIVE_SECONDS_MIN) {
LOG_LIVESTREAM_ERROR("timeout out of range, min:%d!\n", RTSP_KEEPALIVE_SECONDS_MIN);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
return XCAM_SUCCESS;
}
/*destroy a session when connect teardown */
static xcam_s32 on_session_destroy(xcam_void* object, livestream_rtsp_stream_session* rtsp_session)
{
livestream_rtsp_server_ctx* ptr_server_ctx = (livestream_rtsp_server_ctx*)object;
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
xcam_char client_ip[RTSP_IP_MAX_LEN] = {0};
struct list_head* ptr_pos_node = XCAM_NULL;
struct list_head* ptr_tmp_node = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(rtsp_session);
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(ptr_pos_node, ptr_tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(ptr_pos_node, livestream_rtsp_stream_session, list_ptr);
if (0 == strncmp(rtsp_session->session_id, session_in_list->session_id, RTSP_SESSID_MAX_LEN)) {
is_found = XCAM_TRUE;
break;
}
}
if (!is_found || XCAM_NULL == session_in_list) {
LOG_LIVESTREAM_ERROR("could not find correspond media session\n");
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return LIVESTREAM_ERRNO_SESS_NOT_EXISTED;
}
/* when teardown destroy the session and remove it from the sessionlist*/
list_del(&(session_in_list->list_ptr));
ptr_server_ctx->user_num -= 1;
livestream_rtsp_session_get_client_ipaddr(rtsp_session, client_ip, RTSP_IP_MAX_LEN);
ret = livestream_rtsp_session_destroy(rtsp_session);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("stream session destroy failed:0x%x\n", ret);
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return LIVESTREAM_ERRNO_SESS_DESTROY_FAIL;
}
if (ptr_server_ctx->state_listener.func_client_disconnect && strlen(client_ip) > 0) {
ptr_server_ctx->state_listener.func_client_disconnect(&ptr_server_ctx->state_listener, client_ip);
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return XCAM_SUCCESS;
}
/*add a connect session for rtspserver related to a stream*/
static xcam_s32 add_stream_session(livestream_rtsp_server_ctx* ptr_server_ctx,
xcam_char* client_req, xcam_u32 req_len, xcam_s32 socket_fd,
livestream_media_stream_node* ptr_stream_node)
{
livestream_rtsp_session_listener listener;
livestream_rtsp_stream_session* stream_session = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
struct list_head* pos_node = XCAM_NULL;
livestream_rtsp_stream_session* session_node = XCAM_NULL;
xcam_char client_ip[RTSP_IP_MAX_LEN] = {0};
if (XCAM_NULL == ptr_server_ctx || XCAM_NULL == client_req) {
LOG_LIVESTREAM_ERROR("Invalid param!\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (ptr_server_ctx->user_num >= ptr_server_ctx->max_conn_num) {
LOG_LIVESTREAM_ERROR("reach the max connect num:%d \n",
ptr_server_ctx->max_conn_num);
return LIVESTREAM_ERRNO_REACH_MAX_CONNECT;
}
ret = livestream_rtsp_session_create(&stream_session, socket_fd);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("livestream rtsp session create failed ret %d \n", ret);
return LIVESTREAM_ERRNO_SESS_CREATE_FAIL;
}
ret = set_rtsp_config(stream_session, ptr_server_ctx);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("set session rtsp config failed \n");
livestream_rtsp_session_destroy(stream_session);
return LIVESTREAM_ERRNO_SESS_SET_FAIL;
}
if (XCAM_NULL != ptr_stream_node) {
stream_session->buf_size = ptr_stream_node->buf_size;
livestream_rtsp_session_set_media_source(stream_session,
ptr_stream_node->video_stream, ptr_stream_node->audio_stream, ptr_stream_node->name);
}
listener.session_destroy_func = on_session_destroy;
ret = livestream_rtsp_session_set_listener(stream_session, &listener, (xcam_void*)ptr_server_ctx);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("set session listerner failed \n");
livestream_rtsp_session_destroy(stream_session);
return LIVESTREAM_ERRNO_SESS_SET_FAIL;
}
ret = livestream_rtsp_session_client_connect(stream_session, client_req, req_len);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("on client connect failed ret :%d \n", ret);
livestream_rtsp_session_destroy(stream_session);
return LIVESTREAM_ERRNO_SESS_CONNECT_FAIL;
}
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each(pos_node, &ptr_server_ctx->session_list) {
session_node = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (session_node == stream_session) {
LOG_LIVESTREAM_ERROR("rtsp stream session already exist\n");
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
ret = LIVESTREAM_ERRNO_SESS_EXISTED;
goto DES_SESSION;
}
}
list_add(&(stream_session->list_ptr), &(ptr_server_ctx->session_list));
ptr_server_ctx->user_num += 1;
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
livestream_rtsp_session_get_client_ipaddr(stream_session, client_ip, RTSP_IP_MAX_LEN);
if (ptr_server_ctx->state_listener.func_client_connect && strlen(client_ip) > 0) {
ptr_server_ctx->state_listener.func_client_connect(&ptr_server_ctx->state_listener, client_ip);
}
return XCAM_SUCCESS;
DES_SESSION:
livestream_rtsp_session_destroy(stream_session);
return ret;
}
static xcam_s32 check_list_null(livestream_rtsp_server_ctx* ptr_server_ctx, const xcam_char* stream_name)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
xcam_bool need_wait = XCAM_FALSE;
xcam_u32 wait_cnt = 0;
while (wait_cnt <= CHECK_WAIT_MAX_NUM) {
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (0 == strncmp(stream_name, session_in_list->stream_name, RTSP_MAX_STREAMNAME_LEN)) {
need_wait = XCAM_TRUE;
break;
}
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
if (need_wait) {
usleep(CHECK_WAIT_TIMEOUT);
wait_cnt++;
need_wait = XCAM_FALSE;
continue;
} else {
return XCAM_SUCCESS;
}
}
return XCAM_FAILURE;
}
static xcam_bool find_session_valid(livestream_rtsp_server_ctx* ptr_server_ctx,
const xcam_char* stream_name, livestream_rtsp_stream_session** pptr_session)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (0 == strncmp(stream_name, session_in_list->stream_name, RTSP_MAX_STREAMNAME_LEN)) {
if (session_in_list->session_state != LIVESTREAM_RTSP_SESSION_STATE_STOP) {
is_found = XCAM_TRUE;
*pptr_session = session_in_list;
break;
}
}
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return is_found;
}
/*remove all the session related to the media stream if a stream is removed*/
static xcam_s32 remove_stream_session(livestream_rtsp_server_ctx* ptr_server_ctx,
const xcam_char* stream_name)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
xcam_bool is_found = XCAM_TRUE;
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == ptr_server_ctx || XCAM_NULL == stream_name) {
LOG_LIVESTREAM_ERROR("Invalid param ptr_server_ctx=%p, stream_name=%p\n",
ptr_server_ctx, stream_name);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
while (is_found) {
is_found = find_session_valid(ptr_server_ctx, stream_name, &session_in_list);
if (!is_found) {
break;
}
/*when remove a streamsession set stop state and wait for the destroy*/
ret = livestream_rtsp_session_stop(session_in_list);
if ( XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("stream session destroy failed ret:0x%x\n", ret);
return LIVESTREAM_ERRNO_SESS_DESTROY_FAIL;
}
}
ret = check_list_null(ptr_server_ctx, stream_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("remove session timeout, and ret:%d\n", ret);
return LIVESTREAM_ERRNO_SESS_DESTROY_FAIL;
}
return XCAM_SUCCESS;
}
static xcam_s32 on_client_connection(xcam_void* object, xcam_s32 sockfd,
xcam_char* ptr_client_req, xcam_u32 req_len)
{
livestream_rtsp_server_ctx* ptr_server_ctx = (livestream_rtsp_server_ctx*)object;
livestream_media_stream_node* stream_node = XCAM_NULL;
xcam_char stream_str[RTSP_MAX_STREAMNAME_LEN] = {0};
xcam_char reply_str[RTSP_MAX_PROTOCOL_BUFFER] = {0};
struct list_head* pos_node = XCAM_NULL;
xcam_s32 stat_code = RTSP_STATUS_CODE_OK;
xcam_bool is_get_stream_name = XCAM_TRUE;
xcam_bool is_found = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
xcam_s32 resp_len = 0;
xcam_s32 cseq = 0;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(ptr_client_req);
if (!livestream_rtsp_message_check_request(ptr_client_req)) {
LOG_LIVESTREAM_ERROR("invalid rtsp request, just ignore this connection\n");
stat_code = RTSP_STATUS_CODE_BAD_REQUEST;
ret = LIVESTREAM_ERRNO_SESS_BAD_REQUEST;
goto Failed;
}
ret = livestream_rtsp_message_get_stream_name(ptr_client_req, stream_str, RTSP_MAX_STREAMNAME_LEN);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("could not find stream name!\n");
is_get_stream_name = XCAM_FALSE;
}
ret = livestream_rtsp_message_get_cseq(ptr_client_req, &cseq);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("invalid rtsp url, could not find CSeq\n");
stat_code = RTSP_STATUS_CODE_BAD_REQUEST;
ret = LIVESTREAM_ERRNO_SESS_BAD_REQUEST;
goto Failed;
}
if (!is_get_stream_name) {
if (add_stream_session(ptr_server_ctx, ptr_client_req, req_len, sockfd, XCAM_NULL) != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Add stream session failed\n");
stat_code = RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR;
ret = LIVESTREAM_ERRNO_STREAM_ADD_SESS_FAIL;
goto Failed;
}
return XCAM_SUCCESS;
}
//if find stream name ,start session with streamnode
pthread_mutex_lock(&ptr_server_ctx->stream_list_lock);
list_for_each(pos_node, &ptr_server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (!strcasecmp(stream_node->name, stream_str)) {
is_found = XCAM_TRUE;
break;
}
}
if (!is_found || XCAM_NULL == stream_node) {
LOG_LIVESTREAM_ERROR("invalid rtsp request, could not find correspond stream\n");
stat_code = RTSP_STATUS_CODE_BAD_REQUEST;
ret = LIVESTREAM_ERRNO_SESS_STREAM_NOT_FOUND;
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
goto Failed;
}
if (add_stream_session(ptr_server_ctx, ptr_client_req, req_len, sockfd, stream_node) != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Add stream session failed!\n");
stat_code = RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR;
ret = LIVESTREAM_ERRNO_STREAM_ADD_SESS_FAIL;
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
goto Failed;
}
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return XCAM_SUCCESS;
Failed:
livestream_rtsp_message_get_response(stat_code, cseq, reply_str, RTSP_MAX_PROTOCOL_BUFFER);
resp_len = strlen(reply_str);
if (resp_len > 0) {
livestream_rtsp_session_send(sockfd, reply_str, resp_len);
}
livestream_comm_close_socket(&sockfd);
return ret;
}
static xcam_s32 check_stream_config(xcam_livestream_rtsp_source* stream_src, xcam_char* stream_name, xcam_u32 buf_size)
{
if (RTSP_MAX_STREAMNAME_LEN < strlen(stream_name) || 0 == strlen(stream_name)) {
LOG_LIVESTREAM_ERROR("stream name too long max len:%d\n", RTSP_MAX_STREAMNAME_LEN);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (buf_size < RTSP_MIN_BUFFER_SIZE || buf_size > RTSP_MAX_BUFFER_SIZE) {
LOG_LIVESTREAM_ERROR("param buf_size not in the range min:%d max:%d!\n",
RTSP_MIN_BUFFER_SIZE, RTSP_MAX_BUFFER_SIZE);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL == stream_src->video_src_handle && XCAM_NULL == stream_src->audio_src_handle) {
LOG_LIVESTREAM_ERROR("can not add a stream with no audio and no video\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL != stream_src->audio_src_handle
&& XCAM_TRACK_SOURCE_TYPE_AUDIO != stream_src->audio_src_handle->track_type) {
LOG_LIVESTREAM_ERROR("can not add a audio src with video type\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL != stream_src->video_src_handle) {
if (XCAM_TRACK_SOURCE_TYPE_VIDEO != stream_src->video_src_handle->track_type) {
LOG_LIVESTREAM_ERROR("can not add a video src with audio type\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_TRACK_VIDEO_CODEC_H264 != stream_src->video_src_handle->track_source_attr.video_info.codec_type
&& XCAM_TRACK_VIDEO_CODEC_H265 != stream_src->video_src_handle->track_source_attr.video_info.codec_type) {
LOG_LIVESTREAM_ERROR("not support video type :%d \n",
stream_src->video_src_handle->track_source_attr.video_info.codec_type);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL == stream_src->video_src_handle->func_request_key_frame) {
LOG_LIVESTREAM_ERROR("video source call back null error \n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
}
if (XCAM_NULL != stream_src->audio_src_handle) {
if (XCAM_TRACK_SOURCE_TYPE_AUDIO != stream_src->audio_src_handle->track_type) {
LOG_LIVESTREAM_ERROR("can not add a audio src with video type\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (is_audio_codec_support(stream_src->audio_src_handle->track_source_attr.audio_info.codec_type) == XCAM_FALSE) {
LOG_LIVESTREAM_ERROR("stream data illegal\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
}
return XCAM_SUCCESS;
}
static xcam_void get_one_stream(livestream_rtsp_server_ctx* server_ctx, xcam_char* name, xcam_u32 size)
{
livestream_media_stream_node* stream_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
pthread_mutex_lock(&server_ctx->stream_list_lock);
if (size == 0) {
LOG_LIVESTREAM_ERROR("stream name buf size[%u] is illegal\n", size);
return;
}
/* delete all the session related to the mediastream*/
list_for_each_safe(pos_node, tmp_node, &server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (snprintf(name, size - 1, "%s", stream_node->name) < 0) {
LOG_LIVESTREAM_ERROR("string print name error\n");
}
break;
}
pthread_mutex_unlock(&server_ctx->stream_list_lock);
return;
}
static xcam_bool find_one_stream_and_delete(livestream_rtsp_server_ctx* server_ctx,
const xcam_char* stream_name)
{
livestream_media_stream_node* stream_node = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
pthread_mutex_lock(&server_ctx->stream_list_lock);
list_for_each_safe(pos_node, tmp_node, &server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (!strcasecmp(stream_node->name, stream_name))
{
is_found = XCAM_TRUE;
list_del(&(stream_node->list_ptr));
free(stream_node);
stream_node = XCAM_NULL;
server_ctx->stream_num--;
break;
}
}
pthread_mutex_unlock(&server_ctx->stream_list_lock);
return is_found;
}
xcam_s32 xcam_livestream_rtsp_server_write_frame(xcam_void* handle, xcam_track_source_handle track_src,
const xcam_livestream_rtsp_data* ptr_data)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
livestream_media_stream_node* stream_node = XCAM_NULL;
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
xcam_bool is_found_stream = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(handle);
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver not created fail!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(track_src);
RTSPSVR_CHECK_NULL_ERROR(ptr_data);
ret = check_stream_data(track_src, ptr_data);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("rtsperver write frame data illegal\n");
return ret;
}
//find the stream node in the list
pthread_mutex_lock(&ptr_server_ctx->stream_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (stream_node->video_stream == track_src || stream_node->audio_stream == track_src) {
is_found_stream = XCAM_TRUE;
break;
}
}
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
if (XCAM_TRUE != is_found_stream) {
LOG_LIVESTREAM_WARN("stream not find, write frame fail\n");
return LIVESTREAM_ERRNO_STREAM_NOT_EXIST;
}
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (session_in_list->video_stream == track_src || session_in_list->audio_stream == track_src) {
/*write frame for the session*/
ret = livestream_rtsp_session_write_frame(session_in_list, track_src, ptr_data);
if (XCAM_SUCCESS != ret) {
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
LOG_LIVESTREAM_ERROR("Write frame failed ret:0x%x mediatype:0x%x!\n",
ret, track_src->track_type);
return ret;
}
}
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_add_media_stream(xcam_void* handle, xcam_livestream_rtsp_source* stream_src,
xcam_char* stream_name, xcam_u32 buf_size)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_media_stream_node* stream_node = XCAM_NULL;
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(stream_name);
RTSPSVR_CHECK_NULL_ERROR(stream_src);
if (ptr_server_ctx->stream_num >= RTSP_MAX_STREAM_NUM) {
LOG_LIVESTREAM_ERROR("rtsperver stream num reach max:%d\n", RTSP_MAX_STREAM_NUM);
return LIVESTREAM_ERRNO_STREAM_ADD_FAIL;
}
ret = check_stream_config(stream_src, stream_name, buf_size);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("rtsperver check param illegal!\n");
return ret;
}
/*find the stream node in the list */
pthread_mutex_lock(&ptr_server_ctx->stream_list_lock);
list_for_each(pos_node, &ptr_server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (!strcasecmp(stream_node->name, stream_name)) {
LOG_LIVESTREAM_ERROR("media source streamname alreay exist\n");
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return LIVESTREAM_ERRNO_STREAM_EXISTED;
}
}
/* stream node not exist then create and add to the list*/
stream_node = (livestream_media_stream_node*)malloc(sizeof(livestream_media_stream_node));
if (!stream_node) {
LOG_LIVESTREAM_ERROR("dynamic alloc rtsp LiveMediaStreamNode failed\n");
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return LIVESTREAM_ERRNO_MALLOC_FAIL;
}
memset(stream_node, 0x00, sizeof(livestream_media_stream_node));
strncpy(stream_node->name, stream_name, RTSP_MAX_STREAMNAME_LEN - 1);
stream_node->name[RTSP_MAX_STREAMNAME_LEN - 1] = '\0';
stream_node->audio_stream = stream_src->audio_src_handle;
stream_node->video_stream = stream_src->video_src_handle;
stream_node->buf_size = buf_size;
stream_node->audio_start_cnt = 0;
stream_node->video_start_cnt = 0;
ptr_server_ctx->stream_num++;
list_add(&(stream_node->list_ptr), &(ptr_server_ctx->stream_list));
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_remove_media_stream(xcam_void* handle, const xcam_char* stream_name)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
if ( XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(stream_name);
if (RTSP_MAX_STREAMNAME_LEN < strlen(stream_name) || 0 == strlen(stream_name)) {
LOG_LIVESTREAM_ERROR("rtsperver streamname error len \n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
/*when remove a media stream destroy the related connections if existed*/
ret = remove_stream_session(ptr_server_ctx, stream_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("could not find remove stream session for stream: %s ret:%d\n",
stream_name, ret);
return LIVESTREAM_ERRNO_STREAM_REMOVE_FAIL;
}
is_found = find_one_stream_and_delete(ptr_server_ctx, stream_name);
if (!is_found) {
LOG_LIVESTREAM_ERROR("could not find correspond media stream\n");
return LIVESTREAM_ERRNO_STREAM_NOT_EXIST;
}
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_start(xcam_void* handle)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx->net_listener);
if (ptr_server_ctx->is_started) {
LOG_LIVESTREAM_ERROR("Rtspserver already started \n");
return LIVESTREAM_ERRNO_START_LISTENER_AGAIN;
}
ret = livestream_listener_start(ptr_server_ctx->net_listener);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Rtsp start listener failed ret:%d \n", ret);
return LIVESTREAM_ERRNO_START_LISTENER_FAIL;
}
livestream_listener_register_callback(ptr_server_ctx->net_listener,
on_client_connection, (xcam_void*)ptr_server_ctx);
ptr_server_ctx->is_started = XCAM_TRUE;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_stop(xcam_void* handle)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx;
xcam_char tmp_name[RTSP_MAX_STREAMNAME_LEN];
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
if (!ptr_server_ctx->is_started) {
LOG_LIVESTREAM_ERROR("Rtspserver have not been started\n");
return LIVESTREAM_ERRNO_STOP_LISTENER_NOT_STARTED;
}
if (ptr_server_ctx->net_listener == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("net_listener is XCAM_NULL Rtsp start listener failed \n");
return LIVESTREAM_ERRNO_STOP_LISTENER_FAIL;
}
ret = livestream_listener_stop(ptr_server_ctx->net_listener);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Rtsp start listener failed ret:%d \n", ret);
return LIVESTREAM_ERRNO_STOP_LISTENER_FAIL;
}
while (0 != ptr_server_ctx->stream_num) {
get_one_stream(ptr_server_ctx, tmp_name, RTSP_MAX_STREAMNAME_LEN);
ret = remove_stream_session(ptr_server_ctx, tmp_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("could not find remove stream session for stream: %s\n", tmp_name);
return LIVESTREAM_ERRNO_STREAM_REMOVE_SESS_FAIL;
}
find_one_stream_and_delete(ptr_server_ctx, tmp_name);
}
ptr_server_ctx->is_started = XCAM_FALSE;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_set_listener(xcam_void* handle, xcam_server_state_listener* state_listener)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(state_listener);
RTSPSVR_CHECK_NULL_ERROR(state_listener->func_client_connect);
RTSPSVR_CHECK_NULL_ERROR(state_listener->func_client_disconnect);
RTSPSVR_CHECK_NULL_ERROR(state_listener->func_server_error);
ptr_server_ctx->state_listener.func_client_connect = state_listener->func_client_connect;
ptr_server_ctx->state_listener.func_client_disconnect = state_listener->func_client_disconnect;
ptr_server_ctx->state_listener.func_server_error = state_listener->func_server_error;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_create(xcam_void** handle, xcam_livestream_rtsp_config* ptr_rtsp_config)
{
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(handle);
RTSPSVR_CHECK_NULL_ERROR(ptr_rtsp_config);
ret = check_rtsp_config(ptr_rtsp_config);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("config param null !\n");
return ret;
}
if (XCAM_NULL != g_server_ctx) {
LOG_LIVESTREAM_ERROR("RTSPSERVER already created do not create again!\n");
return LIVESTREAM_ERRNO_CREATE_AGAIN;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)malloc(sizeof(livestream_rtsp_server_ctx));
if (!ptr_server_ctx) {
LOG_LIVESTREAM_ERROR("dynamic alloc livestream_rtsp_server_ctx failed\n");
return LIVESTREAM_ERRNO_MALLOC_FAIL;
}
memset(ptr_server_ctx, 0x00, sizeof(livestream_rtsp_server_ctx));
pthread_mutex_init(&ptr_server_ctx->session_list_lock, XCAM_NULL);
pthread_mutex_init(&ptr_server_ctx->stream_list_lock, XCAM_NULL);
ptr_server_ctx->max_conn_num = ptr_rtsp_config->max_conn_num;
ptr_server_ctx->listen_port = ptr_rtsp_config->listen_port;
ptr_server_ctx->max_payload = ptr_rtsp_config->max_payload;
ptr_server_ctx->packet_len = ptr_rtsp_config->packet_len;
ptr_server_ctx->timeout = ptr_rtsp_config->timeout;
ptr_server_ctx->user_num = 0;
ptr_server_ctx->stream_num = 0;
INIT_LIST_HEAD(&ptr_server_ctx->stream_list);
INIT_LIST_HEAD(&ptr_server_ctx->session_list);
ret = livestream_listener_create(ptr_server_ctx->listen_port, &ptr_server_ctx->net_listener);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("Rtsp create listener failed ret:%d\n", ret);
pthread_mutex_destroy(&ptr_server_ctx->stream_list_lock);
pthread_mutex_destroy(&ptr_server_ctx->session_list_lock);
free(ptr_server_ctx);
ptr_server_ctx = XCAM_NULL;
return LIVESTREAM_ERRNO_CREATE_LISTENER_FAIL;
}
*handle = (xcam_void*)ptr_server_ctx;
g_server_ctx = ptr_server_ctx;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_destroy(xcam_void* handle)
{
xcam_char tmp_name[RTSP_MAX_STREAMNAME_LEN];
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(handle);
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
livestream_rtsp_server_ctx* ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
while (0 != ptr_server_ctx->stream_num) {
get_one_stream(ptr_server_ctx, tmp_name, RTSP_MAX_STREAMNAME_LEN);
ret = remove_stream_session(ptr_server_ctx, tmp_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("could not find remove stream session for stream: %s\n", tmp_name);
return LIVESTREAM_ERRNO_STREAM_REMOVE_SESS_FAIL;
}
find_one_stream_and_delete(ptr_server_ctx, tmp_name);
}
pthread_mutex_destroy(&ptr_server_ctx->stream_list_lock);
pthread_mutex_destroy(&ptr_server_ctx->session_list_lock);
ret = livestream_listener_destroy(ptr_server_ctx->net_listener);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("Rtsp destroy listener failed ret:%d \n", ret);
return LIVESTREAM_ERRNO_DESTROY_LISTENER_FAIL;
}
free(ptr_server_ctx);
ptr_server_ctx = XCAM_NULL;
g_server_ctx = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
+858
View File
@@ -0,0 +1,858 @@
/*
* Copyright (c) XCAM. All rights reserved.
*
* This file contains the media buffer implementations for media stream.
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include "list.h"
#include "xcam_log.h"
#include "xcam_mbuf.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
/*macro definition */
#define MBUF_DEBUG 0
#define MBUF_INFO(fmt...) XCAM_LOG_INFO_PRINT("MBUF", fmt)
#define MBUF_WARN(fmt...) XCAM_LOG_WARN_PRINT("MBUF", fmt)
#define MBUF_ERROR(fmt...) XCAM_LOG_ERR_PRINT("MBUF", fmt)
#define MBUF_FATAL(fmt...) XCAM_LOG_FATAL_PRINT("MBUF", fmt)
#define MBUF_ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define MBUF_PAYLOAD_READABLE 0x01
#define MBUF_PAYLOAD_WRITABLE 0x02
#define MBUF_INVALID_64BITS_PTS ((xcam_u64)(-1))
#define MBUF_MALLOC(addr) malloc(addr)
#define MBUF_FREE(addr) free(addr)
#define MBUF_MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex)
#define MBUF_MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
#define IS_READING(block) (MBUF_BLOCK_READING == block->block_status)
#define IS_WRITING(block) (MBUF_BLOCK_WRITING == block->block_status)
#define IS_FREE(block) (MBUF_BLOCK_FREE == block->block_status)
#define IS_HEAD_OF_LIST(block, inst) (&block->block_node == inst->block_head.next)
#define IS_FULL(inst, size) (inst->free < size)
#define MBUF_ASSERT_RETURN(condition, ret_value) \
do { \
if (!(condition)) { \
MBUF_WARN("[%s %d]assert warning\n",__func__,__LINE__); \
return ret_value; \
} \
}while(0)
#define MBUF_FIND_BLOCK_BY_ADDR(addr, inst, block) \
{ \
struct list_head* pos; \
struct list_head* n; \
cam_mbuf_block_info* tmp; \
list_for_each_safe(pos, n, &inst->block_head) { \
tmp = list_entry(pos, cam_mbuf_block_info, block_node); \
if (addr == tmp->addr) { \
block = tmp; \
break; \
} \
} \
}
#define MBUF_FREE_BLOCK_LIST(inst) \
{ \
struct list_head* pos; \
struct list_head* n; \
list_for_each_safe(pos, n, &inst->block_head) { \
list_del(pos); \
} \
}
#define MBUF_FIND_TAIL_BLOCK(inst, block) \
{ \
block = list_entry(inst->block_head.prev, cam_mbuf_block_info, block_node); \
}
#define MBUF_FIND_HEAD_BLOCK(inst, block) \
{ \
block = list_entry(inst->block_head.next, cam_mbuf_block_info, block_node); \
}
typedef enum {
MBUF_BLOCK_FREE = 0,
MBUF_BLOCK_READING,
MBUF_BLOCK_WRITING,
MBUF_BLOCK_BUTT
} cam_mbuf_block_status;
typedef struct {
xcam_u8 *addr; /* User virtual address */
xcam_u32 size; /* Buffer size, in the unit of byte */
} cam_mbuf_buf_info;
/* Describe a buffer block */
typedef struct {
xcam_u8 *addr; /* base address of block */
xcam_u32 size; /* size of block */
xcam_u64 pts;
xcam_u32 seq;
xcam_u16 payload_type; /* mbuffer data payload type */
xcam_u8 key_frame; /* is used to video */
xcam_u8 pack_count; /* pack_count < XCAM_MBUF_MAX_PACK */
xcam_u32 pack_size[XCAM_MBUF_MAX_PACK]; /* pack size of pre pack */
cam_mbuf_block_status block_status; /* Status of block */
struct list_head block_node; /* Block list node */
} cam_mbuf_block_info;
typedef struct {
xcam_u16 payload_type; /* mbuffer data payload type */
xcam_u8 mode; /* readable,writable */
xcam_u8 pad; /* reserved */
} cam_mbuf_payload_attr;
/* Describe a buffer instance */
typedef struct {
xcam_u8 *addr; /* Start user virtual address of the buffer instance */
xcam_u32 size; /* Size of the buffer instance */
xcam_u32 payload_count; /* payload type count of the mbuffer */
cam_mbuf_payload_attr *payload_attr; /* readable,writable of the payload */
xcam_u32 used; /* Used size */
xcam_u32 free; /* Free size */
xcam_u32 freeze; /* Freeze size */
pthread_mutex_t mutex_lock; /* mutex lock */
struct list_head block_head; /* Buffer manager block list head */
} cam_mbuf_inst;
/*static function */
static xcam_s32 cam_mbuf_get_write_buffer(xcam_handle *handle, cam_mbuf_buf_info *buf_info)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *block = XCAM_NULL;
cam_mbuf_block_info *block_head = XCAM_NULL;
xcam_u32 read_offset;
xcam_u32 write_offset;
xcam_u32 tail_free;
xcam_u32 head_free;
xcam_u32 acq_size;
xcam_bool is_alloc = XCAM_FALSE;
MBUF_ASSERT_RETURN(buf_info != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(buf_info->size > 0, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/*Data align*/
buf_info->size = MBUF_ALIGN(buf_info->size,sizeof(xcam_u32));
/* Buffer full */
acq_size = buf_info->size + sizeof(cam_mbuf_block_info);
if (IS_FULL(buf_inst, acq_size)) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_BUFFER_FULL;
}
/* If empty, write from start */
if (list_empty(&buf_inst->block_head)) {
write_offset = read_offset = 0;
} else { /*Find write offset and read offset,only support one writer*/
MBUF_FIND_TAIL_BLOCK(buf_inst, block);
if (IS_WRITING(block)) {
buf_info->addr = block->addr + sizeof(cam_mbuf_block_info);
buf_info->size = block->size - sizeof(cam_mbuf_block_info);
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
MBUF_ERROR("mbuf block is busy:%p,size:%d\n",buf_info->addr,buf_info->size);
return XCAM_ERR_MBUF_BUSY;
}
write_offset = (xcam_u32)block->addr + block->size - (xcam_u32)buf_inst->addr;
MBUF_FIND_HEAD_BLOCK(buf_inst, block_head);
read_offset = (xcam_u32)block_head->addr - (xcam_u32)buf_inst->addr;
}
/* Reverse: write pointer before read pointer, the free area is continuous */
if (write_offset <= read_offset) {
is_alloc = XCAM_TRUE;
} else { /* Normal: write pointer after read pointer, the free area isn't continuous */
tail_free = buf_inst->size - write_offset;
head_free = buf_inst->free - tail_free;
if (tail_free >= acq_size) {
is_alloc = XCAM_TRUE;
} else if (head_free >= acq_size) {
is_alloc = XCAM_TRUE;
/* Alloc from head */
write_offset = 0;
/* Freeze the last area */
buf_inst->freeze = tail_free;
buf_inst->free -= tail_free;
}
}
/* Allocate fail, return */
if (!is_alloc) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_BUFFER_FULL;
}
/* Allocate new block,init block parameter*/
block = (cam_mbuf_block_info *)(buf_inst->addr + write_offset);
block->addr = (xcam_u8 *)block;
buf_info->addr = block->addr + sizeof(cam_mbuf_block_info);
block->size = acq_size;
block->pts = MBUF_INVALID_64BITS_PTS;
block->block_status = MBUF_BLOCK_WRITING;
/* Add block to list */
list_add_tail(&block->block_node, &buf_inst->block_head);
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
static xcam_s32 cam_mbuf_put_write_buffer(xcam_handle *handle, const xcam_mbuf_pack_info *pack_info, cam_mbuf_buf_info *buf_info)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *block = XCAM_NULL;
xcam_u32 write_size;
xcam_u8 i;
MBUF_ASSERT_RETURN(buf_info != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(buf_info->size > 0, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/* Find the tail block */
MBUF_FIND_TAIL_BLOCK(buf_inst, block);
write_size = buf_info->size + sizeof(cam_mbuf_block_info);
if (write_size > block->size) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
MBUF_ERROR("Put size err:%d>%d\n", write_size, block->size);
return XCAM_ERR_MBUF_PUT_BUF_FAILED;
}
/* The block must be WRITING status and its address must be right */
if (IS_WRITING(block) && ((xcam_u32)(buf_info->addr - sizeof(cam_mbuf_block_info)) == (xcam_u32)block->addr)) {
/* If size=0, drop this block */
if (0 == buf_info->size) {
/* Delete block from list */
list_del(&block->block_node);
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
block->pts = pack_info->pts;
block->seq = pack_info->seq;
block->key_frame = pack_info->key_frame;
block->payload_type = pack_info->payload_type;
block->pack_count = pack_info->pack_count;
for (i = 0; i < pack_info->pack_count; i++) {
block->pack_size[i] = pack_info->pack_size[i];
}
block->block_status = MBUF_BLOCK_FREE;
} else {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
MBUF_ERROR("Put fail.\n");
return XCAM_ERR_MBUF_PUT_BUF_FAILED;
}
/* Manage instance */
buf_inst->used += write_size;
buf_inst->free -= write_size;
#if (MBUF_DEBUG == 1)
if (buf_inst->size != buf_inst->used + buf_inst->free + buf_inst->freeze) {
MBUF_FATAL("Error:unmatch, size:%d!= used:%d+free:%d+freeze:%d\n",buf_inst->size,buf_inst->used,
buf_inst->free,buf_inst->freeze);
}
#endif
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
static xcam_s32 cam_mbuf_acq_read_buffer(xcam_handle *handle, xcam_u16 payload_type, xcam_mbuf_pack_info *pack_info)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *buf_block = XCAM_NULL;
xcam_u32 offset;
xcam_u8 i;
MBUF_ASSERT_RETURN(pack_info != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/* Buffer empty */
if ((0 == buf_inst->used) || (list_empty(&buf_inst->block_head))) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_BUFFER_EMPTY;
}
/* Find head block */
MBUF_FIND_HEAD_BLOCK(buf_inst, buf_block);
/* The block must be FREE status */
if (!IS_FREE(buf_block)) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_BUFFER_EMPTY;
}
/* Read from the block */
pack_info->pts = buf_block->pts;
pack_info->seq = buf_block->seq;
pack_info->key_frame = buf_block->key_frame;
pack_info->payload_type = buf_block->payload_type;
pack_info->pack_count = buf_block->pack_count;
offset = 0;
for (i = 0;i < pack_info->pack_count;i++) {
pack_info->pack_addr[i] = buf_block->addr + sizeof(cam_mbuf_block_info) + offset;
pack_info->pack_size[i] = buf_block->pack_size[i];
offset += buf_block->pack_size[i];
}
/* Change status */
buf_block->block_status = MBUF_BLOCK_READING;
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
static xcam_s32 cam_mbuf_read_buffer_over(xcam_handle *handle, xcam_u16 payload_type)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *block = XCAM_NULL;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/* Find head block */
MBUF_FIND_HEAD_BLOCK(buf_inst, block);
if (XCAM_NULL == block) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_RELEASE_FAILED;
}
/* Change status */
if (IS_READING(block)) {
block->block_status = MBUF_BLOCK_FREE;
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
xcam_s32 cam_mbuf_release_read_buffer(xcam_handle *handle, cam_mbuf_buf_info *buf_info)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *block = XCAM_NULL;
MBUF_ASSERT_RETURN(buf_info != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
if (buf_info == XCAM_NULL) {
/* Find head block */
MBUF_FIND_HEAD_BLOCK(buf_inst, block);
} else {
/* Find block by address */
xcam_u8 *addr = buf_info->addr - sizeof(cam_mbuf_block_info);
MBUF_FIND_BLOCK_BY_ADDR(addr, buf_inst, block);
}
if (XCAM_NULL == block) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_READ_FAILED;
}
/* Unfreeze */
if ((0 != buf_inst->freeze) &&
(block->addr + block->size == buf_inst->addr + buf_inst->size - buf_inst->freeze)) {
buf_inst->free += buf_inst->freeze;
buf_inst->freeze = 0;
}
/* Only support free orderly */
if (IS_HEAD_OF_LIST(block, buf_inst) && IS_READING(block)) {
/* Change parameter of instance */
buf_inst->used -= block->size;
buf_inst->free += block->size;
/* Delete block from list */
list_del(&block->block_node);
} else {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_READ_FAILED;
}
#if (MBUF_DEBUG == 1)
if (buf_inst->size != buf_inst->used + buf_inst->free + buf_inst->freeze) {
MBUF_FATAL("Error:unmatch,size:%d!=used:%d+free:%d+freeze:%d\n",buf_inst->size,buf_inst->used,
buf_inst->free,buf_inst->freeze);
}
#endif
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
static xcam_s32 cam_mbuf_release_buffer(xcam_handle *handle, xcam_u16 payload_type)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *block = XCAM_NULL;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/* Find head block */
MBUF_FIND_HEAD_BLOCK(buf_inst, block);
if (XCAM_NULL == block) {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_RELEASE_FAILED;
}
/* Unfreeze */
if ((0 != buf_inst->freeze) &&
(block->addr + block->size == buf_inst->addr + buf_inst->size - buf_inst->freeze)) {
buf_inst->free += buf_inst->freeze;
buf_inst->freeze = 0;
}
/* Only support free orderly */
if (IS_READING(block) || IS_FREE(block)) {
/* Change parameter of instance */
buf_inst->used -= block->size;
buf_inst->free += block->size;
/* Delete block from list */
list_del(&block->block_node);
} else {
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_ERR_MBUF_RELEASE_FAILED;
}
#if (MBUF_DEBUG == 1)
if (buf_inst->size != buf_inst->used + buf_inst->free + buf_inst->freeze) {
MBUF_FATAL("Error:unmatch,size:%d!=used:%d+free:%d+freeze:%d\n",buf_inst->size,buf_inst->used,
buf_inst->free,buf_inst->freeze);
}
#endif
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
static xcam_s32 cam_mbuf_reset(xcam_handle *handle)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/* Free all block */
MBUF_FREE_BLOCK_LIST(buf_inst);
/* Set used/free/freeze size */
buf_inst->used = 0;
buf_inst->free = buf_inst->size;
buf_inst->freeze = 0;
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
static xcam_bool cam_mbuf_check_payload_valid(xcam_handle *handle, xcam_u16 payload_type, xcam_u8 rw_mode)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_payload_attr *attr;
xcam_bool ret = XCAM_FALSE;
xcam_s32 i;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_FALSE);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
buf_inst = (cam_mbuf_inst *)handle;
attr = (cam_mbuf_payload_attr *)buf_inst->payload_attr;
for (i = 0; i < buf_inst->payload_count; i++) {
if ((payload_type == XCAM_MBUF_PAYLOAD_TYPE_ALL) || (payload_type == attr[i].payload_type)) {
if ((attr[i].mode & rw_mode) == rw_mode) {
ret = XCAM_TRUE;
} else {
ret = XCAM_FALSE;
MBUF_ERROR("Payload type:%hu,mode:%hhu is invalid\n",payload_type,attr[i].mode);
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return ret;
}
}
MBUF_ERROR("Payload type:%hu not found\n",payload_type);
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return ret;
}
xcam_s32 xcam_mbuf_get_buffer(xcam_handle **handle, xcam_mbuf_cfg *buf_cfg)
{
xcam_u8* buf_addr;
cam_mbuf_inst* buf_inst = XCAM_NULL;
xcam_u32 attr_size;
int ret;
int i;
MBUF_ASSERT_RETURN(buf_cfg != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(buf_cfg->buf_size != 0, XCAM_ERR_MBUF_PARAM_INVALID);
if ((buf_cfg->payload_count == 0) || (buf_cfg->payload_count > XCAM_MBUF_MAX_PACK)) {
return XCAM_ERR_MBUF_PARAM_INVALID;
}
/* Allocate an instance */
attr_size = buf_cfg->payload_count * sizeof(cam_mbuf_payload_attr);
if ((buf_inst = (cam_mbuf_inst*)MBUF_MALLOC(sizeof(cam_mbuf_inst) + attr_size + buf_cfg->buf_size)) == XCAM_NULL) {
MBUF_FATAL("Malloc failed. need buff size=%d KB\n", buf_cfg->buf_size/1024);
return XCAM_ERR_MBUF_ALLOC_FAILED;
}
memset(buf_inst,0,sizeof(cam_mbuf_inst));
buf_addr = (xcam_u8 *)buf_inst + sizeof(cam_mbuf_inst) + attr_size;
/* Init instance parameter */
buf_inst->addr = buf_addr;
buf_inst->size = buf_cfg->buf_size;
buf_inst->payload_count = buf_cfg->payload_count;
buf_inst->payload_attr = (cam_mbuf_payload_attr *)((xcam_u8 *)buf_inst + sizeof(cam_mbuf_inst));
for (i = 0; i < buf_inst->payload_count; i++) {
buf_inst->payload_attr[i].payload_type = XCAM_MBUF_PAYLOAD_TYPE_INVALID;
buf_inst->payload_attr[i].mode = 0;
}
if ((ret = pthread_mutex_init(&buf_inst->mutex_lock,XCAM_NULL)) != 0) {
MBUF_FATAL("pthread_mutex_init error ret : %x\n",ret);
MBUF_FREE(buf_inst);
return XCAM_ERR_MBUF_MUTEX_INIT_FAILED;
}
/* Init block list parameter */
buf_inst->free = buf_inst->size;
buf_inst->freeze = 0;
buf_inst->used = 0;
INIT_LIST_HEAD(&buf_inst->block_head);
*handle = (xcam_void *)buf_inst;
return XCAM_SUCCESS;
}
xcam_s32 xcam_mbuf_release_buffer(xcam_handle *handle)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
/* If has blocks, free them */
if (!list_empty(&buf_inst->block_head)) {
MBUF_FREE_BLOCK_LIST(buf_inst);
}
/* Free resource */
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
MBUF_FREE(buf_inst);
return XCAM_SUCCESS;
}
xcam_s32 xcam_mbuf_register_payload(xcam_handle *handle, xcam_u16 payload_type)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_payload_attr *attr;
xcam_s32 i;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(payload_type != XCAM_MBUF_PAYLOAD_TYPE_INVALID, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
attr = (cam_mbuf_payload_attr *)buf_inst->payload_attr;
for (i = 0; i < buf_inst->payload_count; i++) {
if (attr[i].payload_type == XCAM_MBUF_PAYLOAD_TYPE_INVALID) {
attr[i].payload_type = payload_type;
attr[i].mode = MBUF_PAYLOAD_READABLE | MBUF_PAYLOAD_WRITABLE;
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
/*Register space is full*/
return XCAM_FAILURE;
}
xcam_s32 xcam_mbuf_unregister_payload(xcam_handle *handle, xcam_u16 payload_type)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_payload_attr *attr;
xcam_s32 i;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(payload_type != XCAM_MBUF_PAYLOAD_TYPE_INVALID, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
attr = (cam_mbuf_payload_attr *)buf_inst->payload_attr;
for (i = 0; i < buf_inst->payload_count; i++) {
if (attr[i].payload_type == payload_type) {
attr[i].payload_type = XCAM_MBUF_PAYLOAD_TYPE_INVALID;
attr[i].mode = 0;
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_FAILURE;
}
xcam_s32 xcam_mbuf_set_rw_enable(xcam_handle *handle, xcam_u16 payload_type, xcam_bool enable_read, xcam_bool enable_write)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_payload_attr *attr;
xcam_s32 i;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(payload_type != XCAM_MBUF_PAYLOAD_TYPE_INVALID, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
attr = (cam_mbuf_payload_attr *)buf_inst->payload_attr;
for (i = 0; i < buf_inst->payload_count; i++) {
if (attr[i].payload_type == payload_type) {
attr[i].mode = 0;
if (enable_read)
attr[i].mode |= MBUF_PAYLOAD_READABLE;
if (enable_write)
attr[i].mode |= MBUF_PAYLOAD_WRITABLE;
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
/*Not found payload type*/
return XCAM_ERR_MBUF_NOT_REGISTERED;
}
xcam_s32 xcam_mbuf_get_rw_enable(xcam_handle *handle, xcam_u16 payload_type, xcam_bool *enable_read, xcam_bool *enable_write)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_payload_attr *attr;
xcam_s32 i;
MBUF_ASSERT_RETURN(handle != XCAM_NULL, XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(payload_type != XCAM_MBUF_PAYLOAD_TYPE_INVALID, XCAM_ERR_MBUF_PARAM_INVALID);
*enable_read = XCAM_FALSE;
*enable_write = XCAM_FALSE;
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
attr = (cam_mbuf_payload_attr *)buf_inst->payload_attr;
for (i = 0; i < buf_inst->payload_count; i++) {
if (attr[i].payload_type == payload_type) {
if (attr[i].mode & MBUF_PAYLOAD_READABLE) {
*enable_read = XCAM_TRUE;
}
if (attr[i].mode & MBUF_PAYLOAD_WRITABLE) {
*enable_write = XCAM_TRUE;
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
}
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
/*Not found payload type*/
return XCAM_ERR_MBUF_NOT_REGISTERED;
}
xcam_s32 xcam_mbuf_write_pack(xcam_handle *handle, const xcam_mbuf_pack_info *pack_info)
{
xcam_u32 i = 0;
xcam_s32 ret;
cam_mbuf_buf_info buf_info;
xcam_u8 *write_addr;
xcam_u32 offset;
/*Check payload type and rw mode*/
if (!cam_mbuf_check_payload_valid(handle, pack_info->payload_type, MBUF_PAYLOAD_WRITABLE)) {
return XCAM_FAILURE;
}
memset(&buf_info,0,sizeof(cam_mbuf_buf_info));
for (i = 0; i < pack_info->pack_count; i++) {
buf_info.size += pack_info->pack_size[i];
}
/*Get write buffer space*/
ret = cam_mbuf_get_write_buffer(handle, &buf_info);
if (ret == XCAM_ERR_MBUF_BUFFER_FULL) {
MBUF_WARN("Mbuf is full!\n");
cam_mbuf_reset(handle);
ret = cam_mbuf_get_write_buffer(handle, &buf_info);
}
if (XCAM_SUCCESS != ret) {
return ret;
}
write_addr = buf_info.addr;
if (write_addr == XCAM_NULL) {
return XCAM_FAILURE;
}
/*Write package data to buffer space*/
offset = 0;
for (i = 0; i < pack_info->pack_count; i++)
{
memcpy(write_addr + offset, pack_info->pack_addr[i], pack_info->pack_size[i]);
offset += pack_info->pack_size[i];
}
/*Update buffer information*/
ret = cam_mbuf_put_write_buffer(handle,pack_info, &buf_info);
return ret;
}
xcam_s32 xcam_mbuf_read_pack(xcam_handle *handle, xcam_u16 payload_type, xcam_mbuf_pack_info *pack_info)
{
xcam_s32 ret = XCAM_SUCCESS;
/*Check payload type and rw mode*/
if (!cam_mbuf_check_payload_valid(handle, payload_type, MBUF_PAYLOAD_READABLE))
{
return XCAM_ERR_MBUF_PAYLOAD_CHECK_ERR;
}
ret = cam_mbuf_acq_read_buffer(handle, payload_type, pack_info);
return ret;
}
xcam_s32 xcam_mbuf_forward(xcam_handle *handle, xcam_u16 payload_type, xcam_u32 step)
{
xcam_s32 ret = XCAM_SUCCESS;
xcam_s32 i = 0;
/*Restore buffer status from reading to free*/
if (step == 0) {
ret = cam_mbuf_read_buffer_over(handle,payload_type);
return ret;
}
for (i = 0; i < step; i++) {
if ((ret = cam_mbuf_release_buffer(handle, payload_type)) != XCAM_SUCCESS) {
break;
}
}
return ret;
}
xcam_s32 xcam_mbuf_debug(xcam_handle *handle, xcam_u16 payload_type)
{
cam_mbuf_inst *buf_inst = XCAM_NULL;
cam_mbuf_block_info *block = XCAM_NULL;
cam_mbuf_payload_attr *attr;
struct list_head *pos;
struct list_head *n;
xcam_s32 i = 0;
MBUF_ASSERT_RETURN(handle != XCAM_NULL,XCAM_ERR_MBUF_PARAM_INVALID);
MBUF_ASSERT_RETURN(payload_type != XCAM_MBUF_PAYLOAD_TYPE_INVALID, XCAM_ERR_MBUF_PARAM_INVALID);
buf_inst = (cam_mbuf_inst *)handle;
MBUF_MUTEX_LOCK(buf_inst->mutex_lock);
MBUF_INFO("---------------------mbuf info-----------------------\n");
MBUF_INFO("addr:%p,size:%d =? total:%d(used:%d+free:%d+freeze:%d) \n", buf_inst->addr,buf_inst->size,
buf_inst->used+buf_inst->free+buf_inst->freeze,buf_inst->used,buf_inst->free,buf_inst->freeze);
attr = (cam_mbuf_payload_attr *)buf_inst->payload_attr;
MBUF_INFO("register info:\n");
for (i = 0; i < buf_inst->payload_count; i++) {
MBUF_INFO("i:%d,type:%d,mode:%d\n",i,attr[i].payload_type,attr[i].mode);
}
if (list_empty(&buf_inst->block_head)) {
MBUF_INFO("\tNone node\n");
} else {
list_for_each_safe(pos, n, &buf_inst->block_head)
{
block = list_entry(pos, cam_mbuf_block_info, block_node);
MBUF_INFO("\tNode %d: addr=%p size=%d status=%d\n", i++, block->addr, block->size,
block->block_status);
}
}
MBUF_INFO("----------------------------------------------------\n");
MBUF_MUTEX_UNLOCK(buf_inst->mutex_lock);
return XCAM_SUCCESS;
}
xcam_s32 xcam_mbuf_get_pack_data_offset(xcam_handle *handle, const xcam_mbuf_pack_info *pack_info, xcam_u32 *offset)
{
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */