diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 59766f69..5ed1f294 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -14,7 +14,7 @@ jobs: run: git submodule update --init - name: apt-get安装依赖库(非必选) - run: sudo apt-get update && sudo apt-get install -y cmake libssl-dev libmp4v2-dev libsdl-dev libavcodec-dev libavutil-dev + run: sudo apt-get update && sudo apt-get install -y cmake libssl-dev libsdl-dev libavcodec-dev libavutil-dev - name: 编译 run: mkdir -p linux_build && cd linux_build && cmake .. && make -j4 diff --git a/.gitignore b/.gitignore index f5ec7af1..61eb6410 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ /3rdpart/media-server/.idea/ /build/ /3rdpart/media-server/.idea/ +/ios/ diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 34b42499..681be205 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 34b42499ce9ee055b5c7cac9a270239984d0e839 +Subproject commit 681be205ef164db08effd83f925bb750eb1fe149 diff --git a/3rdpart/media-server b/3rdpart/media-server index 737b8d85..97cf5e47 160000 --- a/3rdpart/media-server +++ b/3rdpart/media-server @@ -1 +1 @@ -Subproject commit 737b8d852eeb1a36bc77854f327fbbef7cfb81be +Subproject commit 97cf5e47a5af1ff3d4d187f3ebffd9254595df75 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..c80c92fb --- /dev/null +++ b/AUTHORS @@ -0,0 +1,16 @@ +#代码贡献者列表,提交pr时请留下您的联系方式 +#Code contributor list, please leave your contact information when submitting a pull request + +xiongziliang <771730766@qq.com> +Gemfield +huohuo <913481084@qq.com> +[南冠彤](https://github.com/nanguantong2) +[凹凸慢](https://github.com/tsingeye) +[史前小虫](https://github.com/zqsong) +[清涩绿茶](https://github.com/baiyfcu) +[3503207480](https://github.com/3503207480) +[DroidChow](https://github.com/DroidChow) +[火宣](https://github.com/ChinaCCF) +[γ瑞γミ](https://github.com/JerryLinGd) +[茄子](https://github.com/taotaobujue2008) +[好心情](<409257224@qq.com>) diff --git a/Android/app/src/main/cpp/CMakeLists.txt b/Android/app/src/main/cpp/CMakeLists.txt index 2f1fbb0c..0f5ff4e8 100644 --- a/Android/app/src/main/cpp/CMakeLists.txt +++ b/Android/app/src/main/cpp/CMakeLists.txt @@ -37,10 +37,9 @@ endif () set(ENABLE_HLS true) set(ENABLE_OPENSSL true) set(ENABLE_MYSQL false) -set(ENABLE_MP4V2 true) set(ENABLE_FAAC false) set(ENABLE_X264 false) -set(ENABLE_MP4RECORD true) +set(ENABLE_MP4 true) #添加两个静态库 if(ENABLE_HLS) @@ -52,9 +51,9 @@ else() endif() -if(ENABLE_MP4RECORD) - message(STATUS "ENABLE_MP4RECORD defined") - add_definitions(-DENABLE_MP4RECORD) +if(ENABLE_MP4) + message(STATUS "ENABLE_MP4 defined") + add_definitions(-DENABLE_MP4) list(APPEND LINK_LIB_LIST mov flv) endif() @@ -66,16 +65,6 @@ if (ENABLE_OPENSSL) list(APPEND LINK_LIB_LIST ssl crypto) endif () -#查找MP4V2是否安装 -find_package(MP4V2 QUIET) -if (MP4V2_FOUND AND ENABLE_MP4V2) - include_directories(${MP4V2_INCLUDE_DIR}) - list(APPEND LINK_LIB_LIST ${MP4V2_LIBRARY}) - add_definitions(-DENABLE_MP4V2) - message(STATUS "found library:${MP4V2_LIBRARY},ENABLE_MP4V2 defined") -endif () - - #libmpeg if(ENABLE_HLS) aux_source_directory(${MediaServer_Root}/libmpeg/include src_mpeg) @@ -87,7 +76,7 @@ if(ENABLE_HLS) endif(WIN32) endif() -if(ENABLE_MP4RECORD) +if(ENABLE_MP4) aux_source_directory(${MediaServer_Root}/libmov/include src_mov) aux_source_directory(${MediaServer_Root}/libmov/source src_mov) include_directories(${MediaServer_Root}/libmov/include) diff --git a/Android/app/src/main/cpp/native-lib.cpp b/Android/app/src/main/cpp/native-lib.cpp index f6a2946c..ddcdd389 100644 --- a/Android/app/src/main/cpp/native-lib.cpp +++ b/Android/app/src/main/cpp/native-lib.cpp @@ -1,4 +1,14 @@ -#include +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include #include #include "Util/logger.h" #include "Thread/semaphore.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index ee853b01..bf4568b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,10 +43,9 @@ INCLUDE_DIRECTORIES(${MediaKit_Root}) set(ENABLE_HLS true) set(ENABLE_OPENSSL true) set(ENABLE_MYSQL false) -set(ENABLE_MP4V2 true) set(ENABLE_FAAC false) set(ENABLE_X264 false) -set(ENABLE_MP4RECORD true) +set(ENABLE_MP4 true) set(ENABLE_RTPPROXY true) set(LINK_LIB_LIST zlmediakit zltoolkit) @@ -70,15 +69,6 @@ if (MYSQL_FOUND AND ENABLE_MYSQL) list(APPEND LINK_LIB_LIST ${MYSQL_LIBRARIES}) endif () -#查找MP4V2是否安装 -find_package(MP4V2 QUIET) -if (MP4V2_FOUND AND ENABLE_MP4V2) - include_directories(${MP4V2_INCLUDE_DIR}) - list(APPEND LINK_LIB_LIST ${MP4V2_LIBRARY}) - add_definitions(-DENABLE_MP4V2) - message(STATUS "found library:${MP4V2_LIBRARY},ENABLE_MP4V2 defined") -endif () - #查找x264是否安装 find_package(X264 QUIET) if (X264_FOUND AND ENABLE_X264) @@ -127,9 +117,9 @@ if(ENABLE_HLS) endif() #添加mov、flv库用于MP4录制 -if(ENABLE_MP4RECORD) - message(STATUS "ENABLE_MP4RECORD defined") - add_definitions(-DENABLE_MP4RECORD) +if(ENABLE_MP4) + message(STATUS "ENABLE_MP4 defined") + add_definitions(-DENABLE_MP4) aux_source_directory(${MediaServer_Root}/libmov/include src_mov) aux_source_directory(${MediaServer_Root}/libmov/source src_mov) diff --git a/LICENSE b/LICENSE index 367501b6..cdbc206a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,6 @@ MIT License -Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -Copyright (c) 2019 Gemfield -Copyright (c) 2018 huohuo <913481084@qq.com> +Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 555289f3..973d55a0 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,6 @@ [![Build Status](https://travis-ci.org/xiongziliang/ZLMediaKit.svg?branch=master)](https://travis-ci.org/xiongziliang/ZLMediaKit) -## 国内用户请使用gitee镜像下载 -``` -git clone --depth 1 https://gitee.com/xiahcu/ZLMediaKit -cd ZLMediaKit -git submodule update --init -``` ## 项目特点 - 基于C++11开发,避免使用裸指针,代码稳定可靠;同时跨平台移植简单方便,代码清晰简洁。 - 打包多种流媒体协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV),支持协议间的互相转换,提供一站式的服务。 @@ -51,6 +45,7 @@ git submodule update --init - 支持http[s]-flv直播 - 支持websocket-flv直播 - 支持任意编码格式的rtmp推流,只是除H264/H265+AAC外无法转协议 + - 支持[RTMP-H265](https://github.com/ksvc/FFmpeg/wiki) - HLS - 支持HLS文件生成,自带HTTP文件服务器 @@ -85,20 +80,20 @@ git submodule update --init -## 其他功能细节表 +## 细节列表 - 转协议: | 功能/编码格式 | H264 | H265 | AAC | other | | :------------------------------: | :--: | :--: | :--: | :---: | - | RTSP[S] --> RTMP/HTTP[S]-FLV/FLV | Y | N | Y | N | - | RTMP --> RTSP[S] | Y | N | Y | N | + | RTSP[S] --> RTMP/HTTP[S]-FLV/FLV | Y | Y | Y | N | + | RTMP --> RTSP[S] | Y | Y | Y | N | | RTSP[S] --> HLS | Y | Y | Y | N | - | RTMP --> HLS | Y | N | Y | N | + | RTMP --> HLS | Y | Y | Y | N | | RTSP[S] --> MP4 | Y | Y | Y | N | - | RTMP --> MP4 | Y | N | Y | N | - | MP4 --> RTSP[S] | Y | N | Y | N | - | MP4 --> RTMP | Y | N | Y | N | + | RTMP --> MP4 | Y | Y | Y | N | + | MP4 --> RTSP[S] | Y | Y | Y | N | + | MP4 --> RTMP | Y | Y | Y | N | - 流生成: @@ -139,115 +134,17 @@ git submodule update --init | HTTP[S] | Y | | WebSocket[S] | Y | -## 后续任务 -- 完善支持H265 +## 编译以及测试 +请参考wiki:[快速开始](https://github.com/xiongziliang/ZLMediaKit/wiki/%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B) -## 编译要求 -- 编译器支持C++11,GCC4.8/Clang3.3/VC2015或以上 -- cmake3.2或以上 - -## 编译前必看!!! - -- **必须使用git下载完整的代码,不要使用下载zip包的方式下载源码,否则子模块代码默认不下载!你可以像以下这样操作:** -``` -git clone https://github.com/zlmediakit/ZLMediaKit.git -cd ZLMediaKit -git submodule update --init -``` - -## 编译(Linux) -- 我的编译环境 - - Ubuntu16.04 64 bit + gcc5.4 - - cmake 3.5.1 -- 编译 - - ``` - //如果是centos6.x,需要先安装较新版本的gcc以及cmake,然后打开脚本build_for_linux.sh手动编译 - //如果是ubuntu这样的比较新的系统版本可以直接操作第4步 - - 1、安装GCC5.2(如果gcc版本高于4.7可以跳过此步骤) - sudo yum install centos-release-scl -y - sudo yum install devtoolset-4-toolchain -y - scl enable devtoolset-4 bash - - 2、安装cmake - #需要安装新版本cmake,当然你也可以通过yum或者apt-get方式安装(前提是版本够新) - tar -xvf cmake-3.10.0-rc4.tar.gz - cd cmake-3.10.0-rc4 - ./configure - make -j4 - sudo make install - - 3、切换高版本gcc - scl enable devtoolset-4 bash - - 4、编译 - cd ZLMediaKit - ./build_for_linux.sh - ``` - -## 编译(macOS) -- 我的编译环境 - - macOS Sierra(10.12.1) + xcode8.3.1 - - Homebrew 1.1.3 - - cmake 3.8.0 -- 编译 - - ``` - cd ZLMediaKit - ./build_for_mac.sh - ``` - -## 编译(iOS) -- 编译环境:`请参考macOS的编译指导。` -- 生成Xcode工程再编译,[了解更多](https://github.com/leetal/ios-cmake): - - ``` - cd ZLMediaKit - mkdir -p build - cd build - # 生成Xcode工程,工程文件在build目录下 - cmake .. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../cmake/ios.toolchain.cmake -DPLATFORM=OS64COMBINED - ``` - -## 编译(Android) -- 我的编译环境 - - macOS Sierra(10.12.1) + xcode8.3.1 - - Homebrew 1.1.3 - - cmake 3.8.0 - - [android-ndk-r14b](https://dl.google.com/android/repository/android-ndk-r14b-darwin-x86_64.zip) -- 编译 - - ``` - cd ZLMediaKit - export ANDROID_NDK_ROOT=/path/to/ndk - ./build_for_android.sh - ``` -## 编译(Windows) -- 我的编译环境 - - windows 10 - - visual studio 2017 - - [cmake-gui](https://cmake.org/files/v3.10/cmake-3.10.0-rc1-win32-x86.msi) - -- 编译 -``` - 1 进入ZLMediaKit目录执行 git submodule update --init 以下载ZLToolKit的代码 - 2 使用cmake-gui打开工程并生成vs工程文件. -   3 找到工程文件(ZLMediaKit.sln),双击用vs2017打开. -   4 选择编译Release 版本. - 5 找到目标文件并运行测试用例. -``` - -## Docker Image -You can pull a pre-built docker image from Docker Hub and run with +## Docker 镜像 +你可以从Docker Hub下载已经编译好的镜像并启动它: ```bash -docker run -id -p 1935:1935 -p 8080:80 gemfield/zlmediakit +docker run -id -p 1935:1935 -p 8080:80 gemfield/zlmediakit:20.04-runtime-ubuntu18.04 ``` - -Dockerfile is also supplied to build images on Ubuntu 16.04 +你也可以根据Dockerfile编译镜像: ```bash -cd docker -docker build -t zlmediakit . +bash build_docker_images.sh ``` ## 使用方法 @@ -337,27 +234,6 @@ docker build -t zlmediakit . }); ``` -## QA -- 怎么测试服务器性能? - - ZLMediaKit提供了测试性能的示例,代码在tests/test_benchmark.cpp。 - - 这里是测试报告:[benchmark.md](https://github.com/xiongziliang/ZLMediaKit/blob/master/benchmark.md) - -- github下载太慢了,有其他下载方式吗? - - 你可以在通过开源中国获取最新的代码,地址为: - - [ZLToolKit](http://git.oschina.net/xiahcu/ZLToolKit) - - [ZLMediaKit](http://git.oschina.net/xiahcu/ZLMediaKit) - - -- 在windows下编译很多错误? - - 由于本项目主体代码在macOS/linux下开发,部分源码采用的是无bom头的UTF-8编码;由于windows对于utf-8支持不甚友好,所以如果发现编译错误请先尝试添 加bom头再编译。 - 也可以通过参考这篇博客解决: - [vs2015:/utf-8选项解决UTF-8 without BOM 源码中文输出乱码问题](https://blog.csdn.net/10km/article/details/80203286) ## 参考案例 - [IOS摄像头实时录制,生成rtsp/rtmp/hls/http-flv](https://gitee.com/xiahcu/IOSMedia) @@ -380,7 +256,7 @@ docker build -t zlmediakit . - 1、仔细看下readme、wiki,如果有必要可以查看下issue. - 2、如果您的问题还没解决,可以提issue. - 3、有些问题,如果不具备参考性的,无需在issue提的,可以在qq群提. - - 4、QQ私聊一般不接受无偿技术咨询和支持(谈谈人生理想还是可以的😂),毕竟精力有限,谢谢理解. + - 4、QQ私聊一般不接受无偿技术咨询和支持([为什么不提倡QQ私聊](https://github.com/xiongziliang/ZLMediaKit/wiki/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BB%BA%E8%AE%AEQQ%E7%A7%81%E8%81%8A%E5%92%A8%E8%AF%A2%E9%97%AE%E9%A2%98%EF%BC%9F)). ## 致谢 感谢以下各位对本项目包括但不限于代码贡献、问题反馈、资金捐赠等各种方式的支持!以下排名不分先后: diff --git a/README_en.md b/README_en.md index b92cfd15..9d1e5bd1 100644 --- a/README_en.md +++ b/README_en.md @@ -31,6 +31,7 @@ - H264/AAC codec. - Recorded as flv or mp4. - Vod of mp4. + - support [RTMP-H265](https://github.com/ksvc/FFmpeg/wiki) - HLS - RTSP RTMP can be converted into HLS,built-in HTTP server. @@ -58,14 +59,14 @@ | protocol/codec | H264 | H265 | AAC | other | | :------------------------------: | :--: | :--: | :--: | :---: | -| RTSP[S] --> RTMP/HTTP[S]-FLV/FLV | Y | N | Y | N | -| RTMP --> RTSP[S] | Y | N | Y | N | +| RTSP[S] --> RTMP/HTTP[S]-FLV/FLV | Y | Y | Y | N | +| RTMP --> RTSP[S] | Y | Y | Y | N | | RTSP[S] --> HLS | Y | Y | Y | N | -| RTMP --> HLS | Y | N | Y | N | +| RTMP --> HLS | Y | Y | Y | N | | RTSP[S] --> MP4 | Y | Y | Y | N | -| RTMP --> MP4 | Y | N | Y | N | -| MP4 --> RTSP[S] | Y | N | Y | N | -| MP4 --> RTMP | Y | N | Y | N | +| RTMP --> MP4 | Y | Y | Y | N | +| MP4 --> RTSP[S] | Y | Y | Y | N | +| MP4 --> RTMP | Y | Y | Y | N | - Stream generation: diff --git a/api/include/mk_common.h b/api/include/mk_common.h index 08100f69..623b8d98 100755 --- a/api/include/mk_common.h +++ b/api/include/mk_common.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_COMMON_H @@ -31,12 +15,12 @@ #if defined(_WIN32) #if defined(MediaKitApi_EXPORTS) - #define API_EXPORT __declspec(dllexport) - #else - #define API_EXPORT __declspec(dllimport) - #endif + #define API_EXPORT __declspec(dllexport) + #else + #define API_EXPORT __declspec(dllimport) + #endif - #define API_CALL __cdecl + #define API_CALL __cdecl #else #define API_EXPORT #define API_CALL diff --git a/api/include/mk_events.h b/api/include/mk_events.h index 3c7bd4f7..79f435a8 100644 --- a/api/include/mk_events.h +++ b/api/include/mk_events.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_EVENTS_H diff --git a/api/include/mk_events_objects.h b/api/include/mk_events_objects.h index 730f1dc0..7c74fab9 100644 --- a/api/include/mk_events_objects.h +++ b/api/include/mk_events_objects.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_EVENT_OBJECTS_H diff --git a/api/include/mk_httpclient.h b/api/include/mk_httpclient.h index 7acb91dd..39d5fcb4 100755 --- a/api/include/mk_httpclient.h +++ b/api/include/mk_httpclient.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_HTTPCLIENT_H_ diff --git a/api/include/mk_media.h b/api/include/mk_media.h index 1ec00bd5..02332892 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_MEDIA_H_ @@ -148,6 +132,22 @@ typedef void(API_CALL *on_mk_media_close)(void *user_data); */ API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close cb, void *user_data); +/** + * 收到客户端的seek请求时触发该回调 + * @param user_data 用户数据指针,通过mk_media_set_on_seek设置 + * @param stamp_ms seek至的时间轴位置,单位毫秒 + * @return 1代表将处理seek请求,0代表忽略该请求 + */ +typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms); + +/** + * 监听播放器seek请求事件 + * @param ctx 对象指针 + * @param cb 回调指针 + * @param user_data 用户数据指针 + */ +API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data); + /** * 获取总的观看人数 * @param ctx 对象指针 diff --git a/api/include/mk_mediakit.h b/api/include/mk_mediakit.h index c8911a1b..dc7c07c7 100755 --- a/api/include/mk_mediakit.h +++ b/api/include/mk_mediakit.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_API_H_ diff --git a/api/include/mk_player.h b/api/include/mk_player.h index 13ac2bbc..16eae126 100755 --- a/api/include/mk_player.h +++ b/api/include/mk_player.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_PLAYER_H_ diff --git a/api/include/mk_proxyplayer.h b/api/include/mk_proxyplayer.h index 96bb5bf8..3964af78 100644 --- a/api/include/mk_proxyplayer.h +++ b/api/include/mk_proxyplayer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_PROXY_PLAYER_H_ diff --git a/api/include/mk_pusher.h b/api/include/mk_pusher.h index cc4f2645..b6423b08 100644 --- a/api/include/mk_pusher.h +++ b/api/include/mk_pusher.h @@ -1,30 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #ifndef MK_PUSHER_H #define MK_PUSHER_H diff --git a/api/include/mk_recorder.h b/api/include/mk_recorder.h index c60e0e54..c14563ed 100644 --- a/api/include/mk_recorder.h +++ b/api/include/mk_recorder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_RECORDER_API_H_ @@ -60,7 +44,6 @@ API_EXPORT void API_CALL mk_flv_recorder_release(mk_flv_recorder ctx); */ API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *vhost, const char *app, const char *stream, const char *file_path); - ///////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// /** @@ -69,9 +52,9 @@ API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *v * @param vhost 虚拟主机 * @param app 应用名 * @param stream 流id - * @return 录制状态,0:未录制,1:等待MediaSource注册,注册成功后立即开始录制,2:MediaSource已注册,并且正在录制 + * @return 录制状态,0:未录制, 1:正在录制 */ -API_EXPORT int API_CALL mk_recorder_status(int type, const char *vhost, const char *app, const char *stream); +API_EXPORT int API_CALL mk_recorder_is_recording(int type, const char *vhost, const char *app, const char *stream); /** * 开始录制 @@ -80,11 +63,9 @@ API_EXPORT int API_CALL mk_recorder_status(int type, const char *vhost, const ch * @param app 应用名 * @param stream 流id * @param customized_path 录像文件保存自定义目录,默认为空或null则自动生成 - * @param wait_for_record 是否等待流注册后再录制,未注册时,置false将返回失败 - * @param continue_record 流注销时是否继续等待录制还是立即停止录制 - * @return 0代表成功,负数代表失败 + * @return 1代表成功,0代表失败 */ -API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const char *app, const char *stream, const char *customized_path, int wait_for_record, int continue_record); +API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const char *app, const char *stream, const char *customized_path); /** * 停止录制 @@ -96,11 +77,6 @@ API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const cha */ API_EXPORT int API_CALL mk_recorder_stop(int type, const char *vhost, const char *app, const char *stream); -/** - * 停止所有录制,一般程序退出时调用 - */ -API_EXPORT void API_CALL mk_recorder_stop_all(); - #ifdef __cplusplus } #endif diff --git a/api/include/mk_tcp.h b/api/include/mk_tcp.h index 34ffb342..1a2dac80 100644 --- a/api/include/mk_tcp.h +++ b/api/include/mk_tcp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_TCP_H diff --git a/api/include/mk_thread.h b/api/include/mk_thread.h index 2f9b0f37..87c651d1 100644 --- a/api/include/mk_thread.h +++ b/api/include/mk_thread.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_THREAD_H diff --git a/api/include/mk_util.h b/api/include/mk_util.h index e87599f8..63d761f1 100644 --- a/api/include/mk_util.h +++ b/api/include/mk_util.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_UTIL_H diff --git a/api/source/mk_common.cpp b/api/source/mk_common.cpp index 15eff659..ead4c361 100755 --- a/api/source/mk_common.cpp +++ b/api/source/mk_common.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_common.h" diff --git a/api/source/mk_events.cpp b/api/source/mk_events.cpp index 90499f86..e7f5d676 100644 --- a/api/source/mk_events.cpp +++ b/api/source/mk_events.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_events.h" diff --git a/api/source/mk_events_objects.cpp b/api/source/mk_events_objects.cpp index d7ea5534..d4249563 100644 --- a/api/source/mk_events_objects.cpp +++ b/api/source/mk_events_objects.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/api/source/mk_httpclient.cpp b/api/source/mk_httpclient.cpp index e1262011..93c9dd3a 100755 --- a/api/source/mk_httpclient.cpp +++ b/api/source/mk_httpclient.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "mk_httpclient.h" #include "Util/logger.h" diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index 210034d3..e6bb8481 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_media.h" @@ -42,16 +26,21 @@ public: ~MediaHelper(){} void attachEvent(){ - _channel->setListener(shared_from_this()); + _channel->setMediaListener(shared_from_this()); } DevChannel::Ptr &getChannel(){ return _channel; } - void setCallBack(on_mk_media_close cb, void *user_data){ - _cb = cb; - _user_data = user_data; + void setOnClose(on_mk_media_close cb, void *user_data){ + _on_close = cb; + _on_close_data = user_data; + } + + void setOnSeek(on_mk_media_seek cb, void *user_data){ + _on_seek = cb; + _on_seek_data = user_data; } protected: // 通知其停止推流 @@ -60,40 +49,45 @@ protected: //非强制关闭且正有人在观看该视频 return false; } - if(!_cb){ + if(!_on_close){ //未设置回调,没法关闭 WarnL << "请使用mk_media_set_on_close函数设置回调函数!"; return false; } //请在回调中调用mk_media_release函数释放资源,否则MediaSource::close()操作不会生效 - _cb(_user_data); + _on_close(_on_close_data); WarnL << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; return true; } - // 通知无人观看 - void onNoneReader(MediaSource &sender) override{ - if(_channel->totalReaderCount()){ - //统计有误,还有人在看 - return; + bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override{ + if(!_on_seek){ + return false; } - MediaSourceEvent::onNoneReader(sender); + return _on_seek(_on_seek_data,ui32Stamp); } - // 观看总人数 int totalReaderCount(MediaSource &sender) override{ return _channel->totalReaderCount(); } private: DevChannel::Ptr _channel; - on_mk_media_close _cb; - void *_user_data; + on_mk_media_close _on_close = nullptr; + on_mk_media_seek _on_seek = nullptr; + void *_on_seek_data; + void *_on_close_data; }; API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close cb, void *user_data){ assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; - (*obj)->setCallBack(cb,user_data); + (*obj)->setOnClose(cb, user_data); +} + +API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data){ + assert(ctx); + MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; + (*obj)->setOnSeek(cb, user_data); } API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx){ diff --git a/api/source/mk_player.cpp b/api/source/mk_player.cpp index 75c556ac..d9ba3fab 100755 --- a/api/source/mk_player.cpp +++ b/api/source/mk_player.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_player.h" @@ -32,41 +16,41 @@ using namespace toolkit; using namespace mediakit; API_EXPORT mk_player API_CALL mk_player_create() { - MediaPlayer::Ptr *obj = new MediaPlayer::Ptr(new MediaPlayer()); - return obj; + MediaPlayer::Ptr *obj = new MediaPlayer::Ptr(new MediaPlayer()); + return obj; } API_EXPORT void API_CALL mk_player_release(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr *obj = (MediaPlayer::Ptr *)ctx; - delete obj; + assert(ctx); + MediaPlayer::Ptr *obj = (MediaPlayer::Ptr *)ctx; + delete obj; } API_EXPORT void API_CALL mk_player_set_option(mk_player ctx,const char* key,const char *val){ - assert(ctx && key && val); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - string key_str(key), val_str(val); - player->getPoller()->async([key_str,val_str,player](){ - //切换线程后再操作 - (*player)[key_str] = val_str; - }); + assert(ctx && key && val); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + string key_str(key), val_str(val); + player->getPoller()->async([key_str,val_str,player](){ + //切换线程后再操作 + (*player)[key_str] = val_str; + }); } API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url) { - assert(ctx && url); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - string url_str(url); - player->getPoller()->async([url_str,player](){ - //切换线程后再操作 - player->play(url_str); - }); + assert(ctx && url); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + string url_str(url); + player->getPoller()->async([url_str,player](){ + //切换线程后再操作 + player->play(url_str); + }); } API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - player->getPoller()->async([pause,player](){ - //切换线程后再操作 - player->pause(pause); - }); + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + player->getPoller()->async([pause,player](){ + //切换线程后再操作 + player->pause(pause); + }); } API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) { @@ -79,100 +63,100 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) { } static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) { - assert(ctx && cb); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - player->getPoller()->async([cb,user_data,type,player](){ - //切换线程后再操作 - if(type == 0){ - player->setOnPlayResult([cb,user_data](const SockException &ex){ - cb(user_data,ex.getErrCode(),ex.what()); - }); - }else{ - player->setOnShutdown([cb,user_data](const SockException &ex){ - cb(user_data,ex.getErrCode(),ex.what()); - }); - } - }); + assert(ctx && cb); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + player->getPoller()->async([cb,user_data,type,player](){ + //切换线程后再操作 + if(type == 0){ + player->setOnPlayResult([cb,user_data](const SockException &ex){ + cb(user_data,ex.getErrCode(),ex.what()); + }); + }else{ + player->setOnShutdown([cb,user_data](const SockException &ex){ + cb(user_data,ex.getErrCode(),ex.what()); + }); + } + }); } API_EXPORT void API_CALL mk_player_set_on_result(mk_player ctx, on_mk_play_event cb, void *user_data) { - mk_player_set_on_event(ctx,cb,user_data,0); + mk_player_set_on_event(ctx,cb,user_data,0); } API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_event cb, void *user_data) { - mk_player_set_on_event(ctx,cb,user_data,1); + mk_player_set_on_event(ctx,cb,user_data,1); } API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data) { - assert(ctx && cb); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - player->getPoller()->async([player,cb,user_data](){ - //切换线程后再操作 - auto delegate = std::make_shared([cb,user_data](const Frame::Ptr &frame){ - cb(user_data,frame->getTrackType(),frame->getCodecId(),frame->data(),frame->size(),frame->dts(),frame->pts()); - }); - for(auto &track : player->getTracks()){ - track->addDelegate(delegate); - } - }); + assert(ctx && cb); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + player->getPoller()->async([player,cb,user_data](){ + //切换线程后再操作 + auto delegate = std::make_shared([cb,user_data](const Frame::Ptr &frame){ + cb(user_data,frame->getTrackType(),frame->getCodecId(),frame->data(),frame->size(),frame->dts(),frame->pts()); + }); + for(auto &track : player->getTracks()){ + track->addDelegate(delegate); + } + }); } API_EXPORT int API_CALL mk_player_video_width(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); - return track ? track->getVideoWidth() : 0; + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); + return track ? track->getVideoWidth() : 0; } API_EXPORT int API_CALL mk_player_video_height(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); - return track ? track->getVideoHeight() : 0; + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); + return track ? track->getVideoHeight() : 0; } API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); - return track ? track->getVideoFps() : 0; + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + auto track = dynamic_pointer_cast(player->getTrack(TrackVideo)); + return track ? track->getVideoFps() : 0; } API_EXPORT int API_CALL mk_player_audio_samplerate(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); - return track ? track->getAudioSampleRate() : 0; + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); + return track ? track->getAudioSampleRate() : 0; } API_EXPORT int API_CALL mk_player_audio_bit(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); - return track ? track->getAudioSampleBit() : 0; + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); + return track ? track->getAudioSampleBit() : 0; } API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); - return track ? track->getAudioChannel() : 0; + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + auto track = dynamic_pointer_cast(player->getTrack(TrackAudio)); + return track ? track->getAudioChannel() : 0; } API_EXPORT float API_CALL mk_player_duration(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - return player->getDuration(); + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + return player->getDuration(); } API_EXPORT float API_CALL mk_player_progress(mk_player ctx) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - return player->getProgress(); + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + return player->getProgress(); } API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type) { - assert(ctx); - MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); - return player->getPacketLossRate((TrackType)track_type); + assert(ctx); + MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); + return player->getPacketLossRate((TrackType)track_type); } diff --git a/api/source/mk_proxyplayer.cpp b/api/source/mk_proxyplayer.cpp index 00cb341a..91e496af 100644 --- a/api/source/mk_proxyplayer.cpp +++ b/api/source/mk_proxyplayer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_proxyplayer.h" diff --git a/api/source/mk_pusher.cpp b/api/source/mk_pusher.cpp index cdab8d26..06558f79 100644 --- a/api/source/mk_pusher.cpp +++ b/api/source/mk_pusher.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/api/source/mk_recorder.cpp b/api/source/mk_recorder.cpp index efd29c42..087bb3e9 100644 --- a/api/source/mk_recorder.cpp +++ b/api/source/mk_recorder.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_recorder.h" @@ -52,21 +36,17 @@ API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *v } ///////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// -API_EXPORT int API_CALL mk_recorder_status(int type, const char *vhost, const char *app, const char *stream){ +API_EXPORT int API_CALL mk_recorder_is_recording(int type, const char *vhost, const char *app, const char *stream){ assert(vhost && app && stream); - return Recorder::getRecordStatus((Recorder::type)type,vhost,app,stream); + return Recorder::isRecording((Recorder::type)type,vhost,app,stream); } -API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const char *app, const char *stream,const char *customized_path,int wait_for_record, int continue_record){ +API_EXPORT int API_CALL mk_recorder_start(int type, const char *vhost, const char *app, const char *stream,const char *customized_path){ assert(vhost && app && stream); - return Recorder::startRecord((Recorder::type)type,vhost,app,stream,customized_path ? customized_path : "",wait_for_record,continue_record); + return Recorder::startRecord((Recorder::type)type,vhost,app,stream,customized_path ? customized_path : ""); } API_EXPORT int API_CALL mk_recorder_stop(int type, const char *vhost, const char *app, const char *stream){ assert(vhost && app && stream); return Recorder::stopRecord((Recorder::type)type,vhost,app,stream); } - -API_EXPORT void API_CALL mk_recorder_stop_all(){ - Recorder::stopAll(); -} \ No newline at end of file diff --git a/api/source/mk_tcp.cpp b/api/source/mk_tcp.cpp index 4517ea00..ace6bd1d 100644 --- a/api/source/mk_tcp.cpp +++ b/api/source/mk_tcp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_tcp.h" diff --git a/api/source/mk_tcp_private.h b/api/source/mk_tcp_private.h index 379068f4..eba7401e 100644 --- a/api/source/mk_tcp_private.h +++ b/api/source/mk_tcp_private.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MK_TCP_PRIVATE_H diff --git a/api/source/mk_thread.cpp b/api/source/mk_thread.cpp index 185e54f1..950f7be7 100644 --- a/api/source/mk_thread.cpp +++ b/api/source/mk_thread.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_thread.h" diff --git a/api/source/mk_util.cpp b/api/source/mk_util.cpp index 97bd9158..0a4a9eca 100644 --- a/api/source/mk_util.cpp +++ b/api/source/mk_util.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "mk_util.h" diff --git a/api/tests/server.c b/api/tests/server.c index 575313bb..b481f170 100644 --- a/api/tests/server.c +++ b/api/tests/server.c @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/api/tests/websocket.c b/api/tests/websocket.c index 82e2a878..86e5c286 100644 --- a/api/tests/websocket.c +++ b/api/tests/websocket.c @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/build_docker_images.sh b/build_docker_images.sh index a642584f..4e8d1620 100644 --- a/build_docker_images.sh +++ b/build_docker_images.sh @@ -1,3 +1,6 @@ #!/bin/bash -docker build -t gemfield/zlmediakit:20.01-runtime-ubuntu18.04 -f docker/ubuntu18.04/Dockerfile.runtime . -#docker build -t gemfield/zlmediakit:20.01-devel-ubuntu18.04 -f docker/ubuntu18.04/Dockerfile.devel . +set -e +docker build -t gemfield/zlmediakit:20.04-runtime-ubuntu18.04 -f docker/ubuntu18.04/Dockerfile.runtime . +docker build -t gemfield/zlmediakit:20.04-devel-ubuntu18.04 -f docker/ubuntu18.04/Dockerfile.devel . +docker build -t gemfield/zlmediakit:20.04-runtime-ubuntu16.04 -f docker/ubuntu16.04/Dockerfile.runtime . +docker build -t gemfield/zlmediakit:20.04-devel-ubuntu16.04 -f docker/ubuntu16.04/Dockerfile.devel . diff --git a/build_for_android.sh b/build_for_android.sh deleted file mode 100755 index f6fca1b5..00000000 --- a/build_for_android.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -cd .. -git clone --depth=1 https://github.com/xiongziliang/ZLMediaKit.git -cd ZLMediaKit -git submodule init -git submodule update - -mkdir -p android_build -rm -rf ./build -ln -s ./android_build build -cd android_build -cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK_ROOT -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi" -DANDROID_NATIVE_API_LEVEL=android-9 -make -j4 diff --git a/build_for_linux.sh b/build_for_linux.sh index 2a510c59..afd674e1 100755 --- a/build_for_linux.sh +++ b/build_for_linux.sh @@ -6,11 +6,7 @@ git submodule init git submodule update sudo apt-get install cmake -sudo apt-get install libmysqlclient-dev sudo apt-get install libssl-dev -sudo apt-get install libx264-dev -sudo apt-get install libfaac-dev -sudo apt-get install libmp4v2-dev #sudo apt-get install libsdl-dev #sudo apt-get install libavcodec-dev #sudo apt-get install libavutil-dev diff --git a/build_for_mac.sh b/build_for_mac.sh index 60828d2d..fb812db6 100755 --- a/build_for_mac.sh +++ b/build_for_mac.sh @@ -6,11 +6,7 @@ git submodule init git submodule update brew install cmake -brew install mysql brew install openssl -brew install x264 -brew install faac -brew install mp4v2 brew install sdl brew install ffmpeg diff --git a/docker/ubuntu16.04/Dockerfile.devel b/docker/ubuntu16.04/Dockerfile.devel index 650bd206..56044904 100644 --- a/docker/ubuntu16.04/Dockerfile.devel +++ b/docker/ubuntu16.04/Dockerfile.devel @@ -23,9 +23,10 @@ RUN apt-get update && \ libmysqlclient-dev \ libx264-dev \ libfaac-dev \ + ffmpeg \ libmp4v2-dev && \ - apt autoremove -y && \ - apt clean -y && \ + apt-get autoremove -y && \ + apt-get clean -y && \ rm -rf /var/lib/apt/lists/* RUN mkdir -p /opt/media @@ -37,7 +38,7 @@ RUN git clone --depth=1 https://github.com/xiongziliang/ZLMediaKit && \ WORKDIR /opt/media/ZLMediaKit/build RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j4 + make ENV PATH /opt/media/ZLMediaKit/release/linux/Release/:$PATH CMD MediaServer diff --git a/docker/ubuntu16.04/Dockerfile.runtime b/docker/ubuntu16.04/Dockerfile.runtime index 4bd6382f..a21ec505 100644 --- a/docker/ubuntu16.04/Dockerfile.runtime +++ b/docker/ubuntu16.04/Dockerfile.runtime @@ -24,8 +24,8 @@ RUN apt-get update && \ libx264-dev \ libfaac-dev \ libmp4v2-dev && \ - apt autoremove -y && \ - apt clean -y && \ + apt-get autoremove -y && \ + apt-get clean -y && \ rm -rf /var/lib/apt/lists/* RUN mkdir -p /opt/media @@ -37,7 +37,7 @@ RUN git clone --depth=1 https://github.com/xiongziliang/ZLMediaKit && \ WORKDIR /opt/media/ZLMediaKit/build RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j4 + make FROM ubuntu:16.04 LABEL maintainer "Gemfield " @@ -51,12 +51,13 @@ RUN apt-get update && \ libssl-dev \ libx264-dev \ libfaac-dev \ + ffmpeg \ libmp4v2-dev && \ - apt autoremove -y && \ - apt clean -y && \ + apt-get autoremove -y && \ + apt-get clean -y && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/media/bin/ COPY --from=build /opt/media/ZLMediaKit/release/linux/Release/MediaServer /opt/media/bin/MediaServer ENV PATH /opt/media/bin:$PATH -CMD MediaServer \ No newline at end of file +CMD MediaServer diff --git a/docker/ubuntu18.04/Dockerfile.devel b/docker/ubuntu18.04/Dockerfile.devel index 335c9a3f..3cc05989 100644 --- a/docker/ubuntu18.04/Dockerfile.devel +++ b/docker/ubuntu18.04/Dockerfile.devel @@ -24,9 +24,10 @@ RUN apt-get update && \ libmysqlclient-dev \ libx264-dev \ libfaac-dev \ + ffmpeg \ libmp4v2-dev && \ - apt autoremove -y && \ - apt clean -y && \ + apt-get autoremove -y && \ + apt-get clean -y && \ rm -rf /var/lib/apt/lists/* RUN mkdir -p /opt/media @@ -38,7 +39,7 @@ RUN git clone --depth=1 https://github.com/xiongziliang/ZLMediaKit && \ WORKDIR /opt/media/ZLMediaKit/build RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j4 + make ENV PATH /opt/media/ZLMediaKit/release/linux/Release:$PATH -CMD MediaServer \ No newline at end of file +CMD MediaServer diff --git a/docker/ubuntu18.04/Dockerfile.runtime b/docker/ubuntu18.04/Dockerfile.runtime index f10c2658..72095512 100644 --- a/docker/ubuntu18.04/Dockerfile.runtime +++ b/docker/ubuntu18.04/Dockerfile.runtime @@ -24,8 +24,8 @@ RUN apt-get update && \ libx264-dev \ libfaac-dev \ libmp4v2-dev && \ - apt autoremove -y && \ - apt clean -y && \ + apt-get autoremove -y && \ + apt-get clean -y && \ rm -rf /var/lib/apt/lists/* RUN mkdir -p /opt/media @@ -37,7 +37,7 @@ RUN git clone --depth=1 https://github.com/xiongziliang/ZLMediaKit && \ WORKDIR /opt/media/ZLMediaKit/build RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j4 + make FROM ubuntu:18.04 LABEL maintainer "Gemfield " @@ -51,12 +51,13 @@ RUN apt-get update && \ libssl-dev \ libx264-dev \ libfaac-dev \ + ffmpeg \ libmp4v2-dev && \ - apt autoremove -y && \ - apt clean -y && \ + apt-get autoremove -y && \ + apt-get clean -y && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/media/bin/ COPY --from=build /opt/media/ZLMediaKit/release/linux/Release/MediaServer /opt/media/bin/MediaServer ENV PATH /opt/media/bin:$PATH -CMD MediaServer \ No newline at end of file +CMD MediaServer diff --git a/server/FFmpegSource.cpp b/server/FFmpegSource.cpp index d8a821c6..12e96345 100644 --- a/server/FFmpegSource.cpp +++ b/server/FFmpegSource.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "FFmpegSource.h" @@ -42,7 +26,7 @@ onceToken token([]() { //windows下先关闭FFmpeg日志(目前不支持日志重定向) mINI::Instance()[kCmd] = "%s -re -i \"%s\" -loglevel quiet -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s "; #else - string ffmpeg_bin = System::execute("which ffmpeg"); + string ffmpeg_bin = System::execute("which ffmpeg"); mINI::Instance()[kCmd] = "%s -re -i \"%s\" -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s "; #endif //默认ffmpeg命令路径为环境变量中路径 @@ -236,21 +220,12 @@ bool FFmpegSource::close(MediaSource &sender, bool force) { return true; } -void FFmpegSource::onNoneReader(MediaSource &sender) { - auto listener = _listener.lock(); - if(listener){ - listener->onNoneReader(sender); - }else{ - MediaSourceEvent::onNoneReader(sender); - } -} - int FFmpegSource::totalReaderCount(MediaSource &sender) { auto listener = _listener.lock(); if(listener){ return listener->totalReaderCount(sender); } - return 0; + return sender.readerCount(); } void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) { diff --git a/server/FFmpegSource.h b/server/FFmpegSource.h index a11144d7..bbafcb68 100644 --- a/server/FFmpegSource.h +++ b/server/FFmpegSource.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef FFMPEG_SOURCE_H @@ -59,7 +43,6 @@ private: //MediaSourceEvent override bool close(MediaSource &sender,bool force) override; - void onNoneReader(MediaSource &sender) override ; int totalReaderCount(MediaSource &sender) override; private: Process _process; diff --git a/server/Process.cpp b/server/Process.cpp index eb8eac4d..1eeb8081 100644 --- a/server/Process.cpp +++ b/server/Process.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -46,92 +30,92 @@ using namespace toolkit; void Process::run(const string &cmd, const string &log_file_tmp) { - kill(2000); + kill(2000); #ifdef _WIN32 - STARTUPINFO si; - PROCESS_INFORMATION pi; - ZeroMemory(&si, sizeof(si)); //结构体初始化; - ZeroMemory(&pi, sizeof(pi)); + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); //结构体初始化; + ZeroMemory(&pi, sizeof(pi)); - LPTSTR lpDir = const_cast(cmd.data()); + LPTSTR lpDir = const_cast(cmd.data()); - if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){ - //下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程 - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){ + //下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程 + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); - _pid = pi.dwProcessId; - InfoL << "start child proces " << _pid; - } else { - WarnL << "start child proces fail: " << GetLastError(); - } + _pid = pi.dwProcessId; + InfoL << "start child proces " << _pid; + } else { + WarnL << "start child proces fail: " << GetLastError(); + } #else - _pid = fork(); - if (_pid < 0) { - throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg()); - } - if (_pid == 0) { - //子进程关闭core文件生成 - struct rlimit rlim = { 0,0 }; - setrlimit(RLIMIT_CORE, &rlim); + _pid = fork(); + if (_pid < 0) { + throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg()); + } + if (_pid == 0) { + //子进程关闭core文件生成 + struct rlimit rlim = { 0,0 }; + setrlimit(RLIMIT_CORE, &rlim); - //在启动子进程时,暂时禁用SIGINT、SIGTERM信号 - // ignore the SIGINT and SIGTERM - signal(SIGINT, SIG_IGN); - signal(SIGTERM, SIG_IGN); + //在启动子进程时,暂时禁用SIGINT、SIGTERM信号 + // ignore the SIGINT and SIGTERM + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); - string log_file; - if (log_file_tmp.empty()) { - log_file = "/dev/null"; - } - else { - log_file = StrPrinter << log_file_tmp << "." << getpid(); - } + string log_file; + if (log_file_tmp.empty()) { + log_file = "/dev/null"; + } + else { + log_file = StrPrinter << log_file_tmp << "." << getpid(); + } - int log_fd = -1; - int flags = O_CREAT | O_WRONLY | O_APPEND; - mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU;// S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; - File::createfile_path(log_file.data(), mode); - if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) { - fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); - } - else { - // dup to stdout and stderr. - if (dup2(log_fd, STDOUT_FILENO) < 0) { - fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); - } - if (dup2(log_fd, STDERR_FILENO) < 0) { - fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); - } - // close log fd - ::close(log_fd); - } - fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data()); + int log_fd = -1; + int flags = O_CREAT | O_WRONLY | O_APPEND; + mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU;// S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; + File::createfile_path(log_file.data(), mode); + if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) { + fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); + } + else { + // dup to stdout and stderr. + if (dup2(log_fd, STDOUT_FILENO) < 0) { + fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); + } + if (dup2(log_fd, STDERR_FILENO) < 0) { + fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); + } + // close log fd + ::close(log_fd); + } + fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data()); - // close other fds - // TODO: do in right way. - for (int i = 3; i < 1024; i++) { - ::close(i); - } + // close other fds + // TODO: do in right way. + for (int i = 3; i < 1024; i++) { + ::close(i); + } - auto params = split(cmd, " "); - // memory leak in child process, it's ok. - char **charpv_params = new char *[params.size() + 1]; - for (int i = 0; i < (int)params.size(); i++) { - std::string &p = params[i]; - charpv_params[i] = (char *)p.data(); - } - // EOF: NULL - charpv_params[params.size()] = NULL; + auto params = split(cmd, " "); + // memory leak in child process, it's ok. + char **charpv_params = new char *[params.size() + 1]; + for (int i = 0; i < (int)params.size(); i++) { + std::string &p = params[i]; + charpv_params[i] = (char *)p.data(); + } + // EOF: NULL + charpv_params[params.size()] = NULL; - // TODO: execv or execvp - auto ret = execv(params[0].c_str(), charpv_params); - if (ret < 0) { - fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno)); - } - exit(ret); - } - InfoL << "start child proces " << _pid; + // TODO: execv or execvp + auto ret = execv(params[0].c_str(), charpv_params); + if (ret < 0) { + fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno)); + } + exit(ret); + } + InfoL << "start child proces " << _pid; #endif // _WIN32 } @@ -148,27 +132,27 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) { } int status = 0; #ifdef _WIN32 - HANDLE hProcess = NULL; - hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 - if (hProcess == NULL) { - return false; - } + HANDLE hProcess = NULL; + hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 + if (hProcess == NULL) { + return false; + } - CloseHandle(hProcess); + CloseHandle(hProcess); #else - pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG); - int exit_code = (status & 0xFF00) >> 8; - if (exit_code_ptr) { - *exit_code_ptr = (status & 0xFF00) >> 8; - } - if (p < 0) { - WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg(); - return false; - } - if (p > 0) { - InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code; - return false; - } + pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG); + int exit_code = (status & 0xFF00) >> 8; + if (exit_code_ptr) { + *exit_code_ptr = (status & 0xFF00) >> 8; + } + if (p < 0) { + WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg(); + return false; + } + if (p > 0) { + InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code; + return false; + } #endif // _WIN32 return true; @@ -180,22 +164,22 @@ static void s_kill(pid_t pid,int max_delay,bool force){ return; } #ifdef _WIN32 - HANDLE hProcess = NULL; - hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 - if (hProcess == NULL) { - WarnL << "\nOpen Process fAiled: " << GetLastError(); - return; - } - DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程 - if (ret == 0) { - WarnL << GetLastError; - } + HANDLE hProcess = NULL; + hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 + if (hProcess == NULL) { + WarnL << "\nOpen Process fAiled: " << GetLastError(); + return; + } + DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程 + if (ret == 0) { + WarnL << GetLastError; + } #else - if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) { - //进程可能已经退出了 - WarnL << "kill process " << pid << " failed:" << get_uv_errmsg(); - return; - } + if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) { + //进程可能已经退出了 + WarnL << "kill process " << pid << " failed:" << get_uv_errmsg(); + return; + } #endif // _WIN32 diff --git a/server/Process.h b/server/Process.h index 392ccbbf..3c870f9d 100644 --- a/server/Process.h +++ b/server/Process.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef ZLMEDIAKIT_PROCESS_H #define ZLMEDIAKIT_PROCESS_H diff --git a/server/System.cpp b/server/System.cpp index df666120..c92bcc70 100644 --- a/server/System.cpp +++ b/server/System.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if !defined(_WIN32) diff --git a/server/System.h b/server/System.h index 565b99b3..22abdc86 100644 --- a/server/System.h +++ b/server/System.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_SYSTEM_H diff --git a/server/WebApi.cpp b/server/WebApi.cpp index e72d36ec..6afad9b8 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -740,43 +724,37 @@ void installWebApi() { // 开始录制hls或MP4 api_regist1("/index/api/startRecord",[](API_ARGS1){ CHECK_SECRET(); - CHECK_ARGS("type","vhost","app","stream","wait_for_record","continue_record"); - - int result = Recorder::startRecord((Recorder::type)allArgs["type"].as(), - allArgs["vhost"], - allArgs["app"], - allArgs["stream"], - allArgs["customized_path"], - allArgs["wait_for_record"], - allArgs["continue_record"]); - val["result"] = result; + CHECK_ARGS("type","vhost","app","stream"); + val["result"] = Recorder::startRecord((Recorder::type) allArgs["type"].as(), + allArgs["vhost"], + allArgs["app"], + allArgs["stream"], + allArgs["customized_path"]); }); // 停止录制hls或MP4 api_regist1("/index/api/stopRecord",[](API_ARGS1){ CHECK_SECRET(); CHECK_ARGS("type","vhost","app","stream"); - int result = Recorder::stopRecord((Recorder::type)allArgs["type"].as(), - allArgs["vhost"], - allArgs["app"], - allArgs["stream"]); - val["result"] = result; + val["result"] = Recorder::stopRecord((Recorder::type) allArgs["type"].as(), + allArgs["vhost"], + allArgs["app"], + allArgs["stream"]); }); // 获取hls或MP4录制状态 - api_regist1("/index/api/getRecordStatus",[](API_ARGS1){ + api_regist1("/index/api/isRecording",[](API_ARGS1){ CHECK_SECRET(); CHECK_ARGS("type","vhost","app","stream"); - auto status = Recorder::getRecordStatus((Recorder::type)allArgs["type"].as(), - allArgs["vhost"], - allArgs["app"], - allArgs["stream"]); - val["status"] = (int)status; + val["status"] = Recorder::isRecording((Recorder::type) allArgs["type"].as(), + allArgs["vhost"], + allArgs["app"], + allArgs["stream"]); }); - //获取录像文件夹列表或mp4文件列表 - //http://127.0.0.1/index/api/getMp4RecordFile?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01 - api_regist1("/index/api/getMp4RecordFile", [](API_ARGS1){ + //获取录像文件夹列表或mp4文件列表 + //http://127.0.0.1/index/api/getMp4RecordFile?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01 + api_regist1("/index/api/getMp4RecordFile", [](API_ARGS1){ CHECK_SECRET(); CHECK_ARGS("vhost", "app", "stream"); auto record_path = Recorder::getRecordPath(Recorder::type_mp4, allArgs["vhost"], allArgs["app"],allArgs["stream"]); @@ -809,7 +787,7 @@ void installWebApi() { val["data"]["rootPath"] = record_path; val["data"]["paths"] = paths; - }); + }); ////////////以下是注册的Hook API//////////// api_regist1("/index/hook/on_publish",[](API_ARGS1){ diff --git a/server/WebApi.h b/server/WebApi.h index 2a917db3..028a5445 100644 --- a/server/WebApi.h +++ b/server/WebApi.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_WEBAPI_H diff --git a/server/WebHook.cpp b/server/WebHook.cpp index 65933573..113f2b41 100644 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -362,7 +346,7 @@ void installWebHook(){ do_http_hook(hook_stream_not_found,body, nullptr); }); -#ifdef ENABLE_MP4RECORD +#ifdef ENABLE_MP4 //录制mp4文件成功后广播 NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastRecordMP4,[](BroadcastRecordMP4Args){ if(!hook_enable || hook_record_mp4.empty()){ @@ -382,7 +366,7 @@ void installWebHook(){ //执行hook do_http_hook(hook_record_mp4,body, nullptr); }); -#endif //ENABLE_MP4RECORD +#endif //ENABLE_MP4 NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastShellLogin,[](BroadcastShellLoginArgs){ if(!hook_enable || hook_shell_login.empty() || sender.get_peer_ip() == "127.0.0.1"){ diff --git a/server/WebHook.h b/server/WebHook.h index 14af5974..0d39278e 100644 --- a/server/WebHook.h +++ b/server/WebHook.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_WEBHOOK_H diff --git a/server/main.cpp b/server/main.cpp index 6d26bbe9..55ea061e 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -354,12 +338,11 @@ int start_main(int argc,char *argv[]) { } unInstallWebApi(); unInstallWebHook(); - Recorder::stopAll(); //休眠1秒再退出,防止资源释放顺序错误 InfoL << "程序退出中,请等待..."; sleep(1); InfoL << "程序退出完毕!"; - return 0; + return 0; } #ifndef DISABLE_MAIN diff --git a/src/Codec/AACEncoder.cpp b/src/Codec/AACEncoder.cpp index e2241f30..e14c054b 100644 --- a/src/Codec/AACEncoder.cpp +++ b/src/Codec/AACEncoder.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifdef ENABLE_FAAC @@ -47,73 +31,73 @@ AACEncoder::AACEncoder() { } AACEncoder::~AACEncoder() { - if (_hEncoder != nullptr) { - faacEncClose(_hEncoder); - _hEncoder = nullptr; - } - if (_pucAacBuf != nullptr) { - delete[] _pucAacBuf; - _pucAacBuf = nullptr; - } - if (_pucPcmBuf != nullptr) { - delete[] _pucPcmBuf; - _pucPcmBuf = nullptr; - } + if (_hEncoder != nullptr) { + faacEncClose(_hEncoder); + _hEncoder = nullptr; + } + if (_pucAacBuf != nullptr) { + delete[] _pucAacBuf; + _pucAacBuf = nullptr; + } + if (_pucPcmBuf != nullptr) { + delete[] _pucPcmBuf; + _pucPcmBuf = nullptr; + } } bool AACEncoder::init(int iSampleRate, int iChannels, int iSampleBit) { - if (iSampleBit != 16) { - return false; - } - // (1) Open FAAC engine - _hEncoder = faacEncOpen(iSampleRate, iChannels, &_ulInputSamples, - &_ulMaxOutputBytes); - if (_hEncoder == NULL) { - return false; - } - _pucAacBuf = new unsigned char[_ulMaxOutputBytes]; - _ulMaxInputBytes = _ulInputSamples * iSampleBit / 8; - _pucPcmBuf = new unsigned char[_ulMaxInputBytes * 4]; + if (iSampleBit != 16) { + return false; + } + // (1) Open FAAC engine + _hEncoder = faacEncOpen(iSampleRate, iChannels, &_ulInputSamples, + &_ulMaxOutputBytes); + if (_hEncoder == NULL) { + return false; + } + _pucAacBuf = new unsigned char[_ulMaxOutputBytes]; + _ulMaxInputBytes = _ulInputSamples * iSampleBit / 8; + _pucPcmBuf = new unsigned char[_ulMaxInputBytes * 4]; - // (2.1) Get current encoding configuration - faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(_hEncoder); - if (pConfiguration == NULL) { - faacEncClose(_hEncoder); - return false; - } - pConfiguration->aacObjectType =LOW; - pConfiguration->mpegVersion = 4; - pConfiguration->useTns = 1; - pConfiguration->shortctl = SHORTCTL_NORMAL; - pConfiguration->useLfe = 1; - pConfiguration->allowMidside = 1; - pConfiguration->bitRate = 0; - pConfiguration->bandWidth = 0; - pConfiguration->quantqual = 50; - pConfiguration->outputFormat = 1; - pConfiguration->inputFormat = FAAC_INPUT_16BIT; + // (2.1) Get current encoding configuration + faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(_hEncoder); + if (pConfiguration == NULL) { + faacEncClose(_hEncoder); + return false; + } + pConfiguration->aacObjectType =LOW; + pConfiguration->mpegVersion = 4; + pConfiguration->useTns = 1; + pConfiguration->shortctl = SHORTCTL_NORMAL; + pConfiguration->useLfe = 1; + pConfiguration->allowMidside = 1; + pConfiguration->bitRate = 0; + pConfiguration->bandWidth = 0; + pConfiguration->quantqual = 50; + pConfiguration->outputFormat = 1; + pConfiguration->inputFormat = FAAC_INPUT_16BIT; - // (2.2) Set encoding configuration - if(!faacEncSetConfiguration(_hEncoder, pConfiguration)){ - ErrorL << "faacEncSetConfiguration failed"; - faacEncClose(_hEncoder); - return false; - } - return true; + // (2.2) Set encoding configuration + if(!faacEncSetConfiguration(_hEncoder, pConfiguration)){ + ErrorL << "faacEncSetConfiguration failed"; + faacEncClose(_hEncoder); + return false; + } + return true; } int AACEncoder::inputData(char *pcPcmBufr, int iLen, unsigned char **ppucOutBuffer) { - memcpy(_pucPcmBuf + _uiPcmLen, pcPcmBufr, iLen); - _uiPcmLen += iLen; - if (_uiPcmLen < _ulMaxInputBytes) { - return 0; - } + memcpy(_pucPcmBuf + _uiPcmLen, pcPcmBufr, iLen); + _uiPcmLen += iLen; + if (_uiPcmLen < _ulMaxInputBytes) { + return 0; + } - int nRet = faacEncEncode(_hEncoder, (int32_t *) (_pucPcmBuf), _ulInputSamples, _pucAacBuf, _ulMaxOutputBytes); - _uiPcmLen -= _ulMaxInputBytes; - memmove(_pucPcmBuf, _pucPcmBuf + _ulMaxInputBytes, _uiPcmLen); - *ppucOutBuffer = _pucAacBuf; - return nRet; + int nRet = faacEncEncode(_hEncoder, (int32_t *) (_pucPcmBuf), _ulInputSamples, _pucAacBuf, _ulMaxOutputBytes); + _uiPcmLen -= _ulMaxInputBytes; + memmove(_pucPcmBuf, _pucPcmBuf + _ulMaxInputBytes, _uiPcmLen); + *ppucOutBuffer = _pucAacBuf; + return nRet; } } /* namespace mediakit */ diff --git a/src/Codec/AACEncoder.h b/src/Codec/AACEncoder.h index be194816..29440518 100644 --- a/src/Codec/AACEncoder.h +++ b/src/Codec/AACEncoder.h @@ -1,30 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #ifndef CODEC_AACENCODER_H_ #define CODEC_AACENCODER_H_ @@ -32,21 +15,21 @@ namespace mediakit { class AACEncoder { public: - AACEncoder(void); - virtual ~AACEncoder(void); - bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit); - int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer); + AACEncoder(void); + virtual ~AACEncoder(void); + bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit); + int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer); private: - unsigned char *_pucPcmBuf = nullptr; - unsigned int _uiPcmLen = 0; + unsigned char *_pucPcmBuf = nullptr; + unsigned int _uiPcmLen = 0; - unsigned char *_pucAacBuf = nullptr; - void *_hEncoder = nullptr; + unsigned char *_pucAacBuf = nullptr; + void *_hEncoder = nullptr; - unsigned long _ulInputSamples = 0; - unsigned long _ulMaxInputBytes = 0; - unsigned long _ulMaxOutputBytes = 0; + unsigned long _ulInputSamples = 0; + unsigned long _ulMaxInputBytes = 0; + unsigned long _ulMaxOutputBytes = 0; }; diff --git a/src/Codec/H264Encoder.cpp b/src/Codec/H264Encoder.cpp index 94b25f60..bddb6ea8 100644 --- a/src/Codec/H264Encoder.cpp +++ b/src/Codec/H264Encoder.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifdef ENABLE_X264 @@ -38,21 +22,21 @@ H264Encoder::H264Encoder() { } H264Encoder::~H264Encoder() { - //* 清除图像区域 - if (_pPicIn) { - delete _pPicIn; - _pPicIn = nullptr; - } - if (_pPicOut) { - delete _pPicOut; - _pPicOut = nullptr; - } + //* 清除图像区域 + if (_pPicIn) { + delete _pPicIn; + _pPicIn = nullptr; + } + if (_pPicOut) { + delete _pPicOut; + _pPicOut = nullptr; + } - //* 关闭编码器句柄 - if (_pX264Handle) { - x264_encoder_close(_pX264Handle); - _pX264Handle = nullptr; - } + //* 关闭编码器句柄 + if (_pX264Handle) { + x264_encoder_close(_pX264Handle); + _pX264Handle = nullptr; + } } @@ -229,122 +213,122 @@ Value的值就是fps。 } x264_param_t;*/ bool H264Encoder::init(int iWidth, int iHeight, int iFps) { - if (_pX264Handle) { - return true; - } - x264_param_t X264Param, *pX264Param = &X264Param; - //* 配置参数 - //* 使用默认参数 - x264_param_default_preset(pX264Param, "ultrafast", "zerolatency"); + if (_pX264Handle) { + return true; + } + x264_param_t X264Param, *pX264Param = &X264Param; + //* 配置参数 + //* 使用默认参数 + x264_param_default_preset(pX264Param, "ultrafast", "zerolatency"); - //* cpuFlags - pX264Param->i_threads = X264_SYNC_LOOKAHEAD_AUTO; //* 取空缓冲区继续使用不死锁的保证. - //* video Properties - pX264Param->i_width = iWidth; //* 宽度. - pX264Param->i_height = iHeight; //* 高度 - pX264Param->i_frame_total = 0; //* 编码总帧数.不知道用0. - pX264Param->i_keyint_max = iFps * 3; //ffmpeg:gop_size 关键帧最大间隔 - pX264Param->i_keyint_min = iFps * 1; //ffmpeg:keyint_min 关键帧最小间隔 - //* Rate control Parameters - pX264Param->rc.i_bitrate = 5000; //* 码率(比特率,单位Kbps) - pX264Param->rc.i_qp_step = 1; //最大的在帧与帧之间进行切变的量化因子的变化量。ffmpeg:max_qdiff - pX264Param->rc.i_qp_min = 10; //ffmpeg:qmin;最小的量化因子。取值范围1-51。建议在10-30之间。 - pX264Param->rc.i_qp_max = 41; //ffmpeg:qmax;最大的量化因子。取值范围1-51。建议在10-30之间。 - pX264Param->rc.f_qcompress = 0.6;//ffmpeg:qcompress 量化器压缩比率0-1.越小则比特率越区域固定,但是越高越使量化器参数越固定 - pX264Param->analyse.i_me_range = 16; //ffmpeg:me_range 运动侦测的半径 - pX264Param->i_frame_reference = 3; //ffmpeg:refsB和P帧向前预测参考的帧数。取值范围1-16。 - //该值不影响解码的速度,但是越大解码 - //所需的内存越大。这个值在一般情况下 - //越大效果越好,但是超过6以后效果就 - //不明显了。 + //* cpuFlags + pX264Param->i_threads = X264_SYNC_LOOKAHEAD_AUTO; //* 取空缓冲区继续使用不死锁的保证. + //* video Properties + pX264Param->i_width = iWidth; //* 宽度. + pX264Param->i_height = iHeight; //* 高度 + pX264Param->i_frame_total = 0; //* 编码总帧数.不知道用0. + pX264Param->i_keyint_max = iFps * 3; //ffmpeg:gop_size 关键帧最大间隔 + pX264Param->i_keyint_min = iFps * 1; //ffmpeg:keyint_min 关键帧最小间隔 + //* Rate control Parameters + pX264Param->rc.i_bitrate = 5000; //* 码率(比特率,单位Kbps) + pX264Param->rc.i_qp_step = 1; //最大的在帧与帧之间进行切变的量化因子的变化量。ffmpeg:max_qdiff + pX264Param->rc.i_qp_min = 10; //ffmpeg:qmin;最小的量化因子。取值范围1-51。建议在10-30之间。 + pX264Param->rc.i_qp_max = 41; //ffmpeg:qmax;最大的量化因子。取值范围1-51。建议在10-30之间。 + pX264Param->rc.f_qcompress = 0.6;//ffmpeg:qcompress 量化器压缩比率0-1.越小则比特率越区域固定,但是越高越使量化器参数越固定 + pX264Param->analyse.i_me_range = 16; //ffmpeg:me_range 运动侦测的半径 + pX264Param->i_frame_reference = 3; //ffmpeg:refsB和P帧向前预测参考的帧数。取值范围1-16。 + //该值不影响解码的速度,但是越大解码 + //所需的内存越大。这个值在一般情况下 + //越大效果越好,但是超过6以后效果就 + //不明显了。 - pX264Param->analyse.i_trellis = 1; //ffmpeg:trellis - //pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式 - pX264Param->rc.f_qblur = 0.5; //ffmpeg:qblur + pX264Param->analyse.i_trellis = 1; //ffmpeg:trellis + //pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式 + pX264Param->rc.f_qblur = 0.5; //ffmpeg:qblur - //* bitstream parameters - /*open-GOP - 码流里面包含B帧的时候才会出现open-GOP。 - 一个GOP里面的某一帧在解码时要依赖于前一个GOP的某些帧, - 这个GOP就称为open-GOP。 - 有些解码器不能完全支持open-GOP码流, - 例如蓝光解码器,因此在x264里面open-GOP是默认关闭的。 - 对于解码端,接收到的码流如果如下:I0 B0 B1 P0 B2 B3...这就是一个open-GOP码流(I帧后面紧跟B帧)。 - 因此B0 B1的解码需要用到I0前面一个GOP的数据,B0 B1的dts是小于I0的。 - 如果码流如下: I0 P0 B0 B1 P1 B2 B3...这就是一个close-GOP码流, - I0后面所有帧的解码不依赖于I0前面的帧,I0后面所有帧的dts都比I0的大。 - 如果码流是IDR0 B0 B1 P0 B2 B3...那个这个GOP是close-GOP,B0,B1虽然dst比IDR0小, - 但编解码端都刷新了参考缓冲,B0,B1参考不到前向GOP帧。 - 对于编码端,如果编码帧类型决定如下: ...P0 B1 B2 P3 B4 B5 I6这就会输出open-Gop码流 (P0 P3 B1 B2 I6 B4 B5...), - B4 B5的解码依赖P3。 - 如果编码帧类型决定如下...P0 B1 B2 P3 B4 P5 I6这样就不会输出open-GOP码流(P0 P3 B1 B2 P5 B4 I6...)。 - 两者区别在于I6前面的第5帧是设置为B帧还是P帧, - 如果一个GOP的最后一帧(上例中是第5帧)设置为B帧, - 这个码流就是open-GOP,设置为P帧就是close-GOP。 - 由于B帧压缩性能好于P帧,因此open-GOP在编码性能上稍微优于close-GOP, - 但为了兼容性和少一些麻烦,还是把opne-GOP关闭的好。*/ - pX264Param->b_open_gop = 0; - pX264Param->i_bframe = 0; //最大B帧数. - pX264Param->i_bframe_pyramid = 0; - pX264Param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; - //* Log - pX264Param->i_log_level = X264_LOG_ERROR; + //* bitstream parameters + /*open-GOP + 码流里面包含B帧的时候才会出现open-GOP。 + 一个GOP里面的某一帧在解码时要依赖于前一个GOP的某些帧, + 这个GOP就称为open-GOP。 + 有些解码器不能完全支持open-GOP码流, + 例如蓝光解码器,因此在x264里面open-GOP是默认关闭的。 + 对于解码端,接收到的码流如果如下:I0 B0 B1 P0 B2 B3...这就是一个open-GOP码流(I帧后面紧跟B帧)。 + 因此B0 B1的解码需要用到I0前面一个GOP的数据,B0 B1的dts是小于I0的。 + 如果码流如下: I0 P0 B0 B1 P1 B2 B3...这就是一个close-GOP码流, + I0后面所有帧的解码不依赖于I0前面的帧,I0后面所有帧的dts都比I0的大。 + 如果码流是IDR0 B0 B1 P0 B2 B3...那个这个GOP是close-GOP,B0,B1虽然dst比IDR0小, + 但编解码端都刷新了参考缓冲,B0,B1参考不到前向GOP帧。 + 对于编码端,如果编码帧类型决定如下: ...P0 B1 B2 P3 B4 B5 I6这就会输出open-Gop码流 (P0 P3 B1 B2 I6 B4 B5...), + B4 B5的解码依赖P3。 + 如果编码帧类型决定如下...P0 B1 B2 P3 B4 P5 I6这样就不会输出open-GOP码流(P0 P3 B1 B2 P5 B4 I6...)。 + 两者区别在于I6前面的第5帧是设置为B帧还是P帧, + 如果一个GOP的最后一帧(上例中是第5帧)设置为B帧, + 这个码流就是open-GOP,设置为P帧就是close-GOP。 + 由于B帧压缩性能好于P帧,因此open-GOP在编码性能上稍微优于close-GOP, + 但为了兼容性和少一些麻烦,还是把opne-GOP关闭的好。*/ + pX264Param->b_open_gop = 0; + pX264Param->i_bframe = 0; //最大B帧数. + pX264Param->i_bframe_pyramid = 0; + pX264Param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + //* Log + pX264Param->i_log_level = X264_LOG_ERROR; - //* muxing parameters - pX264Param->i_fps_den = 1; //* 帧率分母 - pX264Param->i_fps_num = iFps; //* 帧率分子 - pX264Param->i_timebase_den = pX264Param->i_fps_num; - pX264Param->i_timebase_num = pX264Param->i_fps_den; + //* muxing parameters + pX264Param->i_fps_den = 1; //* 帧率分母 + pX264Param->i_fps_num = iFps; //* 帧率分子 + pX264Param->i_timebase_den = pX264Param->i_fps_num; + pX264Param->i_timebase_num = pX264Param->i_fps_den; - pX264Param->analyse.i_subpel_refine = 1; //这个参数控制在运动估算过程中质量和速度的权衡。Subq=5可以压缩>10%于subq=1。1-7 - pX264Param->analyse.b_fast_pskip = 1; //在P帧内执行早期快速跳跃探测。这个经常在没有任何损失的前提下提高了速度。 + pX264Param->analyse.i_subpel_refine = 1; //这个参数控制在运动估算过程中质量和速度的权衡。Subq=5可以压缩>10%于subq=1。1-7 + pX264Param->analyse.b_fast_pskip = 1; //在P帧内执行早期快速跳跃探测。这个经常在没有任何损失的前提下提高了速度。 - pX264Param->b_annexb = 1; //1前面为0x00000001,0为nal长度 - pX264Param->b_repeat_headers = 1; //关键帧前面是否放sps跟pps帧,0 否 1,放 + pX264Param->b_annexb = 1; //1前面为0x00000001,0为nal长度 + pX264Param->b_repeat_headers = 1; //关键帧前面是否放sps跟pps帧,0 否 1,放 - //* 设置Profile.使用baseline - x264_param_apply_profile(pX264Param, "high"); + //* 设置Profile.使用baseline + x264_param_apply_profile(pX264Param, "high"); - //* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264 - //* 的参数.通过x264_encoder_reconfig更新X264的参数 - _pX264Handle = x264_encoder_open(pX264Param); - if (!_pX264Handle) { - return false; - } - _pPicIn = new x264_picture_t; - _pPicOut = new x264_picture_t; - x264_picture_init(_pPicIn); - x264_picture_init(_pPicOut); - _pPicIn->img.i_csp = X264_CSP_I420; - _pPicIn->img.i_plane = 3; - return true; + //* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264 + //* 的参数.通过x264_encoder_reconfig更新X264的参数 + _pX264Handle = x264_encoder_open(pX264Param); + if (!_pX264Handle) { + return false; + } + _pPicIn = new x264_picture_t; + _pPicOut = new x264_picture_t; + x264_picture_init(_pPicIn); + x264_picture_init(_pPicOut); + _pPicIn->img.i_csp = X264_CSP_I420; + _pPicIn->img.i_plane = 3; + return true; } int H264Encoder::inputData(char* apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame** ppFrame) { - //TimeTicker1(5); - _pPicIn->img.i_stride[0] = aiYuvLen[0]; - _pPicIn->img.i_stride[1] = aiYuvLen[1]; - _pPicIn->img.i_stride[2] = aiYuvLen[2]; - _pPicIn->img.plane[0] = (uint8_t *) apcYuv[0]; - _pPicIn->img.plane[1] = (uint8_t *) apcYuv[1]; - _pPicIn->img.plane[2] = (uint8_t *) apcYuv[2]; - _pPicIn->i_pts = i64Pts; - int iNal; - x264_nal_t* pNals; + //TimeTicker1(5); + _pPicIn->img.i_stride[0] = aiYuvLen[0]; + _pPicIn->img.i_stride[1] = aiYuvLen[1]; + _pPicIn->img.i_stride[2] = aiYuvLen[2]; + _pPicIn->img.plane[0] = (uint8_t *) apcYuv[0]; + _pPicIn->img.plane[1] = (uint8_t *) apcYuv[1]; + _pPicIn->img.plane[2] = (uint8_t *) apcYuv[2]; + _pPicIn->i_pts = i64Pts; + int iNal; + x264_nal_t* pNals; - int iResult = x264_encoder_encode(_pX264Handle, &pNals, &iNal, _pPicIn, - _pPicOut); - if (iResult <= 0) { - return 0; - } - for (int i = 0; i < iNal; i++) { - x264_nal_t pNal = pNals[i]; - _aFrames[i].iType = pNal.i_type; - _aFrames[i].iLength = pNal.i_payload; - _aFrames[i].pucData = pNal.p_payload; - } - *ppFrame = _aFrames; - return iNal; + int iResult = x264_encoder_encode(_pX264Handle, &pNals, &iNal, _pPicIn, + _pPicOut); + if (iResult <= 0) { + return 0; + } + for (int i = 0; i < iNal; i++) { + x264_nal_t pNal = pNals[i]; + _aFrames[i].iType = pNal.i_type; + _aFrames[i].iLength = pNal.i_payload; + _aFrames[i].pucData = pNal.p_payload; + } + *ppFrame = _aFrames; + return iNal; } } /* namespace mediakit */ diff --git a/src/Codec/H264Encoder.h b/src/Codec/H264Encoder.h index 3dd8b323..e60760c4 100644 --- a/src/Codec/H264Encoder.h +++ b/src/Codec/H264Encoder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ @@ -42,21 +26,21 @@ namespace mediakit { class H264Encoder { public: - typedef struct { - int iType; - int iLength; - uint8_t *pucData; - } H264Frame; + typedef struct { + int iType; + int iLength; + uint8_t *pucData; + } H264Frame; - H264Encoder(void); - virtual ~H264Encoder(void); - bool init(int iWidth, int iHeight, int iFps); - int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame); + H264Encoder(void); + virtual ~H264Encoder(void); + bool init(int iWidth, int iHeight, int iFps); + int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame); private: - x264_t* _pX264Handle = nullptr; - x264_picture_t* _pPicIn = nullptr; - x264_picture_t* _pPicOut = nullptr; - H264Frame _aFrames[10]; + x264_t* _pX264Handle = nullptr; + x264_picture_t* _pPicIn = nullptr; + x264_picture_t* _pPicOut = nullptr; + H264Frame _aFrames[10]; }; } /* namespace mediakit */ diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 58fd53cb..310db429 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include #include #include "Device.h" @@ -42,8 +27,8 @@ DevChannel::DevChannel(const string &strVhost, const string &strApp, const string &strId, float fDuration, - bool bEanbleRtsp, - bool bEanbleRtmp, + bool bEanbleRtsp, + bool bEanbleRtmp, bool bEanbleHls, bool bEnableMp4) : MultiMediaSourceMuxer(strVhost, strApp, strId, fDuration, bEanbleRtsp, bEanbleRtmp, bEanbleHls, bEnableMp4) {} @@ -52,50 +37,50 @@ DevChannel::~DevChannel() {} #ifdef ENABLE_X264 void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) { - //TimeTicker1(50); - if (!_pH264Enc) { - _pH264Enc.reset(new H264Encoder()); - if (!_pH264Enc->init(_video->iWidth, _video->iHeight, _video->iFrameRate)) { - _pH264Enc.reset(); - WarnL << "H264Encoder init failed!"; - } - } - if (_pH264Enc) { - H264Encoder::H264Frame *pOut; - int iFrames = _pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut); - for (int i = 0; i < iFrames; i++) { - inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp); - } - } + //TimeTicker1(50); + if (!_pH264Enc) { + _pH264Enc.reset(new H264Encoder()); + if (!_pH264Enc->init(_video->iWidth, _video->iHeight, _video->iFrameRate)) { + _pH264Enc.reset(); + WarnL << "H264Encoder init failed!"; + } + } + if (_pH264Enc) { + H264Encoder::H264Frame *pOut; + int iFrames = _pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut); + for (int i = 0; i < iFrames; i++) { + inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp); + } + } } #endif //ENABLE_X264 #ifdef ENABLE_FAAC void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) { - if (!_pAacEnc) { - _pAacEnc.reset(new AACEncoder()); - if (!_pAacEnc->init(_audio->iSampleRate, _audio->iChannel, _audio->iSampleBit)) { - _pAacEnc.reset(); - WarnL << "AACEncoder init failed!"; - } - } - if (_pAacEnc) { - unsigned char *pucOut; - int iRet = _pAacEnc->inputData(pcData, iDataLen, &pucOut); - if (iRet > 0) { - inputAAC((char *) pucOut, iRet, uiStamp); - } - } + if (!_pAacEnc) { + _pAacEnc.reset(new AACEncoder()); + if (!_pAacEnc->init(_audio->iSampleRate, _audio->iChannel, _audio->iSampleBit)) { + _pAacEnc.reset(); + WarnL << "AACEncoder init failed!"; + } + } + if (_pAacEnc) { + unsigned char *pucOut; + int iRet = _pAacEnc->inputData(pcData, iDataLen, &pucOut); + if (iRet > 0) { + inputAAC((char *) pucOut, iRet, uiStamp); + } + } } #endif //ENABLE_FAAC void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { if(dts == 0){ - dts = (uint32_t)_aTicker[0].elapsedTime(); + dts = (uint32_t)_aTicker[0].elapsedTime(); + } + if(pts == 0){ + pts = dts; } - if(pts == 0){ - pts = dts; - } int prefixeSize; if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { prefixeSize = 4; @@ -105,46 +90,46 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32 prefixeSize = 0; } - H264Frame::Ptr frame = std::make_shared(); - frame->_dts = dts; - frame->_pts = pts; - frame->_buffer.assign("\x00\x00\x00\x01",4); - frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); - frame->_prefix_size = 4; + H264Frame::Ptr frame = std::make_shared(); + frame->_dts = dts; + frame->_pts = pts; + frame->_buffer.assign("\x00\x00\x00\x01",4); + frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->_prefix_size = 4; inputFrame(frame); } void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { - if(dts == 0){ - dts = (uint32_t)_aTicker[0].elapsedTime(); - } - if(pts == 0){ - pts = dts; - } - int prefixeSize; - if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { - prefixeSize = 4; - } else if (memcmp("\x00\x00\x01", pcData, 3) == 0) { - prefixeSize = 3; - } else { - prefixeSize = 0; - } + if(dts == 0){ + dts = (uint32_t)_aTicker[0].elapsedTime(); + } + if(pts == 0){ + pts = dts; + } + int prefixeSize; + if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { + prefixeSize = 4; + } else if (memcmp("\x00\x00\x01", pcData, 3) == 0) { + prefixeSize = 3; + } else { + prefixeSize = 0; + } - H265Frame::Ptr frame = std::make_shared(); - frame->_dts = dts; - frame->_pts = pts; - frame->_buffer.assign("\x00\x00\x00\x01",4); - frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); - frame->_prefix_size = 4; - inputFrame(frame); + H265Frame::Ptr frame = std::make_shared(); + frame->_dts = dts; + frame->_pts = pts; + frame->_buffer.assign("\x00\x00\x00\x01",4); + frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); + frame->_prefix_size = 4; + inputFrame(frame); } void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) { - if(withAdtsHeader){ - inputAAC(pcData+7,iDataLen-7,uiStamp,pcData); - } else if(_audio) { - inputAAC(pcData,iDataLen,uiStamp,(char *)_adtsHeader); - } + if(withAdtsHeader){ + inputAAC(pcData+7,iDataLen-7,uiStamp,pcData); + } else if(_audio) { + inputAAC(pcData,iDataLen,uiStamp,(char *)_adtsHeader); + } } void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader){ @@ -152,54 +137,54 @@ void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t u uiStamp = (uint32_t)_aTicker[1].elapsedTime(); } if(pcAdtsHeader + 7 == pcDataWithoutAdts){ - inputFrame(std::make_shared((char *)pcDataWithoutAdts - 7,iDataLen + 7,uiStamp,7)); - } else { - char *dataWithAdts = new char[iDataLen + 7]; - memcpy(dataWithAdts,pcAdtsHeader,7); - memcpy(dataWithAdts + 7 , pcDataWithoutAdts , iDataLen); - inputFrame(std::make_shared(dataWithAdts,iDataLen + 7,uiStamp,7)); - delete [] dataWithAdts; - } + inputFrame(std::make_shared((char *)pcDataWithoutAdts - 7,iDataLen + 7,uiStamp,0,7)); + } else { + char *dataWithAdts = new char[iDataLen + 7]; + memcpy(dataWithAdts,pcAdtsHeader,7); + memcpy(dataWithAdts + 7 , pcDataWithoutAdts , iDataLen); + inputFrame(std::make_shared(dataWithAdts,iDataLen + 7,uiStamp,0,7)); + delete [] dataWithAdts; + } } void DevChannel::initVideo(const VideoInfo& info) { - _video = std::make_shared(info); - addTrack(std::make_shared()); + _video = std::make_shared(info); + addTrack(std::make_shared()); } void DevChannel::initH265Video(const VideoInfo &info){ - _video = std::make_shared(info); - addTrack(std::make_shared()); + _video = std::make_shared(info); + addTrack(std::make_shared()); } void DevChannel::initAudio(const AudioInfo& info) { - _audio = std::make_shared(info); - addTrack(std::make_shared()); + _audio = std::make_shared(info); + addTrack(std::make_shared()); - AACFrame adtsHeader; - adtsHeader.syncword = 0x0FFF; - adtsHeader.id = 0; - adtsHeader.layer = 0; - adtsHeader.protection_absent = 1; - adtsHeader.profile = info.iProfile;//audioObjectType - 1; - int i = 0; - for(auto rate : samplingFrequencyTable){ - if(rate == info.iSampleRate){ - adtsHeader.sf_index = i; - }; - ++i; - } - adtsHeader.private_bit = 0; - adtsHeader.channel_configuration = info.iChannel; - adtsHeader.original = 0; - adtsHeader.home = 0; - adtsHeader.copyright_identification_bit = 0; - adtsHeader.copyright_identification_start = 0; - adtsHeader.aac_frame_length = 7; - adtsHeader.adts_buffer_fullness = 2047; - adtsHeader.no_raw_data_blocks_in_frame = 0; - writeAdtsHeader(adtsHeader,_adtsHeader); + AACFrame adtsHeader; + adtsHeader.syncword = 0x0FFF; + adtsHeader.id = 0; + adtsHeader.layer = 0; + adtsHeader.protection_absent = 1; + adtsHeader.profile = info.iProfile;//audioObjectType - 1; + int i = 0; + for(auto rate : samplingFrequencyTable){ + if(rate == info.iSampleRate){ + adtsHeader.sf_index = i; + }; + ++i; + } + adtsHeader.private_bit = 0; + adtsHeader.channel_configuration = info.iChannel; + adtsHeader.original = 0; + adtsHeader.home = 0; + adtsHeader.copyright_identification_bit = 0; + adtsHeader.copyright_identification_start = 0; + adtsHeader.aac_frame_length = 7; + adtsHeader.adts_buffer_fullness = 2047; + adtsHeader.no_raw_data_blocks_in_frame = 0; + writeAdtsHeader(adtsHeader,_adtsHeader); } } /* namespace mediakit */ diff --git a/src/Common/Device.h b/src/Common/Device.h index a8c63daf..4b13ee02 100644 --- a/src/Common/Device.h +++ b/src/Common/Device.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef DEVICE_DEVICE_H_ @@ -51,16 +35,16 @@ namespace mediakit { class VideoInfo { public: - int iWidth; - int iHeight; - float iFrameRate; + int iWidth; + int iHeight; + float iFrameRate; }; class AudioInfo { public: - int iChannel; - int iSampleBit; - int iSampleRate; - int iProfile; + int iChannel; + int iSampleBit; + int iSampleRate; + int iProfile; }; /** @@ -68,82 +52,82 @@ public: */ class DevChannel : public MultiMediaSourceMuxer{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; //fDuration<=0为直播,否则为点播 DevChannel(const string &strVhost, const string &strApp, const string &strId, float fDuration = 0, - bool bEanbleRtsp = true, - bool bEanbleRtmp = true, + bool bEanbleRtsp = true, + bool bEanbleRtmp = true, bool bEanbleHls = true, bool bEnableMp4 = false); - virtual ~DevChannel(); + virtual ~DevChannel(); - /** - * 初始化h264视频Track - * 相当于MultiMediaSourceMuxer::addTrack(H264Track::Ptr ); - * @param info - */ + /** + * 初始化h264视频Track + * 相当于MultiMediaSourceMuxer::addTrack(H264Track::Ptr ); + * @param info + */ void initVideo(const VideoInfo &info); - /** - * 初始化h265视频Track - * @param info - */ - void initH265Video(const VideoInfo &info); + /** + * 初始化h265视频Track + * @param info + */ + void initH265Video(const VideoInfo &info); /** * 初始化aac音频Track * 相当于MultiMediaSourceMuxer::addTrack(AACTrack::Ptr ); * @param info */ - void initAudio(const AudioInfo &info); + void initAudio(const AudioInfo &info); - /** - * 输入264帧 - * @param pcData 264单帧数据指针 - * @param iDataLen 数据指针长度 - * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳 - * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts - */ - void inputH264(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); + /** + * 输入264帧 + * @param pcData 264单帧数据指针 + * @param iDataLen 数据指针长度 + * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳 + * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts + */ + void inputH264(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); - /** - * 输入265帧 - * @param pcData 265单帧数据指针 - * @param iDataLen 数据指针长度 - * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳 - * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts - */ - void inputH265(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); + /** + * 输入265帧 + * @param pcData 265单帧数据指针 + * @param iDataLen 数据指针长度 + * @param dts 解码时间戳,单位毫秒;等于0时内部会自动生成时间戳 + * @param pts 播放时间戳,单位毫秒;等于0时内部会赋值为dts + */ + void inputH265(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); - /** - * 输入可能带adts头的aac帧 - * @param pcDataWithAdts 可能带adts头的aac帧 - * @param iDataLen 帧数据长度 - * @param uiStamp 时间戳,单位毫秒,等于0时内部会自动生成时间戳 - * @param withAdtsHeader 是否带adts头 - */ - void inputAAC(const char *pcDataWithAdts, int iDataLen, uint32_t uiStamp, bool withAdtsHeader = true); + /** + * 输入可能带adts头的aac帧 + * @param pcDataWithAdts 可能带adts头的aac帧 + * @param iDataLen 帧数据长度 + * @param uiStamp 时间戳,单位毫秒,等于0时内部会自动生成时间戳 + * @param withAdtsHeader 是否带adts头 + */ + void inputAAC(const char *pcDataWithAdts, int iDataLen, uint32_t uiStamp, bool withAdtsHeader = true); - /** - * 输入不带adts头的aac帧 - * @param pcDataWithoutAdts 不带adts头的aac帧 - * @param iDataLen 帧数据长度 - * @param uiStamp 时间戳,单位毫秒 - * @param pcAdtsHeader adts头 - */ - void inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader); + /** + * 输入不带adts头的aac帧 + * @param pcDataWithoutAdts 不带adts头的aac帧 + * @param iDataLen 帧数据长度 + * @param uiStamp 时间戳,单位毫秒 + * @param pcAdtsHeader adts头 + */ + void inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader); #ifdef ENABLE_X264 - /** - * 输入yuv420p视频帧,内部会完成编码并调用inputH264方法 - * @param apcYuv - * @param aiYuvLen - * @param uiStamp - */ + /** + * 输入yuv420p视频帧,内部会完成编码并调用inputH264方法 + * @param apcYuv + * @param aiYuvLen + * @param uiStamp + */ void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp); #endif //ENABLE_X264 @@ -160,11 +144,11 @@ public: private: #ifdef ENABLE_X264 - std::shared_ptr _pH264Enc; + std::shared_ptr _pH264Enc; #endif //ENABLE_X264 #ifdef ENABLE_FAAC - std::shared_ptr _pAacEnc; + std::shared_ptr _pAacEnc; #endif //ENABLE_FAAC std::shared_ptr _video; std::shared_ptr _audio; diff --git a/src/Common/MediaSink.cpp b/src/Common/MediaSink.cpp index 90cb1797..de315706 100644 --- a/src/Common/MediaSink.cpp +++ b/src/Common/MediaSink.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "MediaSink.h" //最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track diff --git a/src/Common/MediaSink.h b/src/Common/MediaSink.h index c948aaa1..7874092e 100644 --- a/src/Common/MediaSink.h +++ b/src/Common/MediaSink.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_MEDIASINK_H @@ -129,8 +113,8 @@ private: void checkTrackIfReady_l(const Track::Ptr &track); private: mutable recursive_mutex _mtx; - map _track_map; - map > _trackReadyCallback; + unordered_map _track_map; + unordered_map > _trackReadyCallback; bool _allTrackReady = false; Ticker _ticker; int _max_track_size = 2; diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index 9d15ab09..aa30ffbc 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -1,38 +1,19 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #include "MediaSource.h" #include "Record/MP4Reader.h" #include "Util/util.h" #include "Network/sockutil.h" #include "Network/TcpSession.h" - using namespace toolkit; - namespace mediakit { recursive_mutex MediaSource::g_mtxMediaSrc; @@ -78,7 +59,6 @@ vector MediaSource::getTracks(bool trackReady) const { void MediaSource::setTrackSource(const std::weak_ptr &track_src) { _track_source = track_src; - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaResetTracks, *this); } void MediaSource::setListener(const std::weak_ptr &listener){ @@ -117,12 +97,37 @@ void MediaSource::onNoneReader(){ if(!listener){ return; } - listener->onNoneReader(*this); + if (listener->totalReaderCount(*this) == 0) { + listener->onNoneReader(*this); + } +} + +bool MediaSource::setupRecord(Recorder::type type, bool start, const string &custom_path){ + auto listener = _listener.lock(); + if (!listener) { + return false; + } + return listener->setupRecord(*this, type, start, custom_path); +} + +bool MediaSource::isRecording(Recorder::type type){ + auto listener = _listener.lock(); + if(!listener){ + return false; + } + return listener->isRecording(*this, type); } void MediaSource::for_each_media(const function &cb) { - lock_guard lock(g_mtxMediaSrc); - for (auto &pr0 : g_mapMediaSrc) { + decltype(g_mapMediaSrc) copy; + { + //拷贝g_mapMediaSrc后再遍历,考虑到是高频使用的全局单例锁,并且在上锁时会执行回调代码 + //很容易导致多个锁交叉死锁的情况,而且该函数使用频率不高,拷贝开销相对来说是可以接受的 + lock_guard lock(g_mtxMediaSrc); + copy = g_mapMediaSrc; + } + + for (auto &pr0 : copy) { for (auto &pr1 : pr0.second) { for (auto &pr2 : pr1.second) { for (auto &pr3 : pr2.second) { @@ -274,7 +279,7 @@ MediaSource::Ptr MediaSource::find(const string &schema, const string &vhost_tmp if(!ret && bMake){ //未查找媒体源,则创建一个 - ret = MP4Reader::onMakeMediaSource(schema, vhost,app,id); + ret = createFromMP4(schema, vhost, app, id); } return ret; } @@ -381,18 +386,68 @@ void MediaInfo::parse(const string &url){ /////////////////////////////////////MediaSourceEvent////////////////////////////////////// void MediaSourceEvent::onNoneReader(MediaSource &sender){ - //没有任何读取器消费该源,表明该源可以关闭了 - WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId(); - weak_ptr weakPtr = sender.shared_from_this(); + GET_CONFIG(string, recordApp, Record::kAppName); + GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS); - //异步广播该事件,防止同步调用sender.close()导致在接收rtp或rtmp包时清空包缓存等操作 - EventPollerPool::Instance().getPoller()->async([weakPtr](){ - auto strongPtr = weakPtr.lock(); - if(strongPtr){ - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastStreamNoneReader,*strongPtr); + //如果mp4点播, 无人观看时我们强制关闭点播 + bool is_mp4_vod = sender.getApp() == recordApp; + //无人观看mp4点播时,3秒后自动关闭 + auto close_delay = is_mp4_vod ? 3.0 : stream_none_reader_delay / 1000.0; + + //没有任何人观看该视频源,表明该源可以关闭了 + weak_ptr weakSender = sender.shared_from_this(); + _async_close_timer = std::make_shared(close_delay, [weakSender,is_mp4_vod]() { + auto strongSender = weakSender.lock(); + if (!strongSender) { + //对象已经销毁 + return false; } - },false); + + if (strongSender->totalReaderCount() != 0) { + //还有人消费 + return false; + } + + if(!is_mp4_vod){ + //直播时触发无人观看事件,让开发者自行选择是否关闭 + WarnL << "无人观看事件:" + << strongSender->getSchema() << "/" + << strongSender->getVhost() << "/" + << strongSender->getApp() << "/" + << strongSender->getId(); + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastStreamNoneReader, *strongSender); + }else{ + //这个是mp4点播,我们自动关闭 + WarnL << "MP4点播无人观看,自动关闭:" + << strongSender->getSchema() << "/" + << strongSender->getVhost() << "/" + << strongSender->getApp() << "/" + << strongSender->getId(); + strongSender->close(false); + } + + return false; + }, nullptr); } +MediaSource::Ptr MediaSource::createFromMP4(const string &schema, const string &vhost, const string &app, const string &stream, const string &filePath , bool checkApp){ + GET_CONFIG(string, appName, Record::kAppName); + if (checkApp && app != appName) { + return nullptr; + } +#ifdef ENABLE_MP4 + try { + MP4Reader::Ptr pReader(new MP4Reader(vhost, app, stream, filePath)); + pReader->startReadMP4(); + return MediaSource::find(schema, vhost, app, stream, false); + } catch (std::exception &ex) { + WarnL << ex.what(); + return nullptr; + } +#else + WarnL << "创建MP4点播失败,请编译时打开\"ENABLE_MP4\"选项"; + return nullptr; +#endif //ENABLE_MP4 +} } /* namespace mediakit */ \ No newline at end of file diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index e6920050..f3d6e140 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -1,30 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #ifndef ZLMEDIAKIT_MEDIASOURCE_H #define ZLMEDIAKIT_MEDIASOURCE_H @@ -39,6 +22,7 @@ #include "Util/TimeTicker.h" #include "Util/NoticeCenter.h" #include "Extension/Track.h" +#include "Record/Recorder.h" using namespace std; using namespace toolkit; @@ -52,24 +36,25 @@ namespace mediakit { class MediaSource; class MediaSourceEvent{ public: + friend class MediaSource; MediaSourceEvent(){}; virtual ~MediaSourceEvent(){}; // 通知拖动进度条 - virtual bool seekTo(MediaSource &sender,uint32_t ui32Stamp){ - return false; - } - + virtual bool seekTo(MediaSource &sender,uint32_t ui32Stamp){ return false; } // 通知其停止推流 - virtual bool close(MediaSource &sender,bool force) { - return false; - } - - // 通知无人观看 - virtual void onNoneReader(MediaSource &sender); - + virtual bool close(MediaSource &sender,bool force) { return false;} // 观看总人数 virtual int totalReaderCount(MediaSource &sender) = 0; + // 开启或关闭录制 + virtual bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) { return false; }; + // 获取录制状态 + virtual bool isRecording(MediaSource &sender, Recorder::type type) { return false; }; +private: + // 通知无人观看 + void onNoneReader(MediaSource &sender); +private: + Timer::Ptr _async_close_timer; }; /** @@ -124,7 +109,6 @@ public: // 获取监听者 const std::weak_ptr& getListener() const; - // 本协议获取观看者个数,可能返回本协议的观看人数,也可能返回总人数 virtual int readerCount() = 0; // 观看者个数,包括(hls/rtsp/rtmp) @@ -141,6 +125,10 @@ public: bool close(bool force); // 该流无人观看 void onNoneReader(); + // 开启或关闭录制 + virtual bool setupRecord(Recorder::type type, bool start, const string &custom_path); + // 获取录制状态 + virtual bool isRecording(Recorder::type type); // 同步查找流 static Ptr find(const string &schema, const string &vhost, const string &app, const string &id, bool bMake = true) ; @@ -148,6 +136,9 @@ public: static void findAsync(const MediaInfo &info, const std::shared_ptr &session, const function &cb); // 遍历所有流 static void for_each_media(const function &cb); + + // 从mp4文件生成MediaSource + static MediaSource::Ptr createFromMP4(const string &schema, const string &vhost, const string &app, const string &stream, const string &filePath = "", bool checkApp = true); protected: void regist() ; bool unregist() ; diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp new file mode 100644 index 00000000..0f56ddbe --- /dev/null +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -0,0 +1,296 @@ +/* +* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. +* +* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). +* +* Use of this source code is governed by MIT license that can be found in the +* LICENSE file in the root of the source tree. All contributing project authors +* may be found in the AUTHORS file in the root of the source tree. +*/ + +#include "MultiMediaSourceMuxer.h" +namespace mediakit { + +MultiMuxerPrivate::~MultiMuxerPrivate() {} +MultiMuxerPrivate::MultiMuxerPrivate(const string &vhost, + const string &app, + const string &stream, + float dur_sec, + bool enable_rtsp, + bool enable_rtmp, + bool enable_hls, + bool enable_mp4) { + if (enable_rtmp) { + _rtmp = std::make_shared(vhost, app, stream, std::make_shared(dur_sec)); + } + if (enable_rtsp) { + _rtsp = std::make_shared(vhost, app, stream, std::make_shared(dur_sec)); + } + + if (enable_hls) { + _hls = Recorder::createRecorder(Recorder::type_hls, vhost, app, stream); + } + + if (enable_mp4) { + _mp4 = Recorder::createRecorder(Recorder::type_mp4, vhost, app, stream); + } +} + +void MultiMuxerPrivate::resetTracks() { + if (_rtmp) { + _rtmp->resetTracks(); + } + if (_rtsp) { + _rtsp->resetTracks(); + } + + //拷贝智能指针,目的是为了防止跨线程调用设置录像相关api导致的线程竞争问题 + auto hls = _hls; + if (hls) { + hls->resetTracks(); + } + + auto mp4 = _mp4; + if (mp4) { + mp4->resetTracks(); + } +} + +void MultiMuxerPrivate::setMediaListener(const std::weak_ptr &listener) { + if (_rtmp) { + _rtmp->setListener(listener); + } + + if (_rtsp) { + _rtsp->setListener(listener); + } + + auto hls_src = getHlsMediaSource(); + if (hls_src) { + hls_src->setListener(listener); + } + _meida_listener = listener; +} + +int MultiMuxerPrivate::totalReaderCount() const { + auto hls_src = getHlsMediaSource(); + return (_rtsp ? _rtsp->readerCount() : 0) + (_rtmp ? _rtmp->readerCount() : 0) + (hls_src ? hls_src->readerCount() : 0); +} + +static std::shared_ptr makeRecorder(const vector &tracks, Recorder::type type, MediaSource &sender){ + auto recorder = Recorder::createRecorder(type, sender.getVhost(), sender.getApp(), sender.getId()); + for (auto &track : tracks) { + recorder->addTrack(track); + } + return recorder; +} + +//此函数可能跨线程调用 +bool MultiMuxerPrivate::setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path){ + switch (type) { + case Recorder::type_hls : { + if (start && !_hls) { + //开始录制 + _hls = makeRecorder(getTracks(true), type, sender); + auto hls_src = getHlsMediaSource(); + if (hls_src) { + //设置HlsMediaSource的事件监听器 + hls_src->setListener(_meida_listener); + hls_src->setTrackSource(shared_from_this()); + } + } else if (!start && _hls) { + //停止录制 + _hls = nullptr; + } + return true; + } + case Recorder::type_mp4 : { + if (start && !_mp4) { + //开始录制 + _mp4 = makeRecorder(getTracks(true), type, sender);; + } else if (!start && _mp4) { + //停止录制 + _mp4 = nullptr; + } + return true; + } + default: + return false; + } +} + +//此函数可能跨线程调用 +bool MultiMuxerPrivate::isRecording(MediaSource &sender, Recorder::type type){ + switch (type){ + case Recorder::type_hls : + return _hls ? true : false; + case Recorder::type_mp4 : + return _mp4 ? true : false; + default: + return false; + } +} + +void MultiMuxerPrivate::setTimeStamp(uint32_t stamp) { + if (_rtmp) { + _rtmp->setTimeStamp(stamp); + } + if (_rtsp) { + _rtsp->setTimeStamp(stamp); + } +} + +void MultiMuxerPrivate::setTrackListener(Listener *listener) { + _listener = listener; +} + +void MultiMuxerPrivate::onTrackReady(const Track::Ptr &track) { + if (_rtmp) { + _rtmp->addTrack(track); + } + if (_rtsp) { + _rtsp->addTrack(track); + } + + //拷贝智能指针,目的是为了防止跨线程调用设置录像相关api导致的线程竞争问题 + auto hls = _hls; + if (hls) { + hls->addTrack(track); + } + auto mp4 = _mp4; + if (mp4) { + mp4->addTrack(track); + } +} + +void MultiMuxerPrivate::onTrackFrame(const Frame::Ptr &frame) { + if (_rtmp) { + _rtmp->inputFrame(frame); + } + if (_rtsp) { + _rtsp->inputFrame(frame); + } + //拷贝智能指针,目的是为了防止跨线程调用设置录像相关api导致的线程竞争问题 + //此处使用智能指针拷贝来确保线程安全,比互斥锁性能更优 + auto hls = _hls; + if (hls) { + hls->inputFrame(frame); + } + auto mp4 = _mp4; + if (mp4) { + mp4->inputFrame(frame); + } +} + +void MultiMuxerPrivate::onAllTrackReady() { + if (_rtmp) { + _rtmp->setTrackSource(shared_from_this()); + _rtmp->onAllTrackReady(); + } + if (_rtsp) { + _rtsp->setTrackSource(shared_from_this()); + _rtsp->onAllTrackReady(); + } + + auto hls_src = getHlsMediaSource(); + if (hls_src) { + hls_src->setTrackSource(shared_from_this()); + } + + if (_listener) { + _listener->onAllTrackReady(); + } +} + +MediaSource::Ptr MultiMuxerPrivate::getHlsMediaSource() const { + auto recorder = dynamic_pointer_cast(_hls); + if (recorder) { + return recorder->getMediaSource(); + } + return nullptr; +} + +///////////////////////////////////////////////////////////////// + +MultiMediaSourceMuxer::~MultiMediaSourceMuxer() {} +MultiMediaSourceMuxer::MultiMediaSourceMuxer(const string &vhost, + const string &app, + const string &stream, + float dur_sec, + bool enable_rtsp, + bool enable_rtmp, + bool enable_hls, + bool enable_mp4) { + _muxer.reset(new MultiMuxerPrivate(vhost, app, stream, dur_sec, enable_rtsp, enable_rtmp, enable_hls, enable_mp4)); +} + +void MultiMediaSourceMuxer::setMediaListener(const std::weak_ptr &listener) { + _muxer->setMediaListener(shared_from_this()); + _listener = listener; +} + +int MultiMediaSourceMuxer::totalReaderCount() const { + return _muxer->totalReaderCount(); +} + +void MultiMediaSourceMuxer::setTimeStamp(uint32_t stamp) { + _muxer->setTimeStamp(stamp); +} + +void MultiMediaSourceMuxer::setTrackListener(Listener *listener) { + _muxer->setTrackListener(listener); +} + +vector MultiMediaSourceMuxer::getTracks(bool trackReady) const { + return _muxer->getTracks(trackReady); +} + +bool MultiMediaSourceMuxer::seekTo(MediaSource &sender, uint32_t ui32Stamp) { + auto listener = _listener.lock(); + if (!listener) { + return false; + } + return listener->seekTo(sender, ui32Stamp); +} + +bool MultiMediaSourceMuxer::close(MediaSource &sender, bool force) { + auto listener = _listener.lock(); + if (!listener) { + return false; + } + return listener->close(sender, force); +} + +int MultiMediaSourceMuxer::totalReaderCount(MediaSource &sender) { + auto listener = _listener.lock(); + if (!listener) { + return _muxer->totalReaderCount(); + } + return listener->totalReaderCount(sender); +} + +bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) { + return _muxer->setupRecord(sender,type,start,custom_path); +} + +bool MultiMediaSourceMuxer::isRecording(MediaSource &sender, Recorder::type type) { + return _muxer->isRecording(sender,type); +} + +void MultiMediaSourceMuxer::addTrack(const Track::Ptr &track) { + _muxer->addTrack(track); +} + +void MultiMediaSourceMuxer::addTrackCompleted() { + _muxer->addTrackCompleted(); +} + +void MultiMediaSourceMuxer::resetTracks() { + _muxer->resetTracks(); +} + +void MultiMediaSourceMuxer::inputFrame(const Frame::Ptr &frame) { + _muxer->inputFrame(frame); +} + +}//namespace mediakit \ No newline at end of file diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index c0a79adb..5ba6b8fe 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -1,187 +1,176 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_MULTIMEDIASOURCEMUXER_H #define ZLMEDIAKIT_MULTIMEDIASOURCEMUXER_H - #include "Rtsp/RtspMediaSourceMuxer.h" #include "Rtmp/RtmpMediaSourceMuxer.h" #include "Record/Recorder.h" #include "Record/HlsMediaSource.h" #include "Record/HlsRecorder.h" +namespace mediakit{ -/** - * 使用该对象时,应该使用setListener方法来绑定MediaSource相关的事件 - * 否则多种不同类型的MediaSource(rtsp/rtmp/hls)将无法产生关联 - */ -class MultiMediaSourceMuxer : public MediaSink , public std::enable_shared_from_this{ +class MultiMuxerPrivate : public MediaSink , public std::enable_shared_from_this{ public: + friend class MultiMediaSourceMuxer; + typedef std::shared_ptr Ptr; class Listener{ public: Listener() = default; virtual ~Listener() = default; virtual void onAllTrackReady() = 0; }; + ~MultiMuxerPrivate() override ; +private: + MultiMuxerPrivate(const string &vhost, + const string &app, + const string &stream, + float dur_sec, + bool enable_rtsp, + bool enable_rtmp, + bool enable_hls, + bool enable_mp4); + void resetTracks() override; + void setMediaListener(const std::weak_ptr &listener); + int totalReaderCount() const; + void setTimeStamp(uint32_t stamp); + void setTrackListener(Listener *listener); + bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path); + bool isRecording(MediaSource &sender, Recorder::type type); +private: + void onTrackReady(const Track::Ptr & track) override; + void onTrackFrame(const Frame::Ptr &frame) override; + void onAllTrackReady() override; + MediaSource::Ptr getHlsMediaSource() const; +private: + RtmpMediaSourceMuxer::Ptr _rtmp; + RtspMediaSourceMuxer::Ptr _rtsp; + MediaSinkInterface::Ptr _hls; + MediaSinkInterface::Ptr _mp4; + Listener *_listener = nullptr; + std::weak_ptr _meida_listener; +}; + +class MultiMediaSourceMuxer : public MediaSourceEvent, public MediaSinkInterface, public TrackSource, public std::enable_shared_from_this{ +public: + typedef MultiMuxerPrivate::Listener Listener; typedef std::shared_ptr Ptr; - MultiMediaSourceMuxer(const string &vhost, const string &app, const string &stream, float dur_sec = 0.0, - bool enable_rtsp = true, bool enable_rtmp = true, bool enable_hls = true, bool enable_mp4 = false){ - if (enable_rtmp) { - _rtmp = std::make_shared(vhost, app, stream, std::make_shared(dur_sec)); - } - if (enable_rtsp) { - _rtsp = std::make_shared(vhost, app, stream, std::make_shared(dur_sec)); - } - if(enable_hls){ - Recorder::startRecord(Recorder::type_hls,vhost, app, stream, "", true, false); - } - - if(enable_mp4){ - Recorder::startRecord(Recorder::type_mp4,vhost, app, stream, "", true, false); - } - - _get_hls_media_source = [vhost,app,stream](){ - auto recorder = dynamic_pointer_cast(Recorder::getRecorder(Recorder::type_hls,vhost,app,stream)); - if(recorder){ - return recorder->getMediaSource(); - } - return MediaSource::Ptr(); - }; - } - virtual ~MultiMediaSourceMuxer(){} - - /** - * 重置音视频媒体 - */ - void resetTracks() override{ - if(_rtmp){ - _rtmp->resetTracks(); - } - if(_rtsp){ - _rtsp->resetTracks(); - } - } + ~MultiMediaSourceMuxer() override; + MultiMediaSourceMuxer(const string &vhost, + const string &app, + const string &stream, + float dur_sec = 0.0, + bool enable_rtsp = true, + bool enable_rtmp = true, + bool enable_hls = true, + bool enable_mp4 = false); /** * 设置事件监听器 * @param listener */ - void setListener(const std::weak_ptr &listener){ - if(_rtmp) { - _rtmp->setListener(listener); - } - - if(_rtsp) { - _rtsp->setListener(listener); - } - - auto hls_src = _get_hls_media_source(); - if(hls_src){ - hls_src->setListener(listener); - } - } + void setMediaListener(const std::weak_ptr &listener); /** * 返回总的消费者个数 * @return */ - int totalReaderCount() const{ - auto hls_src = _get_hls_media_source(); - return (_rtsp ? _rtsp->readerCount() : 0) + (_rtmp ? _rtmp->readerCount() : 0) + (hls_src ? hls_src->readerCount() : 0); - } - - void setTimeStamp(uint32_t stamp){ - if(_rtmp){ - _rtmp->setTimeStamp(stamp); - } - - if(_rtsp){ - _rtsp->setTimeStamp(stamp); - } - } - - void setTrackListener(Listener *listener){ - _listener = listener; - } -protected: - /** - * 添加音视频媒体 - * @param track 媒体描述 - */ - void onTrackReady(const Track::Ptr & track) override { - if(_rtmp){ - _rtmp->addTrack(track); - } - if(_rtsp){ - _rtsp->addTrack(track); - } - } + int totalReaderCount() const; /** - * 写入帧数据然后打包rtmp - * @param frame 帧数据 + * 设置MediaSource时间戳 + * @param stamp 时间戳 */ - void onTrackFrame(const Frame::Ptr &frame) override { - if(_rtmp) { - _rtmp->inputFrame(frame); - } - if(_rtsp) { - _rtsp->inputFrame(frame); - } - } + void setTimeStamp(uint32_t stamp); /** - * 所有Track都准备就绪,触发媒体注册事件 + * 随着Track就绪事件监听器 + * @param listener 事件监听器 */ - void onAllTrackReady() override{ - if(_rtmp) { - _rtmp->setTrackSource(shared_from_this()); - _rtmp->onAllTrackReady(); - } - if(_rtsp) { - _rtsp->setTrackSource(shared_from_this()); - _rtsp->onAllTrackReady(); - } + void setTrackListener(Listener *listener); - auto hls_src = _get_hls_media_source(); - if(hls_src){ - hls_src->setTrackSource(shared_from_this()); - } + /** + * 获取所有Track + * @param trackReady 是否筛选过滤未就绪的track + * @return 所有Track + */ + vector getTracks(bool trackReady = true) const override; - if(_listener){ - _listener->onAllTrackReady(); - } - } + /** + * 通知拖动进度条 + * @param sender 事件发送者 + * @param ui32Stamp 目标时间戳 + * @return 是否成功 + */ + bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override; + + /** + * 通知停止流生成 + * @param sender 事件发送者 + * @param force 是否强制关闭 + * @return 成功与否 + */ + bool close(MediaSource &sender,bool force) override; + + /** + * 观看总人数 + * @param sender 事件发送者 + * @return 观看总人数 + */ + int totalReaderCount(MediaSource &sender) override; + + /** + * 设置录制状态 + * @param type 录制类型 + * @param start 开始或停止 + * @param custom_path 开启录制时,指定自定义路径 + * @return 是否设置成功 + */ + bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) override; + + /** + * 获取录制状态 + * @param type 录制类型 + * @return 录制状态 + */ + bool isRecording(MediaSource &sender, Recorder::type type) override; + + /** + * 添加track,内部会调用Track的clone方法 + * 只会克隆sps pps这些信息 ,而不会克隆Delegate相关关系 + * @param track + */ + void addTrack(const Track::Ptr & track) override; + + /** + * 添加track完毕 + * @param track + */ + void addTrackCompleted(); + + /** + * 重置track + */ + void resetTracks() override; + + /** + * 写入帧数据 + * @param frame 帧 + */ + void inputFrame(const Frame::Ptr &frame) override; private: - RtmpMediaSourceMuxer::Ptr _rtmp; - RtspMediaSourceMuxer::Ptr _rtsp; - Listener *_listener = nullptr; - function _get_hls_media_source; + MultiMuxerPrivate::Ptr _muxer; + std::weak_ptr _listener; }; - +}//namespace mediakit #endif //ZLMEDIAKIT_MULTIMEDIASOURCEMUXER_H diff --git a/src/Common/Parser.cpp b/src/Common/Parser.cpp index e24fa630..158201cd 100644 --- a/src/Common/Parser.cpp +++ b/src/Common/Parser.cpp @@ -1,6 +1,12 @@ -// -// Created by xzl on 2019/6/28. -// +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "Parser.h" diff --git a/src/Common/Parser.h b/src/Common/Parser.h index bd15d0b8..3630f8cd 100644 --- a/src/Common/Parser.h +++ b/src/Common/Parser.h @@ -1,6 +1,12 @@ -// -// Created by xzl on 2019/6/28. -// +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef ZLMEDIAKIT_PARSER_H #define ZLMEDIAKIT_PARSER_H diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index a0017752..e184dcdb 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Stamp.h" @@ -46,15 +30,15 @@ int64_t DeltaStamp::deltaStamp(int64_t stamp) { //时间戳增量为正,返回之 _last_stamp = stamp; //在直播情况下,时间戳增量不得大于MAX_DELTA_STAMP - return ret < MAX_DELTA_STAMP ? ret : (_playback ? ret : 0); + return ret < MAX_DELTA_STAMP ? ret : 0; } //时间戳增量为负,说明时间戳回环了或回退了 _last_stamp = stamp; - return _playback ? ret : 0; + return 0; } -void DeltaStamp::setPlayBack(bool playback) { +void Stamp::setPlayBack(bool playback) { _playback = playback; } @@ -64,6 +48,14 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, pts = dts; } + if(_playback){ + //这是点播 + dts_out = dts; + pts_out = pts; + _relativeStamp = dts_out; + return; + } + //pts和dts的差值 int pts_dts_diff = pts - dts; diff --git a/src/Common/Stamp.h b/src/Common/Stamp.h index 43d11159..9e49f393 100644 --- a/src/Common/Stamp.h +++ b/src/Common/Stamp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_STAMP_H @@ -45,15 +29,8 @@ public: * @return 时间戳增量 */ int64_t deltaStamp(int64_t stamp); - - /** - * 设置是否为回放模式,回放模式运行时间戳回退 - * @param playback 是否为回放模式 - */ - void setPlayBack(bool playback = true); private: int64_t _last_stamp = 0; - bool _playback = false; }; //该类解决时间戳回环、回退问题 //计算相对时间戳或者产生平滑时间戳 @@ -83,10 +60,17 @@ public: * @return */ int64_t getRelativeStamp() const ; + + /** + * 设置是否为回放模式,回放模式运行时间戳回退 + * @param playback 是否为回放模式 + */ + void setPlayBack(bool playback = true); private: int64_t _relativeStamp = 0; int64_t _last_dts = -1; SmoothTicker _ticker; + bool _playback = false; }; diff --git a/src/Common/config.cpp b/src/Common/config.cpp index ded712dc..4b6b5680 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Common/config.h" @@ -42,20 +26,19 @@ bool loadIniConfig(const char *ini_path){ }else{ ini = exePath() + ".ini"; } - try{ + try{ mINI::Instance().parseFile(ini); NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig); return true; - }catch (std::exception &ex) { - InfoL << "dump ini file to:" << ini; + }catch (std::exception &ex) { + InfoL << "dump ini file to:" << ini; mINI::Instance().dumpFile(ini); return false; - } + } } ////////////广播名称/////////// namespace Broadcast { const string kBroadcastMediaChanged = "kBroadcastMediaChanged"; -const string kBroadcastMediaResetTracks = "kBroadcastMediaResetTracks"; const string kBroadcastRecordMP4 = "kBroadcastRecordMP4"; const string kBroadcastHttpRequest = "kBroadcastHttpRequest"; const string kBroadcastHttpAccess = "kBroadcastHttpAccess"; @@ -90,12 +73,12 @@ onceToken token([](){ mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000; mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000; mINI::Instance()[kEnableVhost] = 0; - mINI::Instance()[kUltraLowDelay] = 1; - mINI::Instance()[kAddMuteAudio] = 1; - mINI::Instance()[kResetWhenRePlay] = 1; - mINI::Instance()[kPublishToRtxp] = 1; - mINI::Instance()[kPublishToHls] = 1; - mINI::Instance()[kPublishToMP4] = 0; + mINI::Instance()[kUltraLowDelay] = 1; + mINI::Instance()[kAddMuteAudio] = 1; + mINI::Instance()[kResetWhenRePlay] = 1; + mINI::Instance()[kPublishToRtxp] = 1; + mINI::Instance()[kPublishToHls] = 1; + mINI::Instance()[kPublishToMP4] = 0; },nullptr); }//namespace General @@ -117,26 +100,26 @@ const string kRootPath = HTTP_FIELD"rootPath"; const string kNotFound = HTTP_FIELD"notFound"; onceToken token([](){ - mINI::Instance()[kSendBufSize] = 64 * 1024; - mINI::Instance()[kMaxReqSize] = 4*1024; - mINI::Instance()[kKeepAliveSecond] = 15; + mINI::Instance()[kSendBufSize] = 64 * 1024; + mINI::Instance()[kMaxReqSize] = 4*1024; + mINI::Instance()[kKeepAliveSecond] = 15; #if defined(_WIN32) - mINI::Instance()[kCharSet] = "gb2312"; + mINI::Instance()[kCharSet] = "gb2312"; #else - mINI::Instance()[kCharSet] ="utf-8"; + mINI::Instance()[kCharSet] ="utf-8"; #endif - mINI::Instance()[kRootPath] = "./www"; - mINI::Instance()[kNotFound] = - "" - "404 Not Found" - "" - "

您访问的资源不存在!

" - "
" - SERVER_NAME - "
" - "" - ""; + mINI::Instance()[kRootPath] = "./www"; + mINI::Instance()[kNotFound] = + "" + "404 Not Found" + "" + "

您访问的资源不存在!

" + "
" + SERVER_NAME + "
" + "" + ""; },nullptr); }//namespace Http @@ -147,7 +130,7 @@ namespace Shell { const string kMaxReqSize = SHELL_FIELD"maxReqSize"; onceToken token([](){ - mINI::Instance()[kMaxReqSize] = 1024; + mINI::Instance()[kMaxReqSize] = 1024; },nullptr); } //namespace Shell @@ -160,11 +143,11 @@ const string kKeepAliveSecond = RTSP_FIELD"keepAliveSecond"; const string kDirectProxy = RTSP_FIELD"directProxy"; onceToken token([](){ - //默认Md5方式认证 - mINI::Instance()[kAuthBasic] = 0; + //默认Md5方式认证 + mINI::Instance()[kAuthBasic] = 0; mINI::Instance()[kHandshakeSecond] = 15; mINI::Instance()[kKeepAliveSecond] = 15; - mINI::Instance()[kDirectProxy] = 1; + mINI::Instance()[kDirectProxy] = 1; },nullptr); } //namespace Rtsp @@ -176,7 +159,7 @@ const string kHandshakeSecond = RTMP_FIELD"handshakeSecond"; const string kKeepAliveSecond = RTMP_FIELD"keepAliveSecond"; onceToken token([](){ - mINI::Instance()[kModifyStamp] = false; + mINI::Instance()[kModifyStamp] = false; mINI::Instance()[kHandshakeSecond] = 15; mINI::Instance()[kKeepAliveSecond] = 15; },nullptr); @@ -197,11 +180,11 @@ const string kClearCount = RTP_FIELD"clearCount"; const string kCycleMS = RTP_FIELD"cycleMS"; onceToken token([](){ - mINI::Instance()[kVideoMtuSize] = 1400; - mINI::Instance()[kAudioMtuSize] = 600; - mINI::Instance()[kMaxRtpCount] = 50; - mINI::Instance()[kClearCount] = 10; - mINI::Instance()[kCycleMS] = 13*60*60*1000; + mINI::Instance()[kVideoMtuSize] = 1400; + mINI::Instance()[kAudioMtuSize] = 600; + mINI::Instance()[kMaxRtpCount] = 50; + mINI::Instance()[kClearCount] = 10; + mINI::Instance()[kCycleMS] = 13*60*60*1000; },nullptr); } //namespace Rtsp @@ -216,9 +199,9 @@ const string kAddrMax = MULTI_FIELD"addrMax"; const string kUdpTTL = MULTI_FIELD"udpTTL"; onceToken token([](){ - mINI::Instance()[kAddrMin] = "239.0.0.0"; - mINI::Instance()[kAddrMax] = "239.255.255.255"; - mINI::Instance()[kUdpTTL] = 64; + mINI::Instance()[kAddrMin] = "239.0.0.0"; + mINI::Instance()[kAddrMax] = "239.255.255.255"; + mINI::Instance()[kUdpTTL] = 64; },nullptr); } //namespace MultiCast @@ -241,13 +224,13 @@ const string kFastStart = RECORD_FIELD"fastStart"; const string kFileRepeat = RECORD_FIELD"fileRepeat"; onceToken token([](){ - mINI::Instance()[kAppName] = "record"; - mINI::Instance()[kSampleMS] = 500; - mINI::Instance()[kFileSecond] = 60*60; - mINI::Instance()[kFilePath] = "./www"; - mINI::Instance()[kFileBufSize] = 64 * 1024; - mINI::Instance()[kFastStart] = false; - mINI::Instance()[kFileRepeat] = false; + mINI::Instance()[kAppName] = "record"; + mINI::Instance()[kSampleMS] = 500; + mINI::Instance()[kFileSecond] = 60*60; + mINI::Instance()[kFilePath] = "./www"; + mINI::Instance()[kFileBufSize] = 64 * 1024; + mINI::Instance()[kFastStart] = false; + mINI::Instance()[kFileRepeat] = false; },nullptr); } //namespace Record @@ -266,11 +249,11 @@ const string kFileBufSize = HLS_FIELD"fileBufSize"; const string kFilePath = HLS_FIELD"filePath"; onceToken token([](){ - mINI::Instance()[kSegmentDuration] = 2; - mINI::Instance()[kSegmentNum] = 3; - mINI::Instance()[kSegmentRetain] = 5; - mINI::Instance()[kFileBufSize] = 64 * 1024; - mINI::Instance()[kFilePath] = "./www"; + mINI::Instance()[kSegmentDuration] = 2; + mINI::Instance()[kSegmentNum] = 3; + mINI::Instance()[kSegmentRetain] = 5; + mINI::Instance()[kFileBufSize] = 64 * 1024; + mINI::Instance()[kFilePath] = "./www"; },nullptr); } //namespace Hls @@ -286,9 +269,9 @@ const string kCheckSource = RTP_PROXY_FIELD"checkSource"; const string kTimeoutSec = RTP_PROXY_FIELD"timeoutSec"; onceToken token([](){ - mINI::Instance()[kDumpDir] = ""; - mINI::Instance()[kCheckSource] = 1; - mINI::Instance()[kTimeoutSec] = 15; + mINI::Instance()[kDumpDir] = ""; + mINI::Instance()[kCheckSource] = 1; + mINI::Instance()[kTimeoutSec] = 15; },nullptr); } //namespace RtpProxy diff --git a/src/Common/config.h b/src/Common/config.h index ba81611c..77bd6b1c 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ @@ -57,7 +41,7 @@ bool loadIniConfig(const char *ini_path = nullptr); #define CLEAR_ARR(arr) for(auto &item : arr){ item = 0;} #endif //CLEAR_ARR -#define SERVER_NAME "ZLMediaKit-4.0" +#define SERVER_NAME "ZLMediaKit-5.0(build in " __DATE__ " " __TIME__ ")" #define VHOST_KEY "vhost" #define HTTP_SCHEMA "http" #define RTSP_SCHEMA "rtsp" @@ -72,10 +56,6 @@ namespace Broadcast { extern const string kBroadcastMediaChanged; #define BroadcastMediaChangedArgs const bool &bRegist, MediaSource &sender -//MediaSource重置Track事件 -extern const string kBroadcastMediaResetTracks; -#define BroadcastMediaResetTracksArgs MediaSource &sender - //录制mp4文件成功后广播 extern const string kBroadcastRecordMP4; #define BroadcastRecordMP4Args const MP4Info &info diff --git a/src/Extension/AAC.cpp b/src/Extension/AAC.cpp index f805e2d5..41e52d2d 100644 --- a/src/Extension/AAC.cpp +++ b/src/Extension/AAC.cpp @@ -1,30 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #include "AAC.h" namespace mediakit{ diff --git a/src/Extension/AAC.h b/src/Extension/AAC.h index 063756f6..547da59c 100644 --- a/src/Extension/AAC.h +++ b/src/Extension/AAC.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_AAC_H @@ -112,7 +96,7 @@ class AACFrameNoCacheAble : public FrameNoCacheAble { public: typedef std::shared_ptr Ptr; - AACFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts,int prefixeSize = 7){ + AACFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts,uint32_t pts = 0,int prefixeSize = 7){ _ptr = ptr; _size = size; _dts = dts; diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index 6a657aab..ab34caff 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -1,29 +1,15 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "AACRtmp.h" +#include "Rtmp/Rtmp.h" namespace mediakit{ @@ -39,9 +25,25 @@ AACFrame::Ptr AACRtmpDecoder::obtainFrame() { return frame; } +static string getAacCfg(const RtmpPacket &thiz) { + string ret; + if (thiz.getMediaType() != FLV_CODEC_AAC) { + return ret; + } + if (!thiz.isCfgFrame()) { + return ret; + } + if (thiz.strBuf.size() < 4) { + WarnL << "bad aac cfg!"; + return ret; + } + ret = thiz.strBuf.substr(2, 2); + return ret; +} + bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool key_pos) { if (pkt->isCfgFrame()) { - _aac_cfg = pkt->getAacCfg(); + _aac_cfg = getAacCfg(*pkt); return false; } if (!_aac_cfg.empty()) { @@ -141,7 +143,7 @@ void AACRtmpEncoder::makeAudioConfigPkt() { break; } uint8_t flvSampleBit = iSampleBit == 16; - uint8_t flvAudioType = 10; //aac + uint8_t flvAudioType = FLV_CODEC_AAC; _ui8AudioFlags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono; diff --git a/src/Extension/AACRtmp.h b/src/Extension/AACRtmp.h index 8181ebfd..4d245dd7 100644 --- a/src/Extension/AACRtmp.h +++ b/src/Extension/AACRtmp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_AACRTMPCODEC_H diff --git a/src/Extension/AACRtp.cpp b/src/Extension/AACRtp.cpp index cc2feb42..a09a8d76 100644 --- a/src/Extension/AACRtp.cpp +++ b/src/Extension/AACRtp.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "AACRtp.h" #define ADTS_HEADER_LEN 7 diff --git a/src/Extension/AACRtp.h b/src/Extension/AACRtp.h index 89f0b279..eba5ceb5 100644 --- a/src/Extension/AACRtp.h +++ b/src/Extension/AACRtp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_AACRTPCODEC_H diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 6aedc4b5..e0a10d2f 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -1,31 +1,17 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Factory.h" +#include "Rtmp/Rtmp.h" #include "H264Rtmp.h" +#include "H265Rtmp.h" #include "AACRtmp.h" #include "H264Rtp.h" #include "AACRtp.h" @@ -88,8 +74,7 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) { return std::make_shared(vps,sps,pps,0,0,0); } - - WarnL << "暂不支持该sdp:" << track->_codec << " " << track->_fmtp; + WarnL << "暂不支持该sdp:" << track->getName(); return nullptr; } @@ -190,9 +175,9 @@ CodecId Factory::getCodecIdByAmf(const AMFValue &val){ if (val.type() != AMF_NULL){ auto type_id = val.as_integer(); switch (type_id){ - case 7: return CodecH264; - case 10: return CodecAAC; - case 12: return CodecH265; + case FLV_CODEC_H264: return CodecH264; + case FLV_CODEC_AAC: return CodecAAC; + case FLV_CODEC_H265: return CodecH265; default: WarnL << "暂不支持该Amf:" << type_id; return CodecInvalid; @@ -211,6 +196,8 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track) { return std::make_shared(track); case CodecAAC: return std::make_shared(track); + case CodecH265: + return std::make_shared(track); default: WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; @@ -221,7 +208,7 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) { switch (codecId){ case CodecAAC: return AMFValue("mp4a"); case CodecH264: return AMFValue("avc1"); - case CodecH265: return AMFValue(12); + case CodecH265: return AMFValue(FLV_CODEC_H265); default: return AMFValue(AMF_NULL); } } diff --git a/src/Extension/Factory.h b/src/Extension/Factory.h index a950599a..fd53a5b7 100644 --- a/src/Extension/Factory.h +++ b/src/Extension/Factory.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_FACTORY_H diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index 2c204e19..9244ca7c 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Frame.h" diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 66218b0c..1cffb7bc 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_FRAME_H @@ -208,13 +192,17 @@ public: virtual ~FrameDispatcher(){} void addDelegate(const FrameWriterInterface::Ptr &delegate){ + //_delegates_write可能多线程同时操作 lock_guard lck(_mtx); - _delegateMap.emplace(delegate.get(),delegate); + _delegates_write.emplace(delegate.get(),delegate); + _need_update = true; } void delDelegate(void *ptr){ + //_delegates_write可能多线程同时操作 lock_guard lck(_mtx); - _delegateMap.erase(ptr); + _delegates_write.erase(ptr); + _need_update = true; } /** @@ -222,14 +210,24 @@ public: * @param frame 帧 */ void inputFrame(const Frame::Ptr &frame) override{ - lock_guard lck(_mtx); - for(auto &pr : _delegateMap){ + if(_need_update){ + //发现代理列表发生变化了,这里同步一次 + lock_guard lck(_mtx); + _delegates_read = _delegates_write; + _need_update = false; + } + + //_delegates_read能确保是单线程操作的 + for(auto &pr : _delegates_read){ pr.second->inputFrame(frame); } + } private: mutex _mtx; - map _delegateMap; + map _delegates_read; + map _delegates_write; + bool _need_update = false; }; /** diff --git a/src/Extension/H264.cpp b/src/Extension/H264.cpp index 2d93db34..73488055 100644 --- a/src/Extension/H264.cpp +++ b/src/Extension/H264.cpp @@ -1,30 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #include "H264.h" #include "SPSParser.h" #include "Util/logger.h" diff --git a/src/Extension/H264.h b/src/Extension/H264.h index b4c71a6b..bf39bfcc 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_H264_H @@ -257,7 +241,7 @@ public: */ void inputFrame(const Frame::Ptr &frame) override{ int type = H264_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); - if(type == H264Frame::NAL_SPS){ + if(type == H264Frame::NAL_SPS || type == H264Frame::NAL_SEI){ //有些设备会把SPS PPS IDR帧当做一个帧打包,所以我们要split一下 bool first_frame = true; splitH264(frame->data() + frame->prefixSize(), diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 2aa4a7cb..53ecef62 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -1,31 +1,14 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "H264Rtmp.h" - namespace mediakit{ H264RtmpDecoder::H264RtmpDecoder() { @@ -44,11 +27,74 @@ bool H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos) { return decodeRtmp(rtmp); } +/** + * 返回不带0x00 00 00 01头的sps + * @return + */ +static string getH264SPS(const RtmpPacket &thiz) { + string ret; + if (thiz.getMediaType() != FLV_CODEC_H264) { + return ret; + } + if (!thiz.isCfgFrame()) { + return ret; + } + if (thiz.strBuf.size() < 13) { + WarnL << "bad H264 cfg!"; + return ret; + } + uint16_t sps_size ; + memcpy(&sps_size, thiz.strBuf.data() + 11,2); + sps_size = ntohs(sps_size); + if ((int) thiz.strBuf.size() < 13 + sps_size) { + WarnL << "bad H264 cfg!"; + return ret; + } + ret.assign(thiz.strBuf.data() + 13, sps_size); + return ret; +} + +/** + * 返回不带0x00 00 00 01头的pps + * @return + */ +static string getH264PPS(const RtmpPacket &thiz) { + string ret; + if (thiz.getMediaType() != FLV_CODEC_H264) { + return ret; + } + if (!thiz.isCfgFrame()) { + return ret; + } + if (thiz.strBuf.size() < 13) { + WarnL << "bad H264 cfg!"; + return ret; + } + uint16_t sps_size ; + memcpy(&sps_size,thiz.strBuf.data() + 11,2); + sps_size = ntohs(sps_size); + + if ((int) thiz.strBuf.size() < 13 + sps_size + 1 + 2) { + WarnL << "bad H264 cfg!"; + return ret; + } + uint16_t pps_size ; + memcpy(&pps_size, thiz.strBuf.data() + 13 + sps_size + 1,2); + pps_size = ntohs(pps_size); + + if ((int) thiz.strBuf.size() < 13 + sps_size + 1 + 2 + pps_size) { + WarnL << "bad H264 cfg!"; + return ret; + } + ret.assign(thiz.strBuf.data() + 13 + sps_size + 1 + 2, pps_size); + return ret; +} + bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { if (pkt->isCfgFrame()) { //缓存sps pps,后续插入到I帧之前 - _sps = pkt->getH264SPS(); - _pps = pkt->getH264PPS(); + _sps = getH264SPS(*pkt); + _pps = getH264PPS(*pkt); onGetH264(_sps.data(), _sps.size(), pkt->timeStamp , pkt->timeStamp); onGetH264(_pps.data(), _pps.size(), pkt->timeStamp , pkt->timeStamp); return false; @@ -77,6 +123,9 @@ bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { } inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t dts,uint32_t pts) { + if(iLen == 0){ + return; + } #if 1 _h264frame->_dts = dts; _h264frame->_pts = pts; @@ -93,8 +142,6 @@ inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t dt #endif } - - //////////////////////////////////////////////////////////////////////// H264RtmpEncoder::H264RtmpEncoder(const Track::Ptr &track) { @@ -151,7 +198,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { if(!_lastPacket) { //I or P or B frame - int8_t flags = 7; //h.264 + int8_t flags = FLV_CODEC_H264; bool is_config = false; flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); @@ -175,35 +222,33 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { _lastPacket->bodySize = _lastPacket->strBuf.size(); } - void H264RtmpEncoder::makeVideoConfigPkt() { - int8_t flags = 7; //h.264 + int8_t flags = FLV_CODEC_H264; flags |= (FLV_KEY_FRAME << 4); bool is_config = true; RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper::obtainObj(); rtmpPkt->strBuf.clear(); - //////////header + //header rtmpPkt->strBuf.push_back(flags); rtmpPkt->strBuf.push_back(!is_config); + //cts rtmpPkt->strBuf.append("\x0\x0\x0", 3); - ////////////sps + //AVCDecoderConfigurationRecord start rtmpPkt->strBuf.push_back(1); // version - - //DebugL<strBuf.push_back(_sps[1]); // profile rtmpPkt->strBuf.push_back(_sps[2]); // compat rtmpPkt->strBuf.push_back(_sps[3]); // level rtmpPkt->strBuf.push_back(0xff); // 6 bits reserved + 2 bits nal size length - 1 (11) rtmpPkt->strBuf.push_back(0xe1); // 3 bits reserved + 5 bits number of sps (00001) + //sps uint16_t size = _sps.size(); size = htons(size); rtmpPkt->strBuf.append((char *) &size, 2); rtmpPkt->strBuf.append(_sps); - - /////////////pps + //pps rtmpPkt->strBuf.push_back(1); // version size = _pps.size(); size = htons(size); @@ -218,10 +263,4 @@ void H264RtmpEncoder::makeVideoConfigPkt() { RtmpCodec::inputRtmp(rtmpPkt, false); } - }//namespace mediakit - - - - - diff --git a/src/Extension/H264Rtmp.h b/src/Extension/H264Rtmp.h index a1cae242..e63c6a34 100644 --- a/src/Extension/H264Rtmp.h +++ b/src/Extension/H264Rtmp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_H264RTMPCODEC_H diff --git a/src/Extension/H264Rtp.cpp b/src/Extension/H264Rtp.cpp index 5df37767..1a3f08a8 100644 --- a/src/Extension/H264Rtp.cpp +++ b/src/Extension/H264Rtp.cpp @@ -1,28 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> - * Copyright (c) 2019 火宣 <459502659@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "H264Rtp.h" @@ -88,24 +71,24 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { * Type==7:SPS frame * Type==8:PPS frame */ - /* - RTF3984 5.2节 Common Structure of the RTP Payload Format + /* + RTF3984 5.2节 Common Structure of the RTP Payload Format Table 1. Summary of NAL unit types and their payload structures - Type Packet Type name Section - --------------------------------------------------------- - 0 undefined - - 1-23 NAL unit Single NAL unit packet per H.264 5.6 - 24 STAP-A Single-time aggregation packet 5.7.1 - 25 STAP-B Single-time aggregation packet 5.7.1 - 26 MTAP16 Multi-time aggregation packet 5.7.2 - 27 MTAP24 Multi-time aggregation packet 5.7.2 - 28 FU-A Fragmentation unit 5.8 - 29 FU-B Fragmentation unit 5.8 - 30-31 undefined - + Type Packet Type name Section + --------------------------------------------------------- + 0 undefined - + 1-23 NAL unit Single NAL unit packet per H.264 5.6 + 24 STAP-A Single-time aggregation packet 5.7.1 + 25 STAP-B Single-time aggregation packet 5.7.1 + 26 MTAP16 Multi-time aggregation packet 5.7.2 + 27 MTAP24 Multi-time aggregation packet 5.7.2 + 28 FU-A Fragmentation unit 5.8 + 29 FU-B Fragmentation unit 5.8 + 30-31 undefined - - */ + */ const uint8_t *frame = (uint8_t *) rtppack->data() + rtppack->offset; int length = rtppack->size() - rtppack->offset; NALU nal; diff --git a/src/Extension/H264Rtp.h b/src/Extension/H264Rtp.h index da4aa2d6..a4e8793c 100644 --- a/src/Extension/H264Rtp.h +++ b/src/Extension/H264Rtp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_H264RTPCODEC_H diff --git a/src/Extension/H265.cpp b/src/Extension/H265.cpp index fc7fd8f2..54183150 100644 --- a/src/Extension/H265.cpp +++ b/src/Extension/H265.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "H265.h" @@ -34,36 +18,36 @@ bool getHEVCInfo(const char * vps, int vps_len,const char * sps,int sps_len,int T_GetBitContext tGetBitBuf; T_HEVCSPS tH265SpsInfo; T_HEVCVPS tH265VpsInfo; - if ( vps_len > 2 ){ - memset(&tGetBitBuf,0,sizeof(tGetBitBuf)); - memset(&tH265VpsInfo,0,sizeof(tH265VpsInfo)); - tGetBitBuf.pu8Buf = (uint8_t*)vps+2; - tGetBitBuf.iBufSize = vps_len-2; - if(0 != h265DecVideoParameterSet((void *) &tGetBitBuf, &tH265VpsInfo)){ - return false; - } - } + if ( vps_len > 2 ){ + memset(&tGetBitBuf,0,sizeof(tGetBitBuf)); + memset(&tH265VpsInfo,0,sizeof(tH265VpsInfo)); + tGetBitBuf.pu8Buf = (uint8_t*)vps+2; + tGetBitBuf.iBufSize = vps_len-2; + if(0 != h265DecVideoParameterSet((void *) &tGetBitBuf, &tH265VpsInfo)){ + return false; + } + } - if ( sps_len > 2 ){ - memset(&tGetBitBuf,0,sizeof(tGetBitBuf)); - memset(&tH265SpsInfo,0,sizeof(tH265SpsInfo)); - tGetBitBuf.pu8Buf = (uint8_t*)sps+2; - tGetBitBuf.iBufSize = sps_len-2; - if(0 != h265DecSeqParameterSet((void *) &tGetBitBuf, &tH265SpsInfo)){ - return false; - } - } - else - return false; + if ( sps_len > 2 ){ + memset(&tGetBitBuf,0,sizeof(tGetBitBuf)); + memset(&tH265SpsInfo,0,sizeof(tH265SpsInfo)); + tGetBitBuf.pu8Buf = (uint8_t*)sps+2; + tGetBitBuf.iBufSize = sps_len-2; + if(0 != h265DecSeqParameterSet((void *) &tGetBitBuf, &tH265SpsInfo)){ + return false; + } + } + else + return false; h265GetWidthHeight(&tH265SpsInfo, &iVideoWidth, &iVideoHeight); - iVideoFps = 0; + iVideoFps = 0; h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps); // ErrorL << iVideoWidth << " " << iVideoHeight << " " << iVideoFps; return true; } bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps) { - return getHEVCInfo(strVps.data(),strVps.size(),strSps.data(),strSps.size(),iVideoWidth,iVideoHeight,iVideoFps); + return getHEVCInfo(strVps.data(),strVps.size(),strSps.data(),strSps.size(),iVideoWidth,iVideoHeight,iVideoFps); } Sdp::Ptr H265Track::getSdp() { diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 80591e32..71069d11 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef ZLMEDIAKIT_H265_H #define ZLMEDIAKIT_H265_H @@ -202,7 +186,7 @@ public: _vps = vps.substr(vps_prefix_len); _sps = sps.substr(sps_prefix_len); _pps = pps.substr(pps_prefix_len); - onReady(); + onReady(); } /** @@ -267,10 +251,10 @@ public: * @param frame 数据帧 */ void inputFrame(const Frame::Ptr &frame) override{ - int type = H265_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); - if(type == H265Frame::NAL_VPS){ - bool first_frame = true; - splitH264(frame->data() + frame->prefixSize(), + int type = H265_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); + if(frame->configFrame()){ + bool first_frame = true; + splitH264(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), [&](const char *ptr, int len){ if(first_frame){ @@ -288,9 +272,9 @@ public: inputFrame_l(sub_frame); } }); - }else{ - inputFrame_l(frame); - } + }else{ + inputFrame_l(frame); + } } private: @@ -336,7 +320,7 @@ private: } } - /** + /** * 解析sps获取宽高fps */ void onReady(){ diff --git a/src/Extension/H265Rtmp.cpp b/src/Extension/H265Rtmp.cpp new file mode 100644 index 00000000..ff346582 --- /dev/null +++ b/src/Extension/H265Rtmp.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include "H265Rtmp.h" +#ifdef ENABLE_MP4 +#include "mpeg4-hevc.h" +#endif//ENABLE_MP4 + +namespace mediakit{ + +H265RtmpDecoder::H265RtmpDecoder() { + _h265frame = obtainFrame(); +} + +H265Frame::Ptr H265RtmpDecoder::obtainFrame() { + //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 + auto frame = obtainObj(); + frame->_buffer.clear(); + frame->_prefix_size = 4; + return frame; +} + +bool H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos) { + return decodeRtmp(rtmp); +} + +#ifdef ENABLE_MP4 +/** + * 返回不带0x00 00 00 01头的sps + * @return + */ +static bool getH265ConfigFrame(const RtmpPacket &thiz,string &frame) { + if (thiz.getMediaType() != FLV_CODEC_H265) { + return false; + } + if (!thiz.isCfgFrame()) { + return false; + } + if (thiz.strBuf.size() < 6) { + WarnL << "bad H265 cfg!"; + return false; + } + + auto extra = thiz.strBuf.data() + 5; + auto bytes = thiz.strBuf.size() - 5; + + struct mpeg4_hevc_t hevc = {0}; + if (mpeg4_hevc_decoder_configuration_record_load((uint8_t *) extra, bytes, &hevc) > 0) { + uint8_t config[1024] = {0}; + int size = mpeg4_hevc_to_nalu(&hevc, config, sizeof(config)); + if (size > 4) { + frame.assign((char *) config + 4, size - 4); + return true; + } + } + + return false; +} +#endif + +bool H265RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) { + if (pkt->isCfgFrame()) { +#ifdef ENABLE_MP4 + string config; + if(getH265ConfigFrame(*pkt,config)){ + onGetH265(config.data(), config.size(), pkt->timeStamp , pkt->timeStamp); + } +#else + WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265-RTMP支持不完善"; +#endif + return false; + } + + if (pkt->strBuf.size() > 9) { + uint32_t iTotalLen = pkt->strBuf.size(); + uint32_t iOffset = 5; + uint8_t *cts_ptr = (uint8_t *) (pkt->strBuf.data() + 2); + int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000; + auto pts = pkt->timeStamp + cts; + + while(iOffset + 4 < iTotalLen){ + uint32_t iFrameLen; + memcpy(&iFrameLen, pkt->strBuf.data() + iOffset, 4); + iFrameLen = ntohl(iFrameLen); + iOffset += 4; + if(iFrameLen + iOffset > iTotalLen){ + break; + } + onGetH265(pkt->strBuf.data() + iOffset, iFrameLen, pkt->timeStamp , pts); + iOffset += iFrameLen; + } + } + return pkt->isVideoKeyFrame(); +} + +inline void H265RtmpDecoder::onGetH265(const char* pcData, int iLen, uint32_t dts,uint32_t pts) { + if(iLen == 0){ + return; + } +#if 1 + _h265frame->_dts = dts; + _h265frame->_pts = pts; + _h265frame->_buffer.assign("\x0\x0\x0\x1", 4); //添加265头 + _h265frame->_buffer.append(pcData, iLen); + + //写入环形缓存 + RtmpCodec::inputFrame(_h265frame); + _h265frame = obtainFrame(); +#else + //防止内存拷贝,这样产生的265帧不会有0x00 00 01头 + auto frame = std::make_shared((char *)pcData,iLen,dts,pts,0); + RtmpCodec::inputFrame(frame); +#endif +} + +//////////////////////////////////////////////////////////////////////// + +H265RtmpEncoder::H265RtmpEncoder(const Track::Ptr &track) { + _track = dynamic_pointer_cast(track); +} + +void H265RtmpEncoder::makeConfigPacket(){ + if (_track && _track->ready()) { + //尝试从track中获取sps pps信息 + _sps = _track->getSps(); + _pps = _track->getPps(); + _vps = _track->getVps(); + } + + if (!_sps.empty() && !_pps.empty() && !_vps.empty()) { + //获取到sps/pps + makeVideoConfigPkt(); + _gotSpsPps = true; + } +} + +void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { + auto pcData = frame->data() + frame->prefixSize(); + auto iLen = frame->size() - frame->prefixSize(); + auto type = H265_TYPE(((uint8_t*)pcData)[0]); + + if (!_gotSpsPps) { + //尝试从frame中获取sps pps + switch (type) { + case H265Frame::NAL_SPS: { + //sps + _sps = string(pcData, iLen); + makeConfigPacket(); + break; + } + case H265Frame::NAL_PPS: { + //pps + _pps = string(pcData, iLen); + makeConfigPacket(); + break; + } + case H265Frame::NAL_VPS: { + //vps + _vps = string(pcData, iLen); + makeConfigPacket(); + break; + } + default: + break; + } + } + + if(type == H265Frame::NAL_SEI_PREFIX || type == H265Frame::NAL_SEI_SUFFIX){ + return; + } + + if(_lastPacket && _lastPacket->timeStamp != frame->dts()) { + RtmpCodec::inputRtmp(_lastPacket, _lastPacket->isVideoKeyFrame()); + _lastPacket = nullptr; + } + + if(!_lastPacket) { + //I or P or B frame + int8_t flags = FLV_CODEC_H265; + bool is_config = false; + flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); + + _lastPacket = ResourcePoolHelper::obtainObj(); + _lastPacket->strBuf.clear(); + _lastPacket->strBuf.push_back(flags); + _lastPacket->strBuf.push_back(!is_config); + auto cts = frame->pts() - frame->dts(); + cts = htonl(cts); + _lastPacket->strBuf.append((char *)&cts + 1, 3); + + _lastPacket->chunkId = CHUNK_VIDEO; + _lastPacket->streamId = STREAM_MEDIA; + _lastPacket->timeStamp = frame->dts(); + _lastPacket->typeId = MSG_VIDEO; + + } + auto size = htonl(iLen); + _lastPacket->strBuf.append((char *) &size, 4); + _lastPacket->strBuf.append(pcData, iLen); + _lastPacket->bodySize = _lastPacket->strBuf.size(); +} + +void H265RtmpEncoder::makeVideoConfigPkt() { +#ifdef ENABLE_MP4 + int8_t flags = FLV_CODEC_H265; + flags |= (FLV_KEY_FRAME << 4); + bool is_config = true; + + RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper::obtainObj(); + rtmpPkt->strBuf.clear(); + + //header + rtmpPkt->strBuf.push_back(flags); + rtmpPkt->strBuf.push_back(!is_config); + //cts + rtmpPkt->strBuf.append("\x0\x0\x0", 3); + + struct mpeg4_hevc_t hevc = {0}; + string vps_sps_pps = string("\x00\x00\x00\x01", 4) + _vps + + string("\x00\x00\x00\x01", 4) + _sps + + string("\x00\x00\x00\x01", 4) + _pps; + h265_annexbtomp4(&hevc, vps_sps_pps.data(), vps_sps_pps.size(), NULL, 0, NULL, NULL); + uint8_t extra_data[1024]; + int extra_data_size = mpeg4_hevc_decoder_configuration_record_save(&hevc, extra_data, sizeof(extra_data)); + if (extra_data_size == -1) { + WarnL << "生成H265 extra_data 失败"; + return; + } + + //HEVCDecoderConfigurationRecord + rtmpPkt->strBuf.append((char *)extra_data, extra_data_size); + + rtmpPkt->bodySize = rtmpPkt->strBuf.size(); + rtmpPkt->chunkId = CHUNK_VIDEO; + rtmpPkt->streamId = STREAM_MEDIA; + rtmpPkt->timeStamp = 0; + rtmpPkt->typeId = MSG_VIDEO; + RtmpCodec::inputRtmp(rtmpPkt, false); +#else + WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265-RTMP支持不完善"; +#endif +} + +}//namespace mediakit diff --git a/src/Extension/H265Rtmp.h b/src/Extension/H265Rtmp.h new file mode 100644 index 00000000..3bcf09c9 --- /dev/null +++ b/src/Extension/H265Rtmp.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_H265RTMPCODEC_H +#define ZLMEDIAKIT_H265RTMPCODEC_H + +#include "Rtmp/RtmpCodec.h" +#include "Extension/Track.h" +#include "Util/ResourcePool.h" +#include "Extension/H265.h" +using namespace toolkit; + +namespace mediakit{ +/** + * h265 Rtmp解码类 + * 将 h265 over rtmp 解复用出 h265-Frame + */ +class H265RtmpDecoder : public RtmpCodec ,public ResourcePoolHelper { +public: + typedef std::shared_ptr Ptr; + + H265RtmpDecoder(); + ~H265RtmpDecoder() {} + + /** + * 输入265 Rtmp包 + * @param rtmp Rtmp包 + * @param key_pos 此参数忽略之 + */ + bool inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos = true) override; + + TrackType getTrackType() const override{ + return TrackVideo; + } + + CodecId getCodecId() const override{ + return CodecH265; + } +protected: + bool decodeRtmp(const RtmpPacket::Ptr &Rtmp); + void onGetH265(const char *pcData, int iLen, uint32_t dts,uint32_t pts); + H265Frame::Ptr obtainFrame(); +protected: + H265Frame::Ptr _h265frame; +}; + +/** + * 265 Rtmp打包类 + */ +class H265RtmpEncoder : public H265RtmpDecoder, public ResourcePoolHelper { +public: + typedef std::shared_ptr Ptr; + + /** + * 构造函数,track可以为空,此时则在inputFrame时输入sps pps + * 如果track不为空且包含sps pps信息, + * 那么inputFrame时可以不输入sps pps + * @param track + */ + H265RtmpEncoder(const Track::Ptr &track); + ~H265RtmpEncoder() {} + + /** + * 输入265帧,可以不带sps pps + * @param frame 帧数据 + */ + void inputFrame(const Frame::Ptr &frame) override; + + /** + * 生成config包 + */ + void makeConfigPacket() override; +private: + void makeVideoConfigPkt(); +private: + string _vps; + string _sps; + string _pps; + H265Track::Ptr _track; + bool _gotSpsPps = false; + RtmpPacket::Ptr _lastPacket; +}; + +}//namespace mediakit + +#endif //ZLMEDIAKIT_H265RTMPCODEC_H diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index 8f41ec76..b41b4cfa 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "H265Rtp.h" diff --git a/src/Extension/H265Rtp.h b/src/Extension/H265Rtp.h index a2844092..1098983a 100644 --- a/src/Extension/H265Rtp.h +++ b/src/Extension/H265Rtp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_H265RTPCODEC_H diff --git a/src/Extension/SPSParser.c b/src/Extension/SPSParser.c index 54c19592..36c2aed7 100644 --- a/src/Extension/SPSParser.c +++ b/src/Extension/SPSParser.c @@ -234,16 +234,16 @@ static const T_AVRational sg_atVuiSar[] = { static inline int getBitsLeft(void *pvHandle) { - int iResLen = 0; - T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; - if(ptPtr->iBufSize <= 0 || ptPtr->iTotalBit <= 0) - { - RPT(RPT_WRN, "buffer size is zero"); - return 0; - } + int iResLen = 0; + T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; + if(ptPtr->iBufSize <= 0 || ptPtr->iTotalBit <= 0) + { + RPT(RPT_WRN, "buffer size is zero"); + return 0; + } - iResLen = ptPtr->iTotalBit - ptPtr->iBitPos; + iResLen = ptPtr->iTotalBit - ptPtr->iBitPos; return iResLen; } @@ -264,7 +264,7 @@ static int getOneBit(void *pvHandle) int iRet = 0; uint8_t *pu8CurChar = NULL; uint8_t u8Shift; - int iResoLen = 0; + int iResoLen = 0; if(NULL == ptPtr) { @@ -272,12 +272,12 @@ static int getOneBit(void *pvHandle) iRet = -1; goto exit; } - iResoLen = getBitsLeft(ptPtr); - if(iResoLen < 1) - { + iResoLen = getBitsLeft(ptPtr); + if(iResoLen < 1) + { iRet = -1; goto exit; - } + } pu8CurChar = ptPtr->pu8Buf + (ptPtr->iBitPos >> 3); u8Shift = 7 - (ptPtr->iCurBitPos); @@ -307,7 +307,7 @@ static int getBits(void *pvHandle, int iN) uint8_t u8Shift; uint32_t u32Result = 0; int iRet = 0; - int iResoLen = 0; + int iResoLen = 0; if(NULL == ptPtr) { @@ -321,12 +321,12 @@ static int getBits(void *pvHandle, int iN) iN = MAX_LEN; } - iResoLen = getBitsLeft(ptPtr); - if(iResoLen < iN) - { + iResoLen = getBitsLeft(ptPtr); + if(iResoLen < iN) + { iRet = -1; goto exit; - } + } if((ptPtr->iBitPos + iN) > ptPtr->iTotalBit) @@ -374,7 +374,7 @@ static inline unsigned int showBits(void *pvHandle, int iN) uint8_t u8Shift; uint32_t u32Result = 0; int iRet = 0; - int iResoLen = 0; + int iResoLen = 0; if(NULL == ptPtr) { @@ -388,12 +388,12 @@ static inline unsigned int showBits(void *pvHandle, int iN) iN = MAX_LEN; } - iResoLen = getBitsLeft(ptPtr); - if(iResoLen < iN) - { + iResoLen = getBitsLeft(ptPtr); + if(iResoLen < iN) + { iRet = -1; goto exit; - } + } if((ptPtr->iBitPos + iN) > ptPtr->iTotalBit) @@ -435,7 +435,7 @@ exit: */ static inline unsigned int showBitsLong(void *pvHandle, int iN) { - T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; + T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; if (iN <= 32) { return showBits(ptPtr, iN); @@ -611,23 +611,23 @@ static void decodeScalingList(void *pvBuf, uint8_t *pu8Factors, int iSize, const uint8_t *pu8FallbackList) { int i; - int iLast = 8; - int iNext = 8; + int iLast = 8; + int iNext = 8; const uint8_t *pu8Scan = iSize == 16 ? sg_au8ZigzagScan : g_au8FfZigzagDirect; if (!getOneBit(pvBuf)) /* matrix not written, we use the predicted one */ memcpy(pu8Factors, pu8FallbackList, iSize * sizeof(uint8_t)); else for (i = 0; i < iSize; i++) - { + { if (iNext) { iNext = (iLast + parseSe(pvBuf)) & 0xff; } if (!i && !iNext) - { - /* matrix not written, we use the preset one */ + { + /* matrix not written, we use the preset one */ memcpy(pu8Factors, pu8JvtList, iSize * sizeof(uint8_t)); break; } @@ -652,49 +652,49 @@ static void decodeScalingList(void *pvBuf, uint8_t *pu8Factors, int iSize, ptSps->iScalingMatrixPresent |= iIsSps; decodeScalingList(pvBuf, pau8ScalingMatrix4[0], 16, sg_aau8DefaultScaling4[0], pau8Fallback[0]); // Intra, Y decodeScalingList(pvBuf, pau8ScalingMatrix4[1], 16, sg_aau8DefaultScaling4[0], pau8ScalingMatrix4[0]); // Intra, Cr - decodeScalingList(pvBuf, pau8ScalingMatrix4[2], 16, sg_aau8DefaultScaling4[0], pau8ScalingMatrix4[1]); // Intra, Cb + decodeScalingList(pvBuf, pau8ScalingMatrix4[2], 16, sg_aau8DefaultScaling4[0], pau8ScalingMatrix4[1]); // Intra, Cb - decodeScalingList(pvBuf, pau8ScalingMatrix4[3], 16, sg_aau8DefaultScaling4[1], pau8Fallback[1]); // Inter, Y + decodeScalingList(pvBuf, pau8ScalingMatrix4[3], 16, sg_aau8DefaultScaling4[1], pau8Fallback[1]); // Inter, Y - decodeScalingList(pvBuf, pau8ScalingMatrix4[4], 16, sg_aau8DefaultScaling4[1], pau8ScalingMatrix4[3]); // Inter, Cr + decodeScalingList(pvBuf, pau8ScalingMatrix4[4], 16, sg_aau8DefaultScaling4[1], pau8ScalingMatrix4[3]); // Inter, Cr - decodeScalingList(pvBuf, pau8ScalingMatrix4[5], 16, sg_aau8DefaultScaling4[1], pau8ScalingMatrix4[4]); // Inter, Cb + decodeScalingList(pvBuf, pau8ScalingMatrix4[5], 16, sg_aau8DefaultScaling4[1], pau8ScalingMatrix4[4]); // Inter, Cb if (iIsSps || ptPps->iTransform8x8Mode) - { + { decodeScalingList(pvBuf, pau8ScalingMatrix8[0], 64, sg_aau8DefaultScaling8[0], pau8Fallback[2]); // Intra, Y decodeScalingList(pvBuf, pau8ScalingMatrix8[3], 64, sg_aau8DefaultScaling8[1], pau8Fallback[3]); // Inter, Y if (ptSps->iChromaFormatIdc == 3) { decodeScalingList(pvBuf, pau8ScalingMatrix8[1], 64, sg_aau8DefaultScaling8[0], pau8ScalingMatrix8[0]); // Intra, Cr - decodeScalingList(pvBuf, pau8ScalingMatrix8[4], 64, sg_aau8DefaultScaling8[1], pau8ScalingMatrix8[3]); // Inter, Cr - decodeScalingList(pvBuf, pau8ScalingMatrix8[2], 64, sg_aau8DefaultScaling8[0], pau8ScalingMatrix8[1]); // Intra, Cb - decodeScalingList(pvBuf, pau8ScalingMatrix8[5], 64, sg_aau8DefaultScaling8[1], pau8ScalingMatrix8[4]); // Inter, Cb - } + decodeScalingList(pvBuf, pau8ScalingMatrix8[4], 64, sg_aau8DefaultScaling8[1], pau8ScalingMatrix8[3]); // Inter, Cr + decodeScalingList(pvBuf, pau8ScalingMatrix8[2], 64, sg_aau8DefaultScaling8[0], pau8ScalingMatrix8[1]); // Intra, Cb + decodeScalingList(pvBuf, pau8ScalingMatrix8[5], 64, sg_aau8DefaultScaling8[1], pau8ScalingMatrix8[4]); // Inter, Cb + } } } - return 0; + return 0; } static int decodeHrdPAarameters(void *pvBuf, T_SPS *ptSps) { int iCpbCount = 0; - int i; + int i; iCpbCount = parseUe(pvBuf); if (iCpbCount > 32U) - { - RPT(RPT_ERR,"iCpbCount %d invalid\n", iCpbCount); - return -1; + { + RPT(RPT_ERR,"iCpbCount %d invalid\n", iCpbCount); + return -1; } getBits(pvBuf, 4); /* bit_rate_scale */ getBits(pvBuf, 4); /* cpb_size_scale */ for (i = 0; i < iCpbCount; i++) - { - parseUe(pvBuf); - parseUe(pvBuf); + { + parseUe(pvBuf); + parseUe(pvBuf); //get_ue_golomb_long(&h->gb); /* bit_rate_value_minus1 */ //get_ue_golomb_long(&h->gb); /* cpb_size_value_minus1 */ getOneBit(pvBuf); /* cbr_flag */ @@ -712,7 +712,7 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) { int iAspectRatioInfoPresentFlag; unsigned int uiAspectRatioIdc; - int iChromaSampleLocation; + int iChromaSampleLocation; iAspectRatioInfoPresentFlag = getOneBit(pvBuf); @@ -725,7 +725,7 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) ptSps->tSar = sg_atFfH264PixelSspect[uiAspectRatioIdc]; } else { - RPT(RPT_ERR,"illegal aspect ratio\n"); + RPT(RPT_ERR,"illegal aspect ratio\n"); return -1; } } else @@ -758,15 +758,15 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) /* chroma_location_info_present_flag */ if (getOneBit(pvBuf)) - { + { /* chroma_sample_location_type_top_field */ iChromaSampleLocation = parseUe(pvBuf); parseUe(pvBuf); /* chroma_sample_location_type_bottom_field */ } - if(getBitsLeft(pvBuf) < 10) - { - return 0; - } + if(getBitsLeft(pvBuf) < 10) + { + return 0; + } ptSps->iTimingInfoPresentFlag = getOneBit(pvBuf); @@ -775,7 +775,7 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) unsigned u32TimeScale = getBits(pvBuf, 32); if (!u32NumUnitsInTick || !u32TimeScale) { - RPT(RPT_ERR,"u32TimeScale/u32NumUnitsInTick invalid or unsupported (%u/%u)\n",u32TimeScale, u32NumUnitsInTick); + RPT(RPT_ERR,"u32TimeScale/u32NumUnitsInTick invalid or unsupported (%u/%u)\n",u32TimeScale, u32NumUnitsInTick); ptSps->iTimingInfoPresentFlag = 0; } else { ptSps->u32NumUnitsInTick = u32NumUnitsInTick; @@ -797,12 +797,12 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) getOneBit(pvBuf); /* low_delay_hrd_flag */ ptSps->iPicStructPresentFlag = getOneBit(pvBuf); - if(getBitsLeft(pvBuf) == 0) - return 0; + if(getBitsLeft(pvBuf) == 0) + return 0; ptSps->iBitstreamRestrictionFlag = getOneBit(pvBuf); if (ptSps->iBitstreamRestrictionFlag) { getOneBit(pvBuf); /* motion_vectors_over_pic_boundaries_flag */ - parseUe(pvBuf); + parseUe(pvBuf); //get_ue_golomb(&h->gb); /* max_bytes_per_pic_denom */ parseUe(pvBuf); //get_ue_golomb(&h->gb); /* max_bits_per_mb_denom */ @@ -812,11 +812,11 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) //get_ue_golomb(&h->gb); /* log2_max_mv_length_vertical */ ptSps->iNumReorderFrames = parseUe(pvBuf); - parseUe(pvBuf); + parseUe(pvBuf); //get_ue_golomb(&h->gb); /*max_dec_frame_buffering*/ if (getBitsLeft(pvBuf) < 0) - { + { ptSps->iNumReorderFrames = 0; ptSps->iBitstreamRestrictionFlag = 0; } @@ -824,7 +824,7 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) if (ptSps->iNumReorderFrames > 16U /* max_dec_frame_buffering || max_dec_frame_buffering > 16 */) { - RPT(RPT_DBG, "Clipping illegal iNumReorderFrames %d\n", + RPT(RPT_DBG, "Clipping illegal iNumReorderFrames %d\n", ptSps->iNumReorderFrames); ptSps->iNumReorderFrames = 16; return -1; @@ -838,10 +838,10 @@ static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) { int iLevelIdc; - int iConstraintSetFlags = 0; + int iConstraintSetFlags = 0; unsigned int uiSpsId; int i; - int iLog2MaxFrameNumMinus4; + int iLog2MaxFrameNumMinus4; int iRet = 0; int iProfileIdc = 0; @@ -910,44 +910,44 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) ptSps->iProfileIdc == 144) { // old High444 profile ptSps->iChromaFormatIdc = parseUe(pvBuf); if (ptSps->iChromaFormatIdc > 3U) - { + { RPT(RPT_ERR, "iChromaFormatIdc %u",ptSps->iChromaFormatIdc); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } - else if (ptSps->iChromaFormatIdc == 3) - { + else if (ptSps->iChromaFormatIdc == 3) + { ptSps->iResidualColorTransformFlag = getOneBit(pvBuf); if (ptSps->iResidualColorTransformFlag) - { - RPT(RPT_ERR, "separate color planes are not supported\n"); - iRet = -1; - goto exit; + { + RPT(RPT_ERR, "separate color planes are not supported\n"); + iRet = -1; + goto exit; } } ptSps->iBitDepthLuma = parseUe(pvBuf) + 8; ptSps->iBitDepthChroma = parseUe(pvBuf) + 8; if (ptSps->iBitDepthChroma != ptSps->iBitDepthLuma) - { - RPT(RPT_ERR, "Different chroma and luma bit depth"); - iRet = -1; - goto exit; + { + RPT(RPT_ERR, "Different chroma and luma bit depth"); + iRet = -1; + goto exit; } if (ptSps->iBitDepthLuma < 8 || ptSps->iBitDepthLuma > 14 || ptSps->iBitDepthChroma < 8 || ptSps->iBitDepthChroma > 14) { - RPT(RPT_ERR, "illegal bit depth value (%d, %d)\n",ptSps->iBitDepthLuma, ptSps->iBitDepthChroma); - iRet = -1; - goto exit; + RPT(RPT_ERR, "illegal bit depth value (%d, %d)\n",ptSps->iBitDepthLuma, ptSps->iBitDepthChroma); + iRet = -1; + goto exit; } ptSps->iTransformBypass = getOneBit(pvBuf); decodeScalingMatrices(pvBuf, ptSps, NULL, 1, ptSps->aau8ScalingMatrix4, ptSps->aau8ScalingMatrix8); } - else - { + else + { ptSps->iChromaFormatIdc = 1; ptSps->iBitDepthLuma = 8; @@ -959,9 +959,9 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) if (iLog2MaxFrameNumMinus4 < MIN_LOG2_MAX_FRAME_NUM - 4 || iLog2MaxFrameNumMinus4 > MAX_LOG2_MAX_FRAME_NUM - 4) { - RPT(RPT_ERR, "iLog2MaxFrameNumMinus4 out of range (0-12): %d\n", iLog2MaxFrameNumMinus4); - iRet = -1; - goto exit; + RPT(RPT_ERR, "iLog2MaxFrameNumMinus4 out of range (0-12): %d\n", iLog2MaxFrameNumMinus4); + iRet = -1; + goto exit; } ptSps->iLog2MaxFrameNum = iLog2MaxFrameNumMinus4 + 4; @@ -969,21 +969,21 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) ptSps->iPocType = parseUe(pvBuf); if (ptSps->iPocType == 0) - { - // FIXME #define + { + // FIXME #define unsigned t = parseUe(pvBuf); if (t>12) - { - RPT(RPT_ERR, "iLog2MaxPocLsb (%d) is out of range\n", t); - iRet = -1; - goto exit; + { + RPT(RPT_ERR, "iLog2MaxPocLsb (%d) is out of range\n", t); + iRet = -1; + goto exit; } ptSps->iLog2MaxPocLsb = t + 4; } - else if (ptSps->iPocType == 1) - { - // FIXME #define + else if (ptSps->iPocType == 1) + { + // FIXME #define ptSps->iDeltaPicOrderAlwaysZeroFlag = getOneBit(pvBuf); ptSps->iOffsetForNonRefPic = parseSe(pvBuf); ptSps->iOffsetForTopToBottomField = parseSe(pvBuf); @@ -991,20 +991,20 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) if ((unsigned)ptSps->iPocCycleLength >= FF_ARRAY_ELEMS(ptSps->asOffsetForRefFrame)) { - RPT(RPT_ERR, "iPocCycleLength overflow %d\n", ptSps->iPocCycleLength); - iRet = -1; - goto exit; + RPT(RPT_ERR, "iPocCycleLength overflow %d\n", ptSps->iPocCycleLength); + iRet = -1; + goto exit; } for (i = 0; i < ptSps->iPocCycleLength; i++) ptSps->asOffsetForRefFrame[i] = parseSe(pvBuf); } - else if (ptSps->iPocType != 2) - { - RPT(RPT_ERR, "illegal POC type %d\n", ptSps->iPocType); - iRet = -1; - goto exit; + else if (ptSps->iPocType != 2) + { + RPT(RPT_ERR, "illegal POC type %d\n", ptSps->iPocType); + iRet = -1; + goto exit; } @@ -1012,9 +1012,9 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) if (ptSps->iRefFrameCount > H264_MAX_PICTURE_COUNT - 2 || ptSps->iRefFrameCount > 16U) { - RPT(RPT_ERR, "too many reference frames %d\n", ptSps->iRefFrameCount); - iRet = -1; - goto exit; + RPT(RPT_ERR, "too many reference frames %d\n", ptSps->iRefFrameCount); + iRet = -1; + goto exit; } ptSps->iGapsInFrameNumAllowedFlag = getOneBit(pvBuf); @@ -1039,8 +1039,8 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) int iWidth = 16 * ptSps->iMbWidth; int iHeight = 16 * ptSps->iMbHeight * (2 - ptSps->iFrameMbsOnlyFlag); - if(1) - { + if(1) + { int vsub = (ptSps->iChromaFormatIdc == 1) ? 1 : 0; int hsub = (ptSps->iChromaFormatIdc == 1 || ptSps->iChromaFormatIdc == 2) ? 1 : 0; @@ -1048,7 +1048,7 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) int step_y = (2 - ptSps->iFrameMbsOnlyFlag) << vsub; if (uiCropLeft & (0x1F >> (ptSps->iBitDepthLuma > 8))) - { + { uiCropLeft &= ~(0x1F >> (ptSps->iBitDepthLuma > 8)); } @@ -1060,9 +1060,9 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) (uiCropTop + uiCropBottom) * step_y >= iHeight ) { - RPT(RPT_ERR, "crop values invalid %d %d %d %d / %d %d\n", uiCropLeft, uiCropRight, uiCropTop, uiCropBottom, iWidth, iHeight); - iRet = -1; - goto exit; + RPT(RPT_ERR, "crop values invalid %d %d %d %d / %d %d\n", uiCropLeft, uiCropRight, uiCropTop, uiCropBottom, iWidth, iHeight); + iRet = -1; + goto exit; } ptSps->uiCropLeft = uiCropLeft * step_x; @@ -1071,8 +1071,8 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) ptSps->uiCropBottom = uiCropBottom * step_y; } } - else - { + else + { ptSps->uiCropLeft = ptSps->uiCropRight = ptSps->uiCropTop = @@ -1088,9 +1088,9 @@ int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) } if (getBitsLeft(pvBuf) < 0) - { - RPT(RPT_ERR, "Overread %s by %d bits\n", ptSps->iVuiParametersPresentFlag ? "VUI" : "SPS", -getBitsLeft(pvBuf)); - iRet = -1; + { + RPT(RPT_ERR, "Overread %s by %d bits\n", ptSps->iVuiParametersPresentFlag ? "VUI" : "SPS", -getBitsLeft(pvBuf)); + iRet = -1; } if (!ptSps->tSar.den) @@ -1102,7 +1102,7 @@ exit: #ifdef SPS_PPS_DEBUG if (1) - { + { static const char csp[4][5] = { "Gray", "420", "422", "444" }; RPT(RPT_DBG, "ptSps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %d/%d b%d reo:%d\n", @@ -1168,7 +1168,7 @@ static int decodeProfileTierLevel(T_GetBitContext *pvBuf, T_PTLCommon *tPtl) return 0; } - + static int parsePtl(T_GetBitContext *pvBuf, T_PTL *tPtl, int max_num_sub_layers) { @@ -1208,7 +1208,7 @@ static int parsePtl(T_GetBitContext *pvBuf, T_PTL *tPtl, int max_num_sub_layers) return 0; } - + static void setDefaultScalingListData(T_ScalingList *sl) { @@ -1536,7 +1536,7 @@ static int decodeHrd(T_GetBitContext *pvBuf, int common_inf_present, return 0; } - + static void decodeVui(T_GetBitContext *pvBuf, T_HEVCSPS *ptSps) { @@ -1702,16 +1702,16 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) ptSps->uiVpsId = getBits(pvBuf, 4); if (ptSps->uiVpsId >= HEVC_MAX_VPS_COUNT) { RPT(RPT_ERR, "VPS id out of range: %d\n", ptSps->uiVpsId); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->iMaxSubLayers = getBits(pvBuf, 3) + 1; if (ptSps->iMaxSubLayers > HEVC_MAX_SUB_LAYERS) { RPT(RPT_ERR, "sps_max_sub_layers out of range: %d\n", ptSps->iMaxSubLayers); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->u8temporalIdNestingFlag = getBits(pvBuf, 1); @@ -1721,15 +1721,15 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) int sps_id = parseUe(pvBuf); if (sps_id >= HEVC_MAX_SPS_COUNT) { RPT(RPT_ERR, "SPS id out of range: %d\n", sps_id); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->iChromaFormatIdc = parseUe(pvBuf); if (ptSps->iChromaFormatIdc > 3U) { RPT(RPT_ERR, "iChromaFormatIdc %d is invalid\n", ptSps->iChromaFormatIdc); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } if (ptSps->iChromaFormatIdc == 3) @@ -1754,14 +1754,14 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) ptSps->iBitDepth = parseUe(pvBuf) + 8; iBitDepthChroma = parseUe(pvBuf) + 8; - + if (ptSps->iChromaFormatIdc && iBitDepthChroma != ptSps->iBitDepth) { RPT(RPT_ERR, "Luma bit depth (%d) is different from chroma bit depth (%d), " "this is unsupported.\n", ptSps->iBitDepth, iBitDepthChroma); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->iBitDepthChroma = iBitDepthChroma; @@ -1769,8 +1769,8 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) if (ptSps->uiLog2MaxPocLsb > 16) { RPT(RPT_ERR, "log2_max_pic_order_cnt_lsb_minus4 out range: %d\n", ptSps->uiLog2MaxPocLsb - 4); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } iSublayerOrderingInfo = getOneBit(pvBuf); @@ -1782,15 +1782,15 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) if (ptSps->stTemporalLayer[i].iMaxDecPicBuffering > (unsigned)HEVC_MAX_DPB_SIZE) { RPT(RPT_ERR, "sps_max_dec_pic_buffering_minus1 out of range: %d\n", ptSps->stTemporalLayer[i].iMaxDecPicBuffering - 1U); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } if (ptSps->stTemporalLayer[i].iNumReorderPics > ptSps->stTemporalLayer[i].iMaxDecPicBuffering - 1) { RPT(RPT_WRN, "sps_max_num_reorder_pics out of range: %d\n", ptSps->stTemporalLayer[i].iNumReorderPics); if (ptSps->stTemporalLayer[i].iNumReorderPics > HEVC_MAX_DPB_SIZE - 1) { - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->stTemporalLayer[i].iMaxDecPicBuffering = ptSps->stTemporalLayer[i].iNumReorderPics + 1; } @@ -1813,33 +1813,33 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) if (ptSps->uiLog2MinCbSize < 3 || ptSps->uiLog2MinCbSize > 30) { RPT(RPT_ERR, "Invalid value %d for uiLog2MinCbSize", ptSps->uiLog2MinCbSize); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } if (ptSps->uiLog2DiffMaxMinCodingBlockSize > 30) { RPT(RPT_ERR, "Invalid value %d for uiLog2DiffMaxMinCodingBlockSize", ptSps->uiLog2DiffMaxMinCodingBlockSize); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } if (ptSps->uiLog2MinTbSize >= ptSps->uiLog2MinCbSize || ptSps->uiLog2MinTbSize < 2) { RPT(RPT_ERR, "Invalid value for uiLog2MinTbSize"); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } if (iLog2DiffMaxMinTransformBlockSize < 0 || iLog2DiffMaxMinTransformBlockSize > 30) { RPT(RPT_ERR, "Invalid value %d for iLog2DiffMaxMinTransformBlockSize", iLog2DiffMaxMinTransformBlockSize); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->iMaxTransformHierarchyDepthInter = parseUe(pvBuf); ptSps->iMaxTransformHierarchyDepthIntra = parseUe(pvBuf); ptSps->u8ScalingListEnableFlag = getOneBit(pvBuf); - + if (ptSps->u8ScalingListEnableFlag) { setDefaultScalingListData(&ptSps->tScalingList); @@ -1854,7 +1854,7 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) ptSps->u8SaoEnabled = getOneBit(pvBuf); ptSps->iPcmEnabledFlag = getOneBit(pvBuf); - + if (ptSps->iPcmEnabledFlag) { ptSps->pcm.u8BitDepth = getBits(pvBuf, 4) + 1; ptSps->pcm.u8BitDepthChroma = getBits(pvBuf, 4) + 1; @@ -1865,8 +1865,8 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) RPT(RPT_ERR, "PCM bit depth (%d, %d) is greater than normal bit depth (%d)\n", ptSps->pcm.u8BitDepth, ptSps->pcm.u8BitDepthChroma, ptSps->iBitDepth); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } ptSps->pcm.u8LoopFilterDisableFlag = getOneBit(pvBuf); @@ -1876,8 +1876,8 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) if (ptSps->uiNbStRps > HEVC_MAX_SHORT_TERM_REF_PIC_SETS) { RPT(RPT_ERR, "Too many short term RPS: %d.\n", ptSps->uiNbStRps); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } for (i = 0; i < ptSps->uiNbStRps; i++) { if ((iRet = hevcDecodeShortTermRps(pvBuf, &ptSps->atStRps[i], @@ -1891,8 +1891,8 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) if (ptSps->u8NumLongTermRefPicsSps > HEVC_MAX_LONG_TERM_REF_PICS) { RPT(RPT_ERR, "Too many long term ref pics: %d.\n", ptSps->u8NumLongTermRefPicsSps); - iRet = -1; - goto exit; + iRet = -1; + goto exit; } for (i = 0; i < ptSps->u8NumLongTermRefPicsSps; i++) { ptSps->au16LtRefPicPocLsbSps[i] = getBits(pvBuf, ptSps->uiLog2MaxPocLsb); @@ -1962,14 +1962,14 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) if (ptSps->uiLog2CtbSize > HEVC_MAX_LOG2_CTB_SIZE) { RPT(RPT_ERR, "CTB size out of range: 2^%d\n", ptSps->uiLog2CtbSize); iRet = -1; - goto exit; + goto exit; } if (ptSps->uiLog2CtbSize < 4) { RPT(RPT_ERR, "uiLog2CtbSize %d differs from the bounds of any known profile\n", ptSps->uiLog2CtbSize); iRet = -1; - goto exit; + goto exit; } ptSps->iCtbWidth = (ptSps->iWidth + (1 << ptSps->uiLog2CtbSize) - 1) >> ptSps->uiLog2CtbSize; @@ -1990,201 +1990,201 @@ int h265DecSeqParameterSet( void *pvBufSrc, T_HEVCSPS *ptSps ) avModUintp2c(ptSps->iHeight, ptSps->uiLog2MinCbSize)) { RPT(RPT_ERR, "Invalid coded frame dimensions.\n"); iRet = -1; - goto exit; + goto exit; } if (ptSps->iMaxTransformHierarchyDepthInter > ptSps->uiLog2CtbSize - ptSps->uiLog2MinTbSize) { RPT(RPT_ERR, "iMaxTransformHierarchyDepthInter out of range: %d\n", ptSps->iMaxTransformHierarchyDepthInter); iRet = -1; - goto exit; + goto exit; } if (ptSps->iMaxTransformHierarchyDepthIntra > ptSps->uiLog2CtbSize - ptSps->uiLog2MinTbSize) { RPT(RPT_ERR, "iMaxTransformHierarchyDepthIntra out of range: %d\n", ptSps->iMaxTransformHierarchyDepthIntra); iRet = -1; - goto exit; + goto exit; } if (ptSps->uiLog2MaxTrafoSize > FFMIN(ptSps->uiLog2CtbSize, 5)) { RPT(RPT_ERR, "max transform block size out of range: %d\n", ptSps->uiLog2MaxTrafoSize); iRet = -1; - goto exit; + goto exit; } if (getBitsLeft(pvBuf) < 0) { RPT(RPT_ERR, "Overread SPS by %d bits\n", -getBitsLeft(pvBuf)); iRet = -1; - goto exit; + goto exit; } - + exit: - getBitContextFree(pvBuf); - return iRet; + getBitContextFree(pvBuf); + return iRet; } int h265DecVideoParameterSet( void *pvBufSrc, T_HEVCVPS *ptVps ) { - int iRet = 0; + int iRet = 0; int i,j; int uiVpsId = 0; - - void *pvBuf = NULL; - if(NULL == pvBufSrc || NULL == ptVps) - { - RPT(RPT_ERR,"ERR null pointer\n"); - iRet = -1; - goto exit; - } + + void *pvBuf = NULL; + if(NULL == pvBufSrc || NULL == ptVps) + { + RPT(RPT_ERR,"ERR null pointer\n"); + iRet = -1; + goto exit; + } - memset((void *)ptVps, 0, sizeof(T_HEVCVPS)); + memset((void *)ptVps, 0, sizeof(T_HEVCVPS)); - pvBuf = deEmulationPrevention(pvBufSrc); - if(NULL == pvBuf) - { - RPT(RPT_ERR,"ERR null pointer\n"); - iRet = -1; - goto exit; - } + pvBuf = deEmulationPrevention(pvBufSrc); + if(NULL == pvBuf) + { + RPT(RPT_ERR,"ERR null pointer\n"); + iRet = -1; + goto exit; + } - RPT(RPT_DBG, "Decoding VPS\n"); + RPT(RPT_DBG, "Decoding VPS\n"); - uiVpsId = getBits(pvBuf, 4); - if (uiVpsId >= HEVC_MAX_VPS_COUNT) { - RPT(RPT_ERR, "VPS id out of range: %d\n", uiVpsId); - iRet = -1; - goto exit; - } + uiVpsId = getBits(pvBuf, 4); + if (uiVpsId >= HEVC_MAX_VPS_COUNT) { + RPT(RPT_ERR, "VPS id out of range: %d\n", uiVpsId); + iRet = -1; + goto exit; + } - if (getBits(pvBuf, 2) != 3) { // vps_reserved_three_2bits - RPT(RPT_ERR, "vps_reserved_three_2bits is not three\n"); - iRet = -1; - goto exit; - } + if (getBits(pvBuf, 2) != 3) { // vps_reserved_three_2bits + RPT(RPT_ERR, "vps_reserved_three_2bits is not three\n"); + iRet = -1; + goto exit; + } - ptVps->iVpsMaxLayers = getBits(pvBuf, 6) + 1; - ptVps->iVpsMaxSubLayers = getBits(pvBuf, 3) + 1; - ptVps->u8VpsTemporalIdNestingFlag = getOneBit(pvBuf); + ptVps->iVpsMaxLayers = getBits(pvBuf, 6) + 1; + ptVps->iVpsMaxSubLayers = getBits(pvBuf, 3) + 1; + ptVps->u8VpsTemporalIdNestingFlag = getOneBit(pvBuf); - if (getBits(pvBuf, 16) != 0xffff) { // vps_reserved_ffff_16bits - RPT(RPT_ERR, "vps_reserved_ffff_16bits is not 0xffff\n"); - iRet = -1; - goto exit; - } + if (getBits(pvBuf, 16) != 0xffff) { // vps_reserved_ffff_16bits + RPT(RPT_ERR, "vps_reserved_ffff_16bits is not 0xffff\n"); + iRet = -1; + goto exit; + } - if (ptVps->iVpsMaxSubLayers > HEVC_MAX_SUB_LAYERS) { - RPT(RPT_ERR, "iVpsMaxSubLayers out of range: %d\n", - ptVps->iVpsMaxSubLayers); - iRet = -1; - goto exit; - } + if (ptVps->iVpsMaxSubLayers > HEVC_MAX_SUB_LAYERS) { + RPT(RPT_ERR, "iVpsMaxSubLayers out of range: %d\n", + ptVps->iVpsMaxSubLayers); + iRet = -1; + goto exit; + } - if (parsePtl(pvBuf, &ptVps->tPtl, ptVps->iVpsMaxSubLayers) < 0){ - iRet = -1; - goto exit; - } + if (parsePtl(pvBuf, &ptVps->tPtl, ptVps->iVpsMaxSubLayers) < 0){ + iRet = -1; + goto exit; + } - ptVps->iVpsSubLayerOrderingInfoPresentFlag = getOneBit(pvBuf); + ptVps->iVpsSubLayerOrderingInfoPresentFlag = getOneBit(pvBuf); - i = ptVps->iVpsSubLayerOrderingInfoPresentFlag ? 0 : ptVps->iVpsMaxSubLayers - 1; - for (; i < ptVps->iVpsMaxSubLayers; i++) { - ptVps->uiVpsMaxDecPicBuffering[i] = parseUe(pvBuf) + 1; - ptVps->auiVpsNumReorderPics[i] = parseUe(pvBuf); - ptVps->auiVpsMaxLatencyIncrease[i] = parseUe(pvBuf) - 1; + i = ptVps->iVpsSubLayerOrderingInfoPresentFlag ? 0 : ptVps->iVpsMaxSubLayers - 1; + for (; i < ptVps->iVpsMaxSubLayers; i++) { + ptVps->uiVpsMaxDecPicBuffering[i] = parseUe(pvBuf) + 1; + ptVps->auiVpsNumReorderPics[i] = parseUe(pvBuf); + ptVps->auiVpsMaxLatencyIncrease[i] = parseUe(pvBuf) - 1; - if (ptVps->uiVpsMaxDecPicBuffering[i] > HEVC_MAX_DPB_SIZE || !ptVps->uiVpsMaxDecPicBuffering[i]) { - RPT(RPT_ERR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n", - ptVps->uiVpsMaxDecPicBuffering[i] - 1); - iRet = -1; - goto exit; - } - if (ptVps->auiVpsNumReorderPics[i] > ptVps->uiVpsMaxDecPicBuffering[i] - 1) { - RPT(RPT_WRN, "vps_max_num_reorder_pics out of range: %d\n", - ptVps->auiVpsNumReorderPics[i]); - } - } + if (ptVps->uiVpsMaxDecPicBuffering[i] > HEVC_MAX_DPB_SIZE || !ptVps->uiVpsMaxDecPicBuffering[i]) { + RPT(RPT_ERR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n", + ptVps->uiVpsMaxDecPicBuffering[i] - 1); + iRet = -1; + goto exit; + } + if (ptVps->auiVpsNumReorderPics[i] > ptVps->uiVpsMaxDecPicBuffering[i] - 1) { + RPT(RPT_WRN, "vps_max_num_reorder_pics out of range: %d\n", + ptVps->auiVpsNumReorderPics[i]); + } + } - ptVps->iVpsMaxLayerId = getBits(pvBuf, 6); - ptVps->iVpsNumLayerSets = parseUe(pvBuf) + 1; - if (ptVps->iVpsNumLayerSets < 1 || ptVps->iVpsNumLayerSets > 1024 || - (ptVps->iVpsNumLayerSets - 1LL) * (ptVps->iVpsMaxLayerId + 1LL) > getBitsLeft(pvBuf)) { - RPT(RPT_ERR, "too many layer_id_included_flags\n"); - iRet = -1; - goto exit; - } + ptVps->iVpsMaxLayerId = getBits(pvBuf, 6); + ptVps->iVpsNumLayerSets = parseUe(pvBuf) + 1; + if (ptVps->iVpsNumLayerSets < 1 || ptVps->iVpsNumLayerSets > 1024 || + (ptVps->iVpsNumLayerSets - 1LL) * (ptVps->iVpsMaxLayerId + 1LL) > getBitsLeft(pvBuf)) { + RPT(RPT_ERR, "too many layer_id_included_flags\n"); + iRet = -1; + goto exit; + } - for (i = 1; i < ptVps->iVpsNumLayerSets; i++) - for (j = 0; j <= ptVps->iVpsMaxLayerId; j++) - getBits(pvBuf, 1); // layer_id_included_flag[i][j] + for (i = 1; i < ptVps->iVpsNumLayerSets; i++) + for (j = 0; j <= ptVps->iVpsMaxLayerId; j++) + getBits(pvBuf, 1); // layer_id_included_flag[i][j] - ptVps->u8VpsTimingInfoPresentFlag = getOneBit(pvBuf); - if (ptVps->u8VpsTimingInfoPresentFlag) { - ptVps->u32VpsNumUnitsInTick = getBits(pvBuf, 32); - ptVps->u32VpsTimeScale = getBits(pvBuf, 32); - ptVps->u8VpsPocProportionalToTimingFlag = getOneBit(pvBuf); - if (ptVps->u8VpsPocProportionalToTimingFlag) - ptVps->iVpsNumTicksPocDiffOne = parseUe(pvBuf) + 1; - ptVps->iVpsNumHrdParameters = parseUe(pvBuf); - if (ptVps->iVpsNumHrdParameters > (unsigned)ptVps->iVpsNumLayerSets) { - RPT(RPT_ERR, - "iVpsNumHrdParameters %d is invalid\n", ptVps->iVpsNumHrdParameters); - iRet = -1; - goto exit; - } - for (i = 0; i < ptVps->iVpsNumHrdParameters; i++) { - int common_inf_present = 1; + ptVps->u8VpsTimingInfoPresentFlag = getOneBit(pvBuf); + if (ptVps->u8VpsTimingInfoPresentFlag) { + ptVps->u32VpsNumUnitsInTick = getBits(pvBuf, 32); + ptVps->u32VpsTimeScale = getBits(pvBuf, 32); + ptVps->u8VpsPocProportionalToTimingFlag = getOneBit(pvBuf); + if (ptVps->u8VpsPocProportionalToTimingFlag) + ptVps->iVpsNumTicksPocDiffOne = parseUe(pvBuf) + 1; + ptVps->iVpsNumHrdParameters = parseUe(pvBuf); + if (ptVps->iVpsNumHrdParameters > (unsigned)ptVps->iVpsNumLayerSets) { + RPT(RPT_ERR, + "iVpsNumHrdParameters %d is invalid\n", ptVps->iVpsNumHrdParameters); + iRet = -1; + goto exit; + } + for (i = 0; i < ptVps->iVpsNumHrdParameters; i++) { + int common_inf_present = 1; - parseUe(pvBuf); // hrd_layer_set_idx - if (i) - common_inf_present = getOneBit(pvBuf); - decodeHrd(pvBuf, common_inf_present, ptVps->iVpsMaxSubLayers); - } - } - getOneBit(pvBuf); /* vps_extension_flag */ + parseUe(pvBuf); // hrd_layer_set_idx + if (i) + common_inf_present = getOneBit(pvBuf); + decodeHrd(pvBuf, common_inf_present, ptVps->iVpsMaxSubLayers); + } + } + getOneBit(pvBuf); /* vps_extension_flag */ - if (getBitsLeft(pvBuf) < 0) { - RPT(RPT_ERR, - "Overread VPS by %d bits\n", -getBitsLeft(pvBuf)); - - iRet = -1; - goto exit; - } + if (getBitsLeft(pvBuf) < 0) { + RPT(RPT_ERR, + "Overread VPS by %d bits\n", -getBitsLeft(pvBuf)); + + iRet = -1; + goto exit; + } exit: - getBitContextFree(pvBuf); - return iRet; + getBitContextFree(pvBuf); + return iRet; } - + void h264GetWidthHeight(T_SPS *ptSps, int *piWidth, int *piHeight) { - // ¿í¸ß¼ÆË㹫ʽ - int iCodeWidth = 0; - int iCodedHeight = 0; - iCodeWidth = 16 * ptSps->iMbWidth; - iCodedHeight = 16 * ptSps->iMbHeight; - *piWidth = iCodeWidth - (ptSps->uiCropRight + ptSps->uiCropLeft); - *piHeight = iCodedHeight - (ptSps->uiCropTop + ptSps->uiCropBottom); - if (*piWidth <= 0 || *piHeight <= 0) { - *piWidth = iCodeWidth; - *piHeight = iCodedHeight; - } + // ¿í¸ß¼ÆË㹫ʽ + int iCodeWidth = 0; + int iCodedHeight = 0; + iCodeWidth = 16 * ptSps->iMbWidth; + iCodedHeight = 16 * ptSps->iMbHeight; + *piWidth = iCodeWidth - (ptSps->uiCropRight + ptSps->uiCropLeft); + *piHeight = iCodedHeight - (ptSps->uiCropTop + ptSps->uiCropBottom); + if (*piWidth <= 0 || *piHeight <= 0) { + *piWidth = iCodeWidth; + *piHeight = iCodedHeight; + } - RPT(RPT_DBG, "iCodeWidth:%d, iCodedHeight:%d\n", iCodeWidth, iCodedHeight); + RPT(RPT_DBG, "iCodeWidth:%d, iCodedHeight:%d\n", iCodeWidth, iCodedHeight); - RPT(RPT_DBG, "*piWidth:%d, *piHeight:%d\n", *piWidth, *piHeight); + RPT(RPT_DBG, "*piWidth:%d, *piHeight:%d\n", *piWidth, *piHeight); - RPT(RPT_DBG, "ptSps->uiCropRight:%d, ptSps->uiCropLeft:%d\n", ptSps->uiCropRight, ptSps->uiCropLeft); + RPT(RPT_DBG, "ptSps->uiCropRight:%d, ptSps->uiCropLeft:%d\n", ptSps->uiCropRight, ptSps->uiCropLeft); - RPT(RPT_DBG, "ptSps->uiCropTop:%d, ptSps->uiCropBottom:%d\n", ptSps->uiCropTop, ptSps->uiCropBottom); + RPT(RPT_DBG, "ptSps->uiCropTop:%d, ptSps->uiCropBottom:%d\n", ptSps->uiCropTop, ptSps->uiCropBottom); } @@ -2213,43 +2213,43 @@ void h264GeFramerate(T_SPS *ptSps, float *pfFramerate) switch(iFrInt) { case 23:// 23.98 - RPT(RPT_DBG, "frame rate:23.98"); + RPT(RPT_DBG, "frame rate:23.98"); break; case 24: - RPT(RPT_DBG, "frame rate:24"); + RPT(RPT_DBG, "frame rate:24"); break; case 25: - RPT(RPT_DBG, "frame rate:25"); + RPT(RPT_DBG, "frame rate:25"); break; case 29://29.97 - RPT(RPT_DBG, "frame rate:29.97"); + RPT(RPT_DBG, "frame rate:29.97"); break; case 30: - RPT(RPT_DBG, "frame rate:30"); + RPT(RPT_DBG, "frame rate:30"); break; case 50: - RPT(RPT_DBG, "frame rate:50"); + RPT(RPT_DBG, "frame rate:50"); break; case 59://59.94 - RPT(RPT_DBG, "frame rate:59.94"); + RPT(RPT_DBG, "frame rate:59.94"); break; case 60: - RPT(RPT_DBG, "frame rate:60"); + RPT(RPT_DBG, "frame rate:60"); break; case 6: - RPT(RPT_DBG, "frame rate:6"); + RPT(RPT_DBG, "frame rate:6"); break; case 8: - RPT(RPT_DBG, "frame rate:8"); + RPT(RPT_DBG, "frame rate:8"); break; case 12: - RPT(RPT_DBG, "frame rate:12"); + RPT(RPT_DBG, "frame rate:12"); break; case 15: - RPT(RPT_DBG, "frame rate:15"); + RPT(RPT_DBG, "frame rate:15"); break; case 10: - RPT(RPT_DBG, "frame rate:10"); + RPT(RPT_DBG, "frame rate:10"); break; default: @@ -2266,21 +2266,21 @@ void h264GeFramerate(T_SPS *ptSps, float *pfFramerate) void h265GetWidthHeight(T_HEVCSPS *ptSps, int *piWidth, int *piHeight) { #if 1 - int iCodeWidth = 0; - int iCodedHeight = 0; - iCodeWidth = ptSps->iWidth; - iCodedHeight = ptSps->iHeight; - *piWidth = ptSps->iWidth - ptSps->tOutputWindow.uiLeftOffset - ptSps->tOutputWindow.uiRightOffset; - *piHeight = ptSps->iHeight - ptSps->tOutputWindow.uiTopOffset - ptSps->tOutputWindow.uiBottomOffset; + int iCodeWidth = 0; + int iCodedHeight = 0; + iCodeWidth = ptSps->iWidth; + iCodedHeight = ptSps->iHeight; + *piWidth = ptSps->iWidth - ptSps->tOutputWindow.uiLeftOffset - ptSps->tOutputWindow.uiRightOffset; + *piHeight = ptSps->iHeight - ptSps->tOutputWindow.uiTopOffset - ptSps->tOutputWindow.uiBottomOffset; - RPT(RPT_DBG, "iCodeWidth:%d, iCodedHeight:%d\n", iCodeWidth, iCodedHeight); + RPT(RPT_DBG, "iCodeWidth:%d, iCodedHeight:%d\n", iCodeWidth, iCodedHeight); - RPT(RPT_DBG, "*piWidth:%d, *piHeight:%d\n", *piWidth, *piHeight); + RPT(RPT_DBG, "*piWidth:%d, *piHeight:%d\n", *piWidth, *piHeight); - RPT(RPT_DBG, "ptSps->tOutputWindow.uiRightOffset:%d, ptSps->tOutputWindow.uiLeftOffset:%d\n", ptSps->tOutputWindow.uiRightOffset, ptSps->tOutputWindow.uiLeftOffset); + RPT(RPT_DBG, "ptSps->tOutputWindow.uiRightOffset:%d, ptSps->tOutputWindow.uiLeftOffset:%d\n", ptSps->tOutputWindow.uiRightOffset, ptSps->tOutputWindow.uiLeftOffset); - RPT(RPT_DBG, "ptSps->tOutputWindow.uiTopOffset:%d, ptSps->tOutputWindow.uiBottomOffset:%d\n", ptSps->tOutputWindow.uiTopOffset, ptSps->tOutputWindow.uiBottomOffset); + RPT(RPT_DBG, "ptSps->tOutputWindow.uiTopOffset:%d, ptSps->tOutputWindow.uiBottomOffset:%d\n", ptSps->tOutputWindow.uiTopOffset, ptSps->tOutputWindow.uiBottomOffset); #endif } @@ -2290,15 +2290,15 @@ void h265GetWidthHeight(T_HEVCSPS *ptSps, int *piWidth, int *piHeight) void h265GeFramerate(T_HEVCVPS *ptVps, T_HEVCSPS *ptSps,float *pfFramerate) { if (ptVps && ptVps->u8VpsTimingInfoPresentFlag) { - *pfFramerate = (float)(ptVps->u32VpsTimeScale) / (float)(ptVps->u32VpsNumUnitsInTick); - + *pfFramerate = (float)(ptVps->u32VpsTimeScale) / (float)(ptVps->u32VpsNumUnitsInTick); + } else if (ptSps && ptSps->tVui.iVuiTimingInfoPresentFlag && ptSps->iVuiPresent) { - *pfFramerate = (float)(ptSps->tVui.u32VuiTimeScale) / (float)(ptSps->tVui.u32VuiNumUnitsInTick); + *pfFramerate = (float)(ptSps->tVui.u32VuiTimeScale) / (float)(ptSps->tVui.u32VuiNumUnitsInTick); + } + else{ + //vps sps可能不包含帧率 + *pfFramerate = 0.0F; + RPT(RPT_WRN, "frame rate:0"); } - else{ - //vps sps可能不包含帧率 - *pfFramerate = 0.0F; - RPT(RPT_WRN, "frame rate:0"); - } } diff --git a/src/Extension/SPSParser.h b/src/Extension/SPSParser.h index 1fb97adc..6cdb6005 100644 --- a/src/Extension/SPSParser.h +++ b/src/Extension/SPSParser.h @@ -434,7 +434,7 @@ typedef struct T_HEVCSPS { int iQpBdOffset; - int iVuiPresent; + int iVuiPresent; }T_HEVCSPS; diff --git a/src/Extension/Track.h b/src/Extension/Track.h index ccd675e9..29b679e8 100644 --- a/src/Extension/Track.h +++ b/src/Extension/Track.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_TRACK_H @@ -137,10 +121,10 @@ public: virtual ~TrackSource(){} /** - * 获取全部的Track - * @param trackReady 是否获取全部已经准备好的Track - * @return - */ + * 获取全部的Track + * @param trackReady 是否获取全部已经准备好的Track + * @return + */ virtual vector getTracks(bool trackReady = true) const = 0; /** diff --git a/src/Http/HttpBody.cpp b/src/Http/HttpBody.cpp index 9e6a0592..fb06e19b 100644 --- a/src/Http/HttpBody.cpp +++ b/src/Http/HttpBody.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "HttpBody.h" diff --git a/src/Http/HttpBody.h b/src/Http/HttpBody.h index c82163a4..9c3064da 100644 --- a/src/Http/HttpBody.h +++ b/src/Http/HttpBody.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_FILEREADER_H diff --git a/src/Http/HttpChunkedSplitter.cpp b/src/Http/HttpChunkedSplitter.cpp index 7521982a..e99c4f98 100644 --- a/src/Http/HttpChunkedSplitter.cpp +++ b/src/Http/HttpChunkedSplitter.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/src/Http/HttpChunkedSplitter.h b/src/Http/HttpChunkedSplitter.h index 0d609e98..5368c4da 100644 --- a/src/Http/HttpChunkedSplitter.h +++ b/src/Http/HttpChunkedSplitter.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef ZLMEDIAKIT_HTTPCHUNKEDSPLITTER_H #define ZLMEDIAKIT_HTTPCHUNKEDSPLITTER_H diff --git a/src/Http/HttpClient.cpp b/src/Http/HttpClient.cpp index c7483b33..6238afde 100644 --- a/src/Http/HttpClient.cpp +++ b/src/Http/HttpClient.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include #include "HttpClient.h" @@ -71,7 +55,7 @@ void HttpClient::sendRequest(const string &strUrl, float fTimeOutSec) { host = FindField(host.data(), NULL, ":"); } _header.emplace("Host", host); - _header.emplace("Tools", "ZLMediaKit"); + _header.emplace("Tools", SERVER_NAME); _header.emplace("Connection", "keep-alive"); _header.emplace("Accept", "*/*"); _header.emplace("Accept-Language", "zh-CN,zh;q=0.8"); diff --git a/src/Http/HttpClient.h b/src/Http/HttpClient.h index 59ab4629..e1f80b47 100644 --- a/src/Http/HttpClient.h +++ b/src/Http/HttpClient.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef Http_HttpClient_h @@ -148,7 +132,7 @@ protected: * 接收http回复完毕, */ virtual void onResponseCompleted(){ - DebugL; + DebugL; } /** diff --git a/src/Http/HttpClientImp.cpp b/src/Http/HttpClientImp.cpp index c6dff3ed..4f87708b 100644 --- a/src/Http/HttpClientImp.cpp +++ b/src/Http/HttpClientImp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Http/HttpClientImp.h" @@ -29,11 +13,11 @@ namespace mediakit { void HttpClientImp::onConnect(const SockException &ex) { - if(!_isHttps){ - HttpClient::onConnect(ex); - } else { - TcpClientWithSSL::onConnect(ex); - } + if(!_isHttps){ + HttpClient::onConnect(ex); + } else { + TcpClientWithSSL::onConnect(ex); + } } diff --git a/src/Http/HttpClientImp.h b/src/Http/HttpClientImp.h index 277d85b5..392770c3 100644 --- a/src/Http/HttpClientImp.h +++ b/src/Http/HttpClientImp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_HTTP_HTTPCLIENTIMP_H_ @@ -36,11 +20,11 @@ namespace mediakit { class HttpClientImp: public TcpClientWithSSL { public: - typedef std::shared_ptr Ptr; - HttpClientImp() {} - virtual ~HttpClientImp() {} + typedef std::shared_ptr Ptr; + HttpClientImp() {} + virtual ~HttpClientImp() {} protected: - void onConnect(const SockException &ex) override ; + void onConnect(const SockException &ex) override ; }; } /* namespace mediakit */ diff --git a/src/Http/HttpCookie.cpp b/src/Http/HttpCookie.cpp index b68342df..260708ae 100644 --- a/src/Http/HttpCookie.cpp +++ b/src/Http/HttpCookie.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "HttpCookie.h" diff --git a/src/Http/HttpCookie.h b/src/Http/HttpCookie.h index 8abdc053..b9ab99b5 100644 --- a/src/Http/HttpCookie.h +++ b/src/Http/HttpCookie.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_HTTPCOOKIE_H diff --git a/src/Http/HttpCookieManager.cpp b/src/Http/HttpCookieManager.cpp index 0c210dab..ef4bbc01 100644 --- a/src/Http/HttpCookieManager.cpp +++ b/src/Http/HttpCookieManager.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Util/util.h" diff --git a/src/Http/HttpCookieManager.h b/src/Http/HttpCookieManager.h index 73f7afae..74792e55 100644 --- a/src/Http/HttpCookieManager.h +++ b/src/Http/HttpCookieManager.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_HTTP_COOKIEMANAGER_H diff --git a/src/Http/HttpDownloader.cpp b/src/Http/HttpDownloader.cpp index aac62e0b..f5148db4 100644 --- a/src/Http/HttpDownloader.cpp +++ b/src/Http/HttpDownloader.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "HttpDownloader.h" @@ -36,75 +20,75 @@ HttpDownloader::HttpDownloader() { } HttpDownloader::~HttpDownloader() { - closeFile(); + closeFile(); } void HttpDownloader::startDownload(const string& url, const string& filePath,bool bAppend,float timeOutSecond) { - _filePath = filePath; - if(_filePath.empty()){ - _filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest(); - } - _saveFile = File::createfile_file(_filePath.data(),bAppend ? "ab" : "wb"); - if(!_saveFile){ - auto strErr = StrPrinter << "打开文件失败:" << filePath << endl; - throw std::runtime_error(strErr); - } - _bDownloadSuccess = false; - if(bAppend){ - auto currentLen = ftell(_saveFile); - if(currentLen){ - //最少续传一个字节,怕遇到http 416的错误 - currentLen -= 1; - fseek(_saveFile,-1,SEEK_CUR); - } - addHeader("Range", StrPrinter << "bytes=" << currentLen << "-" << endl); - } - setMethod("GET"); - sendRequest(url,timeOutSecond); + _filePath = filePath; + if(_filePath.empty()){ + _filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest(); + } + _saveFile = File::createfile_file(_filePath.data(),bAppend ? "ab" : "wb"); + if(!_saveFile){ + auto strErr = StrPrinter << "打开文件失败:" << filePath << endl; + throw std::runtime_error(strErr); + } + _bDownloadSuccess = false; + if(bAppend){ + auto currentLen = ftell(_saveFile); + if(currentLen){ + //最少续传一个字节,怕遇到http 416的错误 + currentLen -= 1; + fseek(_saveFile,-1,SEEK_CUR); + } + addHeader("Range", StrPrinter << "bytes=" << currentLen << "-" << endl); + } + setMethod("GET"); + sendRequest(url,timeOutSecond); } int64_t HttpDownloader::onResponseHeader(const string& status,const HttpHeader& headers) { if(status != "200" && status != "206"){ - //失败 - shutdown(SockException(Err_shutdown,StrPrinter << "Http Status:" << status)); - } - //后续全部是content - return -1; + //失败 + shutdown(SockException(Err_shutdown,StrPrinter << "Http Status:" << status)); + } + //后续全部是content + return -1; } void HttpDownloader::onResponseBody(const char* buf, int64_t size, int64_t recvedSize, int64_t totalSize) { if(_saveFile){ - fwrite(buf,size,1,_saveFile); - } + fwrite(buf,size,1,_saveFile); + } } void HttpDownloader::onResponseCompleted() { - closeFile(); - //InfoL << "md5Sum:" << getMd5Sum(_filePath); - _bDownloadSuccess = true; - if(_onResult){ - _onResult(Err_success,"success",_filePath); - _onResult = nullptr; - } + closeFile(); + //InfoL << "md5Sum:" << getMd5Sum(_filePath); + _bDownloadSuccess = true; + if(_onResult){ + _onResult(Err_success,"success",_filePath); + _onResult = nullptr; + } } void HttpDownloader::onDisconnect(const SockException &ex) { - closeFile(); - if(!_bDownloadSuccess){ - File::delete_file(_filePath.data()); - } - if(_onResult){ - _onResult(ex.getErrCode(),ex.what(),_filePath); - _onResult = nullptr; - } + closeFile(); + if(!_bDownloadSuccess){ + File::delete_file(_filePath.data()); + } + if(_onResult){ + _onResult(ex.getErrCode(),ex.what(),_filePath); + _onResult = nullptr; + } } void HttpDownloader::closeFile() { - if(_saveFile){ - fflush(_saveFile); - fclose(_saveFile); - _saveFile = nullptr; - } + if(_saveFile){ + fflush(_saveFile); + fclose(_saveFile); + _saveFile = nullptr; + } } diff --git a/src/Http/HttpDownloader.h b/src/Http/HttpDownloader.h index d8d147ce..77ecb384 100644 --- a/src/Http/HttpDownloader.h +++ b/src/Http/HttpDownloader.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_HTTP_HTTPDOWNLOADER_H_ @@ -33,30 +17,30 @@ namespace mediakit { class HttpDownloader: public HttpClientImp { public: - typedef std::shared_ptr Ptr; - typedef std::function onDownloadResult; - HttpDownloader(); - virtual ~HttpDownloader(); - //开始下载文件,默认断点续传方式下载 - void startDownload(const string &url,const string &filePath = "",bool bAppend = false, float timeOutSecond = 10 ); - void startDownload(const string &url,const onDownloadResult &cb,float timeOutSecond = 10){ - setOnResult(cb); - startDownload(url,"",false,timeOutSecond); - } - void setOnResult(const onDownloadResult &cb){ - _onResult = cb; - } + typedef std::shared_ptr Ptr; + typedef std::function onDownloadResult; + HttpDownloader(); + virtual ~HttpDownloader(); + //开始下载文件,默认断点续传方式下载 + void startDownload(const string &url,const string &filePath = "",bool bAppend = false, float timeOutSecond = 10 ); + void startDownload(const string &url,const onDownloadResult &cb,float timeOutSecond = 10){ + setOnResult(cb); + startDownload(url,"",false,timeOutSecond); + } + void setOnResult(const onDownloadResult &cb){ + _onResult = cb; + } private: - int64_t onResponseHeader(const string &status,const HttpHeader &headers) override; - void onResponseBody(const char *buf,int64_t size,int64_t recvedSize,int64_t totalSize) override; - void onResponseCompleted() override; - void onDisconnect(const SockException &ex) override; + int64_t onResponseHeader(const string &status,const HttpHeader &headers) override; + void onResponseBody(const char *buf,int64_t size,int64_t recvedSize,int64_t totalSize) override; + void onResponseCompleted() override; + void onDisconnect(const SockException &ex) override; void closeFile(); private: - FILE *_saveFile = nullptr; - string _filePath; - onDownloadResult _onResult; - bool _bDownloadSuccess = false; + FILE *_saveFile = nullptr; + string _filePath; + onDownloadResult _onResult; + bool _bDownloadSuccess = false; }; } /* namespace mediakit */ diff --git a/src/Http/HttpFileManager.cpp b/src/Http/HttpFileManager.cpp index 81cf9a8a..90a37992 100644 --- a/src/Http/HttpFileManager.cpp +++ b/src/Http/HttpFileManager.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/src/Http/HttpFileManager.h b/src/Http/HttpFileManager.h index dc3a613e..9832cf81 100644 --- a/src/Http/HttpFileManager.h +++ b/src/Http/HttpFileManager.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_HTTPFILEMANAGER_H diff --git a/src/Http/HttpRequestSplitter.cpp b/src/Http/HttpRequestSplitter.cpp index fe9779d0..44a2f040 100644 --- a/src/Http/HttpRequestSplitter.cpp +++ b/src/Http/HttpRequestSplitter.cpp @@ -1,30 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #include "HttpRequestSplitter.h" #include "Util/logger.h" #include "Util/util.h" diff --git a/src/Http/HttpRequestSplitter.h b/src/Http/HttpRequestSplitter.h index 8241ecf4..4359e130 100644 --- a/src/Http/HttpRequestSplitter.h +++ b/src/Http/HttpRequestSplitter.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_HTTPREQUESTSPLITTER_H diff --git a/src/Http/HttpRequester.cpp b/src/Http/HttpRequester.cpp index aa9c962e..64233622 100644 --- a/src/Http/HttpRequester.cpp +++ b/src/Http/HttpRequester.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "HttpRequester.h" namespace mediakit{ diff --git a/src/Http/HttpRequester.h b/src/Http/HttpRequester.h index 9de7523a..693fdf4d 100644 --- a/src/Http/HttpRequester.h +++ b/src/Http/HttpRequester.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef Htt_HttpRequester_h diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index a1bae44f..0ce9591c 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #if !defined(_WIN32) #include #endif //!defined(_WIN32) @@ -45,8 +30,8 @@ HttpSession::HttpSession(const Socket::Ptr &pSock) : TcpSession(pSock) { TraceP(this); GET_CONFIG(uint32_t,keep_alive_sec,Http::kKeepAliveSecond); pSock->setSendTimeOutSecond(keep_alive_sec); - //起始接收buffer缓存设置为4K,节省内存 - pSock->setReadBuffer(std::make_shared(4 * 1024)); + //起始接收buffer缓存设置为4K,节省内存 + pSock->setReadBuffer(std::make_shared(4 * 1024)); } HttpSession::~HttpSession() { @@ -61,48 +46,48 @@ void HttpSession::Handle_Req_HEAD(int64_t &content_len){ } int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) { - typedef void (HttpSession::*HttpCMDHandle)(int64_t &); - static unordered_map s_func_map; - static onceToken token([]() { - s_func_map.emplace("GET",&HttpSession::Handle_Req_GET); - s_func_map.emplace("POST",&HttpSession::Handle_Req_POST); + typedef void (HttpSession::*HttpCMDHandle)(int64_t &); + static unordered_map s_func_map; + static onceToken token([]() { + s_func_map.emplace("GET",&HttpSession::Handle_Req_GET); + s_func_map.emplace("POST",&HttpSession::Handle_Req_POST); s_func_map.emplace("HEAD",&HttpSession::Handle_Req_HEAD); }, nullptr); - _parser.Parse(header); - urlDecode(_parser); - string cmd = _parser.Method(); - auto it = s_func_map.find(cmd); - if (it == s_func_map.end()) { - WarnL << "不支持该命令:" << cmd; - sendResponse("405 Not Allowed", true); + _parser.Parse(header); + urlDecode(_parser); + string cmd = _parser.Method(); + auto it = s_func_map.find(cmd); + if (it == s_func_map.end()) { + WarnL << "不支持该命令:" << cmd; + sendResponse("405 Not Allowed", true); return 0; - } + } //跨域 _origin = _parser["Origin"]; //默认后面数据不是content而是header - int64_t content_len = 0; - auto &fun = it->second; + int64_t content_len = 0; + auto &fun = it->second; try { (this->*fun)(content_len); }catch (exception &ex){ shutdown(SockException(Err_shutdown,ex.what())); } - //清空解析器节省内存 - _parser.Clear(); - //返回content长度 - return content_len; + //清空解析器节省内存 + _parser.Clear(); + //返回content长度 + return content_len; } void HttpSession::onRecvContent(const char *data,uint64_t len) { - if(_contentCallBack){ - if(!_contentCallBack(data,len)){ - _contentCallBack = nullptr; - } - } + if(_contentCallBack){ + if(!_contentCallBack(data,len)){ + _contentCallBack = nullptr; + } + } } void HttpSession::onRecv(const Buffer::Ptr &pBuf) { @@ -140,25 +125,25 @@ void HttpSession::onManager() { GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond); if(_ticker.elapsedTime() > keepAliveSec * 1000){ - //1分钟超时 - shutdown(SockException(Err_timeout,"session timeouted")); - } + //1分钟超时 + shutdown(SockException(Err_timeout,"session timeouted")); + } } bool HttpSession::checkWebSocket(){ - auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"]; - if(Sec_WebSocket_Key.empty()){ - return false; - } - auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); + auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"]; + if(Sec_WebSocket_Key.empty()){ + return false; + } + auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); - KeyValue headerOut; - headerOut["Upgrade"] = "websocket"; - headerOut["Connection"] = "Upgrade"; - headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept; - if(!_parser["Sec-WebSocket-Protocol"].empty()){ - headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"]; - } + KeyValue headerOut; + headerOut["Upgrade"] = "websocket"; + headerOut["Connection"] = "Upgrade"; + headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept; + if(!_parser["Sec-WebSocket-Protocol"].empty()){ + headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"]; + } auto res_cb = [this,headerOut](){ _flv_over_websocket = true; @@ -177,28 +162,28 @@ bool HttpSession::checkWebSocket(){ return true; } sendResponse("101 Switching Protocols",false, nullptr,headerOut); - return true; + return true; } //http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2 //如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。 bool HttpSession::checkLiveFlvStream(const function &cb){ - auto pos = strrchr(_parser.Url().data(),'.'); - if(!pos){ - //未找到".flv"后缀 - return false; - } - if(strcasecmp(pos,".flv") != 0){ - //未找到".flv"后缀 - return false; - } - - //这是个.flv的流 - _mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl()); - if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){ - //url不合法 + auto pos = strrchr(_parser.Url().data(),'.'); + if(!pos){ + //未找到".flv"后缀 return false; - } + } + if(strcasecmp(pos,".flv") != 0){ + //未找到".flv"后缀 + return false; + } + + //这是个.flv的流 + _mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl()); + if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){ + //url不合法 + return false; + } _mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀 bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); @@ -270,21 +255,21 @@ void HttpSession::Handle_Req_GET(int64_t &content_len) { } void HttpSession::Handle_Req_GET_l(int64_t &content_len, bool sendBody) { - //先看看是否为WebSocket请求 - if(checkWebSocket()){ - content_len = -1; - _contentCallBack = [this](const char *data,uint64_t len){ + //先看看是否为WebSocket请求 + if(checkWebSocket()){ + content_len = -1; + _contentCallBack = [this](const char *data,uint64_t len){ WebSocketSplitter::decode((uint8_t *)data,len); - //_contentCallBack是可持续的,后面还要处理后续数据 - return true; - }; - return; - } + //_contentCallBack是可持续的,后面还要处理后续数据 + return true; + }; + return; + } - if(emitHttpEvent(false)){ + if(emitHttpEvent(false)){ //拦截http api事件 - return; - } + return; + } if(checkLiveFlvStream()){ //拦截http-flv播放器 @@ -398,7 +383,6 @@ static const string kContentType = "Content-Type"; static const string kContentLength = "Content-Length"; static const string kAccessControlAllowOrigin = "Access-Control-Allow-Origin"; static const string kAccessControlAllowCredentials = "Access-Control-Allow-Credentials"; -static const string kServerName = SERVER_NAME; void HttpSession::sendResponse(const char *pcStatus, bool bClose, @@ -426,7 +410,7 @@ void HttpSession::sendResponse(const char *pcStatus, HttpSession::KeyValue &headerOut = const_cast(header); headerOut.emplace(kDate, dateStr()); - headerOut.emplace(kServer, kServerName); + headerOut.emplace(kServer, SERVER_NAME); headerOut.emplace(kConnection, bClose ? "close" : "keep-alive"); if(!bClose){ string keepAliveString = "timeout="; @@ -498,111 +482,111 @@ void HttpSession::sendResponse(const char *pcStatus, } string HttpSession::urlDecode(const string &str){ - auto ret = strCoding::UrlDecode(str); + auto ret = strCoding::UrlDecode(str); #ifdef _WIN32 GET_CONFIG(string,charSet,Http::kCharSet); - bool isGb2312 = !strcasecmp(charSet.data(), "gb2312"); - if (isGb2312) { - ret = strCoding::UTF8ToGB2312(ret); - } + bool isGb2312 = !strcasecmp(charSet.data(), "gb2312"); + if (isGb2312) { + ret = strCoding::UTF8ToGB2312(ret); + } #endif // _WIN32 return ret; } void HttpSession::urlDecode(Parser &parser){ - parser.setUrl(urlDecode(parser.Url())); - for(auto &pr : _parser.getUrlArgs()){ - const_cast(pr.second) = urlDecode(pr.second); - } + parser.setUrl(urlDecode(parser.Url())); + for(auto &pr : _parser.getUrlArgs()){ + const_cast(pr.second) = urlDecode(pr.second); + } } bool HttpSession::emitHttpEvent(bool doInvoke){ bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); - /////////////////////异步回复Invoker/////////////////////////////// - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){ - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { + /////////////////////异步回复Invoker/////////////////////////////// + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){ + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { //本对象已经销毁 - return; - } + return; + } strongSelf->sendResponse(codeOut.data(), bClose, nullptr, headerOut, body); - }); - }; - ///////////////////广播HTTP事件/////////////////////////// - bool consumed = false;//该事件是否被消费 - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this); - if(!consumed && doInvoke){ - //该事件无人消费,所以返回404 - invoker("404 Not Found",KeyValue(), HttpBody::Ptr()); - } - return consumed; + }); + }; + ///////////////////广播HTTP事件/////////////////////////// + bool consumed = false;//该事件是否被消费 + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this); + if(!consumed && doInvoke){ + //该事件无人消费,所以返回404 + invoker("404 Not Found",KeyValue(), HttpBody::Ptr()); + } + return consumed; } void HttpSession::Handle_Req_POST(int64_t &content_len) { - GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize); + GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize); int64_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data()); - if(totalContentLen == 0){ - //content为空 - //emitHttpEvent内部会选择是否关闭连接 - emitHttpEvent(true); - return; - } + if(totalContentLen == 0){ + //content为空 + //emitHttpEvent内部会选择是否关闭连接 + emitHttpEvent(true); + return; + } //根据Content-Length设置接收缓存大小 if(totalContentLen > 0){ _sock->setReadBuffer(std::make_shared(MIN(totalContentLen + 1,256 * 1024))); }else{ - //不定长度的Content-Length + //不定长度的Content-Length _sock->setReadBuffer(std::make_shared(256 * 1024)); - } + } if(totalContentLen > 0 && totalContentLen < maxReqSize ){ - //返回固定长度的content - content_len = totalContentLen; - auto parserCopy = _parser; - _contentCallBack = [this,parserCopy](const char *data,uint64_t len){ - //恢复http头 - _parser = parserCopy; - //设置content - _parser.setContent(string(data,len)); - //触发http事件,emitHttpEvent内部会选择是否关闭连接 - emitHttpEvent(true); - //清空数据,节省内存 - _parser.Clear(); - //content已经接收完毕 - return false; - }; - }else{ - //返回不固定长度的content - content_len = -1; - auto parserCopy = _parser; - std::shared_ptr recvedContentLen = std::make_shared(0); - bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); + //返回固定长度的content + content_len = totalContentLen; + auto parserCopy = _parser; + _contentCallBack = [this,parserCopy](const char *data,uint64_t len){ + //恢复http头 + _parser = parserCopy; + //设置content + _parser.setContent(string(data,len)); + //触发http事件,emitHttpEvent内部会选择是否关闭连接 + emitHttpEvent(true); + //清空数据,节省内存 + _parser.Clear(); + //content已经接收完毕 + return false; + }; + }else{ + //返回不固定长度的content + content_len = -1; + auto parserCopy = _parser; + std::shared_ptr recvedContentLen = std::make_shared(0); + bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); - _contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){ - *(recvedContentLen) += len; + _contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){ + *(recvedContentLen) += len; - onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen)); + onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen)); - if(*(recvedContentLen) < totalContentLen){ - //数据还没接收完毕 + if(*(recvedContentLen) < totalContentLen){ + //数据还没接收完毕 //_contentCallBack是可持续的,后面还要处理后续content数据 return true; - } + } - //数据接收完毕 + //数据接收完毕 if(!bClose){ - //keep-alive类型连接 - //content接收完毕,后续都是http header - setContentLen(0); + //keep-alive类型连接 + //content接收完毕,后续都是http header + setContentLen(0); //content已经接收完毕 return false; } @@ -611,9 +595,9 @@ void HttpSession::Handle_Req_POST(int64_t &content_len) { shutdown(SockException(Err_shutdown,"recv http content completed")); //content已经接收完毕 return false ; - }; - } - //有后续content数据要处理,暂时不关闭连接 + }; + } + //有后续content数据要处理,暂时不关闭连接 } void HttpSession::sendNotFound(bool bClose) { @@ -632,7 +616,7 @@ void HttpSession::setSocketFlags(){ } void HttpSession::onWrite(const Buffer::Ptr &buffer) { - _ticker.resetTime(); + _ticker.resetTime(); if(!_flv_over_websocket){ _ui64TotalBytes += buffer->size(); send(buffer); @@ -653,11 +637,11 @@ void HttpSession::onWebSocketEncodeData(const Buffer::Ptr &buffer){ } void HttpSession::onDetach() { - shutdown(SockException(Err_shutdown,"rtmp ring buffer detached")); + shutdown(SockException(Err_shutdown,"rtmp ring buffer detached")); } std::shared_ptr HttpSession::getSharedPtr(){ - return dynamic_pointer_cast(shared_from_this()); + return dynamic_pointer_cast(shared_from_this()); } } /* namespace mediakit */ diff --git a/src/Http/HttpSession.h b/src/Http/HttpSession.h index 072681d3..6b9b21fb 100644 --- a/src/Http/HttpSession.h +++ b/src/Http/HttpSession.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef SRC_HTTP_HTTPSESSION_H_ #define SRC_HTTP_HTTPSESSION_H_ @@ -45,51 +30,51 @@ class HttpSession: public TcpSession, public HttpRequestSplitter, public WebSocketSplitter { public: - typedef StrCaseMap KeyValue; - typedef HttpResponseInvokerImp HttpResponseInvoker; - friend class AsyncSender; - /** - * @param errMsg 如果为空,则代表鉴权通过,否则为错误提示 - * @param accessPath 运行或禁止访问的根目录 - * @param cookieLifeSecond 鉴权cookie有效期 - **/ - typedef std::function HttpAccessPathInvoker; + typedef StrCaseMap KeyValue; + typedef HttpResponseInvokerImp HttpResponseInvoker; + friend class AsyncSender; + /** + * @param errMsg 如果为空,则代表鉴权通过,否则为错误提示 + * @param accessPath 运行或禁止访问的根目录 + * @param cookieLifeSecond 鉴权cookie有效期 + **/ + typedef std::function HttpAccessPathInvoker; - HttpSession(const Socket::Ptr &pSock); - virtual ~HttpSession(); + HttpSession(const Socket::Ptr &pSock); + virtual ~HttpSession(); - virtual void onRecv(const Buffer::Ptr &) override; - virtual void onError(const SockException &err) override; - virtual void onManager() override; - static string urlDecode(const string &str); + virtual void onRecv(const Buffer::Ptr &) override; + virtual void onError(const SockException &err) override; + virtual void onManager() override; + static string urlDecode(const string &str); protected: - //FlvMuxer override - void onWrite(const Buffer::Ptr &data) override ; - void onDetach() override; - std::shared_ptr getSharedPtr() override; + //FlvMuxer override + void onWrite(const Buffer::Ptr &data) override ; + void onDetach() override; + std::shared_ptr getSharedPtr() override; - //HttpRequestSplitter override - int64_t onRecvHeader(const char *data,uint64_t len) override; - void onRecvContent(const char *data,uint64_t len) override; + //HttpRequestSplitter override + int64_t onRecvHeader(const char *data,uint64_t len) override; + void onRecvContent(const char *data,uint64_t len) override; - /** - * 重载之用于处理不定长度的content - * 这个函数可用于处理大文件上传、http-flv推流 - * @param header http请求头 - * @param data content分片数据 - * @param len content分片数据大小 - * @param totalSize content总大小,如果为0则是不限长度content - * @param recvedSize 已收数据大小 - */ - virtual void onRecvUnlimitedContent(const Parser &header, - const char *data, - uint64_t len, - uint64_t totalSize, - uint64_t recvedSize){ + /** + * 重载之用于处理不定长度的content + * 这个函数可用于处理大文件上传、http-flv推流 + * @param header http请求头 + * @param data content分片数据 + * @param len content分片数据大小 + * @param totalSize content总大小,如果为0则是不限长度content + * @param recvedSize 已收数据大小 + */ + virtual void onRecvUnlimitedContent(const Parser &header, + const char *data, + uint64_t len, + uint64_t totalSize, + uint64_t recvedSize){ shutdown(SockException(Err_shutdown,"http post content is too huge,default closed")); - } + } - /** + /** * websocket客户端连接上事件 * @param header http头 * @return true代表允许websocket连接,否则拒绝 @@ -99,31 +84,31 @@ protected: return false; } - //WebSocketSplitter override - /** + //WebSocketSplitter override + /** * 发送数据进行websocket协议打包后回调 * @param buffer websocket协议数据 */ - void onWebSocketEncodeData(const Buffer::Ptr &buffer) override; + void onWebSocketEncodeData(const Buffer::Ptr &buffer) override; private: - void Handle_Req_GET(int64_t &content_len); + void Handle_Req_GET(int64_t &content_len); void Handle_Req_GET_l(int64_t &content_len, bool sendBody); void Handle_Req_POST(int64_t &content_len); void Handle_Req_HEAD(int64_t &content_len); bool checkLiveFlvStream(const function &cb = nullptr); - bool checkWebSocket(); - bool emitHttpEvent(bool doInvoke); - void urlDecode(Parser &parser); - void sendNotFound(bool bClose); - void sendResponse(const char *pcStatus, bool bClose, const char *pcContentType = nullptr, - const HttpSession::KeyValue &header = HttpSession::KeyValue(), + bool checkWebSocket(); + bool emitHttpEvent(bool doInvoke); + void urlDecode(Parser &parser); + void sendNotFound(bool bClose); + void sendResponse(const char *pcStatus, bool bClose, const char *pcContentType = nullptr, + const HttpSession::KeyValue &header = HttpSession::KeyValue(), const HttpBody::Ptr &body = nullptr,bool is_http_flv = false); - //设置socket标志 - void setSocketFlags(); + //设置socket标志 + void setSocketFlags(); private: - string _origin; + string _origin; Parser _parser; Ticker _ticker; //消耗的总流量 @@ -132,8 +117,8 @@ private: MediaInfo _mediaInfo; //处理content数据的callback function _contentCallBack; - bool _flv_over_websocket = false; - bool _is_flv_stream = false; + bool _flv_over_websocket = false; + bool _is_flv_stream = false; }; diff --git a/src/Http/WebSocketClient.h b/src/Http/WebSocketClient.h index e3d215a7..a26fdc38 100644 --- a/src/Http/WebSocketClient.h +++ b/src/Http/WebSocketClient.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_WebSocketClient_H diff --git a/src/Http/WebSocketSession.h b/src/Http/WebSocketSession.h index af302b8a..cddee17b 100644 --- a/src/Http/WebSocketSession.h +++ b/src/Http/WebSocketSession.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_WEBSOCKETSESSION_H diff --git a/src/Http/WebSocketSplitter.cpp b/src/Http/WebSocketSplitter.cpp index 42fa47f0..72e9927a 100644 --- a/src/Http/WebSocketSplitter.cpp +++ b/src/Http/WebSocketSplitter.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "WebSocketSplitter.h" diff --git a/src/Http/WebSocketSplitter.h b/src/Http/WebSocketSplitter.h index 159c5465..1d5e154e 100644 --- a/src/Http/WebSocketSplitter.h +++ b/src/Http/WebSocketSplitter.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_WEBSOCKETSPLITTER_H diff --git a/src/Http/strCoding.cpp b/src/Http/strCoding.cpp index 2a01f73e..59bb29fe 100644 --- a/src/Http/strCoding.cpp +++ b/src/Http/strCoding.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -36,76 +20,76 @@ namespace mediakit { //////////////////////////通用/////////////////////// void UTF8ToUnicode(wchar_t* pOut, const char *pText) { - char* uchar = (char *)pOut; - uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F); - uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F); - return; + char* uchar = (char *)pOut; + uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F); + uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F); + return; } void UnicodeToUTF8(char* pOut, const wchar_t* pText) { - // 注意 WCHAR高低字的顺序,低字节在前,高字节在后 - const char* pchar = (const char *)pText; - pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4)); - pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6); - pOut[2] = (0x80 | (pchar[0] & 0x3F)); - return; + // 注意 WCHAR高低字的顺序,低字节在前,高字节在后 + const char* pchar = (const char *)pText; + pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4)); + pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6); + pOut[2] = (0x80 | (pchar[0] & 0x3F)); + return; } char CharToInt(char ch) { - if (ch >= '0' && ch <= '9')return (char)(ch - '0'); - if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10); - if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10); - return -1; + if (ch >= '0' && ch <= '9')return (char)(ch - '0'); + if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10); + if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10); + return -1; } char StrToBin(const char *str) { - char tempWord[2]; - char chn; - tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011 - tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000 - chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000 - return chn; + char tempWord[2]; + char chn; + tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011 + tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000 + chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000 + return chn; } string strCoding::UrlEncode(const string &str) { - string out; + string out; size_t len = str.size(); - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { char ch = str[i]; - if (isalnum((uint8_t)ch)) { + if (isalnum((uint8_t)ch)) { out.push_back(ch); - }else { - char buf[4]; - sprintf(buf, "%%%X%X", (uint8_t)ch >> 4,(uint8_t)ch & 0x0F); + }else { + char buf[4]; + sprintf(buf, "%%%X%X", (uint8_t)ch >> 4,(uint8_t)ch & 0x0F); out.append(buf); - } - } - return out; + } + } + return out; } string strCoding::UrlDecode(const string &str) { - string output = ""; - char tmp[2]; - int i = 0, len = str.length(); - while (i < len) { - if (str[i] == '%') { - if(i > len - 3){ - //防止内存溢出 + string output = ""; + char tmp[2]; + int i = 0, len = str.length(); + while (i < len) { + if (str[i] == '%') { + if(i > len - 3){ + //防止内存溢出 break; - } - tmp[0] = str[i + 1]; - tmp[1] = str[i + 2]; - output += StrToBin(tmp); - i = i + 3; - } else if (str[i] == '+') { - output += ' '; - i++; - } else { - output += str[i]; - i++; - } - } - return output; + } + tmp[0] = str[i + 1]; + tmp[1] = str[i + 2]; + output += StrToBin(tmp); + i = i + 3; + } else if (str[i] == '+') { + output += ' '; + i++; + } else { + output += str[i]; + i++; + } + } + return output; } @@ -113,73 +97,73 @@ string strCoding::UrlDecode(const string &str) { #if defined(_WIN32) void UnicodeToGB2312(char* pOut, wchar_t uData) { - WideCharToMultiByte(CP_ACP, NULL, &uData, 1, pOut, sizeof(wchar_t), NULL, NULL); + WideCharToMultiByte(CP_ACP, NULL, &uData, 1, pOut, sizeof(wchar_t), NULL, NULL); } void Gb2312ToUnicode(wchar_t* pOut, const char *gbBuffer) { - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1); } string strCoding::UTF8ToGB2312(const string &str) { - auto len = str.size(); - auto pText = str.data(); - char Ctemp[4] = {0}; - char *pOut = new char[len + 1]; - memset(pOut, 0, len + 1); + auto len = str.size(); + auto pText = str.data(); + char Ctemp[4] = {0}; + char *pOut = new char[len + 1]; + memset(pOut, 0, len + 1); - int i = 0, j = 0; - while (i < len) - { - if (pText[i] >= 0) - { - pOut[j++] = pText[i++]; - } - else - { - wchar_t Wtemp; - UTF8ToUnicode(&Wtemp, pText + i); - UnicodeToGB2312(Ctemp, Wtemp); - pOut[j] = Ctemp[0]; - pOut[j + 1] = Ctemp[1]; - i += 3; - j += 2; - } - } - string ret = pOut; - delete[] pOut; - return ret; + int i = 0, j = 0; + while (i < len) + { + if (pText[i] >= 0) + { + pOut[j++] = pText[i++]; + } + else + { + wchar_t Wtemp; + UTF8ToUnicode(&Wtemp, pText + i); + UnicodeToGB2312(Ctemp, Wtemp); + pOut[j] = Ctemp[0]; + pOut[j + 1] = Ctemp[1]; + i += 3; + j += 2; + } + } + string ret = pOut; + delete[] pOut; + return ret; } string strCoding::GB2312ToUTF8(const string &str) { - auto len = str.size(); - auto pText = str.data(); - char buf[4] = { 0 }; - int nLength = len * 3; - char* pOut = new char[nLength]; - memset(pOut, 0, nLength); - int i = 0, j = 0; - while (i < len) - { - //如果是英文直接复制就可以 - if (*(pText + i) >= 0) - { - pOut[j++] = pText[i++]; - } - else - { - wchar_t pbuffer; - Gb2312ToUnicode(&pbuffer, pText + i); - UnicodeToUTF8(buf, &pbuffer); - pOut[j] = buf[0]; - pOut[j + 1] = buf[1]; - pOut[j + 2] = buf[2]; - j += 3; - i += 2; - } - } - string ret = pOut; - delete[] pOut; - return ret; + auto len = str.size(); + auto pText = str.data(); + char buf[4] = { 0 }; + int nLength = len * 3; + char* pOut = new char[nLength]; + memset(pOut, 0, nLength); + int i = 0, j = 0; + while (i < len) + { + //如果是英文直接复制就可以 + if (*(pText + i) >= 0) + { + pOut[j++] = pText[i++]; + } + else + { + wchar_t pbuffer; + Gb2312ToUnicode(&pbuffer, pText + i); + UnicodeToUTF8(buf, &pbuffer); + pOut[j] = buf[0]; + pOut[j + 1] = buf[1]; + pOut[j + 2] = buf[2]; + j += 3; + i += 2; + } + } + string ret = pOut; + delete[] pOut; + return ret; } #endif//defined(_WIN32) diff --git a/src/Http/strCoding.h b/src/Http/strCoding.h index 7a2f1411..da634067 100644 --- a/src/Http/strCoding.h +++ b/src/Http/strCoding.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_HTTP_STRCODING_H_ @@ -36,15 +20,15 @@ namespace mediakit { class strCoding { public: - static string UrlEncode(const string &str); //urlutf8 编码 - static string UrlDecode(const string &str); //urlutf8解码 + static string UrlEncode(const string &str); //urlutf8 编码 + static string UrlDecode(const string &str); //urlutf8解码 #if defined(_WIN32) - static string UTF8ToGB2312(const string &str);//utf_8转为gb2312 - static string GB2312ToUTF8(const string &str); //gb2312 转utf_8 + static string UTF8ToGB2312(const string &str);//utf_8转为gb2312 + static string GB2312ToUTF8(const string &str); //gb2312 转utf_8 #endif//defined(_WIN32) private: - strCoding(void); - virtual ~strCoding(void); + strCoding(void); + virtual ~strCoding(void); }; } /* namespace mediakit */ diff --git a/src/Http/strptime_win.h b/src/Http/strptime_win.h index 81626ef5..406a24d9 100644 --- a/src/Http/strptime_win.h +++ b/src/Http/strptime_win.h @@ -1,8 +1,4 @@ -// -// Created by xzl on 2018/11/6. -// - -#ifndef ZLMEDIAKIT_STRPTIME_WIN_H +#ifndef ZLMEDIAKIT_STRPTIME_WIN_H #define ZLMEDIAKIT_STRPTIME_WIN_H #include diff --git a/src/Player/MediaPlayer.cpp b/src/Player/MediaPlayer.cpp index 53365d1a..6b95a4eb 100644 --- a/src/Player/MediaPlayer.cpp +++ b/src/Player/MediaPlayer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -42,29 +26,29 @@ MediaPlayer::MediaPlayer(const EventPoller::Ptr &poller) { MediaPlayer::~MediaPlayer() { } void MediaPlayer::play(const string &strUrl) { - _delegate = PlayerBase::createPlayer(_poller,strUrl); - _delegate->setOnShutdown(_shutdownCB); - _delegate->setOnPlayResult(_playResultCB); + _delegate = PlayerBase::createPlayer(_poller,strUrl); + _delegate->setOnShutdown(_shutdownCB); + _delegate->setOnPlayResult(_playResultCB); _delegate->setOnResume(_resumeCB); _delegate->setMediaSouce(_pMediaSrc); - _delegate->mINI::operator=(*this); - _delegate->play(strUrl); + _delegate->mINI::operator=(*this); + _delegate->play(strUrl); } EventPoller::Ptr MediaPlayer::getPoller(){ - return _poller; + return _poller; } void MediaPlayer::pause(bool bPause) { - if (_delegate) { - _delegate->pause(bPause); - } + if (_delegate) { + _delegate->pause(bPause); + } } void MediaPlayer::teardown() { - if (_delegate) { - _delegate->teardown(); - } + if (_delegate) { + _delegate->teardown(); + } } diff --git a/src/Player/MediaPlayer.h b/src/Player/MediaPlayer.h index c4d989b8..42b6eb61 100644 --- a/src/Player/MediaPlayer.h +++ b/src/Player/MediaPlayer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_PLAYER_MEDIAPLAYER_H_ @@ -39,16 +23,16 @@ namespace mediakit { class MediaPlayer : public PlayerImp { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - MediaPlayer(const EventPoller::Ptr &poller = nullptr); - virtual ~MediaPlayer(); - void play(const string &strUrl) override; - void pause(bool bPause) override; - void teardown() override; - EventPoller::Ptr getPoller(); + MediaPlayer(const EventPoller::Ptr &poller = nullptr); + virtual ~MediaPlayer(); + void play(const string &strUrl) override; + void pause(bool bPause) override; + void teardown() override; + EventPoller::Ptr getPoller(); private: - EventPoller::Ptr _poller; + EventPoller::Ptr _poller; }; } /* namespace mediakit */ diff --git a/src/Player/PlayerBase.cpp b/src/Player/PlayerBase.cpp index 5b94a976..26c9f788 100644 --- a/src/Player/PlayerBase.cpp +++ b/src/Player/PlayerBase.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -33,92 +17,92 @@ using namespace toolkit; namespace mediakit { PlayerBase::Ptr PlayerBase::createPlayer(const EventPoller::Ptr &poller,const string &strUrl) { - static auto releasePlayer = [](PlayerBase *ptr){ - onceToken token(nullptr,[&](){ - delete ptr; - }); - ptr->teardown(); - }; - string prefix = FindField(strUrl.data(), NULL, "://"); + static auto releasePlayer = [](PlayerBase *ptr){ + onceToken token(nullptr,[&](){ + delete ptr; + }); + ptr->teardown(); + }; + string prefix = FindField(strUrl.data(), NULL, "://"); - if (strcasecmp("rtsps",prefix.data()) == 0) { - return PlayerBase::Ptr(new TcpClientWithSSL(poller),releasePlayer); - } + if (strcasecmp("rtsps",prefix.data()) == 0) { + return PlayerBase::Ptr(new TcpClientWithSSL(poller),releasePlayer); + } - if (strcasecmp("rtsp",prefix.data()) == 0) { - return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer); - } + if (strcasecmp("rtsp",prefix.data()) == 0) { + return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer); + } - if (strcasecmp("rtmps",prefix.data()) == 0) { - return PlayerBase::Ptr(new TcpClientWithSSL(poller),releasePlayer); - } + if (strcasecmp("rtmps",prefix.data()) == 0) { + return PlayerBase::Ptr(new TcpClientWithSSL(poller),releasePlayer); + } - if (strcasecmp("rtmp",prefix.data()) == 0) { - return PlayerBase::Ptr(new RtmpPlayerImp(poller),releasePlayer); - } + if (strcasecmp("rtmp",prefix.data()) == 0) { + return PlayerBase::Ptr(new RtmpPlayerImp(poller),releasePlayer); + } - return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer); + return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer); } PlayerBase::PlayerBase() { - this->mINI::operator[](kTimeoutMS) = 10000; - this->mINI::operator[](kMediaTimeoutMS) = 5000; - this->mINI::operator[](kBeatIntervalMS) = 5000; - this->mINI::operator[](kMaxAnalysisMS) = 5000; + this->mINI::operator[](kTimeoutMS) = 10000; + this->mINI::operator[](kMediaTimeoutMS) = 5000; + this->mINI::operator[](kBeatIntervalMS) = 5000; + this->mINI::operator[](kMaxAnalysisMS) = 5000; } ///////////////////////////Demuxer////////////////////////////// bool Demuxer::isInited(int analysisMs) { - if(analysisMs && _ticker.createdTime() > analysisMs){ - //analysisMs毫秒后强制初始化完毕 - return true; - } - if (_videoTrack && !_videoTrack->ready()) { - //视频未准备好 - return false; - } - if (_audioTrack && !_audioTrack->ready()) { - //音频未准备好 - return false; - } - return true; + if(analysisMs && _ticker.createdTime() > analysisMs){ + //analysisMs毫秒后强制初始化完毕 + return true; + } + if (_videoTrack && !_videoTrack->ready()) { + //视频未准备好 + return false; + } + if (_audioTrack && !_audioTrack->ready()) { + //音频未准备好 + return false; + } + return true; } vector Demuxer::getTracks(bool trackReady) const { - vector ret; - if(_videoTrack){ - if(trackReady){ - if(_videoTrack->ready()){ - ret.emplace_back(_videoTrack); - } - }else{ - ret.emplace_back(_videoTrack); - } - } - if(_audioTrack){ - if(trackReady){ - if(_audioTrack->ready()){ - ret.emplace_back(_audioTrack); - } - }else{ - ret.emplace_back(_audioTrack); - } - } - return std::move(ret); + vector ret; + if(_videoTrack){ + if(trackReady){ + if(_videoTrack->ready()){ + ret.emplace_back(_videoTrack); + } + }else{ + ret.emplace_back(_videoTrack); + } + } + if(_audioTrack){ + if(trackReady){ + if(_audioTrack->ready()){ + ret.emplace_back(_audioTrack); + } + }else{ + ret.emplace_back(_audioTrack); + } + } + return std::move(ret); } float Demuxer::getDuration() const { - return _fDuration; + return _fDuration; } void Demuxer::onAddTrack(const Track::Ptr &track){ - if(_listener){ - _listener->onAddTrack(track); - } + if(_listener){ + _listener->onAddTrack(track); + } } void Demuxer::setTrackListener(Demuxer::Listener *listener) { - _listener = listener; + _listener = listener; } } /* namespace mediakit */ diff --git a/src/Player/PlayerBase.h b/src/Player/PlayerBase.h index 8fb397b3..e38d723e 100644 --- a/src/Player/PlayerBase.h +++ b/src/Player/PlayerBase.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_PLAYER_PLAYERBASE_H_ @@ -43,59 +27,59 @@ namespace mediakit { class DemuxerBase : public TrackSource{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - /** - * 获取节目总时长,单位秒 - * @return - */ - virtual float getDuration() const { return 0;} + /** + * 获取节目总时长,单位秒 + * @return + */ + virtual float getDuration() const { return 0;} - /** - * 是否初始化完毕,完毕后方可调用getTrack方法 - * @param analysisMs 数据流最大分析时间 单位毫秒 - * @return - */ - virtual bool isInited(int analysisMs) { return true; } + /** + * 是否初始化完毕,完毕后方可调用getTrack方法 + * @param analysisMs 数据流最大分析时间 单位毫秒 + * @return + */ + virtual bool isInited(int analysisMs) { return true; } }; class PlayerBase : public DemuxerBase, public mINI{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; static Ptr createPlayer(const EventPoller::Ptr &poller,const string &strUrl); - PlayerBase(); - virtual ~PlayerBase(){} + PlayerBase(); + virtual ~PlayerBase(){} - /** - * 开始播放 - * @param strUrl 视频url,支持rtsp/rtmp - */ - virtual void play(const string &strUrl) {} + /** + * 开始播放 + * @param strUrl 视频url,支持rtsp/rtmp + */ + virtual void play(const string &strUrl) {} - /** - * 暂停或恢复 - * @param bPause - */ - virtual void pause(bool bPause) {} + /** + * 暂停或恢复 + * @param bPause + */ + virtual void pause(bool bPause) {} - /** - * 中断播放 - */ - virtual void teardown() {} + /** + * 中断播放 + */ + virtual void teardown() {} - /** - * 设置异常中断回调 - * @param cb - */ - virtual void setOnShutdown( const function &cb) {} + /** + * 设置异常中断回调 + * @param cb + */ + virtual void setOnShutdown( const function &cb) {} - /** - * 设置播放结果回调 - * @param cb - */ - virtual void setOnPlayResult( const function &cb) {} + /** + * 设置播放结果回调 + * @param cb + */ + virtual void setOnPlayResult( const function &cb) {} /** * 设置播放恢复回调 @@ -103,10 +87,10 @@ public: */ virtual void setOnResume( const function &cb) {} - /** - * 获取播放进度,取值 0.0 ~ 1.0 - * @return - */ + /** + * 获取播放进度,取值 0.0 ~ 1.0 + * @return + */ virtual float getProgress() const { return 0;} /** @@ -126,7 +110,7 @@ public: * @param trackType 音频或视频,TrackInvalid时为总丢包率 * @return */ - virtual float getPacketLossRate(TrackType trackType) const {return 0; } + virtual float getPacketLossRate(TrackType trackType) const {return 0; } /** * 获取所有track @@ -146,24 +130,24 @@ protected: template class PlayerImp : public Parent { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - template - PlayerImp(ArgsType &&...args):Parent(std::forward(args)...){} + template + PlayerImp(ArgsType &&...args):Parent(std::forward(args)...){} - virtual ~PlayerImp(){} - void setOnShutdown(const function &cb) override { - if (_delegate) { - _delegate->setOnShutdown(cb); - } - _shutdownCB = cb; - } - void setOnPlayResult(const function &cb) override { - if (_delegate) { - _delegate->setOnPlayResult(cb); - } - _playResultCB = cb; - } + virtual ~PlayerImp(){} + void setOnShutdown(const function &cb) override { + if (_delegate) { + _delegate->setOnShutdown(cb); + } + _shutdownCB = cb; + } + void setOnPlayResult(const function &cb) override { + if (_delegate) { + _delegate->setOnPlayResult(cb); + } + _playResultCB = cb; + } void setOnResume(const function &cb) override { if (_delegate) { @@ -178,12 +162,12 @@ public: } return Parent::isInited(analysisMs); } - float getDuration() const override { - if (_delegate) { - return _delegate->getDuration(); - } - return Parent::getDuration(); - } + float getDuration() const override { + if (_delegate) { + return _delegate->getDuration(); + } + return Parent::getDuration(); + } float getProgress() const override{ if (_delegate) { return _delegate->getProgress(); @@ -198,95 +182,95 @@ public: } void setMediaSouce(const MediaSource::Ptr & src) override { - if (_delegate) { - _delegate->setMediaSouce(src); - } - _pMediaSrc = src; + if (_delegate) { + _delegate->setMediaSouce(src); + } + _pMediaSrc = src; } vector getTracks(bool trackReady = true) const override{ - if (_delegate) { - return _delegate->getTracks(trackReady); - } - return Parent::getTracks(trackReady); - } + if (_delegate) { + return _delegate->getTracks(trackReady); + } + return Parent::getTracks(trackReady); + } protected: - void onShutdown(const SockException &ex) override { - if (_shutdownCB) { - _shutdownCB(ex); - _shutdownCB = nullptr; - } - } + void onShutdown(const SockException &ex) override { + if (_shutdownCB) { + _shutdownCB(ex); + _shutdownCB = nullptr; + } + } - void onPlayResult(const SockException &ex) override { - if(_playResultCB) { - _playResultCB(ex); - _playResultCB = nullptr; - } - } + void onPlayResult(const SockException &ex) override { + if(_playResultCB) { + _playResultCB(ex); + _playResultCB = nullptr; + } + } - void onResume() override{ + void onResume() override{ if(_resumeCB){ _resumeCB(); } } protected: - function _shutdownCB; - function _playResultCB; + function _shutdownCB; + function _playResultCB; function _resumeCB; std::shared_ptr _delegate; - MediaSource::Ptr _pMediaSrc; + MediaSource::Ptr _pMediaSrc; }; class Demuxer : public PlayerBase{ public: - class Listener{ - public: - Listener() = default; - virtual ~Listener() = default; - virtual void onAddTrack(const Track::Ptr &track) = 0; - }; + class Listener{ + public: + Listener() = default; + virtual ~Listener() = default; + virtual void onAddTrack(const Track::Ptr &track) = 0; + }; - Demuxer(){}; - virtual ~Demuxer(){}; + Demuxer(){}; + virtual ~Demuxer(){}; - /** - * 返回是否完成初始化完毕 - * 在构造RtspDemuxer对象时有些rtsp的sdp不包含sps pps信息 - * 所以要等待接收到到sps的rtp包后才能完成 - * - * 在构造RtmpDemuxer对象时是无法获取sps pps aac_cfg等这些信息, - * 所以要调用inputRtmp后才会获取到这些信息,这时才初始化成功 - * @param analysisMs 数据流最大分析时间 单位毫秒 - * @return - */ - bool isInited(int analysisMs) override; + /** + * 返回是否完成初始化完毕 + * 在构造RtspDemuxer对象时有些rtsp的sdp不包含sps pps信息 + * 所以要等待接收到到sps的rtp包后才能完成 + * + * 在构造RtmpDemuxer对象时是无法获取sps pps aac_cfg等这些信息, + * 所以要调用inputRtmp后才会获取到这些信息,这时才初始化成功 + * @param analysisMs 数据流最大分析时间 单位毫秒 + * @return + */ + bool isInited(int analysisMs) override; - /** - * 获取所有Track - * @return 所有Track - */ - vector getTracks(bool trackReady = true) const override; + /** + * 获取所有Track + * @return 所有Track + */ + vector getTracks(bool trackReady = true) const override; - /** - * 获取节目总时长 - * @return 节目总时长,单位秒 - */ - float getDuration() const override; + /** + * 获取节目总时长 + * @return 节目总时长,单位秒 + */ + float getDuration() const override; - /** - * 设置track监听器 - */ - void setTrackListener(Listener *listener); + /** + * 设置track监听器 + */ + void setTrackListener(Listener *listener); protected: - void onAddTrack(const Track::Ptr &track); + void onAddTrack(const Track::Ptr &track); protected: - Listener *_listener = nullptr; - AudioTrack::Ptr _audioTrack; - VideoTrack::Ptr _videoTrack; - Ticker _ticker; - float _fDuration = 0; + Listener *_listener = nullptr; + AudioTrack::Ptr _audioTrack; + VideoTrack::Ptr _videoTrack; + Ticker _ticker; + float _fDuration = 0; }; } /* namespace mediakit */ diff --git a/src/Player/PlayerProxy.cpp b/src/Player/PlayerProxy.cpp index 1ba1d1b7..6b726228 100644 --- a/src/Player/PlayerProxy.cpp +++ b/src/Player/PlayerProxy.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Common/config.h" @@ -65,17 +49,17 @@ static uint8_t s_mute_adts[] = {0xff, 0xf1, 0x6c, 0x40, 0x2d, 0x3f, 0xfc, 0x00, PlayerProxy::PlayerProxy(const string &strVhost, const string &strApp, const string &strSrc, - bool bEnableRtsp, - bool bEnableRtmp, + bool bEnableRtsp, + bool bEnableRtmp, bool bEnableHls, bool bEnableMp4, int iRetryCount, - const EventPoller::Ptr &poller) : MediaPlayer(poller){ - _strVhost = strVhost; - _strApp = strApp; - _strSrc = strSrc; - _bEnableRtsp = bEnableRtsp; - _bEnableRtmp = bEnableRtmp; + const EventPoller::Ptr &poller) : MediaPlayer(poller){ + _strVhost = strVhost; + _strApp = strApp; + _strSrc = strSrc; + _bEnableRtsp = bEnableRtsp; + _bEnableRtmp = bEnableRtmp; _bEnableHls = bEnableHls; _bEnableMp4 = bEnableMp4; _iRetryCount = iRetryCount; @@ -90,88 +74,88 @@ void PlayerProxy::setOnClose(const function &cb){ } void PlayerProxy::play(const string &strUrlTmp) { - weak_ptr weakSelf = shared_from_this(); - std::shared_ptr piFailedCnt(new int(0)); //连续播放失败次数 - setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } + weak_ptr weakSelf = shared_from_this(); + std::shared_ptr piFailedCnt(new int(0)); //连续播放失败次数 + setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } - if(strongSelf->_playCB) { + if(strongSelf->_playCB) { strongSelf->_playCB(err); strongSelf->_playCB = nullptr; } - if(!err) { - // 播放成功 - *piFailedCnt = 0;//连续播放失败次数清0 - strongSelf->onPlaySuccess(); - }else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { - // 播放失败,延时重试播放 - strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); - } - }); - setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - if(strongSelf->_mediaMuxer) { - auto tracks = strongSelf->getTracks(false); - for (auto & track : tracks){ - track->delDelegate(strongSelf->_mediaMuxer.get()); - } + if(!err) { + // 播放成功 + *piFailedCnt = 0;//连续播放失败次数清0 + strongSelf->onPlaySuccess(); + }else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { + // 播放失败,延时重试播放 + strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); + } + }); + setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + if(strongSelf->_mediaMuxer) { + auto tracks = strongSelf->getTracks(false); + for (auto & track : tracks){ + track->delDelegate(strongSelf->_mediaMuxer.get()); + } - GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); - if (resetWhenRePlay) { - strongSelf->_mediaMuxer.reset(); - } else { - strongSelf->_mediaMuxer->resetTracks(); - } - } - //播放异常中断,延时重试播放 - if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { - strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); - } - }); - MediaPlayer::play(strUrlTmp); + GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); + if (resetWhenRePlay) { + strongSelf->_mediaMuxer.reset(); + } else { + strongSelf->_mediaMuxer->resetTracks(); + } + } + //播放异常中断,延时重试播放 + if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { + strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); + } + }); + MediaPlayer::play(strUrlTmp); - MediaSource::Ptr mediaSource; - if(dynamic_pointer_cast(_delegate)){ - //rtsp拉流 - GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy); - if(directProxy && _bEnableRtsp){ - mediaSource = std::make_shared(_strVhost,_strApp,_strSrc); - } - } else if(dynamic_pointer_cast(_delegate)){ - //rtmp拉流 - if(_bEnableRtmp){ - mediaSource = std::make_shared(_strVhost,_strApp,_strSrc); - } - } - if(mediaSource){ - setMediaSouce(mediaSource); - mediaSource->setListener(shared_from_this()); - } + MediaSource::Ptr mediaSource; + if(dynamic_pointer_cast(_delegate)){ + //rtsp拉流 + GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy); + if(directProxy && _bEnableRtsp){ + mediaSource = std::make_shared(_strVhost,_strApp,_strSrc); + } + } else if(dynamic_pointer_cast(_delegate)){ + //rtmp拉流 + if(_bEnableRtmp){ + mediaSource = std::make_shared(_strVhost,_strApp,_strSrc); + } + } + if(mediaSource){ + setMediaSouce(mediaSource); + mediaSource->setListener(shared_from_this()); + } } PlayerProxy::~PlayerProxy() { - _timer.reset(); + _timer.reset(); } void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){ - auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000)); - weak_ptr weakSelf = shared_from_this(); - _timer = std::make_shared(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() { - //播放失败次数越多,则延时越长 - auto strongPlayer = weakSelf.lock(); - if(!strongPlayer) { - return false; - } - WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl; - strongPlayer->MediaPlayer::play(strUrl); - return false; - }, getPoller()); + auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000)); + weak_ptr weakSelf = shared_from_this(); + _timer = std::make_shared(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() { + //播放失败次数越多,则延时越长 + auto strongPlayer = weakSelf.lock(); + if(!strongPlayer) { + return false; + } + WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl; + strongPlayer->MediaPlayer::play(strUrl); + return false; + }, getPoller()); } bool PlayerProxy::close(MediaSource &sender,bool force) { @@ -179,119 +163,112 @@ bool PlayerProxy::close(MediaSource &sender,bool force) { return false; } - //通知其停止推流 - weak_ptr weakSlef = dynamic_pointer_cast(shared_from_this()); - getPoller()->async_first([weakSlef]() { - auto stronSelf = weakSlef.lock(); - if (stronSelf) { - stronSelf->_mediaMuxer.reset(); - stronSelf->setMediaSouce(nullptr); - stronSelf->teardown(); - if(stronSelf->_onClose){ + //通知其停止推流 + weak_ptr weakSlef = dynamic_pointer_cast(shared_from_this()); + getPoller()->async_first([weakSlef]() { + auto stronSelf = weakSlef.lock(); + if (stronSelf) { + stronSelf->_mediaMuxer.reset(); + stronSelf->setMediaSouce(nullptr); + stronSelf->teardown(); + if(stronSelf->_onClose){ stronSelf->_onClose(); - } - } - }); + } + } + }); WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; return true; } -void PlayerProxy::onNoneReader(MediaSource &sender) { - if(!_mediaMuxer || totalReaderCount()){ - return; - } - MediaSourceEvent::onNoneReader(sender); -} - int PlayerProxy::totalReaderCount(){ return (_mediaMuxer ? _mediaMuxer->totalReaderCount() : 0) + (_pMediaSrc ? _pMediaSrc->readerCount() : 0); } int PlayerProxy::totalReaderCount(MediaSource &sender) { - return totalReaderCount(); + return totalReaderCount(); } class MuteAudioMaker : public FrameDispatcher{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - MuteAudioMaker(){}; - virtual ~MuteAudioMaker(){} - void inputFrame(const Frame::Ptr &frame) override { - if(frame->getTrackType() == TrackVideo){ - auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS; - if(_iAudioIndex != iAudioIndex){ - _iAudioIndex = iAudioIndex; - auto aacFrame = std::make_shared((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS); - FrameDispatcher::inputFrame(aacFrame); - } - } - } + MuteAudioMaker(){}; + virtual ~MuteAudioMaker(){} + void inputFrame(const Frame::Ptr &frame) override { + if(frame->getTrackType() == TrackVideo){ + auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS; + if(_iAudioIndex != iAudioIndex){ + _iAudioIndex = iAudioIndex; + auto aacFrame = std::make_shared((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS, 0); + FrameDispatcher::inputFrame(aacFrame); + } + } + } private: - class AACFrameCacheAble : public AACFrameNoCacheAble{ - public: - template - AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward(args)...){}; - virtual ~AACFrameCacheAble() = default; + class AACFrameCacheAble : public AACFrameNoCacheAble{ + public: + template + AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward(args)...){}; + virtual ~AACFrameCacheAble() = default; - bool cacheAble() const override { - return true; - } - }; + bool cacheAble() const override { + return true; + } + }; private: - int _iAudioIndex = 0; + int _iAudioIndex = 0; }; void PlayerProxy::onPlaySuccess() { - GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); - if (dynamic_pointer_cast(_pMediaSrc)) { - //rtsp拉流代理 - if (resetWhenRePlay || !_mediaMuxer) { - _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4)); - } - } else if (dynamic_pointer_cast(_pMediaSrc)) { - //rtmp拉流代理 - if (resetWhenRePlay || !_mediaMuxer) { - _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4)); - } - } else { - //其他拉流代理 - if (resetWhenRePlay || !_mediaMuxer) { - _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4)); - } - } - _mediaMuxer->setListener(shared_from_this()); + GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); + if (dynamic_pointer_cast(_pMediaSrc)) { + //rtsp拉流代理 + if (resetWhenRePlay || !_mediaMuxer) { + _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4)); + } + } else if (dynamic_pointer_cast(_pMediaSrc)) { + //rtmp拉流代理 + if (resetWhenRePlay || !_mediaMuxer) { + _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4)); + } + } else { + //其他拉流代理 + if (resetWhenRePlay || !_mediaMuxer) { + _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4)); + } + } + _mediaMuxer->setMediaListener(shared_from_this()); - auto videoTrack = getTrack(TrackVideo,false); - if(videoTrack){ - //添加视频 - _mediaMuxer->addTrack(videoTrack); - //视频数据写入_mediaMuxer - videoTrack->addDelegate(_mediaMuxer); - } + auto videoTrack = getTrack(TrackVideo,false); + if(videoTrack){ + //添加视频 + _mediaMuxer->addTrack(videoTrack); + //视频数据写入_mediaMuxer + videoTrack->addDelegate(_mediaMuxer); + } - //是否添加静音音频 - GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio); + //是否添加静音音频 + GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio); - auto audioTrack = getTrack(TrackAudio, false); - if(audioTrack){ - //添加音频 - _mediaMuxer->addTrack(audioTrack); - //音频数据写入_mediaMuxer + auto audioTrack = getTrack(TrackAudio, false); + if(audioTrack){ + //添加音频 + _mediaMuxer->addTrack(audioTrack); + //音频数据写入_mediaMuxer audioTrack->addDelegate(_mediaMuxer); }else if(addMuteAudio && videoTrack){ - //没有音频信息,产生一个静音音频 - MuteAudioMaker::Ptr audioMaker = std::make_shared(); - //videoTrack把数据写入MuteAudioMaker - videoTrack->addDelegate(audioMaker); - //添加一个静音Track至_mediaMuxer - _mediaMuxer->addTrack(std::make_shared()); - //MuteAudioMaker生成静音音频然后写入_mediaMuxer; - audioMaker->addDelegate(_mediaMuxer); - } + //没有音频信息,产生一个静音音频 + MuteAudioMaker::Ptr audioMaker = std::make_shared(); + //videoTrack把数据写入MuteAudioMaker + videoTrack->addDelegate(audioMaker); + //添加一个静音Track至_mediaMuxer + _mediaMuxer->addTrack(std::make_shared()); + //MuteAudioMaker生成静音音频然后写入_mediaMuxer; + audioMaker->addDelegate(_mediaMuxer); + } - //添加完毕所有track,防止单track情况下最大等待3秒 + //添加完毕所有track,防止单track情况下最大等待3秒 _mediaMuxer->addTrackCompleted(); if(_pMediaSrc){ diff --git a/src/Player/PlayerProxy.h b/src/Player/PlayerProxy.h index 7560e4c3..4437a68a 100644 --- a/src/Player/PlayerProxy.h +++ b/src/Player/PlayerProxy.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_DEVICE_PLAYERPROXY_H_ @@ -39,24 +23,24 @@ using namespace toolkit; namespace mediakit { class PlayerProxy :public MediaPlayer, - public std::enable_shared_from_this , - public MediaSourceEvent{ + public std::enable_shared_from_this , + public MediaSourceEvent{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; //如果iRetryCount<0,则一直重试播放;否则重试iRetryCount次数 //默认一直重试 - PlayerProxy(const string &strVhost, + PlayerProxy(const string &strVhost, const string &strApp, const string &strSrc, - bool bEnableRtsp = true, - bool bEnableRtmp = true, + bool bEnableRtsp = true, + bool bEnableRtmp = true, bool bEnableHls = true, bool bEnableMp4 = false, int iRetryCount = -1, - const EventPoller::Ptr &poller = nullptr); + const EventPoller::Ptr &poller = nullptr); - virtual ~PlayerProxy(); + virtual ~PlayerProxy(); /** * 设置play结果回调,只触发一次;在play执行之前有效 @@ -81,19 +65,18 @@ public: */ int totalReaderCount() ; private: - //MediaSourceEvent override - bool close(MediaSource &sender,bool force) override; - void onNoneReader(MediaSource &sender) override; - int totalReaderCount(MediaSource &sender) override; - void rePlay(const string &strUrl,int iFailedCnt); - void onPlaySuccess(); + //MediaSourceEvent override + bool close(MediaSource &sender,bool force) override; + int totalReaderCount(MediaSource &sender) override; + void rePlay(const string &strUrl,int iFailedCnt); + void onPlaySuccess(); private: bool _bEnableRtsp; bool _bEnableRtmp; - bool _bEnableHls; - bool _bEnableMp4; + bool _bEnableHls; + bool _bEnableMp4; int _iRetryCount; - MultiMediaSourceMuxer::Ptr _mediaMuxer; + MultiMediaSourceMuxer::Ptr _mediaMuxer; string _strVhost; string _strApp; string _strSrc; diff --git a/src/Pusher/MediaPusher.cpp b/src/Pusher/MediaPusher.cpp index 26f8de8b..f7fca4ed 100644 --- a/src/Pusher/MediaPusher.cpp +++ b/src/Pusher/MediaPusher.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include #include "MediaPusher.h" diff --git a/src/Pusher/MediaPusher.h b/src/Pusher/MediaPusher.h index aba11f64..5e4974fb 100644 --- a/src/Pusher/MediaPusher.h +++ b/src/Pusher/MediaPusher.h @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef SRC_PUSHER_MEDIAPUSHER_H_ #define SRC_PUSHER_MEDIAPUSHER_H_ diff --git a/src/Pusher/PusherBase.cpp b/src/Pusher/PusherBase.cpp index 7637e389..a9e0ea39 100644 --- a/src/Pusher/PusherBase.cpp +++ b/src/Pusher/PusherBase.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include #include "PusherBase.h" diff --git a/src/Pusher/PusherBase.h b/src/Pusher/PusherBase.h index 752f3358..e68e93e1 100644 --- a/src/Pusher/PusherBase.h +++ b/src/Pusher/PusherBase.h @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef SRC_PUSHER_PUSHERBASE_H_ #define SRC_PUSHER_PUSHERBASE_H_ diff --git a/src/Record/HlsMaker.cpp b/src/Record/HlsMaker.cpp index 704e5f61..c54c0e62 100644 --- a/src/Record/HlsMaker.cpp +++ b/src/Record/HlsMaker.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "HlsMaker.h" diff --git a/src/Record/HlsMaker.h b/src/Record/HlsMaker.h index 12e5dab4..2a2324c3 100644 --- a/src/Record/HlsMaker.h +++ b/src/Record/HlsMaker.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef HLSMAKER_H diff --git a/src/Record/HlsMakerImp.cpp b/src/Record/HlsMakerImp.cpp index cdbe8e01..c0b64c19 100644 --- a/src/Record/HlsMakerImp.cpp +++ b/src/Record/HlsMakerImp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "HlsMakerImp.h" diff --git a/src/Record/HlsMakerImp.h b/src/Record/HlsMakerImp.h index d12aef5d..80ea54dd 100644 --- a/src/Record/HlsMakerImp.h +++ b/src/Record/HlsMakerImp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef HLSMAKERIMP_H diff --git a/src/Record/HlsMediaSource.cpp b/src/Record/HlsMediaSource.cpp index 88bc0c71..1f5afa4f 100644 --- a/src/Record/HlsMediaSource.cpp +++ b/src/Record/HlsMediaSource.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "HlsMediaSource.h" diff --git a/src/Record/HlsMediaSource.h b/src/Record/HlsMediaSource.h index 38a192b7..513e90ac 100644 --- a/src/Record/HlsMediaSource.h +++ b/src/Record/HlsMediaSource.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef ZLMEDIAKIT_HLSMEDIASOURCE_H #define ZLMEDIAKIT_HLSMEDIASOURCE_H @@ -44,16 +29,16 @@ public: virtual ~HlsMediaSource() = default; /** - * 获取媒体源的环形缓冲 - */ + * 获取媒体源的环形缓冲 + */ const RingType::Ptr &getRing() const { return _ring; } /** - * 获取播放器个数 - * @return - */ + * 获取播放器个数 + * @return + */ int readerCount() override { return _readerCount.load(); } @@ -79,7 +64,7 @@ private: return; } - if (--_readerCount == 0 && totalReaderCount() == 0) { + if (--_readerCount == 0) { onNoneReader(); } } diff --git a/src/Record/HlsRecorder.h b/src/Record/HlsRecorder.h index 7bebd20b..20c3d68f 100644 --- a/src/Record/HlsRecorder.h +++ b/src/Record/HlsRecorder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef HLSRECORDER_H diff --git a/src/Record/MP4.cpp b/src/Record/MP4.cpp new file mode 100644 index 00000000..878c62c0 --- /dev/null +++ b/src/Record/MP4.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifdef ENABLE_MP4 +#include "MP4.h" +#include "Util/File.h" +#include "Util/logger.h" +#include "Common/config.h" +using namespace toolkit; +namespace mediakit { + +static struct mov_buffer_t s_io = { + [](void* ctx, void* data, uint64_t bytes) { + MP4File *thiz = (MP4File *)ctx; + return thiz->onRead(data,bytes); + }, + [](void* ctx, const void* data, uint64_t bytes){ + MP4File *thiz = (MP4File *)ctx; + return thiz->onWrite(data,bytes); + }, + [](void* ctx, uint64_t offset) { + MP4File *thiz = (MP4File *)ctx; + return thiz->onSeek(offset); + }, + [](void* ctx){ + MP4File *thiz = (MP4File *)ctx; + return thiz->onTell(); + } +}; + +MP4File::Writer MP4File::createWriter(){ + GET_CONFIG(bool, mp4FastStart, Record::kFastStart); + Writer writer; + writer.reset(mov_writer_create(&s_io,this,mp4FastStart ? MOV_FLAG_FASTSTART : 0),[](mov_writer_t *ptr){ + if(ptr){ + mov_writer_destroy(ptr); + } + }); + if(!writer){ + throw std::runtime_error("写入mp4文件失败!"); + } + return writer; +} + +MP4File::Reader MP4File::createReader(){ + Reader reader; + reader.reset(mov_reader_create(&s_io,this),[](mov_reader_t *ptr){ + if(ptr){ + mov_reader_destroy(ptr); + } + }); + if(!reader){ + throw std::runtime_error("读取mp4文件失败!"); + } + return reader; +} + +#if defined(_WIN32) || defined(_WIN64) + #define fseek64 _fseeki64 +#define ftell64 _ftelli64 +#else +#define fseek64 fseek +#define ftell64 ftell +#endif + +void MP4File::openFile(const char *file,const char *mode) { + //创建文件 + auto fp = File::createfile_file(file,mode); + if(!fp){ + throw std::runtime_error(string("打开文件失败:") + file); + } + + GET_CONFIG(uint32_t,mp4BufSize,Record::kFileBufSize); + + //新建文件io缓存 + std::shared_ptr file_buf(new char[mp4BufSize],[](char *ptr){ + if(ptr){ + delete [] ptr; + } + }); + + if(file_buf){ + //设置文件io缓存 + setvbuf(fp, file_buf.get(), _IOFBF, mp4BufSize); + } + + //创建智能指针 + _file.reset(fp,[file_buf](FILE *fp) { + fclose(fp); + }); +} + +void MP4File::closeFile() { + _file = nullptr; +} + +int MP4File::onRead(void *data, uint64_t bytes) { + if (bytes == fread(data, 1, bytes, _file.get())){ + return 0; + } + return 0 != ferror(_file.get()) ? ferror(_file.get()) : -1 /*EOF*/; +} + +int MP4File::onWrite(const void *data, uint64_t bytes) { + return bytes == fwrite(data, 1, bytes, _file.get()) ? 0 : ferror(_file.get()); +} + +int MP4File::onSeek(uint64_t offset) { + return fseek64(_file.get(), offset, SEEK_SET); +} + +uint64_t MP4File::onTell() { + return ftell64(_file.get()); +} + +}//namespace mediakit +#endif //NABLE_MP4RECORD diff --git a/src/Record/MP4.h b/src/Record/MP4.h new file mode 100644 index 00000000..15e201f9 --- /dev/null +++ b/src/Record/MP4.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_MP4_H +#define ZLMEDIAKIT_MP4_H +#ifdef ENABLE_MP4 +#include +#include +#include "mov-writer.h" +#include "mov-reader.h" +#include "mpeg4-hevc.h" +#include "mpeg4-avc.h" +#include "mpeg4-aac.h" +#include "mov-buffer.h" +#include "mov-format.h" +using namespace std; +namespace mediakit { + +class MP4File { +public: + friend struct mov_buffer_t; + typedef std::shared_ptr Writer; + typedef std::shared_ptr Reader; + MP4File() = default; + virtual ~MP4File() = default; + + Writer createWriter(); + Reader createReader(); + void openFile(const char *file,const char *mode); + void closeFile(); + + int onRead(void* data, uint64_t bytes); + int onWrite(const void* data, uint64_t bytes); + int onSeek( uint64_t offset); + uint64_t onTell(); +private: + std::shared_ptr _file; +}; + +}//namespace mediakit +#endif //NABLE_MP4RECORD +#endif //ZLMEDIAKIT_MP4_H diff --git a/src/Record/MP4Demuxer.cpp b/src/Record/MP4Demuxer.cpp new file mode 100644 index 00000000..184035b9 --- /dev/null +++ b/src/Record/MP4Demuxer.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifdef ENABLE_MP4 +#include "MP4Demuxer.h" +#include "Util/logger.h" +#include "Extension/H265.h" +#include "Extension/H264.h" +#include "Extension/AAC.h" +using namespace toolkit; +namespace mediakit { + +MP4Demuxer::MP4Demuxer(const char *file) { + openFile(file,"rb+"); + _mov_reader = createReader(); + getAllTracks(); + _duration_ms = mov_reader_getduration(_mov_reader.get()); +} + +MP4Demuxer::~MP4Demuxer() { + _mov_reader = nullptr; + closeFile(); +} + +int MP4Demuxer::getAllTracks() { + static mov_reader_trackinfo_t s_on_track = { + [](void *param, uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) { + //onvideo + MP4Demuxer *thiz = (MP4Demuxer *)param; + thiz->onVideoTrack(track,object,width,height,extra,bytes); + }, + [](void *param, uint32_t track, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes) { + //onaudio + MP4Demuxer *thiz = (MP4Demuxer *)param; + thiz->onAudioTrack(track,object,channel_count,bit_per_sample,sample_rate,extra,bytes); + }, + [](void *param, uint32_t track, uint8_t object, const void *extra, size_t bytes) { + //onsubtitle, do nothing + } + }; + return mov_reader_getinfo(_mov_reader.get(),&s_on_track,this); +} + +#define SWITCH_CASE(obj_id) case obj_id : return #obj_id +static const char *getObjectName(int obj_id) { + switch (obj_id) { + SWITCH_CASE(MOV_OBJECT_TEXT); + SWITCH_CASE(MOV_OBJECT_MP4V); + SWITCH_CASE(MOV_OBJECT_H264); + SWITCH_CASE(MOV_OBJECT_HEVC); + SWITCH_CASE(MOV_OBJECT_AAC); + SWITCH_CASE(MOV_OBJECT_MP2V); + SWITCH_CASE(MOV_OBJECT_AAC_MAIN); + SWITCH_CASE(MOV_OBJECT_AAC_LOW); + SWITCH_CASE(MOV_OBJECT_AAC_SSR); + SWITCH_CASE(MOV_OBJECT_MP3); + SWITCH_CASE(MOV_OBJECT_MP1V); + SWITCH_CASE(MOV_OBJECT_MP1A); + SWITCH_CASE(MOV_OBJECT_JPEG); + SWITCH_CASE(MOV_OBJECT_PNG); + SWITCH_CASE(MOV_OBJECT_JPEG2000); + SWITCH_CASE(MOV_OBJECT_G719); + SWITCH_CASE(MOV_OBJECT_OPUS); + SWITCH_CASE(MOV_OBJECT_G711a); + SWITCH_CASE(MOV_OBJECT_G711u); + SWITCH_CASE(MOV_OBJECT_AV1); + default: + return "unknown mp4 object"; + } +} + + +void MP4Demuxer::onVideoTrack(uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) { + switch (object) { + case MOV_OBJECT_H264: { + auto video = std::make_shared(); + _track_to_codec.emplace(track,video); + + struct mpeg4_avc_t avc = {0}; + if (mpeg4_avc_decoder_configuration_record_load((uint8_t *) extra, bytes, &avc) > 0) { + uint8_t config[1024] = {0}; + int size = mpeg4_avc_to_nalu(&avc, config, sizeof(config)); + if (size > 0) { + video->inputFrame(std::make_shared((char *)config, size, 0, 4)); + } + } + } + break; + case MOV_OBJECT_HEVC: { + auto video = std::make_shared(); + _track_to_codec.emplace(track,video); + + struct mpeg4_hevc_t hevc = {0}; + if (mpeg4_hevc_decoder_configuration_record_load((uint8_t *) extra, bytes, &hevc) > 0) { + uint8_t config[1024] = {0}; + int size = mpeg4_hevc_to_nalu(&hevc, config, sizeof(config)); + if (size > 0) { + video->inputFrame(std::make_shared((char *) config, size, 0, 4)); + } + } + } + break; + default: + WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); + break; + } +} + +void MP4Demuxer::onAudioTrack(uint32_t track_id, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes) { + switch(object){ + case MOV_OBJECT_AAC:{ + auto audio = std::make_shared(bytes > 0 ? string((char *)extra,bytes) : ""); + _track_to_codec.emplace(track_id, audio); + } + break; + default: + WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); + break; + } +} + +int64_t MP4Demuxer::seekTo(int64_t stamp_ms) { + if(0 != mov_reader_seek(_mov_reader.get(),&stamp_ms)){ + return -1; + } + return stamp_ms; +} + +struct Context{ + MP4Demuxer *thiz; + int flags; + int64_t pts; + int64_t dts; + uint32_t track_id; + BufferRaw::Ptr buffer; +}; + +Frame::Ptr MP4Demuxer::readFrame(bool &keyFrame) { + static mov_reader_onread mov_reader_onread = [](void *param, uint32_t track_id, const void *buffer, size_t bytes, int64_t pts, int64_t dts, int flags) { + Context *ctx = (Context *) param; + ctx->pts = pts; + ctx->dts = dts; + ctx->flags = flags; + ctx->track_id = track_id; + }; + + static mov_onalloc mov_onalloc = [](void *param, int bytes) -> void * { + Context *ctx = (Context *) param; + ctx->buffer = ctx->thiz->_buffer_pool.obtain(); + ctx->buffer->setCapacity(bytes + 1); + ctx->buffer->setSize(bytes); + return ctx->buffer->data(); + }; + + Context ctx = {this, 0}; + auto ret = mov_reader_read2(_mov_reader.get(), mov_onalloc, mov_reader_onread, &ctx); + switch (ret) { + case 0 : + return nullptr; + + case 1 : { + keyFrame = ctx.flags & MOV_AV_FLAG_KEYFREAME; + return makeFrame(ctx.track_id, ctx.buffer, ctx.pts, ctx.dts); + } + + default: + WarnL << "读取mp4文件数据失败:" << ret; + return nullptr; + } +} + +template +class FrameWrapper : public Parent{ +public: + ~FrameWrapper() = default; + FrameWrapper(const Buffer::Ptr &buf, int64_t pts, int64_t dts, int prefix) : Parent(buf->data(), buf->size(), dts, pts, prefix){ + _buf = buf; + } + bool cacheAble() const override { + return true; + } +private: + Buffer::Ptr _buf; +}; + +Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int64_t pts, int64_t dts) { + auto it = _track_to_codec.find(track_id); + if (it == _track_to_codec.end()) { + return nullptr; + } + auto numBytes = buf->size(); + auto pBytes = buf->data(); + auto codec = it->second->getCodecId(); + switch (codec) { + case CodecH264 : + case CodecH265 : { + uint32_t iOffset = 0; + while (iOffset < numBytes) { + uint32_t iFrameLen; + memcpy(&iFrameLen, pBytes + iOffset, 4); + iFrameLen = ntohl(iFrameLen); + if (iFrameLen + iOffset + 4 > numBytes) { + return nullptr; + } + memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4); + iOffset += (iFrameLen + 4); + } + if (codec == CodecH264) { + return std::make_shared >(buf, pts, dts, 4); + } + return std::make_shared >(buf, pts, dts, 4); + } + case CodecAAC : + return std::make_shared >(buf, pts, dts, 0); + default: + return nullptr; + } +} + +vector MP4Demuxer::getTracks(bool trackReady) const { + vector ret; + for (auto &pr : _track_to_codec) { + if(trackReady && !pr.second->ready()){ + continue; + } + ret.push_back(pr.second); + } + return std::move(ret); +} + +uint64_t MP4Demuxer::getDurationMS() const { + return _duration_ms; +} + +}//namespace mediakit +#endif// ENABLE_MP4 \ No newline at end of file diff --git a/src/Record/MP4Demuxer.h b/src/Record/MP4Demuxer.h new file mode 100644 index 00000000..3d415db2 --- /dev/null +++ b/src/Record/MP4Demuxer.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_MP4DEMUXER_H +#define ZLMEDIAKIT_MP4DEMUXER_H +#ifdef ENABLE_MP4 +#include "MP4.h" +#include "Extension/Track.h" +#include "Util/ResourcePool.h" +namespace mediakit { + +class MP4Demuxer : public MP4File, public TrackSource{ +public: + typedef std::shared_ptr Ptr; + MP4Demuxer(const char *file); + ~MP4Demuxer() override; + int64_t seekTo(int64_t stamp_ms); + Frame::Ptr readFrame(bool &keyFrame); + vector getTracks(bool trackReady) const override ; + uint64_t getDurationMS() const; +private: + int getAllTracks(); + void onVideoTrack(uint32_t track_id, uint8_t object, int width, int height, const void* extra, size_t bytes); + void onAudioTrack(uint32_t track_id, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void* extra, size_t bytes); + Frame::Ptr makeFrame(uint32_t track_id, const Buffer::Ptr &buf,int64_t pts, int64_t dts); +private: + MP4File::Reader _mov_reader; + uint64_t _duration_ms = 0; + map _track_to_codec; + ResourcePool _buffer_pool; +}; + + +}//namespace mediakit +#endif//ENABLE_MP4 +#endif //ZLMEDIAKIT_MP4DEMUXER_H diff --git a/src/Record/MP4Muxer.cpp b/src/Record/MP4Muxer.cpp index a8dd967a..2eb5436a 100644 --- a/src/Record/MP4Muxer.cpp +++ b/src/Record/MP4Muxer.cpp @@ -1,76 +1,42 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ -#ifdef ENABLE_MP4RECORD - +#ifdef ENABLE_MP4 #include "MP4Muxer.h" #include "Util/File.h" -#include "Common/config.h" - namespace mediakit{ -#if defined(_WIN32) || defined(_WIN64) - #define fseek64 _fseeki64 - #define ftell64 _ftelli64 -#else - #define fseek64 fseek - #define ftell64 ftell -#endif - -void MP4MuxerBase::init(int flags) { - static struct mov_buffer_t s_io = { - [](void* ctx, void* data, uint64_t bytes) { - MP4MuxerBase *thiz = (MP4MuxerBase *)ctx; - return thiz->onRead(data,bytes); - }, - [](void* ctx, const void* data, uint64_t bytes){ - MP4MuxerBase *thiz = (MP4MuxerBase *)ctx; - return thiz->onWrite(data,bytes); - }, - [](void* ctx, uint64_t offset) { - MP4MuxerBase *thiz = (MP4MuxerBase *)ctx; - return thiz->onSeek(offset); - }, - [](void* ctx){ - MP4MuxerBase *thiz = (MP4MuxerBase *)ctx; - return thiz->onTell(); - } - }; - _mov_writter.reset(mov_writer_create(&s_io,this,flags),[](mov_writer_t *ptr){ - if(ptr){ - mov_writer_destroy(ptr); - } - }); +MP4Muxer::MP4Muxer(const char *file) { + _file_name = file; + openMP4(); +} + +MP4Muxer::~MP4Muxer() { + closeMP4(); +} + +void MP4Muxer::openMP4(){ + closeMP4(); + openFile(_file_name.data(), "wb+"); + _mov_writter = createWriter(); +} +void MP4Muxer::closeMP4(){ + _mov_writter = nullptr; + closeFile(); } -/////////////////////////////////// void MP4Muxer::resetTracks() { _codec_to_trackid.clear(); _started = false; _have_video = false; + openMP4(); } void MP4Muxer::inputFrame(const Frame::Ptr &frame) { @@ -192,7 +158,7 @@ void MP4Muxer::addTrack(const Track::Ptr &track) { return; } - struct mpeg4_avc_t avc = {0}; + struct mpeg4_avc_t avc = {0}; string sps_pps = string("\x00\x00\x00\x01", 4) + h264_track->getSps() + string("\x00\x00\x00\x01", 4) + h264_track->getPps(); h264_annexbtomp4(&avc, sps_pps.data(), sps_pps.size(), NULL, 0, NULL, NULL); @@ -230,7 +196,7 @@ void MP4Muxer::addTrack(const Track::Ptr &track) { return; } - struct mpeg4_hevc_t hevc = {0}; + struct mpeg4_hevc_t hevc = {0}; string vps_sps_pps = string("\x00\x00\x00\x01", 4) + h265_track->getVps() + string("\x00\x00\x00\x01", 4) + h265_track->getSps() + string("\x00\x00\x00\x01", 4) + h265_track->getPps(); @@ -263,70 +229,5 @@ void MP4Muxer::addTrack(const Track::Ptr &track) { } } -MP4MuxerFile::MP4MuxerFile(const char *file){ - _file_name = file; - openFile(file); -} - -void MP4MuxerFile::openFile(const char *file) { - //创建文件 - auto fp = File::createfile_file(file,"wb+"); - if(!fp){ - throw std::runtime_error(string("打开文件失败:") + file); - } - - GET_CONFIG(uint32_t,mp4BufSize,Record::kFileBufSize); - - //新建文件io缓存 - std::shared_ptr file_buf(new char[mp4BufSize],[](char *ptr){ - if(ptr){ - delete [] ptr; - } - }); - - if(file_buf){ - //设置文件io缓存 - setvbuf(fp, file_buf.get(), _IOFBF, mp4BufSize); - } - - //创建智能指针 - _file.reset(fp,[file_buf](FILE *fp) { - fclose(fp); - }); - - GET_CONFIG(bool, mp4FastStart, Record::kFastStart); - init(mp4FastStart ? MOV_FLAG_FASTSTART : 0); -} - -MP4MuxerFile::~MP4MuxerFile() { - _mov_writter = nullptr; -} - -int MP4MuxerFile::onRead(void *data, uint64_t bytes) { - if (bytes == fread(data, 1, bytes, _file.get())){ - return 0; - } - return 0 != ferror(_file.get()) ? ferror(_file.get()) : -1 /*EOF*/; -} - -int MP4MuxerFile::onWrite(const void *data, uint64_t bytes) { - return bytes == fwrite(data, 1, bytes, _file.get()) ? 0 : ferror(_file.get()); -} - -int MP4MuxerFile::onSeek(uint64_t offset) { - return fseek64(_file.get(), offset, SEEK_SET); -} - -uint64_t MP4MuxerFile::onTell() { - return ftell64(_file.get()); -} - - -void MP4MuxerFile::resetTracks(){ - MP4Muxer::resetTracks(); - openFile(_file_name.data()); -} - }//namespace mediakit - -#endif//#ifdef ENABLE_MP4RECORD +#endif//#ifdef ENABLE_MP4 diff --git a/src/Record/MP4Muxer.h b/src/Record/MP4Muxer.h index 3285107e..7975bf2f 100644 --- a/src/Record/MP4Muxer.h +++ b/src/Record/MP4Muxer.h @@ -1,66 +1,31 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_MP4MUXER_H #define ZLMEDIAKIT_MP4MUXER_H -#ifdef ENABLE_MP4RECORD +#ifdef ENABLE_MP4 #include "Common/MediaSink.h" -#include "mov-writer.h" -#include "mpeg4-hevc.h" -#include "mpeg4-avc.h" -#include "mpeg4-aac.h" -#include "mov-buffer.h" -#include "mov-format.h" #include "Extension/AAC.h" #include "Extension/H264.h" #include "Extension/H265.h" #include "Common/Stamp.h" +#include "MP4.h" namespace mediakit{ -class MP4MuxerBase{ +class MP4Muxer : public MediaSinkInterface, public MP4File{ public: - MP4MuxerBase() = default; - virtual ~MP4MuxerBase() = default; -protected: - virtual int onRead(void* data, uint64_t bytes) = 0; - virtual int onWrite(const void* data, uint64_t bytes) = 0; - virtual int onSeek( uint64_t offset) = 0; - virtual uint64_t onTell() = 0; - void init(int flags); -protected: - std::shared_ptr _mov_writter; -}; - -class MP4Muxer : public MediaSinkInterface , public MP4MuxerBase{ -public: - MP4Muxer() = default; - ~MP4Muxer() override = default; + MP4Muxer(const char *file); + ~MP4Muxer() override; /** * 添加已经ready状态的track @@ -75,6 +40,11 @@ public: * 重置所有track */ void resetTracks() override ; + +private: + void openMP4(); + void closeMP4(); + private: struct track_info{ int track_id = -1; @@ -84,28 +54,10 @@ private: List _frameCached; bool _started = false; bool _have_video = false; -}; - - -class MP4MuxerFile : public MP4Muxer { -public: - typedef std::shared_ptr Ptr; - MP4MuxerFile(const char *file); - ~MP4MuxerFile(); - void resetTracks() override ; -protected: - int onRead(void* data, uint64_t bytes) override; - int onWrite(const void* data, uint64_t bytes) override; - int onSeek( uint64_t offset) override; - uint64_t onTell() override ; - void openFile(const char *file); -private: - std::shared_ptr _file; + MP4File::Writer _mov_writter; string _file_name; }; }//namespace mediakit - -#endif//#ifdef ENABLE_MP4RECORD - +#endif//#ifdef ENABLE_MP4 #endif //ZLMEDIAKIT_MP4MUXER_H diff --git a/src/Record/MP4Reader.cpp b/src/Record/MP4Reader.cpp index 3fd552b4..025a9c39 100644 --- a/src/Record/MP4Reader.cpp +++ b/src/Record/MP4Reader.cpp @@ -1,372 +1,155 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ +#ifdef ENABLE_MP4 #include "MP4Reader.h" #include "Common/config.h" -#include "Util/mini.h" -#include "Util/File.h" -#include "Http/HttpSession.h" -#include "Extension/AAC.h" -#include "Extension/H264.h" #include "Thread/WorkThreadPool.h" - using namespace toolkit; - namespace mediakit { -#ifdef ENABLE_MP4V2 MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath ) { - _poller = WorkThreadPool::Instance().getPoller(); + _poller = WorkThreadPool::Instance().getPoller(); auto strFileName = filePath; if(strFileName.empty()){ - GET_CONFIG(string,recordPath,Record::kFilePath); + GET_CONFIG(string,recordPath,Record::kFilePath); GET_CONFIG(bool,enableVhost,General::kEnableVhost); if(enableVhost){ strFileName = strVhost + "/" + strApp + "/" + strId; }else{ strFileName = strApp + "/" + strId; } - strFileName = File::absolutePath(strFileName,recordPath); + strFileName = File::absolutePath(strFileName,recordPath); } - _hMP4File = MP4Read(strFileName.data()); - if(_hMP4File == MP4_INVALID_FILE_HANDLE){ - throw runtime_error(StrPrinter << "打开MP4文件失败:" << strFileName << endl); - } - _video_trId = MP4FindTrackId(_hMP4File, 0, MP4_VIDEO_TRACK_TYPE, 0); - if(_video_trId != MP4_INVALID_TRACK_ID){ - if(strcmp(MP4GetTrackMediaDataName(_hMP4File, _video_trId),"avc1") ==0){ - auto _video_timescale = MP4GetTrackTimeScale(_hMP4File, _video_trId); - auto _video_duration = MP4GetTrackDuration(_hMP4File, _video_trId); - _video_num_samples = MP4GetTrackNumberOfSamples(_hMP4File, _video_trId); - _video_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File, _video_trId); - _video_width = MP4GetTrackVideoWidth(_hMP4File, _video_trId); - _video_height = MP4GetTrackVideoHeight(_hMP4File, _video_trId); - _video_framerate = MP4GetTrackVideoFrameRate(_hMP4File, _video_trId); - _pcVideoSample = std::shared_ptr (new uint8_t[_video_sample_max_size],[](uint8_t *ptr){ - delete [] ptr; - }); - uint8_t **seqheader; - uint8_t **pictheader; - uint32_t *pictheadersize; - uint32_t *seqheadersize; - uint32_t ix; - if(MP4GetTrackH264SeqPictHeaders(_hMP4File, _video_trId, &seqheader, &seqheadersize, &pictheader, &pictheadersize)){ - for (ix = 0; seqheadersize[ix] != 0; ix++) { - _strSps.assign((char *)(seqheader[ix]), seqheadersize[ix]); - float framerate; - getAVCInfo(_strSps, (int &)_video_width, (int &)_video_height, framerate); - _video_framerate = framerate; - _strSps = string("\x0\x0\x0\x1",4) + _strSps; - MP4Free(seqheader[ix]); - } - MP4Free(seqheader); - MP4Free(seqheadersize); - for (ix = 0; pictheadersize[ix] != 0; ix++) { - _strPps.assign("\x0\x0\x0\x1",4); - _strPps.append((char *)(pictheader[ix]), pictheadersize[ix]); - MP4Free(pictheader[ix]); - } - MP4Free(pictheader); - MP4Free(pictheadersize); - } - _video_ms = 1000.0 * _video_duration / _video_timescale; - /*InfoL << "\r\n" - << _video_ms << "\r\n" - << _video_num_samples << "\r\n" - << _video_framerate << "\r\n" - << _video_width << "\r\n" - << _video_height << "\r\n";*/ - } else { - //如果不是h264,则忽略 - _video_trId = MP4_INVALID_TRACK_ID; - } - } - - - _audio_trId = MP4FindTrackId(_hMP4File, 0, MP4_AUDIO_TRACK_TYPE, 0); - if (_audio_trId != MP4_INVALID_TRACK_ID) { - if (strcmp(MP4GetTrackMediaDataName(_hMP4File, _audio_trId), "mp4a") == 0) { - _audio_sample_rate = MP4GetTrackTimeScale(_hMP4File, _audio_trId); - auto _audio_duration = MP4GetTrackDuration(_hMP4File, _audio_trId); - _audio_num_samples = MP4GetTrackNumberOfSamples(_hMP4File,_audio_trId); - _audio_num_channels = MP4GetTrackAudioChannels(_hMP4File, _audio_trId); - _audio_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File,_audio_trId); - uint8_t *ppConfig; - uint32_t pConfigSize; - if(MP4GetTrackESConfiguration(_hMP4File,_audio_trId,&ppConfig,&pConfigSize)){ - _strAacCfg.assign((char *)ppConfig, pConfigSize); - makeAdtsHeader(_strAacCfg, _adts); - writeAdtsHeader(_adts,_adts.buffer); - getAACInfo(_adts, (int &)_audio_sample_rate, (int &)_audio_num_channels); - MP4Free(ppConfig); - } - _audio_ms = 1000.0 * _audio_duration / _audio_sample_rate; - /*InfoL << "\r\n" - << _audio_ms << "\r\n" - << _audio_num_samples << "\r\n" - << _audio_num_channels << "\r\n" - << _audio_sample_rate << "\r\n";*/ - }else{ - _audio_trId = MP4_INVALID_TRACK_ID; - } - } - if(_audio_trId == MP4_INVALID_TRACK_ID && _video_trId == MP4_INVALID_TRACK_ID){ - MP4Close(_hMP4File); - _hMP4File = MP4_INVALID_FILE_HANDLE; - throw runtime_error(StrPrinter << "该MP4文件音视频格式不支持:" << strFileName << endl); - } - - _iDuration = MAX(_video_ms,_audio_ms); - _mediaMuxer.reset(new MultiMediaSourceMuxer(strVhost, strApp, strId, _iDuration / 1000.0, true, true, false, false)); - if (_audio_trId != MP4_INVALID_TRACK_ID) { - AACTrack::Ptr track = std::make_shared(_strAacCfg); - _mediaMuxer->addTrack(track); - } - - if (_video_trId != MP4_INVALID_TRACK_ID) { - H264Track::Ptr track = std::make_shared(_strSps,_strPps); - _mediaMuxer->addTrack(track); - } - + _demuxer = std::make_shared(strFileName.data()); + _mediaMuxer.reset(new MultiMediaSourceMuxer(strVhost, strApp, strId, _demuxer->getDurationMS() / 1000.0, true, true, false, false)); + auto tracks = _demuxer->getTracks(false); + if(tracks.empty()){ + throw std::runtime_error(StrPrinter << "该mp4文件没有有效的track:" << strFileName); + } + for(auto &track : tracks){ + _mediaMuxer->addTrack(track); + if(track->getTrackType() == TrackVideo){ + _have_video = true; + } + } //添加完毕所有track,防止单track情况下最大等待3秒 _mediaMuxer->addTrackCompleted(); } +bool MP4Reader::readSample() { + bool keyFrame = false; + bool eof = false; + while (true) { + auto frame = _demuxer->readFrame(keyFrame); + if (!frame) { + eof = true; + break; + } + _mediaMuxer->inputFrame(frame); + if (frame->dts() > getCurrentStamp()) { + break; + } + } -MP4Reader::~MP4Reader() { - if (_hMP4File != MP4_INVALID_FILE_HANDLE) { - MP4Close(_hMP4File); - _hMP4File = MP4_INVALID_FILE_HANDLE; - } + GET_CONFIG(bool, fileRepeat, Record::kFileRepeat); + if (eof && fileRepeat) { + //需要从头开始看 + seekTo(0); + return true; + } + + return !eof; } - void MP4Reader::startReadMP4() { - auto strongSelf = shared_from_this(); - GET_CONFIG(uint32_t,sampleMS,Record::kSampleMS); + GET_CONFIG(uint32_t, sampleMS, Record::kSampleMS); + auto strongSelf = shared_from_this(); + _mediaMuxer->setMediaListener(strongSelf); - _timer = std::make_shared(sampleMS / 1000.0f,[strongSelf](){ - return strongSelf->readSample(0,false); - }, _poller); + //先获取关键帧 + seekTo(0); + //读sampleMS毫秒的数据用于产生MediaSource + setCurrentStamp(getCurrentStamp() + sampleMS); + readSample(); - //先读sampleMS毫秒的数据用于产生MediaSouce - readSample(sampleMS, false); - _mediaMuxer->setListener(strongSelf); + //启动定时器 + _timer = std::make_shared(sampleMS / 1000.0f, [strongSelf]() { + lock_guard lck(strongSelf->_mtx); + return strongSelf->readSample(); + }, _poller); } - bool MP4Reader::seekTo(MediaSource &sender,uint32_t ui32Stamp){ - seek(ui32Stamp); - return true; + +uint32_t MP4Reader::getCurrentStamp() { + return _seek_to + _seek_ticker.elapsedTime(); } + +void MP4Reader::setCurrentStamp(uint32_t ui32Stamp){ + _seek_to = ui32Stamp; + _seek_ticker.resetTime(); + _mediaMuxer->setTimeStamp(ui32Stamp); +} + +bool MP4Reader::seekTo(MediaSource &sender,uint32_t ui32Stamp){ + return seekTo(ui32Stamp); +} + +bool MP4Reader::seekTo(uint32_t ui32Stamp){ + lock_guard lck(_mtx); + if (ui32Stamp > _demuxer->getDurationMS()) { + //超过文件长度 + return false; + } + auto stamp = _demuxer->seekTo(ui32Stamp); + if(stamp == -1){ + //seek失败 + return false; + } + + if(!_have_video){ + //没有视频,不需要搜索关键帧 + //设置当前时间戳 + setCurrentStamp(stamp); + return true; + } + //搜索到下一帧关键帧 + bool keyFrame = false; + while (true) { + auto frame = _demuxer->readFrame(keyFrame); + if(!frame){ + //文件读完了都未找到下一帧关键帧 + return false; + } + if(keyFrame || frame->keyFrame() || frame->configFrame()){ + //定位到key帧 + _mediaMuxer->inputFrame(frame); + //设置当前时间戳 + setCurrentStamp(frame->dts()); + return true; + } + } +} + bool MP4Reader::close(MediaSource &sender,bool force){ if(!_mediaMuxer || (!force && _mediaMuxer->totalReaderCount())){ return false; } - _timer.reset(); + _timer.reset(); WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; return true; } -void MP4Reader::onNoneReader(MediaSource &sender) { - if(!_mediaMuxer || _mediaMuxer->totalReaderCount()){ - return; - } - MediaSourceEvent::onNoneReader(sender); -} - int MP4Reader::totalReaderCount(MediaSource &sender) { - return _mediaMuxer ? _mediaMuxer->totalReaderCount() : sender.readerCount(); + return _mediaMuxer ? _mediaMuxer->totalReaderCount() : sender.readerCount(); } -bool MP4Reader::readSample(int iTimeInc,bool justSeekSyncFrame) { - TimeTicker(); - lock_guard lck(_mtx); - auto bFlag0 = readVideoSample(iTimeInc,justSeekSyncFrame);//数据没读完 - auto bFlag1 = readAudioSample(iTimeInc,justSeekSyncFrame);//数据没读完 - auto bFlag2 = _mediaMuxer->totalReaderCount() > 0;//读取者大于0 - if((bFlag0 || bFlag1) && bFlag2){ - _alive.resetTime(); - } - //重头开始循环读取 - GET_CONFIG(bool,fileRepeat,Record::kFileRepeat); - if (fileRepeat && !bFlag0 && !bFlag1) { - seek(0); - } - //DebugL << "alive ..."; - //3秒延时关闭 - return _alive.elapsedTime() < 3 * 1000; -} -inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) { - if (_video_trId != MP4_INVALID_TRACK_ID) { - auto iNextSample = getVideoSampleId(iTimeInc); - MP4SampleId iIdx = _video_current; - for (; iIdx < iNextSample; iIdx++) { - uint8_t *pBytes = _pcVideoSample.get(); - uint32_t numBytes = _video_sample_max_size; - MP4Duration pRenderingOffset; - if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){ - if (!justSeekSyncFrame) { - uint32_t dts = (double) _video_ms * iIdx / _video_num_samples; - uint32_t pts = dts + pRenderingOffset / 90; - uint32_t iOffset = 0; - while (iOffset < numBytes) { - uint32_t iFrameLen; - memcpy(&iFrameLen,pBytes + iOffset,4); - iFrameLen = ntohl(iFrameLen); - if(iFrameLen + iOffset + 4> numBytes){ - break; - } - memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4); - writeH264(pBytes + iOffset, iFrameLen + 4, dts, pts); - iOffset += (iFrameLen + 4); - } - }else if(_bSyncSample){ - break; - } - }else{ - ErrorL << "读取视频失败:" << iIdx + 1; - } - } - _video_current = iIdx; - return _video_current < _video_num_samples; - } - return false; -} - -inline bool MP4Reader::readAudioSample(int iTimeInc,bool justSeekSyncFrame) { - if (_audio_trId != MP4_INVALID_TRACK_ID) { - auto iNextSample = getAudioSampleId(iTimeInc); - for (auto i = _audio_current; i < iNextSample; i++) { - uint32_t numBytes = _audio_sample_max_size; - uint8_t *pBytes = _adts.buffer + 7; - if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){ - if (!justSeekSyncFrame) { - uint32_t dts = (double) _audio_ms * i / _audio_num_samples; - _adts.aac_frame_length = 7 + numBytes; - writeAdtsHeader(_adts, _adts.buffer); - writeAAC(_adts.buffer, _adts.aac_frame_length, dts); - } - }else{ - ErrorL << "读取音频失败:" << i+ 1; - } - } - _audio_current = iNextSample; - return _audio_current < _audio_num_samples; - } - return false; -} - -inline void MP4Reader::writeH264(uint8_t *pucData,int iLen,uint32_t dts,uint32_t pts) { - _mediaMuxer->inputFrame(std::make_shared((char*)pucData,iLen,dts,pts)); -} - -inline void MP4Reader::writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp) { - _mediaMuxer->inputFrame(std::make_shared((char*)pucData,iLen,uiStamp)); -} - -inline MP4SampleId MP4Reader::getVideoSampleId(int iTimeInc ) { - MP4SampleId video_current = (double)_video_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _video_ms; - video_current = MAX(0,MIN(_video_num_samples, video_current)); - return video_current; - -} - -inline MP4SampleId MP4Reader::getAudioSampleId(int iTimeInc) { - MP4SampleId audio_current = (double)_audio_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _audio_ms ; - audio_current = MAX(0,MIN(_audio_num_samples,audio_current)); - return audio_current; -} -inline void MP4Reader::setSeekTime(uint32_t iSeekTime){ - _iSeekTime = MAX(0, MIN(iSeekTime,_iDuration)); - _ticker.resetTime(); - if (_audio_trId != MP4_INVALID_TRACK_ID) { - _audio_current = getAudioSampleId(); - } - if (_video_trId != MP4_INVALID_TRACK_ID) { - _video_current = getVideoSampleId(); - } -} - -inline uint32_t MP4Reader::getVideoCurrentTime(){ - return (double)_video_current * _video_ms /_video_num_samples; -} -void MP4Reader::seek(uint32_t iSeekTime,bool bReStart){ - lock_guard lck(_mtx); - if(iSeekTime == 0 || _video_trId == MP4_INVALID_TRACK_ID){ - setSeekTime(iSeekTime); - }else{ - setSeekTime(iSeekTime - 5000); - //在之后的10秒查找关键帧 - readVideoSample(10000, true); - if (_bSyncSample) { - //找到关键帧 - auto iIdr = _video_current; - setSeekTime(getVideoCurrentTime()); - _video_current = iIdr; - }else{ - //未找到关键帧 - setSeekTime(iSeekTime); - } - } - _mediaMuxer->setTimeStamp(_iSeekTime); - - if(bReStart){ - _timer.reset(); - startReadMP4(); - } -} - -#endif //ENABLE_MP4V2 - - - -MediaSource::Ptr MP4Reader::onMakeMediaSource(const string &strSchema, - const string &strVhost, - const string &strApp, - const string &strId, - const string &filePath, - bool checkApp ){ -#ifdef ENABLE_MP4V2 - GET_CONFIG(string,appName,Record::kAppName); - if (checkApp && strApp != appName) { - return nullptr; - } - try { - MP4Reader::Ptr pReader(new MP4Reader(strVhost,strApp, strId,filePath)); - pReader->startReadMP4(); - return MediaSource::find(strSchema,strVhost,strApp, strId, false); - } catch (std::exception &ex) { - WarnL << ex.what(); - return nullptr; - } -#else - return nullptr; -#endif //ENABLE_MP4V2 -} - - - } /* namespace mediakit */ +#endif //ENABLE_MP4 \ No newline at end of file diff --git a/src/Record/MP4Reader.h b/src/Record/MP4Reader.h index 30487c41..bb7e365e 100644 --- a/src/Record/MP4Reader.h +++ b/src/Record/MP4Reader.h @@ -1,132 +1,61 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_MEDIAFILE_MEDIAREADER_H_ #define SRC_MEDIAFILE_MEDIAREADER_H_ - +#ifdef ENABLE_MP4 +#include "MP4Demuxer.h" #include "Common/MultiMediaSourceMuxer.h" -#include "Extension/AAC.h" - -#ifdef ENABLE_MP4V2 -#include -#endif //ENABLE_MP4V2 using namespace toolkit; - namespace mediakit { class MP4Reader : public std::enable_shared_from_this ,public MediaSourceEvent{ public: - typedef std::shared_ptr Ptr; - virtual ~MP4Reader(); + typedef std::shared_ptr Ptr; + virtual ~MP4Reader() = default; - /** - * 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource - * @param strVhost 虚拟主机 - * @param strApp 应用名 - * @param strId 流id - * @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件 - */ - MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath = ""); - /** - * 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有, - * 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有) - */ - void startReadMP4(); - - /** - * 自动生成MP4Reader对象然后查找相关的MediaSource对象 - * @param strSchema 协议名 - * @param strVhost 虚拟主机 - * @param strApp 应用名 - * @param strId 流id - * @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件 - * @param checkApp 是否检查app,防止服务器上文件被乱访问 - * @return MediaSource - */ - static MediaSource::Ptr onMakeMediaSource(const string &strSchema, - const string &strVhost, - const string &strApp, - const string &strId, - const string &filePath = "", - bool checkApp = true); + /** + * 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource + * @param strVhost 虚拟主机 + * @param strApp 应用名 + * @param strId 流id + * @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件 + */ + MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath = ""); + /** + * 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有, + * 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有) + */ + void startReadMP4(); private: - //MediaSourceEvent override - bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override; - bool close(MediaSource &sender,bool force) override; - void onNoneReader(MediaSource &sender) override; - int totalReaderCount(MediaSource &sender) override; -#ifdef ENABLE_MP4V2 - void seek(uint32_t iSeekTime,bool bReStart = true); - inline void setSeekTime(uint32_t iSeekTime); - inline uint32_t getVideoCurrentTime(); - inline MP4SampleId getVideoSampleId(int iTimeInc = 0); - inline MP4SampleId getAudioSampleId(int iTimeInc = 0); - bool readSample(int iTimeInc, bool justSeekSyncFrame); - inline bool readVideoSample(int iTimeInc,bool justSeekSyncFrame); - inline bool readAudioSample(int iTimeInc,bool justSeekSyncFrame); - inline void writeH264(uint8_t *pucData,int iLen,uint32_t dts,uint32_t pts); - inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp); + //MediaSourceEvent override + bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override; + bool close(MediaSource &sender,bool force) override; + int totalReaderCount(MediaSource &sender) override; + + bool readSample(); + uint32_t getCurrentStamp(); + void setCurrentStamp(uint32_t ui32Stamp); + bool seekTo(uint32_t ui32Stamp); private: - MP4FileHandle _hMP4File = MP4_INVALID_FILE_HANDLE; - MP4TrackId _video_trId = MP4_INVALID_TRACK_ID; - uint32_t _video_ms = 0; - uint32_t _video_num_samples = 0; - uint32_t _video_sample_max_size = 0; - uint32_t _video_width = 0; - uint32_t _video_height = 0; - uint32_t _video_framerate = 0; - string _strPps; - string _strSps; - bool _bSyncSample = false; - - MP4TrackId _audio_trId = MP4_INVALID_TRACK_ID; - uint32_t _audio_ms = 0; - uint32_t _audio_num_samples = 0; - uint32_t _audio_sample_max_size = 0; - uint32_t _audio_sample_rate = 0; - uint32_t _audio_num_channels = 0; - string _strAacCfg; - AACFrame _adts; - - int _iDuration = 0; - MultiMediaSourceMuxer::Ptr _mediaMuxer; - MP4SampleId _video_current = 0; - MP4SampleId _audio_current = 0; - std::shared_ptr _pcVideoSample; - - int _iSeekTime = 0 ; - Ticker _ticker; - Ticker _alive; - recursive_mutex _mtx; - Timer::Ptr _timer; - EventPoller::Ptr _poller; -#endif //ENABLE_MP4V2 + recursive_mutex _mtx; + MultiMediaSourceMuxer::Ptr _mediaMuxer; + uint32_t _seek_to; + Ticker _seek_ticker; + Timer::Ptr _timer; + EventPoller::Ptr _poller; + MP4Demuxer::Ptr _demuxer; + bool _have_video = false; }; } /* namespace mediakit */ - +#endif //ENABLE_MP4 #endif /* SRC_MEDIAFILE_MEDIAREADER_H_ */ diff --git a/src/Record/MP4Recorder.cpp b/src/Record/MP4Recorder.cpp index a92f3fde..bf0966a9 100644 --- a/src/Record/MP4Recorder.cpp +++ b/src/Record/MP4Recorder.cpp @@ -1,30 +1,14 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ -#ifdef ENABLE_MP4RECORD +#ifdef ENABLE_MP4 #include #include #include "Common/config.h" @@ -36,31 +20,31 @@ using namespace toolkit; namespace mediakit { MP4Recorder::MP4Recorder(const string& strPath, - const string &strVhost, - const string &strApp, - const string &strStreamId) { - _strPath = strPath; - /////record 业务逻辑////// - _info.strAppName = strApp; - _info.strStreamId = strStreamId; - _info.strVhost = strVhost; - _info.strFolder = strPath; + const string &strVhost, + const string &strApp, + const string &strStreamId) { + _strPath = strPath; + /////record 业务逻辑////// + _info.strAppName = strApp; + _info.strStreamId = strStreamId; + _info.strVhost = strVhost; + _info.strFolder = strPath; } MP4Recorder::~MP4Recorder() { - closeFile(); + closeFile(); } void MP4Recorder::createFile() { - closeFile(); - auto strDate = getTimeStr("%Y-%m-%d"); - auto strTime = getTimeStr("%H-%M-%S"); - auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4"; - auto strFile = _strPath + strDate + "/" + strTime + ".mp4"; + closeFile(); + auto strDate = getTimeStr("%Y-%m-%d"); + auto strTime = getTimeStr("%H-%M-%S"); + auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4"; + auto strFile = _strPath + strDate + "/" + strTime + ".mp4"; - /////record 业务逻辑////// - _info.ui64StartedTime = ::time(NULL); - _info.strFileName = strTime + ".mp4"; - _info.strFilePath = strFile; + /////record 业务逻辑////// + _info.ui64StartedTime = ::time(NULL); + _info.strFileName = strTime + ".mp4"; + _info.strFilePath = strFile; GET_CONFIG(string,appName,Record::kAppName); _info.strUrl = appName + "/" + _info.strAppName + "/" @@ -68,81 +52,81 @@ void MP4Recorder::createFile() { + strDate + "/" + strTime + ".mp4"; - try { - _muxer = std::make_shared(strFileTmp.data()); - for(auto &track :_tracks){ + try { + _muxer = std::make_shared(strFileTmp.data()); + for(auto &track :_tracks){ //添加track _muxer->addTrack(track); - } - _strFileTmp = strFileTmp; - _strFile = strFile; - _createFileTicker.resetTime(); - }catch(std::exception &ex) { - WarnL << ex.what(); - } + } + _strFileTmp = strFileTmp; + _strFile = strFile; + _createFileTicker.resetTime(); + }catch(std::exception &ex) { + WarnL << ex.what(); + } } void MP4Recorder::asyncClose() { - auto muxer = _muxer; - auto strFileTmp = _strFileTmp; - auto strFile = _strFile; - auto info = _info; - WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() { - //获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间 - const_cast(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime; - //关闭mp4非常耗时,所以要放在后台线程执行 - const_cast(muxer).reset(); - //临时文件名改成正式文件名,防止mp4未完成时被访问 - rename(strFileTmp.data(),strFile.data()); - //获取文件大小 - struct stat fileData; - stat(strFile.data(), &fileData); - const_cast(info).ui64FileSize = fileData.st_size; - /////record 业务逻辑////// - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info); - }); + auto muxer = _muxer; + auto strFileTmp = _strFileTmp; + auto strFile = _strFile; + auto info = _info; + WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() { + //获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间 + const_cast(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime; + //关闭mp4非常耗时,所以要放在后台线程执行 + const_cast(muxer).reset(); + //临时文件名改成正式文件名,防止mp4未完成时被访问 + rename(strFileTmp.data(),strFile.data()); + //获取文件大小 + struct stat fileData; + stat(strFile.data(), &fileData); + const_cast(info).ui64FileSize = fileData.st_size; + /////record 业务逻辑////// + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info); + }); } void MP4Recorder::closeFile() { - if (_muxer) { - asyncClose(); - _muxer = nullptr; - } + if (_muxer) { + asyncClose(); + _muxer = nullptr; + } } void MP4Recorder::inputFrame(const Frame::Ptr &frame) { - GET_CONFIG(uint32_t,recordSec,Record::kFileSecond); - if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) && - (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){ - //成立条件 - //1、_muxer为空 - //2、到了切片时间,并且只有音频 - //3、到了切片时间,有视频并且遇到视频的关键帧 - createFile(); - } + GET_CONFIG(uint32_t,recordSec,Record::kFileSecond); + if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) && + (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){ + //成立条件 + //1、_muxer为空 + //2、到了切片时间,并且只有音频 + //3、到了切片时间,有视频并且遇到视频的关键帧 + createFile(); + } - if(_muxer){ - //生成mp4文件 - _muxer->inputFrame(frame); - } + if(_muxer){ + //生成mp4文件 + _muxer->inputFrame(frame); + } } void MP4Recorder::addTrack(const Track::Ptr & track){ - //保存所有的track,为创建MP4MuxerFile做准备 - _tracks.emplace_back(track); - if(track->getTrackType() == TrackVideo){ - _haveVideo = true; - } + //保存所有的track,为创建MP4MuxerFile做准备 + _tracks.emplace_back(track); + if(track->getTrackType() == TrackVideo){ + _haveVideo = true; + } } void MP4Recorder::resetTracks() { - closeFile(); - _tracks.clear(); - _haveVideo = false; - _createFileTicker.resetTime(); + closeFile(); + _tracks.clear(); + _haveVideo = false; + _createFileTicker.resetTime(); } } /* namespace mediakit */ -#endif //ENABLE_MP4RECORD +#endif //ENABLE_MP4 diff --git a/src/Record/MP4Recorder.h b/src/Record/MP4Recorder.h index 838f2507..60f3c561 100644 --- a/src/Record/MP4Recorder.h +++ b/src/Record/MP4Recorder.h @@ -1,27 +1,11 @@ - /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef MP4MAKER_H_ @@ -42,38 +26,38 @@ namespace mediakit { class MP4Info { public: - time_t ui64StartedTime; //GMT标准时间,单位秒 - time_t ui64TimeLen;//录像长度,单位秒 - off_t ui64FileSize;//文件大小,单位BYTE - string strFilePath;//文件路径 - string strFileName;//文件名称 - string strFolder;//文件夹路径 - string strUrl;//播放路径 - string strAppName;//应用名称 - string strStreamId;//流ID - string strVhost;//vhost + time_t ui64StartedTime; //GMT标准时间,单位秒 + time_t ui64TimeLen;//录像长度,单位秒 + off_t ui64FileSize;//文件大小,单位BYTE + string strFilePath;//文件路径 + string strFileName;//文件名称 + string strFolder;//文件夹路径 + string strUrl;//播放路径 + string strAppName;//应用名称 + string strStreamId;//流ID + string strVhost;//vhost }; -#ifdef ENABLE_MP4RECORD +#ifdef ENABLE_MP4 class MP4Recorder : public MediaSinkInterface{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - MP4Recorder(const string &strPath, - const string &strVhost, - const string &strApp, - const string &strStreamId); - virtual ~MP4Recorder(); + MP4Recorder(const string &strPath, + const string &strVhost, + const string &strApp, + const string &strStreamId); + virtual ~MP4Recorder(); - /** - * 重置所有Track - */ - void resetTracks() override; + /** + * 重置所有Track + */ + void resetTracks() override; - /** + /** * 输入frame */ - void inputFrame(const Frame::Ptr &frame) override; + void inputFrame(const Frame::Ptr &frame) override; /** * 添加ready状态的track @@ -84,17 +68,17 @@ private: void closeFile(); void asyncClose(); private: - string _strPath; - string _strFile; - string _strFileTmp; - Ticker _createFileTicker; - MP4Info _info; - bool _haveVideo = false; - MP4MuxerFile::Ptr _muxer; - list _tracks; + string _strPath; + string _strFile; + string _strFileTmp; + Ticker _createFileTicker; + MP4Info _info; + bool _haveVideo = false; + MP4Muxer::Ptr _muxer; + list _tracks; }; -#endif ///ENABLE_MP4RECORD +#endif ///ENABLE_MP4 } /* namespace mediakit */ diff --git a/src/Record/Recorder.cpp b/src/Record/Recorder.cpp index d5710b9b..38d6b98a 100644 --- a/src/Record/Recorder.cpp +++ b/src/Record/Recorder.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "Recorder.h" #include "Common/config.h" @@ -70,286 +54,6 @@ string Recorder::getRecordPath(Recorder::type type, const string &vhost, const s return ""; } } -//////////////////////////////////////////////////////////////////////////////////////// - -class RecorderHelper { -public: - typedef std::shared_ptr Ptr; - - /** - * 构建函数 - * @param bContinueRecord false表明hls录制从头开始录制(意味着hls临时文件在媒体反注册时会被删除) - */ - RecorderHelper(const MediaSinkInterface::Ptr &recorder, bool bContinueRecord) { - _recorder = recorder; - _continueRecord = bContinueRecord; - } - - ~RecorderHelper() { - resetTracks(); - } - - // 附则于track上 - void attachTracks(vector &&tracks, const string &schema){ - if(isTracksSame(tracks)){ - return; - } - resetTracks(); - _tracks = std::move(tracks); - _schema = schema; - for (auto &track : _tracks) { - _recorder->addTrack(track); - track->addDelegate(_recorder); - } - } - - - // 判断新的tracks是否与之前的一致 - bool isTracksSame(const vector &tracks){ - if(tracks.size() != _tracks.size()) { - return false; - } - int i = 0; - for(auto &track : tracks){ - if(track != _tracks[i++]){ - return false; - } - } - return true; - } - - // 重置所有track - void resetTracks(){ - if(_tracks.empty()){ - return; - } - for (auto &track : _tracks) { - track->delDelegate(_recorder.get()); - } - _tracks.clear(); - _recorder->resetTracks(); - } - - // 返回false表明hls录制从头开始录制(意味着hls临时文件在媒体反注册时会被删除) - bool continueRecord(){ - return _continueRecord; - } - - bool isRecording() { - return !_tracks.empty(); - } - - const string &getSchema() const{ - return _schema; - } - - const MediaSinkInterface::Ptr& getRecorder() const{ - return _recorder; - } -private: - MediaSinkInterface::Ptr _recorder; - vector _tracks; - bool _continueRecord; - string _schema; -}; - - -template -class MediaSourceWatcher { -public: - static MediaSourceWatcher& Instance(){ - static MediaSourceWatcher instance; - return instance; - } - - Recorder::status getRecordStatus(const string &vhost, const string &app, const string &stream_id) { - return getRecordStatus_l(getRecorderKey(vhost, app, stream_id)); - } - - MediaSinkInterface::Ptr getRecorder(const string &vhost, const string &app, const string &stream_id) const{ - auto key = getRecorderKey(vhost, app, stream_id); - lock_guard lck(_recorder_mtx); - auto it = _recorder_map.find(key); - if (it == _recorder_map.end()) { - return nullptr; - } - return it->second->getRecorder(); - } - - int startRecord(const string &vhost, const string &app, const string &stream_id, const string &customized_path, bool waitForRecord, bool continueRecord) { - auto key = getRecorderKey(vhost, app, stream_id); - lock_guard lck(_recorder_mtx); - if (getRecordStatus_l(key) != Recorder::status_not_record) { - // 已经在录制了 - return 0; - } - - auto src = findMediaSource(vhost, app, stream_id); - if (!waitForRecord && !src) { - // 暂时无法开启录制 - return -1; - } - - auto recorder = Recorder::createRecorder(type, vhost, app, stream_id, customized_path); - if (!recorder) { - // 创建录制器失败 - WarnL << "不支持该录制类型:" << type; - return -2; - } - auto helper = std::make_shared(recorder, continueRecord); - if(src){ - auto tracks = src->getTracks(needTrackReady()); - if(tracks.size()){ - helper->attachTracks(std::move(tracks),src->getSchema()); - } - auto hls_recorder = dynamic_pointer_cast(recorder); - if(hls_recorder){ - hls_recorder->getMediaSource()->setListener(src->getListener()); - } - } - - _recorder_map[key] = std::move(helper); - return 0; - } - - bool stopRecord(const string &vhost, const string &app, const string &stream_id) { - lock_guard lck(_recorder_mtx); - return _recorder_map.erase(getRecorderKey(vhost, app, stream_id)); - } - - void stopAll(){ - lock_guard lck(_recorder_mtx); - _recorder_map.clear(); - } - -private: - MediaSourceWatcher(){ - //保存NoticeCenter的强引用,防止在MediaSourceWatcher单例释放前释放NoticeCenter单例 - _notice_center = NoticeCenter::Instance().shared_from_this(); - _notice_center->addListener(this,Broadcast::kBroadcastMediaChanged,[this](BroadcastMediaChangedArgs){ - if(!bRegist){ - removeRecorder(sender); - } - }); - _notice_center->addListener(this,Broadcast::kBroadcastMediaResetTracks,[this](BroadcastMediaResetTracksArgs){ - addRecorder(sender); - }); - } - - ~MediaSourceWatcher(){ - _notice_center->delListener(this,Broadcast::kBroadcastMediaChanged); - _notice_center->delListener(this,Broadcast::kBroadcastMediaResetTracks); - } - - void addRecorder(MediaSource &sender){ - auto tracks = sender.getTracks(needTrackReady()); - auto key = getRecorderKey(sender.getVhost(),sender.getApp(),sender.getId()); - lock_guard lck(_recorder_mtx); - auto it = _recorder_map.find(key); - if(it == _recorder_map.end()){ - // 录像记录不存在 - return; - } - - if(!it->second->isRecording() || it->second->getSchema() == sender.getSchema()){ - // 绑定的协议一致或者并未正在录制则替换tracks - if (!tracks.empty()) { - it->second->attachTracks(std::move(tracks),sender.getSchema()); - } - } - } - - void removeRecorder(MediaSource &sender){ - auto key = getRecorderKey(sender.getVhost(),sender.getApp(),sender.getId()); - lock_guard lck(_recorder_mtx); - auto it = _recorder_map.find(key); - if(it == _recorder_map.end() || it->second->getSchema() != sender.getSchema()){ - // 录像记录不存在或绑定的协议不一致 - return; - } - - if(it->second->continueRecord()){ - // 如果可以继续录制,那么只重置tracks,不删除对象 - it->second->resetTracks(); - }else{ - // 删除对象(意味着可能删除hls临时文件) - _recorder_map.erase(it); - } - } - - Recorder::status getRecordStatus_l(const string &key) { - auto it = _recorder_map.find(key); - if (it == _recorder_map.end()) { - return Recorder::status_not_record; - } - return it->second->isRecording() ? Recorder::status_recording : Recorder::status_wait_record; - } - - // 查找MediaSource以便录制 - MediaSource::Ptr findMediaSource(const string &vhost, const string &app, const string &stream_id) { - bool need_ready = needTrackReady(); - auto src = MediaSource::find(RTMP_SCHEMA, vhost, app, stream_id); - if (src) { - auto ret = src->getTracks(need_ready); - if (!ret.empty()) { - return std::move(src); - } - } - - src = MediaSource::find(RTSP_SCHEMA, vhost, app, stream_id); - if (src) { - auto ret = src->getTracks(need_ready); - if (!ret.empty()) { - return std::move(src); - } - } - return nullptr; - } - - string getRecorderKey(const string &vhost, const string &app, const string &stream_id) const{ - return vhost + "/" + app + "/" + stream_id; - } - - - /** - * 有些录制类型不需要track就绪即可录制 - */ - bool needTrackReady(){ - switch (type){ - case Recorder::type_hls: - return false; - case Recorder::type_mp4: - return true; - default: - return true; - } - } -private: - mutable recursive_mutex _recorder_mtx; - NoticeCenter::Ptr _notice_center; - unordered_map _recorder_map; -}; - - -Recorder::status Recorder::getRecordStatus(Recorder::type type, const string &vhost, const string &app, const string &stream_id) { - switch (type){ - case type_mp4: - return MediaSourceWatcher::Instance().getRecordStatus(vhost,app,stream_id); - case type_hls: - return MediaSourceWatcher::Instance().getRecordStatus(vhost,app,stream_id); - } - return status_not_record; -} - -std::shared_ptr Recorder::getRecorder(type type, const string &vhost, const string &app, const string &stream_id){ - switch (type){ - case type_mp4: - return MediaSourceWatcher::Instance().getRecorder(vhost,app,stream_id); - case type_hls: - return MediaSourceWatcher::Instance().getRecorder(vhost,app,stream_id); - } - return nullptr; -} std::shared_ptr Recorder::createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path){ auto path = Recorder::getRecordPath(type, vhost, app, stream_id); @@ -364,7 +68,7 @@ std::shared_ptr Recorder::createRecorder(type type, const st } case Recorder::type_mp4: { -#if defined(ENABLE_MP4RECORD) +#if defined(ENABLE_MP4) return std::make_shared(path, vhost, app, stream_id); #endif return nullptr; @@ -375,30 +79,36 @@ std::shared_ptr Recorder::createRecorder(type type, const st } } -int Recorder::startRecord(Recorder::type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path, bool waitForRecord, bool continueRecord) { - switch (type){ - case type_mp4: - return MediaSourceWatcher::Instance().startRecord(vhost,app,stream_id,customized_path,waitForRecord,continueRecord); - case type_hls: - return MediaSourceWatcher::Instance().startRecord(vhost,app,stream_id,customized_path,waitForRecord,continueRecord); +static MediaSource::Ptr getMediaSource(const string &vhost, const string &app, const string &stream_id){ + auto src = MediaSource::find(RTMP_SCHEMA, vhost, app, stream_id, false); + if(src){ + return src; } - WarnL << "unknown record type: " << type; - return -3; + return MediaSource::find(RTSP_SCHEMA, vhost, app, stream_id, false); } -bool Recorder::stopRecord(Recorder::type type, const string &vhost, const string &app, const string &stream_id) { - switch (type){ - case type_mp4: - return MediaSourceWatcher::Instance().stopRecord(vhost,app,stream_id); - case type_hls: - return MediaSourceWatcher::Instance().stopRecord(vhost,app,stream_id); +bool Recorder::isRecording(type type, const string &vhost, const string &app, const string &stream_id){ + auto src = getMediaSource(vhost, app, stream_id); + if(!src){ + return false; } - return false; + return src->isRecording(type); } -void Recorder::stopAll() { - MediaSourceWatcher::Instance().stopAll(); - MediaSourceWatcher::Instance().stopAll(); +bool Recorder::startRecord(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path){ + auto src = getMediaSource(vhost, app, stream_id); + if(!src){ + return false; + } + return src->setupRecord(type,true,customized_path); +} + +bool Recorder::stopRecord(type type, const string &vhost, const string &app, const string &stream_id){ + auto src = getMediaSource(vhost, app, stream_id); + if(!src){ + return false; + } + return src->setupRecord(type, false, ""); } } /* namespace mediakit */ diff --git a/src/Record/Recorder.h b/src/Record/Recorder.h index cb3d9cc6..670de9f8 100644 --- a/src/Record/Recorder.h +++ b/src/Record/Recorder.h @@ -1,68 +1,51 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_MEDIAFILE_RECORDER_H_ #define SRC_MEDIAFILE_RECORDER_H_ - #include #include using namespace std; - namespace mediakit { - class MediaSinkInterface; class Recorder{ public: - typedef enum { - // 未录制 - status_not_record = 0, - // 等待MediaSource注册,注册成功后立即开始录制 - status_wait_record = 1, - // MediaSource已注册,并且正在录制 - status_recording = 2, - } status; + typedef enum { + // 录制hls + type_hls = 0, + // 录制MP4 + type_mp4 = 1 + } type; - typedef enum { - // 录制hls - type_hls = 0, - // 录制MP4 - type_mp4 = 1 - } type; - - /** - * 获取录制文件绝对路径 - * @param type hls还是MP4录制 + /** + * 获取录制文件绝对路径 + * @param type hls还是MP4录制 * @param vhost 虚拟主机 * @param app 应用名 * @param stream_id 流id * @param customized_path 录像文件保存自定义目录,默认为空则自动生成 - * @return 录制文件绝对路径 - */ - static string getRecordPath(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path = ""); + * @return 录制文件绝对路径 + */ + static string getRecordPath(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path = ""); + + /** + * 创建录制器对象 + * @param type hls还是MP4录制 + * @param vhost 虚拟主机 + * @param app 应用名 + * @param stream_id 流id + * @param customized_path 录像文件保存自定义目录,默认为空则自动生成 + * @return 对象指针,可能为nullptr + */ + static std::shared_ptr createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path = ""); /** * 获取录制状态 @@ -70,61 +53,34 @@ public: * @param vhost 虚拟主机 * @param app 应用名 * @param stream_id 流id - * @return 录制状态 + * @return 是否真正录制 */ - static status getRecordStatus(type type, const string &vhost, const string &app, const string &stream_id); + static bool isRecording(type type, const string &vhost, const string &app, const string &stream_id); - /** - * 开始录制 - * @param type hls还是MP4录制 + /** + * 开始录制 + * @param type hls还是MP4录制 * @param vhost 虚拟主机 * @param app 应用名 * @param stream_id 流id * @param customized_path 录像文件保存自定义目录,默认为空则自动生成 - * @param waitForRecord 是否等待流注册后再录制,未注册时,置false将返回失败 - * @param continueRecord 流注销时是否继续等待录制还是立即停止录制 - * @return 0代表成功,负数代表失败 - */ - static int startRecord(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path,bool waitForRecord, bool continueRecord); + * @return 成功与否 + */ + static bool startRecord(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path); - /** - * 停止录制 - * @param type hls还是MP4录制 + /** + * 停止录制 + * @param type hls还是MP4录制 * @param vhost 虚拟主机 * @param app 应用名 * @param stream_id 流id - */ - static bool stopRecord(type type, const string &vhost, const string &app, const string &stream_id); + */ + static bool stopRecord(type type, const string &vhost, const string &app, const string &stream_id); - /** - * 停止所有录制,一般程序退出时调用 - */ - static void stopAll(); - - /** - * 获取录制对象 - * @param type hls还是MP4录制 - * @param vhost 虚拟主机 - * @param app 应用名 - * @param stream_id 流id - */ - static std::shared_ptr getRecorder(type type, const string &vhost, const string &app, const string &stream_id); - - /** - * 创建录制器对象 - * @param type hls还是MP4录制 - * @param vhost 虚拟主机 - * @param app 应用名 - * @param stream_id 流id - * @param customized_path 录像文件保存自定义目录,默认为空则自动生成 - * @return 对象指针,可能为nullptr - */ - static std::shared_ptr createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path); private: - Recorder() = delete; - ~Recorder() = delete; + Recorder() = delete; + ~Recorder() = delete; }; } /* namespace mediakit */ - #endif /* SRC_MEDIAFILE_RECORDER_H_ */ diff --git a/src/Record/TsMuxer.cpp b/src/Record/TsMuxer.cpp index e63c4f8f..4da7eab9 100644 --- a/src/Record/TsMuxer.cpp +++ b/src/Record/TsMuxer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "TsMuxer.h" diff --git a/src/Record/TsMuxer.h b/src/Record/TsMuxer.h index b484a864..7f20e968 100644 --- a/src/Record/TsMuxer.h +++ b/src/Record/TsMuxer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef TSMUXER_H diff --git a/src/Rtmp/FlvMuxer.cpp b/src/Rtmp/FlvMuxer.cpp index dc7c96e8..cc4866cc 100644 --- a/src/Rtmp/FlvMuxer.cpp +++ b/src/Rtmp/FlvMuxer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "FlvMuxer.h" diff --git a/src/Rtmp/FlvMuxer.h b/src/Rtmp/FlvMuxer.h index a01d6250..d51c0b4d 100644 --- a/src/Rtmp/FlvMuxer.h +++ b/src/Rtmp/FlvMuxer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_FLVMUXER_H diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index a987a098..52a9111b 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "Rtmp.h" #include "Extension/Factory.h" namespace mediakit{ diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index 8607fa62..a02fc0d8 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef __rtmp_h #define __rtmp_h @@ -87,6 +72,10 @@ using namespace toolkit; #define FLV_KEY_FRAME 1 #define FLV_INTER_FRAME 2 +#define FLV_CODEC_AAC 10 +#define FLV_CODEC_H264 7 +#define FLV_CODEC_H265 12 + namespace mediakit { #if defined(_WIN32) @@ -215,84 +204,6 @@ public: const static int channel[] = { 1, 2 }; return channel[flvStereoOrMono]; } - - /** - * 返回不带0x00 00 00 01头的sps - * @return - */ - string getH264SPS() const { - string ret; - if (getMediaType() != 7) { - return ret; - } - if (!isCfgFrame()) { - return ret; - } - if (strBuf.size() < 13) { - WarnL << "bad H264 cfg!"; - return ret; - } - uint16_t sps_size ; - memcpy(&sps_size,strBuf.data() + 11,2); - sps_size = ntohs(sps_size); - if ((int) strBuf.size() < 13 + sps_size) { - WarnL << "bad H264 cfg!"; - return ret; - } - ret.assign(strBuf.data() + 13, sps_size); - return ret; - } - - /** - * 返回不带0x00 00 00 01头的pps - * @return - */ - string getH264PPS() const { - string ret; - if (getMediaType() != 7) { - return ret; - } - if (!isCfgFrame()) { - return ret; - } - if (strBuf.size() < 13) { - WarnL << "bad H264 cfg!"; - return ret; - } - uint16_t sps_size ; - memcpy(&sps_size,strBuf.data() + 11,2); - sps_size = ntohs(sps_size); - - if ((int) strBuf.size() < 13 + sps_size + 1 + 2) { - WarnL << "bad H264 cfg!"; - return ret; - } - uint16_t pps_size ; - memcpy(&pps_size,strBuf.data() + 13 + sps_size + 1,2); - pps_size = ntohs(pps_size); - - if ((int) strBuf.size() < 13 + sps_size + 1 + 2 + pps_size) { - WarnL << "bad H264 cfg!"; - return ret; - } - ret.assign(strBuf.data() + 13 + sps_size + 1 + 2, pps_size); - return ret; - } - string getAacCfg() const { - string ret; - if (getMediaType() != 10) { - return ret; - } - if (!isCfgFrame()) { - return ret; - } - if (strBuf.size() < 4) { - WarnL << "bad aac cfg!"; - return ret; - } - ret = strBuf.substr(2, 2); - return ret; - } }; @@ -325,7 +236,7 @@ public: const map &header = map()){ _metadata.set("duration", dur_sec); _metadata.set("fileSize", 0); - _metadata.set("server","ZLMediaKit"); + _metadata.set("server",SERVER_NAME); for (auto &pr : header){ _metadata.set(pr.first, pr.second); } diff --git a/src/Rtmp/RtmpCodec.h b/src/Rtmp/RtmpCodec.h index 25f2fc5a..bb74fb69 100644 --- a/src/Rtmp/RtmpCodec.h +++ b/src/Rtmp/RtmpCodec.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTMPCODEC_H diff --git a/src/Rtmp/RtmpDemuxer.cpp b/src/Rtmp/RtmpDemuxer.cpp index 65f8fb91..bfdd6795 100644 --- a/src/Rtmp/RtmpDemuxer.cpp +++ b/src/Rtmp/RtmpDemuxer.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "RtmpDemuxer.h" #include "Extension/Factory.h" diff --git a/src/Rtmp/RtmpDemuxer.h b/src/Rtmp/RtmpDemuxer.h index a2c900a8..6d1c264d 100644 --- a/src/Rtmp/RtmpDemuxer.h +++ b/src/Rtmp/RtmpDemuxer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPDEMUXER_H_ @@ -41,27 +25,27 @@ namespace mediakit { class RtmpDemuxer : public Demuxer{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - RtmpDemuxer() = default; - virtual ~RtmpDemuxer() = default; + RtmpDemuxer() = default; + virtual ~RtmpDemuxer() = default; - void loadMetaData(const AMFValue &metadata); + void loadMetaData(const AMFValue &metadata); - /** - * 开始解复用 - * @param pkt rtmp包 - * @return true 代表是i帧 - */ - bool inputRtmp(const RtmpPacket::Ptr &pkt); + /** + * 开始解复用 + * @param pkt rtmp包 + * @return true 代表是i帧 + */ + bool inputRtmp(const RtmpPacket::Ptr &pkt); private: - void makeVideoTrack(const AMFValue &val); - void makeAudioTrack(const AMFValue &val); + void makeVideoTrack(const AMFValue &val); + void makeAudioTrack(const AMFValue &val); private: - bool _tryedGetVideoTrack = false; - bool _tryedGetAudioTrack = false; - RtmpCodec::Ptr _audioRtmpDecoder; - RtmpCodec::Ptr _videoRtmpDecoder; + bool _tryedGetVideoTrack = false; + bool _tryedGetAudioTrack = false; + RtmpCodec::Ptr _audioRtmpDecoder; + RtmpCodec::Ptr _videoRtmpDecoder; }; } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpMediaSource.h b/src/Rtmp/RtmpMediaSource.h index db13960e..f002f533 100644 --- a/src/Rtmp/RtmpMediaSource.h +++ b/src/Rtmp/RtmpMediaSource.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPMEDIASOURCE_H_ @@ -58,163 +42,144 @@ namespace mediakit { */ class RtmpMediaSource : public MediaSource, public RingDelegate { public: - typedef std::shared_ptr Ptr; - typedef RingBuffer RingType; + typedef std::shared_ptr Ptr; + typedef RingBuffer RingType; - /** - * 构造函数 - * @param vhost 虚拟主机名 - * @param app 应用名 - * @param stream_id 流id - * @param ring_size 可以设置固定的环形缓冲大小,0则自适应 - */ - RtmpMediaSource(const string &vhost, - const string &app, - const string &stream_id, - int ring_size = RTMP_GOP_SIZE) : - MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) { - } + /** + * 构造函数 + * @param vhost 虚拟主机名 + * @param app 应用名 + * @param stream_id 流id + * @param ring_size 可以设置固定的环形缓冲大小,0则自适应 + */ + RtmpMediaSource(const string &vhost, + const string &app, + const string &stream_id, + int ring_size = RTMP_GOP_SIZE) : + MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) { + } - virtual ~RtmpMediaSource() {} + virtual ~RtmpMediaSource() {} - /** - * 获取媒体源的环形缓冲 - */ - const RingType::Ptr &getRing() const { - return _ring; - } + /** + * 获取媒体源的环形缓冲 + */ + const RingType::Ptr &getRing() const { + return _ring; + } - /** - * 获取播放器个数 - * @return - */ - int readerCount() override { - return _ring ? _ring->readerCount() : 0; - } + /** + * 获取播放器个数 + * @return + */ + int readerCount() override { + return _ring ? _ring->readerCount() : 0; + } - /** - * 获取metadata - */ - const AMFValue &getMetaData() const { - lock_guard lock(_mtx); - return _metadata; - } + /** + * 获取metadata + */ + const AMFValue &getMetaData() const { + lock_guard lock(_mtx); + return _metadata; + } - /** - * 获取所有的config帧 - */ - template - void getConfigFrame(const FUNC &f) { - lock_guard lock(_mtx); - for (auto &pr : _config_frame_map) { - f(pr.second); - } - } + /** + * 获取所有的config帧 + */ + template + void getConfigFrame(const FUNC &f) { + lock_guard lock(_mtx); + for (auto &pr : _config_frame_map) { + f(pr.second); + } + } - /** - * 设置metadata - */ - virtual void setMetaData(const AMFValue &metadata) { - lock_guard lock(_mtx); - _metadata = metadata; - if(_ring){ - regist(); - } - } + /** + * 设置metadata + */ + virtual void setMetaData(const AMFValue &metadata) { + lock_guard lock(_mtx); + _metadata = metadata; + if(_ring){ + regist(); + } + } - /** - * 输入rtmp包 - * @param pkt rtmp包 - * @param key 是否为关键帧 - */ - void onWrite(const RtmpPacket::Ptr &pkt, bool key = true) override { - lock_guard lock(_mtx); - if(pkt->typeId == MSG_VIDEO){ - //有视频,那么启用GOP缓存 + /** + * 输入rtmp包 + * @param pkt rtmp包 + * @param key 是否为关键帧 + */ + void onWrite(const RtmpPacket::Ptr &pkt, bool key = true) override { + lock_guard lock(_mtx); + if(pkt->typeId == MSG_VIDEO){ + //有视频,那么启用GOP缓存 _have_video = true; - } - if (pkt->isCfgFrame()) { - _config_frame_map[pkt->typeId] = pkt; - return; - } + } + if (pkt->isCfgFrame()) { + _config_frame_map[pkt->typeId] = pkt; + return; + } - if (!_ring) { - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) { - auto strongSelf = weakSelf.lock(); - if (!strongSelf) { - return; - } - strongSelf->onReaderChanged(size); - }; + if (!_ring) { + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { + return; + } + strongSelf->onReaderChanged(size); + }; - //rtmp包缓存最大允许512个,如果是纯视频(25fps)大概为20秒数据 - //但是这个是GOP缓存的上限值,真实的GOP缓存大小等于两个I帧之间的包数的两倍 - //而且每次遇到I帧,则会清空GOP缓存,所以真实的GOP缓存远小于此值 - _ring = std::make_shared(_ring_size,std::move(lam)); - onReaderChanged(0); + //rtmp包缓存最大允许512个,如果是纯视频(25fps)大概为20秒数据 + //但是这个是GOP缓存的上限值,真实的GOP缓存大小等于两个I帧之间的包数的两倍 + //而且每次遇到I帧,则会清空GOP缓存,所以真实的GOP缓存远小于此值 + _ring = std::make_shared(_ring_size,std::move(lam)); + onReaderChanged(0); - if(_metadata){ - regist(); - } - } - _track_stamps_map[pkt->typeId] = pkt->timeStamp; - //不存在视频,为了减少缓存延时,那么关闭GOP缓存 - _ring->write(pkt, _have_video ? pkt->isVideoKeyFrame() : true); - checkNoneReader(); - } + if(_metadata){ + regist(); + } + } + _track_stamps_map[pkt->typeId] = pkt->timeStamp; + //不存在视频,为了减少缓存延时,那么关闭GOP缓存 + _ring->write(pkt, _have_video ? pkt->isVideoKeyFrame() : true); + } - /** - * 获取当前时间戳 - */ - uint32_t getTimeStamp(TrackType trackType) override { - lock_guard lock(_mtx); - switch (trackType) { - case TrackVideo: - return _track_stamps_map[MSG_VIDEO]; - case TrackAudio: - return _track_stamps_map[MSG_AUDIO]; - default: - return MAX(_track_stamps_map[MSG_VIDEO], _track_stamps_map[MSG_AUDIO]); - } - } + /** + * 获取当前时间戳 + */ + uint32_t getTimeStamp(TrackType trackType) override { + lock_guard lock(_mtx); + switch (trackType) { + case TrackVideo: + return _track_stamps_map[MSG_VIDEO]; + case TrackAudio: + return _track_stamps_map[MSG_AUDIO]; + default: + return MAX(_track_stamps_map[MSG_VIDEO], _track_stamps_map[MSG_AUDIO]); + } + } private: - /** - * 每次增减消费者都会触发该函数 - */ - void onReaderChanged(int size) { - //我们记录最后一次活动时间 - _reader_changed_ticker.resetTime(); - if (size != 0 || totalReaderCount() != 0) { - //还有消费者正在观看该流 - _async_emit_none_reader = false; - return; - } - _async_emit_none_reader = true; - } + /** + * 每次增减消费者都会触发该函数 + */ + void onReaderChanged(int size) { + if (size == 0) { + onNoneReader(); + } + } - /** - * 检查是否无人消费该流, - * 如果无人消费且超过一定时间会触发onNoneReader事件 - */ - void checkNoneReader() { - GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS); - if (_async_emit_none_reader && _reader_changed_ticker.elapsedTime() > stream_none_reader_delay) { - _async_emit_none_reader = false; - onNoneReader(); - } - } -protected: - int _ring_size; - bool _async_emit_none_reader = false; - bool _have_video = false; - mutable recursive_mutex _mtx; - Ticker _reader_changed_ticker; - AMFValue _metadata; - RingBuffer::Ptr _ring; - unordered_map _track_stamps_map; - unordered_map _config_frame_map; +private: + int _ring_size; + bool _have_video = false; + mutable recursive_mutex _mtx; + AMFValue _metadata; + RingBuffer::Ptr _ring; + unordered_map _track_stamps_map; + unordered_map _config_frame_map; }; } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpMediaSourceImp.h b/src/Rtmp/RtmpMediaSourceImp.h index fca06936..954180b9 100644 --- a/src/Rtmp/RtmpMediaSourceImp.h +++ b/src/Rtmp/RtmpMediaSourceImp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPTORTSPMEDIASOURCE_H_ @@ -45,46 +29,46 @@ using namespace toolkit; namespace mediakit { class RtmpMediaSourceImp: public RtmpMediaSource, public Demuxer::Listener , public MultiMediaSourceMuxer::Listener { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - /** - * 构造函数 - * @param vhost 虚拟主机 - * @param app 应用名 - * @param id 流id - * @param ringSize 环形缓存大小 - */ - RtmpMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTMP_GOP_SIZE) : RtmpMediaSource(vhost, app, id, ringSize) { - _demuxer = std::make_shared(); - _demuxer->setTrackListener(this); - } + /** + * 构造函数 + * @param vhost 虚拟主机 + * @param app 应用名 + * @param id 流id + * @param ringSize 环形缓存大小 + */ + RtmpMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTMP_GOP_SIZE) : RtmpMediaSource(vhost, app, id, ringSize) { + _demuxer = std::make_shared(); + _demuxer->setTrackListener(this); + } - ~RtmpMediaSourceImp() = default; + ~RtmpMediaSourceImp() = default; - /** - * 设置metadata - */ - void setMetaData(const AMFValue &metadata) override{ - _demuxer->loadMetaData(metadata); - RtmpMediaSource::setMetaData(metadata); - } + /** + * 设置metadata + */ + void setMetaData(const AMFValue &metadata) override{ + _demuxer->loadMetaData(metadata); + RtmpMediaSource::setMetaData(metadata); + } - /** - * 输入rtmp并解析 - */ - void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override { - key_pos = _demuxer->inputRtmp(pkt); - RtmpMediaSource::onWrite(pkt,key_pos); - } + /** + * 输入rtmp并解析 + */ + void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override { + key_pos = _demuxer->inputRtmp(pkt); + RtmpMediaSource::onWrite(pkt,key_pos); + } - /** - * 设置监听器 - * @param listener - */ - void setListener(const std::weak_ptr &listener) override { + /** + * 设置监听器 + * @param listener + */ + void setListener(const std::weak_ptr &listener) override { RtmpMediaSource::setListener(listener); if(_muxer){ - _muxer->setListener(listener); + _muxer->setMediaListener(listener); } } @@ -95,42 +79,69 @@ public: return readerCount() + (_muxer ? _muxer->totalReaderCount() : 0); } - /** - * 设置协议转换 - * @param enableRtsp 是否转换成rtsp - * @param enableHls 是否转换成hls - * @param enableMP4 是否mp4录制 - */ - void setProtocolTranslation(bool enableRtsp, bool enableHls, bool enableMP4) { - //不重复生成rtmp - _muxer = std::make_shared(getVhost(), getApp(), getId(), _demuxer->getDuration(), enableRtsp, false, enableHls, enableMP4); - _muxer->setListener(getListener()); - _muxer->setTrackListener(this); + /** + * 设置录制状态 + * @param type 录制类型 + * @param start 开始或停止 + * @param custom_path 开启录制时,指定自定义路径 + * @return 是否设置成功 + */ + bool setupRecord(Recorder::type type, bool start, const string &custom_path) override{ + if(_muxer){ + return _muxer->setupRecord(*this,type, start, custom_path); + } + return RtmpMediaSource::setupRecord(type, start, custom_path); + } + + /** + * 获取录制状态 + * @param type 录制类型 + * @return 录制状态 + */ + bool isRecording(Recorder::type type) override{ + if(_muxer){ + return _muxer->isRecording(*this,type); + } + return RtmpMediaSource::isRecording(type); + } + + + /** + * 设置协议转换 + * @param enableRtsp 是否转换成rtsp + * @param enableHls 是否转换成hls + * @param enableMP4 是否mp4录制 + */ + void setProtocolTranslation(bool enableRtsp, bool enableHls, bool enableMP4) { + //不重复生成rtmp + _muxer = std::make_shared(getVhost(), getApp(), getId(), _demuxer->getDuration(), enableRtsp, false, enableHls, enableMP4); + _muxer->setMediaListener(getListener()); + _muxer->setTrackListener(this); for(auto &track : _demuxer->getTracks(false)){ _muxer->addTrack(track); track->addDelegate(_muxer); } - } + } - /** - * _demuxer触发的添加Track事件 - */ - void onAddTrack(const Track::Ptr &track) override { - if(_muxer){ - _muxer->addTrack(track); - track->addDelegate(_muxer); - } - } + /** + * _demuxer触发的添加Track事件 + */ + void onAddTrack(const Track::Ptr &track) override { + if(_muxer){ + _muxer->addTrack(track); + track->addDelegate(_muxer); + } + } - /** - * _muxer触发的所有Track就绪的事件 - */ - void onAllTrackReady() override{ - setTrackSource(_muxer); - } + /** + * _muxer触发的所有Track就绪的事件 + */ + void onAllTrackReady() override{ + setTrackSource(_muxer); + } private: - RtmpDemuxer::Ptr _demuxer; - MultiMediaSourceMuxer::Ptr _muxer; + RtmpDemuxer::Ptr _demuxer; + MultiMediaSourceMuxer::Ptr _muxer; }; } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpMediaSourceMuxer.h b/src/Rtmp/RtmpMediaSourceMuxer.h index dce7e70e..c1ab506c 100644 --- a/src/Rtmp/RtmpMediaSourceMuxer.h +++ b/src/Rtmp/RtmpMediaSourceMuxer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTMPMEDIASOURCEMUXER_H diff --git a/src/Rtmp/RtmpMuxer.cpp b/src/Rtmp/RtmpMuxer.cpp index 89d345ca..5f935df1 100644 --- a/src/Rtmp/RtmpMuxer.cpp +++ b/src/Rtmp/RtmpMuxer.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "RtmpMuxer.h" #include "Extension/Factory.h" diff --git a/src/Rtmp/RtmpMuxer.h b/src/Rtmp/RtmpMuxer.h index cc09178e..ad6f27e6 100644 --- a/src/Rtmp/RtmpMuxer.h +++ b/src/Rtmp/RtmpMuxer.h @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef ZLMEDIAKIT_RTMPMUXER_H #define ZLMEDIAKIT_RTMPMUXER_H diff --git a/src/Rtmp/RtmpPlayer.cpp b/src/Rtmp/RtmpPlayer.cpp index 5251ca42..54f1e106 100644 --- a/src/Rtmp/RtmpPlayer.cpp +++ b/src/Rtmp/RtmpPlayer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "RtmpPlayer.h" @@ -38,35 +22,35 @@ RtmpPlayer::RtmpPlayer(const EventPoller::Ptr &poller) : TcpClient(poller) { } RtmpPlayer::~RtmpPlayer() { - DebugL << endl; + DebugL << endl; } void RtmpPlayer::teardown() { - if (alive()) { - shutdown(SockException(Err_shutdown,"teardown")); - } - _strApp.clear(); - _strStream.clear(); - _strTcUrl.clear(); - _pBeatTimer.reset(); - _pPlayTimer.reset(); - _pMediaTimer.reset(); - _iSeekTo = 0; - RtmpProtocol::reset(); + if (alive()) { + shutdown(SockException(Err_shutdown,"teardown")); + } + _strApp.clear(); + _strStream.clear(); + _strTcUrl.clear(); + _pBeatTimer.reset(); + _pPlayTimer.reset(); + _pMediaTimer.reset(); + _iSeekTo = 0; + RtmpProtocol::reset(); - CLEAR_ARR(_aiFistStamp); - CLEAR_ARR(_aiNowStamp); + CLEAR_ARR(_aiFistStamp); + CLEAR_ARR(_aiNowStamp); - lock_guard lck(_mtxOnResultCB); - _mapOnResultCB.clear(); - lock_guard lck2(_mtxOnStatusCB); - _dqOnStatusCB.clear(); + lock_guard lck(_mtxOnResultCB); + _mapOnResultCB.clear(); + lock_guard lck2(_mtxOnStatusCB); + _dqOnStatusCB.clear(); } void RtmpPlayer::play(const string &strUrl) { - teardown(); - string strHost = FindField(strUrl.data(), "://", "/"); - _strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); + teardown(); + string strHost = FindField(strUrl.data(), "://", "/"); + _strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); _strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL); _strTcUrl = string("rtmp://") + strHost + "/" + _strApp; @@ -74,48 +58,48 @@ void RtmpPlayer::play(const string &strUrl) { onPlayResult_l(SockException(Err_other,"rtmp url非法"),false); return; } - DebugL << strHost << " " << _strApp << " " << _strStream; + DebugL << strHost << " " << _strApp << " " << _strStream; - auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); - if (iPort <= 0) { + auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); + if (iPort <= 0) { //rtmp 默认端口1935 - iPort = 1935; - } else { + iPort = 1935; + } else { //服务器域名 - strHost = FindField(strHost.data(), NULL, ":"); - } - if(!(*this)[kNetAdapter].empty()){ - setNetAdapter((*this)[kNetAdapter]); - } + strHost = FindField(strHost.data(), NULL, ":"); + } + if(!(*this)[kNetAdapter].empty()){ + setNetAdapter((*this)[kNetAdapter]); + } - weak_ptr weakSelf= dynamic_pointer_cast(shared_from_this()); - float playTimeOutSec = (*this)[kTimeoutMS].as() / 1000.0; - _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { - return false; - } - strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout"),false); - return false; - },getPoller())); + weak_ptr weakSelf= dynamic_pointer_cast(shared_from_this()); + float playTimeOutSec = (*this)[kTimeoutMS].as() / 1000.0; + _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { + auto strongSelf=weakSelf.lock(); + if(!strongSelf) { + return false; + } + strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout"),false); + return false; + },getPoller())); - _metadata_got = false; - startConnect(strHost, iPort , playTimeOutSec); + _metadata_got = false; + startConnect(strHost, iPort , playTimeOutSec); } void RtmpPlayer::onErr(const SockException &ex){ //定时器_pPlayTimer为空后表明握手结束了 - onPlayResult_l(ex, !_pPlayTimer); + onPlayResult_l(ex, !_pPlayTimer); } void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) { - WarnL << ex.getErrCode() << " " << ex.what(); + WarnL << ex.getErrCode() << " " << ex.what(); if(!ex){ //播放成功,恢复rtmp接收超时定时器 _mediaTicker.resetTime(); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); int timeoutMS = (*this)[kMediaTimeoutMS].as(); - //创建rtmp数据接收超时检测定时器 + //创建rtmp数据接收超时检测定时器 _pMediaTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { auto strongSelf=weakSelf.lock(); if(!strongSelf) { @@ -130,110 +114,110 @@ void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete },getPoller())); } - if (!handshakeCompleted) { - //开始播放阶段 - _pPlayTimer.reset(); - onPlayResult(ex); - } else if (ex) { - //播放成功后异常断开回调 - onShutdown(ex); - } else { - //恢复播放 - onResume(); - } + if (!handshakeCompleted) { + //开始播放阶段 + _pPlayTimer.reset(); + onPlayResult(ex); + } else if (ex) { + //播放成功后异常断开回调 + onShutdown(ex); + } else { + //恢复播放 + onResume(); + } - if(ex){ - teardown(); - } + if(ex){ + teardown(); + } } void RtmpPlayer::onConnect(const SockException &err){ - if(err.getErrCode() != Err_success) { - onPlayResult_l(err, false); - return; - } - weak_ptr weakSelf= dynamic_pointer_cast(shared_from_this()); - startClientSession([weakSelf](){ + if(err.getErrCode() != Err_success) { + onPlayResult_l(err, false); + return; + } + weak_ptr weakSelf= dynamic_pointer_cast(shared_from_this()); + startClientSession([weakSelf](){ auto strongSelf=weakSelf.lock(); - if(!strongSelf) { + if(!strongSelf) { return; } - strongSelf->send_connect(); - }); + strongSelf->send_connect(); + }); } void RtmpPlayer::onRecv(const Buffer::Ptr &pBuf){ - try { - onParseRtmp(pBuf->data(), pBuf->size()); - } catch (exception &e) { - SockException ex(Err_other, e.what()); + try { + onParseRtmp(pBuf->data(), pBuf->size()); + } catch (exception &e) { + SockException ex(Err_other, e.what()); //定时器_pPlayTimer为空后表明握手结束了 - onPlayResult_l(ex, !_pPlayTimer); - } + onPlayResult_l(ex, !_pPlayTimer); + } } void RtmpPlayer::pause(bool bPause) { - send_pause(bPause); + send_pause(bPause); } inline void RtmpPlayer::send_connect() { - AMFValue obj(AMF_OBJECT); - obj.set("app", _strApp); - obj.set("tcUrl", _strTcUrl); - //未使用代理 - obj.set("fpad", false); - //参考librtmp,什么作用? - obj.set("capabilities", 15); - //SUPPORT_VID_CLIENT_SEEK 支持seek - obj.set("videoFunction", 1); + AMFValue obj(AMF_OBJECT); + obj.set("app", _strApp); + obj.set("tcUrl", _strTcUrl); + //未使用代理 + obj.set("fpad", false); + //参考librtmp,什么作用? + obj.set("capabilities", 15); + //SUPPORT_VID_CLIENT_SEEK 支持seek + obj.set("videoFunction", 1); //只支持aac obj.set("audioCodecs", (double)(0x0400)); //只支持H264 obj.set("videoCodecs", (double)(0x0080)); - sendInvoke("connect", obj); - addOnResultCB([this](AMFDecoder &dec){ - //TraceL << "connect result"; - dec.load(); - auto val = dec.load(); - auto level = val["level"].as_string(); - auto code = val["code"].as_string(); - if(level != "status"){ - throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); - } - send_createStream(); - }); + sendInvoke("connect", obj); + addOnResultCB([this](AMFDecoder &dec){ + //TraceL << "connect result"; + dec.load(); + auto val = dec.load(); + auto level = val["level"].as_string(); + auto code = val["code"].as_string(); + if(level != "status"){ + throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); + } + send_createStream(); + }); } inline void RtmpPlayer::send_createStream() { - AMFValue obj(AMF_NULL); - sendInvoke("createStream", obj); - addOnResultCB([this](AMFDecoder &dec){ - //TraceL << "createStream result"; - dec.load(); - _ui32StreamId = dec.load(); - send_play(); - }); + AMFValue obj(AMF_NULL); + sendInvoke("createStream", obj); + addOnResultCB([this](AMFDecoder &dec){ + //TraceL << "createStream result"; + dec.load(); + _ui32StreamId = dec.load(); + send_play(); + }); } inline void RtmpPlayer::send_play() { - AMFEncoder enc; - enc << "play" << ++_iReqID << nullptr << _strStream << (double)_ui32StreamId; - sendRequest(MSG_CMD, enc.data()); - auto fun = [this](AMFValue &val){ - //TraceL << "play onStatus"; - auto level = val["level"].as_string(); - auto code = val["code"].as_string(); - if(level != "status"){ - throw std::runtime_error(StrPrinter <<"play 失败:" << level << " " << code << endl); - } - }; - addOnStatusCB(fun); - addOnStatusCB(fun); + AMFEncoder enc; + enc << "play" << ++_iReqID << nullptr << _strStream << (double)_ui32StreamId; + sendRequest(MSG_CMD, enc.data()); + auto fun = [this](AMFValue &val){ + //TraceL << "play onStatus"; + auto level = val["level"].as_string(); + auto code = val["code"].as_string(); + if(level != "status"){ + throw std::runtime_error(StrPrinter <<"play 失败:" << level << " " << code << endl); + } + }; + addOnStatusCB(fun); + addOnStatusCB(fun); } inline void RtmpPlayer::send_pause(bool bPause) { - AMFEncoder enc; - enc << "pause" << ++_iReqID << nullptr << bPause; - sendRequest(MSG_CMD, enc.data()); - auto fun = [this,bPause](AMFValue &val){ + AMFEncoder enc; + enc << "pause" << ++_iReqID << nullptr << bPause; + sendRequest(MSG_CMD, enc.data()); + auto fun = [this,bPause](AMFValue &val){ //TraceL << "pause onStatus"; auto level = val["level"].as_string(); auto code = val["code"].as_string(); @@ -250,147 +234,147 @@ inline void RtmpPlayer::send_pause(bool bPause) { _pMediaTimer.reset(); } } - }; - addOnStatusCB(fun); + }; + addOnStatusCB(fun); - _pBeatTimer.reset(); - if(bPause){ - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as() / 1000.0,[weakSelf](){ - auto strongSelf = weakSelf.lock(); - if (!strongSelf){ - return false; - } - uint32_t timeStamp = ::time(NULL); - strongSelf->sendUserControl(CONTROL_PING_REQUEST, timeStamp); - return true; - },getPoller())); - } + _pBeatTimer.reset(); + if(bPause){ + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + _pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as() / 1000.0,[weakSelf](){ + auto strongSelf = weakSelf.lock(); + if (!strongSelf){ + return false; + } + uint32_t timeStamp = ::time(NULL); + strongSelf->sendUserControl(CONTROL_PING_REQUEST, timeStamp); + return true; + },getPoller())); + } } void RtmpPlayer::onCmd_result(AMFDecoder &dec){ - auto iReqId = dec.load(); - lock_guard lck(_mtxOnResultCB); - auto it = _mapOnResultCB.find(iReqId); - if(it != _mapOnResultCB.end()){ - it->second(dec); - _mapOnResultCB.erase(it); - }else{ - WarnL << "unhandled _result"; - } + auto iReqId = dec.load(); + lock_guard lck(_mtxOnResultCB); + auto it = _mapOnResultCB.find(iReqId); + if(it != _mapOnResultCB.end()){ + it->second(dec); + _mapOnResultCB.erase(it); + }else{ + WarnL << "unhandled _result"; + } } void RtmpPlayer::onCmd_onStatus(AMFDecoder &dec) { - AMFValue val; - while(true){ - val = dec.load(); - if(val.type() == AMF_OBJECT){ - break; - } - } - if(val.type() != AMF_OBJECT){ - throw std::runtime_error("onStatus:the result object was not found"); - } + AMFValue val; + while(true){ + val = dec.load(); + if(val.type() == AMF_OBJECT){ + break; + } + } + if(val.type() != AMF_OBJECT){ + throw std::runtime_error("onStatus:the result object was not found"); + } lock_guard lck(_mtxOnStatusCB); - if(_dqOnStatusCB.size()){ - _dqOnStatusCB.front()(val); - _dqOnStatusCB.pop_front(); - }else{ - auto level = val["level"]; - auto code = val["code"].as_string(); - if(level.type() == AMF_STRING){ - if(level.as_string() != "status"){ - throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); - } - } - //WarnL << "unhandled onStatus:" << code; + if(_dqOnStatusCB.size()){ + _dqOnStatusCB.front()(val); + _dqOnStatusCB.pop_front(); + }else{ + auto level = val["level"]; + auto code = val["code"].as_string(); + if(level.type() == AMF_STRING){ + if(level.as_string() != "status"){ + throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); + } + } + //WarnL << "unhandled onStatus:" << code; } } void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) { - //TraceL; - auto val = dec.load(); - if(!onCheckMeta(val)){ - throw std::runtime_error("onCheckMeta failed"); - } - _metadata_got = true; + //TraceL; + auto val = dec.load(); + if(!onCheckMeta(val)){ + throw std::runtime_error("onCheckMeta failed"); + } + _metadata_got = true; } void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) { - //TraceL << ui32StreamId; - onPlayResult_l(SockException(Err_other,"rtmp stream dry"), true); + //TraceL << ui32StreamId; + onPlayResult_l(SockException(Err_other,"rtmp stream dry"), true); } void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) { - _mediaTicker.resetTime(); - if(!_pPlayTimer){ - //已经触发了onPlayResult事件,直接触发onMediaData事件 - onMediaData(packet); - return; - } + _mediaTicker.resetTime(); + if(!_pPlayTimer){ + //已经触发了onPlayResult事件,直接触发onMediaData事件 + onMediaData(packet); + return; + } - if(packet->isCfgFrame()){ - //输入配置帧以便初始化完成各个track - onMediaData(packet); - }else{ - //先触发onPlayResult事件,这个时候解码器才能初始化完毕 - onPlayResult_l(SockException(Err_success,"play rtmp success"), false); - //触发onPlayResult事件后,再把帧数据输入到解码器 - onMediaData(packet); - } + if(packet->isCfgFrame()){ + //输入配置帧以便初始化完成各个track + onMediaData(packet); + }else{ + //先触发onPlayResult事件,这个时候解码器才能初始化完毕 + onPlayResult_l(SockException(Err_success,"play rtmp success"), false); + //触发onPlayResult事件后,再把帧数据输入到解码器 + onMediaData(packet); + } } void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { - typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec); - static unordered_map s_func_map; - static onceToken token([]() { - s_func_map.emplace("_error",&RtmpPlayer::onCmd_result); - s_func_map.emplace("_result",&RtmpPlayer::onCmd_result); - s_func_map.emplace("onStatus",&RtmpPlayer::onCmd_onStatus); - s_func_map.emplace("onMetaData",&RtmpPlayer::onCmd_onMetaData); - }, []() {}); + typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec); + static unordered_map s_func_map; + static onceToken token([]() { + s_func_map.emplace("_error",&RtmpPlayer::onCmd_result); + s_func_map.emplace("_result",&RtmpPlayer::onCmd_result); + s_func_map.emplace("onStatus",&RtmpPlayer::onCmd_onStatus); + s_func_map.emplace("onMetaData",&RtmpPlayer::onCmd_onMetaData); + }, []() {}); - switch (chunkData.typeId) { - case MSG_CMD: - case MSG_CMD3: - case MSG_DATA: - case MSG_DATA3: { - AMFDecoder dec(chunkData.strBuf, 0); - std::string type = dec.load(); - auto it = s_func_map.find(type); - if(it != s_func_map.end()){ - auto fun = it->second; - (this->*fun)(dec); - }else{ - WarnL << "can not support cmd:" << type; - } - } - break; - case MSG_AUDIO: - case MSG_VIDEO: { + switch (chunkData.typeId) { + case MSG_CMD: + case MSG_CMD3: + case MSG_DATA: + case MSG_DATA3: { + AMFDecoder dec(chunkData.strBuf, 0); + std::string type = dec.load(); + auto it = s_func_map.find(type); + if(it != s_func_map.end()){ + auto fun = it->second; + (this->*fun)(dec); + }else{ + WarnL << "can not support cmd:" << type; + } + } + break; + case MSG_AUDIO: + case MSG_VIDEO: { auto idx = chunkData.typeId%2; if (_aNowStampTicker[idx].elapsedTime() > 500) { - //计算播放进度时间轴用 + //计算播放进度时间轴用 _aiNowStamp[idx] = chunkData.timeStamp; } - if(!_metadata_got){ - if(!onCheckMeta(TitleMeta().getMetadata())){ - throw std::runtime_error("onCheckMeta failed"); - } - _metadata_got = true; - } - onMediaData_l(std::make_shared(std::move(chunkData))); - } - break; - default: - //WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); - break; - } + if(!_metadata_got){ + if(!onCheckMeta(TitleMeta().getMetadata())){ + throw std::runtime_error("onCheckMeta failed"); + } + _metadata_got = true; + } + onMediaData_l(std::make_shared(std::move(chunkData))); + } + break; + default: + //WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); + break; + } } uint32_t RtmpPlayer::getProgressMilliSecond() const{ - uint32_t iTime[2] = {0,0}; + uint32_t iTime[2] = {0,0}; for(auto i = 0 ;i < 2 ;i++){ iTime[i] = _aiNowStamp[i] - _aiFistStamp[i]; } @@ -407,7 +391,7 @@ void RtmpPlayer::seekToMilliSecond(uint32_t seekMS){ //TraceL << "seek result"; _aNowStampTicker[0].resetTime(); _aNowStampTicker[1].resetTime(); - int iTimeInc = seekMS - getProgressMilliSecond(); + int iTimeInc = seekMS - getProgressMilliSecond(); for(auto i = 0 ;i < 2 ;i++){ _aiFistStamp[i] = _aiNowStamp[i] + iTimeInc; _aiNowStamp[i] = _aiFistStamp[i]; diff --git a/src/Rtmp/RtmpPlayer.h b/src/Rtmp/RtmpPlayer.h index 10bc8ff1..d3f61fc6 100644 --- a/src/Rtmp/RtmpPlayer.h +++ b/src/Rtmp/RtmpPlayer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RtmpPlayer2_H_ @@ -47,77 +31,77 @@ namespace mediakit { //实现了rtmp播放器协议部分的功能,及数据接收功能 class RtmpPlayer:public PlayerBase, public TcpClient, public RtmpProtocol{ public: - typedef std::shared_ptr Ptr; - RtmpPlayer(const EventPoller::Ptr &poller); - virtual ~RtmpPlayer(); + typedef std::shared_ptr Ptr; + RtmpPlayer(const EventPoller::Ptr &poller); + virtual ~RtmpPlayer(); - void play(const string &strUrl) override; - void pause(bool bPause) override; - void teardown() override; + void play(const string &strUrl) override; + void pause(bool bPause) override; + void teardown() override; protected: - virtual bool onCheckMeta(const AMFValue &val) =0; - virtual void onMediaData(const RtmpPacket::Ptr &chunkData) =0; - uint32_t getProgressMilliSecond() const; - void seekToMilliSecond(uint32_t ms); + virtual bool onCheckMeta(const AMFValue &val) =0; + virtual void onMediaData(const RtmpPacket::Ptr &chunkData) =0; + uint32_t getProgressMilliSecond() const; + void seekToMilliSecond(uint32_t ms); protected: - void onMediaData_l(const RtmpPacket::Ptr &chunkData); - //在获取config帧后才触发onPlayResult_l(而不是收到play命令回复),所以此时所有track都初始化完毕了 - void onPlayResult_l(const SockException &ex, bool handshakeCompleted); + void onMediaData_l(const RtmpPacket::Ptr &chunkData); + //在获取config帧后才触发onPlayResult_l(而不是收到play命令回复),所以此时所有track都初始化完毕了 + void onPlayResult_l(const SockException &ex, bool handshakeCompleted); - //form Tcpclient - void onRecv(const Buffer::Ptr &pBuf) override; - void onConnect(const SockException &err) override; - void onErr(const SockException &ex) override; - //from RtmpProtocol - void onRtmpChunk(RtmpPacket &chunkData) override; - void onStreamDry(uint32_t ui32StreamId) override; + //form Tcpclient + void onRecv(const Buffer::Ptr &pBuf) override; + void onConnect(const SockException &err) override; + void onErr(const SockException &ex) override; + //from RtmpProtocol + void onRtmpChunk(RtmpPacket &chunkData) override; + void onStreamDry(uint32_t ui32StreamId) override; void onSendRawData(const Buffer::Ptr &buffer) override{ send(buffer); } - template - inline void addOnResultCB(const FUN &fun) { - lock_guard lck(_mtxOnResultCB); - _mapOnResultCB.emplace(_iReqID, fun); - } - template - inline void addOnStatusCB(const FUN &fun) { - lock_guard lck(_mtxOnStatusCB); - _dqOnStatusCB.emplace_back(fun); - } + template + inline void addOnResultCB(const FUN &fun) { + lock_guard lck(_mtxOnResultCB); + _mapOnResultCB.emplace(_iReqID, fun); + } + template + inline void addOnStatusCB(const FUN &fun) { + lock_guard lck(_mtxOnStatusCB); + _dqOnStatusCB.emplace_back(fun); + } - void onCmd_result(AMFDecoder &dec); - void onCmd_onStatus(AMFDecoder &dec); - void onCmd_onMetaData(AMFDecoder &dec); + void onCmd_result(AMFDecoder &dec); + void onCmd_onStatus(AMFDecoder &dec); + void onCmd_onMetaData(AMFDecoder &dec); - inline void send_connect(); - inline void send_createStream(); - inline void send_play(); - inline void send_pause(bool bPause); + inline void send_connect(); + inline void send_createStream(); + inline void send_play(); + inline void send_pause(bool bPause); private: - string _strApp; - string _strStream; - string _strTcUrl; - bool _bPaused = false; + string _strApp; + string _strStream; + string _strTcUrl; + bool _bPaused = false; - unordered_map > _mapOnResultCB; - recursive_mutex _mtxOnResultCB; - deque > _dqOnStatusCB; - recursive_mutex _mtxOnStatusCB; + unordered_map > _mapOnResultCB; + recursive_mutex _mtxOnResultCB; + deque > _dqOnStatusCB; + recursive_mutex _mtxOnStatusCB; - //超时功能实现 - Ticker _mediaTicker; - std::shared_ptr _pMediaTimer; - std::shared_ptr _pPlayTimer; - //心跳定时器 - std::shared_ptr _pBeatTimer; + //超时功能实现 + Ticker _mediaTicker; + std::shared_ptr _pMediaTimer; + std::shared_ptr _pPlayTimer; + //心跳定时器 + std::shared_ptr _pBeatTimer; - //播放进度控制 - uint32_t _iSeekTo = 0; - uint32_t _aiFistStamp[2] = { 0, 0 }; - uint32_t _aiNowStamp[2] = { 0, 0 }; - Ticker _aNowStampTicker[2]; - bool _metadata_got = false; + //播放进度控制 + uint32_t _iSeekTo = 0; + uint32_t _aiFistStamp[2] = { 0, 0 }; + uint32_t _aiNowStamp[2] = { 0, 0 }; + Ticker _aNowStampTicker[2]; + bool _metadata_got = false; }; } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpPlayerImp.h b/src/Rtmp/RtmpPlayerImp.h index e90acc43..f7678dbe 100644 --- a/src/Rtmp/RtmpPlayerImp.h +++ b/src/Rtmp/RtmpPlayerImp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPPLAYERIMP_H_ @@ -73,7 +57,7 @@ private: return true; } void onMediaData(const RtmpPacket::Ptr &chunkData) override { - if(_pRtmpMediaSrc){ + if(_pRtmpMediaSrc){ if(!_set_meta_data && !chunkData->isCfgFrame()){ _set_meta_data = true; _pRtmpMediaSrc->setMetaData(TitleMeta().getMetadata()); @@ -81,7 +65,7 @@ private: _pRtmpMediaSrc->onWrite(chunkData); } if(!_delegate){ - //这个流没有metadata + //这个流没有metadata _delegate.reset(new RtmpDemuxer()); } _delegate->inputRtmp(chunkData); diff --git a/src/Rtmp/RtmpProtocol.cpp b/src/Rtmp/RtmpProtocol.cpp index 4de21a47..3789b3c3 100644 --- a/src/Rtmp/RtmpProtocol.cpp +++ b/src/Rtmp/RtmpProtocol.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "RtmpProtocol.h" #include "Rtmp/utils.h" #include "Util/util.h" @@ -36,28 +21,28 @@ using namespace toolkit; #include static string openssl_HMACsha256(const void *key,unsigned int key_len, - const void *data,unsigned int data_len){ - std::shared_ptr out(new char[32],[](char *ptr){delete [] ptr;}); - unsigned int out_len; + const void *data,unsigned int data_len){ + std::shared_ptr out(new char[32],[](char *ptr){delete [] ptr;}); + unsigned int out_len; #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER > 0x10100000L) //openssl 1.1.0新增api,老版本api作废 - HMAC_CTX *ctx = HMAC_CTX_new(); - HMAC_CTX_reset(ctx); - HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), NULL); - HMAC_Update(ctx, (unsigned char*)data, data_len); - HMAC_Final(ctx, (unsigned char *)out.get(), &out_len); - HMAC_CTX_reset(ctx); - HMAC_CTX_free(ctx); + HMAC_CTX *ctx = HMAC_CTX_new(); + HMAC_CTX_reset(ctx); + HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), NULL); + HMAC_Update(ctx, (unsigned char*)data, data_len); + HMAC_Final(ctx, (unsigned char *)out.get(), &out_len); + HMAC_CTX_reset(ctx); + HMAC_CTX_free(ctx); #else - HMAC_CTX ctx; - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL); - HMAC_Update(&ctx, (unsigned char*)data, data_len); - HMAC_Final(&ctx, (unsigned char *)out.get(), &out_len); - HMAC_CTX_cleanup(&ctx); + HMAC_CTX ctx; + HMAC_CTX_init(&ctx); + HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL); + HMAC_Update(&ctx, (unsigned char*)data, data_len); + HMAC_Final(&ctx, (unsigned char *)out.get(), &out_len); + HMAC_CTX_cleanup(&ctx); #endif //defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER > 0x10100000L) - return string(out.get(),out_len); + return string(out.get(),out_len); } #endif //ENABLE_OPENSSL @@ -74,117 +59,117 @@ static string openssl_HMACsha256(const void *key,unsigned int key_len, namespace mediakit { RtmpProtocol::RtmpProtocol() { - _nextHandle = [this](){ - handle_C0C1(); - }; + _nextHandle = [this](){ + handle_C0C1(); + }; } RtmpProtocol::~RtmpProtocol() { - reset(); + reset(); } void RtmpProtocol::reset() { - ////////////ChunkSize//////////// - _iChunkLenIn = DEFAULT_CHUNK_LEN; - _iChunkLenOut = DEFAULT_CHUNK_LEN; - ////////////Acknowledgement//////////// - _ui32ByteSent = 0; - _ui32LastSent = 0; - _ui32WinSize = 0; - ///////////PeerBandwidth/////////// - _ui32Bandwidth = 2500000; - _ui8LimitType = 2; - ////////////Chunk//////////// - _mapChunkData.clear(); - _iNowStreamID = 0; - _iNowChunkID = 0; - //////////Invoke Request////////// - _iReqID = 0; - //////////Rtmp parser////////// - _strRcvBuf.clear(); - _ui32StreamId = STREAM_CONTROL; - _nextHandle = [this]() { - handle_C0C1(); - }; + ////////////ChunkSize//////////// + _iChunkLenIn = DEFAULT_CHUNK_LEN; + _iChunkLenOut = DEFAULT_CHUNK_LEN; + ////////////Acknowledgement//////////// + _ui32ByteSent = 0; + _ui32LastSent = 0; + _ui32WinSize = 0; + ///////////PeerBandwidth/////////// + _ui32Bandwidth = 2500000; + _ui8LimitType = 2; + ////////////Chunk//////////// + _mapChunkData.clear(); + _iNowStreamID = 0; + _iNowChunkID = 0; + //////////Invoke Request////////// + _iReqID = 0; + //////////Rtmp parser////////// + _strRcvBuf.clear(); + _ui32StreamId = STREAM_CONTROL; + _nextHandle = [this]() { + handle_C0C1(); + }; } void RtmpProtocol::sendAcknowledgement(uint32_t ui32Size) { - std::string control; - uint32_t stream = htonl(ui32Size); - control.append((char *) &stream, 4); - sendRequest(MSG_ACK, control); + std::string control; + uint32_t stream = htonl(ui32Size); + control.append((char *) &stream, 4); + sendRequest(MSG_ACK, control); } void RtmpProtocol::sendAcknowledgementSize(uint32_t ui32Size) { - uint32_t windowSize = htonl(ui32Size); - std::string set_windowSize((char *) &windowSize, 4); - sendRequest(MSG_WIN_SIZE, set_windowSize); + uint32_t windowSize = htonl(ui32Size); + std::string set_windowSize((char *) &windowSize, 4); + sendRequest(MSG_WIN_SIZE, set_windowSize); } void RtmpProtocol::sendPeerBandwidth(uint32_t ui32Size) { - uint32_t peerBandwidth = htonl(ui32Size); - std::string set_peerBandwidth((char *) &peerBandwidth, 4); - set_peerBandwidth.push_back((char) 0x02); - sendRequest(MSG_SET_PEER_BW, set_peerBandwidth); + uint32_t peerBandwidth = htonl(ui32Size); + std::string set_peerBandwidth((char *) &peerBandwidth, 4); + set_peerBandwidth.push_back((char) 0x02); + sendRequest(MSG_SET_PEER_BW, set_peerBandwidth); } void RtmpProtocol::sendChunkSize(uint32_t ui32Size) { - uint32_t len = htonl(ui32Size); - std::string set_chunk((char *) &len, 4); - sendRequest(MSG_SET_CHUNK, set_chunk); - _iChunkLenOut = ui32Size; + uint32_t len = htonl(ui32Size); + std::string set_chunk((char *) &len, 4); + sendRequest(MSG_SET_CHUNK, set_chunk); + _iChunkLenOut = ui32Size; } void RtmpProtocol::sendPingRequest(uint32_t ui32TimeStamp) { - sendUserControl(CONTROL_PING_REQUEST, ui32TimeStamp); + sendUserControl(CONTROL_PING_REQUEST, ui32TimeStamp); } void RtmpProtocol::sendPingResponse(uint32_t ui32TimeStamp) { - sendUserControl(CONTROL_PING_RESPONSE, ui32TimeStamp); + sendUserControl(CONTROL_PING_RESPONSE, ui32TimeStamp); } void RtmpProtocol::sendSetBufferLength(uint32_t ui32StreamId, - uint32_t ui32Length) { - std::string control; - ui32StreamId = htonl(ui32StreamId); - control.append((char *) &ui32StreamId, 4); - ui32Length = htonl(ui32Length); - control.append((char *) &ui32Length, 4); - sendUserControl(CONTROL_SETBUFFER, control); + uint32_t ui32Length) { + std::string control; + ui32StreamId = htonl(ui32StreamId); + control.append((char *) &ui32StreamId, 4); + ui32Length = htonl(ui32Length); + control.append((char *) &ui32Length, 4); + sendUserControl(CONTROL_SETBUFFER, control); } void RtmpProtocol::sendUserControl(uint16_t ui16EventType, - uint32_t ui32EventData) { - std::string control; - uint16_t type = htons(ui16EventType); - control.append((char *) &type, 2); - uint32_t stream = htonl(ui32EventData); - control.append((char *) &stream, 4); - sendRequest(MSG_USER_CONTROL, control); + uint32_t ui32EventData) { + std::string control; + uint16_t type = htons(ui16EventType); + control.append((char *) &type, 2); + uint32_t stream = htonl(ui32EventData); + control.append((char *) &stream, 4); + sendRequest(MSG_USER_CONTROL, control); } void RtmpProtocol::sendUserControl(uint16_t ui16EventType, - const string& strEventData) { - std::string control; - uint16_t type = htons(ui16EventType); - control.append((char *) &type, 2); - control.append(strEventData); - sendRequest(MSG_USER_CONTROL, control); + const string& strEventData) { + std::string control; + uint16_t type = htons(ui16EventType); + control.append((char *) &type, 2); + control.append(strEventData); + sendRequest(MSG_USER_CONTROL, control); } void RtmpProtocol::sendResponse(int iType, const string& str) { - if(!_bDataStarted && (iType == MSG_DATA)){ - _bDataStarted = true; - } - sendRtmp(iType, _iNowStreamID, str, 0, _bDataStarted ? CHUNK_CLIENT_REQUEST_AFTER : CHUNK_CLIENT_REQUEST_BEFORE); + if(!_bDataStarted && (iType == MSG_DATA)){ + _bDataStarted = true; + } + sendRtmp(iType, _iNowStreamID, str, 0, _bDataStarted ? CHUNK_CLIENT_REQUEST_AFTER : CHUNK_CLIENT_REQUEST_BEFORE); } void RtmpProtocol::sendInvoke(const string& strCmd, const AMFValue& val) { - AMFEncoder enc; - enc << strCmd << ++_iReqID << val; - sendRequest(MSG_CMD, enc.data()); + AMFEncoder enc; + enc << strCmd << ++_iReqID << val; + sendRequest(MSG_CMD, enc.data()); } void RtmpProtocol::sendRequest(int iCmd, const string& str) { - sendRtmp(iCmd, _ui32StreamId, str, 0, CHUNK_SERVER_REQUEST); + sendRtmp(iCmd, _ui32StreamId, str, 0, CHUNK_SERVER_REQUEST); } class BufferPartial : public Buffer { @@ -220,15 +205,15 @@ void RtmpProtocol::sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, auto strErr = StrPrinter << "不支持发送该类型的块流 ID:" << iChunkId << endl; throw std::runtime_error(strErr); } - //是否有扩展时间戳 + //是否有扩展时间戳 bool bExtStamp = ui32TimeStamp >= 0xFFFFFF; //rtmp头 - BufferRaw::Ptr bufferHeader = obtainBuffer(); - bufferHeader->setCapacity(sizeof(RtmpHeader)); - bufferHeader->setSize(sizeof(RtmpHeader)); - //对rtmp头赋值,如果使用整形赋值,在arm android上可能由于数据对齐导致总线错误的问题 - RtmpHeader *header = (RtmpHeader*) bufferHeader->data(); + BufferRaw::Ptr bufferHeader = obtainBuffer(); + bufferHeader->setCapacity(sizeof(RtmpHeader)); + bufferHeader->setSize(sizeof(RtmpHeader)); + //对rtmp头赋值,如果使用整形赋值,在arm android上可能由于数据对齐导致总线错误的问题 + RtmpHeader *header = (RtmpHeader*) bufferHeader->data(); header->flags = (iChunkId & 0x3f) | (0 << 6); header->typeId = ui8Type; set_be24(header->timeStamp, bExtStamp ? 0xFFFFFF : ui32TimeStamp); @@ -238,23 +223,23 @@ void RtmpProtocol::sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, onSendRawData(bufferHeader); //扩展时间戳字段 - BufferRaw::Ptr bufferExtStamp; + BufferRaw::Ptr bufferExtStamp; if (bExtStamp) { //生成扩展时间戳 - bufferExtStamp = obtainBuffer(); - bufferExtStamp->setCapacity(4); - bufferExtStamp->setSize(4); - set_be32(bufferExtStamp->data(), ui32TimeStamp); - } + bufferExtStamp = obtainBuffer(); + bufferExtStamp->setCapacity(4); + bufferExtStamp->setSize(4); + set_be32(bufferExtStamp->data(), ui32TimeStamp); + } - //生成一个字节的flag,标明是什么chunkId - BufferRaw::Ptr bufferFlags = obtainBuffer(); - bufferFlags->setCapacity(1); - bufferFlags->setSize(1); - bufferFlags->data()[0] = (iChunkId & 0x3f) | (3 << 6); + //生成一个字节的flag,标明是什么chunkId + BufferRaw::Ptr bufferFlags = obtainBuffer(); + bufferFlags->setCapacity(1); + bufferFlags->setSize(1); + bufferFlags->data()[0] = (iChunkId & 0x3f) | (3 << 6); size_t offset = 0; - uint32_t totalSize = sizeof(RtmpHeader); + uint32_t totalSize = sizeof(RtmpHeader); while (offset < buf->size()) { if (offset) { onSendRawData(bufferFlags); @@ -279,122 +264,122 @@ void RtmpProtocol::sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, void RtmpProtocol::onParseRtmp(const char *pcRawData, int iSize) { - _strRcvBuf.append(pcRawData, iSize); - auto cb = _nextHandle; - cb(); + _strRcvBuf.append(pcRawData, iSize); + auto cb = _nextHandle; + cb(); } ////for client//// void RtmpProtocol::startClientSession(const function &callBack) { - //发送 C0C1 - char handshake_head = HANDSHAKE_PLAINTEXT; - onSendRawData(obtainBuffer(&handshake_head, 1)); - RtmpHandshake c1(0); - onSendRawData(obtainBuffer((char *) (&c1), sizeof(c1))); - _nextHandle = [this,callBack]() { - //等待 S0+S1+S2 - handle_S0S1S2(callBack); - }; + //发送 C0C1 + char handshake_head = HANDSHAKE_PLAINTEXT; + onSendRawData(obtainBuffer(&handshake_head, 1)); + RtmpHandshake c1(0); + onSendRawData(obtainBuffer((char *) (&c1), sizeof(c1))); + _nextHandle = [this,callBack]() { + //等待 S0+S1+S2 + handle_S0S1S2(callBack); + }; } void RtmpProtocol::handle_S0S1S2(const function &callBack) { - if (_strRcvBuf.size() < 1 + 2 * C1_HANDSHARK_SIZE) { - //数据不够 - return; - } - if (_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) { - throw std::runtime_error("only plaintext[0x03] handshake supported"); - } - //发送 C2 - const char *pcC2 = _strRcvBuf.data() + 1; - onSendRawData(obtainBuffer(pcC2, C1_HANDSHARK_SIZE)); - _strRcvBuf.erase(0, 1 + 2 * C1_HANDSHARK_SIZE); - //握手结束 - _nextHandle = [this]() { - //握手结束并且开始进入解析命令模式 - handle_rtmp(); - }; - callBack(); + if (_strRcvBuf.size() < 1 + 2 * C1_HANDSHARK_SIZE) { + //数据不够 + return; + } + if (_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) { + throw std::runtime_error("only plaintext[0x03] handshake supported"); + } + //发送 C2 + const char *pcC2 = _strRcvBuf.data() + 1; + onSendRawData(obtainBuffer(pcC2, C1_HANDSHARK_SIZE)); + _strRcvBuf.erase(0, 1 + 2 * C1_HANDSHARK_SIZE); + //握手结束 + _nextHandle = [this]() { + //握手结束并且开始进入解析命令模式 + handle_rtmp(); + }; + callBack(); } ////for server //// void RtmpProtocol::handle_C0C1() { - if (_strRcvBuf.size() < 1 + C1_HANDSHARK_SIZE) { - //need more data! - return; - } - if (_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) { - throw std::runtime_error("only plaintext[0x03] handshake supported"); - } - if(memcmp(_strRcvBuf.data() + 5,"\x00\x00\x00\x00",4) ==0 ){ - //simple handsharke - handle_C1_simple(); - }else{ + if (_strRcvBuf.size() < 1 + C1_HANDSHARK_SIZE) { + //need more data! + return; + } + if (_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) { + throw std::runtime_error("only plaintext[0x03] handshake supported"); + } + if(memcmp(_strRcvBuf.data() + 5,"\x00\x00\x00\x00",4) ==0 ){ + //simple handsharke + handle_C1_simple(); + }else{ #ifdef ENABLE_OPENSSL - //complex handsharke - handle_C1_complex(); + //complex handsharke + handle_C1_complex(); #else - WarnL << "未打开ENABLE_OPENSSL宏,复杂握手采用简单方式处理,flash播放器可能无法播放!"; - handle_C1_simple(); + WarnL << "未打开ENABLE_OPENSSL宏,复杂握手采用简单方式处理,flash播放器可能无法播放!"; + handle_C1_simple(); #endif//ENABLE_OPENSSL - } - _strRcvBuf.erase(0, 1 + C1_HANDSHARK_SIZE); + } + _strRcvBuf.erase(0, 1 + C1_HANDSHARK_SIZE); } void RtmpProtocol::handle_C1_simple(){ - //发送S0 - char handshake_head = HANDSHAKE_PLAINTEXT; - onSendRawData(obtainBuffer(&handshake_head, 1)); - //发送S1 - RtmpHandshake s1(0); - onSendRawData(obtainBuffer((char *) &s1, C1_HANDSHARK_SIZE)); - //发送S2 - onSendRawData(obtainBuffer(_strRcvBuf.data() + 1, C1_HANDSHARK_SIZE)); - //等待C2 - _nextHandle = [this]() { - handle_C2(); - }; + //发送S0 + char handshake_head = HANDSHAKE_PLAINTEXT; + onSendRawData(obtainBuffer(&handshake_head, 1)); + //发送S1 + RtmpHandshake s1(0); + onSendRawData(obtainBuffer((char *) &s1, C1_HANDSHARK_SIZE)); + //发送S2 + onSendRawData(obtainBuffer(_strRcvBuf.data() + 1, C1_HANDSHARK_SIZE)); + //等待C2 + _nextHandle = [this]() { + handle_C2(); + }; } #ifdef ENABLE_OPENSSL void RtmpProtocol::handle_C1_complex(){ - //参考自:http://blog.csdn.net/win_lin/article/details/13006803 - //skip c0,time,version - const char *c1_start = _strRcvBuf.data() + 1; - const char *schema_start = c1_start + 8; - char *digest_start; - try{ - /* c1s1 schema0 - time: 4bytes - version: 4bytes - key: 764bytes - digest: 764bytes - */ - auto digest = get_C1_digest((uint8_t *)schema_start + C1_SCHEMA_SIZE,&digest_start); - string c1_joined(c1_start,C1_HANDSHARK_SIZE); - c1_joined.erase(digest_start - c1_start , C1_DIGEST_SIZE ); - check_C1_Digest(digest,c1_joined); + //参考自:http://blog.csdn.net/win_lin/article/details/13006803 + //skip c0,time,version + const char *c1_start = _strRcvBuf.data() + 1; + const char *schema_start = c1_start + 8; + char *digest_start; + try{ + /* c1s1 schema0 + time: 4bytes + version: 4bytes + key: 764bytes + digest: 764bytes + */ + auto digest = get_C1_digest((uint8_t *)schema_start + C1_SCHEMA_SIZE,&digest_start); + string c1_joined(c1_start,C1_HANDSHARK_SIZE); + c1_joined.erase(digest_start - c1_start , C1_DIGEST_SIZE ); + check_C1_Digest(digest,c1_joined); - send_complex_S0S1S2(0,digest); + send_complex_S0S1S2(0,digest); // InfoL << "schema0"; - }catch(std::exception &ex){ - //貌似flash从来都不用schema1 + }catch(std::exception &ex){ + //貌似flash从来都不用schema1 // WarnL << "try rtmp complex schema0 failed:" << ex.what(); - try{ - /* c1s1 schema1 - time: 4bytes - version: 4bytes - digest: 764bytes - key: 764bytes - */ - auto digest = get_C1_digest((uint8_t *)schema_start,&digest_start); - string c1_joined(c1_start,C1_HANDSHARK_SIZE); - c1_joined.erase(digest_start - c1_start , C1_DIGEST_SIZE ); - check_C1_Digest(digest,c1_joined); + try{ + /* c1s1 schema1 + time: 4bytes + version: 4bytes + digest: 764bytes + key: 764bytes + */ + auto digest = get_C1_digest((uint8_t *)schema_start,&digest_start); + string c1_joined(c1_start,C1_HANDSHARK_SIZE); + c1_joined.erase(digest_start - c1_start , C1_DIGEST_SIZE ); + check_C1_Digest(digest,c1_joined); - send_complex_S0S1S2(1,digest); + send_complex_S0S1S2(1,digest); // InfoL << "schema1"; - }catch(std::exception &ex){ + }catch(std::exception &ex){ // WarnL << "try rtmp complex schema1 failed:" << ex.what(); - handle_C1_simple(); - } - } + handle_C1_simple(); + } + } } #if !defined(u_int8_t) @@ -424,353 +409,353 @@ static u_int8_t FPKey[] = { 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE }; // 62 void RtmpProtocol::check_C1_Digest(const string &digest,const string &data){ - auto sha256 = openssl_HMACsha256(FPKey,C1_FPKEY_SIZE,data.data(),data.size()); - if(sha256 != digest){ - throw std::runtime_error("digest mismatched"); - }else{ - InfoL << "check rtmp complex handshark success!"; - } + auto sha256 = openssl_HMACsha256(FPKey,C1_FPKEY_SIZE,data.data(),data.size()); + if(sha256 != digest){ + throw std::runtime_error("digest mismatched"); + }else{ + InfoL << "check rtmp complex handshark success!"; + } } string RtmpProtocol::get_C1_digest(const uint8_t *ptr,char **digestPos){ - /* 764bytes digest结构 - offset: 4bytes - random-data: (offset)bytes - digest-data: 32bytes - random-data: (764-4-offset-32)bytes - */ - int offset = 0; - for(int i=0;i> 6]; - _iNowChunkID = flags & 0x3f; - switch (_iNowChunkID) { - case 0: { - //0 值表示二字节形式,并且 ID 范围 64 - 319 - //(第二个字节 + 64)。 - if (_strRcvBuf.size() < 2) { - //need more data - return; - } - _iNowChunkID = 64 + (uint8_t) (_strRcvBuf[1]); - iOffset = 1; - } - break; - case 1: { - //1 值表示三字节形式,并且 ID 范围为 64 - 65599 - //((第三个字节) * 256 + 第二个字节 + 64)。 - if (_strRcvBuf.size() < 3) { - //need more data - return; - } - _iNowChunkID = 64 + ((uint8_t) (_strRcvBuf[2]) << 8) + (uint8_t) (_strRcvBuf[1]); - iOffset = 2; - } - break; - default: - //带有 2 值的块流 ID 被保留,用于下层协议控制消息和命令。 - break; - } + while (!_strRcvBuf.empty()) { + uint8_t flags = _strRcvBuf[0]; + int iOffset = 0; + static const size_t HEADER_LENGTH[] = { 12, 8, 4, 1 }; + size_t iHeaderLen = HEADER_LENGTH[flags >> 6]; + _iNowChunkID = flags & 0x3f; + switch (_iNowChunkID) { + case 0: { + //0 值表示二字节形式,并且 ID 范围 64 - 319 + //(第二个字节 + 64)。 + if (_strRcvBuf.size() < 2) { + //need more data + return; + } + _iNowChunkID = 64 + (uint8_t) (_strRcvBuf[1]); + iOffset = 1; + } + break; + case 1: { + //1 值表示三字节形式,并且 ID 范围为 64 - 65599 + //((第三个字节) * 256 + 第二个字节 + 64)。 + if (_strRcvBuf.size() < 3) { + //need more data + return; + } + _iNowChunkID = 64 + ((uint8_t) (_strRcvBuf[2]) << 8) + (uint8_t) (_strRcvBuf[1]); + iOffset = 2; + } + break; + default: + //带有 2 值的块流 ID 被保留,用于下层协议控制消息和命令。 + break; + } - if (_strRcvBuf.size() < iHeaderLen + iOffset) { - //need more data - return; - } - RtmpHeader &header = *((RtmpHeader *) (_strRcvBuf.data() + iOffset)); - auto &chunkData = _mapChunkData[_iNowChunkID]; - chunkData.chunkId = _iNowChunkID; - switch (iHeaderLen) { - case 12: + if (_strRcvBuf.size() < iHeaderLen + iOffset) { + //need more data + return; + } + RtmpHeader &header = *((RtmpHeader *) (_strRcvBuf.data() + iOffset)); + auto &chunkData = _mapChunkData[_iNowChunkID]; + chunkData.chunkId = _iNowChunkID; + switch (iHeaderLen) { + case 12: chunkData.hasAbsStamp = true; - chunkData.streamId = load_le32(header.streamId); - case 8: - chunkData.bodySize = load_be24(header.bodySize); - chunkData.typeId = header.typeId; - case 4: - chunkData.deltaStamp = load_be24(header.timeStamp); + chunkData.streamId = load_le32(header.streamId); + case 8: + chunkData.bodySize = load_be24(header.bodySize); + chunkData.typeId = header.typeId; + case 4: + chunkData.deltaStamp = load_be24(header.timeStamp); chunkData.hasExtStamp = chunkData.deltaStamp == 0xFFFFFF; - } - + } + if (chunkData.hasExtStamp) { - if (_strRcvBuf.size() < iHeaderLen + iOffset + 4) { - //need more data - return; - } + if (_strRcvBuf.size() < iHeaderLen + iOffset + 4) { + //need more data + return; + } chunkData.deltaStamp = load_be32(_strRcvBuf.data() + iOffset + iHeaderLen); - iOffset += 4; - } - + iOffset += 4; + } + if (chunkData.bodySize < chunkData.strBuf.size()) { - throw std::runtime_error("非法的bodySize"); - } + throw std::runtime_error("非法的bodySize"); + } + + auto iMore = min(_iChunkLenIn, chunkData.bodySize - chunkData.strBuf.size()); + if (_strRcvBuf.size() < iHeaderLen + iOffset + iMore) { + //need more data + return; + } - auto iMore = min(_iChunkLenIn, chunkData.bodySize - chunkData.strBuf.size()); - if (_strRcvBuf.size() < iHeaderLen + iOffset + iMore) { - //need more data - return; - } - chunkData.strBuf.append(_strRcvBuf, iHeaderLen + iOffset, iMore); - _strRcvBuf.erase(0, iHeaderLen + iOffset + iMore); + _strRcvBuf.erase(0, iHeaderLen + iOffset + iMore); - if (chunkData.strBuf.size() == chunkData.bodySize) { + if (chunkData.strBuf.size() == chunkData.bodySize) { //frame is ready _iNowStreamID = chunkData.streamId; chunkData.timeStamp = chunkData.deltaStamp + (chunkData.hasAbsStamp ? 0 : chunkData.timeStamp); - if(chunkData.bodySize){ - handle_rtmpChunk(chunkData); - } - chunkData.strBuf.clear(); + if(chunkData.bodySize){ + handle_rtmpChunk(chunkData); + } + chunkData.strBuf.clear(); chunkData.hasAbsStamp = false; chunkData.hasExtStamp = false; chunkData.deltaStamp = 0; - } - } + } + } } void RtmpProtocol::handle_rtmpChunk(RtmpPacket& chunkData) { - switch (chunkData.typeId) { - case MSG_ACK: { - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("MSG_ACK: Not enough data"); - } - //auto bytePeerRecv = load_be32(&chunkData.strBuf[0]); - //TraceL << "MSG_ACK:" << bytePeerRecv; - } - break; - case MSG_SET_CHUNK: { - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("MSG_SET_CHUNK :Not enough data"); - } - _iChunkLenIn = load_be32(&chunkData.strBuf[0]); - TraceL << "MSG_SET_CHUNK:" << _iChunkLenIn; - } - break; - case MSG_USER_CONTROL: { - //user control message - if (chunkData.strBuf.size() < 2) { - throw std::runtime_error("MSG_USER_CONTROL: Not enough data."); - } - uint16_t event_type = load_be16(&chunkData.strBuf[0]); - chunkData.strBuf.erase(0, 2); - switch (event_type) { - case CONTROL_PING_REQUEST: { - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("CONTROL_PING_REQUEST: Not enough data."); - } - uint32_t timeStamp = load_be32(&chunkData.strBuf[0]); - //TraceL << "CONTROL_PING_REQUEST:" << timeStamp; - sendUserControl(CONTROL_PING_RESPONSE, timeStamp); - } - break; - case CONTROL_PING_RESPONSE: { - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("CONTROL_PING_RESPONSE: Not enough data."); - } - //uint32_t timeStamp = load_be32(&chunkData.strBuf[0]); - //TraceL << "CONTROL_PING_RESPONSE:" << timeStamp; - } - break; - case CONTROL_STREAM_BEGIN: { - //开始播放 - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("CONTROL_STREAM_BEGIN: Not enough data."); - } - uint32_t stramId = load_be32(&chunkData.strBuf[0]); - onStreamBegin(stramId); - TraceL << "CONTROL_STREAM_BEGIN:" << stramId; - } - break; + switch (chunkData.typeId) { + case MSG_ACK: { + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("MSG_ACK: Not enough data"); + } + //auto bytePeerRecv = load_be32(&chunkData.strBuf[0]); + //TraceL << "MSG_ACK:" << bytePeerRecv; + } + break; + case MSG_SET_CHUNK: { + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("MSG_SET_CHUNK :Not enough data"); + } + _iChunkLenIn = load_be32(&chunkData.strBuf[0]); + TraceL << "MSG_SET_CHUNK:" << _iChunkLenIn; + } + break; + case MSG_USER_CONTROL: { + //user control message + if (chunkData.strBuf.size() < 2) { + throw std::runtime_error("MSG_USER_CONTROL: Not enough data."); + } + uint16_t event_type = load_be16(&chunkData.strBuf[0]); + chunkData.strBuf.erase(0, 2); + switch (event_type) { + case CONTROL_PING_REQUEST: { + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("CONTROL_PING_REQUEST: Not enough data."); + } + uint32_t timeStamp = load_be32(&chunkData.strBuf[0]); + //TraceL << "CONTROL_PING_REQUEST:" << timeStamp; + sendUserControl(CONTROL_PING_RESPONSE, timeStamp); + } + break; + case CONTROL_PING_RESPONSE: { + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("CONTROL_PING_RESPONSE: Not enough data."); + } + //uint32_t timeStamp = load_be32(&chunkData.strBuf[0]); + //TraceL << "CONTROL_PING_RESPONSE:" << timeStamp; + } + break; + case CONTROL_STREAM_BEGIN: { + //开始播放 + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("CONTROL_STREAM_BEGIN: Not enough data."); + } + uint32_t stramId = load_be32(&chunkData.strBuf[0]); + onStreamBegin(stramId); + TraceL << "CONTROL_STREAM_BEGIN:" << stramId; + } + break; - case CONTROL_STREAM_EOF: { - //暂停 - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("CONTROL_STREAM_EOF: Not enough data."); - } - uint32_t stramId = load_be32(&chunkData.strBuf[0]); - onStreamEof(stramId); - TraceL << "CONTROL_STREAM_EOF:" << stramId; - } - break; - case CONTROL_STREAM_DRY: { - //停止播放 - if (chunkData.strBuf.size() < 4) { - throw std::runtime_error("CONTROL_STREAM_DRY: Not enough data."); - } - uint32_t stramId = load_be32(&chunkData.strBuf[0]); - onStreamDry(stramId); - TraceL << "CONTROL_STREAM_DRY:" << stramId; - } - break; - default: - //WarnL << "unhandled user control:" << event_type; - break; - } - } - break; + case CONTROL_STREAM_EOF: { + //暂停 + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("CONTROL_STREAM_EOF: Not enough data."); + } + uint32_t stramId = load_be32(&chunkData.strBuf[0]); + onStreamEof(stramId); + TraceL << "CONTROL_STREAM_EOF:" << stramId; + } + break; + case CONTROL_STREAM_DRY: { + //停止播放 + if (chunkData.strBuf.size() < 4) { + throw std::runtime_error("CONTROL_STREAM_DRY: Not enough data."); + } + uint32_t stramId = load_be32(&chunkData.strBuf[0]); + onStreamDry(stramId); + TraceL << "CONTROL_STREAM_DRY:" << stramId; + } + break; + default: + //WarnL << "unhandled user control:" << event_type; + break; + } + } + break; - case MSG_WIN_SIZE: { - _ui32WinSize = load_be32(&chunkData.strBuf[0]); - TraceL << "MSG_WIN_SIZE:" << _ui32WinSize; - } - break; - case MSG_SET_PEER_BW: { - _ui32Bandwidth = load_be32(&chunkData.strBuf[0]); - _ui8LimitType = chunkData.strBuf[4]; - TraceL << "MSG_SET_PEER_BW:" << _ui32WinSize; - } - break; - case MSG_AGGREGATE: { - auto ptr = (uint8_t*)chunkData.strBuf.data(); - auto ptr_tail = ptr + chunkData.strBuf.length() ; - while(ptr + 8 + 3 < ptr_tail){ - auto type = *ptr; - ptr += 1; - auto size = load_be24(ptr); - ptr += 3; - auto ts = load_be24(ptr); - ptr += 3; - ts |= (*ptr << 24); - ptr += 1; + case MSG_WIN_SIZE: { + _ui32WinSize = load_be32(&chunkData.strBuf[0]); + TraceL << "MSG_WIN_SIZE:" << _ui32WinSize; + } + break; + case MSG_SET_PEER_BW: { + _ui32Bandwidth = load_be32(&chunkData.strBuf[0]); + _ui8LimitType = chunkData.strBuf[4]; + TraceL << "MSG_SET_PEER_BW:" << _ui32WinSize; + } + break; + case MSG_AGGREGATE: { + auto ptr = (uint8_t*)chunkData.strBuf.data(); + auto ptr_tail = ptr + chunkData.strBuf.length() ; + while(ptr + 8 + 3 < ptr_tail){ + auto type = *ptr; + ptr += 1; + auto size = load_be24(ptr); + ptr += 3; + auto ts = load_be24(ptr); + ptr += 3; + ts |= (*ptr << 24); + ptr += 1; - //参考ffmpeg忽略了3个字节 - /** - * while (next - pkt->data < pkt->size - RTMP_HEADER) { - type = bytestream_get_byte(&next); - size = bytestream_get_be24(&next); - cts = bytestream_get_be24(&next); - cts |= bytestream_get_byte(&next) << 24; - if (!pts) - pts = cts; - ts += cts - pts; - pts = cts; - if (size + 3 + 4 > pkt->data + pkt->size - next) - break; - bytestream_put_byte(&p, type); - bytestream_put_be24(&p, size); - bytestream_put_be24(&p, ts); - bytestream_put_byte(&p, ts >> 24); - memcpy(p, next, size + 3 + 4); - p += size + 3; - bytestream_put_be32(&p, size + RTMP_HEADER); - next += size + 3 + 4; - } - */ - ptr += 3; - //参考FFmpeg多拷贝了4个字节 - size += 4; - if(ptr + size > ptr_tail){ + //参考ffmpeg忽略了3个字节 + /** + * while (next - pkt->data < pkt->size - RTMP_HEADER) { + type = bytestream_get_byte(&next); + size = bytestream_get_be24(&next); + cts = bytestream_get_be24(&next); + cts |= bytestream_get_byte(&next) << 24; + if (!pts) + pts = cts; + ts += cts - pts; + pts = cts; + if (size + 3 + 4 > pkt->data + pkt->size - next) + break; + bytestream_put_byte(&p, type); + bytestream_put_be24(&p, size); + bytestream_put_be24(&p, ts); + bytestream_put_byte(&p, ts >> 24); + memcpy(p, next, size + 3 + 4); + p += size + 3; + bytestream_put_be32(&p, size + RTMP_HEADER); + next += size + 3 + 4; + } + */ + ptr += 3; + //参考FFmpeg多拷贝了4个字节 + size += 4; + if(ptr + size > ptr_tail){ // ErrorL << ptr + size << " " << ptr_tail << " " << ptr_tail - ptr - size; - break; - } + break; + } // DebugL << (int)type << " " << size << " " << ts << " " << chunkData.timeStamp << " " << ptr_tail - ptr; - RtmpPacket sub_packet ; - sub_packet.strBuf.resize(size); - memcpy((char *)sub_packet.strBuf.data(),ptr,size); - sub_packet.typeId = type; - sub_packet.bodySize = size; - sub_packet.timeStamp = ts; - sub_packet.streamId = chunkData.streamId; - sub_packet.chunkId = chunkData.chunkId; - handle_rtmpChunk(sub_packet); - ptr += size; - } + RtmpPacket sub_packet ; + sub_packet.strBuf.resize(size); + memcpy((char *)sub_packet.strBuf.data(),ptr,size); + sub_packet.typeId = type; + sub_packet.bodySize = size; + sub_packet.timeStamp = ts; + sub_packet.streamId = chunkData.streamId; + sub_packet.chunkId = chunkData.chunkId; + handle_rtmpChunk(sub_packet); + ptr += size; + } // InfoL << ptr_tail - ptr; - } - break; - default: - onRtmpChunk(chunkData); - break; - } + } + break; + default: + onRtmpChunk(chunkData); + break; + } } BufferRaw::Ptr RtmpProtocol::obtainBuffer() { @@ -778,9 +763,9 @@ BufferRaw::Ptr RtmpProtocol::obtainBuffer() { } BufferRaw::Ptr RtmpProtocol::obtainBuffer(const void *data, int len) { - auto buffer = obtainBuffer(); - buffer->assign((const char *)data,len); - return buffer; + auto buffer = obtainBuffer(); + buffer->assign((const char *)data,len); + return buffer; } } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpProtocol.h b/src/Rtmp/RtmpProtocol.h index d9632975..3eb2d07f 100644 --- a/src/Rtmp/RtmpProtocol.h +++ b/src/Rtmp/RtmpProtocol.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPPROTOCOL_H_ @@ -45,77 +29,77 @@ namespace mediakit { class RtmpProtocol { public: - RtmpProtocol(); - virtual ~RtmpProtocol(); - //作为客户端发送c0c1,等待s0s1s2并且回调 - void startClientSession(const function &cb); - void onParseRtmp(const char *pcRawData,int iSize); - void reset(); + RtmpProtocol(); + virtual ~RtmpProtocol(); + //作为客户端发送c0c1,等待s0s1s2并且回调 + void startClientSession(const function &cb); + void onParseRtmp(const char *pcRawData,int iSize); + void reset(); protected: - virtual void onSendRawData(const Buffer::Ptr &buffer) = 0; - virtual void onRtmpChunk(RtmpPacket &chunkData) = 0; - virtual void onStreamBegin(uint32_t ui32StreamId){ - _ui32StreamId = ui32StreamId; - } - virtual void onStreamEof(uint32_t ui32StreamId){}; - virtual void onStreamDry(uint32_t ui32StreamId){}; + virtual void onSendRawData(const Buffer::Ptr &buffer) = 0; + virtual void onRtmpChunk(RtmpPacket &chunkData) = 0; + virtual void onStreamBegin(uint32_t ui32StreamId){ + _ui32StreamId = ui32StreamId; + } + virtual void onStreamEof(uint32_t ui32StreamId){}; + virtual void onStreamDry(uint32_t ui32StreamId){}; protected: - void sendAcknowledgement(uint32_t ui32Size); - void sendAcknowledgementSize(uint32_t ui32Size); - void sendPeerBandwidth(uint32_t ui32Size); - void sendChunkSize(uint32_t ui32Size); - void sendPingRequest(uint32_t ui32TimeStamp = ::time(NULL)); - void sendPingResponse(uint32_t ui32TimeStamp = ::time(NULL)); - void sendSetBufferLength(uint32_t ui32StreamId, uint32_t ui32Length); - void sendUserControl(uint16_t ui16EventType, uint32_t ui32EventData); - void sendUserControl(uint16_t ui16EventType, const string &strEventData); + void sendAcknowledgement(uint32_t ui32Size); + void sendAcknowledgementSize(uint32_t ui32Size); + void sendPeerBandwidth(uint32_t ui32Size); + void sendChunkSize(uint32_t ui32Size); + void sendPingRequest(uint32_t ui32TimeStamp = ::time(NULL)); + void sendPingResponse(uint32_t ui32TimeStamp = ::time(NULL)); + void sendSetBufferLength(uint32_t ui32StreamId, uint32_t ui32Length); + void sendUserControl(uint16_t ui16EventType, uint32_t ui32EventData); + void sendUserControl(uint16_t ui16EventType, const string &strEventData); - void sendInvoke(const string &strCmd, const AMFValue &val); - void sendRequest(int iCmd, const string &str); - void sendResponse(int iType, const string &str); - void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const std::string &strBuf, uint32_t ui32TimeStamp, int iChunkID); - void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const Buffer::Ptr &buffer, uint32_t ui32TimeStamp, int iChunkID); + void sendInvoke(const string &strCmd, const AMFValue &val); + void sendRequest(int iCmd, const string &str); + void sendResponse(int iType, const string &str); + void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const std::string &strBuf, uint32_t ui32TimeStamp, int iChunkID); + void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const Buffer::Ptr &buffer, uint32_t ui32TimeStamp, int iChunkID); protected: - int _iReqID = 0; - uint32_t _ui32StreamId = STREAM_CONTROL; - int _iNowStreamID = 0; - int _iNowChunkID = 0; - bool _bDataStarted = false; - inline BufferRaw::Ptr obtainBuffer(); - inline BufferRaw::Ptr obtainBuffer(const void *data, int len); - //ResourcePool _bufferPool; + int _iReqID = 0; + uint32_t _ui32StreamId = STREAM_CONTROL; + int _iNowStreamID = 0; + int _iNowChunkID = 0; + bool _bDataStarted = false; + inline BufferRaw::Ptr obtainBuffer(); + inline BufferRaw::Ptr obtainBuffer(const void *data, int len); + //ResourcePool _bufferPool; private: - void handle_S0S1S2(const function &cb); - void handle_C0C1(); - void handle_C1_simple(); + void handle_S0S1S2(const function &cb); + void handle_C0C1(); + void handle_C1_simple(); #ifdef ENABLE_OPENSSL - void handle_C1_complex(); - string get_C1_digest(const uint8_t *ptr,char **digestPos); - string get_C1_key(const uint8_t *ptr); - void check_C1_Digest(const string &digest,const string &data); - void send_complex_S0S1S2(int schemeType,const string &digest); + void handle_C1_complex(); + string get_C1_digest(const uint8_t *ptr,char **digestPos); + string get_C1_key(const uint8_t *ptr); + void check_C1_Digest(const string &digest,const string &data); + void send_complex_S0S1S2(int schemeType,const string &digest); #endif //ENABLE_OPENSSL - void handle_C2(); - void handle_rtmp(); - void handle_rtmpChunk(RtmpPacket &chunkData); + void handle_C2(); + void handle_rtmp(); + void handle_rtmpChunk(RtmpPacket &chunkData); private: - ////////////ChunkSize//////////// - size_t _iChunkLenIn = DEFAULT_CHUNK_LEN; - size_t _iChunkLenOut = DEFAULT_CHUNK_LEN; - ////////////Acknowledgement//////////// - uint32_t _ui32ByteSent = 0; - uint32_t _ui32LastSent = 0; - uint32_t _ui32WinSize = 0; - ///////////PeerBandwidth/////////// - uint32_t _ui32Bandwidth = 2500000; - uint8_t _ui8LimitType = 2; - ////////////Chunk//////////// - unordered_map _mapChunkData; - //////////Rtmp parser////////// - string _strRcvBuf; - function _nextHandle; + ////////////ChunkSize//////////// + size_t _iChunkLenIn = DEFAULT_CHUNK_LEN; + size_t _iChunkLenOut = DEFAULT_CHUNK_LEN; + ////////////Acknowledgement//////////// + uint32_t _ui32ByteSent = 0; + uint32_t _ui32LastSent = 0; + uint32_t _ui32WinSize = 0; + ///////////PeerBandwidth/////////// + uint32_t _ui32Bandwidth = 2500000; + uint8_t _ui8LimitType = 2; + ////////////Chunk//////////// + unordered_map _mapChunkData; + //////////Rtmp parser////////// + string _strRcvBuf; + function _nextHandle; }; } /* namespace mediakit */ diff --git a/src/Rtmp/RtmpPusher.cpp b/src/Rtmp/RtmpPusher.cpp index ea2ebca8..c4f25df1 100644 --- a/src/Rtmp/RtmpPusher.cpp +++ b/src/Rtmp/RtmpPusher.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "RtmpPusher.h" #include "Rtmp/utils.h" #include "Util/util.h" @@ -34,55 +19,55 @@ using namespace mediakit::Client; namespace mediakit { RtmpPusher::RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src) : TcpClient(poller){ - _pMediaSrc=src; + _pMediaSrc=src; } RtmpPusher::~RtmpPusher() { - teardown(); - DebugL << endl; + teardown(); + DebugL << endl; } void RtmpPusher::teardown() { - if (alive()) { - _strApp.clear(); - _strStream.clear(); - _strTcUrl.clear(); - { - lock_guard lck(_mtxOnResultCB); - _mapOnResultCB.clear(); - } + if (alive()) { + _strApp.clear(); + _strStream.clear(); + _strTcUrl.clear(); + { + lock_guard lck(_mtxOnResultCB); + _mapOnResultCB.clear(); + } { lock_guard lck(_mtxOnStatusCB); _dqOnStatusCB.clear(); } - _pPublishTimer.reset(); + _pPublishTimer.reset(); reset(); shutdown(SockException(Err_shutdown,"teardown")); - } + } } void RtmpPusher::onPublishResult(const SockException &ex,bool handshakeCompleted) { - if(!handshakeCompleted){ - //播放结果回调 - _pPublishTimer.reset(); - if(_onPublished){ - _onPublished(ex); - } - } else { - //播放成功后异常断开回调 - if(_onShutdown){ - _onShutdown(ex); - } - } + if(!handshakeCompleted){ + //播放结果回调 + _pPublishTimer.reset(); + if(_onPublished){ + _onPublished(ex); + } + } else { + //播放成功后异常断开回调 + if(_onShutdown){ + _onShutdown(ex); + } + } - if(ex){ - teardown(); - } + if(ex){ + teardown(); + } } void RtmpPusher::publish(const string &strUrl) { - teardown(); - string strHost = FindField(strUrl.data(), "://", "/"); - _strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); + teardown(); + string strHost = FindField(strUrl.data(), "://", "/"); + _strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); _strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL); _strTcUrl = string("rtmp://") + strHost + "/" + _strApp; @@ -90,16 +75,16 @@ void RtmpPusher::publish(const string &strUrl) { onPublishResult(SockException(Err_other,"rtmp url非法"),false); return; } - DebugL << strHost << " " << _strApp << " " << _strStream; + DebugL << strHost << " " << _strApp << " " << _strStream; - auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); - if (iPort <= 0) { + auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); + if (iPort <= 0) { //rtmp 默认端口1935 - iPort = 1935; - } else { + iPort = 1935; + } else { //服务器域名 - strHost = FindField(strHost.data(), NULL, ":"); - } + strHost = FindField(strHost.data(), NULL, ":"); + } weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); float publishTimeOutSec = (*this)[kTimeoutMS].as() / 1000.0; @@ -116,23 +101,23 @@ void RtmpPusher::publish(const string &strUrl) { setNetAdapter((*this)[kNetAdapter]); } - startConnect(strHost, iPort); + startConnect(strHost, iPort); } void RtmpPusher::onErr(const SockException &ex){ - //定时器_pPublishTimer为空后表明握手结束了 - onPublishResult(ex,!_pPublishTimer); + //定时器_pPublishTimer为空后表明握手结束了 + onPublishResult(ex,!_pPublishTimer); } void RtmpPusher::onConnect(const SockException &err){ - if(err) { - onPublishResult(err,false); - return; - } - //推流器不需要多大的接收缓存,节省内存占用 - _sock->setReadBuffer(std::make_shared(1 * 1024)); + if(err) { + onPublishResult(err,false); + return; + } + //推流器不需要多大的接收缓存,节省内存占用 + _sock->setReadBuffer(std::make_shared(1 * 1024)); - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - startClientSession([weakSelf](){ + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + startClientSession([weakSelf](){ auto strongSelf=weakSelf.lock(); if(!strongSelf) { return; @@ -140,63 +125,63 @@ void RtmpPusher::onConnect(const SockException &err){ strongSelf->sendChunkSize(60000); strongSelf->send_connect(); - }); + }); } void RtmpPusher::onRecv(const Buffer::Ptr &pBuf){ - try { - onParseRtmp(pBuf->data(), pBuf->size()); - } catch (exception &e) { - SockException ex(Err_other, e.what()); - //定时器_pPublishTimer为空后表明握手结束了 - onPublishResult(ex,!_pPublishTimer); - } + try { + onParseRtmp(pBuf->data(), pBuf->size()); + } catch (exception &e) { + SockException ex(Err_other, e.what()); + //定时器_pPublishTimer为空后表明握手结束了 + onPublishResult(ex,!_pPublishTimer); + } } inline void RtmpPusher::send_connect() { - AMFValue obj(AMF_OBJECT); - obj.set("app", _strApp); - obj.set("type", "nonprivate"); - obj.set("tcUrl", _strTcUrl); - obj.set("swfUrl", _strTcUrl); - sendInvoke("connect", obj); - addOnResultCB([this](AMFDecoder &dec){ - //TraceL << "connect result"; - dec.load(); - auto val = dec.load(); - auto level = val["level"].as_string(); - auto code = val["code"].as_string(); - if(level != "status"){ - throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); - } - send_createStream(); - }); + AMFValue obj(AMF_OBJECT); + obj.set("app", _strApp); + obj.set("type", "nonprivate"); + obj.set("tcUrl", _strTcUrl); + obj.set("swfUrl", _strTcUrl); + sendInvoke("connect", obj); + addOnResultCB([this](AMFDecoder &dec){ + //TraceL << "connect result"; + dec.load(); + auto val = dec.load(); + auto level = val["level"].as_string(); + auto code = val["code"].as_string(); + if(level != "status"){ + throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); + } + send_createStream(); + }); } inline void RtmpPusher::send_createStream() { - AMFValue obj(AMF_NULL); - sendInvoke("createStream", obj); - addOnResultCB([this](AMFDecoder &dec){ - //TraceL << "createStream result"; - dec.load(); - _ui32StreamId = dec.load(); - send_publish(); - }); + AMFValue obj(AMF_NULL); + sendInvoke("createStream", obj); + addOnResultCB([this](AMFDecoder &dec){ + //TraceL << "createStream result"; + dec.load(); + _ui32StreamId = dec.load(); + send_publish(); + }); } inline void RtmpPusher::send_publish() { - AMFEncoder enc; - enc << "publish" << ++_iReqID << nullptr << _strStream << _strApp ; - sendRequest(MSG_CMD, enc.data()); + AMFEncoder enc; + enc << "publish" << ++_iReqID << nullptr << _strStream << _strApp ; + sendRequest(MSG_CMD, enc.data()); - addOnStatusCB([this](AMFValue &val) { - auto level = val["level"].as_string(); - auto code = val["code"].as_string(); - if(level != "status") { - throw std::runtime_error(StrPrinter <<"publish 失败:" << level << " " << code << endl); - } - //start send media - send_metaData(); - }); + addOnStatusCB([this](AMFValue &val) { + auto level = val["level"].as_string(); + auto code = val["code"].as_string(); + if(level != "status") { + throw std::runtime_error(StrPrinter <<"publish 失败:" << level << " " << code << endl); + } + //start send media + send_metaData(); + }); } inline void RtmpPusher::send_metaData(){ @@ -216,11 +201,11 @@ inline void RtmpPusher::send_metaData(){ _pRtmpReader = src->getRing()->attach(getPoller()); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); _pRtmpReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt){ - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - strongSelf->sendRtmp(pkt->typeId, strongSelf->_ui32StreamId, pkt, pkt->timeStamp, pkt->chunkId); + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + strongSelf->sendRtmp(pkt->typeId, strongSelf->_ui32StreamId, pkt, pkt->timeStamp, pkt->chunkId); }); _pRtmpReader->setDetachCB([weakSelf](){ auto strongSelf = weakSelf.lock(); @@ -229,84 +214,84 @@ inline void RtmpPusher::send_metaData(){ } }); onPublishResult(SockException(Err_success,"success"), false); - //提升发送性能 - setSocketFlags(); + //提升发送性能 + setSocketFlags(); } void RtmpPusher::setSocketFlags(){ - GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); - if(!ultraLowDelay) { + GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); + if(!ultraLowDelay) { //提高发送性能 (*this) << SocketFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); SockUtil::setNoDelay(_sock->rawFD(), false); - } + } } void RtmpPusher::onCmd_result(AMFDecoder &dec){ - auto iReqId = dec.load(); - lock_guard lck(_mtxOnResultCB); - auto it = _mapOnResultCB.find(iReqId); - if(it != _mapOnResultCB.end()){ - it->second(dec); - _mapOnResultCB.erase(it); - }else{ - WarnL << "unhandled _result"; - } + auto iReqId = dec.load(); + lock_guard lck(_mtxOnResultCB); + auto it = _mapOnResultCB.find(iReqId); + if(it != _mapOnResultCB.end()){ + it->second(dec); + _mapOnResultCB.erase(it); + }else{ + WarnL << "unhandled _result"; + } } void RtmpPusher::onCmd_onStatus(AMFDecoder &dec) { - AMFValue val; - while(true){ - val = dec.load(); - if(val.type() == AMF_OBJECT){ - break; - } - } - if(val.type() != AMF_OBJECT){ - throw std::runtime_error("onStatus:the result object was not found"); - } + AMFValue val; + while(true){ + val = dec.load(); + if(val.type() == AMF_OBJECT){ + break; + } + } + if(val.type() != AMF_OBJECT){ + throw std::runtime_error("onStatus:the result object was not found"); + } lock_guard lck(_mtxOnStatusCB); - if(_dqOnStatusCB.size()){ - _dqOnStatusCB.front()(val); - _dqOnStatusCB.pop_front(); - }else{ - auto level = val["level"]; - auto code = val["code"].as_string(); - if(level.type() == AMF_STRING){ - if(level.as_string() != "status"){ - throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); - } - } + if(_dqOnStatusCB.size()){ + _dqOnStatusCB.front()(val); + _dqOnStatusCB.pop_front(); + }else{ + auto level = val["level"]; + auto code = val["code"].as_string(); + if(level.type() == AMF_STRING){ + if(level.as_string() != "status"){ + throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); + } + } } } void RtmpPusher::onRtmpChunk(RtmpPacket &chunkData) { - switch (chunkData.typeId) { - case MSG_CMD: - case MSG_CMD3: { - typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec); - static unordered_map g_mapCmd; - static onceToken token([]() { - g_mapCmd.emplace("_error",&RtmpPusher::onCmd_result); - g_mapCmd.emplace("_result",&RtmpPusher::onCmd_result); - g_mapCmd.emplace("onStatus",&RtmpPusher::onCmd_onStatus); - }, []() {}); + switch (chunkData.typeId) { + case MSG_CMD: + case MSG_CMD3: { + typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec); + static unordered_map g_mapCmd; + static onceToken token([]() { + g_mapCmd.emplace("_error",&RtmpPusher::onCmd_result); + g_mapCmd.emplace("_result",&RtmpPusher::onCmd_result); + g_mapCmd.emplace("onStatus",&RtmpPusher::onCmd_onStatus); + }, []() {}); - AMFDecoder dec(chunkData.strBuf, 0); - std::string type = dec.load(); - auto it = g_mapCmd.find(type); - if(it != g_mapCmd.end()){ - auto fun = it->second; - (this->*fun)(dec); - }else{ - WarnL << "can not support cmd:" << type; - } - } - break; - default: - //WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); - break; - } + AMFDecoder dec(chunkData.strBuf, 0); + std::string type = dec.load(); + auto it = g_mapCmd.find(type); + if(it != g_mapCmd.end()){ + auto fun = it->second; + (this->*fun)(dec); + }else{ + WarnL << "can not support cmd:" << type; + } + } + break; + default: + //WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); + break; + } } diff --git a/src/Rtmp/RtmpPusher.h b/src/Rtmp/RtmpPusher.h index 9be06f37..af825968 100644 --- a/src/Rtmp/RtmpPusher.h +++ b/src/Rtmp/RtmpPusher.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPPUSHER_H_ @@ -36,66 +20,66 @@ namespace mediakit { class RtmpPusher: public RtmpProtocol , public TcpClient , public PusherBase{ public: - typedef std::shared_ptr Ptr; - RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src); - virtual ~RtmpPusher(); + typedef std::shared_ptr Ptr; + RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src); + virtual ~RtmpPusher(); - void publish(const string &strUrl) override ; + void publish(const string &strUrl) override ; - void teardown() override; + void teardown() override; - void setOnPublished(const Event &cb) override { - _onPublished = cb; - } + void setOnPublished(const Event &cb) override { + _onPublished = cb; + } - void setOnShutdown(const Event &cb) override{ - _onShutdown = cb; - } + void setOnShutdown(const Event &cb) override{ + _onShutdown = cb; + } protected: - //for Tcpclient override - void onRecv(const Buffer::Ptr &pBuf) override; - void onConnect(const SockException &err) override; - void onErr(const SockException &ex) override; + //for Tcpclient override + void onRecv(const Buffer::Ptr &pBuf) override; + void onConnect(const SockException &err) override; + void onErr(const SockException &ex) override; - //for RtmpProtocol override - void onRtmpChunk(RtmpPacket &chunkData) override; - void onSendRawData(const Buffer::Ptr &buffer) override{ - send(buffer); - } + //for RtmpProtocol override + void onRtmpChunk(RtmpPacket &chunkData) override; + void onSendRawData(const Buffer::Ptr &buffer) override{ + send(buffer); + } private: - void onPublishResult(const SockException &ex,bool handshakeCompleted); + void onPublishResult(const SockException &ex,bool handshakeCompleted); - template - inline void addOnResultCB(const FUN &fun) { - lock_guard lck(_mtxOnResultCB); - _mapOnResultCB.emplace(_iReqID, fun); - } - template - inline void addOnStatusCB(const FUN &fun) { - lock_guard lck(_mtxOnStatusCB); - _dqOnStatusCB.emplace_back(fun); - } + template + inline void addOnResultCB(const FUN &fun) { + lock_guard lck(_mtxOnResultCB); + _mapOnResultCB.emplace(_iReqID, fun); + } + template + inline void addOnStatusCB(const FUN &fun) { + lock_guard lck(_mtxOnStatusCB); + _dqOnStatusCB.emplace_back(fun); + } - void onCmd_result(AMFDecoder &dec); - void onCmd_onStatus(AMFDecoder &dec); - void onCmd_onMetaData(AMFDecoder &dec); + void onCmd_result(AMFDecoder &dec); + void onCmd_onStatus(AMFDecoder &dec); + void onCmd_onMetaData(AMFDecoder &dec); - inline void send_connect(); - inline void send_createStream(); - inline void send_publish(); - inline void send_metaData(); - void setSocketFlags(); + inline void send_connect(); + inline void send_createStream(); + inline void send_publish(); + inline void send_metaData(); + void setSocketFlags(); private: - string _strApp; - string _strStream; - string _strTcUrl; + string _strApp; + string _strStream; + string _strTcUrl; - unordered_map > _mapOnResultCB; - recursive_mutex _mtxOnResultCB; - deque > _dqOnStatusCB; - recursive_mutex _mtxOnStatusCB; - //超时功能实现 - std::shared_ptr _pPublishTimer; + unordered_map > _mapOnResultCB; + recursive_mutex _mtxOnResultCB; + deque > _dqOnStatusCB; + recursive_mutex _mtxOnStatusCB; + //超时功能实现 + std::shared_ptr _pPublishTimer; //源 std::weak_ptr _pMediaSrc; RtmpMediaSource::RingType::RingReader::Ptr _pRtmpReader; diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index 15e4342f..b8551421 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -1,38 +1,20 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ - #include "RtmpSession.h" #include "Common/config.h" #include "Util/onceToken.h" - namespace mediakit { RtmpSession::RtmpSession(const Socket::Ptr &pSock) : TcpSession(pSock) { - DebugP(this); + DebugP(this); GET_CONFIG(uint32_t,keep_alive_sec,Rtmp::kKeepAliveSecond); pSock->setSendTimeOutSecond(keep_alive_sec); //起始接收buffer缓存设置为4K,节省内存 @@ -65,42 +47,42 @@ void RtmpSession::onManager() { GET_CONFIG(uint32_t,handshake_sec,Rtmp::kHandshakeSecond); GET_CONFIG(uint32_t,keep_alive_sec,Rtmp::kKeepAliveSecond); - if (_ticker.createdTime() > handshake_sec * 1000) { - if (!_pRingReader && !_pPublisherSrc) { - shutdown(SockException(Err_timeout,"illegal connection")); - } - } - if (_pPublisherSrc) { - //publisher - if (_ticker.elapsedTime() > keep_alive_sec * 1000) { - shutdown(SockException(Err_timeout,"recv data from rtmp pusher timeout")); - } - } + if (_ticker.createdTime() > handshake_sec * 1000) { + if (!_pRingReader && !_pPublisherSrc) { + shutdown(SockException(Err_timeout,"illegal connection")); + } + } + if (_pPublisherSrc) { + //publisher + if (_ticker.elapsedTime() > keep_alive_sec * 1000) { + shutdown(SockException(Err_timeout,"recv data from rtmp pusher timeout")); + } + } } void RtmpSession::onRecv(const Buffer::Ptr &pBuf) { - _ticker.resetTime(); - try { + _ticker.resetTime(); + try { _ui64TotalBytes += pBuf->size(); - onParseRtmp(pBuf->data(), pBuf->size()); - } catch (exception &e) { - shutdown(SockException(Err_shutdown, e.what())); - } + onParseRtmp(pBuf->data(), pBuf->size()); + } catch (exception &e) { + shutdown(SockException(Err_shutdown, e.what())); + } } void RtmpSession::onCmd_connect(AMFDecoder &dec) { - auto params = dec.load(); - double amfVer = 0; - AMFValue objectEncoding = params["objectEncoding"]; - if(objectEncoding){ - amfVer = objectEncoding.as_number(); - } - ///////////set chunk size//////////////// - sendChunkSize(60000); - ////////////window Acknowledgement size///// - sendAcknowledgementSize(5000000); - ///////////set peerBandwidth//////////////// - sendPeerBandwidth(5000000); + auto params = dec.load(); + double amfVer = 0; + AMFValue objectEncoding = params["objectEncoding"]; + if(objectEncoding){ + amfVer = objectEncoding.as_number(); + } + ///////////set chunk size//////////////// + sendChunkSize(60000); + ////////////window Acknowledgement size///// + sendAcknowledgementSize(5000000); + ///////////set peerBandwidth//////////////// + sendPeerBandwidth(5000000); _mediaInfo._app = params["app"].as_string(); _strTcUrl = params["tcUrl"].as_string(); @@ -108,27 +90,27 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) { //defaultVhost:默认vhost _strTcUrl = string(RTMP_SCHEMA) + "://" + DEFAULT_VHOST + "/" + _mediaInfo._app; } - bool ok = true; //(app == APP_NAME); - AMFValue version(AMF_OBJECT); - version.set("fmsVer", "FMS/3,0,1,123"); - version.set("capabilities", 31.0); - AMFValue status(AMF_OBJECT); - status.set("level", ok ? "status" : "error"); - status.set("code", ok ? "NetConnection.Connect.Success" : "NetConnection.Connect.InvalidApp"); - status.set("description", ok ? "Connection succeeded." : "InvalidApp."); - status.set("objectEncoding", amfVer); - sendReply(ok ? "_result" : "_error", version, status); - if (!ok) { - throw std::runtime_error("Unsupported application: " + _mediaInfo._app); - } + bool ok = true; //(app == APP_NAME); + AMFValue version(AMF_OBJECT); + version.set("fmsVer", "FMS/3,0,1,123"); + version.set("capabilities", 31.0); + AMFValue status(AMF_OBJECT); + status.set("level", ok ? "status" : "error"); + status.set("code", ok ? "NetConnection.Connect.Success" : "NetConnection.Connect.InvalidApp"); + status.set("description", ok ? "Connection succeeded." : "InvalidApp."); + status.set("objectEncoding", amfVer); + sendReply(ok ? "_result" : "_error", version, status); + if (!ok) { + throw std::runtime_error("Unsupported application: " + _mediaInfo._app); + } - AMFEncoder invoke; - invoke << "onBWDone" << 0.0 << nullptr; - sendResponse(MSG_CMD, invoke.data()); + AMFEncoder invoke; + invoke << "onBWDone" << 0.0 << nullptr; + sendResponse(MSG_CMD, invoke.data()); } void RtmpSession::onCmd_createStream(AMFDecoder &dec) { - sendReply("_result", nullptr, double(STREAM_MEDIA)); + sendReply("_result", nullptr, double(STREAM_MEDIA)); } void RtmpSession::onCmd_publish(AMFDecoder &dec) { @@ -140,7 +122,7 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) { DebugP(strongSelf.get()) << "publish 回复时间:" << pTicker->elapsedTime() << "ms"; } })); - dec.load();/* NULL */ + dec.load();/* NULL */ _mediaInfo.parse(_strTcUrl + "/" + getStreamId(dec.load())); _mediaInfo._schema = RTMP_SCHEMA; @@ -203,12 +185,12 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) { } void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) { - AMFValue status(AMF_OBJECT); - status.set("level", "status"); - status.set("code", "NetStream.Unpublish.Success"); - status.set("description", "Stop publishing."); - sendReply("onStatus", nullptr, status); - throw std::runtime_error(StrPrinter << "Stop publishing" << endl); + AMFValue status(AMF_OBJECT); + status.set("level", "status"); + status.set("code", "NetStream.Unpublish.Success"); + status.set("description", "Stop publishing."); + sendReply("onStatus", nullptr, status); + throw std::runtime_error(StrPrinter << "Stop publishing" << endl); } @@ -274,6 +256,12 @@ void RtmpSession::sendPlayResponse(const string &err,const RtmpMediaSource::Ptr invoke.clear(); invoke << "onMetaData" << metadata; sendResponse(MSG_DATA, invoke.data()); + auto duration = metadata["duration"].as_number(); + if(duration > 0){ + //这是点播,使用绝对时间戳 + _stamp[0].setPlayBack(); + _stamp[1].setPlayBack(); + } } @@ -355,7 +343,7 @@ void RtmpSession::doPlay(AMFDecoder &dec){ } } void RtmpSession::onCmd_play2(AMFDecoder &dec) { - doPlay(dec); + doPlay(dec); } string RtmpSession::getStreamId(const string &str){ @@ -390,49 +378,49 @@ string RtmpSession::getStreamId(const string &str){ } void RtmpSession::onCmd_play(AMFDecoder &dec) { - dec.load();/* NULL */ + dec.load();/* NULL */ _mediaInfo.parse(_strTcUrl + "/" + getStreamId(dec.load())); _mediaInfo._schema = RTMP_SCHEMA; - doPlay(dec); + doPlay(dec); } void RtmpSession::onCmd_pause(AMFDecoder &dec) { - dec.load();/* NULL */ - bool paused = dec.load(); - TraceP(this) << paused; - AMFValue status(AMF_OBJECT); - status.set("level", "status"); - status.set("code", paused ? "NetStream.Pause.Notify" : "NetStream.Unpause.Notify"); - status.set("description", paused ? "Paused stream." : "Unpaused stream."); - sendReply("onStatus", nullptr, status); + dec.load();/* NULL */ + bool paused = dec.load(); + TraceP(this) << paused; + AMFValue status(AMF_OBJECT); + status.set("level", "status"); + status.set("code", paused ? "NetStream.Pause.Notify" : "NetStream.Unpause.Notify"); + status.set("description", paused ? "Paused stream." : "Unpaused stream."); + sendReply("onStatus", nullptr, status); //streamBegin - sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN, - STREAM_MEDIA); - if (!_pRingReader) { - throw std::runtime_error("Rtmp not started yet!"); - } - if (paused) { - _pRingReader->setReadCB(nullptr); - } else { - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } + sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN, + STREAM_MEDIA); + if (!_pRingReader) { + throw std::runtime_error("Rtmp not started yet!"); + } + if (paused) { + _pRingReader->setReadCB(nullptr); + } else { + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + _pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } strongSelf->onSendMedia(pkt); - }); - } + }); + } } void RtmpSession::setMetaData(AMFDecoder &dec) { - if (!_pPublisherSrc) { - throw std::runtime_error("not a publisher"); - } - std::string type = dec.load(); - if (type != "onMetaData") { - throw std::runtime_error("can only set metadata"); - } + if (!_pPublisherSrc) { + throw std::runtime_error("not a publisher"); + } + std::string type = dec.load(); + if (type != "onMetaData") { + throw std::runtime_error("can only set metadata"); + } auto metadata = dec.load(); // dumpMetadata(metadata); _pPublisherSrc->setMetaData(metadata); @@ -453,42 +441,42 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) { s_cmd_functions.emplace("pause",&RtmpSession::onCmd_pause);}, []() {}); std::string method = dec.load(); - auto it = s_cmd_functions.find(method); - if (it == s_cmd_functions.end()) { + auto it = s_cmd_functions.find(method); + if (it == s_cmd_functions.end()) { // TraceP(this) << "can not support cmd:" << method; - return; - } - _dNowReqID = dec.load(); - auto fun = it->second; - (this->*fun)(dec); + return; + } + _dNowReqID = dec.load(); + auto fun = it->second; + (this->*fun)(dec); } void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) { - switch (chunkData.typeId) { - case MSG_CMD: - case MSG_CMD3: { - AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); - onProcessCmd(dec); - } - break; + switch (chunkData.typeId) { + case MSG_CMD: + case MSG_CMD3: { + AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); + onProcessCmd(dec); + } + break; - case MSG_DATA: - case MSG_DATA3: { - AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); - std::string type = dec.load(); - if (type == "@setDataFrame") { - setMetaData(dec); - }else{ + case MSG_DATA: + case MSG_DATA3: { + AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); + std::string type = dec.load(); + if (type == "@setDataFrame") { + setMetaData(dec); + }else{ TraceP(this) << "unknown notify:" << type; } - } - break; - case MSG_AUDIO: - case MSG_VIDEO: { - if (!_pPublisherSrc) { - throw std::runtime_error("Not a rtmp publisher!"); - } - GET_CONFIG(bool,rtmp_modify_stamp,Rtmp::kModifyStamp); + } + break; + case MSG_AUDIO: + case MSG_VIDEO: { + if (!_pPublisherSrc) { + throw std::runtime_error("Not a rtmp publisher!"); + } + GET_CONFIG(bool,rtmp_modify_stamp,Rtmp::kModifyStamp); if(rtmp_modify_stamp){ int64_t dts_out; _stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true); @@ -500,30 +488,29 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) { _pPublisherSrc->setMetaData(TitleMeta().getMetadata()); } _pPublisherSrc->onWrite(std::make_shared(std::move(chunkData))); - } - break; - default: - WarnP(this) << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); - break; - } + } + break; + default: + WarnP(this) << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); + break; + } } void RtmpSession::onCmd_seek(AMFDecoder &dec) { dec.load();/* NULL */ + AMFValue status(AMF_OBJECT); + AMFEncoder invoke; + status.set("level", "status"); + status.set("code", "NetStream.Seek.Notify"); + status.set("description", "Seeking."); + sendReply("onStatus", nullptr, status); + auto milliSeconds = dec.load().as_number(); InfoP(this) << "rtmp seekTo(ms):" << milliSeconds; auto stongSrc = _pPlayerSrc.lock(); if (stongSrc) { - _stamp[0].setPlayBack(); - _stamp[1].setPlayBack(); stongSrc->seekTo(milliSeconds); } - AMFValue status(AMF_OBJECT); - AMFEncoder invoke; - status.set("level", "status"); - status.set("code", "NetStream.Seek.Notify"); - status.set("description", "Seeking."); - sendReply("onStatus", nullptr, status); } void RtmpSession::onSendMedia(const RtmpPacket::Ptr &pkt) { @@ -544,14 +531,6 @@ bool RtmpSession::close(MediaSource &sender,bool force) { return true; } -void RtmpSession::onNoneReader(MediaSource &sender) { - //此回调在其他线程触发 - if(!_pPublisherSrc || _pPublisherSrc->totalReaderCount()){ - return; - } - MediaSourceEvent::onNoneReader(sender); -} - int RtmpSession::totalReaderCount(MediaSource &sender) { return _pPublisherSrc ? _pPublisherSrc->totalReaderCount() : sender.readerCount(); } diff --git a/src/Rtmp/RtmpSession.h b/src/Rtmp/RtmpSession.h index f5b6df79..a61ad864 100644 --- a/src/Rtmp/RtmpSession.h +++ b/src/Rtmp/RtmpSession.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTMP_RTMPSESSION_H_ @@ -45,65 +29,64 @@ namespace mediakit { class RtmpSession: public TcpSession ,public RtmpProtocol , public MediaSourceEvent{ public: - typedef std::shared_ptr Ptr; - RtmpSession(const Socket::Ptr &_sock); - virtual ~RtmpSession(); - void onRecv(const Buffer::Ptr &pBuf) override; - void onError(const SockException &err) override; - void onManager() override; + typedef std::shared_ptr Ptr; + RtmpSession(const Socket::Ptr &_sock); + virtual ~RtmpSession(); + void onRecv(const Buffer::Ptr &pBuf) override; + void onError(const SockException &err) override; + void onManager() override; private: - void onProcessCmd(AMFDecoder &dec); - void onCmd_connect(AMFDecoder &dec); - void onCmd_createStream(AMFDecoder &dec); + void onProcessCmd(AMFDecoder &dec); + void onCmd_connect(AMFDecoder &dec); + void onCmd_createStream(AMFDecoder &dec); - void onCmd_publish(AMFDecoder &dec); - void onCmd_deleteStream(AMFDecoder &dec); + void onCmd_publish(AMFDecoder &dec); + void onCmd_deleteStream(AMFDecoder &dec); - void onCmd_play(AMFDecoder &dec); - void onCmd_play2(AMFDecoder &dec); - void doPlay(AMFDecoder &dec); - void doPlayResponse(const string &err,const std::function &cb); - void sendPlayResponse(const string &err,const RtmpMediaSource::Ptr &src); + void onCmd_play(AMFDecoder &dec); + void onCmd_play2(AMFDecoder &dec); + void doPlay(AMFDecoder &dec); + void doPlayResponse(const string &err,const std::function &cb); + void sendPlayResponse(const string &err,const RtmpMediaSource::Ptr &src); - void onCmd_seek(AMFDecoder &dec); - void onCmd_pause(AMFDecoder &dec); - void setMetaData(AMFDecoder &dec); + void onCmd_seek(AMFDecoder &dec); + void onCmd_pause(AMFDecoder &dec); + void setMetaData(AMFDecoder &dec); - void onSendMedia(const RtmpPacket::Ptr &pkt); - void onSendRawData(const Buffer::Ptr &buffer) override{ + void onSendMedia(const RtmpPacket::Ptr &pkt); + void onSendRawData(const Buffer::Ptr &buffer) override{ _ui64TotalBytes += buffer->size(); - send(buffer); - } - void onRtmpChunk(RtmpPacket &chunkData) override; + send(buffer); + } + void onRtmpChunk(RtmpPacket &chunkData) override; - template - inline void sendReply(const char *str, const first &reply, const second &status) { - AMFEncoder invoke; - invoke << str << _dNowReqID << reply << status; - sendResponse(MSG_CMD, invoke.data()); - } + template + inline void sendReply(const char *str, const first &reply, const second &status) { + AMFEncoder invoke; + invoke << str << _dNowReqID << reply << status; + sendResponse(MSG_CMD, invoke.data()); + } - //MediaSourceEvent override - bool close(MediaSource &sender,bool force) override ; - void onNoneReader(MediaSource &sender) override; - int totalReaderCount(MediaSource &sender) override; + //MediaSourceEvent override + bool close(MediaSource &sender,bool force) override ; + int totalReaderCount(MediaSource &sender) override; - void setSocketFlags(); - string getStreamId(const string &str); - void dumpMetadata(const AMFValue &metadata); + void setSocketFlags(); + string getStreamId(const string &str); + void dumpMetadata(const AMFValue &metadata); private: - std::string _strTcUrl; - MediaInfo _mediaInfo; - double _dNowReqID = 0; - bool _set_meta_data = false; - Ticker _ticker;//数据接收时间 - RingBuffer::RingReader::Ptr _pRingReader; - std::shared_ptr _pPublisherSrc; - std::weak_ptr _pPlayerSrc; - //时间戳修整器 - Stamp _stamp[2]; - //消耗的总流量 - uint64_t _ui64TotalBytes = 0; + std::string _strTcUrl; + MediaInfo _mediaInfo; + double _dNowReqID = 0; + bool _set_meta_data = false; + Ticker _ticker;//数据接收时间 + RingBuffer::RingReader::Ptr _pRingReader; + std::shared_ptr _pPublisherSrc; + std::weak_ptr _pPlayerSrc; + //时间戳修整器 + Stamp _stamp[2]; + //消耗的总流量 + uint64_t _ui64TotalBytes = 0; }; diff --git a/src/Rtmp/amf.cpp b/src/Rtmp/amf.cpp index 2478cc10..c19136cb 100644 --- a/src/Rtmp/amf.cpp +++ b/src/Rtmp/amf.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include #include #include "amf.h" @@ -35,130 +20,130 @@ using namespace toolkit; /////////////////////AMFValue///////////////////////////// inline void AMFValue::destroy() { - switch (_type) { - case AMF_STRING: - if (_value.string) { - delete _value.string; - _value.string = nullptr; - } - break; - case AMF_OBJECT: - case AMF_ECMA_ARRAY: - if (_value.object) { - delete _value.object; - _value.object = nullptr; - } - break; - case AMF_STRICT_ARRAY: - if (_value.array) { - delete _value.array; - _value.array = nullptr; - } - break; - default: - break; - } + switch (_type) { + case AMF_STRING: + if (_value.string) { + delete _value.string; + _value.string = nullptr; + } + break; + case AMF_OBJECT: + case AMF_ECMA_ARRAY: + if (_value.object) { + delete _value.object; + _value.object = nullptr; + } + break; + case AMF_STRICT_ARRAY: + if (_value.array) { + delete _value.array; + _value.array = nullptr; + } + break; + default: + break; + } } inline void AMFValue::init() { - switch (_type) { - case AMF_OBJECT: - case AMF_ECMA_ARRAY: - _value.object = new mapType; - break; - case AMF_STRING: - _value.string = new std::string; - break; - case AMF_STRICT_ARRAY: - _value.array = new arrayType; - break; + switch (_type) { + case AMF_OBJECT: + case AMF_ECMA_ARRAY: + _value.object = new mapType; + break; + case AMF_STRING: + _value.string = new std::string; + break; + case AMF_STRICT_ARRAY: + _value.array = new arrayType; + break; - default: - break; - } + default: + break; + } } AMFValue::AMFValue(AMFType type) : - _type(type) { - init(); + _type(type) { + init(); } AMFValue::~AMFValue() { - destroy(); + destroy(); } AMFValue::AMFValue(const char *s) : - _type(AMF_STRING) { - init(); - *_value.string = s; + _type(AMF_STRING) { + init(); + *_value.string = s; } AMFValue::AMFValue(const std::string &s) : - _type(AMF_STRING) { - init(); - *_value.string = s; + _type(AMF_STRING) { + init(); + *_value.string = s; } AMFValue::AMFValue(double n) : - _type(AMF_NUMBER) { - init(); - _value.number = n; + _type(AMF_NUMBER) { + init(); + _value.number = n; } AMFValue::AMFValue(int i) : - _type(AMF_INTEGER) { - init(); - _value.integer = i; + _type(AMF_INTEGER) { + init(); + _value.integer = i; } AMFValue::AMFValue(bool b) : - _type(AMF_BOOLEAN) { - init(); - _value.boolean = b; + _type(AMF_BOOLEAN) { + init(); + _value.boolean = b; } AMFValue::AMFValue(const AMFValue &from) : - _type(AMF_NULL) { - *this = from; + _type(AMF_NULL) { + *this = from; } AMFValue::AMFValue(AMFValue &&from) { - *this = std::forward(from); + *this = std::forward(from); } AMFValue& AMFValue::operator =(const AMFValue &from) { - return *this = const_cast(from); + return *this = const_cast(from); } AMFValue& AMFValue::operator =(AMFValue &&from) { - destroy(); - _type = from._type; - init(); - switch (_type) { - case AMF_STRING: - *_value.string = (*from._value.string); - break; - case AMF_OBJECT: - case AMF_ECMA_ARRAY: - *_value.object = (*from._value.object); - break; - case AMF_STRICT_ARRAY: - *_value.array = (*from._value.array); - break; - case AMF_NUMBER: - _value.number = from._value.number; - break; - case AMF_INTEGER: - _value.integer = from._value.integer; - break; - case AMF_BOOLEAN: - _value.boolean = from._value.boolean; - break; - default: - break; - } - return *this; + destroy(); + _type = from._type; + init(); + switch (_type) { + case AMF_STRING: + *_value.string = (*from._value.string); + break; + case AMF_OBJECT: + case AMF_ECMA_ARRAY: + *_value.object = (*from._value.object); + break; + case AMF_STRICT_ARRAY: + *_value.array = (*from._value.array); + break; + case AMF_NUMBER: + _value.number = from._value.number; + break; + case AMF_INTEGER: + _value.integer = from._value.integer; + break; + case AMF_BOOLEAN: + _value.boolean = from._value.boolean; + break; + default: + break; + } + return *this; } @@ -305,156 +290,156 @@ const AMFValue::arrayType &AMFValue::getArr() const { /////////////////////////////////////////////////////////////////////////// enum { - AMF0_NUMBER, - AMF0_BOOLEAN, - AMF0_STRING, - AMF0_OBJECT, - AMF0_MOVIECLIP, - AMF0_NULL, - AMF0_UNDEFINED, - AMF0_REFERENCE, - AMF0_ECMA_ARRAY, - AMF0_OBJECT_END, - AMF0_STRICT_ARRAY, - AMF0_DATE, - AMF0_LONG_STRING, - AMF0_UNSUPPORTED, - AMF0_RECORD_SET, - AMF0_XML_OBJECT, - AMF0_TYPED_OBJECT, - AMF0_SWITCH_AMF3, + AMF0_NUMBER, + AMF0_BOOLEAN, + AMF0_STRING, + AMF0_OBJECT, + AMF0_MOVIECLIP, + AMF0_NULL, + AMF0_UNDEFINED, + AMF0_REFERENCE, + AMF0_ECMA_ARRAY, + AMF0_OBJECT_END, + AMF0_STRICT_ARRAY, + AMF0_DATE, + AMF0_LONG_STRING, + AMF0_UNSUPPORTED, + AMF0_RECORD_SET, + AMF0_XML_OBJECT, + AMF0_TYPED_OBJECT, + AMF0_SWITCH_AMF3, }; enum { - AMF3_UNDEFINED, - AMF3_NULL, - AMF3_FALSE, - AMF3_TRUE, - AMF3_INTEGER, - AMF3_NUMBER, - AMF3_STRING, - AMF3_LEGACY_XML, - AMF3_DATE, - AMF3_ARRAY, - AMF3_OBJECT, - AMF3_XML, - AMF3_BYTE_ARRAY, + AMF3_UNDEFINED, + AMF3_NULL, + AMF3_FALSE, + AMF3_TRUE, + AMF3_INTEGER, + AMF3_NUMBER, + AMF3_STRING, + AMF3_LEGACY_XML, + AMF3_DATE, + AMF3_ARRAY, + AMF3_OBJECT, + AMF3_XML, + AMF3_BYTE_ARRAY, }; ////////////////////////////////Encoder////////////////////////////////////////// AMFEncoder & AMFEncoder::operator <<(const char *s) { - if (s) { - buf += char(AMF0_STRING); - uint16_t str_len = htons(strlen(s)); - buf.append((char *) &str_len, 2); - buf += s; - } else { - buf += char(AMF0_NULL); - } - return *this; + if (s) { + buf += char(AMF0_STRING); + uint16_t str_len = htons(strlen(s)); + buf.append((char *) &str_len, 2); + buf += s; + } else { + buf += char(AMF0_NULL); + } + return *this; } AMFEncoder & AMFEncoder::operator <<(const std::string &s) { - if (!s.empty()) { - buf += char(AMF0_STRING); - uint16_t str_len = htons(s.size()); - buf.append((char *) &str_len, 2); - buf += s; - } else { - buf += char(AMF0_NULL); - } - return *this; + if (!s.empty()) { + buf += char(AMF0_STRING); + uint16_t str_len = htons(s.size()); + buf.append((char *) &str_len, 2); + buf += s; + } else { + buf += char(AMF0_NULL); + } + return *this; } AMFEncoder & AMFEncoder::operator <<(std::nullptr_t) { - buf += char(AMF0_NULL); - return *this; + buf += char(AMF0_NULL); + return *this; } AMFEncoder & AMFEncoder::write_undefined() { - buf += char(AMF0_UNDEFINED); - return *this; + buf += char(AMF0_UNDEFINED); + return *this; } AMFEncoder & AMFEncoder::operator <<(const int n){ - return (*this) << (double)n; + return (*this) << (double)n; } AMFEncoder & AMFEncoder::operator <<(const double n) { - buf += char(AMF0_NUMBER); - uint64_t encoded = 0; - memcpy(&encoded, &n, 8); - uint32_t val = htonl(encoded >> 32); - buf.append((char *) &val, 4); - val = htonl(encoded); - buf.append((char *) &val, 4); - return *this; + buf += char(AMF0_NUMBER); + uint64_t encoded = 0; + memcpy(&encoded, &n, 8); + uint32_t val = htonl(encoded >> 32); + buf.append((char *) &val, 4); + val = htonl(encoded); + buf.append((char *) &val, 4); + return *this; } AMFEncoder & AMFEncoder::operator <<(const bool b) { - buf += char(AMF0_BOOLEAN); - buf += char(b); - return *this; + buf += char(AMF0_BOOLEAN); + buf += char(b); + return *this; } AMFEncoder & AMFEncoder::operator <<(const AMFValue& value) { - switch ((int) value.type()) { - case AMF_STRING: - *this << value.as_string(); - break; - case AMF_NUMBER: - *this << value.as_number(); - break; - case AMF_INTEGER: - *this << value.as_integer(); - break; - case AMF_BOOLEAN: - *this << value.as_boolean(); - break; - case AMF_OBJECT: { - buf += char(AMF0_OBJECT); - for (auto &pr : value.getMap()) { - write_key(pr.first); - *this << pr.second; - } - write_key(""); - buf += char(AMF0_OBJECT_END); - } - break; - case AMF_ECMA_ARRAY: { - buf += char(AMF0_ECMA_ARRAY); - uint32_t sz = htonl(value.getMap().size()); - buf.append((char *) &sz, 4); - for (auto &pr : value.getMap()) { - write_key(pr.first); - *this << pr.second; - } - write_key(""); - buf += char(AMF0_OBJECT_END); - } - break; - case AMF_NULL: - *this << nullptr; - break; - case AMF_UNDEFINED: - this->write_undefined(); - break; - case AMF_STRICT_ARRAY: { - buf += char(AMF0_STRICT_ARRAY); - uint32_t sz = htonl(value.getArr().size()); - buf.append((char *) &sz, 4); - for (auto &val : value.getArr()) { - *this << val; - } - //write_key(""); - //buf += char(AMF0_OBJECT_END); - } - break; - } - return *this; + switch ((int) value.type()) { + case AMF_STRING: + *this << value.as_string(); + break; + case AMF_NUMBER: + *this << value.as_number(); + break; + case AMF_INTEGER: + *this << value.as_integer(); + break; + case AMF_BOOLEAN: + *this << value.as_boolean(); + break; + case AMF_OBJECT: { + buf += char(AMF0_OBJECT); + for (auto &pr : value.getMap()) { + write_key(pr.first); + *this << pr.second; + } + write_key(""); + buf += char(AMF0_OBJECT_END); + } + break; + case AMF_ECMA_ARRAY: { + buf += char(AMF0_ECMA_ARRAY); + uint32_t sz = htonl(value.getMap().size()); + buf.append((char *) &sz, 4); + for (auto &pr : value.getMap()) { + write_key(pr.first); + *this << pr.second; + } + write_key(""); + buf += char(AMF0_OBJECT_END); + } + break; + case AMF_NULL: + *this << nullptr; + break; + case AMF_UNDEFINED: + this->write_undefined(); + break; + case AMF_STRICT_ARRAY: { + buf += char(AMF0_STRICT_ARRAY); + uint32_t sz = htonl(value.getArr().size()); + buf.append((char *) &sz, 4); + for (auto &val : value.getArr()) { + *this << val; + } + //write_key(""); + //buf += char(AMF0_OBJECT_END); + } + break; + } + return *this; } void AMFEncoder::write_key(const std::string& s) { - uint16_t str_len = htons(s.size()); - buf.append((char *) &str_len, 2); - buf += s; + uint16_t str_len = htons(s.size()); + buf.append((char *) &str_len, 2); + buf += s; } void AMFEncoder::clear() { @@ -468,237 +453,237 @@ const std::string& AMFEncoder::data() const { //////////////////Decoder////////////////// uint8_t AMFDecoder::front() { - if (pos >= buf.size()) { - throw std::runtime_error("Not enough data"); - } - return uint8_t(buf[pos]); + if (pos >= buf.size()) { + throw std::runtime_error("Not enough data"); + } + return uint8_t(buf[pos]); } uint8_t AMFDecoder::pop_front() { - if (version == 0 && front() == AMF0_SWITCH_AMF3) { - InfoL << "entering AMF3 mode"; - pos++; - version = 3; - } + if (version == 0 && front() == AMF0_SWITCH_AMF3) { + InfoL << "entering AMF3 mode"; + pos++; + version = 3; + } - if (pos >= buf.size()) { - throw std::runtime_error("Not enough data"); - } - return uint8_t(buf[pos++]); + if (pos >= buf.size()) { + throw std::runtime_error("Not enough data"); + } + return uint8_t(buf[pos++]); } template<> double AMFDecoder::load() { - if (pop_front() != AMF0_NUMBER) { - throw std::runtime_error("Expected a number"); - } - if (pos + 8 > buf.size()) { - throw std::runtime_error("Not enough data"); - } - uint64_t val = ((uint64_t) load_be32(&buf[pos]) << 32) - | load_be32(&buf[pos + 4]); - double n = 0; - memcpy(&n, &val, 8); - pos += 8; - return n; + if (pop_front() != AMF0_NUMBER) { + throw std::runtime_error("Expected a number"); + } + if (pos + 8 > buf.size()) { + throw std::runtime_error("Not enough data"); + } + uint64_t val = ((uint64_t) load_be32(&buf[pos]) << 32) + | load_be32(&buf[pos + 4]); + double n = 0; + memcpy(&n, &val, 8); + pos += 8; + return n; } template<> bool AMFDecoder::load() { - if (pop_front() != AMF0_BOOLEAN) { - throw std::runtime_error("Expected a boolean"); - } - return pop_front() != 0; + if (pop_front() != AMF0_BOOLEAN) { + throw std::runtime_error("Expected a boolean"); + } + return pop_front() != 0; } template<> unsigned int AMFDecoder::load() { - unsigned int value = 0; - for (int i = 0; i < 4; ++i) { - uint8_t b = pop_front(); - if (i == 3) { - /* use all bits from 4th byte */ - value = (value << 8) | b; - break; - } - value = (value << 7) | (b & 0x7f); - if ((b & 0x80) == 0) - break; - } - return value; + unsigned int value = 0; + for (int i = 0; i < 4; ++i) { + uint8_t b = pop_front(); + if (i == 3) { + /* use all bits from 4th byte */ + value = (value << 8) | b; + break; + } + value = (value << 7) | (b & 0x7f); + if ((b & 0x80) == 0) + break; + } + return value; } template<> int AMFDecoder::load() { - if (version == 3) { - return load(); - } else { - return load(); - } + if (version == 3) { + return load(); + } else { + return load(); + } } template<> std::string AMFDecoder::load() { - size_t str_len = 0; - uint8_t type = pop_front(); - if (version == 3) { - if (type != AMF3_STRING) { - throw std::runtime_error("Expected a string"); - } - str_len = load() / 2; + size_t str_len = 0; + uint8_t type = pop_front(); + if (version == 3) { + if (type != AMF3_STRING) { + throw std::runtime_error("Expected a string"); + } + str_len = load() / 2; - } else { - if (type != AMF0_STRING) { - throw std::runtime_error("Expected a string"); - } - if (pos + 2 > buf.size()) { - throw std::runtime_error("Not enough data"); - } - str_len = load_be16(&buf[pos]); - pos += 2; - } - if (pos + str_len > buf.size()) { - throw std::runtime_error("Not enough data"); - } - std::string s(buf, pos, str_len); - pos += str_len; - return s; + } else { + if (type != AMF0_STRING) { + throw std::runtime_error("Expected a string"); + } + if (pos + 2 > buf.size()) { + throw std::runtime_error("Not enough data"); + } + str_len = load_be16(&buf[pos]); + pos += 2; + } + if (pos + str_len > buf.size()) { + throw std::runtime_error("Not enough data"); + } + std::string s(buf, pos, str_len); + pos += str_len; + return s; } template<> AMFValue AMFDecoder::load() { - uint8_t type = front(); - if (version == 3) { - switch (type) { - case AMF3_STRING: - return load(); - case AMF3_NUMBER: - return load(); - case AMF3_INTEGER: - return load(); - case AMF3_FALSE: - pos++; - return false; - case AMF3_TRUE: - pos++; - return true; - case AMF3_OBJECT: - return load_object(); - case AMF3_ARRAY: - return load_ecma(); - case AMF3_NULL: - pos++; - return AMF_NULL; - case AMF3_UNDEFINED: - pos++; - return AMF_UNDEFINED; - default: - throw std::runtime_error( - StrPrinter << "Unsupported AMF3 type:" << (int) type << endl); - } - } else { - switch (type) { - case AMF0_STRING: - return load(); - case AMF0_NUMBER: - return load(); - case AMF0_BOOLEAN: - return load(); - case AMF0_OBJECT: - return load_object(); - case AMF0_ECMA_ARRAY: - return load_ecma(); - case AMF0_NULL: - pos++; - return AMF_NULL; - case AMF0_UNDEFINED: - pos++; - return AMF_UNDEFINED; - case AMF0_STRICT_ARRAY: - return load_arr(); - default: - throw std::runtime_error( - StrPrinter << "Unsupported AMF type:" << (int) type << endl); - } - } + uint8_t type = front(); + if (version == 3) { + switch (type) { + case AMF3_STRING: + return load(); + case AMF3_NUMBER: + return load(); + case AMF3_INTEGER: + return load(); + case AMF3_FALSE: + pos++; + return false; + case AMF3_TRUE: + pos++; + return true; + case AMF3_OBJECT: + return load_object(); + case AMF3_ARRAY: + return load_ecma(); + case AMF3_NULL: + pos++; + return AMF_NULL; + case AMF3_UNDEFINED: + pos++; + return AMF_UNDEFINED; + default: + throw std::runtime_error( + StrPrinter << "Unsupported AMF3 type:" << (int) type << endl); + } + } else { + switch (type) { + case AMF0_STRING: + return load(); + case AMF0_NUMBER: + return load(); + case AMF0_BOOLEAN: + return load(); + case AMF0_OBJECT: + return load_object(); + case AMF0_ECMA_ARRAY: + return load_ecma(); + case AMF0_NULL: + pos++; + return AMF_NULL; + case AMF0_UNDEFINED: + pos++; + return AMF_UNDEFINED; + case AMF0_STRICT_ARRAY: + return load_arr(); + default: + throw std::runtime_error( + StrPrinter << "Unsupported AMF type:" << (int) type << endl); + } + } } std::string AMFDecoder::load_key() { - if (pos + 2 > buf.size()) { - throw std::runtime_error("Not enough data"); - } - size_t str_len = load_be16(&buf[pos]); - pos += 2; - if (pos + str_len > buf.size()) { - throw std::runtime_error("Not enough data"); - } - std::string s(buf, pos, str_len); - pos += str_len; - return s; + if (pos + 2 > buf.size()) { + throw std::runtime_error("Not enough data"); + } + size_t str_len = load_be16(&buf[pos]); + pos += 2; + if (pos + str_len > buf.size()) { + throw std::runtime_error("Not enough data"); + } + std::string s(buf, pos, str_len); + pos += str_len; + return s; } AMFValue AMFDecoder::load_object() { - AMFValue object(AMF_OBJECT); - if (pop_front() != AMF0_OBJECT) { - throw std::runtime_error("Expected an object"); - } - while (1) { - std::string key = load_key(); - if (key.empty()) - break; - AMFValue value = load(); - object.set(key, value); - } - if (pop_front() != AMF0_OBJECT_END) { - throw std::runtime_error("expected object end"); - } - return object; + AMFValue object(AMF_OBJECT); + if (pop_front() != AMF0_OBJECT) { + throw std::runtime_error("Expected an object"); + } + while (1) { + std::string key = load_key(); + if (key.empty()) + break; + AMFValue value = load(); + object.set(key, value); + } + if (pop_front() != AMF0_OBJECT_END) { + throw std::runtime_error("expected object end"); + } + return object; } AMFValue AMFDecoder::load_ecma() { - /* ECMA array is the same as object, with 4 extra zero bytes */ - AMFValue object(AMF_ECMA_ARRAY); - if (pop_front() != AMF0_ECMA_ARRAY) { - throw std::runtime_error("Expected an ECMA array"); - } - if (pos + 4 > buf.size()) { - throw std::runtime_error("Not enough data"); - } - pos += 4; - while (1) { - std::string key = load_key(); - if (key.empty()) - break; - AMFValue value = load(); - object.set(key, value); - } - if (pop_front() != AMF0_OBJECT_END) { - throw std::runtime_error("expected object end"); - } - return object; + /* ECMA array is the same as object, with 4 extra zero bytes */ + AMFValue object(AMF_ECMA_ARRAY); + if (pop_front() != AMF0_ECMA_ARRAY) { + throw std::runtime_error("Expected an ECMA array"); + } + if (pos + 4 > buf.size()) { + throw std::runtime_error("Not enough data"); + } + pos += 4; + while (1) { + std::string key = load_key(); + if (key.empty()) + break; + AMFValue value = load(); + object.set(key, value); + } + if (pop_front() != AMF0_OBJECT_END) { + throw std::runtime_error("expected object end"); + } + return object; } AMFValue AMFDecoder::load_arr() { - /* ECMA array is the same as object, with 4 extra zero bytes */ - AMFValue object(AMF_STRICT_ARRAY); - if (pop_front() != AMF0_STRICT_ARRAY) { - throw std::runtime_error("Expected an STRICT array"); - } - if (pos + 4 > buf.size()) { - throw std::runtime_error("Not enough data"); - } - int arrSize = load_be32(&buf[pos]); - pos += 4; - while (arrSize--) { - AMFValue value = load(); - object.add(value); - } - /*pos += 2; - if (pop_front() != AMF0_OBJECT_END) { - throw std::runtime_error("expected object end"); - }*/ - return object; + /* ECMA array is the same as object, with 4 extra zero bytes */ + AMFValue object(AMF_STRICT_ARRAY); + if (pop_front() != AMF0_STRICT_ARRAY) { + throw std::runtime_error("Expected an STRICT array"); + } + if (pos + 4 > buf.size()) { + throw std::runtime_error("Not enough data"); + } + int arrSize = load_be32(&buf[pos]); + pos += 4; + while (arrSize--) { + AMFValue value = load(); + object.add(value); + } + /*pos += 2; + if (pop_front() != AMF0_OBJECT_END) { + throw std::runtime_error("expected object end"); + }*/ + return object; } AMFDecoder::AMFDecoder(const std::string &buf_in, size_t pos_in, int version_in) : diff --git a/src/Rtmp/amf.h b/src/Rtmp/amf.h index da299b41..830fbe28 100644 --- a/src/Rtmp/amf.h +++ b/src/Rtmp/amf.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef __amf_h #define __amf_h @@ -36,15 +21,15 @@ using namespace std; enum AMFType { - AMF_NUMBER, - AMF_INTEGER, - AMF_BOOLEAN, - AMF_STRING, - AMF_OBJECT, - AMF_NULL, - AMF_UNDEFINED, - AMF_ECMA_ARRAY, - AMF_STRICT_ARRAY, + AMF_NUMBER, + AMF_INTEGER, + AMF_BOOLEAN, + AMF_STRING, + AMF_OBJECT, + AMF_NULL, + AMF_UNDEFINED, + AMF_ECMA_ARRAY, + AMF_STRICT_ARRAY, }; class AMFValue; @@ -55,79 +40,79 @@ public: typedef std::map mapType; typedef std::vector arrayType; - AMFValue(AMFType type = AMF_NULL); - AMFValue(const char *s); - AMFValue(const std::string &s); - AMFValue(double n); - AMFValue(int i); - AMFValue(bool b); - AMFValue(const AMFValue &from); - AMFValue(AMFValue &&from); - AMFValue &operator =(const AMFValue &from); - AMFValue &operator =(AMFValue &&from); - ~AMFValue(); + AMFValue(AMFType type = AMF_NULL); + AMFValue(const char *s); + AMFValue(const std::string &s); + AMFValue(double n); + AMFValue(int i); + AMFValue(bool b); + AMFValue(const AMFValue &from); + AMFValue(AMFValue &&from); + AMFValue &operator =(const AMFValue &from); + AMFValue &operator =(AMFValue &&from); + ~AMFValue(); - void clear(); - AMFType type() const ; - const std::string &as_string() const; - double as_number() const; - int as_integer() const; + void clear(); + AMFType type() const ; + const std::string &as_string() const; + double as_number() const; + int as_integer() const; bool as_boolean() const; - string to_string() const; - const AMFValue &operator[](const char *str) const; - void object_for_each(const function &fun) const ; - operator bool() const; - void set(const std::string &s, const AMFValue &val); - void add(const AMFValue &val); + string to_string() const; + const AMFValue &operator[](const char *str) const; + void object_for_each(const function &fun) const ; + operator bool() const; + void set(const std::string &s, const AMFValue &val); + void add(const AMFValue &val); private: const mapType &getMap() const; const arrayType &getArr() const; void destroy(); void init(); private: - AMFType _type; - union { - std::string *string; - double number; - int integer; - bool boolean; - mapType *object; - arrayType *array; - } _value; + AMFType _type; + union { + std::string *string; + double number; + int integer; + bool boolean; + mapType *object; + arrayType *array; + } _value; }; class AMFDecoder { public: - AMFDecoder(const std::string &buf, size_t pos, int version = 0); - template - TP load(); + AMFDecoder(const std::string &buf, size_t pos, int version = 0); + template + TP load(); private: - std::string load_key(); - AMFValue load_object(); - AMFValue load_ecma(); - AMFValue load_arr(); - uint8_t front(); - uint8_t pop_front(); + std::string load_key(); + AMFValue load_object(); + AMFValue load_ecma(); + AMFValue load_arr(); + uint8_t front(); + uint8_t pop_front(); private: - const std::string &buf; - size_t pos; - int version; + const std::string &buf; + size_t pos; + int version; }; class AMFEncoder { public: - AMFEncoder & operator <<(const char *s); - AMFEncoder & operator <<(const std::string &s); - AMFEncoder & operator <<(std::nullptr_t); - AMFEncoder & operator <<(const int n); - AMFEncoder & operator <<(const double n); - AMFEncoder & operator <<(const bool b); - AMFEncoder & operator <<(const AMFValue &value); - const std::string& data() const ; - void clear() ; + AMFEncoder & operator <<(const char *s); + AMFEncoder & operator <<(const std::string &s); + AMFEncoder & operator <<(std::nullptr_t); + AMFEncoder & operator <<(const int n); + AMFEncoder & operator <<(const double n); + AMFEncoder & operator <<(const bool b); + AMFEncoder & operator <<(const AMFValue &value); + const std::string& data() const ; + void clear() ; private: - void write_key(const std::string &s); - AMFEncoder &write_undefined(); + void write_key(const std::string &s); + AMFEncoder &write_undefined(); private: std::string buf; }; diff --git a/src/Rtmp/utils.cpp b/src/Rtmp/utils.cpp index d9a668eb..8f039c4b 100644 --- a/src/Rtmp/utils.cpp +++ b/src/Rtmp/utils.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include "utils.h" #include #include @@ -38,54 +23,54 @@ using namespace toolkit; */ uint32_t load_be32(const void *p) { - uint32_t val; - memcpy(&val, p, sizeof val); - return ntohl(val); + uint32_t val; + memcpy(&val, p, sizeof val); + return ntohl(val); } uint16_t load_be16(const void *p) { - uint16_t val; - memcpy(&val, p, sizeof val); - return ntohs(val); + uint16_t val; + memcpy(&val, p, sizeof val); + return ntohs(val); } uint32_t load_le32(const void *p) { - const uint8_t *data = (const uint8_t *) p; - return data[0] | ((uint32_t) data[1] << 8) | - ((uint32_t) data[2] << 16) | ((uint32_t) data[3] << 24); + const uint8_t *data = (const uint8_t *) p; + return data[0] | ((uint32_t) data[1] << 8) | + ((uint32_t) data[2] << 16) | ((uint32_t) data[3] << 24); } uint32_t load_be24(const void *p) { - const uint8_t *data = (const uint8_t *) p; - return data[2] | ((uint32_t) data[1] << 8) | ((uint32_t) data[0] << 16); + const uint8_t *data = (const uint8_t *) p; + return data[2] | ((uint32_t) data[1] << 8) | ((uint32_t) data[0] << 16); } void set_be24(void *p, uint32_t val) { - uint8_t *data = (uint8_t *) p; - data[0] = val >> 16; - data[1] = val >> 8; - data[2] = val; + uint8_t *data = (uint8_t *) p; + data[0] = val >> 16; + data[1] = val >> 8; + data[2] = val; } void set_le32(void *p, uint32_t val) { - uint8_t *data = (uint8_t *) p; - data[0] = val; - data[1] = val >> 8; - data[2] = val >> 16; - data[3] = val >> 24; + uint8_t *data = (uint8_t *) p; + data[0] = val; + data[1] = val >> 8; + data[2] = val >> 16; + data[3] = val >> 24; } void set_be32(void *p, uint32_t val) { - uint8_t *data = (uint8_t *) p; - data[3] = val; - data[2] = val >> 8; - data[1] = val >> 16; - data[0] = val >> 24; + uint8_t *data = (uint8_t *) p; + data[3] = val; + data[2] = val >> 8; + data[1] = val >> 16; + data[0] = val >> 24; } diff --git a/src/Rtmp/utils.h b/src/Rtmp/utils.h index 9723aba4..50b14cc1 100644 --- a/src/Rtmp/utils.h +++ b/src/Rtmp/utils.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef __utils_h #define __utils_h diff --git a/src/Rtp/Decoder.cpp b/src/Rtp/Decoder.cpp index ca6e8a6b..e37fec10 100644 --- a/src/Rtp/Decoder.cpp +++ b/src/Rtp/Decoder.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2020 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/Decoder.h b/src/Rtp/Decoder.h index 406508d2..203d51d9 100644 --- a/src/Rtp/Decoder.h +++ b/src/Rtp/Decoder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2020 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_DECODER_H diff --git a/src/Rtp/PSDecoder.cpp b/src/Rtp/PSDecoder.cpp index 77733d2b..911ef046 100644 --- a/src/Rtp/PSDecoder.cpp +++ b/src/Rtp/PSDecoder.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/PSDecoder.h b/src/Rtp/PSDecoder.h index 967a4ed4..b7f3a3ae 100644 --- a/src/Rtp/PSDecoder.h +++ b/src/Rtp/PSDecoder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_PSDECODER_H diff --git a/src/Rtp/RtpDecoder.cpp b/src/Rtp/RtpDecoder.cpp index 7bcd23e1..a08ada4f 100644 --- a/src/Rtp/RtpDecoder.cpp +++ b/src/Rtp/RtpDecoder.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/RtpDecoder.h b/src/Rtp/RtpDecoder.h index 52a32022..6f54e432 100644 --- a/src/Rtp/RtpDecoder.h +++ b/src/Rtp/RtpDecoder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPDECODER_H diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 654ac363..fd37904d 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) @@ -78,7 +62,6 @@ static string printAddress(const struct sockaddr *addr){ RtpProcess::RtpProcess(uint32_t ssrc) { _ssrc = ssrc; _track = std::make_shared(); - _track = std::make_shared(); _track->_interleaved = 0; _track->_samplerate = 90000; _track->_type = TrackVideo; @@ -283,7 +266,7 @@ void RtpProcess::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d WarnL << "audio track change to AAC from codecid:" << getCodecName(_codecid_audio); return; } - _muxer->inputFrame(std::make_shared((char *) data, bytes, dts, 7)); + _muxer->inputFrame(std::make_shared((char *) data, bytes, dts, 0, 7)); break; } default: @@ -315,7 +298,7 @@ int RtpProcess::totalReaderCount(){ } void RtpProcess::setListener(const std::weak_ptr &listener){ - _muxer->setListener(listener); + _muxer->setMediaListener(listener); } diff --git a/src/Rtp/RtpProcess.h b/src/Rtp/RtpProcess.h index d4395ecf..50f0a6bb 100644 --- a/src/Rtp/RtpProcess.h +++ b/src/Rtp/RtpProcess.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPPROCESS_H @@ -55,8 +39,6 @@ protected: void onRtpSorted(const RtpPacket::Ptr &rtp, int track_index) override ; void onRtpDecode(const uint8_t *packet, int bytes, uint32_t timestamp, int flags) override; void onDecode(int stream,int codecid,int flags,int64_t pts,int64_t dts, const void *data,int bytes); -private: - void getNextRtpType(); private: std::shared_ptr _save_file_rtp; std::shared_ptr _save_file_ps; @@ -70,7 +52,7 @@ private: MultiMediaSourceMuxer::Ptr _muxer; std::shared_ptr _merger; Ticker _last_rtp_time; - map _stamps; + unordered_map _stamps; uint32_t _dts = 0; Decoder::Ptr _decoder; }; diff --git a/src/Rtp/RtpSelector.cpp b/src/Rtp/RtpSelector.cpp index 95c6e473..fbddccdc 100644 --- a/src/Rtp/RtpSelector.cpp +++ b/src/Rtp/RtpSelector.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) @@ -142,13 +126,6 @@ bool RtpProcessHelper::close(MediaSource &sender, bool force) { return true; } -void RtpProcessHelper::onNoneReader(MediaSource &sender) { - if(!_process || _process->totalReaderCount()){ - return; - } - MediaSourceEvent::onNoneReader(sender); -} - int RtpProcessHelper::totalReaderCount(MediaSource &sender) { return _process ? _process->totalReaderCount() : sender.totalReaderCount(); } diff --git a/src/Rtp/RtpSelector.h b/src/Rtp/RtpSelector.h index 9edaca54..8e4ca205 100644 --- a/src/Rtp/RtpSelector.h +++ b/src/Rtp/RtpSelector.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPSELECTOR_H @@ -47,8 +31,6 @@ public: protected: // 通知其停止推流 bool close(MediaSource &sender,bool force) override; - // 通知无人观看 - void onNoneReader(MediaSource &sender) override; // 观看总人数 int totalReaderCount(MediaSource &sender) override; private: diff --git a/src/Rtp/RtpSession.cpp b/src/Rtp/RtpSession.cpp index e638b88e..57d71d41 100644 --- a/src/Rtp/RtpSession.cpp +++ b/src/Rtp/RtpSession.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) @@ -87,14 +71,6 @@ bool RtpSession::close(MediaSource &sender, bool force) { return true; } -void RtpSession::onNoneReader(MediaSource &sender) { - //此回调在其他线程触发 - if(!_process || _process->totalReaderCount()){ - return; - } - MediaSourceEvent::onNoneReader(sender); -} - int RtpSession::totalReaderCount(MediaSource &sender) { //此回调在其他线程触发 return _process ? _process->totalReaderCount() : sender.totalReaderCount(); diff --git a/src/Rtp/RtpSession.h b/src/Rtp/RtpSession.h index e8d2afed..a3557029 100644 --- a/src/Rtp/RtpSession.h +++ b/src/Rtp/RtpSession.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPSESSION_H @@ -46,8 +30,6 @@ public: protected: // 通知其停止推流 bool close(MediaSource &sender,bool force) override; - // 通知无人观看 - void onNoneReader(MediaSource &sender) override; // 观看总人数 int totalReaderCount(MediaSource &sender) override; void onRtpPacket(const char *data,uint64_t len) override; diff --git a/src/Rtp/RtpSplitter.cpp b/src/Rtp/RtpSplitter.cpp index 2317f68b..01414f20 100644 --- a/src/Rtp/RtpSplitter.cpp +++ b/src/Rtp/RtpSplitter.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/RtpSplitter.h b/src/Rtp/RtpSplitter.h index 34a026a4..45776b01 100644 --- a/src/Rtp/RtpSplitter.h +++ b/src/Rtp/RtpSplitter.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPSPLITTER_H diff --git a/src/Rtp/TSDecoder.cpp b/src/Rtp/TSDecoder.cpp index 9f1bee8c..b8486fcf 100644 --- a/src/Rtp/TSDecoder.cpp +++ b/src/Rtp/TSDecoder.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2020 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #if defined(ENABLE_RTPPROXY) #include "mpeg-ts.h" #include "TSDecoder.h" diff --git a/src/Rtp/TSDecoder.h b/src/Rtp/TSDecoder.h index dc442726..6de2397c 100644 --- a/src/Rtp/TSDecoder.h +++ b/src/Rtp/TSDecoder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2020 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_TSDECODER_H diff --git a/src/Rtp/UdpRecver.cpp b/src/Rtp/UdpRecver.cpp index 79995a85..484855cf 100644 --- a/src/Rtp/UdpRecver.cpp +++ b/src/Rtp/UdpRecver.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #if defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/UdpRecver.h b/src/Rtp/UdpRecver.h index f2a19a36..98361064 100644 --- a/src/Rtp/UdpRecver.h +++ b/src/Rtp/UdpRecver.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_UDPRECVER_H diff --git a/src/Rtsp/RtpCodec.cpp b/src/Rtsp/RtpCodec.cpp index 9e5d5a3c..5343b4fb 100644 --- a/src/Rtsp/RtpCodec.cpp +++ b/src/Rtsp/RtpCodec.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "RtpCodec.h" diff --git a/src/Rtsp/RtpCodec.h b/src/Rtsp/RtpCodec.h index 338de751..c8645d70 100644 --- a/src/Rtsp/RtpCodec.h +++ b/src/Rtsp/RtpCodec.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPCODEC_H diff --git a/src/Rtsp/RtpMultiCaster.cpp b/src/Rtsp/RtpMultiCaster.cpp index 1de5bcfe..88a38244 100644 --- a/src/Rtsp/RtpMultiCaster.cpp +++ b/src/Rtsp/RtpMultiCaster.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -37,47 +21,47 @@ using namespace toolkit; namespace mediakit{ MultiCastAddressMaker &MultiCastAddressMaker::Instance() { - static MultiCastAddressMaker instance; - return instance; + static MultiCastAddressMaker instance; + return instance; } static uint32_t addressToInt(const string &ip){ struct in_addr addr; bzero(&addr,sizeof(addr)); - addr.s_addr = inet_addr(ip.data()); + addr.s_addr = inet_addr(ip.data()); return (uint32_t)ntohl((uint32_t &)addr.s_addr); } std::shared_ptr MultiCastAddressMaker::obtain(uint32_t iTry) { - lock_guard lck(_mtx); + lock_guard lck(_mtx); GET_CONFIG(string,addrMinStr,MultiCast::kAddrMin); GET_CONFIG(string,addrMaxStr,MultiCast::kAddrMax); uint32_t addrMin = addressToInt(addrMinStr); - uint32_t addrMax = addressToInt(addrMaxStr); + uint32_t addrMax = addressToInt(addrMaxStr); - if(_iAddr > addrMax || _iAddr == 0){ - _iAddr = addrMin; - } - auto iGotAddr = _iAddr++; - if(_setBadAddr.find(iGotAddr) != _setBadAddr.end()){ - //已经分配过了 - if(iTry){ - return obtain(--iTry); - } - //分配完了,应该不可能到这里 - ErrorL; - return nullptr; - } - _setBadAddr.emplace(iGotAddr); - std::shared_ptr ret(new uint32_t(iGotAddr),[](uint32_t *ptr){ - MultiCastAddressMaker::Instance().release(*ptr); - delete ptr; - }); - return ret; + if(_iAddr > addrMax || _iAddr == 0){ + _iAddr = addrMin; + } + auto iGotAddr = _iAddr++; + if(_setBadAddr.find(iGotAddr) != _setBadAddr.end()){ + //已经分配过了 + if(iTry){ + return obtain(--iTry); + } + //分配完了,应该不可能到这里 + ErrorL; + return nullptr; + } + _setBadAddr.emplace(iGotAddr); + std::shared_ptr ret(new uint32_t(iGotAddr),[](uint32_t *ptr){ + MultiCastAddressMaker::Instance().release(*ptr); + delete ptr; + }); + return ret; } void MultiCastAddressMaker::release(uint32_t iAddr){ - lock_guard lck(_mtx); - _setBadAddr.erase(iAddr); + lock_guard lck(_mtx); + _setBadAddr.erase(iAddr); } @@ -85,106 +69,111 @@ recursive_mutex RtpMultiCaster::g_mtx; unordered_map > RtpMultiCaster::g_mapBroadCaster; void RtpMultiCaster::setDetachCB(void* listener, const onDetach& cb) { - lock_guard lck(_mtx); - if(cb){ - _mapDetach.emplace(listener,cb); - }else{ - _mapDetach.erase(listener); - } + lock_guard lck(_mtx); + if(cb){ + _mapDetach.emplace(listener,cb); + }else{ + _mapDetach.erase(listener); + } } RtpMultiCaster::~RtpMultiCaster() { - _pReader->setReadCB(nullptr); - _pReader->setDetachCB(nullptr); - DebugL; + _pReader->setReadCB(nullptr); + _pReader->setDetachCB(nullptr); + DebugL; } RtpMultiCaster::RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) { - auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA,strVhost,strApp, strStream)); - if(!src){ - auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl; - throw std::runtime_error(strErr); - } - _multiAddr = MultiCastAddressMaker::Instance().obtain(); - for(auto i = 0; i < 2; i++){ - _apUdpSock[i].reset(new Socket(poller)); - if(!_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){ - auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl; - throw std::runtime_error(strErr); - } - auto fd = _apUdpSock[i]->rawFD(); + auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA,strVhost,strApp, strStream)); + if(!src){ + auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl; + throw std::runtime_error(strErr); + } + _multiAddr = MultiCastAddressMaker::Instance().obtain(); + for(auto i = 0; i < 2; i++){ + _apUdpSock[i].reset(new Socket(poller)); + if(!_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){ + auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl; + throw std::runtime_error(strErr); + } + auto fd = _apUdpSock[i]->rawFD(); GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL); SockUtil::setMultiTTL(fd, udpTTL); - SockUtil::setMultiLOOP(fd, false); - SockUtil::setMultiIF(fd, strLocalIp.data()); + SockUtil::setMultiLOOP(fd, false); + SockUtil::setMultiIF(fd, strLocalIp.data()); - struct sockaddr_in &peerAddr = _aPeerUdpAddr[i]; - peerAddr.sin_family = AF_INET; - peerAddr.sin_port = htons(_apUdpSock[i]->get_local_port()); - peerAddr.sin_addr.s_addr = htonl(*_multiAddr); - bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); - _apUdpSock[i]->setSendPeerAddr((struct sockaddr *)&peerAddr); - } - _pReader = src->getRing()->attach(poller); - _pReader->setReadCB([this](const RtpPacket::Ptr &pkt){ - int i = (int)(pkt->type); - auto &pSock = _apUdpSock[i]; - auto &peerAddr = _aPeerUdpAddr[i]; - BufferRtp::Ptr buffer(new BufferRtp(pkt,4)); - pSock->send(buffer); - }); - _pReader->setDetachCB([this](){ - unordered_map _mapDetach_copy; - { - lock_guard lck(_mtx); - _mapDetach_copy = std::move(_mapDetach); - } - for(auto &pr : _mapDetach_copy){ - pr.second(); - } - }); - DebugL << MultiCastAddressMaker::toString(*_multiAddr) << " " - << _apUdpSock[0]->get_local_port() << " " - << _apUdpSock[1]->get_local_port() << " " + struct sockaddr_in &peerAddr = _aPeerUdpAddr[i]; + peerAddr.sin_family = AF_INET; + peerAddr.sin_port = htons(_apUdpSock[i]->get_local_port()); + peerAddr.sin_addr.s_addr = htonl(*_multiAddr); + bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); + _apUdpSock[i]->setSendPeerAddr((struct sockaddr *)&peerAddr); + } + _pReader = src->getRing()->attach(poller); + _pReader->setReadCB([this](const RtspMediaSource::RingDataType &pkt){ + int i = 0; + int size = pkt->size(); + pkt->for_each([&](const RtpPacket::Ptr &rtp) { + int i = (int) (rtp->type); + auto &pSock = _apUdpSock[i]; + auto &peerAddr = _aPeerUdpAddr[i]; + BufferRtp::Ptr buffer(new BufferRtp(rtp, 4)); + pSock->send(buffer, nullptr, 0, ++i == size); + }); + }); + + _pReader->setDetachCB([this](){ + unordered_map _mapDetach_copy; + { + lock_guard lck(_mtx); + _mapDetach_copy = std::move(_mapDetach); + } + for(auto &pr : _mapDetach_copy){ + pr.second(); + } + }); + DebugL << MultiCastAddressMaker::toString(*_multiAddr) << " " + << _apUdpSock[0]->get_local_port() << " " + << _apUdpSock[1]->get_local_port() << " " << strVhost << " " - << strApp << " " << strStream; + << strApp << " " << strStream; } uint16_t RtpMultiCaster::getPort(TrackType trackType){ - return _apUdpSock[trackType]->get_local_port(); + return _apUdpSock[trackType]->get_local_port(); } string RtpMultiCaster::getIP(){ - return inet_ntoa(_aPeerUdpAddr[0].sin_addr); + return inet_ntoa(_aPeerUdpAddr[0].sin_addr); } RtpMultiCaster::Ptr RtpMultiCaster::make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream){ - try{ - auto ret = Ptr(new RtpMultiCaster(poller,strLocalIp,strVhost,strApp,strStream),[poller](RtpMultiCaster *ptr){ + try{ + auto ret = Ptr(new RtpMultiCaster(poller,strLocalIp,strVhost,strApp,strStream),[poller](RtpMultiCaster *ptr){ poller->async([ptr]() { delete ptr; }); - }); - lock_guard lck(g_mtx); - string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl; - weak_ptr weakPtr = ret; - g_mapBroadCaster.emplace(strKey,weakPtr); - return ret; - }catch (std::exception &ex) { - WarnL << ex.what(); - return nullptr; - } + }); + lock_guard lck(g_mtx); + string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl; + weak_ptr weakPtr = ret; + g_mapBroadCaster.emplace(strKey,weakPtr); + return ret; + }catch (std::exception &ex) { + WarnL << ex.what(); + return nullptr; + } } RtpMultiCaster::Ptr RtpMultiCaster::get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) { - string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl; - lock_guard lck(g_mtx); - auto it = g_mapBroadCaster.find(strKey); - if (it == g_mapBroadCaster.end()) { - return make(poller,strLocalIp,strVhost,strApp, strStream); - } - auto ret = it->second.lock(); - if (!ret) { - g_mapBroadCaster.erase(it); - return make(poller,strLocalIp,strVhost,strApp, strStream); - } - return ret; + string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl; + lock_guard lck(g_mtx); + auto it = g_mapBroadCaster.find(strKey); + if (it == g_mapBroadCaster.end()) { + return make(poller,strLocalIp,strVhost,strApp, strStream); + } + auto ret = it->second.lock(); + if (!ret) { + g_mapBroadCaster.erase(it); + return make(poller,strLocalIp,strVhost,strApp, strStream); + } + return ret; } diff --git a/src/Rtsp/RtpMultiCaster.h b/src/Rtsp/RtpMultiCaster.h index e95802b1..3e960cdb 100644 --- a/src/Rtsp/RtpMultiCaster.h +++ b/src/Rtsp/RtpMultiCaster.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTSP_RTPBROADCASTER_H_ @@ -45,48 +29,48 @@ namespace mediakit{ class MultiCastAddressMaker { public: - static MultiCastAddressMaker &Instance(); + static MultiCastAddressMaker &Instance(); - static bool isMultiCastAddress(uint32_t iAddr){ - static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as(); - static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as(); - return iAddr >= addrMin && iAddr <= addrMax; - } - static string toString(uint32_t iAddr){ - iAddr = htonl(iAddr); - return ::inet_ntoa((struct in_addr &)(iAddr)); - } - virtual ~MultiCastAddressMaker(){} - std::shared_ptr obtain(uint32_t iTry = 10); + static bool isMultiCastAddress(uint32_t iAddr){ + static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as(); + static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as(); + return iAddr >= addrMin && iAddr <= addrMax; + } + static string toString(uint32_t iAddr){ + iAddr = htonl(iAddr); + return ::inet_ntoa((struct in_addr &)(iAddr)); + } + virtual ~MultiCastAddressMaker(){} + std::shared_ptr obtain(uint32_t iTry = 10); private: - MultiCastAddressMaker(){}; - void release(uint32_t iAddr); - uint32_t _iAddr = 0; - recursive_mutex _mtx; - unordered_set _setBadAddr; + MultiCastAddressMaker(){}; + void release(uint32_t iAddr); + uint32_t _iAddr = 0; + recursive_mutex _mtx; + unordered_set _setBadAddr; }; class RtpMultiCaster { public: - typedef std::shared_ptr Ptr; - typedef function onDetach; - virtual ~RtpMultiCaster(); - static Ptr get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); - void setDetachCB(void *listener,const onDetach &cb); - uint16_t getPort(TrackType trackType); - string getIP(); + typedef std::shared_ptr Ptr; + typedef function onDetach; + virtual ~RtpMultiCaster(); + static Ptr get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); + void setDetachCB(void *listener,const onDetach &cb); + uint16_t getPort(TrackType trackType); + string getIP(); private: - static recursive_mutex g_mtx; - static unordered_map > g_mapBroadCaster; - static Ptr make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); + static recursive_mutex g_mtx; + static unordered_map > g_mapBroadCaster; + static Ptr make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); - std::shared_ptr _multiAddr; - recursive_mutex _mtx; - unordered_map _mapDetach; - RtspMediaSource::RingType::RingReader::Ptr _pReader; - Socket::Ptr _apUdpSock[2]; - struct sockaddr_in _aPeerUdpAddr[2]; + std::shared_ptr _multiAddr; + recursive_mutex _mtx; + unordered_map _mapDetach; + RtspMediaSource::RingType::RingReader::Ptr _pReader; + Socket::Ptr _apUdpSock[2]; + struct sockaddr_in _aPeerUdpAddr[2]; - RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); + RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); }; diff --git a/src/Rtsp/RtpReceiver.cpp b/src/Rtsp/RtpReceiver.cpp index f2ff31f7..2b6602f1 100644 --- a/src/Rtsp/RtpReceiver.cpp +++ b/src/Rtsp/RtpReceiver.cpp @@ -1,36 +1,20 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "Common/config.h" #include "RtpReceiver.h" #define POP_HEAD(trackidx) \ - auto it = _rtp_sort_cache_map[trackidx].begin(); \ - onRtpSorted(it->second, trackidx); \ - _rtp_sort_cache_map[trackidx].erase(it); + auto it = _rtp_sort_cache_map[trackidx].begin(); \ + onRtpSorted(it->second, trackidx); \ + _rtp_sort_cache_map[trackidx].erase(it); #define AV_RB16(x) \ ((((const uint8_t*)(x))[0] << 8) | \ diff --git a/src/Rtsp/RtpReceiver.h b/src/Rtsp/RtpReceiver.h index 5ebac35f..1631184e 100644 --- a/src/Rtsp/RtpReceiver.h +++ b/src/Rtsp/RtpReceiver.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTPRECEIVER_H diff --git a/src/Rtsp/Rtsp.cpp b/src/Rtsp/Rtsp.cpp index d6d95258..8ae86f84 100644 --- a/src/Rtsp/Rtsp.cpp +++ b/src/Rtsp/Rtsp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -30,177 +14,227 @@ namespace mediakit{ -static void getAttrSdp(const map &attr, _StrPrinter &printer){ - const map::value_type *ptr = nullptr; - for(auto &pr : attr){ - if(pr.first == "control"){ - ptr = ≺ - continue; - } - if(pr.second.empty()){ - printer << "a=" << pr.first << "\r\n"; - }else{ - printer << "a=" << pr.first << ":" << pr.second << "\r\n"; - } - } - if(ptr){ - printer << "a=" << ptr->first << ":" << ptr->second << "\r\n"; - } +int RtpPayload::getClockRate(int pt){ + switch (pt){ +#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return clock_rate; + RTP_PT_MAP(SWITCH_CASE) +#undef SWITCH_CASE + default: return 90000; + } } -string SdpTrack::toString() const { - _StrPrinter _printer; - switch (_type){ - case TrackTitle:{ - _printer << "v=" << 0 << "\r\n"; - if(!_o.empty()){ - _printer << "o="<< _o << "\r\n"; - } - if(!_c.empty()){ - _printer << "c=" << _c << "\r\n"; - } - if(!_t.empty()){ - _printer << "t=" << _t << "\r\n"; - } - _printer << "s=RTSP Session, streamed by the ZLMediaKit\r\n"; - _printer << "i=ZLMediaKit Live Stream\r\n"; - getAttrSdp(_attr,_printer); - } - break; - case TrackAudio: - case TrackVideo:{ - if(_type == TrackAudio){ - _printer << "m=audio 0 RTP/AVP " << _pt << "\r\n"; - }else{ - _printer << "m=video 0 RTP/AVP " << _pt << "\r\n"; - } - if(!_b.empty()){ - _printer << "b=" <<_b << "\r\n"; - } - getAttrSdp(_attr,_printer); - } - break; - default: - break; - } - return _printer; +TrackType RtpPayload::getTrackType(int pt){ + switch (pt){ +#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return type; + RTP_PT_MAP(SWITCH_CASE) +#undef SWITCH_CASE + default: return TrackInvalid; + } +} + +int RtpPayload::getAudioChannel(int pt){ + switch (pt){ +#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return channel; + RTP_PT_MAP(SWITCH_CASE) +#undef SWITCH_CASE + default: return 1; + } +} + +const char * RtpPayload::getName(int pt){ + switch (pt){ +#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return #name; + RTP_PT_MAP(SWITCH_CASE) +#undef SWITCH_CASE + default: return "unknown payload type"; + } +} + +static void getAttrSdp(const map &attr, _StrPrinter &printer){ + const map::value_type *ptr = nullptr; + for(auto &pr : attr){ + if(pr.first == "control"){ + ptr = ≺ + continue; + } + if(pr.second.empty()){ + printer << "a=" << pr.first << "\r\n"; + }else{ + printer << "a=" << pr.first << ":" << pr.second << "\r\n"; + } + } + if(ptr){ + printer << "a=" << ptr->first << ":" << ptr->second << "\r\n"; + } +} + +string SdpTrack::getName() const{ + switch (_pt){ +#define SWITCH_CASE(name, type, value, clock_rate, channel) case value : return #name; + RTP_PT_MAP(SWITCH_CASE) +#undef SWITCH_CASE + default: return _codec; + } +} + +string SdpTrack::toString() const { + _StrPrinter _printer; + switch (_type){ + case TrackTitle:{ + _printer << "v=" << 0 << "\r\n"; + if(!_o.empty()){ + _printer << "o="<< _o << "\r\n"; + } + if(!_c.empty()){ + _printer << "c=" << _c << "\r\n"; + } + if(!_t.empty()){ + _printer << "t=" << _t << "\r\n"; + } + + _printer << "s=Streamed by " << SERVER_NAME << "\r\n"; + getAttrSdp(_attr,_printer); + } + break; + case TrackAudio: + case TrackVideo:{ + if(_type == TrackAudio){ + _printer << "m=audio 0 RTP/AVP " << _pt << "\r\n"; + }else{ + _printer << "m=video 0 RTP/AVP " << _pt << "\r\n"; + } + if(!_b.empty()){ + _printer << "b=" <<_b << "\r\n"; + } + getAttrSdp(_attr,_printer); + } + break; + default: + break; + } + return _printer; } static TrackType toTrackType(const string &str) { - if (str == "") { - return TrackTitle; - } + if (str == "") { + return TrackTitle; + } - if (str == "video") { - return TrackVideo; - } + if (str == "video") { + return TrackVideo; + } - if (str == "audio") { - return TrackAudio; - } + if (str == "audio") { + return TrackAudio; + } - return TrackInvalid; + return TrackInvalid; } void SdpParser::load(const string &sdp) { - { - _track_vec.clear(); - string key; - SdpTrack::Ptr track = std::make_shared(); + { + _track_vec.clear(); + SdpTrack::Ptr track = std::make_shared(); + track->_type = TrackTitle; + _track_vec.emplace_back(track); - auto lines = split(sdp, "\n"); - for (auto &line : lines) { - trim(line); - if (line.size() < 2 || line[1] != '=') { - continue; - } - char opt = line[0]; - string opt_val = line.substr(2); - switch (opt) { - case 'o': - track->_o = opt_val; - break; - case 's': - track->_s = opt_val; - break; - case 'i': - track->_i = opt_val; - break; - case 'c': - track->_c = opt_val; - break; - case 't': - track->_t = opt_val; - break; - case 'b': - track->_b = opt_val; - break; - case 'm': { - track->_type = toTrackType(key); - _track_vec.emplace_back(track); - track = std::make_shared(); - key = FindField(opt_val.data(), nullptr, " "); - track->_m = opt_val; - } - break; - case 'a': { - string attr = FindField(opt_val.data(), nullptr, ":"); - if (attr.empty()) { - track->_attr[opt_val] = ""; - } else { - track->_attr[attr] = FindField(opt_val.data(), ":", nullptr); - } - } - break; - default: - track->_other[opt] = opt_val; - break; - } - } - track->_type = toTrackType(key); - _track_vec.emplace_back(track); - } + auto lines = split(sdp, "\n"); + for (auto &line : lines) { + trim(line); + if (line.size() < 2 || line[1] != '=') { + continue; + } + char opt = line[0]; + string opt_val = line.substr(2); + switch (opt) { + case 'o': + track->_o = opt_val; + break; + case 's': + track->_s = opt_val; + break; + case 'i': + track->_i = opt_val; + break; + case 'c': + track->_c = opt_val; + break; + case 't': + track->_t = opt_val; + break; + case 'b': + track->_b = opt_val; + break; + case 'm': { + track = std::make_shared(); + int pt, port; + char rtp[16] = {0}, type[16]; + if (4 == sscanf(opt_val.data(), " %15[^ ] %d %15[^ ] %d", type, &port, rtp, &pt)) { + track->_pt = pt; + track->_samplerate = RtpPayload::getClockRate(pt) ; + track->_type = toTrackType(type); + track->_m = opt_val; + track->_port = port; + _track_vec.emplace_back(track); + } + } + break; + case 'a': { + string attr = FindField(opt_val.data(), nullptr, ":"); + if (attr.empty()) { + track->_attr[opt_val] = ""; + } else { + track->_attr[attr] = FindField(opt_val.data(), ":", nullptr); + } + } + break; + default: + track->_other[opt] = opt_val; + break; + } + } + } - for (auto &track_ptr : _track_vec) { - auto &track = *track_ptr; - auto it = track._attr.find("range"); - if (it != track._attr.end()) { - char name[16] = {0}, start[16] = {0}, end[16] = {0}; - int ret = sscanf(it->second.data(), "%15[^=]=%15[^-]-%15s", name, start, end); - if (3 == ret || 2 == ret) { - if (strcmp(start, "now") == 0) { - strcpy(start, "0"); - } - track._start = atof(start); - track._end = atof(end); - track._duration = track._end - track._start; - } - } + for (auto &track_ptr : _track_vec) { + auto &track = *track_ptr; + auto it = track._attr.find("range"); + if (it != track._attr.end()) { + char name[16] = {0}, start[16] = {0}, end[16] = {0}; + int ret = sscanf(it->second.data(), "%15[^=]=%15[^-]-%15s", name, start, end); + if (3 == ret || 2 == ret) { + if (strcmp(start, "now") == 0) { + strcpy(start, "0"); + } + track._start = atof(start); + track._end = atof(end); + track._duration = track._end - track._start; + } + } - it = track._attr.find("rtpmap"); - if(it != track._attr.end()){ - auto rtpmap = it->second; - int pt, samplerate; - char codec[16] = {0}; - if (3 == sscanf(rtpmap.data(), "%d %15[^/]/%d", &pt, codec, &samplerate)) { - track._pt = pt; - track._codec = codec; - track._samplerate = samplerate; - } - } + it = track._attr.find("rtpmap"); + if(it != track._attr.end()){ + auto rtpmap = it->second; + int pt, samplerate; + char codec[16] = {0}; + if (3 == sscanf(rtpmap.data(), "%d %15[^/]/%d", &pt, codec, &samplerate)) { + track._pt = pt; + track._codec = codec; + track._samplerate = samplerate; + } + } - it = track._attr.find("fmtp"); - if(it != track._attr.end()) { - track._fmtp = it->second; - } + it = track._attr.find("fmtp"); + if(it != track._attr.end()) { + track._fmtp = it->second; + } - it = track._attr.find("control"); - if(it != track._attr.end()) { - track._control = it->second; - auto surffix = string("/") + track._control; - track._control_surffix = surffix.substr(1 + surffix.rfind('/')); - } - } + it = track._attr.find("control"); + if(it != track._attr.end()) { + track._control = it->second; + auto surffix = string("/") + track._control; + track._control_surffix = surffix.substr(1 + surffix.rfind('/')); + } + } } bool SdpParser::available() const { @@ -208,112 +242,112 @@ bool SdpParser::available() const { } SdpTrack::Ptr SdpParser::getTrack(TrackType type) const { - for (auto &track : _track_vec){ - if(track->_type == type){ - return track; - } - } - return nullptr; + for (auto &track : _track_vec){ + if(track->_type == type){ + return track; + } + } + return nullptr; } vector SdpParser::getAvailableTrack() const { - vector ret; - bool audio_added = false; - bool video_added = false; - for (auto &track : _track_vec){ - if(track->_type == TrackAudio ){ - if(!audio_added){ - ret.emplace_back(track); - audio_added = true; - } - continue; - } + vector ret; + bool audio_added = false; + bool video_added = false; + for (auto &track : _track_vec){ + if(track->_type == TrackAudio ){ + if(!audio_added){ + ret.emplace_back(track); + audio_added = true; + } + continue; + } - if(track->_type == TrackVideo ){ - if(!video_added){ - ret.emplace_back(track); - video_added = true; - } - continue; - } - } - return std::move(ret); + if(track->_type == TrackVideo ){ + if(!video_added){ + ret.emplace_back(track); + video_added = true; + } + continue; + } + } + return std::move(ret); } string SdpParser::toString() const { - string title,audio,video; - for(auto &track : _track_vec){ - switch (track->_type){ - case TrackTitle:{ - title = track->toString(); - } - break; - case TrackVideo:{ - video = track->toString(); - } - break; - case TrackAudio:{ - audio = track->toString(); - } - break; - default: - break; - } - } - return title + video + audio; + string title,audio,video; + for(auto &track : _track_vec){ + switch (track->_type){ + case TrackTitle:{ + title = track->toString(); + } + break; + case TrackVideo:{ + video = track->toString(); + } + break; + case TrackAudio:{ + audio = track->toString(); + } + break; + default: + break; + } + } + return title + video + audio; } bool RtspUrl::parse(const string &strUrl) { - auto schema = FindField(strUrl.data(), nullptr, "://"); - bool isSSL = strcasecmp(schema.data(), "rtsps") == 0; - //查找"://"与"/"之间的字符串,用于提取用户名密码 - auto middle_url = FindField(strUrl.data(), "://", "/"); - if (middle_url.empty()) { - middle_url = FindField(strUrl.data(), "://", nullptr); - } - auto pos = middle_url.rfind('@'); - if (pos == string::npos) { - //并没有用户名密码 - return setup(isSSL, strUrl, "", ""); - } + auto schema = FindField(strUrl.data(), nullptr, "://"); + bool isSSL = strcasecmp(schema.data(), "rtsps") == 0; + //查找"://"与"/"之间的字符串,用于提取用户名密码 + auto middle_url = FindField(strUrl.data(), "://", "/"); + if (middle_url.empty()) { + middle_url = FindField(strUrl.data(), "://", nullptr); + } + auto pos = middle_url.rfind('@'); + if (pos == string::npos) { + //并没有用户名密码 + return setup(isSSL, strUrl, "", ""); + } - //包含用户名密码 - auto user_pwd = middle_url.substr(0, pos); - auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); - auto url = StrPrinter << "rtsp://" << suffix << endl; - if (user_pwd.find(":") == string::npos) { - return setup(isSSL, url, user_pwd, ""); - } - auto user = FindField(user_pwd.data(), nullptr, ":"); - auto pwd = FindField(user_pwd.data(), ":", nullptr); - return setup(isSSL, url, user, pwd); + //包含用户名密码 + auto user_pwd = middle_url.substr(0, pos); + auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); + auto url = StrPrinter << "rtsp://" << suffix << endl; + if (user_pwd.find(":") == string::npos) { + return setup(isSSL, url, user_pwd, ""); + } + auto user = FindField(user_pwd.data(), nullptr, ":"); + auto pwd = FindField(user_pwd.data(), ":", nullptr); + return setup(isSSL, url, user, pwd); } bool RtspUrl::setup(bool isSSL, const string &strUrl, const string &strUser, const string &strPwd) { - auto ip = FindField(strUrl.data(), "://", "/"); - if (ip.empty()) { - ip = split(FindField(strUrl.data(), "://", NULL), "?")[0]; - } - auto port = atoi(FindField(ip.data(), ":", NULL).data()); - if (port <= 0 || port > UINT16_MAX) { - //rtsp 默认端口554 - port = isSSL ? 322 : 554; - } else { - //服务器域名 - ip = FindField(ip.data(), NULL, ":"); - } + auto ip = FindField(strUrl.data(), "://", "/"); + if (ip.empty()) { + ip = split(FindField(strUrl.data(), "://", NULL), "?")[0]; + } + auto port = atoi(FindField(ip.data(), ":", NULL).data()); + if (port <= 0 || port > UINT16_MAX) { + //rtsp 默认端口554 + port = isSSL ? 322 : 554; + } else { + //服务器域名 + ip = FindField(ip.data(), NULL, ":"); + } - if (ip.empty()) { - return false; - } + if (ip.empty()) { + return false; + } - _url = std::move(strUrl); - _user = std::move(strUser); - _passwd = std::move(strPwd); - _host = std::move(ip); - _port = port; - _is_ssl = isSSL; - return true; + _url = std::move(strUrl); + _user = std::move(strUser); + _passwd = std::move(strPwd); + _host = std::move(ip); + _port = port; + _is_ssl = isSSL; + return true; } }//namespace mediakit diff --git a/src/Rtsp/Rtsp.h b/src/Rtsp/Rtsp.h index 26e2a979..a1debdf4 100644 --- a/src/Rtsp/Rtsp.h +++ b/src/Rtsp/Rtsp.h @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef RTSP_RTSP_H_ #define RTSP_RTSP_H_ @@ -42,87 +27,134 @@ namespace mediakit { namespace Rtsp { typedef enum { - RTP_Invalid = -1, - RTP_TCP = 0, - RTP_UDP = 1, - RTP_MULTICAST = 2, + RTP_Invalid = -1, + RTP_TCP = 0, + RTP_UDP = 1, + RTP_MULTICAST = 2, } eRtpType; + +#define RTP_PT_MAP(XX) \ + XX(PCMU, TrackAudio, 0, 8000, 1) \ + XX(GSM, TrackAudio , 3, 8000, 1) \ + XX(G723, TrackAudio, 4, 8000, 1) \ + XX(DVI4_8000, TrackAudio, 5, 8000, 1) \ + XX(DVI4_16000, TrackAudio, 6, 16000, 1) \ + XX(LPC, TrackAudio, 7, 8000, 1) \ + XX(PCMA, TrackAudio, 8, 8000, 1) \ + XX(G722, TrackAudio, 9, 8000, 1) \ + XX(L16_Stereo, TrackAudio, 10, 44100, 2) \ + XX(L16_Mono, TrackAudio, 11, 44100, 1) \ + XX(QCELP, TrackAudio, 12, 8000, 1) \ + XX(CN, TrackAudio, 13, 8000, 1) \ + XX(MPA, TrackAudio, 14, 90000, 1) \ + XX(G728, TrackAudio, 15, 8000, 1) \ + XX(DVI4_11025, TrackAudio, 16, 11025, 1) \ + XX(DVI4_22050, TrackAudio, 17, 22050, 1) \ + XX(G729, TrackAudio, 18, 8000, 1) \ + XX(CelB, TrackVideo, 25, 90000, 1) \ + XX(JPEG, TrackVideo, 26, 90000, 1) \ + XX(nv, TrackVideo, 28, 90000, 1) \ + XX(H261, TrackVideo, 31, 90000, 1) \ + XX(MPV, TrackVideo, 32, 90000, 1) \ + XX(MP2T, TrackVideo, 33, 90000, 1) \ + XX(H263, TrackVideo, 34, 90000, 1) \ + +typedef enum { +#define ENUM_DEF(name, type, value, clock_rate, channel) PT_ ## name = value, + RTP_PT_MAP(ENUM_DEF) +#undef ENUM_DEF + PT_MAX = 128 +} PayloadType; + }; class RtpPacket : public BufferRaw{ public: - typedef std::shared_ptr Ptr; - uint8_t interleaved; - uint8_t PT; - bool mark; - //时间戳,单位毫秒 - uint32_t timeStamp; - uint16_t sequence; - uint32_t ssrc; - uint32_t offset; - TrackType type; + typedef std::shared_ptr Ptr; + uint8_t interleaved; + uint8_t PT; + bool mark; + //时间戳,单位毫秒 + uint32_t timeStamp; + uint16_t sequence; + uint32_t ssrc; + uint32_t offset; + TrackType type; +}; + +class RtpPayload{ +public: + static int getClockRate(int pt); + static TrackType getTrackType(int pt); + static int getAudioChannel(int pt); + static const char *getName(int pt); +private: + RtpPayload() = delete; + ~RtpPayload() = delete; }; class RtcpCounter { public: - uint32_t pktCnt = 0; - uint32_t octCount = 0; - //网络字节序 - uint32_t timeStamp = 0; - uint32_t lastTimeStamp = 0; + uint32_t pktCnt = 0; + uint32_t octCount = 0; + //网络字节序 + uint32_t timeStamp = 0; + uint32_t lastTimeStamp = 0; }; class SdpTrack { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - string _m; - string _o; - string _s; - string _i; - string _c; - string _t; - string _b; + string _m; + string _o; + string _s; + string _i; + string _c; + string _t; + string _b; + uint16_t _port; - float _duration = 0; - float _start = 0; - float _end = 0; + float _duration = 0; + float _start = 0; + float _end = 0; - map _other; - map _attr; + map _other; + map _attr; - string toString() const; + string toString() const; + string getName() const; public: - int _pt; - string _codec; - int _samplerate; - string _fmtp; - string _control; - string _control_surffix; - TrackType _type; + int _pt; + string _codec; + int _samplerate; + string _fmtp; + string _control; + string _control_surffix; + TrackType _type; public: - uint8_t _interleaved = 0; - bool _inited = false; - uint32_t _ssrc = 0; - uint16_t _seq = 0; - //时间戳,单位毫秒 - uint32_t _time_stamp = 0; + uint8_t _interleaved = 0; + bool _inited = false; + uint32_t _ssrc = 0; + uint16_t _seq = 0; + //时间戳,单位毫秒 + uint32_t _time_stamp = 0; }; class SdpParser { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - SdpParser() {} - SdpParser(const string &sdp) { load(sdp); } - ~SdpParser() {} - void load(const string &sdp); - bool available() const; - SdpTrack::Ptr getTrack(TrackType type) const; - vector getAvailableTrack() const; - string toString() const ; + SdpParser() {} + SdpParser(const string &sdp) { load(sdp); } + ~SdpParser() {} + void load(const string &sdp); + bool available() const; + SdpTrack::Ptr getTrack(TrackType type) const; + vector getAvailableTrack() const; + string toString() const ; private: - vector _track_vec; + vector _track_vec; }; /** @@ -130,18 +162,18 @@ private: */ class RtspUrl{ public: - string _url; - string _user; - string _passwd; - string _host; - uint16_t _port; - bool _is_ssl; + string _url; + string _user; + string _passwd; + string _host; + uint16_t _port; + bool _is_ssl; public: - RtspUrl() = default; - ~RtspUrl() = default; - bool parse(const string &url); + RtspUrl() = default; + ~RtspUrl() = default; + bool parse(const string &url); private: - bool setup(bool,const string &, const string &, const string &); + bool setup(bool,const string &, const string &, const string &); }; /** @@ -149,44 +181,44 @@ private: */ class Sdp : public CodecInfo{ public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - /** - * 构造sdp - * @param sample_rate 采样率 - * @param playload_type pt类型 - */ - Sdp(uint32_t sample_rate, uint8_t playload_type){ - _sample_rate = sample_rate; - _playload_type = playload_type; - } + /** + * 构造sdp + * @param sample_rate 采样率 + * @param playload_type pt类型 + */ + Sdp(uint32_t sample_rate, uint8_t playload_type){ + _sample_rate = sample_rate; + _playload_type = playload_type; + } - virtual ~Sdp(){} + virtual ~Sdp(){} - /** - * 获取sdp字符串 - * @return - */ - virtual string getSdp() const = 0; + /** + * 获取sdp字符串 + * @return + */ + virtual string getSdp() const = 0; - /** - * 获取pt - * @return - */ - uint8_t getPlayloadType() const{ - return _playload_type; - } + /** + * 获取pt + * @return + */ + uint8_t getPlayloadType() const{ + return _playload_type; + } - /** - * 获取采样率 - * @return - */ - uint32_t getSampleRate() const{ - return _sample_rate; - } + /** + * 获取采样率 + * @return + */ + uint32_t getSampleRate() const{ + return _sample_rate; + } private: - uint8_t _playload_type; - uint32_t _sample_rate; + uint8_t _playload_type; + uint32_t _sample_rate; }; /** @@ -195,56 +227,57 @@ private: class TitleSdp : public Sdp{ public: - /** - * 构造title类型sdp - * @param dur_sec rtsp点播时长,0代表直播,单位秒 - * @param header 自定义sdp描述 - * @param version sdp版本 - */ - TitleSdp(float dur_sec = 0, - const map &header = map(), - int version = 0) : Sdp(0,0){ - _printer << "v=" << version << "\r\n"; + /** + * 构造title类型sdp + * @param dur_sec rtsp点播时长,0代表直播,单位秒 + * @param header 自定义sdp描述 + * @param version sdp版本 + */ + TitleSdp(float dur_sec = 0, + const map &header = map(), + int version = 0) : Sdp(0,0){ + _printer << "v=" << version << "\r\n"; - if(!header.empty()){ - for (auto &pr : header){ - _printer << pr.first << "=" << pr.second << "\r\n"; - } - } else { - _printer << "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n"; - _printer << "s=RTSP Session, streamed by the ZLMediaKit\r\n"; - _printer << "i=ZLMediaKit Live Stream\r\n"; - _printer << "c=IN IP4 0.0.0.0\r\n"; - _printer << "t=0 0\r\n"; - } + if(!header.empty()){ + for (auto &pr : header){ + _printer << pr.first << "=" << pr.second << "\r\n"; + } + } else { + _printer << "o=- 0 0 IN IP4 0.0.0.0\r\n"; + _printer << "s=Streamed by " << SERVER_NAME << "\r\n"; + _printer << "c=IN IP4 0.0.0.0\r\n"; + _printer << "t=0 0\r\n"; + } - if(dur_sec <= 0){ - _printer << "a=range:npt=0-\r\n"; - }else{ - _printer << "a=range:npt=0-" << dur_sec << "\r\n"; - } - _printer << "a=control:*\r\n"; - } - string getSdp() const override { - return _printer; - } - /** - * 返回音频或视频类型 - * @return - */ - TrackType getTrackType() const override { - return TrackTitle; - } + if(dur_sec <= 0){ + //直播 + _printer << "a=range:npt=now-\r\n"; + }else{ + //点播 + _printer << "a=range:npt=0-" << dur_sec << "\r\n"; + } + _printer << "a=control:*\r\n"; + } + string getSdp() const override { + return _printer; + } + /** + * 返回音频或视频类型 + * @return + */ + TrackType getTrackType() const override { + return TrackTitle; + } - /** - * 返回编码器id - * @return - */ - CodecId getCodecId() const override{ - return CodecInvalid; - } + /** + * 返回编码器id + * @return + */ + CodecId getCodecId() const override{ + return CodecInvalid; + } private: - _StrPrinter _printer; + _StrPrinter _printer; }; } //namespace mediakit diff --git a/src/Rtsp/RtspDemuxer.cpp b/src/Rtsp/RtspDemuxer.cpp index 950d2e12..2c406b2a 100644 --- a/src/Rtsp/RtspDemuxer.cpp +++ b/src/Rtsp/RtspDemuxer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -35,83 +19,83 @@ using namespace std; namespace mediakit { void RtspDemuxer::loadSdp(const string &sdp){ - loadSdp(SdpParser(sdp)); + loadSdp(SdpParser(sdp)); } void RtspDemuxer::loadSdp(const SdpParser &attr) { - auto tracks = attr.getAvailableTrack(); - for (auto &track : tracks){ - switch (track->_type) { - case TrackVideo: { - makeVideoTrack(track); - } - break; - case TrackAudio: { - makeAudioTrack(track); - } - break; - default: - break; - } - } - auto titleTrack = attr.getTrack(TrackTitle); - if(titleTrack){ - _fDuration = titleTrack->_duration; - } + auto tracks = attr.getAvailableTrack(); + for (auto &track : tracks){ + switch (track->_type) { + case TrackVideo: { + makeVideoTrack(track); + } + break; + case TrackAudio: { + makeAudioTrack(track); + } + break; + default: + break; + } + } + auto titleTrack = attr.getTrack(TrackTitle); + if(titleTrack){ + _fDuration = titleTrack->_duration; + } } bool RtspDemuxer::inputRtp(const RtpPacket::Ptr & rtp) { - switch (rtp->type) { - case TrackVideo:{ - if(_videoRtpDecoder){ - return _videoRtpDecoder->inputRtp(rtp, true); - } - return false; - } - case TrackAudio:{ - if(_audioRtpDecoder){ - _audioRtpDecoder->inputRtp(rtp, false); - return false; - } - return false; - } - default: - return false; - } + switch (rtp->type) { + case TrackVideo:{ + if(_videoRtpDecoder){ + return _videoRtpDecoder->inputRtp(rtp, true); + } + return false; + } + case TrackAudio:{ + if(_audioRtpDecoder){ + _audioRtpDecoder->inputRtp(rtp, false); + return false; + } + return false; + } + default: + return false; + } } void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) { - //生成Track对象 + //生成Track对象 _audioTrack = dynamic_pointer_cast(Factory::getTrackBySdp(audio)); if(_audioTrack){ - //生成RtpCodec对象以便解码rtp - _audioRtpDecoder = Factory::getRtpDecoderByTrack(_audioTrack); - if(_audioRtpDecoder){ - //设置rtp解码器代理,生成的frame写入该Track - _audioRtpDecoder->addDelegate(_audioTrack); - onAddTrack(_audioTrack); - } else{ - //找不到相应的rtp解码器,该track无效 - _audioTrack.reset(); - } + //生成RtpCodec对象以便解码rtp + _audioRtpDecoder = Factory::getRtpDecoderByTrack(_audioTrack); + if(_audioRtpDecoder){ + //设置rtp解码器代理,生成的frame写入该Track + _audioRtpDecoder->addDelegate(_audioTrack); + onAddTrack(_audioTrack); + } else{ + //找不到相应的rtp解码器,该track无效 + _audioTrack.reset(); + } } } void RtspDemuxer::makeVideoTrack(const SdpTrack::Ptr &video) { - //生成Track对象 - _videoTrack = dynamic_pointer_cast(Factory::getTrackBySdp(video)); - if(_videoTrack){ - //生成RtpCodec对象以便解码rtp - _videoRtpDecoder = Factory::getRtpDecoderByTrack(_videoTrack); - if(_videoRtpDecoder){ - //设置rtp解码器代理,生成的frame写入该Track - _videoRtpDecoder->addDelegate(_videoTrack); - onAddTrack(_videoTrack); - }else{ - //找不到相应的rtp解码器,该track无效 - _videoTrack.reset(); - } - } + //生成Track对象 + _videoTrack = dynamic_pointer_cast(Factory::getTrackBySdp(video)); + if(_videoTrack){ + //生成RtpCodec对象以便解码rtp + _videoRtpDecoder = Factory::getRtpDecoderByTrack(_videoTrack); + if(_videoRtpDecoder){ + //设置rtp解码器代理,生成的frame写入该Track + _videoRtpDecoder->addDelegate(_videoTrack); + onAddTrack(_videoTrack); + }else{ + //找不到相应的rtp解码器,该track无效 + _videoTrack.reset(); + } + } } } /* namespace mediakit */ diff --git a/src/Rtsp/RtspDemuxer.h b/src/Rtsp/RtspDemuxer.h index c864c19a..ae98e48a 100644 --- a/src/Rtsp/RtspDemuxer.h +++ b/src/Rtsp/RtspDemuxer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTP_RTSPDEMUXER_H_ @@ -39,8 +23,8 @@ namespace mediakit { class RtspDemuxer : public Demuxer{ public: - typedef std::shared_ptr Ptr; - RtspDemuxer() = default; + typedef std::shared_ptr Ptr; + RtspDemuxer() = default; virtual ~RtspDemuxer() = default; /** @@ -48,19 +32,19 @@ public: */ void loadSdp(const string &sdp); - /** - * 开始解复用 - * @param rtp rtp包 - * @return true 代表是i帧第一个rtp包 - */ - bool inputRtp(const RtpPacket::Ptr &rtp); + /** + * 开始解复用 + * @param rtp rtp包 + * @return true 代表是i帧第一个rtp包 + */ + bool inputRtp(const RtpPacket::Ptr &rtp); private: - void makeAudioTrack(const SdpTrack::Ptr &audio); - void makeVideoTrack(const SdpTrack::Ptr &video); - void loadSdp(const SdpParser &parser); + void makeAudioTrack(const SdpTrack::Ptr &audio); + void makeVideoTrack(const SdpTrack::Ptr &video); + void loadSdp(const SdpParser &parser); private: - RtpCodec::Ptr _audioRtpDecoder; - RtpCodec::Ptr _videoRtpDecoder; + RtpCodec::Ptr _audioRtpDecoder; + RtpCodec::Ptr _videoRtpDecoder; }; } /* namespace mediakit */ diff --git a/src/Rtsp/RtspMediaSource.h b/src/Rtsp/RtspMediaSource.h index 48edce20..11ff43e7 100644 --- a/src/Rtsp/RtspMediaSource.h +++ b/src/Rtsp/RtspMediaSource.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTSP_RTSPMEDIASOURCE_H_ @@ -43,190 +27,280 @@ #include "Thread/ThreadPool.h" using namespace std; using namespace toolkit; - -#define RTP_GOP_SIZE 2048 - +#define RTP_GOP_SIZE 512 namespace mediakit { +class RtpVideoCache { +public: + + RtpVideoCache() { + _cache = std::make_shared >(); + } + + virtual ~RtpVideoCache() = default; + + void inputVideoRtp(const RtpPacket::Ptr &rtp, bool key_pos) { + if (_last_rtp_stamp != rtp->timeStamp) { + //时间戳发生变化了 + flushAll(); + } else if (_cache->size() > RTP_GOP_SIZE) { + //这个逻辑用于避免时间戳异常的流导致的内存暴增问题 + flushAll(); + } + + //追加数据到最后 + _cache->emplace_back(rtp); + _last_rtp_stamp = rtp->timeStamp; + if (key_pos) { + _key_pos = key_pos; + } + } + + virtual void onFlushVideoRtp(std::shared_ptr > &, bool key_pos) = 0; + +private: + + void flushAll() { + if (_cache->empty()) { + return; + } + onFlushVideoRtp(_cache, _key_pos); + _cache = std::make_shared >(); + _key_pos = false; + } + +private: + + std::shared_ptr > _cache; + uint32_t _last_rtp_stamp = 0; + bool _key_pos = false; +}; + +class RtpAudioCache { +public: + + RtpAudioCache() { + _cache = std::make_shared >(); + } + + virtual ~RtpAudioCache() = default; + + void inputAudioRtp(const RtpPacket::Ptr &rtp) { + if (rtp->timeStamp > _last_rtp_stamp + 100) { + //累积了100ms的音频数据 + flushAll(); + } else if (_cache->size() > 10) { + //或者audio rtp缓存超过10个 + flushAll(); + } + + //追加数据到最后 + _cache->emplace_back(rtp); + _last_rtp_stamp = rtp->timeStamp; + } + + virtual void onFlushAudioRtp(std::shared_ptr > &) = 0; + +private: + + void flushAll() { + if (_cache->empty()) { + return; + } + onFlushAudioRtp(_cache); + _cache = std::make_shared >(); + } + +private: + + std::shared_ptr > _cache; + uint32_t _last_rtp_stamp = 0; +}; + /** * rtsp媒体源的数据抽象 * rtsp有关键的两要素,分别是sdp、rtp包 * 只要生成了这两要素,那么要实现rtsp推流、rtsp服务器就很简单了 * rtsp推拉流协议中,先传递sdp,然后再协商传输方式(tcp/udp/组播),最后一直传递rtp */ -class RtspMediaSource : public MediaSource, public RingDelegate { +class RtspMediaSource : public MediaSource, public RingDelegate, public RtpVideoCache, public RtpAudioCache { public: - typedef ResourcePool PoolType; - typedef std::shared_ptr Ptr; - typedef RingBuffer RingType; + typedef ResourcePool PoolType; + typedef std::shared_ptr Ptr; + typedef std::shared_ptr > RingDataType; + typedef RingBuffer RingType; - /** - * 构造函数 - * @param vhost 虚拟主机名 - * @param app 应用名 - * @param stream_id 流id - * @param ring_size 可以设置固定的环形缓冲大小,0则自适应 - */ - RtspMediaSource(const string &vhost, - const string &app, - const string &stream_id, - int ring_size = RTP_GOP_SIZE) : - MediaSource(RTSP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {} + /** + * 构造函数 + * @param vhost 虚拟主机名 + * @param app 应用名 + * @param stream_id 流id + * @param ring_size 可以设置固定的环形缓冲大小,0则自适应 + */ + RtspMediaSource(const string &vhost, + const string &app, + const string &stream_id, + int ring_size = RTP_GOP_SIZE) : + MediaSource(RTSP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {} - virtual ~RtspMediaSource() {} + virtual ~RtspMediaSource() {} - /** - * 获取媒体源的环形缓冲 - */ - const RingType::Ptr &getRing() const { - return _ring; - } + /** + * 获取媒体源的环形缓冲 + */ + const RingType::Ptr &getRing() const { + return _ring; + } - /** - * 获取播放器个数 - */ - int readerCount() override { - return _ring ? _ring->readerCount() : 0; - } + /** + * 获取播放器个数 + */ + int readerCount() override { + return _ring ? _ring->readerCount() : 0; + } - /** - * 获取该源的sdp - */ - const string &getSdp() const { - return _sdp; - } + /** + * 获取该源的sdp + */ + const string &getSdp() const { + return _sdp; + } - /** - * 获取相应轨道的ssrc - */ - virtual uint32_t getSsrc(TrackType trackType) { - auto track = _sdp_parser.getTrack(trackType); - if (!track) { - return 0; - } - return track->_ssrc; - } + /** + * 获取相应轨道的ssrc + */ + virtual uint32_t getSsrc(TrackType trackType) { + auto track = _sdp_parser.getTrack(trackType); + if (!track) { + return 0; + } + return track->_ssrc; + } - /** - * 获取相应轨道的seqence - */ - virtual uint16_t getSeqence(TrackType trackType) { - auto track = _sdp_parser.getTrack(trackType); - if (!track) { - return 0; - } - return track->_seq; - } + /** + * 获取相应轨道的seqence + */ + virtual uint16_t getSeqence(TrackType trackType) { + auto track = _sdp_parser.getTrack(trackType); + if (!track) { + return 0; + } + return track->_seq; + } - /** - * 获取相应轨道的时间戳,单位毫秒 - */ - uint32_t getTimeStamp(TrackType trackType) override { - auto track = _sdp_parser.getTrack(trackType); - if (track) { - return track->_time_stamp; - } - auto tracks = _sdp_parser.getAvailableTrack(); - switch (tracks.size()) { - case 0: - return 0; - case 1: - return tracks[0]->_time_stamp; - default: - return MAX(tracks[0]->_time_stamp, tracks[1]->_time_stamp); - } - } + /** + * 获取相应轨道的时间戳,单位毫秒 + */ + uint32_t getTimeStamp(TrackType trackType) override { + auto track = _sdp_parser.getTrack(trackType); + if (track) { + return track->_time_stamp; + } + auto tracks = _sdp_parser.getAvailableTrack(); + switch (tracks.size()) { + case 0: + return 0; + case 1: + return tracks[0]->_time_stamp; + default: + return MIN(tracks[0]->_time_stamp, tracks[1]->_time_stamp); + } + } - /** - * 更新时间戳 - */ - void setTimeStamp(uint32_t uiStamp) override { - auto tracks = _sdp_parser.getAvailableTrack(); - for (auto &track : tracks) { - track->_time_stamp = uiStamp; - } - } + /** + * 更新时间戳 + */ + void setTimeStamp(uint32_t uiStamp) override { + auto tracks = _sdp_parser.getAvailableTrack(); + for (auto &track : tracks) { + track->_time_stamp = uiStamp; + } + } - /** - * 设置sdp - */ - virtual void setSdp(const string &sdp) { - _sdp = sdp; - _sdp_parser.load(sdp); - _have_video = (bool)_sdp_parser.getTrack(TrackVideo); - if (_ring) { - regist(); - } - } + /** + * 设置sdp + */ + virtual void setSdp(const string &sdp) { + _sdp = sdp; + _sdp_parser.load(sdp); + _have_video = (bool)_sdp_parser.getTrack(TrackVideo); + if (_ring) { + regist(); + } + } - /** - * 输入rtp - * @param rtp rtp包 - * @param keyPos 该包是否为关键帧的第一个包 - */ - void onWrite(const RtpPacket::Ptr &rtp, bool keyPos) override { - auto track = _sdp_parser.getTrack(rtp->type); - if (track) { - track->_seq = rtp->sequence; - track->_time_stamp = rtp->timeStamp; - track->_ssrc = rtp->ssrc; - } - if (!_ring) { - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) { - auto strongSelf = weakSelf.lock(); - if (!strongSelf) { - return; - } - strongSelf->onReaderChanged(size); - }; + /** + * 输入rtp + * @param rtp rtp包 + * @param keyPos 该包是否为关键帧的第一个包 + */ + void onWrite(const RtpPacket::Ptr &rtp, bool keyPos) override { + auto track = _sdp_parser.getTrack(rtp->type); + if (track) { + track->_seq = rtp->sequence; + track->_time_stamp = rtp->timeStamp; + track->_ssrc = rtp->ssrc; + } + if (!_ring) { + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { + return; + } + strongSelf->onReaderChanged(size); + }; //rtp包缓存最大允许2048个,大概最多3MB数据 //但是这个是GOP缓存的上限值,真实的GOP缓存大小等于两个I帧之间的包数的两倍 //而且每次遇到I帧,则会清空GOP缓存,所以真实的GOP缓存远小于此值 - _ring = std::make_shared(_ring_size, std::move(lam)); - onReaderChanged(0); - if (!_sdp.empty()) { - regist(); - } - } - //不存在视频,为了减少缓存延时,那么关闭GOP缓存 - _ring->write(rtp, _have_video ? keyPos : true); - checkNoneReader(); - } -private: - /** - * 每次增减消费者都会触发该函数 - */ - void onReaderChanged(int size) { - //我们记录最后一次活动时间 - _reader_changed_ticker.resetTime(); - if (size != 0 || totalReaderCount() != 0) { - //还有消费者正在观看该流 - _async_emit_none_reader = false; - return; - } - _async_emit_none_reader = true; - } + _ring = std::make_shared(_ring_size, std::move(lam)); + onReaderChanged(0); + if (!_sdp.empty()) { + regist(); + } + } - /** - * 检查是否无人消费该流, - * 如果无人消费且超过一定时间会触发onNoneReader事件 - */ - void checkNoneReader() { - GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS); - if (_async_emit_none_reader && _reader_changed_ticker.elapsedTime() > stream_none_reader_delay) { - _async_emit_none_reader = false; - onNoneReader(); - } - } -protected: - int _ring_size; - bool _async_emit_none_reader = false; - bool _have_video = false; - Ticker _reader_changed_ticker; - SdpParser _sdp_parser; - string _sdp; - RingType::Ptr _ring; + if(rtp->type == TrackVideo){ + RtpVideoCache::inputVideoRtp(rtp, keyPos); + }else{ + RtpAudioCache::inputAudioRtp(rtp); + } + } + +private: + + /** + * 批量flush时间戳相同的视频rtp包时触发该函数 + * @param rtp_list 时间戳相同的rtp包列表 + * @param key_pos 是否包含关键帧 + */ + void onFlushVideoRtp(std::shared_ptr > &rtp_list, bool key_pos) override { + _ring->write(rtp_list, key_pos); + } + + /** + * 批量flush一定数量的音频rtp包时触发该函数 + * @param rtp_list rtp包列表 + */ + void onFlushAudioRtp(std::shared_ptr > &rtp_list) override{ + //只有音频的话,就不存在gop缓存的意义 + _ring->write(rtp_list, !_have_video); + } + + /** + * 每次增减消费者都会触发该函数 + */ + void onReaderChanged(int size) { + if (size == 0) { + onNoneReader(); + } + } +private: + int _ring_size; + bool _have_video = false; + SdpParser _sdp_parser; + string _sdp; + RingType::Ptr _ring; }; } /* namespace mediakit */ diff --git a/src/Rtsp/RtspMediaSourceImp.h b/src/Rtsp/RtspMediaSourceImp.h index 4586df2b..495158f3 100644 --- a/src/Rtsp/RtspMediaSourceImp.h +++ b/src/Rtsp/RtspMediaSourceImp.h @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef SRC_RTSP_RTSPTORTMPMEDIASOURCE_H_ #define SRC_RTSP_RTSPTORTMPMEDIASOURCE_H_ @@ -39,12 +23,12 @@ public: typedef std::shared_ptr Ptr; /** - * 构造函数 - * @param vhost 虚拟主机 - * @param app 应用名 - * @param id 流id - * @param ringSize 环形缓存大小 - */ + * 构造函数 + * @param vhost 虚拟主机 + * @param app 应用名 + * @param id 流id + * @param ringSize 环形缓存大小 + */ RtspMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTP_GOP_SIZE) : RtspMediaSource(vhost, app, id,ringSize) { _demuxer = std::make_shared(); _demuxer->setTrackListener(this); @@ -69,13 +53,13 @@ public: } /** - * 设置监听器 - * @param listener - */ + * 设置监听器 + * @param listener + */ void setListener(const std::weak_ptr &listener) override { RtspMediaSource::setListener(listener); if(_muxer){ - _muxer->setListener(listener); + _muxer->setMediaListener(listener); } } @@ -87,15 +71,42 @@ public: } /** - * 设置协议转换 - * @param enableRtmp 是否转换成rtmp - * @param enableHls 是否转换成hls - * @param enableMP4 是否mp4录制 - */ + * 设置录制状态 + * @param type 录制类型 + * @param start 开始或停止 + * @param custom_path 开启录制时,指定自定义路径 + * @return 是否设置成功 + */ + bool setupRecord(Recorder::type type, bool start, const string &custom_path) override{ + if(_muxer){ + return _muxer->setupRecord(*this,type, start, custom_path); + } + return RtspMediaSource::setupRecord(type, start, custom_path); + } + + /** + * 获取录制状态 + * @param type 录制类型 + * @return 录制状态 + */ + bool isRecording(Recorder::type type) override{ + if(_muxer){ + return _muxer->isRecording(*this,type); + } + return RtspMediaSource::isRecording(type); + } + + + /** + * 设置协议转换 + * @param enableRtmp 是否转换成rtmp + * @param enableHls 是否转换成hls + * @param enableMP4 是否mp4录制 + */ void setProtocolTranslation(bool enableRtmp,bool enableHls,bool enableMP4){ //不重复生成rtsp _muxer = std::make_shared(getVhost(), getApp(), getId(), _demuxer->getDuration(), false, enableRtmp, enableHls, enableMP4); - _muxer->setListener(getListener()); + _muxer->setMediaListener(getListener()); _muxer->setTrackListener(this); for(auto &track : _demuxer->getTracks(false)){ _muxer->addTrack(track); @@ -104,8 +115,8 @@ public: } /** - * _demuxer触发的添加Track事件 - */ + * _demuxer触发的添加Track事件 + */ void onAddTrack(const Track::Ptr &track) override { if(_muxer){ _muxer->addTrack(track); diff --git a/src/Rtsp/RtspMediaSourceMuxer.h b/src/Rtsp/RtspMediaSourceMuxer.h index 834374e6..4d2683ab 100644 --- a/src/Rtsp/RtspMediaSourceMuxer.h +++ b/src/Rtsp/RtspMediaSourceMuxer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTSPMEDIASOURCEMUXER_H diff --git a/src/Rtsp/RtspMuxer.cpp b/src/Rtsp/RtspMuxer.cpp index 04ac57dd..cb6e3969 100644 --- a/src/Rtsp/RtspMuxer.cpp +++ b/src/Rtsp/RtspMuxer.cpp @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "RtspMuxer.h" #include "Extension/Factory.h" diff --git a/src/Rtsp/RtspMuxer.h b/src/Rtsp/RtspMuxer.h index 18a74515..89251e6c 100644 --- a/src/Rtsp/RtspMuxer.h +++ b/src/Rtsp/RtspMuxer.h @@ -1,28 +1,12 @@ /* -* MIT License -* -* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> -* -* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef ZLMEDIAKIT_RTSPMUXER_H #define ZLMEDIAKIT_RTSPMUXER_H diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 682cbe19..e96c3d1f 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -1,29 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> - * Copyright (c) 2018 huohuo <913481084@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include #include #include @@ -43,29 +27,29 @@ using namespace mediakit::Client; namespace mediakit { enum PlayType { - type_play = 0, - type_pause, - type_seek + type_play = 0, + type_pause, + type_seek }; RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){ - RtpReceiver::setPoolSize(64); + RtpReceiver::setPoolSize(64); } RtspPlayer::~RtspPlayer(void) { DebugL << endl; } void RtspPlayer::teardown(){ - if (alive()) { - sendRtspRequest("TEARDOWN" ,_strContentBase); - shutdown(SockException(Err_shutdown,"teardown")); - } + if (alive()) { + sendRtspRequest("TEARDOWN" ,_strContentBase); + shutdown(SockException(Err_shutdown,"teardown")); + } - _rtspMd5Nonce.clear(); - _rtspRealm.clear(); - _aTrackInfo.clear(); + _rtspMd5Nonce.clear(); + _rtspRealm.clear(); + _aTrackInfo.clear(); _strSession.clear(); _strContentBase.clear(); - RtpReceiver::clear(); + RtpReceiver::clear(); CLEAR_ARR(_apRtpSock); CLEAR_ARR(_apRtcpSock); @@ -74,65 +58,65 @@ void RtspPlayer::teardown(){ CLEAR_ARR(_aui64RtpRecv) CLEAR_ARR(_aui16NowSeq) - _pPlayTimer.reset(); + _pPlayTimer.reset(); _pRtpTimer.reset(); - _uiCseq = 1; - _onHandshake = nullptr; + _uiCseq = 1; + _onHandshake = nullptr; } void RtspPlayer::play(const string &strUrl){ - RtspUrl url; - if(!url.parse(strUrl)){ - onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false); - return; - } + RtspUrl url; + if(!url.parse(strUrl)){ + onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false); + return; + } - teardown(); + teardown(); - if (url._user.size()) { - (*this)[kRtspUser] = url._user; - } - if (url._passwd.size()) { - (*this)[kRtspPwd] = url._passwd; - (*this)[kRtspPwdIsMD5] = false; - } + if (url._user.size()) { + (*this)[kRtspUser] = url._user; + } + if (url._passwd.size()) { + (*this)[kRtspPwd] = url._passwd; + (*this)[kRtspPwdIsMD5] = false; + } - _strUrl = url._url; - _eType = (Rtsp::eRtpType)(int)(*this)[kRtpType]; - DebugL << url._url << " " << (url._user.size() ? url._user : "null") << " " << (url._passwd.size() ? url._passwd : "null") << " " << _eType; + _strUrl = url._url; + _eType = (Rtsp::eRtpType)(int)(*this)[kRtpType]; + DebugL << url._url << " " << (url._user.size() ? url._user : "null") << " " << (url._passwd.size() ? url._passwd : "null") << " " << _eType; - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - float playTimeOutSec = (*this)[kTimeoutMS].as() / 1000.0; - _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { - return false; - } - strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout"),false); - return false; - },getPoller())); + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + float playTimeOutSec = (*this)[kTimeoutMS].as() / 1000.0; + _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { + auto strongSelf=weakSelf.lock(); + if(!strongSelf) { + return false; + } + strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout"),false); + return false; + },getPoller())); - if(!(*this)[kNetAdapter].empty()){ - setNetAdapter((*this)[kNetAdapter]); - } - startConnect(url._host, url._port, playTimeOutSec); + if(!(*this)[kNetAdapter].empty()){ + setNetAdapter((*this)[kNetAdapter]); + } + startConnect(url._host, url._port, playTimeOutSec); } void RtspPlayer::onConnect(const SockException &err){ - if(err.getErrCode() != Err_success) { - onPlayResult_l(err,false); - return; - } + if(err.getErrCode() != Err_success) { + onPlayResult_l(err,false); + return; + } - sendDescribe(); + sendDescribe(); } void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) { input(pBuf->data(),pBuf->size()); } void RtspPlayer::onErr(const SockException &ex) { - //定时器_pPlayTimer为空后表明握手结束了 - onPlayResult_l(ex,!_pPlayTimer); + //定时器_pPlayTimer为空后表明握手结束了 + onPlayResult_l(ex,!_pPlayTimer); } // from live555 bool RtspPlayer::handleAuthenticationFailure(const string ¶msStr) { @@ -167,25 +151,25 @@ bool RtspPlayer::handleAuthenticationFailure(const string ¶msStr) { return false; } void RtspPlayer::handleResDESCRIBE(const Parser& parser) { - string authInfo = parser["WWW-Authenticate"]; - //发送DESCRIBE命令后的回复 - if ((parser.Url() == "401") && handleAuthenticationFailure(authInfo)) { - sendDescribe(); - return; - } - if(parser.Url() == "302" || parser.Url() == "301"){ - auto newUrl = parser["Location"]; - if(newUrl.empty()){ - throw std::runtime_error("未找到Location字段(跳转url)"); - } - play(newUrl); - return; - } - if (parser.Url() != "200") { - throw std::runtime_error( - StrPrinter << "DESCRIBE:" << parser.Url() << " " << parser.Tail() << endl); - } - _strContentBase = parser["Content-Base"]; + string authInfo = parser["WWW-Authenticate"]; + //发送DESCRIBE命令后的回复 + if ((parser.Url() == "401") && handleAuthenticationFailure(authInfo)) { + sendDescribe(); + return; + } + if(parser.Url() == "302" || parser.Url() == "301"){ + auto newUrl = parser["Location"]; + if(newUrl.empty()){ + throw std::runtime_error("未找到Location字段(跳转url)"); + } + play(newUrl); + return; + } + if (parser.Url() != "200") { + throw std::runtime_error( + StrPrinter << "DESCRIBE:" << parser.Url() << " " << parser.Tail() << endl); + } + _strContentBase = parser["Content-Base"]; if(_strContentBase.empty()){ _strContentBase = _strUrl; @@ -194,58 +178,58 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) { _strContentBase.pop_back(); } - SdpParser sdpParser(parser.Content()); - //解析sdp - _aTrackInfo = sdpParser.getAvailableTrack(); - auto title = sdpParser.getTrack(TrackTitle); - bool isPlayback = false; - if(title && title->_duration ){ - isPlayback = true; - } + SdpParser sdpParser(parser.Content()); + //解析sdp + _aTrackInfo = sdpParser.getAvailableTrack(); + auto title = sdpParser.getTrack(TrackTitle); + _is_play_back = false; + if(title && title->_duration ){ + _is_play_back = true; + } for(auto &stamp : _stamp){ - stamp.setPlayBack(isPlayback); + stamp.setPlayBack(_is_play_back); stamp.setRelativeStamp(0); } - if (_aTrackInfo.empty()) { - throw std::runtime_error("无有效的Sdp Track"); - } - if (!onCheckSDP(sdpParser.toString())) { - throw std::runtime_error("onCheckSDP faied"); - } + if (_aTrackInfo.empty()) { + throw std::runtime_error("无有效的Sdp Track"); + } + if (!onCheckSDP(sdpParser.toString())) { + throw std::runtime_error("onCheckSDP faied"); + } - sendSetup(0); + sendSetup(0); } //有必要的情况下创建udp端口 void RtspPlayer::createUdpSockIfNecessary(int track_idx){ - auto &rtpSockRef = _apRtpSock[track_idx]; - auto &rtcpSockRef = _apRtcpSock[track_idx]; - if(!rtpSockRef){ - rtpSockRef.reset(new Socket(getPoller())); - //rtp随机端口 - if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) { - rtpSockRef.reset(); - throw std::runtime_error("open rtp sock failed"); - } - } + auto &rtpSockRef = _apRtpSock[track_idx]; + auto &rtcpSockRef = _apRtcpSock[track_idx]; + if(!rtpSockRef){ + rtpSockRef.reset(new Socket(getPoller())); + //rtp随机端口 + if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) { + rtpSockRef.reset(); + throw std::runtime_error("open rtp sock failed"); + } + } - if(!rtcpSockRef){ - rtcpSockRef.reset(new Socket(getPoller())); - //rtcp端口为rtp端口+1,目的是为了兼容某些服务器,其实更推荐随机端口 - if (!rtcpSockRef->bindUdpSock(rtpSockRef->get_local_port() + 1, get_local_ip().data())) { - rtcpSockRef.reset(); - throw std::runtime_error("open rtcp sock failed"); - } - } + if(!rtcpSockRef){ + rtcpSockRef.reset(new Socket(getPoller())); + //rtcp端口为rtp端口+1,目的是为了兼容某些服务器,其实更推荐随机端口 + if (!rtcpSockRef->bindUdpSock(rtpSockRef->get_local_port() + 1, get_local_ip().data())) { + rtcpSockRef.reset(); + throw std::runtime_error("open rtcp sock failed"); + } + } - if(rtpSockRef->get_local_port() % 2 != 0){ - //如果rtp端口不是偶数,那么与rtcp端口互换,目的是兼容一些要求严格的服务器 - Socket::Ptr tmp = rtpSockRef; - rtpSockRef = rtcpSockRef; - rtcpSockRef = tmp; - } + if(rtpSockRef->get_local_port() % 2 != 0){ + //如果rtp端口不是偶数,那么与rtcp端口互换,目的是兼容一些要求严格的服务器 + Socket::Ptr tmp = rtpSockRef; + rtpSockRef = rtcpSockRef; + rtcpSockRef = tmp; + } } @@ -253,91 +237,91 @@ void RtspPlayer::createUdpSockIfNecessary(int track_idx){ void RtspPlayer::sendSetup(unsigned int trackIndex) { _onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex); auto &track = _aTrackInfo[trackIndex]; - auto baseUrl = _strContentBase + "/" + track->_control_surffix; - switch (_eType) { - case Rtsp::RTP_TCP: { - sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1}); - } - break; - case Rtsp::RTP_MULTICAST: { - sendRtspRequest("SETUP",baseUrl,{"Transport","Transport: RTP/AVP;multicast"}); - } - break; - case Rtsp::RTP_UDP: { - createUdpSockIfNecessary(trackIndex); - sendRtspRequest("SETUP",baseUrl,{"Transport", + auto baseUrl = _strContentBase + "/" + track->_control_surffix; + switch (_eType) { + case Rtsp::RTP_TCP: { + sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1}); + } + break; + case Rtsp::RTP_MULTICAST: { + sendRtspRequest("SETUP",baseUrl,{"Transport","Transport: RTP/AVP;multicast"}); + } + break; + case Rtsp::RTP_UDP: { + createUdpSockIfNecessary(trackIndex); + sendRtspRequest("SETUP",baseUrl,{"Transport", StrPrinter << "RTP/AVP;unicast;client_port=" << _apRtpSock[trackIndex]->get_local_port() << "-" << _apRtcpSock[trackIndex]->get_local_port()}); - } - break; - default: - break; - } + } + break; + default: + break; + } } void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) { - if (parser.Url() != "200") { - throw std::runtime_error( - StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl); - } - if (uiTrackIndex == 0) { - _strSession = parser["Session"]; + if (parser.Url() != "200") { + throw std::runtime_error( + StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl); + } + if (uiTrackIndex == 0) { + _strSession = parser["Session"]; _strSession.append(";"); _strSession = FindField(_strSession.data(), nullptr, ";"); - } + } - auto strTransport = parser["Transport"]; - if(strTransport.find("TCP") != string::npos || strTransport.find("interleaved") != string::npos){ - _eType = Rtsp::RTP_TCP; - }else if(strTransport.find("multicast") != string::npos){ - _eType = Rtsp::RTP_MULTICAST; - }else{ - _eType = Rtsp::RTP_UDP; - } + auto strTransport = parser["Transport"]; + if(strTransport.find("TCP") != string::npos || strTransport.find("interleaved") != string::npos){ + _eType = Rtsp::RTP_TCP; + }else if(strTransport.find("multicast") != string::npos){ + _eType = Rtsp::RTP_MULTICAST; + }else{ + _eType = Rtsp::RTP_UDP; + } - RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP); + RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP); - if(_eType == Rtsp::RTP_TCP) { - string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-"); - _aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data()); - }else{ - const char *strPos = (_eType == Rtsp::RTP_MULTICAST ? "port=" : "server_port=") ; - auto port_str = FindField((strTransport + ";").data(), strPos, ";"); - uint16_t rtp_port = atoi(FindField(port_str.data(), NULL, "-").data()); + if(_eType == Rtsp::RTP_TCP) { + string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-"); + _aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data()); + }else{ + const char *strPos = (_eType == Rtsp::RTP_MULTICAST ? "port=" : "server_port=") ; + auto port_str = FindField((strTransport + ";").data(), strPos, ";"); + uint16_t rtp_port = atoi(FindField(port_str.data(), NULL, "-").data()); uint16_t rtcp_port = atoi(FindField(port_str.data(), "-",NULL).data()); auto &pRtpSockRef = _apRtpSock[uiTrackIndex]; auto &pRtcpSockRef = _apRtcpSock[uiTrackIndex]; - if (_eType == Rtsp::RTP_MULTICAST) { - //udp组播 - auto multiAddr = FindField((strTransport + ";").data(), "destination=", ";"); + if (_eType == Rtsp::RTP_MULTICAST) { + //udp组播 + auto multiAddr = FindField((strTransport + ";").data(), "destination=", ";"); pRtpSockRef.reset(new Socket(getPoller())); - if (!pRtpSockRef->bindUdpSock(rtp_port, multiAddr.data())) { - pRtpSockRef.reset(); - throw std::runtime_error("open udp sock err"); - } - auto fd = pRtpSockRef->rawFD(); - if (-1 == SockUtil::joinMultiAddrFilter(fd, multiAddr.data(), get_peer_ip().data(),get_local_ip().data())) { - SockUtil::joinMultiAddr(fd, multiAddr.data(),get_local_ip().data()); - } - } else { - createUdpSockIfNecessary(uiTrackIndex); - //udp单播 - struct sockaddr_in rtpto; - rtpto.sin_port = ntohs(rtp_port); - rtpto.sin_family = AF_INET; - rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data()); - pRtpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto)); - //发送rtp打洞包 - pRtpSockRef->send("\xce\xfa\xed\xfe", 4); + if (!pRtpSockRef->bindUdpSock(rtp_port, multiAddr.data())) { + pRtpSockRef.reset(); + throw std::runtime_error("open udp sock err"); + } + auto fd = pRtpSockRef->rawFD(); + if (-1 == SockUtil::joinMultiAddrFilter(fd, multiAddr.data(), get_peer_ip().data(),get_local_ip().data())) { + SockUtil::joinMultiAddr(fd, multiAddr.data(),get_local_ip().data()); + } + } else { + createUdpSockIfNecessary(uiTrackIndex); + //udp单播 + struct sockaddr_in rtpto; + rtpto.sin_port = ntohs(rtp_port); + rtpto.sin_family = AF_INET; + rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data()); + pRtpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto)); + //发送rtp打洞包 + pRtpSockRef->send("\xce\xfa\xed\xfe", 4); - //设置rtcp发送目标,为后续发送rtcp做准备 + //设置rtcp发送目标,为后续发送rtcp做准备 rtpto.sin_port = ntohs(rtcp_port); rtpto.sin_family = AF_INET; rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data()); pRtcpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto)); - } + } auto srcIP = inet_addr(get_peer_ip().data()); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); @@ -368,98 +352,98 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) strongSelf->onRtcpPacket(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex], (unsigned char *) buf->data(), buf->size()); }); } - } + } - if (uiTrackIndex < _aTrackInfo.size() - 1) { - //需要继续发送SETUP命令 - sendSetup(uiTrackIndex + 1); - return; - } - //所有setup命令发送完毕 - //发送play命令 + if (uiTrackIndex < _aTrackInfo.size() - 1) { + //需要继续发送SETUP命令 + sendSetup(uiTrackIndex + 1); + return; + } + //所有setup命令发送完毕 + //发送play命令 sendPause(type_play, 0); } void RtspPlayer::sendDescribe() { - //发送DESCRIBE命令后处理函数:handleResDESCRIBE - _onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1); - sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"}); + //发送DESCRIBE命令后处理函数:handleResDESCRIBE + _onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1); + sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"}); } void RtspPlayer::sendPause(int type , uint32_t seekMS){ - _onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,type); - //开启或暂停rtsp - switch (type){ - case type_pause: - sendRtspRequest("PAUSE", _strContentBase); - break; - case type_play: - sendRtspRequest("PLAY", _strContentBase); - break; - case type_seek: - sendRtspRequest("PLAY", _strContentBase, {"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"}); - break; - default: - WarnL << "unknown type : " << type; - _onHandshake = nullptr; - break; - } + _onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,type); + //开启或暂停rtsp + switch (type){ + case type_pause: + sendRtspRequest("PAUSE", _strContentBase); + break; + case type_play: + sendRtspRequest("PLAY", _strContentBase); + break; + case type_seek: + sendRtspRequest("PLAY", _strContentBase, {"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"}); + break; + default: + WarnL << "unknown type : " << type; + _onHandshake = nullptr; + break; + } } void RtspPlayer::pause(bool bPause) { sendPause(bPause ? type_pause : type_seek, getProgressMilliSecond()); } void RtspPlayer::handleResPAUSE(const Parser& parser,int type) { - if (parser.Url() != "200") { - switch (type) { - case type_pause: - WarnL << "Pause failed:" << parser.Url() << " " << parser.Tail() << endl; - break; - case type_play: - WarnL << "Play failed:" << parser.Url() << " " << parser.Tail() << endl; - break; - case type_seek: - WarnL << "Seek failed:" << parser.Url() << " " << parser.Tail() << endl; - break; - } - return; - } + if (parser.Url() != "200") { + switch (type) { + case type_pause: + WarnL << "Pause failed:" << parser.Url() << " " << parser.Tail() << endl; + break; + case type_play: + WarnL << "Play failed:" << parser.Url() << " " << parser.Tail() << endl; + break; + case type_seek: + WarnL << "Seek failed:" << parser.Url() << " " << parser.Tail() << endl; + break; + } + return; + } - if (type == type_pause) { - //暂停成功! - _pRtpTimer.reset(); - return; - } + if (type == type_pause) { + //暂停成功! + _pRtpTimer.reset(); + return; + } - //play或seek成功 - uint32_t iSeekTo = 0; - //修正时间轴 - auto strRange = parser["Range"]; - if (strRange.size()) { - auto strStart = FindField(strRange.data(), "npt=", "-"); - if (strStart == "now") { - strStart = "0"; - } - iSeekTo = 1000 * atof(strStart.data()); - DebugL << "seekTo(ms):" << iSeekTo; - } - //设置相对时间戳 - _stamp[0].setRelativeStamp(iSeekTo); - _stamp[1].setRelativeStamp(iSeekTo); - onPlayResult_l(SockException(Err_success, type == type_seek ? "resum rtsp success" : "rtsp play success"), type == type_seek); + //play或seek成功 + uint32_t iSeekTo = 0; + //修正时间轴 + auto strRange = parser["Range"]; + if (strRange.size()) { + auto strStart = FindField(strRange.data(), "npt=", "-"); + if (strStart == "now") { + strStart = "0"; + } + iSeekTo = 1000 * atof(strStart.data()); + DebugL << "seekTo(ms):" << iSeekTo; + } + //设置相对时间戳 + _stamp[0].setRelativeStamp(iSeekTo); + _stamp[1].setRelativeStamp(iSeekTo); + onPlayResult_l(SockException(Err_success, type == type_seek ? "resum rtsp success" : "rtsp play success"), type == type_seek); } void RtspPlayer::onWholeRtspPacket(Parser &parser) { try { - decltype(_onHandshake) fun; - _onHandshake.swap(fun); + decltype(_onHandshake) fun; + _onHandshake.swap(fun); if(fun){ fun(parser); } parser.Clear(); } catch (std::exception &err) { - //定时器_pPlayTimer为空后表明握手结束了 - onPlayResult_l(SockException(Err_other, err.what()),!_pPlayTimer); + //定时器_pPlayTimer为空后表明握手结束了 + onPlayResult_l(SockException(Err_other, err.what()),!_pPlayTimer); } } @@ -610,39 +594,39 @@ void RtspPlayer::sendReceiverReport(bool overTcp,int iTrackIndex){ void RtspPlayer::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx){ - //统计丢包率 - if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) { - _aui16FirstSeq[trackidx] = rtppt->sequence; - _aui64RtpRecv[trackidx] = 0; - } - _aui64RtpRecv[trackidx] ++; - _aui16NowSeq[trackidx] = rtppt->sequence; + //统计丢包率 + if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) { + _aui16FirstSeq[trackidx] = rtppt->sequence; + _aui64RtpRecv[trackidx] = 0; + } + _aui64RtpRecv[trackidx] ++; + _aui16NowSeq[trackidx] = rtppt->sequence; - //计算相对时间戳 - int64_t dts_out; - _stamp[trackidx].revise(rtppt->timeStamp,rtppt->timeStamp,dts_out,dts_out); + //计算相对时间戳 + int64_t dts_out; + _stamp[trackidx].revise(rtppt->timeStamp,rtppt->timeStamp,dts_out,dts_out); rtppt->timeStamp = dts_out; - onRecvRTP_l(rtppt,_aTrackInfo[trackidx]); + onRecvRTP_l(rtppt,_aTrackInfo[trackidx]); } float RtspPlayer::getPacketLossRate(TrackType type) const{ - int iTrackIdx = getTrackIndexByTrackType(type); - if(iTrackIdx == -1){ - uint64_t totalRecv = 0; - uint64_t totalSend = 0; - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - totalRecv += _aui64RtpRecv[i]; - totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1); - } - if(totalSend == 0){ - return 0; - } - return 1.0 - (double)totalRecv / totalSend; - } + int iTrackIdx = getTrackIndexByTrackType(type); + if(iTrackIdx == -1){ + uint64_t totalRecv = 0; + uint64_t totalSend = 0; + for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { + totalRecv += _aui64RtpRecv[i]; + totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1); + } + if(totalSend == 0){ + return 0; + } + return 1.0 - (double)totalRecv / totalSend; + } - if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){ - return 0; - } - return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1); + if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){ + return 0; + } + return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1); } uint32_t RtspPlayer::getProgressMilliSecond() const{ @@ -653,70 +637,70 @@ void RtspPlayer::seekToMilliSecond(uint32_t ms) { } void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list &header) { - string key; - StrCaseMap header_map; - int i = 0; - for(auto &val : header){ - if(++i % 2 == 0){ - header_map.emplace(key,val); - }else{ - key = val; - } - } - sendRtspRequest(cmd,url,header_map); + string key; + StrCaseMap header_map; + int i = 0; + for(auto &val : header){ + if(++i % 2 == 0){ + header_map.emplace(key,val); + }else{ + key = val; + } + } + sendRtspRequest(cmd,url,header_map); } void RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const) { - auto header = header_const; - header.emplace("CSeq",StrPrinter << _uiCseq++); - header.emplace("User-Agent",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")"); + auto header = header_const; + header.emplace("CSeq",StrPrinter << _uiCseq++); + header.emplace("User-Agent",SERVER_NAME); - if(!_strSession.empty()){ - header.emplace("Session",_strSession); - } + if(!_strSession.empty()){ + header.emplace("Session",_strSession); + } - if(!_rtspRealm.empty() && !(*this)[kRtspUser].empty()){ - if(!_rtspMd5Nonce.empty()){ - //MD5认证 - /* - response计算方法如下: - RTSP客户端应该使用username + password并计算response如下: - (1)当password为MD5编码,则 - response = md5( password:nonce:md5(public_method:url) ); - (2)当password为ANSI字符串,则 - response= md5( md5(username:realm:password):nonce:md5(public_method:url) ); - */ - string encrypted_pwd = (*this)[kRtspPwd]; - if(!(*this)[kRtspPwdIsMD5].as()){ - encrypted_pwd = MD5((*this)[kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest(); - } - auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest(); - _StrPrinter printer; - printer << "Digest "; - printer << "username=\"" << (*this)[kRtspUser] << "\", "; - printer << "realm=\"" << _rtspRealm << "\", "; - printer << "nonce=\"" << _rtspMd5Nonce << "\", "; - printer << "uri=\"" << url << "\", "; - printer << "response=\"" << response << "\""; - header.emplace("Authorization",printer); - }else if(!(*this)[kRtspPwdIsMD5].as()){ - //base64认证 - string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd]; - char authStrBase64[1024] = {0}; - av_base64_encode(authStrBase64,sizeof(authStrBase64),(uint8_t *)authStr.data(),authStr.size()); - header.emplace("Authorization",StrPrinter << "Basic " << authStrBase64 ); - } - } + if(!_rtspRealm.empty() && !(*this)[kRtspUser].empty()){ + if(!_rtspMd5Nonce.empty()){ + //MD5认证 + /* + response计算方法如下: + RTSP客户端应该使用username + password并计算response如下: + (1)当password为MD5编码,则 + response = md5( password:nonce:md5(public_method:url) ); + (2)当password为ANSI字符串,则 + response= md5( md5(username:realm:password):nonce:md5(public_method:url) ); + */ + string encrypted_pwd = (*this)[kRtspPwd]; + if(!(*this)[kRtspPwdIsMD5].as()){ + encrypted_pwd = MD5((*this)[kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest(); + } + auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest(); + _StrPrinter printer; + printer << "Digest "; + printer << "username=\"" << (*this)[kRtspUser] << "\", "; + printer << "realm=\"" << _rtspRealm << "\", "; + printer << "nonce=\"" << _rtspMd5Nonce << "\", "; + printer << "uri=\"" << url << "\", "; + printer << "response=\"" << response << "\""; + header.emplace("Authorization",printer); + }else if(!(*this)[kRtspPwdIsMD5].as()){ + //base64认证 + string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd]; + char authStrBase64[1024] = {0}; + av_base64_encode(authStrBase64,sizeof(authStrBase64),(uint8_t *)authStr.data(),authStr.size()); + header.emplace("Authorization",StrPrinter << "Basic " << authStrBase64 ); + } + } - _StrPrinter printer; - printer << cmd << " " << url << " RTSP/1.0\r\n"; - for (auto &pr : header){ - printer << pr.first << ": " << pr.second << "\r\n"; - } - send(printer << "\r\n"); + _StrPrinter printer; + printer << cmd << " " << url << " RTSP/1.0\r\n"; + for (auto &pr : header){ + printer << pr.first << ": " << pr.second << "\r\n"; + } + send(printer << "\r\n"); } void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &track) { - _rtpTicker.resetTime(); + _rtpTicker.resetTime(); onRecvRTP(pkt,track); int iTrackIndex = getTrackIndexByInterleaved(pkt->interleaved); @@ -740,22 +724,22 @@ void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &tra } void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) { - WarnL << ex.getErrCode() << " " << ex.what(); + WarnL << ex.getErrCode() << " " << ex.what(); if(!ex){ //播放成功,恢复rtp接收超时定时器 _rtpTicker.resetTime(); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); int timeoutMS = (*this)[kMediaTimeoutMS].as(); - //创建rtp数据接收超时检测定时器 - _pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { + //创建rtp数据接收超时检测定时器 + _pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { auto strongSelf=weakSelf.lock(); if(!strongSelf) { return false; } if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) { - //接收rtp媒体数据包超时 - strongSelf->onPlayResult_l(SockException(Err_timeout,"receive rtp timeout"), true); + //接收rtp媒体数据包超时 + strongSelf->onPlayResult_l(SockException(Err_timeout,"receive rtp timeout"), true); return false; } return true; @@ -780,27 +764,27 @@ void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete } int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{ - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (_aTrackInfo[i]->_interleaved == interleaved) { - return i; - } - } - if(_aTrackInfo.size() == 1){ - return 0; - } - return -1; + for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { + if (_aTrackInfo[i]->_interleaved == interleaved) { + return i; + } + } + if(_aTrackInfo.size() == 1){ + return 0; + } + return -1; } int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const { - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (_aTrackInfo[i]->_type == trackType) { - return i; - } - } - if(_aTrackInfo.size() == 1){ - return 0; - } - return -1; + for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { + if (_aTrackInfo[i]->_type == trackType) { + return i; + } + } + if(_aTrackInfo.size() == 1){ + return 0; + } + return -1; } } /* namespace mediakit */ diff --git a/src/Rtsp/RtspPlayer.h b/src/Rtsp/RtspPlayer.h index 5f4f7395..4a094e4e 100644 --- a/src/Rtsp/RtspPlayer.h +++ b/src/Rtsp/RtspPlayer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTSPPLAYER_RTSPPLAYER_H_TXT_ @@ -50,18 +34,18 @@ namespace mediakit { //实现了rtsp播放器协议部分的功能,及数据接收功能 class RtspPlayer: public PlayerBase,public TcpClient, public RtspSplitter, public RtpReceiver { public: - typedef std::shared_ptr Ptr; + typedef std::shared_ptr Ptr; - RtspPlayer(const EventPoller::Ptr &poller) ; - virtual ~RtspPlayer(void); - void play(const string &strUrl) override; - void pause(bool bPause) override; - void teardown() override; - float getPacketLossRate(TrackType type) const override; + RtspPlayer(const EventPoller::Ptr &poller) ; + virtual ~RtspPlayer(void); + void play(const string &strUrl) override; + void pause(bool bPause) override; + void teardown() override; + float getPacketLossRate(TrackType type) const override; protected: - //派生类回调函数 - virtual bool onCheckSDP(const string &strSdp) = 0; - virtual void onRecvRTP(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track) = 0; + //派生类回调函数 + virtual bool onCheckSDP(const string &strSdp) = 0; + virtual void onRecvRTP(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track) = 0; uint32_t getProgressMilliSecond() const; void seekToMilliSecond(uint32_t ms); @@ -83,7 +67,7 @@ protected: * @param rtppt rtp数据包 * @param trackidx track索引 */ - void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; + void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; /** @@ -95,63 +79,66 @@ protected: */ virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen); - /////////////TcpClient override///////////// - void onConnect(const SockException &err) override; - void onRecv(const Buffer::Ptr &pBuf) override; - void onErr(const SockException &ex) override; + /////////////TcpClient override///////////// + void onConnect(const SockException &err) override; + void onRecv(const Buffer::Ptr &pBuf) override; + void onErr(const SockException &ex) override; private: - void onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track); - void onPlayResult_l(const SockException &ex , bool handshakeCompleted); + void onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track); + void onPlayResult_l(const SockException &ex , bool handshakeCompleted); int getTrackIndexByInterleaved(int interleaved) const; - int getTrackIndexByTrackType(TrackType trackType) const; + int getTrackIndexByTrackType(TrackType trackType) const; - void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex); - void handleResDESCRIBE(const Parser &parser); - bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr); - void handleResPAUSE(const Parser &parser, int type); + void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex); + void handleResDESCRIBE(const Parser &parser); + bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr); + void handleResPAUSE(const Parser &parser, int type); - //发送SETUP命令 - void sendSetup(unsigned int uiTrackIndex); - void sendPause(int type , uint32_t ms); - void sendDescribe(); + //发送SETUP命令 + void sendSetup(unsigned int uiTrackIndex); + void sendPause(int type , uint32_t ms); + void sendDescribe(); void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap()); - void sendRtspRequest(const string &cmd, const string &url ,const std::initializer_list &header); + void sendRtspRequest(const string &cmd, const string &url ,const std::initializer_list &header); void sendReceiverReport(bool overTcp,int iTrackIndex); - void createUdpSockIfNecessary(int track_idx); + void createUdpSockIfNecessary(int track_idx); private: - string _strUrl; - vector _aTrackInfo; - function _onHandshake; + string _strUrl; + vector _aTrackInfo; + function _onHandshake; Socket::Ptr _apRtpSock[2]; //RTP端口,trackid idx 为数组下标 Socket::Ptr _apRtcpSock[2];//RTCP端口,trackid idx 为数组下标 //rtsp鉴权相关 - string _rtspMd5Nonce; - string _rtspRealm; - //rtsp info - string _strSession; - unsigned int _uiCseq = 1; - string _strContentBase; - Rtsp::eRtpType _eType = Rtsp::RTP_TCP; + string _rtspMd5Nonce; + string _rtspRealm; + //rtsp info + string _strSession; + unsigned int _uiCseq = 1; + string _strContentBase; + Rtsp::eRtpType _eType = Rtsp::RTP_TCP; - /* 丢包率统计需要用到的参数 */ - uint16_t _aui16FirstSeq[2] = { 0 , 0}; - uint16_t _aui16NowSeq[2] = { 0 , 0 }; - uint64_t _aui64RtpRecv[2] = { 0 , 0}; + /* 丢包率统计需要用到的参数 */ + uint16_t _aui16FirstSeq[2] = { 0 , 0}; + uint16_t _aui16NowSeq[2] = { 0 , 0 }; + uint64_t _aui64RtpRecv[2] = { 0 , 0}; - //超时功能实现 - Ticker _rtpTicker; - std::shared_ptr _pPlayTimer; - std::shared_ptr _pRtpTimer; + //超时功能实现 + Ticker _rtpTicker; + std::shared_ptr _pPlayTimer; + std::shared_ptr _pRtpTimer; - //时间戳 - Stamp _stamp[2]; + //时间戳 + Stamp _stamp[2]; - //rtcp相关 + //rtcp相关 RtcpCounter _aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标 Ticker _aRtcpTicker[2]; //rtcp发送时间,trackid idx 为数组下标 + + //是否为rtsp点播 + bool _is_play_back; }; } /* namespace mediakit */ diff --git a/src/Rtsp/RtspPlayerImp.h b/src/Rtsp/RtspPlayerImp.h index f61ac7c6..2c9ea972 100644 --- a/src/Rtsp/RtspPlayerImp.h +++ b/src/Rtsp/RtspPlayerImp.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_RTP_RTPPARSERTESTER_H_ @@ -43,9 +27,9 @@ namespace mediakit { class RtspPlayerImp: public PlayerImp { public: - typedef std::shared_ptr Ptr; - RtspPlayerImp(const EventPoller::Ptr &poller) : PlayerImp(poller){} - virtual ~RtspPlayerImp(){ + typedef std::shared_ptr Ptr; + RtspPlayerImp(const EventPoller::Ptr &poller) : PlayerImp(poller){} + virtual ~RtspPlayerImp(){ DebugL<(_pMediaSrc); - if(_pRtspMediaSrc){ + //派生类回调函数 + bool onCheckSDP(const string &sdp) override { + _pRtspMediaSrc = dynamic_pointer_cast(_pMediaSrc); + if(_pRtspMediaSrc){ _pRtspMediaSrc->setSdp(sdp); - } + } _delegate.reset(new RtspDemuxer); _delegate->loadSdp(sdp); return true; - } - void onRecvRTP(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track) override { + } + void onRecvRTP(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track) override { if(_pRtspMediaSrc){ // rtsp直接代理是无法判断该rtp是否是I帧,所以GOP缓存基本是无效的 // 为了减少内存使用,那么我们设置为一直关键帧以便清空GOP缓存 @@ -99,7 +83,7 @@ private: } } private: - RtspMediaSource::Ptr _pRtspMediaSrc; + RtspMediaSource::Ptr _pRtspMediaSrc; int _maxAnalysisMS = 0; }; diff --git a/src/Rtsp/RtspPusher.cpp b/src/Rtsp/RtspPusher.cpp index 7dd6a61f..922a553f 100644 --- a/src/Rtsp/RtspPusher.cpp +++ b/src/Rtsp/RtspPusher.cpp @@ -1,6 +1,12 @@ -// -// Created by xzl on 2019/3/27. -// +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #include "Util/MD5.h" #include "Util/base64.h" @@ -295,23 +301,36 @@ void RtspPusher::sendOptions() { sendRtspRequest("OPTIONS",_strContentBase); } -inline void RtspPusher::sendRtpPacket(const RtpPacket::Ptr & pkt) { +inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { //InfoL<<(int)pkt.Interleaved; switch (_eType) { case Rtsp::RTP_TCP: { - BufferRtp::Ptr buffer(new BufferRtp(pkt)); - send(buffer); + int i = 0; + int size = pkt->size(); + setSendFlushFlag(false); + pkt->for_each([&](const RtpPacket::Ptr &rtp) { + if (++i == size) { + setSendFlushFlag(true); + } + BufferRtp::Ptr buffer(new BufferRtp(rtp)); + send(buffer); + }); } break; case Rtsp::RTP_UDP: { - int iTrackIndex = getTrackIndexByTrackType(pkt->type); - auto &pSock = _apUdpSock[iTrackIndex]; - if (!pSock) { - shutdown(SockException(Err_shutdown,"udp sock not opened yet")); - return; - } - BufferRtp::Ptr buffer(new BufferRtp(pkt,4)); - pSock->send(buffer); + int i = 0; + int size = pkt->size(); + pkt->for_each([&](const RtpPacket::Ptr &rtp) { + int iTrackIndex = getTrackIndexByTrackType(rtp->type); + auto &pSock = _apUdpSock[iTrackIndex]; + if (!pSock) { + shutdown(SockException(Err_shutdown,"udp sock not opened yet")); + return; + } + + BufferRtp::Ptr buffer(new BufferRtp(rtp,4)); + pSock->send(buffer, nullptr, 0, ++i == size); + }); } break; default: @@ -331,7 +350,6 @@ inline int RtspPusher::getTrackIndexByTrackType(TrackType type) { return -1; } - void RtspPusher::sendRecord() { _onHandshake = [this](const Parser& parser){ auto src = _pMediaSrc.lock(); @@ -341,7 +359,7 @@ void RtspPusher::sendRecord() { _pRtspReader = src->getRing()->attach(getPoller()); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pRtspReader->setReadCB([weakSelf](const RtpPacket::Ptr &pkt){ + _pRtspReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pkt){ auto strongSelf = weakSelf.lock(); if(!strongSelf) { return; @@ -398,7 +416,7 @@ void RtspPusher::sendRtspRequest(const string &cmd, const string &url, const std void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const,const string &sdp ) { auto header = header_const; header.emplace("CSeq",StrPrinter << _uiCseq++); - header.emplace("User-Agent",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")"); + header.emplace("User-Agent",SERVER_NAME); if(!_strSession.empty()){ header.emplace("Session",_strSession); diff --git a/src/Rtsp/RtspPusher.h b/src/Rtsp/RtspPusher.h index 99431f4d..ccc4c76f 100644 --- a/src/Rtsp/RtspPusher.h +++ b/src/Rtsp/RtspPusher.h @@ -1,6 +1,12 @@ -// -// Created by xzl on 2019/3/27. -// +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef ZLMEDIAKIT_RTSPPUSHER_H #define ZLMEDIAKIT_RTSPPUSHER_H @@ -61,7 +67,7 @@ private: inline int getTrackIndexByTrackType(TrackType type); - void sendRtpPacket(const RtpPacket::Ptr & pkt) ; + void sendRtpPacket(const RtspMediaSource::RingDataType & pkt) ; void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap(),const string &sdp = "" ); void sendRtspRequest(const string &cmd, const string &url ,const std::initializer_list &header,const string &sdp = ""); diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index 29a62779..a64a640d 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -94,16 +78,16 @@ void RtspSession::onError(const SockException& err) { << ")断开:" << err.what() << ",耗时(s):" << duration; - if (_rtpType == Rtsp::RTP_MULTICAST) { - //取消UDP端口监听 - UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this); - } + if (_rtpType == Rtsp::RTP_MULTICAST) { + //取消UDP端口监听 + UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this); + } - if (_http_x_sessioncookie.size() != 0) { - //移除http getter的弱引用记录 - lock_guard lock(g_mtxGetter); - g_mapGetter.erase(_http_x_sessioncookie); - } + if (_http_x_sessioncookie.size() != 0) { + //移除http getter的弱引用记录 + lock_guard lock(g_mtxGetter); + g_mapGetter.erase(_http_x_sessioncookie); + } //流量统计事件广播 GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold); @@ -118,30 +102,30 @@ void RtspSession::onManager() { GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond); if (_ticker.createdTime() > handshake_sec * 1000) { - if (_strSession.size() == 0) { - shutdown(SockException(Err_timeout,"illegal connection")); - return; - } - } + if (_strSession.size() == 0) { + shutdown(SockException(Err_timeout,"illegal connection")); + return; + } + } - if ((_rtpType == Rtsp::RTP_UDP || _pushSrc ) && _ticker.elapsedTime() > keep_alive_sec * 1000) { - //如果是推流端或者rtp over udp类型的播放端,那么就做超时检测 + if ((_rtpType == Rtsp::RTP_UDP || _pushSrc ) && _ticker.elapsedTime() > keep_alive_sec * 1000) { + //如果是推流端或者rtp over udp类型的播放端,那么就做超时检测 shutdown(SockException(Err_timeout,"rtp over udp session timeouted")); return; - } + } } void RtspSession::onRecv(const Buffer::Ptr &pBuf) { - _ticker.resetTime(); + _ticker.resetTime(); _ui64TotalBytes += pBuf->size(); if (_onRecv) { - //http poster的请求数据转发给http getter处理 - _onRecv(pBuf); - } else { + //http poster的请求数据转发给http getter处理 + _onRecv(pBuf); + } else { // TraceP(this) << pBuf->size() << "\r\n" << pBuf->data(); - input(pBuf->data(),pBuf->size()); - } + input(pBuf->data(),pBuf->size()); + } } //字符串是否以xx结尾 @@ -151,37 +135,37 @@ static inline bool end_of(const string &str, const string &substr){ }; void RtspSession::onWholeRtspPacket(Parser &parser) { - string strCmd = parser.Method(); //提取出请求命令字 - _iCseq = atoi(parser["CSeq"].data()); - if(_strContentBase.empty() && strCmd != "GET"){ - _strContentBase = parser.Url(); - _mediaInfo.parse(parser.FullUrl()); + string strCmd = parser.Method(); //提取出请求命令字 + _iCseq = atoi(parser["CSeq"].data()); + if(_strContentBase.empty() && strCmd != "GET"){ + _strContentBase = parser.Url(); + _mediaInfo.parse(parser.FullUrl()); _mediaInfo._schema = RTSP_SCHEMA; } - typedef void (RtspSession::*rtsp_request_handler)(const Parser &parser); - static unordered_map s_cmd_functions; - static onceToken token( []() { - s_cmd_functions.emplace("OPTIONS",&RtspSession::handleReq_Options); - s_cmd_functions.emplace("DESCRIBE",&RtspSession::handleReq_Describe); - s_cmd_functions.emplace("ANNOUNCE",&RtspSession::handleReq_ANNOUNCE); - s_cmd_functions.emplace("RECORD",&RtspSession::handleReq_RECORD); - s_cmd_functions.emplace("SETUP",&RtspSession::handleReq_Setup); - s_cmd_functions.emplace("PLAY",&RtspSession::handleReq_Play); - s_cmd_functions.emplace("PAUSE",&RtspSession::handleReq_Pause); - s_cmd_functions.emplace("TEARDOWN",&RtspSession::handleReq_Teardown); - s_cmd_functions.emplace("GET",&RtspSession::handleReq_Get); - s_cmd_functions.emplace("POST",&RtspSession::handleReq_Post); - s_cmd_functions.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); - s_cmd_functions.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); - }, []() {}); + typedef void (RtspSession::*rtsp_request_handler)(const Parser &parser); + static unordered_map s_cmd_functions; + static onceToken token( []() { + s_cmd_functions.emplace("OPTIONS",&RtspSession::handleReq_Options); + s_cmd_functions.emplace("DESCRIBE",&RtspSession::handleReq_Describe); + s_cmd_functions.emplace("ANNOUNCE",&RtspSession::handleReq_ANNOUNCE); + s_cmd_functions.emplace("RECORD",&RtspSession::handleReq_RECORD); + s_cmd_functions.emplace("SETUP",&RtspSession::handleReq_Setup); + s_cmd_functions.emplace("PLAY",&RtspSession::handleReq_Play); + s_cmd_functions.emplace("PAUSE",&RtspSession::handleReq_Pause); + s_cmd_functions.emplace("TEARDOWN",&RtspSession::handleReq_Teardown); + s_cmd_functions.emplace("GET",&RtspSession::handleReq_Get); + s_cmd_functions.emplace("POST",&RtspSession::handleReq_Post); + s_cmd_functions.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); + s_cmd_functions.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); + }, []() {}); - auto it = s_cmd_functions.find(strCmd); - if (it == s_cmd_functions.end()) { + auto it = s_cmd_functions.find(strCmd); + if (it == s_cmd_functions.end()) { sendRtspResponse("403 Forbidden"); shutdown(SockException(Err_shutdown,StrPrinter << "403 Forbidden:" << strCmd)); return; - } + } auto &fun = it->second; try { @@ -197,57 +181,57 @@ void RtspSession::onWholeRtspPacket(Parser &parser) { } void RtspSession::onRtpPacket(const char *data, uint64_t len) { - if(!_pushSrc){ - return; - } + if(!_pushSrc){ + return; + } - int trackIdx = -1; - uint8_t interleaved = data[1]; - if(interleaved %2 == 0){ - trackIdx = getTrackIndexByInterleaved(interleaved); + int trackIdx = -1; + uint8_t interleaved = data[1]; + if(interleaved %2 == 0){ + trackIdx = getTrackIndexByInterleaved(interleaved); if (trackIdx != -1) { handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4); } - }else{ + }else{ trackIdx = getTrackIndexByInterleaved(interleaved - 1); if (trackIdx != -1) { onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4); } - } + } } void RtspSession::onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen){ } int64_t RtspSession::getContentLength(Parser &parser) { - if(parser.Method() == "POST"){ - //http post请求的content数据部分是base64编码后的rtsp请求信令包 - return remainDataSize(); - } - return RtspSplitter::getContentLength(parser); + if(parser.Method() == "POST"){ + //http post请求的content数据部分是base64编码后的rtsp请求信令包 + return remainDataSize(); + } + return RtspSplitter::getContentLength(parser); } void RtspSession::handleReq_Options(const Parser &parser) { - //支持这些命令 - sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"}); + //支持这些命令 + sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"}); } void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { - auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA, - _mediaInfo._vhost, - _mediaInfo._app, - _mediaInfo._streamid, - false)); - if(src){ - sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing."); + auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA, + _mediaInfo._vhost, + _mediaInfo._app, + _mediaInfo._streamid, + false)); + if(src){ + sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing."); string err = StrPrinter << "ANNOUNCE:" << "Already publishing:" << _mediaInfo._vhost << " " << _mediaInfo._app << " " << _mediaInfo._streamid << endl; - throw SockException(Err_shutdown,err); - } + throw SockException(Err_shutdown,err); + } auto full_url = parser.FullUrl(); if(end_of(full_url,".sdp")){ @@ -260,67 +244,67 @@ void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { _strSession = makeRandStr(12); _aTrackInfo = sdpParser.getAvailableTrack(); - _pushSrc = std::make_shared(_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid); - _pushSrc->setListener(dynamic_pointer_cast(shared_from_this())); + _pushSrc = std::make_shared(_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid); + _pushSrc->setListener(dynamic_pointer_cast(shared_from_this())); _pushSrc->setSdp(sdpParser.toString()); - sendRtspResponse("200 OK",{"Content-Base",_strContentBase + "/"}); + sendRtspResponse("200 OK",{"Content-Base",_strContentBase + "/"}); } void RtspSession::handleReq_RECORD(const Parser &parser){ - if (_aTrackInfo.empty() || parser["Session"] != _strSession) { - send_SessionNotFound(); + if (_aTrackInfo.empty() || parser["Session"] != _strSession) { + send_SessionNotFound(); throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when record" : "session not found when record"); - } - auto onRes = [this](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){ - bool authSuccess = err.empty(); - if(!authSuccess){ - sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err); - shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err)); - return; - } + } + auto onRes = [this](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){ + bool authSuccess = err.empty(); + if(!authSuccess){ + sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err); + shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err)); + return; + } //设置转协议 _pushSrc->setProtocolTranslation(enableRtxp,enableHls,enableMP4); - _StrPrinter rtp_info; - for(auto &track : _aTrackInfo){ - if (track->_inited == false) { - //还有track没有setup + _StrPrinter rtp_info; + for(auto &track : _aTrackInfo){ + if (track->_inited == false) { + //还有track没有setup shutdown(SockException(Err_shutdown,"track not setuped")); return; - } - rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ","; - } + } + rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ","; + } - rtp_info.pop_back(); - sendRtspResponse("200 OK", {"RTP-Info",rtp_info}); - if(_rtpType == Rtsp::RTP_TCP){ - //如果是rtsp推流服务器,并且是TCP推流,那么加大TCP接收缓存,这样能提升接收性能 - _sock->setReadBuffer(std::make_shared(256 * 1024)); + rtp_info.pop_back(); + sendRtspResponse("200 OK", {"RTP-Info",rtp_info}); + if(_rtpType == Rtsp::RTP_TCP){ + //如果是rtsp推流服务器,并且是TCP推流,那么加大TCP接收缓存,这样能提升接收性能 + _sock->setReadBuffer(std::make_shared(256 * 1024)); setSocketFlags(); - } - }; + } + }; - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - Broadcast::PublishAuthInvoker invoker = [weakSelf,onRes](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){ - auto strongSelf = weakSelf.lock(); - if(!strongSelf){ - return; - } - strongSelf->async([weakSelf,onRes,err,enableRtxp,enableHls,enableMP4](){ - auto strongSelf = weakSelf.lock(); - if(!strongSelf){ - return; - } - onRes(err,enableRtxp,enableHls,enableMP4); - }); - }; + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + Broadcast::PublishAuthInvoker invoker = [weakSelf,onRes](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){ + auto strongSelf = weakSelf.lock(); + if(!strongSelf){ + return; + } + strongSelf->async([weakSelf,onRes,err,enableRtxp,enableHls,enableMP4](){ + auto strongSelf = weakSelf.lock(); + if(!strongSelf){ + return; + } + onRes(err,enableRtxp,enableHls,enableMP4); + }); + }; - //rtsp推流需要鉴权 - auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish,_mediaInfo,invoker,*this); - if(!flag){ - //该事件无人监听,默认不鉴权 + //rtsp推流需要鉴权 + auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish,_mediaInfo,invoker,*this); + if(!flag){ + //该事件无人监听,默认不鉴权 GET_CONFIG(bool,toRtxp,General::kPublishToRtxp); GET_CONFIG(bool,toHls,General::kPublishToHls); GET_CONFIG(bool,toMP4,General::kPublishToMP4); @@ -385,7 +369,7 @@ void RtspSession::onAuthSuccess() { strongSelf->_aTrackInfo = SdpParser(rtsp_src->getSdp()).getAvailableTrack(); if (strongSelf->_aTrackInfo.empty()) { //该流无效 - DebugL << "无trackInfo,该流无效"; + DebugL << "无trackInfo,该流无效"; strongSelf->send_StreamNotFound(); strongSelf->shutdown(SockException(Err_shutdown,"can not find any available track in sdp")); return; @@ -472,7 +456,7 @@ void RtspSession::onAuthBasic(const string &realm,const string &strBase64){ } void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ - DebugP(this) << strMd5; + DebugP(this) << strMd5; auto mapTmp = Parser::parseArgs(strMd5,",","="); decltype(mapTmp) map; for(auto &pr : mapTmp){ @@ -561,7 +545,7 @@ void RtspSession::onAuthUser(const string &realm,const string &authorization){ } //请求中包含认证信息 auto authType = FindField(authorization.data(),NULL," "); - auto authStr = FindField(authorization.data()," ",NULL); + auto authStr = FindField(authorization.data()," ",NULL); if(authType.empty() || authStr.empty()){ //认证信息格式不合法,回复401 Unauthorized onAuthFailed(realm,"can not find auth type or auth string"); @@ -579,50 +563,50 @@ void RtspSession::onAuthUser(const string &realm,const string &authorization){ } } inline void RtspSession::send_StreamNotFound() { - sendRtspResponse("404 Stream Not Found",{"Connection","Close"}); + sendRtspResponse("404 Stream Not Found",{"Connection","Close"}); } inline void RtspSession::send_UnsupportedTransport() { - sendRtspResponse("461 Unsupported Transport",{"Connection","Close"}); + sendRtspResponse("461 Unsupported Transport",{"Connection","Close"}); } inline void RtspSession::send_SessionNotFound() { - sendRtspResponse("454 Session Not Found",{"Connection","Close"}); + sendRtspResponse("454 Session Not Found",{"Connection","Close"}); } void RtspSession::handleReq_Setup(const Parser &parser) { //处理setup命令,该函数可能进入多次 auto controlSuffix = split(parser.FullUrl(),"/").back();// parser.FullUrl().substr(_strContentBase.size()); if(controlSuffix.front() == '/'){ - controlSuffix = controlSuffix.substr(1); + controlSuffix = controlSuffix.substr(1); } - int trackIdx = getTrackIndexByControlSuffix(controlSuffix); - if (trackIdx == -1) { - //未找到相应track + int trackIdx = getTrackIndexByControlSuffix(controlSuffix); + if (trackIdx == -1) { + //未找到相应track throw SockException(Err_shutdown, StrPrinter << "can not find any track by control suffix:" << controlSuffix); } - SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx]; - if (trackRef->_inited) { - //已经初始化过该Track + SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx]; + if (trackRef->_inited) { + //已经初始化过该Track throw SockException(Err_shutdown, "can not setup one track twice"); - } - trackRef->_inited = true; //现在初始化 + } + trackRef->_inited = true; //现在初始化 - if(_rtpType == Rtsp::RTP_Invalid){ - auto &strTransport = parser["Transport"]; - if(strTransport.find("TCP") != string::npos){ - _rtpType = Rtsp::RTP_TCP; - }else if(strTransport.find("multicast") != string::npos){ - _rtpType = Rtsp::RTP_MULTICAST; - }else{ - _rtpType = Rtsp::RTP_UDP; - } - } + if(_rtpType == Rtsp::RTP_Invalid){ + auto &strTransport = parser["Transport"]; + if(strTransport.find("TCP") != string::npos){ + _rtpType = Rtsp::RTP_TCP; + }else if(strTransport.find("multicast") != string::npos){ + _rtpType = Rtsp::RTP_MULTICAST; + }else{ + _rtpType = Rtsp::RTP_UDP; + } + } //允许接收rtp、rtcp包 - RtspSplitter::enableRecvRtp(_rtpType == Rtsp::RTP_TCP); + RtspSplitter::enableRecvRtp(_rtpType == Rtsp::RTP_TCP); - switch (_rtpType) { - case Rtsp::RTP_TCP: { + switch (_rtpType) { + case Rtsp::RTP_TCP: { if(_pushSrc){ //rtsp推流时,interleaved由推流者决定 auto key_values = Parser::parseArgs(parser["Transport"],";","="); @@ -636,192 +620,192 @@ void RtspSession::handleReq_Setup(const Parser &parser) { //rtsp播放时,由于数据共享分发,所以interleaved必须由服务器决定 trackRef->_interleaved = 2 * trackRef->_type; } - sendRtspResponse("200 OK", - {"Transport",StrPrinter << "RTP/AVP/TCP;unicast;" - << "interleaved=" << (int)trackRef->_interleaved << "-" << (int)trackRef->_interleaved + 1 << ";" - << "ssrc=" << printSSRC(trackRef->_ssrc), - "x-Transport-Options" , "late-tolerance=1.400000", - "x-Dynamic-Rate" , "1" - }); - } - break; - case Rtsp::RTP_UDP: { - //我们用trackIdx区分rtp和rtcp包 - auto pSockRtp = std::make_shared(_sock->getPoller()); - if (!pSockRtp->bindUdpSock(0,get_local_ip().data())) { - //分配端口失败 - send_NotAcceptable(); + sendRtspResponse("200 OK", + {"Transport",StrPrinter << "RTP/AVP/TCP;unicast;" + << "interleaved=" << (int)trackRef->_interleaved << "-" << (int)trackRef->_interleaved + 1 << ";" + << "ssrc=" << printSSRC(trackRef->_ssrc), + "x-Transport-Options" , "late-tolerance=1.400000", + "x-Dynamic-Rate" , "1" + }); + } + break; + case Rtsp::RTP_UDP: { + //我们用trackIdx区分rtp和rtcp包 + auto pSockRtp = std::make_shared(_sock->getPoller()); + if (!pSockRtp->bindUdpSock(0,get_local_ip().data())) { + //分配端口失败 + send_NotAcceptable(); throw SockException(Err_shutdown, "open rtp socket failed"); } - auto pSockRtcp = std::make_shared(_sock->getPoller()); - if (!pSockRtcp->bindUdpSock(pSockRtp->get_local_port() + 1,get_local_ip().data())) { - //分配端口失败 - send_NotAcceptable(); + auto pSockRtcp = std::make_shared(_sock->getPoller()); + if (!pSockRtcp->bindUdpSock(pSockRtp->get_local_port() + 1,get_local_ip().data())) { + //分配端口失败 + send_NotAcceptable(); throw SockException(Err_shutdown, "open rtcp socket failed"); } - _apRtpSock[trackIdx] = pSockRtp; - _apRtcpSock[trackIdx] = pSockRtcp; - //设置客户端内网端口信息 - string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL); - uint16_t ui16RtpPort = atoi( FindField(strClientPort.data(), NULL, "-").data()); + _apRtpSock[trackIdx] = pSockRtp; + _apRtcpSock[trackIdx] = pSockRtcp; + //设置客户端内网端口信息 + string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL); + uint16_t ui16RtpPort = atoi( FindField(strClientPort.data(), NULL, "-").data()); uint16_t ui16RtcpPort = atoi( FindField(strClientPort.data(), "-" , NULL).data()); struct sockaddr_in peerAddr; //设置rtp发送目标地址 - peerAddr.sin_family = AF_INET; - peerAddr.sin_port = htons(ui16RtpPort); - peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data()); - bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); - pSockRtp->setSendPeerAddr((struct sockaddr *)(&peerAddr)); + peerAddr.sin_family = AF_INET; + peerAddr.sin_port = htons(ui16RtpPort); + peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data()); + bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); + pSockRtp->setSendPeerAddr((struct sockaddr *)(&peerAddr)); - //设置rtcp发送目标地址 + //设置rtcp发送目标地址 peerAddr.sin_family = AF_INET; peerAddr.sin_port = htons(ui16RtcpPort); peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data()); bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); pSockRtcp->setSendPeerAddr((struct sockaddr *)(&peerAddr)); - //尝试获取客户端nat映射地址 - startListenPeerUdpData(trackIdx); - //InfoP(this) << "分配端口:" << srv_port; + //尝试获取客户端nat映射地址 + startListenPeerUdpData(trackIdx); + //InfoP(this) << "分配端口:" << srv_port; - sendRtspResponse("200 OK", - {"Transport",StrPrinter << "RTP/AVP/UDP;unicast;" - << "client_port=" << strClientPort << ";" - << "server_port=" << pSockRtp->get_local_port() << "-" << pSockRtcp->get_local_port() << ";" - << "ssrc=" << printSSRC(trackRef->_ssrc) - }); - } - break; - case Rtsp::RTP_MULTICAST: { - if(!_multicaster){ - _multicaster = RtpMultiCaster::get(getPoller(),get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid); - if (!_multicaster) { - send_NotAcceptable(); + sendRtspResponse("200 OK", + {"Transport",StrPrinter << "RTP/AVP/UDP;unicast;" + << "client_port=" << strClientPort << ";" + << "server_port=" << pSockRtp->get_local_port() << "-" << pSockRtcp->get_local_port() << ";" + << "ssrc=" << printSSRC(trackRef->_ssrc) + }); + } + break; + case Rtsp::RTP_MULTICAST: { + if(!_multicaster){ + _multicaster = RtpMultiCaster::get(getPoller(),get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid); + if (!_multicaster) { + send_NotAcceptable(); throw SockException(Err_shutdown, "can not get a available udp multicast socket"); } - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _multicaster->setDetachCB(this, [weakSelf]() { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - strongSelf->safeShutdown(SockException(Err_shutdown,"ring buffer detached")); - }); - } - int iSrvPort = _multicaster->getPort(trackRef->_type); - //我们用trackIdx区分rtp和rtcp包 - //由于组播udp端口是共享的,而rtcp端口为组播udp端口+1,所以rtcp端口需要改成共享端口 - auto pSockRtcp = UDPServer::Instance().getSock(getPoller(),get_local_ip().data(),2*trackIdx + 1,iSrvPort + 1); - if (!pSockRtcp) { - //分配端口失败 - send_NotAcceptable(); + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + _multicaster->setDetachCB(this, [weakSelf]() { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + strongSelf->safeShutdown(SockException(Err_shutdown,"ring buffer detached")); + }); + } + int iSrvPort = _multicaster->getPort(trackRef->_type); + //我们用trackIdx区分rtp和rtcp包 + //由于组播udp端口是共享的,而rtcp端口为组播udp端口+1,所以rtcp端口需要改成共享端口 + auto pSockRtcp = UDPServer::Instance().getSock(getPoller(),get_local_ip().data(),2*trackIdx + 1,iSrvPort + 1); + if (!pSockRtcp) { + //分配端口失败 + send_NotAcceptable(); throw SockException(Err_shutdown, "open shared rtcp socket failed"); - } - startListenPeerUdpData(trackIdx); + } + startListenPeerUdpData(trackIdx); GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL); - sendRtspResponse("200 OK", - {"Transport",StrPrinter << "RTP/AVP;multicast;" - << "destination=" << _multicaster->getIP() << ";" - << "source=" << get_local_ip() << ";" - << "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";" - << "ttl=" << udpTTL << ";" - << "ssrc=" << printSSRC(trackRef->_ssrc) - }); - } - break; - default: - break; - } + sendRtspResponse("200 OK", + {"Transport",StrPrinter << "RTP/AVP;multicast;" + << "destination=" << _multicaster->getIP() << ";" + << "source=" << get_local_ip() << ";" + << "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";" + << "ttl=" << udpTTL << ";" + << "ssrc=" << printSSRC(trackRef->_ssrc) + }); + } + break; + default: + break; + } } void RtspSession::handleReq_Play(const Parser &parser) { - if (_aTrackInfo.empty() || parser["Session"] != _strSession) { - send_SessionNotFound(); + if (_aTrackInfo.empty() || parser["Session"] != _strSession) { + send_SessionNotFound(); throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when play" : "session not found when play"); } - auto strRange = parser["Range"]; + auto strRange = parser["Range"]; auto onRes = [this,strRange](const string &err){ bool authSuccess = err.empty(); if(!authSuccess){ //第一次play是播放,否则是恢复播放。只对播放鉴权 - sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err); + sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err); shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err)); return; } auto pMediaSrc = _pMediaSrc.lock(); if(!pMediaSrc){ - send_StreamNotFound(); - shutdown(SockException(Err_shutdown,"rtsp stream released")); - return; + send_StreamNotFound(); + shutdown(SockException(Err_shutdown,"rtsp stream released")); + return; } bool useBuf = true; - _enableSendRtp = false; + _enableSendRtp = false; - if (strRange.size() && !_bFirstPlay) { + if (strRange.size() && !_bFirstPlay) { //这个是seek操作 - auto strStart = FindField(strRange.data(), "npt=", "-"); - if (strStart == "now") { - strStart = "0"; - } - auto iStartTime = 1000 * atof(strStart.data()); - InfoP(this) << "rtsp seekTo(ms):" << iStartTime; - useBuf = !pMediaSrc->seekTo(iStartTime); - }else if(pMediaSrc->totalReaderCount() == 0){ - //第一个消费者 - pMediaSrc->seekTo(0); - } - _bFirstPlay = false; + auto strStart = FindField(strRange.data(), "npt=", "-"); + if (strStart == "now") { + strStart = "0"; + } + auto iStartTime = 1000 * atof(strStart.data()); + InfoP(this) << "rtsp seekTo(ms):" << iStartTime; + useBuf = !pMediaSrc->seekTo(iStartTime); + }else if(pMediaSrc->totalReaderCount() == 0){ + //第一个消费者 + pMediaSrc->seekTo(0); + } + _bFirstPlay = false; - _StrPrinter rtp_info; - for(auto &track : _aTrackInfo){ - if (track->_inited == false) { - //还有track没有setup + _StrPrinter rtp_info; + for(auto &track : _aTrackInfo){ + if (track->_inited == false) { + //还有track没有setup shutdown(SockException(Err_shutdown,"track not setuped")); return; - } - track->_ssrc = pMediaSrc->getSsrc(track->_type); - track->_seq = pMediaSrc->getSeqence(track->_type); - track->_time_stamp = pMediaSrc->getTimeStamp(track->_type); + } + track->_ssrc = pMediaSrc->getSsrc(track->_type); + track->_seq = pMediaSrc->getSeqence(track->_type); + track->_time_stamp = pMediaSrc->getTimeStamp(track->_type); - rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";" - << "seq=" << track->_seq << ";" - << "rtptime=" << (int)(track->_time_stamp * (track->_samplerate / 1000)) << ","; - } + rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";" + << "seq=" << track->_seq << ";" + << "rtptime=" << (int)(track->_time_stamp * (track->_samplerate / 1000)) << ","; + } - rtp_info.pop_back(); + rtp_info.pop_back(); - sendRtspResponse("200 OK", - {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0, - "RTP-Info",rtp_info - }); + sendRtspResponse("200 OK", + {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 << "-", + "RTP-Info",rtp_info + }); - _enableSendRtp = true; + _enableSendRtp = true; setSocketFlags(); - if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pRtpReader = pMediaSrc->getRing()->attach(getPoller(),useBuf); - _pRtpReader->setDetachCB([weakSelf]() { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } + if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + _pRtpReader = pMediaSrc->getRing()->attach(getPoller(),useBuf); + _pRtpReader->setDetachCB([weakSelf]() { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } strongSelf->shutdown(SockException(Err_shutdown,"rtsp ring buffer detached")); }); - _pRtpReader->setReadCB([weakSelf](const RtpPacket::Ptr &pack) { - auto strongSelf = weakSelf.lock(); - if(!strongSelf) { - return; - } - if(strongSelf->_enableSendRtp) { - strongSelf->sendRtpPacket(pack); - } - }); - } + _pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + if(strongSelf->_enableSendRtp) { + strongSelf->sendRtpPacket(pack); + } + }); + } }; weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); @@ -852,69 +836,69 @@ void RtspSession::handleReq_Play(const Parser &parser) { } void RtspSession::handleReq_Pause(const Parser &parser) { - if (parser["Session"] != _strSession) { - send_SessionNotFound(); + if (parser["Session"] != _strSession) { + send_SessionNotFound(); throw SockException(Err_shutdown,"session not found when pause"); } - sendRtspResponse("200 OK"); - _enableSendRtp = false; + sendRtspResponse("200 OK"); + _enableSendRtp = false; } void RtspSession::handleReq_Teardown(const Parser &parser) { - sendRtspResponse("200 OK"); + sendRtspResponse("200 OK"); throw SockException(Err_shutdown,"rtsp player send teardown request"); } void RtspSession::handleReq_Get(const Parser &parser) { - _http_x_sessioncookie = parser["x-sessioncookie"]; - sendRtspResponse("200 OK", - {"Cache-Control","no-store", - "Pragma","no-store", - "Content-Type","application/x-rtsp-tunnelled", - },"","HTTP/1.0"); + _http_x_sessioncookie = parser["x-sessioncookie"]; + sendRtspResponse("200 OK", + {"Cache-Control","no-store", + "Pragma","no-store", + "Content-Type","application/x-rtsp-tunnelled", + },"","HTTP/1.0"); - //注册http getter,以便http poster绑定 - lock_guard lock(g_mtxGetter); - g_mapGetter[_http_x_sessioncookie] = dynamic_pointer_cast(shared_from_this()); + //注册http getter,以便http poster绑定 + lock_guard lock(g_mtxGetter); + g_mapGetter[_http_x_sessioncookie] = dynamic_pointer_cast(shared_from_this()); } void RtspSession::handleReq_Post(const Parser &parser) { - lock_guard lock(g_mtxGetter); - string sessioncookie = parser["x-sessioncookie"]; - //Poster 找到 Getter - auto it = g_mapGetter.find(sessioncookie); - if (it == g_mapGetter.end()) { + lock_guard lock(g_mtxGetter); + string sessioncookie = parser["x-sessioncookie"]; + //Poster 找到 Getter + auto it = g_mapGetter.find(sessioncookie); + if (it == g_mapGetter.end()) { throw SockException(Err_shutdown,"can not find http getter by x-sessioncookie"); } - //Poster 找到Getter的SOCK - auto httpGetterWeak = it->second; - //移除http getter的弱引用记录 - g_mapGetter.erase(sessioncookie); + //Poster 找到Getter的SOCK + auto httpGetterWeak = it->second; + //移除http getter的弱引用记录 + g_mapGetter.erase(sessioncookie); - //http poster收到请求后转发给http getter处理 - _onRecv = [this,httpGetterWeak](const Buffer::Ptr &pBuf){ - auto httpGetterStrong = httpGetterWeak.lock(); - if(!httpGetterStrong){ - shutdown(SockException(Err_shutdown,"http getter released")); - return; - } + //http poster收到请求后转发给http getter处理 + _onRecv = [this,httpGetterWeak](const Buffer::Ptr &pBuf){ + auto httpGetterStrong = httpGetterWeak.lock(); + if(!httpGetterStrong){ + shutdown(SockException(Err_shutdown,"http getter released")); + return; + } - //切换到http getter的线程 - httpGetterStrong->async([pBuf,httpGetterWeak](){ - auto httpGetterStrong = httpGetterWeak.lock(); - if(!httpGetterStrong){ - return; - } - httpGetterStrong->onRecv(std::make_shared(decodeBase64(string(pBuf->data(),pBuf->size())))); - }); - }; + //切换到http getter的线程 + httpGetterStrong->async([pBuf,httpGetterWeak](){ + auto httpGetterStrong = httpGetterWeak.lock(); + if(!httpGetterStrong){ + return; + } + httpGetterStrong->onRecv(std::make_shared(decodeBase64(string(pBuf->data(),pBuf->size())))); + }); + }; - if(!parser.Content().empty()){ - //http poster后面的粘包 - _onRecv(std::make_shared(parser.Content())); - } + if(!parser.Content().empty()){ + //http poster后面的粘包 + _onRecv(std::make_shared(parser.Content())); + } sendRtspResponse("200 OK", {"Cache-Control","no-store", @@ -924,33 +908,33 @@ void RtspSession::handleReq_Post(const Parser &parser) { } void RtspSession::handleReq_SET_PARAMETER(const Parser &parser) { - //TraceP(this) <onWrite(rtppt, false); + _pushSrc->onWrite(rtppt, false); } inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) { - //这是rtcp心跳包,说明播放器还存活 - _ticker.resetTime(); + //这是rtcp心跳包,说明播放器还存活 + _ticker.resetTime(); - if(intervaled % 2 == 0){ - if(_pushSrc){ - //这是rtsp推流上来的rtp包 - handleOneRtp(intervaled / 2,_aTrackInfo[intervaled / 2],( unsigned char *)pBuf->data(),pBuf->size()); - }else if(!_udpSockConnected.count(intervaled)){ + if(intervaled % 2 == 0){ + if(_pushSrc){ + //这是rtsp推流上来的rtp包 + handleOneRtp(intervaled / 2,_aTrackInfo[intervaled / 2],( unsigned char *)pBuf->data(),pBuf->size()); + }else if(!_udpSockConnected.count(intervaled)){ //这是rtsp播放器的rtp打洞包 _udpSockConnected.emplace(intervaled); _apRtpSock[intervaled / 2]->setSendPeerAddr(&addr); - } - }else{ - //rtcp包 + } + }else{ + //rtcp包 if(!_udpSockConnected.count(intervaled)){ _udpSockConnected.emplace(intervaled); _apRtcpSock[(intervaled - 1) / 2]->setSendPeerAddr(&addr); @@ -961,13 +945,13 @@ inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBu inline void RtspSession::startListenPeerUdpData(int trackIdx) { - weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); + weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); auto srcIP = inet_addr(get_peer_ip().data()); - auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr,int intervaled){ - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { - return false; - } + auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr,int intervaled){ + auto strongSelf=weakSelf.lock(); + if(!strongSelf) { + return false; + } if (((struct sockaddr_in *) pPeerAddr)->sin_addr.s_addr != srcIP) { WarnP(strongSelf.get()) << ((intervaled % 2 == 0) ? "收到其他地址的rtp数据:" : "收到其他地址的rtcp数据:") @@ -975,154 +959,154 @@ inline void RtspSession::startListenPeerUdpData(int trackIdx) { return true; } - struct sockaddr addr=*pPeerAddr; - strongSelf->async([weakSelf,pBuf,addr,intervaled]() { - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { - return; - } - strongSelf->onRcvPeerUdpData(intervaled,pBuf,addr); - }); - return true; - }; + struct sockaddr addr=*pPeerAddr; + strongSelf->async([weakSelf,pBuf,addr,intervaled]() { + auto strongSelf=weakSelf.lock(); + if(!strongSelf) { + return; + } + strongSelf->onRcvPeerUdpData(intervaled,pBuf,addr); + }); + return true; + }; - switch (_rtpType){ - case Rtsp::RTP_MULTICAST:{ - //组播使用的共享rtcp端口 - UDPServer::Instance().listenPeer(get_peer_ip().data(), this, [onUdpData]( - int intervaled, const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr) { - return onUdpData(pBuf,pPeerAddr,intervaled); - }); - } - break; - case Rtsp::RTP_UDP:{ - auto setEvent = [&](Socket::Ptr &sock,int intervaled){ - if(!sock){ - WarnP(this) << "udp端口为空:" << intervaled; - return; - } - sock->setOnRead([onUdpData,intervaled](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){ - onUdpData(pBuf,pPeerAddr,intervaled); - }); - }; - setEvent(_apRtpSock[trackIdx], 2*trackIdx ); - setEvent(_apRtcpSock[trackIdx], 2*trackIdx + 1 ); - } - break; + switch (_rtpType){ + case Rtsp::RTP_MULTICAST:{ + //组播使用的共享rtcp端口 + UDPServer::Instance().listenPeer(get_peer_ip().data(), this, [onUdpData]( + int intervaled, const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr) { + return onUdpData(pBuf,pPeerAddr,intervaled); + }); + } + break; + case Rtsp::RTP_UDP:{ + auto setEvent = [&](Socket::Ptr &sock,int intervaled){ + if(!sock){ + WarnP(this) << "udp端口为空:" << intervaled; + return; + } + sock->setOnRead([onUdpData,intervaled](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){ + onUdpData(pBuf,pPeerAddr,intervaled); + }); + }; + setEvent(_apRtpSock[trackIdx], 2*trackIdx ); + setEvent(_apRtcpSock[trackIdx], 2*trackIdx + 1 ); + } + break; - default: - break; - } + default: + break; + } } static string dateStr(){ - char buf[64]; - time_t tt = time(NULL); - strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt)); - return buf; + char buf[64]; + time_t tt = time(NULL); + strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt)); + return buf; } bool RtspSession::sendRtspResponse(const string &res_code, - const StrCaseMap &header_const, - const string &sdp, - const char *protocol){ - auto header = header_const; - header.emplace("CSeq",StrPrinter << _iCseq); - if(!_strSession.empty()){ - header.emplace("Session",_strSession); - } + const StrCaseMap &header_const, + const string &sdp, + const char *protocol){ + auto header = header_const; + header.emplace("CSeq",StrPrinter << _iCseq); + if(!_strSession.empty()){ + header.emplace("Session",_strSession); + } - header.emplace("Server",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")"); - header.emplace("Date",dateStr()); + header.emplace("Server",SERVER_NAME); + header.emplace("Date",dateStr()); - if(!sdp.empty()){ - header.emplace("Content-Length",StrPrinter << sdp.size()); - header.emplace("Content-Type","application/sdp"); - } + if(!sdp.empty()){ + header.emplace("Content-Length",StrPrinter << sdp.size()); + header.emplace("Content-Type","application/sdp"); + } - _StrPrinter printer; - printer << protocol << " " << res_code << "\r\n"; - for (auto &pr : header){ - printer << pr.first << ": " << pr.second << "\r\n"; - } + _StrPrinter printer; + printer << protocol << " " << res_code << "\r\n"; + for (auto &pr : header){ + printer << pr.first << ": " << pr.second << "\r\n"; + } - printer << "\r\n"; + printer << "\r\n"; - if(!sdp.empty()){ - printer << sdp; - } + if(!sdp.empty()){ + printer << sdp; + } // DebugP(this) << printer; - return send(std::make_shared(printer)) > 0 ; + return send(std::make_shared(printer)) > 0 ; } int RtspSession::send(const Buffer::Ptr &pkt){ // if(!_enableSendRtp){ // DebugP(this) << pkt->data(); // } - _ui64TotalBytes += pkt->size(); - return TcpSession::send(pkt); + _ui64TotalBytes += pkt->size(); + return TcpSession::send(pkt); } bool RtspSession::sendRtspResponse(const string &res_code, - const std::initializer_list &header, - const string &sdp, - const char *protocol) { - string key; - StrCaseMap header_map; - int i = 0; - for(auto &val : header){ - if(++i % 2 == 0){ - header_map.emplace(key,val); - }else{ - key = val; - } - } - return sendRtspResponse(res_code,header_map,sdp,protocol); + const std::initializer_list &header, + const string &sdp, + const char *protocol) { + string key; + StrCaseMap header_map; + int i = 0; + for(auto &val : header){ + if(++i % 2 == 0){ + header_map.emplace(key,val); + }else{ + key = val; + } + } + return sendRtspResponse(res_code,header_map,sdp,protocol); } inline string RtspSession::printSSRC(uint32_t ui32Ssrc) { - char tmp[9] = { 0 }; - ui32Ssrc = htonl(ui32Ssrc); - uint8_t *pSsrc = (uint8_t *) &ui32Ssrc; - for (int i = 0; i < 4; i++) { - sprintf(tmp + 2 * i, "%02X", pSsrc[i]); - } - return tmp; + char tmp[9] = { 0 }; + ui32Ssrc = htonl(ui32Ssrc); + uint8_t *pSsrc = (uint8_t *) &ui32Ssrc; + for (int i = 0; i < 4; i++) { + sprintf(tmp + 2 * i, "%02X", pSsrc[i]); + } + return tmp; } inline int RtspSession::getTrackIndexByTrackType(TrackType type) { - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (type == _aTrackInfo[i]->_type) { - return i; - } - } + for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { + if (type == _aTrackInfo[i]->_type) { + return i; + } + } if(_aTrackInfo.size() == 1){ return 0; } - return -1; + return -1; } inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) { - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (controlSuffix == _aTrackInfo[i]->_control_surffix) { - return i; - } - } - if(_aTrackInfo.size() == 1){ + for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { + if (controlSuffix == _aTrackInfo[i]->_control_surffix) { + return i; + } + } + if(_aTrackInfo.size() == 1){ return 0; - } - return -1; + } + return -1; } inline int RtspSession::getTrackIndexByInterleaved(int interleaved){ - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (_aTrackInfo[i]->_interleaved == interleaved) { - return i; - } - } + for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { + if (_aTrackInfo[i]->_interleaved == interleaved) { + return i; + } + } if(_aTrackInfo.size() == 1){ return 0; } - return -1; + return -1; } bool RtspSession::close(MediaSource &sender,bool force) { @@ -1130,41 +1114,45 @@ bool RtspSession::close(MediaSource &sender,bool force) { if(!_pushSrc || (!force && _pushSrc->totalReaderCount())){ return false; } - string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; - safeShutdown(SockException(Err_shutdown,err)); - return true; -} - - -void RtspSession::onNoneReader(MediaSource &sender){ - //此回调在其他线程触发 - if(!_pushSrc || _pushSrc->totalReaderCount()){ - return; - } - MediaSourceEvent::onNoneReader(sender); + string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; + safeShutdown(SockException(Err_shutdown,err)); + return true; } int RtspSession::totalReaderCount(MediaSource &sender) { return _pushSrc ? _pushSrc->totalReaderCount() : sender.readerCount(); } -void RtspSession::sendRtpPacket(const RtpPacket::Ptr & pkt) { +void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { //InfoP(this) <<(int)pkt.Interleaved; switch (_rtpType) { case Rtsp::RTP_TCP: { - send(pkt); + int i = 0; + int size = pkt->size(); + setSendFlushFlag(false); + pkt->for_each([&](const RtpPacket::Ptr &rtp) { + if (++i == size) { + setSendFlushFlag(true); + } + send(rtp); + }); } break; case Rtsp::RTP_UDP: { - int iTrackIndex = getTrackIndexByTrackType(pkt->type); - auto &pSock = _apRtpSock[iTrackIndex]; - if (!pSock) { - shutdown(SockException(Err_shutdown,"udp sock not opened yet")); - return; - } - BufferRtp::Ptr buffer(new BufferRtp(pkt,4)); - _ui64TotalBytes += buffer->size(); - pSock->send(buffer); + int i = 0; + int size = pkt->size(); + pkt->for_each([&](const RtpPacket::Ptr &rtp) { + int iTrackIndex = getTrackIndexByTrackType(rtp->type); + auto &pSock = _apRtpSock[iTrackIndex]; + if (!pSock) { + shutdown(SockException(Err_shutdown, "udp sock not opened yet")); + return; + } + + BufferRtp::Ptr buffer(new BufferRtp(rtp, 4)); + _ui64TotalBytes += buffer->size(); + pSock->send(buffer, nullptr, 0, ++i == size); + }); } break; default: diff --git a/src/Rtsp/RtspSession.h b/src/Rtsp/RtspSession.h index 6a77dfc5..eadafdff 100644 --- a/src/Rtsp/RtspSession.h +++ b/src/Rtsp/RtspSession.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SESSION_RTSPSESSION_H_ @@ -69,20 +53,20 @@ private: class RtspSession: public TcpSession, public RtspSplitter, public RtpReceiver , public MediaSourceEvent{ public: - typedef std::shared_ptr Ptr; - typedef std::function onGetRealm; + typedef std::shared_ptr Ptr; + typedef std::function onGetRealm; //encrypted为true是则表明是md5加密的密码,否则是明文密码 //在请求明文密码时如果提供md5密码者则会导致认证失败 - typedef std::function onAuth; + typedef std::function onAuth; - RtspSession(const Socket::Ptr &pSock); - virtual ~RtspSession(); - ////TcpSession override//// - void onRecv(const Buffer::Ptr &pBuf) override; - void onError(const SockException &err) override; - void onManager() override; + RtspSession(const Socket::Ptr &pSock); + virtual ~RtspSession(); + ////TcpSession override//// + void onRecv(const Buffer::Ptr &pBuf) override; + void onError(const SockException &err) override; + void onManager() override; protected: - //RtspSplitter override + //RtspSplitter override /** * 收到完整的rtsp包回调,包括sdp等content数据 * @param parser rtsp包 @@ -103,14 +87,13 @@ protected: */ int64_t getContentLength(Parser &parser) override; - //RtpReceiver override - void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; - //MediaSourceEvent override - bool close(MediaSource &sender,bool force) override ; - void onNoneReader(MediaSource &sender) override; - int totalReaderCount(MediaSource &sender) override; + //RtpReceiver override + void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; + //MediaSourceEvent override + bool close(MediaSource &sender,bool force) override ; + int totalReaderCount(MediaSource &sender) override; - //TcpSession override + //TcpSession override int send(const Buffer::Ptr &pkt) override; /** @@ -122,123 +105,121 @@ protected: */ virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen); private: - //处理options方法,获取服务器能力 + //处理options方法,获取服务器能力 void handleReq_Options(const Parser &parser); - //处理describe方法,请求服务器rtsp sdp信息 + //处理describe方法,请求服务器rtsp sdp信息 void handleReq_Describe(const Parser &parser); - //处理ANNOUNCE方法,请求推流,附带sdp + //处理ANNOUNCE方法,请求推流,附带sdp void handleReq_ANNOUNCE(const Parser &parser); - //处理record方法,开始推流 + //处理record方法,开始推流 void handleReq_RECORD(const Parser &parser); - //处理setup方法,播放和推流协商rtp传输方式用 + //处理setup方法,播放和推流协商rtp传输方式用 void handleReq_Setup(const Parser &parser); - //处理play方法,开始或恢复播放 + //处理play方法,开始或恢复播放 void handleReq_Play(const Parser &parser); - //处理pause方法,暂停播放 + //处理pause方法,暂停播放 void handleReq_Pause(const Parser &parser); - //处理teardown方法,结束播放 + //处理teardown方法,结束播放 void handleReq_Teardown(const Parser &parser); - //处理Get方法,rtp over http才用到 + //处理Get方法,rtp over http才用到 void handleReq_Get(const Parser &parser); - //处理Post方法,rtp over http才用到 + //处理Post方法,rtp over http才用到 void handleReq_Post(const Parser &parser); - //处理SET_PARAMETER、GET_PARAMETER方法,一般用于心跳 + //处理SET_PARAMETER、GET_PARAMETER方法,一般用于心跳 void handleReq_SET_PARAMETER(const Parser &parser); - //rtsp资源未找到 - void inline send_StreamNotFound(); - //不支持的传输模式 - void inline send_UnsupportedTransport(); - //会话id错误 - void inline send_SessionNotFound(); - //一般rtsp服务器打开端口失败时触发 - void inline send_NotAcceptable(); - //ssrc转字符串 - inline string printSSRC(uint32_t ui32Ssrc); + //rtsp资源未找到 + void inline send_StreamNotFound(); + //不支持的传输模式 + void inline send_UnsupportedTransport(); + //会话id错误 + void inline send_SessionNotFound(); + //一般rtsp服务器打开端口失败时触发 + void inline send_NotAcceptable(); + //ssrc转字符串 + inline string printSSRC(uint32_t ui32Ssrc); - //获取track下标 - inline int getTrackIndexByTrackType(TrackType type); + //获取track下标 + inline int getTrackIndexByTrackType(TrackType type); inline int getTrackIndexByControlSuffix(const string &controlSuffix); - inline int getTrackIndexByInterleaved(int interleaved); + inline int getTrackIndexByInterleaved(int interleaved); - //一般用于接收udp打洞包,也用于rtsp推流 - inline void onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr &addr); - //配合onRcvPeerUdpData使用 - inline void startListenPeerUdpData(int iTrackIdx); + //一般用于接收udp打洞包,也用于rtsp推流 + inline void onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr &addr); + //配合onRcvPeerUdpData使用 + inline void startListenPeerUdpData(int iTrackIdx); ////rtsp专有认证相关//// - //认证成功 + //认证成功 void onAuthSuccess(); - //认证失败 + //认证失败 void onAuthFailed(const string &realm,const string &why,bool close = true); - //开始走rtsp专有认证流程 + //开始走rtsp专有认证流程 void onAuthUser(const string &realm,const string &authorization); - //校验base64方式的认证加密 + //校验base64方式的认证加密 void onAuthBasic(const string &realm,const string &strBase64); - //校验md5方式的认证加密 + //校验md5方式的认证加密 void onAuthDigest(const string &realm,const string &strMd5); - //发送rtp给客户端 - void sendRtpPacket(const RtpPacket::Ptr &pkt); - //回复客户端 - bool sendRtspResponse(const string &res_code,const std::initializer_list &header, const string &sdp = "" , const char *protocol = "RTSP/1.0"); - bool sendRtspResponse(const string &res_code,const StrCaseMap &header = StrCaseMap(), const string &sdp = "",const char *protocol = "RTSP/1.0"); - //服务器发送rtcp - void sendSenderReport(bool overTcp,int iTrackIndex); - //设置socket标志 - void setSocketFlags(); + //发送rtp给客户端 + void sendRtpPacket(const RtspMediaSource::RingDataType &pkt); + //回复客户端 + bool sendRtspResponse(const string &res_code,const std::initializer_list &header, const string &sdp = "" , const char *protocol = "RTSP/1.0"); + bool sendRtspResponse(const string &res_code,const StrCaseMap &header = StrCaseMap(), const string &sdp = "",const char *protocol = "RTSP/1.0"); + //服务器发送rtcp + void sendSenderReport(bool overTcp,int iTrackIndex); + //设置socket标志 + void setSocketFlags(); private: - //用于判断客户端是否超时 - Ticker _ticker; - //收到的seq,回复时一致 - int _iCseq = 0; - //ContentBase - string _strContentBase; - //Session号 - string _strSession; - //是否第一次播放,第一次播放需要鉴权,第二次播放属于暂停恢复 - bool _bFirstPlay = true; - //url解析后保存的相关信息 + //用于判断客户端是否超时 + Ticker _ticker; + //收到的seq,回复时一致 + int _iCseq = 0; + //ContentBase + string _strContentBase; + //Session号 + string _strSession; + //是否第一次播放,第一次播放需要鉴权,第二次播放属于暂停恢复 + bool _bFirstPlay = true; + //url解析后保存的相关信息 MediaInfo _mediaInfo; - //rtsp播放器绑定的直播源 - std::weak_ptr _pMediaSrc; - //直播源读取器 - RingBuffer::RingReader::Ptr _pRtpReader; - //推流或拉流客户端采用的rtp传输方式 - Rtsp::eRtpType _rtpType = Rtsp::RTP_Invalid; - //sdp里面有效的track,包含音频或视频 - vector _aTrackInfo; - ////////RTP over udp//////// - //RTP端口,trackid idx 为数组下标 - Socket::Ptr _apRtpSock[2]; - //RTCP端口,trackid idx 为数组下标 - Socket::Ptr _apRtcpSock[2]; - //标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号 + //rtsp播放器绑定的直播源 + std::weak_ptr _pMediaSrc; + //直播源读取器 + RtspMediaSource::RingType::RingReader::Ptr _pRtpReader; + //推流或拉流客户端采用的rtp传输方式 + Rtsp::eRtpType _rtpType = Rtsp::RTP_Invalid; + //sdp里面有效的track,包含音频或视频 + vector _aTrackInfo; + ////////RTP over udp//////// + //RTP端口,trackid idx 为数组下标 + Socket::Ptr _apRtpSock[2]; + //RTCP端口,trackid idx 为数组下标 + Socket::Ptr _apRtcpSock[2]; + //标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号 unordered_set _udpSockConnected; - ////////RTP over udp_multicast//////// - //共享的rtp组播对象 - RtpMultiCaster::Ptr _multicaster; + ////////RTP over udp_multicast//////// + //共享的rtp组播对象 + RtpMultiCaster::Ptr _multicaster; - //登录认证 + //登录认证 string _strNonce; //消耗的总流量 uint64_t _ui64TotalBytes = 0; - //RTSP over HTTP - //quicktime 请求rtsp会产生两次tcp连接, - //一次发送 get 一次发送post,需要通过x-sessioncookie关联起来 - string _http_x_sessioncookie; - function _onRecv; - //是否开始发送rtp + //RTSP over HTTP + //quicktime 请求rtsp会产生两次tcp连接, + //一次发送 get 一次发送post,需要通过x-sessioncookie关联起来 + string _http_x_sessioncookie; + function _onRecv; + //是否开始发送rtp bool _enableSendRtp; //rtsp推流相关 - RtspMediaSourceImp::Ptr _pushSrc; - //rtcp统计,trackid idx 为数组下标 - RtcpCounter _aRtcpCnt[2]; - //rtcp发送时间,trackid idx 为数组下标 - Ticker _aRtcpTicker[2]; - //时间戳修整器 - Stamp _stamp[2]; + RtspMediaSourceImp::Ptr _pushSrc; + //rtcp统计,trackid idx 为数组下标 + RtcpCounter _aRtcpCnt[2]; + //rtcp发送时间,trackid idx 为数组下标 + Ticker _aRtcpTicker[2]; }; /** diff --git a/src/Rtsp/RtspSplitter.cpp b/src/Rtsp/RtspSplitter.cpp index 1994ad10..caaf1054 100644 --- a/src/Rtsp/RtspSplitter.cpp +++ b/src/Rtsp/RtspSplitter.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/src/Rtsp/RtspSplitter.h b/src/Rtsp/RtspSplitter.h index 5390c654..c319410c 100644 --- a/src/Rtsp/RtspSplitter.h +++ b/src/Rtsp/RtspSplitter.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_RTSPSPLITTER_H diff --git a/src/Rtsp/UDPServer.cpp b/src/Rtsp/UDPServer.cpp index 210d04b0..7dd47615 100644 --- a/src/Rtsp/UDPServer.cpp +++ b/src/Rtsp/UDPServer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "UDPServer.h" @@ -38,76 +22,76 @@ UDPServer::UDPServer() { } UDPServer::~UDPServer() { - InfoL; + InfoL; } Socket::Ptr UDPServer::getSock(const EventPoller::Ptr &poller,const char* strLocalIp, int intervaled,uint16_t iLocalPort) { - lock_guard lck(_mtxUpdSock); - string strKey = StrPrinter << strLocalIp << ":" << intervaled << endl; - auto it = _mapUpdSock.find(strKey); - if (it == _mapUpdSock.end()) { - Socket::Ptr pSock(new Socket(poller)); - //InfoL<bindUdpSock(iLocalPort, strLocalIp)) { - //分配失败 - return nullptr; - } + lock_guard lck(_mtxUpdSock); + string strKey = StrPrinter << strLocalIp << ":" << intervaled << endl; + auto it = _mapUpdSock.find(strKey); + if (it == _mapUpdSock.end()) { + Socket::Ptr pSock(new Socket(poller)); + //InfoL<bindUdpSock(iLocalPort, strLocalIp)) { + //分配失败 + return nullptr; + } - pSock->setOnRead(bind(&UDPServer::onRcvData, this, intervaled, placeholders::_1,placeholders::_2)); - pSock->setOnErr(bind(&UDPServer::onErr, this, strKey, placeholders::_1)); - _mapUpdSock[strKey] = pSock; - DebugL << strLocalIp << " " << pSock->get_local_port() << " " << intervaled; - return pSock; - } - return it->second; + pSock->setOnRead(bind(&UDPServer::onRcvData, this, intervaled, placeholders::_1,placeholders::_2)); + pSock->setOnErr(bind(&UDPServer::onErr, this, strKey, placeholders::_1)); + _mapUpdSock[strKey] = pSock; + DebugL << strLocalIp << " " << pSock->get_local_port() << " " << intervaled; + return pSock; + } + return it->second; } void UDPServer::listenPeer(const char* strPeerIp, void* pSelf, const onRecvData& cb) { - lock_guard lck(_mtxDataHandler); - auto &mapRef = _mapDataHandler[strPeerIp]; - mapRef.emplace(pSelf, cb); + lock_guard lck(_mtxDataHandler); + auto &mapRef = _mapDataHandler[strPeerIp]; + mapRef.emplace(pSelf, cb); } void UDPServer::stopListenPeer(const char* strPeerIp, void* pSelf) { - lock_guard lck(_mtxDataHandler); - auto it0 = _mapDataHandler.find(strPeerIp); - if (it0 == _mapDataHandler.end()) { - return; - } - auto &mapRef = it0->second; - auto it1 = mapRef.find(pSelf); - if (it1 != mapRef.end()) { - mapRef.erase(it1); - } - if (mapRef.size() == 0) { - _mapDataHandler.erase(it0); - } + lock_guard lck(_mtxDataHandler); + auto it0 = _mapDataHandler.find(strPeerIp); + if (it0 == _mapDataHandler.end()) { + return; + } + auto &mapRef = it0->second; + auto it1 = mapRef.find(pSelf); + if (it1 != mapRef.end()) { + mapRef.erase(it1); + } + if (mapRef.size() == 0) { + _mapDataHandler.erase(it0); + } } void UDPServer::onErr(const string& strKey, const SockException& err) { - WarnL << err.what(); - lock_guard lck(_mtxUpdSock); - _mapUpdSock.erase(strKey); + WarnL << err.what(); + lock_guard lck(_mtxUpdSock); + _mapUpdSock.erase(strKey); } void UDPServer::onRcvData(int intervaled, const Buffer::Ptr &pBuf, struct sockaddr* pPeerAddr) { - //TraceL << trackIndex; - struct sockaddr_in *in = (struct sockaddr_in *) pPeerAddr; - string peerIp = inet_ntoa(in->sin_addr); - lock_guard lck(_mtxDataHandler); - auto it0 = _mapDataHandler.find(peerIp); - if (it0 == _mapDataHandler.end()) { - return; - } - auto &mapRef = it0->second; - for (auto it1 = mapRef.begin(); it1 != mapRef.end(); ++it1) { - onRecvData &funRef = it1->second; - if (!funRef(intervaled, pBuf, pPeerAddr)) { - it1 = mapRef.erase(it1); - } - } - if (mapRef.size() == 0) { - _mapDataHandler.erase(it0); - } + //TraceL << trackIndex; + struct sockaddr_in *in = (struct sockaddr_in *) pPeerAddr; + string peerIp = inet_ntoa(in->sin_addr); + lock_guard lck(_mtxDataHandler); + auto it0 = _mapDataHandler.find(peerIp); + if (it0 == _mapDataHandler.end()) { + return; + } + auto &mapRef = it0->second; + for (auto it1 = mapRef.begin(); it1 != mapRef.end(); ++it1) { + onRecvData &funRef = it1->second; + if (!funRef(intervaled, pBuf, pPeerAddr)) { + it1 = mapRef.erase(it1); + } + } + if (mapRef.size() == 0) { + _mapDataHandler.erase(it0); + } } } /* namespace mediakit */ diff --git a/src/Rtsp/UDPServer.h b/src/Rtsp/UDPServer.h index 497986a8..d7c0e487 100644 --- a/src/Rtsp/UDPServer.h +++ b/src/Rtsp/UDPServer.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef RTSP_UDPSERVER_H_ @@ -43,21 +27,21 @@ namespace mediakit { class UDPServer : public std::enable_shared_from_this { public: - typedef function< bool(int intervaled, const Buffer::Ptr &buffer, struct sockaddr *peer_addr)> onRecvData; - ~UDPServer(); - static UDPServer &Instance(); - Socket::Ptr getSock(const EventPoller::Ptr &poller,const char *strLocalIp, int intervaled,uint16_t iLocalPort = 0); - void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb); - void stopListenPeer(const char *strPeerIp, void *pSelf); + typedef function< bool(int intervaled, const Buffer::Ptr &buffer, struct sockaddr *peer_addr)> onRecvData; + ~UDPServer(); + static UDPServer &Instance(); + Socket::Ptr getSock(const EventPoller::Ptr &poller,const char *strLocalIp, int intervaled,uint16_t iLocalPort = 0); + void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb); + void stopListenPeer(const char *strPeerIp, void *pSelf); private: - UDPServer(); - void onRcvData(int intervaled, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr); - void onErr(const string &strKey,const SockException &err); - unordered_map _mapUpdSock; - mutex _mtxUpdSock; + UDPServer(); + void onRcvData(int intervaled, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr); + void onErr(const string &strKey,const SockException &err); + unordered_map _mapUpdSock; + mutex _mtxUpdSock; - unordered_map > _mapDataHandler; - mutex _mtxDataHandler; + unordered_map > _mapDataHandler; + mutex _mtxDataHandler; }; } /* namespace mediakit */ diff --git a/src/Shell/ShellCMD.h b/src/Shell/ShellCMD.h index e3a44901..a401f73f 100644 --- a/src/Shell/ShellCMD.h +++ b/src/Shell/ShellCMD.h @@ -1,6 +1,12 @@ -// -// Created by xzl on 2017/12/1. -// +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ #ifndef SRC_SHELL_SHELLCMD_H_ #define SRC_SHELL_SHELLCMD_H_ diff --git a/src/Shell/ShellSession.cpp b/src/Shell/ShellSession.cpp index 7822245c..e7f29285 100644 --- a/src/Shell/ShellSession.cpp +++ b/src/Shell/ShellSession.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include "ShellSession.h" @@ -48,29 +32,29 @@ ShellSession::~ShellSession() { } void ShellSession::onRecv(const Buffer::Ptr&buf) { - //DebugL << hexdump(buf->data(), buf->size()); + //DebugL << hexdump(buf->data(), buf->size()); GET_CONFIG(uint32_t,maxReqSize,Shell::kMaxReqSize); if (_strRecvBuf.size() + buf->size() >= maxReqSize) { - shutdown(SockException(Err_other,"recv buffer overflow")); - return; - } - _beatTicker.resetTime(); - _strRecvBuf.append(buf->data(), buf->size()); - if (_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) { - send("\033[0m\r\n Bye bye!\r\n"); - shutdown(SockException(Err_other,"received Ctrl+C")); - return; - } - size_t index; - string line; - while ((index = _strRecvBuf.find("\r\n")) != std::string::npos) { - line = _strRecvBuf.substr(0, index); - _strRecvBuf.erase(0, index + 2); - if (!onCommandLine(line)) { - shutdown(SockException(Err_other,"exit cmd")); - return; - } - } + shutdown(SockException(Err_other,"recv buffer overflow")); + return; + } + _beatTicker.resetTime(); + _strRecvBuf.append(buf->data(), buf->size()); + if (_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) { + send("\033[0m\r\n Bye bye!\r\n"); + shutdown(SockException(Err_other,"received Ctrl+C")); + return; + } + size_t index; + string line; + while ((index = _strRecvBuf.find("\r\n")) != std::string::npos) { + line = _strRecvBuf.substr(0, index); + _strRecvBuf.erase(0, index + 2); + if (!onCommandLine(line)) { + shutdown(SockException(Err_other,"exit cmd")); + return; + } + } } void ShellSession::onError(const SockException &err){ @@ -78,19 +62,19 @@ void ShellSession::onError(const SockException &err){ } void ShellSession::onManager() { - if (_beatTicker.elapsedTime() > 1000 * 60 * 5) { - //5 miniutes for alive + if (_beatTicker.elapsedTime() > 1000 * 60 * 5) { + //5 miniutes for alive shutdown(SockException(Err_timeout,"session timeout")); - return; - } + return; + } } inline bool ShellSession::onCommandLine(const string& line) { auto loginInterceptor = _loginInterceptor; if (loginInterceptor) { - bool ret = loginInterceptor(line); - return ret; - } + bool ret = loginInterceptor(line); + return ret; + } try { std::shared_ptr ss(new stringstream); CMDRegister::Instance()(line,ss); @@ -102,21 +86,21 @@ inline bool ShellSession::onCommandLine(const string& line) { send("\r\n"); } printShellPrefix(); - return true; + return true; } inline void ShellSession::pleaseInputUser() { - send("\033[0m"); - send(StrPrinter << SERVER_NAME << " login: " << endl); - _loginInterceptor = [this](const string &user_name) { - _strUserName=user_name; + send("\033[0m"); + send(StrPrinter << SERVER_NAME << " login: " << endl); + _loginInterceptor = [this](const string &user_name) { + _strUserName=user_name; pleaseInputPasswd(); - return true; - }; + return true; + }; } inline void ShellSession::pleaseInputPasswd() { - send("Password: \033[8m"); - _loginInterceptor = [this](const string &passwd) { + send("Password: \033[8m"); + _loginInterceptor = [this](const string &passwd) { auto onAuth = [this](const string &errMessage){ if(!errMessage.empty()){ //鉴权失败 @@ -157,12 +141,12 @@ inline void ShellSession::pleaseInputPasswd() { //如果无人监听shell登录事件,那么默认shell无法登录 onAuth("please listen kBroadcastShellLogin event"); } - return true; - }; + return true; + }; } inline void ShellSession::printShellPrefix() { - send(StrPrinter << _strUserName << "@" << SERVER_NAME << "# " << endl); + send(StrPrinter << _strUserName << "@" << SERVER_NAME << "# " << endl); } }/* namespace mediakit */ diff --git a/src/Shell/ShellSession.h b/src/Shell/ShellSession.h index 4c3732ca..dd7d1bb6 100644 --- a/src/Shell/ShellSession.h +++ b/src/Shell/ShellSession.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef SRC_SHELL_SHELLSESSION_H_ @@ -37,23 +21,23 @@ namespace mediakit { class ShellSession: public TcpSession { public: - ShellSession(const Socket::Ptr &_sock); - virtual ~ShellSession(); + ShellSession(const Socket::Ptr &_sock); + virtual ~ShellSession(); - void onRecv(const Buffer::Ptr &) override; + void onRecv(const Buffer::Ptr &) override; void onError(const SockException &err) override; - void onManager() override; + void onManager() override; private: - inline bool onCommandLine(const string &); - inline void pleaseInputUser(); - inline void pleaseInputPasswd(); - inline void printShellPrefix(); + inline bool onCommandLine(const string &); + inline void pleaseInputUser(); + inline void pleaseInputPasswd(); + inline void printShellPrefix(); - function _loginInterceptor; - string _strRecvBuf; - Ticker _beatTicker; - string _strUserName; + function _loginInterceptor; + string _strRecvBuf; + Ticker _beatTicker; + string _strUserName; }; } /* namespace mediakit */ diff --git a/tests/DeviceHK/DeviceHK.cpp b/tests/DeviceHK/DeviceHK.cpp index f1d57d8c..563cee8c 100644 --- a/tests/DeviceHK/DeviceHK.cpp +++ b/tests/DeviceHK/DeviceHK.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifdef ENABLE_HKDEVICE #include "DeviceHK.h" #include "Util/TimeTicker.h" @@ -32,232 +17,232 @@ namespace mediakit { #define HK_APP_NAME "live" DeviceHK::DeviceHK() { - InfoL << endl; - static onceToken token( []() { - NET_DVR_Init(); - NET_DVR_SetDVRMessageCallBack_V31([](LONG lCommand,NET_DVR_ALARMER *pAlarmer,char *pAlarmInfo,DWORD dwBufLen,void* pUser){ - WarnL< hkLoginCB; - loginInfo.bUseAsynLogin = TRUE; - weak_ptr weakSelf = shared_from_this(); - loginInfo.pUser = new hkLoginCB([weakSelf,cb](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo ) { - //TraceL<sSerialNumber; - connectResult result; - if(dwResult==TRUE) { - result.strDevName=(char *)(lpDeviceInfo->sSerialNumber); - result.ui16ChnStart=lpDeviceInfo->byStartChan; - result.ui16ChnCount=lpDeviceInfo->byChanNum; - auto _strongSelf=weakSelf.lock(); - if(_strongSelf) { - auto strongSelf=dynamic_pointer_cast(_strongSelf); - strongSelf->onConnected(lUserID,lpDeviceInfo); - } - } else { - WarnL<<"connect deviceHK failed:"<(pUser); - (*fun)(lUserID,dwResult,lpDeviceInfo); - delete fun; - }; - NET_DVR_SetConnectTime(iTimeOut * 1000, 3); - NET_DVR_Login_V40(&loginInfo, &loginResult); + //callback info + typedef function< void(LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo)> hkLoginCB; + loginInfo.bUseAsynLogin = TRUE; + weak_ptr weakSelf = shared_from_this(); + loginInfo.pUser = new hkLoginCB([weakSelf,cb](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo ) { + //TraceL<sSerialNumber; + connectResult result; + if(dwResult==TRUE) { + result.strDevName=(char *)(lpDeviceInfo->sSerialNumber); + result.ui16ChnStart=lpDeviceInfo->byStartChan; + result.ui16ChnCount=lpDeviceInfo->byChanNum; + auto _strongSelf=weakSelf.lock(); + if(_strongSelf) { + auto strongSelf=dynamic_pointer_cast(_strongSelf); + strongSelf->onConnected(lUserID,lpDeviceInfo); + } + } else { + WarnL<<"connect deviceHK failed:"<(pUser); + (*fun)(lUserID,dwResult,lpDeviceInfo); + delete fun; + }; + NET_DVR_SetConnectTime(iTimeOut * 1000, 3); + NET_DVR_Login_V40(&loginInfo, &loginResult); } void DeviceHK::disconnect(const relustCB& cb) { - m_mapChannels.clear(); - if (m_i64LoginId >= 0) { - NET_DVR_Logout(m_i64LoginId); - m_i64LoginId = -1; - Device::onDisconnected(true); - } + m_mapChannels.clear(); + if (m_i64LoginId >= 0) { + NET_DVR_Logout(m_i64LoginId); + m_i64LoginId = -1; + Device::onDisconnected(true); + } } void DeviceHK::addChannel(int iChn, bool bMainStream) { - DevChannel::Ptr channel( new DevChannelHK(m_i64LoginId, (char *) m_deviceInfo.sSerialNumber, iChn, bMainStream)); - m_mapChannels[iChn] = channel; + DevChannel::Ptr channel( new DevChannelHK(m_i64LoginId, (char *) m_deviceInfo.sSerialNumber, iChn, bMainStream)); + m_mapChannels[iChn] = channel; } void DeviceHK::delChannel(int chn) { - m_mapChannels.erase(chn); + m_mapChannels.erase(chn); } void DeviceHK::onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo) { - m_i64LoginId = lUserID; - m_deviceInfo = *lpDeviceInfo; - Device::onConnected(); + m_i64LoginId = lUserID; + m_deviceInfo = *lpDeviceInfo; + Device::onConnected(); } void DeviceHK::addAllChannel(bool bMainStream) { - InfoL << endl; - for (int i = 0; i < m_deviceInfo.byChanNum; i++) { - addChannel(m_deviceInfo.byStartChan + i, bMainStream); - } + InfoL << endl; + for (int i = 0; i < m_deviceInfo.byChanNum; i++) { + addChannel(m_deviceInfo.byStartChan + i, bMainStream); + } } DevChannelHK::DevChannelHK(int64_t i64LoginId, const char* pcDevName, int iChn, bool bMainStream) : - DevChannel(HK_APP_NAME,(StrPrinter<(pUser); - if(self->m_i64PreviewHandle!=(int64_t)lPlayHandle) { - return; - } - self->onPreview(dwDataType,pBuffer,dwBufSize); - }, this); - if (m_i64PreviewHandle == -1) { - throw std::runtime_error( StrPrinter << "设备[" << pcDevName << "/" << iChn << "]开始实时预览失败:" - << NET_DVR_GetLastError() << endl); - } + DevChannel(HK_APP_NAME,(StrPrinter<(pUser); + if(self->m_i64PreviewHandle!=(int64_t)lPlayHandle) { + return; + } + self->onPreview(dwDataType,pBuffer,dwBufSize); + }, this); + if (m_i64PreviewHandle == -1) { + throw std::runtime_error( StrPrinter << "设备[" << pcDevName << "/" << iChn << "]开始实时预览失败:" + << NET_DVR_GetLastError() << endl); + } } DevChannelHK::~DevChannelHK() { - InfoL << endl; - if (m_i64PreviewHandle >= 0) { - NET_DVR_StopRealPlay(m_i64PreviewHandle); - m_i64PreviewHandle = -1; - } - if (m_iPlayHandle >= 0) { - PlayM4_StopSoundShare(m_iPlayHandle); - PlayM4_Stop(m_iPlayHandle); - m_iPlayHandle = -1; - } + InfoL << endl; + if (m_i64PreviewHandle >= 0) { + NET_DVR_StopRealPlay(m_i64PreviewHandle); + m_i64PreviewHandle = -1; + } + if (m_iPlayHandle >= 0) { + PlayM4_StopSoundShare(m_iPlayHandle); + PlayM4_Stop(m_iPlayHandle); + m_iPlayHandle = -1; + } } void DevChannelHK::onPreview(DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize) { - //TimeTicker1(-1); - switch (dwDataType) { - case NET_DVR_SYSHEAD: { //系统头数据 - if (!PlayM4_GetPort(&m_iPlayHandle)) { //获取播放库未使用的通道号 - WarnL << "PlayM4_GetPort:" << NET_DVR_GetLastError(); - break; - } - if (dwBufSize > 0) { - if (!PlayM4_SetStreamOpenMode(m_iPlayHandle, STREAME_REALTIME)) { //设置实时流播放模式 - WarnL << "PlayM4_SetStreamOpenMode:" << NET_DVR_GetLastError(); - break; - } - if (!PlayM4_OpenStream(m_iPlayHandle, pBuffer, dwBufSize, - 1024 * 1024)) { //打开流接口 - WarnL << "PlayM4_OpenStream:" << NET_DVR_GetLastError(); - break; - } + //TimeTicker1(-1); + switch (dwDataType) { + case NET_DVR_SYSHEAD: { //系统头数据 + if (!PlayM4_GetPort(&m_iPlayHandle)) { //获取播放库未使用的通道号 + WarnL << "PlayM4_GetPort:" << NET_DVR_GetLastError(); + break; + } + if (dwBufSize > 0) { + if (!PlayM4_SetStreamOpenMode(m_iPlayHandle, STREAME_REALTIME)) { //设置实时流播放模式 + WarnL << "PlayM4_SetStreamOpenMode:" << NET_DVR_GetLastError(); + break; + } + if (!PlayM4_OpenStream(m_iPlayHandle, pBuffer, dwBufSize, + 1024 * 1024)) { //打开流接口 + WarnL << "PlayM4_OpenStream:" << NET_DVR_GetLastError(); + break; + } - PlayM4_SetDecCallBackMend(m_iPlayHandle, - [](int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2) { - DevChannelHK *chn=reinterpret_cast(nUser); - if(chn->m_iPlayHandle!=nPort) { - return; - } - chn->onGetDecData(pBuf,nSize,pFrameInfo); - }, this); - if (!PlayM4_Play(m_iPlayHandle, 0)) { //播放开始 - WarnL << "PlayM4_Play:" << NET_DVR_GetLastError(); - break; - } - InfoL << "设置解码器成功!" << endl; - //打开音频解码, 需要码流是复合流 - if (!PlayM4_PlaySoundShare(m_iPlayHandle)) { - WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError(); - break; - } - } - } - break; - case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据) - if (dwBufSize > 0 && m_iPlayHandle != -1) { - if (!PlayM4_InputData(m_iPlayHandle, pBuffer, dwBufSize)) { - WarnL << "PlayM4_InputData:" << NET_DVR_GetLastError(); - break; - } - } - } - break; - case NET_DVR_AUDIOSTREAMDATA: { //音频数据 - } - break; - case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息 - } - break; - default: - break; - } + PlayM4_SetDecCallBackMend(m_iPlayHandle, + [](int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2) { + DevChannelHK *chn=reinterpret_cast(nUser); + if(chn->m_iPlayHandle!=nPort) { + return; + } + chn->onGetDecData(pBuf,nSize,pFrameInfo); + }, this); + if (!PlayM4_Play(m_iPlayHandle, 0)) { //播放开始 + WarnL << "PlayM4_Play:" << NET_DVR_GetLastError(); + break; + } + InfoL << "设置解码器成功!" << endl; + //打开音频解码, 需要码流是复合流 + if (!PlayM4_PlaySoundShare(m_iPlayHandle)) { + WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError(); + break; + } + } + } + break; + case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据) + if (dwBufSize > 0 && m_iPlayHandle != -1) { + if (!PlayM4_InputData(m_iPlayHandle, pBuffer, dwBufSize)) { + WarnL << "PlayM4_InputData:" << NET_DVR_GetLastError(); + break; + } + } + } + break; + case NET_DVR_AUDIOSTREAMDATA: { //音频数据 + } + break; + case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息 + } + break; + default: + break; + } } void DevChannelHK::onGetDecData(char* pBuf, int nSize, FRAME_INFO* pFrameInfo) { - //InfoL << pFrameInfo->nType; - switch (pFrameInfo->nType) { - case T_YV12: { - if (!m_bVideoSeted) { - m_bVideoSeted = true; - VideoInfo video; - video.iWidth = pFrameInfo->nWidth; - video.iHeight = pFrameInfo->nHeight; - video.iFrameRate = pFrameInfo->nFrameRate; - initVideo(video); - } - char *yuv[3]; - int yuv_len[3]; - yuv_len[0] = pFrameInfo->nWidth; - yuv_len[1] = pFrameInfo->nWidth / 2; - yuv_len[2] = pFrameInfo->nWidth / 2; - int dwOffset_Y = pFrameInfo->nWidth * pFrameInfo->nHeight; - yuv[0] = pBuf; - yuv[2] = yuv[0] + dwOffset_Y; - yuv[1] = yuv[2] + dwOffset_Y / 4; - inputYUV(yuv, yuv_len, pFrameInfo->nStamp); - } - break; - case T_AUDIO16: { - if (!m_bAudioSeted) { - m_bAudioSeted = true; - AudioInfo audio; - audio.iChannel = pFrameInfo->nWidth; - audio.iSampleBit = pFrameInfo->nHeight; - audio.iSampleRate = pFrameInfo->nFrameRate; - initAudio(audio); - } - inputPCM(pBuf, nSize, pFrameInfo->nStamp); - } - break; - default: - break; - } + //InfoL << pFrameInfo->nType; + switch (pFrameInfo->nType) { + case T_YV12: { + if (!m_bVideoSeted) { + m_bVideoSeted = true; + VideoInfo video; + video.iWidth = pFrameInfo->nWidth; + video.iHeight = pFrameInfo->nHeight; + video.iFrameRate = pFrameInfo->nFrameRate; + initVideo(video); + } + char *yuv[3]; + int yuv_len[3]; + yuv_len[0] = pFrameInfo->nWidth; + yuv_len[1] = pFrameInfo->nWidth / 2; + yuv_len[2] = pFrameInfo->nWidth / 2; + int dwOffset_Y = pFrameInfo->nWidth * pFrameInfo->nHeight; + yuv[0] = pBuf; + yuv[2] = yuv[0] + dwOffset_Y; + yuv[1] = yuv[2] + dwOffset_Y / 4; + inputYUV(yuv, yuv_len, pFrameInfo->nStamp); + } + break; + case T_AUDIO16: { + if (!m_bAudioSeted) { + m_bAudioSeted = true; + AudioInfo audio; + audio.iChannel = pFrameInfo->nWidth; + audio.iSampleBit = pFrameInfo->nHeight; + audio.iSampleRate = pFrameInfo->nFrameRate; + initAudio(audio); + } + inputPCM(pBuf, nSize, pFrameInfo->nStamp); + } + break; + default: + break; + } } } /* namespace mediakit */ diff --git a/tests/DeviceHK/DeviceHK.h b/tests/DeviceHK/DeviceHK.h index 69e716b3..92f5de64 100644 --- a/tests/DeviceHK/DeviceHK.h +++ b/tests/DeviceHK/DeviceHK.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef DEVICE_DEVICEHK_H_ @@ -41,26 +25,26 @@ namespace mediakit { class connectInfo { public: - connectInfo(const char *_strDevIp, - uint16_t _ui16DevPort, - const char *_strUserName, - const char *_strPwd) { - strDevIp = _strDevIp; - ui16DevPort = _ui16DevPort; - strUserName = _strUserName; - strPwd = _strPwd; - } - string strDevIp; - uint16_t ui16DevPort; - string strUserName; - string strPwd; + connectInfo(const char *_strDevIp, + uint16_t _ui16DevPort, + const char *_strUserName, + const char *_strPwd) { + strDevIp = _strDevIp; + ui16DevPort = _ui16DevPort; + strUserName = _strUserName; + strPwd = _strPwd; + } + string strDevIp; + uint16_t ui16DevPort; + string strUserName; + string strPwd; }; class connectResult { public: - string strDevName; - uint16_t ui16ChnStart; - uint16_t ui16ChnCount; + string strDevName; + uint16_t ui16ChnStart; + uint16_t ui16ChnCount; }; typedef function connectCB; @@ -68,28 +52,28 @@ typedef function relustCB; class Device: public enable_shared_from_this { public: - typedef std::shared_ptr Ptr; - Device() { - } - virtual ~Device(){ disconnect([](bool bSuccess){ - });}; + typedef std::shared_ptr Ptr; + Device() { + } + virtual ~Device(){ disconnect([](bool bSuccess){ + });}; - virtual void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3)=0; + virtual void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3)=0; - virtual void disconnect(const relustCB &cb) { - } + virtual void disconnect(const relustCB &cb) { + } - virtual void addChannel(int iChnIndex, bool bMainStream = true)=0; + virtual void addChannel(int iChnIndex, bool bMainStream = true)=0; - virtual void delChannel(int iChnIndex)=0; + virtual void delChannel(int iChnIndex)=0; - virtual void addAllChannel(bool bMainStream = true)=0; + virtual void addAllChannel(bool bMainStream = true)=0; protected: - void onConnected() { - } - void onDisconnected(bool bSelfDisconnect) { - } + void onConnected() { + } + void onDisconnected(bool bSelfDisconnect) { + } }; @@ -97,36 +81,36 @@ protected: class DevChannelHK; class DeviceHK: public Device { public: - typedef std::shared_ptr Ptr; - DeviceHK(); - virtual ~DeviceHK(); + typedef std::shared_ptr Ptr; + DeviceHK(); + virtual ~DeviceHK(); - void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3) override; - void disconnect(const relustCB &cb) override; + void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3) override; + void disconnect(const relustCB &cb) override; - void addChannel(int iChnIndex, bool bMainStream = true) override; - void delChannel(int iChnIndex) override; - void addAllChannel(bool bMainStream = true) override; + void addChannel(int iChnIndex, bool bMainStream = true) override; + void delChannel(int iChnIndex) override; + void addAllChannel(bool bMainStream = true) override; private: - map > m_mapChannels; - int64_t m_i64LoginId = -1; - NET_DVR_DEVICEINFO_V30 m_deviceInfo; - void onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo); + map > m_mapChannels; + int64_t m_i64LoginId = -1; + NET_DVR_DEVICEINFO_V30 m_deviceInfo; + void onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo); }; class DevChannelHK: public DevChannel { public: - typedef std::shared_ptr Ptr; - DevChannelHK(int64_t i64LoginId, const char *pcDevName, int iChn, bool bMainStream = true); - virtual ~DevChannelHK(); + typedef std::shared_ptr Ptr; + DevChannelHK(int64_t i64LoginId, const char *pcDevName, int iChn, bool bMainStream = true); + virtual ~DevChannelHK(); protected: - int64_t m_i64LoginId = -1; - int64_t m_i64PreviewHandle = -1; - int m_iPlayHandle = -1; - void onPreview(DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize); - void onGetDecData(char * pBuf, int nSize, FRAME_INFO * pFrameInfo); - bool m_bVideoSeted = false; - bool m_bAudioSeted = false; + int64_t m_i64LoginId = -1; + int64_t m_i64PreviewHandle = -1; + int m_iPlayHandle = -1; + void onPreview(DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize); + void onGetDecData(char * pBuf, int nSize, FRAME_INFO * pFrameInfo); + bool m_bVideoSeted = false; + bool m_bAudioSeted = false; }; } /* namespace mediakit */ diff --git a/tests/H264Decoder.h b/tests/H264Decoder.h index daf3d45f..31dd8229 100644 --- a/tests/H264Decoder.h +++ b/tests/H264Decoder.h @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #ifndef H264Decoder_H_ @@ -46,51 +30,51 @@ namespace mediakit { class H264Decoder { public: - H264Decoder(void){ - avcodec_register_all(); - AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_H264); - if (!pCodec) { - throw std::runtime_error("未找到H264解码器"); - } - m_pContext.reset(avcodec_alloc_context3(pCodec), [](AVCodecContext *pCtx) { - avcodec_close(pCtx); - avcodec_free_context(&pCtx); - }); - if (!m_pContext) { - throw std::runtime_error("创建解码器失败"); - } - if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) { - /* we do not send complete frames */ - m_pContext->flags |= AV_CODEC_FLAG_TRUNCATED; - } - if(avcodec_open2(m_pContext.get(), pCodec, NULL)< 0){ - throw std::runtime_error("打开编码器失败"); - } - m_pFrame.reset(av_frame_alloc(),[](AVFrame *pFrame){ - av_frame_free(&pFrame); - }); - if (!m_pFrame) { - throw std::runtime_error("创建帧缓存失败"); - } - } - virtual ~H264Decoder(void){} - bool inputVideo(unsigned char* data,unsigned int dataSize,uint32_t ui32Stamp,AVFrame **ppFrame){ - AVPacket pkt; - av_init_packet(&pkt); - pkt.data = data; - pkt.size = dataSize; - pkt.dts = ui32Stamp; - int iGotPicture ; - auto iLen = avcodec_decode_video2(m_pContext.get(), m_pFrame.get(), &iGotPicture, &pkt); - if (!iGotPicture || iLen < 0) { - return false; - } - *ppFrame = m_pFrame.get(); - return true; - } + H264Decoder(void){ + avcodec_register_all(); + AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_H264); + if (!pCodec) { + throw std::runtime_error("未找到H264解码器"); + } + m_pContext.reset(avcodec_alloc_context3(pCodec), [](AVCodecContext *pCtx) { + avcodec_close(pCtx); + avcodec_free_context(&pCtx); + }); + if (!m_pContext) { + throw std::runtime_error("创建解码器失败"); + } + if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) { + /* we do not send complete frames */ + m_pContext->flags |= AV_CODEC_FLAG_TRUNCATED; + } + if(avcodec_open2(m_pContext.get(), pCodec, NULL)< 0){ + throw std::runtime_error("打开编码器失败"); + } + m_pFrame.reset(av_frame_alloc(),[](AVFrame *pFrame){ + av_frame_free(&pFrame); + }); + if (!m_pFrame) { + throw std::runtime_error("创建帧缓存失败"); + } + } + virtual ~H264Decoder(void){} + bool inputVideo(unsigned char* data,unsigned int dataSize,uint32_t ui32Stamp,AVFrame **ppFrame){ + AVPacket pkt; + av_init_packet(&pkt); + pkt.data = data; + pkt.size = dataSize; + pkt.dts = ui32Stamp; + int iGotPicture ; + auto iLen = avcodec_decode_video2(m_pContext.get(), m_pFrame.get(), &iGotPicture, &pkt); + if (!iGotPicture || iLen < 0) { + return false; + } + *ppFrame = m_pFrame.get(); + return true; + } private: - std::shared_ptr m_pContext; - std::shared_ptr m_pFrame; + std::shared_ptr m_pContext; + std::shared_ptr m_pFrame; }; diff --git a/tests/YuvDisplayer.h b/tests/YuvDisplayer.h index 1cd77867..2b5fcf3c 100644 --- a/tests/YuvDisplayer.h +++ b/tests/YuvDisplayer.h @@ -1,26 +1,13 @@ /* - * MIT License + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * - * Copyright (c) 2017 xiongziliang <771730766@qq.com> + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #ifndef YUVDISPLAYER_H_ #define YUVDISPLAYER_H_ #include @@ -65,13 +52,13 @@ public: SDL_PushEvent(&event); } - void runLoop(){ - bool flag = true; - std::function task; - SDL_Event event; - while(flag){ - SDL_WaitEvent(&event); - switch (event.type){ + void runLoop(){ + bool flag = true; + std::function task; + SDL_Event event; + while(flag){ + SDL_WaitEvent(&event); + switch (event.type){ case REFRESH_EVENT:{ { lock_guard lck(_mtxTask); @@ -91,17 +78,17 @@ public: default: break; } - } - } + } + } - void shutdown(){ - doTask([](){return false;}); - } + void shutdown(){ + doTask([](){return false;}); + } private: SDLDisplayerHelper(){ }; ~SDLDisplayerHelper(){ - shutdown(); + shutdown(); }; private: std::deque > _taskList; @@ -112,7 +99,7 @@ private: class YuvDisplayer { public: - YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){ + YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){ static onceToken token([]() { if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) == -1) { @@ -131,39 +118,39 @@ public: SDL_Quit(); }); - _title = title; - _hwnd = hwnd; - } - virtual ~YuvDisplayer(){ - if (_texture) { - SDL_DestroyTexture(_texture); - _texture = nullptr; - } - if (_render) { - SDL_DestroyRenderer(_render); - _render = nullptr; - } - if (_win) { - SDL_DestroyWindow(_win); - _win = nullptr; - } - } - bool displayYUV(AVFrame *pFrame){ - if (!_win) { - if (_hwnd) { - _win = SDL_CreateWindowFrom(_hwnd); - }else { - _win = SDL_CreateWindow(_title.data(), - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - pFrame->width, - pFrame->height, - SDL_WINDOW_OPENGL); - } - } - if (_win && ! _render){ + _title = title; + _hwnd = hwnd; + } + virtual ~YuvDisplayer(){ + if (_texture) { + SDL_DestroyTexture(_texture); + _texture = nullptr; + } + if (_render) { + SDL_DestroyRenderer(_render); + _render = nullptr; + } + if (_win) { + SDL_DestroyWindow(_win); + _win = nullptr; + } + } + bool displayYUV(AVFrame *pFrame){ + if (!_win) { + if (_hwnd) { + _win = SDL_CreateWindowFrom(_hwnd); + }else { + _win = SDL_CreateWindow(_title.data(), + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + pFrame->width, + pFrame->height, + SDL_WINDOW_OPENGL); + } + } + if (_win && ! _render){ #if 0 - SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */ + SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */ SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware acceleration */ SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized @@ -172,34 +159,34 @@ public: rendering to texture */ #endif - _render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED); - } - if (_render && !_texture) { - _texture = SDL_CreateTexture(_render, SDL_PIXELFORMAT_IYUV, - SDL_TEXTUREACCESS_STREAMING, - pFrame->width, - pFrame->height); - } - if (_texture) { - SDL_UpdateYUVTexture(_texture, nullptr, - pFrame->data[0], pFrame->linesize[0], - pFrame->data[1], pFrame->linesize[1], - pFrame->data[2], pFrame->linesize[2]); + _render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED); + } + if (_render && !_texture) { + _texture = SDL_CreateTexture(_render, SDL_PIXELFORMAT_IYUV, + SDL_TEXTUREACCESS_STREAMING, + pFrame->width, + pFrame->height); + } + if (_texture) { + SDL_UpdateYUVTexture(_texture, nullptr, + pFrame->data[0], pFrame->linesize[0], + pFrame->data[1], pFrame->linesize[1], + pFrame->data[2], pFrame->linesize[2]); - //SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]); - SDL_RenderClear(_render); - SDL_RenderCopy(_render, _texture, nullptr, nullptr); - SDL_RenderPresent(_render); - return true; - } - return false; - } + //SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]); + SDL_RenderClear(_render); + SDL_RenderCopy(_render, _texture, nullptr, nullptr); + SDL_RenderPresent(_render); + return true; + } + return false; + } private: - string _title; - SDL_Window *_win = nullptr; - SDL_Renderer *_render = nullptr; - SDL_Texture *_texture = nullptr; - void *_hwnd = nullptr; + string _title; + SDL_Window *_win = nullptr; + SDL_Renderer *_render = nullptr; + SDL_Texture *_texture = nullptr; + void *_hwnd = nullptr; }; #endif /* YUVDISPLAYER_H_ */ \ No newline at end of file diff --git a/tests/bom.cpp b/tests/bom.cpp index 3502d382..46f1e1a8 100644 --- a/tests/bom.cpp +++ b/tests/bom.cpp @@ -1,4 +1,14 @@ -#include +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include #include #if !defined(_WIN32) #include @@ -126,6 +136,7 @@ void process_file(const char *file,bool rm_bom){ InfoL << (rm_bom ? "删除" : "添加") << "bom:" << file; } +/// 这个程序是为了统一添加或删除utf-8 bom头 int main(int argc, char *argv[]) { CMD_main cmd_main; try { @@ -148,7 +159,7 @@ int main(int argc, char *argv[]) { bool no_filter = filter_set.find("*") != filter_set.end(); //设置日志 Logger::Instance().add(std::make_shared()); - + path = File::absolutePath(path, ""); for_each_file(path.data(),[&](const char *path){ if(!no_filter){ //开启了过滤器 diff --git a/tests/tab.cpp b/tests/tab.cpp new file mode 100644 index 00000000..7382f75d --- /dev/null +++ b/tests/tab.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include "Util/CMD.h" +#include "Util/util.h" +#include "Util/logger.h" +#include "Util/File.h" + +using namespace std; +using namespace toolkit; + +class CMD_main : public CMD { +public: + CMD_main() { + _parser.reset(new OptionParser(nullptr)); + (*_parser) << Option('f',/*该选项简称,如果是\x00则说明无简称*/ + "filter",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/ + Option::ArgRequired,/*该选项后面必须跟值*/ + "c,cpp,cxx,c,h,hpp",/*该选项默认值*/ + true,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/ + "文件后缀过滤器",/*该选项说明文字*/ + nullptr); + + (*_parser) << Option('i',/*该选项简称,如果是\x00则说明无简称*/ + "in",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/ + Option::ArgRequired,/*该选项后面必须跟值*/ + nullptr,/*该选项默认值*/ + true,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/ + "文件夹或文件",/*该选项说明文字*/ + nullptr); + } + + virtual ~CMD_main() {} +}; + +vector split(const string& s, const char *delim) { + vector ret; + int last = 0; + int index = s.find(delim, last); + while (index != string::npos) { + if (index - last >= 0) { + ret.push_back(s.substr(last, index - last)); + } + last = index + strlen(delim); + index = s.find(delim, last); + } + if (!s.size() || s.size() - last >= 0) { + ret.push_back(s.substr(last)); + } + return ret; +} + +void process_file(const char *file) { + auto str = File::loadFile(file); + if (str.empty()) { + return; + } + auto lines = ::split(str, "\n"); + deque lines_copy; + for (auto &line : lines) { + if(line.empty()){ + lines_copy.push_back(""); + continue; + } + string line_copy; + bool flag = false; + int i = 0; + for (auto &ch : line) { + ++i; + switch (ch) { + case '\t' : + line_copy.append(" "); + break; + case ' ': + line_copy.push_back(ch); + break; + default: + line_copy.push_back(ch); + flag = true; + break; + } + if (flag) { + line_copy.append(line.substr(i)); + break; + } + } + lines_copy.push_back(line_copy); + } + str.clear(); + for (auto &line : lines_copy) { + str.append(line); + str.push_back('\n'); + } + if(!lines_copy.empty()){ + str.pop_back(); + } + File::saveFile(str, file); +} + +/// 这个程序是为了统一替换tab为4个空格 +int main(int argc, char *argv[]) { + CMD_main cmd_main; + try { + cmd_main.operator()(argc, argv); + } catch (std::exception &ex) { + cout << ex.what() << endl; + return -1; + } + + string path = cmd_main["in"]; + string filter = cmd_main["filter"]; + auto vec = ::split(filter, ","); + + set filter_set; + for (auto ext : vec) { + filter_set.emplace(ext); + } + + bool no_filter = filter_set.find("*") != filter_set.end(); + //设置日志 + Logger::Instance().add(std::make_shared()); + path = File::absolutePath(path, ""); + DebugL << path; + File::scanDir(path, [&](const string &path, bool isDir) { + if (isDir) { + return true; + } + if (!no_filter) { + //开启了过滤器 + auto pos = strstr(path.data(), "."); + if (pos == nullptr) { + //没有后缀 + return true; + } + auto ext = pos + 1; + if (filter_set.find(ext) == filter_set.end()) { + //后缀不匹配 + return true; + } + } + //该文件匹配 + process_file(path.data()); + return true; + }, true); + return 0; +} diff --git a/tests/test_benchmark.cpp b/tests/test_benchmark.cpp index 0aee3733..3dd65944 100644 --- a/tests/test_benchmark.cpp +++ b/tests/test_benchmark.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include #include #include diff --git a/tests/test_httpApi.cpp b/tests/test_httpApi.cpp index 8694eac6..4cf3ab85 100644 --- a/tests/test_httpApi.cpp +++ b/tests/test_httpApi.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -50,89 +34,89 @@ const char kPort[] = HTTP_FIELD"port"; #define HTTPS_PORT 443 extern const char kSSLPort[] = HTTP_FIELD"sslport"; onceToken token1([](){ - mINI::Instance()[kPort] = HTTP_PORT; - mINI::Instance()[kSSLPort] = HTTPS_PORT; + mINI::Instance()[kPort] = HTTP_PORT; + mINI::Instance()[kSSLPort] = HTTPS_PORT; },nullptr); }//namespace Http } // namespace mediakit void initEventListener(){ - static onceToken s_token([](){ - NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpRequest,[](BroadcastHttpRequestArgs){ - //const Parser &parser,HttpSession::HttpResponseInvoker &invoker,bool &consumed - if(strstr(parser.Url().data(),"/api/") != parser.Url().data()){ - return; - } - //url以"/api/起始,说明是http api" - consumed = true;//该http请求已被消费 + static onceToken s_token([](){ + NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpRequest,[](BroadcastHttpRequestArgs){ + //const Parser &parser,HttpSession::HttpResponseInvoker &invoker,bool &consumed + if(strstr(parser.Url().data(),"/api/") != parser.Url().data()){ + return; + } + //url以"/api/起始,说明是http api" + consumed = true;//该http请求已被消费 - _StrPrinter printer; - ////////////////method//////////////////// - printer << "\r\nmethod:\r\n\t" << parser.Method(); - ////////////////url///////////////// - printer << "\r\nurl:\r\n\t" << parser.Url(); - ////////////////protocol///////////////// - printer << "\r\nprotocol:\r\n\t" << parser.Tail(); - ///////////////args////////////////// - printer << "\r\nargs:\r\n"; - for(auto &pr : parser.getUrlArgs()){ - printer << "\t" << pr.first << " : " << pr.second << "\r\n"; - } - ///////////////header////////////////// - printer << "\r\nheader:\r\n"; - for(auto &pr : parser.getValues()){ - printer << "\t" << pr.first << " : " << pr.second << "\r\n"; - } - ////////////////content///////////////// - printer << "\r\ncontent:\r\n" << parser.Content(); - auto contentOut = printer << endl; + _StrPrinter printer; + ////////////////method//////////////////// + printer << "\r\nmethod:\r\n\t" << parser.Method(); + ////////////////url///////////////// + printer << "\r\nurl:\r\n\t" << parser.Url(); + ////////////////protocol///////////////// + printer << "\r\nprotocol:\r\n\t" << parser.Tail(); + ///////////////args////////////////// + printer << "\r\nargs:\r\n"; + for(auto &pr : parser.getUrlArgs()){ + printer << "\t" << pr.first << " : " << pr.second << "\r\n"; + } + ///////////////header////////////////// + printer << "\r\nheader:\r\n"; + for(auto &pr : parser.getValues()){ + printer << "\t" << pr.first << " : " << pr.second << "\r\n"; + } + ////////////////content///////////////// + printer << "\r\ncontent:\r\n" << parser.Content(); + auto contentOut = printer << endl; - ////////////////我们测算异步回复,当然你也可以同步回复///////////////// - EventPollerPool::Instance().getPoller()->async([invoker,contentOut](){ - HttpSession::KeyValue headerOut; - //你可以自定义header,如果跟默认header重名,则会覆盖之 - //默认header有:Server,Connection,Date,Content-Type,Content-Length - //请勿覆盖Connection、Content-Length键 - //键名覆盖时不区分大小写 - headerOut["TestHeader"] = "HeaderValue"; - invoker("200 OK",headerOut,contentOut); - }); - }); - }, nullptr); + ////////////////我们测算异步回复,当然你也可以同步回复///////////////// + EventPollerPool::Instance().getPoller()->async([invoker,contentOut](){ + HttpSession::KeyValue headerOut; + //你可以自定义header,如果跟默认header重名,则会覆盖之 + //默认header有:Server,Connection,Date,Content-Type,Content-Length + //请勿覆盖Connection、Content-Length键 + //键名覆盖时不区分大小写 + headerOut["TestHeader"] = "HeaderValue"; + invoker("200 OK",headerOut,contentOut); + }); + }); + }, nullptr); } int main(int argc,char *argv[]){ - //设置退出信号处理函数 - static semaphore sem; - signal(SIGINT, [](int) { sem.post(); });// 设置退出信号 + //设置退出信号处理函数 + static semaphore sem; + signal(SIGINT, [](int) { sem.post(); });// 设置退出信号 - //设置日志 - Logger::Instance().add(std::make_shared()); - Logger::Instance().setWriter(std::make_shared()); + //设置日志 + Logger::Instance().add(std::make_shared()); + Logger::Instance().setWriter(std::make_shared()); - //加载配置文件,如果配置文件不存在就创建一个 - loadIniConfig(); - initEventListener(); + //加载配置文件,如果配置文件不存在就创建一个 + loadIniConfig(); + initEventListener(); - //加载证书,证书包含公钥和私钥 - SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data()); - //信任某个自签名证书 - SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data()); - //不忽略无效证书证书(例如自签名或过期证书) - SSL_Initor::Instance().ignoreInvalidCertificate(false); + //加载证书,证书包含公钥和私钥 + SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data()); + //信任某个自签名证书 + SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data()); + //不忽略无效证书证书(例如自签名或过期证书) + SSL_Initor::Instance().ignoreInvalidCertificate(false); - //开启http服务器 - TcpServer::Ptr httpSrv(new TcpServer()); - httpSrv->start(mINI::Instance()[Http::kPort]);//默认80 + //开启http服务器 + TcpServer::Ptr httpSrv(new TcpServer()); + httpSrv->start(mINI::Instance()[Http::kPort]);//默认80 //如果支持ssl,还可以开启https服务器 - TcpServer::Ptr httpsSrv(new TcpServer()); - httpsSrv->start(mINI::Instance()[Http::kSSLPort]);//默认443 + TcpServer::Ptr httpsSrv(new TcpServer()); + httpsSrv->start(mINI::Instance()[Http::kSSLPort]);//默认443 - InfoL << "你可以在浏览器输入:http://127.0.0.1/api/my_api?key0=val0&key1=参数1" << endl; + InfoL << "你可以在浏览器输入:http://127.0.0.1/api/my_api?key0=val0&key1=参数1" << endl; - sem.wait(); - return 0; + sem.wait(); + return 0; } diff --git a/tests/test_httpClient.cpp b/tests/test_httpClient.cpp index 7aaf167d..c4f7d35a 100644 --- a/tests/test_httpClient.cpp +++ b/tests/test_httpClient.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/tests/test_player.cpp b/tests/test_player.cpp index 8fd33159..ed15f8b5 100644 --- a/tests/test_player.cpp +++ b/tests/test_player.cpp @@ -1,28 +1,13 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ + #include #include "Util/util.h" #include "Util/logger.h" diff --git a/tests/test_pusher.cpp b/tests/test_pusher.cpp index d51aeadb..d64c84ad 100644 --- a/tests/test_pusher.cpp +++ b/tests/test_pusher.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -90,7 +74,15 @@ int domain(const string &playUrl, const string &pushUrl) { //拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream" //你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请查看test_rtmpPusherMp4.cpp代码) - PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST, "app", "stream",true,true,false,false,-1 , poller)); + MediaInfo info(pushUrl); + bool enable_rtsp = true; + bool enable_rtmp = true; + if(info._schema == RTSP_SCHEMA){ + enable_rtmp = false; + }else if(info._schema == RTMP_SCHEMA){ + enable_rtsp = false; + } + PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST, "app", "stream",enable_rtsp,enable_rtmp,false,false,-1 , poller)); //可以指定rtsp拉流方式,支持tcp和udp方式,默认tcp // (*player)[Client::kRtpType] = Rtsp::RTP_UDP; player->play(playUrl.data()); diff --git a/tests/test_pusherMp4.cpp b/tests/test_pusherMp4.cpp index 9b94631b..49fcf6fe 100644 --- a/tests/test_pusherMp4.cpp +++ b/tests/test_pusherMp4.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -48,93 +32,93 @@ Timer::Ptr g_timer; //推流失败或断开延迟2秒后重试推流 void rePushDelay(const EventPoller::Ptr &poller, const string &schema, - const string &vhost, - const string &app, - const string &stream, - const string &filePath, - const string &url) ; + const string &vhost, + const string &app, + const string &stream, + const string &filePath, + const string &url) ; //创建推流器并开始推流 void createPusher(const EventPoller::Ptr &poller, const string &schema, - const string &vhost, - const string &app, - const string &stream, - const string &filePath, - const string &url) { - //不限制APP名,并且指定文件绝对路径 - auto src = MP4Reader::onMakeMediaSource(schema,vhost,app,stream,filePath, false); + const string &vhost, + const string &app, + const string &stream, + const string &filePath, + const string &url) { + //不限制APP名,并且指定文件绝对路径 + auto src = MediaSource::createFromMP4(schema,vhost,app,stream,filePath, false); if(!src){ //文件不存在 WarnL << "MP4文件不存在:" << filePath; return; } - //创建推流器并绑定一个MediaSource + //创建推流器并绑定一个MediaSource pusher.reset(new MediaPusher(src,poller)); - //可以指定rtsp推流方式,支持tcp和udp方式,默认tcp + //可以指定rtsp推流方式,支持tcp和udp方式,默认tcp // (*pusher)[Client::kRtpType] = Rtsp::RTP_UDP; - //设置推流中断处理逻辑 - pusher->setOnShutdown([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) { - WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what(); + //设置推流中断处理逻辑 + pusher->setOnShutdown([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) { + WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what(); //重新推流 - rePushDelay(poller,schema,vhost,app, stream,filePath, url); - }); - //设置发布结果处理逻辑 - pusher->setOnPublished([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) { - if (ex) { - WarnL << "Publish fail:" << ex.getErrCode() << " " << ex.what(); - //如果发布失败,就重试 - rePushDelay(poller,schema,vhost,app, stream, filePath ,url); - }else { - InfoL << "Publish success,Please play with player:" << url; - } - }); - pusher->publish(url); + rePushDelay(poller,schema,vhost,app, stream,filePath, url); + }); + //设置发布结果处理逻辑 + pusher->setOnPublished([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) { + if (ex) { + WarnL << "Publish fail:" << ex.getErrCode() << " " << ex.what(); + //如果发布失败,就重试 + rePushDelay(poller,schema,vhost,app, stream, filePath ,url); + }else { + InfoL << "Publish success,Please play with player:" << url; + } + }); + pusher->publish(url); } //推流失败或断开延迟2秒后重试推流 void rePushDelay(const EventPoller::Ptr &poller, const string &schema, - const string &vhost, - const string &app, - const string &stream, - const string &filePath, - const string &url) { - g_timer = std::make_shared(2,[poller,schema,vhost,app, stream, filePath,url]() { - InfoL << "Re-Publishing..."; - //重新推流 - createPusher(poller,schema,vhost,app, stream, filePath,url); - //此任务不重复 - return false; - }, poller); + const string &vhost, + const string &app, + const string &stream, + const string &filePath, + const string &url) { + g_timer = std::make_shared(2,[poller,schema,vhost,app, stream, filePath,url]() { + InfoL << "Re-Publishing..."; + //重新推流 + createPusher(poller,schema,vhost,app, stream, filePath,url); + //此任务不重复 + return false; + }, poller); } //这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了 int domain(const string & filePath,const string & pushUrl){ - //设置日志 - Logger::Instance().add(std::make_shared()); - Logger::Instance().setWriter(std::make_shared()); + //设置日志 + Logger::Instance().add(std::make_shared()); + Logger::Instance().setWriter(std::make_shared()); auto poller = EventPollerPool::Instance().getPoller(); //vhost/app/stream可以随便自己填,现在不限制app应用名了 createPusher(poller,FindField(pushUrl.data(), nullptr,"://"),DEFAULT_VHOST,"live","stream",filePath,pushUrl); - //设置退出信号处理函数 - static semaphore sem; - signal(SIGINT, [](int) { sem.post(); });// 设置退出信号 + //设置退出信号处理函数 + static semaphore sem; + signal(SIGINT, [](int) { sem.post(); });// 设置退出信号 sem.wait(); - pusher.reset(); - g_timer.reset(); - return 0; + pusher.reset(); + g_timer.reset(); + return 0; } int main(int argc,char *argv[]){ //可以使用test_server生成的mp4文件 - //文件使用绝对路径,推流url支持rtsp和rtmp - return domain("/Users/xzl/Desktop/bear-1280x720-long.mp4","rtsp://127.0.0.1/live/rtsp_push"); + //文件使用绝对路径,推流url支持rtsp和rtmp + return domain("/Users/xzl/git/ZLMediaKit/release/mac/Debug/www/record/live/rtsp_test1/2020-04-03/15-32-24.mp4","rtsp://127.0.0.1/live/rtsp_push"); } diff --git a/tests/test_rtp.cpp b/tests/test_rtp.cpp index 8e36a131..9248a24b 100644 --- a/tests/test_rtp.cpp +++ b/tests/test_rtp.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2019 Gemfield + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/tests/test_server.cpp b/tests/test_server.cpp index 02d67a1c..aa4b8780 100644 --- a/tests/test_server.cpp +++ b/tests/test_server.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include @@ -354,9 +338,8 @@ int main(int argc,char *argv[]) { signal(SIGHUP, [](int) { loadIniConfig(); }); sem.wait(); - Recorder::stopAll(); lock_guard lck(s_mtxFlvRecorder); s_mapFlvRecorder.clear(); - return 0; + return 0; } diff --git a/tests/test_wsClient.cpp b/tests/test_wsClient.cpp index a0b025e5..a2d7b07b 100644 --- a/tests/test_wsClient.cpp +++ b/tests/test_wsClient.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include diff --git a/tests/test_wsServer.cpp b/tests/test_wsServer.cpp index 1821467b..48a8a60c 100644 --- a/tests/test_wsServer.cpp +++ b/tests/test_wsServer.cpp @@ -1,27 +1,11 @@ /* - * MIT License - * - * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com> + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. */ #include