+
+
+
+
+
+
+
+
+
+
+
+
+ decodeData
+ ObjectiveC
+ EXPRESSION
+
+
+ decodeData[0]
+ ObjectiveC
+ EXPRESSION
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/device/CMakeLists.txt b/device/CMakeLists.txt
new file mode 100644
index 0000000..ca7b457
--- /dev/null
+++ b/device/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.14)
+project(librtsp_c C)
+
+set(CMAKE_C_STANDARD 99)
+find_library(WS2_32_LIBRARY ws2_32)
+
+add_executable(librtsp_c main.c thirdparty/map/src/map.c
+librtsp.c sock.c
+thirdparty/base64_simple/base64.c
+)
+
+target_link_libraries(librtsp_c ${WS2_32_LIBRARY})
diff --git a/device/librtsp.c b/device/librtsp.c
new file mode 100644
index 0000000..0fa77c5
--- /dev/null
+++ b/device/librtsp.c
@@ -0,0 +1,65 @@
+#include "librtsp.h"
+
+RtspClient *ConectRtsp(char *ip,int port,char *desc){
+ if(0 == ip || 0 == desc){
+ return 0;
+ }
+ RtspClient *ret = (RtspClient*)malloc(sizeof(RtspClient));
+ ret->sock = Connect(ip,port);
+ if(ret->sock < 0){
+ return 0;
+ }
+ strcpy(ret->hostIp,ip);
+ ret->port = port;
+ ret->cesq = 0;
+ strcpy(ret->despcrtion,desc);
+ return ret;
+}
+
+int SendOption(RtspClient*p,CallBack *c){
+ char pRecv[500];
+ char buf[500];
+ sprintf(buf,"OPTIONS rtsp://%s:%d/%s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Lavf57.71.100\r\n\r\n",p->hostIp,p->port,
+ p->despcrtion,p->cesq);
+ int ret = Send(p->sock,buf,strlen(buf));
+ printf("send %d \r\ndata is:\r\n%s\r\n",ret,buf);
+ if(0 > ret){
+ closesocket(p->sock);
+ p->conn = FALSE;
+ return -1;
+ }
+ if(Recv(p->sock,pRecv,500) > 0) {
+ printf("recv: %s\r\n",pRecv);
+ } else{
+ printf("error recv ");
+ return -1;
+ }
+}
+
+int SendAnnounce(RtspClient *p,CallBack callback){
+ char pRecv[500] = {0};
+ char buf[500] = {0};
+ char length[10] = {0};
+ sprintf(buf,"ANNOUNCE rtsp://%s:%d/%s RTSP/1.0\r\nContent-Type: application/sdp\r\n"
+ "CSeq: %d\r\nUser-Agent: Lavf57.71.100\r\nContent-Length:",p->hostIp,p->port,
+ p->despcrtion,p->cesq);
+ sprintf(length,"%d",strlen(buf));
+ int len = strlen(buf) + 7 + strlen(length);
+ sprintf(length,"%d",len);
+ strcat(buf,length);
+ strcat(buf,"\r\n\r\n");
+
+ int ret = Send(p->sock,buf,strlen(buf));
+ printf("send %d \r\ndata is:\r\n%s\r\n",ret,buf);
+ if(0 > ret){
+ closesocket(p->sock);
+ p->conn = FALSE;
+ return -1;
+ }
+ if(Recv(p->sock,pRecv,500) > 0) {
+ printf("recv: %s\r\n",pRecv);
+ } else{
+ printf("error recv ");
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/device/librtsp.h b/device/librtsp.h
new file mode 100644
index 0000000..a73caa5
--- /dev/null
+++ b/device/librtsp.h
@@ -0,0 +1,43 @@
+//
+// Created by 29019 on 2019/9/11.
+//
+
+#ifndef LIBRTSP_C_LIBRTSP_H
+#define LIBRTSP_C_LIBRTSP_H
+
+#include "sock.h"
+#include "thirdparty/map/src/map.h"
+#include "stdio.h"
+#include "list.h"
+
+typedef struct _T_Param{
+ char key[50];
+ char value[140];
+ struct list_head p;
+}Params;
+
+typedef struct _T_RtspClientCtx{
+ char hostIp[30];
+ int port;
+ char despcrtion[50];
+ Sock sock;
+ int cesq;
+ boolean conn;
+}RtspClient;
+// callback function that receive data.
+typedef int (*CallBack)(RtspClient *client,const char * data,int len);
+typedef enum _E_Method{
+ OPTIONS = 0,
+ POST,
+ ANNOUNCE,
+ SETUP,
+ RECORD
+}Method;
+RtspClient *ConectRtsp(char *ip,int port,char *desc);
+int GenPayload(Method method,char *data);
+int SendOption(RtspClient*p,CallBack *c);
+int SendSetup(RtspClient *p,CallBack *c);
+int SendRecord(RtspClient *p,CallBack *c);
+int SendAnnounce(RtspClient *p,CallBack);
+
+#endif //LIBRTSP_C_LIBRTSP_H
diff --git a/device/list.h b/device/list.h
new file mode 100644
index 0000000..ed020a4
--- /dev/null
+++ b/device/list.h
@@ -0,0 +1,700 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+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;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add_rcu(struct list_head * new,
+ struct list_head * prev, struct list_head * next)
+{
+ new->next = next;
+ new->prev = prev;
+ smp_wmb();
+ next->prev = new;
+ prev->next = new;
+}
+
+/**
+ * list_add_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
+{
+ __list_add_rcu(new, head, head->next);
+}
+
+/**
+ * list_add_tail_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_tail_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_tail_rcu(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add_rcu(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_rcu - deletes entry from list without re-initialization
+ * @entry: the element to delete from the list.
+ *
+ * Note: list_empty on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_del_rcu()
+ * or list_add_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ *
+ * Note that the caller is not permitted to immediately free
+ * the newly deleted entry. Instead, either synchronize_rcu()
+ * or call_rcu() must be used to defer freeing until an RCU
+ * grace period has elapsed.
+ */
+static inline void list_del_rcu(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->prev = LIST_POISON2;
+}
+
+/*
+ * list_replace_rcu - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * The old entry will be replaced with the new entry atomically.
+ */
+static inline void list_replace_rcu(struct list_head *old, struct list_head *new){
+ new->next = old->next;
+ new->prev = old->prev;
+ smp_wmb();
+ new->next->prev = new;
+ new->prev->next = new;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+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);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+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;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+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);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ * list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_rcu - iterate over an rcu-protected list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = rcu_dereference(pos->next))
+
+#define __list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = rcu_dereference(pos->next))
+
+/**
+ * list_for_each_safe_rcu - iterate over an rcu-protected list safe
+ * against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = rcu_dereference(n), n = pos->next)
+
+/**
+ * list_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_entry_rcu(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = rcu_dereference(list_entry(pos->member.next, \
+ typeof(*pos), member)))
+
+
+/**
+ * list_for_each_continue_rcu - iterate over an rcu-protected list
+ * continuing after existing point.
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next; prefetch((pos)->next), (pos) != (head); \
+ (pos) = rcu_dereference((pos)->next))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_rcu - deletes entry from hash list without re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry().
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (n->pprev) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+
+/**
+ * hlist_add_head_rcu - adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs. Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_add_head_rcu(struct hlist_node *n,
+ struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ n->pprev = &h->first;
+ smp_wmb();
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if(next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+#define hlist_for_each_rcu(pos, head) \
+ for ((pos) = (head)->first; pos && ({ prefetch((pos)->next); 1; }); \
+ (pos) = rcu_dereference((pos)->next))
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_head_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = rcu_dereference(pos->next))
+
+#else
+#warning "don't include kernel headers in userspace"
+#endif /* __KERNEL__ */
diff --git a/device/main.c b/device/main.c
new file mode 100644
index 0000000..38bdfa8
--- /dev/null
+++ b/device/main.c
@@ -0,0 +1,21 @@
+#include "thirdparty/map/src/map.h"
+#include "sock.h"
+#include
+#include "list.h"
+#include "librtsp.h"
+#include "thirdparty/base64_simple/base64.h"
+
+int main() {
+ unsigned char decodeData[500] = {0};
+ RtspClient *p = ConectRtsp("118.24.238.198", 554, "sword");
+ if (0 == p) {
+ printf("error connect server\r\n");
+ return -1;
+ }
+ SendOption(p, 0);
+ SendAnnounce(p, 0);
+ base64_decode("2QAKKy0A8ARPywgAAADACAAAAMD0eMGVA==",
+ strlen("2QAKKy0A8ARPywgAAADACAAAAMD0eMGVA=="), decodeData);
+
+ printf("decode data %s\r\n", decodeData);
+}
\ No newline at end of file
diff --git a/device/sock.c b/device/sock.c
new file mode 100644
index 0000000..7abb38c
--- /dev/null
+++ b/device/sock.c
@@ -0,0 +1,82 @@
+#include "sock.h"
+#pragma comment(lib, "ws2_32.lib")
+#ifdef WIN32
+Sock Connect(char *ip,int port){
+ if(0 == ip){
+ return -1;
+ }
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ wVersionRequested = MAKEWORD(2,0);
+ err = WSAStartup(wVersionRequested,&wsaData);//
+ SOCKET ret = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//create socket
+ if(ret < 0){
+ printf("error malloc socket%d\r\n",ret);
+ exit(0);
+ }
+ SOCKADDR_IN addrSrv;
+ addrSrv.sin_addr.S_un.S_addr = inet_addr(ip);//"49.152.49.84");
+ addrSrv.sin_family = AF_INET;
+ addrSrv.sin_port = htons(port);
+ if(SOCKET_ERROR==connect(ret,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))){
+ closesocket(ret);
+ DWORD gle = WSAGetLastError();
+ printf("connect socket error code %ld\r\n",gle);
+ return -1;
+ }
+ return ret;
+}
+
+int Send(Sock s,char*dat, int len){
+ fd_set wFds;
+ FD_ZERO(&wFds);
+ FD_SET(s,&wFds);
+
+ int ret = select(s + 1,0,&wFds,0,0);
+ // time expire
+ if(ret == 0){
+ return 0;
+ }else if(ret > 0){
+ if(FD_ISSET(s,&wFds)){
+ int recv = send(s,dat,len,0);
+ if(recv < 0)
+ {
+ closesocket(s);
+ return -2;
+ }
+ return recv;
+ }
+ }else{
+ printf("error code %d\r\n",ret);
+ return -1;
+ }
+}
+int Recv(Sock s,char *rec,int len){
+ fd_set rFds;
+ fd_set eFds;
+ FD_ZERO(&rFds);
+ FD_SET(s,&rFds);
+
+ int ret = select(s + 1,&rFds,0,0,0);
+ // time expire
+ if(ret == 0){
+ return 0;
+ }else if(ret > 0){
+ if(FD_ISSET(s,&rFds)){
+ int recvDat = recv(s,rec,len,0);
+ if(recvDat <0)
+ {
+ closesocket(s);
+ return -1;
+ }
+ return recvDat;
+ }
+ if(FD_ISSET(s,&eFds)){
+ closesocket(s);
+ return -3;
+ }
+ }
+ return -1;
+}
+#endif
diff --git a/device/sock.h b/device/sock.h
new file mode 100644
index 0000000..894fb66
--- /dev/null
+++ b/device/sock.h
@@ -0,0 +1,63 @@
+#ifndef __SOCK__
+#define __SOCK__
+#include
+#include
+#include "stdio.h"
+#ifdef linux
+typedef int Sock;
+#endif
+
+#ifdef WIN32
+typedef SOCKET Sock;
+#endif
+Sock Connect(char *ip,int port);
+int Send(Sock s,char*dat, int len);
+int Recv(Sock s,char *rec,int len);
+/*
+ANNOUNCE rtsp://118.24.238.198:554/Sword RTSP/1.0
+CSeq: 1
+User-Agent: EasyPusher v1.2.16.1105
+Content-Type: application/sdp
+ Content-Length: 384
+
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=EasyDarwin
+i=EasyDarwin
+c=IN IP4 127.0.0.1
+t=0 0
+a=x-qt-text-nam:EasyDarwin
+ a=x-qt-text-inf:EasyDarwin
+ a=x-qt-text-cmt:source application::EasyDarwin
+a=x-qt-text-aut:
+a=x-qt-text-cpy:
+m=video 0 RTP/AVP 96
+a=rtpmap:96 H264/90000
+a=fmtp:96 packetization-mode=1;sprop-parameter-sets=,2QAKKy0A8ARPywgAAADACAAAAMD0eMGVA==
+a=control:streamid=0
+
+ANNOUNCE rtsp://118.24.238.198:554/Sword RTSP/1.0
+CSeq: 1
+User-Agent: EasyPusher v1.2.16.1105
+Content-Type: application/sdp
+Content-Length: 384
+
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=EasyDarwin
+i=EasyDarwin
+c=IN IP4 127.0.0.1
+t=0 0
+a=x-qt-text-nam:EasyDarwin
+a=x-qt-text-inf:EasyDarwin
+a=x-qt-text-cmt:source application::EasyDarwin
+a=x-qt-text-aut:
+a=x-qt-text-cpy:
+m=video 0 RTP/AVP 96
+a=rtpmap:96 H264/90000
+a=fmtp:96 packetization-mode=1;sprop-parameter-sets=,2QAKKy0A8ARPywgAAADACAAAAMD0eMGVA==
+a=control:streamid=0
+
+*/
+
+#endif
\ No newline at end of file
diff --git a/device/thirdparty/map/LICENSE b/device/thirdparty/map/LICENSE
new file mode 100644
index 0000000..03b6555
--- /dev/null
+++ b/device/thirdparty/map/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014 rxi
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/device/thirdparty/map/README.md b/device/thirdparty/map/README.md
new file mode 100644
index 0000000..805b425
--- /dev/null
+++ b/device/thirdparty/map/README.md
@@ -0,0 +1,109 @@
+# map
+A type-safe generic hashmap implementation for C.
+
+## Installation
+The [map.c](src/map.c?raw=1) and [map.h](src/map.h?raw=1) files can be dropped
+into an existing C project and compiled along with it.
+
+
+## Usage
+Before using a map it should first be initialised using the `map_init()`
+function.
+```c
+map_int_t m;
+map_init(&m);
+```
+
+Values can added to a map using the `map_set()` function.
+```c
+map_set(&m, "testkey", 123);
+```
+
+To retrieve a value from a map, the `map_get()` function can be used.
+`map_get()` will return a pointer to the key's value, or `NULL` if no mapping
+for that key exists.
+```c
+int *val = map_get(&m, "testkey");
+if (val) {
+ printf("value: %d\n", *val);
+} else {
+ printf("value not found\n");
+}
+```
+
+When you are done with a map the `map_deinit()` function should be called on
+it. This will free any memory the map allocated during use.
+```c
+map_deinit(&m);
+```
+
+
+## Types
+map.h provides the following predefined map types:
+
+Contained Type | Type name
+----------------|----------------------------------
+void* | map_void_t
+char* | map_str_t
+int | map_int_t
+char | map_char_t
+float | map_float_t
+double | map_double_t
+
+To define a new map type the `map_t()` macro should be used:
+```c
+/* Creates the type uint_map_t for storing unsigned ints */
+typedef map_t(unsigned int) uint_map_t;
+```
+
+## Functions
+All map functions are macro functions. The parameter `m` in each function
+should be a pointer to the map struct which the operation is to be performed
+on. The `key` parameter should always be a string value.
+
+### map\_t(T)
+Creates a map struct for containing values of type `T`.
+```c
+/* Typedefs the struct `fp_map_t` as a container for type FILE* */
+typedef map_t(FILE*) fp_map_t;
+```
+
+### map\_init(m)
+Initialises the map, this must be called before the map can be used.
+
+### map\_deinit(m)
+Deinitialises the map, freeing the memory the map allocated during use;
+this should be called when we're finished with a map.
+
+### map\_get(m, key)
+Returns a pointer to the value of the given `key`. If no mapping for the `key`
+exists then `NULL` will be returned.
+
+### map\_set(m, key, value)
+Sets the given `key` to the given `value`. Returns `0` on success, otherwise
+`-1` is returned and the map remains unchanged.
+
+### map\_remove(m, key)
+Removes the mapping of the given `key` from the map. If the `key` does not
+exist in the map then the function has no effect.
+
+### map\_iter(m)
+Returns a `map_iter_t` which can be used with `map_next()` to iterate all the
+keys in the map.
+
+### map\_next(m, iter)
+Uses the `map_iter_t` returned by `map_iter()` to iterate all the keys in the
+map. `map_next()` returns a key with each call and returns `NULL` when there
+are no more keys.
+```c
+const char *key;
+map_iter_t iter = map_iter(&m);
+
+while ((key = map_next(&m, &iter))) {
+ printf("%s -> %d", key, *map_get(&m, key));
+}
+```
+
+## License
+This library is free software; you can redistribute it and/or modify it under
+the terms of the MIT license. See [LICENSE](LICENSE) for details.
diff --git a/device/thirdparty/map/package.json b/device/thirdparty/map/package.json
new file mode 100644
index 0000000..7b5115b
--- /dev/null
+++ b/device/thirdparty/map/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "map",
+ "version": "0.1.0",
+ "repo": "rxi/map",
+ "description": "Type-safe generic hash map",
+ "keywords": ["hashmap", "map", "table", "hashtable", "dict", "dictionary"],
+ "license": "MIT",
+ "src": ["src/map.c", "src/map.h"]
+}
diff --git a/device/thirdparty/map/src/map.c b/device/thirdparty/map/src/map.c
new file mode 100644
index 0000000..308ccad
--- /dev/null
+++ b/device/thirdparty/map/src/map.c
@@ -0,0 +1,193 @@
+/**
+ * Copyright (c) 2014 rxi
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include
+#include
+#include "map.h"
+
+struct map_node_t {
+ unsigned hash;
+ void *value;
+ map_node_t *next;
+ /* char key[]; */
+ /* char value[]; */
+};
+
+
+static unsigned map_hash(const char *str) {
+ unsigned hash = 5381;
+ while (*str) {
+ hash = ((hash << 5) + hash) ^ *str++;
+ }
+ return hash;
+}
+
+
+static map_node_t *map_newnode(const char *key, void *value, int vsize) {
+ map_node_t *node;
+ int ksize = strlen(key) + 1;
+ int voffset = ksize + ((sizeof(void*) - ksize) % sizeof(void*));
+ node = malloc(sizeof(*node) + voffset + vsize);
+ if (!node) return NULL;
+ memcpy(node + 1, key, ksize);
+ node->hash = map_hash(key);
+ node->value = ((char*) (node + 1)) + voffset;
+ memcpy(node->value, value, vsize);
+ return node;
+}
+
+
+static int map_bucketidx(map_base_t *m, unsigned hash) {
+ /* If the implementation is changed to allow a non-power-of-2 bucket count,
+ * the line below should be changed to use mod instead of AND */
+ return hash & (m->nbuckets - 1);
+}
+
+
+static void map_addnode(map_base_t *m, map_node_t *node) {
+ int n = map_bucketidx(m, node->hash);
+ node->next = m->buckets[n];
+ m->buckets[n] = node;
+}
+
+
+static int map_resize(map_base_t *m, int nbuckets) {
+ map_node_t *nodes, *node, *next;
+ map_node_t **buckets;
+ int i;
+ /* Chain all nodes together */
+ nodes = NULL;
+ i = m->nbuckets;
+ while (i--) {
+ node = (m->buckets)[i];
+ while (node) {
+ next = node->next;
+ node->next = nodes;
+ nodes = node;
+ node = next;
+ }
+ }
+ /* Reset buckets */
+ buckets = realloc(m->buckets, sizeof(*m->buckets) * nbuckets);
+ if (buckets != NULL) {
+ m->buckets = buckets;
+ m->nbuckets = nbuckets;
+ }
+ if (m->buckets) {
+ memset(m->buckets, 0, sizeof(*m->buckets) * m->nbuckets);
+ /* Re-add nodes to buckets */
+ node = nodes;
+ while (node) {
+ next = node->next;
+ map_addnode(m, node);
+ node = next;
+ }
+ }
+ /* Return error code if realloc() failed */
+ return (buckets == NULL) ? -1 : 0;
+}
+
+
+static map_node_t **map_getref(map_base_t *m, const char *key) {
+ unsigned hash = map_hash(key);
+ map_node_t **next;
+ if (m->nbuckets > 0) {
+ next = &m->buckets[map_bucketidx(m, hash)];
+ while (*next) {
+ if ((*next)->hash == hash && !strcmp((char*) (*next + 1), key)) {
+ return next;
+ }
+ next = &(*next)->next;
+ }
+ }
+ return NULL;
+}
+
+
+void map_deinit_(map_base_t *m) {
+ map_node_t *next, *node;
+ int i;
+ i = m->nbuckets;
+ while (i--) {
+ node = m->buckets[i];
+ while (node) {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+ }
+ free(m->buckets);
+}
+
+
+void *map_get_(map_base_t *m, const char *key) {
+ map_node_t **next = map_getref(m, key);
+ return next ? (*next)->value : NULL;
+}
+
+
+int map_set_(map_base_t *m, const char *key, void *value, int vsize) {
+ int n, err;
+ map_node_t **next, *node;
+ /* Find & replace existing node */
+ next = map_getref(m, key);
+ if (next) {
+ memcpy((*next)->value, value, vsize);
+ return 0;
+ }
+ /* Add new node */
+ node = map_newnode(key, value, vsize);
+ if (node == NULL) goto fail;
+ if (m->nnodes >= m->nbuckets) {
+ n = (m->nbuckets > 0) ? (m->nbuckets << 1) : 1;
+ err = map_resize(m, n);
+ if (err) goto fail;
+ }
+ map_addnode(m, node);
+ m->nnodes++;
+ return 0;
+ fail:
+ if (node) free(node);
+ return -1;
+}
+
+
+void map_remove_(map_base_t *m, const char *key) {
+ map_node_t *node;
+ map_node_t **next = map_getref(m, key);
+ if (next) {
+ node = *next;
+ *next = (*next)->next;
+ free(node);
+ m->nnodes--;
+ }
+}
+
+
+map_iter_t map_iter_(void) {
+ map_iter_t iter;
+ iter.bucketidx = -1;
+ iter.node = NULL;
+ return iter;
+}
+
+
+const char *map_next_(map_base_t *m, map_iter_t *iter) {
+ if (iter->node) {
+ iter->node = iter->node->next;
+ if (iter->node == NULL) goto nextBucket;
+ } else {
+ nextBucket:
+ do {
+ if (++iter->bucketidx >= m->nbuckets) {
+ return NULL;
+ }
+ iter->node = m->buckets[iter->bucketidx];
+ } while (iter->node == NULL);
+ }
+ return (char*) (iter->node + 1);
+}
diff --git a/device/thirdparty/map/src/map.h b/device/thirdparty/map/src/map.h
new file mode 100644
index 0000000..71af710
--- /dev/null
+++ b/device/thirdparty/map/src/map.h
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2014 rxi
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifndef MAP_H
+#define MAP_H
+
+#include
+
+#define MAP_VERSION "0.1.0"
+
+struct map_node_t;
+typedef struct map_node_t map_node_t;
+
+typedef struct {
+ map_node_t **buckets;
+ unsigned nbuckets, nnodes;
+} map_base_t;
+
+typedef struct {
+ unsigned bucketidx;
+ map_node_t *node;
+} map_iter_t;
+
+
+#define map_t(T)\
+ struct { map_base_t base; T *ref; T tmp; }
+
+
+#define map_init(m)\
+ memset(m, 0, sizeof(*(m)))
+
+
+#define map_deinit(m)\
+ map_deinit_(&(m)->base)
+
+
+#define map_get(m, key)\
+ ( (m)->ref = map_get_(&(m)->base, key) )
+
+
+#define map_set(m, key, value)\
+ ( (m)->tmp = (value),\
+ map_set_(&(m)->base, key, &(m)->tmp, sizeof((m)->tmp)) )
+
+
+#define map_remove(m, key)\
+ map_remove_(&(m)->base, key)
+
+
+#define map_iter(m)\
+ map_iter_()
+
+
+#define map_next(m, iter)\
+ map_next_(&(m)->base, iter)
+
+
+void map_deinit_(map_base_t *m);
+void *map_get_(map_base_t *m, const char *key);
+int map_set_(map_base_t *m, const char *key, void *value, int vsize);
+void map_remove_(map_base_t *m, const char *key);
+map_iter_t map_iter_(void);
+const char *map_next_(map_base_t *m, map_iter_t *iter);
+
+
+typedef map_t(void*) map_void_t;
+typedef map_t(char*) map_str_t;
+typedef map_t(int) map_int_t;
+typedef map_t(char) map_char_t;
+typedef map_t(float) map_float_t;
+typedef map_t(double) map_double_t;
+
+#endif