mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 02:34:26 +08:00
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:
commit
2ffdfab71e
24
.github/ISSUE_TEMPLATE/bug.md
vendored
24
.github/ISSUE_TEMPLATE/bug.md
vendored
@ -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粘贴至此
|
||||
```
|
||||
* **其他需要补充的信息**:
|
||||
|
4
.github/ISSUE_TEMPLATE/compile.md
vendored
4
.github/ISSUE_TEMPLATE/compile.md
vendored
@ -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
6
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: 技术咨询
|
||||
url: https://t.zsxq.com/FcVK5
|
||||
about: 请在知识星球发起技术咨询
|
6
.github/ISSUE_TEMPLATE/feature.md
vendored
6
.github/ISSUE_TEMPLATE/feature.md
vendored
@ -7,8 +7,8 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**描述该功能的用处,可以提供相关资料描述该功能**
|
||||
## 描述该功能的用处,可以提供相关资料描述该功能
|
||||
|
||||
**该功能是否用于改进项目缺陷,如果是,请描述现有缺陷**
|
||||
## 该功能是否用于改进项目缺陷,如果是,请描述现有缺陷
|
||||
|
||||
**描述你期望实现该功能的方式和最终效果**
|
||||
## 描述你期望实现该功能的方式和最终效果
|
||||
|
19
.github/ISSUE_TEMPLATE/question.md
vendored
19
.github/ISSUE_TEMPLATE/question.md
vendored
@ -1,19 +0,0 @@
|
||||
---
|
||||
name: 技术咨询
|
||||
about: 使用咨询、技术咨询等
|
||||
title: "[技术咨询] 咨询描述(必填)"
|
||||
labels: 技术咨询
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**咨询的功能模块**
|
||||
- 请描述您想咨询zlmediakit的哪部分功能
|
||||
|
||||
**咨询的具体内容和问题**
|
||||
- 此处展开您咨询内容的描述
|
||||
|
||||
**注意事项**
|
||||
- 技术咨询前请先认真阅读readme, [wiki](https://github.com/xia-chu/ZLMediaKit/wiki),如有必要,您也可以同时搜索已经答复的issue,如果没找到答案才在此提issue
|
||||
|
||||
- 技术咨询不属于bug缺陷,要求用户先star(收藏)本项目,否则会直接关闭issue
|
8
.github/ISSUE_TEMPLATE/requirement.md
vendored
8
.github/ISSUE_TEMPLATE/requirement.md
vendored
@ -1,8 +0,0 @@
|
||||
---
|
||||
name: issue创建要求
|
||||
about: 不符合模板要求不便定位问题,可能会被管理员直接关闭
|
||||
title: ""
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
34
.github/workflows/android.yml
vendored
34
.github/workflows/android.yml
vendored
@ -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'
|
||||
})
|
||||
|
15
.github/workflows/docker.yml
vendored
15
.github/workflows/docker.yml
vendored
@ -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
51
.github/workflows/issue_lint.yml
vendored
Normal 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',
|
||||
});
|
119
.github/workflows/linux.yml
vendored
119
.github/workflows/linux.yml
vendored
@ -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: 运行MediaServer
|
||||
run: pwd && cd release/linux/Debug && sudo ./MediaServer -d &
|
||||
- name: 下载 usrsctp
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: sctplab/usrsctp
|
||||
fetch-depth: 1
|
||||
ref: 0.9.5.0
|
||||
path: 3rdpart/usrsctp
|
||||
|
||||
- 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'
|
||||
})
|
||||
|
67
.github/workflows/macos.yml
vendored
67
.github/workflows/macos.yml
vendored
@ -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'
|
||||
})
|
2
.github/workflows/style.yml
vendored
2
.github/workflows/style.yml
vendored
@ -4,7 +4,7 @@ on: [pull_request]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
|
48
.github/workflows/windows.yml
vendored
48
.github/workflows/windows.yml
vendored
@ -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'
|
||||
})
|
||||
|
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -6,4 +6,7 @@
|
||||
url = https://gitee.com/ireader/media-server
|
||||
[submodule "3rdpart/jsoncpp"]
|
||||
path = 3rdpart/jsoncpp
|
||||
url = https://gitee.com/mirrors/jsoncpp.git
|
||||
url = https://gitee.com/mirrors/jsoncpp.git
|
||||
[submodule "www/webassist"]
|
||||
path = www/webassist
|
||||
url = https://gitee.com/victor1002/zlm_webassist
|
||||
|
@ -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
|
@ -47,7 +47,7 @@ set(MediaServer_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/media-server")
|
||||
# TODO: 补一个函数处理各种库
|
||||
|
||||
# 添加 mov、flv 库用于 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
|
@ -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
|
||||
#undef assert
|
||||
#endif//assert
|
||||
#ifdef assert
|
||||
#undef 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
|
29
AUTHORS
29
AUTHORS
@ -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)
|
||||
@ -82,4 +81,30 @@ WuPeng <wp@zafu.edu.cn>
|
||||
[fruit Juice](https://github.com/xuandu)
|
||||
[tbago](https://github.com/tbago)
|
||||
[Luosh](https://github.com/Luosh)
|
||||
[linxiaoyan87](https://github.com/linxiaoyan)
|
||||
[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)
|
@ -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,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)
|
||||
|
||||
##############################################################################
|
||||
# 设置socket默认缓冲区大小为256k.如果设置为0则不设置socket的默认缓冲区大小,使用系统内核默认值(设置为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()
|
||||
|
||||
#cpp测试demo程序
|
||||
#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
10
LICENSE
@ -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" 的信息。
|
||||
否则本项目主要权利人(项目发起人、主要作者)保留声索起诉的权利。
|
||||
|
49
README.md
49
README.md
@ -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)
|
||||
|
||||
## 使用案例
|
||||
|
||||
|
49
README_en.md
49
README_en.md
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
* 目前支持3种,分别是RtmpMediaSource、RtspMediaSource、HlsMediaSource
|
||||
@ -138,11 +174,11 @@ 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,
|
||||
const char *vhost,
|
||||
const char *app,
|
||||
const char *stream,
|
||||
int from_mp4);
|
||||
API_EXPORT mk_media_source API_CALL mk_media_source_find2(const char *schema,
|
||||
const char *vhost,
|
||||
const char *app,
|
||||
const char *stream,
|
||||
int from_mp4);
|
||||
//MediaSource::for_each_media()
|
||||
API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb, 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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* 获取总的观看人数
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 主动模式时连接到服务器是否成功的回调
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* 获取音频采样率
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
///////////////////////////////////////////日志/////////////////////////////////////////////
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -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,11 +335,11 @@ 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,
|
||||
const char *vhost,
|
||||
const char *app,
|
||||
const char *stream,
|
||||
int from_mp4) {
|
||||
API_EXPORT mk_media_source API_CALL mk_media_source_find2(const char *schema,
|
||||
const char *vhost,
|
||||
const char *app,
|
||||
const char *stream,
|
||||
int from_mp4) {
|
||||
assert(schema && vhost && app && stream);
|
||||
auto src = MediaSource::find(schema, vhost, app, stream, from_mp4);
|
||||
return (mk_media_source)src.get();
|
||||
@ -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;
|
||||
@ -480,4 +558,22 @@ API_EXPORT void API_CALL mk_auth_invoker_clone_release(const mk_auth_invoker ctx
|
||||
assert(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
|
||||
}
|
||||
|
@ -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) {
|
||||
_cb(_user_data.get(), _ptr);
|
||||
}
|
||||
~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) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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后再编译";
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)));
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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
152
api/tests/h264_pusher.c
Normal 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;
|
||||
}
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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} )
|
||||
|
@ -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-2016,c.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
1
conf/novideo.yuv
Normal file
File diff suppressed because one or more lines are too long
24
conf/readme.md
Normal file
24
conf/readme.md
Normal 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性能。
|
146
default.pem
146
default.pem
@ -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==
|
||||
-----END CERTIFICATE-----
|
||||
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
|
||||
L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
|
||||
98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
|
||||
xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
|
||||
GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
|
||||
n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
|
||||
-----END CERTIFICATE-----
|
@ -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"]
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
20
dockerfile
20
dockerfile
@ -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/*
|
||||
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"]
|
||||
|
@ -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[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[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
|
||||
}
|
||||
|
||||
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
57
ext-codec/AAC.h
Normal 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
66
ext-codec/AACRtmp.cpp
Normal 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
|
@ -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
127
ext-codec/AACRtp.cpp
Normal 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
64
ext-codec/AACRtp.h
Normal 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
48
ext-codec/CMakeLists.txt
Normal 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
188
ext-codec/G711.cpp
Normal 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
|
||||
|
||||
|
@ -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
|
@ -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 ¶m) {
|
||||
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
48
ext-codec/G711Rtp.h
Normal 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 ¶m) override;
|
||||
|
||||
private:
|
||||
uint32_t _channels = 1;
|
||||
uint32_t _pkt_dur_ms = 20;
|
||||
FrameImp::Ptr _cache_frame;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
#endif //ZLMEDIAKIT_G711RTP_H
|
@ -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
|
@ -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 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param pps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 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 01头的sps/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
109
ext-codec/H264Rtmp.cpp
Normal 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
|
@ -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) {}
|
||||
|
||||
/**
|
||||
* 输入264帧,可以不带sps 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
|
@ -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) {
|
@ -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,26 +57,11 @@ 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 帧数据,必须
|
||||
*/
|
@ -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
|
||||
|
@ -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 01头的vps/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
Loading…
Reference in New Issue
Block a user