GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
Executable
+17
@@ -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
|
||||
Executable
+173
@@ -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;
|
||||
}
|
||||
Executable
+120
@@ -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
@@ -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
@@ -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_*/
|
||||
Executable
+93
@@ -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
|
||||
Executable
+170
@@ -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
@@ -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_
|
||||
Executable
+73
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
Executable
+858
@@ -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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user