Merge branch 'master' of github.com:ZLMediaKit/ZLMediaKit into transcode2

# Conflicts:
#	CMakeLists.txt
#	conf/config.ini
#	src/Common/MediaSink.cpp
#	src/Common/MediaSink.h
#	src/Common/MediaSource.cpp
#	src/Common/MultiMediaSourceMuxer.h
#	src/Common/config.cpp
#	src/Common/config.h
#	src/Extension/AAC.cpp
#	src/Extension/AAC.h
#	src/Rtsp/RtpCodec.h
#	src/Rtsp/RtspMuxer.cpp
#	src/Rtsp/RtspMuxer.h
#	webrtc/Nack.cpp
#	webrtc/WebRtcTransport.cpp
This commit is contained in:
cqm 2024-07-12 09:48:01 +08:00
commit 2ffdfab71e
465 changed files with 18124 additions and 9008 deletions

View File

@ -20,14 +20,14 @@ assignees: ''
* https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
-->
### 现象描述
## 现象描述
<!--
在使用什么功能产生的问题? 其异常表现是什么?
如: 在测试 WebRTC 功能时, 使用 Chrome 浏览器访问 ZLMediait 自带网页播放 FFmpeg 以 RTSP 协议推送的图像有卡顿/花屏.
-->
### 如何复现?
## 如何复现?
<!--
明确的复现步骤对快速解决问题极有帮助.
@ -37,7 +37,7 @@ assignees: ''
1. 期望 ..., 结果 ...
-->
### 相关日志或截图
## 相关日志或截图
<!--
由于日志通长较长, 建议将日志信息填写到下面的 "日志内容..."
@ -50,11 +50,14 @@ assignees: ''
<details>
<summary>展开查看详细日志</summary>
<pre>
日志内容...
```
#详细日志粘在这里!
```
</pre>
</details>
### 配置
## 配置
<!--
部分常见问题是由于配置错误导致的, 建议仔细阅读配置文件中的注释信息
@ -65,11 +68,14 @@ assignees: ''
<details>
<summary>展开查看详细配置</summary>
<pre>
配置内容...
```ini
#config.ini内容粘在这里!
```
</pre>
</details>
### 各种环境信息
## 各种环境信息
<!--
请填写相关环境信息, 详细的环境信息有助于快速复现定位问题.
@ -82,4 +88,8 @@ assignees: ''
* **代码提交记录/git commit hash**:
* **操作系统及版本**:
* **硬件信息**:
* **crash backtrace**:
```
#崩溃信息backtrace粘贴至此
```
* **其他需要补充的信息**:

View File

@ -20,7 +20,7 @@ assignees: ''
* https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
-->
### 相关日志及环境信息
## 相关日志及环境信息
<!--
由于编译日志通长较长, 建议将日志信息填写到下面 `````` block 内,或者上传日志文件
@ -41,7 +41,7 @@ assignees: ''
编译目录下的 `CMakeCache.txt` 文件内容,请直接上传为附件。
### 各种环境信息
## 各种环境信息
<!--
请填写相关环境信息, 详细的环境信息有助于快速复现定位问题.

6
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,6 @@
blank_issues_enabled: false
contact_links:
- name: 技术咨询
url: https://t.zsxq.com/FcVK5
about: 请在知识星球发起技术咨询

View File

@ -7,8 +7,8 @@ assignees: ''
---
**描述该功能的用处,可以提供相关资料描述该功能**
## 描述该功能的用处,可以提供相关资料描述该功能
**该功能是否用于改进项目缺陷,如果是,请描述现有缺陷**
## 该功能是否用于改进项目缺陷,如果是,请描述现有缺陷
**描述你期望实现该功能的方式和最终效果**
## 描述你期望实现该功能的方式和最终效果

View File

@ -1,19 +0,0 @@
---
name: 技术咨询
about: 使用咨询、技术咨询等
title: "[技术咨询] 咨询描述(必填)"
labels: 技术咨询
assignees: ''
---
**咨询的功能模块**
- 请描述您想咨询zlmediakit的哪部分功能
**咨询的具体内容和问题**
- 此处展开您咨询内容的描述
**注意事项**
- 技术咨询前请先认真阅读readme, [wiki](https://github.com/xia-chu/ZLMediaKit/wiki),如有必要您也可以同时搜索已经答复的issue如果没找到答案才在此提issue
- 技术咨询不属于bug缺陷要求用户先star(收藏)本项目否则会直接关闭issue

View File

@ -1,8 +0,0 @@
---
name: issue创建要求
about: 不符合模板要求不便定位问题,可能会被管理员直接关闭
title: ""
labels: ''
assignees: ''
---

View File

@ -23,3 +23,37 @@ jobs:
- name: 编译
run: cd Android && ./gradlew build
- name: 设置环境变量
run: |
echo "BRANCH=$(echo ${GITHUB_REF#refs/heads/} | tr -s "/\?%*:|\"<>" "_")" >> $GITHUB_ENV
echo "BRANCH2=$(echo ${GITHUB_REF#refs/heads/} )" >> $GITHUB_ENV
echo "DATE=$(date +%Y-%m-%d)" >> $GITHUB_ENV
- name: 打包二进制
id: upload
uses: actions/upload-artifact@v4
with:
name: ${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}
path: Android/app/build/outputs/apk/debug/*
if-no-files-found: error
retention-days: 90
- name: issue评论
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/feature/test'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: 483,
owner: context.repo.owner,
repo: context.repo.repo,
body: '- 下载地址: [${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}](${{ steps.upload.outputs.artifact-url }})\n'
+ '- 分支: ${{ env.BRANCH2 }}\n'
+ '- git hash: ${{ github.sha }} \n'
+ '- 编译日期: ${{ env.DATE }}\n'
+ '- 编译记录: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n'
+ '- 开启特性: 未开启openssl/webrtc/datachannel等功能\n'
+ '- 打包ci名: ${{ github.workflow }}\n'
})

View File

@ -7,12 +7,6 @@ on:
- "feature/*"
- "release/*"
pull_request:
branches:
- "master"
- "feature/*"
- "release/*"
env:
# Use docker.io for Docker Hub if empty
REGISTRY: docker.io
@ -21,7 +15,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
permissions:
contents: read
packages: write
@ -39,10 +33,7 @@ jobs:
# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@d6a3abf1bdea83574e28d40543793018b6035605
with:
cosign-release: 'v1.7.1'
uses: sigstore/cosign-installer@d572c9c13673d2e0a26fabf90b5748f36886883f
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
@ -55,7 +46,6 @@ jobs:
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
registry: ${{ env.REGISTRY }}
@ -73,6 +63,7 @@ jobs:
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/feature/test'
id: build-and-push
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
with:

51
.github/workflows/issue_lint.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: issue_lint
on:
issues:
types: [opened]
jobs:
issue_lint:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs').promises;
const getTitles = (str) => (
[...str.matchAll(/^## (.*)/gm)].map((m) => m[0])
);
const titles = getTitles(context.payload.issue.body);
for (let file of await fs.readdir('.github/ISSUE_TEMPLATE')) {
if (!file.endsWith('.md')) {
continue;
}
const template = await fs.readFile(`.github/ISSUE_TEMPLATE/${file}`, 'utf-8');
const templateTitles = getTitles(template);
if (templateTitles.every((title) => titles.includes(title))) {
process.exit(0);
}
}
await github.rest.issues.createComment({
owner: context.issue.owner,
repo: context.issue.repo,
issue_number: context.issue.number,
body: '此issue由于不符合模板规范已经自动关闭请重新按照模板规范确保包含模板中所有章节标题再提交\n',
});
await github.rest.issues.update({
owner: context.issue.owner,
repo: context.issue.repo,
issue_number: context.issue.number,
state: 'closed',
});

View File

@ -13,9 +13,6 @@ jobs:
- name: 下载submodule源码
run: mv -f .gitmodules_github .gitmodules && git submodule sync && git submodule update --init
- name: apt-get安装依赖库(非必选)
run: sudo apt-get update && sudo apt-get install -y cmake libssl-dev libsdl-dev libavcodec-dev libavutil-dev libswscale-dev libresample-dev libusrsctp-dev
- name: 下载 SRTP
uses: actions/checkout@v2
with:
@ -24,13 +21,115 @@ jobs:
ref: v2.3.0
path: 3rdpart/libsrtp
- name: 编译 SRTP
run: cd 3rdpart/libsrtp && ./configure --enable-openssl && make -j4 && sudo make install
- name: 下载 openssl
uses: actions/checkout@v2
with:
repository: openssl/openssl
fetch-depth: 1
ref: OpenSSL_1_1_1
path: 3rdpart/openssl
- name: 编译
run: mkdir -p linux_build && cd linux_build && cmake .. -DENABLE_WEBRTC=true -DENABLE_FFMPEG=true && make -j $(nproc)
- name: 下载 usrsctp
uses: actions/checkout@v2
with:
repository: sctplab/usrsctp
fetch-depth: 1
ref: 0.9.5.0
path: 3rdpart/usrsctp
- name: 运行MediaServer
run: pwd && cd release/linux/Debug && sudo ./MediaServer -d &
- name: 启动 Docker 容器, 在Docker 容器中执行脚本
run: |
docker pull centos:7
docker run -v $(pwd):/root -w /root --rm centos:7 sh -c "
#!/bin/bash
set -x
# Backup original CentOS-Base.repo file
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
# Define new repository configuration
cat <<EOF > /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-7 - Base - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/7/os/x86_64/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
[updates]
name=CentOS-7 - Updates - mirrors.aliyun.com
baseurl=http://mirrors.aliyun.com/centos/7/updates/x86_64/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
EOF
# Clean yum cache and recreate it
yum clean all
yum makecache
echo \"CentOS 7 软件源已成功切换\"
yum install -y git wget gcc gcc-c++ make
mkdir -p /root/install
cd 3rdpart/openssl
./config no-shared --prefix=/root/install
make -j $(nproc)
make install
cd ../../
wget https://github.com/Kitware/CMake/releases/download/v3.29.5/cmake-3.29.5.tar.gz
tar -xf cmake-3.29.5.tar.gz
cd cmake-3.29.5
OPENSSL_ROOT_DIR=/root/install ./configure
make -j $(nproc)
make install
cd ..
cd 3rdpart/usrsctp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON ..
make -j $(nproc)
make install
cd ../../../
cd 3rdpart/libsrtp && ./configure --enable-openssl --with-openssl-dir=/root/install && make -j $(nproc) && make install
cd ../../
mkdir -p linux_build && cd linux_build && cmake .. -DOPENSSL_ROOT_DIR=/root/install -DCMAKE_BUILD_TYPE=Release && make -j $(nproc)
"
- name: 设置环境变量
run: |
echo "BRANCH=$(echo ${GITHUB_REF#refs/heads/} | tr -s "/\?%*:|\"<>" "_")" >> $GITHUB_ENV
echo "BRANCH2=$(echo ${GITHUB_REF#refs/heads/} )" >> $GITHUB_ENV
echo "DATE=$(date +%Y-%m-%d)" >> $GITHUB_ENV
- name: 打包二进制
id: upload
uses: actions/upload-artifact@v4
with:
name: ${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}
path: release/*
if-no-files-found: error
retention-days: 90
- name: issue评论
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/feature/test'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: 483,
owner: context.repo.owner,
repo: context.repo.repo,
body: '- 下载地址: [${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}](${{ steps.upload.outputs.artifact-url }})\n'
+ '- 分支: ${{ env.BRANCH2 }}\n'
+ '- git hash: ${{ github.sha }} \n'
+ '- 编译日期: ${{ env.DATE }}\n'
+ '- 编译记录: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n'
+ '- 打包ci名: ${{ github.workflow }}\n'
+ '- 开启特性: openssl/webrtc/datachannel\n'
+ '- 说明: 本二进制在centos7(x64)上编译,请确保您的机器系统不低于此版本\n'
})

View File

@ -13,27 +13,54 @@ jobs:
- name: 下载submodule源码
run: mv -f .gitmodules_github .gitmodules && git submodule sync && git submodule update --init
# - name: 安装brew
# run: ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
#
# - name: brew安装依赖库(非必选)
# run: brew update && brew install cmake openssl sdl2 ffmpeg
# - name: 下载 SRTP
# uses: actions/checkout@v2
# with:
# repository: cisco/libsrtp
# fetch-depth: 1
# ref: v2.3.0
# path: 3rdpart/libsrtp
#
# - name: 编译 SRTP
# run: cd 3rdpart/libsrtp && ./configure --enable-openssl && make -j4 && sudo make install
- name: 配置 vcpkg
uses: lukka/run-vcpkg@v7
with:
vcpkgDirectory: '${{github.workspace}}/vcpkg'
vcpkgTriplet: arm64-osx
# 2024.06.01
vcpkgGitCommitId: '47364fbc300756f64f7876b549d9422d5f3ec0d3'
vcpkgArguments: 'openssl libsrtp[openssl] usrsctp'
- name: 编译
run: mkdir -p build && cd build && cmake .. && make -j $(nproc)
uses: lukka/run-cmake@v3
with:
useVcpkgToolchainFile: true
buildDirectory: '${{github.workspace}}/build'
cmakeAppendedArgs: ''
cmakeBuildType: 'Release'
- name: 运行MediaServer
run: pwd && cd release/darwin/Debug && sudo ./MediaServer -d &
- name: 设置环境变量
run: |
echo "BRANCH=$(echo ${GITHUB_REF#refs/heads/} | tr -s "/\?%*:|\"<>" "_")" >> $GITHUB_ENV
echo "BRANCH2=$(echo ${GITHUB_REF#refs/heads/} )" >> $GITHUB_ENV
echo "DATE=$(date +%Y-%m-%d)" >> $GITHUB_ENV
- name: 打包二进制
id: upload
uses: actions/upload-artifact@v4
with:
name: ${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}
path: release/*
if-no-files-found: error
retention-days: 90
- name: issue评论
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/feature/test'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: 483,
owner: context.repo.owner,
repo: context.repo.repo,
body: '- 下载地址: [${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}](${{ steps.upload.outputs.artifact-url }})\n'
+ '- 分支: ${{ env.BRANCH2 }}\n'
+ '- git hash: ${{ github.sha }} \n'
+ '- 编译日期: ${{ env.DATE }}\n'
+ '- 编译记录: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n'
+ '- 打包ci名: ${{ github.workflow }}\n'
+ '- 开启特性: openssl/webrtc/datachannel\n'
+ '- 说明: 此二进制为arm64版本\n'
})

View File

@ -4,7 +4,7 @@ on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:

View File

@ -17,14 +17,52 @@ jobs:
with:
vcpkgDirectory: '${{github.workspace}}/vcpkg'
vcpkgTriplet: x64-windows-static
# 2021.05.12
vcpkgGitCommitId: '5568f110b509a9fd90711978a7cb76bae75bb092'
vcpkgArguments: 'openssl libsrtp'
# 2024.06.01
vcpkgGitCommitId: '47364fbc300756f64f7876b549d9422d5f3ec0d3'
vcpkgArguments: 'openssl libsrtp[openssl] usrsctp'
- name: 编译
uses: lukka/run-cmake@v3
with:
useVcpkgToolchainFile: true
buildDirectory: '${{github.workspace}}/build'
cmakeAppendedArgs: '-DCMAKE_ENABLE_WEBRTC:BOOL=ON'
cmakeBuildType: 'RelWithDebInfo'
cmakeAppendedArgs: ''
cmakeBuildType: 'Release'
- name: 设置环境变量
run: |
$dateString = Get-Date -Format "yyyy-MM-dd"
$branch = $env:GITHUB_REF -replace "refs/heads/", "" -replace "[\\/\\\?\%\*:\|\x22<>]", "_"
$branch2 = $env:GITHUB_REF -replace "refs/heads/", ""
echo "BRANCH=$branch" >> $env:GITHUB_ENV
echo "BRANCH2=$branch2" >> $env:GITHUB_ENV
echo "DATE=$dateString" >> $env:GITHUB_ENV
- name: 打包二进制
id: upload
uses: actions/upload-artifact@v4
with:
name: ${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}
path: release/*
if-no-files-found: error
retention-days: 90
- name: issue评论
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/feature/test'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: 483,
owner: context.repo.owner,
repo: context.repo.repo,
body: '- 下载地址: [${{ github.workflow }}_${{ env.BRANCH }}_${{ env.DATE }}](${{ steps.upload.outputs.artifact-url }})\n'
+ '- 分支: ${{ env.BRANCH2 }}\n'
+ '- git hash: ${{ github.sha }} \n'
+ '- 编译日期: ${{ env.DATE }}\n'
+ '- 编译记录: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n'
+ '- 打包ci名: ${{ github.workflow }}\n'
+ '- 开启特性: openssl/webrtc/datachannel\n'
+ '- 说明: 此二进制为x64版本\n'
})

3
.gitmodules vendored
View File

@ -7,3 +7,6 @@
[submodule "3rdpart/jsoncpp"]
path = 3rdpart/jsoncpp
url = https://gitee.com/mirrors/jsoncpp.git
[submodule "www/webassist"]
path = www/webassist
url = https://gitee.com/victor1002/zlm_webassist

View File

@ -7,3 +7,6 @@
[submodule "3rdpart/jsoncpp"]
path = 3rdpart/jsoncpp
url = https://github.com/open-source-parsers/jsoncpp.git
[submodule "www/webassist"]
path = www/webassist
url = https://github.com/1002victor/zlm_webassist

View File

@ -47,7 +47,7 @@ set(MediaServer_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/media-server")
# TODO:
# movflv MP4
if (ENABLE_MP4 OR ENABLE_HLS_FMP4)
if (ENABLE_MP4)
# MOV
set(MediaServer_MOV_ROOT ${MediaServer_ROOT}/libmov)
aux_source_directory(${MediaServer_MOV_ROOT}/include MOV_SRC_LIST)
@ -80,10 +80,6 @@ if (ENABLE_MP4 OR ENABLE_HLS_FMP4)
message(STATUS "ENABLE_MP4 defined")
update_cached_list(MK_COMPILE_DEFINITIONS ENABLE_MP4)
endif ()
if (ENABLE_HLS_FMP4)
message(STATUS "ENABLE_HLS_FMP4 defined")
update_cached_list(MK_COMPILE_DEFINITIONS ENABLE_HLS_FMP4)
endif ()
endif ()
# mpeg ts
@ -151,6 +147,17 @@ if(HAVE_RECVMMSG_API)
list(APPEND COMPILE_DEFINITIONS HAVE_RECVMMSG_API)
endif()
# check the socket buffer size set by the upper cmake project, if it is set, use the setting of the upper cmake project, otherwise set it to 256K
# if the socket buffer size is set to 0, it means that the socket buffer size is not set, and the kernel default value is used(just for linux)
if(DEFINED SOCKET_DEFAULT_BUF_SIZE)
if (SOCKET_DEFAULT_BUF_SIZE EQUAL 0)
message(STATUS "Socket default buffer size is not set, use the kernel default value")
else()
message(STATUS "Socket default buffer size is set to ${SOCKET_DEFAULT_BUF_SIZE}")
endif ()
add_definitions(-DSOCKET_DEFAULT_BUF_SIZE=${SOCKET_DEFAULT_BUF_SIZE})
endif()
set(ToolKit_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/ZLToolKit)
#
file(GLOB ToolKit_SRC_LIST

@ -1 +1 @@
Subproject commit a4b8b5e00aac6251254a513c7759605c0ba35f90
Subproject commit fb695d203421d906c473018022a736fa4a7a47e4

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -13,22 +13,18 @@
#include <stdio.h>
#ifndef NDEBUG
#ifdef assert
#ifdef assert
#undef assert
#endif//assert
#endif//assert
#ifdef __cplusplus
extern "C" {
#endif
extern void Assert_Throw(int failed, const char *exp, const char *func, const char *file, int line, const char *str);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern void Assert_Throw(int failed, const char *exp, const char *func, const char *file, int line, const char *str);
#ifdef __cplusplus
}
#endif
#define assert(exp) Assert_Throw(!(exp), #exp, __FUNCTION__, __FILE__, __LINE__, NULL)
#else
#define assert(e) ((void)0)
#endif//NDEBUG
#define assert(exp) Assert_Throw(!(exp), #exp, __FUNCTION__, __FILE__, __LINE__, NULL)
#endif //ZLMEDIAKIT_ASSERT_H

@ -1 +1 @@
Subproject commit 8190e061bc2d95da37479a638aa2c9e483e58ec6
Subproject commit 69098a18b9af0c47549d9a271c054d13ca92b006

@ -1 +1 @@
Subproject commit cdbb3d6b9ea254f454c6e466c5962af5ace01199
Subproject commit cf83ebc62e65ae6f3b73bc5ebd06cb0b2da49fa5

27
AUTHORS
View File

@ -44,7 +44,6 @@ Xinghua Zhao <(holychaossword@hotmail.com>
[Dw9](https://github.com/Dw9)
明月惊鹊 <mingyuejingque@gmail.com>
cgm <2958580318@qq.com>
hejilin <1724010622@qq.com>
alexliyu7352 <liyu7352@gmail.com>
cgm <2958580318@qq.com>
[haorui wang](https://github.com/HaoruiWang)
@ -83,3 +82,29 @@ WuPeng <wp@zafu.edu.cn>
[tbago](https://github.com/tbago)
[Luosh](https://github.com/Luosh)
[linxiaoyan87](https://github.com/linxiaoyan)
[waken](https://github.com/mc373906408)
[Deepslient](https://github.com/Deepslient)
[imp_rayjay](https://github.com/rayjay214)
[ArmstrongCN](https://github.com/ArmstrongCN)
[leibnewton](https://github.com/leibnewton)
[Grin](https://github.com/xyyangkun)
[xbpeng121](https://github.com/xbpeng121)
[lvchenyun](https://github.com/lvchenyun)
[Fummowo](https://github.com/Fummowo)
[Jovial Young ](https://github.com/JHYoung1034)
[yujitai](https://github.com/yujitai)
[KisChang](https://github.com/kisChang)
[zjx94](https://github.com/zjx94)
[LeiZhi.Mai ](https://github.com/blueskiner)
[JiaHao](https://github.com/nashiracn)
[chdahuzi](https://github.com/chdahuzi)
[snysmtx](https://github.com/snysmtx)
[SetoKaiba](https://github.com/SetoKaiba)
[sandro-qiang](https://github.com/sandro-qiang)
[Paul Philippov](https://github.com/themactep)
[张传峰](https://github.com/zhang-chuanfeng)
[lidaofu-hub](https://github.com/lidaofu-hub)
[huangcaichun](https://github.com/huangcaichun)
[jamesZHANG500](https://github.com/jamesZHANG500)
[weidelong](https://github.com/wdl1697454803)
[小强先生](https://github.com/linshangqiang)

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -24,11 +24,13 @@
cmake_minimum_required(VERSION 3.1.3)
#
# Load custom modules
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
project(ZLMediaKit LANGUAGES C CXX)
# 使 C++11
# Enable C++11
set(CMAKE_CXX_STANDARD 11)
option(ENABLE_API "Enable C API SDK" ON)
@ -39,9 +41,9 @@ option(ENABLE_FAAC "Enable FAAC" OFF)
option(ENABLE_FFMPEG "Enable FFmpeg" OFF)
option(ENABLE_HLS "Enable HLS" ON)
option(ENABLE_JEMALLOC_STATIC "Enable static linking to the jemalloc library" OFF)
option(ENABLE_JEMALLOC_DUMP "Enable jemalloc to dump malloc statistics" OFF)
option(ENABLE_MEM_DEBUG "Enable Memory Debug" OFF)
option(ENABLE_MP4 "Enable MP4" ON)
option(ENABLE_HLS_FMP4 "Enable HLS-FMP4" ON)
option(ENABLE_MSVC_MT "Enable MSVC Mt/Mtd lib" ON)
option(ENABLE_MYSQL "Enable MySQL" OFF)
option(ENABLE_OPENSSL "Enable OpenSSL" ON)
@ -55,10 +57,14 @@ option(ENABLE_SCTP "Enable SCTP" ON)
option(ENABLE_WEBRTC "Enable WebRTC" ON)
option(ENABLE_X264 "Enable x264" OFF)
option(ENABLE_WEPOLL "Enable wepoll" ON)
option(DISABLE_REPORT "Disable report to report.zlmediakit.com" off)
option(ENABLE_VIDEOSTACK "Enable video stack" OFF)
option(DISABLE_REPORT "Disable report to report.zlmediakit.com" OFF)
option(USE_SOLUTION_FOLDERS "Enable solution dir supported" ON)
##############################################################################
# socket256k.0socket,使用系统内核默认值(设置为0仅对linux有效)
# Set the default buffer size of the socket to 256k. If set to 0, the default buffer size of the socket will not be set,
# and the system kernel default value will be used (setting to 0 is only valid for linux)
set(SOCKET_DEFAULT_BUF_SIZE 262144 CACHE STRING "Default buffer size for socket" FORCE)
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "Debug")
@ -67,12 +73,14 @@ endif()
message(STATUS "编译类型: ${CMAKE_BUILD_TYPE}")
# 便, FORCE CACHE,
# To facilitate the troubleshooting of compilation problems, you need to FORCE CACHE, otherwise you need to set it on the command line to take effect
set(CMAKE_VERBOSE_MAKEFILE ON CACHE INTERNAL "" FORCE)
# TODO: include server ,
set(CMAKE_INCLUDE_CURRENT_DIR OFF)
#
# Install path
if(NOT CMAKE_INSTALL_PREFIX)
if(UNIX)
set(INSTALL_PATH_LIB lib${LIB_SUFFIX})
@ -80,6 +88,7 @@ if(NOT CMAKE_INSTALL_PREFIX)
set(INSTALL_PATH_RUNTIME bin)
elseif(WIN32)
# Windows ?
# Install to the user's home directory under Windows?
set(INSTALL_PATH_LIB $ENV{HOME}/${CMAKE_PROJECT_NAME}/lib)
set(INSTALL_PATH_INCLUDE $ENV{HOME}/${CMAKE_PROJECT_NAME}/include)
else()
@ -94,11 +103,14 @@ endif()
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME_LOWER)
# , bin, lib
# Windows 32/64
# Set the output directory, including bin, lib and other files
# Windows no longer distinguishes 32/64
set(OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/release/${SYSTEM_NAME_LOWER}/${CMAKE_BUILD_TYPE})
set(LIBRARY_OUTPUT_PATH ${OUTPUT_DIR})
set(EXECUTABLE_OUTPUT_PATH ${OUTPUT_DIR})
# git
# Add git version information
set(COMMIT_HASH "Git_Unkown_commit")
set(COMMIT_TIME "Git_Unkown_time")
set(BRANCH_NAME "Git_Unkown_branch")
@ -130,8 +142,8 @@ if(GIT_FOUND)
endif()
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.h.ini
${CMAKE_CURRENT_BINARY_DIR}/version.h
${CMAKE_CURRENT_SOURCE_DIR}/ZLMVersion.h.ini
${CMAKE_CURRENT_BINARY_DIR}/ZLMVersion.h
@ONLY)
message(STATUS "Git version is ${BRANCH_NAME} ${COMMIT_HASH}/${COMMIT_TIME} ${BUILD_TIME}")
@ -139,6 +151,7 @@ message(STATUS "Git version is ${BRANCH_NAME} ${COMMIT_HASH}/${COMMIT_TIME} ${BU
##############################################################################
# 便
# Convenient to modify global variables
function(update_cached name value)
set("${name}" "${value}" CACHE INTERNAL "*** Internal ***" FORCE)
endfunction()
@ -179,13 +192,19 @@ if(UNIX)
set(COMPILE_OPTIONS_DEFAULT
"-fPIC"
"-Wall;-Wextra"
"-Wno-unused-function;-Wno-unused-parameter;-Wno-unused-variable"
"-Wno-unused-function;-Wno-unused-parameter;-Wno-unused-variable;-Wno-deprecated-declarations"
"-Wno-error=extra;-Wno-error=missing-field-initializers;-Wno-error=type-limits")
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(COMPILE_OPTIONS_DEFAULT ${COMPILE_OPTIONS_DEFAULT} "-g3")
else()
set(COMPILE_OPTIONS_DEFAULT ${COMPILE_OPTIONS_DEFAULT} "-g0")
endif()
elseif(WIN32)
if (MSVC)
set(COMPILE_OPTIONS_DEFAULT
# TODO: /wd4819
"/wd4566;/wd4819"
"/wd4566;/wd4819;/utf-8"
# warning C4530: C++ exception handler used, but unwind semantics are not enabled.
"/EHsc")
# disable Windows logo
@ -201,6 +220,7 @@ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
endif()
# mediakit runtime
# mediakit and various runtime dependencies
update_cached(MK_LINK_LIBRARIES "")
update_cached(MK_COMPILE_DEFINITIONS ENABLE_VERSION)
@ -225,9 +245,11 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
endif()
# ffmpeg ,
# Multiple modules depend on ffmpeg related libraries, unified search
if(ENABLE_FFMPEG)
find_package(PkgConfig QUIET)
# ffmpeg/libutil
# find ffmpeg/libutil installed
if(PKG_CONFIG_FOUND)
pkg_check_modules(AVUTIL QUIET IMPORTED_TARGET libavutil)
if(AVUTIL_FOUND)
@ -237,6 +259,7 @@ if(ENABLE_FFMPEG)
endif()
# ffmpeg/libavcodec
# find ffmpeg/libavcodec installed
if(PKG_CONFIG_FOUND)
pkg_check_modules(AVCODEC QUIET IMPORTED_TARGET libavcodec)
if(AVCODEC_FOUND)
@ -246,6 +269,7 @@ if(ENABLE_FFMPEG)
endif()
# ffmpeg/libswscale
# find ffmpeg/libswscale installed
if(PKG_CONFIG_FOUND)
pkg_check_modules(SWSCALE QUIET IMPORTED_TARGET libswscale)
if(SWSCALE_FOUND)
@ -255,6 +279,7 @@ if(ENABLE_FFMPEG)
endif()
# ffmpeg/libswresample
# find ffmpeg/libswresample installed
if(PKG_CONFIG_FOUND)
pkg_check_modules(SWRESAMPLE QUIET IMPORTED_TARGET libswresample)
if(SWRESAMPLE_FOUND)
@ -264,6 +289,7 @@ if(ENABLE_FFMPEG)
endif()
# ffmpeg/libutil
# find ffmpeg/libutil installed
if(NOT AVUTIL_FOUND)
find_package(AVUTIL QUIET)
if(AVUTIL_FOUND)
@ -274,6 +300,7 @@ if(ENABLE_FFMPEG)
endif ()
# ffmpeg/libavcodec
# find ffmpeg/libavcodec installed
if(NOT AVCODEC_FOUND)
find_package(AVCODEC QUIET)
if(AVCODEC_FOUND)
@ -284,6 +311,7 @@ if(ENABLE_FFMPEG)
endif()
# ffmpeg/libswscale
# find ffmpeg/libswscale installed
if(NOT SWSCALE_FOUND)
find_package(SWSCALE QUIET)
if(SWSCALE_FOUND)
@ -294,6 +322,7 @@ if(ENABLE_FFMPEG)
endif()
# ffmpeg/libswresample
# find ffmpeg/libswresample installed
if(NOT SWRESAMPLE_FOUND)
find_package(SWRESAMPLE QUIET)
if(SWRESAMPLE_FOUND)
@ -308,7 +337,7 @@ if(ENABLE_FFMPEG)
update_cached_list(MK_LINK_LIBRARIES ${CMAKE_DL_LIBS})
else()
set(ENABLE_FFMPEG OFF)
message(WARNING "ffmpeg 相关功能未找到")
message(WARNING "ffmpeg related functions not found")
endif()
endif()
@ -316,7 +345,7 @@ if(ENABLE_MEM_DEBUG)
update_cached_list(MK_LINK_LIBRARIES
"-Wl,-wrap,free;-Wl,-wrap,malloc;-Wl,-wrap,realloc;-Wl,-wrap,calloc")
update_cached_list(MK_COMPILE_DEFINITIONS ENABLE_MEM_DEBUG)
message(STATUS "已启用内存调试功能")
message(STATUS "Memory debugging enabled")
endif()
if(ENABLE_ASAN)
@ -326,32 +355,46 @@ if(ENABLE_ASAN)
# > In order to use AddressSanitizer you will need to
# > compile and link your program using clang with the -fsanitize=address switch.
update_cached_list(MK_LINK_LIBRARIES "-fsanitize=address")
message(STATUS "已启用 Address Sanitize")
message(STATUS "Address Sanitize enabled")
endif()
# TODO: jemalloc ?
# jemalloc
# Static compilation after downloading jemalloc
set(DEP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rdpart/external-${CMAKE_SYSTEM_NAME})
if(ENABLE_JEMALLOC_STATIC)
if(NOT EXISTS ${DEP_ROOT_DIR})
file(MAKE_DIRECTORY ${DEP_ROOT_DIR})
endif()
if (ENABLE_JEMALLOC_DUMP)
set(ENABLE_JEMALLOC_STAT ON)
else ()
set(ENABLE_JEMALLOC_STAT OFF)
endif ()
include(Jemalloc)
include_directories(SYSTEM ${DEP_ROOT_DIR}/${JEMALLOC_NAME}/include/jemalloc)
include_directories(SYSTEM ${DEP_ROOT_DIR}/${JEMALLOC_NAME}/include)
link_directories(${DEP_ROOT_DIR}/${JEMALLOC_NAME}/lib)
#
# Used to affect subsequent lookup process
set(JEMALLOC_ROOT_DIR "${DEP_ROOT_DIR}/${JEMALLOC_NAME}")
endif()
# jemalloc
# Link the jemalloc library by default to avoid memory fragmentation
find_package(JEMALLOC QUIET)
if(JEMALLOC_FOUND)
message(STATUS "found library: ${JEMALLOC_LIBRARIES}")
include_directories(${JEMALLOC_INCLUDE_DIR})
update_cached_list(MK_LINK_LIBRARIES ${JEMALLOC_LIBRARIES})
add_definitions(-DUSE_JEMALLOC)
message(STATUS "jemalloc will be used to avoid memory fragmentation")
if (ENABLE_JEMALLOC_DUMP)
add_definitions(-DENABLE_JEMALLOC_DUMP)
message(STATUS "jemalloc will save memory usage statistics when the program exits")
endif ()
endif()
# openssl
# find openssl installed
find_package(OpenSSL QUIET)
if(OPENSSL_FOUND AND ENABLE_OPENSSL)
message(STATUS "found library: ${OPENSSL_LIBRARIES}, ENABLE_OPENSSL defined")
@ -360,6 +403,8 @@ if(OPENSSL_FOUND AND ENABLE_OPENSSL)
update_cached_list(MK_LINK_LIBRARIES ${OPENSSL_LIBRARIES})
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND OPENSSL_USE_STATIC_LIBS)
update_cached_list(MK_LINK_LIBRARIES ${CMAKE_DL_LIBS})
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows" AND OPENSSL_USE_STATIC_LIBS)
update_cached_list(MK_LINK_LIBRARIES Crypt32)
endif()
else()
set(ENABLE_OPENSSL OFF)
@ -368,6 +413,7 @@ else()
endif()
# mysql
# find mysql installed
find_package(MYSQL QUIET)
if(MYSQL_FOUND AND ENABLE_MYSQL)
message(STATUS "found library: ${MYSQL_LIBRARIES}, ENABLE_MYSQL defined")
@ -380,6 +426,7 @@ if(MYSQL_FOUND AND ENABLE_MYSQL)
endif()
# x264
# find x264 installed
find_package(X264 QUIET)
if(X264_FOUND AND ENABLE_X264)
message(STATUS "found library: ${X264_LIBRARIES}, ENABLE_X264 defined")
@ -390,6 +437,7 @@ if(X264_FOUND AND ENABLE_X264)
endif()
# faac
# find faac installed
find_package(FAAC QUIET)
if(FAAC_FOUND AND ENABLE_FAAC)
message(STATUS "found library:${FAAC_LIBRARIES}, ENABLE_FAAC defined")
@ -400,10 +448,21 @@ endif()
if(WIN32)
update_cached_list(MK_LINK_LIBRARIES WS2_32 Iphlpapi shlwapi)
elseif(ANDROID)
update_cached_list(MK_LINK_LIBRARIES log)
elseif(NOT ANDROID OR IOS)
update_cached_list(MK_LINK_LIBRARIES pthread)
endif()
if(ENABLE_VIDEOSTACK)
if(ENABLE_FFMPEG AND ENABLE_X264)
message(STATUS "ENABLE_VIDEOSTACK defined")
update_cached_list(MK_COMPILE_DEFINITIONS ENABLE_VIDEOSTACK)
else()
message(WARNING "ENABLE_VIDEOSTACK requires ENABLE_FFMPEG and ENABLE_X264")
endif ()
endif ()
# ----------------------------------------------------------------------------
# Solution folders:
# ----------------------------------------------------------------------------
@ -436,6 +495,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdpart)
add_subdirectory(3rdpart)
add_subdirectory(ext-codec)
if(ENABLE_SRT)
add_subdirectory(srt)
endif()
@ -457,26 +518,37 @@ if(ENABLE_PLAYER AND ENABLE_FFMPEG)
endif()
#MediaServer
#MediaServer main program
if(ENABLE_SERVER)
add_subdirectory(server)
endif()
# Android add_subdirectory
# Android will add_subdirectory and depend on this variable
if(ENABLE_SERVER_LIB AND NOT CMAKE_PARENT_LIST_FILE STREQUAL CMAKE_CURRENT_LIST_FILE)
set(MK_LINK_LIBRARIES ${MK_LINK_LIBRARIES} PARENT_SCOPE)
endif()
# IOS
# IOS does not compile executable programs
if(IOS)
return()
endif()
#cppdemo
#cpp test demo program
if (ENABLE_TESTS)
add_subdirectory(tests)
endif ()
# www
# Copy www folder, configuration file, default certificate
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/www" DESTINATION ${EXECUTABLE_OUTPUT_PATH})
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf/config.ini" DESTINATION ${EXECUTABLE_OUTPUT_PATH})
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/default.pem" DESTINATION ${EXECUTABLE_OUTPUT_PATH})
# VideoStack
# Copy the default background image used by VideoStack when there is no video stream
if (ENABLE_VIDEOSTACK AND ENABLE_FFMPEG AND ENABLE_X264)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf/novideo.yuv" DESTINATION ${EXECUTABLE_OUTPUT_PATH})
endif ()

10
LICENSE
View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
Copyright (c) 2016-present 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
@ -19,3 +19,11 @@ 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.
----------------------------------------------------------------------------------------
补充协议:
本项目采用类MIT协议用户在履行MIT协议义务的同时应当同时遵循保留ZLMediaKit软件版权信息的义务。
用户不得去除ZLMediaKit提供的各种服务中包括但不限于 "title"、"Server"、"User-Agent" 等字段中 "ZLMediaKit" 的信息。
否则本项目主要权利人(项目发起人、主要作者)保留声索起诉的权利。

View File

@ -36,6 +36,7 @@
- 极致体验,[独家特性](https://github.com/ZLMediaKit/ZLMediaKit/wiki/ZLMediakit%E7%8B%AC%E5%AE%B6%E7%89%B9%E6%80%A7%E4%BB%8B%E7%BB%8D)
- [谁在使用zlmediakit?](https://github.com/ZLMediaKit/ZLMediaKit/issues/511)
- 全面支持ipv6网络
- 支持多轨道模式(一个流中多个视频/音频)
## 项目定位
@ -76,16 +77,19 @@
- 通过cookie追踪技术可以模拟HLS播放为长连接可以实现HLS按需拉流、播放统计等业务
- 支持HLS播发器支持拉流HLS转rtsp/rtmp/mp4
- 支持H264/H265/AAC/G711/OPUS编码
- 支持多轨道模式
- TS
- 支持http[s]-ts直播
- 支持ws[s]-ts直播
- 支持H264/H265/AAC/G711/OPUS编码
- 支持多轨道模式
- fMP4
- 支持http[s]-fmp4直播
- 支持ws[s]-fmp4直播
- 支持H264/H265/AAC/G711/OPUS/MJPEG编码
- 支持多轨道模式
- HTTP[S]与WebSocket
- 服务器支持`目录索引生成`,`文件下载`,`表单提交请求`
@ -104,11 +108,13 @@
- 支持es/ps rtp转推
- 支持GB28181主动拉流模式
- 支持双向语音对讲
- 支持多轨道模式
- MP4点播与录制
- 支持录制为FLV/HLS/MP4
- RTSP/RTMP/HTTP-FLV/WS-FLV支持MP4文件点播支持seek
- 支持H264/H265/AAC/G711/OPUS编码
- 支持多轨道模式
- WebRTC
- 支持WebRTC推流支持转其他协议
@ -153,12 +159,15 @@
- 2、作为独立的流媒体服务器使用不想做c/c++开发的,可以参考 [restful api](https://github.com/ZLMediaKit/ZLMediaKit/wiki/MediaServer支持的HTTP-API) 和 [web hook](https://github.com/ZLMediaKit/ZLMediaKit/wiki/MediaServer支持的HTTP-HOOK-API ).
- 3、如果想做c/c++开发,添加业务逻辑增加功能,可以参考这里的[测试程序](https://github.com/ZLMediaKit/ZLMediaKit/tree/master/tests).
## 二进制文件下载
zlmediakit采用 github action 持续集成自动编译打包上传编译产出包,请在[issue列表](https://github.com/ZLMediaKit/ZLMediaKit/issues/483)下载最新sdk库文件以及可执行文件。
## Docker 镜像
你可以从Docker Hub下载已经编译好的镜像并启动它
```bash
#此镜像为github持续集成自动编译推送,跟代码(master分支)保持最新状态
#此镜像为github action 持续集成自动编译推送,跟代码(master分支)保持最新状态
docker run -id -p 1935:1935 -p 8080:80 -p 8443:443 -p 8554:554 -p 10000:10000 -p 10000:10000/udp -p 8000:8000/udp -p 9000:9000/udp zlmediakit/zlmediakit:master
```
@ -182,11 +191,15 @@ bash build_docker_images.sh
- [jessibuca](https://github.com/langhuihui/jessibuca) 基于wasm支持H265的播放器
- [wsPlayer](https://github.com/v354412101/wsPlayer) 基于MSE的websocket-fmp4播放器
- [BXC_gb28181Player](https://github.com/any12345com/BXC_gb28181Player) C++开发的支持国标GB28181协议的视频流播放器
- [RTCPlayer](https://github.com/leo94666/RTCPlayer) 一个基于Android客户端的的RTC播放器
- WEB管理网站
- [zlm_webassist](https://github.com/1002victor/zlm_webassist) 本项目配套的前后端分离web管理项目
- [AKStreamNVR](https://github.com/langmansh/AKStreamNVR) 前后端分离web项目,支持webrtc播放
- SDK
- [spring-boot-starter](https://github.com/lunasaw/zlm-spring-boot-starter) 本项目hook和rest接口starter
- [java sdk](https://github.com/lidaofu-hub/j_zlm_sdk) 本项目c sdk完整java包装库
- [c# sdk](https://github.com/malegend/ZLMediaKit.Autogen) 本项目c sdk完整c#包装库
- [metaRTC](https://github.com/metartc/metaRTC) 全国产纯c webrtc sdk
@ -213,7 +226,7 @@ bash build_docker_images.sh
- 请关注微信公众号获取最新消息推送:
<img src=https://user-images.githubusercontent.com/11495632/232451702-4c50bc72-84d8-4c94-af2b-57290088ba7a.png width=15% />
- 也可以自愿有偿加入知识星球咨询和获取资料
- 也可以自愿有偿加入知识星球咨询、获取资料以及加入微信技术群
<img src= https://user-images.githubusercontent.com/11495632/231946329-aa8517b0-3cf5-49cf-8c75-a93ed58cb9d2.png width=30% />
@ -327,6 +340,38 @@ bash build_docker_images.sh
[tbago](https://github.com/tbago)
[Luosh](https://github.com/Luosh)
[linxiaoyan87](https://github.com/linxiaoyan)
[waken](https://github.com/mc373906408)
[Deepslient](https://github.com/Deepslient)
[imp_rayjay](https://github.com/rayjay214)
[ArmstrongCN](https://github.com/ArmstrongCN)
[leibnewton](https://github.com/leibnewton)
[1002victor](https://github.com/1002victor)
[Grin](https://github.com/xyyangkun)
[xbpeng121](https://github.com/xbpeng121)
[lvchenyun](https://github.com/lvchenyun)
[Fummowo](https://github.com/Fummowo)
[Jovial Young ](https://github.com/JHYoung1034)
[yujitai](https://github.com/yujitai)
[KisChang](https://github.com/kisChang)
[zjx94](https://github.com/zjx94)
[LeiZhi.Mai ](https://github.com/blueskiner)
[JiaHao](https://github.com/nashiracn)
[chdahuzi](https://github.com/chdahuzi)
[snysmtx](https://github.com/snysmtx)
[SetoKaiba](https://github.com/SetoKaiba)
[sandro-qiang](https://github.com/sandro-qiang)
[Paul Philippov](https://github.com/themactep)
[张传峰](https://github.com/zhang-chuanfeng)
[lidaofu-hub](https://github.com/lidaofu-hub)
[huangcaichun](https://github.com/huangcaichun)
[jamesZHANG500](https://github.com/jamesZHANG500)
[weidelong](https://github.com/wdl1697454803)
[小强先生](https://github.com/linshangqiang)
[李之阳](https://github.com/leo94666)
同时感谢JetBrains对开源项目的支持本项目使用CLion开发与调试
[![JetBrains](https://resources.jetbrains.com/storage/products/company/brand/logos/CLion.svg)](https://jb.gg/OpenSourceSupport)
## 使用案例

View File

@ -157,7 +157,7 @@ It is recommended to compile on Ubuntu or macOS. Compiling on Windows is cumbers
- **You must use Git to clone the complete code. Do not download the source code by downloading the ZIP package. Otherwise, the submodule code will not be downloaded by default. You can do it like this:**
```
git clone https://github.com/xia-chu/ZLMediaKit.git
git clone https://github.com/ZLMediaKit/ZLMediaKit.git
cd ZLMediaKit
git submodule update --init
```
@ -279,12 +279,12 @@ git submodule update --init
return;
}
auto viedoTrack = strongPlayer->getTrack(TrackVideo);
if (!viedoTrack) {
auto videoTrack = strongPlayer->getTrack(TrackVideo);
if (!videoTrack) {
WarnL << "No video Track!";
return;
}
viedoTrack->addDelegate([](const Frame::Ptr &frame) {
videoTrack->addDelegate([](const Frame::Ptr &frame) {
//please decode video here
});
});
@ -324,6 +324,10 @@ git submodule update --init
});
```
## Binary file download
zlmediakit uses github action to continuously integrate automatic compilation package and upload the compilation output package. Please download the latest sdk library file and executable file at [issue list] (https://github.com/ZLMediaKit/ZLMediaKit/issues/483).
## Docker Image
You can download the pre-compiled image from Docker Hub and start it:
@ -342,6 +346,7 @@ bash build_docker_images.sh
## Collaborative Projects
- Visual management website
- [A backend management website for this project](https://github.com/1002victor/zlm_webassist)
- [The latest web project with front-end and back-end separation, supporting webrtc playback](https://github.com/langmansh/AKStreamNVR)
- [Management web site based on ZLMediaKit master branch](https://gitee.com/kkkkk5G/MediaServerUI)
- [Management web site based on ZLMediaKit branch](https://github.com/chenxiaolei/ZLMediaKit_NVR_UI)
@ -356,6 +361,8 @@ bash build_docker_images.sh
- [Hikvision ehome server implemented in Go](https://github.com/tsingeye/FreeEhome)
- Client
- [Http Api and hook in zlm-spring-boot-starter](https://github.com/lunasaw/zlm-spring-boot-starter)
- [Complete java wrapper library for c sdk](https://github.com/lidaofu-hub/j_zlm_sdk)
- [Complete C# wrapper library for c sdk](https://github.com/malegend/ZLMediaKit.Autogen)
- [Push client implemented based on C SDK](https://github.com/hctym1995/ZLM_ApiDemo)
- [Http API and Hook in C#](https://github.com/chengxiaosheng/ZLMediaKit.HttpApi)
@ -366,6 +373,8 @@ bash build_docker_images.sh
- [WebSocket-fmp4 player based on MSE](https://github.com/v354412101/wsPlayer)
- [Domestic webrtc sdk(metaRTC)](https://github.com/metartc/metaRTC)
- [GB28181 player implemented in C++](https://github.com/any12345com/BXC_gb28181Player)
- [Android RTCPlayer](https://github.com/leo94666/RTCPlayer)
## License
@ -491,6 +500,38 @@ Thanks to all those who have supported this project in various ways, including b
[tbago](https://github.com/tbago)
[Luosh](https://github.com/Luosh)
[linxiaoyan87](https://github.com/linxiaoyan)
[waken](https://github.com/mc373906408)
[Deepslient](https://github.com/Deepslient)
[imp_rayjay](https://github.com/rayjay214)
[ArmstrongCN](https://github.com/ArmstrongCN)
[leibnewton](https://github.com/leibnewton)
[1002victor](https://github.com/1002victor)
[Grin](https://github.com/xyyangkun)
[xbpeng121](https://github.com/xbpeng121)
[lvchenyun](https://github.com/lvchenyun)
[Fummowo](https://github.com/Fummowo)
[Jovial Young ](https://github.com/JHYoung1034)
[yujitai](https://github.com/yujitai)
[KisChang](https://github.com/kisChang)
[zjx94](https://github.com/zjx94)
[LeiZhi.Mai ](https://github.com/blueskiner)
[JiaHao](https://github.com/nashiracn)
[chdahuzi](https://github.com/chdahuzi)
[snysmtx](https://github.com/snysmtx)
[SetoKaiba](https://github.com/SetoKaiba)
[sandro-qiang](https://github.com/sandro-qiang)
[Paul Philippov](https://github.com/themactep)
[张传峰](https://github.com/zhang-chuanfeng)
[lidaofu-hub](https://github.com/lidaofu-hub)
[huangcaichun](https://github.com/huangcaichun)
[jamesZHANG500](https://github.com/jamesZHANG500)
[weidelong](https://github.com/wdl1697454803)
[小强先生](https://github.com/linshangqiang)
[李之阳](https://github.com/leo94666)
Also thank to JetBrains for their support for open source project, we developed and debugged zlmediakit with CLion:
[![JetBrains](https://resources.jetbrains.com/storage/products/company/brand/logos/CLion.svg)](https://jb.gg/OpenSourceSupport)
## Use Cases

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -24,6 +24,10 @@
# define API_CALL
#endif
#ifndef _WIN32
#define _strdup strdup
#endif
#if defined(_WIN32) && defined(_MSC_VER)
# if !defined(GENERATE_EXPORT)
# if defined(MediaKitApi_EXPORTS)
@ -47,6 +51,9 @@ extern "C" {
//输出日志到回调函数(mk_events::on_mk_log)
#define LOG_CALLBACK (1 << 2)
//向下兼容
#define mk_env_init1 mk_env_init2
//回调user_data回调函数
typedef void(API_CALL *on_user_data_free)(void *user_data);
@ -100,7 +107,7 @@ API_EXPORT void API_CALL mk_stop_all_server();
* @param ssl ssl证书内容或路径NULL
* @param ssl_pwd NULL
*/
API_EXPORT void API_CALL mk_env_init1(int thread_num,
API_EXPORT void API_CALL mk_env_init2(int thread_num,
int log_level,
int log_mask,
const char *log_file_path,

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -132,7 +132,12 @@ typedef struct {
/**
* mp4分片文件成功后广播
*/
void (API_CALL *on_mk_record_mp4)(const mk_mp4_info mp4);
void (API_CALL *on_mk_record_mp4)(const mk_record_info mp4);
/**
* ts分片文件成功后广播
*/
void (API_CALL *on_mk_record_ts)(const mk_record_info ts);
/**
* shell登录鉴权
@ -175,7 +180,34 @@ typedef struct {
* @param err
* @param msg
*/
void(API_CALL *on_mk_media_send_rtp_stop)(const char *vhost, const char *app, const char *stream, const char *ssrc, int err, const char *msg);
void (API_CALL *on_mk_media_send_rtp_stop)(const char *vhost, const char *app, const char *stream, const char *ssrc, int err, const char *msg);
/**
* rtc sctp连接中///
* @param rtc_transport
*/
void (API_CALL *on_mk_rtc_sctp_connecting)(mk_rtc_transport rtc_transport);
void (API_CALL *on_mk_rtc_sctp_connected)(mk_rtc_transport rtc_transport);
void (API_CALL *on_mk_rtc_sctp_failed)(mk_rtc_transport rtc_transport);
void (API_CALL *on_mk_rtc_sctp_closed)(mk_rtc_transport rtc_transport);
/**
* rtc数据通道发送数据回调
* @param rtc_transport
* @param msg
* @param len
*/
void (API_CALL *on_mk_rtc_sctp_send)(mk_rtc_transport rtc_transport, const uint8_t *msg, size_t len);
/**
* rtc数据通道接收数据回调
* @param rtc_transport
* @param streamId id
* @param ppid id
* @param msg
* @param len
*/
void (API_CALL *on_mk_rtc_sctp_received)(mk_rtc_transport rtc_transport, uint16_t streamId, uint32_t ppid, const uint8_t *msg, size_t len);
} mk_events;

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -13,37 +13,53 @@
#include "mk_common.h"
#include "mk_tcp.h"
#include "mk_track.h"
#include "mk_util.h"
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////MP4Info/////////////////////////////////////////////
//MP4Info对象的C映射
typedef struct mk_mp4_info_t *mk_mp4_info;
///////////////////////////////////////////RecordInfo/////////////////////////////////////////////
//RecordInfo对象的C映射
typedef struct mk_record_info_t *mk_record_info;
// GMT 标准时间,单位秒
API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx);
API_EXPORT uint64_t API_CALL mk_record_info_get_start_time(const mk_record_info ctx);
// 录像长度,单位秒
API_EXPORT float API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx);
API_EXPORT float API_CALL mk_record_info_get_time_len(const mk_record_info ctx);
// 文件大小,单位 BYTE
API_EXPORT size_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx);
API_EXPORT size_t API_CALL mk_record_info_get_file_size(const mk_record_info ctx);
// 文件路径
API_EXPORT const char* API_CALL mk_mp4_info_get_file_path(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_file_path(const mk_record_info ctx);
// 文件名称
API_EXPORT const char* API_CALL mk_mp4_info_get_file_name(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_file_name(const mk_record_info ctx);
// 文件夹路径
API_EXPORT const char* API_CALL mk_mp4_info_get_folder(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_folder(const mk_record_info ctx);
// 播放路径
API_EXPORT const char* API_CALL mk_mp4_info_get_url(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_url(const mk_record_info ctx);
// 应用名称
API_EXPORT const char* API_CALL mk_mp4_info_get_vhost(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_vhost(const mk_record_info ctx);
// 流 ID
API_EXPORT const char* API_CALL mk_mp4_info_get_app(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_app(const mk_record_info ctx);
// 虚拟主机
API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx);
API_EXPORT const char *API_CALL mk_record_info_get_stream(const mk_record_info ctx);
//// 下面宏保障用户代码兼容性, 二进制abi不兼容用户需要重新编译链接 /////
#define mk_mp4_info mk_record_info
#define mk_mp4_info_get_start_time mk_record_info_get_start_time
#define mk_mp4_info_get_time_len mk_record_info_get_time_len
#define mk_mp4_info_get_file_size mk_record_info_get_file_size
#define mk_mp4_info_get_file_path mk_record_info_get_file_path
#define mk_mp4_info_get_file_name mk_record_info_get_file_name
#define mk_mp4_info_get_folder mk_record_info_get_folder
#define mk_mp4_info_get_url mk_record_info_get_url
#define mk_mp4_info_get_vhost mk_record_info_get_vhost
#define mk_mp4_info_get_app mk_record_info_get_app
#define mk_mp4_info_get_stream mk_record_info_get_stream
///////////////////////////////////////////Parser/////////////////////////////////////////////
//Parser对象的C映射
typedef struct mk_parser_t *mk_parser;
//Parser对象中Headers foreach回调
typedef void(API_CALL *on_mk_parser_header_cb)(void *user_data, const char *key, const char *val);
//Parser::Method(),获取命令字譬如GET/POST
API_EXPORT const char* API_CALL mk_parser_get_method(const mk_parser ctx);
//Parser::Url(),获取HTTP的访问url(不包括?后面的参数)
@ -58,6 +74,8 @@ API_EXPORT const char* API_CALL mk_parser_get_tail(const mk_parser ctx);
API_EXPORT const char* API_CALL mk_parser_get_header(const mk_parser ctx,const char *key);
//Parser::Content(),获取HTTP body
API_EXPORT const char* API_CALL mk_parser_get_content(const mk_parser ctx, size_t *length);
//循环获取所有header
API_EXPORT void API_CALL mk_parser_headers_for_each(const mk_parser ctx, on_mk_parser_header_cb cb, void *user_data);
///////////////////////////////////////////MediaInfo/////////////////////////////////////////////
//MediaInfo对象的C映射
@ -100,6 +118,24 @@ API_EXPORT int API_CALL mk_media_source_get_total_reader_count(const mk_media_so
API_EXPORT int API_CALL mk_media_source_get_track_count(const mk_media_source ctx);
// copy track reference by index from MediaSource, please use mk_track_unref to release it
API_EXPORT mk_track API_CALL mk_media_source_get_track(const mk_media_source ctx, int index);
// MediaSource::Track:loss
API_EXPORT float API_CALL mk_media_source_get_track_loss(const mk_media_source ctx, const mk_track track);
// MediaSource::broadcastMessage
API_EXPORT int API_CALL mk_media_source_broadcast_msg(const mk_media_source ctx, const char *msg, size_t len);
// MediaSource::getOriginUrl()
API_EXPORT const char* API_CALL mk_media_source_get_origin_url(const mk_media_source ctx);
// MediaSource::getOriginType()
API_EXPORT int API_CALL mk_media_source_get_origin_type(const mk_media_source ctx);
// MediaSource::getOriginTypeStr(), 使用后请用mk_free释放返回值
API_EXPORT const char *API_CALL mk_media_source_get_origin_type_str(const mk_media_source ctx);
// MediaSource::getCreateStamp()
API_EXPORT uint64_t API_CALL mk_media_source_get_create_stamp(const mk_media_source ctx);
// MediaSource::isRecording() 0:hls,1:MP4
API_EXPORT int API_CALL mk_media_source_is_recording(const mk_media_source ctx, int type);
// MediaSource::getBytesSpeed()
API_EXPORT int API_CALL mk_media_source_get_bytes_speed(const mk_media_source ctx);
// MediaSource::getAliveSecond()
API_EXPORT uint64_t API_CALL mk_media_source_get_alive_second(const mk_media_source ctx);
/**
* ZLMediaKit中被称作为MediaSource
* 3RtmpMediaSourceRtspMediaSourceHlsMediaSource
@ -138,7 +174,7 @@ API_EXPORT void API_CALL mk_media_source_find(const char *schema,
void *user_data,
on_mk_media_source_find_cb cb);
API_EXPORT const mk_media_source API_CALL mk_media_source_find2(const char *schema,
API_EXPORT mk_media_source API_CALL mk_media_source_find2(const char *schema,
const char *vhost,
const char *app,
const char *stream,
@ -314,6 +350,8 @@ API_EXPORT void API_CALL mk_publish_auth_invoker_do(const mk_publish_auth_invoke
int enable_hls,
int enable_mp4);
API_EXPORT void API_CALL mk_publish_auth_invoker_do2(const mk_publish_auth_invoker ctx, const char *err_msg, mk_ini option);
/**
* mk_publish_auth_invoker对象线mk_publish_auth_invoker_do
* mk_publish_auth_invoker_do
@ -346,6 +384,20 @@ API_EXPORT mk_auth_invoker API_CALL mk_auth_invoker_clone(const mk_auth_invoker
*/
API_EXPORT void API_CALL mk_auth_invoker_clone_release(const mk_auth_invoker ctx);
///////////////////////////////////////////WebRtcTransport/////////////////////////////////////////////
//WebRtcTransport对象的C映射
typedef struct mk_rtc_transport_t *mk_rtc_transport;
/**
* rtc数据通道
* @param ctx
* @param streamId id
* @param ppid id
* @param msg
* @param len
*/
API_EXPORT void API_CALL mk_rtc_send_datachannel(const mk_rtc_transport ctx, uint16_t streamId, uint32_t ppid, const char* msg, size_t len);
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -12,6 +12,7 @@
#define MK_PROXY_PLAYER_H_
#include "mk_common.h"
#include "mk_util.h"
#ifdef __cplusplus
extern "C" {
@ -31,6 +32,44 @@ typedef struct mk_proxy_player_t *mk_proxy_player;
*/
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create(const char *vhost, const char *app, const char *stream, int hls_enabled, int mp4_enabled);
/**
*
* @param vhost __defaultVhost__
* @param app
* @param stream
* @param option ProtocolOption相关配置
* @return
*/
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create2(const char *vhost, const char *app, const char *stream, mk_ini option);
/**
*
* @param vhost __defaultVhost__
* @param app
* @param stream
* @param rtp_type rtsp播放方式:RTP_TCP = 0, RTP_UDP = 1, RTP_MULTICAST = 2
* @param hls_enabled hls
* @param mp4_enabled mp4
* @param retry_count <0
* @return
*/
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create3(const char *vhost, const char *app, const char *stream, int hls_enabled, int mp4_enabled, int retry_count);
/**
*
* @param vhost __defaultVhost__
* @param app
* @param stream
* @param option ProtocolOption相关配置
* @param retry_count <0
* @return
*/
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create4(const char *vhost, const char *app, const char *stream, mk_ini option, int retry_count);
/**
*
* @param ctx
@ -40,7 +79,7 @@ API_EXPORT void API_CALL mk_proxy_player_release(mk_proxy_player ctx);
/**
*
* @param ctx
* @param key , net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms
* @param key , net_adapter/rtp_type/rtsp_user/rtsp_pwd/protocol_timeout_ms/media_timeout_ms/beat_interval_ms/rtsp_speed
* @param val ,string
*/
API_EXPORT void API_CALL mk_proxy_player_set_option(mk_proxy_player ctx, const char *key, const char *val);
@ -59,7 +98,9 @@ API_EXPORT void API_CALL mk_proxy_player_play(mk_proxy_player ctx, const char *u
* mk_proxy_player_release函数MediaSource.close()
* @param user_data mk_proxy_player_set_on_close函数设置
*/
typedef void(API_CALL *on_mk_proxy_player_close)(void *user_data, int err, const char *what, int sys_err);
typedef void(API_CALL *on_mk_proxy_player_cb)(void *user_data, int err, const char *what, int sys_err);
// 保持兼容
#define on_mk_proxy_player_close on_mk_proxy_player_cb
/**
* MediaSource.close()
@ -69,8 +110,17 @@ typedef void(API_CALL *on_mk_proxy_player_close)(void *user_data, int err, const
* @param cb
* @param user_data
*/
API_EXPORT void API_CALL mk_proxy_player_set_on_close(mk_proxy_player ctx, on_mk_proxy_player_close cb, void *user_data);
API_EXPORT void API_CALL mk_proxy_player_set_on_close2(mk_proxy_player ctx, on_mk_proxy_player_close cb, void *user_data, on_user_data_free user_data_free);
API_EXPORT void API_CALL mk_proxy_player_set_on_close(mk_proxy_player ctx, on_mk_proxy_player_cb cb, void *user_data);
API_EXPORT void API_CALL mk_proxy_player_set_on_close2(mk_proxy_player ctx, on_mk_proxy_player_cb cb, void *user_data, on_user_data_free user_data_free);
/**
*
* @param ctx
* @param cb
* @param user_data
* @param user_data_free
*/
API_EXPORT void API_CALL mk_proxy_player_set_on_play_result(mk_proxy_player ctx, on_mk_proxy_player_cb cb, void *user_data, on_user_data_free user_data_free);
/**
*

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -24,6 +24,7 @@ typedef struct mk_rtp_server_t *mk_rtp_server;
* @return
*/
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create(uint16_t port, int tcp_mode, const char *stream_id);
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create2(uint16_t port, int tcp_mode, const char *vhost, const char *app, const char *stream_id);
/**
* TCP

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -73,6 +73,21 @@ API_EXPORT const char* API_CALL mk_track_codec_name(mk_track track);
*/
API_EXPORT int API_CALL mk_track_bit_rate(mk_track track);
/**
* 1: 0
*/
API_EXPORT int API_CALL mk_track_ready(mk_track track);
/**
*
*/
API_EXPORT uint64_t API_CALL mk_track_frames(mk_track track);
/**
*
*/
API_EXPORT uint64_t API_CALL mk_track_duration(mk_track track);
/**
* frame输出事件
* @param track track对象
@ -114,6 +129,21 @@ API_EXPORT int API_CALL mk_track_video_height(mk_track track);
*/
API_EXPORT int API_CALL mk_track_video_fps(mk_track track);
/**
*
*/
API_EXPORT uint64_t API_CALL mk_track_video_key_frames(mk_track track);
/**
* GOP关键帧间隔
*/
API_EXPORT int API_CALL mk_track_video_gop_size(mk_track track);
/**
* ()
*/
API_EXPORT int API_CALL mk_track_video_gop_interval_ms(mk_track track);
/**
*
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -128,6 +128,15 @@ API_EXPORT char *API_CALL mk_ini_dump_string(mk_ini ini);
* @param file
*/
API_EXPORT void API_CALL mk_ini_dump_file(mk_ini ini, const char *file);
///////////////////////////////////////////统计/////////////////////////////////////////////
typedef void(API_CALL *on_mk_get_statistic_cb)(void *user_data, mk_ini ini);
/**
*
* @param ini
*/
API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb cb, void *user_data, on_user_data_free free_cb);
///////////////////////////////////////////日志/////////////////////////////////////////////

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -33,12 +33,11 @@ static TcpServer::Ptr shell_server;
#ifdef ENABLE_RTPPROXY
#include "Rtp/RtpServer.h"
static std::shared_ptr<RtpServer> rtpServer;
static RtpServer::Ptr rtpServer;
#endif
#ifdef ENABLE_WEBRTC
#include "../webrtc/WebRtcSession.h"
#include "../webrtc/WebRtcTransport.h"
static UdpServer::Ptr rtcServer_udp;
static TcpServer::Ptr rtcServer_tcp;
#endif
@ -84,7 +83,7 @@ API_EXPORT void API_CALL mk_stop_all_server(){
stopAllTcpServer();
}
API_EXPORT void API_CALL mk_env_init1(int thread_num,
API_EXPORT void API_CALL mk_env_init2(int thread_num,
int log_level,
int log_mask,
const char *log_file_path,
@ -159,7 +158,7 @@ API_EXPORT void API_CALL mk_set_option(const char *key, const char *val) {
}
mINI::Instance()[key] = val;
//广播配置文件热加载
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
NOTICE_EMIT(BroadcastReloadConfigArgs, Broadcast::kBroadcastReloadConfig);
}
API_EXPORT const char * API_CALL mk_get_option(const char *key)
@ -280,7 +279,6 @@ API_EXPORT uint16_t API_CALL mk_rtc_server_start(uint16_t port) {
class WebRtcArgsUrl : public mediakit::WebRtcArgs {
public:
WebRtcArgsUrl(std::string url) { _url = std::move(url); }
~WebRtcArgsUrl() = default;
toolkit::variant operator[](const std::string &key) const override {
if (key == "url") {
@ -305,10 +303,11 @@ API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2(void *user_data, on_user_data
auto session = std::make_shared<HttpSession>(Socket::createSocket());
std::string offer_str = offer;
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
WebRtcPluginManager::Instance().getAnswerSdp(*session, type, WebRtcArgsUrl(url),
[offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable {
auto args = std::make_shared<WebRtcArgsUrl>(url);
WebRtcPluginManager::Instance().negotiateSdp(*session, type, *args, [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable {
auto &handler = const_cast<WebRtcInterface &>(exchanger);
try {
auto sdp_answer = exchangeSdp(exchanger, offer_str);
auto sdp_answer = handler.getAnswerSdp(offer_str);
cb(ptr.get(), sdp_answer.data(), nullptr);
} catch (std::exception &ex) {
cb(ptr.get(), nullptr, ex.what());

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -15,6 +15,10 @@
#include "Rtsp/RtspSession.h"
#include "Record/MP4Recorder.h"
#ifdef ENABLE_WEBRTC
#include "webrtc/WebRtcTransport.h"
#endif
using namespace toolkit;
using namespace mediakit;
@ -38,7 +42,13 @@ API_EXPORT void API_CALL mk_events_listen(const mk_events *events){
NoticeCenter::Instance().addListener(&s_tag,Broadcast::kBroadcastRecordMP4,[](BroadcastRecordMP4Args){
if(s_events.on_mk_record_mp4){
s_events.on_mk_record_mp4((mk_mp4_info)&info);
s_events.on_mk_record_mp4((mk_record_info)&info);
}
});
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRecordTs, [](BroadcastRecordTsArgs) {
if (s_events.on_mk_record_ts) {
s_events.on_mk_record_ts((mk_record_info)&info);
}
});
@ -167,6 +177,43 @@ API_EXPORT void API_CALL mk_events_listen(const mk_events *events){
sender.getMediaTuple().stream.c_str(), ssrc.c_str(), ex.getErrCode(), ex.what());
}
});
#ifdef ENABLE_WEBRTC
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpConnecting,[](BroadcastRtcSctpConnectArgs){
if (s_events.on_mk_rtc_sctp_connecting) {
s_events.on_mk_rtc_sctp_connecting((mk_rtc_transport)&sender);
}
});
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpConnected,[](BroadcastRtcSctpConnectArgs){
if (s_events.on_mk_rtc_sctp_connected) {
s_events.on_mk_rtc_sctp_connected((mk_rtc_transport)&sender);
}
});
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpFailed,[](BroadcastRtcSctpConnectArgs){
if (s_events.on_mk_rtc_sctp_failed) {
s_events.on_mk_rtc_sctp_failed((mk_rtc_transport)&sender);
}
});
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpClosed,[](BroadcastRtcSctpConnectArgs){
if (s_events.on_mk_rtc_sctp_closed) {
s_events.on_mk_rtc_sctp_closed((mk_rtc_transport)&sender);
}
});
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpSend,[](BroadcastRtcSctpSendArgs){
if (s_events.on_mk_rtc_sctp_send) {
s_events.on_mk_rtc_sctp_send((mk_rtc_transport)&sender, data, len);
}
});
NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpReceived,[](BroadcastRtcSctpReceivedArgs){
if (s_events.on_mk_rtc_sctp_received) {
s_events.on_mk_rtc_sctp_received((mk_rtc_transport)&sender, streamId, ppid, msg, len);
}
});
#endif
});
}

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -18,65 +18,69 @@
#include "Http/HttpClient.h"
#include "Rtsp/RtspSession.h"
#ifdef ENABLE_WEBRTC
#include "webrtc/WebRtcTransport.h"
#endif
using namespace toolkit;
using namespace mediakit;
///////////////////////////////////////////RecordInfo/////////////////////////////////////////////
API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx){
API_EXPORT uint64_t API_CALL mk_record_info_get_start_time(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->start_time;
}
API_EXPORT float API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx){
API_EXPORT float API_CALL mk_record_info_get_time_len(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->time_len;
}
API_EXPORT size_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx){
API_EXPORT size_t API_CALL mk_record_info_get_file_size(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->file_size;
}
API_EXPORT const char* API_CALL mk_mp4_info_get_file_path(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_file_path(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->file_path.c_str();
}
API_EXPORT const char* API_CALL mk_mp4_info_get_file_name(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_file_name(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->file_name.c_str();
}
API_EXPORT const char* API_CALL mk_mp4_info_get_folder(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_folder(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->folder.c_str();
}
API_EXPORT const char* API_CALL mk_mp4_info_get_url(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_url(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->url.c_str();
}
API_EXPORT const char* API_CALL mk_mp4_info_get_vhost(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_vhost(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->vhost.c_str();
}
API_EXPORT const char* API_CALL mk_mp4_info_get_app(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_app(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->app.c_str();
}
API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx){
API_EXPORT const char *API_CALL mk_record_info_get_stream(const mk_record_info ctx) {
assert(ctx);
RecordInfo *info = (RecordInfo *)ctx;
return info->stream.c_str();
@ -121,12 +125,19 @@ API_EXPORT const char* API_CALL mk_parser_get_content(const mk_parser ctx, size_
}
return parser->content().c_str();
}
API_EXPORT void API_CALL mk_parser_headers_for_each(const mk_parser ctx, on_mk_parser_header_cb cb, void *user_data){
assert(ctx && cb);
Parser *parser = (Parser *)ctx;
for (auto it = parser->getHeader().begin(); it != parser->getHeader().end(); ++it) {
cb(user_data, it->first.c_str(), it->second.c_str());
}
}
///////////////////////////////////////////MediaInfo/////////////////////////////////////////////
API_EXPORT const char* API_CALL mk_media_info_get_params(const mk_media_info ctx){
assert(ctx);
MediaInfo *info = (MediaInfo *)ctx;
return info->param_strs.c_str();
return info->params.c_str();
}
API_EXPORT const char* API_CALL mk_media_info_get_schema(const mk_media_info ctx){
@ -214,6 +225,66 @@ API_EXPORT mk_track API_CALL mk_media_source_get_track(const mk_media_source ctx
return (mk_track) new Track::Ptr(std::move(tracks[index]));
}
API_EXPORT float API_CALL mk_media_source_get_track_loss(const mk_media_source ctx, const mk_track track) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
// rtp推流只有一个统计器但是可能有多个track如果短时间多次获取间隔丢包率第二次会获取为-1
return src->getLossRate((*((Track::Ptr *)track))->getTrackType());
}
API_EXPORT int API_CALL mk_media_source_broadcast_msg(const mk_media_source ctx, const char *msg, size_t len) {
assert(ctx && msg && len);
MediaSource *src = (MediaSource *)ctx;
Any any;
Buffer::Ptr buffer = std::make_shared<BufferLikeString>(std::string(msg, len));
any.set(std::move(buffer));
return src->broadcastMessage(any);
}
API_EXPORT const char* API_CALL mk_media_source_get_origin_url(const mk_media_source ctx) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return _strdup(src->getOriginUrl().c_str());
}
API_EXPORT int API_CALL mk_media_source_get_origin_type(const mk_media_source ctx) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return static_cast<int>(src->getOriginType());
}
API_EXPORT const char* API_CALL mk_media_source_get_origin_type_str(const mk_media_source ctx) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return _strdup(getOriginTypeString(src->getOriginType()).c_str());
}
API_EXPORT uint64_t API_CALL mk_media_source_get_create_stamp(const mk_media_source ctx) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return src->getCreateStamp();
}
API_EXPORT int API_CALL mk_media_source_is_recording(const mk_media_source ctx,int type) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return src->isRecording((Recorder::type)type);
}
API_EXPORT int API_CALL mk_media_source_get_bytes_speed(const mk_media_source ctx) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return src->getBytesSpeed();
}
API_EXPORT uint64_t API_CALL mk_media_source_get_alive_second(const mk_media_source ctx) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
return src->getAliveSecond();
}
API_EXPORT int API_CALL mk_media_source_close(const mk_media_source ctx,int force){
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
@ -264,7 +335,7 @@ API_EXPORT void API_CALL mk_media_source_find(const char *schema,
cb(user_data, (mk_media_source)src.get());
}
API_EXPORT const mk_media_source API_CALL mk_media_source_find2(const char *schema,
API_EXPORT mk_media_source API_CALL mk_media_source_find2(const char *schema,
const char *vhost,
const char *app,
const char *stream,
@ -451,6 +522,13 @@ API_EXPORT void API_CALL mk_publish_auth_invoker_do(const mk_publish_auth_invoke
(*invoker)(err_msg ? err_msg : "", option);
}
API_EXPORT void API_CALL mk_publish_auth_invoker_do2(const mk_publish_auth_invoker ctx, const char *err_msg, mk_ini ini) {
assert(ctx);
Broadcast::PublishAuthInvoker *invoker = (Broadcast::PublishAuthInvoker *)ctx;
ProtocolOption option(ini ? *((mINI *)ini) : mINI{} );
(*invoker)(err_msg ? err_msg : "", option);
}
API_EXPORT mk_publish_auth_invoker API_CALL mk_publish_auth_invoker_clone(const mk_publish_auth_invoker ctx){
assert(ctx);
Broadcast::PublishAuthInvoker *invoker = (Broadcast::PublishAuthInvoker *)ctx;
@ -481,3 +559,21 @@ API_EXPORT void API_CALL mk_auth_invoker_clone_release(const mk_auth_invoker ctx
Broadcast::AuthInvoker *invoker = (Broadcast::AuthInvoker *)ctx;
delete invoker;
}
///////////////////////////////////////////WebRtcTransport/////////////////////////////////////////////
API_EXPORT void API_CALL mk_rtc_send_datachannel(const mk_rtc_transport ctx, uint16_t streamId, uint32_t ppid, const char *msg, size_t len) {
#ifdef ENABLE_WEBRTC
assert(ctx && msg);
WebRtcTransport *transport = (WebRtcTransport *)ctx;
std::string msg_str(msg, len);
std::weak_ptr<WebRtcTransport> weak_trans = transport->shared_from_this();
transport->getPoller()->async([streamId, ppid, msg_str, weak_trans]() {
// 切换线程后再操作
if (auto trans = weak_trans.lock()) {
trans->sendDatachannel(streamId, ppid, msg_str.c_str(), msg_str.size());
}
});
#else
WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC";
#endif
}

View File

@ -1,115 +1,70 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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_frame.h"
#include "mk_track.h"
#include "Extension/Frame.h"
#include "Extension/H264.h"
#include "Extension/H265.h"
#include "Extension/AAC.h"
#include "Record/MPEG.h"
#include "Extension/Factory.h"
using namespace mediakit;
extern "C" {
#define XX(name, type, value, str, mpeg_id) API_EXPORT const int MK##name = value;
#define XX(name, type, value, str, mpeg_id, mp4_id) API_EXPORT const int MK##name = value;
CODEC_MAP(XX)
#undef XX
}
class FrameFromPtrForC : public FrameFromPtr {
namespace {
class BufferFromPtr : public toolkit::Buffer {
public:
using Ptr = std::shared_ptr<FrameFromPtrForC>;
template<typename ...ARGS>
FrameFromPtrForC(bool cache_able, uint32_t flags, on_mk_frame_data_release cb, std::shared_ptr<void> user_data, ARGS &&...args) : FrameFromPtr(
std::forward<ARGS>(args)...) {
_flags = flags;
BufferFromPtr(char *ptr, size_t size, on_mk_frame_data_release cb, std::shared_ptr<void> user_data) {
_ptr = ptr;
_size = size;
_cb = cb;
_user_data = std::move(user_data);
_cache_able = cache_able;
}
~FrameFromPtrForC() override {
if (_cb) {
~BufferFromPtr() override {
_cb(_user_data.get(), _ptr);
}
}
bool cacheAble() const override {
return _cache_able;
}
bool keyFrame() const override {
return _flags & MK_FRAME_FLAG_IS_KEY;
}
bool configFrame() const override {
return _flags & MK_FRAME_FLAG_IS_CONFIG;
}
//默认返回false
bool dropAble() const override {
return _flags & MK_FRAME_FLAG_DROP_ABLE;
}
//默认返回true
bool decodeAble() const override {
return !(_flags & MK_FRAME_FLAG_NOT_DECODE_ABLE);
}
char *data() const override { return _ptr; }
size_t size() const override { return _size; }
private:
uint32_t _flags;
char *_ptr;
size_t _size;
on_mk_frame_data_release _cb;
std::shared_ptr<void> _user_data;
bool _cache_able;
};
}; // namespace
static mk_frame mk_frame_create_complex(int codec_id, uint64_t dts, uint64_t pts, uint32_t frame_flags, size_t prefix_size,
char *data, size_t size, on_mk_frame_data_release cb, std::shared_ptr<void> user_data) {
switch (codec_id) {
case CodecH264:
return (mk_frame)new Frame::Ptr(new H264FrameHelper<FrameFromPtrForC>(
cb, frame_flags, cb, std::move(user_data), (CodecId)codec_id, data, size, dts, pts, prefix_size));
case CodecH265:
return (mk_frame)new Frame::Ptr(new H265FrameHelper<FrameFromPtrForC>(
cb, frame_flags, cb, std::move(user_data), (CodecId)codec_id, data, size, dts, pts, prefix_size));
default:
return (mk_frame)new Frame::Ptr(new FrameFromPtrForC(
cb, frame_flags, cb, std::move(user_data), (CodecId)codec_id, data, size, dts, pts, prefix_size));
static mk_frame mk_frame_create_complex(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
on_mk_frame_data_release cb, std::shared_ptr<void> user_data) {
if (!cb) {
// no cacheable
return (mk_frame) new Frame::Ptr(Factory::getFrameFromPtr((CodecId)codec_id, data, size, dts, pts));
}
// cacheable
auto buffer = std::make_shared<BufferFromPtr>((char *)data, size, cb, std::move(user_data));
return (mk_frame) new Frame::Ptr(Factory::getFrameFromBuffer((CodecId)codec_id, std::move(buffer), dts, pts));
}
API_EXPORT mk_frame API_CALL mk_frame_create(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
on_mk_frame_data_release cb, void *user_data) {
return mk_frame_create2(codec_id, dts, pts, data, size, cb, user_data, nullptr);
}
API_EXPORT mk_frame API_CALL mk_frame_create2(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
on_mk_frame_data_release cb, void *user_data, on_user_data_free user_data_free) {
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
switch (codec_id) {
case CodecH264:
case CodecH265:
return mk_frame_create_complex(codec_id, dts, pts, 0, prefixSize(data, size), (char *)data, size, cb, std::move(ptr));
case CodecAAC: {
int prefix = 0;
if ((((uint8_t *) data)[0] == 0xFF && (((uint8_t *) data)[1] & 0xF0) == 0xF0) && size > ADTS_HEADER_LEN) {
prefix = ADTS_HEADER_LEN;
}
return mk_frame_create_complex(codec_id, dts, pts, 0, prefix, (char *)data, size, cb, std::move(ptr));
}
default:
return mk_frame_create_complex(codec_id, dts, pts, 0, 0, (char *)data, size, cb, std::move(ptr));
}
return mk_frame_create_complex(codec_id, dts, pts, data, size, cb, std::move(ptr));
}
API_EXPORT void API_CALL mk_frame_unref(mk_frame frame) {

View File

@ -1,17 +1,16 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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_h264_splitter.h"
#include "Http/HttpRequestSplitter.h"
#include "Extension/H264.h"
#include "Extension/H265.h"
#include "Extension/Factory.h"
using namespace mediakit;
@ -28,8 +27,9 @@ protected:
private:
bool _h265 = false;
bool _have_decode_frame = false;
onH264 _cb;
size_t _search_pos = 0;
toolkit::BufferLikeString _buffer;
};
void H264Splitter::setOnSplitted(H264Splitter::onH264 cb) {
@ -43,11 +43,21 @@ H264Splitter::~H264Splitter() {
}
ssize_t H264Splitter::onRecvHeader(const char *data, size_t len) {
_cb(data, len);
auto frame = Factory::getFrameFromPtr(_h265 ? CodecH265 : CodecH264, (char *)data, len, 0, 0);
if (_have_decode_frame && (frame->decodeAble() || frame->configFrame())) {
// 缓存中存在可解码帧且下一帧是可解码帧或者配置帧那么flush缓存
_cb(_buffer.data(), _buffer.size());
_buffer.assign(data, len);
_have_decode_frame = frame->decodeAble();
} else {
// 还需要缓存
_buffer.append(data, len);
_have_decode_frame = _have_decode_frame || frame->decodeAble();
}
return 0;
}
static const char *onSearchPacketTail_l(const char *data, size_t len) {
const char *H264Splitter::onSearchPacketTail(const char *data, size_t len) {
for (size_t i = 2; len > 2 && i < len - 2; ++i) {
//判断0x00 00 01
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
@ -61,28 +71,6 @@ static const char *onSearchPacketTail_l(const char *data, size_t len) {
return nullptr;
}
const char *H264Splitter::onSearchPacketTail(const char *data, size_t len) {
auto last_frame = data + _search_pos;
auto next_frame = onSearchPacketTail_l(last_frame, len - _search_pos);
if (!next_frame) {
return nullptr;
}
auto last_frame_len = next_frame - last_frame;
Frame::Ptr frame;
if (_h265) {
frame = std::make_shared<H265FrameNoCacheAble>((char *) last_frame, last_frame_len, 0, 0, prefixSize(last_frame, last_frame_len));
} else {
frame = std::make_shared<H264FrameNoCacheAble>((char *) last_frame, last_frame_len, 0, 0, prefixSize(last_frame, last_frame_len));
}
if (frame->decodeAble()) {
_search_pos = 0;
return next_frame;
}
_search_pos += last_frame_len;
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
API_EXPORT mk_h264_splitter API_CALL mk_h264_splitter_create(on_mk_h264_splitter_frame cb, void *user_data, int is_h265) {

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,7 +11,6 @@
#include "mk_player.h"
#include "Util/logger.h"
#include "Player/MediaPlayer.h"
#include "Extension/H264.h"
using namespace std;
using namespace toolkit;
@ -24,7 +23,6 @@ public:
MediaPlayerForC(){
_player = std::make_shared<MediaPlayer>();
}
~MediaPlayerForC() = default;
MediaPlayer *operator->(){
return _player.get();

View File

@ -1,26 +1,43 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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"
#include "Player/PlayerProxy.h"
#include "mk_util.h"
using namespace toolkit;
using namespace mediakit;
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create(const char *vhost, const char *app, const char *stream, int hls_enabled, int mp4_enabled) {
return mk_proxy_player_create3(vhost, app, stream, hls_enabled, mp4_enabled,-1);
}
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create2(const char *vhost, const char *app, const char *stream, mk_ini ini) {
return mk_proxy_player_create4(vhost, app, stream, ini, -1);
}
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create3(const char *vhost, const char *app, const char *stream, int hls_enabled, int mp4_enabled, int retry_count) {
assert(vhost && app && stream);
ProtocolOption option;
option.enable_hls = hls_enabled;
option.enable_mp4 = mp4_enabled;
PlayerProxy::Ptr *obj(new PlayerProxy::Ptr(new PlayerProxy(vhost, app, stream, option)));
return (mk_proxy_player) obj;
PlayerProxy::Ptr *obj(new PlayerProxy::Ptr(new PlayerProxy(vhost, app, stream, option, retry_count)));
return (mk_proxy_player)obj;
}
API_EXPORT mk_proxy_player API_CALL mk_proxy_player_create4(const char *vhost, const char *app, const char *stream, mk_ini ini, int retry_count) {
assert(vhost && app && stream);
ProtocolOption option(*((mINI *)ini));
PlayerProxy::Ptr *obj(new PlayerProxy::Ptr(new PlayerProxy(vhost, app, stream, option, retry_count)));
return (mk_proxy_player)obj;
}
API_EXPORT void API_CALL mk_proxy_player_release(mk_proxy_player ctx) {
@ -67,6 +84,20 @@ API_EXPORT void API_CALL mk_proxy_player_set_on_close2(mk_proxy_player ctx, on_m
});
}
API_EXPORT void API_CALL mk_proxy_player_set_on_play_result(mk_proxy_player ctx, on_mk_proxy_player_close cb, void *user_data, on_user_data_free user_data_free) {
assert(ctx);
PlayerProxy::Ptr &obj = *((PlayerProxy::Ptr *)ctx);
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
obj->getPoller()->async([obj, cb, ptr]() {
// 切换线程再操作
obj->setPlayCallbackOnce([cb, ptr](const SockException &ex) {
if (cb) {
cb(ptr.get(), ex.getErrCode(), ex.what(), ex.getCustomCode());
}
});
});
}
API_EXPORT int API_CALL mk_proxy_player_total_reader_count(mk_proxy_player ctx){
assert(ctx);
PlayerProxy::Ptr &obj = *((PlayerProxy::Ptr *) ctx);

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -18,7 +18,13 @@ using namespace mediakit;
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create(uint16_t port, int tcp_mode, const char *stream_id) {
RtpServer::Ptr *server = new RtpServer::Ptr(new RtpServer);
(*server)->start(port, stream_id, (RtpServer::TcpMode)tcp_mode);
(*server)->start(port, MediaTuple { DEFAULT_VHOST, kRtpAppName, stream_id, "" }, (RtpServer::TcpMode)tcp_mode);
return (mk_rtp_server)server;
}
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create2(uint16_t port, int tcp_mode, const char *vhost, const char *app, const char *stream_id) {
RtpServer::Ptr *server = new RtpServer::Ptr(new RtpServer);
(*server)->start(port, MediaTuple { vhost, app, stream_id, "" }, (RtpServer::TcpMode)tcp_mode);
return (mk_rtp_server)server;
}
@ -56,7 +62,7 @@ API_EXPORT void API_CALL mk_rtp_server_set_on_detach2(mk_rtp_server ctx, on_mk_r
RtpServer::Ptr *server = (RtpServer::Ptr *) ctx;
if (cb) {
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
(*server)->setOnDetach([cb, ptr]() {
(*server)->setOnDetach([cb, ptr](const SockException &ex) {
cb(ptr.get());
});
} else {
@ -71,6 +77,11 @@ API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create(uint16_t port, int enable
return nullptr;
}
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create2(uint16_t port, int tcp_mode, const char *vhost, const char *app, const char *stream_id) {
WarnL << "请打开ENABLE_RTPPROXY后再编译";
return nullptr;
}
API_EXPORT void API_CALL mk_rtp_server_release(mk_rtp_server ctx) {
WarnL << "请打开ENABLE_RTPPROXY后再编译";
}

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -33,9 +33,8 @@ private:
class SessionForC : public toolkit::Session {
public:
SessionForC(const toolkit::Socket::Ptr &pSock) ;
~SessionForC() override = default;
void onRecv(const toolkit::Buffer::Ptr &buffer) override ;
SessionForC(const toolkit::Socket::Ptr &pSock);
void onRecv(const toolkit::Buffer::Ptr &buffer) override;
void onError(const toolkit::SockException &err) override;
void onManager() override;
std::shared_ptr<void> _user_data;

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -80,8 +80,6 @@ public:
_user_data = std::move(user_data);
}
~TimerForC() = default;
uint64_t operator()(){
lock_guard<recursive_mutex> lck(_mxt);
if(!_cb){
@ -135,8 +133,6 @@ API_EXPORT void API_CALL mk_timer_release(mk_timer ctx){
class WorkThreadPoolForC : public TaskExecutorGetterImp {
public:
~WorkThreadPoolForC() override = default;
WorkThreadPoolForC(const char *name, size_t n_thread, int priority) {
//最低优先级
addPoller(name, n_thread, (ThreadPool::Priority) priority, false);

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -27,8 +27,6 @@ public:
}
}
~VideoTrackForC() override = default;
int getVideoHeight() const override {
return _args.video.height;
}
@ -45,16 +43,16 @@ public:
return _codec_id;
}
bool ready() override {
bool ready() const override {
return true;
}
Track::Ptr clone() override {
auto track_in = std::shared_ptr<Track>(shared_from_this());
Track::Ptr clone() const override {
auto track_in = std::shared_ptr<Track>(const_cast<VideoTrackForC *>(this)->shared_from_this());
return Factory::getTrackByAbstractTrack(track_in);
}
Sdp::Ptr getSdp() override {
Sdp::Ptr getSdp(uint8_t) const override {
return nullptr;
}
@ -65,17 +63,15 @@ private:
class AudioTrackForC : public AudioTrackImp, public std::enable_shared_from_this<AudioTrackForC> {
public:
~AudioTrackForC() override = default;
AudioTrackForC(int codec_id, codec_args *args) :
AudioTrackImp((CodecId) codec_id, args->audio.sample_rate, args->audio.channels, 16) {}
Track::Ptr clone() override {
auto track_in = std::shared_ptr<Track>(shared_from_this());
Track::Ptr clone() const override {
auto track_in = std::shared_ptr<Track>(const_cast<AudioTrackForC *>(this)->shared_from_this());
return Factory::getTrackByAbstractTrack(track_in);
}
Sdp::Ptr getSdp() override {
Sdp::Ptr getSdp(uint8_t payload_type) const override {
return nullptr;
}
};
@ -113,6 +109,21 @@ API_EXPORT int API_CALL mk_track_bit_rate(mk_track track) {
return (*((Track::Ptr *) track))->getBitRate();
}
API_EXPORT int API_CALL mk_track_ready(mk_track track) {
assert(track);
return (*((Track::Ptr *)track))->ready();
}
API_EXPORT uint64_t API_CALL mk_track_frames(mk_track track) {
assert(track);
return (*((Track::Ptr *)track))->getFrames();
}
API_EXPORT uint64_t API_CALL mk_track_duration(mk_track track) {
assert(track);
return (*((Track::Ptr *)track))->getDuration();
}
API_EXPORT void *API_CALL mk_track_add_delegate(mk_track track, on_mk_frame_out cb, void *user_data) {
return mk_track_add_delegate2(track, cb, user_data, nullptr);
}
@ -171,6 +182,36 @@ API_EXPORT int API_CALL mk_track_video_fps(mk_track track) {
return 0;
}
API_EXPORT uint64_t API_CALL mk_track_video_key_frames(mk_track track) {
assert(track);
auto video = dynamic_pointer_cast<VideoTrack>((*((Track::Ptr *)track)));
if (video) {
return video->getVideoFps();
}
WarnL << "not video track";
return 0;
}
API_EXPORT int API_CALL mk_track_video_gop_size(mk_track track) {
assert(track);
auto video = dynamic_pointer_cast<VideoTrack>((*((Track::Ptr *)track)));
if (video) {
return video->getVideoGopSize();
}
WarnL << "not video track";
return 0;
}
API_EXPORT int API_CALL mk_track_video_gop_interval_ms(mk_track track) {
assert(track);
auto video = dynamic_pointer_cast<VideoTrack>((*((Track::Ptr *)track)));
if (video) {
return video->getVideoGopInterval();
}
WarnL << "not video track";
return 0;
}
API_EXPORT int API_CALL mk_track_audio_sample_rate(mk_track track) {
assert(track);
auto audio = dynamic_pointer_cast<AudioTrack>((*((Track::Ptr *) track)));

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -15,16 +15,15 @@
#include "Util/util.h"
#include "Util/mini.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Poller/EventPoller.h"
#include "Thread/WorkThreadPool.h"
#include "Common/config.h"
using namespace std;
using namespace toolkit;
using namespace mediakit;
#ifndef _WIN32
#define _strdup strdup
#endif
API_EXPORT void API_CALL mk_free(void *ptr) {
free(ptr);
}
@ -65,7 +64,7 @@ API_EXPORT mk_ini API_CALL mk_ini_default() {
static void emit_ini_file_reload(mk_ini ini) {
if (ini == mk_ini_default()) {
// 广播配置文件热加载
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
NOTICE_EMIT(BroadcastReloadConfigArgs, Broadcast::kBroadcastReloadConfig);
}
}
@ -136,6 +135,129 @@ API_EXPORT void API_CALL mk_ini_dump_file(mk_ini ini, const char *file) {
ptr->dumpFile(file);
}
extern uint64_t getTotalMemUsage();
extern uint64_t getTotalMemBlock();
extern uint64_t getThisThreadMemUsage();
extern uint64_t getThisThreadMemBlock();
extern std::vector<size_t> getBlockTypeSize();
extern uint64_t getTotalMemBlockByType(int type);
extern uint64_t getThisThreadMemBlockByType(int type);
namespace mediakit {
class MediaSource;
class MultiMediaSourceMuxer;
class FrameImp;
class Frame;
class RtpPacket;
class RtmpPacket;
} // namespace mediakit
namespace toolkit {
class TcpServer;
class TcpSession;
class UdpServer;
class UdpSession;
class TcpClient;
class Socket;
class Buffer;
class BufferRaw;
class BufferLikeString;
class BufferList;
} // namespace toolkit
API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb func, void *user_data, on_user_data_free free_cb) {
assert(func);
std::shared_ptr<void> data(user_data, free_cb);
auto cb = [func, data](const toolkit::mINI &ini) { func(data.get(), (mk_ini)&ini); };
auto obj = std::make_shared<toolkit::mINI>();
auto &val = *obj;
val["object.MediaSource"] = ObjectStatistic<MediaSource>::count();
val["object.MultiMediaSourceMuxer"] = ObjectStatistic<MultiMediaSourceMuxer>::count();
val["object.TcpServer"] = ObjectStatistic<TcpServer>::count();
val["object.TcpSession"] = ObjectStatistic<TcpSession>::count();
val["object.UdpServer"] = ObjectStatistic<UdpServer>::count();
val["object.UdpSession"] = ObjectStatistic<UdpSession>::count();
val["object.TcpClient"] = ObjectStatistic<TcpClient>::count();
val["object.Socket"] = ObjectStatistic<Socket>::count();
val["object.FrameImp"] = ObjectStatistic<FrameImp>::count();
val["object.Frame"] = ObjectStatistic<Frame>::count();
val["object.Buffer"] = ObjectStatistic<Buffer>::count();
val["object.BufferRaw"] = ObjectStatistic<BufferRaw>::count();
val["object.BufferLikeString"] = ObjectStatistic<BufferLikeString>::count();
val["object.BufferList"] = ObjectStatistic<BufferList>::count();
val["object.RtpPacket"] = ObjectStatistic<RtpPacket>::count();
val["object.RtmpPacket"] = ObjectStatistic<RtmpPacket>::count();
#ifdef ENABLE_MEM_DEBUG
auto bytes = getTotalMemUsage();
val["memory.memUsage"] = bytes;
val["memory.memUsageMB"] = (int)(bytes / 1024 / 1024);
val["memory.memBlock"] = getTotalMemBlock();
static auto block_type_size = getBlockTypeSize();
{
int i = 0;
string str;
size_t last = 0;
for (auto sz : block_type_size) {
str.append(to_string(last) + "~" + to_string(sz) + ":" + to_string(getTotalMemBlockByType(i++)) + ";");
last = sz;
}
str.pop_back();
val["memory.memBlockTypeCount"] = str;
}
#endif
auto thread_size = EventPollerPool::Instance().getExecutorSize() + WorkThreadPool::Instance().getExecutorSize();
std::shared_ptr<vector<toolkit::mINI>> thread_mem_info = std::make_shared<vector<toolkit::mINI>>(thread_size);
shared_ptr<void> finished(nullptr, [thread_mem_info, cb, obj](void *) {
for (auto &val : *thread_mem_info) {
auto thread_name = val["name"];
replace(thread_name, "...", "~~~");
auto prefix = "thread-" + thread_name + ".";
for (auto &pr : val) {
(*obj).emplace(prefix + pr.first, std::move(pr.second));
}
}
// 触发回调
cb(*obj);
});
auto pos = 0;
auto lambda = [&](const TaskExecutor::Ptr &executor) {
auto &val = (*thread_mem_info)[pos++];
val["load"] = executor->load();
Ticker ticker;
executor->async([finished, &val, ticker]() {
val["name"] = getThreadName();
val["delay"] = ticker.elapsedTime();
#ifdef ENABLE_MEM_DEBUG
auto bytes = getThisThreadMemUsage();
val["memUsage"] = bytes;
val["memUsageMB"] = bytes / 1024 / 1024;
val["memBlock"] = getThisThreadMemBlock();
{
int i = 0;
string str;
size_t last = 0;
for (auto sz : block_type_size) {
str.append(to_string(last) + "~" + to_string(sz) + ":" + to_string(getThisThreadMemBlockByType(i++)) + ";");
last = sz;
}
str.pop_back();
val["memBlockTypeCount"] = str;
}
#endif
});
};
EventPollerPool::Instance().for_each(lambda);
WorkThreadPool::Instance().for_each(lambda);
}
API_EXPORT void API_CALL mk_log_printf(int level, const char *file, const char *function, int line, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

152
api/tests/h264_pusher.c Normal file
View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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 <signal.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include "windows.h"
#else
#include "unistd.h"
#endif
#include "mk_mediakit.h"
static int exit_flag = 0;
static void s_on_exit(int sig) {
exit_flag = 1;
}
static void on_h264_frame(void *user_data, mk_h264_splitter splitter, const char *data, int size) {
#ifdef _WIN32
Sleep(40);
#else
usleep(40 * 1000);
#endif
static int dts = 0;
mk_frame frame = mk_frame_create(MKCodecH264, dts, dts, data, size, NULL, NULL);
dts += 40;
mk_media_input_frame((mk_media)user_data, frame);
mk_frame_unref(frame);
}
typedef struct {
mk_pusher pusher;
char *url;
} Context;
void release_context(void *user_data) {
Context *ptr = (Context *)user_data;
if (ptr->pusher) {
mk_pusher_release(ptr->pusher);
}
free(ptr->url);
free(ptr);
log_info("停止推流");
}
void on_push_result(void *user_data, int err_code, const char *err_msg) {
Context *ptr = (Context *)user_data;
if (err_code == 0) {
log_info("推流成功: %s", ptr->url);
} else {
log_warn("推流%s失败: %d(%s)", ptr->url, err_code, err_msg);
}
}
void on_push_shutdown(void *user_data, int err_code, const char *err_msg) {
Context *ptr = (Context *)user_data;
log_warn("推流%s中断: %d(%s)", ptr->url, err_code, err_msg);
}
void API_CALL on_regist(void *user_data, mk_media_source sender, int regist) {
Context *ptr = (Context *)user_data;
const char *schema = mk_media_source_get_schema(sender);
if (strstr(ptr->url, schema) != ptr->url) {
// 协议匹配失败
return;
}
if (!regist) {
// 注销
if (ptr->pusher) {
mk_pusher_release(ptr->pusher);
ptr->pusher = NULL;
}
} else {
// 注册
if (!ptr->pusher) {
ptr->pusher = mk_pusher_create_src(sender);
mk_pusher_set_on_result2(ptr->pusher, on_push_result, ptr, NULL);
mk_pusher_set_on_shutdown2(ptr->pusher, on_push_shutdown, ptr, NULL);
// 开始推流
mk_pusher_publish(ptr->pusher, ptr->url);
}
}
}
int main(int argc, char *argv[]) {
if (argc < 3) {
log_error("Usage: /path/to/h264/file rtsp_or_rtmp_url");
return -1;
}
mk_config config = { .ini = NULL,
.ini_is_path = 1,
.log_level = 0,
.log_mask = LOG_CONSOLE,
.log_file_path = NULL,
.log_file_days = 0,
.ssl = NULL,
.ssl_is_path = 1,
.ssl_pwd = NULL,
.thread_num = 0 };
mk_env_init(&config);
FILE *fp = fopen(argv[1], "rb");
if (!fp) {
log_error("打开文件失败!");
return -1;
}
mk_media media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0);
// h264的codec
codec_args v_args = { 0 };
mk_track v_track = mk_track_create(MKCodecH264, &v_args);
mk_media_init_track(media, v_track);
mk_media_init_complete(media);
mk_track_unref(v_track);
Context *ctx = (Context *)malloc(sizeof(Context));
memset(ctx, 0, sizeof(Context));
ctx->url = strdup(argv[2]);
mk_media_set_on_regist2(media, on_regist, ctx, release_context);
// 创建h264分帧器
mk_h264_splitter splitter = mk_h264_splitter_create(on_h264_frame, media, 0);
signal(SIGINT, s_on_exit); // 设置退出信号
signal(SIGTERM, s_on_exit); // 设置退出信号
char buf[1024];
while (!exit_flag) {
int size = fread(buf, 1, sizeof(buf) - 1, fp);
if (size > 0) {
mk_h264_splitter_input_data(splitter, buf, size);
} else {
// 文件读完了,重新开始
fseek(fp, 0, SEEK_SET);
}
}
log_info("文件读取完毕");
mk_h264_splitter_release(splitter);
mk_media_release(media);
fclose(fp);
return 0;
}

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -189,6 +189,14 @@ static void on_mk_webrtc_get_answer_sdp_func(void *user_data, const char *answer
free((void *)answer);
}
}
void API_CALL on_get_statistic_cb(void *user_data, mk_ini ini) {
const char *response_header[] = { NULL };
char *str = mk_ini_dump_string(ini);
mk_http_response_invoker_do_string(user_data, 200, response_header, str);
mk_free(str);
}
/**
* http api请求广播(GET/POST)
* @param parser http请求内容对象
@ -247,6 +255,9 @@ void API_CALL on_mk_http_request(const mk_parser parser,
mk_webrtc_get_answer_sdp(mk_http_response_invoker_clone(invoker), on_mk_webrtc_get_answer_sdp_func,
mk_parser_get_url_param(parser, "type"), mk_parser_get_content(parser, NULL), rtc_url);
} else if (strcmp(url, "/index/api/getStatistic") == 0) {
//拦截api: /index/api/webrtc
mk_get_statistic(on_get_statistic_cb, mk_http_response_invoker_clone(invoker), (on_user_data_free) mk_http_response_invoker_clone_release);
} else {
*consumed = 0;
return;
@ -387,7 +398,7 @@ void API_CALL on_mk_rtsp_auth(const mk_media_info url_info,
/**
* mp4分片文件成功后广播
*/
void API_CALL on_mk_record_mp4(const mk_mp4_info mp4) {
void API_CALL on_mk_record_mp4(const mk_record_info mp4) {
log_printf(LOG_LEV,
"\nstart_time: %d\n"
"time_len: %d\n"
@ -399,16 +410,16 @@ void API_CALL on_mk_record_mp4(const mk_mp4_info mp4) {
"vhost: %s\n"
"app: %s\n"
"stream: %s\n",
mk_mp4_info_get_start_time(mp4),
mk_mp4_info_get_time_len(mp4),
mk_mp4_info_get_file_size(mp4),
mk_mp4_info_get_file_path(mp4),
mk_mp4_info_get_file_name(mp4),
mk_mp4_info_get_folder(mp4),
mk_mp4_info_get_url(mp4),
mk_mp4_info_get_vhost(mp4),
mk_mp4_info_get_app(mp4),
mk_mp4_info_get_stream(mp4));
mk_record_info_get_start_time(mp4),
mk_record_info_get_time_len(mp4),
mk_record_info_get_file_size(mp4),
mk_record_info_get_file_path(mp4),
mk_record_info_get_file_name(mp4),
mk_record_info_get_folder(mp4),
mk_record_info_get_url(mp4),
mk_record_info_get_vhost(mp4),
mk_record_info_get_app(mp4),
mk_record_info_get_stream(mp4));
}
/**

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/

View File

@ -1,21 +1,34 @@
# Download and build Jemalloc
set(JEMALLOC_VERSION 5.2.1)
set(JEMALLOC_VERSION 5.3.0)
set(JEMALLOC_NAME jemalloc-${JEMALLOC_VERSION})
set(JEMALLOC_TAR_PATH ${DEP_ROOT_DIR}/${JEMALLOC_NAME}.tar.bz2)
list(APPEND jemalloc_CONFIG_ARGS --disable-initial-exec-tls)
list(APPEND jemalloc_CONFIG_ARGS --without-export)
#list(APPEND jemalloc_CONFIG_ARGS --without-export)
if (ENABLE_JEMALLOC_STAT)
list(APPEND jemalloc_CONFIG_ARGS --enable-stats)
message(STATUS "Jemalloc stats enabled")
else ()
list(APPEND jemalloc_CONFIG_ARGS --disable-stats)
message(STATUS "Jemalloc stats disabled")
endif ()
list(APPEND jemalloc_CONFIG_ARGS --disable-libdl)
#list(APPEND jemalloc_CONFIG_ARGS --disable-cxx)
#list(APPEND jemalloc_CONFIG_ARGS --with-jemalloc-prefix=je_)
#list(APPEND jemalloc_CONFIG_ARGS --enable-debug)
if(NOT EXISTS ${JEMALLOC_TAR_PATH})
message(STATUS "Downloading ${JEMALLOC_NAME}...")
file(DOWNLOAD https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/${JEMALLOC_NAME}.tar.bz2
${JEMALLOC_TAR_PATH})
set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/${JEMALLOC_NAME}.tar.bz2)
message(STATUS "Downloading ${JEMALLOC_NAME} from ${JEMALLOC_URL}")
file(DOWNLOAD ${JEMALLOC_URL} ${JEMALLOC_TAR_PATH} SHOW_PROGRESS STATUS JEMALLOC_DOWNLOAD_STATUS LOG JEMALLOC_DOWNLOAD_LOG)
list(GET JEMALLOC_DOWNLOAD_STATUS 0 JEMALLOC_DOWNLOAD_STATUS_CODE)
if(NOT JEMALLOC_DOWNLOAD_STATUS_CODE EQUAL 0)
file(REMOVE ${JEMALLOC_TAR_PATH})
message(STATUS "${JEMALLOC_DOWNLOAD_LOG}")
message(FATAL_ERROR "${JEMALLOC_NAME} download failed! error is ${JEMALLOC_DOWNLOAD_STATUS}")
return()
endif ()
endif()
SET( DIR_CONTAINING_JEMALLOC ${DEP_ROOT_DIR}/${JEMALLOC_NAME} )

View File

@ -15,6 +15,8 @@ secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
snapRoot=./www/snap/
#默认截图图片在启动FFmpeg截图后但是截图还未生成时可以返回默认的预设图片
defaultSnap=./www/logo.png
#downloadFile http接口可访问文件的根目录支持多个目录不同目录通过分号(;)分隔
downloadRoot=./www
[ffmpeg]
#FFmpeg可执行程序路径,支持相对路径/绝对路径
@ -22,7 +24,7 @@ bin=/usr/bin/ffmpeg
#FFmpeg拉流再推流的命令模板通过该模板可以设置再编码的一些参数
cmd=%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s
#FFmpeg生成截图的命令可以通过修改该配置改变截图分辨率或质量
snap=%s -i %s -y -f mjpeg -frames:v 1 %s
snap=%s -i %s -y -f mjpeg -frames:v 1 -an %s
#FFmpeg日志的路径如果置空则不生成FFmpeg日志
#可以为相对(相对于本可执行程序目录)或绝对路径
log=./ffmpeg/ffmpeg.log
@ -58,6 +60,10 @@ continue_push_ms=15000
# 此外音频转码正常都是用于webrtc的一般也会开启WEBRTC, 即-DENABLE_WEBRTC=1, 此前必须自己装好libsrtp库, 安装过程详见wiki
# audio_transcode配置项可通过配置文件hook来打开注意如果编译时没启用FFMPEG此选项会自动关闭使用此分支前得先确保启用FFMPEG
audio_transcode=1
#平滑发送定时器间隔单位毫秒置0则关闭开启后影响cpu性能同时增加内存
#该配置开启后可以解决一些流发送不平滑导致zlmediakit转发也不平滑的问题
paced_sender_ms=0
#是否开启转换为hls(mpegts)
enable_hls=1
#是否开启转换为hls(fmp4)
@ -132,6 +138,8 @@ wait_track_ready_ms=10000
wait_add_track_ms=3000
#如果track未就绪我们先缓存帧数据但是有最大个数限制防止内存溢出
unready_frame_cache=100
#是否启用观看人数变化事件广播置1则启用置0则关闭
broadcast_player_count_changed=0
[hls]
#hls写文件的buf大小调整参数可以提高文件io性能
@ -141,6 +149,8 @@ segDur=2
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个)
#如果设置为0则不删除切片而是保存为点播
segNum=3
#HLS切片延迟个数大于0将生成hls_delay.m3u8文件0则不生成
segDelay=0
#HLS切片从m3u8文件中移除后继续保留在磁盘上的个数
segRetain=5
#是否广播 hls切片(ts/fmp4)完成通知(on_record_ts)
@ -152,6 +162,8 @@ deleteDelaySec=10
#0为不保留不起作用
#1为保留则不删除hls文件如果开启此功能注意磁盘大小或者定期手动清理hls文件
segKeep=0
#如果设置为1则第一个切片长度强制设置为1个GOP。当GOP小于segDur可以提高首屏速度
fastRegister=0
# 转码成opus音频时的比特率
opusBitrate=64000
# 转码成AAC音频时的比特率
@ -161,43 +173,43 @@ aacBitrate=64000
#是否启用hook事件启用后推拉流都将进行鉴权
enable=0
#播放器或推流器使用流量事件,置空则关闭
on_flow_report=https://127.0.0.1/index/hook/on_flow_report
on_flow_report=
#访问http文件鉴权事件置空则关闭鉴权
on_http_access=https://127.0.0.1/index/hook/on_http_access
on_http_access=
#播放鉴权事件,置空则关闭鉴权
on_play=https://127.0.0.1/index/hook/on_play
on_play=
#推流鉴权事件,置空则关闭鉴权
on_publish=https://127.0.0.1/index/hook/on_publish
on_publish=
#录制mp4切片完成事件
on_record_mp4=https://127.0.0.1/index/hook/on_record_mp4
on_record_mp4=
# 录制 hls ts(或fmp4) 切片完成事件
on_record_ts=https://127.0.0.1/index/hook/on_record_ts
on_record_ts=
#rtsp播放鉴权事件此事件中比对rtsp的用户名密码
on_rtsp_auth=https://127.0.0.1/index/hook/on_rtsp_auth
on_rtsp_auth=
#rtsp播放是否开启专属鉴权事件置空则关闭rtsp鉴权。rtsp播放鉴权还支持url方式鉴权
#建议开发者统一采用url参数方式鉴权rtsp用户名密码鉴权一般在设备上用的比较多
#开启rtsp专属鉴权后将不再触发on_play鉴权事件
on_rtsp_realm=https://127.0.0.1/index/hook/on_rtsp_realm
on_rtsp_realm=
#远程telnet调试鉴权事件
on_shell_login=https://127.0.0.1/index/hook/on_shell_login
on_shell_login=
#直播流注册或注销事件
on_stream_changed=https://127.0.0.1/index/hook/on_stream_changed
on_stream_changed=
#过滤on_stream_changed hook的协议类型可以选择只监听某些感兴趣的协议置空则不过滤协议
stream_changed_schemas=rtsp/rtmp/fmp4/ts/hls/hls.fmp4
#无人观看流事件通过该事件可以选择是否关闭无人观看的流。配合general.streamNoneReaderDelayMS选项一起使用
on_stream_none_reader=https://127.0.0.1/index/hook/on_stream_none_reader
on_stream_none_reader=
#播放时未找到流事件通过配合hook.on_stream_none_reader事件可以完成按需拉流
on_stream_not_found=https://127.0.0.1/index/hook/on_stream_not_found
on_stream_not_found=
#服务器启动报告,可以用于服务器的崩溃重启事件监听
on_server_started=https://127.0.0.1/index/hook/on_server_started
on_server_started=
#服务器退出报告,当服务器正常退出时触发
on_server_exited=https://127.0.0.1/index/hook/on_server_exited
on_server_exited=
#server保活上报
on_server_keepalive=https://127.0.0.1/index/hook/on_server_keepalive
on_server_keepalive=
#发送rtp(startSendRtp)被动关闭时回调
on_send_rtp_stopped=https://127.0.0.1/index/hook/on_send_rtp_stopped
on_send_rtp_stopped=
#rtp server 超时未收到数据
on_rtp_server_timeout=https://127.0.0.1/index/hook/on_rtp_server_timeout
on_rtp_server_timeout=
#hook api最大等待回复时间单位秒
timeoutSec=10
@ -225,7 +237,7 @@ timeout_sec=15
retry_count=3
[http]
#http服务器字符编码windows上默认gb2312
#http服务器字符编码
charSet=utf-8
#http链接超时时间
keepAliveSecond=30
@ -260,7 +272,7 @@ forwarded_ip_header=
#默认允许所有跨域请求
allow_cross_domains=1
#允许访问http api和http文件索引的ip地址范围白名单置空情况下不做限制
allow_ip_range=127.0.0.1,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255
allow_ip_range=::1,127.0.0.1,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255
[multicast]
#rtp组播截止组播ip地址
@ -283,6 +295,8 @@ sampleMS=500
fastStart=0
#MP4点播(rtsp/rtmp/http-flv/ws-flv)是否循环播放文件
fileRepeat=0
#MP4录制写文件格式是否采用fmp4启用的话断电未完成录制的文件也能正常打开
enableFmp4=0
[rtmp]
#rtmp必须在此时间内完成握手否则服务器会断开链接单位秒
@ -294,6 +308,10 @@ keepAliveSecond=15
port=1935
#rtmps服务器监听地址
sslport=0
# rtmp是否直接代理模式
directProxy=1
#h265 rtmp打包采用增强型rtmp标准还是国内拓展标准
enhanced=0
[rtp]
#音频mtu大小该参数限制rtp最大字节数推荐不要超过1400
@ -331,6 +349,13 @@ opus_pt=100
#如果不调用startSendRtp相关接口可以置0节省内存
gop_cache=1
#国标发送g711 rtp 打包时每个包的语音时长是多少默认是100 ms范围为20~180ms (gb28181-2016c.2.4规定)
#最好为20 的倍数程序自动向20的倍数取整
rtp_g711_dur_ms = 100
#udp接收数据socket buffer大小配置
#4*1024*1024=4196304
udp_recv_socket_buffer=4194304
[rtc]
#rtc播放推流、播放超时时间
timeoutSec=15
@ -350,7 +375,7 @@ tcpPort = 8000
rembBitRate=0
#rtc支持的音频codec类型,在前面的优先级更高
#以下范例为所有支持的音频codec
preferredCodecA=PCMU,PCMA,opus,mpeg4-generic
preferredCodecA=PCMA,PCMU,opus,mpeg4-generic
#rtc支持的视频codec类型,在前面的优先级更高
#以下范例为所有支持的视频codec
preferredCodecV=H264,H265,AV1,VP9,VP8
@ -359,6 +384,29 @@ preferredCodecV=H264,H265,AV1,VP9,VP8
# 将由rtc流入g711音频转成aac并转给其他协议流
transcodeG711=0
#webrtc比特率设置
start_bitrate=0
max_bitrate=0
min_bitrate=0
#nack接收端
#Nack缓存包最早时间间隔
maxNackMS=5000
#Nack包检查间隔(包数量)
rtpCacheCheckInterval=100
#nack发送端
#最大保留的rtp丢包状态个数
nackMaxSize=2048
#rtp丢包状态最长保留时间
nackMaxMS=3000
#nack最多请求重传次数
nackMaxCount=15
#nack重传频率rtt的倍数
nackIntervalRatio=1.0
#nack包中rtp个数减小此值可以让nack包响应更灵敏
nackRtpSize=8
[srt]
#srt播放推流、播放超时时间,单位秒
timeoutSec=5

1
conf/novideo.yuv Normal file

File diff suppressed because one or more lines are too long

24
conf/readme.md Normal file
View File

@ -0,0 +1,24 @@
## 配置文件影响性能的参数
### 1、protocol.enable_xxx
控制转协议开关关闭某些协议节省cpu和内存。
### 2、protocol.xxx_demand
控制按需转协议开启转协议且按需转协议时无人观看时节省cpu和内存但是第一个播放器无法秒开影响体验
### 3、protocol.paced_sender_ms
平滑发送定时器频率,用于解决数据源发送不平滑导致转发不平滑播放器卡顿问题,开启后定时器根据数据时间戳驱动数据发送,提高用户体验。
但是增加cpu和内存使用。定时器间隔越小cpu占用越高但是平滑度越好建议设置30~100ms。此功能结合protocol.modify_stamp为2(抑制时间戳跳跃)最佳。
### 4、general.mergeWriteMS
开启合并写,减少发送数据时系统调用次数以及线程间数据共享频率,大大提高转发性能,但是牺牲播放延时和发送平滑度。
### 5、rtp_proxy.gop_cache
开启startSendRtp级联接口的gop缓存功能用于国标级联秒开。该选项不影响zlmediakit对外提供直播服务的秒开。
开启该选项后增加内存使用对cpu影响较小如果不调用startSendRtp接口建议关闭。
### 6、hls.fileBufSize
调整该配置可以提高hls协议写磁盘io性能。
### 7、record.fileBufSize
调整该配置可以提高mp4录制写磁盘io性能。

View File

@ -1,89 +1,89 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAjTFnNz2btUHR/K8TegU2n06lXsQuW4AfsMGthBLvnz2zdgL2
uVxfRCuleoRpECEV9I80ibTXAJlouRLbnhLHto8gzyLeQue9/DtxTEGcS7y2aMha
0wAoUcOBv7tAITSnFepGHXoYgyU7HOCvn96U1bzqLTOhxOCH/xy003dwoEC7+Pjl
dsWs/16cpvYiZV/dZvzDDKIpHSIvQy1whi6N0SDpzz/ncThn1z8xcJDx0I1jVR76
juP7TttbyhqJkO+fOlLn4yP9K5wZ/dPFJn2+bQRCrzGc4SM7J5YOq8ckTTTbZtSp
9yPpm7O5QyfdzePhOpRrjWroLsqaDOPV2UQlzwIDAQABAoIBADCWTh8P19vdnR3X
v5uPXLcgkL7WQt+g7Qbd91CKVaRWTsHvDilGVNA4Ntc85oyy3gPNHfa/YPdnU0bQ
6vtwGgLEKTWumY6rgdDhQcFMmLTlaV4QiFSw6q8MWMN6c/yZSmA7wMoXAIVs0/VB
ip44sb4Fpw5MBMCjxZjwL3fP09WJPlUqx09vVo7eH8rFwLBikmn982IzRigAx1I8
TX0wkdqvv33MSxBXPMQIrwPqjf2arxWFzb6vp6yolYbMZtgORF9gznWABRy3oY50
9jFkTkbxZFlSMVuF7nlM0WJj5Q9/IelBqpozODWUVvB+6inCqkxNLkbh0ISbpXWC
16gUZfUCgYEAxWo3FRNBrNXhVD5h2N4ApyUXkZ5UYIY5zbsHEJCrPjooh9uHu9kh
xXh5v11J/7TV9BfwLZ4qRbDBH4fq0DKEOXOZRLY5Lo4KbrYmlEDCabuJdmwwHeGh
S5K37F5z/+zPz9KWkKN+9Rg32xdLxh0969O77GnvuBrhzASpVsF6ZFMCgYEAtxf1
eVg4Kxzuy0AWs+CisSVQc+5CbZ9teKA5fli2EVSmL5dsrKatVTIDghudJgQTU6cr
zP9I20K11jeqIoK5saQXH3CzogN6aDuKssq4rDbvVSZ09Zry6N1WMz9GPe31zEYw
sdU1w7vUw+l3unFfWOP4oZm0MH+na61V1YohCRUCgYANlp0J/1RS8DndUZnskoNa
/eucY1iNeE+8QHZhBoQy+U/W4h56qJxxejRvHp28UxczAP7QNQXV3C++2t0nzYJa
bgGLwDs5YB+JtVH8fGSlYHo6w4GgXOp8SDIOvAWiBQvc0zL367kOZ8dYdkcJ8PNV
KzLROA1/D6KhJ2T8ir7A7wKBgQCjVVxGw8xXqZfc+W9HSD3aic8bnJDl+jNOSKEB
dWH2U+1sx0jLPGWketlmV/v4zenv1lHcrl/wObK9RysfXj8JmbiG86NMBI5OLc+t
b+sOtnMLIyNzdqb71Xfwf6HJ3V5IvNTzz6AG3KkRnFSSnlDQm45RmyyDl11jUV4h
APg3gQKBgBzFeuKWnaTZz1FQBr5Ytl9gtxBRMl+49jtkqyzErJYFHe0MTWeD/1xj
mEC/7UERYWhIQF1L4ah6c0QkecR3F1s9/IYK/QHsnSJFwRyFuMas6StCERsDq5oQ
GWpXAmw7JTa8OYwxVjORdXY25Iwv6rEr6iUYBWZrkhoWYBySWpSZ
MIIEowIBAAKCAQEAtgg0vsIc8bIMb9hAO1Lwq2TVNYMiD928WCVwq7Bj3B9LM8ci
fN+mBxHz35SeC9JnQysbKAf8VVfVi7GVzwFq4VaRreoIl8DoMbBORb2iKxfLXKEH
S283bbl17csAYHTTBqFsKnO3kKvYoDHRKFX0T0rzZibI0ACQiylW+ALE3fVS0hFI
8fmoZnIAOyQ15RLp7KPO4bMRVdZaOqRUZeW0YzbvOBeGZKbx3bXiscL9RwfGSxlF
MCLahaJsBrVDo4/IGDRCmSydK8k/41MHd86pGPzCixBx7cqtKO/6+cVeEuGxfJPf
JVuxNq6vkRSt2HxCc6i2iagA2uL/WYdg3Pa/4wIDAQABAoIBAADFrCObAzBrRu46
hps50NeJR/ZAJibXE/NzxTSVPPc0EseXcqgA8t1Y0CYEpV77d4CrcCQNVJ6wDrHX
AQGtydxG17tbIMo0AUgkrVBSa5uvMCembzd8s0l93egyUkAWfsaqbKEJeJ/eer7D
N1Xqd2zWro2iYHuxZOuSM1I+AMPIQsmYJ71w6/h9YpQh436Vd+zNQ5k/nWpLHihT
VB2ECrJ36IbuiYo3UbSr9gQjyBSMkk/oUqO4jonkb6L7r0mqHXNeblycg99/m6i7
O5c5DQKMhzqibwvNNf6uvWCcLKfF5Kqzzf9DKR3/pYOBQrVTA24l4UFsfTdEKUNS
a8W3P8ECgYEA6CQOG15V9upc2nPzfFwgftGyomSMYH54PkSFdr2R4djyXkyil6Ik
efK3E+lKr9YnzwcLw3csPmVt3lqSgixQUMcyXXrhCttfk/qzSJkI+UZPQE+SrNeW
0c+blQOzVcfbNRu248iGFaRx+5qA6PMH4UZTgn7e6nXoPUgRp4ryI/MCgYEAyL24
R7uMSuPQBRJFU84Lu+Rv4lkKdCYSLuQtMZly74m11iG6e+EHJQx0C3eexrC8LhOV
Sm4xTlwVrYQ+IdW51bhAwwHcnzGUzpbESJSDK5ZTd/P5daz8yt8ZaGbUFxNEsxTr
ElKPRcjJH5CRuyYr24DYg+CpMGdlF0N6Pcx5IFECgYAedlzDiqWNOUPmBsE02IIL
IklmtfsVzoLI6QT6h/XUxTtI1JWhgE15EzijDEIYwOmIaUxJ4iGULos0Wn5PRrFj
aEBbs/xECHWKXaOZKzvaOje8ILUGqWPJNI0eCNZHs2o4leJyEaZGwMWUVroD16B5
F1luDmgCLGbFY+etLLaJsQKBgB40VbcNZDWcg59PuXi7pw5Vd/RB243QcKn3kUlG
QoICYYbfulSLbmzHq+pRzGUvEJGKRstVOzwEJQrfvA2RQA4FVFFDRXP6nN5c1xno
prf3PYXuAtoO9lZ8LTGFT2JNdufPPPOb0oz4gjKqqRLU0oKLp4hoVGzBEffnIkyM
KKmRAoGBAIGXh4gvxzEQMgGzfKfNuxKCT9SEhsg7NU++Iey3qn4G4t+jIWOt2Gi7
5+y49JWoGq6DL+2ZVVw6Cn6wd9tfzDKD5GhvIztK0z1+wqpFOL4M8bwqJDOKgsZ3
PCPASbxPgMyNCjRhvxBuscCr+dRFYDUrirOK9EUPyO9EoNTPPN9a
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIGAjCCBOqgAwIBAgIQAiXv68Xco/vd9YeB4g3HLjANBgkqhkiG9w0BAQsFADBu
MIIGBTCCBO2gAwIBAgIQDNIYeWoFoT3jxF2+HmEbTDANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
RFYgVExTIENBIC0gRzEwHhcNMjIwOTE4MDAwMDAwWhcNMjMwOTE4MjM1OTU5WjAh
RFYgVExTIENBIC0gRzIwHhcNMjMwOTI4MDAwMDAwWhcNMjQwOTI3MjM1OTU5WjAh
MR8wHQYDVQQDExZkZWZhdWx0LnpsbWVkaWFraXQuY29tMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAjTFnNz2btUHR/K8TegU2n06lXsQuW4AfsMGthBLv
nz2zdgL2uVxfRCuleoRpECEV9I80ibTXAJlouRLbnhLHto8gzyLeQue9/DtxTEGc
S7y2aMha0wAoUcOBv7tAITSnFepGHXoYgyU7HOCvn96U1bzqLTOhxOCH/xy003dw
oEC7+PjldsWs/16cpvYiZV/dZvzDDKIpHSIvQy1whi6N0SDpzz/ncThn1z8xcJDx
0I1jVR76juP7TttbyhqJkO+fOlLn4yP9K5wZ/dPFJn2+bQRCrzGc4SM7J5YOq8ck
TTTbZtSp9yPpm7O5QyfdzePhOpRrjWroLsqaDOPV2UQlzwIDAQABo4IC5zCCAuMw
HwYDVR0jBBgwFoAUVXRPsnJP9WC6UNHX5lFcmgGHGtcwHQYDVR0OBBYEFPnRZrfz
q/QAf5u4Xp4eGWvhMdvfMCEGA1UdEQQaMBiCFmRlZmF1bHQuemxtZWRpYWtpdC5j
b20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
AjA+BgNVHSAENzA1MDMGBmeBDAECATApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9DUFMwgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYY
AQEFAAOCAQ8AMIIBCgKCAQEAtgg0vsIc8bIMb9hAO1Lwq2TVNYMiD928WCVwq7Bj
3B9LM8cifN+mBxHz35SeC9JnQysbKAf8VVfVi7GVzwFq4VaRreoIl8DoMbBORb2i
KxfLXKEHS283bbl17csAYHTTBqFsKnO3kKvYoDHRKFX0T0rzZibI0ACQiylW+ALE
3fVS0hFI8fmoZnIAOyQ15RLp7KPO4bMRVdZaOqRUZeW0YzbvOBeGZKbx3bXiscL9
RwfGSxlFMCLahaJsBrVDo4/IGDRCmSydK8k/41MHd86pGPzCixBx7cqtKO/6+cVe
EuGxfJPfJVuxNq6vkRSt2HxCc6i2iagA2uL/WYdg3Pa/4wIDAQABo4IC6jCCAuYw
HwYDVR0jBBgwFoAUeN+RkF/u3qz2xXXr1UxVU+8kSrYwHQYDVR0OBBYEFHmEMVp9
9EHIPWA2U1iLKogCosGFMCEGA1UdEQQaMBiCFmRlZmF1bHQuemxtZWRpYWtpdC5j
b20wPgYDVR0gBDcwNTAzBgZngQwBAgEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3
dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggr
BgEFBQcDAQYIKwYBBQUHAwIwgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5odHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRW5jcnlwdGlvbkV2ZXJ5d2hlcmVEVlRMU0NBLUcx
LmNydDAJBgNVHRMEAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdgDoPtDa
PvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYNQt3JvAAAEAwBHMEUCIEaO
G4ffzzaE6OMqiu6PUr+Y+wO2tsXCkGt1jt04Ix1qAiEAhNZwqFACieds1ZbY3r/p
wlF3iFbhqp+kNfPzon7kwc8AdgA1zxkbv7FsV78PrUxtQsu7ticgJlHqP+Eq76gD
wzvWTAAAAYNQt3JVAAAEAwBHMEUCIBOErqyKvihAEKItLWG/Plgtxh/hCTMsE+t5
+MfsAQLCAiEA76d50S4iy1wxya+8IUASVlKStaHNqBkJAS+Oadxs2sMAdwCzc3cH
4YRQ+GOG1gWp3BEJSnktsWcMC4fc8AMOeTalmgAAAYNQt3LIAAAEAwBIMEYCIQC/
kfFCpwF76sw/Qx3sxR8b3srW+Ds0k/6VrIIDZcYV5gIhAKkLmuyeDvzulp0y4f0t
GDgIN/OoURq6CuHA67UJlsWzMA0GCSqGSIb3DQEBCwUAA4IBAQB0BwVxPRihSdPJ
FUPLQ+ClHy9O/UisnRD7NadQQtbcMXn6L9Lwd0f2la0ytLQAKHADOZDA08KfQ5qW
B19OeQOlTwp2nhY2ZvoLEG+paeh0gYxIgD76APnd/m3g2H7GeW144ymjPcZRoldj
ZKYSdzStJJIFYXzL3FR9wjkMc4xOEes/IY5PFtj8OT8CFf7zl0R7L2Vcw9RGYi9u
vLjGwwJW9kXTX8UlKXFyjJN0ZyrmxBQHq5uNtigx8xy6HtMnPsc58tp1IqitIELp
HIur2XrRPBJA5XtpDg3AE8bXhRTM8oFMPL0UoSFWyWRYGgBo1Msc10dpXPtmbgIc
pPW8w+2c
ZXJ0cy5kaWdpY2VydC5jb20vRW5jcnlwdGlvbkV2ZXJ5d2hlcmVEVlRMU0NBLUcy
LmNydDAMBgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdgDu
zdBk1dsazsVct520zROiModGfLzs3sNRSFlGcR+1mwAAAYravqonAAAEAwBHMEUC
IQDX+gqsd7I0yzjkhgp2YrccUlTx4wkFptFvmQxeChImRgIgJdgJa2Uamd790BCI
/CZwSqmRlor5eU8exAixdcopYpcAdwBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZ
u7+rOdiEcwAAAYravqqCAAAEAwBIMEYCIQCP6rkKg2FlF92CyMbVMk3ESh/9gVaM
tRsv5I//i5IVigIhAINHERhy7812wR47fwmvqWDjxyOB1ZodU7WA9D5L/1bVAHYA
2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sAAAGK2r6qQQAABAMARzBF
AiAiz3bp/j4SlnVxKg1HZY+YdUboi+kaKf5G8X6aFLIqUgIhAPPCm5UN05p7Oqrc
sP/wdHDB7O/2AbUksYSLhidmwfmhMA0GCSqGSIb3DQEBCwUAA4IBAQBmaG51jU1E
MsgT1VzutQUXglEvJGVf54cA+0TSfjfnP1n9ALdKjGxHL3KBh4UkPx5zdE5//FUX
dacua6BQEWSCmMtYL0CFieFnLGXh0mgkfvRaP6+3xe6TkJ4kuyJkMS9YMDpVl80F
2GLlE09EsZ3Xk9+SCpmWOPLOCDFURbwpc5ht+acROfzYJQyCY0L8EGbyL5/q9oMn
ugRGh4oyGvXgKvFIPzpZkaOmb0b63/uBc5JkiyQhuFdYaS2cLOwupXmCtIHL4Od6
OU8/8smT8NEkD7d3lUijtc84q2TihW7ebT7RtOco49PDvFP/7w28QjxM8Ohv9/Gz
Xyta8ICQVwmK
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIQAnmsRYvBskWr+YBTzSybsTANBgkqhkiG9w0BAQsFADBh
MIIEqjCCA5KgAwIBAgIQDeD/te5iy2EQn2CMnO1e0zANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzExMjcxMjQ2MTBaFw0yNzExMjcxMjQ2MTBaMG4xCzAJBgNVBAYTAlVT
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xNzExMjcxMjQ2NDBaFw0yNzExMjcxMjQ2NDBaMG4xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPeP6wkab41dyQh6mKc
oHqt3jRIxW5MDvf9QyiOR7VfFwK656es0UFiIb74N9pRntzF1UgYzDGu3ppZVMdo
lbxhm6dWS9OK/lFehKNT0OYI9aqk6F+U7cA6jxSC+iDBPXwdF4rs3KRyp3aQn6pj
pp1yr7IB6Y4zv72Ee/PlZ/6rK6InC6WpK0nPVOYR7n9iDuPe1E4IxUMBH/T33+3h
yuH3dvfgiWUOUkjdpMbyxX+XNle5uEIiyBsi4IvbcTCh8ruifCIi5mDXkZrnMT8n
wfYCV6v6kDdXkbgGRLKsR4pucbJtbKqIkUGxuZI2t7pfewKRc5nWecvDBZf3+p1M
pA8CAwEAAaOCAU8wggFLMB0GA1UdDgQWBBRVdE+yck/1YLpQ0dfmUVyaAYca1zAf
BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYw
MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO8Uf46i/nr7pkgTDqnE
eSIfCFqvPnUq3aF1tMJ5hh9MnO6Lmt5UdHfBGwC9Si+XjK12cjZgxObsL6Rg1njv
NhAMJ4JunN0JGGRJGSevbJsA3sc68nbPQzuKp5Jc8vpryp2mts38pSCXorPR+sch
QisKA7OSQ1MjcFN0d7tbrceWFNbzgL2csJVQeogOBGSe/KZEIZw6gXLKeFe7mupn
NYJROi2iC11+HuF79iAttMc32Cv6UOxixY/3ZV+LzpLnklFq98XORgwkIJL1HuvP
ha8yvb+W6JislZJL+HLFtidoxmI7Qm3ZyIV66W533DsGFimFJkz3y0GeHWuSVMbI
lfsCAwEAAaOCAU8wggFLMB0GA1UdDgQWBBR435GQX+7erPbFdevVTFVT7yRKtjAf
BgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAK3Gp6/aGq7aBZsxf/oQ+TD/B
SwW3AU4ETK+GQf2kFzYZkby5SFrHdPomunx2HBzViUchGoofGgg7gHW0W3MlQAXW
M0r5LUvStcr82QDWYNPaUy4taCQmyaJ+VB+6wxHstSigOlSNF2a6vg4rgexixeiV
4YSB03Yqp2t3TeZHM9ESfkus74nQyW7pRGezj+TC44xCagCQQOzzNmzEAP2SnCrJ
sNE2DpRVMnL8J6xBRdjmOsC3N6cQuKuRXbzByVBjCqAA8t1L0I+9wXJerLPyErjy
rMKWaBFLmfK/AHNF4ZihwPGOc7w6UHczBZXH5RFzJNnww+WnKuTPI0HfnVH8lg==
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
-----END CERTIFICATE-----

View File

@ -94,7 +94,7 @@ RUN cd /opt \
&& make install
RUN cd /opt \
&& git clone --depth 1 https://github.com/xia-chu/ZLMediaKit.git \
&& git clone --depth 1 https://github.com/ZLMediaKit/ZLMediaKit.git \
&& cd ZLMediaKit \
&& git submodule update --init \
&& mkdir -p build release/linux/Release/ \
@ -112,7 +112,7 @@ RUN mkdir -p /opt/build/opt/zlm/ /opt/build/usr/local/bin/ /opt/build/usr/bin/
&& /usr/bin/cp -ip /usr/bin/which ./usr/bin/
FROM centos:${Version}
LABEL maintainer="chengxiaosheng <kevin__cheng@outlook.com>" project-url="https://github.com/xia-chu/ZLMediaKit" description="一个基于C++11的高性能运营级流媒体服务框架"
LABEL maintainer="chengxiaosheng <kevin__cheng@outlook.com>" project-url="https://github.com/ZLMediaKit/ZLMediaKit" description="一个基于C++11的高性能运营级流媒体服务框架"
EXPOSE 9000/tcp \
1935/tcp \
@ -128,4 +128,4 @@ WORKDIR /opt/zlm
VOLUME [ "/opt/zlm/conf/","/opt/zlm/log/","opt/zlm/ffmpeg/"]
COPY --from=build /opt/build /
ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH TZ=Asia/Shanghai
CMD ./MediaServer -c ./conf/config.ini
CMD ["./MediaServer", "-c" , "./conf/config.ini"]

View File

@ -32,7 +32,7 @@ RUN apt-get update && \
RUN mkdir -p /opt/media
WORKDIR /opt/media
RUN git clone --depth=1 https://github.com/xia-chu/ZLMediaKit && \
RUN git clone --depth=1 https://github.com/ZLMediaKit/ZLMediaKit && \
cd ZLMediaKit && git submodule update --init --recursive && \
mkdir -p build release/linux/Release/
@ -41,4 +41,4 @@ RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \
make
ENV PATH /opt/media/ZLMediaKit/release/linux/Release/:$PATH
CMD MediaServer
CMD ["MediaServer"]

View File

@ -31,7 +31,7 @@ RUN apt-get update && \
RUN mkdir -p /opt/media
WORKDIR /opt/media
RUN git clone --depth=1 https://github.com/xia-chu/ZLMediaKit && \
RUN git clone --depth=1 https://github.com/ZLMediaKit/ZLMediaKit && \
cd ZLMediaKit && git submodule update --init --recursive && \
mkdir -p build release/linux/Release/
@ -60,4 +60,4 @@ RUN apt-get update && \
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
CMD ["MediaServer"]

View File

@ -33,7 +33,7 @@ RUN apt-get update && \
RUN mkdir -p /opt/media
WORKDIR /opt/media
RUN git clone --depth=1 https://github.com/xia-chu/ZLMediaKit && \
RUN git clone --depth=1 https://github.com/ZLMediaKit/ZLMediaKit && \
cd ZLMediaKit && git submodule update --init --recursive && \
mkdir -p build release/linux/Release/
@ -42,4 +42,4 @@ RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \
make
ENV PATH /opt/media/ZLMediaKit/release/linux/Release:$PATH
CMD MediaServer
CMD ["MediaServer"]

View File

@ -31,7 +31,7 @@ RUN apt-get update && \
RUN mkdir -p /opt/media
WORKDIR /opt/media
RUN git clone --depth=1 https://github.com/xia-chu/ZLMediaKit && \
RUN git clone --depth=1 https://github.com/ZLMediaKit/ZLMediaKit && \
cd ZLMediaKit && git submodule update --init --recursive && \
mkdir -p build release/linux/Release/
@ -60,4 +60,4 @@ RUN apt-get update && \
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
CMD ["MediaServer"]

View File

@ -1,4 +1,4 @@
FROM ubuntu:18.04 AS build
FROM ubuntu:20.04 AS build
ARG MODEL
#shell,rtmp,rtsp,rtsps,http,https,rtp
EXPOSE 1935/tcp
@ -31,24 +31,31 @@ RUN apt-get update && \
gcc \
g++ \
libavcodec-dev libavutil-dev libswscale-dev libresample-dev \
libsdl-dev libusrsctp-dev \
gdb && \
apt-get autoremove -y && \
apt-get clean -y && \
wget https://github.com/cisco/libsrtp/archive/v2.2.0.tar.gz -O libsrtp-2.2.0.tar.gz && tar xfv libsrtp-2.2.0.tar.gz && \
cd libsrtp-2.2.0 && ./configure --enable-openssl && make -j $(nproc) && make install && \
rm -rf /var/lib/apt/lists/*
RUN mkdir -p /opt/media
COPY . /opt/media/ZLMediaKit
WORKDIR /opt/media/ZLMediaKit
# 3rdpart init
WORKDIR /opt/media/ZLMediaKit/3rdpart
RUN wget https://github.com/cisco/libsrtp/archive/v2.3.0.tar.gz -O libsrtp-2.3.0.tar.gz && \
tar xfv libsrtp-2.3.0.tar.gz && \
mv libsrtp-2.3.0 libsrtp && \
cd libsrtp && ./configure --enable-openssl && make -j $(nproc) && make install
#RUN git submodule update --init --recursive && \
RUN mkdir -p build release/linux/${MODEL}/
WORKDIR /opt/media/ZLMediaKit/build
RUN cmake -DCMAKE_BUILD_TYPE=${MODEL} -DENABLE_WEBRTC=true -DENABLE_FFMPEG=true -DENABLE_TESTS=false -DENABLE_API=false .. && \
make -j $(nproc)
FROM ubuntu:18.04
FROM ubuntu:20.04
ARG MODEL
# ADD sources.list /etc/apt/sources.list
@ -68,6 +75,7 @@ RUN apt-get update && \
gcc \
g++ \
libavcodec-dev libavutil-dev libswscale-dev libresample-dev \
libsdl-dev libusrsctp-dev \
gdb && \
apt-get autoremove -y && \
apt-get clean -y && \
@ -83,4 +91,4 @@ COPY --from=build /opt/media/ZLMediaKit/release/linux/${MODEL}/MediaServer /opt/
COPY --from=build /opt/media/ZLMediaKit/release/linux/${MODEL}/config.ini /opt/media/conf/
COPY --from=build /opt/media/ZLMediaKit/www/ /opt/media/bin/www/
ENV PATH /opt/media/bin:$PATH
CMD ["sh","-c","./MediaServer -s default.pem -c ../conf/config.ini -l 0"]
CMD ["./MediaServer","-s", "default.pem", "-c", "../conf/config.ini", "-l","0"]

View File

@ -1,14 +1,18 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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"
#include "AACRtp.h"
#include "AACRtmp.h"
#include "Common/Parser.h"
#include "Extension/Factory.h"
#ifdef ENABLE_MP4
#include "mpeg4-aac.h"
#endif
@ -17,57 +21,60 @@ using namespace std;
using namespace toolkit;
namespace mediakit{
unsigned const samplingFrequencyTable[16] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0 };
#ifndef ENABLE_MP4
class AdtsHeader{
class AdtsHeader {
public:
unsigned int syncword = 0; //12 bslbf 同步字The bit string 1111 1111 1111说明一个ADTS帧的开始
unsigned int id; //1 bslbf MPEG 标示符, 设置为1
unsigned int layer; //2 uimsbf Indicates which layer is used. Set to 00
unsigned int protection_absent; //1 bslbf 表示是否误码校验
unsigned int profile; //2 uimsbf 表示使用哪个级别的AAC如01 Low Complexity(LC)--- AACLC
unsigned int sf_index; //4 uimsbf 表示使用的采样率下标
unsigned int private_bit; //1 bslbf
unsigned int channel_configuration; //3 uimsbf 表示声道数
unsigned int original; //1 bslbf
unsigned int home; //1 bslbf
//下面的为改变的参数即每一帧都不同
unsigned int copyright_identification_bit; //1 bslbf
unsigned int copyright_identification_start; //1 bslbf
unsigned int syncword = 0; // 12 bslbf 同步字The bit string 1111 1111 1111说明一个ADTS帧的开始
unsigned int id; // 1 bslbf MPEG 标示符, 设置为1
unsigned int layer; // 2 uimsbf Indicates which layer is used. Set to 00
unsigned int protection_absent; // 1 bslbf 表示是否误码校验
unsigned int profile; // 2 uimsbf 表示使用哪个级别的AAC如01 Low Complexity(LC)--- AACLC
unsigned int sf_index; // 4 uimsbf 表示使用的采样率下标
unsigned int private_bit; // 1 bslbf
unsigned int channel_configuration; // 3 uimsbf 表示声道数
unsigned int original; // 1 bslbf
unsigned int home; // 1 bslbf
// 下面的为改变的参数即每一帧都不同
unsigned int copyright_identification_bit; // 1 bslbf
unsigned int copyright_identification_start; // 1 bslbf
unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 说明是码率可变的码流
//no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
//所以说number_of_raw_data_blocks_in_frame == 0
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
unsigned int adts_buffer_fullness; // 11 bslbf 0x7FF 说明是码率可变的码流
// no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
// 所以说number_of_raw_data_blocks_in_frame == 0
// 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
unsigned int no_raw_data_blocks_in_frame; // 2 uimsfb
};
static void dumpAdtsHeader(const AdtsHeader &hed, uint8_t *out) {
out[0] = (hed.syncword >> 4 & 0xFF); //8bit
out[1] = (hed.syncword << 4 & 0xF0); //4 bit
out[1] |= (hed.id << 3 & 0x08); //1 bit
out[1] |= (hed.layer << 1 & 0x06); //2bit
out[1] |= (hed.protection_absent & 0x01); //1 bit
out[0] = (hed.syncword >> 4 & 0xFF); // 8bit
out[1] = (hed.syncword << 4 & 0xF0); // 4 bit
out[1] |= (hed.id << 3 & 0x08); // 1 bit
out[1] |= (hed.layer << 1 & 0x06); // 2bit
out[1] |= (hed.protection_absent & 0x01); // 1 bit
out[2] = (hed.profile << 6 & 0xC0); // 2 bit
out[2] |= (hed.sf_index << 2 & 0x3C); //4bit
out[2] |= (hed.private_bit << 1 & 0x02); //1 bit
out[2] |= (hed.channel_configuration >> 2 & 0x03); //1 bit
out[2] |= (hed.sf_index << 2 & 0x3C); // 4bit
out[2] |= (hed.private_bit << 1 & 0x02); // 1 bit
out[2] |= (hed.channel_configuration >> 2 & 0x03); // 1 bit
out[3] = (hed.channel_configuration << 6 & 0xC0); // 2 bit
out[3] |= (hed.original << 5 & 0x20); //1 bit
out[3] |= (hed.home << 4 & 0x10); //1 bit
out[3] |= (hed.copyright_identification_bit << 3 & 0x08); //1 bit
out[3] |= (hed.copyright_identification_start << 2 & 0x04); //1 bit
out[3] |= (hed.aac_frame_length >> 11 & 0x03); //2 bit
out[4] = (hed.aac_frame_length >> 3 & 0xFF); //8 bit
out[5] = (hed.aac_frame_length << 5 & 0xE0); //3 bit
out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F); //5 bit
out[6] = (hed.adts_buffer_fullness << 2 & 0xFC); //6 bit
out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03); //2 bit
out[3] |= (hed.original << 5 & 0x20); // 1 bit
out[3] |= (hed.home << 4 & 0x10); // 1 bit
out[3] |= (hed.copyright_identification_bit << 3 & 0x08); // 1 bit
out[3] |= (hed.copyright_identification_start << 2 & 0x04); // 1 bit
out[3] |= (hed.aac_frame_length >> 11 & 0x03); // 2 bit
out[4] = (hed.aac_frame_length >> 3 & 0xFF); // 8 bit
out[5] = (hed.aac_frame_length << 5 & 0xE0); // 3 bit
out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F); // 5 bit
out[6] = (hed.adts_buffer_fullness << 2 & 0xFC); // 6 bit
out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03); // 2 bit
}
static void parseAacConfig(const string &config, AdtsHeader &adts) {
static bool parseAacConfig(const string &config, AdtsHeader &adts) {
if (config.size() < 2) {
return false;
}
uint8_t cfg1 = config[0];
uint8_t cfg2 = config[1];
@ -94,6 +101,7 @@ static void parseAacConfig(const string &config, AdtsHeader &adts) {
adts.aac_frame_length = 7;
adts.adts_buffer_fullness = 2047;
adts.no_raw_data_blocks_in_frame = 0;
return true;
}
#endif// ENABLE_MP4
@ -168,10 +176,12 @@ int dumpAacConfig(const string &config, size_t length, uint8_t *out, size_t out_
#endif
}
bool parseAacConfig(const string &config, int &samplerate, int &channels){
bool parseAacConfig(const string &config, int &samplerate, int &channels) {
#ifndef ENABLE_MP4
AdtsHeader header;
parseAacConfig(config, header);
if (!parseAacConfig(config, header)) {
return false;
}
samplerate = samplingFrequencyTable[header.sf_index];
channels = header.channel_configuration;
return true;
@ -199,53 +209,36 @@ public:
/**
*
* @param aac_cfg aac两个字节的配置描述
* @param payload_type rtp payload type
* @param sample_rate
* @param payload_type rtp payload type 98
* @param channels
* @param bitrate
*/
AACSdp(const string &aac_cfg,
int sample_rate,
int channels,
int bitrate = 128,
int payload_type = 98) : Sdp(sample_rate,payload_type){
AACSdp(const string &aac_cfg, int payload_type, int sample_rate, int channels, int bitrate)
: Sdp(sample_rate, payload_type) {
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << sample_rate << "/" << channels << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecAAC) << "/" << sample_rate << "/" << channels << "\r\n";
string configStr;
char buf[4] = {0};
for(auto &ch : aac_cfg){
char buf[4] = { 0 };
for (auto &ch : aac_cfg) {
snprintf(buf, sizeof(buf), "%02X", (uint8_t)ch);
configStr.append(buf);
}
_printer << "a=fmtp:" << payload_type << " streamtype=5;profile-level-id=1;mode=AAC-hbr;"
<< "sizelength=13;indexlength=3;indexdeltalength=3;config=" << configStr << "\r\n";
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
}
string getSdp() const override {
return _printer;
}
string getSdp() const override { return _printer; }
CodecId getCodecId() const override {
return CodecAAC;
}
private:
_StrPrinter _printer;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
AACTrack::AACTrack(const string &aac_cfg) {
if (aac_cfg.size() < 2) {
throw std::invalid_argument("adts配置必须最少2个字节");
}
_cfg = aac_cfg;
onReady();
}
AACTrack::AACTrack(int samplerate, int channel, int profile) : _channel(channel), _sampleRate(samplerate) {
uint8_t audioSpecificConfig[2] = { 0 };
uint8_t audioObjectType = profile+1;
@ -259,18 +252,22 @@ AACTrack::AACTrack(int samplerate, int channel, int profile) : _channel(channel)
_cfg.resize(2);
_cfg[0] = (audioObjectType << 3) | (samplingFrequencyIndex >> 1);
_cfg[1] = (samplingFrequencyIndex << 7) | (channel << 3);
// onReady();
// update();
}
const string &AACTrack::getConfig() const {
return _cfg;
AACTrack::AACTrack(const string &aac_cfg) {
if (aac_cfg.size() < 2) {
throw std::invalid_argument("adts配置必须最少2个字节");
}
_cfg = aac_cfg;
update();
}
CodecId AACTrack::getCodecId() const {
return CodecAAC;
}
bool AACTrack::ready() {
bool AACTrack::ready() const {
return !_cfg.empty();
}
@ -286,9 +283,25 @@ int AACTrack::getAudioChannel() const {
return _channel;
}
static Frame::Ptr addADTSHeader(const Frame::Ptr &frame_in, const std::string &aac_config) {
auto frame = FrameImp::create();
frame->_codec_id = CodecAAC;
// 生成adts头
char adts_header[32] = { 0 };
auto size = dumpAacConfig(aac_config, frame_in->size(), (uint8_t *)adts_header, sizeof(adts_header));
CHECK(size > 0, "Invalid adts config");
frame->_prefix_size = size;
frame->_dts = frame_in->dts();
frame->_buffer.assign(adts_header, size);
frame->_buffer.append(frame_in->data(), frame_in->size());
frame->setIndex(frame_in->getIndex());
return frame;
}
bool AACTrack::inputFrame(const Frame::Ptr &frame) {
if (!frame->prefixSize()) {
return inputFrame_l(frame);
CHECK(ready());
return inputFrame_l(addADTSHeader(frame, _cfg));
}
bool ret = false;
@ -299,66 +312,139 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
auto ptr = frame->data();
auto end = frame->data() + frame->size();
while (ptr < end) {
auto frame_len = getAacFrameLength((uint8_t *) ptr, end - ptr);
auto frame_len = getAacFrameLength((uint8_t *)ptr, end - ptr);
if (frame_len < ADTS_HEADER_LEN) {
break;
}
if (frame_len == (int)frame->size()) {
return inputFrame_l(frame);
}
auto sub_frame = std::make_shared<FrameTSInternal<FrameFromPtr> >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN,dts,pts);
auto sub_frame = std::make_shared<FrameInternalBase<FrameFromPtr>>(frame, (char *)ptr, frame_len, dts, pts, ADTS_HEADER_LEN);
ptr += frame_len;
if (ptr > end) {
WarnL << "invalid aac length in adts header: " << frame_len
<< ", remain data size: " << end - (ptr - frame_len);
break;
}
sub_frame->setCodecId(CodecAAC);
if (inputFrame_l(sub_frame)) {
ret = true;
}
dts += 1024*1000/getAudioSampleRate();
pts += 1024*1000/getAudioSampleRate();
dts += 1024 * 1000 / getAudioSampleRate();
pts += 1024 * 1000 / getAudioSampleRate();
}
return ret;
}
bool AACTrack::inputFrame_l(const Frame::Ptr &frame) {
if (_cfg.empty()) {
//未获取到aac_cfg信息
if (frame->prefixSize()) {
//根据7个字节的adts头生成aac config
_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
onReady();
} else {
WarnL << "无法获取adts头!";
}
if (_cfg.empty() && frame->prefixSize()) {
// 未获取到aac_cfg信息根据7个字节的adts头生成aac config
_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize());
update();
}
if (frame->size() > frame->prefixSize()) {
//除adts头外有实际负载
// 除adts头外有实际负载
return AudioTrack::inputFrame(frame);
}
return false;
}
void AACTrack::onReady() {
if (_cfg.size() < 2) {
return;
}
parseAacConfig(_cfg, _sampleRate, _channel);
toolkit::Buffer::Ptr AACTrack::getExtraData() const {
CHECK(ready());
return std::make_shared<BufferString>(_cfg);
}
Track::Ptr AACTrack::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
void AACTrack::setExtraData(const uint8_t *data, size_t size) {
CHECK(size >= 2);
_cfg.assign((char *)data, size);
update();
}
Sdp::Ptr AACTrack::getSdp() {
if(!ready()){
bool AACTrack::update() {
return parseAacConfig(_cfg, _sampleRate, _channel);
}
Track::Ptr AACTrack::clone() const {
return std::make_shared<AACTrack>(*this);
}
Sdp::Ptr AACTrack::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<AACSdp>(getConfig(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
return std::make_shared<AACSdp>(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
}
}//namespace mediakit
namespace {
CodecId getCodec() {
return CodecAAC;
}
Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) {
if (sample_rate && channels)
return std::make_shared<AACTrack>(sample_rate, channels, 1);
return std::make_shared<AACTrack>();
}
Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
string aac_cfg_str = findSubString(track->_fmtp.data(), "config=", ";");
if (aac_cfg_str.empty()) {
aac_cfg_str = findSubString(track->_fmtp.data(), "config=", nullptr);
}
if (aac_cfg_str.empty()) {
// 如果sdp中获取不到aac config信息那么在rtp也无法获取那么忽略该Track
return nullptr;
}
string aac_cfg;
for (size_t i = 0; i < aac_cfg_str.size() / 2; ++i) {
unsigned int cfg;
sscanf(aac_cfg_str.substr(i * 2, 2).data(), "%02X", &cfg);
cfg &= 0x00FF;
aac_cfg.push_back((char)cfg);
}
return std::make_shared<AACTrack>(aac_cfg);
}
RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) {
return std::make_shared<AACRtpEncoder>();
}
RtpCodec::Ptr getRtpDecoderByCodecId() {
return std::make_shared<AACRtpDecoder>();
}
RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) {
return std::make_shared<AACRtmpEncoder>(track);
}
RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) {
return std::make_shared<AACRtmpDecoder>(track);
}
size_t aacPrefixSize(const char *data, size_t bytes) {
uint8_t *ptr = (uint8_t *)data;
size_t prefix = 0;
if (!(bytes > ADTS_HEADER_LEN && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)) {
return 0;
}
return ADTS_HEADER_LEN;
}
Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
return std::make_shared<FrameFromPtr>(CodecAAC, (char *)data, bytes, dts, pts, aacPrefixSize(data, bytes));
}
} // namespace
CodecPlugin aac_plugin = { getCodec,
getTrackByCodecId,
getTrackBySdp,
getRtpEncoderByCodecId,
getRtpDecoderByCodecId,
getRtmpEncoderByTrack,
getRtmpDecoderByTrack,
getFrameFromPtr };
} // namespace mediakit

57
ext-codec/AAC.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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
#define ZLMEDIAKIT_AAC_H
#include "Extension/Frame.h"
#include "Extension/Track.h"
#define ADTS_HEADER_LEN 7
namespace mediakit{
/**
* aac音频通道
*/
class AACTrack : public AudioTrack {
public:
using Ptr = std::shared_ptr<AACTrack>;
AACTrack() = default;
AACTrack(int samplerate, int channel, int profile=1);
/**
* aac extra data
*/
AACTrack(const std::string &aac_cfg);
bool ready() const override;
CodecId getCodecId() const override;
int getAudioChannel() const override;
int getAudioSampleRate() const override;
int getAudioSampleBit() const override;
bool inputFrame(const Frame::Ptr &frame) override;
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
bool update() override;
private:
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
bool inputFrame_l(const Frame::Ptr &frame);
private:
std::string _cfg;
int _channel = 0;
int _sampleRate = 0;
int _sampleBit = 16;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_AAC_H

66
ext-codec/AACRtmp.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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"
using namespace std;
using namespace toolkit;
namespace mediakit {
void AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
CHECK_RET(pkt->size() > 2);
if (pkt->isConfigFrame()) {
getTrack()->setExtraData((uint8_t *)pkt->data() + 2, pkt->size() - 2);
return;
}
RtmpCodec::inputFrame(std::make_shared<FrameFromPtr>(CodecAAC, pkt->buffer.data() + 2, pkt->buffer.size() - 2, pkt->time_stamp));
}
/////////////////////////////////////////////////////////////////////////////////////
bool AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
auto pkt = RtmpPacket::create();
// header
pkt->buffer.push_back(_audio_flv_flags);
pkt->buffer.push_back((uint8_t)RtmpAACPacketType::aac_raw);
// aac data
pkt->buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
pkt->body_size = pkt->buffer.size();
pkt->chunk_id = CHUNK_AUDIO;
pkt->stream_index = STREAM_MEDIA;
pkt->time_stamp = frame->dts();
pkt->type_id = MSG_AUDIO;
RtmpCodec::inputRtmp(pkt);
return true;
}
void AACRtmpEncoder::makeConfigPacket() {
_audio_flv_flags = getAudioRtmpFlags(getTrack());
auto pkt = RtmpPacket::create();
// header
pkt->buffer.push_back(_audio_flv_flags);
pkt->buffer.push_back((uint8_t)RtmpAACPacketType::aac_config_header);
// aac config
auto extra_data = getTrack()->getExtraData();
CHECK(extra_data);
pkt->buffer.append(extra_data->data(), extra_data->size());
pkt->body_size = pkt->buffer.size();
pkt->chunk_id = CHUNK_AUDIO;
pkt->stream_index = STREAM_MEDIA;
pkt->time_stamp = 0;
pkt->type_id = MSG_AUDIO;
RtmpCodec::inputRtmp(pkt);
}
}//namespace mediakit

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,43 +11,31 @@
#ifndef ZLMEDIAKIT_AACRTMPCODEC_H
#define ZLMEDIAKIT_AACRTMPCODEC_H
#include "AAC.h"
#include "Rtmp/RtmpCodec.h"
#include "Extension/Track.h"
#include "Extension/AAC.h"
namespace mediakit{
namespace mediakit {
/**
* aac Rtmp转adts类
*/
class AACRtmpDecoder : public RtmpCodec{
class AACRtmpDecoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<AACRtmpDecoder>;
AACRtmpDecoder() {}
~AACRtmpDecoder() {}
AACRtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* Rtmp并解码
* @param rtmp Rtmp数据包
*/
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
CodecId getCodecId() const override{
return CodecAAC;
}
private:
void onGetAAC(const char *data, size_t len, uint32_t stamp);
private:
std::string _aac_cfg;
};
/**
* aac adts转Rtmp类
*/
class AACRtmpEncoder : public AACRtmpDecoder{
class AACRtmpEncoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<AACRtmpEncoder>;
@ -57,8 +45,7 @@ public:
* inputFrame时可以不输入adts头
* @param track
*/
AACRtmpEncoder(const Track::Ptr &track);
~AACRtmpEncoder() {}
AACRtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* aac adts头
@ -72,12 +59,7 @@ public:
void makeConfigPacket() override;
private:
void makeAudioConfigPkt();
private:
uint8_t _audio_flv_flags;
AACTrack::Ptr _track;
std::string _aac_cfg;
uint8_t _audio_flv_flags {0};
};
}//namespace mediakit

127
ext-codec/AACRtp.cpp Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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"
namespace mediakit{
bool AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
auto ptr = (char *)frame->data() + frame->prefixSize();
auto size = frame->size() - frame->prefixSize();
auto remain_size = size;
auto max_size = getRtpInfo().getMaxSize() - 4;
while (remain_size > 0) {
if (remain_size <= max_size) {
outputRtp(ptr, remain_size, size, true, frame->dts());
break;
}
outputRtp(ptr, max_size, size, false, frame->dts());
ptr += max_size;
remain_size -= max_size;
}
return true;
}
void AACRtpEncoder::outputRtp(const char *data, size_t len, size_t total_len, bool mark, uint64_t stamp) {
auto rtp = getRtpInfo().makeRtp(TrackAudio, nullptr, len + 4, mark, stamp);
auto payload = rtp->data() + RtpPacket::kRtpTcpHeaderSize + RtpPacket::kRtpHeaderSize;
payload[0] = 0;
payload[1] = 16;
payload[2] = ((total_len) >> 5) & 0xFF;
payload[3] = ((total_len & 0x1F) << 3) & 0xFF;
memcpy(payload + 4, data, len);
RtpCodec::inputRtp(std::move(rtp), false);
}
/////////////////////////////////////////////////////////////////////////////////////
AACRtpDecoder::AACRtpDecoder() {
obtainFrame();
}
void AACRtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
_frame = FrameImp::create();
_frame->_codec_id = CodecAAC;
}
bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
auto payload_size = rtp->getPayloadSize();
if (payload_size <= 0) {
// 无实际负载
return false;
}
auto stamp = rtp->getStampMS();
// rtp数据开始部分
auto ptr = rtp->getPayload();
// rtp数据末尾
auto end = ptr + payload_size;
// 首2字节表示Au-Header的个数单位bit所以除以16得到Au-Header个数
auto au_header_count = ((ptr[0] << 8) | ptr[1]) >> 4;
if (!au_header_count) {
// 问题issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869
WarnL << "invalid aac rtp au_header_count";
return false;
}
// 记录au_header起始指针
auto au_header_ptr = ptr + 2;
ptr = au_header_ptr + au_header_count * 2;
if (end < ptr) {
// 数据不够
return false;
}
if (!_last_dts) {
// 记录第一个时间戳
_last_dts = stamp;
}
// 每个audio unit时间戳增量
auto dts_inc = (stamp - _last_dts) / au_header_count;
if (dts_inc < 0 || dts_inc > 100) {
// 时间戳增量异常,忽略
dts_inc = 0;
}
for (auto i = 0u; i < (size_t)au_header_count; ++i) {
// 之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度低3位无用
auto size = ((au_header_ptr[0] << 8) | au_header_ptr[1]) >> 3;
auto len = std::min<int>(size, end - ptr);
if (len <= 0) {
break;
}
_frame->_buffer.append((char *)ptr, len);
ptr += len;
au_header_ptr += 2;
if (_frame->size() >= (size_t)size) {
// 设置当前audio unit时间戳
_frame->_dts = _last_dts + i * dts_inc;
flushData();
}
}
// 记录上次时间戳
_last_dts = stamp;
return false;
}
void AACRtpDecoder::flushData() {
auto ptr = reinterpret_cast<const uint8_t *>(_frame->data());
if ((ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0) && _frame->size() > ADTS_HEADER_LEN) {
// adts头打入了rtp包不符合规范兼容EasyPusher的bug
_frame->_prefix_size = ADTS_HEADER_LEN;
}
RtpCodec::inputFrame(_frame);
obtainFrame();
}
}//namespace mediakit

64
ext-codec/AACRtp.h Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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
#define ZLMEDIAKIT_AACRTPCODEC_H
#include "AAC.h"
#include "Rtsp/RtpCodec.h"
namespace mediakit {
/**
* aac rtp转adts类
*/
class AACRtpDecoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<AACRtpDecoder>;
AACRtpDecoder();
/**
* rtp并解码
* @param rtp rtp数据包
* @param key_pos false,
*/
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
private:
void obtainFrame();
void flushData();
private:
uint64_t _last_dts = 0;
FrameImp::Ptr _frame;
};
/**
* aac adts转rtp类
*/
class AACRtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<AACRtpEncoder>;
/**
* aac dats头
* @param frame dats头的aac数据
*/
bool inputFrame(const Frame::Ptr &frame) override;
private:
void outputRtp(const char *data, size_t len, size_t total_len, bool mark, uint64_t stamp);
};
}//namespace mediakit
#endif //ZLMEDIAKIT_AACRTPCODEC_H

48
ext-codec/CMakeLists.txt Normal file
View File

@ -0,0 +1,48 @@
# MIT License
#
# Copyright (c) 2016-2022 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
# 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.
#
set(COMPILE_DEFINITIONS)
set(INCLUDE_DIRECTORIES)
file(GLOB EXT_SRC_LIST
${CMAKE_CURRENT_SOURCE_DIR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
add_library(ext-codec STATIC ${EXT_SRC_LIST})
add_library(ZLMediaKit::ext-codec ALIAS ext-codec)
target_compile_options(ext-codec PRIVATE ${COMPILE_OPTIONS_DEFAULT})
target_compile_definitions(ext-codec PUBLIC ${COMPILE_DEFINITIONS})
target_link_libraries(ext-codec PRIVATE ZLMediaKit::MediaKit ZLMediaKit::ToolKit ${LINK_LIBRARIES})
target_include_directories(ext-codec
PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>"
${INCLUDE_DIRECTORIES})
update_cached_list(MK_LINK_LIBRARIES ZLMediaKit::ext-codec ${LINK_LIBRARIES})

188
ext-codec/G711.cpp Normal file
View File

@ -0,0 +1,188 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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 "G711.h"
#include "G711Rtp.h"
#include "Extension/Factory.h"
#include "Extension/CommonRtp.h"
#include "Extension/CommonRtmp.h"
using namespace std;
using namespace toolkit;
namespace mediakit {
/**
* G711类型SDP
*/
class G711Sdp : public Sdp {
public:
/**
* G711采样率固定为8000
* @param codecId G711A G711U
* @param payload_type rtp payload type
* @param sample_rate
* @param channels
* @param bitrate
*/
G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate)
: Sdp(sample_rate, payload_type) {
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(codecId) << "/" << sample_rate << "/" << channels << "\r\n";
}
string getSdp() const override {
return _printer;
}
private:
_StrPrinter _printer;
};
Track::Ptr G711Track::clone() const {
return std::make_shared<G711Track>(*this);
}
Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
const auto codec = getCodecId();
const auto sample_rate = getAudioSampleRate();
const auto audio_channel = getAudioChannel();
const auto bitrate = getBitRate() >> 10;
if (sample_rate == 8000 && audio_channel == 1) {
// https://datatracker.ietf.org/doc/html/rfc3551#section-6
payload_type = (codec == CodecG711U) ? Rtsp::PT_PCMU : Rtsp::PT_PCMA;
}
return std::make_shared<G711Sdp>(codec, payload_type, sample_rate, audio_channel, bitrate);
}
namespace {
CodecId getCodecA() {
return CodecG711A;
}
CodecId getCodecU() {
return CodecG711U;
}
Track::Ptr getTrackByCodecId_l(CodecId codec, int sample_rate, int channels, int sample_bit) {
return (sample_rate && channels && sample_bit) ? std::make_shared<G711Track>(codec, sample_rate, channels, sample_bit) : nullptr;
}
Track::Ptr getTrackByCodecIdA(int sample_rate, int channels, int sample_bit) {
return getTrackByCodecId_l(CodecG711A, sample_rate, channels, sample_bit);
}
Track::Ptr getTrackByCodecIdU(int sample_rate, int channels, int sample_bit) {
return getTrackByCodecId_l(CodecG711U, sample_rate, channels, sample_bit);
}
Track::Ptr getTrackBySdp_l(CodecId codec, const SdpTrack::Ptr &track) {
return std::make_shared<G711Track>(codec, track->_samplerate, track->_channel, 16);
}
Track::Ptr getTrackBySdpA(const SdpTrack::Ptr &track) {
return getTrackBySdp_l(CodecG711A, track);
}
Track::Ptr getTrackBySdpU(const SdpTrack::Ptr &track) {
return getTrackBySdp_l(CodecG711U, track);
}
RtpCodec::Ptr getRtpEncoderByCodecId_l(CodecId codec, uint8_t pt) {
if (pt == Rtsp::PT_PCMA || pt == Rtsp::PT_PCMU) {
return std::make_shared<G711RtpEncoder>(codec, 1);
}
return std::make_shared<CommonRtpEncoder>();
}
RtpCodec::Ptr getRtpEncoderByCodecIdA(uint8_t pt) {
return getRtpEncoderByCodecId_l(CodecG711A, pt);
}
RtpCodec::Ptr getRtpEncoderByCodecIdU(uint8_t pt) {
return getRtpEncoderByCodecId_l(CodecG711U, pt);
}
RtpCodec::Ptr getRtpDecoderByCodecId_l(CodecId codec) {
return std::make_shared<CommonRtpDecoder>(codec);
}
RtpCodec::Ptr getRtpDecoderByCodecIdA() {
return getRtpDecoderByCodecId_l(CodecG711A);
}
RtpCodec::Ptr getRtpDecoderByCodecIdU() {
return getRtpDecoderByCodecId_l(CodecG711U);
}
RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) {
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
if (audio_track->getAudioSampleRate() != 8000 || audio_track->getAudioChannel() != 1 || audio_track->getAudioSampleBit() != 16) {
//rtmp对g711只支持8000/1/16规格但是ZLMediaKit可以解析其他规格的G711
WarnL << "RTMP only support G711 with 8000/1/16, now is"
<< audio_track->getAudioSampleRate() << "/"
<< audio_track->getAudioChannel() << "/"
<< audio_track->getAudioSampleBit()
<< ", ignored it";
return nullptr;
}
return std::make_shared<CommonRtmpEncoder>(track);
}
RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) {
return std::make_shared<CommonRtmpDecoder>(track);
}
Frame::Ptr getFrameFromPtr_l(CodecId codec, const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
return std::make_shared<FrameFromPtr>(codec, (char *)data, bytes, dts, pts);
}
Frame::Ptr getFrameFromPtrA(const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
return getFrameFromPtr_l(CodecG711A, (char *)data, bytes, dts, pts);
}
Frame::Ptr getFrameFromPtrU(const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
return getFrameFromPtr_l(CodecG711U, (char *)data, bytes, dts, pts);
}
} // namespace
CodecPlugin g711a_plugin = { getCodecA,
getTrackByCodecIdA,
getTrackBySdpA,
getRtpEncoderByCodecIdA,
getRtpDecoderByCodecIdA,
getRtmpEncoderByTrack,
getRtmpDecoderByTrack,
getFrameFromPtrA };
CodecPlugin g711u_plugin = { getCodecU,
getTrackByCodecIdU,
getTrackBySdpU,
getRtpEncoderByCodecIdU,
getRtpDecoderByCodecIdU,
getRtmpEncoderByTrack,
getRtmpDecoderByTrack,
getFrameFromPtrU };
}//namespace mediakit

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,8 +11,8 @@
#ifndef ZLMEDIAKIT_G711_H
#define ZLMEDIAKIT_G711_H
#include "Frame.h"
#include "Track.h"
#include "Extension/Frame.h"
#include "Extension/Track.h"
namespace mediakit{
@ -25,8 +25,8 @@ public:
G711Track(CodecId codecId, int sample_rate = 8000, int channels = 1, int sample_bit = 16) : AudioTrackImp(codecId, sample_rate, channels, sample_bit) {}
private:
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
};
}//namespace mediakit

View File

@ -2,23 +2,33 @@
namespace mediakit {
G711RtpEncoder::G711RtpEncoder(
CodecId codec, uint32_t ssrc, uint32_t mtu_size, uint32_t sample_rate, uint8_t payload_type, uint8_t interleaved,
uint32_t channels)
: CommonRtpDecoder(codec)
, RtpInfo(ssrc, mtu_size, sample_rate, payload_type, interleaved) {
G711RtpEncoder::G711RtpEncoder(CodecId codec, uint32_t channels){
_cache_frame = FrameImp::create();
_cache_frame->_codec_id = codec;
_channels = channels;
}
void G711RtpEncoder::setOpt(int opt, const toolkit::Any &param) {
if (opt == RTP_ENCODER_PKT_DUR_MS) {
if (param.is<uint32_t>()) {
auto dur = param.get<uint32_t>();
if (dur < 20 || dur > 180) {
WarnL << "set g711 rtp encoder duration ms failed for " << dur;
return;
}
// 向上 20ms 取整
_pkt_dur_ms = (dur + 19) / 20 * 20;
}
}
}
bool G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
auto dur = (_cache_frame->size() - _cache_frame->prefixSize()) / (8 * _channels);
auto next_pts = _cache_frame->pts() + dur;
if (next_pts == 0) {
_cache_frame->_pts = frame->pts();
} else {
if ((next_pts + 20) < frame->pts()) { // 有丢包超过20ms
if ((next_pts + _pkt_dur_ms) < frame->pts()) { // 有丢包超过20ms
_cache_frame->_pts = frame->pts() - dur;
}
}
@ -28,24 +38,20 @@ bool G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
auto ptr = _cache_frame->data() + _cache_frame->prefixSize();
auto len = _cache_frame->size() - _cache_frame->prefixSize();
auto remain_size = len;
auto max_size = 160 * _channels; // 20 ms per rtp
int n = 0;
size_t max_size = 160 * _channels * _pkt_dur_ms / 20; // 20 ms per 160 byte
size_t n = 0;
bool mark = false;
while (remain_size >= max_size) {
size_t rtp_size;
if (remain_size >= max_size) {
rtp_size = max_size;
} else {
break;
}
assert(remain_size >= max_size);
const size_t rtp_size = max_size;
n++;
stamp += 20;
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, rtp_size, mark, stamp), false);
stamp += _pkt_dur_ms;
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackAudio, ptr, rtp_size, mark, stamp), false);
ptr += rtp_size;
remain_size -= rtp_size;
}
_cache_frame->_buffer.erase(0, n * max_size);
_cache_frame->_pts += 20 * n;
_cache_frame->_pts += (uint64_t)_pkt_dur_ms * n;
return len > 0;
}

48
ext-codec/G711Rtp.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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_G711RTP_H
#define ZLMEDIAKIT_G711RTP_H
#include "Rtsp/RtpCodec.h"
#include "Extension/Frame.h"
#include "Extension/CommonRtp.h"
namespace mediakit {
/**
* G711 rtp编码类
*/
class G711RtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<G711RtpEncoder>;
/**
*
* @param codec
* @param channels
*/
G711RtpEncoder(CodecId codec, uint32_t channels);
/**
* rtp
*/
bool inputFrame(const Frame::Ptr &frame) override;
void setOpt(int opt, const toolkit::Any &param) override;
private:
uint32_t _channels = 1;
uint32_t _pkt_dur_ms = 20;
FrameImp::Ptr _cache_frame;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_G711RTP_H

View File

@ -1,18 +1,26 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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 "H264Rtmp.h"
#include "H264Rtp.h"
#include "SPSParser.h"
#include "Util/logger.h"
#include "Util/base64.h"
#include "Common/Parser.h"
#include "Common/config.h"
#include "Extension/Factory.h"
#ifdef ENABLE_MP4
#include "mpeg4-avc.h"
#endif
using namespace std;
using namespace toolkit;
@ -109,24 +117,7 @@ size_t prefixSize(const char *ptr, size_t len) {
H264Track::H264Track(const string &sps, const string &pps, int sps_prefix_len, int pps_prefix_len) {
_sps = sps.substr(sps_prefix_len);
_pps = pps.substr(pps_prefix_len);
onReady();
}
H264Track::H264Track(const Frame::Ptr &sps, const Frame::Ptr &pps) {
if (sps->getCodecId() != CodecH264 || pps->getCodecId() != CodecH264) {
throw std::invalid_argument("必须输入H264类型的帧");
}
_sps = string(sps->data() + sps->prefixSize(), sps->size() - sps->prefixSize());
_pps = string(pps->data() + pps->prefixSize(), pps->size() - pps->prefixSize());
onReady();
}
const string &H264Track::getSps() const {
return _sps;
}
const string &H264Track::getPps() const {
return _pps;
H264Track::update();
}
CodecId H264Track::getCodecId() const {
@ -145,7 +136,7 @@ float H264Track::getVideoFps() const {
return _fps;
}
bool H264Track::ready() {
bool H264Track::ready() const {
return !_sps.empty() && !_pps.empty();
}
@ -168,15 +159,95 @@ bool H264Track::inputFrame(const Frame::Ptr &frame) {
return ret;
}
void H264Track::onReady() {
if (!getAVCInfo(_sps, _width, _height, _fps)) {
_sps.clear();
_pps.clear();
toolkit::Buffer::Ptr H264Track::getExtraData() const {
CHECK(ready());
#ifdef ENABLE_MP4
struct mpeg4_avc_t avc;
memset(&avc, 0, sizeof(avc));
string sps_pps = string("\x00\x00\x00\x01", 4) + _sps + string("\x00\x00\x00\x01", 4) + _pps;
h264_annexbtomp4(&avc, sps_pps.data(), (int)sps_pps.size(), NULL, 0, NULL, NULL);
std::string extra_data;
extra_data.resize(1024);
auto extra_data_size = mpeg4_avc_decoder_configuration_record_save(&avc, (uint8_t *)extra_data.data(), extra_data.size());
if (extra_data_size == -1) {
WarnL << "生成H264 extra_data 失败";
return nullptr;
}
extra_data.resize(extra_data_size);
return std::make_shared<BufferString>(std::move(extra_data));
#else
std::string extra_data;
// AVCDecoderConfigurationRecord start
extra_data.push_back(1); // version
extra_data.push_back(_sps[1]); // profile
extra_data.push_back(_sps[2]); // compat
extra_data.push_back(_sps[3]); // level
extra_data.push_back((char)0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
extra_data.push_back((char)0xe1); // 3 bits reserved + 5 bits number of sps (00001)
// sps
uint16_t size = (uint16_t)_sps.size();
size = htons(size);
extra_data.append((char *)&size, 2);
extra_data.append(_sps);
// pps
extra_data.push_back(1); // version
size = (uint16_t)_pps.size();
size = htons(size);
extra_data.append((char *)&size, 2);
extra_data.append(_pps);
return std::make_shared<BufferString>(std::move(extra_data));
#endif
}
Track::Ptr H264Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
void H264Track::setExtraData(const uint8_t *data, size_t bytes) {
#ifdef ENABLE_MP4
struct mpeg4_avc_t avc;
memset(&avc, 0, sizeof(avc));
if (mpeg4_avc_decoder_configuration_record_load(data, bytes, &avc) > 0) {
std::vector<uint8_t> config(bytes * 2);
int size = mpeg4_avc_to_nalu(&avc, config.data(), bytes * 2);
if (size > 4) {
splitH264((char *)config.data(), size, 4, [&](const char *ptr, size_t len, size_t prefix) {
inputFrame_l(std::make_shared<H264FrameNoCacheAble>((char *)ptr, len, 0, 0, prefix));
});
update();
}
}
#else
CHECK(bytes >= 8); // 6 + 2
size_t offset = 6;
uint16_t sps_size = data[offset] << 8 | data[offset + 1];
auto sps_ptr = data + offset + 2;
offset += (2 + sps_size);
CHECK(bytes >= offset + 2); // + pps_size
_sps.assign((char *)sps_ptr, sps_size);
uint16_t pps_size = data[offset] << 8 | data[offset + 1];
auto pps_ptr = data + offset + 2;
offset += (2 + pps_size);
CHECK(bytes >= offset);
_pps.assign((char *)pps_ptr, pps_size);
update();
#endif
}
bool H264Track::update() {
return getAVCInfo(_sps, _width, _height, _fps);
}
std::vector<Frame::Ptr> H264Track::getConfigFrames() const {
if (!ready()) {
return {};
}
return { createConfigFrame<H264Frame>(_sps, 0, getIndex()),
createConfigFrame<H264Frame>(_pps, 0, getIndex()) };
}
Track::Ptr H264Track::clone() const {
return std::make_shared<H264Track>(*this);
}
bool H264Track::inputFrame_l(const Frame::Ptr &frame) {
@ -214,41 +285,29 @@ bool H264Track::inputFrame_l(const Frame::Ptr &frame) {
}
if (_width == 0 && ready()) {
onReady();
update();
}
return ret;
}
void H264Track::insertConfigFrame(const Frame::Ptr &frame) {
if (!_sps.empty()) {
auto spsFrame = FrameImp::create<H264Frame>();
spsFrame->_prefix_size = 4;
spsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
spsFrame->_buffer.append(_sps);
spsFrame->_dts = frame->dts();
VideoTrack::inputFrame(spsFrame);
VideoTrack::inputFrame(createConfigFrame<H264Frame>(_sps, frame->dts(), frame->getIndex()));
}
if (!_pps.empty()) {
auto ppsFrame = FrameImp::create<H264Frame>();
ppsFrame->_prefix_size = 4;
ppsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
ppsFrame->_buffer.append(_pps);
ppsFrame->_dts = frame->dts();
VideoTrack::inputFrame(ppsFrame);
VideoTrack::inputFrame(createConfigFrame<H264Frame>(_pps, frame->dts(), frame->getIndex()));
}
}
class H264Sdp : public Sdp {
public:
H264Sdp(const string &strSPS, const string &strPPS, int bitrate, int payload_type = 96)
: Sdp(90000, payload_type) {
//视频通道
H264Sdp(const string &strSPS, const string &strPPS, int payload_type, int bitrate) : Sdp(90000, payload_type) {
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << 90000 << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecH264) << "/" << 90000 << "\r\n";
/**
Single NAI Unit Mode = 0. // Single NAI mode (Only nals from 1-23 are allowed)
@ -271,23 +330,76 @@ public:
_printer << "; sprop-parameter-sets=";
_printer << encodeBase64(strSPS) << ",";
_printer << encodeBase64(strPPS) << "\r\n";
_printer << "a=control:trackID=" << (int)TrackVideo << "\r\n";
}
string getSdp() const { return _printer; }
CodecId getCodecId() const { return CodecH264; }
private:
_StrPrinter _printer;
};
Sdp::Ptr H264Track::getSdp() {
Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<H264Sdp>(getSps(), getPps(), getBitRate() / 1024);
return std::make_shared<H264Sdp>(_sps, _pps, payload_type, getBitRate() / 1024);
}
namespace {
CodecId getCodec() {
return CodecH264;
}
Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) {
return std::make_shared<H264Track>();
}
Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
//a=fmtp:96 packetization-mode=1;profile-level-id=42C01F;sprop-parameter-sets=Z0LAH9oBQBboQAAAAwBAAAAPI8YMqA==,aM48gA==
auto map = Parser::parseArgs(track->_fmtp, ";", "=");
auto sps_pps = map["sprop-parameter-sets"];
string base64_SPS = findSubString(sps_pps.data(), NULL, ",");
string base64_PPS = findSubString(sps_pps.data(), ",", NULL);
auto sps = decodeBase64(base64_SPS);
auto pps = decodeBase64(base64_PPS);
if (sps.empty() || pps.empty()) {
//如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
return std::make_shared<H264Track>();
}
return std::make_shared<H264Track>(sps, pps, 0, 0);
}
RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) {
return std::make_shared<H264RtpEncoder>();
}
RtpCodec::Ptr getRtpDecoderByCodecId() {
return std::make_shared<H264RtpDecoder>();
}
RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) {
return std::make_shared<H264RtmpEncoder>(track);
}
RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) {
return std::make_shared<H264RtmpDecoder>(track);
}
Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
return std::make_shared<H264FrameNoCacheAble>((char *)data, bytes, dts, pts, prefixSize(data, bytes));
}
} // namespace
CodecPlugin h264_plugin = { getCodec,
getTrackByCodecId,
getTrackBySdp,
getRtpEncoderByCodecId,
getRtpDecoderByCodecId,
getRtmpEncoderByTrack,
getRtmpDecoderByTrack,
getFrameFromPtr };
} // namespace mediakit

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,14 +11,13 @@
#ifndef ZLMEDIAKIT_H264_H
#define ZLMEDIAKIT_H264_H
#include "Frame.h"
#include "Track.h"
#include "Extension/Frame.h"
#include "Extension/Track.h"
#define H264_TYPE(v) ((uint8_t)(v) & 0x1F)
namespace mediakit{
bool getAVCInfo(const std::string &strSps,int &iVideoWidth, int &iVideoHeight, float &iVideoFps);
void splitH264(const char *ptr, size_t len, size_t prefix, const std::function<void(const char *, size_t, size_t)> &cb);
size_t prefixSize(const char *ptr, size_t len);
@ -43,8 +42,6 @@ public:
this->_codec_id = CodecH264;
}
~H264FrameHelper() override = default;
bool keyFrame() const override {
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
return H264_TYPE(*nal_ptr) == NAL_IDR && decodeAble();
@ -107,32 +104,22 @@ public:
* @param sps_prefix_len 264340x00 00 00 01
* @param pps_prefix_len 264340x00 00 00 01
*/
H264Track(const std::string &sps,const std::string &pps,int sps_prefix_len = 4,int pps_prefix_len = 4);
H264Track(const std::string &sps, const std::string &pps, int sps_prefix_len = 4, int pps_prefix_len = 4);
/**
* h264类型的媒体
* @param sps sps帧
* @param pps pps帧
*/
H264Track(const Frame::Ptr &sps,const Frame::Ptr &pps);
/**
* 0x00 00 00 01sps/pps
*/
const std::string &getSps() const;
const std::string &getPps() const;
bool ready() override;
bool ready() const override;
CodecId getCodecId() const override;
int getVideoHeight() const override;
int getVideoWidth() const override;
float getVideoFps() const override;
bool inputFrame(const Frame::Ptr &frame) override;
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
bool update() override;
std::vector<Frame::Ptr> getConfigFrames() const override;
private:
void onReady();
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
bool inputFrame_l(const Frame::Ptr &frame);
void insertConfigFrame(const Frame::Ptr &frame);
@ -145,5 +132,17 @@ private:
std::string _pps;
};
template <typename FrameType>
Frame::Ptr createConfigFrame(const std::string &data, uint64_t dts, int index) {
auto frame = FrameImp::create<FrameType>();
frame->_prefix_size = 4;
frame->_buffer.assign("\x00\x00\x00\x01", 4);
frame->_buffer.append(data);
frame->_dts = dts;
frame->setIndex(index);
return frame;
}
}//namespace mediakit
#endif //ZLMEDIAKIT_H264_H

109
ext-codec/H264Rtmp.cpp Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT-like 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/utils.h"
#include "H264Rtmp.h"
using namespace std;
using namespace toolkit;
namespace mediakit {
void H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
if (pkt->isConfigFrame()) {
CHECK_RET(pkt->size() > 5);
getTrack()->setExtraData((uint8_t *)pkt->data() + 5, pkt->size() - 5);
return;
}
CHECK_RET(pkt->size() > 9);
uint8_t *cts_ptr = (uint8_t *)(pkt->buffer.data() + 2);
int32_t cts = (((cts_ptr[0] << 16) | (cts_ptr[1] << 8) | (cts_ptr[2])) + 0xff800000) ^ 0xff800000;
auto pts = pkt->time_stamp + cts;
splitFrame((uint8_t *)pkt->data() + 5, pkt->size() - 5, pkt->time_stamp, pts);
}
void H264RtmpDecoder::splitFrame(const uint8_t *data, size_t size, uint32_t dts, uint32_t pts) {
auto end = data + size;
while (data + 4 < end) {
uint32_t frame_len = load_be32(data);
data += 4;
if (data + frame_len > end) {
break;
}
outputFrame((const char *)data, frame_len, dts, pts);
data += frame_len;
}
}
void H264RtmpDecoder::outputFrame(const char *data, size_t len, uint32_t dts, uint32_t pts) {
auto frame = FrameImp::create<H264Frame>();
frame->_prefix_size = 4;
frame->_dts = dts;
frame->_pts = pts;
frame->_buffer.assign("\x00\x00\x00\x01", 4); // 添加264头
frame->_buffer.append(data, len);
RtmpCodec::inputFrame(frame);
}
////////////////////////////////////////////////////////////////////////
void H264RtmpEncoder::flush() {
inputFrame(nullptr);
}
bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (!_rtmp_packet) {
_rtmp_packet = RtmpPacket::create();
//flags/not config/cts预占位
_rtmp_packet->buffer.resize(5);
}
return _merger.inputFrame(frame, [this](uint64_t dts, uint64_t pts, const Buffer::Ptr &, bool have_key_frame) {
// flags
_rtmp_packet->buffer[0] = (uint8_t)RtmpVideoCodec::h264 | ((uint8_t)(have_key_frame ? RtmpFrameType::key_frame : RtmpFrameType::inter_frame) << 4);
_rtmp_packet->buffer[1] = (uint8_t)RtmpH264PacketType::h264_nalu;
int32_t cts = pts - dts;
// cts
set_be24(&_rtmp_packet->buffer[2], cts);
_rtmp_packet->time_stamp = dts;
_rtmp_packet->body_size = _rtmp_packet->buffer.size();
_rtmp_packet->chunk_id = CHUNK_VIDEO;
_rtmp_packet->stream_index = STREAM_MEDIA;
_rtmp_packet->type_id = MSG_VIDEO;
// 输出rtmp packet
RtmpCodec::inputRtmp(_rtmp_packet);
_rtmp_packet = nullptr;
}, &_rtmp_packet->buffer);
}
void H264RtmpEncoder::makeConfigPacket() {
auto flags = (uint8_t)RtmpVideoCodec::h264;
flags |= ((uint8_t)RtmpFrameType::key_frame << 4);
auto pkt = RtmpPacket::create();
// header
pkt->buffer.push_back(flags);
pkt->buffer.push_back((uint8_t)RtmpH264PacketType::h264_config_header);
// cts
pkt->buffer.append("\x0\x0\x0", 3);
// AVCDecoderConfigurationRecord start
auto extra_data = getTrack()->getExtraData();
CHECK(extra_data);
pkt->buffer.append(extra_data->data(), extra_data->size());
pkt->body_size = pkt->buffer.size();
pkt->chunk_id = CHUNK_VIDEO;
pkt->stream_index = STREAM_MEDIA;
pkt->time_stamp = 0;
pkt->type_id = MSG_VIDEO;
RtmpCodec::inputRtmp(pkt);
}
}//namespace mediakit

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,11 +11,11 @@
#ifndef ZLMEDIAKIT_H264RTMPCODEC_H
#define ZLMEDIAKIT_H264RTMPCODEC_H
#include "H264.h"
#include "Rtmp/RtmpCodec.h"
#include "Extension/Track.h"
#include "Extension/H264.h"
namespace mediakit{
namespace mediakit {
/**
* h264 Rtmp解码类
* h264 over rtmp h264-Frame
@ -24,8 +24,7 @@ class H264RtmpDecoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<H264RtmpDecoder>;
H264RtmpDecoder();
~H264RtmpDecoder() {}
H264RtmpDecoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 264 Rtmp包
@ -33,24 +32,15 @@ public:
*/
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
CodecId getCodecId() const override{
return CodecH264;
}
protected:
void onGetH264(const char *data, size_t len, uint32_t dts, uint32_t pts);
H264Frame::Ptr obtainFrame();
protected:
H264Frame::Ptr _h264frame;
std::string _sps;
std::string _pps;
private:
void outputFrame(const char *data, size_t len, uint32_t dts, uint32_t pts);
void splitFrame(const uint8_t *data, size_t size, uint32_t dts, uint32_t pts);
};
/**
* 264 Rtmp打包类
*/
class H264RtmpEncoder : public H264RtmpDecoder{
class H264RtmpEncoder : public RtmpCodec {
public:
using Ptr = std::shared_ptr<H264RtmpEncoder>;
@ -60,8 +50,7 @@ public:
* inputFrame时可以不输入sps pps
* @param track
*/
H264RtmpEncoder(const Track::Ptr &track);
~H264RtmpEncoder() = default;
H264RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
/**
* 264sps pps
@ -80,13 +69,8 @@ public:
void makeConfigPacket() override;
private:
void makeVideoConfigPkt();
private:
bool _got_config_frame = false;
H264Track::Ptr _track;
RtmpPacket::Ptr _rtmp_packet;
FrameMerger _merger{FrameMerger::mp4_nal_size};
FrameMerger _merger { FrameMerger::mp4_nal_size };
};
}//namespace mediakit

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -44,13 +44,15 @@ H264Frame::Ptr H264RtpDecoder::obtainFrame() {
bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
auto seq = rtp->getSeq();
auto ret = decodeRtp(rtp);
if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) {
auto last_is_gop = _is_gop;
_is_gop = decodeRtp(rtp);
if (!_gop_dropped && seq != (uint16_t)(_last_seq + 1) && _last_seq) {
_gop_dropped = true;
WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
}
_last_seq = seq;
return ret;
// 确保有sps rtp的时候gop从sps开始否则从关键帧开始
return _is_gop && !last_is_gop;
}
/*
@ -74,7 +76,7 @@ bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
_frame->_buffer.append((char *) ptr, size);
_frame->_pts = stamp;
auto key = _frame->keyFrame();
auto key = _frame->keyFrame() || _frame->configFrame();
outputFrame(rtp, _frame);
return key;
}
@ -127,7 +129,7 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
if (!fu->end_bit) {
//非末尾包
return fu->start_bit ? _frame->keyFrame() : false;
return fu->start_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
}
//确保下一次fu必须收到第一个包
@ -190,10 +192,6 @@ void H264RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr
////////////////////////////////////////////////////////////////////////
H264RtpEncoder::H264RtpEncoder(uint32_t ssrc, uint32_t mtu, uint32_t sample_rate, uint8_t pt, uint8_t interleaved)
: RtpInfo(ssrc, mtu, sample_rate, pt, interleaved) {
}
void H264RtpEncoder::insertConfigFrame(uint64_t pts){
if (!_sps || !_pps) {
return;
@ -204,7 +202,7 @@ void H264RtpEncoder::insertConfigFrame(uint64_t pts){
}
void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
if (len + 3 <= getMaxSize()) {
if (len + 3 <= getRtpInfo().getMaxSize()) {
// 采用STAP-A/Single NAL unit packet per H.264 模式
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
} else {
@ -214,7 +212,7 @@ void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_
}
void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
auto packet_size = getMaxSize() - 2;
auto packet_size = getRtpInfo().getMaxSize() - 2;
if (len <= packet_size + 1) {
// 小于FU-A打包最小字节长度要求采用STAP-A/Single NAL unit packet per H.264 模式
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
@ -236,7 +234,7 @@ void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
}
//传入nullptr先不做payload的内存拷贝
auto rtp = makeRtp(getTrackType(), nullptr, packet_size + 2, fu_flags->end_bit && is_mark, pts);
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, packet_size + 2, fu_flags->end_bit && is_mark, pts);
//rtp payload 负载部分
uint8_t *payload = rtp->getPayload();
//FU-A 第1个字节
@ -264,7 +262,7 @@ void H264RtpEncoder::packRtpSmallFrame(const char *data, size_t len, uint64_t pt
void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
// 如果帧长度不超过mtu,为了兼容性 webrtc采用STAP-A模式打包
auto rtp = makeRtp(getTrackType(), nullptr, len + 3, is_mark, pts);
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, len + 3, is_mark, pts);
uint8_t *payload = rtp->getPayload();
//STAP-A
payload[0] = (ptr[0] & (~0x1F)) | 24;
@ -277,7 +275,7 @@ void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, boo
void H264RtpEncoder::packRtpSingleNalu(const char *data, size_t len, uint64_t pts, bool is_mark, bool gop_pos) {
// Single NAL unit packet per H.264 模式
RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, is_mark, pts), gop_pos);
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, data, len, is_mark, pts), gop_pos);
}
bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,12 +11,12 @@
#ifndef ZLMEDIAKIT_H264RTPCODEC_H
#define ZLMEDIAKIT_H264RTPCODEC_H
#include "Rtsp/RtpCodec.h"
#include "Extension/H264.h"
#include "H264.h"
// for DtsGenerator
#include "Common/Stamp.h"
#include "Rtsp/RtpCodec.h"
namespace mediakit{
namespace mediakit {
/**
* h264 rtp解码类
@ -28,7 +28,6 @@ public:
using Ptr = std::shared_ptr<H264RtpDecoder>;
H264RtpDecoder();
~H264RtpDecoder() override = default;
/**
* 264 rtp包
@ -37,10 +36,6 @@ public:
*/
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
CodecId getCodecId() const override{
return CodecH264;
}
private:
bool singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp);
bool unpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp);
@ -51,6 +46,7 @@ private:
void outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame);
private:
bool _is_gop = false;
bool _gop_dropped = false;
bool _fu_dropped = true;
uint16_t _last_seq = 0;
@ -61,25 +57,10 @@ private:
/**
* 264 rtp打包类
*/
class H264RtpEncoder : public H264RtpDecoder ,public RtpInfo{
class H264RtpEncoder : public RtpCodec {
public:
using Ptr = std::shared_ptr<H264RtpEncoder>;
/**
* @param ssrc ssrc
* @param mtu mtu大小
* @param sample_rate 90000
* @param pt pt类型
* @param interleaved rtsp interleaved
*/
H264RtpEncoder(uint32_t ssrc,
uint32_t mtu = 1400,
uint32_t sample_rate = 90000,
uint8_t pt = 96,
uint8_t interleaved = TrackVideo * 2);
~H264RtpEncoder() override = default;
/**
* 264
* @param frame

View File

@ -1,16 +1,24 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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"
#include "H265Rtp.h"
#include "H265Rtmp.h"
#include "SPSParser.h"
#include "Util/base64.h"
#include "Common/Parser.h"
#include "Extension/Factory.h"
#ifdef ENABLE_MP4
#include "mpeg4-hevc.h"
#endif
using namespace std;
using namespace toolkit;
@ -58,19 +66,7 @@ H265Track::H265Track(const string &vps,const string &sps, const string &pps,int
_vps = vps.substr(vps_prefix_len);
_sps = sps.substr(sps_prefix_len);
_pps = pps.substr(pps_prefix_len);
onReady();
}
const string &H265Track::getVps() const {
return _vps;
}
const string &H265Track::getSps() const {
return _sps;
}
const string &H265Track::getPps() const {
return _pps;
H265Track::update();
}
CodecId H265Track::getCodecId() const {
@ -89,7 +85,7 @@ float H265Track::getVideoFps() const {
return _fps;
}
bool H265Track::ready() {
bool H265Track::ready() const {
return !_vps.empty() && !_sps.empty() && !_pps.empty();
}
@ -139,21 +135,67 @@ bool H265Track::inputFrame_l(const Frame::Ptr &frame) {
}
}
if (_width == 0 && ready()) {
onReady();
update();
}
return ret;
}
void H265Track::onReady() {
if (!getHEVCInfo(_vps, _sps, _width, _height, _fps)) {
_vps.clear();
_sps.clear();
_pps.clear();
toolkit::Buffer::Ptr H265Track::getExtraData() const {
CHECK(ready());
#ifdef ENABLE_MP4
struct mpeg4_hevc_t hevc;
memset(&hevc, 0, sizeof(hevc));
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(), (int) vps_sps_pps.size(), NULL, 0, NULL, NULL);
std::string extra_data;
extra_data.resize(1024);
auto extra_data_size = mpeg4_hevc_decoder_configuration_record_save(&hevc, (uint8_t *)extra_data.data(), extra_data.size());
if (extra_data_size == -1) {
WarnL << "生成H265 extra_data 失败";
return nullptr;
}
return std::make_shared<BufferString>(std::move(extra_data));
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265的支持不完善";
return nullptr;
#endif
}
Track::Ptr H265Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type>(*this);
void H265Track::setExtraData(const uint8_t *data, size_t bytes) {
#ifdef ENABLE_MP4
struct mpeg4_hevc_t hevc;
memset(&hevc, 0, sizeof(hevc));
if (mpeg4_hevc_decoder_configuration_record_load(data, bytes, &hevc) > 0) {
std::vector<uint8_t> config(bytes * 2);
int size = mpeg4_hevc_to_nalu(&hevc, config.data(), bytes * 2);
if (size > 4) {
splitH264((char *)config.data(), size, 4, [&](const char *ptr, size_t len, size_t prefix) {
inputFrame_l(std::make_shared<H265FrameNoCacheAble>((char *)ptr, len, 0, 0, prefix));
});
update();
}
}
#else
WarnL << "请开启MP4相关功能并使能\"ENABLE_MP4\",否则对H265的支持不完善";
#endif
}
bool H265Track::update() {
return getHEVCInfo(_vps, _sps, _width, _height, _fps);
}
std::vector<Frame::Ptr> H265Track::getConfigFrames() const {
if (!ready()) {
return {};
}
return { createConfigFrame<H265Frame>(_vps, 0, getIndex()),
createConfigFrame<H265Frame>(_sps, 0, getIndex()),
createConfigFrame<H265Frame>(_pps, 0, getIndex()) };
}
Track::Ptr H265Track::clone() const {
return std::make_shared<H265Track>(*this);
}
void H265Track::insertConfigFrame(const Frame::Ptr &frame) {
@ -161,29 +203,13 @@ void H265Track::insertConfigFrame(const Frame::Ptr &frame) {
return;
}
if (!_vps.empty()) {
auto vpsFrame = FrameImp::create<H265Frame>();
vpsFrame->_prefix_size = 4;
vpsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
vpsFrame->_buffer.append(_vps);
vpsFrame->_dts = frame->dts();
VideoTrack::inputFrame(vpsFrame);
VideoTrack::inputFrame(createConfigFrame<H265Frame>(_vps, frame->dts(), frame->getIndex()));
}
if (!_sps.empty()) {
auto spsFrame = FrameImp::create<H265Frame>();
spsFrame->_prefix_size = 4;
spsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
spsFrame->_buffer.append(_sps);
spsFrame->_dts = frame->dts();
VideoTrack::inputFrame(spsFrame);
VideoTrack::inputFrame(createConfigFrame<H265Frame>(_sps, frame->dts(), frame->getIndex()));
}
if (!_pps.empty()) {
auto ppsFrame = FrameImp::create<H265Frame>();
ppsFrame->_prefix_size = 4;
ppsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
ppsFrame->_buffer.append(_pps);
ppsFrame->_dts = frame->dts();
VideoTrack::inputFrame(ppsFrame);
VideoTrack::inputFrame(createConfigFrame<H265Frame>(_pps, frame->dts(), frame->getIndex()));
}
}
@ -201,17 +227,13 @@ public:
* @param payload_type rtp payload type 96
* @param bitrate
*/
H265Sdp(const string &strVPS,
const string &strSPS,
const string &strPPS,
int bitrate = 4000,
int payload_type = 96) : Sdp(90000,payload_type) {
H265Sdp(const string &strVPS, const string &strSPS, const string &strPPS, int payload_type, int bitrate) : Sdp(90000, payload_type) {
//视频通道
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
if (bitrate) {
_printer << "b=AS:" << bitrate << "\r\n";
}
_printer << "a=rtpmap:" << payload_type << " " << getCodecName() << "/" << 90000 << "\r\n";
_printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecH265) << "/" << 90000 << "\r\n";
_printer << "a=fmtp:" << payload_type << " ";
_printer << "sprop-vps=";
_printer << encodeBase64(strVPS) << "; ";
@ -219,27 +241,75 @@ public:
_printer << encodeBase64(strSPS) << "; ";
_printer << "sprop-pps=";
_printer << encodeBase64(strPPS) << "\r\n";
_printer << "a=control:trackID=" << (int)TrackVideo << "\r\n";
}
string getSdp() const override {
return _printer;
}
string getSdp() const override { return _printer; }
CodecId getCodecId() const override {
return CodecH265;
}
private:
_StrPrinter _printer;
};
Sdp::Ptr H265Track::getSdp() {
if(!ready()){
Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<H265Sdp>(getVps(), getSps(), getPps(), getBitRate() / 1024);
return std::make_shared<H265Sdp>(_vps, _sps, _pps, payload_type, getBitRate() / 1024);
}
namespace {
CodecId getCodec() {
return CodecH265;
}
Track::Ptr getTrackByCodecId(int sample_rate, int channels, int sample_bit) {
return std::make_shared<H265Track>();
}
Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
// a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBdoAKAgC0WNrkky/AIAAADAAgAAAMBlQg=; sprop-pps=RAHA8vA8kAA=
auto map = Parser::parseArgs(track->_fmtp, ";", "=");
auto vps = decodeBase64(map["sprop-vps"]);
auto sps = decodeBase64(map["sprop-sps"]);
auto pps = decodeBase64(map["sprop-pps"]);
if (sps.empty() || pps.empty()) {
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
return std::make_shared<H265Track>();
}
return std::make_shared<H265Track>(vps, sps, pps, 0, 0, 0);
}
RtpCodec::Ptr getRtpEncoderByCodecId(uint8_t pt) {
return std::make_shared<H265RtpEncoder>();
}
RtpCodec::Ptr getRtpDecoderByCodecId() {
return std::make_shared<H265RtpDecoder>();
}
RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) {
return std::make_shared<H265RtmpEncoder>(track);
}
RtmpCodec::Ptr getRtmpDecoderByTrack(const Track::Ptr &track) {
return std::make_shared<H265RtmpDecoder>(track);
}
Frame::Ptr getFrameFromPtr(const char *data, size_t bytes, uint64_t dts, uint64_t pts) {
return std::make_shared<H265FrameNoCacheAble>((char *)data, bytes, dts, pts, prefixSize(data, bytes));
}
} // namespace
CodecPlugin h265_plugin = { getCodec,
getTrackByCodecId,
getTrackBySdp,
getRtpEncoderByCodecId,
getRtpDecoderByCodecId,
getRtmpEncoderByTrack,
getRtmpDecoderByTrack,
getFrameFromPtr };
}//namespace mediakit

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* Use of this source code is governed by MIT-like 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.
*/
@ -11,16 +11,14 @@
#ifndef ZLMEDIAKIT_H265_H
#define ZLMEDIAKIT_H265_H
#include "Frame.h"
#include "Track.h"
#include "H264.h"
#include "Extension/Track.h"
#include "Extension/Frame.h"
#define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f)
namespace mediakit {
bool getHEVCInfo(const std::string &strVps, const std::string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps);
template<typename Parent>
class H265FrameHelper : public Parent{
public:
@ -64,8 +62,6 @@ public:
this->_codec_id = CodecH265;
}
~H265FrameHelper() override = default;
bool keyFrame() const override {
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
auto type = H265_TYPE(*nal_ptr);
@ -137,24 +133,20 @@ public:
*/
H265Track(const std::string &vps,const std::string &sps, const std::string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4);
/**
* 0x00 00 00 01vps/sps/pps
*/
const std::string &getVps() const;
const std::string &getSps() const;
const std::string &getPps() const;
bool ready() override;
bool ready() const override;
CodecId getCodecId() const override;
int getVideoWidth() const override;
int getVideoHeight() const override;
float getVideoFps() const override;
bool inputFrame(const Frame::Ptr &frame) override;
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
bool update() override;
std::vector<Frame::Ptr> getConfigFrames() const override;
private:
void onReady();
Sdp::Ptr getSdp() override;
Track::Ptr clone() override;
Sdp::Ptr getSdp(uint8_t payload_type) const override;
Track::Ptr clone() const override;
bool inputFrame_l(const Frame::Ptr &frame);
void insertConfigFrame(const Frame::Ptr &frame);

Some files were not shown because too many files have changed in this diff Show More