├── BarbieGirl.alaw ├── BarbieGirl.h264 ├── LICENSE ├── Makefile ├── Makefile.shared ├── README.md ├── build_lib.sh ├── comm.h ├── demo.cfg ├── demo.vs ├── ReadMe.txt ├── demo.vs.sln ├── demo.vs.vcxproj ├── demo.vs.vcxproj.filters └── demo.vs.vcxproj.user ├── queue.h ├── rtp_enc.c ├── rtp_enc.h ├── rtsp.log ├── rtsp_demo.c ├── rtsp_demo.h ├── rtsp_msg.c ├── rtsp_msg.h ├── stream_queue.c ├── stream_queue.h ├── test.c ├── utils.c └── utils.h /BarbieGirl.alaw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bxinquan/rtsp_demo/73a1ea3875386c9849e6f6f295dd44c4565c8aa3/BarbieGirl.alaw -------------------------------------------------------------------------------- /BarbieGirl.h264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bxinquan/rtsp_demo/73a1ea3875386c9849e6f6f295dd44c4565c8aa3/BarbieGirl.h264 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 bxinquan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | OBJS = test.o rtsp_demo.o rtsp_msg.o rtp_enc.o stream_queue.o utils.o 4 | TAR = demo 5 | 6 | CC ?= gcc 7 | CFLAGS += -g -Wall -D__LINUX__ 8 | 9 | all: $(TAR) 10 | 11 | $(TAR) : $(OBJS) 12 | $(CC) $(CFLAGS) -o $@ $^ -lrt 13 | 14 | %.o : %.c 15 | $(CC) $(CFLAGS) -c $^ 16 | 17 | clean: 18 | rm -f $(OBJS) $(TAR) 19 | -------------------------------------------------------------------------------- /Makefile.shared: -------------------------------------------------------------------------------- 1 | 2 | 3 | OBJS = rtsp_demo.o rtsp_msg.o rtp_enc.o stream_queue.o utils.o 4 | TAR = librtsp_demo.so 5 | 6 | CC ?= gcc 7 | CFLAGS += -g -Wall -D__LINUX__ -fPIC 8 | 9 | all: $(TAR) 10 | 11 | $(TAR) : $(OBJS) 12 | $(CC) $(CFLAGS) -shared -o $@ $^ 13 | 14 | %.o : %.c 15 | $(CC) $(CFLAGS) -c $^ 16 | 17 | clean: 18 | rm -f $(OBJS) $(TAR) 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 本Demo基于标准C库编写实现嵌入式RTSP服务器,主要用于网络摄像头/网络录像机提供RTSP直播预览服务 2 | 版本:rtsp_demo_20170329 3 | 学习RTSP时写的一个简易的RTSP服务器源码 4 | 支持H264/H265/aac/g726/G711A流 5 | 支持多通道 6 | 不依赖三方库 7 | 支持windows及linux,vs2010/gcc编译 8 | -------------------------------------------------------------------------------- /build_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PLAT=$1 4 | if [ "$PLAT" == "" ]; then 5 | echo "$0 x86|android_arm|dm6446|dm365|hi3515|hi3518|hi3516|hi3535|hi3516a|hi3518ev20x" 6 | exit 7 | fi 8 | 9 | CROSS_COMPILE= 10 | CFLAGS= 11 | 12 | case $PLAT in 13 | x86) 14 | CROSS_COMPILE= 15 | CFLAGS= 16 | ;; 17 | android_arm) 18 | CROSS_COMPILE="arm-linux-androideabi-" 19 | CFLAGS="--sysroot=/opt/android-ndk-r10/platforms/android-19/arch-arm -march=armv7-a" 20 | ;; 21 | dm6446) 22 | CROSS_COMPILE="arm_v5t_le-" 23 | CFLAGS= 24 | ;; 25 | dm365) 26 | CROSS_COMPILE="arm-none-linux-gnueabi-" 27 | CFLAGS= 28 | ;; 29 | hi3515) 30 | CROSS_COMPILE="arm-hisi-linux-" 31 | CFLAGS= 32 | ;; 33 | hi3518) 34 | CROSS_COMPILE="arm-hisiv100nptl-linux-" 35 | CFLAGS= 36 | ;; 37 | hi3516) 38 | CROSS_COMPILE="arm-hisiv100-linux-" 39 | CFLAGS= 40 | ;; 41 | hi3535) 42 | CROSS_COMPILE="arm-hisiv100nptl-linux-" 43 | CFLAGS="-march=armv7-a -mcpu=cortex-a9" 44 | ;; 45 | hi3516a) 46 | CROSS_COMPILE="arm-hisiv300-linux-" 47 | CFLAGS="-mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations" 48 | ;; 49 | hi3518ev20x) 50 | CROSS_COMPILE="arm-hisiv300-linux-" 51 | CFLAGS="-march=armv5te -mcpu=arm926ej-s -mno-unaligned-access -fno-aggressive-loop-optimizations" 52 | ;; 53 | esac 54 | 55 | PREFIX=$(pwd)/install/${PLAT} 56 | CC=${CROSS_COMPILE}gcc 57 | export CC CFLAGS 58 | 59 | make -f Makefile.shared clean 60 | make -f Makefile.shared 61 | 62 | mkdir -p ${PREFIX}/include 63 | mkdir -p ${PREFIX}/lib 64 | 65 | cp rtsp_demo.h ${PREFIX}/include/ 66 | cp librtsp_demo.so ${PREFIX}/lib/ 67 | 68 | rm librtsp_demo.so 69 | 70 | -------------------------------------------------------------------------------- /comm.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: comm.h 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Sunday, December 20, 2015 AM07:37:50 CST 6 | ************************************************************************/ 7 | 8 | #ifndef __COMM_H__ 9 | #define __COMM_H__ 10 | 11 | #include 12 | 13 | #define dbg(fmt, ...) do {printf("[DEBUG %s:%d:%s] " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);} while(0) 14 | #define info(fmt, ...) do {printf("[INFO %s:%d:%s] " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);} while(0) 15 | #define warn(fmt, ...) do {printf("[WARN %s:%d:%s] " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);} while(0) 16 | #define err(fmt, ...) do {printf("[ERROR %s:%d:%s] " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);} while(0) 17 | 18 | #ifdef __WIN32__ 19 | #define FD_SETSIZE 1024 20 | #define snprintf _snprintf 21 | #include 22 | #endif 23 | 24 | #ifdef __LINUX__ 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #endif 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /demo.cfg: -------------------------------------------------------------------------------- 1 | path=/live/chn0 video=BarbieGirl.h264 audio=BarbieGirl.alaw 2 | path=/live/chn1 video=BarbieGirl.h264 3 | path=/live/chn2 audio=BarbieGirl.alaw 4 | -------------------------------------------------------------------------------- /demo.vs/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : demo.vs Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this demo.vs application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your demo.vs application. 9 | 10 | 11 | demo.vs.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | demo.vs.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | demo.vs.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named demo.vs.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /demo.vs/demo.vs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo.vs", "demo.vs.vcxproj", "{6C9FFE71-5C82-439E-B704-A9DD10BEBFE6}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {6C9FFE71-5C82-439E-B704-A9DD10BEBFE6}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {6C9FFE71-5C82-439E-B704-A9DD10BEBFE6}.Debug|Win32.Build.0 = Debug|Win32 14 | {6C9FFE71-5C82-439E-B704-A9DD10BEBFE6}.Release|Win32.ActiveCfg = Release|Win32 15 | {6C9FFE71-5C82-439E-B704-A9DD10BEBFE6}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /demo.vs/demo.vs.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {6C9FFE71-5C82-439E-B704-A9DD10BEBFE6} 15 | Win32Proj 16 | demovs 17 | 18 | 19 | 20 | Application 21 | true 22 | Unicode 23 | 24 | 25 | Application 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | true 42 | demo 43 | false 44 | 45 | 46 | false 47 | demo 48 | false 49 | 50 | 51 | 52 | 53 | 54 | Level3 55 | Disabled 56 | WIN32;_DEBUG;_CONSOLE;__WIN32__;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 57 | 58 | 59 | Console 60 | true 61 | ws2_32.lib;winmm.lib;%(AdditionalDependencies) 62 | 63 | 64 | 65 | 66 | Level3 67 | 68 | 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;_CONSOLE;__WIN32__;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 73 | 74 | 75 | Console 76 | true 77 | true 78 | true 79 | ws2_32.lib;winmm.lib;%(AdditionalDependencies) 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /demo.vs/demo.vs.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | -------------------------------------------------------------------------------- /demo.vs/demo.vs.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1991, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 30 | */ 31 | 32 | #ifndef _SYS_QUEUE_H_ 33 | #define _SYS_QUEUE_H_ 34 | 35 | /* 36 | * This file defines five types of data structures: singly-linked lists, 37 | * lists, simple queues, tail queues, and circular queues. 38 | * 39 | * A singly-linked list is headed by a single forward pointer. The 40 | * elements are singly linked for minimum space and pointer manipulation 41 | * overhead at the expense of O(n) removal for arbitrary elements. New 42 | * elements can be added to the list after an existing element or at the 43 | * head of the list. Elements being removed from the head of the list 44 | * should use the explicit macro for this purpose for optimum 45 | * efficiency. A singly-linked list may only be traversed in the forward 46 | * direction. Singly-linked lists are ideal for applications with large 47 | * datasets and few or no removals or for implementing a LIFO queue. 48 | * 49 | * A list is headed by a single forward pointer (or an array of forward 50 | * pointers for a hash table header). The elements are doubly linked 51 | * so that an arbitrary element can be removed without a need to 52 | * traverse the list. New elements can be added to the list before 53 | * or after an existing element or at the head of the list. A list 54 | * may only be traversed in the forward direction. 55 | * 56 | * A simple queue is headed by a pair of pointers, one the head of the 57 | * list and the other to the tail of the list. The elements are singly 58 | * linked to save space, so elements can only be removed from the 59 | * head of the list. New elements can be added to the list after 60 | * an existing element, at the head of the list, or at the end of the 61 | * list. A simple queue may only be traversed in the forward direction. 62 | * 63 | * A tail queue is headed by a pair of pointers, one to the head of the 64 | * list and the other to the tail of the list. The elements are doubly 65 | * linked so that an arbitrary element can be removed without a need to 66 | * traverse the list. New elements can be added to the list before or 67 | * after an existing element, at the head of the list, or at the end of 68 | * the list. A tail queue may be traversed in either direction. 69 | * 70 | * A circle queue is headed by a pair of pointers, one to the head of the 71 | * list and the other to the tail of the list. The elements are doubly 72 | * linked so that an arbitrary element can be removed without a need to 73 | * traverse the list. New elements can be added to the list before or after 74 | * an existing element, at the head of the list, or at the end of the list. 75 | * A circle queue may be traversed in either direction, but has a more 76 | * complex end of list detection. 77 | * 78 | * For details on the use of these macros, see the queue(3) manual page. 79 | */ 80 | 81 | /* 82 | * List definitions. 83 | */ 84 | #define LIST_HEAD(name, type) \ 85 | struct name { \ 86 | struct type *lh_first; /* first element */ \ 87 | } 88 | 89 | #define LIST_HEAD_INITIALIZER(head) \ 90 | { NULL } 91 | 92 | #define LIST_ENTRY(type) \ 93 | struct { \ 94 | struct type *le_next; /* next element */ \ 95 | struct type **le_prev; /* address of previous next element */ \ 96 | } 97 | 98 | /* 99 | * List functions. 100 | */ 101 | #define LIST_INIT(head) do { \ 102 | (head)->lh_first = NULL; \ 103 | } while (/*CONSTCOND*/0) 104 | 105 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 106 | if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ 107 | (listelm)->field.le_next->field.le_prev = \ 108 | &(elm)->field.le_next; \ 109 | (listelm)->field.le_next = (elm); \ 110 | (elm)->field.le_prev = &(listelm)->field.le_next; \ 111 | } while (/*CONSTCOND*/0) 112 | 113 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 114 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 115 | (elm)->field.le_next = (listelm); \ 116 | *(listelm)->field.le_prev = (elm); \ 117 | (listelm)->field.le_prev = &(elm)->field.le_next; \ 118 | } while (/*CONSTCOND*/0) 119 | 120 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 121 | if (((elm)->field.le_next = (head)->lh_first) != NULL) \ 122 | (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ 123 | (head)->lh_first = (elm); \ 124 | (elm)->field.le_prev = &(head)->lh_first; \ 125 | } while (/*CONSTCOND*/0) 126 | 127 | #define LIST_REMOVE(elm, field) do { \ 128 | if ((elm)->field.le_next != NULL) \ 129 | (elm)->field.le_next->field.le_prev = \ 130 | (elm)->field.le_prev; \ 131 | *(elm)->field.le_prev = (elm)->field.le_next; \ 132 | } while (/*CONSTCOND*/0) 133 | 134 | #define LIST_FOREACH(var, head, field) \ 135 | for ((var) = ((head)->lh_first); \ 136 | (var); \ 137 | (var) = ((var)->field.le_next)) 138 | 139 | /* 140 | * List access methods. 141 | */ 142 | #define LIST_EMPTY(head) ((head)->lh_first == NULL) 143 | #define LIST_FIRST(head) ((head)->lh_first) 144 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 145 | 146 | 147 | /* 148 | * Singly-linked List definitions. 149 | */ 150 | #define SLIST_HEAD(name, type) \ 151 | struct name { \ 152 | struct type *slh_first; /* first element */ \ 153 | } 154 | 155 | #define SLIST_HEAD_INITIALIZER(head) \ 156 | { NULL } 157 | 158 | #define SLIST_ENTRY(type) \ 159 | struct { \ 160 | struct type *sle_next; /* next element */ \ 161 | } 162 | 163 | /* 164 | * Singly-linked List functions. 165 | */ 166 | #define SLIST_INIT(head) do { \ 167 | (head)->slh_first = NULL; \ 168 | } while (/*CONSTCOND*/0) 169 | 170 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 171 | (elm)->field.sle_next = (slistelm)->field.sle_next; \ 172 | (slistelm)->field.sle_next = (elm); \ 173 | } while (/*CONSTCOND*/0) 174 | 175 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 176 | (elm)->field.sle_next = (head)->slh_first; \ 177 | (head)->slh_first = (elm); \ 178 | } while (/*CONSTCOND*/0) 179 | 180 | #define SLIST_REMOVE_HEAD(head, field) do { \ 181 | (head)->slh_first = (head)->slh_first->field.sle_next; \ 182 | } while (/*CONSTCOND*/0) 183 | 184 | #define SLIST_REMOVE(head, elm, type, field) do { \ 185 | if ((head)->slh_first == (elm)) { \ 186 | SLIST_REMOVE_HEAD((head), field); \ 187 | } \ 188 | else { \ 189 | struct type *curelm = (head)->slh_first; \ 190 | while(curelm->field.sle_next != (elm)) \ 191 | curelm = curelm->field.sle_next; \ 192 | curelm->field.sle_next = \ 193 | curelm->field.sle_next->field.sle_next; \ 194 | } \ 195 | } while (/*CONSTCOND*/0) 196 | 197 | #define SLIST_FOREACH(var, head, field) \ 198 | for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) 199 | 200 | /* 201 | * Singly-linked List access methods. 202 | */ 203 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 204 | #define SLIST_FIRST(head) ((head)->slh_first) 205 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 206 | 207 | 208 | /* 209 | * Singly-linked Tail queue declarations. 210 | */ 211 | #define STAILQ_HEAD(name, type) \ 212 | struct name { \ 213 | struct type *stqh_first; /* first element */ \ 214 | struct type **stqh_last; /* addr of last next element */ \ 215 | } 216 | 217 | #define STAILQ_HEAD_INITIALIZER(head) \ 218 | { NULL, &(head).stqh_first } 219 | 220 | #define STAILQ_ENTRY(type) \ 221 | struct { \ 222 | struct type *stqe_next; /* next element */ \ 223 | } 224 | 225 | /* 226 | * Singly-linked Tail queue functions. 227 | */ 228 | #define STAILQ_INIT(head) do { \ 229 | (head)->stqh_first = NULL; \ 230 | (head)->stqh_last = &(head)->stqh_first; \ 231 | } while (/*CONSTCOND*/0) 232 | 233 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 234 | if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ 235 | (head)->stqh_last = &(elm)->field.stqe_next; \ 236 | (head)->stqh_first = (elm); \ 237 | } while (/*CONSTCOND*/0) 238 | 239 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 240 | (elm)->field.stqe_next = NULL; \ 241 | *(head)->stqh_last = (elm); \ 242 | (head)->stqh_last = &(elm)->field.stqe_next; \ 243 | } while (/*CONSTCOND*/0) 244 | 245 | #define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 246 | if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ 247 | (head)->stqh_last = &(elm)->field.stqe_next; \ 248 | (listelm)->field.stqe_next = (elm); \ 249 | } while (/*CONSTCOND*/0) 250 | 251 | #define STAILQ_REMOVE_HEAD(head, field) do { \ 252 | if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ 253 | (head)->stqh_last = &(head)->stqh_first; \ 254 | } while (/*CONSTCOND*/0) 255 | 256 | #define STAILQ_REMOVE(head, elm, type, field) do { \ 257 | if ((head)->stqh_first == (elm)) { \ 258 | STAILQ_REMOVE_HEAD((head), field); \ 259 | } else { \ 260 | struct type *curelm = (head)->stqh_first; \ 261 | while (curelm->field.stqe_next != (elm)) \ 262 | curelm = curelm->field.stqe_next; \ 263 | if ((curelm->field.stqe_next = \ 264 | curelm->field.stqe_next->field.stqe_next) == NULL) \ 265 | (head)->stqh_last = &(curelm)->field.stqe_next; \ 266 | } \ 267 | } while (/*CONSTCOND*/0) 268 | 269 | #define STAILQ_FOREACH(var, head, field) \ 270 | for ((var) = ((head)->stqh_first); \ 271 | (var); \ 272 | (var) = ((var)->field.stqe_next)) 273 | 274 | #define STAILQ_CONCAT(head1, head2) do { \ 275 | if (!STAILQ_EMPTY((head2))) { \ 276 | *(head1)->stqh_last = (head2)->stqh_first; \ 277 | (head1)->stqh_last = (head2)->stqh_last; \ 278 | STAILQ_INIT((head2)); \ 279 | } \ 280 | } while (/*CONSTCOND*/0) 281 | 282 | /* 283 | * Singly-linked Tail queue access methods. 284 | */ 285 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 286 | #define STAILQ_FIRST(head) ((head)->stqh_first) 287 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 288 | 289 | 290 | /* 291 | * Simple queue definitions. 292 | */ 293 | #define SIMPLEQ_HEAD(name, type) \ 294 | struct name { \ 295 | struct type *sqh_first; /* first element */ \ 296 | struct type **sqh_last; /* addr of last next element */ \ 297 | } 298 | 299 | #define SIMPLEQ_HEAD_INITIALIZER(head) \ 300 | { NULL, &(head).sqh_first } 301 | 302 | #define SIMPLEQ_ENTRY(type) \ 303 | struct { \ 304 | struct type *sqe_next; /* next element */ \ 305 | } 306 | 307 | /* 308 | * Simple queue functions. 309 | */ 310 | #define SIMPLEQ_INIT(head) do { \ 311 | (head)->sqh_first = NULL; \ 312 | (head)->sqh_last = &(head)->sqh_first; \ 313 | } while (/*CONSTCOND*/0) 314 | 315 | #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ 316 | if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ 317 | (head)->sqh_last = &(elm)->field.sqe_next; \ 318 | (head)->sqh_first = (elm); \ 319 | } while (/*CONSTCOND*/0) 320 | 321 | #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ 322 | (elm)->field.sqe_next = NULL; \ 323 | *(head)->sqh_last = (elm); \ 324 | (head)->sqh_last = &(elm)->field.sqe_next; \ 325 | } while (/*CONSTCOND*/0) 326 | 327 | #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 328 | if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ 329 | (head)->sqh_last = &(elm)->field.sqe_next; \ 330 | (listelm)->field.sqe_next = (elm); \ 331 | } while (/*CONSTCOND*/0) 332 | 333 | #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ 334 | if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ 335 | (head)->sqh_last = &(head)->sqh_first; \ 336 | } while (/*CONSTCOND*/0) 337 | 338 | #define SIMPLEQ_REMOVE(head, elm, type, field) do { \ 339 | if ((head)->sqh_first == (elm)) { \ 340 | SIMPLEQ_REMOVE_HEAD((head), field); \ 341 | } else { \ 342 | struct type *curelm = (head)->sqh_first; \ 343 | while (curelm->field.sqe_next != (elm)) \ 344 | curelm = curelm->field.sqe_next; \ 345 | if ((curelm->field.sqe_next = \ 346 | curelm->field.sqe_next->field.sqe_next) == NULL) \ 347 | (head)->sqh_last = &(curelm)->field.sqe_next; \ 348 | } \ 349 | } while (/*CONSTCOND*/0) 350 | 351 | #define SIMPLEQ_FOREACH(var, head, field) \ 352 | for ((var) = ((head)->sqh_first); \ 353 | (var); \ 354 | (var) = ((var)->field.sqe_next)) 355 | 356 | /* 357 | * Simple queue access methods. 358 | */ 359 | #define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) 360 | #define SIMPLEQ_FIRST(head) ((head)->sqh_first) 361 | #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) 362 | 363 | 364 | /* 365 | * Tail queue definitions. 366 | */ 367 | #define _TAILQ_HEAD(name, type, qual) \ 368 | struct name { \ 369 | qual type *tqh_first; /* first element */ \ 370 | qual type *qual *tqh_last; /* addr of last next element */ \ 371 | } 372 | #define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) 373 | 374 | #define TAILQ_HEAD_INITIALIZER(head) \ 375 | { NULL, &(head).tqh_first } 376 | 377 | #define _TAILQ_ENTRY(type, qual) \ 378 | struct { \ 379 | qual type *tqe_next; /* next element */ \ 380 | qual type *qual *tqe_prev; /* address of previous next element */\ 381 | } 382 | #define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) 383 | 384 | /* 385 | * Tail queue functions. 386 | */ 387 | #define TAILQ_INIT(head) do { \ 388 | (head)->tqh_first = NULL; \ 389 | (head)->tqh_last = &(head)->tqh_first; \ 390 | } while (/*CONSTCOND*/0) 391 | 392 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 393 | if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ 394 | (head)->tqh_first->field.tqe_prev = \ 395 | &(elm)->field.tqe_next; \ 396 | else \ 397 | (head)->tqh_last = &(elm)->field.tqe_next; \ 398 | (head)->tqh_first = (elm); \ 399 | (elm)->field.tqe_prev = &(head)->tqh_first; \ 400 | } while (/*CONSTCOND*/0) 401 | 402 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 403 | (elm)->field.tqe_next = NULL; \ 404 | (elm)->field.tqe_prev = (head)->tqh_last; \ 405 | *(head)->tqh_last = (elm); \ 406 | (head)->tqh_last = &(elm)->field.tqe_next; \ 407 | } while (/*CONSTCOND*/0) 408 | 409 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 410 | if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ 411 | (elm)->field.tqe_next->field.tqe_prev = \ 412 | &(elm)->field.tqe_next; \ 413 | else \ 414 | (head)->tqh_last = &(elm)->field.tqe_next; \ 415 | (listelm)->field.tqe_next = (elm); \ 416 | (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ 417 | } while (/*CONSTCOND*/0) 418 | 419 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 420 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 421 | (elm)->field.tqe_next = (listelm); \ 422 | *(listelm)->field.tqe_prev = (elm); \ 423 | (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ 424 | } while (/*CONSTCOND*/0) 425 | 426 | #define TAILQ_REMOVE(head, elm, field) do { \ 427 | if (((elm)->field.tqe_next) != NULL) \ 428 | (elm)->field.tqe_next->field.tqe_prev = \ 429 | (elm)->field.tqe_prev; \ 430 | else \ 431 | (head)->tqh_last = (elm)->field.tqe_prev; \ 432 | *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ 433 | } while (/*CONSTCOND*/0) 434 | 435 | #define TAILQ_FOREACH(var, head, field) \ 436 | for ((var) = ((head)->tqh_first); \ 437 | (var); \ 438 | (var) = ((var)->field.tqe_next)) 439 | 440 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 441 | for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ 442 | (var); \ 443 | (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) 444 | 445 | #define TAILQ_CONCAT(head1, head2, field) do { \ 446 | if (!TAILQ_EMPTY(head2)) { \ 447 | *(head1)->tqh_last = (head2)->tqh_first; \ 448 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 449 | (head1)->tqh_last = (head2)->tqh_last; \ 450 | TAILQ_INIT((head2)); \ 451 | } \ 452 | } while (/*CONSTCOND*/0) 453 | 454 | /* 455 | * Tail queue access methods. 456 | */ 457 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 458 | #define TAILQ_FIRST(head) ((head)->tqh_first) 459 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 460 | 461 | #define TAILQ_LAST(head, headname) \ 462 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 463 | #define TAILQ_PREV(elm, headname, field) \ 464 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 465 | 466 | 467 | /* 468 | * Circular queue definitions. 469 | */ 470 | #define CIRCLEQ_HEAD(name, type) \ 471 | struct name { \ 472 | struct type *cqh_first; /* first element */ \ 473 | struct type *cqh_last; /* last element */ \ 474 | } 475 | 476 | #define CIRCLEQ_HEAD_INITIALIZER(head) \ 477 | { (void *)&head, (void *)&head } 478 | 479 | #define CIRCLEQ_ENTRY(type) \ 480 | struct { \ 481 | struct type *cqe_next; /* next element */ \ 482 | struct type *cqe_prev; /* previous element */ \ 483 | } 484 | 485 | /* 486 | * Circular queue functions. 487 | */ 488 | #define CIRCLEQ_INIT(head) do { \ 489 | (head)->cqh_first = (void *)(head); \ 490 | (head)->cqh_last = (void *)(head); \ 491 | } while (/*CONSTCOND*/0) 492 | 493 | #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 494 | (elm)->field.cqe_next = (listelm)->field.cqe_next; \ 495 | (elm)->field.cqe_prev = (listelm); \ 496 | if ((listelm)->field.cqe_next == (void *)(head)) \ 497 | (head)->cqh_last = (elm); \ 498 | else \ 499 | (listelm)->field.cqe_next->field.cqe_prev = (elm); \ 500 | (listelm)->field.cqe_next = (elm); \ 501 | } while (/*CONSTCOND*/0) 502 | 503 | #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ 504 | (elm)->field.cqe_next = (listelm); \ 505 | (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ 506 | if ((listelm)->field.cqe_prev == (void *)(head)) \ 507 | (head)->cqh_first = (elm); \ 508 | else \ 509 | (listelm)->field.cqe_prev->field.cqe_next = (elm); \ 510 | (listelm)->field.cqe_prev = (elm); \ 511 | } while (/*CONSTCOND*/0) 512 | 513 | #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ 514 | (elm)->field.cqe_next = (head)->cqh_first; \ 515 | (elm)->field.cqe_prev = (void *)(head); \ 516 | if ((head)->cqh_last == (void *)(head)) \ 517 | (head)->cqh_last = (elm); \ 518 | else \ 519 | (head)->cqh_first->field.cqe_prev = (elm); \ 520 | (head)->cqh_first = (elm); \ 521 | } while (/*CONSTCOND*/0) 522 | 523 | #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ 524 | (elm)->field.cqe_next = (void *)(head); \ 525 | (elm)->field.cqe_prev = (head)->cqh_last; \ 526 | if ((head)->cqh_first == (void *)(head)) \ 527 | (head)->cqh_first = (elm); \ 528 | else \ 529 | (head)->cqh_last->field.cqe_next = (elm); \ 530 | (head)->cqh_last = (elm); \ 531 | } while (/*CONSTCOND*/0) 532 | 533 | #define CIRCLEQ_REMOVE(head, elm, field) do { \ 534 | if ((elm)->field.cqe_next == (void *)(head)) \ 535 | (head)->cqh_last = (elm)->field.cqe_prev; \ 536 | else \ 537 | (elm)->field.cqe_next->field.cqe_prev = \ 538 | (elm)->field.cqe_prev; \ 539 | if ((elm)->field.cqe_prev == (void *)(head)) \ 540 | (head)->cqh_first = (elm)->field.cqe_next; \ 541 | else \ 542 | (elm)->field.cqe_prev->field.cqe_next = \ 543 | (elm)->field.cqe_next; \ 544 | } while (/*CONSTCOND*/0) 545 | 546 | #define CIRCLEQ_FOREACH(var, head, field) \ 547 | for ((var) = ((head)->cqh_first); \ 548 | (var) != (const void *)(head); \ 549 | (var) = ((var)->field.cqe_next)) 550 | 551 | #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ 552 | for ((var) = ((head)->cqh_last); \ 553 | (var) != (const void *)(head); \ 554 | (var) = ((var)->field.cqe_prev)) 555 | 556 | /* 557 | * Circular queue access methods. 558 | */ 559 | #define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) 560 | #define CIRCLEQ_FIRST(head) ((head)->cqh_first) 561 | #define CIRCLEQ_LAST(head) ((head)->cqh_last) 562 | #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) 563 | #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) 564 | 565 | #define CIRCLEQ_LOOP_NEXT(head, elm, field) \ 566 | (((elm)->field.cqe_next == (void *)(head)) \ 567 | ? ((head)->cqh_first) \ 568 | : (elm->field.cqe_next)) 569 | #define CIRCLEQ_LOOP_PREV(head, elm, field) \ 570 | (((elm)->field.cqe_prev == (void *)(head)) \ 571 | ? ((head)->cqh_last) \ 572 | : (elm->field.cqe_prev)) 573 | 574 | #endif /* sys/queue.h */ 575 | -------------------------------------------------------------------------------- /rtp_enc.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: rtp_enc.c 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Saturday, December 19, 2015 PM09:16:04 CST 6 | ************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "comm.h" 13 | #include "rtp_enc.h" 14 | 15 | struct rtphdr 16 | { 17 | #ifdef __BIG_ENDIAN__ 18 | uint16_t v:2; 19 | uint16_t p:1; 20 | uint16_t x:1; 21 | uint16_t cc:4; 22 | uint16_t m:1; 23 | uint16_t pt:7; 24 | #else 25 | uint16_t cc:4; 26 | uint16_t x:1; 27 | uint16_t p:1; 28 | uint16_t v:2; 29 | uint16_t pt:7; 30 | uint16_t m:1; 31 | #endif 32 | uint16_t seq; 33 | uint32_t ts; 34 | uint32_t ssrc; 35 | }; 36 | 37 | #define RTPHDR_SIZE (12) 38 | 39 | int rtp_enc_h264 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]) 40 | { 41 | int count = 0; 42 | uint8_t nalhdr; 43 | uint32_t rtp_ts; 44 | 45 | if (!e || !frame || len <= 0 || !packets || !pktsizs) 46 | return -1; 47 | 48 | //drop 0001 49 | if (frame[0] == 0 && frame[1] == 0 && frame[2] == 1) { 50 | frame += 3; 51 | len -= 3; 52 | } 53 | if (frame[0] == 0 && frame[1] == 0 && frame[2] == 0 && frame[3] == 1) { 54 | frame += 4; 55 | len -= 4; 56 | } 57 | 58 | nalhdr = frame[0]; 59 | rtp_ts = (uint32_t)(ts * e->sample_rate / 1000000); 60 | 61 | while (len > 0 && packets[count] && pktsizs[count] > RTPHDR_SIZE) { 62 | struct rtphdr *hdr = (struct rtphdr*)packets[count]; 63 | int pktsiz = pktsizs[count]; 64 | hdr->v = 2; 65 | hdr->p = 0; 66 | hdr->x = 0; 67 | hdr->cc = 0; 68 | hdr->m = 0; 69 | hdr->pt = e->pt; 70 | hdr->seq = htons(e->seq++); 71 | hdr->ts = htonl(rtp_ts); 72 | hdr->ssrc = htonl(e->ssrc); 73 | 74 | if (count == 0 && len <= pktsiz - RTPHDR_SIZE) { 75 | hdr->m = 1; 76 | memcpy(packets[count] + RTPHDR_SIZE, frame, len); 77 | pktsizs[count] = RTPHDR_SIZE + len; 78 | frame += len; 79 | len -= len; 80 | } else { 81 | int mark = 0; 82 | if (count == 0) { 83 | frame ++; //drop nalu header 84 | len --; 85 | } else if (len <= pktsiz - RTPHDR_SIZE - 2) { 86 | mark = 1; 87 | } 88 | hdr->m = mark; 89 | 90 | packets[count][RTPHDR_SIZE + 0] = (nalhdr & 0xe0) | 28;//FU-A 91 | packets[count][RTPHDR_SIZE + 1] = (nalhdr & 0x1f);//FU-A 92 | if (count == 0) { 93 | packets[count][RTPHDR_SIZE + 1] |= 0x80; //S 94 | } 95 | 96 | if (mark) { 97 | packets[count][RTPHDR_SIZE + 1] |= 0x40; //E 98 | memcpy(packets[count] + RTPHDR_SIZE + 2, frame, len); 99 | pktsizs[count] = RTPHDR_SIZE + 2 + len; 100 | frame += len; 101 | len -= len; 102 | } else { 103 | memcpy(packets[count] + RTPHDR_SIZE + 2, frame, pktsiz - RTPHDR_SIZE - 2); 104 | pktsizs[count] = pktsiz; 105 | frame += pktsiz - RTPHDR_SIZE - 2; 106 | len -= pktsiz - RTPHDR_SIZE - 2; 107 | } 108 | } 109 | count ++; 110 | } 111 | return count; 112 | } 113 | 114 | int rtp_enc_h265 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]) 115 | { 116 | int count = 0; 117 | uint8_t nalhdr[2]; 118 | uint32_t rtp_ts; 119 | 120 | if (!e || !frame || len <= 0 || !packets || !pktsizs) 121 | return -1; 122 | 123 | //drop 0001 124 | if (frame[0] == 0 && frame[1] == 0 && frame[2] == 1) { 125 | frame += 3; 126 | len -= 3; 127 | } 128 | if (frame[0] == 0 && frame[1] == 0 && frame[2] == 0 && frame[3] == 1) { 129 | frame += 4; 130 | len -= 4; 131 | } 132 | 133 | nalhdr[0] = frame[0]; 134 | nalhdr[1] = frame[1]; 135 | rtp_ts = (uint32_t)(ts * e->sample_rate / 1000000); 136 | 137 | while (len > 0 && packets[count] && pktsizs[count] > RTPHDR_SIZE) { 138 | struct rtphdr *hdr = (struct rtphdr*)packets[count]; 139 | int pktsiz = pktsizs[count]; 140 | hdr->v = 2; 141 | hdr->p = 0; 142 | hdr->x = 0; 143 | hdr->cc = 0; 144 | hdr->m = 0; 145 | hdr->pt = e->pt; 146 | hdr->seq = htons(e->seq++); 147 | hdr->ts = htonl(rtp_ts); 148 | hdr->ssrc = htonl(e->ssrc); 149 | 150 | if (count == 0 && len <= pktsiz - RTPHDR_SIZE) { 151 | hdr->m = 1; 152 | memcpy(packets[count] + RTPHDR_SIZE, frame, len); 153 | pktsizs[count] = RTPHDR_SIZE + len; 154 | frame += len; 155 | len -= len; 156 | } else { 157 | int mark = 0; 158 | if (count == 0) { 159 | frame += 2; //drop nalu header 160 | len -= 2; 161 | } else if (len <= pktsiz - RTPHDR_SIZE - 3) { 162 | mark = 1; 163 | } 164 | hdr->m = mark; 165 | 166 | packets[count][RTPHDR_SIZE + 0] = (nalhdr[0] & 0x81) | (49 << 1);//FU-A 167 | packets[count][RTPHDR_SIZE + 1] = (nalhdr[1]); 168 | packets[count][RTPHDR_SIZE + 2] = ((nalhdr[0] >> 1) & 0x3f);//FU-A 169 | if (count == 0) { 170 | packets[count][RTPHDR_SIZE + 2] |= 0x80; //S 171 | } 172 | 173 | if (mark) { 174 | packets[count][RTPHDR_SIZE + 2] |= 0x40; //E 175 | memcpy(packets[count] + RTPHDR_SIZE + 3, frame, len); 176 | pktsizs[count] = RTPHDR_SIZE + 3 + len; 177 | frame += len; 178 | len -= len; 179 | } else { 180 | memcpy(packets[count] + RTPHDR_SIZE + 3, frame, pktsiz - RTPHDR_SIZE - 3); 181 | pktsizs[count] = pktsiz; 182 | frame += pktsiz - RTPHDR_SIZE - 3; 183 | len -= pktsiz - RTPHDR_SIZE - 3; 184 | } 185 | } 186 | count ++; 187 | } 188 | return count; 189 | } 190 | 191 | int rtp_enc_aac (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]) 192 | { 193 | int count = 0; 194 | uint32_t rtp_ts; 195 | uint32_t au_len; 196 | 197 | if (!e || !frame || len <= 0 || !packets || !pktsizs) 198 | return -1; 199 | 200 | //drop fff 201 | if (frame[0] == 0xff && (frame[1] & 0xf0) == 0xf0) { 202 | frame += 7; 203 | len -= 7; 204 | } 205 | 206 | rtp_ts = (uint32_t)(ts * e->sample_rate / 1000000); 207 | au_len = len; 208 | 209 | while (len > 0 && packets[count] && pktsizs[count] > RTPHDR_SIZE + 4) { 210 | struct rtphdr *hdr = (struct rtphdr*)packets[count]; 211 | int pktsiz = pktsizs[count]; 212 | hdr->v = 2; 213 | hdr->p = 0; 214 | hdr->x = 0; 215 | hdr->cc = 0; 216 | hdr->m = 0; 217 | hdr->pt = e->pt; 218 | hdr->seq = htons(e->seq++); 219 | hdr->ts = htonl(rtp_ts); 220 | hdr->ssrc = htonl(e->ssrc); 221 | 222 | packets[count][RTPHDR_SIZE+0] = 0x00; 223 | packets[count][RTPHDR_SIZE+1] = 0x10; 224 | packets[count][RTPHDR_SIZE+2] = au_len >> 5; 225 | packets[count][RTPHDR_SIZE+3] = (au_len & 0x1f) << 3; 226 | 227 | if (len <= pktsiz - RTPHDR_SIZE - 4) { 228 | hdr->m = 1; 229 | memcpy(packets[count] + RTPHDR_SIZE + 4, frame, len); 230 | pktsizs[count] = RTPHDR_SIZE + 4 + len; 231 | frame += len; 232 | len -= len; 233 | } else { 234 | memcpy(packets[count] + RTPHDR_SIZE + 4, frame, pktsiz - RTPHDR_SIZE - 4); 235 | pktsizs[count] = pktsiz; 236 | frame += pktsiz - RTPHDR_SIZE - 4; 237 | len -= pktsiz - RTPHDR_SIZE - 4; 238 | } 239 | count ++; 240 | } 241 | 242 | return count; 243 | } 244 | 245 | int rtp_enc_g711 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]) 246 | { 247 | int count = 0; 248 | uint32_t rtp_ts; 249 | 250 | if (!e || !frame || len <= 0 || !packets || !pktsizs) 251 | return -1; 252 | 253 | rtp_ts = (uint32_t)(ts * e->sample_rate / 1000000); 254 | while (len > 0 && packets[count] && pktsizs[count] > RTPHDR_SIZE) { 255 | struct rtphdr *hdr = (struct rtphdr*)packets[count]; 256 | int pktsiz = pktsizs[count]; 257 | hdr->v = 2; 258 | hdr->p = 0; 259 | hdr->x = 0; 260 | hdr->cc = 0; 261 | hdr->m = (e->seq == 0); 262 | hdr->pt = e->pt; 263 | hdr->seq = htons(e->seq++); 264 | hdr->ts = htonl(rtp_ts); 265 | hdr->ssrc = htonl(e->ssrc); 266 | 267 | if (len <= pktsiz - RTPHDR_SIZE) { 268 | memcpy(packets[count] + RTPHDR_SIZE, frame, len); 269 | pktsizs[count] = RTPHDR_SIZE + len; 270 | frame += len; 271 | len -= len; 272 | } else { 273 | memcpy(packets[count] + RTPHDR_SIZE, frame, pktsiz - RTPHDR_SIZE); 274 | pktsizs[count] = pktsiz; 275 | frame += pktsiz - RTPHDR_SIZE; 276 | len -= pktsiz - RTPHDR_SIZE; 277 | } 278 | count ++; 279 | } 280 | 281 | return count; 282 | } 283 | 284 | int rtp_enc_g726 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]) 285 | { 286 | return rtp_enc_g711(e, frame, len, ts, packets, pktsizs); 287 | } 288 | -------------------------------------------------------------------------------- /rtp_enc.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: rtp_enc.h 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Saturday, December 19, 2015 PM08:27:54 CST 6 | ************************************************************************/ 7 | 8 | #ifndef __RTP_ENC_H__ 9 | #define __RTP_ENC_H__ 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef struct __rtp_enc 18 | { 19 | uint8_t pt; 20 | uint16_t seq; 21 | uint32_t ssrc; 22 | uint32_t sample_rate; 23 | } rtp_enc; 24 | 25 | int rtp_enc_h264 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]); 26 | int rtp_enc_h265 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]); 27 | int rtp_enc_aac (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]); 28 | int rtp_enc_g711 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]); 29 | int rtp_enc_g726 (rtp_enc *e, const uint8_t *frame, int len, uint64_t ts, uint8_t *packets[], int pktsizs[]); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /rtsp.log: -------------------------------------------------------------------------------- 1 | OPTIONS rtsp://192.168.6.68 RTSP/1.0 2 | CSeq: 2 3 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 4 | 5 | RTSP/1.0 200 OK 6 | CSeq: 2 7 | Public: OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER 8 | Date: Fri, Dec 25 2015 14:08:41 GMT 9 | 10 | DESCRIBE rtsp://192.168.6.68 RTSP/1.0 11 | CSeq: 3 12 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 13 | Accept: application/sdp 14 | 15 | RTSP/1.0 200 OK 16 | CSeq: 3 17 | Content-Type: application/sdp 18 | Content-Base: rtsp://192.168.6.68/ 19 | Content-Length: 679 20 | 21 | v=0 22 | o=- 1451052521156494 1451052521156494 IN IP4 192.168.6.68 23 | s=Media Presentation 24 | e=NONE 25 | b=AS:5100 26 | t=0 0 27 | a=control:rtsp://192.168.6.68/ 28 | m=video 0 RTP/AVP 96 29 | c=IN IP4 0.0.0.0 30 | b=AS:5000 31 | a=recvonly 32 | a=x-dimensions:1280,960 33 | a=control:rtsp://192.168.6.68/trackID=1 34 | a=rtpmap:96 H264/90000 35 | a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z2QAIK2EAQwgCGEAQwgCGEAQwgCEK1AoA803AQEBAg==,aO48sA== 36 | m=audio 0 RTP/AVP 0 37 | c=IN IP4 0.0.0.0 38 | b=AS:50 39 | a=recvonly 40 | a=control:rtsp://192.168.6.68/trackID=2 41 | a=rtpmap:0 PCMU/8000 42 | a=Media_header:MEDIAINFO=494D4B48010100000400010010710110401F000000FA000000000000000000000000000000000000; 43 | a=appversion:1.0 44 | SETUP rtsp://192.168.6.68/trackID=1 RTSP/1.0 45 | CSeq: 4 46 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 47 | Transport: RTP/AVP;unicast;client_port=56296-56297 48 | 49 | RTSP/1.0 200 OK 50 | CSeq: 4 51 | Session: 283812775;timeout=60 52 | Transport: RTP/AVP;unicast;client_port=56296-56297;server_port=8236-8237;ssrc=2d02fa0f;mode="play" 53 | Date: Fri, Dec 25 2015 14:08:41 GMT 54 | 55 | SETUP rtsp://192.168.6.68/trackID=2 RTSP/1.0 56 | CSeq: 5 57 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 58 | Transport: RTP/AVP;unicast;client_port=56298-56299 59 | Session: 283812775 60 | 61 | RTSP/1.0 200 OK 62 | CSeq: 5 63 | Session: 283812775;timeout=60 64 | Transport: RTP/AVP;unicast;client_port=56298-56299;server_port=8234-8235;ssrc=1266baad;mode="play" 65 | Date: Fri, Dec 25 2015 14:08:41 GMT 66 | 67 | PLAY rtsp://192.168.6.68/ RTSP/1.0 68 | CSeq: 6 69 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 70 | Session: 283812775 71 | Range: npt=0.000- 72 | 73 | RTSP/1.0 200 OK 74 | CSeq: 6 75 | Session: 283812775 76 | RTP-Info: url=rtsp://192.168.6.68/trackID=1;seq=16387;rtptime=1724325370,url=rtsp://192.168.6.68/trackID=2;seq=30619;rtptime=153273528 77 | Date: Fri, Dec 25 2015 14:08:41 GMT 78 | 79 | GET_PARAMETER rtsp://192.168.6.68/ RTSP/1.0 80 | CSeq: 7 81 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 82 | Session: 283812775 83 | 84 | RTSP/1.0 200 OK 85 | CSeq: 7 86 | Date: Fri, Dec 25 2015 14:08:41 GMT 87 | 88 | TEARDOWN rtsp://192.168.6.68/ RTSP/1.0 89 | CSeq: 8 90 | User-Agent: LibVLC/2.1.5 (LIVE555 Streaming Media v2014.05.27) 91 | Session: 283812775 92 | 93 | RTSP/1.0 200 OK 94 | CSeq: 8 95 | Session: 283812775 96 | Date: Fri, Dec 25 2015 14:08:49 GMT 97 | 98 | -------------------------------------------------------------------------------- /rtsp_demo.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: rtsp_demo.c 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Monday, November 23, 2015 AM12:34:09 CST 6 | ************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "comm.h" 15 | #include "rtsp_demo.h" 16 | #include "rtsp_msg.h" 17 | #include "rtp_enc.h" 18 | #include "queue.h" 19 | #include "stream_queue.h" 20 | #include "utils.h" 21 | 22 | 23 | #ifdef __WIN32__ 24 | #define MSG_DONTWAIT 0 25 | #define SK_EAGAIN (WSAEWOULDBLOCK) 26 | #define SK_EINTR (WSAEINTR) 27 | typedef int SOCKLEN; 28 | #endif 29 | 30 | #ifdef __LINUX__ 31 | #define SOCKET_ERROR (-1) 32 | #define INVALID_SOCKET (-1) 33 | #define SK_EAGAIN (EAGAIN) 34 | #define SK_EINTR (EINTR) 35 | #define closesocket(x) close(x) 36 | typedef int SOCKET; 37 | typedef socklen_t SOCKLEN; 38 | #endif 39 | 40 | static int sk_errno (void) 41 | { 42 | #ifdef __WIN32__ 43 | return WSAGetLastError(); 44 | #endif 45 | #ifdef __LINUX__ 46 | return (errno); 47 | #endif 48 | } 49 | 50 | static const char *sk_strerror (int err) 51 | { 52 | #ifdef __WIN32__ 53 | static char serr_code_buf[24]; 54 | sprintf(serr_code_buf, "WSAE-%d", err); 55 | return serr_code_buf; 56 | #endif 57 | #ifdef __LINUX__ 58 | return strerror(err); 59 | #endif 60 | } 61 | 62 | struct rtsp_session; 63 | struct rtsp_client_connection; 64 | TAILQ_HEAD(rtsp_session_queue_head, rtsp_session); 65 | TAILQ_HEAD(rtsp_client_connection_queue_head, rtsp_client_connection); 66 | 67 | struct rtsp_session 68 | { 69 | char path[64]; 70 | int vcodec_id; 71 | int acodec_id; 72 | 73 | int auth_type; 74 | char auth_user[16]; 75 | char auth_passwd[16]; 76 | 77 | union { 78 | struct codec_data_h264 h264; 79 | struct codec_data_h265 h265; 80 | } vcodec_data; 81 | 82 | union { 83 | struct codec_data_g726 g726; 84 | struct codec_data_aac aac; 85 | } acodec_data; 86 | 87 | rtp_enc vrtpe; 88 | rtp_enc artpe; 89 | struct stream_queue *vstreamq; 90 | struct stream_queue *astreamq; 91 | 92 | uint64_t video_ntptime_of_zero_ts; 93 | uint64_t audio_ntptime_of_zero_ts; 94 | 95 | struct rtsp_demo *demo; 96 | struct rtsp_client_connection_queue_head connections_qhead; 97 | TAILQ_ENTRY(rtsp_session) demo_entry; 98 | }; 99 | 100 | struct rtp_connection 101 | { 102 | int is_over_tcp; 103 | int tcp_interleaved[2];//if is_over_tcp=1. [0] is rtp interleaved, [1] is rtcp interleaved 104 | SOCKET udp_sockfd[2]; //if is_over_tcp=0. [0] is rtp socket, [1] is rtcp socket 105 | uint16_t udp_localport[2]; //if is_over_tcp=0. [0] is rtp local port, [1] is rtcp local port 106 | uint16_t udp_peerport[2]; //if is_over_tcp=0. [0] is rtp peer port, [1] is rtcp peer port 107 | struct in_addr peer_addr; //peer ipv4 addr 108 | int streamq_index; 109 | uint32_t ssrc; 110 | uint32_t rtcp_packet_count; 111 | uint32_t rtcp_octet_count; 112 | uint64_t rtcp_last_ts; 113 | }; 114 | 115 | #define RTP_MAX_PKTSIZ ((1500-42)/4*4) 116 | #define VRTP_MAX_NBPKTS (400) 117 | #define ARTP_MAX_NBPKTS (10) 118 | #define VRTP_PT_ID (96) 119 | #define ARTP_PT_ID (97) 120 | #define VRTSP_SUBPATH "track1" 121 | #define ARTSP_SUBPATH "track2" 122 | 123 | #define RTSP_REQBUF_MAX_SIZ (1024) 124 | //#define RTSP_RESBUF_MAX_SIZ (1024) 125 | #if (RTP_MAX_PKTSIZ+4 < RTSP_REQBUF_MAX_SIZ) 126 | #define RTSP_RESBUF_MAX_SIZ (RTSP_REQ_BUF_MAX_SIZ) 127 | #else 128 | #define RTSP_RESBUF_MAX_SIZ (RTP_MAX_PKTSIZ+4) 129 | #endif 130 | 131 | struct rtsp_client_connection 132 | { 133 | int state; //session state 134 | #define RTSP_CC_STATE_INIT 0 135 | #define RTSP_CC_STATE_READY 1 136 | #define RTSP_CC_STATE_PLAYING 2 137 | #define RTSP_CC_STATE_RECORDING 3 138 | 139 | SOCKET sockfd; //rtsp client socket 140 | struct in_addr peer_addr; //peer ipv4 addr 141 | unsigned int peer_port; //peer ipv4 port 142 | unsigned long session_id; //session id 143 | 144 | char reqbuf[RTSP_REQBUF_MAX_SIZ]; 145 | int reqlen; 146 | 147 | char resbuf[RTSP_RESBUF_MAX_SIZ]; 148 | int resoff; 149 | int reslen; 150 | 151 | struct rtp_connection *vrtp; 152 | struct rtp_connection *artp; 153 | 154 | struct rtsp_demo *demo; 155 | struct rtsp_session *session; 156 | TAILQ_ENTRY(rtsp_client_connection) demo_entry; 157 | TAILQ_ENTRY(rtsp_client_connection) session_entry; 158 | }; 159 | 160 | struct rtsp_demo 161 | { 162 | SOCKET sockfd; //rtsp server socket 0:invalid 163 | struct rtsp_session_queue_head sessions_qhead; 164 | struct rtsp_client_connection_queue_head connections_qhead; 165 | }; 166 | 167 | static struct rtsp_demo *__alloc_demo (void) 168 | { 169 | struct rtsp_demo *d = (struct rtsp_demo*) calloc(1, sizeof(struct rtsp_demo)); 170 | if (NULL == d) { 171 | err("alloc memory for rtsp_demo failed\n"); 172 | return NULL; 173 | } 174 | TAILQ_INIT(&d->sessions_qhead); 175 | TAILQ_INIT(&d->connections_qhead); 176 | return d; 177 | } 178 | 179 | static void __free_demo (struct rtsp_demo *d) 180 | { 181 | if (d) { 182 | free(d); 183 | } 184 | } 185 | 186 | static struct rtsp_session *__alloc_session (struct rtsp_demo *d) 187 | { 188 | struct rtsp_session *s = (struct rtsp_session*) calloc(1, sizeof(struct rtsp_session)); 189 | if (NULL == s) { 190 | err("alloc memory for rtsp_session failed\n"); 191 | return NULL; 192 | } 193 | 194 | s->demo = d; 195 | TAILQ_INIT(&s->connections_qhead); 196 | TAILQ_INSERT_TAIL(&d->sessions_qhead, s, demo_entry); 197 | return s; 198 | } 199 | 200 | static void __free_session (struct rtsp_session *s) 201 | { 202 | if (s) { 203 | struct rtsp_demo *d = s->demo; 204 | TAILQ_REMOVE(&d->sessions_qhead, s, demo_entry); 205 | free(s); 206 | } 207 | } 208 | 209 | static struct rtsp_client_connection *__alloc_client_connection (struct rtsp_demo *d) 210 | { 211 | struct rtsp_client_connection *cc = (struct rtsp_client_connection*) calloc(1, sizeof(struct rtsp_client_connection)); 212 | if (NULL == cc) { 213 | err("alloc memory for rtsp_session failed\n"); 214 | return NULL; 215 | } 216 | 217 | cc->demo = d; 218 | TAILQ_INSERT_TAIL(&d->connections_qhead, cc, demo_entry); 219 | return cc; 220 | } 221 | 222 | static void __free_client_connection (struct rtsp_client_connection *cc) 223 | { 224 | if (cc) { 225 | struct rtsp_demo *d = cc->demo; 226 | TAILQ_REMOVE(&d->connections_qhead, cc, demo_entry); 227 | free(cc); 228 | } 229 | } 230 | 231 | static void __client_connection_bind_session (struct rtsp_client_connection *cc, struct rtsp_session *s) 232 | { 233 | if (cc->session == NULL) { 234 | cc->session = s; 235 | TAILQ_INSERT_TAIL(&s->connections_qhead, cc, session_entry); 236 | } 237 | } 238 | 239 | static void __client_connection_unbind_session (struct rtsp_client_connection *cc) 240 | { 241 | struct rtsp_session *s = cc->session; 242 | if (s) { 243 | TAILQ_REMOVE(&s->connections_qhead, cc, session_entry); 244 | cc->session = NULL; 245 | } 246 | } 247 | 248 | rtsp_demo_handle rtsp_new_demo (int port) 249 | { 250 | struct rtsp_demo *d = NULL; 251 | struct sockaddr_in inaddr; 252 | SOCKET sockfd; 253 | int ret; 254 | 255 | #ifdef __WIN32__ 256 | WSADATA ws; 257 | WSAStartup(MAKEWORD(2,2), &ws); 258 | #endif 259 | 260 | d = __alloc_demo(); 261 | if (NULL == d) { 262 | return NULL; 263 | } 264 | 265 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 266 | if (sockfd == INVALID_SOCKET) { 267 | err("create socket failed : %s\n", sk_strerror(sk_errno())); 268 | __free_demo(d); 269 | return NULL; 270 | } 271 | 272 | if (port <= 0) 273 | port = 554; 274 | 275 | memset(&inaddr, 0, sizeof(inaddr)); 276 | inaddr.sin_family = AF_INET; 277 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); 278 | inaddr.sin_port = htons(port); 279 | ret = bind(sockfd, (struct sockaddr*)&inaddr, sizeof(inaddr)); 280 | if (ret == SOCKET_ERROR) { 281 | err("bind socket to address failed : %s\n", sk_strerror(sk_errno())); 282 | closesocket(sockfd); 283 | __free_demo(d); 284 | return NULL; 285 | } 286 | 287 | ret = listen(sockfd, 128); //XXX 288 | if (ret == SOCKET_ERROR) { 289 | err("listen socket failed : %s\n", sk_strerror(sk_errno())); 290 | closesocket(sockfd); 291 | __free_demo(d); 292 | return NULL; 293 | } 294 | 295 | d->sockfd = sockfd; 296 | 297 | info("rtsp server demo starting on port %d\n", port); 298 | return (rtsp_demo_handle)d; 299 | } 300 | 301 | #ifdef __WIN32__ 302 | #include 303 | #endif 304 | #ifdef __LINUX__ 305 | #include 306 | #include 307 | #endif 308 | 309 | static int rtsp_set_client_socket (SOCKET sockfd) 310 | { 311 | int ret; 312 | 313 | #ifdef __WIN32__ 314 | unsigned long nonblocked = 1; 315 | int sndbufsiz = 1024 * 256; 316 | int keepalive = 1; 317 | struct tcp_keepalive alive_in, alive_out; 318 | unsigned long alive_retlen; 319 | struct linger ling; 320 | 321 | ret = ioctlsocket(sockfd, FIONBIO, &nonblocked); 322 | if (ret == SOCKET_ERROR) { 323 | warn("ioctlsocket FIONBIO failed: %s\n", sk_strerror(sk_errno())); 324 | } 325 | 326 | ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*)&sndbufsiz, sizeof(sndbufsiz)); 327 | if (ret == SOCKET_ERROR) { 328 | warn("setsockopt SO_SNDBUF failed: %s\n", sk_strerror(sk_errno())); 329 | } 330 | 331 | ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keepalive, sizeof(keepalive)); 332 | if (ret == SOCKET_ERROR) { 333 | warn("setsockopt setsockopt SO_KEEPALIVE failed: %s\n", sk_strerror(sk_errno())); 334 | } 335 | 336 | alive_in.onoff = TRUE; 337 | alive_in.keepalivetime = 60000; 338 | alive_in.keepaliveinterval = 30000; 339 | ret = WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in), 340 | &alive_out, sizeof(alive_out), &alive_retlen, NULL, NULL); 341 | if (ret == SOCKET_ERROR) { 342 | warn("WSAIoctl SIO_KEEPALIVE_VALS failed: %s\n", sk_strerror(sk_errno())); 343 | } 344 | 345 | memset(&ling, 0, sizeof(ling)); 346 | ling.l_onoff = 1; 347 | ling.l_linger = 0; 348 | ret = setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&ling, sizeof(ling)); //resolve too many TCP CLOSE_WAIT 349 | if (ret == SOCKET_ERROR) { 350 | warn("setsockopt SO_LINGER failed: %s\n", sk_strerror(sk_errno())); 351 | } 352 | #endif 353 | 354 | #ifdef __LINUX__ 355 | int sndbufsiz = 1024 * 256; 356 | int keepalive = 1; 357 | int keepidle = 60; 358 | int keepinterval = 3; 359 | int keepcount = 5; 360 | struct linger ling; 361 | 362 | ret = fcntl(sockfd, F_GETFL, 0); 363 | if (ret < 0) { 364 | warn("fcntl F_GETFL failed: %s\n", strerror(errno)); 365 | } else { 366 | ret |= O_NONBLOCK; 367 | ret = fcntl(sockfd, F_SETFL, ret); 368 | if (ret < 0) { 369 | warn("fcntl F_SETFL failed: %s\n", strerror(errno)); 370 | } 371 | } 372 | 373 | ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*)&sndbufsiz, sizeof(sndbufsiz)); 374 | if (ret == SOCKET_ERROR) { 375 | warn("setsockopt SO_SNDBUF failed: %s\n", sk_strerror(sk_errno())); 376 | } 377 | 378 | ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keepalive, sizeof(keepalive)); 379 | if (ret == SOCKET_ERROR) { 380 | warn("setsockopt SO_KEEPALIVE failed: %s\n", sk_strerror(sk_errno())); 381 | } 382 | 383 | ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (const char*)&keepidle, sizeof(keepidle)); 384 | if (ret == SOCKET_ERROR) { 385 | warn("setsockopt TCP_KEEPIDLE failed: %s\n", sk_strerror(sk_errno())); 386 | } 387 | 388 | ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (const char*)&keepinterval, sizeof(keepinterval)); 389 | if (ret == SOCKET_ERROR) { 390 | warn("setsockopt TCP_KEEPINTVL failed: %s\n", sk_strerror(sk_errno())); 391 | } 392 | 393 | ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (const char*)&keepcount, sizeof(keepcount)); 394 | if (ret == SOCKET_ERROR) { 395 | warn("setsockopt TCP_KEEPCNT failed: %s\n", sk_strerror(sk_errno())); 396 | } 397 | 398 | memset(&ling, 0, sizeof(ling)); 399 | ling.l_onoff = 1; 400 | ling.l_linger = 0; 401 | ret = setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&ling, sizeof(ling)); //resolve too many TCP CLOSE_WAIT 402 | if (ret == SOCKET_ERROR) { 403 | warn("setsockopt SO_LINGER failed: %s\n", sk_strerror(sk_errno())); 404 | } 405 | #endif 406 | return 0; 407 | } 408 | 409 | static struct rtsp_client_connection *rtsp_new_client_connection (struct rtsp_demo *d) 410 | { 411 | struct rtsp_client_connection *cc = NULL; 412 | struct sockaddr_in inaddr; 413 | SOCKET sockfd; 414 | SOCKLEN addrlen = sizeof(inaddr); 415 | 416 | sockfd = accept(d->sockfd, (struct sockaddr*)&inaddr, &addrlen); 417 | if (sockfd == INVALID_SOCKET) { 418 | err("accept failed : %s\n", sk_strerror(sk_errno())); 419 | return NULL; 420 | } 421 | 422 | rtsp_set_client_socket(sockfd);//XXX DEBUG 423 | 424 | info("new rtsp client comming [peer %s:%u]\n", 425 | inet_ntoa(inaddr.sin_addr), ntohs(inaddr.sin_port)); 426 | 427 | cc = __alloc_client_connection(d); 428 | if (cc == NULL) { 429 | closesocket(sockfd); 430 | return NULL; 431 | } 432 | 433 | cc->state = RTSP_CC_STATE_INIT; 434 | cc->sockfd = sockfd; 435 | cc->peer_addr = inaddr.sin_addr; 436 | cc->peer_port = ntohs(inaddr.sin_port); 437 | 438 | return cc; 439 | } 440 | 441 | static void rtsp_del_rtp_connection (struct rtsp_client_connection *cc, int isaudio); 442 | static void rtsp_del_client_connection (struct rtsp_client_connection *cc) 443 | { 444 | if (cc) { 445 | info("delete client socket %d [peer %s:%u]\n", cc->sockfd, inet_ntoa(cc->peer_addr), cc->peer_port); 446 | __client_connection_unbind_session(cc); 447 | rtsp_del_rtp_connection(cc, 0); 448 | rtsp_del_rtp_connection(cc, 1); 449 | closesocket(cc->sockfd); 450 | __free_client_connection(cc); 451 | } 452 | } 453 | 454 | static int rtsp_path_match (const char *main_path, const char *full_path) 455 | { 456 | char path0[64] = {0}; 457 | char path1[64] = {0}; 458 | 459 | strncpy(path0, main_path, sizeof(path0) - 2); 460 | strncpy(path1, full_path, sizeof(path1) - 2); 461 | 462 | if (path0[strlen(path0) - 1] != '/') 463 | strcat(path0, "/"); 464 | if (path1[strlen(path1) - 1] != '/') 465 | strcat(path1, "/"); 466 | 467 | if (strncmp(path0, path1, strlen(path0))) 468 | return 0; 469 | return 1; 470 | } 471 | 472 | rtsp_session_handle rtsp_new_session (rtsp_demo_handle demo, const char *path) 473 | { 474 | struct rtsp_demo *d = (struct rtsp_demo*)demo; 475 | struct rtsp_session *s = NULL; 476 | 477 | if (!d || !path || strlen(path) == 0) { 478 | err("param invalid\n"); 479 | goto fail; 480 | } 481 | 482 | TAILQ_FOREACH(s, &d->sessions_qhead, demo_entry) { 483 | if (rtsp_path_match(s->path, path) || rtsp_path_match(path, s->path)) { 484 | err("path:%s (%s) is exist!!!\n", s->path, path); 485 | goto fail; 486 | } 487 | } 488 | 489 | s = __alloc_session(d); 490 | if (NULL == s) { 491 | goto fail; 492 | } 493 | 494 | strncpy(s->path, path, sizeof(s->path) - 1); 495 | s->vcodec_id = RTSP_CODEC_ID_NONE; 496 | s->acodec_id = RTSP_CODEC_ID_NONE; 497 | 498 | info("add session path: %s\n", s->path); 499 | return (rtsp_session_handle)s; 500 | fail: 501 | if (s) { 502 | free(s); 503 | } 504 | return NULL; 505 | } 506 | 507 | int rtsp_set_auth (rtsp_session_handle session, int type, const char *user, const char *passwd) 508 | { 509 | struct rtsp_session *s = (struct rtsp_session*)session; 510 | if (!s || (s->auth_type != RTSP_AUTH_TYPE_NONE && s->auth_type != type)) 511 | return -1; 512 | 513 | switch(type) { 514 | case RTSP_AUTH_TYPE_NONE: 515 | s->auth_type = RTSP_AUTH_TYPE_NONE; 516 | memset(s->auth_user, 0, sizeof(s->auth_user)); 517 | memset(s->auth_passwd, 0, sizeof(s->auth_passwd)); 518 | break; 519 | case RTSP_AUTH_TYPE_BASIC: 520 | if (!user || !passwd) { 521 | err("please set user/passwd!\n"); 522 | return -1; 523 | } 524 | if (strlen(user) < 1 || strlen(user) + 1 > sizeof(s->auth_user)) { 525 | err("user too short or too length!\n"); 526 | return -1; 527 | } 528 | if (strlen(passwd) < 1 || strlen(passwd) + 1 > sizeof(s->auth_passwd)) { 529 | err("passwd too short or too length!\n"); 530 | return -1; 531 | } 532 | s->auth_type = RTSP_AUTH_TYPE_BASIC; 533 | strcpy(s->auth_user, user); 534 | strcpy(s->auth_passwd, passwd); 535 | break; 536 | case RTSP_AUTH_TYPE_DIGEST: 537 | default: 538 | err("not support this authorization type %d\n", type); 539 | return -1; 540 | } 541 | 542 | return 0; 543 | } 544 | 545 | int rtsp_set_video (rtsp_session_handle session, int codec_id, const uint8_t *codec_data, int data_len) 546 | { 547 | struct rtsp_session *s = (struct rtsp_session*)session; 548 | if (!s || (s->vcodec_id != RTSP_CODEC_ID_NONE && s->vcodec_id != codec_id)) 549 | return -1; 550 | 551 | switch (codec_id) { 552 | case RTSP_CODEC_ID_VIDEO_H264: 553 | case RTSP_CODEC_ID_VIDEO_H265: 554 | break; 555 | default: 556 | err("not supported codec_id %d for video\n", codec_id); 557 | return -1; 558 | } 559 | 560 | s->vcodec_id = codec_id; 561 | s->vrtpe.pt = VRTP_PT_ID; 562 | s->vrtpe.seq = 0; 563 | s->vrtpe.ssrc = 0; 564 | s->vrtpe.sample_rate = 90000; 565 | memset(&s->vcodec_data, 0, sizeof(s->vcodec_data)); 566 | 567 | if (codec_data && data_len > 0) { 568 | switch (codec_id) { 569 | case RTSP_CODEC_ID_VIDEO_H264: 570 | if (rtsp_codec_data_parse_from_user_h264(codec_data, data_len, &s->vcodec_data.h264) <= 0) { 571 | warn("parse codec_data failed\n"); 572 | break; 573 | } 574 | break; 575 | case RTSP_CODEC_ID_VIDEO_H265: 576 | if (rtsp_codec_data_parse_from_user_h265(codec_data, data_len, &s->vcodec_data.h265) <= 0) { 577 | warn("parse codec_data failed\n"); 578 | break; 579 | } 580 | break; 581 | } 582 | } 583 | 584 | if (!s->vstreamq) { 585 | //NOTE must VRTP_MAX_NBPKTS+1. Circular Queue requires at least 1 free elements for Empty element 586 | s->vstreamq = streamq_alloc(RTP_MAX_PKTSIZ, VRTP_MAX_NBPKTS + 1); 587 | if (!s->vstreamq) { 588 | err("alloc memory for video rtp queue failed\n"); 589 | s->vcodec_id = RTSP_CODEC_ID_NONE; 590 | return -1; 591 | } 592 | } 593 | 594 | return 0; 595 | } 596 | 597 | int rtsp_set_audio (rtsp_session_handle session, int codec_id, const uint8_t *codec_data, int data_len) 598 | { 599 | struct rtsp_session *s = (struct rtsp_session*)session; 600 | if (!s || (s->acodec_id != RTSP_CODEC_ID_NONE && s->acodec_id != codec_id)) 601 | return -1; 602 | 603 | switch (codec_id) { 604 | case RTSP_CODEC_ID_AUDIO_G711A: 605 | case RTSP_CODEC_ID_AUDIO_G711U: 606 | case RTSP_CODEC_ID_AUDIO_G726: 607 | case RTSP_CODEC_ID_AUDIO_AAC: 608 | break; 609 | default: 610 | err("not supported codec_id %d for audio\n", codec_id); 611 | return -1; 612 | } 613 | 614 | s->acodec_id = codec_id; 615 | s->artpe.pt = ARTP_PT_ID; 616 | s->artpe.seq = 0; 617 | s->artpe.ssrc = 0; 618 | s->artpe.sample_rate = 8000; 619 | memset(&s->acodec_data, 0, sizeof(s->acodec_data)); 620 | 621 | if (codec_data && data_len > 0) { 622 | switch (codec_id) { 623 | case RTSP_CODEC_ID_AUDIO_G726: 624 | if (rtsp_codec_data_parse_from_user_g726(codec_data, data_len, &s->acodec_data.g726) <= 0) { 625 | warn("parse codec_data failed\n"); 626 | break; 627 | } 628 | break; 629 | case RTSP_CODEC_ID_AUDIO_AAC: 630 | if (rtsp_codec_data_parse_from_user_aac(codec_data, data_len, &s->acodec_data.aac) <= 0) { 631 | warn("parse codec_data failed\n"); 632 | break; 633 | } 634 | s->artpe.sample_rate = s->acodec_data.aac.sample_rate; 635 | break; 636 | } 637 | } 638 | 639 | if (!s->astreamq) { 640 | //NOTE must VRTP_MAX_NBPKTS+1. Circular Queue requires at least 1 free elements for Empty element 641 | s->astreamq = streamq_alloc(RTP_MAX_PKTSIZ, ARTP_MAX_NBPKTS + 1); 642 | if (!s->astreamq) { 643 | err("alloc memory for audio rtp queue failed\n"); 644 | s->acodec_id = RTSP_CODEC_ID_NONE; 645 | return -1; 646 | } 647 | } 648 | 649 | return 0; 650 | } 651 | 652 | void rtsp_del_session (rtsp_session_handle session) 653 | { 654 | struct rtsp_session *s = (struct rtsp_session*)session; 655 | if (s) { 656 | struct rtsp_client_connection *cc; 657 | while ((cc = TAILQ_FIRST(&s->connections_qhead))) { 658 | rtsp_del_client_connection(cc); 659 | } 660 | info("del session path: %s\n", s->path); 661 | if (s->vstreamq) 662 | streamq_free(s->vstreamq); 663 | if (s->astreamq) 664 | streamq_free(s->astreamq); 665 | __free_session(s); 666 | } 667 | } 668 | 669 | void rtsp_del_demo (rtsp_demo_handle demo) 670 | { 671 | struct rtsp_demo *d = (struct rtsp_demo*)demo; 672 | if (d) { 673 | struct rtsp_session *s; 674 | struct rtsp_client_connection *cc; 675 | 676 | while ((cc = TAILQ_FIRST(&d->connections_qhead))) { 677 | rtsp_del_client_connection(cc); 678 | } 679 | while ((s = TAILQ_FIRST(&d->sessions_qhead))) { 680 | rtsp_del_session(s); 681 | } 682 | 683 | closesocket(d->sockfd); 684 | __free_demo(d); 685 | } 686 | } 687 | 688 | static int build_simple_sdp (struct rtsp_session *s, const char *ip, const char *uri, char *sdpbuf, int maxlen) 689 | { 690 | char *p = sdpbuf; 691 | 692 | p += sprintf(p, "v=0\r\n"); 693 | p += sprintf(p, "o=- 0 0 IN IP4 %s\r\n", ip ? ip : "0.0.0.0"); 694 | p += sprintf(p, "s=rtsp_demo\r\n"); 695 | p += sprintf(p, "t=0 0\r\n"); 696 | p += sprintf(p, "c=IN IP4 %s\r\n", ip ? ip : "0.0.0.0"); 697 | p += sprintf(p, "a=control:%s\r\n", uri ? uri : "*"); 698 | p += sprintf(p, "a=range:npt=0-\r\n"); 699 | 700 | if (s->vcodec_id != RTSP_CODEC_ID_NONE) { 701 | switch (s->vcodec_id) { 702 | case RTSP_CODEC_ID_VIDEO_H264: 703 | p += rtsp_build_sdp_media_attr_h264(VRTP_PT_ID, s->vrtpe.sample_rate, 704 | &s->vcodec_data.h264, p, maxlen - (p - sdpbuf)); 705 | break; 706 | case RTSP_CODEC_ID_VIDEO_H265: 707 | p += rtsp_build_sdp_media_attr_h265(VRTP_PT_ID, s->vrtpe.sample_rate, 708 | &s->vcodec_data.h265, p, maxlen - (p - sdpbuf)); 709 | break; 710 | } 711 | if (uri) 712 | p += sprintf(p, "a=control:%s/%s\r\n", uri, VRTSP_SUBPATH); 713 | else 714 | p += sprintf(p, "a=control:%s\r\n", VRTSP_SUBPATH); 715 | } 716 | 717 | if (s->acodec_id != RTSP_CODEC_ID_NONE) { 718 | switch (s->acodec_id) { 719 | case RTSP_CODEC_ID_AUDIO_G711A: 720 | p += rtsp_build_sdp_media_attr_g711a(ARTP_PT_ID, s->artpe.sample_rate, 721 | p, maxlen - (p - sdpbuf)); 722 | break; 723 | case RTSP_CODEC_ID_AUDIO_G711U: 724 | p += rtsp_build_sdp_media_attr_g711u(ARTP_PT_ID, s->artpe.sample_rate, 725 | p, maxlen - (p - sdpbuf)); 726 | break; 727 | case RTSP_CODEC_ID_AUDIO_G726: 728 | p += rtsp_build_sdp_media_attr_g726(ARTP_PT_ID, s->artpe.sample_rate, 729 | &s->acodec_data.g726, p, maxlen - (p - sdpbuf)); 730 | break; 731 | case RTSP_CODEC_ID_AUDIO_AAC: 732 | p += rtsp_build_sdp_media_attr_aac(ARTP_PT_ID, s->artpe.sample_rate, 733 | &s->acodec_data.aac, p, maxlen - (p - sdpbuf)); 734 | break; 735 | } 736 | if (uri) 737 | p += sprintf(p, "a=control:%s/%s\r\n", uri, ARTSP_SUBPATH); 738 | else 739 | p += sprintf(p, "a=control:%s\r\n", ARTSP_SUBPATH); 740 | } 741 | 742 | return (p - sdpbuf); 743 | } 744 | 745 | static int rtsp_authorization_request (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 746 | { 747 | // struct rtsp_demo *d = cc->demo; 748 | struct rtsp_session *s = cc->session; 749 | 750 | char basic_up[32] = ""; 751 | char basic_b64a[64] = ""; 752 | char basic_b64b[64] = ""; 753 | 754 | switch (s->auth_type) { 755 | case RTSP_AUTH_TYPE_NONE: 756 | return 0; 757 | case RTSP_AUTH_TYPE_BASIC: 758 | if (rtsp_msg_get_auth_basic(reqmsg, basic_b64a, sizeof(basic_b64a))) { 759 | dbg("authorization get fail. [peer %s:%u]\n", inet_ntoa(cc->peer_addr), cc->peer_port); 760 | rtsp_msg_set_www_auth_basic(resmsg, "rtsp_demo"); 761 | rtsp_msg_set_response(resmsg, 401);//Unauthorized 762 | return 1; 763 | } 764 | sprintf(basic_up, "%s:%s", s->auth_user, s->auth_passwd); 765 | base64_encode(basic_b64b, sizeof(basic_b64b), (uint8_t*)basic_up, strlen(basic_up)); 766 | if (strcmp(basic_b64a, basic_b64b)) { 767 | warn("authorization basic fail, my %s his %s. [peer %s:%u]\n", 768 | basic_b64b, basic_b64a, inet_ntoa(cc->peer_addr), cc->peer_port); 769 | rtsp_msg_set_www_auth_basic(resmsg, "rtsp_demo"); 770 | rtsp_msg_set_response(resmsg, 401);//Unauthorized 771 | return 1; 772 | } 773 | break; 774 | 775 | case RTSP_AUTH_TYPE_DIGEST: 776 | //TODO 777 | default: 778 | break; 779 | } 780 | return 0; 781 | } 782 | 783 | static int rtsp_handle_OPTIONS (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 784 | { 785 | // struct rtsp_demo *d = cc->demo; 786 | // struct rtsp_session *s = cc->session; 787 | uint32_t public_ = 0; 788 | dbg("\n"); 789 | public_ |= RTSP_MSG_PUBLIC_OPTIONS; 790 | public_ |= RTSP_MSG_PUBLIC_DESCRIBE; 791 | public_ |= RTSP_MSG_PUBLIC_SETUP; 792 | public_ |= RTSP_MSG_PUBLIC_PAUSE; 793 | public_ |= RTSP_MSG_PUBLIC_PLAY; 794 | public_ |= RTSP_MSG_PUBLIC_TEARDOWN; 795 | rtsp_msg_set_public(resmsg, public_); 796 | return 0; 797 | } 798 | 799 | static int rtsp_handle_DESCRIBE (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 800 | { 801 | // struct rtsp_demo *d = cc->demo; 802 | struct rtsp_session *s = cc->session; 803 | char sdpbuf[1024] = ""; 804 | int sdplen = 0; 805 | uint32_t accept = 0; 806 | const rtsp_msg_uri_s *puri = &reqmsg->hdrs.startline.reqline.uri; 807 | char uri[128] = ""; 808 | 809 | dbg("\n"); 810 | if (rtsp_msg_get_accept(reqmsg, &accept) < 0 && !(accept & RTSP_MSG_ACCEPT_SDP)) { 811 | rtsp_msg_set_response(resmsg, 406); 812 | warn("client not support accept SDP\n"); 813 | return 0; 814 | } 815 | 816 | //build uri 817 | sprintf(uri, "rtsp://%s", puri->ipaddr); 818 | if (puri->port != 0) 819 | sprintf(uri + strlen(uri), ":%u", puri->port); 820 | strcat(uri, s->path); 821 | 822 | sdplen = build_simple_sdp(s, puri->ipaddr, uri, sdpbuf, sizeof(sdpbuf)); 823 | 824 | rtsp_msg_set_content_type(resmsg, RTSP_MSG_CONTENT_TYPE_SDP); 825 | rtsp_msg_set_content_length(resmsg, sdplen); 826 | rtsp_msg_set_x_accept_dynamic_rate(resmsg, 1); //for QuickTime Player 827 | resmsg->body.body = rtsp_mem_dup(sdpbuf, sdplen); 828 | return 0; 829 | } 830 | 831 | static unsigned long __rtp_gen_ssrc (void) 832 | { 833 | static unsigned long ssrc = 0x22345678; 834 | return ssrc++; 835 | } 836 | 837 | static int __rtp_udp_local_setup (struct rtp_connection *rtp) 838 | { 839 | int i, ret; 840 | 841 | for (i = 65536/4*3/2*2; i < 65536; i += 2) { 842 | SOCKET rtpsock, rtcpsock; 843 | struct sockaddr_in inaddr; 844 | uint16_t port; 845 | 846 | rtpsock = socket(AF_INET, SOCK_DGRAM, 0); 847 | if (rtpsock == INVALID_SOCKET) { 848 | err("create rtp socket failed: %s\n", sk_strerror(sk_errno())); 849 | return -1; 850 | } 851 | 852 | rtcpsock = socket(AF_INET, SOCK_DGRAM, 0); 853 | if (rtcpsock == INVALID_SOCKET) { 854 | err("create rtcp socket failed: %s\n", sk_strerror(sk_errno())); 855 | closesocket(rtpsock); 856 | return -1; 857 | } 858 | 859 | port = i; 860 | memset(&inaddr, 0, sizeof(inaddr)); 861 | inaddr.sin_family = AF_INET; 862 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); 863 | inaddr.sin_port = htons(port); 864 | ret = bind(rtpsock, (struct sockaddr*)&inaddr, sizeof(inaddr)); 865 | if (ret == SOCKET_ERROR) { 866 | closesocket(rtpsock); 867 | closesocket(rtcpsock); 868 | continue; 869 | } 870 | 871 | port = i + 1; 872 | memset(&inaddr, 0, sizeof(inaddr)); 873 | inaddr.sin_family = AF_INET; 874 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); 875 | inaddr.sin_port = htons(port); 876 | ret = bind(rtcpsock, (struct sockaddr*)&inaddr, sizeof(inaddr)); 877 | if (ret == SOCKET_ERROR) { 878 | closesocket(rtpsock); 879 | closesocket(rtcpsock); 880 | continue; 881 | } 882 | 883 | #ifdef __WIN32__ 884 | { 885 | unsigned long nonblocked = 1; 886 | ret = ioctlsocket(rtpsock, FIONBIO, &nonblocked); 887 | if (ret == SOCKET_ERROR) { 888 | warn("ioctlsocket FIONBIO failed: %s\n", sk_strerror(sk_errno())); 889 | } 890 | ret = ioctlsocket(rtcpsock, FIONBIO, &nonblocked); 891 | if (ret == SOCKET_ERROR) { 892 | warn("ioctlsocket FIONBIO failed: %s\n", sk_strerror(sk_errno())); 893 | } 894 | } 895 | #endif 896 | #ifdef __LINUX__ 897 | ret = fcntl(rtpsock, F_GETFL, 0); 898 | if (ret < 0) { 899 | warn("fcntl F_GETFL failed: %s\n", strerror(errno)); 900 | } else { 901 | ret |= O_NONBLOCK; 902 | ret = fcntl(rtpsock, F_SETFL, ret); 903 | if (ret < 0) { 904 | warn("fcntl F_SETFL failed: %s\n", strerror(errno)); 905 | } 906 | } 907 | ret = fcntl(rtcpsock, F_GETFL, 0); 908 | if (ret < 0) { 909 | warn("fcntl F_GETFL failed: %s\n", strerror(errno)); 910 | } else { 911 | ret |= O_NONBLOCK; 912 | ret = fcntl(rtcpsock, F_SETFL, ret); 913 | if (ret < 0) { 914 | warn("fcntl F_SETFL failed: %s\n", strerror(errno)); 915 | } 916 | } 917 | #endif 918 | rtp->is_over_tcp = 0; 919 | rtp->udp_sockfd[0] = rtpsock; 920 | rtp->udp_sockfd[1] = rtcpsock; 921 | rtp->udp_localport[0] = i; 922 | rtp->udp_localport[1] = i + 1; 923 | 924 | return 0; 925 | } 926 | 927 | err("not found free local port for rtp/rtcp\n"); 928 | return -1; 929 | } 930 | 931 | static int rtsp_new_rtp_connection (struct rtsp_client_connection *cc, int isaudio, int istcp, int peer_port, int peer_interleaved) 932 | { 933 | struct rtp_connection *rtp; 934 | struct in_addr peer_addr = cc->peer_addr; 935 | 936 | rtp = (struct rtp_connection*) calloc(1, sizeof(struct rtp_connection)); 937 | if (rtp == NULL) { 938 | err("alloc mem for rtp session failed: %s\n", strerror(errno)); 939 | return -1; 940 | } 941 | 942 | rtp->is_over_tcp = !!istcp; 943 | rtp->peer_addr = peer_addr; 944 | rtp->ssrc = __rtp_gen_ssrc(); 945 | 946 | if (istcp) { 947 | rtp->tcp_interleaved[0] = peer_interleaved; 948 | rtp->tcp_interleaved[1] = peer_interleaved + 1; 949 | dbg("new rtp over tcp for %s ssrc:%08x peer_addr:%s interleaved:%u-%u [peer %s:%u]\n", 950 | (isaudio ? "audio" : "video"), 951 | rtp->ssrc, 952 | inet_ntoa(peer_addr), 953 | rtp->tcp_interleaved[0], rtp->tcp_interleaved[1], 954 | inet_ntoa(cc->peer_addr), cc->peer_port); 955 | } else { 956 | if (__rtp_udp_local_setup(rtp) < 0) { 957 | free(rtp); 958 | return -1; 959 | } 960 | rtp->udp_peerport[0] = peer_port; 961 | rtp->udp_peerport[1] = peer_port + 1; 962 | dbg("new rtp over udp for %s ssrc:%08x local_port:%u-%u peer_addr:%s peer_port:%u-%u [peer %s:%u]\n", 963 | (isaudio ? "audio" : "video"), 964 | rtp->ssrc, 965 | rtp->udp_localport[0], rtp->udp_localport[1], 966 | inet_ntoa(peer_addr), 967 | rtp->udp_peerport[0], rtp->udp_peerport[1], 968 | inet_ntoa(cc->peer_addr), cc->peer_port); 969 | } 970 | 971 | if (isaudio) { 972 | cc->artp = rtp; 973 | } else { 974 | cc->vrtp = rtp; 975 | } 976 | 977 | return 0; 978 | } 979 | 980 | static void rtsp_del_rtp_connection (struct rtsp_client_connection *cc, int isaudio) 981 | { 982 | struct rtp_connection *rtp; 983 | 984 | if (isaudio) { 985 | rtp = cc->artp; 986 | cc->artp = NULL; 987 | } else { 988 | rtp = cc->vrtp; 989 | cc->vrtp = NULL; 990 | } 991 | 992 | if (rtp) { 993 | if (!(rtp->is_over_tcp)) { 994 | closesocket(rtp->udp_sockfd[0]); 995 | closesocket(rtp->udp_sockfd[1]); 996 | } 997 | free(rtp); 998 | } 999 | } 1000 | 1001 | static int rtsp_handle_SETUP (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 1002 | { 1003 | // struct rtsp_demo *d = cc->demo; 1004 | struct rtsp_session *s = cc->session; 1005 | struct rtp_connection *rtp = NULL; 1006 | int istcp = 0, isaudio = 0; 1007 | char vpath[64] = ""; 1008 | char apath[64] = ""; 1009 | uint32_t x_dynamic_rate; 1010 | int ret; 1011 | 1012 | dbg("\n"); 1013 | 1014 | if (!reqmsg->hdrs.transport) { 1015 | rtsp_msg_set_response(resmsg, 461); 1016 | warn("rtsp no transport err\n"); 1017 | return 0; 1018 | } 1019 | 1020 | if (reqmsg->hdrs.transport->type == RTSP_MSG_TRANSPORT_TYPE_RTP_AVP_TCP) { 1021 | istcp = 1; 1022 | if (!(reqmsg->hdrs.transport->flags & RTSP_MSG_TRANSPORT_FLAG_INTERLEAVED)) { 1023 | warn("rtsp no interleaved err\n"); 1024 | rtsp_msg_set_response(resmsg, 461); 1025 | return 0; 1026 | } 1027 | } else { 1028 | if (!(reqmsg->hdrs.transport->flags & RTSP_MSG_TRANSPORT_FLAG_CLIENT_PORT)) { 1029 | warn("rtsp no client_port err\n"); 1030 | rtsp_msg_set_response(resmsg, 461); 1031 | return 0; 1032 | } 1033 | } 1034 | 1035 | snprintf(vpath, sizeof(vpath) - 1, "%s/%s", s->path, VRTSP_SUBPATH); 1036 | snprintf(apath, sizeof(vpath) - 1, "%s/%s", s->path, ARTSP_SUBPATH); 1037 | if (s->vcodec_id != RTSP_CODEC_ID_NONE && rtsp_path_match(vpath, reqmsg->hdrs.startline.reqline.uri.abspath)) { 1038 | isaudio = 0; 1039 | } else if (s->acodec_id != RTSP_CODEC_ID_NONE && rtsp_path_match(apath, reqmsg->hdrs.startline.reqline.uri.abspath)) { 1040 | isaudio = 1; 1041 | } else { 1042 | warn("rtsp urlpath:%s err\n", reqmsg->hdrs.startline.reqline.uri.abspath); 1043 | rtsp_msg_set_response(resmsg, 461); 1044 | return 0; 1045 | } 1046 | 1047 | rtsp_del_rtp_connection(cc, isaudio); 1048 | 1049 | ret = rtsp_new_rtp_connection(cc, isaudio, istcp, reqmsg->hdrs.transport->client_port, reqmsg->hdrs.transport->interleaved); 1050 | if (ret < 0) { 1051 | rtsp_msg_set_response(resmsg, 500); 1052 | return 0; 1053 | } 1054 | 1055 | rtp = isaudio ? cc->artp : cc->vrtp; 1056 | 1057 | if (istcp) { 1058 | rtsp_msg_set_transport_tcp(resmsg, rtp->ssrc, rtp->tcp_interleaved[0]); 1059 | } else { 1060 | rtsp_msg_set_transport_udp(resmsg, rtp->ssrc, rtp->udp_peerport[0], rtp->udp_localport[0]); 1061 | } 1062 | 1063 | //for QuickTime Player 1064 | if (rtsp_msg_get_x_dynamic_rate(reqmsg, &x_dynamic_rate) < 0) { 1065 | x_dynamic_rate = 0; 1066 | } 1067 | rtsp_msg_set_x_dynamic_rate(resmsg, x_dynamic_rate); 1068 | 1069 | if (cc->state == RTSP_CC_STATE_PLAYING) { 1070 | rtp->streamq_index = streamq_tail((isaudio ? s->astreamq : s->vstreamq)); 1071 | } 1072 | 1073 | if (cc->state == RTSP_CC_STATE_INIT) { 1074 | cc->state = RTSP_CC_STATE_READY; 1075 | cc->session_id = rtsp_msg_gen_session_id(); 1076 | rtsp_msg_set_session(resmsg, cc->session_id); 1077 | } 1078 | 1079 | return 0; 1080 | } 1081 | 1082 | static int rtsp_handle_PAUSE (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 1083 | { 1084 | // struct rtsp_demo *d = cc->demo; 1085 | // struct rtsp_session *s = cc->session; 1086 | 1087 | dbg("\n"); 1088 | if (cc->state != RTSP_CC_STATE_READY && cc->state != RTSP_CC_STATE_PLAYING) 1089 | { 1090 | rtsp_msg_set_response(resmsg, 455); 1091 | warn("rtsp status err\n"); 1092 | return 0; 1093 | } 1094 | 1095 | if (cc->state != RTSP_CC_STATE_READY) 1096 | cc->state = RTSP_CC_STATE_READY; 1097 | return 0; 1098 | } 1099 | 1100 | static int rtsp_handle_PLAY (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 1101 | { 1102 | // struct rtsp_demo *d = cc->demo; 1103 | struct rtsp_session *s = cc->session; 1104 | 1105 | dbg("\n"); 1106 | if (cc->state != RTSP_CC_STATE_READY && cc->state != RTSP_CC_STATE_PLAYING) 1107 | { 1108 | rtsp_msg_set_response(resmsg, 455); 1109 | warn("rtsp status err\n"); 1110 | return 0; 1111 | } 1112 | 1113 | if (cc->state != RTSP_CC_STATE_PLAYING) { 1114 | if (cc->vrtp && s->vstreamq) 1115 | cc->vrtp->streamq_index = streamq_tail(s->vstreamq); 1116 | if (cc->artp && s->astreamq) 1117 | cc->artp->streamq_index = streamq_tail(s->astreamq); 1118 | cc->state = RTSP_CC_STATE_PLAYING; 1119 | } 1120 | return 0; 1121 | } 1122 | 1123 | static int rtsp_handle_TEARDOWN (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 1124 | { 1125 | // struct rtsp_demo *d = cc->demo; 1126 | struct rtsp_session *s = cc->session; 1127 | char vpath[64] = ""; 1128 | char apath[64] = ""; 1129 | dbg("\n"); 1130 | 1131 | snprintf(vpath, sizeof(vpath) - 1, "%s/%s", s->path, VRTSP_SUBPATH); 1132 | snprintf(apath, sizeof(vpath) - 1, "%s/%s", s->path, ARTSP_SUBPATH); 1133 | 1134 | if (rtsp_path_match(vpath, reqmsg->hdrs.startline.reqline.uri.abspath)) { 1135 | rtsp_del_rtp_connection(cc, 0); 1136 | } else if (rtsp_path_match(apath, reqmsg->hdrs.startline.reqline.uri.abspath)) { 1137 | rtsp_del_rtp_connection(cc, 1); 1138 | } else { 1139 | rtsp_del_rtp_connection(cc, 0); 1140 | rtsp_del_rtp_connection(cc, 1); 1141 | } 1142 | if (!cc->vrtp && !cc->artp) { 1143 | cc->state = RTSP_CC_STATE_INIT; 1144 | } 1145 | return 0; 1146 | } 1147 | 1148 | static int rtsp_process_request (struct rtsp_client_connection *cc, const rtsp_msg_s *reqmsg, rtsp_msg_s *resmsg) 1149 | { 1150 | struct rtsp_demo *d = cc->demo; 1151 | struct rtsp_session *s = cc->session; 1152 | const char *path = reqmsg->hdrs.startline.reqline.uri.abspath; 1153 | uint32_t cseq = 0, session = 0; 1154 | 1155 | rtsp_msg_set_response(resmsg, 200); 1156 | rtsp_msg_set_date(resmsg, NULL); 1157 | rtsp_msg_set_server(resmsg, "rtsp_demo (" __DATE__ " " __TIME__ ")"); 1158 | 1159 | if (rtsp_msg_get_cseq(reqmsg, &cseq) < 0) { 1160 | rtsp_msg_set_response(resmsg, 400); 1161 | warn("No CSeq field\n"); 1162 | return 0; 1163 | } 1164 | rtsp_msg_set_cseq(resmsg, cseq); 1165 | 1166 | if (cc->state != RTSP_CC_STATE_INIT) { 1167 | if (rtsp_msg_get_session(reqmsg, &session) < 0 || session != cc->session_id) { 1168 | warn("Invalid Session field\n"); 1169 | rtsp_msg_set_response(resmsg, 454); 1170 | return 0; 1171 | } 1172 | rtsp_msg_set_session(resmsg, session); 1173 | } 1174 | 1175 | if (s) { 1176 | if (rtsp_path_match(s->path, path) == 0) { // /live/chn0 1177 | warn("path is not matched %s (old:%s)\n", path, s->path); 1178 | rtsp_msg_set_response(resmsg, 451); 1179 | return 0; 1180 | } 1181 | } else if (reqmsg->hdrs.startline.reqline.method != RTSP_MSG_METHOD_OPTIONS) { 1182 | TAILQ_FOREACH(s, &d->sessions_qhead, demo_entry) { 1183 | if (rtsp_path_match(s->path, path)) { 1184 | break; 1185 | } 1186 | } 1187 | if (NULL == s) { 1188 | warn("Not found session path: %s\n", path); 1189 | rtsp_msg_set_response(resmsg, 454); 1190 | return 0; 1191 | } 1192 | __client_connection_bind_session(cc, s); 1193 | } 1194 | 1195 | switch (reqmsg->hdrs.startline.reqline.method) { 1196 | case RTSP_MSG_METHOD_OPTIONS: 1197 | return rtsp_handle_OPTIONS(cc, reqmsg, resmsg); 1198 | case RTSP_MSG_METHOD_DESCRIBE: 1199 | if (rtsp_authorization_request(cc, reqmsg, resmsg)) 1200 | return 0; 1201 | return rtsp_handle_DESCRIBE(cc, reqmsg, resmsg); 1202 | case RTSP_MSG_METHOD_SETUP: 1203 | if (rtsp_authorization_request(cc, reqmsg, resmsg)) 1204 | return 0; 1205 | return rtsp_handle_SETUP(cc, reqmsg, resmsg); 1206 | case RTSP_MSG_METHOD_PAUSE: 1207 | if (rtsp_authorization_request(cc, reqmsg, resmsg)) 1208 | return 0; 1209 | return rtsp_handle_PAUSE(cc, reqmsg, resmsg); 1210 | case RTSP_MSG_METHOD_PLAY: 1211 | if (rtsp_authorization_request(cc, reqmsg, resmsg)) 1212 | return 0; 1213 | return rtsp_handle_PLAY(cc, reqmsg, resmsg); 1214 | case RTSP_MSG_METHOD_TEARDOWN: 1215 | if (rtsp_authorization_request(cc, reqmsg, resmsg)) 1216 | return 0; 1217 | return rtsp_handle_TEARDOWN(cc, reqmsg, resmsg); 1218 | default: 1219 | break; 1220 | } 1221 | 1222 | rtsp_msg_set_response(resmsg, 501); 1223 | return 0; 1224 | } 1225 | 1226 | static int rtsp_recv_msg (struct rtsp_client_connection *cc, rtsp_msg_s *msg) 1227 | { 1228 | int ret; 1229 | 1230 | if (sizeof(cc->reqbuf) - cc->reqlen - 1 > 0) { 1231 | ret = recv(cc->sockfd, cc->reqbuf + cc->reqlen, sizeof(cc->reqbuf) - cc->reqlen - 1, MSG_DONTWAIT); 1232 | if (ret == 0) { 1233 | dbg("peer closed [peer %s:%u]\n", inet_ntoa(cc->peer_addr), cc->peer_port); 1234 | return -1; 1235 | } 1236 | if (ret == SOCKET_ERROR) { 1237 | if (sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1238 | err("recv data failed: %s\n", sk_strerror(sk_errno())); 1239 | return -1; 1240 | } 1241 | ret = 0; 1242 | } 1243 | cc->reqlen += ret; 1244 | cc->reqbuf[cc->reqlen] = 0; 1245 | } 1246 | 1247 | if (cc->reqlen == 0) { 1248 | return 0; 1249 | } 1250 | 1251 | ret = rtsp_msg_parse_from_array(msg, cc->reqbuf, cc->reqlen); 1252 | if (ret < 0) { 1253 | err("Invalid frame\n"); 1254 | return -1; 1255 | } 1256 | if (ret == 0) { 1257 | return 0; 1258 | } 1259 | 1260 | //dbg("recv %d bytes rtsp message from %s\n", ret, inet_ntoa(cc->peer_addr)); 1261 | 1262 | memmove(cc->reqbuf, cc->reqbuf + ret, cc->reqlen - ret); 1263 | cc->reqlen -= ret; 1264 | return ret; 1265 | } 1266 | 1267 | static int rtsp_send_msg (struct rtsp_client_connection *cc, rtsp_msg_s *msg) 1268 | { 1269 | int size, ret; 1270 | 1271 | if (cc->reslen > 0) { 1272 | ret = send(cc->sockfd, cc->resbuf + cc->resoff, cc->reslen, 0); 1273 | if (ret != cc->reslen) { 1274 | if (ret > 0 && ret < cc->reslen) { 1275 | cc->resoff += ret; 1276 | cc->reslen -= ret; 1277 | warn("rtsp send message failed, buffer has %d bytes. [peer %s:%u]\n", 1278 | cc->reslen, inet_ntoa(cc->peer_addr), cc->peer_port); 1279 | return 0; 1280 | } 1281 | if (ret == SOCKET_ERROR && sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1282 | warn("rtsp send buffer fail: %s. [peer %s:%u]\n", 1283 | sk_strerror(sk_errno()), inet_ntoa(cc->peer_addr), cc->peer_port); 1284 | return -1; 1285 | } 1286 | return 0; 1287 | } 1288 | cc->resoff = 0; 1289 | cc->reslen = 0; 1290 | } 1291 | 1292 | size = rtsp_msg_build_to_array(msg, cc->resbuf, sizeof(cc->resbuf)); 1293 | if (size < 0) { 1294 | err("rtsp_msg_build_to_array failed\n"); 1295 | return -1; 1296 | } 1297 | 1298 | ret = send(cc->sockfd, cc->resbuf, size, 0); 1299 | if (ret != size) { 1300 | if (ret > 0 && ret < size) { 1301 | cc->resoff = ret; 1302 | cc->reslen = size - ret; 1303 | dbg("rtsp send message %d bytes, store %d bytes to buffer. [peer %s:%u]\n", 1304 | ret, cc->reslen, inet_ntoa(cc->peer_addr), cc->peer_port); 1305 | return size; 1306 | } 1307 | if (ret == SOCKET_ERROR && sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1308 | warn("rtsp send message fail: %s. [peer %s:%u]\n", 1309 | sk_strerror(sk_errno()), inet_ntoa(cc->peer_addr), cc->peer_port); 1310 | return -1; 1311 | } 1312 | return 0; 1313 | } 1314 | 1315 | //dbg("sent %d bytes rtsp message. [peer %s:%u]\n", ret, inet_ntoa(cc->peer_addr), cc->peer_port); 1316 | return ret; 1317 | } 1318 | 1319 | static int rtsp_send_interlaced_frame (struct rtsp_client_connection *cc, int channel, const uint8_t *data, int len) 1320 | { 1321 | int ret; 1322 | uint8_t szbuf[4]; 1323 | 1324 | if (cc->reslen > 0) { 1325 | ret = send(cc->sockfd, cc->resbuf + cc->resoff, cc->reslen, 0); 1326 | if (ret != cc->reslen) { 1327 | if (ret > 0 && ret < cc->reslen) { 1328 | cc->resoff += ret; 1329 | cc->reslen -= ret; 1330 | warn("rtsp send interlaced frame failed, buffer has %d bytes. [peer %s:%u]\n", 1331 | cc->reslen, inet_ntoa(cc->peer_addr), cc->peer_port); 1332 | return 0; 1333 | } 1334 | if (ret == SOCKET_ERROR && sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1335 | warn("rtsp send buffer fail: %s. [peer %s:%u]\n", 1336 | sk_strerror(sk_errno()), inet_ntoa(cc->peer_addr), cc->peer_port); 1337 | return -1; 1338 | } 1339 | return 0; 1340 | } 1341 | cc->resoff = 0; 1342 | cc->reslen = 0; 1343 | } 1344 | 1345 | if (len + 4 > (int)sizeof(cc->resbuf)) { 1346 | err("interlaced frame too big %d bytes, more then sizeof resbuf %d bytes. " 1347 | "please modify source code!!! [peer %s:%u]\n", len + 4, 1348 | sizeof(cc->resbuf), inet_ntoa(cc->peer_addr), cc->peer_port); 1349 | return -1; 1350 | } 1351 | 1352 | //XXX one times to send a complete interlaced frame 1353 | szbuf[0] = '$'; 1354 | szbuf[1] = channel; 1355 | *((uint16_t*)&szbuf[2]) = htons(len); 1356 | ret = send(cc->sockfd, (const char*)szbuf, 4, 0); 1357 | if (ret != 4) { 1358 | if (ret > 0 && ret < 4) { 1359 | cc->resoff = 0; 1360 | cc->reslen = 4 - ret + len; 1361 | memcpy(cc->resbuf, szbuf + ret, 4 - ret); 1362 | memcpy(cc->resbuf + 4 - ret, data, len); 1363 | dbg("rtsp send interlaced header %d bytes, store %d bytes to buffer. [peer %s:%u]\n", 1364 | ret, cc->reslen, inet_ntoa(cc->peer_addr), cc->peer_port); 1365 | return len; 1366 | } 1367 | if (ret == SOCKET_ERROR && sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1368 | warn("rtsp send interlaced header fail: %s. [peer %s:%u]\n", 1369 | sk_strerror(sk_errno()), inet_ntoa(cc->peer_addr), cc->peer_port); 1370 | return -1; 1371 | } 1372 | return 0; 1373 | } 1374 | 1375 | ret = send(cc->sockfd, (const char*)data, len, 0); 1376 | if (ret != len) { 1377 | if (ret > 0 && ret < len) { 1378 | cc->resoff = 0; 1379 | cc->reslen = len - ret; 1380 | memcpy(cc->resbuf, data + ret, len - ret); 1381 | dbg("rtsp send interlaced data %d bytes, store %d bytes to buffer. [peer %s:%u]\n", 1382 | ret, cc->reslen, inet_ntoa(cc->peer_addr), cc->peer_port); 1383 | } else { 1384 | cc->resoff = 0; 1385 | cc->reslen = len; 1386 | memcpy(cc->resbuf, data, len); 1387 | dbg("rtsp send interlaced data fail: %s, store %d bytes to buffer. [peer %s:%u]\n", 1388 | sk_strerror(sk_errno()), cc->reslen, inet_ntoa(cc->peer_addr), cc->peer_port); 1389 | } 1390 | } 1391 | 1392 | return len; 1393 | } 1394 | 1395 | static int rtsp_recv_rtp_over_udp (struct rtsp_client_connection *cc, int isaudio) 1396 | { 1397 | struct rtp_connection *rtp = isaudio ? cc->artp : cc->vrtp; 1398 | struct sockaddr_in inaddr; 1399 | SOCKLEN addrlen = sizeof(inaddr); 1400 | char szbuf[128]; 1401 | int len; 1402 | 1403 | len = recvfrom(rtp->udp_sockfd[0], szbuf, sizeof(szbuf), MSG_DONTWAIT, (struct sockaddr*)&inaddr, &addrlen); 1404 | if (len == SOCKET_ERROR) { 1405 | if (sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1406 | warn("rtp over udp recv failed: %s\n", sk_strerror(sk_errno())); 1407 | return -1; 1408 | } 1409 | return 0; 1410 | } 1411 | 1412 | //dbg("rtp over udp recv %d bytes [peer %s:%u]\n", len, inet_ntoa(cc->peer_addr), cc->peer_port); 1413 | 1414 | if (!memcmp(&inaddr.sin_addr, &rtp->peer_addr, sizeof(inaddr.sin_addr)) 1415 | && rtp->udp_peerport[0] != ntohs(inaddr.sin_port)) 1416 | { 1417 | dbg("rtp over udp port change %u to %u. [peer %s:%u]\n", rtp->udp_peerport[0], 1418 | ntohs(inaddr.sin_port), inet_ntoa(cc->peer_addr), cc->peer_port); 1419 | rtp->udp_peerport[0] = ntohs(inaddr.sin_port); 1420 | } 1421 | 1422 | //TODO process rtp frame 1423 | return len; 1424 | } 1425 | 1426 | static int rtsp_recv_rtcp_over_udp (struct rtsp_client_connection *cc, int isaudio) 1427 | { 1428 | struct rtp_connection *rtp = isaudio ? cc->artp : cc->vrtp; 1429 | struct sockaddr_in inaddr; 1430 | SOCKLEN addrlen = sizeof(inaddr); 1431 | char szbuf[128]; 1432 | int len; 1433 | 1434 | len = recvfrom(rtp->udp_sockfd[1], szbuf, sizeof(szbuf), MSG_DONTWAIT, (struct sockaddr*)&inaddr, &addrlen); 1435 | if (len == SOCKET_ERROR) { 1436 | if (sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1437 | warn("rtcp over udp recv failed: %s\n", sk_strerror(sk_errno())); 1438 | return -1; 1439 | } 1440 | return 0; 1441 | } 1442 | 1443 | //dbg("rtcp over udp recv %d bytes [peer %s:%u]\n", len, inet_ntoa(cc->peer_addr), cc->peer_port); 1444 | 1445 | if (!memcmp(&inaddr.sin_addr, &rtp->peer_addr, sizeof(inaddr.sin_addr)) 1446 | && rtp->udp_peerport[1] != ntohs(inaddr.sin_port)) 1447 | { 1448 | dbg("rtcp over udp port change %u to %u. [peer %s:%u]\n",rtp->udp_peerport[1], 1449 | ntohs(inaddr.sin_port), inet_ntoa(cc->peer_addr), cc->peer_port); 1450 | rtp->udp_peerport[1] = ntohs(inaddr.sin_port); 1451 | } 1452 | 1453 | //TODO process rtcp frame 1454 | return len; 1455 | } 1456 | 1457 | static int rtp_send_over_udp (struct rtp_connection *c, const uint8_t *data, int size) 1458 | { 1459 | struct sockaddr_in inaddr; 1460 | SOCKET sockfd = c->udp_sockfd[0]; 1461 | int ret = -1; 1462 | 1463 | memset(&inaddr, 0, sizeof(inaddr)); 1464 | inaddr.sin_family = AF_INET; 1465 | inaddr.sin_addr = c->peer_addr; 1466 | inaddr.sin_port = htons(c->udp_peerport[0]); 1467 | 1468 | ret = sendto(sockfd, (const char*)data, size, 0, (struct sockaddr*)&inaddr, sizeof(inaddr)); 1469 | if (ret != size) { 1470 | if (sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1471 | warn("rtp over udp send %d bytes to %s failed: %s\n", size, inet_ntoa(c->peer_addr), sk_strerror(sk_errno())); 1472 | return -1; 1473 | } 1474 | return 0; 1475 | } 1476 | return size; 1477 | } 1478 | 1479 | static int rtsp_tx_video_packet (struct rtsp_client_connection *cc) 1480 | { 1481 | // struct rtsp_demo *d = cc->demo; 1482 | struct rtsp_session *s = cc->session; 1483 | struct stream_queue *q = s->vstreamq; 1484 | struct rtp_connection *rtp = cc->vrtp; 1485 | uint8_t *ppacket = NULL; 1486 | int *ppktlen = NULL; 1487 | int count = 0; 1488 | 1489 | /*dbg("index=%d head=%d tail=%d used=%d\n", 1490 | rtp->streamq_index, 1491 | streamq_head(q), 1492 | streamq_tail(q), 1493 | streamq_inused(q, rtp->streamq_index));*/ 1494 | 1495 | while (streamq_inused(q, rtp->streamq_index) > 0) { 1496 | streamq_query(q, rtp->streamq_index, (char**)&ppacket, &ppktlen); 1497 | 1498 | if (*ppktlen > 0) { 1499 | *((uint32_t*)(&ppacket[8])) = htonl(rtp->ssrc); //modify ssrc 1500 | if (rtp->is_over_tcp) { 1501 | if (rtsp_send_interlaced_frame(cc, rtp->tcp_interleaved[0], ppacket, *ppktlen) != *ppktlen) { 1502 | break; 1503 | } 1504 | } else { 1505 | if (rtp_send_over_udp(rtp, ppacket, *ppktlen) != *ppktlen) { 1506 | break; 1507 | } 1508 | } 1509 | 1510 | rtp->rtcp_packet_count ++; 1511 | rtp->rtcp_octet_count += *ppktlen - 12;//XXX 1512 | } 1513 | rtp->streamq_index = streamq_next(q, rtp->streamq_index); 1514 | count ++; 1515 | } 1516 | 1517 | return count; 1518 | } 1519 | 1520 | static int rtsp_tx_audio_packet (struct rtsp_client_connection *cc) 1521 | { 1522 | // struct rtsp_demo *d = cc->demo; 1523 | struct rtsp_session *s = cc->session; 1524 | struct stream_queue *q = s->astreamq; 1525 | struct rtp_connection *rtp = cc->artp; 1526 | uint8_t *ppacket = NULL; 1527 | int *ppktlen = NULL; 1528 | int count = 0; 1529 | 1530 | while (streamq_inused(q, rtp->streamq_index) > 0) { 1531 | streamq_query(q, rtp->streamq_index, (char**)&ppacket, &ppktlen); 1532 | 1533 | if (*ppktlen > 0) { 1534 | *((uint32_t*)(&ppacket[8])) = htonl(rtp->ssrc); //modify ssrc 1535 | if (rtp->is_over_tcp) { 1536 | if (rtsp_send_interlaced_frame(cc, rtp->tcp_interleaved[0], ppacket, *ppktlen) != *ppktlen) { 1537 | break; 1538 | } 1539 | } else { 1540 | if (rtp_send_over_udp(rtp, ppacket, *ppktlen) != *ppktlen) { 1541 | break; 1542 | } 1543 | } 1544 | 1545 | rtp->rtcp_packet_count ++; 1546 | rtp->rtcp_octet_count += *ppktlen - 12;//XXX 1547 | } 1548 | rtp->streamq_index = streamq_next(q, rtp->streamq_index); 1549 | count ++; 1550 | } 1551 | 1552 | return count; 1553 | } 1554 | 1555 | struct rtcp_sr { 1556 | #ifdef __BIG_ENDIAN__ 1557 | uint16_t pt:8; 1558 | uint16_t v:2; 1559 | uint16_t p:1; 1560 | uint16_t rc:5; 1561 | #else 1562 | uint16_t rc:5; 1563 | uint16_t p:1; 1564 | uint16_t v:2; 1565 | uint16_t pt:8; 1566 | #endif 1567 | uint16_t length; 1568 | uint32_t ssrc; 1569 | uint32_t ntpts_msw; 1570 | uint32_t ntpts_lsw; 1571 | uint32_t rtp_ts; 1572 | uint32_t packet_count; 1573 | uint32_t octet_count; 1574 | }; 1575 | 1576 | static int rtsp_try_tx_rtcp_sr (struct rtsp_client_connection *cc, int isaudio, uint64_t ts) 1577 | { 1578 | struct rtsp_session *s = cc->session; 1579 | struct rtp_connection *rtp = isaudio ? cc->artp : cc->vrtp; 1580 | uint64_t ntptime_of_zero_ts = isaudio ? s->audio_ntptime_of_zero_ts : s->video_ntptime_of_zero_ts; 1581 | uint32_t sample_rate = isaudio ? s->artpe.sample_rate : s->vrtpe.sample_rate; 1582 | 1583 | struct rtcp_sr sr = {0}; 1584 | uint32_t ntpts_msw = 0; 1585 | uint32_t ntpts_lsw = 0; 1586 | uint32_t rtp_ts = 0; 1587 | int size = sizeof(sr); 1588 | 1589 | 1590 | if (rtp->rtcp_last_ts && ts < rtp->rtcp_last_ts + 5000000ULL) { 1591 | return 0; 1592 | } 1593 | 1594 | ntpts_msw = (uint32_t)((ntptime_of_zero_ts + ts) / 1000000ULL); 1595 | ntpts_lsw = (uint32_t)(((ntptime_of_zero_ts + ts) % 1000000ULL) * (1ULL << 32) / 1000000ULL); 1596 | rtp_ts = (uint32_t)(ts * sample_rate / 1000000ULL); 1597 | 1598 | sr.v = 2; 1599 | sr.p = 0; 1600 | sr.rc = 0; 1601 | sr.pt = 200; 1602 | sr.length = htons(size / 4 - 1); 1603 | sr.ssrc = htonl(rtp->ssrc); 1604 | sr.ntpts_msw = htonl(ntpts_msw); 1605 | sr.ntpts_lsw = htonl(ntpts_lsw); 1606 | sr.rtp_ts = htonl(rtp_ts); 1607 | sr.packet_count = htonl(rtp->rtcp_packet_count); 1608 | sr.octet_count = htonl(rtp->rtcp_octet_count); 1609 | 1610 | if (rtp->is_over_tcp) { 1611 | int ret = rtsp_send_interlaced_frame(cc, rtp->tcp_interleaved[1], (const uint8_t*)&sr, size); 1612 | if (ret != size) { 1613 | return ret; 1614 | } 1615 | } else { 1616 | struct sockaddr_in inaddr; 1617 | SOCKET sockfd = rtp->udp_sockfd[1]; 1618 | int ret = -1; 1619 | 1620 | memset(&inaddr, 0, sizeof(inaddr)); 1621 | inaddr.sin_family = AF_INET; 1622 | inaddr.sin_addr = rtp->peer_addr; 1623 | inaddr.sin_port = htons(rtp->udp_peerport[1]); 1624 | 1625 | ret = sendto(sockfd, (const char*)&sr, size, 0, (struct sockaddr*)&inaddr, sizeof(inaddr)); 1626 | if (ret == SOCKET_ERROR) { 1627 | if (sk_errno() != SK_EAGAIN && sk_errno() != SK_EINTR) { 1628 | warn("rtcp over udp send %d bytes to %s failed: %s. [peer %s:%u]\n", 1629 | size, inet_ntoa(rtp->peer_addr), sk_strerror(sk_errno()), 1630 | inet_ntoa(rtp->peer_addr), cc->peer_port); 1631 | return -1; 1632 | } 1633 | return 0; 1634 | } 1635 | } 1636 | 1637 | rtp->rtcp_last_ts = ts; 1638 | return size; 1639 | } 1640 | 1641 | int rtsp_do_event (rtsp_demo_handle demo) 1642 | { 1643 | struct rtsp_demo *d = (struct rtsp_demo*)demo; 1644 | struct rtsp_client_connection *cc = NULL; 1645 | struct timeval tv; 1646 | fd_set rfds; 1647 | fd_set wfds; 1648 | SOCKET maxfd; 1649 | int ret; 1650 | 1651 | if (NULL == d) { 1652 | return -1; 1653 | } 1654 | 1655 | FD_ZERO(&rfds); 1656 | FD_ZERO(&wfds); 1657 | 1658 | FD_SET(d->sockfd, &rfds); 1659 | 1660 | maxfd = d->sockfd; 1661 | TAILQ_FOREACH(cc, &d->connections_qhead, demo_entry) { 1662 | struct rtsp_session *s = cc->session; 1663 | struct rtp_connection *vrtp = cc->vrtp; 1664 | struct rtp_connection *artp = cc->artp; 1665 | 1666 | FD_SET(cc->sockfd, &rfds); 1667 | if (cc->sockfd > maxfd) 1668 | maxfd = cc->sockfd; 1669 | 1670 | if (cc->state != RTSP_CC_STATE_PLAYING) 1671 | continue; 1672 | 1673 | if (vrtp && streamq_inused(s->vstreamq, vrtp->streamq_index) > 0) { 1674 | //add video rtp sock to wfds 1675 | if (vrtp->is_over_tcp) { 1676 | FD_SET(cc->sockfd, &wfds); 1677 | } else { 1678 | FD_SET(vrtp->udp_sockfd[0], &wfds); 1679 | if (vrtp->udp_sockfd[0] > maxfd) 1680 | maxfd = vrtp->udp_sockfd[0]; 1681 | } 1682 | } 1683 | 1684 | if (artp && streamq_inused(s->astreamq, artp->streamq_index) > 0) { 1685 | //add audio rtp sock to wfds 1686 | if (artp->is_over_tcp) { 1687 | FD_SET(cc->sockfd, &wfds); 1688 | } else { 1689 | FD_SET(artp->udp_sockfd[0], &wfds); 1690 | if (artp->udp_sockfd[0] > maxfd) 1691 | maxfd = artp->udp_sockfd[0]; 1692 | } 1693 | } 1694 | 1695 | if (vrtp && (!vrtp->is_over_tcp)) { 1696 | //add video rtp/rtcp sock to rfds 1697 | FD_SET(vrtp->udp_sockfd[0], &rfds); 1698 | FD_SET(vrtp->udp_sockfd[1], &rfds); 1699 | if (vrtp->udp_sockfd[0] > maxfd) 1700 | maxfd = vrtp->udp_sockfd[0]; 1701 | if (vrtp->udp_sockfd[1] > maxfd) 1702 | maxfd = vrtp->udp_sockfd[1]; 1703 | } 1704 | 1705 | if (artp && (!artp->is_over_tcp)) { 1706 | //add audio rtp/rtcp sock to rfds 1707 | FD_SET(artp->udp_sockfd[0], &rfds); 1708 | FD_SET(artp->udp_sockfd[1], &rfds); 1709 | if (artp->udp_sockfd[0] > maxfd) 1710 | maxfd = artp->udp_sockfd[0]; 1711 | if (artp->udp_sockfd[1] > maxfd) 1712 | maxfd = artp->udp_sockfd[1]; 1713 | } 1714 | } 1715 | 1716 | memset(&tv, 0, sizeof(tv)); 1717 | tv.tv_sec = 0; 1718 | tv.tv_usec = 0; 1719 | 1720 | ret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); 1721 | if (ret < 0) { 1722 | err("select failed : %s\n", strerror(errno)); 1723 | return -1; 1724 | } 1725 | if (ret == 0) { 1726 | return 0; 1727 | } 1728 | 1729 | if (FD_ISSET(d->sockfd, &rfds)) { 1730 | //new client_connection 1731 | rtsp_new_client_connection(d); 1732 | } 1733 | 1734 | cc = TAILQ_FIRST(&d->connections_qhead); //NOTE do not use TAILQ_FOREACH 1735 | while (cc) { 1736 | struct rtsp_client_connection *cc1 = cc; 1737 | struct rtsp_session *s = cc1->session; 1738 | struct rtp_connection *vrtp = cc1->vrtp; 1739 | struct rtp_connection *artp = cc1->artp; 1740 | cc = TAILQ_NEXT(cc, demo_entry); 1741 | 1742 | if (FD_ISSET(cc1->sockfd, &rfds)) { 1743 | do { 1744 | rtsp_msg_s reqmsg, resmsg; 1745 | rtsp_msg_init(&reqmsg); 1746 | rtsp_msg_init(&resmsg); 1747 | 1748 | ret = rtsp_recv_msg(cc1, &reqmsg); 1749 | if (ret == 0) 1750 | break; 1751 | if (ret < 0) { 1752 | rtsp_del_client_connection(cc1); 1753 | cc1 = NULL; 1754 | break; 1755 | } 1756 | 1757 | if (reqmsg.type == RTSP_MSG_TYPE_INTERLEAVED) { 1758 | //TODO process RTCP over TCP frame 1759 | rtsp_msg_free(&reqmsg); 1760 | continue; 1761 | } 1762 | 1763 | if (reqmsg.type != RTSP_MSG_TYPE_REQUEST) { 1764 | err("not request frame.\n"); 1765 | rtsp_msg_free(&reqmsg); 1766 | continue; 1767 | } 1768 | 1769 | ret = rtsp_process_request(cc1, &reqmsg, &resmsg); 1770 | if (ret < 0) { 1771 | err("request internal err\n"); 1772 | } else { 1773 | rtsp_send_msg(cc1, &resmsg); 1774 | } 1775 | 1776 | rtsp_msg_free(&reqmsg); 1777 | rtsp_msg_free(&resmsg); 1778 | } while (cc1); 1779 | 1780 | if (cc1 == NULL) 1781 | continue; 1782 | } 1783 | 1784 | if (cc1->state != RTSP_CC_STATE_PLAYING) 1785 | continue; 1786 | 1787 | if (vrtp && streamq_inused(s->vstreamq, vrtp->streamq_index) > 0) { 1788 | //send rtp video packet 1789 | if (vrtp->is_over_tcp && FD_ISSET(cc1->sockfd, &wfds)) { 1790 | rtsp_tx_video_packet(cc1); 1791 | //dbg("resend video packet for tcp [peer %s:%u]\n", inet_ntoa(cc1->peer_addr), cc1->peer_port); 1792 | } else if ((!vrtp->is_over_tcp) && FD_ISSET(vrtp->udp_sockfd[0], &wfds)) { 1793 | rtsp_tx_video_packet(cc1); //very useful for udp 1794 | //dbg("resend video packet for udp [peer %s:%u]\n", inet_ntoa(cc1->peer_addr), cc1->peer_port); 1795 | } 1796 | } 1797 | 1798 | if (artp && streamq_inused(s->astreamq, artp->streamq_index) > 0) { 1799 | //send rtp audio packet 1800 | if (artp->is_over_tcp && FD_ISSET(cc1->sockfd, &wfds)) { 1801 | rtsp_tx_audio_packet(cc1); 1802 | //dbg("resend audio packet for tcp [peer %s:%u]\n", inet_ntoa(cc1->peer_addr), cc1->peer_port); 1803 | } else if (0 == artp->is_over_tcp && FD_ISSET(artp->udp_sockfd[0], &wfds)) { 1804 | rtsp_tx_audio_packet(cc1); //very useful for udp 1805 | //dbg("resend audio packet for udp [peer %s:%u]\n", inet_ntoa(cc1->peer_addr), cc1->peer_port); 1806 | } 1807 | } 1808 | 1809 | if (vrtp && (!vrtp->is_over_tcp)) { 1810 | //process video rtcp socket 1811 | if (FD_ISSET(vrtp->udp_sockfd[0], &rfds)) { 1812 | rtsp_recv_rtp_over_udp(cc1, 0); 1813 | } 1814 | if (FD_ISSET(vrtp->udp_sockfd[1], &rfds)) { 1815 | rtsp_recv_rtcp_over_udp(cc1, 0); 1816 | } 1817 | } 1818 | if (artp && (!artp->is_over_tcp)) { 1819 | //process audio rtcp socket 1820 | if (FD_ISSET(artp->udp_sockfd[0], &rfds)) { 1821 | rtsp_recv_rtp_over_udp(cc1, 1); 1822 | } 1823 | if (FD_ISSET(artp->udp_sockfd[1], &rfds)) { 1824 | rtsp_recv_rtcp_over_udp(cc1, 1); 1825 | } 1826 | } 1827 | } 1828 | 1829 | return 1; 1830 | } 1831 | 1832 | int rtsp_tx_video (rtsp_session_handle session, const uint8_t *frame, int len, uint64_t ts) 1833 | { 1834 | struct rtsp_session *s = (struct rtsp_session*) session; 1835 | struct stream_queue *q = NULL; 1836 | struct rtsp_client_connection *cc = NULL; 1837 | uint8_t *packets[VRTP_MAX_NBPKTS+1] = {NULL}; 1838 | int pktsizs[VRTP_MAX_NBPKTS+1] = {0}; 1839 | int *pktlens[VRTP_MAX_NBPKTS] = {NULL}; 1840 | int i, index, count, start; 1841 | 1842 | if (!s || !frame || s->vcodec_id == RTSP_CODEC_ID_NONE) 1843 | return -1; 1844 | 1845 | //XXX guess request the number of rtp packet for this frame. +4 for SPS+PPS+VPS+SEI+I frame 1846 | count = (len + RTP_MAX_PKTSIZ - 12 - 4 - 1) / (RTP_MAX_PKTSIZ - 12 - 4) + 4; 1847 | 1848 | //get free buffer 1849 | q = s->vstreamq; 1850 | index = streamq_tail(q); 1851 | for (i = 0; i < VRTP_MAX_NBPKTS && i < count; i++) { 1852 | if (streamq_next(q, index) == streamq_head(q)) 1853 | streamq_pop(q); 1854 | streamq_query(q, index, (char**)&packets[i], &pktlens[i]); 1855 | pktsizs[i] = RTP_MAX_PKTSIZ; 1856 | index = streamq_next(q, index); 1857 | } 1858 | packets[i] = NULL; 1859 | pktsizs[i] = 0; 1860 | 1861 | //move all slow rtp connections streamq_index to queue tail 1862 | TAILQ_FOREACH(cc, &s->connections_qhead, session_entry) { 1863 | struct rtp_connection *rtp = cc->vrtp; 1864 | if (cc->state != RTSP_CC_STATE_PLAYING || !rtp) 1865 | continue; 1866 | if (!streamq_inused(q, rtp->streamq_index) && rtp->streamq_index != streamq_tail(q)) { 1867 | rtp->streamq_index = streamq_head(q); 1868 | warn("client lost video packet [peer %s:%u]\n", inet_ntoa(cc->peer_addr), cc->peer_port); 1869 | } 1870 | } 1871 | 1872 | switch (s->vcodec_id) { 1873 | case RTSP_CODEC_ID_VIDEO_H264: 1874 | if (s->vcodec_data.h264.pps_len == 0 || s->vcodec_data.h264.pps_len == 0) { 1875 | if (rtsp_codec_data_parse_from_frame_h264(frame, len, &s->vcodec_data.h264) < 0) { 1876 | warn("rtsp_codec_data_parse_from_frame_h264 failed\n"); 1877 | } else { 1878 | // dbg("rtsp_codec_data_parse_from_frame_h264 sps:%u pps:%u success\n", 1879 | // s->vcodec_data.h264.sps_len, s->vcodec_data.h264.pps_len); 1880 | } 1881 | } 1882 | break; 1883 | case RTSP_CODEC_ID_VIDEO_H265: 1884 | if (s->vcodec_data.h265.pps_len == 0 || s->vcodec_data.h265.pps_len == 0 || s->vcodec_data.h265.vps_len == 0) { 1885 | if (rtsp_codec_data_parse_from_frame_h265(frame, len, &s->vcodec_data.h265) < 0) { 1886 | warn("rtsp_codec_data_parse_from_frame_h265 failed\n"); 1887 | } else { 1888 | // dbg("rtsp_codec_data_parse_from_frame_h265 vps:%u sps:%u pps:%u success\n", 1889 | // s->vcodec_data.h265.vps, s->vcodec_data.h265.sps_len, s->vcodec_data.h265.pps_len); 1890 | } 1891 | } 1892 | break; 1893 | } 1894 | 1895 | start = 0; 1896 | count = 0; 1897 | while (start < len && packets[count] && pktsizs[count] > 0) { 1898 | const uint8_t *p = NULL; 1899 | int size = 0; 1900 | int ret; 1901 | 1902 | p = rtsp_find_h264_h265_nalu(frame + start, len - start, &size); 1903 | if (!p) { 1904 | warn("not found nal header\n"); 1905 | break; 1906 | } 1907 | //dbg("size:%d\n", size); 1908 | 1909 | switch (s->vcodec_id) { 1910 | case RTSP_CODEC_ID_VIDEO_H264: 1911 | ret = rtp_enc_h264(&s->vrtpe, p, size, ts, &packets[count], &pktsizs[count]); 1912 | if (ret <= 0) { 1913 | err("rtp_enc_h264 ret = %d\n", ret); 1914 | return -1; 1915 | } 1916 | break; 1917 | case RTSP_CODEC_ID_VIDEO_H265: 1918 | ret = rtp_enc_h265(&s->vrtpe, p, size, ts, &packets[count], &pktsizs[count]); 1919 | if (ret <= 0) { 1920 | err("rtp_enc_h265 ret = %d\n", ret); 1921 | return -1; 1922 | } 1923 | break; 1924 | } 1925 | 1926 | count += ret; 1927 | start = p - frame + size; 1928 | } 1929 | 1930 | for (i = 0; i < count; i++) { 1931 | *pktlens[i] = pktsizs[i]; 1932 | streamq_push(q); 1933 | } 1934 | 1935 | //first send 1936 | TAILQ_FOREACH(cc, &s->connections_qhead, session_entry) { 1937 | struct rtp_connection *rtp = cc->vrtp; 1938 | if (cc->state != RTSP_CC_STATE_PLAYING || !rtp) 1939 | continue; 1940 | 1941 | rtsp_try_tx_rtcp_sr(cc, 0, ts); 1942 | rtsp_tx_video_packet(cc); 1943 | } 1944 | 1945 | return len; 1946 | } 1947 | 1948 | int rtsp_tx_audio (rtsp_session_handle session, const uint8_t *frame, int len, uint64_t ts) 1949 | { 1950 | struct rtsp_session *s = (struct rtsp_session*) session; 1951 | struct stream_queue *q = NULL; 1952 | struct rtsp_client_connection *cc = NULL; 1953 | uint8_t *packets[ARTP_MAX_NBPKTS+1] = {NULL}; 1954 | int pktsizs[ARTP_MAX_NBPKTS+1] = {0}; 1955 | int *pktlens[ARTP_MAX_NBPKTS] = {NULL}; 1956 | int i, index, count; 1957 | 1958 | if (!s || !frame || s->acodec_id == RTSP_CODEC_ID_NONE) 1959 | return -1; 1960 | 1961 | //XXX guess request the number of rtp packet for this frame 1962 | count = (len + RTP_MAX_PKTSIZ - 12 - 4 - 1) / (RTP_MAX_PKTSIZ - 12 - 4); 1963 | 1964 | //get free buffer 1965 | q = s->astreamq; 1966 | index = streamq_tail(q); 1967 | for (i = 0; i < ARTP_MAX_NBPKTS && i < count; i++) { 1968 | if (streamq_next(q, index) == streamq_head(q)) 1969 | streamq_pop(q); 1970 | streamq_query(q, index, (char**)&packets[i], &pktlens[i]); 1971 | pktsizs[i] = RTP_MAX_PKTSIZ; 1972 | index = streamq_next(q, index); 1973 | } 1974 | packets[i] = NULL; 1975 | pktsizs[i] = 0; 1976 | 1977 | //move all slow rtp connections streamq_index to queue tail 1978 | TAILQ_FOREACH(cc, &s->connections_qhead, session_entry) { 1979 | struct rtp_connection *rtp = cc->artp; 1980 | if (cc->state != RTSP_CC_STATE_PLAYING || !rtp) 1981 | continue; 1982 | if (!streamq_inused(q, rtp->streamq_index) && rtp->streamq_index != streamq_tail(q)) { 1983 | rtp->streamq_index = streamq_head(q); 1984 | warn("client lost audio packet [peer %s:%u]\n", inet_ntoa(cc->peer_addr), cc->peer_port); 1985 | } 1986 | } 1987 | 1988 | switch (s->acodec_id) { 1989 | case RTSP_CODEC_ID_AUDIO_G711A: 1990 | case RTSP_CODEC_ID_AUDIO_G711U: 1991 | count = rtp_enc_g711(&s->artpe, frame, len, ts, packets, pktsizs); 1992 | if (count <= 0) { 1993 | err("rtp_enc_g711 ret = %d\n", count); 1994 | return -1; 1995 | } 1996 | break; 1997 | case RTSP_CODEC_ID_AUDIO_G726: 1998 | count = rtp_enc_g726(&s->artpe, frame, len, ts, packets, pktsizs); 1999 | if (count <= 0) { 2000 | err("rtp_enc_g726 ret = %d\n", count); 2001 | return -1; 2002 | } 2003 | break; 2004 | case RTSP_CODEC_ID_AUDIO_AAC: 2005 | if (s->acodec_data.aac.audio_specific_config_len == 0) { 2006 | if (rtsp_codec_data_parse_from_frame_aac(frame, len, &s->acodec_data.aac) < 0) { 2007 | // warn("rtsp_codec_data_parse_from_frame_aac failed\n"); 2008 | } else { 2009 | // dbg("rtsp_codec_data_parse_from_frame_aac success\n"); 2010 | s->artpe.sample_rate = s->acodec_data.aac.sample_rate; 2011 | } 2012 | } 2013 | count = rtp_enc_aac(&s->artpe, frame, len, ts, packets, pktsizs); 2014 | if (count <= 0) { 2015 | err("rtp_enc_aac ret = %d\n", count); 2016 | return -1; 2017 | } 2018 | break; 2019 | } 2020 | 2021 | for (i = 0; i < count; i++) { 2022 | *pktlens[i] = pktsizs[i]; 2023 | streamq_push(q); 2024 | } 2025 | 2026 | //first send 2027 | TAILQ_FOREACH(cc, &s->connections_qhead, session_entry) { 2028 | struct rtp_connection *rtp = cc->artp; 2029 | if (cc->state != RTSP_CC_STATE_PLAYING || !rtp) 2030 | continue; 2031 | 2032 | rtsp_try_tx_rtcp_sr(cc, 1, ts); 2033 | rtsp_tx_audio_packet(cc); 2034 | } 2035 | 2036 | return len; 2037 | } 2038 | 2039 | //return us from system running 2040 | uint64_t rtsp_get_reltime (void) 2041 | { 2042 | #ifdef __WIN32__ 2043 | return (timeGetTime() * 1000ULL); 2044 | #endif 2045 | #ifdef __LINUX__ 2046 | struct timespec tp; 2047 | clock_gettime(CLOCK_MONOTONIC, &tp); 2048 | return (tp.tv_sec * 1000000ULL + tp.tv_nsec / 1000ULL); 2049 | #endif 2050 | } 2051 | 2052 | //return us from 1970/1/1 00:00:00 2053 | static uint64_t rtsp_get_abstime (void) 2054 | { 2055 | #ifdef __WIN32__ 2056 | FILETIME ft; 2057 | uint64_t t; 2058 | GetSystemTimeAsFileTime(&ft); 2059 | t = (uint64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime; 2060 | return t / 10 - 11644473600000000ULL; 2061 | #endif 2062 | #ifdef __LINUX__ 2063 | struct timeval tv; 2064 | gettimeofday(&tv, NULL); 2065 | return (tv.tv_sec * 1000000ULL + tv.tv_usec); 2066 | #endif 2067 | } 2068 | 2069 | //return us from 1900/1/1 00:00:00 2070 | uint64_t rtsp_get_ntptime (void) 2071 | { 2072 | #define NTP_OFFSET_US (2208988800000000ULL) 2073 | return (rtsp_get_abstime() + NTP_OFFSET_US); 2074 | } 2075 | 2076 | int rtsp_sync_video_ts (rtsp_session_handle session, uint64_t ts, uint64_t ntptime) 2077 | { 2078 | struct rtsp_session *s = (struct rtsp_session*) session; 2079 | 2080 | if (!s || s->vcodec_id == RTSP_CODEC_ID_NONE) 2081 | return -1; 2082 | 2083 | s->video_ntptime_of_zero_ts = ntptime - ts; //XXX 2084 | return 0; 2085 | } 2086 | 2087 | int rtsp_sync_audio_ts (rtsp_session_handle session, uint64_t ts, uint64_t ntptime) 2088 | { 2089 | struct rtsp_session *s = (struct rtsp_session*) session; 2090 | 2091 | if (!s || s->acodec_id == RTSP_CODEC_ID_NONE) 2092 | return -1; 2093 | 2094 | s->audio_ntptime_of_zero_ts = ntptime - ts; //XXX 2095 | return 0; 2096 | } 2097 | 2098 | -------------------------------------------------------------------------------- /rtsp_demo.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: rtsp_demo.h 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Monday, November 23, 2015 AM12:22:43 CST 6 | ************************************************************************/ 7 | 8 | #ifndef __RTSP_DEMO_H__ 9 | #define __RTSP_DEMO_H__ 10 | /* 11 | * a simple RTSP server demo 12 | * RTP over UDP/TCP H264/G711a 13 | * */ 14 | 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | enum rtsp_codec_id { 22 | RTSP_CODEC_ID_NONE = 0, 23 | RTSP_CODEC_ID_VIDEO_H264 = 0x0001, /*codec_data is SPS + PPS frames*/ 24 | RTSP_CODEC_ID_VIDEO_H265, /*codec_data is VPS + SPS + PPS frames*/ 25 | RTSP_CODEC_ID_VIDEO_MPEG4, /*now not support*/ 26 | RTSP_CODEC_ID_VIDEO_MJPEG, /*now not support*/ 27 | RTSP_CODEC_ID_AUDIO_G711A = 0x4001, /*codec_data is NULL*/ 28 | RTSP_CODEC_ID_AUDIO_G711U, /*codec_data is NULL*/ 29 | RTSP_CODEC_ID_AUDIO_G726, /*codec_data is bitrate (int)*/ 30 | RTSP_CODEC_ID_AUDIO_AAC, /*codec_data is audio specific config (2bytes). frame type is ADTS*/ 31 | }; 32 | 33 | enum rtsp_auth_type { 34 | RTSP_AUTH_TYPE_NONE = 0, 35 | RTSP_AUTH_TYPE_BASIC, 36 | RTSP_AUTH_TYPE_DIGEST, /*now not support*/ 37 | }; 38 | 39 | typedef void * rtsp_demo_handle; 40 | typedef void * rtsp_session_handle; 41 | 42 | rtsp_demo_handle rtsp_new_demo (int port); 43 | int rtsp_do_event (rtsp_demo_handle demo); 44 | rtsp_session_handle rtsp_new_session (rtsp_demo_handle demo, const char *path); 45 | int rtsp_set_auth (rtsp_session_handle session, int type, const char *user, const char *passwd); 46 | int rtsp_set_video (rtsp_session_handle session, int codec_id, const uint8_t *codec_data, int data_len); 47 | int rtsp_set_audio (rtsp_session_handle session, int codec_id, const uint8_t *codec_data, int data_len); 48 | int rtsp_tx_video (rtsp_session_handle session, const uint8_t *frame, int len, uint64_t ts); 49 | int rtsp_tx_audio (rtsp_session_handle session, const uint8_t *frame, int len, uint64_t ts); 50 | void rtsp_del_session (rtsp_session_handle session); 51 | void rtsp_del_demo (rtsp_demo_handle demo); 52 | 53 | uint64_t rtsp_get_reltime (void); 54 | uint64_t rtsp_get_ntptime (void); 55 | int rtsp_sync_video_ts (rtsp_session_handle session, uint64_t ts, uint64_t ntptime); 56 | int rtsp_sync_audio_ts (rtsp_session_handle session, uint64_t ts, uint64_t ntptime); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | #endif 62 | -------------------------------------------------------------------------------- /rtsp_msg.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: rtsp_msg.c 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Friday, December 11, 2015 AM05:02:48 CST 6 | ************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "comm.h" 15 | #include "rtsp_msg.h" 16 | 17 | 18 | void *rtsp_mem_alloc (int size) 19 | { 20 | if (size > 0) 21 | return calloc(1, size); 22 | return NULL; 23 | } 24 | 25 | void rtsp_mem_free (void *ptr) 26 | { 27 | if (ptr) 28 | free(ptr); 29 | } 30 | 31 | void *rtsp_mem_dup (const void *ptr, int size) 32 | { 33 | void *ptr1 = calloc(1, size); 34 | if (ptr1 && ptr) 35 | memcpy(ptr1, ptr, size); 36 | return ptr1; 37 | } 38 | 39 | char *rtsp_str_dup (const char *str) 40 | { 41 | int len = strlen(str); 42 | char *str1 = (char*) calloc(1, len + 1); 43 | if (str1 && str) 44 | memcpy(str1, str, len); 45 | return str1; 46 | } 47 | 48 | #define ARRAY_SIZE(_arr) (sizeof(_arr)/sizeof(_arr[0])) 49 | 50 | typedef struct __rtsp_msg_int2str_tbl_s 51 | { 52 | int intval; 53 | int strsiz; 54 | const char *strval; 55 | } rtsp_msg_int2str_tbl_s; 56 | 57 | static const char *rtsp_msg_int2str (const rtsp_msg_int2str_tbl_s *tbl, int num, int intval) 58 | { 59 | int i; 60 | for (i = 0; i < num; i++) { 61 | if (intval == tbl[i].intval) 62 | return tbl[i].strval; 63 | } 64 | return tbl[num-1].strval; 65 | } 66 | 67 | static int rtsp_msg_str2int (const rtsp_msg_int2str_tbl_s *tbl, int num, const char *str) 68 | { 69 | int i; 70 | for (i = 0; i < num; i++) { 71 | if (strncmp(tbl[i].strval, str, tbl[i].strsiz) == 0) 72 | return tbl[i].intval; 73 | } 74 | return tbl[num-1].intval; 75 | } 76 | 77 | static const rtsp_msg_int2str_tbl_s rtsp_msg_method_tbl[] = { 78 | { RTSP_MSG_METHOD_OPTIONS, 7, "OPTIONS", }, 79 | { RTSP_MSG_METHOD_DESCRIBE, 8, "DESCRIBE", }, 80 | { RTSP_MSG_METHOD_SETUP, 5, "SETUP", }, 81 | { RTSP_MSG_METHOD_PLAY, 4, "PLAY", }, 82 | { RTSP_MSG_METHOD_RECORD, 6, "RECORD", }, 83 | { RTSP_MSG_METHOD_PAUSE, 5, "PAUSE", }, 84 | { RTSP_MSG_METHOD_TEARDOWN, 8, "TEARDOWN", }, 85 | { RTSP_MSG_METHOD_ANNOUNCE, 8, "ANNOUNCE", }, 86 | { RTSP_MSG_METHOD_SET_PARAMETER, 13, "SET_PARAMETER", }, 87 | { RTSP_MSG_METHOD_GET_PARAMETER, 13, "GET_PARAMETER", }, 88 | { RTSP_MSG_METHOD_REDIRECT, 8, "REDIRECT", }, 89 | { RTSP_MSG_METHOD_BUTT, 0, "", }, 90 | }; 91 | 92 | static const rtsp_msg_int2str_tbl_s rtsp_msg_uri_scheme_tbl[] = { 93 | {RTSP_MSG_URI_SCHEME_RTSPU, 6, "rtspu:"}, 94 | {RTSP_MSG_URI_SCHEME_RTSP, 5, "rtsp:"}, 95 | {RTSP_MSG_URI_SCHEME_BUTT, 0, ""}, 96 | }; 97 | 98 | static const rtsp_msg_int2str_tbl_s rtsp_msg_version_tbl[] = { 99 | {RTSP_MSG_VERSION_1_0, 8, "RTSP/1.0"}, 100 | {RTSP_MSG_VERSION_BUTT, 0, ""}, 101 | }; 102 | 103 | static const rtsp_msg_int2str_tbl_s rtsp_msg_status_code_tbl[] = { 104 | {100, 0, "Continue"}, 105 | {200, 0, "OK"}, 106 | {201, 0, "Created"}, 107 | {250, 0, "Low on Storage Space"}, 108 | {300, 0, "Multiple Choices"}, 109 | {301, 0, "Moved Permanently"}, 110 | {302, 0, "Moved Temporarily"}, 111 | {303, 0, "See Other"}, 112 | {305, 0, "Use Proxy"}, 113 | {400, 0, "Bad Request"}, 114 | {401, 0, "Unauthorized"}, 115 | {402, 0, "Payment Required"}, 116 | {403, 0, "Forbidden"}, 117 | {404, 0, "Not Found"}, 118 | {405, 0, "Method Not Allowed"}, 119 | {406, 0, "Not Acceptable"}, 120 | {407, 0, "Proxy Authentication Required"}, 121 | {408, 0, "Request Timeout"}, 122 | {410, 0, "Gone"}, 123 | {411, 0, "Length Required"}, 124 | {412, 0, "Precondition Failed"}, 125 | {413, 0, "Request Entity Too Large"}, 126 | {414, 0, "Request-URI Too Long"}, 127 | {415, 0, "Unsupported Media Type"}, 128 | {451, 0, "Invalid parameter"}, 129 | {452, 0, "Illegal Conference Identifier"}, 130 | {453, 0, "Not Enough Bandwidth"}, 131 | {454, 0, "Session Not Found"}, 132 | {455, 0, "Method Not Valid In This State"}, 133 | {456, 0, "Header Field Not Valid"}, 134 | {457, 0, "Invalid Range"}, 135 | {458, 0, "Parameter Is Read-Only"}, 136 | {459, 0, "Aggregate Operation Not Allowed"}, 137 | {460, 0, "Only Aggregate Operation Allowed"}, 138 | {461, 0, "Unsupported Transport"}, 139 | {462, 0, "Destination Unreachable"}, 140 | {500, 0, "Internal Server Error"}, 141 | {501, 0, "Not Implemented"}, 142 | {502, 0, "Bad Gateway"}, 143 | {503, 0, "Service Unavailable"}, 144 | {504, 0, "Gateway Timeout"}, 145 | {505, 0, "RTSP Version Not Supported"}, 146 | {551, 0, "Option not support"}, 147 | }; 148 | 149 | static const rtsp_msg_int2str_tbl_s rtsp_msg_transport_type_tbl[] = { 150 | {RTSP_MSG_TRANSPORT_TYPE_RTP_AVP_TCP, 11, "RTP/AVP/TCP"}, 151 | {RTSP_MSG_TRANSPORT_TYPE_RTP_AVP, 7, "RTP/AVP"}, 152 | {RTSP_MSG_TRANSPORT_TYPE_BUTT, 0, ""}, 153 | }; 154 | 155 | static const rtsp_msg_int2str_tbl_s rtsp_msg_content_type_tbl[] = { 156 | {RTSP_MSG_CONTENT_TYPE_SDP, 15, "application/sdp"}, 157 | {RTSP_MSG_CONTENT_TYPE_RTSL, 16, "application/rtsl"}, 158 | {RTSP_MSG_CONTENT_TYPE_MHEG, 16, "application/mheg"}, 159 | {RTSP_MSG_CONTENT_TYPE_BUTT, 0, ""}, 160 | }; 161 | 162 | static int rtsp_msg_parse_uri (const char *line, rtsp_msg_uri_s *uri) 163 | { 164 | const char *p = line, *q; 165 | unsigned int tmp; 166 | 167 | uri->scheme = (rtsp_msg_uri_scheme_e) rtsp_msg_str2int(rtsp_msg_uri_scheme_tbl, 168 | ARRAY_SIZE(rtsp_msg_uri_scheme_tbl), line); 169 | if (uri->scheme == RTSP_MSG_URI_SCHEME_BUTT) { 170 | err("parse scheme failed. line: %s\n", line); 171 | return -1; 172 | } 173 | uri->port = 0; //default 174 | uri->ipaddr[0] = 0; 175 | uri->abspath[0] = 0; 176 | 177 | while (islower(*p) || *p == ':') p++; 178 | if (*p != '/' || *(p+1) != '/') { 179 | err("parse ip failed. line: %s\n", line); 180 | return -1; 181 | } 182 | p += 2; 183 | 184 | q = p; 185 | while (isgraph(*q) && *q != ':' && *q != '/') q++; 186 | if (*q == ':') { 187 | if (sscanf(q + 1, "%u", &tmp) != 1) { 188 | err("parse uri port failed. line: %s\n", line); 189 | return -1; 190 | } 191 | uri->port = tmp; 192 | } 193 | tmp = q - p; 194 | if (tmp > sizeof(uri->ipaddr) - 1) 195 | tmp = sizeof(uri->ipaddr) - 1; 196 | memcpy(uri->ipaddr, p, tmp); 197 | uri->ipaddr[tmp] = 0; 198 | 199 | while (isgraph(*q) && *q != '/') q++; 200 | if (*q != '/') 201 | return (q - line); 202 | 203 | p = q; 204 | while (isgraph(*q)) q++; 205 | tmp = q - p; 206 | if (tmp > sizeof(uri->abspath) - 1) 207 | tmp = sizeof(uri->abspath) - 1; 208 | memcpy(uri->abspath, p, tmp); 209 | uri->abspath[tmp] = 0; 210 | 211 | return (q - line); 212 | } 213 | 214 | static int rtsp_msg_build_uri (const rtsp_msg_uri_s *uri, char *line, int size) 215 | { 216 | if (uri->port) 217 | snprintf(line, size, "%s//%s:%u%s", 218 | rtsp_msg_int2str(rtsp_msg_uri_scheme_tbl, 219 | ARRAY_SIZE(rtsp_msg_uri_scheme_tbl), uri->scheme), 220 | uri->ipaddr, uri->port, uri->abspath); 221 | else 222 | snprintf(line, size, "%s//%s%s", 223 | rtsp_msg_int2str(rtsp_msg_uri_scheme_tbl, 224 | ARRAY_SIZE(rtsp_msg_uri_scheme_tbl), uri->scheme), 225 | uri->ipaddr, uri->abspath); 226 | return strlen(line); 227 | } 228 | 229 | //return 0. if success 230 | static int rtsp_msg_parse_startline (rtsp_msg_s *msg, const char *line) 231 | { 232 | const char *p = line; 233 | int ret; 234 | ret = rtsp_msg_str2int(rtsp_msg_method_tbl, 235 | ARRAY_SIZE(rtsp_msg_method_tbl), p); 236 | if (ret != RTSP_MSG_METHOD_BUTT) { 237 | msg->type = RTSP_MSG_TYPE_REQUEST; 238 | msg->hdrs.startline.reqline.method = (rtsp_msg_method_e) ret; 239 | while (isgraph(*p)) p++; p++; //next field 240 | ret = rtsp_msg_parse_uri(p, &msg->hdrs.startline.reqline.uri); 241 | if (ret <= 0) 242 | return -1; 243 | while (isgraph(*p)) p++; p++; //next field 244 | ret = rtsp_msg_str2int(rtsp_msg_version_tbl, 245 | ARRAY_SIZE(rtsp_msg_version_tbl), p); 246 | if (ret == RTSP_MSG_VERSION_BUTT) { 247 | err("parse version failed. line: %s\n", line); 248 | return -1; 249 | } 250 | return 0; 251 | } 252 | 253 | ret = rtsp_msg_str2int(rtsp_msg_version_tbl, 254 | ARRAY_SIZE(rtsp_msg_version_tbl), p); 255 | if (ret != RTSP_MSG_VERSION_BUTT) { 256 | msg->type = RTSP_MSG_TYPE_RESPONSE; 257 | msg->hdrs.startline.resline.version = (rtsp_msg_version_e) ret; 258 | while (isgraph(*p)) p++; p++; //next field 259 | if (sscanf(p, "%d", &ret) != 1) { 260 | err("parse status-code failed. line: %s\n", line); 261 | return -1; 262 | } 263 | msg->hdrs.startline.resline.status_code = ret; 264 | return 0; 265 | } 266 | 267 | if (*p != '$') { 268 | err("parse startline failed: %s\n", line); 269 | return -1; 270 | } 271 | 272 | msg->type = RTSP_MSG_TYPE_INTERLEAVED; 273 | msg->hdrs.startline.interline.channel = *((uint8_t*)(p+1)); 274 | msg->hdrs.startline.interline.length = *((uint16_t*)(p+2)); //XXX 275 | msg->hdrs.startline.interline.reserved = 0; 276 | return 0; 277 | } 278 | 279 | static int rtsp_msg_build_startline (const rtsp_msg_s *msg, char *line, int size) 280 | { 281 | char *p = line; 282 | int ret; 283 | 284 | if (msg->type == RTSP_MSG_TYPE_REQUEST) { 285 | snprintf(line, size, "%s ", 286 | rtsp_msg_int2str(rtsp_msg_method_tbl, 287 | ARRAY_SIZE(rtsp_msg_method_tbl), 288 | msg->hdrs.startline.reqline.method)); 289 | ret = strlen(p); 290 | p += ret; 291 | size -= ret; 292 | if (size <= 1) 293 | return (p - line); 294 | 295 | ret = rtsp_msg_build_uri(&msg->hdrs.startline.reqline.uri, 296 | p, size); 297 | p += ret; 298 | size -= ret; 299 | if (size <= 1) 300 | return (p - line); 301 | 302 | snprintf(p, size, " %s\r\n", 303 | rtsp_msg_int2str(rtsp_msg_version_tbl, 304 | ARRAY_SIZE(rtsp_msg_version_tbl), 305 | msg->hdrs.startline.reqline.version)); 306 | p += strlen(p); 307 | return (p - line); 308 | } 309 | 310 | if (msg->type == RTSP_MSG_TYPE_RESPONSE) { 311 | snprintf(p, size, "%s %u %s\r\n", 312 | rtsp_msg_int2str(rtsp_msg_version_tbl, 313 | ARRAY_SIZE(rtsp_msg_version_tbl), 314 | msg->hdrs.startline.resline.version), 315 | msg->hdrs.startline.resline.status_code, 316 | rtsp_msg_int2str(rtsp_msg_status_code_tbl, 317 | ARRAY_SIZE(rtsp_msg_status_code_tbl), 318 | msg->hdrs.startline.resline.status_code)); 319 | return strlen(p); 320 | } 321 | 322 | return 0; 323 | } 324 | 325 | //Transport 326 | static int rtsp_msg_parse_transport (rtsp_msg_s *msg, const char *line) 327 | { 328 | rtsp_msg_hdr_s *hdrs = &msg->hdrs; 329 | const char *p; 330 | unsigned int tmp; 331 | 332 | if (hdrs->transport) { 333 | rtsp_mem_free(hdrs->transport); 334 | hdrs->transport = NULL; 335 | } 336 | 337 | hdrs->transport = (rtsp_msg_transport_s *) rtsp_mem_alloc(sizeof(rtsp_msg_transport_s)); 338 | if (!hdrs->transport) { 339 | err("rtsp_mem_alloc for %s failed\n", "rtsp_msg_transport_s"); 340 | return -1; 341 | } 342 | 343 | p = strstr(line, "RTP/AVP"); 344 | if (!p) { 345 | err("parse transport failed. line: %s\n", line); 346 | rtsp_mem_free(hdrs->transport); 347 | hdrs->transport = NULL; 348 | return -1; 349 | } 350 | hdrs->transport->type = (rtsp_msg_transport_type_e) rtsp_msg_str2int( 351 | rtsp_msg_transport_type_tbl, 352 | ARRAY_SIZE(rtsp_msg_transport_type_tbl), p); 353 | 354 | if ((p=strstr(line, "ssrc="))) { 355 | if (sscanf(p, "ssrc=%X", &tmp) == 1) { 356 | hdrs->transport->flags |= RTSP_MSG_TRANSPORT_FLAG_SSRC; 357 | hdrs->transport->ssrc = tmp; 358 | } 359 | } 360 | 361 | if ((p=strstr(line, "unicast"))) { 362 | hdrs->transport->flags |= RTSP_MSG_TRANSPORT_FLAG_UNICAST; 363 | } 364 | if ((p=strstr(line, "multicast"))) { 365 | hdrs->transport->flags |= RTSP_MSG_TRANSPORT_FLAG_MULTICAST; 366 | } 367 | 368 | if ((p=strstr(line, "client_port="))) { 369 | if (sscanf(p, "client_port=%u-%*u", &tmp) == 1) { 370 | hdrs->transport->flags |= RTSP_MSG_TRANSPORT_FLAG_CLIENT_PORT; 371 | hdrs->transport->client_port = tmp; 372 | } 373 | } 374 | 375 | if ((p=strstr(line, "server_port="))) { 376 | if (sscanf(p, "server_port=%u-%*u", &tmp) == 1) { 377 | hdrs->transport->flags |= RTSP_MSG_TRANSPORT_FLAG_SERVER_PORT; 378 | hdrs->transport->server_port = tmp; 379 | } 380 | } 381 | 382 | if ((p=strstr(line, "interleaved="))) { 383 | if (sscanf(p, "interleaved=%u-%*u", &tmp) == 1) { 384 | hdrs->transport->flags |= RTSP_MSG_TRANSPORT_FLAG_INTERLEAVED; 385 | hdrs->transport->interleaved = tmp; 386 | } 387 | } 388 | return 0; 389 | } 390 | 391 | static int rtsp_msg_build_transport (const rtsp_msg_s *msg, char *line, int size) 392 | { 393 | const rtsp_msg_hdr_s *hdrs = &msg->hdrs; 394 | if (hdrs->transport) { 395 | char *p = line; 396 | int len; 397 | snprintf(p, size, "Transport: %s", rtsp_msg_int2str(rtsp_msg_transport_type_tbl, 398 | ARRAY_SIZE(rtsp_msg_transport_type_tbl), hdrs->transport->type)); 399 | #define TRANSPORT_BUILD_STEP() \ 400 | len = strlen(p); \ 401 | p += len; \ 402 | size -= len; \ 403 | if (size <= 1) { \ 404 | return (p - line); \ 405 | } 406 | TRANSPORT_BUILD_STEP(); 407 | 408 | if (hdrs->transport->flags & RTSP_MSG_TRANSPORT_FLAG_SSRC) { 409 | snprintf(p, size, ";ssrc=%08X", hdrs->transport->ssrc); 410 | TRANSPORT_BUILD_STEP(); 411 | } 412 | 413 | if (hdrs->transport->flags & RTSP_MSG_TRANSPORT_FLAG_MULTICAST) { 414 | snprintf(p, size, ";multicast"); 415 | TRANSPORT_BUILD_STEP(); 416 | } else if (hdrs->transport->flags & RTSP_MSG_TRANSPORT_FLAG_UNICAST) { 417 | snprintf(p, size, ";unicast"); 418 | TRANSPORT_BUILD_STEP(); 419 | } 420 | 421 | if (hdrs->transport->flags & RTSP_MSG_TRANSPORT_FLAG_CLIENT_PORT) { 422 | snprintf(p, size, ";client_port=%u-%u", 423 | hdrs->transport->client_port, 424 | hdrs->transport->client_port + 1); 425 | TRANSPORT_BUILD_STEP(); 426 | } 427 | 428 | if (hdrs->transport->flags & RTSP_MSG_TRANSPORT_FLAG_SERVER_PORT) { 429 | snprintf(p, size, ";server_port=%u-%u", 430 | hdrs->transport->server_port, 431 | hdrs->transport->server_port + 1); 432 | TRANSPORT_BUILD_STEP(); 433 | } 434 | 435 | if (hdrs->transport->flags & RTSP_MSG_TRANSPORT_FLAG_INTERLEAVED) { 436 | snprintf(p, size, ";interleaved=%u-%u", 437 | hdrs->transport->interleaved, 438 | hdrs->transport->interleaved + 1); 439 | TRANSPORT_BUILD_STEP(); 440 | } 441 | 442 | snprintf(p, size, "\r\n"); 443 | TRANSPORT_BUILD_STEP(); 444 | return (p - line); 445 | } 446 | return 0; 447 | } 448 | 449 | //Range 450 | static int rtsp_msg_parse_range (rtsp_msg_s *msg, const char *line) 451 | { 452 | return 0;//TODO 453 | } 454 | 455 | static int rtsp_msg_build_range (const rtsp_msg_s *msg, char *line, int size) 456 | { 457 | return 0;//TODO 458 | } 459 | 460 | //Authorization 461 | static int rtsp_msg_parse_auth (rtsp_msg_s *msg, const char *line) 462 | { 463 | rtsp_msg_hdr_s *hdrs = &msg->hdrs; 464 | const char *p = line; 465 | unsigned int tmp = 0; 466 | 467 | if (hdrs->auth) { 468 | rtsp_mem_free(hdrs->auth); 469 | hdrs->auth = NULL; 470 | } 471 | hdrs->auth = (rtsp_msg_auth_s*) rtsp_mem_alloc(sizeof(rtsp_msg_auth_s)); 472 | if (!hdrs->auth) { 473 | err("rtsp_mem_alloc for %s failed\n", "rtsp_msg_auth_s"); 474 | return -1; 475 | } 476 | 477 | while (isgraph(*p) && *p != ':') p++; 478 | if (*p != ':') { 479 | rtsp_mem_free(hdrs->auth); 480 | hdrs->auth = NULL; 481 | err("parse %s failed. line: %s\n", "rtsp_msg_auth_s", line); 482 | return -1; 483 | } 484 | p++; 485 | while (*p == ' ') p++; 486 | if (0 == strncmp(p, "Basic ", 6)) { 487 | hdrs->auth->type = RTSP_MSG_AUTH_TYPE_BASIC; 488 | p += 6; 489 | while (isgraph(*p) && tmp < sizeof(hdrs->auth->basic_b64) - 1) { 490 | hdrs->auth->basic_b64[tmp++] = *p++; 491 | } 492 | hdrs->auth->basic_b64[tmp] = 0; 493 | } else if (0 == strncmp(p, "Digest ", 7)) { 494 | hdrs->auth->type = RTSP_MSG_AUTH_TYPE_DIGEST; 495 | //TODO 496 | } else { 497 | rtsp_mem_free(hdrs->auth); 498 | hdrs->auth = NULL; 499 | err("parse %s failed. line: %s\n", "rtsp_msg_auth_s", line); 500 | return -1; 501 | } 502 | return 0; 503 | } 504 | 505 | static int rtsp_msg_build_auth (const rtsp_msg_s *msg, char *line, int size) 506 | { 507 | return 0;//TODO 508 | } 509 | 510 | //WWW-Authorization 511 | static int rtsp_msg_parse_www_auth (rtsp_msg_s *msg, const char *line) 512 | { 513 | return 0;//TODO 514 | } 515 | 516 | static int rtsp_msg_build_www_auth (const rtsp_msg_s *msg, char *line, int size) 517 | { 518 | if (msg->hdrs.www_auth) { 519 | if (msg->hdrs.www_auth->type == RTSP_MSG_AUTH_TYPE_BASIC) { 520 | snprintf(line, size, "WWW-Authenticate: Basic realm=\"%s\"\r\n", 521 | msg->hdrs.www_auth->realm); 522 | return strlen(line); 523 | } else { 524 | //TODO 525 | return 0; 526 | } 527 | } 528 | return 0; 529 | } 530 | 531 | //RTP-Info 532 | static int rtsp_msg_parse_rtp_info (rtsp_msg_s *msg, const char *line) 533 | { 534 | return 0;//TODO 535 | } 536 | 537 | static int rtsp_msg_build_rtp_info (const rtsp_msg_s *msg, char *line, int size) 538 | { 539 | return 0;//TODO 540 | } 541 | 542 | //like CSeq/Session int 543 | #define DEFINE_PARSE_BUILD_LIKE_CSEQ(_name, _type, _param, _fmt) \ 544 | static int rtsp_msg_parse_##_name (rtsp_msg_s *msg, const char *line) \ 545 | { \ 546 | rtsp_msg_hdr_s *hdrs = &msg->hdrs; \ 547 | if (hdrs->_name) { \ 548 | rtsp_mem_free(hdrs->_name); \ 549 | hdrs->_name = NULL; \ 550 | } \ 551 | hdrs->_name = (_type*)rtsp_mem_alloc(sizeof(_type)); \ 552 | if (!hdrs->_name) { \ 553 | err("rtsp_mem_alloc for %s failed\n", #_type); \ 554 | return -1; \ 555 | } \ 556 | if (sscanf(line, _fmt, &hdrs->_name->_param) != 1) { \ 557 | rtsp_mem_free(hdrs->_name); \ 558 | hdrs->_name = NULL; \ 559 | err("parse %s failed. line: %s\n", #_name, line); \ 560 | return -1; \ 561 | } \ 562 | return 0; \ 563 | } \ 564 | static int rtsp_msg_build_##_name (const rtsp_msg_s *msg, char *line, int size) \ 565 | { \ 566 | if (msg->hdrs._name) { \ 567 | snprintf(line, size, _fmt "\r\n", msg->hdrs._name->_param); \ 568 | return strlen(line); \ 569 | } \ 570 | return 0; \ 571 | } 572 | 573 | DEFINE_PARSE_BUILD_LIKE_CSEQ(cseq, rtsp_msg_cseq_s, cseq, "CSeq: %u") 574 | DEFINE_PARSE_BUILD_LIKE_CSEQ(session, rtsp_msg_session_s, session, "Session: %08X") 575 | DEFINE_PARSE_BUILD_LIKE_CSEQ(content_length, rtsp_msg_content_length_s, length, "Content-Length: %u") 576 | DEFINE_PARSE_BUILD_LIKE_CSEQ(x_accept_dynamic_rate, rtsp_msg_x_accept_dynamic_rate, x_accept_dynamic_rate, "x-accept-dynamic-Rate: %u") 577 | DEFINE_PARSE_BUILD_LIKE_CSEQ(x_dynamic_rate, rtsp_msg_x_dynamic_rate, x_dynamic_rate, "x-dynamic-rate: %u") 578 | 579 | //like Server/User-Agent char[] 580 | #define DEFINE_PARSE_BUILD_LIKE_SERVER(_name, _type, _param, _fmt) \ 581 | static int rtsp_msg_parse_##_name (rtsp_msg_s *msg, const char *line) \ 582 | { \ 583 | rtsp_msg_hdr_s *hdrs = &msg->hdrs; \ 584 | const char *p = line; \ 585 | unsigned int tmp = 0; \ 586 | if (hdrs->_name) { \ 587 | rtsp_mem_free(hdrs->_name); \ 588 | hdrs->_name = NULL; \ 589 | } \ 590 | hdrs->_name = (_type*)rtsp_mem_alloc(sizeof(_type)); \ 591 | if (!hdrs->_name) { \ 592 | err("rtsp_mem_alloc for %s failed\n", #_type); \ 593 | return -1; \ 594 | } \ 595 | while (isgraph(*p) && *p != ':') p++; \ 596 | if (*p != ':') { \ 597 | rtsp_mem_free(hdrs->_name); \ 598 | hdrs->_name = NULL; \ 599 | err("parse %s failed. line: %s\n", #_name, line); \ 600 | return -1; \ 601 | } \ 602 | p++; \ 603 | while (*p == ' ') p++; \ 604 | while (isprint(*p) && tmp < sizeof(hdrs->_name->_param) - 1) { \ 605 | hdrs->_name->_param[tmp++] = *p++; \ 606 | } \ 607 | hdrs->_name->_param[tmp] = 0; \ 608 | return 0; \ 609 | } \ 610 | static int rtsp_msg_build_##_name (const rtsp_msg_s *msg, char *line, int size) \ 611 | { \ 612 | if (msg->hdrs._name) { \ 613 | snprintf(line, size, _fmt "\r\n", msg->hdrs._name->_param); \ 614 | return strlen(line); \ 615 | } \ 616 | return 0; \ 617 | } 618 | 619 | DEFINE_PARSE_BUILD_LIKE_SERVER(server, rtsp_msg_server_s, server, "Server: %s") 620 | DEFINE_PARSE_BUILD_LIKE_SERVER(user_agent, rtsp_msg_user_agent_s, user_agent, "User-Agent: %s") 621 | DEFINE_PARSE_BUILD_LIKE_SERVER(date, rtsp_msg_date_s, http_date, "Date: %s") 622 | 623 | //like Content-Type 624 | #define DEFINE_PARSE_BUILD_LIKE_CONTENT_TYPE(_name, _type, _param, _fmt, _tbl) \ 625 | static int rtsp_msg_parse_##_name (rtsp_msg_s *msg, const char *line) \ 626 | { \ 627 | rtsp_msg_hdr_s *hdrs = &msg->hdrs; \ 628 | const char *p = line; \ 629 | int num = ARRAY_SIZE(_tbl); \ 630 | int i = 0; \ 631 | if (hdrs->_name) { \ 632 | rtsp_mem_free(hdrs->_name); \ 633 | hdrs->_name = NULL; \ 634 | } \ 635 | hdrs->_name = (_type*)rtsp_mem_alloc(sizeof(_type)); \ 636 | if (!hdrs->_name) { \ 637 | err("rtsp_mem_alloc for %s failed\n", #_type); \ 638 | return -1; \ 639 | } \ 640 | while (isgraph(*p) && *p != ':') p++; \ 641 | if (*p != ':') { \ 642 | rtsp_mem_free(hdrs->_name); \ 643 | hdrs->_name = NULL; \ 644 | err("parse %s failed. line: %s\n", #_name, line); \ 645 | return -1; \ 646 | } \ 647 | p++; \ 648 | while (*p == ' ') p++; \ 649 | for (i = 0; i < num; i++) { \ 650 | if (_tbl[i].strsiz && strstr(p, _tbl[i].strval)) { \ 651 | *((int*)&hdrs->_name->_param) = _tbl[i].intval; \ 652 | return 0; \ 653 | } \ 654 | } \ 655 | rtsp_mem_free(hdrs->_name); \ 656 | hdrs->_name = NULL; \ 657 | return -1; \ 658 | } \ 659 | static int rtsp_msg_build_##_name (const rtsp_msg_s *msg, char *line, int size) \ 660 | { \ 661 | if (msg->hdrs._name) { \ 662 | int i, num = ARRAY_SIZE(_tbl); \ 663 | for (i = 0; i < num; i++) { \ 664 | if ((int)msg->hdrs._name->_param == _tbl[i].intval) { \ 665 | snprintf(line, size, _fmt "\r\n", _tbl[i].strval); \ 666 | return strlen(line); \ 667 | } \ 668 | } \ 669 | return 0; \ 670 | } \ 671 | return 0; \ 672 | } 673 | 674 | DEFINE_PARSE_BUILD_LIKE_CONTENT_TYPE(content_type, rtsp_msg_content_type_s, type, "Content-Type: %s", rtsp_msg_content_type_tbl) 675 | 676 | //like Public/Accept 677 | #define DEFINE_PARSE_BUILD_LIKE_PUBLIC(_name, _type, _param, _fmt, _tbl) \ 678 | static int rtsp_msg_parse_##_name (rtsp_msg_s *msg, const char *line) \ 679 | { \ 680 | rtsp_msg_hdr_s *hdrs = &msg->hdrs; \ 681 | const char *p = line; \ 682 | int num = ARRAY_SIZE(_tbl); \ 683 | int i = 0; \ 684 | if (hdrs->_name) { \ 685 | rtsp_mem_free(hdrs->_name); \ 686 | hdrs->_name = NULL; \ 687 | } \ 688 | hdrs->_name = (_type*)rtsp_mem_alloc(sizeof(_type)); \ 689 | if (!hdrs->_name) { \ 690 | err("rtsp_mem_alloc for %s failed\n", #_type); \ 691 | return -1; \ 692 | } \ 693 | while (isgraph(*p) && *p != ':') p++; \ 694 | if (*p != ':') { \ 695 | rtsp_mem_free(hdrs->_name); \ 696 | hdrs->_name = NULL; \ 697 | err("parse %s failed. line: %s\n", #_name, line); \ 698 | return -1; \ 699 | } \ 700 | p++; \ 701 | while (*p == ' ') p++; \ 702 | for (i = 0; i < num; i++) { \ 703 | if (_tbl[i].strsiz && strstr(p, _tbl[i].strval)) \ 704 | hdrs->_name->_param |= 1 << _tbl[i].intval; \ 705 | } \ 706 | return 0; \ 707 | } \ 708 | static int rtsp_msg_build_##_name (const rtsp_msg_s *msg, char *line, int size) \ 709 | { \ 710 | if (msg->hdrs._name) { \ 711 | char *p = line; \ 712 | int len, i, flag = 0; \ 713 | int num = ARRAY_SIZE(_tbl); \ 714 | snprintf(p, size, _fmt, ""); \ 715 | len = strlen(p); \ 716 | p += len; \ 717 | size -= len; \ 718 | if (size <= 1) { \ 719 | return (p - line); \ 720 | } \ 721 | for (i = 0; i < num; i++) { \ 722 | if (msg->hdrs._name->_param & (1 << _tbl[i].intval)) { \ 723 | if (flag) { \ 724 | snprintf(p, size, ", %s", _tbl[i].strval); \ 725 | } else { \ 726 | snprintf(p, size, "%s", _tbl[i].strval); \ 727 | flag = 1; \ 728 | } \ 729 | len = strlen(p); \ 730 | p += len; \ 731 | size -= len; \ 732 | if (size <= 1) { \ 733 | return (p - line); \ 734 | } \ 735 | } \ 736 | } \ 737 | snprintf(p, size, "\r\n"); \ 738 | len = strlen(p); \ 739 | p += len; \ 740 | return (p - line); \ 741 | } \ 742 | return 0; \ 743 | } 744 | 745 | DEFINE_PARSE_BUILD_LIKE_PUBLIC(public_, rtsp_msg_public_s, public_, "Public: %s", rtsp_msg_method_tbl) 746 | DEFINE_PARSE_BUILD_LIKE_PUBLIC(accept, rtsp_msg_accept_s, accept, "Accept: %s", rtsp_msg_content_type_tbl) 747 | 748 | typedef int (*rtsp_msg_line_parser) (rtsp_msg_s *msg, const char *line); 749 | typedef struct __rtsp_msg_str2parser_tbl_s 750 | { 751 | int strsiz; 752 | const char *strval; 753 | rtsp_msg_line_parser parser; 754 | } rtsp_msg_str2parser_tbl_s; 755 | 756 | static const rtsp_msg_str2parser_tbl_s rtsp_msg_hdr_line_parse_tbl[] = { 757 | {6, "CSeq: ", rtsp_msg_parse_cseq}, 758 | {6, "Date: ", rtsp_msg_parse_date}, 759 | {9, "Session: ", rtsp_msg_parse_session}, 760 | {11, "Transport: ", rtsp_msg_parse_transport}, 761 | {7, "Range: ", rtsp_msg_parse_range}, 762 | {8, "Accept: ", rtsp_msg_parse_accept}, 763 | {15, "Authorization: ", rtsp_msg_parse_auth}, 764 | {19, "WWW-Authorization: ", rtsp_msg_parse_www_auth}, 765 | {12, "User-Agent: ", rtsp_msg_parse_user_agent}, 766 | {8, "Public: ", rtsp_msg_parse_public_}, 767 | {10, "RTP-Info: ", rtsp_msg_parse_rtp_info}, 768 | {8, "Server: ", rtsp_msg_parse_server}, 769 | {14, "Content-Type: ", rtsp_msg_parse_content_type}, 770 | {16, "Content-Length: ", rtsp_msg_parse_content_length}, 771 | {23, "x-accept-dynamic-rate: ", rtsp_msg_parse_x_accept_dynamic_rate}, 772 | {15, "x-dynamic-rate: ", rtsp_msg_parse_x_dynamic_rate}, 773 | }; 774 | 775 | static rtsp_msg_line_parser rtsp_msg_str2parser (const char *line) 776 | { 777 | const rtsp_msg_str2parser_tbl_s *tbl = rtsp_msg_hdr_line_parse_tbl; 778 | int num = ARRAY_SIZE(rtsp_msg_hdr_line_parse_tbl); 779 | int i; 780 | 781 | for (i = 0; i < num; i++) { 782 | if (strncmp(tbl[i].strval, line, tbl[i].strsiz) == 0) 783 | return tbl[i].parser; 784 | } 785 | return NULL; 786 | } 787 | 788 | //@start: data 789 | //@line: store current line (has \0. but no \r\n) 790 | //@maxlen: line max size 791 | //@return: non-NULL is next line pointer. NULL has no next line 792 | static const char *rtsp_msg_hdr_next_line (const char *start, char *line, int maxlen) 793 | { 794 | const char *p = start; 795 | 796 | while (*p && *p != '\r' && *p != '\n') p++; 797 | if (*p != '\r' || *(p+1) != '\n') 798 | return NULL; 799 | 800 | if (line && maxlen > 0) { 801 | maxlen --; 802 | if (maxlen > p - start) 803 | maxlen = p - start; 804 | memcpy(line, start, maxlen); 805 | line[maxlen] = '\0'; 806 | } 807 | 808 | return (p + 2); 809 | } 810 | 811 | int rtsp_msg_init (rtsp_msg_s *msg) 812 | { 813 | if (msg) 814 | memset(msg, 0, sizeof(rtsp_msg_s)); 815 | return 0; 816 | } 817 | 818 | //free all msg elements. not free msg 819 | void rtsp_msg_free (rtsp_msg_s *msg) 820 | { 821 | if (msg->hdrs.cseq) 822 | rtsp_mem_free(msg->hdrs.cseq); 823 | if (msg->hdrs.date) 824 | rtsp_mem_free(msg->hdrs.date); 825 | if (msg->hdrs.session) 826 | rtsp_mem_free(msg->hdrs.session); 827 | if (msg->hdrs.transport) 828 | rtsp_mem_free(msg->hdrs.transport); 829 | if (msg->hdrs.range) 830 | rtsp_mem_free(msg->hdrs.range); 831 | if (msg->hdrs.x_accept_dynamic_rate) 832 | rtsp_mem_free(msg->hdrs.x_accept_dynamic_rate); 833 | if (msg->hdrs.x_dynamic_rate) 834 | rtsp_mem_free(msg->hdrs.x_dynamic_rate); 835 | 836 | if (msg->hdrs.accept) 837 | rtsp_mem_free(msg->hdrs.accept); 838 | if (msg->hdrs.auth) 839 | rtsp_mem_free(msg->hdrs.auth); 840 | if (msg->hdrs.www_auth) 841 | rtsp_mem_free(msg->hdrs.www_auth); 842 | if (msg->hdrs.user_agent) 843 | rtsp_mem_free(msg->hdrs.user_agent); 844 | 845 | if (msg->hdrs.public_) 846 | rtsp_mem_free(msg->hdrs.public_); 847 | //TODO free rtp-info 848 | if (msg->hdrs.server) 849 | rtsp_mem_free(msg->hdrs.server); 850 | 851 | if (msg->hdrs.content_type) 852 | rtsp_mem_free(msg->hdrs.content_type); 853 | if (msg->hdrs.content_length) 854 | rtsp_mem_free(msg->hdrs.content_length); 855 | 856 | if (msg->body.body) 857 | rtsp_mem_free(msg->body.body); 858 | 859 | memset(msg, 0, sizeof(rtsp_msg_s)); 860 | } 861 | 862 | uint32_t rtsp_msg_gen_session_id (void) 863 | { 864 | static uint32_t session_id = 0x12345678; 865 | return session_id++; //FIXME 866 | } 867 | 868 | //return frame real size. when frame is completed 869 | //return 0. when frame size is not enough 870 | //return -1. when frame is invalid 871 | int rtsp_msg_frame_size (const void *data, int size) 872 | { 873 | const char *frame = (const char *)data; 874 | const char *p; 875 | int hdrlen = 0, content_len = 0; 876 | 877 | //check first 878 | p = strstr(frame, "\r\n"); 879 | if (!p || size < p - frame + 2) { 880 | if (size > 256) 881 | return -1; //first line is too large 882 | return 0; 883 | } 884 | 885 | //check headers 886 | p = strstr(frame, "\r\n\r\n"); 887 | if (!p || size < p - frame + 4) { 888 | if (size > 1024) 889 | return -1; //headers is too large 890 | return 0; 891 | } 892 | hdrlen = p - frame + 4; 893 | 894 | //get content-length 895 | p = frame; 896 | while ((p = rtsp_msg_hdr_next_line(p, NULL, 0))) { 897 | if (strncmp(p, "\r\n", 2) == 0) 898 | break; //header end 899 | if (strncmp(p, "Content-Length", 14) == 0) { 900 | if (sscanf(p, "Content-Length: %d", &content_len) != 1) { 901 | err("parse Content-Length failed. line: %s", p); 902 | return -1; 903 | } 904 | } 905 | } 906 | 907 | if (size < hdrlen + content_len) 908 | return 0; 909 | return (hdrlen + content_len); 910 | } 911 | 912 | //return data's bytes which is parsed. when success 913 | //return 0. when data is not enough 914 | //return -1. when data is invalid 915 | int rtsp_msg_parse_from_array (rtsp_msg_s *msg, const void *data, int size) 916 | { 917 | const char *frame = (const char *)data; 918 | const char *p = frame; 919 | char line[256]; 920 | int ret; 921 | 922 | memset(msg, 0, sizeof(rtsp_msg_s)); 923 | 924 | //interleaved frame 925 | if (frame[0] == '$') { 926 | uint16_t interlen = *((uint16_t*)(p+2)); 927 | interlen = ntohs(interlen); 928 | if (size < interlen + 4) 929 | return 0; 930 | msg->type = RTSP_MSG_TYPE_INTERLEAVED; 931 | msg->hdrs.startline.interline.channel = *((uint8_t*)(p+1)); 932 | msg->hdrs.startline.interline.length = interlen; 933 | msg->body.body = rtsp_mem_dup((const char*)data + 4, interlen); 934 | return (interlen + 4); 935 | } 936 | 937 | dbg("\n%s", frame); 938 | 939 | ret = rtsp_msg_frame_size(data, size); 940 | if (ret <= 0) 941 | return ret; 942 | size = ret; 943 | 944 | p = rtsp_msg_hdr_next_line(p, line, sizeof(line)); 945 | if (!p) { 946 | return -1; 947 | } 948 | 949 | ret = rtsp_msg_parse_startline(msg, line); 950 | if (ret < 0) 951 | return -1; 952 | 953 | while ((p = rtsp_msg_hdr_next_line(p, line, sizeof(line)))) { 954 | rtsp_msg_line_parser parser; 955 | 956 | if (strlen(line) == 0) 957 | break; 958 | parser = rtsp_msg_str2parser(line); 959 | if (!parser) { 960 | warn("unknown line: %s\n", line); 961 | continue; 962 | } 963 | 964 | ret = (*parser) (msg, line); 965 | if (ret < 0) { 966 | err("parse failed. line: %s\n", line); 967 | break; 968 | } 969 | } 970 | if (!p || strlen(line)) { 971 | //dbg("p = %p len = %lu\n", p, strlen(line)); 972 | rtsp_msg_free(msg); 973 | return -1; 974 | } 975 | 976 | if (msg->hdrs.content_length) { 977 | msg->body.body = rtsp_mem_dup(p, msg->hdrs.content_length->length); 978 | if (!msg->body.body) { 979 | err("set body failed\n"); 980 | rtsp_msg_free(msg); 981 | return -1; 982 | } 983 | } 984 | 985 | //debug 986 | ret = p - frame; 987 | if (msg->hdrs.content_length) 988 | ret += msg->hdrs.content_length->length; 989 | if (ret != size) { 990 | warn("frame size is %d. but real used %d\n", size, ret); 991 | } 992 | 993 | return size; 994 | } 995 | 996 | //return data's bytes which is used. when success 997 | //return -1. when failed 998 | int rtsp_msg_build_to_array (const rtsp_msg_s *msg, void *data, int size) 999 | { 1000 | char *frame = (char *)data; 1001 | char *p = frame; 1002 | int len; 1003 | 1004 | //interleaved frame 1005 | if (msg->type == RTSP_MSG_TYPE_INTERLEAVED) { 1006 | uint8_t hdr[4]; 1007 | uint16_t interlen = msg->hdrs.startline.interline.length; 1008 | hdr[0] = '$'; 1009 | hdr[1] = msg->hdrs.startline.interline.channel; 1010 | *((uint16_t*)(&hdr[2])) = htons(interlen); 1011 | if (size > 4 + interlen) 1012 | size = interlen + 4; 1013 | memcpy(data, hdr, 4); 1014 | if (msg->body.body) 1015 | memcpy((char*)data + 4, msg->body.body, size - 4); 1016 | return size; 1017 | } 1018 | 1019 | #define MSG_BUILD_STEP() \ 1020 | do { \ 1021 | if (len < 0) \ 1022 | return -1; \ 1023 | p += len; \ 1024 | size -= len; \ 1025 | if (size <= 1) \ 1026 | return (p - frame); \ 1027 | } while(0) 1028 | 1029 | len = rtsp_msg_build_startline(msg, p, size);; 1030 | MSG_BUILD_STEP(); 1031 | 1032 | #define MSG_BUILD_LINE(_name) \ 1033 | do { \ 1034 | if (msg->hdrs._name) { \ 1035 | len = rtsp_msg_build_##_name(msg, p, size); \ 1036 | MSG_BUILD_STEP(); \ 1037 | } \ 1038 | } while(0) 1039 | 1040 | MSG_BUILD_LINE(cseq); 1041 | MSG_BUILD_LINE(date); 1042 | MSG_BUILD_LINE(session); 1043 | MSG_BUILD_LINE(transport); 1044 | MSG_BUILD_LINE(range); 1045 | MSG_BUILD_LINE(x_accept_dynamic_rate); 1046 | MSG_BUILD_LINE(x_dynamic_rate); 1047 | 1048 | MSG_BUILD_LINE(accept); 1049 | MSG_BUILD_LINE(auth); 1050 | MSG_BUILD_LINE(www_auth); 1051 | MSG_BUILD_LINE(user_agent); 1052 | 1053 | MSG_BUILD_LINE(public_); 1054 | MSG_BUILD_LINE(rtp_info); 1055 | MSG_BUILD_LINE(server); 1056 | 1057 | MSG_BUILD_LINE(content_type); 1058 | MSG_BUILD_LINE(content_length); 1059 | 1060 | snprintf(p, size, "\r\n"); 1061 | len = strlen(p); 1062 | MSG_BUILD_STEP(); 1063 | 1064 | if (msg->hdrs.content_length) { 1065 | len = msg->hdrs.content_length->length; 1066 | if (len > size) 1067 | len = size; 1068 | memcpy(p, msg->body.body, len); 1069 | p += len; 1070 | //size -= len; 1071 | } 1072 | 1073 | dbg("\n%s", frame); 1074 | return (p - frame); 1075 | } 1076 | 1077 | int rtsp_msg_set_request (rtsp_msg_s *msg, rtsp_msg_method_e mt, const char *ipaddr, const char *abspath) 1078 | { 1079 | msg->type = RTSP_MSG_TYPE_REQUEST; 1080 | msg->hdrs.startline.reqline.method = mt; 1081 | msg->hdrs.startline.reqline.uri.scheme = RTSP_MSG_URI_SCHEME_RTSP; 1082 | strncpy(msg->hdrs.startline.reqline.uri.ipaddr, ipaddr, 1083 | sizeof(msg->hdrs.startline.reqline.uri.ipaddr) - 1); 1084 | strncpy(msg->hdrs.startline.reqline.uri.abspath, abspath, 1085 | sizeof(msg->hdrs.startline.reqline.uri.abspath) - 1); 1086 | msg->hdrs.startline.reqline.version = RTSP_MSG_VERSION_1_0; 1087 | return 0; 1088 | } 1089 | 1090 | int rtsp_msg_set_response (rtsp_msg_s *msg, int status_code) 1091 | { 1092 | msg->type = RTSP_MSG_TYPE_RESPONSE; 1093 | msg->hdrs.startline.resline.version = RTSP_MSG_VERSION_1_0; 1094 | msg->hdrs.startline.resline.status_code = status_code; 1095 | return 0; 1096 | } 1097 | 1098 | int rtsp_msg_get_cseq (const rtsp_msg_s *msg, uint32_t *cseq) 1099 | { 1100 | if (!msg->hdrs.cseq) 1101 | return -1; 1102 | if (cseq) 1103 | *cseq = msg->hdrs.cseq->cseq; 1104 | return 0; 1105 | } 1106 | 1107 | int rtsp_msg_set_cseq (rtsp_msg_s *msg, uint32_t cseq) 1108 | { 1109 | if (!msg->hdrs.cseq) 1110 | msg->hdrs.cseq = (rtsp_msg_cseq_s*) rtsp_mem_alloc(sizeof(rtsp_msg_cseq_s)); 1111 | if (!msg->hdrs.cseq) 1112 | return -1; 1113 | msg->hdrs.cseq->cseq = cseq; 1114 | return 0; 1115 | } 1116 | 1117 | int rtsp_msg_get_session (const rtsp_msg_s *msg, uint32_t *session) 1118 | { 1119 | if (!msg->hdrs.session) 1120 | return -1; 1121 | if (session) 1122 | *session = msg->hdrs.session->session; 1123 | return 0; 1124 | } 1125 | 1126 | int rtsp_msg_set_session (rtsp_msg_s *msg, uint32_t session) 1127 | { 1128 | if (!msg->hdrs.session) 1129 | msg->hdrs.session = (rtsp_msg_session_s*) rtsp_mem_alloc(sizeof(rtsp_msg_session_s)); 1130 | if (!msg->hdrs.session) 1131 | return -1; 1132 | msg->hdrs.session->session = session; 1133 | return 0; 1134 | } 1135 | 1136 | int rtsp_msg_get_date (const rtsp_msg_s *msg, char *date, int len) 1137 | { 1138 | if (!msg->hdrs.date) 1139 | return -1; 1140 | if (date) 1141 | strncpy(date, msg->hdrs.date->http_date, len - 1); 1142 | return 0; 1143 | } 1144 | 1145 | int rtsp_msg_set_date (rtsp_msg_s *msg, const char *date) 1146 | { 1147 | if (!msg->hdrs.date) 1148 | msg->hdrs.date = (rtsp_msg_date_s*) rtsp_mem_alloc(sizeof(rtsp_msg_date_s)); 1149 | if (!msg->hdrs.date) 1150 | return -1; 1151 | if (date) { 1152 | strncpy(msg->hdrs.date->http_date, date, sizeof(msg->hdrs.date->http_date) - 1); 1153 | } else { 1154 | time_t tt = time(NULL); 1155 | strftime(msg->hdrs.date->http_date, sizeof(msg->hdrs.date->http_date), 1156 | "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt)); 1157 | } 1158 | return 0; 1159 | } 1160 | 1161 | int rtsp_msg_set_transport_udp (rtsp_msg_s *msg, uint32_t ssrc, int client_port, int server_port) 1162 | { 1163 | if (!msg->hdrs.transport) 1164 | msg->hdrs.transport = (rtsp_msg_transport_s*) rtsp_mem_alloc(sizeof(rtsp_msg_transport_s)); 1165 | if (!msg->hdrs.transport) 1166 | return -1; 1167 | msg->hdrs.transport->type = RTSP_MSG_TRANSPORT_TYPE_RTP_AVP; 1168 | msg->hdrs.transport->flags |= RTSP_MSG_TRANSPORT_FLAG_SSRC | RTSP_MSG_TRANSPORT_FLAG_UNICAST; 1169 | msg->hdrs.transport->ssrc = ssrc; 1170 | if (client_port >= 0) { 1171 | msg->hdrs.transport->flags |= RTSP_MSG_TRANSPORT_FLAG_CLIENT_PORT; 1172 | msg->hdrs.transport->client_port = client_port; 1173 | } 1174 | if (server_port >= 0) { 1175 | msg->hdrs.transport->flags |= RTSP_MSG_TRANSPORT_FLAG_SERVER_PORT; 1176 | msg->hdrs.transport->server_port = server_port; 1177 | } 1178 | return 0; 1179 | } 1180 | 1181 | int rtsp_msg_set_transport_tcp (rtsp_msg_s *msg, uint32_t ssrc, int interleaved) 1182 | { 1183 | if (!msg->hdrs.transport) 1184 | msg->hdrs.transport = (rtsp_msg_transport_s*) rtsp_mem_alloc(sizeof(rtsp_msg_transport_s)); 1185 | if (!msg->hdrs.transport) 1186 | return -1; 1187 | msg->hdrs.transport->type = RTSP_MSG_TRANSPORT_TYPE_RTP_AVP_TCP; 1188 | msg->hdrs.transport->flags |= RTSP_MSG_TRANSPORT_FLAG_SSRC; 1189 | msg->hdrs.transport->ssrc = ssrc; 1190 | if (interleaved >= 0) { 1191 | msg->hdrs.transport->flags |= RTSP_MSG_TRANSPORT_FLAG_INTERLEAVED; 1192 | msg->hdrs.transport->interleaved = interleaved; 1193 | } 1194 | return 0; 1195 | } 1196 | 1197 | int rtsp_msg_get_accept (const rtsp_msg_s *msg, uint32_t *accept) 1198 | { 1199 | if (!msg->hdrs.accept) 1200 | return -1; 1201 | if (accept) 1202 | *accept = msg->hdrs.accept->accept; 1203 | return 0; 1204 | } 1205 | 1206 | int rtsp_msg_set_accept (rtsp_msg_s *msg, uint32_t accept) 1207 | { 1208 | if (!msg->hdrs.accept) 1209 | msg->hdrs.accept = (rtsp_msg_accept_s*) rtsp_mem_alloc(sizeof(rtsp_msg_accept_s)); 1210 | if (!msg->hdrs.accept) 1211 | return -1; 1212 | msg->hdrs.accept->accept = accept; 1213 | return 0; 1214 | } 1215 | 1216 | int rtsp_msg_get_user_agent (const rtsp_msg_s *msg, char *user_agent, int len) 1217 | { 1218 | if (!msg->hdrs.user_agent) 1219 | return -1; 1220 | if (user_agent) 1221 | strncpy(user_agent, msg->hdrs.user_agent->user_agent, len - 1); 1222 | return 0; 1223 | } 1224 | 1225 | int rtsp_msg_set_user_agent (rtsp_msg_s *msg, const char *user_agent) 1226 | { 1227 | if (!msg->hdrs.user_agent) 1228 | msg->hdrs.user_agent = (rtsp_msg_user_agent_s*) rtsp_mem_alloc(sizeof(rtsp_msg_user_agent_s)); 1229 | if (!msg->hdrs.user_agent) 1230 | return -1; 1231 | if (user_agent) { 1232 | strncpy(msg->hdrs.user_agent->user_agent, user_agent, sizeof(msg->hdrs.user_agent->user_agent) - 1); 1233 | } else { 1234 | strncpy(msg->hdrs.user_agent->user_agent, "rtsp_msg_user_agent", 1235 | sizeof(msg->hdrs.user_agent->user_agent) - 1); 1236 | } 1237 | return 0; 1238 | } 1239 | 1240 | int rtsp_msg_get_public (const rtsp_msg_s *msg, uint32_t *public_) 1241 | { 1242 | if (!msg->hdrs.public_) 1243 | return -1; 1244 | if (public_) 1245 | *public_ = msg->hdrs.public_->public_; 1246 | return 0; 1247 | } 1248 | 1249 | int rtsp_msg_set_public (rtsp_msg_s *msg, uint32_t public_) 1250 | { 1251 | if (!msg->hdrs.public_) 1252 | msg->hdrs.public_ = (rtsp_msg_public_s*) rtsp_mem_alloc(sizeof(rtsp_msg_public_s)); 1253 | if (!msg->hdrs.public_) 1254 | return -1; 1255 | msg->hdrs.public_->public_ = public_; 1256 | return 0; 1257 | } 1258 | 1259 | int rtsp_msg_get_server (const rtsp_msg_s *msg, char *server, int len) 1260 | { 1261 | if (!msg->hdrs.server) 1262 | return -1; 1263 | if (server) 1264 | strncpy(server, msg->hdrs.server->server, len - 1); 1265 | return 0; 1266 | } 1267 | 1268 | int rtsp_msg_set_server (rtsp_msg_s *msg, const char *server) 1269 | { 1270 | if (!msg->hdrs.server) 1271 | msg->hdrs.server = (rtsp_msg_server_s*) rtsp_mem_alloc(sizeof(rtsp_msg_server_s)); 1272 | if (!msg->hdrs.server) 1273 | return -1; 1274 | if (server) { 1275 | strncpy(msg->hdrs.server->server, server, sizeof(msg->hdrs.server->server) - 1); 1276 | } else { 1277 | strncpy(msg->hdrs.server->server, "rtsp_msg_server", 1278 | sizeof(msg->hdrs.server->server) - 1); 1279 | } 1280 | return 0; 1281 | } 1282 | 1283 | int rtsp_msg_get_content_type (const rtsp_msg_s *msg, int *type) 1284 | { 1285 | if (!msg->hdrs.content_type) 1286 | return -1; 1287 | if (type) 1288 | *type = msg->hdrs.content_type->type; 1289 | return 0; 1290 | } 1291 | 1292 | int rtsp_msg_set_content_type (rtsp_msg_s *msg, int type) 1293 | { 1294 | if (!msg->hdrs.content_type) 1295 | msg->hdrs.content_type = (rtsp_msg_content_type_s*) rtsp_mem_alloc(sizeof(rtsp_msg_content_type_s)); 1296 | if (!msg->hdrs.content_type) 1297 | return -1; 1298 | msg->hdrs.content_type->type = (rtsp_msg_content_type_e) type; 1299 | return 0; 1300 | } 1301 | 1302 | int rtsp_msg_get_content_length (const rtsp_msg_s *msg, int *length) 1303 | { 1304 | if (!msg->hdrs.content_length) 1305 | return -1; 1306 | if (length) 1307 | *length = msg->hdrs.content_length->length; 1308 | return 0; 1309 | } 1310 | 1311 | int rtsp_msg_set_content_length (rtsp_msg_s *msg, int length) 1312 | { 1313 | if (!msg->hdrs.content_length) 1314 | msg->hdrs.content_length = (rtsp_msg_content_length_s*) rtsp_mem_alloc(sizeof(rtsp_msg_content_length_s)); 1315 | if (!msg->hdrs.content_length) 1316 | return -1; 1317 | msg->hdrs.content_length->length = length; 1318 | return 0; 1319 | } 1320 | 1321 | int rtsp_msg_get_auth_basic (const rtsp_msg_s *msg, char *basic_b64, int len) 1322 | { 1323 | if (!msg->hdrs.auth || msg->hdrs.auth->type != RTSP_MSG_AUTH_TYPE_BASIC) 1324 | return -1; 1325 | if (basic_b64) 1326 | strncpy(basic_b64, msg->hdrs.auth->basic_b64, len - 1); 1327 | return 0; 1328 | } 1329 | 1330 | int rtsp_msg_set_www_auth_basic (rtsp_msg_s *msg, const char *realm) 1331 | { 1332 | if (!msg->hdrs.www_auth) 1333 | msg->hdrs.www_auth = (rtsp_msg_www_auth_s*) rtsp_mem_alloc(sizeof(rtsp_msg_www_auth_s)); 1334 | if (!msg->hdrs.www_auth) 1335 | return -1; 1336 | msg->hdrs.www_auth->type = RTSP_MSG_AUTH_TYPE_BASIC; 1337 | strncpy(msg->hdrs.www_auth->realm, realm, 1338 | sizeof(msg->hdrs.www_auth->realm) - 1); 1339 | return 0; 1340 | } 1341 | 1342 | int rtsp_msg_set_x_accept_dynamic_rate (rtsp_msg_s *msg, uint32_t x_accept_dynamic_rate) 1343 | { 1344 | if (!msg->hdrs.x_accept_dynamic_rate) 1345 | msg->hdrs.x_accept_dynamic_rate = (rtsp_msg_x_accept_dynamic_rate*) rtsp_mem_alloc(sizeof(rtsp_msg_x_accept_dynamic_rate)); 1346 | if (!msg->hdrs.x_accept_dynamic_rate) 1347 | return -1; 1348 | msg->hdrs.x_accept_dynamic_rate->x_accept_dynamic_rate = x_accept_dynamic_rate; 1349 | return 0; 1350 | } 1351 | 1352 | int rtsp_msg_get_x_dynamic_rate (const rtsp_msg_s *msg, uint32_t *x_dynamic_rate) 1353 | { 1354 | if (!msg->hdrs.x_dynamic_rate) 1355 | return -1; 1356 | if (x_dynamic_rate) 1357 | *x_dynamic_rate = msg->hdrs.x_dynamic_rate->x_dynamic_rate; 1358 | return 0; 1359 | } 1360 | 1361 | int rtsp_msg_set_x_dynamic_rate (rtsp_msg_s *msg, uint32_t x_dynamic_rate) 1362 | { 1363 | if (!msg->hdrs.x_dynamic_rate) 1364 | msg->hdrs.x_dynamic_rate = (rtsp_msg_x_dynamic_rate*) rtsp_mem_alloc(sizeof(rtsp_msg_x_dynamic_rate)); 1365 | if (!msg->hdrs.x_dynamic_rate) 1366 | return -1; 1367 | msg->hdrs.x_dynamic_rate->x_dynamic_rate = x_dynamic_rate; 1368 | return 0; 1369 | } 1370 | 1371 | #if 0 1372 | #include 1373 | int main(int argc, char *argv[]) 1374 | { 1375 | const char *file = "rtsp.log"; 1376 | int fd; 1377 | char srcbuf[1024]; 1378 | char dstbuf[1024]; 1379 | int srclen, dstlen; 1380 | int ret; 1381 | rtsp_msg_s msg; 1382 | 1383 | rtsp_msg_init(&msg); 1384 | 1385 | if (argc > 1) 1386 | file = argv[1]; 1387 | 1388 | fd = open(file, O_RDONLY); 1389 | if (fd < 0) { 1390 | perror("open failed"); 1391 | return -1; 1392 | } 1393 | 1394 | srclen = 0; 1395 | do { 1396 | ret = rtsp_msg_parse_from_array(&msg, srcbuf, srclen); 1397 | if (ret < 0) { 1398 | printf(">>>>>>>>>>1\n"); 1399 | break; 1400 | } 1401 | if (ret == 0) { 1402 | ret = read(fd, srcbuf + srclen, sizeof(srcbuf) - srclen); 1403 | if (ret <= 0) { 1404 | printf(">>>>>>>>>>>2\n"); 1405 | break; 1406 | } 1407 | srclen += ret; 1408 | continue; 1409 | } 1410 | 1411 | printf("ret = %d\n", ret); 1412 | memmove(srcbuf, srcbuf + ret, srclen - ret); 1413 | srclen -= ret; 1414 | 1415 | ret = rtsp_msg_build_to_array(&msg, dstbuf, sizeof(dstbuf)); 1416 | if (ret <= 0) { 1417 | printf(">>>>>>>>>>3\n"); 1418 | break; 1419 | } 1420 | printf("ret = %d\n", ret); 1421 | fwrite(dstbuf, ret, 1, stderr); 1422 | rtsp_msg_free(&msg); 1423 | } while (srclen || ret > 0); 1424 | srcbuf[srclen] = 0; 1425 | printf("srclen = %d\n%s", srclen, srcbuf); 1426 | 1427 | close(fd); 1428 | return 0; 1429 | } 1430 | #endif 1431 | 1432 | 1433 | -------------------------------------------------------------------------------- /rtsp_msg.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: rtsp_msg.h 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Friday, December 11, 2015 AM03:31:53 CST 6 | ************************************************************************/ 7 | 8 | #ifndef __RTSP_MSG_H__ 9 | #define __RTSP_MSG_H__ 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | //RTSP/1.0 Message Parse/Build 18 | 19 | typedef enum __rtsp_msg_type_e 20 | { 21 | RTSP_MSG_TYPE_REQUEST = 0, 22 | RTSP_MSG_TYPE_RESPONSE, 23 | RTSP_MSG_TYPE_INTERLEAVED, 24 | RTSP_MSG_TYPE_BUTT, 25 | } rtsp_msg_type_e; 26 | 27 | typedef enum __rtsp_msg_method_e 28 | { 29 | RTSP_MSG_METHOD_OPTIONS = 0, 30 | RTSP_MSG_METHOD_DESCRIBE, 31 | RTSP_MSG_METHOD_SETUP, 32 | RTSP_MSG_METHOD_PLAY, 33 | RTSP_MSG_METHOD_RECORD, 34 | RTSP_MSG_METHOD_PAUSE, 35 | RTSP_MSG_METHOD_TEARDOWN, 36 | RTSP_MSG_METHOD_ANNOUNCE, 37 | RTSP_MSG_METHOD_SET_PARAMETER, 38 | RTSP_MSG_METHOD_GET_PARAMETER, 39 | RTSP_MSG_METHOD_REDIRECT, 40 | RTSP_MSG_METHOD_BUTT, 41 | } rtsp_msg_method_e; 42 | 43 | typedef enum __rtsp_msg_uri_scheme_e 44 | { 45 | RTSP_MSG_URI_SCHEME_RTSP = 0, 46 | RTSP_MSG_URI_SCHEME_RTSPU, 47 | RTSP_MSG_URI_SCHEME_BUTT, 48 | } rtsp_msg_uri_scheme_e; 49 | 50 | typedef struct __rtsp_msg_uri_s 51 | { 52 | rtsp_msg_uri_scheme_e scheme; 53 | uint16_t port; 54 | char ipaddr[32]; 55 | char abspath[64]; 56 | } rtsp_msg_uri_s; 57 | 58 | typedef enum __rtsp_msg_version_e 59 | { 60 | RTSP_MSG_VERSION_1_0 = 0, 61 | RTSP_MSG_VERSION_BUTT, 62 | } rtsp_msg_version_e; 63 | 64 | typedef struct __rtsp_msg_request_line_s 65 | { 66 | rtsp_msg_method_e method; 67 | rtsp_msg_uri_s uri; 68 | rtsp_msg_version_e version; 69 | } rtsp_msg_request_line_s; 70 | 71 | typedef struct __rtsp_msg_response_line_s 72 | { 73 | rtsp_msg_version_e version; 74 | uint32_t status_code; 75 | } rtsp_msg_response_line_s; 76 | 77 | typedef struct __rtsp_msg_interleaved_line_s 78 | { 79 | uint8_t channel; 80 | uint16_t length; 81 | uint8_t reserved; 82 | } rtsp_msg_interleaved_line_s; 83 | 84 | //CSeq g req. all 85 | typedef struct __rtsp_msg_cseq_s 86 | { 87 | uint32_t cseq; 88 | } rtsp_msg_cseq_s; 89 | 90 | //Date g opt. all 91 | typedef struct __rtsp_msg_date_s 92 | { 93 | char http_date[48]; 94 | } rtsp_msg_date_s; 95 | 96 | //Session Rr req. all but SETUP,OPTIONS 97 | typedef struct __rtsp_msg_session_s 98 | { 99 | uint32_t session; 100 | } rtsp_msg_session_s; 101 | 102 | typedef enum __rtsp_msg_transport_type_e 103 | { 104 | RTSP_MSG_TRANSPORT_TYPE_RTP_AVP = 0, //RTPoverUDP 105 | RTSP_MSG_TRANSPORT_TYPE_RTP_AVP_TCP, //RTPoverTCP 106 | RTSP_MSG_TRANSPORT_TYPE_BUTT, 107 | } rtsp_msg_transport_type_e; 108 | 109 | //Transport Rr req. SETUP 110 | typedef struct __rtsp_msg_transport_s 111 | { 112 | rtsp_msg_transport_type_e type; 113 | uint32_t flags; 114 | #define RTSP_MSG_TRANSPORT_FLAG_SSRC (1<<0) 115 | #define RTSP_MSG_TRANSPORT_FLAG_UNICAST (1<<1) 116 | #define RTSP_MSG_TRANSPORT_FLAG_MULTICAST (1<<2) 117 | #define RTSP_MSG_TRANSPORT_FLAG_CLIENT_PORT (1<<3) 118 | #define RTSP_MSG_TRANSPORT_FLAG_SERVER_PORT (1<<4) 119 | #define RTSP_MSG_TRANSPORT_FLAG_INTERLEAVED (1<<5) 120 | uint32_t ssrc; 121 | uint16_t client_port;//rtcp is rtp + 1 122 | uint16_t server_port; 123 | uint8_t interleaved; 124 | } rtsp_msg_transport_s; 125 | 126 | typedef enum __rtsp_msg_time_type_e 127 | { 128 | RTSP_MSG_TIME_TYPE_SMPTE = 0, 129 | RTSP_MSG_TIME_TYPE_NPT, 130 | RTSP_MSG_TIME_TYPE_UTC, 131 | RTSP_MSG_TIME_TYPE_BUTT, 132 | } rtsp_msg_time_type_e; 133 | 134 | typedef struct __rtsp_msg_time_smpte_s 135 | { 136 | //10:07:33:05.01 137 | uint32_t seconds; //10*3600 + 07*60 + 33 138 | uint32_t subframes; //05*100 + 01 139 | } rtsp_msg_time_smpte_s; 140 | 141 | typedef struct __rtsp_msg_time_npt_s 142 | { 143 | //123.45 144 | uint32_t secords; //123 145 | uint32_t usecords; //45 146 | } rtsp_msg_time_npt_s; 147 | 148 | typedef struct __rtsp_msg_time_utc_s 149 | { 150 | //19961108T142730.25Z 151 | uint32_t secords; //1996/11/08 14:27:30 - 1900/1/1 0:0:0 152 | uint32_t usecords; //25 153 | } rtsp_msg_time_utc_s; 154 | 155 | //Range Rr opt. PLAY,PAUSE,RECORD 156 | typedef struct __rtsp_msg_range_s 157 | { 158 | rtsp_msg_time_type_e type; 159 | union __start_u { 160 | rtsp_msg_time_smpte_s smpte; 161 | rtsp_msg_time_npt_s npt; 162 | rtsp_msg_time_utc_s utc; 163 | } start; 164 | union __end_u { 165 | rtsp_msg_time_smpte_s smpte; 166 | rtsp_msg_time_npt_s npt; 167 | rtsp_msg_time_utc_s utc; 168 | } end; 169 | } rtsp_msg_range_s; 170 | 171 | typedef enum __rtsp_msg_content_type_e 172 | { 173 | RTSP_MSG_CONTENT_TYPE_SDP = 0, 174 | RTSP_MSG_CONTENT_TYPE_RTSL, 175 | RTSP_MSG_CONTENT_TYPE_MHEG, 176 | RTSP_MSG_CONTENT_TYPE_BUTT, 177 | } rtsp_msg_content_type_e; 178 | 179 | //Accept R opt. entity 180 | typedef struct __rtsp_msg_accept_s 181 | { 182 | uint32_t accept; 183 | #define RTSP_MSG_ACCEPT_SDP (1< File Name: stream_queue.c 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Sunday, May 22, 2016 PM10:25:44 CST 6 | ************************************************************************/ 7 | 8 | #include 9 | 10 | #include "comm.h" 11 | #include "stream_queue.h" 12 | 13 | struct stream_queue *streamq_alloc (int pktsiz, int nbpkts) 14 | { 15 | struct stream_queue *q; 16 | 17 | if (pktsiz <= 0 || nbpkts <= 0) 18 | return NULL; 19 | 20 | q = (struct stream_queue*) calloc(1, sizeof(struct stream_queue) + pktsiz * nbpkts + sizeof(int) * nbpkts); 21 | if (!q) { 22 | err("alloc memory failed for stream_queue\n"); 23 | return NULL; 24 | } 25 | 26 | q->pktsiz = pktsiz; 27 | q->nbpkts = nbpkts; 28 | q->pktlen = (int*)(((char*)q) + sizeof(struct stream_queue)); 29 | q->buf = (char*)(((char*)q) + sizeof(struct stream_queue) + sizeof(int) * nbpkts); 30 | 31 | return q; 32 | } 33 | 34 | int streamq_query (struct stream_queue *q, int index, char **ppacket, int **ppktlen) 35 | { 36 | if (!q || index >= q->nbpkts) 37 | return -1; 38 | if (ppacket) 39 | *ppacket = q->buf + index * q->pktsiz; 40 | if (ppktlen) 41 | *ppktlen = &q->pktlen[index]; 42 | return 0; 43 | } 44 | 45 | int streamq_inused (struct stream_queue *q, int index) 46 | { 47 | if (!q) 48 | return -1; 49 | if ((q->head <= index && index < q->tail) || (q->head > q->tail && (index >= q->head || index < q->tail))) 50 | return 1; 51 | return 0; 52 | } 53 | 54 | int streamq_next (struct stream_queue *q, int index) 55 | { 56 | if (!q) 57 | return -1; 58 | 59 | index = (index + 1) % q->nbpkts; 60 | return index; 61 | } 62 | 63 | int streamq_head (struct stream_queue *q) 64 | { 65 | if (!q) 66 | return -1; 67 | return q->head; 68 | } 69 | 70 | int streamq_tail (struct stream_queue *q) 71 | { 72 | if (!q) 73 | return -1; 74 | return q->tail; 75 | } 76 | 77 | int streamq_push (struct stream_queue *q) 78 | { 79 | if (!q) 80 | return -1; 81 | if ((q->tail + 1) % q->nbpkts == q->head) 82 | return -1; 83 | q->tail = (q->tail + 1) % q->nbpkts; 84 | return q->tail; 85 | } 86 | 87 | int streamq_pop (struct stream_queue *q) 88 | { 89 | if (!q) 90 | return -1; 91 | if (q->head == q->tail) 92 | return -1; 93 | q->head = (q->head + 1) % q->nbpkts; 94 | return q->head; 95 | } 96 | 97 | void streamq_free (struct stream_queue *q) 98 | { 99 | if (q) { 100 | free(q); 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /stream_queue.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: stream_queue.h 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Sunday, May 22, 2016 PM09:35:22 CST 6 | ************************************************************************/ 7 | 8 | #ifndef __STREAM_QUEUE_H__ 9 | #define __STREAM_QUEUE_H__ 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | struct stream_queue { 16 | int pktsiz; 17 | int nbpkts; 18 | int head; 19 | int tail; 20 | int *pktlen; 21 | char *buf; 22 | }; 23 | 24 | struct stream_queue *streamq_alloc (int pktsiz, int nbpkts); 25 | int streamq_query (struct stream_queue *q, int index, char **ppacket, int **ppktlen); 26 | int streamq_inused (struct stream_queue *q, int index); 27 | int streamq_next (struct stream_queue *q, int index); 28 | int streamq_head (struct stream_queue *q); 29 | int streamq_tail (struct stream_queue *q); 30 | int streamq_push (struct stream_queue *q); 31 | int streamq_pop (struct stream_queue *q); 32 | void streamq_free (struct stream_queue *q); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: test.c 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Saturday, December 12, 2015 PM03:19:12 CST 6 | ************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "rtsp_demo.h" 16 | 17 | static int flag_run = 1; 18 | static void sig_proc(int signo) 19 | { 20 | flag_run = 0; 21 | } 22 | 23 | static int get_next_video_frame (FILE *fp, uint8_t **buff, int *size) 24 | { 25 | uint8_t szbuf[1024]; 26 | int szlen = 0; 27 | int ret; 28 | if (!(*buff)) { 29 | *buff = (uint8_t*)malloc(2*1024*1024); 30 | if (!(*buff)) 31 | return -1; 32 | } 33 | 34 | *size = 0; 35 | 36 | while ((ret = fread(szbuf + szlen, 1, sizeof(szbuf) - szlen, fp)) > 0) { 37 | int i = 3; 38 | szlen += ret; 39 | while (i < szlen - 3 && !(szbuf[i] == 0 && szbuf[i+1] == 0 && (szbuf[i+2] == 1 || (szbuf[i+2] == 0 && szbuf[i+3] == 1)))) i++; 40 | memcpy(*buff + *size, szbuf, i); 41 | *size += i; 42 | memmove(szbuf, szbuf + i, szlen - i); 43 | szlen -= i; 44 | if (szlen > 3) { 45 | //printf("szlen %d\n", szlen); 46 | fseek(fp, -szlen, SEEK_CUR); 47 | break; 48 | } 49 | } 50 | if (ret > 0) 51 | return *size; 52 | return 0; 53 | } 54 | 55 | static int get_next_audio_frame (FILE *fp, uint8_t **buff, int *size) 56 | { 57 | int ret; 58 | #define AUDIO_FRAME_SIZE 320 59 | if (!(*buff)) { 60 | *buff = (uint8_t*)malloc(AUDIO_FRAME_SIZE); 61 | if (!(*buff)) 62 | return -1; 63 | } 64 | 65 | ret = fread(*buff, 1, AUDIO_FRAME_SIZE, fp); 66 | if (ret > 0) { 67 | *size = ret; 68 | return ret; 69 | } 70 | return 0; 71 | } 72 | 73 | #define MAX_SESSION_NUM 64 74 | #define DEMO_CFG_FILE "demo.cfg" 75 | 76 | struct demo_cfg 77 | { 78 | int session_count; 79 | struct { 80 | char path[64]; 81 | char video_file[64]; 82 | char audio_file[64]; 83 | } session_cfg[MAX_SESSION_NUM]; 84 | }; 85 | 86 | static int load_cfg(struct demo_cfg *cfg, const char *cfg_file) 87 | { 88 | //cfgline: path=%s video=%s audio=%s 89 | FILE *fp = fopen(cfg_file, "r"); 90 | char line[256]; 91 | int count = 0; 92 | 93 | if (!fp) { 94 | fprintf(stderr, "open %s failed\n", cfg_file); 95 | return -1; 96 | } 97 | 98 | memset(cfg, 0, sizeof(*cfg)); 99 | while (fgets(line, sizeof(line) - 1, fp)) { 100 | const char *p; 101 | memset(&cfg->session_cfg[count], 0, sizeof(cfg->session_cfg[count])); 102 | 103 | if (line[0] == '#') 104 | continue; 105 | 106 | p = strstr(line, "path="); 107 | if (!p) 108 | continue; 109 | if (sscanf(p, "path=%s", cfg->session_cfg[count].path) != 1) 110 | continue; 111 | if ((p = strstr(line, "video="))) { 112 | if (sscanf(p, "video=%s", cfg->session_cfg[count].video_file) != 1) { 113 | fprintf(stderr, "parse video file failed %s\n", p); 114 | } 115 | } 116 | if ((p = strstr(line, "audio="))) { 117 | if (sscanf(p, "audio=%s", cfg->session_cfg[count].audio_file) != 1) { 118 | fprintf(stderr, "parse audio file failed %s\n", p); 119 | } 120 | } 121 | if (strlen(cfg->session_cfg[count].video_file) || strlen(cfg->session_cfg[count].audio_file)) { 122 | count ++; 123 | } else { 124 | fprintf(stderr, "parse line %s failed\n", line); 125 | } 126 | } 127 | cfg->session_count = count; 128 | fclose(fp); 129 | return count; 130 | } 131 | 132 | #ifdef __LINUX__ 133 | #include 134 | #endif 135 | #ifdef __WIN32__ 136 | #include 137 | #define usleep(x) Sleep((x)/1000) 138 | #endif 139 | 140 | int main(int argc, char *argv[]) 141 | { 142 | const char *cfg_file = DEMO_CFG_FILE; 143 | struct demo_cfg cfg; 144 | FILE *fp[MAX_SESSION_NUM][2] = {{NULL}}; 145 | rtsp_demo_handle demo; 146 | rtsp_session_handle session[MAX_SESSION_NUM] = {NULL}; 147 | int session_count = 0; 148 | uint8_t *vbuf = NULL; 149 | uint8_t *abuf = NULL; 150 | uint64_t ts = 0; 151 | int vsize = 0, asize = 0; 152 | int ret, ch; 153 | 154 | if (argc > 1) 155 | cfg_file = argv[1]; 156 | 157 | ret = load_cfg(&cfg, cfg_file); 158 | if (ret < 0) { 159 | fprintf(stderr, "Usage: %s [CFG_FILE]\n", argv[0]); 160 | getchar(); 161 | return 0; 162 | } 163 | 164 | //rtsp_demo usage: 165 | //rtsp_new_demo 166 | //rtsp_new_session 167 | //rtsp_set_video 168 | //rtsp_set_audio 169 | //while(1){ 170 | // rtsp_tx_video 171 | // rtsp_tx_audio 172 | // rtsp_do_event 173 | //} 174 | //rtsp_del_session 175 | //rtsp_del_demo 176 | 177 | demo = rtsp_new_demo(8554); 178 | if (NULL == demo) { 179 | printf("rtsp_new_demo failed\n"); 180 | return 0; 181 | } 182 | 183 | session_count = cfg.session_count; 184 | for (ch = 0; ch < session_count; ch++) { 185 | if (strlen(cfg.session_cfg[ch].video_file)) { 186 | fp[ch][0] = fopen(cfg.session_cfg[ch].video_file, "rb"); 187 | if (!fp[ch][0]) { 188 | fprintf(stderr, "open %s failed\n", cfg.session_cfg[ch].video_file); 189 | } 190 | } 191 | 192 | if (strlen(cfg.session_cfg[ch].audio_file)) { 193 | fp[ch][1] = fopen(cfg.session_cfg[ch].audio_file, "rb"); 194 | if (!fp[ch][1]) { 195 | fprintf(stderr, "open %s failed\n", cfg.session_cfg[ch].audio_file); 196 | } 197 | } 198 | 199 | if (fp[ch][0] == NULL && fp[ch][1] == NULL) 200 | continue; 201 | 202 | session[ch] = rtsp_new_session(demo, cfg.session_cfg[ch].path); 203 | if (NULL == session[ch]) { 204 | printf("rtsp_new_session failed\n"); 205 | continue; 206 | } 207 | 208 | //rtsp_set_auth(session[ch], RTSP_AUTH_TYPE_BASIC, "admin", "123456"); 209 | if (fp[ch][0]) { 210 | rtsp_set_video(session[ch], RTSP_CODEC_ID_VIDEO_H264, NULL, 0); 211 | rtsp_sync_video_ts(session[ch], rtsp_get_reltime(), rtsp_get_ntptime()); 212 | } 213 | if (fp[ch][1]) { 214 | rtsp_set_audio(session[ch], RTSP_CODEC_ID_AUDIO_G711A, NULL, 0); 215 | rtsp_sync_audio_ts(session[ch], rtsp_get_reltime(), rtsp_get_ntptime()); 216 | } 217 | 218 | printf("==========> rtsp://127.0.0.1:8554%s for %s %s <===========\n", cfg.session_cfg[ch].path, 219 | fp[ch][0] ? cfg.session_cfg[ch].video_file : "", 220 | fp[ch][1] ? cfg.session_cfg[ch].audio_file : ""); 221 | } 222 | 223 | ts = rtsp_get_reltime(); 224 | signal(SIGINT, sig_proc); 225 | #ifdef __LINUX__ 226 | signal(SIGPIPE, SIG_IGN); 227 | #endif 228 | while (flag_run) { 229 | uint8_t type = 0; 230 | 231 | for (ch = 0; ch < session_count; ch++) { 232 | if (fp[ch][0]) { 233 | read_video_again: 234 | ret = get_next_video_frame(fp[ch][0], &vbuf, &vsize); 235 | if (ret < 0) { 236 | fprintf(stderr, "get_next_video_frame failed\n"); 237 | flag_run = 0; 238 | break; 239 | } 240 | if (ret == 0) { 241 | fseek(fp[ch][0], 0, SEEK_SET); 242 | if (fp[ch][1]) 243 | fseek(fp[ch][1], 0, SEEK_SET); 244 | goto read_video_again; 245 | } 246 | 247 | if (session[ch]) 248 | rtsp_tx_video(session[ch], vbuf, vsize, ts); 249 | 250 | type = 0; 251 | if (vbuf[0] == 0 && vbuf[1] == 0 && vbuf[2] == 1) { 252 | type = vbuf[3] & 0x1f; 253 | } 254 | if (vbuf[0] == 0 && vbuf[1] == 0 && vbuf[2] == 0 && vbuf[3] == 1) { 255 | type = vbuf[4] & 0x1f; 256 | } 257 | if (type != 5 && type != 1) 258 | goto read_video_again; 259 | } 260 | 261 | if (fp[ch][1]) { 262 | ret = get_next_audio_frame(fp[ch][1], &abuf, &asize); 263 | if (ret < 0) { 264 | fprintf(stderr, "get_next_audio_frame failed\n"); 265 | break; 266 | } 267 | if (ret == 0) { 268 | fseek(fp[ch][1], 0, SEEK_SET); 269 | if (fp[ch][0]) 270 | fseek(fp[ch][0], 0, SEEK_SET); 271 | continue; 272 | } 273 | if (session[ch]) 274 | rtsp_tx_audio(session[ch], abuf, asize, ts); 275 | } 276 | } 277 | 278 | do { 279 | ret = rtsp_do_event(demo); 280 | if (ret > 0) 281 | continue; 282 | if (ret < 0) 283 | break; 284 | usleep(20000); 285 | } while (rtsp_get_reltime() - ts < 1000000 / 25); 286 | if (ret < 0) 287 | break; 288 | ts += 1000000 / 25; 289 | printf(".");fflush(stdout); 290 | } 291 | 292 | free(vbuf); 293 | free(abuf); 294 | 295 | for (ch = 0; ch < session_count; ch++) { 296 | if (fp[ch][0]) 297 | fclose(fp[ch][0]); 298 | if (fp[ch][1]) 299 | fclose(fp[ch][1]); 300 | if (session[ch]) 301 | rtsp_del_session(session[ch]); 302 | } 303 | 304 | rtsp_del_demo(demo); 305 | printf("Exit.\n"); 306 | getchar(); 307 | return 0; 308 | } 309 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: utils.c 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Sunday, May 22, 2016 PM09:35:22 CST 6 | ************************************************************************/ 7 | 8 | #include 9 | #include "comm.h" 10 | #include "utils.h" 11 | 12 | /***************************************************************************** 13 | * b64_encode: Stolen from VLC's http.c. 14 | * Simplified by Michael. 15 | * Fixed edge cases and made it work from data (vs. strings) by Ryan. 16 | *****************************************************************************/ 17 | char *base64_encode (char *out, int out_size, const uint8_t *in, int in_size) 18 | { 19 | static const char b64[] = 20 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 21 | char *ret, *dst; 22 | unsigned i_bits = 0; 23 | int i_shift = 0; 24 | int bytes_remaining = in_size; 25 | 26 | #define __UINT_MAX (~0lu) 27 | #define __BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) 28 | #define __RB32(x) \ 29 | (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ 30 | (((const uint8_t*)(x))[1] << 16) | \ 31 | (((const uint8_t*)(x))[2] << 8) | \ 32 | ((const uint8_t*)(x))[3]) 33 | if (in_size >= __UINT_MAX / 4 || 34 | out_size < __BASE64_SIZE(in_size)) 35 | return NULL; 36 | ret = dst = out; 37 | while (bytes_remaining > 3) { 38 | i_bits = __RB32(in); 39 | in += 3; bytes_remaining -= 3; 40 | *dst++ = b64[ i_bits>>26 ]; 41 | *dst++ = b64[(i_bits>>20) & 0x3F]; 42 | *dst++ = b64[(i_bits>>14) & 0x3F]; 43 | *dst++ = b64[(i_bits>>8 ) & 0x3F]; 44 | } 45 | i_bits = 0; 46 | while (bytes_remaining) { 47 | i_bits = (i_bits << 8) + *in++; 48 | bytes_remaining--; 49 | i_shift += 8; 50 | } 51 | while (i_shift > 0) { 52 | *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; 53 | i_shift -= 6; 54 | } 55 | while ((dst - ret) & 3) 56 | *dst++ = '='; 57 | *dst = '\0'; 58 | 59 | return ret; 60 | } 61 | 62 | const uint8_t *rtsp_find_h264_h265_nalu (const uint8_t *buff, int len, int *size) 63 | { 64 | const uint8_t *s = NULL; 65 | const uint8_t *ptr = buff; 66 | while (len >= 3) { 67 | if (ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 1) { 68 | //found start code 001 69 | if (ptr > buff && *(ptr-1) == 0) { 70 | //is 0001 71 | ptr --; 72 | len ++; 73 | } 74 | if (!s) { 75 | if (len < 4) 76 | return NULL; 77 | s = ptr; 78 | } else { 79 | *size = (ptr - s); 80 | return s; 81 | } 82 | ptr += 3; 83 | len -= 3; 84 | continue; 85 | } 86 | ptr ++; 87 | len --; 88 | } 89 | if (!s) 90 | return NULL; 91 | *size = (ptr - s + len); 92 | return s; 93 | } 94 | 95 | const uint8_t *rtsp_find_aac_adts (const uint8_t *buff, int len, int *size) 96 | { 97 | const uint8_t *s = buff; 98 | while (len > 2) { 99 | if (s[0] == 0xff && (s[1] & 0xf0) == 0xf0) { 100 | break; 101 | } 102 | buff ++; 103 | len --; 104 | } 105 | 106 | if (len <= 2) 107 | return NULL; 108 | 109 | //aac_frame_length 110 | *size = 0; 111 | *size |= (s[3] & 3) << 11; 112 | *size |= (s[4] << 3); 113 | *size |= (s[5] >> 5); 114 | 115 | if (*size > len) 116 | return NULL; 117 | 118 | return s; 119 | } 120 | 121 | int rtsp_codec_data_parse_from_user_h264 (const uint8_t *codec_data, int data_len, struct codec_data_h264 *pst_codec_data) 122 | { 123 | const uint8_t *s = codec_data; 124 | const uint8_t *frame = NULL; 125 | int len = data_len; 126 | int size = 0; 127 | int ret = 0; 128 | 129 | while (len > 3) { 130 | uint8_t type = 0; 131 | if (pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) { 132 | break; 133 | } 134 | 135 | frame = rtsp_find_h264_h265_nalu(s, len, &size); 136 | if (!frame) { 137 | break; 138 | } 139 | 140 | len = len - (frame - s + size); 141 | s = frame + size; 142 | 143 | if (frame[2] == 0) { 144 | frame += 4; //drop 0001 145 | size -= 4; 146 | } else { 147 | frame += 3; //drop 001 148 | size -= 3; 149 | } 150 | 151 | type = frame[0] & 0x1f; 152 | if (type == 7) { 153 | dbg("sps %d\n", size); 154 | if (size > (int)sizeof(pst_codec_data->sps)) 155 | size = sizeof(pst_codec_data->sps); 156 | memcpy(pst_codec_data->sps, frame, size); 157 | pst_codec_data->sps_len = size; 158 | ret ++; 159 | } 160 | if (type == 8) { 161 | dbg("pps %d\n", size); 162 | if (size > (int)sizeof(pst_codec_data->pps)) 163 | size = sizeof(pst_codec_data->pps); 164 | memcpy(pst_codec_data->pps, frame, size); 165 | pst_codec_data->pps_len = size; 166 | ret ++; 167 | } 168 | } 169 | 170 | return (ret >= 2 ? 1 : 0); 171 | } 172 | 173 | int rtsp_codec_data_parse_from_user_h265 (const uint8_t *codec_data, int data_len, struct codec_data_h265 *pst_codec_data) 174 | { 175 | const uint8_t *s = codec_data; 176 | const uint8_t *frame = NULL; 177 | int len = data_len; 178 | int size = 0; 179 | int ret = 0; 180 | 181 | while (len > 3) { 182 | uint8_t type = 0; 183 | if (pst_codec_data->vps_len > 0 && pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) { 184 | break; 185 | } 186 | 187 | frame = rtsp_find_h264_h265_nalu(s, len, &size); 188 | if (!frame) { 189 | break; 190 | } 191 | 192 | len = len - (frame - s + size); 193 | s = frame + size; 194 | 195 | if (frame[2] == 0) { 196 | frame += 4; //drop 0001 197 | size -= 4; 198 | } else { 199 | frame += 3; //drop 001 200 | size -= 3; 201 | } 202 | 203 | type = (frame[0] >> 1) & 0x3f; 204 | if (type == 32) { 205 | dbg("vps %d\n", size); 206 | if (size > (int)sizeof(pst_codec_data->vps)) 207 | size = sizeof(pst_codec_data->vps); 208 | memcpy(pst_codec_data->vps, frame, size); 209 | pst_codec_data->vps_len = size; 210 | ret ++; 211 | } 212 | if (type == 33) { 213 | dbg("sps %d\n", size); 214 | if (size > (int)sizeof(pst_codec_data->sps)) 215 | size = sizeof(pst_codec_data->sps); 216 | memcpy(pst_codec_data->sps, frame, size); 217 | pst_codec_data->sps_len = size; 218 | ret ++; 219 | } 220 | if (type == 34) { 221 | dbg("pps %d\n", size); 222 | if (size > (int)sizeof(pst_codec_data->pps)) 223 | size = sizeof(pst_codec_data->pps); 224 | memcpy(pst_codec_data->pps, frame, size); 225 | pst_codec_data->pps_len = size; 226 | ret ++; 227 | } 228 | } 229 | 230 | return (ret >= 3 ? 1 : 0); 231 | } 232 | 233 | int rtsp_codec_data_parse_from_user_g726 (const uint8_t *codec_data, int data_len, struct codec_data_g726 *pst_codec_data) 234 | { 235 | int bit_rate; 236 | 237 | if (data_len != sizeof(bit_rate)) { 238 | err("bit rate invalid\n"); 239 | return -1; 240 | } 241 | 242 | bit_rate = *((int*)codec_data); 243 | 244 | switch (bit_rate) { 245 | case 16000: 246 | case 24000: 247 | case 32000: 248 | case 40000: 249 | break; 250 | default: 251 | err("bit rate invalid\n"); 252 | return -1; 253 | } 254 | 255 | pst_codec_data->bit_rate = bit_rate; 256 | return 1; 257 | } 258 | 259 | int rtsp_codec_data_parse_from_user_aac (const uint8_t *codec_data, int data_len, struct codec_data_aac *pst_codec_data) 260 | { 261 | int sample_rate_index, channels; 262 | const uint32_t sample_rate_tbl[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0}; 263 | if (data_len != 2) { 264 | err("audio specific config invalid\n"); 265 | return -1; 266 | } 267 | 268 | sample_rate_index = ((codec_data[0] & 0x7) << 1) | (codec_data[1] >> 7); 269 | channels = (codec_data[1] >> 3) & 0x0f; 270 | 271 | if (sample_rate_index > 12 || channels > 7) { 272 | err("audio specific config invalid\n"); 273 | return -1; 274 | } 275 | 276 | memcpy(pst_codec_data->audio_specific_config, codec_data, data_len); 277 | pst_codec_data->audio_specific_config_len = data_len; 278 | pst_codec_data->sample_rate = sample_rate_tbl[sample_rate_index]; 279 | pst_codec_data->channels = (channels == 7) ? 8 : channels; 280 | dbg("config=%02X%02X sample_rate=%d channels=%d\n", 281 | pst_codec_data->audio_specific_config[0], pst_codec_data->audio_specific_config[1], 282 | sample_rate_tbl[sample_rate_index], channels); 283 | 284 | return 1; 285 | } 286 | 287 | int rtsp_codec_data_parse_from_frame_h264 (const uint8_t *frame, int len, struct codec_data_h264 *pst_codec_data) 288 | { 289 | return rtsp_codec_data_parse_from_user_h264(frame, len, pst_codec_data); 290 | } 291 | 292 | int rtsp_codec_data_parse_from_frame_h265 (const uint8_t *frame, int len, struct codec_data_h265 *pst_codec_data) 293 | { 294 | return rtsp_codec_data_parse_from_user_h265(frame, len, pst_codec_data); 295 | } 296 | 297 | int rtsp_codec_data_parse_from_frame_aac (const uint8_t *frame, int len, struct codec_data_aac *pst_codec_data) 298 | { 299 | int profile, sample_rate_index, channels; 300 | const uint32_t sample_rate_tbl[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0}; 301 | int size = 0; 302 | 303 | if (pst_codec_data->audio_specific_config_len > 0) 304 | return 0; 305 | 306 | frame = rtsp_find_aac_adts(frame, len, &size); 307 | if (!frame) { 308 | err("find adts header failed\n"); 309 | return -1; 310 | } 311 | 312 | profile = frame[2] >> 6; 313 | sample_rate_index = (frame[2] >> 2) & 0x0f; 314 | channels = ((frame[2] & 0x1) << 1) | (frame[3] >> 6); 315 | 316 | if (sample_rate_index > 12 || channels > 7) { 317 | err("audio specific config invalid\n"); 318 | return -1; 319 | } 320 | 321 | pst_codec_data->audio_specific_config[0] = ((profile + 1) << 3) | ((sample_rate_index >> 1) & 0x7); 322 | pst_codec_data->audio_specific_config[1] = ((sample_rate_index & 0x1) << 7) | (channels << 3); 323 | pst_codec_data->audio_specific_config_len = 2; 324 | pst_codec_data->sample_rate = sample_rate_tbl[sample_rate_index]; 325 | pst_codec_data->channels = (channels == 7) ? 8 : channels; 326 | dbg("config=%02X%02X sample_rate=%d channels=%d\n", 327 | pst_codec_data->audio_specific_config[0], pst_codec_data->audio_specific_config[1], 328 | sample_rate_tbl[sample_rate_index], channels); 329 | 330 | return 1; 331 | } 332 | 333 | int rtsp_build_sdp_media_attr_h264 (int pt, int sample_rate, const struct codec_data_h264 *pst_codec_data, char *sdpbuf, int maxlen) 334 | { 335 | char *p = sdpbuf; 336 | // dbg("\n"); 337 | 338 | p += sprintf(p, "m=video 0 RTP/AVP %d\r\n", pt); 339 | p += sprintf(p, "a=rtpmap:%d H264/%d\r\n", pt, sample_rate); 340 | if (pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) { 341 | const uint8_t *sps = pst_codec_data->sps; 342 | const uint8_t *pps = pst_codec_data->pps; 343 | int sps_len = pst_codec_data->sps_len; 344 | int pps_len = pst_codec_data->pps_len; 345 | unsigned profileLevelId = (sps[1]<<16) | (sps[2]<<8) | sps[3]; 346 | p += sprintf(p, "a=fmtp:%d packetization-mode=1;profile-level-id=%06X;sprop-parameter-sets=", pt, profileLevelId); 347 | base64_encode(p, (maxlen - (p - sdpbuf)), sps, sps_len); 348 | p += strlen(p); 349 | p += sprintf(p, ","); 350 | base64_encode(p, (maxlen - (p - sdpbuf)), pps, pps_len); 351 | p += strlen(p); 352 | p += sprintf(p, "\r\n"); 353 | } else { 354 | p += sprintf(p, "a=fmtp:%d packetization-mode=1\r\n", pt); 355 | } 356 | 357 | return (p - sdpbuf); 358 | } 359 | 360 | int rtsp_build_sdp_media_attr_h265 (int pt, int sample_rate, const struct codec_data_h265 *pst_codec_data, char *sdpbuf, int maxlen) 361 | { 362 | char *p = sdpbuf; 363 | // dbg("\n"); 364 | 365 | p += sprintf(p, "m=video 0 RTP/AVP %d\r\n", pt); 366 | p += sprintf(p, "a=rtpmap:%d H265/%d\r\n", pt, sample_rate); 367 | if (pst_codec_data->vps_len > 0 && pst_codec_data->sps_len > 0 && pst_codec_data->pps_len > 0) { 368 | const uint8_t *vps = pst_codec_data->vps; 369 | const uint8_t *sps = pst_codec_data->sps; 370 | const uint8_t *pps = pst_codec_data->pps; 371 | int vps_len = pst_codec_data->vps_len; 372 | int sps_len = pst_codec_data->sps_len; 373 | int pps_len = pst_codec_data->pps_len; 374 | 375 | p += sprintf(p, "a=fmtp:%d", pt); 376 | p += sprintf(p, " sprop-vps="); 377 | base64_encode(p, (maxlen - (p - sdpbuf)), vps, vps_len); 378 | p += strlen(p); 379 | p += sprintf(p, ";sprop-sps="); 380 | base64_encode(p, (maxlen - (p - sdpbuf)), sps, sps_len); 381 | p += strlen(p); 382 | p += sprintf(p, ";sprop-pps="); 383 | base64_encode(p, (maxlen - (p - sdpbuf)), pps, pps_len); 384 | p += strlen(p); 385 | p += sprintf(p, "\r\n"); 386 | } 387 | 388 | return (p - sdpbuf); 389 | } 390 | 391 | int rtsp_build_sdp_media_attr_g711a (int pt, int sample_rate, char *sdpbuf, int maxlen) 392 | { 393 | char *p = sdpbuf; 394 | // dbg("\n"); 395 | 396 | p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt); 397 | p += sprintf(p, "a=rtpmap:%d PCMA/%d/1\r\n", pt, sample_rate); 398 | 399 | return (p - sdpbuf); 400 | } 401 | 402 | int rtsp_build_sdp_media_attr_g711u (int pt, int sample_rate, char *sdpbuf, int maxlen) 403 | { 404 | char *p = sdpbuf; 405 | // dbg("\n"); 406 | 407 | p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt); 408 | p += sprintf(p, "a=rtpmap:%d PCMU/%d/1\r\n", pt, sample_rate); 409 | 410 | return (p - sdpbuf); 411 | } 412 | 413 | int rtsp_build_sdp_media_attr_g726 (int pt, int sample_rate, const struct codec_data_g726 *pst_codec_data, char *sdpbuf, int maxlen) 414 | { 415 | char *p = sdpbuf; 416 | // dbg("\n"); 417 | 418 | p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt); 419 | p += sprintf(p, "a=rtpmap:%d G726-%d/%d/1\r\n", pt, 420 | pst_codec_data->bit_rate ? pst_codec_data->bit_rate / 1000 : 32, 421 | sample_rate); 422 | 423 | return (p - sdpbuf); 424 | } 425 | 426 | int rtsp_build_sdp_media_attr_aac (int pt, int sample_rate, const struct codec_data_aac *pst_codec_data, char *sdpbuf, int maxlen) 427 | { 428 | char *p = sdpbuf; 429 | // dbg("\n"); 430 | 431 | p += sprintf(p, "m=audio 0 RTP/AVP %d\r\n", pt); 432 | p += sprintf(p, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n", pt, 433 | pst_codec_data->sample_rate ? pst_codec_data->sample_rate : 44100, 434 | pst_codec_data->channels ? pst_codec_data->channels : 2); 435 | 436 | if (pst_codec_data->audio_specific_config_len == 2) { 437 | p += sprintf(p, "a=fmtp:%d profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=%02X%02X\r\n", 438 | pt, pst_codec_data->audio_specific_config[0], pst_codec_data->audio_specific_config[1]); 439 | } else { 440 | p += sprintf(p, "a=fmtp:%d profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3\r\n", pt); 441 | } 442 | return (p - sdpbuf); 443 | } 444 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: utils.h 3 | > Author: bxq 4 | > Mail: 544177215@qq.com 5 | > Created Time: Sunday, May 22, 2016 PM09:35:22 CST 6 | ************************************************************************/ 7 | 8 | #ifndef __UTILS_H__ 9 | #define __UTILS_H__ 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | struct codec_data_h264 { 18 | uint8_t sps[64]; //no nal leader code 001 19 | uint8_t pps[64]; 20 | uint32_t sps_len; 21 | uint32_t pps_len; 22 | }; 23 | 24 | struct codec_data_h265 { 25 | uint8_t vps[64]; 26 | uint8_t sps[64]; 27 | uint8_t pps[64]; 28 | uint32_t vps_len; 29 | uint32_t sps_len; 30 | uint32_t pps_len; 31 | }; 32 | 33 | struct codec_data_g726 { 34 | uint32_t bit_rate; 35 | }; 36 | 37 | struct codec_data_aac { 38 | uint8_t audio_specific_config[64]; 39 | uint32_t audio_specific_config_len; 40 | uint32_t sample_rate; 41 | uint32_t channels; 42 | }; 43 | 44 | char *base64_encode (char *out, int out_size, const uint8_t *in, int in_size); 45 | const uint8_t *rtsp_find_h264_h265_nalu (const uint8_t *buff, int len, int *size); 46 | 47 | int rtsp_codec_data_parse_from_user_h264 (const uint8_t *codec_data, int data_len, struct codec_data_h264 *pst_codec_data); 48 | int rtsp_codec_data_parse_from_user_h265 (const uint8_t *codec_data, int data_len, struct codec_data_h265 *pst_codec_data); 49 | int rtsp_codec_data_parse_from_user_g726 (const uint8_t *codec_data, int data_len, struct codec_data_g726 *pst_codec_data); 50 | int rtsp_codec_data_parse_from_user_aac (const uint8_t *codec_data, int data_len, struct codec_data_aac *pst_codec_data); 51 | 52 | int rtsp_codec_data_parse_from_frame_h264 (const uint8_t *frame, int len, struct codec_data_h264 *pst_codec_data); 53 | int rtsp_codec_data_parse_from_frame_h265 (const uint8_t *frame, int len, struct codec_data_h265 *pst_codec_data); 54 | int rtsp_codec_data_parse_from_frame_aac (const uint8_t *frame, int len, struct codec_data_aac *pst_codec_data); 55 | 56 | int rtsp_build_sdp_media_attr_h264 (int pt, int sample_rate, const struct codec_data_h264 *pst_codec_data, char *sdpbuf, int maxlen); 57 | int rtsp_build_sdp_media_attr_h265 (int pt, int sample_rate, const struct codec_data_h265 *pst_codec_data, char *sdpbuf, int maxlen); 58 | int rtsp_build_sdp_media_attr_g711a (int pt, int sample_rate, char *sdpbuf, int maxlen); 59 | int rtsp_build_sdp_media_attr_g711u (int pt, int sample_rate, char *sdpbuf, int maxlen); 60 | int rtsp_build_sdp_media_attr_g726 (int pt, int sample_rate, const struct codec_data_g726 *pst_codec_data, char *sdpbuf, int maxlen); 61 | int rtsp_build_sdp_media_attr_aac (int pt, int sample_rate, const struct codec_data_aac *pst_codec_data, char *sdpbuf, int maxlen); 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | #endif 67 | --------------------------------------------------------------------------------