Compare commits

...

160 Commits

Author SHA1 Message Date
Haibo Chen(陈海博)
27b5d15320 Fix H.264 B-frame detection logic to comply with specification. v5.0.224 (#4414)
For H.264, only when the NAL Type is 1, 2, 3, or 4 is it possible for
B-frames to be present; that is, non-IDR pictures and slice data.

The current `SrsVideoFrame::parse_avc_bframe()` function uses incorrect
logic to determine if a NALU can contain B-frames. The original
implementation only checked for specific NALU types (IDR, SPS, PPS) to
mark as non-B-frames, but this approach misses many other NALU types
that cannot contain B-frames according to the H.264 specification.

According to H.264 specification (ISO_IEC_14496-10-AVC-2012.pdf, Table
7-1), B-frames can **only** exist in these specific NALU types:
- Type 1: Non-IDR coded slice (`SrsAvcNaluTypeNonIDR`)
- Type 2: Coded slice data partition A (`SrsAvcNaluTypeDataPartitionA`)
- Type 3: Coded slice data partition B (`SrsAvcNaluTypeDataPartitionB`)
- Type 4: Coded slice data partition C (`SrsAvcNaluTypeDataPartitionC`)

All other NALU types (IDR=5, SEI=6, SPS=7, PPS=8, AUD=9, etc.) cannot
contain B-frames by definition.

---------

Co-authored-by: Jacob Su <suzp1984@gmail.com>
Co-authored-by: winlin <winlinvip@gmail.com>
2025-07-10 09:18:02 -04:00
winlin
7edfaa0a66 Upgrade actions worlflow image to Ubuntu 22.04 2025-04-26 00:13:00 -04:00
john
3df44f8cb2 free sample to prevent memory leak. v5.0.222 (#4305)
修复`SrsRtpRawPayload::copy()`方法中sample_覆盖的问题。

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: winlin <winlinvip@gmail.com>

---------

Co-authored-by: john <hondaxiao@tencent.com>
2025-03-21 10:39:57 +08:00
john
3456fc690e update geekyeggo/delete-artifact to 5.0.0. v5.0.221 v6.0.163 v7.0.25 (#4302)
>
https://github.com/marketplace/actions/delete-artifact?version=v5.0.0#-compatibility

The current version of `actions/upload-artifact` is `v4`, and the
corresponding version for `delete-artifact` should be `v5`.

---------

`TRANS_BY_GPT4`

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: winlin <winlinvip@gmail.com>

---------

Co-authored-by: john <hondaxiao@tencent.com>
2025-03-18 08:28:43 +08:00
john
bd333fe7b4 fix typo about heartbeat. v5.0.220 (#4253)
---------

Co-authored-by: Haibo Chen <495810242@qq.com>
Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: winlin <winlinvip@gmail.com>

---------

Co-authored-by: john <hondaxiao@tencent.com>
2025-02-24 21:02:31 +08:00
john
5851fa05d2 fix ci error. v5.0.219 (#4291)
Starting January 30th, 2025, GitHub Actions customers will no longer be
able to use v3 of
[actions/upload-artifact](https://github.com/actions/upload-artifact) or
[actions/download-artifact](https://github.com/actions/download-artifact).
Customers should update workflows to begin using [v4 of the artifact
actions](https://github.blog/2024-02-12-get-started-with-v4-of-github-actions-artifacts/).
Learn more:
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/

---------

Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: winlin <winlinvip@gmail.com>

---------

Co-authored-by: john <hondaxiao@tencent.com>
2025-02-24 19:37:23 +08:00
john
4526a8b781 update copyright to 2025. v5.0.218 (#4271)
update copyright to 2025

---------

Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: winlin <winlinvip@gmail.com>
2025-02-24 19:30:55 +08:00
Haibo Chen
65ea140126 HLS: Fix error when stream has extension. #4215 v5.0.217 (#4216)
---------

Co-authored-by: Jacob Su <suzp1984@gmail.com>
Co-authored-by: winlin <winlinvip@gmail.com>
2024-10-31 18:02:54 +08:00
Jacob Su
b0e7f62ca7 RTC2RTMP: Fix screen sharing stutter caused by packet loss. v5.0.216 (#4160)
1. Refer this commit, which contains the web demo to capture screen as
video stream through RTC.
2. Copy the `trunk/research/players/whip.html` and
`trunk/research/players/js/srs.sdk.js` to replace the `develop` branch
source code.
3. `./configure && make`
4. `./objs/srs -c conf/rtc2rtmp.conf`
5. open `http://localhost:8080/players/whip.html?schema=http`
6. check `Screen` radio option.
7. click `publish`, then check the screen to share.
8. play the rtmp live stream: `rtmp://localhost/live/livestream`
9. check the video stuttering.

When capture screen by the chrome web browser, which send RTP packet
with empty payload frequently, then all the cached RTP packets are
dropped before next key frame arrive in this case.

The OBS screen stream and camera stream do not have such problem.

><img width="581" alt="Screenshot 2024-08-28 at 2 49 46 PM"
src="https://github.com/user-attachments/assets/9557dbd2-c799-4dfd-b336-5bbf2e4f8fb8">

---------

Co-authored-by: winlin <winlinvip@gmail.com>
2024-10-15 19:45:36 +08:00
Winlin
bfdbbb9be0 Heartbeat: Report ports for proxy server. v5.0.215 (#4171)
The heartbeat of SRS is a timer that requests an HTTP URL. We can use
this heartbeat to report the necessary information for registering the
backend server with the proxy server.

```text
SRS(backend) --heartbeat---> Proxy server
```

A proxy server is a specialized load balancer for media servers. It
operates at the application level rather than the TCP level. For more
information about the proxy server, see issue #4158.

Note that we will merge this PR into SRS 5.0+, allowing the use of SRS
5.0+ as the backend server, not limited to SRS 7.0. However, the proxy
server is introduced in SRS 7.0.

It's also possible to implement a registration service, allowing you to
use other media servers as backend servers. For example, if you gather
information about an nginx-rtmp server and register it with the proxy
server, the proxy will forward RTMP streams to nginx-rtmp. The backend
server is not limited to SRS.

---------

Co-authored-by: Jacob Su <suzp1984@gmail.com>
2024-09-09 10:39:53 +08:00
Winlin
ad0d510ba2 Edge: Improve stability for state and fd closing. v5.0.214 (#4126)
1. Should always stop coroutine before close fd, see #511, #1784
2. When edge forwarder coroutine quit, always set the error code.
3. Do not unpublish if invalid state.

---------

Co-authored-by: Jacob Su <suzp1984@gmail.com>
2024-07-24 10:16:33 +08:00
Jacob Su
313913737f RTC: Support dropping h.264 SEI from NALUs. v5.0.213 (#4057)
try to fix #4052.

---------

Co-authored-by: winlin <winlinvip@gmail.com>
2024-06-03 16:37:10 +08:00
Winlin
9995147704 RTMP: Do not response publish start message if hooks fail. v5.0.212 (#4038)
Fix #4037 SRS should not send the publish start message
`onStatus(NetStream.Publish.Start)` if hooks fail, which causes OBS to
repeatedly reconnect.

Note that this fix does not send an RTMP error message when publishing
fails, because neither OBS nor FFmpeg process this specific error
message; they only display a general error.

Apart from the order of messages, nothing else has been changed.
Previously, we sent the publish start message
`onStatus(NetStream.Publish.Start)` before the HTTP hook `on_publish`;
now, we have modified it to send this message after the HTTP hook.
2024-04-23 15:22:41 +08:00
Jacob Su
299a542f10 Support x509 certification chiain in single pem file. v5.0.211 (#4033)
Fix #3967 There is an API `SSL_use_certificate_chain_file`, which can load the
certification chain and also single certificate.

---------

Co-authored-by: winlin <winlinvip@gmail.com>
2024-04-22 10:16:59 +08:00
winlin
d9cc57a3f3 Release v5.0-r2, 5.0 release2, v5.0.210, 163515 lines. 2024-04-03 15:04:09 +08:00
Winlin
c75c9840d5 Merge pull request from GHSA-gv9r-qcjc-5hj7
* Filter JSONP callback function name. v5.0.210,v6.0.121

* Add utest.

* Refine utest
2024-03-28 11:02:09 +08:00
john
ee6a68d24c System: Disable feature that obtains versions and check features status. v5.0.209 (#3990)
See https://github.com/ossrs/srs/issues/2424

---------

Co-authored-by: john <hondaxiao@tencent.com>
2024-03-19 19:16:38 +08:00
winlin
f32c8c31c0 Release v5.0-r1, 5.0 release1, v5.0.208, 163441 lines. 2024-02-15 12:10:19 +08:00
john
732569f792 WHIP: Fix bug for converting WHIP to RTMP/HLS. v5.0.208 (#3920)
1. When converting RTC to RTMP, it is necessary to synchronize the audio
and video timestamps. When the synchronization status changes, whether
it is unsynchronized or synchronized, print logs to facilitate
troubleshooting of such issues.
2. Chrome uses the STAP-A packet, which means a single RTP packet
contains SPS/PPS information. OBS WHIP, on the other hand, sends SPS and
PPS in separate RTP packets. Therefore, SPS and PPS are in two
independent RTP packets, and SRS needs to cache these two packets.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2024-02-06 14:22:33 +08:00
john
ba150beb0f RTC: Fix video and audio track pt_ is not change in player before publisher. v5.0.207 (#3925)
For WebRTC:
when player before publisher, it will happen track pt didn't change.

 - At source change step, change track pt

---------

Co-authored-by: mingche.tsai <w41203208.work@gmail.com>
Co-authored-by: john <hondaxiao@tencent.com>
2024-02-05 15:17:32 +08:00
john
96a8d17573 Configure: print enabled/disable sanitizer. v5.0.206 (#3923)
---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2024-02-05 12:16:05 +08:00
winlin
55026a4fc7 Release v5.0-r0, 5.0 release0, v5.0.205, 163363 lines. 2023-12-30 09:30:05 +08:00
winlin
e15fb07916 Switch to 2013-2024. v5.0.205 2023-12-30 09:29:07 +08:00
Haibo Chen
ef5d216dbc Enhancing the compatibility of options.sh. v5.0.204 (#3916)
Accommodate certain complex parameters that include the "=" character,
for example.
`configure --extra-flags="-O2 -D_FORTIFY_SOURCE=2"`

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-12-30 09:13:01 +08:00
winlin
4aef9bb6af Fix version bug. 2023-12-30 09:03:30 +08:00
john
43d15ed3d8 RTC: Support OPUS stereo SDP option. v5.0.203 (#3910)
In an SDK that supports RTC Opus stereo, the parameter "stereo=1" may
appear. SRS (Spatial Reference System) needs to handle this correctly
and return an answer to enable WebRTC stereo support.

---------

`TRANS_BY_GPT4`
2023-12-14 23:31:54 +08:00
john
52b01b14e9 Security: Support IP whitelist for HTTP-FLV, HLS, WebRTC, and SRT. v5.0.202 (#3902)
Security is the built-in IP whitelist feature of SRS, which allows and
denies certain IP and IP range users. Previously, it only supported
RTMP, but this PR now supports HTTP-FLV, HLS, WebRTC, SRT, and other
protocols.

See https://ossrs.io/lts/en-us/docs/v6/doc/security as example.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-12-14 21:37:38 +08:00
john
0808be18ad fix 'sed' error in options.sh. v5.0.201 (#3891)
The `-` character, when placed in the middle of a regular expression, is
interpreted as a range. It must be placed at the beginning or end to be
interpreted as a literal character.

---------

`TRANS_BY_GPT4`

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-11-23 13:32:42 +08:00
winlin
f1b419df4c Release v5.0-b7, 5.0 beta7, v5.0.200, 163305 lines. 2023-11-19 21:57:17 +08:00
Winlin
a1901b5213 Change the hls_aof_ratio to 2.1. v5.0.200 (#3886)
In pure audio mode, there are no keyframes. Therefore, we can only rely
on the length of the slice to determine whether it should be output.
`hls_aof_ratio` is the coefficient that, once reached, will generate a
new slice.

In scenarios with video, if the `hls_aof_ratio` is too small, for
example 1.2, and the GOP (Group of Pictures) is 10 seconds, then a slice
will definitely be generated at 12 seconds. At this point, if there are
no keyframes, it will cause the next slice to start with a non-keyframe.

A safer coefficient is twice the GOP (Group of Pictures). This way, it
won't trigger incorrectly and prevent the individual transcoding of a ts
segment file.

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-11-19 21:53:51 +08:00
Haibo Chen
4e4cce867b Support configure with --extra-ldflags. v5.0.199 (#3879)
1. add --extra-ldflags
2. support  commas in configure file
3. support link system library for utest

```
./configure --extra-ldflags=-Wl,-z,now
```
2023-11-15 17:45:26 +08:00
Haibo Chen
316f4641ac Don't compile libopus when enable sys-ffmpeg. v5.0.198 (#3851) 2023-11-06 14:54:13 +08:00
chundonglinlin
f1db76011b RTC: Refine FFmpeg opus audio noisy issue. v5.0.197 (#3852)
When converting between AAC and Opus formats (aac2opus or opus2aac), the
`av_frame_get_buffer` API is frequently called.

The goal is to optimize the code logic and reduce the frequent
allocation and deallocation of memory.

In the case of aac2opus, av_frame_get_buffer is still frequently called.
In the case of opus2aac, the goal is to avoid calling
av_frame_get_buffer and reduce memory allocations.

Before calling the `av_audio_fifo_read` API, use
`av_frame_make_writable` to check if the frame is writable. If it is not
writable, create a new frame.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-11-04 16:28:52 +08:00
chundonglinlin
35f479c6bc Support build without cache to test if actions fail. v5.0.196 (#3858)
By default, caching is enabled during compilation, which means that data
is cached in Docker. This helps to avoid compiling third-party
dependency libraries. However, sometimes when updating third-party
libraries, it's necessary to disable caching to temporarily verify if
the pipeline can succeed. Therefore, a configure option should be added.
When this option is enabled, the compilation cache will not be used, and
all third-party libraries will be compiled from scratch.

---------

Co-authored-by: winlin <winlinvip@gmail.com>
2023-11-01 17:49:51 +08:00
winlin
fb7a000f47 Release v5.0-b6, 5.0 beta6, v5.0.195, 163303 lines. 2023-10-25 20:40:48 +08:00
john
268bac58bd RTC: Fix FFmpeg opus audio noisy issue. v5.0.195 (#3845)
Follow the example in FFmpeg's doc, before calling the API
`avcodec_send_frame`, always use `av_frame_alloc` to create a new frame.

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-10-25 11:58:35 +08:00
chundonglinlin
d51cabb4b7 WebRTC: TCP transport should use read_fully instead of read. v5.0.194 (#3847)
SRS supports TCP WebRTC by reading 2 bytes of length, like `read(buf,
2)`. However, in some cases, it might receive 1 byte, causing subsequent
data to be incorrect and making it unable to push or play streams.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-23 14:54:24 +08:00
john
a9223ebe47 Added system library option for ffmpeg, srtp, srt libraries. v5.0.193 (#3846)
---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-20 22:35:18 +08:00
john
56a4ca3f7e Disable asan by default. v5.0.192 (#3840)
---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-17 23:07:35 +08:00
john
ba33bb8f8b Support set the ice-ufrag and ice-pwd for connectivity check. v5.0.191 (#3837)
Checking the HTTPS API or UDP connectivity for WHIP tests can be
difficult. For example, if the UDP port isn't available but the API is
fine, OBS only says it can't connect to the server. It's hard to see the
HTTPS API response or check if the UDP port is available.

This feature lets you set the ice username and password in SRS. You can
then send a STUN request using nc and see the response, making it easier
to check UDP port connectivity.

1. Use curl to test the WHIP API, including ice-frag and ice-pwd
queries.
2. Use nc to send a STUN binding request to test UDP connectivity.
3. If both the API and UDP are working, you should get a STUN response.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-17 22:36:10 +08:00
john
3da81e4b75 Refine docker detect mechenism. v5.0.190 (#3758)
When using Docker, logs are usually printed to console (stdout and
stderr). However, since Docker detection occurs late, after log
initialization, the default log output may be incorrect. In Docker, logs
may still be written to a file instead of the console as expected.

Additionally, the Dockerfile has been improved with a new environment
variable `SRS_IN_DOCKER=on` to clearly indicate a Docker environment. If
automatic Docker detection fails, the configuration will be read, and
this variable will correctly inform SRS that it's in a Docker
environment.

Lastly, the default configuration values have been improved for Docker
environments. By default, `SRS_LOG_TANK=console` and daemon mode is
disabled.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-17 21:27:07 +08:00
肖志宏
ef7fe1b186 Fix bug for upgrading to OpenSSL 3.0. v5.0.189 (#3827)
The fix is for the DH_set_length error. As shown in lines 2-5, OpenSSL
3.0 added a check for length, which allowed this issue to be exposed.
```
1 if (dh->params.q == NULL) {
2       /* secret exponent length, must satisfy 2^(l-1) <= p */
3        if (dh->length != 0
4            && dh->length >= BN_num_bits(dh->params.p))
5            goto err;
6        l = dh->length ? dh->length : BN_num_bits(dh->params.p) - 1;
7        if (!BN_priv_rand_ex(priv_key, l, BN_RAND_TOP_ONE,
8                             BN_RAND_BOTTOM_ANY, 0, ctx))
9            goto err;
        ... ...
    }
```

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-11 20:52:25 +08:00
肖志宏
53ebf58583 SRT: Fix the missing config mss. v5.0.188 (#3825)
---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-10-10 20:27:30 +08:00
john
75c9c5a849 Solve the problem of inaccurate HLS TS duration. v5.0.187 (#3824) 2023-10-09 20:29:27 +08:00
肖志宏
8b80566f78 Use new cache image name. v5.0.186 2023-10-08 21:13:47 +08:00
winlin
ed0be6c7dc Release v5.0-b5, 5.0 beta5, v5.0.185, 163254 lines. 2023-09-28 09:52:37 +08:00
Haibo Chen
4455065246
Cherry-pick from develop, for srt utest. v5.0.185 (#3816) 2023-09-28 09:48:54 +08:00
Haibo Chen
3ddacdb47b Build: Support sys-ssl for srt. v5.0.184 (#3806)
support sys-ssl for srt

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-09-21 23:06:14 +08:00
winlin
632d457194 Upgrade libsrt to v1.5.3. v5.0.183 (#3808) 2023-09-21 22:31:38 +08:00
Winlin
389a62ee3a WebRTC: Support WHEP for play. v5.0.182 (#3404)
RFC for WHIP: https://datatracker.ietf.org/doc/draft-ietf-wish-whip/

RFC for WHEP: https://datatracker.ietf.org/doc/draft-murillo-whep/

Please note that SRS 5.0 already had WHIP support. I didn't write a
document about WHIP, because WHIP is not a RFC right now, but there are
clues in
[srs-unity](https://github.com/ossrs/srs-unity#usage-publisher). SRS
WHIP url for publisher:
`http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream`

This PR is for WHEP, the url for player is
`http://localhost:1985/rtc/v1/whep/?app=live&stream=livestream`

PS: There is a great PR for OBS to have WHIP support, see
https://github.com/obsproject/obs-studio/pull/7926 and #3581

PS: WHIP for FFmpeg https://github.com/ossrs/ffmpeg-webrtc/pull/1

See #3170

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-09-21 18:43:57 +08:00
john
456f5d64a9 Prevent the output of srt logs in utest. v5.0.181 (#3807)
Prevent the output of srt logs in utest.

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-09-21 15:42:20 +08:00
john
21ae618c48 SRT: Log level to debug when no socket to accept. v5.0.180 (#3696) 2023-09-21 15:11:55 +08:00
Winlin
bc0a516fd1 Support FFmpeg timecode, fix AMF0 parsing failed. v5.0.179 (#3804)
Please see https://github.com/ossrs/srs/issues/3803 for detail:

1. When using FFmpeg with the `-map 0` option, there may be a 4-byte
timecode in the AMF0 Data.
2. SRS should be able to handle this packet without causing a parsing
error, as it's generally expected to be an AMF0 string, not a 4-byte
timecode.
3. Disregard the timecode since SRS doesn't utilize it.

See [Error submitting a packet to the muxer: Broken pipe, Error muxing a
packet](https://trac.ffmpeg.org/ticket/10565)

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-09-18 13:53:28 +08:00
Mr. Li
b352fd0cfe Fix RBSP issue, where 0x03 should be removed. v5.0.178 (#3597)
ISO_IEC_14496-10-AVC-2012.pdf, page 65
7.4.1.1 Encapsulation of an SODB within an RBSP (informative)

... 00 00 03 xx, the 03 byte should be drop where xx represents any 2
bit pattern: 00, 01, 10, or 11.

---------

Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: winlin <winlin@vip.126.com>
2023-09-09 11:15:30 +08:00
john
fc9a44d4b4 Fix dash crash if format not supported. v5.0.177 (#3795)
Fix the issue of DASH crashing when audio/video formats are not
supported.

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-09-07 23:02:28 +08:00
winlin
ea1f96e6c5 Release v5.0-b4, 5.0 beta4, v5.0.176, 162919 lines. 2023-08-31 09:47:52 +08:00
Winlin
0df81c3b34 Support HTTP-API for fetching reload result. v5.0.176 (#3779)
During a Reload, several stages will be passed through:
1. Parsing new configurations: Parse.
2. Transforming configurations: Transform.
3. Applying configurations: Apply.

Previously, any error at any stage would result in a direct exit, making
the system completely dependent on configuration checks:

```bash
./objs/srs -c conf/srs.conf -t
echo $?
```

Optimized to: If an error occurs before applying the configuration, it
can be ignored. If an error occurs during the application of the
configuration, some of the configuration may have already taken effect,
leading to unpredictable behavior, so SRS will exit directly.

Added a new HTTP API to query the result of the reload.

```nginx
http_api {
    enabled         on;
    raw_api {
        enabled on;
        allow_reload on;
    }
}
```

```bash
curl http://localhost:1985/api/v1/raw?rpc=reload-fetch
```

```json
{
  "code": 0,
  "data": {
    "err": 0,
    "msg": "Success",
    "state": 0,
    "rid": "0s6y0n9"
  }
}

{
  "code": 0,
  "data": {
    "err": 1023,
    "msg": "code=1023(ConfigInvalid) : parse file : parse buffer containers/conf/srs.release-local.conf : root parse : parse dir : parse include buffer containers/data/config/srs.vhost.conf : read token, line=0, state=0 : line 3: unexpected end of file, expecting ; or \"}\"",
    "state": 1,
    "rid": "0g4z471"
  }
}
```

This way, you can know if the last reload of the system was successful.

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-08-30 19:36:11 +08:00
Jacob Su
cbb5edcc3c SrsContextId assignment can be improved without create a duplicated one. v5.0.175 (#3503)
SrsContextId object creation can be improved on `srs_protocol_log.cpp`,
No need to create one, then assign it back. It seems a common mistake
for Cpp programmers.

---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-08-28 15:55:54 +08:00
Winlin
8d6b882034 HLS: Fix on_hls and hls_dispose critical zone issue. v5.0.174 (#3781)
on_hls and hls_dispose are two coroutines, with potential race
conditions. That is, during on_hls, if the API Server being accessed is
slower, it will switch to the hls_dispose coroutine to start cleaning
up. However, when the API Server is processing the slice, a situation
may occur where the slice does not exist, resulting in the following
log:

```
[2023-08-22 12:03:20.309][WARN][40][x5l48q7b][11] ignore task failed code=4005(HttpStatus)(Invalid HTTP status code) : callback on_hls http://localhost:2024/terraform/v1/hooks/srs/hls : http: post http://localhost:2024/terraform/v1/hooks/srs/hls with {"server_id":"vid-5d7dxn8","service_id":"cu153o7g","action":"on_hls","client_id":"x5l48q7b","ip":"172.17.0.1","vhost":"__defaultVhost__","app":"live","tcUrl":"srt://172.17.0.2/live","stream":"stream-44572-2739617660809856576","param":"secret=1ed8e0ffbc53439c8fc8da30ab8c19f0","duration":4.57,"cwd":"/usr/local/srs-stack/platform","file":"./objs/nginx/html/live/stream-44572-2739617660809856576-1.ts","url":"live/stream-44572-2739617660809856576-1.ts","m3u8":"./objs/nginx/html/live/stream-44572-2739617660809856576.m3u8","m3u8_url":"live/stream-44572-2739617660809856576.m3u8","seq_no":1,"stream_url":"/live/stream-44572-2739617660809856576","stream_id":"vid-0n9zoz3"}, status=500, res=invalid ts file ./objs/nginx/html/live/stream-44572-2739617660809856576-1.ts: stat ./objs/nginx/html/live/stream-44572-2739617660809856576-1.ts: no such file or directory
thread [40][x5l48q7b]: call() [./src/app/srs_app_hls.cpp:122][errno=11]
thread [40][x5l48q7b]: on_hls() [./src/app/srs_app_http_hooks.cpp:401][errno=11]
thread [40][x5l48q7b]: do_post() [./src/app/srs_app_http_hooks.cpp:638][errno=11]

[error] 2023/08/22 12:03:20.076984 [52][1001] Serve /terraform/v1/hooks/srs/hls failed, err is stat ./objs/nginx/html/live/stream-44572-2739617660809856576-1.ts: no such file or directory
invalid ts file ./objs/nginx/html/live/stream-44572-2739617660809856576-1.ts
main.handleOnHls.func1.1
	/g/platform/srs-hooks.go:684
main.handleOnHls.func1
	/g/platform/srs-hooks.go:720
net/http.HandlerFunc.ServeHTTP
	/usr/local/go/src/net/http/server.go:2084
net/http.(*ServeMux).ServeHTTP
	/usr/local/go/src/net/http/server.go:2462
net/http.serverHandler.ServeHTTP
	/usr/local/go/src/net/http/server.go:2916
net/http.(*conn).serve
	/usr/local/go/src/net/http/server.go:1966
runtime.goexit
	/usr/local/go/src/runtime/asm_amd64.s:1571
```

Similarly, when stopping the stream, on_hls will also be called to
handle the last slice. If the API Server is slower at this time, it will
enter hls_dispose and call unpublish repeatedly. Since the previous
unpublish is still blocked in on_hls, the following interference log
will appear:

```
[2023-08-22 12:03:18.748][INFO][40][6498088c] hls cycle to dispose hls /live/stream-44572-2739617660809856576, timeout=10000000ms
[2023-08-22 12:03:18.752][WARN][40][6498088c][115] flush audio ignored, for segment is not open.
[2023-08-22 12:03:18.752][WARN][40][6498088c][115] ignore the segment close, for segment is not open.
```

Although this log will not cause problems, it can interfere with
judgment.

The solution is to add an 'unpublishing' status. If it is in the
'unpublishing' status, then do not clean up the slices.

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-08-28 11:43:14 +08:00
Winlin
fdcff383ae Support include empty config file. v5.0.173 (#3768)
SRS supports including another configuration in the include package.
When generating configurations, we can only generate the changed
configurations, while the unchanged configurations are in the fixed
files, for example:

```nginx
listen 1935;
include server.conf;
```

In `server.conf`, we can manage the changing configurations with the
program:

```nginx
http_api { enabled on; }
```

However, during system initialization, we often create an empty
`server.conf`, and the content is generated only after the program
starts, so `server.conf` might be an empty file. This also makes it
convenient to use a script to confirm the existence of this file:

```bash
touch server.conf
```

Currently, SRS does not support empty configurations and will report an
error. This PR is to solve this problem, making it more convenient to
use include.

`TRANS_BY_GPT4`

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-08-28 10:58:37 +08:00
Winlin
20f238eb9a HLS: Support reload HLS asynchronously. v5.0.172 (#3782)
When reloading HLS, it directly operates unpublish and publish. At this
time, if HLS is pushed, an exception may occur.

The reason is that these two coroutines operated on the HLS object at
the same time, causing a null pointer.

Solution: Use asynchronous reload. During reload, only set variables and
let the message processing coroutine implement the reload.

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-08-25 09:44:56 +08:00
terrencetang2023
df8c028054 Bugfix: Log format output type does not match. v5.0.171 (#3775)
A segmentation fault occurred on arm
https://github.com/ossrs/srs/issues/3714

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
2023-08-22 09:39:47 +08:00
winlin
94a53431ff Update latest release to SRS 5.0 2023-08-02 15:01:09 +08:00
winlin
c3d265c07c Release v5.0-b3, 5.0 beta3, v5.0.170, 162704 lines. 2023-08-02 11:04:49 +08:00
winlin
939f6b484b HLS: Ignore empty NALU to avoid error. v5.0.170 2023-08-02 11:02:22 +08:00
Mr. Li
08147f81bf Bugfix: Eliminate the redundant declaration of the _srs_rtc_manager variable. v5.0.169 (#3699)
It is advised to eliminate any instances of _srs_rtc_manager that occur
multiple times.

---------

Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-07-26 20:17:23 +08:00
john
c7851da464 API: Fix HTTPS callback issue using SNI in TLS client handshake. v5.0.168 (#3695)
---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-07-21 12:33:01 +08:00
chundonglinlin
e11b93d664 WebRTC: Support config the bitrate of transcoding AAC to Opus. v5.0.167, v6.0.60 (#3515)
---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-07-18 11:11:49 +08:00
winlin
497ea2bc90 For #2508, Add platform information. 2023-07-11 07:01:31 +08:00
winlin
f61fd18f5e Fix release note issue. 2023-07-10 10:35:00 +08:00
winlin
4811dd76f8 Release v5.0-b2, 5.0 beta2, v5.0.166, 162520 lines. 2023-07-10 08:22:48 +08:00
chundonglinlin
29271a46d3 Compile: Fix typo for 3rdparty. v5.0.166, v6.0.59 (#3615)
---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-07-10 08:22:34 +08:00
winlin
c6eddc72e9 Fix issue of srs-player failing to play HTTP-FLV. v5.0.165 2023-07-09 17:54:51 +08:00
winlin
cbcc41c156 Add new docker tag x.y.z for helm. 2023-07-02 17:19:27 +08:00
Winlin
6d679fd0e3 WHIP: Improve WHIP deletion by token verification. v5.0.164, v6.0.58 (#3595)
------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-07-01 19:10:09 +08:00
wangzhen
17f0d1fefc BugFix: Resolve the problem of srs_error_t memory leak. v5.0.163, v6.0.57 (#3605)
---------

Co-authored-by: Haibo Chen <495810242@qq.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-07-01 18:50:45 +08:00
Haibo Chen
3955d3fe55 Improve the usage of "transcode" in the "full.conf" file. v5.0.162, v6.0.56 (#3596)
---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: john <hondaxiao@tencent.com>
2023-06-30 07:16:27 +08:00
panda
3a14bb4620 Upgrade jquery from 1.10.2 to 1.12.2 (#3571)
---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-06-30 06:29:50 +08:00
Winlin
883ef7513b Switch to 5.0 document, because it's beta now. (#3609)
------

Co-authored-by: john <hondaxiao@tencent.com>
2023-06-30 06:06:33 +08:00
Kazuo
596270feff H264: Fix H.264 ISOM reserved bit value. v5.0.161, v6.0.55 (#3551)
---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-06-22 06:37:43 +08:00
Haibo Chen
fbccdb92b7 Fix Permission Issue in depend.sh for OpenSSL Compilation. v5.0.160, v6.0.53 (#3592)
---------

Co-authored-by: john <hondaxiao@tencent.com>
2023-06-20 15:32:38 +08:00
john
ca46185ace Fix crash when process rtcp feedback message. v5.0.159, v6.0.52 (#3591)
---------

Co-authored-by: johzzy <hellojinqiang@gmail.com>
2023-06-20 13:21:42 +08:00
Winlin
5759025e43 WHIP: Add OBS support, ensuring compatibility with a unique SDP. v5.0.158, v6.0.51 (#3581)
1. Ignore SDP GROUP LS.
2. Support ice in global session info.
3. Support audio codec "OPUS" or "opus".

---------

Co-authored-by: Johnny <hellojinqiang@gmail.com>
2023-06-15 12:13:10 +08:00
winlin
1713a542ed Release v5.0-b1, 5.0 beta1, v5.0.157, 162494 lines. 2023-06-11 08:22:45 +08:00
panda
1e43bb6b9f Fix command injection in api-server for HTTP callback. v5.0.157, v6.0.48 2023-06-05 16:41:19 +08:00
Winlin
1545425e06 TEST: Upgrade pion to v3.2.9. (#3567)
------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-06-05 11:43:41 +08:00
Winlin
900c4cdd97 DTLS: Use bio callback to get fragment packet. v5.0.156, v6.0.47 (#3565)
1. The MTU is effective, with the certificate being split into two DTLS records to comply with the limit.
2. The issue occurs when using BIO_get_mem_data, which retrieves all DTLS packets in a single call, even though each is smaller than the MTU.
3. An alternative callback is available for using BIO_new with BIO_s_mem.
4. Improvements to the MTU setting were made, including adding the DTLS_set_link_mtu function and removing the SSL_set_max_send_fragment function.
5. The handshake process was refined, calling SSL_do_handshake only after ICE completion, and using SSL_read to handle handshake messages.
6. The session close code was improved to enable immediate closure upon receiving an SSL CloseNotify or fatal message.

------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-06-05 10:54:57 +08:00
chundonglinlin
79fd66d8e6 SSL: Fix SSL_get_error get the error of other coroutine. v5.0.156, v6.0.46 (#3513)
---------

Co-authored-by: john <hondaxiao@tencent.com>
Co-authored-by: winlin <winlin@vip.126.com>
2023-05-29 13:03:59 +08:00
winlin
9ffbefac1c Update release workflow and remove unnecessary scripts
1. Updated the release workflow for GitHub action.
2. Removed the script that updates the lh.ossrs.net and d.ossrs.net.
3. Only kept a demo script for updating r.ossrs.net.

Please note that this code has not been tested yet, but it is expected to work. The changes will be triggered in the next release.
2023-05-14 17:39:39 +08:00
winlin
6e77653cdc Release v5.0-b0, 5.0 beta0, v5.0.155, 162600 lines. 2023-05-14 13:07:56 +08:00
winlin
261bebcad1 Support the publishing of RTP plaintext packets using WHIP. v5.0.155 2023-05-14 12:50:35 +08:00
ChenGH
a570169a27 asan: Fix memory leak in asan by releasing global IPs when run_directly_or_daemon fails. v5.0.154, v6.0.44 (#3541)
- Resolved a memory leak issue in asan when run_directly_or_daemon fails
- Previously, global IP lists were not freed, causing asan to report memory leaks
- Updated the code to always free global IP lists, regardless of whether run_directly_or_daemon fails or succeeds

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-05-14 12:25:48 +08:00
winlin
33db1584bf WHIP: Improve HTTP DELETE for notifying server unpublish event. v5.0.153 2023-05-12 15:27:03 +08:00
Winlin
d1e770c4e5 WHIP: Improve HTTP DELETE for notifying server unpublish event (#3539)
This PR improves the functionality of the HTTP DELETE method used by WHIP to notify the server when the client stops publishing. The URL is parsed from the location header returned by SRS, and the URL is refined with the addition of the action=delete parameter to ensure more accurate identification of the DELETE request.

Furthermore, SRS will disconnect and close the session, enabling the client to publish the stream again quickly and easily. This update eliminates the approximately 30-second waiting period previously required for republishing the stream after an unpublish event.

Overall, this update provides a more effective and efficient method for notifying the server about unpublish events and will enhance the workflow experience for users of the WHIP platform.

-------

Co-authored-by: Haibo Chen <495810242@qq.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-05-12 15:25:26 +08:00
Haibo Chen
12f3a31175 API: Support HTTP basic authentication for API. v6.0.4, v5.0.152 (#3458)
PICK 771ae0a1a6

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: john <hondaxiao@tencent.com>
2023-04-01 12:48:33 +08:00
chundonglinlin
41decbae95 WebRTC: Error message carries the SDP when failed. v5.0.151, v6.0.39 (#3450)
PICK 571043ff3d

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-03-27 22:28:34 +08:00
Winlin
fdaab863dc WebRTC: Support configure CANDIDATE by env (#3470)
In dockerfile, we can set the default RTC candidate to env:

```
ENV SRS_RTC_SERVER_CANDIDATE=\$CANDIDATE
CMD ["./objs/srs", "-e"]
```

When starts a docker container, user can setup the candidate by env:

```
docker run --rm -it --env CANDIDATE=1.2.3.4 ossrs/srs:5
```

We should parse the content of SRS_RTC_SERVER_CANDIDATE as env variable name and parse it again.

PICK b34255c3d0

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: pengfei.ma <pengfei.ma@ctechm.com>
2023-03-27 19:25:20 +08:00
yashwardhan-jyani
6b2c6b3274 Remove unneccessary NULL check in srs_freep. v5.0.150, v6.0.38 (#3477)
PICK b574ad1a07

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: john <hondaxiao@tencent.com>
2023-03-25 12:10:17 +08:00
john
cd19667a34 RTC: Call on_play before create session, for it might be freed for timeout. v5.0.149, v6.0.37 (#3455)
PICK d8755711c1

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-03-25 11:45:59 +08:00
winlin
cdc65be447 Fix release workflow bug. 2023-03-23 13:58:58 +08:00
winlin
55fbee3304 Release v5.0-a5, 5.0 alpha5, v5.0.148, 162066 lines. 2023-03-23 10:35:01 +08:00
Winlin
5cc794b22d WHIP: Support DELETE resource for Larix Broadcaster. v5.0.148 v6.0.36 (#3427)
* WHIP: Support DELETE resource.
* Support push by Larix.
* FLV: Disable stash buffer for realtime.
* WHEP: Fix muted issue.

-------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: panda <542638787@qq.com>
2023-03-23 10:22:00 +08:00
Winlin
dfef94411f Support WHIP and WHEP player. v5.0.147 and v6.0.35 (#3460)
PICK c001acaae9

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: panda <542638787@qq.com>
2023-03-21 08:51:42 +08:00
chundonglinlin
2f1d0ccd34 HttpConn: judge nb_chunk no memory address. (#3465)
Co-authored-by: john <hondaxiao@tencent.com>
2023-03-20 14:22:28 +08:00
Winlin
34c78a74fe WebRTC: Warning if no ideal profile. v6.0.33, v5.0.146 (#3446)
For WebRTC, SRS expect the h.264 codec is:

```
a=rtpmap:106 H264/90000
a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
```

But sometimes, the device does not support the profile, for example only bellow:

```
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e033
a=fmtp:122 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=420033
a=fmtp:121 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640033
a=fmtp:120 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0033
```

So we should warning user about the profile missmatch, because it might not work.

PICK a7514484a2

----------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: LiPeng <lipeng19811218@gmail.com>
2023-03-07 20:02:05 +08:00
Winlin
47aa42f1e2 Support configure for generic linux. v5.0.145, v6.0.32 (#3445)
If your OS is not CentOS, Ubuntu, macOS, cygwin64, run of configure will fail with:

```
Your OS Linux is not supported.
```

For other linux systems, we should support an option:

```
./configure --generic-linux=on
```

Please note that you might still fail for other issues while configuring or building.

PICK b31940a15a

-------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-03-07 19:12:06 +08:00
MarkCao
36a72282e6 Kickoff publisher when stream is idle, which means no players. v6.0.31, v5.0.144 (#3105)
For some use scenario, the publisher is invited when player want to view the stream:

1. Publisher connect to system, but does not publish any stream to SRS yet.
2. Player connect to system and start to request the stream.
3. System notifies publisher to publish stream to SRS.
4. Player play the stream from SRS.

Please notice that `system` means your business system, not SRS.

This is what we called `on-demand-live-streaming`, so when the last player stop to view the stream, what happends?

1. System needs to notify publisher to stop publish.
2. Or, SRS disconnect the publisher when idle(the last player stops playing).

This PR is for the solution 2, so that the cleanup is very simple, your system does not need to notify publisher to stop publish, because SRS has already disconnected the publihser.

PICK 8fde0366fb

---------

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-03-06 09:13:39 +08:00
chundonglinlin
0a0fb23be0 API: Add service_id for http_hooks, which identify the process, v6.0.28, v5.0.142 (#3424)
PICK 733aeaa641

Co-authored-by: Winlin <winlin@vip.126.com>
Co-authored-by: Haibo Chen <495810242@qq.com>
2023-02-25 08:44:59 +08:00
Winlin
7fe0e28dd5 Compatible with legacy RTMP URL. v5.0.142. v6.0.27 (#3429)
For compatibility, transform
  rtmp://ip/app...vhost...VHOST/stream
to typical format:
  rtmp://ip/app/stream?vhost=VHOST

This is used for some legacy devices, which does not
support standard HTTP url query string.

PICK b75668b509

---------

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: john <hondaxiao@tencent.com>
2023-02-23 10:13:18 +08:00
chundonglinlin
f12096534a SRT: fix req param leak. (#3423)
PICK b957463e5e

Co-authored-by: john <hondaxiao@tencent.com>
2023-02-16 08:26:24 +08:00
winlin
9c9f3f1247 Rename SRS_SRS_LOG_TANK to SRS_LOG_TANK. #3410 2023-02-13 11:35:06 +08:00
winlin
af7f5b3c55 Release v5.0-a4, 5.0 alpha4, v5.0.141, 161897 lines. 2023-02-12 16:25:31 +08:00
john
7839c667af SRT: Reduce latency to 200ms of srt2rtc.conf (#3409)
PICK 64fa116c65

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-02-12 16:23:57 +08:00
chundonglinlin
d1dec927d9 Config: Error when both HLS and HTTP-TS enabled. (#3400)
PICK 5b001fe344

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: john <hondaxiao@tencent.com>
2023-02-08 20:48:42 +08:00
Haibo Chen
ed95a8f53d GB: fix pointer not free (#3396)
PICK 47c2d59b31

Co-authored-by: pengfei.ma <pengfei.ma@ctechm.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-02-07 20:28:17 +08:00
winlin
b602e47e1c Update the dev code for SRS 2023-01-31 16:18:41 +08:00
Haibo Chen
a970bfd2a3 HLS: support kick-off hls client (#3371)
* HLS: support kick-off hls client
* Refine error response when reject HLS client.
* Rename SrsM3u8CtxInfo to SrsHlsVirtualConn
* Update release v5.0.139 v6.0.21

PICK 7e83874af0

---------

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: john <hondaxiao@tencent.com>
2023-01-29 11:43:04 +08:00
john
d6477c24d6 RTC: fix rtc publisher pli cid (#3318)
* RTC: fix rtc publisher pli cid
* RTC: log bridge request keyframe
* Update release v6.0.19 v5.0.138

PICK 7922057467

Co-authored-by: Winlin <winlin@vip.126.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-01-19 10:55:16 +08:00
panda
9600e495c7 Rewrite research/api-server code by Go, remove Python. (#3382)
* support api-server golang

* Update release to v6.0.18 and v5.0.137

PICK 81566868bf

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
Co-authored-by: ChenGH <chengh_math@126.com>
2023-01-18 13:14:26 +08:00
john
4a31b2ea1f SRT: fix crash when srt_to_rtmp off (#3386)
* SRT: fix crash when srt_to_rtmp off
* Release v5.0.136 v6.0.17

PICK c5ccee1edf

Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-01-18 08:54:01 +08:00
chundonglinlin
be8b1b94a6 API: Support server/pid/service label for exporter and api. (#3385)
* Exporter: Support server/pid/service.(#3378)
* API: Support return server/pid/service.(#3378)
* Use 8-length service id.
* Update release v5.0.135 v6.0.16

PICK 02653ce2aa

Co-authored-by: winlin <winlin@vip.126.com>
Co-authored-by: Haibo Chen <495810242@qq.com>
2023-01-18 07:28:25 +08:00
Haibo Chen
9bf45bea01 GB: Fix PSM parsing indicator bug. v5.0.134 (#3383)
PICK a78936f517

Co-authored-by: pengfei.ma <pengfei.ma@ctechm.com>
Co-authored-by: chundonglinlin <chundonglinlin@163.com>
2023-01-17 13:05:35 +08:00
Winlin
a4e7427433
Config: Support better env name for prefixed with srs (#3370)
* Actions: Fix github action warnings.

* Forward: Bind the context id of source or stream.

* Config: Support better env names.

Co-authored-by: pengfei.ma <pengfei.ma@ctechm.com>
Co-authored-by: Haibo Chen <495810242@qq.com>
2023-01-11 10:39:05 +08:00
winlin
920d492942 GB: Compatible with deprecated config. 2023-01-08 13:20:41 +08:00
stone
25eb21efe8
Improve file writer performance by fwrite with cache. v5.0.133 (#3308)
* SrsFileWriter leverages libc buffer to boost dvr write speed.

* Refactor SrsFileWriter to use libc file functions mockable

* Add utest and refine code.

Co-authored-by: winlin <winlin@vip.126.com>
2023-01-08 12:05:37 +08:00
winlin
fb1790230b Test: Refine blackbox test args. 2023-01-08 11:52:06 +08:00
Winlin
e655948e96 DVR: Support blackbox test based on hooks. v5.0.132 (#3365) 2023-01-07 21:33:02 +08:00
winlin
a27ce1d50f FFmpeg: Support build with FFmpeg native opus. v5.0.131 (#3140) 2023-01-06 17:44:00 +08:00
winlin
372390f8d1 Build: Refine install tips. 2023-01-06 17:43:41 +08:00
winlin
3612473516 CORS: Refine HTTP CORS headers. v5.0.130 2023-01-05 20:25:38 +08:00
winlin
62963b206f Test: Add blackbox test for SRT. 2023-01-05 09:03:12 +08:00
winlin
95b534ff10 Test: Run fast and slow blackbox tests seperately. 2023-01-03 22:47:07 +08:00
winlin
c31a8076bb Test: Add chunksize and atc blackbox test for RTMP. 2023-01-03 22:11:33 +08:00
winlin
d02b942263 SRS4: Security: Enable CIDR for allow/deny play/publish. (#2914)
PICK 55ca61ec9c
2023-01-03 17:09:47 +08:00
winlin
3b59972a90 Add blackbox test for HLS and MP3 codec. v5.0.129 (#296) (#465) 2023-01-03 16:49:59 +08:00
Winlin
e3a4ff9fa1
Test: Add blackbox for MP3 audio codec. (#3358) 2023-01-03 16:46:39 +08:00
winlin
30779f3b5a Test: Add blackbox for HLS. 2023-01-03 14:23:32 +08:00
winlin
a47b3a7842 Release v5.0-a3, 5.0 alpha3, v5.0.128, 161327 lines. 2023-01-02 19:09:37 +08:00
Winlin
2141d220b4
Test: Support blackbox test by FFmpeg. v5.0.128 (#3355)
1. Enable blackbox test for each PR and push.
2. Refine Makefile and README for srs-bench.
3. Add blackbox using FFmpeg and ffprobe.
4. Add blackbox basic test for RTMP stream.
5. Add blackbox basic test for HTTP-FLV stream.
6. Fix utest rand seed issue.
2023-01-02 15:33:17 +08:00
ChenGH
dd0f398296
Asan: Disable asan for CentOS and use statically link if possible. v5.0.127 (#3347) (#3352)
* Asan: Disable asan for CentOS and use statically link if possible. v5.0.127 (#3347)

1. Disable asan for all CentOS by default, however user could enable it.
2. Link asan statically if possible.

* Update version to v5.0.127

Co-authored-by: winlin <winlin@vip.126.com>
2023-01-02 14:57:47 +08:00
winlin
02a18b328c MP3: Upgrade mpegts.js to support HTTP-TS with mp3. v5.0.126 (#296) 2023-01-01 20:15:00 +08:00
Haibo Chen
3727d0527c
API: Fix duplicated on_stop callback event bug. (#3349)
* fix hls bug:Duplicated on_stop callback

* improve utest

* Refine magic number.

* API: Fix duplicated on_stop callback event bug. v5.0.125

Co-authored-by: winlin <winlin@vip.126.com>
2023-01-01 19:24:50 +08:00
winlin
6caca900b3 Live: Refine log for monotonically increase. 2023-01-01 15:13:25 +08:00
winlin
e690c93bcf Script: Refine depends tools. v5.0.124
1. Never auto install tools now, user should do it.
2. Support --help and --version for SRS.
3. Install tools for cygwin64.
2023-01-01 13:40:28 +08:00
winlin
72f8ed4916 Update license date to 2023. v5.0.123 2023-01-01 08:49:13 +08:00
winlin
7bdb7270cf Asan: Refine asan warning message for macOS. 2022-12-31 19:36:56 +08:00
winlin
7750bdae10 GB28181: Enable regression test for gb28181. v5.0.122
1. Build regression test tool for gb28181.
2. Run regression test for gb28181.
3. Format go code and eliminate logs.
4. Change base docker to ubuntu20.
2022-12-31 19:36:49 +08:00
winlin
4b09a7d686 Configure: Reorder the functions, nothing changed. 2022-12-31 12:22:06 +08:00
winlin
5559ac25fe Refine configure to guess OS automatically. v5.0.121
1. Guess for macOS and cygwin64.
2. Refine options for configure.
2022-12-31 12:22:06 +08:00
winlin
6299dee1b6 Update new authors. 2022-12-31 12:22:05 +08:00
winlin
07a9a005d5 Refine default config file for SRS. v5.0.120
1. Docker use srs.conf and env variables.
2. Show help if run SRS without any options.
3. Do not guess config file, use whatever from user.
2022-12-31 12:21:51 +08:00
winlin
ae3b367487 Asan: Only link by statically for asan. 2022-12-29 16:26:03 +08:00
winlin
87a2ef100a Script: Discover version from code. 2022-12-28 14:32:18 +08:00
winlin
8a0ac8e3a1 FLV: Fix bug for header flag gussing. v5.0.119 (#939) 2022-12-26 17:53:01 +08:00
winlin
386bb41f63 Script: Fix configure help bug. 2022-12-26 16:03:13 +08:00
winlin
37867533cd MP3: Convert RTMP(MP3) to WebRTC(OPUS). v5.0.118 (#296) (#3340) 2022-12-26 13:24:07 +08:00
winlin
1c5788c638 MP3: Support decode mp3 by FFmpeg natively. (#296) (#3340) 2022-12-26 13:23:39 +08:00
winlin
fe3502e6ad Actions: Fix github actions bug. 2022-12-25 21:32:35 +08:00
winlin
95defe6dad MP3: Support dump stream information. v5.0.117 (#296) (#3339) 2022-12-25 21:11:08 +08:00
winlin
23b7939574 Actions: Fix GitHub actions warnings. 2022-12-25 20:19:20 +08:00
1948 changed files with 174145 additions and 68009 deletions

View File

@ -6,7 +6,7 @@ on: [push, pull_request]
jobs:
analyze:
name: actions-codeql-analyze
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
fail-fast: false
@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@ -9,12 +9,11 @@ on:
jobs:
envs:
name: envs
runs-on: ubuntu-20.04
steps:
##################################################################################################################
# Git checkout
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# The github.ref is, for example, refs/tags/v5.0.145 or refs/tags/v5.0-r8
# Generate variables like:
# SRS_TAG=v5.0-r8
@ -22,6 +21,7 @@ jobs:
# SRS_VERSION=5.0.145
# SRS_VERSION=5.0-r8
# SRS_MAJOR=5
# SRS_XYZ=5.0.157
# @see https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
- name: Generate varaiables
run: |
@ -31,14 +31,22 @@ jobs:
echo "SRS_VERSION=$SRS_VERSION" >> $GITHUB_ENV
SRS_MAJOR=$(echo $SRS_TAG| cut -c 2)
echo "SRS_MAJOR=$SRS_MAJOR" >> $GITHUB_ENV
VFILE="trunk/src/core/srs_core_version5.hpp"
SRS_X=$(cat $VFILE |grep VERSION_MAJOR |awk '{print $3}')
SRS_Y=$(cat $VFILE |grep VERSION_MINOR |awk '{print $3}')
SRS_Z=$(cat $VFILE |grep VERSION_REVISION |awk '{print $3}')
SRS_XYZ=$SRS_X.$SRS_Y.$SRS_Z
echo "SRS_XYZ=$SRS_XYZ" >> $GITHUB_ENV
# Map a step output to a job output, see https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
outputs:
SRS_TAG: ${{ env.SRS_TAG }}
SRS_VERSION: ${{ env.SRS_VERSION }}
SRS_MAJOR: ${{ env.SRS_MAJOR }}
SRS_XYZ: ${{ env.SRS_XYZ }}
runs-on: ubuntu-22.04
test:
name: test
runs-on: ubuntu-20.04
needs:
- envs
steps:
@ -51,7 +59,7 @@ jobs:
##################################################################################################################
# Git checkout
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
##################################################################################################################
# Tests
- name: Build test image
@ -65,12 +73,10 @@ jobs:
docker run --rm srs:test bash -c 'make && \
./objs/srs -c conf/regression-test.conf && \
cd 3rdparty/srs-bench && make && ./objs/srs_test -test.v'
outputs:
SRS_TEST_DONE: ok
runs-on: ubuntu-22.04
draft:
name: draft
runs-on: ubuntu-20.04
needs:
- envs
steps:
@ -83,13 +89,14 @@ jobs:
allowUpdates: true
tag: ${{ github.ref }}
draft: true
prerelease: true
prerelease: false
# Map a step output to a job output, see https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
outputs:
SRS_RELEASE_ID: ${{ steps.create_draft.outputs.id }}
runs-on: ubuntu-22.04
cygwin64:
name: cygwin64
runs-on: windows-latest
needs:
- envs
- draft
@ -100,11 +107,11 @@ jobs:
uses: cygwin/cygwin-install-action@master
with:
platform: x86_64
packages: bash make gcc-g++ cmake automake patch pkg-config tcl
packages: bash make gcc-g++ cmake automake patch pkg-config tcl unzip
install-dir: C:\cygwin64
##################################################################################################################
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
##################################################################################################################
- name: Covert output to env
env:
@ -152,13 +159,14 @@ jobs:
with:
release_id: ${{ env.SRS_RELEASE_ID }}
assets_path: ${{ env.SRS_CYGWIN_TAR }}
# Map a step output to a job output, see https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
outputs:
SRS_CYGWIN_TAR: ${{ env.SRS_CYGWIN_TAR }}
SRS_CYGWIN_MD5: ${{ env.SRS_CYGWIN_MD5 }}
runs-on: windows-latest
linux:
name: linux
runs-on: ubuntu-20.04
needs:
- envs
- draft
@ -173,7 +181,7 @@ jobs:
##################################################################################################################
# Git checkout
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
##################################################################################################################
# Create source tar for release. Note that it's for OpenWRT package srs-server, so the filename MUST be
# srs-server-xxx.tar.gz, because the package is named srs-server.
@ -219,15 +227,16 @@ jobs:
with:
release_id: ${{ env.SRS_RELEASE_ID }}
assets_path: ${{ env.SRS_SOURCE_TAR }}
# Map a step output to a job output, see https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
outputs:
SRS_PACKAGE_ZIP: ${{ env.SRS_PACKAGE_ZIP }}
SRS_PACKAGE_MD5: ${{ env.SRS_PACKAGE_MD5 }}
SRS_SOURCE_TAR: ${{ env.SRS_SOURCE_TAR }}
SRS_SOURCE_MD5: ${{ env.SRS_SOURCE_MD5 }}
runs-on: ubuntu-22.04
docker-srs:
name: docker-srs
runs-on: ubuntu-20.04
needs:
- envs
steps:
@ -237,21 +246,22 @@ jobs:
echo "SRS_TAG=${{ needs.envs.outputs.SRS_TAG }}" >> $GITHUB_ENV
echo "SRS_VERSION=${{ needs.envs.outputs.SRS_VERSION }}" >> $GITHUB_ENV
echo "SRS_MAJOR=${{ needs.envs.outputs.SRS_MAJOR }}" >> $GITHUB_ENV
echo "SRS_XYZ=${{ needs.envs.outputs.SRS_XYZ }}" >> $GITHUB_ENV
##################################################################################################################
# Git checkout
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# See https://github.com/crazy-max/ghaction-docker-buildx#moved-to-docker-organization
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
##################################################################################################################
# Create main images for Docker
- name: Login to docker hub
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: "${{ secrets.DOCKER_USERNAME }}"
password: "${{ secrets.DOCKER_PASSWORD }}"
@ -262,26 +272,27 @@ jobs:
echo "Release ossrs/srs:$SRS_TAG"
docker buildx build --platform linux/arm/v7,linux/arm64/v8,linux/amd64 \
--output "type=image,push=true" \
-t ossrs/srs:$SRS_TAG --build-arg SRS_AUTO_PACKAGER=$PACKAGER -f trunk/Dockerfile .
-t ossrs/srs:$SRS_TAG --build-arg SRS_AUTO_PACKAGER=$PACKAGER -f Dockerfile .
# Docker alias images
# TODO: FIXME: If stable, please set the latest from 4.0 to 5.0
- name: Docker alias images for ossrs/srs
uses: akhilerm/tag-push-action@v2.0.0
uses: akhilerm/tag-push-action@v2.1.0
with:
src: ossrs/srs:${{ env.SRS_TAG }}
dst: |
ossrs/srs:${{ env.SRS_VERSION }}
ossrs/srs:${{ env.SRS_MAJOR }}
ossrs/srs:v${{ env.SRS_MAJOR }}
outputs:
SRS_DOCKER_DONE: ok
ossrs/srs:${{ env.SRS_XYZ }}
ossrs/srs:v${{ env.SRS_XYZ }}
runs-on: ubuntu-22.04
aliyun-srs:
name: aliyun-srs
runs-on: ubuntu-20.04
needs:
- envs
- docker-srs
- test
steps:
##################################################################################################################
- name: Covert output to env
@ -289,16 +300,17 @@ jobs:
echo "SRS_TAG=${{ needs.envs.outputs.SRS_TAG }}" >> $GITHUB_ENV
echo "SRS_VERSION=${{ needs.envs.outputs.SRS_VERSION }}" >> $GITHUB_ENV
echo "SRS_MAJOR=${{ needs.envs.outputs.SRS_MAJOR }}" >> $GITHUB_ENV
echo "SRS_XYZ=${{ needs.envs.outputs.SRS_XYZ }}" >> $GITHUB_ENV
# Aliyun ACR
# TODO: FIXME: If stable, please set the latest from 4.0 to 5.0
- name: Login aliyun hub
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: registry.cn-hangzhou.aliyuncs.com
username: "${{ secrets.ACR_USERNAME }}"
password: "${{ secrets.ACR_PASSWORD }}"
- name: Push to Aliyun registry for ossrs/srs
uses: akhilerm/tag-push-action@v2.0.0
uses: akhilerm/tag-push-action@v2.1.0
with:
src: ossrs/srs:${{ env.SRS_TAG }}
dst: |
@ -306,12 +318,12 @@ jobs:
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:${{ env.SRS_VERSION }}
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:${{ env.SRS_MAJOR }}
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:v${{ env.SRS_MAJOR }}
outputs:
SRS_ALIYUN_DONE: ok
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:${{ env.SRS_XYZ }}
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:v${{ env.SRS_XYZ }}
runs-on: ubuntu-22.04
update:
name: update
runs-on: ubuntu-20.04
needs:
- aliyun-srs
- envs
@ -325,20 +337,18 @@ jobs:
##################################################################################################################
# Git checkout
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
##################################################################################################################
# Generate variables like:
# SRS_LH_OSSRS_NET=1.2.3.4
- name: Build variables for lh.ossrs.net
# SRS_R_OSSRS_NET=1.2.3.4
- name: Build variables for r.ossrs.net
run: |
SRS_LH_OSSRS_NET=$(dig +short lh.ossrs.net)
SRS_D_OSSRS_NET=$(dig +short d.ossrs.net)
echo "SRS_LH_OSSRS_NET=$SRS_LH_OSSRS_NET" >> $GITHUB_ENV
echo "SRS_D_OSSRS_NET=$SRS_D_OSSRS_NET" >> $GITHUB_ENV
- name: Release to lh.ossrs.net
SRS_R_OSSRS_NET=$(dig +short r.ossrs.net)
echo "SRS_R_OSSRS_NET=$SRS_R_OSSRS_NET" >> $GITHUB_ENV
- name: Release to r.ossrs.net
uses: appleboy/ssh-action@master
with:
host: ${{ env.SRS_LH_OSSRS_NET }}
host: ${{ env.SRS_R_OSSRS_NET }}
username: root
key: ${{ secrets.DIGITALOCEAN_SSHKEY }}
port: 22
@ -346,39 +356,11 @@ jobs:
timeout: 60s
command_timeout: 30m
script: |
docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:$SRS_MAJOR
docker rm -f srs-dev
#
# Cleanup old docker images.
for image in $(docker images |grep '<none>' |awk '{print $3}'); do
docker rmi -f $image
echo "Remove image $image, r0=$?"
done
- name: Release to d.ossrs.net
uses: appleboy/ssh-action@master
with:
host: ${{ env.SRS_D_OSSRS_NET }}
username: root
key: ${{ secrets.DIGITALOCEAN_SSHKEY }}
port: 22
envs: SRS_MAJOR
timeout: 60s
command_timeout: 30m
script: |
docker pull ossrs/srs:$SRS_MAJOR
docker rm -f srs-dev
#
# Cleanup old docker images.
for image in $(docker images |grep '<none>' |awk '{print $3}'); do
docker rmi -f $image
echo "Remove image $image, r0=$?"
done
outputs:
SRS_UPDATE_DONE: ok
echo "Update r.ossrs.net ok for SRS $SRS_MAJOR"
runs-on: ubuntu-22.04
release:
name: release
runs-on: ubuntu-20.04
needs:
- update
- envs
@ -392,6 +374,7 @@ jobs:
echo "SRS_TAG=${{ needs.envs.outputs.SRS_TAG }}" >> $GITHUB_ENV
echo "SRS_VERSION=${{ needs.envs.outputs.SRS_VERSION }}" >> $GITHUB_ENV
echo "SRS_MAJOR=${{ needs.envs.outputs.SRS_MAJOR }}" >> $GITHUB_ENV
echo "SRS_XYZ=${{ needs.envs.outputs.SRS_XYZ }}" >> $GITHUB_ENV
echo "SRS_RELEASE_ID=${{ needs.draft.outputs.SRS_RELEASE_ID }}" >> $GITHUB_ENV
echo "SRS_PACKAGE_ZIP=${{ needs.linux.outputs.SRS_PACKAGE_ZIP }}" >> $GITHUB_ENV
echo "SRS_PACKAGE_MD5=${{ needs.linux.outputs.SRS_PACKAGE_MD5 }}" >> $GITHUB_ENV
@ -402,10 +385,8 @@ jobs:
##################################################################################################################
# Git checkout
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Create release.
# TODO: FIXME: Refine the release when 5.0 released
# TODO: FIXME: Change prerelease to false when 5.0 released
- name: Update release
id: update_release
uses: ncipollo/release-action@v1
@ -432,10 +413,12 @@ jobs:
## Docker
* [docker pull ossrs/srs:${{ env.SRS_MAJOR }}](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started)
* [docker pull ossrs/srs:${{ env.SRS_TAG }}](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started)
* [docker pull ossrs/srs:v${{ env.SRS_XYZ }}](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started)
## Docker Mirror: aliyun.com
* [docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:${{ env.SRS_MAJOR }}](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started)
* [docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:${{ env.SRS_TAG }}](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started)
* [docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:v${{ env.SRS_XYZ }}](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started)
## Doc: ossrs.io
* [Getting Started](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started)
@ -447,11 +430,13 @@ jobs:
* [中文Wiki首页](https://ossrs.net/lts/zh-cn/docs/v5/doc/introduction)
* [中文FAQ](https://ossrs.net/lts/zh-cn/faq), [功能列表](https://github.com/ossrs/srs/blob/${{ github.sha }}/trunk/doc/Features.md#features) 或 [修订历史](https://github.com/ossrs/srs/blob/${{ github.sha }}/trunk/doc/CHANGELOG.md#changelog)
draft: false
prerelease: true
prerelease: false
makeLatest: true
runs-on: ubuntu-22.04
done:
name: done
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs:
- update
- release

View File

@ -4,6 +4,7 @@ name: "Test"
on: [push, pull_request]
# The dependency graph:
# test(6m)
# multiple-arch-armv7(13m)
# multiple-arch-aarch64(7m)
# cygwin64-cache(1m)
@ -16,31 +17,35 @@ on: [push, pull_request]
# build-cross-arm(3m)
# build-cross-aarch64(3m)
# multiple-arch-amd64(2m)
# utest(3m)
# coverage(3m) - Must depends on utest.
# coverage(3m)
jobs:
cygwin64-cache:
name: cygwin64-cache
runs-on: ubuntu-20.04
steps:
- name: Download Cache for Cygwin
run: |
echo "Generate convert.sh" &&
echo "for file in \$(find objs -type l); do" > convert.sh &&
echo " REAL=\$(readlink -f \$file) &&" >> convert.sh &&
echo " echo \"convert \$file to \$REAL\" &&" >> convert.sh &&
echo " rm -rf \$file &&" >> convert.sh &&
echo " cp -r \$REAL \$file" >> convert.sh &&
echo "done" >> convert.sh &&
cat convert.sh &&
docker run --rm -v $(pwd):/srs -w /usr/local/srs-cache/srs/trunk ossrs/srs:cygwin64-cache \
tar jcf /srs/objs.tar.bz2 objs &&
bash -c "bash /srs/convert.sh && tar cf /srs/objs.tar.bz2 objs" &&
pwd && du -sh *
##################################################################################################################
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v4
with:
name: srs-cache
path: objs.tar.bz2
retention-days: 1
outputs:
SRS_CYGWIN_CACHE_DONE: ok
runs-on: ubuntu-22.04
cygwin64:
name: cygwin64
runs-on: windows-latest
needs:
- cygwin64-cache
steps:
@ -50,17 +55,18 @@ jobs:
uses: cygwin/cygwin-install-action@master
with:
platform: x86_64
packages: bash make gcc-g++ cmake automake patch pkg-config tcl
packages: bash make gcc-g++ cmake automake patch pkg-config tcl unzip
install-dir: C:\cygwin64
##################################################################################################################
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
##################################################################################################################
# Note that we must download artifact after checkout code, because it will change the files in workspace.
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v4
with:
name: srs-cache
- uses: geekyeggo/delete-artifact@v2
# https://github.com/marketplace/actions/delete-artifact?version=v5.0.0#-compatibility
- uses: geekyeggo/delete-artifact@v5.0.0
with:
name: srs-cache
##################################################################################################################
@ -71,21 +77,19 @@ jobs:
shell: C:\cygwin64\bin\bash.exe --login '{0}'
run: |
WORKDIR=$(cygpath -u $SRS_WORKSPACE) && export PATH=/usr/bin:/usr/local/bin && cd ${WORKDIR} &&
pwd && rm -rf /usr/local/srs-cache && mkdir -p /usr/local/srs-cache/srs/trunk &&
pwd && rm -rf /usr/local/srs-cache && mkdir -p /usr/local/srs-cache/srs/trunk && ls -lh &&
tar xf objs.tar.bz2 -C /usr/local/srs-cache/srs/trunk/ && du -sh /usr/local/srs-cache/srs/trunk/* &&
cd ${WORKDIR}/trunk && ./configure --gb28181=on --utest=on && ls -lh && du -sh * && du -sh objs/* &&
cd ${WORKDIR}/trunk && make utest && ./objs/srs_utest
outputs:
SRS_CYGWIN_DONE: ok
runs-on: windows-latest
build-centos7:
name: build-centos7
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Build for CentOS 7
- name: Build on CentOS7, baseline
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target centos7-baseline .
@ -97,119 +101,115 @@ jobs:
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target centos7-no-asm .
- name: Build on CentOS7, C++98, no FFmpeg
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target centos7-ansi-no-ffmpeg .
outputs:
SRS_BUILD_CENTOS7_DONE: ok
runs-on: ubuntu-22.04
build-ubuntu16:
name: build-ubuntu16
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Build for Ubuntu16
- name: Build on Ubuntu16, baseline
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu16-baseline .
- name: Build on Ubuntu16, with all features
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu16-all .
outputs:
SRS_BUILD_UBUNTU16_DONE: ok
runs-on: ubuntu-22.04
build-ubuntu18:
name: build-ubuntu18
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Build for Ubuntu18
- name: Build on Ubuntu18, baseline
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu18-baseline .
- name: Build on Ubuntu18, with all features
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu18-all .
outputs:
SRS_BUILD_UBUNTU18_DONE: ok
runs-on: ubuntu-22.04
build-ubuntu20:
name: build-ubuntu20
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Build for Ubuntu20
- name: Build on Ubuntu20, baseline
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-baseline .
- name: Build on Ubuntu20, with all features
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-all .
outputs:
SRS_BUILD_UBUNTU20_DONE: ok
runs-on: ubuntu-22.04
build-cross-arm:
name: build-cross-arm
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Cross Build for ARMv7 on Ubuntu16
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu16-cross-armv7 .
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu16-cache-cross-armv7 .
- name: Cross Build for ARMv7 on Ubuntu20
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-cross-armv7 .
outputs:
SRS_BUILD_CROSS_ARM_DONE: ok
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-cache-cross-armv7 .
runs-on: ubuntu-22.04
build-cross-aarch64:
name: build-cross-aarch64
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Cross Build for AARCH64 on Ubuntu16
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu16-cross-aarch64 .
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu16-cache-cross-aarch64 .
- name: Cross Build for AARCH64 on Ubuntu20
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-cross-aarch64 .
outputs:
SRS_BUILD_CROSS_AARCH64_DONE: ok
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-cache-cross-aarch64 .
runs-on: ubuntu-22.04
utest:
name: utest
runs-on: ubuntu-20.04
test:
name: utest-regression-blackbox-test
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Tests
- name: Build test image
run: docker build --tag srs:test -f trunk/Dockerfile.test .
run: docker build --tag srs:test --build-arg MAKEARGS='-j2' -f trunk/Dockerfile.test .
# For blackbox-test
- name: Run SRS blackbox-test
run: |
#docker run --rm -w /srs/trunk/3rdparty/srs-bench srs:test ./objs/srs_blackbox_test -test.v \
# -test.run 'TestFast_RtmpPublish_DvrFlv_Basic' -srs-log -srs-stdout srs-ffmpeg-stderr -srs-dvr-stderr \
# -srs-ffprobe-stdout
docker run --rm -w /srs/trunk/3rdparty/srs-bench srs:test \
./objs/srs_blackbox_test -test.v -test.run '^TestFast' -test.parallel 64
docker run --rm -w /srs/trunk/3rdparty/srs-bench srs:test \
./objs/srs_blackbox_test -test.v -test.run '^TestSlow' -test.parallel 4
# For utest
- name: Run SRS utest
run: docker run --rm srs:test bash -c 'make utest && ./objs/srs_utest'
run: docker run --rm srs:test ./objs/srs_utest
# For regression-test
- name: Run SRS regression-test
run: |
docker run --rm srs:test bash -c 'make && \
./objs/srs -c conf/regression-test.conf && \
cd 3rdparty/srs-bench && make && ./objs/srs_test -test.v'
outputs:
SRS_UTEST_DONE: ok
docker run --rm srs:test bash -c './objs/srs -c conf/regression-test.conf && \
cd 3rdparty/srs-bench && (./objs/srs_test -test.v || (cat ../../objs/srs.log && exit 1)) && \
./objs/srs_gb28181_test -test.v'
runs-on: ubuntu-22.04
coverage:
name: coverage
runs-on: ubuntu-20.04
needs:
- utest
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Tests
- name: Build coverage image
run: docker build --tag srs:cov -f trunk/Dockerfile.cov .
run: docker build --tag srs:cov --build-arg MAKEARGS='-j2' -f trunk/Dockerfile.cov .
# For coverage
- name: Run SRS covergae
if: ${{ startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/pull/') }}
@ -227,96 +227,90 @@ jobs:
#
echo "For github.ref=${{ github.ref }}, github.sha=${{ github.sha }}"
echo "SRS_BRANCH=$SRS_BRANCH, SRS_PR=$SRS_PR, SRS_SHA=$SRS_SHA, SRS_PROJECT=$SRS_PROJECT"
docker run --rm --env CODECOV_TOKEN=$CODECOV_TOKEN \
--env SRS_BRANCH=$SRS_BRANCH --env SRS_PR=$SRS_PR --env SRS_SHA=$SRS_SHA --env SRS_PROJECT=$SRS_PROJECT \
srs:cov bash -c 'make utest && ./objs/srs_utest && bash auto/codecov.sh'
docker run --rm --env CODECOV_TOKEN=$CODECOV_TOKEN --env SRS_BRANCH=$SRS_BRANCH \
--env SRS_PR=$SRS_PR --env SRS_SHA=$SRS_SHA --env SRS_PROJECT=$SRS_PROJECT \
srs:cov bash -c './objs/srs_utest && bash auto/codecov.sh'
#
outputs:
SRS_COVERAGE_DONE: ok
runs-on: ubuntu-22.04
multiple-arch-armv7:
name: multiple-arch-armv7
runs-on: ubuntu-20.04
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# See https://github.com/crazy-max/ghaction-docker-buildx#moved-to-docker-organization
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Build multiple archs image
run: |
docker buildx build --platform linux/arm/v7 \
--output "type=image,push=false" \
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
-f trunk/Dockerfile .
outputs:
SRS_MULTIPLE_ARCH_ARMV7_DONE: ok
--build-arg INSTALLDEPENDS="NO" \
-f Dockerfile .
runs-on: ubuntu-22.04
multiple-arch-aarch64:
name: multiple-arch-aarch64
runs-on: ubuntu-20.04
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# See https://github.com/crazy-max/ghaction-docker-buildx#moved-to-docker-organization
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Build multiple archs image
run: |
docker buildx build --platform linux/arm64/v8 \
--output "type=image,push=false" \
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
-f trunk/Dockerfile .
outputs:
SRS_MULTIPLE_ARCH_AARCH64_DONE: ok
--build-arg INSTALLDEPENDS="NO" \
-f Dockerfile .
runs-on: ubuntu-22.04
multiple-arch-amd64:
name: multiple-arch-amd64
runs-on: ubuntu-20.04
needs:
- fast
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# See https://github.com/crazy-max/ghaction-docker-buildx#moved-to-docker-organization
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Build multiple archs image
run: |
docker buildx build --platform linux/amd64 \
--output "type=image,push=false" \
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
-f trunk/Dockerfile .
outputs:
SRS_MULTIPLE_ARCH_AMD64_DONE: ok
-f Dockerfile .
runs-on: ubuntu-22.04
fast:
name: fast
needs:
- cygwin64-cache
runs-on: ubuntu-20.04
steps:
- run: echo 'Start fast jobs'
outputs:
SRS_FAST_DONE: ok
runs-on: ubuntu-22.04
done:
name: done
needs:
- cygwin64
- coverage
- test
- build-centos7
- build-ubuntu16
- build-ubuntu18
@ -326,7 +320,7 @@ jobs:
- multiple-arch-armv7
- multiple-arch-aarch64
- multiple-arch-amd64
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- run: echo 'All done'

View File

@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="private" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="-c console.conf" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" WORKING_DIR="file://$CMakeCurrentBuildDir$/../../../" PASS_PARENT_ENVS_2="true" PROJECT_NAME="srs" TARGET_NAME="srs" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="srs" RUN_TARGET_NAME="srs">
<envs>
<env name="SRS_RTC_SERVER_ENABLED" value="on" />
<env name="MallocNanoZone" value="0" />
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />

11
.run/srs-stack.run.xml Normal file
View File

@ -0,0 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="srs-stack" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="-c containers/conf/srs.release-local.conf" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" WORKING_DIR="file://$USER_HOME$/git/srs-stack/platform" PASS_PARENT_ENVS_2="true" PROJECT_NAME="srs" TARGET_NAME="srs" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="srs" RUN_TARGET_NAME="srs">
<envs>
<env name="SRS_RTC_SERVER_ENABLED" value="on" />
<env name="MallocNanoZone" value="0" />
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@ -2,10 +2,13 @@ ARG ARCH
ARG IMAGE=ossrs/srs:ubuntu20
FROM ${ARCH}${IMAGE} AS build
ARG CONFARGS
ARG MAKEARGS
ARG INSTALLDEPENDS
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG SRS_AUTO_PACKAGER
RUN echo "BUILDPLATFORM: $BUILDPLATFORM, TARGETPLATFORM: $TARGETPLATFORM, PACKAGER: ${#SRS_AUTO_PACKAGER}"
RUN echo "BUILDPLATFORM: $BUILDPLATFORM, TARGETPLATFORM: $TARGETPLATFORM, PACKAGER: ${#SRS_AUTO_PACKAGER}, CONFARGS: ${CONFARGS}, MAKEARGS: ${MAKEARGS}, INSTALLDEPENDS: ${INSTALLDEPENDS}"
# https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image
ENV DEBIAN_FRONTEND noninteractive
@ -15,7 +18,9 @@ ENV DEBIAN_FRONTEND noninteractive
SHELL ["/bin/bash", "-c"]
# Install depends tools.
RUN apt-get update && apt-get install -y gcc make g++ patch unzip perl git libasan5
RUN if [[ $INSTALLDEPENDS != 'NO' ]]; then \
apt-get update && apt-get install -y gcc make g++ patch unzip perl git libasan5; \
fi
# Copy source code to docker.
COPY . /srs
@ -24,7 +29,7 @@ WORKDIR /srs/trunk
# Build and install SRS.
# Note that SRT is enabled by default, so we configure without --srt=on.
# Note that we have copied all files by make install.
RUN ./configure --gb28181=on --sanitizer-static=on && make && make install
RUN ./configure --sanitizer=off --gb28181=on ${CONFARGS} && make ${MAKEARGS} && make install
############################################################
# dist
@ -36,7 +41,7 @@ ARG TARGETPLATFORM
RUN echo "BUILDPLATFORM: $BUILDPLATFORM, TARGETPLATFORM: $TARGETPLATFORM"
# Expose ports for streaming @see https://github.com/ossrs/srs#ports
EXPOSE 1935 1985 8080 8000/udp 10080/udp
EXPOSE 1935 1985 8080 5060 9000 8000/udp 10080/udp
# FFMPEG 4.1
COPY --from=build /usr/local/bin/ffmpeg /usr/local/srs/objs/ffmpeg/bin/ffmpeg
@ -51,4 +56,6 @@ RUN ldd /usr/local/srs/objs/ffmpeg/bin/ffmpeg && \
# Default workdir and command.
WORKDIR /usr/local/srs
ENV SRS_DAEMON=off SRS_IN_DOCKER=on
CMD ["./objs/srs", "-c", "conf/docker.conf"]

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2022 The SRS Authors
Copyright (c) 2013-2025 The SRS Authors
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

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2022 The SRS Authors
Copyright (c) 2013-2024 The SRS Authors
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

View File

@ -1,4 +1,4 @@
Copyright (c) 2013-2022 The SRS Authors
Copyright (c) 2013-2024 The SRS Authors
SRS is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

106
README.md
View File

@ -11,24 +11,25 @@
[![](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fossrs%2Fsrs.svg?type=small)](https://app.fossa.com/projects/git%2Bgithub.com%2Fossrs%2Fsrs?ref=badge_small)
[![](https://ossrs.net/wiki/images/srs-faq.svg)](https://ossrs.net/lts/zh-cn/faq)
[![](https://badgen.net/badge/srs/stackoverflow/orange?icon=terminal)](https://stackoverflow.com/questions/tagged/simple-realtime-server)
[![](https://opencollective.com/srs-server/tiers/badge.svg)](https://opencollective.com/srs-server/contribute)
[![](https://opencollective.com/srs-server/tiers/badge.svg)](https://opencollective.com/srs-server)
[![](https://img.shields.io/docker/pulls/ossrs/srs)](https://hub.docker.com/r/ossrs/srs/tags)
[![](https://ossrs.net/wiki/images/do-btn-srs-125x20.svg)](https://cloud.digitalocean.com/droplets/new?appId=104916642&size=s-1vcpu-1gb&region=sgp1&image=ossrs-srs&type=applications)
[![](https://ossrs.net/wiki/images/do-btn-srs-125x20.svg)](https://cloud.digitalocean.com/droplets/new?appId=133468816&size=s-1vcpu-512mb-10gb&region=sgp1&image=ossrs-srs&type=applications)
SRS/5.0(Bee) is a simple, high efficiency and realtime video server, supports RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH and GB28181.
SRS/5.0([Bee](https://ossrs.net/lts/zh-cn/product#release50)) is a simple, high efficiency and realtime video server, supports RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH and GB28181.
[![SRS Overview](https://ossrs.net/wiki/images/SRS-SingleNode-4.0-sd.png?v=114)](https://ossrs.net/wiki/images/SRS-SingleNode-4.0-hd.png)
> Note: The single node architecture for SRS, for detail please see [here](https://www.figma.com/file/333POxVznQ8Wz1Rxlppn36/SRS-4.0-Server-Arch).
SRS is licenced under [MIT](https://github.com/ossrs/srs/blob/5.0release/LICENSE) or [MulanPSL-2.0](https://spdx.org/licenses/MulanPSL-2.0.html),
and note that [MulanPSL-2.0 is compatible with Apache-2.0](https://www.apache.org/legal/resolved.html#category-a),
but some third-party libraries are distributed using their [own licenses](https://ossrs.io/lts/en-us/license).
SRS is licenced under [MIT](https://github.com/ossrs/srs/blob/develop/LICENSE) by default, and SRS is also licensed
under [MIT](https://github.com/ossrs/srs/blob/develop/LICENSE) or [MulanPSL-2.0](https://spdx.org/licenses/MulanPSL-2.0.html).
Please note that [MulanPSL-2.0 is compatible with Apache-2.0](https://www.apache.org/legal/resolved.html#category-a),
and some third-party libraries are distributed under their [licenses](https://ossrs.io/lts/en-us/license).
<a name="product"></a> <a name="usage-docker"></a>
## Usage
Please read guide [Getting Started](https://ossrs.io/lts/en-us/docs/v4/doc/getting-started) or [中文文档:起步](https://ossrs.net/lts/zh-cn/docs/v4/doc/getting-started).
Please refer to the [Getting Started](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started) or [中文文档:起步](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started) guide.
To build SRS from source:
@ -65,44 +66,65 @@ Note that if convert RTMP to WebRTC, please use [`rtmp2rtc.conf`](https://github
> however it's also easy to build SRS from source code, for detail please see
> **Getting Started([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/getting-started) / [EN](https://ossrs.io/lts/en-us/docs/v4/doc/getting-started))**.
> Note: If need HTTPS, by which WebRTC and modern browsers require, please read
> **HTTPS API([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/http-api#https-api) / [EN](https://ossrs.io/lts/en-us/docs/v4/doc/http-api#https-api))**
> and **HTTPS Callback([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/http-callback#https-callback) / [EN](https://ossrs.io/lts/en-us/docs/v4/doc/http-callback#https-callback))**
> and **HTTPS Live Streaming([CN](https://ossrs.io/lts/en-us/docs/v4/doc/delivery-http-flv#https-flv-live-stream) / [EN](https://ossrs.io/lts/en-us/docs/v4/doc/delivery-http-flv#https-flv-live-stream))**,
> however HTTPS proxy also works perfect with SRS such as Nginx.
> Note: In addition to FFmpeg or OBS, it is possible to [publish by H5](http://localhost:8080/players/whip.html) via WHIP as well.
> To enable WebRTC to publish and convert it to RTMP, please refer to the wiki([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/webrtc#rtc-to-rtmp), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/webrtc#rtc-to-rtmp)) documentation.
> It is essential to ensure the candidate([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/webrtc#config-candidate) or [EN](https://ossrs.io/lts/en-us/docs/v5/doc/webrtc#config-candidate))
> is set correctly for WebRTC to avoid potential issues, as it can cause significant problems.
> Note: It is highly recommended to run SRS directly with docker([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started)),
> CVM([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started-cloud) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started-cloud)),
> or K8s([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started-k8s) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started-k8s)).
> However, compiling SRS from source code is also possible and easy. For detailed instructions, please refer to the
> "Getting Started"([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/getting-started)) guide.
> Note: If you require HTTPS for WebRTC and modern browsers, please refer to the HTTPS API([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/http-api#https-api) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/http-api#https-api)),
> HTTPS Callback([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/http-callback#https-callback) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/http-callback#https-callback)),
> and HTTPS Live Streaming([CN](https://ossrs.io/lts/en-us/docs/v5/doc/delivery-http-flv#https-flv-live-stream) / [EN](https://ossrs.io/lts/en-us/docs/v5/doc/delivery-http-flv#https-flv-live-stream))
> documentation. Additionally, SRS works perfectly with an HTTPS proxy like Nginx.
<a name="srs-40-wiki"></a> <a name="wiki"></a>
From here, please read wikis:
* How to deliver RTMP streaming?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-rtmp), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-rtmp))
* How to deliver WebRTC streaming? ([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/webrtc))
* How to covert RTMP to HTTP-FLV streaming?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-http-flv), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-http-flv))
* How to covert RTMP to HLS streaming?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-hls), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-hls))
* How to deliver low-latency streaming?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-realtime), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-realtime))
* How to build RTMP Edge-Cluster?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-rtmp-cluster), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-rtmp-cluster))
* How to build RTMP Origin-Cluster?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-origin-cluster), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-origin-cluster))
* How to build HLS Edge-Cluster?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-hls-cluster), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-hls-cluster))
* What are the steps to deliver RTMP streaming? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-rtmp), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-rtmp))
* What is the process for delivering WebRTC streaming? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/webrtc), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/webrtc))
* What are the steps to convert RTMP to HTTP-FLV streaming? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-http-flv), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-http-flv))
* How can RTMP be converted to HLS streaming? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-hls), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-hls))
* What is the best approach for delivering low-latency streaming? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-realtime), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-realtime))
* How can an RTMP Edge-Cluster be constructed? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-rtmp-cluster), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-rtmp-cluster))
* What is the process for building an RTMP Origin-Cluster? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-origin-cluster), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-origin-cluster))
* How can an HLS Edge-Cluster be set up?([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-hls-cluster), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-hls-cluster))
Other important wiki:
* Usage: How to deliver DASH(Experimental)?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-dash), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-dash))
* Usage: How to transode RTMP stream by FFMPEG?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-ffmpeg), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-ffmpeg))
* Usage: How to deliver HTTP FLV Live Streaming Cluster?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-http-flvCluster), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-http-flvCluster))
* Usage: How to deliver HLS by NGINX Cluster?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-hls-cluster), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-hls-cluster))
* Usage: How to ingest file/stream/device to RTMP?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-ingest), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-ingest))
* Usage: How to forward stream to other servers?([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/sample-forward), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/sample-forward))
* Usage: How to improve edge performance for multiple CPUs? ([CN](https://ossrs.net/lts/zh-cn/docs/v4/doc/reuse-port), [EN](https://ossrs.io/lts/en-us/docs/v4/doc/reuse-port))
* Usage: How to file a bug or contact us? ([CN](https://ossrs.net/lts/zh-cn/contact), [EN](https://ossrs.io/lts/en-us/contact))
* Usage: What is the method for delivering DASH (Experimental)? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-dash), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-dash))
* Usage: How can an RTMP stream be transcoded using FFMPEG? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-ffmpeg), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-ffmpeg))
* Usage: What is the process for setting up an HTTP FLV Live Streaming Cluster? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-http-flvCluster), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-http-flvCluster))
* Usage: How can HLS be delivered using an NGINX Cluster? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-hls-cluster), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-hls-cluster))
* Usage: What steps are to ingest a file, stream, or device to RTMP? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-ingest), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-ingest))
* Usage: How can a stream be forwarded to other servers? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/sample-forward), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/sample-forward))
* Usage: What are the strategies for improving edge performance on multiple CPUs? ([CN](https://ossrs.net/lts/zh-cn/docs/v5/doc/reuse-port), [EN](https://ossrs.io/lts/en-us/docs/v5/doc/reuse-port))
* Usage: How can bugs be reported or contact be made with us? ([CN](https://ossrs.net/lts/zh-cn/contact), [EN](https://ossrs.io/lts/en-us/contact))
## Sponsor
Would you like additional assistance from us? By becoming a sponsor or backer of SRS, we can provide you
with the support you need:
* Backer: $5 per month, online text chat support through Discord.
* Sponsor: $100 per month, online text chat plus online meeting support.
Please visit [OpenCollective](https://opencollective.com/srs-server) to become a backer or sponsor, and send
us a direct message on [Discord](https://discord.gg/yZ4BnPmHAd). We are currently providing support to the
developers listed below:
[![](https://opencollective.com/srs-server/backers.svg?width=800&button=false)](https://opencollective.com/srs-server)
We at SRS aim to establish a non-profit, open-source community that assists developers worldwide in creating
your own high-quality streaming and RTC platforms to support your businesses.
## AUTHORS
Thank you to all our contributors! 🙏
[![](https://opencollective.com/srs-server/contributors.svg?width=800&button=false)](https://opencollective.com/srs-server/contribute)
> Note: You may provide financial support for this project by donating [via Open Collective](https://opencollective.com/srs-server/contribute). Thank you for your support!
The [TOC(Technical Oversight Committee)](trunk/AUTHORS.md#toc), [Developers](trunk/AUTHORS.md#developers) and [contributors](trunk/AUTHORS.md#contributors):
The [TOC(Technical Oversight Committee)](trunk/AUTHORS.md#toc) and [contributors](trunk/AUTHORS.md#contributors):
* [Winlin](https://github.com/winlinvip): Focus on [ST](https://github.com/ossrs/state-threads) and [Issues/PR](https://github.com/ossrs/srs/issues).
* [ZhaoWenjie](https://github.com/wenjiegit): Focus on [HDS](https://github.com/simple-rtmp-server/srs/wiki/v4_CN_DeliveryHDS) and [Windows](https://github.com/ossrs/srs/issues/2532).
@ -137,6 +159,20 @@ but some third-party libraries are distributed using their [own licenses](https:
## Releases
* 2024-04-03, [Release v5.0-r2](https://github.com/ossrs/srs/releases/tag/v5.0-r2), v5.0-r2, 5.0 release2, v5.0.210, 163515 lines.
* 2024-02-15, [Release v5.0-r1](https://github.com/ossrs/srs/releases/tag/v5.0-r1), v5.0-r1, 5.0 release1, v5.0.208, 163441 lines.
* 2023-12-30, [Release v5.0-r0](https://github.com/ossrs/srs/releases/tag/v5.0-r0), v5.0-r0, 5.0 release0, v5.0.205, 163363 lines.
* 2023-11-19, [Release v5.0-b7](https://github.com/ossrs/srs/releases/tag/v5.0-b7), v5.0-b7, 5.0 beta7, v5.0.200, 163305 lines.
* 2023-10-25, [Release v5.0-b6](https://github.com/ossrs/srs/releases/tag/v5.0-b6), v5.0-b6, 5.0 beta6, v5.0.195, 163303 lines.
* 2023-09-28, [Release v5.0-b5](https://github.com/ossrs/srs/releases/tag/v5.0-b5), v5.0-b5, 5.0 beta5, v5.0.185, 163254 lines.
* 2023-08-31, [Release v5.0-b4](https://github.com/ossrs/srs/releases/tag/v5.0-b4), v5.0-b4, 5.0 beta4, v5.0.176, 162919 lines.
* 2023-08-02, [Release v5.0-b3](https://github.com/ossrs/srs/releases/tag/v5.0-b3), v5.0-b3, 5.0 beta3, v5.0.170, 162704 lines.
* 2023-07-09, [Release v5.0-b2](https://github.com/ossrs/srs/releases/tag/v5.0-b2), v5.0-b2, 5.0 beta2, v5.0.166, 162520 lines.
* 2023-06-11, [Release v5.0-b1](https://github.com/ossrs/srs/releases/tag/v5.0-b1), v5.0-b1, 5.0 beta1, v5.0.157, 162494 lines.
* 2023-05-14, [Release v5.0-b0](https://github.com/ossrs/srs/releases/tag/v5.0-b0), v5.0-b0, 5.0 beta0, v5.0.155, 162600 lines.
* 2023-03-23, [Release v5.0-a5](https://github.com/ossrs/srs/releases/tag/v5.0-a5), v5.0-a5, 5.0 alpha5, v5.0.148, 162066 lines.
* 2023-02-12, [Release v5.0-a4](https://github.com/ossrs/srs/releases/tag/v5.0-a4), v5.0-a4, 5.0 alpha4, v5.0.141, 161897 lines.
* 2023-01-02, [Release v5.0-a3](https://github.com/ossrs/srs/releases/tag/v5.0-a3), v5.0-a3, 5.0 alpha3, v5.0.128, 161327 lines.
* 2022-12-18, [Release v5.0-a2](https://github.com/ossrs/srs/releases/tag/v5.0-a2), v5.0-a2, 5.0 alpha2, v5.0.112, 161233 lines.
* 2022-12-01, [Release v5.0-a1](https://github.com/ossrs/srs/releases/tag/v5.0-a1), v5.0-a1, 5.0 alpha1, v5.0.100, 160817 lines.
* 2022-11-25, [Release v5.0-a0](https://github.com/ossrs/srs/releases/tag/v5.0-a0), v5.0-a0, 5.0 alpha0, v5.0.98, 159813 lines.

Binary file not shown.

View File

@ -9,8 +9,8 @@ nginx-1.5.7.zip
* for srs to support hls streaming.
srt-1-fit
srt-1.4.1.tar.gz
* https://github.com/Haivision/srt/releases/tag/v1.4.1
srt-1.5.3.tar.gz
* https://github.com/Haivision/srt/releases/tag/v1.5.3
* https://ossrs.net/lts/zh-cn/license#srt
openssl-1.1-fit
@ -24,10 +24,6 @@ openssl-OpenSSL_1_0_2u.tar.gz
* SRTP depends on openssl 1.0.*, so we use both ssl versions.
* https://ossrs.net/lts/zh-cn/license#openssl
CherryPy-3.2.4.zip
* sample api server for srs.
* https://pypi.python.org/pypi/CherryPy/3.2.4
libsrtp-2.3.0.tar.gz
* For WebRTC, SRTP to encrypt and decrypt RTP.
* https://github.com/cisco/libsrtp/releases/tag/v2.3.0

Binary file not shown.

View File

@ -0,0 +1,225 @@
/*
* (I)DCT Transforms
* Copyright (c) 2009 Peter Ross <pross@xvid.org>
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
* Copyright (c) 2010 Vitor Sessak
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* (Inverse) Discrete Cosine Transforms. These are also known as the
* type II and type III DCTs respectively.
*/
#include <math.h>
#include <string.h>
#include "libavutil/mathematics.h"
#include "dct.h"
#include "dct32.h"
/* sin((M_PI * x / (2 * n)) */
#define SIN(s, n, x) (s->costab[(n) - (x)])
/* cos((M_PI * x / (2 * n)) */
#define COS(s, n, x) (s->costab[x])
static void dst_calc_I_c(DCTContext *ctx, FFTSample *data)
{
int n = 1 << ctx->nbits;
int i;
data[0] = 0;
for (i = 1; i < n / 2; i++) {
float tmp1 = data[i ];
float tmp2 = data[n - i];
float s = SIN(ctx, n, 2 * i);
s *= tmp1 + tmp2;
tmp1 = (tmp1 - tmp2) * 0.5f;
data[i] = s + tmp1;
data[n - i] = s - tmp1;
}
data[n / 2] *= 2;
ctx->rdft.rdft_calc(&ctx->rdft, data);
data[0] *= 0.5f;
for (i = 1; i < n - 2; i += 2) {
data[i + 1] += data[i - 1];
data[i] = -data[i + 2];
}
data[n - 1] = 0;
}
static void dct_calc_I_c(DCTContext *ctx, FFTSample *data)
{
int n = 1 << ctx->nbits;
int i;
float next = -0.5f * (data[0] - data[n]);
for (i = 0; i < n / 2; i++) {
float tmp1 = data[i];
float tmp2 = data[n - i];
float s = SIN(ctx, n, 2 * i);
float c = COS(ctx, n, 2 * i);
c *= tmp1 - tmp2;
s *= tmp1 - tmp2;
next += c;
tmp1 = (tmp1 + tmp2) * 0.5f;
data[i] = tmp1 - s;
data[n - i] = tmp1 + s;
}
ctx->rdft.rdft_calc(&ctx->rdft, data);
data[n] = data[1];
data[1] = next;
for (i = 3; i <= n; i += 2)
data[i] = data[i - 2] - data[i];
}
static void dct_calc_III_c(DCTContext *ctx, FFTSample *data)
{
int n = 1 << ctx->nbits;
int i;
float next = data[n - 1];
float inv_n = 1.0f / n;
for (i = n - 2; i >= 2; i -= 2) {
float val1 = data[i];
float val2 = data[i - 1] - data[i + 1];
float c = COS(ctx, n, i);
float s = SIN(ctx, n, i);
data[i] = c * val1 + s * val2;
data[i + 1] = s * val1 - c * val2;
}
data[1] = 2 * next;
ctx->rdft.rdft_calc(&ctx->rdft, data);
for (i = 0; i < n / 2; i++) {
float tmp1 = data[i] * inv_n;
float tmp2 = data[n - i - 1] * inv_n;
float csc = ctx->csc2[i] * (tmp1 - tmp2);
tmp1 += tmp2;
data[i] = tmp1 + csc;
data[n - i - 1] = tmp1 - csc;
}
}
static void dct_calc_II_c(DCTContext *ctx, FFTSample *data)
{
int n = 1 << ctx->nbits;
int i;
float next;
for (i = 0; i < n / 2; i++) {
float tmp1 = data[i];
float tmp2 = data[n - i - 1];
float s = SIN(ctx, n, 2 * i + 1);
s *= tmp1 - tmp2;
tmp1 = (tmp1 + tmp2) * 0.5f;
data[i] = tmp1 + s;
data[n-i-1] = tmp1 - s;
}
ctx->rdft.rdft_calc(&ctx->rdft, data);
next = data[1] * 0.5;
data[1] *= -1;
for (i = n - 2; i >= 0; i -= 2) {
float inr = data[i ];
float ini = data[i + 1];
float c = COS(ctx, n, i);
float s = SIN(ctx, n, i);
data[i] = c * inr + s * ini;
data[i + 1] = next;
next += s * inr - c * ini;
}
}
static void dct32_func(DCTContext *ctx, FFTSample *data)
{
ctx->dct32(data, data);
}
av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse)
{
int n = 1 << nbits;
int i;
int ret;
memset(s, 0, sizeof(*s));
s->nbits = nbits;
s->inverse = inverse;
if (inverse == DCT_II && nbits == 5) {
s->dct_calc = dct32_func;
} else {
ff_init_ff_cos_tabs(nbits + 2);
s->costab = ff_cos_tabs[nbits + 2];
s->csc2 = av_malloc_array(n / 2, sizeof(FFTSample));
if (!s->csc2)
return AVERROR(ENOMEM);
if ((ret = ff_rdft_init(&s->rdft, nbits, inverse == DCT_III)) < 0) {
av_freep(&s->csc2);
return ret;
}
for (i = 0; i < n / 2; i++)
s->csc2[i] = 0.5 / sin((M_PI / (2 * n) * (2 * i + 1)));
switch (inverse) {
case DCT_I : s->dct_calc = dct_calc_I_c; break;
case DCT_II : s->dct_calc = dct_calc_II_c; break;
case DCT_III: s->dct_calc = dct_calc_III_c; break;
case DST_I : s->dct_calc = dst_calc_I_c; break;
}
}
s->dct32 = ff_dct32_float;
if (ARCH_X86)
ff_dct_init_x86(s);
return 0;
}
av_cold void ff_dct_end(DCTContext *s)
{
ff_rdft_end(&s->rdft);
av_freep(&s->csc2);
}

View File

@ -0,0 +1,25 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_DCT32_H
#define AVCODEC_DCT32_H
void ff_dct32_float(float *dst, const float *src);
void ff_dct32_fixed(int *dst, const int *src);
#endif /* AVCODEC_DCT32_H */

View File

@ -0,0 +1,20 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define DCT32_FLOAT 0
#include "dct32_template.c"

View File

@ -0,0 +1,20 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define DCT32_FLOAT 1
#include "dct32_template.c"

View File

@ -0,0 +1,288 @@
/*
* Template for the Discrete Cosine Transform for 32 samples
* Copyright (c) 2001, 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dct32.h"
#include "mathops.h"
#include "libavutil/internal.h"
#ifdef CHECKED
#define SUINT int
#define SUINT32 int32_t
#else
#define SUINT unsigned
#define SUINT32 uint32_t
#endif
#if DCT32_FLOAT
# define dct32 ff_dct32_float
# define FIXHR(x) ((float)(x))
# define MULH3(x, y, s) ((s)*(y)*(x))
# define INTFLOAT float
# define SUINTFLOAT float
#else
# define dct32 ff_dct32_fixed
# define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5))
# define MULH3(x, y, s) MULH((s)*(x), y)
# define INTFLOAT int
# define SUINTFLOAT SUINT
#endif
/* tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j))) */
/* cos(i*pi/64) */
#define COS0_0 FIXHR(0.50060299823519630134/2)
#define COS0_1 FIXHR(0.50547095989754365998/2)
#define COS0_2 FIXHR(0.51544730992262454697/2)
#define COS0_3 FIXHR(0.53104259108978417447/2)
#define COS0_4 FIXHR(0.55310389603444452782/2)
#define COS0_5 FIXHR(0.58293496820613387367/2)
#define COS0_6 FIXHR(0.62250412303566481615/2)
#define COS0_7 FIXHR(0.67480834145500574602/2)
#define COS0_8 FIXHR(0.74453627100229844977/2)
#define COS0_9 FIXHR(0.83934964541552703873/2)
#define COS0_10 FIXHR(0.97256823786196069369/2)
#define COS0_11 FIXHR(1.16943993343288495515/4)
#define COS0_12 FIXHR(1.48416461631416627724/4)
#define COS0_13 FIXHR(2.05778100995341155085/8)
#define COS0_14 FIXHR(3.40760841846871878570/8)
#define COS0_15 FIXHR(10.19000812354805681150/32)
#define COS1_0 FIXHR(0.50241928618815570551/2)
#define COS1_1 FIXHR(0.52249861493968888062/2)
#define COS1_2 FIXHR(0.56694403481635770368/2)
#define COS1_3 FIXHR(0.64682178335999012954/2)
#define COS1_4 FIXHR(0.78815462345125022473/2)
#define COS1_5 FIXHR(1.06067768599034747134/4)
#define COS1_6 FIXHR(1.72244709823833392782/4)
#define COS1_7 FIXHR(5.10114861868916385802/16)
#define COS2_0 FIXHR(0.50979557910415916894/2)
#define COS2_1 FIXHR(0.60134488693504528054/2)
#define COS2_2 FIXHR(0.89997622313641570463/2)
#define COS2_3 FIXHR(2.56291544774150617881/8)
#define COS3_0 FIXHR(0.54119610014619698439/2)
#define COS3_1 FIXHR(1.30656296487637652785/4)
#define COS4_0 FIXHR(M_SQRT1_2/2)
/* butterfly operator */
#define BF(a, b, c, s)\
{\
tmp0 = val##a + val##b;\
tmp1 = val##a - val##b;\
val##a = tmp0;\
val##b = MULH3(tmp1, c, 1<<(s));\
}
#define BF0(a, b, c, s)\
{\
tmp0 = tab[a] + tab[b];\
tmp1 = tab[a] - tab[b];\
val##a = tmp0;\
val##b = MULH3(tmp1, c, 1<<(s));\
}
#define BF1(a, b, c, d)\
{\
BF(a, b, COS4_0, 1);\
BF(c, d,-COS4_0, 1);\
val##c += val##d;\
}
#define BF2(a, b, c, d)\
{\
BF(a, b, COS4_0, 1);\
BF(c, d,-COS4_0, 1);\
val##c += val##d;\
val##a += val##c;\
val##c += val##b;\
val##b += val##d;\
}
#define ADD(a, b) val##a += val##b
/* DCT32 without 1/sqrt(2) coef zero scaling. */
void dct32(INTFLOAT *out, const INTFLOAT *tab_arg)
{
const SUINTFLOAT *tab = tab_arg;
SUINTFLOAT tmp0, tmp1;
SUINTFLOAT val0 , val1 , val2 , val3 , val4 , val5 , val6 , val7 ,
val8 , val9 , val10, val11, val12, val13, val14, val15,
val16, val17, val18, val19, val20, val21, val22, val23,
val24, val25, val26, val27, val28, val29, val30, val31;
/* pass 1 */
BF0( 0, 31, COS0_0 , 1);
BF0(15, 16, COS0_15, 5);
/* pass 2 */
BF( 0, 15, COS1_0 , 1);
BF(16, 31,-COS1_0 , 1);
/* pass 1 */
BF0( 7, 24, COS0_7 , 1);
BF0( 8, 23, COS0_8 , 1);
/* pass 2 */
BF( 7, 8, COS1_7 , 4);
BF(23, 24,-COS1_7 , 4);
/* pass 3 */
BF( 0, 7, COS2_0 , 1);
BF( 8, 15,-COS2_0 , 1);
BF(16, 23, COS2_0 , 1);
BF(24, 31,-COS2_0 , 1);
/* pass 1 */
BF0( 3, 28, COS0_3 , 1);
BF0(12, 19, COS0_12, 2);
/* pass 2 */
BF( 3, 12, COS1_3 , 1);
BF(19, 28,-COS1_3 , 1);
/* pass 1 */
BF0( 4, 27, COS0_4 , 1);
BF0(11, 20, COS0_11, 2);
/* pass 2 */
BF( 4, 11, COS1_4 , 1);
BF(20, 27,-COS1_4 , 1);
/* pass 3 */
BF( 3, 4, COS2_3 , 3);
BF(11, 12,-COS2_3 , 3);
BF(19, 20, COS2_3 , 3);
BF(27, 28,-COS2_3 , 3);
/* pass 4 */
BF( 0, 3, COS3_0 , 1);
BF( 4, 7,-COS3_0 , 1);
BF( 8, 11, COS3_0 , 1);
BF(12, 15,-COS3_0 , 1);
BF(16, 19, COS3_0 , 1);
BF(20, 23,-COS3_0 , 1);
BF(24, 27, COS3_0 , 1);
BF(28, 31,-COS3_0 , 1);
/* pass 1 */
BF0( 1, 30, COS0_1 , 1);
BF0(14, 17, COS0_14, 3);
/* pass 2 */
BF( 1, 14, COS1_1 , 1);
BF(17, 30,-COS1_1 , 1);
/* pass 1 */
BF0( 6, 25, COS0_6 , 1);
BF0( 9, 22, COS0_9 , 1);
/* pass 2 */
BF( 6, 9, COS1_6 , 2);
BF(22, 25,-COS1_6 , 2);
/* pass 3 */
BF( 1, 6, COS2_1 , 1);
BF( 9, 14,-COS2_1 , 1);
BF(17, 22, COS2_1 , 1);
BF(25, 30,-COS2_1 , 1);
/* pass 1 */
BF0( 2, 29, COS0_2 , 1);
BF0(13, 18, COS0_13, 3);
/* pass 2 */
BF( 2, 13, COS1_2 , 1);
BF(18, 29,-COS1_2 , 1);
/* pass 1 */
BF0( 5, 26, COS0_5 , 1);
BF0(10, 21, COS0_10, 1);
/* pass 2 */
BF( 5, 10, COS1_5 , 2);
BF(21, 26,-COS1_5 , 2);
/* pass 3 */
BF( 2, 5, COS2_2 , 1);
BF(10, 13,-COS2_2 , 1);
BF(18, 21, COS2_2 , 1);
BF(26, 29,-COS2_2 , 1);
/* pass 4 */
BF( 1, 2, COS3_1 , 2);
BF( 5, 6,-COS3_1 , 2);
BF( 9, 10, COS3_1 , 2);
BF(13, 14,-COS3_1 , 2);
BF(17, 18, COS3_1 , 2);
BF(21, 22,-COS3_1 , 2);
BF(25, 26, COS3_1 , 2);
BF(29, 30,-COS3_1 , 2);
/* pass 5 */
BF1( 0, 1, 2, 3);
BF2( 4, 5, 6, 7);
BF1( 8, 9, 10, 11);
BF2(12, 13, 14, 15);
BF1(16, 17, 18, 19);
BF2(20, 21, 22, 23);
BF1(24, 25, 26, 27);
BF2(28, 29, 30, 31);
/* pass 6 */
ADD( 8, 12);
ADD(12, 10);
ADD(10, 14);
ADD(14, 9);
ADD( 9, 13);
ADD(13, 11);
ADD(11, 15);
out[ 0] = val0;
out[16] = val1;
out[ 8] = val2;
out[24] = val3;
out[ 4] = val4;
out[20] = val5;
out[12] = val6;
out[28] = val7;
out[ 2] = val8;
out[18] = val9;
out[10] = val10;
out[26] = val11;
out[ 6] = val12;
out[22] = val13;
out[14] = val14;
out[30] = val15;
ADD(24, 28);
ADD(28, 26);
ADD(26, 30);
ADD(30, 25);
ADD(25, 29);
ADD(29, 27);
ADD(27, 31);
out[ 1] = val16 + val24;
out[17] = val17 + val25;
out[ 9] = val18 + val26;
out[25] = val19 + val27;
out[ 5] = val20 + val28;
out[21] = val21 + val29;
out[13] = val22 + val30;
out[29] = val23 + val31;
out[ 3] = val24 + val20;
out[19] = val25 + val21;
out[11] = val26 + val22;
out[27] = val27 + val23;
out[ 7] = val28 + val18;
out[23] = val29 + val19;
out[15] = val30 + val17;
out[31] = val31;
}

View File

@ -0,0 +1,50 @@
/*
* MPEG Audio common code
* Copyright (c) 2001, 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* MPEG Audio common code.
*/
#include "mpegaudio.h"
/* bitrate is in kb/s */
int ff_mpa_l2_select_table(int bitrate, int nb_channels, int freq, int lsf)
{
int ch_bitrate, table;
ch_bitrate = bitrate / nb_channels;
if (!lsf) {
if ((freq == 48000 && ch_bitrate >= 56) ||
(ch_bitrate >= 56 && ch_bitrate <= 80))
table = 0;
else if (freq != 48000 && ch_bitrate >= 96)
table = 1;
else if (freq != 32000 && ch_bitrate <= 48)
table = 2;
else
table = 3;
} else {
table = 4;
}
return table;
}

View File

@ -0,0 +1,81 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* mpeg audio declarations for both encoder and decoder.
*/
#ifndef AVCODEC_MPEGAUDIO_H
#define AVCODEC_MPEGAUDIO_H
#ifndef USE_FLOATS
# define USE_FLOATS 0
#endif
#include <stdint.h>
#include "libavutil/internal.h"
/* max frame size, in samples */
#define MPA_FRAME_SIZE 1152
/* max compressed frame size */
#define MPA_MAX_CODED_FRAME_SIZE 1792
#define MPA_MAX_CHANNELS 2
#define SBLIMIT 32 /* number of subbands */
#define MPA_STEREO 0
#define MPA_JSTEREO 1
#define MPA_DUAL 2
#define MPA_MONO 3
#ifndef FRAC_BITS
#define FRAC_BITS 23 /* fractional bits for sb_samples and dct */
#define WFRAC_BITS 16 /* fractional bits for window */
#endif
#define IMDCT_SCALAR 1.759
#define FRAC_ONE (1 << FRAC_BITS)
#define FIX(a) ((int)((a) * FRAC_ONE))
#if USE_FLOATS
# define INTFLOAT float
# define SUINTFLOAT float
typedef float MPA_INT;
typedef float OUT_INT;
#elif FRAC_BITS <= 15
# define INTFLOAT int
# define SUINTFLOAT SUINT
typedef int16_t MPA_INT;
typedef int16_t OUT_INT;
#else
# define INTFLOAT int
# define SUINTFLOAT SUINT
typedef int32_t MPA_INT;
typedef int16_t OUT_INT;
#endif
int ff_mpa_l2_select_table(int bitrate, int nb_channels, int freq, int lsf);
#endif /* AVCODEC_MPEGAUDIO_H */

View File

@ -0,0 +1,143 @@
/*
* MPEG Audio parser
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "parser.h"
#include "mpegaudiodecheader.h"
#include "libavutil/common.h"
#include "libavformat/apetag.h" // for APE tag.
#include "libavformat/id3v1.h" // for ID3v1_TAG_SIZE
typedef struct MpegAudioParseContext {
ParseContext pc;
int frame_size;
uint32_t header;
int header_count;
int no_bitrate;
} MpegAudioParseContext;
#define MPA_HEADER_SIZE 4
/* header + layer + freq + lsf/mpeg25 */
#define SAME_HEADER_MASK \
(0xffe00000 | (3 << 17) | (3 << 10) | (3 << 19))
static int mpegaudio_parse(AVCodecParserContext *s1,
AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
MpegAudioParseContext *s = s1->priv_data;
ParseContext *pc = &s->pc;
uint32_t state= pc->state;
int i;
int next= END_NOT_FOUND;
int flush = !buf_size;
for(i=0; i<buf_size; ){
if(s->frame_size){
int inc= FFMIN(buf_size - i, s->frame_size);
i += inc;
s->frame_size -= inc;
state = 0;
if(!s->frame_size){
next= i;
break;
}
}else{
while(i<buf_size){
int ret, sr, channels, bit_rate, frame_size;
enum AVCodecID codec_id = avctx->codec_id;
state= (state<<8) + buf[i++];
ret = ff_mpa_decode_header(state, &sr, &channels, &frame_size, &bit_rate, &codec_id);
if (ret < 4) {
if (i > 4)
s->header_count = -2;
} else {
int header_threshold = avctx->codec_id != AV_CODEC_ID_NONE && avctx->codec_id != codec_id;
if((state&SAME_HEADER_MASK) != (s->header&SAME_HEADER_MASK) && s->header)
s->header_count= -3;
s->header= state;
s->header_count++;
s->frame_size = ret-4;
if (s->header_count > header_threshold) {
avctx->sample_rate= sr;
avctx->channels = channels;
s1->duration = frame_size;
avctx->codec_id = codec_id;
if (s->no_bitrate || !avctx->bit_rate) {
s->no_bitrate = 1;
avctx->bit_rate += (bit_rate - avctx->bit_rate) / (s->header_count - header_threshold);
}
}
if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) {
s->frame_size = 0;
next = buf_size;
} else if (codec_id == AV_CODEC_ID_MP3ADU) {
avpriv_report_missing_feature(avctx,
"MP3ADU full parser");
*poutbuf = NULL;
*poutbuf_size = 0;
return buf_size; /* parsers must not return error codes */
}
break;
}
}
}
}
pc->state= state;
if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
*poutbuf = NULL;
*poutbuf_size = 0;
return buf_size;
}
if (flush && buf_size >= ID3v1_TAG_SIZE && memcmp(buf, "TAG", 3) == 0) {
*poutbuf = NULL;
*poutbuf_size = 0;
return next;
}
if (flush && buf_size >= APE_TAG_FOOTER_BYTES && memcmp(buf, APE_TAG_PREAMBLE, 8) == 0) {
*poutbuf = NULL;
*poutbuf_size = 0;
return next;
}
*poutbuf = buf;
*poutbuf_size = buf_size;
return next;
}
AVCodecParser ff_mpegaudio_parser = {
.codec_ids = { AV_CODEC_ID_MP1, AV_CODEC_ID_MP2, AV_CODEC_ID_MP3, AV_CODEC_ID_MP3ADU },
.priv_data_size = sizeof(MpegAudioParseContext),
.parser_parse = mpegaudio_parse,
.parser_close = ff_parse_close,
};

View File

@ -0,0 +1,43 @@
/*
* Generate a header file for hardcoded mpegaudiodec tables
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#define CONFIG_HARDCODED_TABLES 0
#include "libavutil/tablegen.h"
#include "mpegaudio_tablegen.h"
#include "tableprint.h"
int main(void)
{
mpegaudio_tableinit();
write_fileheader();
WRITE_ARRAY("static const", int8_t, table_4_3_exp);
WRITE_ARRAY("static const", uint32_t, table_4_3_value);
WRITE_ARRAY("static const", uint32_t, exp_table_fixed);
WRITE_ARRAY("static const", float, exp_table_float);
WRITE_2D_ARRAY("static const", uint32_t, expval_table_fixed);
WRITE_2D_ARRAY("static const", float, expval_table_float);
return 0;
}

View File

@ -0,0 +1,91 @@
/*
* Header file for hardcoded mpegaudiodec tables
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MPEGAUDIO_TABLEGEN_H
#define AVCODEC_MPEGAUDIO_TABLEGEN_H
#include <stdint.h>
#include <math.h>
#include "libavutil/attributes.h"
#define TABLE_4_3_SIZE (8191 + 16)*4
#if CONFIG_HARDCODED_TABLES
#define mpegaudio_tableinit()
#include "libavcodec/mpegaudio_tables.h"
#else
static int8_t table_4_3_exp[TABLE_4_3_SIZE];
static uint32_t table_4_3_value[TABLE_4_3_SIZE];
static uint32_t exp_table_fixed[512];
static uint32_t expval_table_fixed[512][16];
static float exp_table_float[512];
static float expval_table_float[512][16];
#define FRAC_BITS 23
#define IMDCT_SCALAR 1.759
static av_cold void mpegaudio_tableinit(void)
{
int i, value, exponent;
static const double exp2_lut[4] = {
1.00000000000000000000, /* 2 ^ (0 * 0.25) */
1.18920711500272106672, /* 2 ^ (1 * 0.25) */
M_SQRT2 , /* 2 ^ (2 * 0.25) */
1.68179283050742908606, /* 2 ^ (3 * 0.25) */
};
static double pow43_lut[16];
double exp2_base = 2.11758236813575084767080625169910490512847900390625e-22; // 2^(-72)
double exp2_val;
double pow43_val = 0;
for (i = 0; i < 16; ++i)
pow43_lut[i] = i * cbrt(i);
for (i = 1; i < TABLE_4_3_SIZE; i++) {
double f, fm;
int e, m;
double value = i / 4;
if ((i & 3) == 0)
pow43_val = value / IMDCT_SCALAR * cbrt(value);
f = pow43_val * exp2_lut[i & 3];
fm = frexp(f, &e);
m = llrint(fm * (1LL << 31));
e += FRAC_BITS - 31 + 5 - 100;
/* normalized to FRAC_BITS */
table_4_3_value[i] = m;
table_4_3_exp[i] = -e;
}
for (exponent = 0; exponent < 512; exponent++) {
if (exponent && (exponent & 3) == 0)
exp2_base *= 2;
exp2_val = exp2_base * exp2_lut[exponent & 3] / IMDCT_SCALAR;
for (value = 0; value < 16; value++) {
double f = pow43_lut[value] * exp2_val;
expval_table_fixed[exponent][value] = (f < 0xFFFFFFFF ? llrint(f) : 0xFFFFFFFF);
expval_table_float[exponent][value] = f;
}
exp_table_fixed[exponent] = expval_table_fixed[exponent][1];
exp_table_float[exponent] = expval_table_float[exponent][1];
}
}
#endif /* CONFIG_HARDCODED_TABLES */
#endif /* AVCODEC_MPEGAUDIO_TABLEGEN_H */

View File

@ -0,0 +1,146 @@
/*
* MPEG Audio common tables
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* mpeg audio layer common tables.
*/
#include "mpegaudiodata.h"
const uint16_t avpriv_mpa_bitrate_tab[2][3][15] = {
{ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 },
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } },
{ {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}
}
};
const uint16_t avpriv_mpa_freq_tab[3] = { 44100, 48000, 32000 };
/*******************************************************/
/* layer 2 tables */
const int ff_mpa_sblimit_table[5] = { 27 , 30 , 8, 12 , 30 };
const int ff_mpa_quant_steps[17] = {
3, 5, 7, 9, 15,
31, 63, 127, 255, 511,
1023, 2047, 4095, 8191, 16383,
32767, 65535
};
/* we use a negative value if grouped */
const int ff_mpa_quant_bits[17] = {
-5, -7, 3, -10, 4,
5, 6, 7, 8, 9,
10, 11, 12, 13, 14,
15, 16
};
/* encoding tables which give the quantization index. Note how it is
possible to store them efficiently ! */
static const unsigned char alloc_table_1[] = {
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
3, 0, 1, 2, 3, 4, 5, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
2, 0, 1, 16,
};
static const unsigned char alloc_table_3[] = {
4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
};
static const unsigned char alloc_table_4[] = {
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
3, 0, 1, 3, 4, 5, 6, 7,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
2, 0, 1, 3,
};
const unsigned char * const ff_mpa_alloc_tables[5] =
{ alloc_table_1, alloc_table_1, alloc_table_3, alloc_table_3, alloc_table_4, };

View File

@ -0,0 +1,44 @@
/*
* MPEG Audio common tables
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* mpeg audio layer common tables.
*/
#ifndef AVCODEC_MPEGAUDIODATA_H
#define AVCODEC_MPEGAUDIODATA_H
#include <stdint.h>
#include "internal.h"
#define MODE_EXT_MS_STEREO 2
#define MODE_EXT_I_STEREO 1
extern av_export_avcodec const uint16_t avpriv_mpa_bitrate_tab[2][3][15];
extern av_export_avcodec const uint16_t avpriv_mpa_freq_tab[3];
extern const int ff_mpa_sblimit_table[5];
extern const int ff_mpa_quant_steps[17];
extern const int ff_mpa_quant_bits[17];
extern const unsigned char * const ff_mpa_alloc_tables[5];
#endif /* AVCODEC_MPEGAUDIODATA_H */

View File

@ -0,0 +1,120 @@
/*
* Fixed-point MPEG audio decoder
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "libavutil/samplefmt.h"
#define USE_FLOATS 0
#include "mpegaudio.h"
#define SHR(a,b) (((int)(a))>>(b))
/* WARNING: only correct for positive numbers */
#define FIXR_OLD(a) ((int)((a) * FRAC_ONE + 0.5))
#define FIXR(a) ((int)((a) * FRAC_ONE + 0.5))
#define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5))
#define MULH3(x, y, s) MULH((s)*(x), y)
#define MULLx(x, y, s) MULL((int)(x),(y),s)
#define RENAME(a) a ## _fixed
#define OUT_FMT AV_SAMPLE_FMT_S16
#define OUT_FMT_P AV_SAMPLE_FMT_S16P
#include "mpegaudiodec_template.c"
#if CONFIG_MP1_DECODER
AVCodec ff_mp1_decoder = {
.name = "mp1",
.long_name = NULL_IF_CONFIG_SMALL("MP1 (MPEG audio layer 1)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP1,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP2_DECODER
AVCodec ff_mp2_decoder = {
.name = "mp2",
.long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP2,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP3_DECODER
AVCodec ff_mp3_decoder = {
.name = "mp3",
.long_name = NULL_IF_CONFIG_SMALL("MP3 (MPEG audio layer 3)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP3,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP3ADU_DECODER
AVCodec ff_mp3adu_decoder = {
.name = "mp3adu",
.long_name = NULL_IF_CONFIG_SMALL("ADU (Application Data Unit) MP3 (MPEG audio layer 3)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP3ADU,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.decode = decode_frame_adu,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP3ON4_DECODER
AVCodec ff_mp3on4_decoder = {
.name = "mp3on4",
.long_name = NULL_IF_CONFIG_SMALL("MP3onMP4"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP3ON4,
.priv_data_size = sizeof(MP3On4DecodeContext),
.init = decode_init_mp3on4,
.close = decode_close_mp3on4,
.decode = decode_frame_mp3on4,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush_mp3on4,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_NONE },
};
#endif

View File

@ -0,0 +1,124 @@
/*
* Float MPEG Audio decoder
* Copyright (c) 2010 Michael Niedermayer
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "libavutil/samplefmt.h"
#define USE_FLOATS 1
#include "mpegaudio.h"
#define SHR(a,b) ((a)*(1.0f/(1<<(b))))
#define FIXR_OLD(a) ((int)((a) * FRAC_ONE + 0.5))
#define FIXR(x) ((float)(x))
#define FIXHR(x) ((float)(x))
#define MULH3(x, y, s) ((s)*(y)*(x))
#define MULLx(x, y, s) ((y)*(x))
#define RENAME(a) a ## _float
#define OUT_FMT AV_SAMPLE_FMT_FLT
#define OUT_FMT_P AV_SAMPLE_FMT_FLTP
#include "mpegaudiodec_template.c"
#if CONFIG_MP1FLOAT_DECODER
AVCodec ff_mp1float_decoder = {
.name = "mp1float",
.long_name = NULL_IF_CONFIG_SMALL("MP1 (MPEG audio layer 1)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP1,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.close = decode_close,
.decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP2FLOAT_DECODER
AVCodec ff_mp2float_decoder = {
.name = "mp2float",
.long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP2,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.decode = decode_frame,
.close = decode_close,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP3FLOAT_DECODER
AVCodec ff_mp3float_decoder = {
.name = "mp3float",
.long_name = NULL_IF_CONFIG_SMALL("MP3 (MPEG audio layer 3)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP3,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.close = decode_close,
.decode = decode_frame,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP3ADUFLOAT_DECODER
AVCodec ff_mp3adufloat_decoder = {
.name = "mp3adufloat",
.long_name = NULL_IF_CONFIG_SMALL("ADU (Application Data Unit) MP3 (MPEG audio layer 3)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP3ADU,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.close = decode_close,
.decode = decode_frame_adu,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_NONE },
};
#endif
#if CONFIG_MP3ON4FLOAT_DECODER
AVCodec ff_mp3on4float_decoder = {
.name = "mp3on4float",
.long_name = NULL_IF_CONFIG_SMALL("MP3onMP4"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP3ON4,
.priv_data_size = sizeof(MP3On4DecodeContext),
.init = decode_init_mp3on4,
.close = decode_close_mp3on4,
.decode = decode_frame_mp3on4,
.capabilities = AV_CODEC_CAP_DR1,
.flush = flush_mp3on4,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
/*
* MPEG Audio header decoder
* Copyright (c) 2001, 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* MPEG Audio header decoder.
*/
#include "libavutil/common.h"
#include "avcodec.h"
#include "internal.h"
#include "mpegaudio.h"
#include "mpegaudiodata.h"
#include "mpegaudiodecheader.h"
int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header)
{
int sample_rate, frame_size, mpeg25, padding;
int sample_rate_index, bitrate_index;
int ret;
ret = ff_mpa_check_header(header);
if (ret < 0)
return ret;
if (header & (1<<20)) {
s->lsf = (header & (1<<19)) ? 0 : 1;
mpeg25 = 0;
} else {
s->lsf = 1;
mpeg25 = 1;
}
s->layer = 4 - ((header >> 17) & 3);
/* extract frequency */
sample_rate_index = (header >> 10) & 3;
if (sample_rate_index >= FF_ARRAY_ELEMS(avpriv_mpa_freq_tab))
sample_rate_index = 0;
sample_rate = avpriv_mpa_freq_tab[sample_rate_index] >> (s->lsf + mpeg25);
sample_rate_index += 3 * (s->lsf + mpeg25);
s->sample_rate_index = sample_rate_index;
s->error_protection = ((header >> 16) & 1) ^ 1;
s->sample_rate = sample_rate;
bitrate_index = (header >> 12) & 0xf;
padding = (header >> 9) & 1;
//extension = (header >> 8) & 1;
s->mode = (header >> 6) & 3;
s->mode_ext = (header >> 4) & 3;
//copyright = (header >> 3) & 1;
//original = (header >> 2) & 1;
//emphasis = header & 3;
if (s->mode == MPA_MONO)
s->nb_channels = 1;
else
s->nb_channels = 2;
if (bitrate_index != 0) {
frame_size = avpriv_mpa_bitrate_tab[s->lsf][s->layer - 1][bitrate_index];
s->bit_rate = frame_size * 1000;
switch(s->layer) {
case 1:
frame_size = (frame_size * 12000) / sample_rate;
frame_size = (frame_size + padding) * 4;
break;
case 2:
frame_size = (frame_size * 144000) / sample_rate;
frame_size += padding;
break;
default:
case 3:
frame_size = (frame_size * 144000) / (sample_rate << s->lsf);
frame_size += padding;
break;
}
s->frame_size = frame_size;
} else {
/* if no frame size computed, signal it */
return 1;
}
#if defined(DEBUG)
ff_dlog(NULL, "layer%d, %d Hz, %d kbits/s, ",
s->layer, s->sample_rate, s->bit_rate);
if (s->nb_channels == 2) {
if (s->layer == 3) {
if (s->mode_ext & MODE_EXT_MS_STEREO)
ff_dlog(NULL, "ms-");
if (s->mode_ext & MODE_EXT_I_STEREO)
ff_dlog(NULL, "i-");
}
ff_dlog(NULL, "stereo");
} else {
ff_dlog(NULL, "mono");
}
ff_dlog(NULL, "\n");
#endif
return 0;
}
int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate, enum AVCodecID *codec_id)
{
MPADecodeHeader s1, *s = &s1;
if (avpriv_mpegaudio_decode_header(s, head) != 0) {
return -1;
}
switch(s->layer) {
case 1:
*codec_id = AV_CODEC_ID_MP1;
*frame_size = 384;
break;
case 2:
*codec_id = AV_CODEC_ID_MP2;
*frame_size = 1152;
break;
default:
case 3:
if (*codec_id != AV_CODEC_ID_MP3ADU)
*codec_id = AV_CODEC_ID_MP3;
if (s->lsf)
*frame_size = 576;
else
*frame_size = 1152;
break;
}
*sample_rate = s->sample_rate;
*channels = s->nb_channels;
*bit_rate = s->bit_rate;
return s->frame_size;
}

View File

@ -0,0 +1,80 @@
/*
* MPEG Audio header decoder
* Copyright (c) 2001, 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* MPEG Audio header decoder.
*/
#ifndef AVCODEC_MPEGAUDIODECHEADER_H
#define AVCODEC_MPEGAUDIODECHEADER_H
#include "avcodec.h"
#define MP3_MASK 0xFFFE0CCF
#define MPA_DECODE_HEADER \
int frame_size; \
int error_protection; \
int layer; \
int sample_rate; \
int sample_rate_index; /* between 0 and 8 */ \
int bit_rate; \
int nb_channels; \
int mode; \
int mode_ext; \
int lsf;
typedef struct MPADecodeHeader {
MPA_DECODE_HEADER
} MPADecodeHeader;
/* header decoding. MUST check the header before because no
consistency check is done there. Return 1 if free format found and
that the frame size must be computed externally */
int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header);
/* useful helper to get MPEG audio stream info. Return -1 if error in
header, otherwise the coded frame size in bytes */
int ff_mpa_decode_header(uint32_t head, int *sample_rate,
int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id);
/* fast header check for resync */
static inline int ff_mpa_check_header(uint32_t header){
/* header */
if ((header & 0xffe00000) != 0xffe00000)
return -1;
/* version check */
if ((header & (3<<19)) == 1<<19)
return -1;
/* layer check */
if ((header & (3<<17)) == 0)
return -1;
/* bit rate */
if ((header & (0xf<<12)) == 0xf<<12)
return -1;
/* frequency */
if ((header & (3<<10)) == 3<<10)
return -1;
return 0;
}
#endif /* AVCODEC_MPEGAUDIODECHEADER_H */

View File

@ -0,0 +1,615 @@
/*
* MPEG Audio decoder
* copyright (c) 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* mpeg audio layer decoder tables.
*/
#ifndef AVCODEC_MPEGAUDIODECTAB_H
#define AVCODEC_MPEGAUDIODECTAB_H
#include <stddef.h>
#include <stdint.h>
#include "mpegaudio.h"
/*******************************************************/
/* layer 3 tables */
/* layer 3 huffman tables */
typedef struct HuffTable {
int xsize;
const uint8_t *bits;
const uint16_t *codes;
} HuffTable;
/* layer3 scale factor size */
static const uint8_t slen_table[2][16] = {
{ 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 },
{ 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 },
};
/* number of lsf scale factors for a given size */
static const uint8_t lsf_nsf_table[6][3][4] = {
{ { 6, 5, 5, 5 }, { 9, 9, 9, 9 }, { 6, 9, 9, 9 } },
{ { 6, 5, 7, 3 }, { 9, 9, 12, 6 }, { 6, 9, 12, 6 } },
{ { 11, 10, 0, 0 }, { 18, 18, 0, 0 }, { 15, 18, 0, 0 } },
{ { 7, 7, 7, 0 }, { 12, 12, 12, 0 }, { 6, 15, 12, 0 } },
{ { 6, 6, 6, 3 }, { 12, 9, 9, 6 }, { 6, 12, 9, 6 } },
{ { 8, 8, 5, 0 }, { 15, 12, 9, 0 }, { 6, 18, 9, 0 } },
};
/* mpegaudio layer 3 huffman tables */
static const uint16_t mpa_huffcodes_1[4] = {
0x0001, 0x0001, 0x0001, 0x0000,
};
static const uint8_t mpa_huffbits_1[4] = {
1, 3, 2, 3,
};
static const uint16_t mpa_huffcodes_2[9] = {
0x0001, 0x0002, 0x0001, 0x0003, 0x0001, 0x0001, 0x0003, 0x0002,
0x0000,
};
static const uint8_t mpa_huffbits_2[9] = {
1, 3, 6, 3, 3, 5, 5, 5,
6,
};
static const uint16_t mpa_huffcodes_3[9] = {
0x0003, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0002,
0x0000,
};
static const uint8_t mpa_huffbits_3[9] = {
2, 2, 6, 3, 2, 5, 5, 5,
6,
};
static const uint16_t mpa_huffcodes_5[16] = {
0x0001, 0x0002, 0x0006, 0x0005, 0x0003, 0x0001, 0x0004, 0x0004,
0x0007, 0x0005, 0x0007, 0x0001, 0x0006, 0x0001, 0x0001, 0x0000,
};
static const uint8_t mpa_huffbits_5[16] = {
1, 3, 6, 7, 3, 3, 6, 7,
6, 6, 7, 8, 7, 6, 7, 8,
};
static const uint16_t mpa_huffcodes_6[16] = {
0x0007, 0x0003, 0x0005, 0x0001, 0x0006, 0x0002, 0x0003, 0x0002,
0x0005, 0x0004, 0x0004, 0x0001, 0x0003, 0x0003, 0x0002, 0x0000,
};
static const uint8_t mpa_huffbits_6[16] = {
3, 3, 5, 7, 3, 2, 4, 5,
4, 4, 5, 6, 6, 5, 6, 7,
};
static const uint16_t mpa_huffcodes_7[36] = {
0x0001, 0x0002, 0x000a, 0x0013, 0x0010, 0x000a, 0x0003, 0x0003,
0x0007, 0x000a, 0x0005, 0x0003, 0x000b, 0x0004, 0x000d, 0x0011,
0x0008, 0x0004, 0x000c, 0x000b, 0x0012, 0x000f, 0x000b, 0x0002,
0x0007, 0x0006, 0x0009, 0x000e, 0x0003, 0x0001, 0x0006, 0x0004,
0x0005, 0x0003, 0x0002, 0x0000,
};
static const uint8_t mpa_huffbits_7[36] = {
1, 3, 6, 8, 8, 9, 3, 4,
6, 7, 7, 8, 6, 5, 7, 8,
8, 9, 7, 7, 8, 9, 9, 9,
7, 7, 8, 9, 9, 10, 8, 8,
9, 10, 10, 10,
};
static const uint16_t mpa_huffcodes_8[36] = {
0x0003, 0x0004, 0x0006, 0x0012, 0x000c, 0x0005, 0x0005, 0x0001,
0x0002, 0x0010, 0x0009, 0x0003, 0x0007, 0x0003, 0x0005, 0x000e,
0x0007, 0x0003, 0x0013, 0x0011, 0x000f, 0x000d, 0x000a, 0x0004,
0x000d, 0x0005, 0x0008, 0x000b, 0x0005, 0x0001, 0x000c, 0x0004,
0x0004, 0x0001, 0x0001, 0x0000,
};
static const uint8_t mpa_huffbits_8[36] = {
2, 3, 6, 8, 8, 9, 3, 2,
4, 8, 8, 8, 6, 4, 6, 8,
8, 9, 8, 8, 8, 9, 9, 10,
8, 7, 8, 9, 10, 10, 9, 8,
9, 9, 11, 11,
};
static const uint16_t mpa_huffcodes_9[36] = {
0x0007, 0x0005, 0x0009, 0x000e, 0x000f, 0x0007, 0x0006, 0x0004,
0x0005, 0x0005, 0x0006, 0x0007, 0x0007, 0x0006, 0x0008, 0x0008,
0x0008, 0x0005, 0x000f, 0x0006, 0x0009, 0x000a, 0x0005, 0x0001,
0x000b, 0x0007, 0x0009, 0x0006, 0x0004, 0x0001, 0x000e, 0x0004,
0x0006, 0x0002, 0x0006, 0x0000,
};
static const uint8_t mpa_huffbits_9[36] = {
3, 3, 5, 6, 8, 9, 3, 3,
4, 5, 6, 8, 4, 4, 5, 6,
7, 8, 6, 5, 6, 7, 7, 8,
7, 6, 7, 7, 8, 9, 8, 7,
8, 8, 9, 9,
};
static const uint16_t mpa_huffcodes_10[64] = {
0x0001, 0x0002, 0x000a, 0x0017, 0x0023, 0x001e, 0x000c, 0x0011,
0x0003, 0x0003, 0x0008, 0x000c, 0x0012, 0x0015, 0x000c, 0x0007,
0x000b, 0x0009, 0x000f, 0x0015, 0x0020, 0x0028, 0x0013, 0x0006,
0x000e, 0x000d, 0x0016, 0x0022, 0x002e, 0x0017, 0x0012, 0x0007,
0x0014, 0x0013, 0x0021, 0x002f, 0x001b, 0x0016, 0x0009, 0x0003,
0x001f, 0x0016, 0x0029, 0x001a, 0x0015, 0x0014, 0x0005, 0x0003,
0x000e, 0x000d, 0x000a, 0x000b, 0x0010, 0x0006, 0x0005, 0x0001,
0x0009, 0x0008, 0x0007, 0x0008, 0x0004, 0x0004, 0x0002, 0x0000,
};
static const uint8_t mpa_huffbits_10[64] = {
1, 3, 6, 8, 9, 9, 9, 10,
3, 4, 6, 7, 8, 9, 8, 8,
6, 6, 7, 8, 9, 10, 9, 9,
7, 7, 8, 9, 10, 10, 9, 10,
8, 8, 9, 10, 10, 10, 10, 10,
9, 9, 10, 10, 11, 11, 10, 11,
8, 8, 9, 10, 10, 10, 11, 11,
9, 8, 9, 10, 10, 11, 11, 11,
};
static const uint16_t mpa_huffcodes_11[64] = {
0x0003, 0x0004, 0x000a, 0x0018, 0x0022, 0x0021, 0x0015, 0x000f,
0x0005, 0x0003, 0x0004, 0x000a, 0x0020, 0x0011, 0x000b, 0x000a,
0x000b, 0x0007, 0x000d, 0x0012, 0x001e, 0x001f, 0x0014, 0x0005,
0x0019, 0x000b, 0x0013, 0x003b, 0x001b, 0x0012, 0x000c, 0x0005,
0x0023, 0x0021, 0x001f, 0x003a, 0x001e, 0x0010, 0x0007, 0x0005,
0x001c, 0x001a, 0x0020, 0x0013, 0x0011, 0x000f, 0x0008, 0x000e,
0x000e, 0x000c, 0x0009, 0x000d, 0x000e, 0x0009, 0x0004, 0x0001,
0x000b, 0x0004, 0x0006, 0x0006, 0x0006, 0x0003, 0x0002, 0x0000,
};
static const uint8_t mpa_huffbits_11[64] = {
2, 3, 5, 7, 8, 9, 8, 9,
3, 3, 4, 6, 8, 8, 7, 8,
5, 5, 6, 7, 8, 9, 8, 8,
7, 6, 7, 9, 8, 10, 8, 9,
8, 8, 8, 9, 9, 10, 9, 10,
8, 8, 9, 10, 10, 11, 10, 11,
8, 7, 7, 8, 9, 10, 10, 10,
8, 7, 8, 9, 10, 10, 10, 10,
};
static const uint16_t mpa_huffcodes_12[64] = {
0x0009, 0x0006, 0x0010, 0x0021, 0x0029, 0x0027, 0x0026, 0x001a,
0x0007, 0x0005, 0x0006, 0x0009, 0x0017, 0x0010, 0x001a, 0x000b,
0x0011, 0x0007, 0x000b, 0x000e, 0x0015, 0x001e, 0x000a, 0x0007,
0x0011, 0x000a, 0x000f, 0x000c, 0x0012, 0x001c, 0x000e, 0x0005,
0x0020, 0x000d, 0x0016, 0x0013, 0x0012, 0x0010, 0x0009, 0x0005,
0x0028, 0x0011, 0x001f, 0x001d, 0x0011, 0x000d, 0x0004, 0x0002,
0x001b, 0x000c, 0x000b, 0x000f, 0x000a, 0x0007, 0x0004, 0x0001,
0x001b, 0x000c, 0x0008, 0x000c, 0x0006, 0x0003, 0x0001, 0x0000,
};
static const uint8_t mpa_huffbits_12[64] = {
4, 3, 5, 7, 8, 9, 9, 9,
3, 3, 4, 5, 7, 7, 8, 8,
5, 4, 5, 6, 7, 8, 7, 8,
6, 5, 6, 6, 7, 8, 8, 8,
7, 6, 7, 7, 8, 8, 8, 9,
8, 7, 8, 8, 8, 9, 8, 9,
8, 7, 7, 8, 8, 9, 9, 10,
9, 8, 8, 9, 9, 9, 9, 10,
};
static const uint16_t mpa_huffcodes_13[256] = {
0x0001, 0x0005, 0x000e, 0x0015, 0x0022, 0x0033, 0x002e, 0x0047,
0x002a, 0x0034, 0x0044, 0x0034, 0x0043, 0x002c, 0x002b, 0x0013,
0x0003, 0x0004, 0x000c, 0x0013, 0x001f, 0x001a, 0x002c, 0x0021,
0x001f, 0x0018, 0x0020, 0x0018, 0x001f, 0x0023, 0x0016, 0x000e,
0x000f, 0x000d, 0x0017, 0x0024, 0x003b, 0x0031, 0x004d, 0x0041,
0x001d, 0x0028, 0x001e, 0x0028, 0x001b, 0x0021, 0x002a, 0x0010,
0x0016, 0x0014, 0x0025, 0x003d, 0x0038, 0x004f, 0x0049, 0x0040,
0x002b, 0x004c, 0x0038, 0x0025, 0x001a, 0x001f, 0x0019, 0x000e,
0x0023, 0x0010, 0x003c, 0x0039, 0x0061, 0x004b, 0x0072, 0x005b,
0x0036, 0x0049, 0x0037, 0x0029, 0x0030, 0x0035, 0x0017, 0x0018,
0x003a, 0x001b, 0x0032, 0x0060, 0x004c, 0x0046, 0x005d, 0x0054,
0x004d, 0x003a, 0x004f, 0x001d, 0x004a, 0x0031, 0x0029, 0x0011,
0x002f, 0x002d, 0x004e, 0x004a, 0x0073, 0x005e, 0x005a, 0x004f,
0x0045, 0x0053, 0x0047, 0x0032, 0x003b, 0x0026, 0x0024, 0x000f,
0x0048, 0x0022, 0x0038, 0x005f, 0x005c, 0x0055, 0x005b, 0x005a,
0x0056, 0x0049, 0x004d, 0x0041, 0x0033, 0x002c, 0x002b, 0x002a,
0x002b, 0x0014, 0x001e, 0x002c, 0x0037, 0x004e, 0x0048, 0x0057,
0x004e, 0x003d, 0x002e, 0x0036, 0x0025, 0x001e, 0x0014, 0x0010,
0x0035, 0x0019, 0x0029, 0x0025, 0x002c, 0x003b, 0x0036, 0x0051,
0x0042, 0x004c, 0x0039, 0x0036, 0x0025, 0x0012, 0x0027, 0x000b,
0x0023, 0x0021, 0x001f, 0x0039, 0x002a, 0x0052, 0x0048, 0x0050,
0x002f, 0x003a, 0x0037, 0x0015, 0x0016, 0x001a, 0x0026, 0x0016,
0x0035, 0x0019, 0x0017, 0x0026, 0x0046, 0x003c, 0x0033, 0x0024,
0x0037, 0x001a, 0x0022, 0x0017, 0x001b, 0x000e, 0x0009, 0x0007,
0x0022, 0x0020, 0x001c, 0x0027, 0x0031, 0x004b, 0x001e, 0x0034,
0x0030, 0x0028, 0x0034, 0x001c, 0x0012, 0x0011, 0x0009, 0x0005,
0x002d, 0x0015, 0x0022, 0x0040, 0x0038, 0x0032, 0x0031, 0x002d,
0x001f, 0x0013, 0x000c, 0x000f, 0x000a, 0x0007, 0x0006, 0x0003,
0x0030, 0x0017, 0x0014, 0x0027, 0x0024, 0x0023, 0x0035, 0x0015,
0x0010, 0x0017, 0x000d, 0x000a, 0x0006, 0x0001, 0x0004, 0x0002,
0x0010, 0x000f, 0x0011, 0x001b, 0x0019, 0x0014, 0x001d, 0x000b,
0x0011, 0x000c, 0x0010, 0x0008, 0x0001, 0x0001, 0x0000, 0x0001,
};
static const uint8_t mpa_huffbits_13[256] = {
1, 4, 6, 7, 8, 9, 9, 10,
9, 10, 11, 11, 12, 12, 13, 13,
3, 4, 6, 7, 8, 8, 9, 9,
9, 9, 10, 10, 11, 12, 12, 12,
6, 6, 7, 8, 9, 9, 10, 10,
9, 10, 10, 11, 11, 12, 13, 13,
7, 7, 8, 9, 9, 10, 10, 10,
10, 11, 11, 11, 11, 12, 13, 13,
8, 7, 9, 9, 10, 10, 11, 11,
10, 11, 11, 12, 12, 13, 13, 14,
9, 8, 9, 10, 10, 10, 11, 11,
11, 11, 12, 11, 13, 13, 14, 14,
9, 9, 10, 10, 11, 11, 11, 11,
11, 12, 12, 12, 13, 13, 14, 14,
10, 9, 10, 11, 11, 11, 12, 12,
12, 12, 13, 13, 13, 14, 16, 16,
9, 8, 9, 10, 10, 11, 11, 12,
12, 12, 12, 13, 13, 14, 15, 15,
10, 9, 10, 10, 11, 11, 11, 13,
12, 13, 13, 14, 14, 14, 16, 15,
10, 10, 10, 11, 11, 12, 12, 13,
12, 13, 14, 13, 14, 15, 16, 17,
11, 10, 10, 11, 12, 12, 12, 12,
13, 13, 13, 14, 15, 15, 15, 16,
11, 11, 11, 12, 12, 13, 12, 13,
14, 14, 15, 15, 15, 16, 16, 16,
12, 11, 12, 13, 13, 13, 14, 14,
14, 14, 14, 15, 16, 15, 16, 16,
13, 12, 12, 13, 13, 13, 15, 14,
14, 17, 15, 15, 15, 17, 16, 16,
12, 12, 13, 14, 14, 14, 15, 14,
15, 15, 16, 16, 19, 18, 19, 16,
};
static const uint16_t mpa_huffcodes_15[256] = {
0x0007, 0x000c, 0x0012, 0x0035, 0x002f, 0x004c, 0x007c, 0x006c,
0x0059, 0x007b, 0x006c, 0x0077, 0x006b, 0x0051, 0x007a, 0x003f,
0x000d, 0x0005, 0x0010, 0x001b, 0x002e, 0x0024, 0x003d, 0x0033,
0x002a, 0x0046, 0x0034, 0x0053, 0x0041, 0x0029, 0x003b, 0x0024,
0x0013, 0x0011, 0x000f, 0x0018, 0x0029, 0x0022, 0x003b, 0x0030,
0x0028, 0x0040, 0x0032, 0x004e, 0x003e, 0x0050, 0x0038, 0x0021,
0x001d, 0x001c, 0x0019, 0x002b, 0x0027, 0x003f, 0x0037, 0x005d,
0x004c, 0x003b, 0x005d, 0x0048, 0x0036, 0x004b, 0x0032, 0x001d,
0x0034, 0x0016, 0x002a, 0x0028, 0x0043, 0x0039, 0x005f, 0x004f,
0x0048, 0x0039, 0x0059, 0x0045, 0x0031, 0x0042, 0x002e, 0x001b,
0x004d, 0x0025, 0x0023, 0x0042, 0x003a, 0x0034, 0x005b, 0x004a,
0x003e, 0x0030, 0x004f, 0x003f, 0x005a, 0x003e, 0x0028, 0x0026,
0x007d, 0x0020, 0x003c, 0x0038, 0x0032, 0x005c, 0x004e, 0x0041,
0x0037, 0x0057, 0x0047, 0x0033, 0x0049, 0x0033, 0x0046, 0x001e,
0x006d, 0x0035, 0x0031, 0x005e, 0x0058, 0x004b, 0x0042, 0x007a,
0x005b, 0x0049, 0x0038, 0x002a, 0x0040, 0x002c, 0x0015, 0x0019,
0x005a, 0x002b, 0x0029, 0x004d, 0x0049, 0x003f, 0x0038, 0x005c,
0x004d, 0x0042, 0x002f, 0x0043, 0x0030, 0x0035, 0x0024, 0x0014,
0x0047, 0x0022, 0x0043, 0x003c, 0x003a, 0x0031, 0x0058, 0x004c,
0x0043, 0x006a, 0x0047, 0x0036, 0x0026, 0x0027, 0x0017, 0x000f,
0x006d, 0x0035, 0x0033, 0x002f, 0x005a, 0x0052, 0x003a, 0x0039,
0x0030, 0x0048, 0x0039, 0x0029, 0x0017, 0x001b, 0x003e, 0x0009,
0x0056, 0x002a, 0x0028, 0x0025, 0x0046, 0x0040, 0x0034, 0x002b,
0x0046, 0x0037, 0x002a, 0x0019, 0x001d, 0x0012, 0x000b, 0x000b,
0x0076, 0x0044, 0x001e, 0x0037, 0x0032, 0x002e, 0x004a, 0x0041,
0x0031, 0x0027, 0x0018, 0x0010, 0x0016, 0x000d, 0x000e, 0x0007,
0x005b, 0x002c, 0x0027, 0x0026, 0x0022, 0x003f, 0x0034, 0x002d,
0x001f, 0x0034, 0x001c, 0x0013, 0x000e, 0x0008, 0x0009, 0x0003,
0x007b, 0x003c, 0x003a, 0x0035, 0x002f, 0x002b, 0x0020, 0x0016,
0x0025, 0x0018, 0x0011, 0x000c, 0x000f, 0x000a, 0x0002, 0x0001,
0x0047, 0x0025, 0x0022, 0x001e, 0x001c, 0x0014, 0x0011, 0x001a,
0x0015, 0x0010, 0x000a, 0x0006, 0x0008, 0x0006, 0x0002, 0x0000,
};
static const uint8_t mpa_huffbits_15[256] = {
3, 4, 5, 7, 7, 8, 9, 9,
9, 10, 10, 11, 11, 11, 12, 13,
4, 3, 5, 6, 7, 7, 8, 8,
8, 9, 9, 10, 10, 10, 11, 11,
5, 5, 5, 6, 7, 7, 8, 8,
8, 9, 9, 10, 10, 11, 11, 11,
6, 6, 6, 7, 7, 8, 8, 9,
9, 9, 10, 10, 10, 11, 11, 11,
7, 6, 7, 7, 8, 8, 9, 9,
9, 9, 10, 10, 10, 11, 11, 11,
8, 7, 7, 8, 8, 8, 9, 9,
9, 9, 10, 10, 11, 11, 11, 12,
9, 7, 8, 8, 8, 9, 9, 9,
9, 10, 10, 10, 11, 11, 12, 12,
9, 8, 8, 9, 9, 9, 9, 10,
10, 10, 10, 10, 11, 11, 11, 12,
9, 8, 8, 9, 9, 9, 9, 10,
10, 10, 10, 11, 11, 12, 12, 12,
9, 8, 9, 9, 9, 9, 10, 10,
10, 11, 11, 11, 11, 12, 12, 12,
10, 9, 9, 9, 10, 10, 10, 10,
10, 11, 11, 11, 11, 12, 13, 12,
10, 9, 9, 9, 10, 10, 10, 10,
11, 11, 11, 11, 12, 12, 12, 13,
11, 10, 9, 10, 10, 10, 11, 11,
11, 11, 11, 11, 12, 12, 13, 13,
11, 10, 10, 10, 10, 11, 11, 11,
11, 12, 12, 12, 12, 12, 13, 13,
12, 11, 11, 11, 11, 11, 11, 11,
12, 12, 12, 12, 13, 13, 12, 13,
12, 11, 11, 11, 11, 11, 11, 12,
12, 12, 12, 12, 13, 13, 13, 13,
};
static const uint16_t mpa_huffcodes_16[256] = {
0x0001, 0x0005, 0x000e, 0x002c, 0x004a, 0x003f, 0x006e, 0x005d,
0x00ac, 0x0095, 0x008a, 0x00f2, 0x00e1, 0x00c3, 0x0178, 0x0011,
0x0003, 0x0004, 0x000c, 0x0014, 0x0023, 0x003e, 0x0035, 0x002f,
0x0053, 0x004b, 0x0044, 0x0077, 0x00c9, 0x006b, 0x00cf, 0x0009,
0x000f, 0x000d, 0x0017, 0x0026, 0x0043, 0x003a, 0x0067, 0x005a,
0x00a1, 0x0048, 0x007f, 0x0075, 0x006e, 0x00d1, 0x00ce, 0x0010,
0x002d, 0x0015, 0x0027, 0x0045, 0x0040, 0x0072, 0x0063, 0x0057,
0x009e, 0x008c, 0x00fc, 0x00d4, 0x00c7, 0x0183, 0x016d, 0x001a,
0x004b, 0x0024, 0x0044, 0x0041, 0x0073, 0x0065, 0x00b3, 0x00a4,
0x009b, 0x0108, 0x00f6, 0x00e2, 0x018b, 0x017e, 0x016a, 0x0009,
0x0042, 0x001e, 0x003b, 0x0038, 0x0066, 0x00b9, 0x00ad, 0x0109,
0x008e, 0x00fd, 0x00e8, 0x0190, 0x0184, 0x017a, 0x01bd, 0x0010,
0x006f, 0x0036, 0x0034, 0x0064, 0x00b8, 0x00b2, 0x00a0, 0x0085,
0x0101, 0x00f4, 0x00e4, 0x00d9, 0x0181, 0x016e, 0x02cb, 0x000a,
0x0062, 0x0030, 0x005b, 0x0058, 0x00a5, 0x009d, 0x0094, 0x0105,
0x00f8, 0x0197, 0x018d, 0x0174, 0x017c, 0x0379, 0x0374, 0x0008,
0x0055, 0x0054, 0x0051, 0x009f, 0x009c, 0x008f, 0x0104, 0x00f9,
0x01ab, 0x0191, 0x0188, 0x017f, 0x02d7, 0x02c9, 0x02c4, 0x0007,
0x009a, 0x004c, 0x0049, 0x008d, 0x0083, 0x0100, 0x00f5, 0x01aa,
0x0196, 0x018a, 0x0180, 0x02df, 0x0167, 0x02c6, 0x0160, 0x000b,
0x008b, 0x0081, 0x0043, 0x007d, 0x00f7, 0x00e9, 0x00e5, 0x00db,
0x0189, 0x02e7, 0x02e1, 0x02d0, 0x0375, 0x0372, 0x01b7, 0x0004,
0x00f3, 0x0078, 0x0076, 0x0073, 0x00e3, 0x00df, 0x018c, 0x02ea,
0x02e6, 0x02e0, 0x02d1, 0x02c8, 0x02c2, 0x00df, 0x01b4, 0x0006,
0x00ca, 0x00e0, 0x00de, 0x00da, 0x00d8, 0x0185, 0x0182, 0x017d,
0x016c, 0x0378, 0x01bb, 0x02c3, 0x01b8, 0x01b5, 0x06c0, 0x0004,
0x02eb, 0x00d3, 0x00d2, 0x00d0, 0x0172, 0x017b, 0x02de, 0x02d3,
0x02ca, 0x06c7, 0x0373, 0x036d, 0x036c, 0x0d83, 0x0361, 0x0002,
0x0179, 0x0171, 0x0066, 0x00bb, 0x02d6, 0x02d2, 0x0166, 0x02c7,
0x02c5, 0x0362, 0x06c6, 0x0367, 0x0d82, 0x0366, 0x01b2, 0x0000,
0x000c, 0x000a, 0x0007, 0x000b, 0x000a, 0x0011, 0x000b, 0x0009,
0x000d, 0x000c, 0x000a, 0x0007, 0x0005, 0x0003, 0x0001, 0x0003,
};
static const uint8_t mpa_huffbits_16[256] = {
1, 4, 6, 8, 9, 9, 10, 10,
11, 11, 11, 12, 12, 12, 13, 9,
3, 4, 6, 7, 8, 9, 9, 9,
10, 10, 10, 11, 12, 11, 12, 8,
6, 6, 7, 8, 9, 9, 10, 10,
11, 10, 11, 11, 11, 12, 12, 9,
8, 7, 8, 9, 9, 10, 10, 10,
11, 11, 12, 12, 12, 13, 13, 10,
9, 8, 9, 9, 10, 10, 11, 11,
11, 12, 12, 12, 13, 13, 13, 9,
9, 8, 9, 9, 10, 11, 11, 12,
11, 12, 12, 13, 13, 13, 14, 10,
10, 9, 9, 10, 11, 11, 11, 11,
12, 12, 12, 12, 13, 13, 14, 10,
10, 9, 10, 10, 11, 11, 11, 12,
12, 13, 13, 13, 13, 15, 15, 10,
10, 10, 10, 11, 11, 11, 12, 12,
13, 13, 13, 13, 14, 14, 14, 10,
11, 10, 10, 11, 11, 12, 12, 13,
13, 13, 13, 14, 13, 14, 13, 11,
11, 11, 10, 11, 12, 12, 12, 12,
13, 14, 14, 14, 15, 15, 14, 10,
12, 11, 11, 11, 12, 12, 13, 14,
14, 14, 14, 14, 14, 13, 14, 11,
12, 12, 12, 12, 12, 13, 13, 13,
13, 15, 14, 14, 14, 14, 16, 11,
14, 12, 12, 12, 13, 13, 14, 14,
14, 16, 15, 15, 15, 17, 15, 11,
13, 13, 11, 12, 14, 14, 13, 14,
14, 15, 16, 15, 17, 15, 14, 11,
9, 8, 8, 9, 9, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 8,
};
static const uint16_t mpa_huffcodes_24[256] = {
0x000f, 0x000d, 0x002e, 0x0050, 0x0092, 0x0106, 0x00f8, 0x01b2,
0x01aa, 0x029d, 0x028d, 0x0289, 0x026d, 0x0205, 0x0408, 0x0058,
0x000e, 0x000c, 0x0015, 0x0026, 0x0047, 0x0082, 0x007a, 0x00d8,
0x00d1, 0x00c6, 0x0147, 0x0159, 0x013f, 0x0129, 0x0117, 0x002a,
0x002f, 0x0016, 0x0029, 0x004a, 0x0044, 0x0080, 0x0078, 0x00dd,
0x00cf, 0x00c2, 0x00b6, 0x0154, 0x013b, 0x0127, 0x021d, 0x0012,
0x0051, 0x0027, 0x004b, 0x0046, 0x0086, 0x007d, 0x0074, 0x00dc,
0x00cc, 0x00be, 0x00b2, 0x0145, 0x0137, 0x0125, 0x010f, 0x0010,
0x0093, 0x0048, 0x0045, 0x0087, 0x007f, 0x0076, 0x0070, 0x00d2,
0x00c8, 0x00bc, 0x0160, 0x0143, 0x0132, 0x011d, 0x021c, 0x000e,
0x0107, 0x0042, 0x0081, 0x007e, 0x0077, 0x0072, 0x00d6, 0x00ca,
0x00c0, 0x00b4, 0x0155, 0x013d, 0x012d, 0x0119, 0x0106, 0x000c,
0x00f9, 0x007b, 0x0079, 0x0075, 0x0071, 0x00d7, 0x00ce, 0x00c3,
0x00b9, 0x015b, 0x014a, 0x0134, 0x0123, 0x0110, 0x0208, 0x000a,
0x01b3, 0x0073, 0x006f, 0x006d, 0x00d3, 0x00cb, 0x00c4, 0x00bb,
0x0161, 0x014c, 0x0139, 0x012a, 0x011b, 0x0213, 0x017d, 0x0011,
0x01ab, 0x00d4, 0x00d0, 0x00cd, 0x00c9, 0x00c1, 0x00ba, 0x00b1,
0x00a9, 0x0140, 0x012f, 0x011e, 0x010c, 0x0202, 0x0179, 0x0010,
0x014f, 0x00c7, 0x00c5, 0x00bf, 0x00bd, 0x00b5, 0x00ae, 0x014d,
0x0141, 0x0131, 0x0121, 0x0113, 0x0209, 0x017b, 0x0173, 0x000b,
0x029c, 0x00b8, 0x00b7, 0x00b3, 0x00af, 0x0158, 0x014b, 0x013a,
0x0130, 0x0122, 0x0115, 0x0212, 0x017f, 0x0175, 0x016e, 0x000a,
0x028c, 0x015a, 0x00ab, 0x00a8, 0x00a4, 0x013e, 0x0135, 0x012b,
0x011f, 0x0114, 0x0107, 0x0201, 0x0177, 0x0170, 0x016a, 0x0006,
0x0288, 0x0142, 0x013c, 0x0138, 0x0133, 0x012e, 0x0124, 0x011c,
0x010d, 0x0105, 0x0200, 0x0178, 0x0172, 0x016c, 0x0167, 0x0004,
0x026c, 0x012c, 0x0128, 0x0126, 0x0120, 0x011a, 0x0111, 0x010a,
0x0203, 0x017c, 0x0176, 0x0171, 0x016d, 0x0169, 0x0165, 0x0002,
0x0409, 0x0118, 0x0116, 0x0112, 0x010b, 0x0108, 0x0103, 0x017e,
0x017a, 0x0174, 0x016f, 0x016b, 0x0168, 0x0166, 0x0164, 0x0000,
0x002b, 0x0014, 0x0013, 0x0011, 0x000f, 0x000d, 0x000b, 0x0009,
0x0007, 0x0006, 0x0004, 0x0007, 0x0005, 0x0003, 0x0001, 0x0003,
};
static const uint8_t mpa_huffbits_24[256] = {
4, 4, 6, 7, 8, 9, 9, 10,
10, 11, 11, 11, 11, 11, 12, 9,
4, 4, 5, 6, 7, 8, 8, 9,
9, 9, 10, 10, 10, 10, 10, 8,
6, 5, 6, 7, 7, 8, 8, 9,
9, 9, 9, 10, 10, 10, 11, 7,
7, 6, 7, 7, 8, 8, 8, 9,
9, 9, 9, 10, 10, 10, 10, 7,
8, 7, 7, 8, 8, 8, 8, 9,
9, 9, 10, 10, 10, 10, 11, 7,
9, 7, 8, 8, 8, 8, 9, 9,
9, 9, 10, 10, 10, 10, 10, 7,
9, 8, 8, 8, 8, 9, 9, 9,
9, 10, 10, 10, 10, 10, 11, 7,
10, 8, 8, 8, 9, 9, 9, 9,
10, 10, 10, 10, 10, 11, 11, 8,
10, 9, 9, 9, 9, 9, 9, 9,
9, 10, 10, 10, 10, 11, 11, 8,
10, 9, 9, 9, 9, 9, 9, 10,
10, 10, 10, 10, 11, 11, 11, 8,
11, 9, 9, 9, 9, 10, 10, 10,
10, 10, 10, 11, 11, 11, 11, 8,
11, 10, 9, 9, 9, 10, 10, 10,
10, 10, 10, 11, 11, 11, 11, 8,
11, 10, 10, 10, 10, 10, 10, 10,
10, 10, 11, 11, 11, 11, 11, 8,
11, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 8,
12, 10, 10, 10, 10, 10, 10, 11,
11, 11, 11, 11, 11, 11, 11, 8,
8, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 8, 8, 8, 8, 4,
};
static const HuffTable mpa_huff_tables[16] = {
{ 1, NULL, NULL },
{ 2, mpa_huffbits_1, mpa_huffcodes_1 },
{ 3, mpa_huffbits_2, mpa_huffcodes_2 },
{ 3, mpa_huffbits_3, mpa_huffcodes_3 },
{ 4, mpa_huffbits_5, mpa_huffcodes_5 },
{ 4, mpa_huffbits_6, mpa_huffcodes_6 },
{ 6, mpa_huffbits_7, mpa_huffcodes_7 },
{ 6, mpa_huffbits_8, mpa_huffcodes_8 },
{ 6, mpa_huffbits_9, mpa_huffcodes_9 },
{ 8, mpa_huffbits_10, mpa_huffcodes_10 },
{ 8, mpa_huffbits_11, mpa_huffcodes_11 },
{ 8, mpa_huffbits_12, mpa_huffcodes_12 },
{ 16, mpa_huffbits_13, mpa_huffcodes_13 },
{ 16, mpa_huffbits_15, mpa_huffcodes_15 },
{ 16, mpa_huffbits_16, mpa_huffcodes_16 },
{ 16, mpa_huffbits_24, mpa_huffcodes_24 },
};
static const uint8_t mpa_huff_data[32][2] = {
{ 0, 0 },
{ 1, 0 },
{ 2, 0 },
{ 3, 0 },
{ 0, 0 },
{ 4, 0 },
{ 5, 0 },
{ 6, 0 },
{ 7, 0 },
{ 8, 0 },
{ 9, 0 },
{ 10, 0 },
{ 11, 0 },
{ 12, 0 },
{ 0, 0 },
{ 13, 0 },
{ 14, 1 },
{ 14, 2 },
{ 14, 3 },
{ 14, 4 },
{ 14, 6 },
{ 14, 8 },
{ 14, 10 },
{ 14, 13 },
{ 15, 4 },
{ 15, 5 },
{ 15, 6 },
{ 15, 7 },
{ 15, 8 },
{ 15, 9 },
{ 15, 11 },
{ 15, 13 },
};
/* huffman tables for quadrules */
static const uint8_t mpa_quad_codes[2][16] = {
{ 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1, },
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, },
};
static const uint8_t mpa_quad_bits[2][16] = {
{ 1, 4, 4, 5, 4, 6, 5, 6, 4, 5, 5, 6, 5, 6, 6, 6, },
{ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, },
};
/* band size tables */
static const uint8_t band_size_long[9][22] = {
{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10,
12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158, }, /* 44100 */
{ 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10,
12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192, }, /* 48000 */
{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12,
16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26, }, /* 32000 */
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16,
20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 22050 */
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16,
18, 22, 26, 32, 38, 46, 52, 64, 70, 76, 36, }, /* 24000 */
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16,
20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 16000 */
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16,
20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 11025 */
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16,
20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 12000 */
{ 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32,
40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2, }, /* 8000 */
};
static const uint8_t band_size_short[9][13] = {
{ 4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56, }, /* 44100 */
{ 4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66, }, /* 48000 */
{ 4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12, }, /* 32000 */
{ 4, 4, 4, 6, 6, 8, 10, 14, 18, 26, 32, 42, 18, }, /* 22050 */
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 32, 44, 12, }, /* 24000 */
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 16000 */
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 11025 */
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 12000 */
{ 8, 8, 8, 12, 16, 20, 24, 28, 36, 2, 2, 2, 26, }, /* 8000 */
};
static const uint8_t mpa_pretab[2][22] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 },
};
/* table for alias reduction (XXX: store it as integer !) */
static const float ci_table[8] = {
-0.6, -0.535, -0.33, -0.185, -0.095, -0.041, -0.0142, -0.0037,
};
#endif /* AVCODEC_MPEGAUDIODECTAB_H */

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2011 Mans Rullgard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "libavutil/attributes.h"
#include "libavutil/thread.h"
#include "mpegaudiodsp.h"
#include "dct.h"
#include "dct32.h"
static AVOnce mpadsp_float_table_init = AV_ONCE_INIT;
static AVOnce mpadsp_fixed_table_init = AV_ONCE_INIT;
av_cold void ff_mpadsp_init(MPADSPContext *s)
{
DCTContext dct;
ff_dct_init(&dct, 5, DCT_II);
ff_thread_once(&mpadsp_float_table_init, &ff_init_mpadsp_tabs_float);
ff_thread_once(&mpadsp_fixed_table_init, &ff_init_mpadsp_tabs_fixed);
s->apply_window_float = ff_mpadsp_apply_window_float;
s->apply_window_fixed = ff_mpadsp_apply_window_fixed;
s->dct32_float = dct.dct32;
s->dct32_fixed = ff_dct32_fixed;
s->imdct36_blocks_float = ff_imdct36_blocks_float;
s->imdct36_blocks_fixed = ff_imdct36_blocks_fixed;
if (ARCH_AARCH64) ff_mpadsp_init_aarch64(s);
if (ARCH_ARM) ff_mpadsp_init_arm(s);
if (ARCH_PPC) ff_mpadsp_init_ppc(s);
if (ARCH_X86) ff_mpadsp_init_x86(s);
if (HAVE_MIPSFPU) ff_mpadsp_init_mipsfpu(s);
if (HAVE_MIPSDSP) ff_mpadsp_init_mipsdsp(s);
}

View File

@ -0,0 +1,94 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MPEGAUDIODSP_H
#define AVCODEC_MPEGAUDIODSP_H
#include <stddef.h>
#include <stdint.h>
#include "libavutil/common.h"
typedef struct MPADSPContext {
void (*apply_window_float)(float *synth_buf, float *window,
int *dither_state, float *samples,
ptrdiff_t incr);
void (*apply_window_fixed)(int32_t *synth_buf, int32_t *window,
int *dither_state, int16_t *samples,
ptrdiff_t incr);
void (*dct32_float)(float *dst, const float *src);
void (*dct32_fixed)(int *dst, const int *src);
void (*imdct36_blocks_float)(float *out, float *buf, float *in,
int count, int switch_point, int block_type);
void (*imdct36_blocks_fixed)(int *out, int *buf, int *in,
int count, int switch_point, int block_type);
} MPADSPContext;
void ff_mpadsp_init(MPADSPContext *s);
extern int32_t ff_mpa_synth_window_fixed[];
extern float ff_mpa_synth_window_float[];
extern const int32_t ff_mpa_enwindow[257];
void ff_mpa_synth_filter_fixed(MPADSPContext *s,
int32_t *synth_buf_ptr, int *synth_buf_offset,
int32_t *window, int *dither_state,
int16_t *samples, ptrdiff_t incr,
int32_t *sb_samples);
void ff_mpa_synth_filter_float(MPADSPContext *s,
float *synth_buf_ptr, int *synth_buf_offset,
float *window, int *dither_state,
float *samples, ptrdiff_t incr,
float *sb_samples);
void ff_mpadsp_init_aarch64(MPADSPContext *s);
void ff_mpadsp_init_arm(MPADSPContext *s);
void ff_mpadsp_init_ppc(MPADSPContext *s);
void ff_mpadsp_init_x86(MPADSPContext *s);
void ff_mpadsp_init_mipsfpu(MPADSPContext *s);
void ff_mpadsp_init_mipsdsp(MPADSPContext *s);
void ff_mpa_synth_init_float(float *window);
void ff_mpa_synth_init_fixed(int32_t *window);
void ff_mpadsp_apply_window_float(float *synth_buf, float *window,
int *dither_state, float *samples,
ptrdiff_t incr);
void ff_mpadsp_apply_window_fixed(int32_t *synth_buf, int32_t *window,
int *dither_state, int16_t *samples,
ptrdiff_t incr);
void ff_imdct36_blocks_float(float *out, float *buf, float *in,
int count, int switch_point, int block_type);
void ff_imdct36_blocks_fixed(int *out, int *buf, int *in,
int count, int switch_point, int block_type);
void ff_init_mpadsp_tabs_float(void);
void ff_init_mpadsp_tabs_fixed(void);
/** For SSE implementation, MDCT_BUF_SIZE/2 should be 128-bit aligned */
#define MDCT_BUF_SIZE FFALIGN(36, 2*4)
extern int ff_mdct_win_fixed[8][MDCT_BUF_SIZE];
extern float ff_mdct_win_float[8][MDCT_BUF_SIZE];
#endif /* AVCODEC_MPEGAUDIODSP_H */

View File

@ -0,0 +1,56 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mpegaudiodsp.h"
/* half mpeg encoding window (full precision) */
const int32_t ff_mpa_enwindow[257] = {
0, -1, -1, -1, -1, -1, -1, -2,
-2, -2, -2, -3, -3, -4, -4, -5,
-5, -6, -7, -7, -8, -9, -10, -11,
-13, -14, -16, -17, -19, -21, -24, -26,
-29, -31, -35, -38, -41, -45, -49, -53,
-58, -63, -68, -73, -79, -85, -91, -97,
-104, -111, -117, -125, -132, -139, -147, -154,
-161, -169, -176, -183, -190, -196, -202, -208,
213, 218, 222, 225, 227, 228, 228, 227,
224, 221, 215, 208, 200, 189, 177, 163,
146, 127, 106, 83, 57, 29, -2, -36,
-72, -111, -153, -197, -244, -294, -347, -401,
-459, -519, -581, -645, -711, -779, -848, -919,
-991, -1064, -1137, -1210, -1283, -1356, -1428, -1498,
-1567, -1634, -1698, -1759, -1817, -1870, -1919, -1962,
-2001, -2032, -2057, -2075, -2085, -2087, -2080, -2063,
2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535,
1414, 1280, 1131, 970, 794, 605, 402, 185,
-45, -288, -545, -814, -1095, -1388, -1692, -2006,
-2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
-5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597,
-7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585,
-9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750,
-9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134,
6574, 5959, 5288, 4561, 3776, 2935, 2037, 1082,
70, -998, -2122, -3300, -4533, -5818, -7154, -8540,
-9975,-11455,-12980,-14548,-16155,-17799,-19478,-21189,
-22929,-24694,-26482,-28289,-30112,-31947,-33791,-35640,
-37489,-39336,-41176,-43006,-44821,-46617,-48390,-50137,
-51853,-53534,-55178,-56778,-58333,-59838,-61289,-62684,
-64019,-65290,-66494,-67629,-68692,-69679,-70590,-71420,
-72169,-72835,-73415,-73908,-74313,-74630,-74856,-74992,
75038,
};

View File

@ -0,0 +1,20 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define USE_FLOATS 0
#include "mpegaudiodsp_template.c"

View File

@ -0,0 +1,20 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define USE_FLOATS 1
#include "mpegaudiodsp_template.c"

View File

@ -0,0 +1,401 @@
/*
* Copyright (c) 2001, 2002 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include "libavutil/attributes.h"
#include "libavutil/mem.h"
#include "dct32.h"
#include "mathops.h"
#include "mpegaudiodsp.h"
#include "mpegaudio.h"
#if USE_FLOATS
#define RENAME(n) n##_float
static inline float round_sample(float *sum)
{
float sum1=*sum;
*sum = 0;
return sum1;
}
#define MACS(rt, ra, rb) rt+=(ra)*(rb)
#define MULS(ra, rb) ((ra)*(rb))
#define MULH3(x, y, s) ((s)*(y)*(x))
#define MLSS(rt, ra, rb) rt-=(ra)*(rb)
#define MULLx(x, y, s) ((y)*(x))
#define FIXHR(x) ((float)(x))
#define FIXR(x) ((float)(x))
#define SHR(a,b) ((a)*(1.0f/(1<<(b))))
#else
#define RENAME(n) n##_fixed
#define OUT_SHIFT (WFRAC_BITS + FRAC_BITS - 15)
static inline int round_sample(int64_t *sum)
{
int sum1;
sum1 = (int)((*sum) >> OUT_SHIFT);
*sum &= (1<<OUT_SHIFT)-1;
return av_clip_int16(sum1);
}
# define MULS(ra, rb) MUL64(ra, rb)
# define MACS(rt, ra, rb) MAC64(rt, ra, rb)
# define MLSS(rt, ra, rb) MLS64(rt, ra, rb)
# define MULH3(x, y, s) MULH((s)*(x), y)
# define MULLx(x, y, s) MULL((int)(x),(y),s)
# define SHR(a,b) (((int)(a))>>(b))
# define FIXR(a) ((int)((a) * FRAC_ONE + 0.5))
# define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5))
#endif
/** Window for MDCT. Actually only the elements in [0,17] and
[MDCT_BUF_SIZE/2, MDCT_BUF_SIZE/2 + 17] are actually used. The rest
is just to preserve alignment for SIMD implementations.
*/
DECLARE_ALIGNED(16, INTFLOAT, RENAME(ff_mdct_win))[8][MDCT_BUF_SIZE];
DECLARE_ALIGNED(16, MPA_INT, RENAME(ff_mpa_synth_window))[512+256];
#define SUM8(op, sum, w, p) \
{ \
op(sum, (w)[0 * 64], (p)[0 * 64]); \
op(sum, (w)[1 * 64], (p)[1 * 64]); \
op(sum, (w)[2 * 64], (p)[2 * 64]); \
op(sum, (w)[3 * 64], (p)[3 * 64]); \
op(sum, (w)[4 * 64], (p)[4 * 64]); \
op(sum, (w)[5 * 64], (p)[5 * 64]); \
op(sum, (w)[6 * 64], (p)[6 * 64]); \
op(sum, (w)[7 * 64], (p)[7 * 64]); \
}
#define SUM8P2(sum1, op1, sum2, op2, w1, w2, p) \
{ \
INTFLOAT tmp;\
tmp = p[0 * 64];\
op1(sum1, (w1)[0 * 64], tmp);\
op2(sum2, (w2)[0 * 64], tmp);\
tmp = p[1 * 64];\
op1(sum1, (w1)[1 * 64], tmp);\
op2(sum2, (w2)[1 * 64], tmp);\
tmp = p[2 * 64];\
op1(sum1, (w1)[2 * 64], tmp);\
op2(sum2, (w2)[2 * 64], tmp);\
tmp = p[3 * 64];\
op1(sum1, (w1)[3 * 64], tmp);\
op2(sum2, (w2)[3 * 64], tmp);\
tmp = p[4 * 64];\
op1(sum1, (w1)[4 * 64], tmp);\
op2(sum2, (w2)[4 * 64], tmp);\
tmp = p[5 * 64];\
op1(sum1, (w1)[5 * 64], tmp);\
op2(sum2, (w2)[5 * 64], tmp);\
tmp = p[6 * 64];\
op1(sum1, (w1)[6 * 64], tmp);\
op2(sum2, (w2)[6 * 64], tmp);\
tmp = p[7 * 64];\
op1(sum1, (w1)[7 * 64], tmp);\
op2(sum2, (w2)[7 * 64], tmp);\
}
void RENAME(ff_mpadsp_apply_window)(MPA_INT *synth_buf, MPA_INT *window,
int *dither_state, OUT_INT *samples,
ptrdiff_t incr)
{
register const MPA_INT *w, *w2, *p;
int j;
OUT_INT *samples2;
#if USE_FLOATS
float sum, sum2;
#else
int64_t sum, sum2;
#endif
/* copy to avoid wrap */
memcpy(synth_buf + 512, synth_buf, 32 * sizeof(*synth_buf));
samples2 = samples + 31 * incr;
w = window;
w2 = window + 31;
sum = *dither_state;
p = synth_buf + 16;
SUM8(MACS, sum, w, p);
p = synth_buf + 48;
SUM8(MLSS, sum, w + 32, p);
*samples = round_sample(&sum);
samples += incr;
w++;
/* we calculate two samples at the same time to avoid one memory
access per two sample */
for(j=1;j<16;j++) {
sum2 = 0;
p = synth_buf + 16 + j;
SUM8P2(sum, MACS, sum2, MLSS, w, w2, p);
p = synth_buf + 48 - j;
SUM8P2(sum, MLSS, sum2, MLSS, w + 32, w2 + 32, p);
*samples = round_sample(&sum);
samples += incr;
sum += sum2;
*samples2 = round_sample(&sum);
samples2 -= incr;
w++;
w2--;
}
p = synth_buf + 32;
SUM8(MLSS, sum, w + 32, p);
*samples = round_sample(&sum);
*dither_state= sum;
}
/* 32 sub band synthesis filter. Input: 32 sub band samples, Output:
32 samples. */
void RENAME(ff_mpa_synth_filter)(MPADSPContext *s, MPA_INT *synth_buf_ptr,
int *synth_buf_offset,
MPA_INT *window, int *dither_state,
OUT_INT *samples, ptrdiff_t incr,
MPA_INT *sb_samples)
{
MPA_INT *synth_buf;
int offset;
offset = *synth_buf_offset;
synth_buf = synth_buf_ptr + offset;
s->RENAME(dct32)(synth_buf, sb_samples);
s->RENAME(apply_window)(synth_buf, window, dither_state, samples, incr);
offset = (offset - 32) & 511;
*synth_buf_offset = offset;
}
av_cold void RENAME(ff_mpa_synth_init)(MPA_INT *window)
{
int i, j;
/* max = 18760, max sum over all 16 coefs : 44736 */
for(i=0;i<257;i++) {
INTFLOAT v;
v = ff_mpa_enwindow[i];
#if USE_FLOATS
v *= 1.0 / (1LL<<(16 + FRAC_BITS));
#endif
window[i] = v;
if ((i & 63) != 0)
v = -v;
if (i != 0)
window[512 - i] = v;
}
// Needed for avoiding shuffles in ASM implementations
for(i=0; i < 8; i++)
for(j=0; j < 16; j++)
window[512+16*i+j] = window[64*i+32-j];
for(i=0; i < 8; i++)
for(j=0; j < 16; j++)
window[512+128+16*i+j] = window[64*i+48-j];
}
av_cold void RENAME(ff_init_mpadsp_tabs)(void)
{
int i, j;
/* compute mdct windows */
for (i = 0; i < 36; i++) {
for (j = 0; j < 4; j++) {
double d;
if (j == 2 && i % 3 != 1)
continue;
d = sin(M_PI * (i + 0.5) / 36.0);
if (j == 1) {
if (i >= 30) d = 0;
else if (i >= 24) d = sin(M_PI * (i - 18 + 0.5) / 12.0);
else if (i >= 18) d = 1;
} else if (j == 3) {
if (i < 6) d = 0;
else if (i < 12) d = sin(M_PI * (i - 6 + 0.5) / 12.0);
else if (i < 18) d = 1;
}
//merge last stage of imdct into the window coefficients
d *= 0.5 * IMDCT_SCALAR / cos(M_PI * (2 * i + 19) / 72);
if (j == 2)
RENAME(ff_mdct_win)[j][i/3] = FIXHR((d / (1<<5)));
else {
int idx = i < 18 ? i : i + (MDCT_BUF_SIZE/2 - 18);
RENAME(ff_mdct_win)[j][idx] = FIXHR((d / (1<<5)));
}
}
}
/* NOTE: we do frequency inversion adter the MDCT by changing
the sign of the right window coefs */
for (j = 0; j < 4; j++) {
for (i = 0; i < MDCT_BUF_SIZE; i += 2) {
RENAME(ff_mdct_win)[j + 4][i ] = RENAME(ff_mdct_win)[j][i ];
RENAME(ff_mdct_win)[j + 4][i + 1] = -RENAME(ff_mdct_win)[j][i + 1];
}
}
}
/* cos(pi*i/18) */
#define C1 FIXHR(0.98480775301220805936/2)
#define C2 FIXHR(0.93969262078590838405/2)
#define C3 FIXHR(0.86602540378443864676/2)
#define C4 FIXHR(0.76604444311897803520/2)
#define C5 FIXHR(0.64278760968653932632/2)
#define C6 FIXHR(0.5/2)
#define C7 FIXHR(0.34202014332566873304/2)
#define C8 FIXHR(0.17364817766693034885/2)
/* 0.5 / cos(pi*(2*i+1)/36) */
static const INTFLOAT icos36[9] = {
FIXR(0.50190991877167369479),
FIXR(0.51763809020504152469), //0
FIXR(0.55168895948124587824),
FIXR(0.61038729438072803416),
FIXR(0.70710678118654752439), //1
FIXR(0.87172339781054900991),
FIXR(1.18310079157624925896),
FIXR(1.93185165257813657349), //2
FIXR(5.73685662283492756461),
};
/* 0.5 / cos(pi*(2*i+1)/36) */
static const INTFLOAT icos36h[9] = {
FIXHR(0.50190991877167369479/2),
FIXHR(0.51763809020504152469/2), //0
FIXHR(0.55168895948124587824/2),
FIXHR(0.61038729438072803416/2),
FIXHR(0.70710678118654752439/2), //1
FIXHR(0.87172339781054900991/2),
FIXHR(1.18310079157624925896/4),
FIXHR(1.93185165257813657349/4), //2
// FIXHR(5.73685662283492756461),
};
/* using Lee like decomposition followed by hand coded 9 points DCT */
static void imdct36(INTFLOAT *out, INTFLOAT *buf, SUINTFLOAT *in, INTFLOAT *win)
{
int i, j;
SUINTFLOAT t0, t1, t2, t3, s0, s1, s2, s3;
SUINTFLOAT tmp[18], *tmp1, *in1;
for (i = 17; i >= 1; i--)
in[i] += in[i-1];
for (i = 17; i >= 3; i -= 2)
in[i] += in[i-2];
for (j = 0; j < 2; j++) {
tmp1 = tmp + j;
in1 = in + j;
t2 = in1[2*4] + in1[2*8] - in1[2*2];
t3 = in1[2*0] + SHR(in1[2*6],1);
t1 = in1[2*0] - in1[2*6];
tmp1[ 6] = t1 - SHR(t2,1);
tmp1[16] = t1 + t2;
t0 = MULH3(in1[2*2] + in1[2*4] , C2, 2);
t1 = MULH3(in1[2*4] - in1[2*8] , -2*C8, 1);
t2 = MULH3(in1[2*2] + in1[2*8] , -C4, 2);
tmp1[10] = t3 - t0 - t2;
tmp1[ 2] = t3 + t0 + t1;
tmp1[14] = t3 + t2 - t1;
tmp1[ 4] = MULH3(in1[2*5] + in1[2*7] - in1[2*1], -C3, 2);
t2 = MULH3(in1[2*1] + in1[2*5], C1, 2);
t3 = MULH3(in1[2*5] - in1[2*7], -2*C7, 1);
t0 = MULH3(in1[2*3], C3, 2);
t1 = MULH3(in1[2*1] + in1[2*7], -C5, 2);
tmp1[ 0] = t2 + t3 + t0;
tmp1[12] = t2 + t1 - t0;
tmp1[ 8] = t3 - t1 - t0;
}
i = 0;
for (j = 0; j < 4; j++) {
t0 = tmp[i];
t1 = tmp[i + 2];
s0 = t1 + t0;
s2 = t1 - t0;
t2 = tmp[i + 1];
t3 = tmp[i + 3];
s1 = MULH3(t3 + t2, icos36h[ j], 2);
s3 = MULLx(t3 - t2, icos36 [8 - j], FRAC_BITS);
t0 = s0 + s1;
t1 = s0 - s1;
out[(9 + j) * SBLIMIT] = MULH3(t1, win[ 9 + j], 1) + buf[4*(9 + j)];
out[(8 - j) * SBLIMIT] = MULH3(t1, win[ 8 - j], 1) + buf[4*(8 - j)];
buf[4 * ( 9 + j )] = MULH3(t0, win[MDCT_BUF_SIZE/2 + 9 + j], 1);
buf[4 * ( 8 - j )] = MULH3(t0, win[MDCT_BUF_SIZE/2 + 8 - j], 1);
t0 = s2 + s3;
t1 = s2 - s3;
out[(9 + 8 - j) * SBLIMIT] = MULH3(t1, win[ 9 + 8 - j], 1) + buf[4*(9 + 8 - j)];
out[ j * SBLIMIT] = MULH3(t1, win[ j], 1) + buf[4*( j)];
buf[4 * ( 9 + 8 - j )] = MULH3(t0, win[MDCT_BUF_SIZE/2 + 9 + 8 - j], 1);
buf[4 * ( j )] = MULH3(t0, win[MDCT_BUF_SIZE/2 + j], 1);
i += 4;
}
s0 = tmp[16];
s1 = MULH3(tmp[17], icos36h[4], 2);
t0 = s0 + s1;
t1 = s0 - s1;
out[(9 + 4) * SBLIMIT] = MULH3(t1, win[ 9 + 4], 1) + buf[4*(9 + 4)];
out[(8 - 4) * SBLIMIT] = MULH3(t1, win[ 8 - 4], 1) + buf[4*(8 - 4)];
buf[4 * ( 9 + 4 )] = MULH3(t0, win[MDCT_BUF_SIZE/2 + 9 + 4], 1);
buf[4 * ( 8 - 4 )] = MULH3(t0, win[MDCT_BUF_SIZE/2 + 8 - 4], 1);
}
void RENAME(ff_imdct36_blocks)(INTFLOAT *out, INTFLOAT *buf, INTFLOAT *in,
int count, int switch_point, int block_type)
{
int j;
for (j=0 ; j < count; j++) {
/* apply window & overlap with previous buffer */
/* select window */
int win_idx = (switch_point && j < 2) ? 0 : block_type;
INTFLOAT *win = RENAME(ff_mdct_win)[win_idx + (4 & -(j & 1))];
imdct36(out, buf, in, win);
in += 18;
buf += ((j&3) != 3 ? 1 : (72-3));
out++;
}
}

View File

@ -0,0 +1,41 @@
/*
* The simplest mpeg audio layer 2 encoder
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mpegaudioenc_template.c"
AVCodec ff_mp2fixed_encoder = {
.name = "mp2fixed",
.long_name = NULL_IF_CONFIG_SMALL("MP2 fixed point (MPEG audio layer 2)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP2,
.priv_data_size = sizeof(MpegAudioContext),
.init = MPA_encode_init,
.encode2 = MPA_encode_frame,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
.supported_samplerates = (const int[]){
44100, 48000, 32000, 22050, 24000, 16000, 0
},
.channel_layouts = (const uint64_t[]){ AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_STEREO,
0 },
.defaults = mp2_defaults,
};

View File

@ -0,0 +1,42 @@
/*
* The simplest mpeg audio layer 2 encoder
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define USE_FLOATS 1
#include "mpegaudioenc_template.c"
AVCodec ff_mp2_encoder = {
.name = "mp2",
.long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
.type = AVMEDIA_TYPE_AUDIO,
.id = AV_CODEC_ID_MP2,
.priv_data_size = sizeof(MpegAudioContext),
.init = MPA_encode_init,
.encode2 = MPA_encode_frame,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
.supported_samplerates = (const int[]){
44100, 48000, 32000, 22050, 24000, 16000, 0
},
.channel_layouts = (const uint64_t[]){ AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_STEREO,
0 },
.defaults = mp2_defaults,
};

View File

@ -0,0 +1,785 @@
/*
* The simplest mpeg audio layer 2 encoder
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* The simplest mpeg audio layer 2 encoder.
*/
#include "libavutil/channel_layout.h"
#include "avcodec.h"
#include "internal.h"
#include "put_bits.h"
#define FRAC_BITS 15 /* fractional bits for sb_samples and dct */
#define WFRAC_BITS 14 /* fractional bits for window */
#include "mpegaudio.h"
#include "mpegaudiodsp.h"
#include "mpegaudiodata.h"
#include "mpegaudiotab.h"
/* currently, cannot change these constants (need to modify
quantization stage) */
#define MUL(a,b) (((int64_t)(a) * (int64_t)(b)) >> FRAC_BITS)
#define SAMPLES_BUF_SIZE 4096
typedef struct MpegAudioContext {
PutBitContext pb;
int nb_channels;
int lsf; /* 1 if mpeg2 low bitrate selected */
int bitrate_index; /* bit rate */
int freq_index;
int frame_size; /* frame size, in bits, without padding */
/* padding computation */
int frame_frac, frame_frac_incr, do_padding;
short samples_buf[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */
int samples_offset[MPA_MAX_CHANNELS]; /* offset in samples_buf */
int sb_samples[MPA_MAX_CHANNELS][3][12][SBLIMIT];
unsigned char scale_factors[MPA_MAX_CHANNELS][SBLIMIT][3]; /* scale factors */
/* code to group 3 scale factors */
unsigned char scale_code[MPA_MAX_CHANNELS][SBLIMIT];
int sblimit; /* number of used subbands */
const unsigned char *alloc_table;
int16_t filter_bank[512];
int scale_factor_table[64];
unsigned char scale_diff_table[128];
#if USE_FLOATS
float scale_factor_inv_table[64];
#else
int8_t scale_factor_shift[64];
unsigned short scale_factor_mult[64];
#endif
unsigned short total_quant_bits[17]; /* total number of bits per allocation group */
} MpegAudioContext;
static av_cold int MPA_encode_init(AVCodecContext *avctx)
{
MpegAudioContext *s = avctx->priv_data;
int freq = avctx->sample_rate;
int bitrate = avctx->bit_rate;
int channels = avctx->channels;
int i, v, table;
float a;
if (channels <= 0 || channels > 2){
av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed in mp2\n", channels);
return AVERROR(EINVAL);
}
bitrate = bitrate / 1000;
s->nb_channels = channels;
avctx->frame_size = MPA_FRAME_SIZE;
avctx->initial_padding = 512 - 32 + 1;
/* encoding freq */
s->lsf = 0;
for(i=0;i<3;i++) {
if (avpriv_mpa_freq_tab[i] == freq)
break;
if ((avpriv_mpa_freq_tab[i] / 2) == freq) {
s->lsf = 1;
break;
}
}
if (i == 3){
av_log(avctx, AV_LOG_ERROR, "Sampling rate %d is not allowed in mp2\n", freq);
return AVERROR(EINVAL);
}
s->freq_index = i;
/* encoding bitrate & frequency */
for(i=1;i<15;i++) {
if (avpriv_mpa_bitrate_tab[s->lsf][1][i] == bitrate)
break;
}
if (i == 15 && !avctx->bit_rate) {
i = 14;
bitrate = avpriv_mpa_bitrate_tab[s->lsf][1][i];
avctx->bit_rate = bitrate * 1000;
}
if (i == 15){
av_log(avctx, AV_LOG_ERROR, "bitrate %d is not allowed in mp2\n", bitrate);
return AVERROR(EINVAL);
}
s->bitrate_index = i;
/* compute total header size & pad bit */
a = (float)(bitrate * 1000 * MPA_FRAME_SIZE) / (freq * 8.0);
s->frame_size = ((int)a) * 8;
/* frame fractional size to compute padding */
s->frame_frac = 0;
s->frame_frac_incr = (int)((a - floor(a)) * 65536.0);
/* select the right allocation table */
table = ff_mpa_l2_select_table(bitrate, s->nb_channels, freq, s->lsf);
/* number of used subbands */
s->sblimit = ff_mpa_sblimit_table[table];
s->alloc_table = ff_mpa_alloc_tables[table];
ff_dlog(avctx, "%d kb/s, %d Hz, frame_size=%d bits, table=%d, padincr=%x\n",
bitrate, freq, s->frame_size, table, s->frame_frac_incr);
for(i=0;i<s->nb_channels;i++)
s->samples_offset[i] = 0;
for(i=0;i<257;i++) {
int v;
v = ff_mpa_enwindow[i];
#if WFRAC_BITS != 16
v = (v + (1 << (16 - WFRAC_BITS - 1))) >> (16 - WFRAC_BITS);
#endif
s->filter_bank[i] = v;
if ((i & 63) != 0)
v = -v;
if (i != 0)
s->filter_bank[512 - i] = v;
}
for(i=0;i<64;i++) {
v = (int)(exp2((3 - i) / 3.0) * (1 << 20));
if (v <= 0)
v = 1;
s->scale_factor_table[i] = v;
#if USE_FLOATS
s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20);
#else
#define P 15
s->scale_factor_shift[i] = 21 - P - (i / 3);
s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0);
#endif
}
for(i=0;i<128;i++) {
v = i - 64;
if (v <= -3)
v = 0;
else if (v < 0)
v = 1;
else if (v == 0)
v = 2;
else if (v < 3)
v = 3;
else
v = 4;
s->scale_diff_table[i] = v;
}
for(i=0;i<17;i++) {
v = ff_mpa_quant_bits[i];
if (v < 0)
v = -v;
else
v = v * 3;
s->total_quant_bits[i] = 12 * v;
}
return 0;
}
/* 32 point floating point IDCT without 1/sqrt(2) coef zero scaling */
static void idct32(int *out, int *tab)
{
int i, j;
int *t, *t1, xr;
const int *xp = costab32;
for(j=31;j>=3;j-=2) tab[j] += tab[j - 2];
t = tab + 30;
t1 = tab + 2;
do {
t[0] += t[-4];
t[1] += t[1 - 4];
t -= 4;
} while (t != t1);
t = tab + 28;
t1 = tab + 4;
do {
t[0] += t[-8];
t[1] += t[1-8];
t[2] += t[2-8];
t[3] += t[3-8];
t -= 8;
} while (t != t1);
t = tab;
t1 = tab + 32;
do {
t[ 3] = -t[ 3];
t[ 6] = -t[ 6];
t[11] = -t[11];
t[12] = -t[12];
t[13] = -t[13];
t[15] = -t[15];
t += 16;
} while (t != t1);
t = tab;
t1 = tab + 8;
do {
int x1, x2, x3, x4;
x3 = MUL(t[16], FIX(M_SQRT2*0.5));
x4 = t[0] - x3;
x3 = t[0] + x3;
x2 = MUL(-(t[24] + t[8]), FIX(M_SQRT2*0.5));
x1 = MUL((t[8] - x2), xp[0]);
x2 = MUL((t[8] + x2), xp[1]);
t[ 0] = x3 + x1;
t[ 8] = x4 - x2;
t[16] = x4 + x2;
t[24] = x3 - x1;
t++;
} while (t != t1);
xp += 2;
t = tab;
t1 = tab + 4;
do {
xr = MUL(t[28],xp[0]);
t[28] = (t[0] - xr);
t[0] = (t[0] + xr);
xr = MUL(t[4],xp[1]);
t[ 4] = (t[24] - xr);
t[24] = (t[24] + xr);
xr = MUL(t[20],xp[2]);
t[20] = (t[8] - xr);
t[ 8] = (t[8] + xr);
xr = MUL(t[12],xp[3]);
t[12] = (t[16] - xr);
t[16] = (t[16] + xr);
t++;
} while (t != t1);
xp += 4;
for (i = 0; i < 4; i++) {
xr = MUL(tab[30-i*4],xp[0]);
tab[30-i*4] = (tab[i*4] - xr);
tab[ i*4] = (tab[i*4] + xr);
xr = MUL(tab[ 2+i*4],xp[1]);
tab[ 2+i*4] = (tab[28-i*4] - xr);
tab[28-i*4] = (tab[28-i*4] + xr);
xr = MUL(tab[31-i*4],xp[0]);
tab[31-i*4] = (tab[1+i*4] - xr);
tab[ 1+i*4] = (tab[1+i*4] + xr);
xr = MUL(tab[ 3+i*4],xp[1]);
tab[ 3+i*4] = (tab[29-i*4] - xr);
tab[29-i*4] = (tab[29-i*4] + xr);
xp += 2;
}
t = tab + 30;
t1 = tab + 1;
do {
xr = MUL(t1[0], *xp);
t1[0] = (t[0] - xr);
t[0] = (t[0] + xr);
t -= 2;
t1 += 2;
xp++;
} while (t >= tab);
for(i=0;i<32;i++) {
out[i] = tab[bitinv32[i]];
}
}
#define WSHIFT (WFRAC_BITS + 15 - FRAC_BITS)
static void filter(MpegAudioContext *s, int ch, const short *samples, int incr)
{
short *p, *q;
int sum, offset, i, j;
int tmp[64];
int tmp1[32];
int *out;
offset = s->samples_offset[ch];
out = &s->sb_samples[ch][0][0][0];
for(j=0;j<36;j++) {
/* 32 samples at once */
for(i=0;i<32;i++) {
s->samples_buf[ch][offset + (31 - i)] = samples[0];
samples += incr;
}
/* filter */
p = s->samples_buf[ch] + offset;
q = s->filter_bank;
/* maxsum = 23169 */
for(i=0;i<64;i++) {
sum = p[0*64] * q[0*64];
sum += p[1*64] * q[1*64];
sum += p[2*64] * q[2*64];
sum += p[3*64] * q[3*64];
sum += p[4*64] * q[4*64];
sum += p[5*64] * q[5*64];
sum += p[6*64] * q[6*64];
sum += p[7*64] * q[7*64];
tmp[i] = sum;
p++;
q++;
}
tmp1[0] = tmp[16] >> WSHIFT;
for( i=1; i<=16; i++ ) tmp1[i] = (tmp[i+16]+tmp[16-i]) >> WSHIFT;
for( i=17; i<=31; i++ ) tmp1[i] = (tmp[i+16]-tmp[80-i]) >> WSHIFT;
idct32(out, tmp1);
/* advance of 32 samples */
offset -= 32;
out += 32;
/* handle the wrap around */
if (offset < 0) {
memmove(s->samples_buf[ch] + SAMPLES_BUF_SIZE - (512 - 32),
s->samples_buf[ch], (512 - 32) * 2);
offset = SAMPLES_BUF_SIZE - 512;
}
}
s->samples_offset[ch] = offset;
}
static void compute_scale_factors(MpegAudioContext *s,
unsigned char scale_code[SBLIMIT],
unsigned char scale_factors[SBLIMIT][3],
int sb_samples[3][12][SBLIMIT],
int sblimit)
{
int *p, vmax, v, n, i, j, k, code;
int index, d1, d2;
unsigned char *sf = &scale_factors[0][0];
for(j=0;j<sblimit;j++) {
for(i=0;i<3;i++) {
/* find the max absolute value */
p = &sb_samples[i][0][j];
vmax = abs(*p);
for(k=1;k<12;k++) {
p += SBLIMIT;
v = abs(*p);
if (v > vmax)
vmax = v;
}
/* compute the scale factor index using log 2 computations */
if (vmax > 1) {
n = av_log2(vmax);
/* n is the position of the MSB of vmax. now
use at most 2 compares to find the index */
index = (21 - n) * 3 - 3;
if (index >= 0) {
while (vmax <= s->scale_factor_table[index+1])
index++;
} else {
index = 0; /* very unlikely case of overflow */
}
} else {
index = 62; /* value 63 is not allowed */
}
ff_dlog(NULL, "%2d:%d in=%x %x %d\n",
j, i, vmax, s->scale_factor_table[index], index);
/* store the scale factor */
av_assert2(index >=0 && index <= 63);
sf[i] = index;
}
/* compute the transmission factor : look if the scale factors
are close enough to each other */
d1 = s->scale_diff_table[sf[0] - sf[1] + 64];
d2 = s->scale_diff_table[sf[1] - sf[2] + 64];
/* handle the 25 cases */
switch(d1 * 5 + d2) {
case 0*5+0:
case 0*5+4:
case 3*5+4:
case 4*5+0:
case 4*5+4:
code = 0;
break;
case 0*5+1:
case 0*5+2:
case 4*5+1:
case 4*5+2:
code = 3;
sf[2] = sf[1];
break;
case 0*5+3:
case 4*5+3:
code = 3;
sf[1] = sf[2];
break;
case 1*5+0:
case 1*5+4:
case 2*5+4:
code = 1;
sf[1] = sf[0];
break;
case 1*5+1:
case 1*5+2:
case 2*5+0:
case 2*5+1:
case 2*5+2:
code = 2;
sf[1] = sf[2] = sf[0];
break;
case 2*5+3:
case 3*5+3:
code = 2;
sf[0] = sf[1] = sf[2];
break;
case 3*5+0:
case 3*5+1:
case 3*5+2:
code = 2;
sf[0] = sf[2] = sf[1];
break;
case 1*5+3:
code = 2;
if (sf[0] > sf[2])
sf[0] = sf[2];
sf[1] = sf[2] = sf[0];
break;
default:
av_assert2(0); //cannot happen
code = 0; /* kill warning */
}
ff_dlog(NULL, "%d: %2d %2d %2d %d %d -> %d\n", j,
sf[0], sf[1], sf[2], d1, d2, code);
scale_code[j] = code;
sf += 3;
}
}
/* The most important function : psycho acoustic module. In this
encoder there is basically none, so this is the worst you can do,
but also this is the simpler. */
static void psycho_acoustic_model(MpegAudioContext *s, short smr[SBLIMIT])
{
int i;
for(i=0;i<s->sblimit;i++) {
smr[i] = (int)(fixed_smr[i] * 10);
}
}
#define SB_NOTALLOCATED 0
#define SB_ALLOCATED 1
#define SB_NOMORE 2
/* Try to maximize the smr while using a number of bits inferior to
the frame size. I tried to make the code simpler, faster and
smaller than other encoders :-) */
static void compute_bit_allocation(MpegAudioContext *s,
short smr1[MPA_MAX_CHANNELS][SBLIMIT],
unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
int *padding)
{
int i, ch, b, max_smr, max_ch, max_sb, current_frame_size, max_frame_size;
int incr;
short smr[MPA_MAX_CHANNELS][SBLIMIT];
unsigned char subband_status[MPA_MAX_CHANNELS][SBLIMIT];
const unsigned char *alloc;
memcpy(smr, smr1, s->nb_channels * sizeof(short) * SBLIMIT);
memset(subband_status, SB_NOTALLOCATED, s->nb_channels * SBLIMIT);
memset(bit_alloc, 0, s->nb_channels * SBLIMIT);
/* compute frame size and padding */
max_frame_size = s->frame_size;
s->frame_frac += s->frame_frac_incr;
if (s->frame_frac >= 65536) {
s->frame_frac -= 65536;
s->do_padding = 1;
max_frame_size += 8;
} else {
s->do_padding = 0;
}
/* compute the header + bit alloc size */
current_frame_size = 32;
alloc = s->alloc_table;
for(i=0;i<s->sblimit;i++) {
incr = alloc[0];
current_frame_size += incr * s->nb_channels;
alloc += 1 << incr;
}
for(;;) {
/* look for the subband with the largest signal to mask ratio */
max_sb = -1;
max_ch = -1;
max_smr = INT_MIN;
for(ch=0;ch<s->nb_channels;ch++) {
for(i=0;i<s->sblimit;i++) {
if (smr[ch][i] > max_smr && subband_status[ch][i] != SB_NOMORE) {
max_smr = smr[ch][i];
max_sb = i;
max_ch = ch;
}
}
}
if (max_sb < 0)
break;
ff_dlog(NULL, "current=%d max=%d max_sb=%d max_ch=%d alloc=%d\n",
current_frame_size, max_frame_size, max_sb, max_ch,
bit_alloc[max_ch][max_sb]);
/* find alloc table entry (XXX: not optimal, should use
pointer table) */
alloc = s->alloc_table;
for(i=0;i<max_sb;i++) {
alloc += 1 << alloc[0];
}
if (subband_status[max_ch][max_sb] == SB_NOTALLOCATED) {
/* nothing was coded for this band: add the necessary bits */
incr = 2 + nb_scale_factors[s->scale_code[max_ch][max_sb]] * 6;
incr += s->total_quant_bits[alloc[1]];
} else {
/* increments bit allocation */
b = bit_alloc[max_ch][max_sb];
incr = s->total_quant_bits[alloc[b + 1]] -
s->total_quant_bits[alloc[b]];
}
if (current_frame_size + incr <= max_frame_size) {
/* can increase size */
b = ++bit_alloc[max_ch][max_sb];
current_frame_size += incr;
/* decrease smr by the resolution we added */
smr[max_ch][max_sb] = smr1[max_ch][max_sb] - quant_snr[alloc[b]];
/* max allocation size reached ? */
if (b == ((1 << alloc[0]) - 1))
subband_status[max_ch][max_sb] = SB_NOMORE;
else
subband_status[max_ch][max_sb] = SB_ALLOCATED;
} else {
/* cannot increase the size of this subband */
subband_status[max_ch][max_sb] = SB_NOMORE;
}
}
*padding = max_frame_size - current_frame_size;
av_assert0(*padding >= 0);
}
/*
* Output the MPEG audio layer 2 frame. Note how the code is small
* compared to other encoders :-)
*/
static void encode_frame(MpegAudioContext *s,
unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
int padding)
{
int i, j, k, l, bit_alloc_bits, b, ch;
unsigned char *sf;
int q[3];
PutBitContext *p = &s->pb;
/* header */
put_bits(p, 12, 0xfff);
put_bits(p, 1, 1 - s->lsf); /* 1 = MPEG-1 ID, 0 = MPEG-2 lsf ID */
put_bits(p, 2, 4-2); /* layer 2 */
put_bits(p, 1, 1); /* no error protection */
put_bits(p, 4, s->bitrate_index);
put_bits(p, 2, s->freq_index);
put_bits(p, 1, s->do_padding); /* use padding */
put_bits(p, 1, 0); /* private_bit */
put_bits(p, 2, s->nb_channels == 2 ? MPA_STEREO : MPA_MONO);
put_bits(p, 2, 0); /* mode_ext */
put_bits(p, 1, 0); /* no copyright */
put_bits(p, 1, 1); /* original */
put_bits(p, 2, 0); /* no emphasis */
/* bit allocation */
j = 0;
for(i=0;i<s->sblimit;i++) {
bit_alloc_bits = s->alloc_table[j];
for(ch=0;ch<s->nb_channels;ch++) {
put_bits(p, bit_alloc_bits, bit_alloc[ch][i]);
}
j += 1 << bit_alloc_bits;
}
/* scale codes */
for(i=0;i<s->sblimit;i++) {
for(ch=0;ch<s->nb_channels;ch++) {
if (bit_alloc[ch][i])
put_bits(p, 2, s->scale_code[ch][i]);
}
}
/* scale factors */
for(i=0;i<s->sblimit;i++) {
for(ch=0;ch<s->nb_channels;ch++) {
if (bit_alloc[ch][i]) {
sf = &s->scale_factors[ch][i][0];
switch(s->scale_code[ch][i]) {
case 0:
put_bits(p, 6, sf[0]);
put_bits(p, 6, sf[1]);
put_bits(p, 6, sf[2]);
break;
case 3:
case 1:
put_bits(p, 6, sf[0]);
put_bits(p, 6, sf[2]);
break;
case 2:
put_bits(p, 6, sf[0]);
break;
}
}
}
}
/* quantization & write sub band samples */
for(k=0;k<3;k++) {
for(l=0;l<12;l+=3) {
j = 0;
for(i=0;i<s->sblimit;i++) {
bit_alloc_bits = s->alloc_table[j];
for(ch=0;ch<s->nb_channels;ch++) {
b = bit_alloc[ch][i];
if (b) {
int qindex, steps, m, sample, bits;
/* we encode 3 sub band samples of the same sub band at a time */
qindex = s->alloc_table[j+b];
steps = ff_mpa_quant_steps[qindex];
for(m=0;m<3;m++) {
sample = s->sb_samples[ch][k][l + m][i];
/* divide by scale factor */
#if USE_FLOATS
{
float a;
a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]];
q[m] = (int)((a + 1.0) * steps * 0.5);
}
#else
{
int q1, e, shift, mult;
e = s->scale_factors[ch][i][k];
shift = s->scale_factor_shift[e];
mult = s->scale_factor_mult[e];
/* normalize to P bits */
if (shift < 0)
q1 = sample << (-shift);
else
q1 = sample >> shift;
q1 = (q1 * mult) >> P;
q1 += 1 << P;
if (q1 < 0)
q1 = 0;
q[m] = (q1 * (unsigned)steps) >> (P + 1);
}
#endif
if (q[m] >= steps)
q[m] = steps - 1;
av_assert2(q[m] >= 0 && q[m] < steps);
}
bits = ff_mpa_quant_bits[qindex];
if (bits < 0) {
/* group the 3 values to save bits */
put_bits(p, -bits,
q[0] + steps * (q[1] + steps * q[2]));
} else {
put_bits(p, bits, q[0]);
put_bits(p, bits, q[1]);
put_bits(p, bits, q[2]);
}
}
}
/* next subband in alloc table */
j += 1 << bit_alloc_bits;
}
}
}
/* padding */
for(i=0;i<padding;i++)
put_bits(p, 1, 0);
/* flush */
flush_put_bits(p);
}
static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
MpegAudioContext *s = avctx->priv_data;
const int16_t *samples = (const int16_t *)frame->data[0];
short smr[MPA_MAX_CHANNELS][SBLIMIT];
unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT];
int padding, i, ret;
for(i=0;i<s->nb_channels;i++) {
filter(s, i, samples + i, s->nb_channels);
}
for(i=0;i<s->nb_channels;i++) {
compute_scale_factors(s, s->scale_code[i], s->scale_factors[i],
s->sb_samples[i], s->sblimit);
}
for(i=0;i<s->nb_channels;i++) {
psycho_acoustic_model(s, smr[i]);
}
compute_bit_allocation(s, smr, bit_alloc, &padding);
if ((ret = ff_alloc_packet2(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE, 0)) < 0)
return ret;
init_put_bits(&s->pb, avpkt->data, avpkt->size);
encode_frame(s, bit_alloc, padding);
if (frame->pts != AV_NOPTS_VALUE)
avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding);
avpkt->size = put_bits_count(&s->pb) / 8;
*got_packet_ptr = 1;
return 0;
}
static const AVCodecDefault mp2_defaults[] = {
{ "b", "0" },
{ NULL },
};

View File

@ -0,0 +1,102 @@
/*
* mpeg audio layer 2 tables. Most of them come from the mpeg audio
* specification.
*
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* mpeg audio layer 2 tables.
* Most of them come from the mpeg audio specification.
*/
#ifndef AVCODEC_MPEGAUDIOTAB_H
#define AVCODEC_MPEGAUDIOTAB_H
#include <stdint.h>
#include "mpegaudio.h"
static const int costab32[30] = {
FIX(0.54119610014619701222),
FIX(1.3065629648763763537),
FIX(0.50979557910415917998),
FIX(2.5629154477415054814),
FIX(0.89997622313641556513),
FIX(0.60134488693504528634),
FIX(0.5024192861881556782),
FIX(5.1011486186891552563),
FIX(0.78815462345125020249),
FIX(0.64682178335999007679),
FIX(0.56694403481635768927),
FIX(1.0606776859903470633),
FIX(1.7224470982383341955),
FIX(0.52249861493968885462),
FIX(10.19000812354803287),
FIX(0.674808341455005678),
FIX(1.1694399334328846596),
FIX(0.53104259108978413284),
FIX(2.0577810099534108446),
FIX(0.58293496820613388554),
FIX(0.83934964541552681272),
FIX(0.50547095989754364798),
FIX(3.4076084184687189804),
FIX(0.62250412303566482475),
FIX(0.97256823786196078263),
FIX(0.51544730992262455249),
FIX(1.4841646163141661852),
FIX(0.5531038960344445421),
FIX(0.74453627100229857749),
FIX(0.5006029982351962726),
};
static const int bitinv32[32] = {
0, 16, 8, 24, 4, 20, 12, 28,
2, 18, 10, 26, 6, 22, 14, 30,
1, 17, 9, 25, 5, 21, 13, 29,
3, 19, 11, 27, 7, 23, 15, 31
};
/* signal to noise ratio of each quantification step (could be
computed from quant_steps[]). The values are dB multiplied by 10
*/
static const unsigned short quant_snr[17] = {
70, 110, 160, 208,
253, 316, 378, 439,
499, 559, 620, 680,
740, 800, 861, 920,
980
};
/* fixed psycho acoustic model. Values of SNR taken from the 'toolame'
project */
static const float fixed_smr[SBLIMIT] = {
30, 17, 16, 10, 3, 12, 8, 2.5,
5, 5, 6, 6, 5, 6, 10, 6,
-4, -10, -21, -30, -42, -55, -68, -75,
-75, -75, -75, -75, -91, -107, -110, -108
};
static const unsigned char nb_scale_factors[4] = { 3, 2, 1, 2 };
#endif /* AVCODEC_MPEGAUDIOTAB_H */

View File

@ -0,0 +1,117 @@
/*
* (I)RDFT transforms
* Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <math.h>
#include "libavutil/mathematics.h"
#include "rdft.h"
/**
* @file
* (Inverse) Real Discrete Fourier Transforms.
*/
/** Map one real FFT into two parallel real even and odd FFTs. Then interleave
* the two real FFTs into one complex FFT. Unmangle the results.
* ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
*/
static void rdft_calc_c(RDFTContext *s, FFTSample *data)
{
int i, i1, i2;
FFTComplex ev, od, odsum;
const int n = 1 << s->nbits;
const float k1 = 0.5;
const float k2 = 0.5 - s->inverse;
const FFTSample *tcos = s->tcos;
const FFTSample *tsin = s->tsin;
if (!s->inverse) {
s->fft.fft_permute(&s->fft, (FFTComplex*)data);
s->fft.fft_calc(&s->fft, (FFTComplex*)data);
}
/* i=0 is a special case because of packing, the DC term is real, so we
are going to throw the N/2 term (also real) in with it. */
ev.re = data[0];
data[0] = ev.re+data[1];
data[1] = ev.re-data[1];
#define RDFT_UNMANGLE(sign0, sign1) \
for (i = 1; i < (n>>2); i++) { \
i1 = 2*i; \
i2 = n-i1; \
/* Separate even and odd FFTs */ \
ev.re = k1*(data[i1 ]+data[i2 ]); \
od.im = k2*(data[i2 ]-data[i1 ]); \
ev.im = k1*(data[i1+1]-data[i2+1]); \
od.re = k2*(data[i1+1]+data[i2+1]); \
/* Apply twiddle factors to the odd FFT and add to the even FFT */ \
odsum.re = od.re*tcos[i] sign0 od.im*tsin[i]; \
odsum.im = od.im*tcos[i] sign1 od.re*tsin[i]; \
data[i1 ] = ev.re + odsum.re; \
data[i1+1] = ev.im + odsum.im; \
data[i2 ] = ev.re - odsum.re; \
data[i2+1] = odsum.im - ev.im; \
}
if (s->negative_sin) {
RDFT_UNMANGLE(+,-)
} else {
RDFT_UNMANGLE(-,+)
}
data[2*i+1]=s->sign_convention*data[2*i+1];
if (s->inverse) {
data[0] *= k1;
data[1] *= k1;
s->fft.fft_permute(&s->fft, (FFTComplex*)data);
s->fft.fft_calc(&s->fft, (FFTComplex*)data);
}
}
av_cold int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans)
{
int n = 1 << nbits;
int ret;
s->nbits = nbits;
s->inverse = trans == IDFT_C2R || trans == DFT_C2R;
s->sign_convention = trans == IDFT_R2C || trans == DFT_C2R ? 1 : -1;
s->negative_sin = trans == DFT_C2R || trans == DFT_R2C;
if (nbits < 4 || nbits > 16)
return AVERROR(EINVAL);
if ((ret = ff_fft_init(&s->fft, nbits-1, trans == IDFT_C2R || trans == IDFT_R2C)) < 0)
return ret;
ff_init_ff_cos_tabs(nbits);
s->tcos = ff_cos_tabs[nbits];
s->tsin = ff_cos_tabs[nbits] + (n >> 2);
s->rdft_calc = rdft_calc_c;
if (ARCH_ARM) ff_rdft_init_arm(s);
return 0;
}
av_cold void ff_rdft_end(RDFTContext *s)
{
ff_fft_end(&s->fft);
}

View File

@ -1,7 +1,7 @@
/*
The MIT License (MIT)
Copyright (c) 2019 winlin
Copyright (c) 2025 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -412,10 +412,18 @@ func run(ctx context.Context) error {
oh.SetHeader(w)
if o := r.Header.Get("Origin"); len(o) > 0 {
// SRS does not need cookie or credentials, so we disable CORS credentials, and use * for CORS origin,
// headers, expose headers and methods.
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, HEAD, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Expose-Headers", "Server,range,Content-Length,Content-Range")
w.Header().Set("Access-Control-Allow-Headers", "origin,range,accept-encoding,referer,Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type")
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
w.Header().Set("Access-Control-Allow-Headers", "*")
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
w.Header().Set("Access-Control-Allow-Methods", "*")
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
w.Header().Set("Access-Control-Expose-Headers", "*")
// https://stackoverflow.com/a/24689738/17679565
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
w.Header().Set("Access-Control-Allow-Credentials", "false")
}
// For matched OPTIONS, directly return without response.

View File

@ -1,7 +1,7 @@
/*
The MIT License (MIT)
Copyright (c) 2019 winlin
Copyright (c) 2025 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,7 +1,7 @@
/*
The MIT License (MIT)
Copyright (c) 2019 winlin
Copyright (c) 2025 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2017 winlin
Copyright (c) 2013-2025 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,7 +1,7 @@
/*
The MIT License (MIT)
Copyright (c) 2019 winlin
Copyright (c) 2025 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -35,7 +35,7 @@ func VersionMinor() int {
}
func VersionRevision() int {
return 26
return 27
}
func Version() string {

Binary file not shown.

View File

@ -0,0 +1,4 @@
1116c1116
< LOGC(cnlog.Debug, log << "srt_accept: no pending connection available at the moment");
---
> LOGC(cnlog.Error, log << "srt_accept: no pending connection available at the moment");

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2017 winlin
Copyright (c) 2013-2025 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Winlin
* Copyright (c) 2013-2025 Winlin
*
* 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

View File

@ -2,7 +2,7 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Winlin
* Copyright (c) 2013-2025 Winlin
*
* 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

View File

@ -9,7 +9,7 @@
}
</style>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/jquery-1.12.2.min.js"></script>
<script type="text/javascript" src="js/adapter-7.4.0.min.js"></script>
<script type="text/javascript" src="js/srs.sdk.js"></script>
<script type="text/javascript" src="js/srs.sig.js"></script>

View File

@ -9,7 +9,7 @@
}
</style>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/jquery-1.12.2.min.js"></script>
<script type="text/javascript" src="js/adapter-7.4.0.min.js"></script>
<script type="text/javascript" src="js/srs.sdk.js"></script>
<script type="text/javascript" src="js/srs.sig.js"></script>

View File

@ -7,3 +7,4 @@ objs
.format.txt
.DS_Store
*.log

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2021 Winlin
Copyright (c) 2025 Winlin
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

View File

@ -3,23 +3,56 @@
default: bench test
clean:
rm -f ./objs/srs_bench ./objs/srs_test
rm -rf ./objs
.format.txt: *.go srs/*.go vnet/*.go janus/*.go gb28181/*.go
gofmt -w .
echo "done" > .format.txt
#########################################################################################################
# SRS benchmark tool for SRS, janus, GB28181.
./objs/.format.bench.txt: *.go janus/*.go ./objs/.format.srs.txt ./objs/.format.gb28181.txt
gofmt -w *.go janus
mkdir -p objs && echo "done" > ./objs/.format.bench.txt
bench: ./objs/srs_bench
./objs/srs_bench: .format.txt *.go srs/*.go vnet/*.go janus/*.go gb28181/*.go Makefile
./objs/srs_bench: ./objs/.format.bench.txt *.go janus/*.go srs/*.go vnet/*.go gb28181/*.go Makefile
go build -mod=vendor -o objs/srs_bench .
test: ./objs/srs_test
#########################################################################################################
# For all regression tests.
test: ./objs/srs_test ./objs/srs_gb28181_test ./objs/srs_blackbox_test
./objs/srs_test: .format.txt *.go srs/*.go vnet/*.go Makefile
#########################################################################################################
# For SRS regression test.
./objs/.format.srs.txt: srs/*.go vnet/*.go
gofmt -w srs vnet
mkdir -p objs && echo "done" > ./objs/.format.srs.txt
./objs/srs_test: ./objs/.format.srs.txt *.go srs/*.go vnet/*.go Makefile
go test ./srs -mod=vendor -c -o ./objs/srs_test
#########################################################################################################
# For gb28181 test.
./objs/.format.gb28181.txt: gb28181/*.go
gofmt -w gb28181
mkdir -p objs && echo "done" > ./objs/.format.gb28181.txt
./objs/srs_gb28181_test: ./objs/.format.gb28181.txt *.go gb28181/*.go Makefile
go test ./gb28181 -mod=vendor -c -o ./objs/srs_gb28181_test
#########################################################################################################
# For blackbox test.
./objs/.format.blackbox.txt: blackbox/*.go
gofmt -w blackbox
mkdir -p objs && echo "done" > ./objs/.format.blackbox.txt
./objs/srs_blackbox_test: ./objs/.format.blackbox.txt *.go blackbox/*.go Makefile
go test ./blackbox -mod=vendor -c -o ./objs/srs_blackbox_test
#########################################################################################################
# Help menu.
help:
@echo "Usage: make [bench|test]"
@echo "Usage: make [default|bench|test|clean]"
@echo " default The default entry for make is bench+test"
@echo " bench Make the bench to ./objs/srs_bench"
@echo " test Make the test tool to ./objs/srs_test"
@echo " test Make the test tool to ./objs/srs_test and ./objs/srs_gb28181_test ./objs/srs_blackbox_test"
@echo " clean Remove all tools at ./objs"

View File

@ -1,16 +1,38 @@
# srs-bench
WebRTC benchmark on [pion/webrtc](https://github.com/pion/webrtc) for [SRS](https://github.com/ossrs/srs).
SB(SRS Bench) is a set of benchmark and regression test tools, for SRS and other media servers, supports HTTP-FLV, RTMP,
HLS, WebRTC and GB28181.
For RTMP/HLS/FLV benchmark, please use branch [master](https://github.com/ossrs/srs-bench/tree/master).
## Usage
编译和使用
下载代码和编译:
```bash
git clone https://github.com/ossrs/srs-bench.git && git checkout feature/rtc &&
make && ./objs/srs_bench -h
git clone -b feature/rtc https://github.com/ossrs/srs-bench.git &&
cd srs-bench && make
```
编译会生成下面的工具:
* `./objs/srs_bench` 压测模拟大量客户端的负载测试支持SRS、GB28181和Janus三种场景。
* `./objs/srs_test` 回归测试(SRS)SRS服务器的回归测试。
* `./objs/srs_gb28181_test` 回归测试(GB28181)GB服务器的回归测试。
* `./objs/srs_blackbox_test` 黑盒测试(SRS)SRS服务器的黑盒测试也可以换成其他媒体服务器。
> Note: 查看工具的全部参数请执行`./objs/xx -h`
有些场景若需要编译和启动SRS:
```bash
git clone https://github.com/ossrs/srs.git &&
cd srs/trunk && ./configure --h265=on --gb28181=on && make &&
./objs/srs -c conf/console.conf
```
具体场景,请按下面的操作启动测试。
## Player for Live
直播播放压测,一个流,很多个播放。
@ -61,7 +83,8 @@ ffmpeg -re -i doc/source.200kbps.768x320.flv -c copy -f flv -y rtmp://localhost/
> 备注URL的变量格式参考Go的`fmt.Sprintf`,比如可以用`webrtc://localhost/live/livestream_%03d`。
## DVR
<a name="dvr"></a>
## DVR for Benchmark
录制场景,主要是把内容录制下来后,可分析,也可以用于推流。
@ -102,11 +125,7 @@ ffmpeg -re -i doc/source.200kbps.768x320.flv -c copy -f flv -y rtmp://localhost/
回归测试需要先启动[SRS](https://github.com/ossrs/srs/issues/307)支持WebRTC推拉流
```bash
if [[ ! -z $(ifconfig en0 inet| grep 'inet '|awk '{print $2}') ]]; then
docker run -p 1935:1935 -p 8080:8080 -p 1985:1985 -p 8000:8000/udp \
--rm --env CANDIDATE=$(ifconfig en0 inet| grep 'inet '|awk '{print $2}')\
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:4 objs/srs -c conf/rtc.conf
fi
./objs/srs -c conf/rtc.conf
```
然后运行回归测试用例,如果只跑一次,可以直接运行:
@ -167,6 +186,95 @@ make && ./objs/srs_test -test.v -srs-log -test.run TestRtcBasic_PublishPlay
* `-srs-play-pli`播放时PLI的间隔毫秒。默认值`5000`即5秒。
* `-srs-dtls-drop-packets`DTLS丢包测试丢了多少个包算成功默认值`5`
> Note: 查看全部参数请执行`./objs/srs_test -h`
<a name="gb28181"></a>
## GB28181 Test
支持GB28181的压测使用选项`-sfu gb28181`可以查看帮助:
```bash
make && ./objs/srs_bench -sfu gb28181 --help
```
运行回归测试用例,更多命令请参考[Regression Test](#regression-test)
```bash
go test ./gb28181 -mod=vendor -v -count=1
```
也可以用make编译出重复使用的二进制
```bash
make && ./objs/srs_gb28181_test -test.v
```
支持的参数如下:
* `-srs-sip`SIP服务器地址。默认值`tcp://127.0.0.1:5060`
* `-srs-stream`GB的user即流名称一般会加上随机的后缀。默认值`3402000000`
* `-srs-timeout`每个Case的超时时间毫秒。默认值`11000`即11秒。
* `-srs-publish-audio`,推流时,使用的音频文件。默认值:`avatar.aac`
* `-srs-publish-video`,推流时,使用的视频文件。默认值:`avatar.h264`
* `-srs-publish-video-fps`推流时视频文件的FPS。默认值`25`
其他不常用参数:
* `-srs-log`,是否开启详细日志。默认值:`false`
> Note: 查看全部参数请执行`./objs/srs_gb28181_test -h`
## Blackbox Test
使用FFmpeg作为客户端对流媒体服务器SRS进行黑盒压测完全黑盒的回归测试。
运行回归测试用例,如果只跑一次,可以直接运行:
```bash
go test ./blackbox -mod=vendor -v -count=1
```
也可以用make编译出重复使用的二进制
```bash
make && ./objs/srs_blackbox_test -test.v
```
由于黑盒测试依赖特殊的FFmpeg可以在Docker中编译和启动
```bash
docker run --rm -it -v $(pwd):/g -w /g ossrs/srs:ubuntu20 bash
make && ./objs/srs_blackbox_test -test.v
```
> Note: 依赖SRS二进制当然也可以在这个Docker中编译SRS具体请参考SRS的Wiki。
支持的参数如下:
* `-srs-binary`每个测试用例都需要启动一个SRS服务因此需要设置SRS的位置。默认值`../../objs/srs`
* `-srs-ffmpeg`FFmpeg工具的位置用来推流和录制。默认值`ffmpeg`
* `-srs-ffprobe`ffprobe工具的位置用来分析流的信息。默认值`ffprobe`
* `-srs-timeout`每个Case的超时时间毫秒。默认值`64000`即64秒。
* `-srs-publish-avatar`,测试源文件路径。默认值:`avatar.flv`。
* `-srs-ffprobe-duration`每个Case的探测时间毫秒。默认值`16000`即16秒。
* `-srs-ffprobe-timeout`每个Case的探测超时时间毫秒。默认值`21000`即21秒。
其他不常用参数:
* `-srs-log`,是否开启详细日志。默认值:`false`
* `-srs-server-log`是否开启SRS的stdout详细日志。默认值`false`
* `-srs-ffmpeg-log`是否开启FFmpeg的stderr详细日志。默认值`false`
* `-srs-dvr-log`是否开启DVR的stderr详细日志。默认值`false`
* `-srs-ffprobe-log`是否开启FFprobe的stdout详细日志。默认值`false`
由于每个黑盒的用例时间都很长,可以开启并行:
```bash
./objs/srs_blackbox_test -test.v -test.parallel 8
```
> Note: 查看全部参数请执行`./objs/srs_blackbox_test -h`
## GCOVR
本机生成覆盖率时,我们使用工具[gcovr](https://gcovr.com/en/stable/guide.html)。
@ -221,31 +329,4 @@ make -j10 && ./objs/srs_bench -sfu janus \
-nn 5
```
## GB28181
支持GB28181的压测使用选项`-sfu gb28181`可以查看帮助:
```bash
make && ./objs/srs_bench -sfu gb28181 --help
```
运行回归测试用例,更多命令请参考[Regression Test](#regression-test)
```bash
go test ./gb28181 -mod=vendor -v -count=1
```
支持的参数如下:
* `-srs-sip`SIP服务器地址。默认值`tcp://127.0.0.1:5060`
* `-srs-stream`GB的user即流名称一般会加上随机的后缀。默认值`3402000000`
* `-srs-timeout`每个Case的超时时间毫秒。默认值`11000`即11秒。
* `-srs-publish-audio`,推流时,使用的音频文件。默认值:`avatar.aac`
* `-srs-publish-video`,推流时,使用的视频文件。默认值:`avatar.h264`
* `-srs-publish-video-fps`推流时视频文件的FPS。默认值`25`
其他不常用参数:
* `-srs-log`,是否开启详细日志。默认值:`false`
2021.01, Winlin

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox

View File

@ -0,0 +1,50 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"github.com/ossrs/go-oryx-lib/logger"
"io/ioutil"
"math/rand"
"os"
"testing"
"time"
)
func TestMain(m *testing.M) {
if err := prepareTest(); err != nil {
logger.Ef(nil, "Prepare test fail, err %+v", err)
os.Exit(-1)
}
// Disable the logger during all tests.
if *srsLog == false {
olw := logger.Switch(ioutil.Discard)
defer func() {
logger.Switch(olw)
}()
}
// Init rand seed.
rand.Seed(time.Now().UnixNano())
os.Exit(m.Run())
}

View File

@ -0,0 +1,143 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"math/rand"
"os"
"path"
"sync"
"testing"
"time"
)
func TestFast_RtmpPublish_DvrFlv_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start hooks service.
hooks := NewHooksService()
wg.Add(1)
go func() {
defer wg.Done()
r6 = hooks.Run(ctx, cancel)
}()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_VHOST_DVR_ENABLED=on",
"SRS_VHOST_DVR_DVR_PLAN=session",
"SRS_VHOST_DVR_DVR_PATH=./objs/nginx/html/[app]/[stream].[timestamp].flv",
fmt.Sprintf("SRS_VHOST_DVR_DVR_DURATION=%v", *srsFFprobeDuration),
"SRS_VHOST_HTTP_HOOKS_ENABLED=on",
fmt.Sprintf("SRS_VHOST_HTTP_HOOKS_ON_DVR=http://localhost:%v/api/v1/dvrs", hooks.HooksAPI()),
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-hooks.ReadyCtx().Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
// When process quit, still keep case to run.
v.cancelCaseWhenQuit, v.ffmpegDuration = false, duration
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrByFFmpeg, v.streamURL = false, streamURL
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
wg.Add(1)
go func() {
defer wg.Done()
for evt := range hooks.HooksEvents() {
if onDvrEvt, ok := evt.(*HooksEventOnDvr); ok {
fp := path.Join(svr.WorkDir(), onDvrEvt.File)
logger.Tf(ctx, "FFprobe: Set the dvrFile=%v from callback", fp)
v.dvrFile = fp
}
}
}()
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration/2 {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration/2, m.String(), str)
}
}
}

View File

@ -0,0 +1,116 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"math/rand"
"os"
"path"
"sync"
"testing"
"time"
)
func TestFast_RtmpPublish_HlsPlay_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_SERVER_ENABLED=on",
"SRS_VHOST_HLS_ENABLED=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.m3u8", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
// Note that HLS score is low, so we only check duration. Note that only check half of duration, because we
// might get only some pieces of segments.
if dv := m.Duration(); dv < duration/2 {
r4 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration/2, m.String(), str)
}
}
}

View File

@ -0,0 +1,93 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"net/http"
"sync"
"testing"
"time"
)
func TestFast_Http_Api_Basic_Auth(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_API_AUTH_ENABLED=on",
"SRS_HTTP_API_AUTH_USERNAME=admin",
"SRS_HTTP_API_AUTH_PASSWORD=admin",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
<-svr.ReadyCtx().Done()
if true {
defer cancel()
var res *http.Response
url := fmt.Sprintf("http://admin:admin@localhost:%v/api/v1/versions", svr.APIPort())
res, r1 = http.Get(url)
if r1 == nil && res.StatusCode != 200 {
r2 = errors.Errorf("get status code=%v, expect=200", res.StatusCode)
}
url = fmt.Sprintf("http://admin:123456@localhost:%v/api/v1/versions", svr.APIPort())
res, r3 = http.Get(url)
if r3 == nil && res.StatusCode != 401 {
r4 = errors.Errorf("get status code=%v, expect=401", res.StatusCode)
}
url = fmt.Sprintf("http://localhost:%v/api/v1/versions", svr.APIPort())
res, r5 = http.Get(url)
if r5 == nil && res.StatusCode != 401 {
r6 = errors.Errorf("get status code=%v, expect=401", res.StatusCode)
}
}
}

View File

@ -0,0 +1,473 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"math/rand"
"os"
"path"
"sync"
"testing"
"time"
)
func TestFast_RtmpPublish_RtmpPlay_CodecMP3_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer()
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vcodec", "copy", "-acodec", "libmp3lame", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.flv", streamID))
v.streamURL = fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
if a := m.Audio(); a == nil {
r6 = errors.Errorf("no audio, %v, %v", m.String(), str)
} else if a.CodecName != "mp3" {
r7 = errors.Errorf("invalid audio codec=%v, %v, %v", a.CodecName, m.String(), str)
}
}
}
func TestFast_RtmpPublish_HttpFlvPlay_CodecMP3_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_SERVER_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_ENABLED=on",
// If guessing, we might got no audio because transcoding might be delay for sending audio packets.
"SRS_VHOST_HTTP_REMUX_GUESS_HAS_AV=off",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vcodec", "copy", "-acodec", "libmp3lame", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.flv", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.flv", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
if a := m.Audio(); a == nil {
r6 = errors.Errorf("no audio, %v, %v", m.String(), str)
} else if a.CodecName != "mp3" {
r7 = errors.Errorf("invalid audio codec=%v, %v, %v", a.CodecName, m.String(), str)
}
}
}
func TestFast_RtmpPublish_HttpMp3Play_CodecMP3_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_SERVER_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_MOUNT=[vhost]/[app]/[stream].mp3",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vn", "-acodec", "libmp3lame", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.mp3", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.mp3", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 1 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
// Note that HTTP-MP3 score is low, so we only check duration.
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
if a := m.Audio(); a == nil {
r6 = errors.Errorf("no audio, %v, %v", m.String(), str)
} else if a.CodecName != "mp3" {
r7 = errors.Errorf("invalid audio codec=%v, %v, %v", a.CodecName, m.String(), str)
}
}
}
func TestFast_RtmpPublish_HttpTsPlay_CodecMP3_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_SERVER_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_MOUNT=[vhost]/[app]/[stream].ts",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vcodec", "copy", "-acodec", "libmp3lame", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.ts", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
// Note that HTTP-TS score is low, so we only check duration.
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
if a := m.Audio(); a == nil {
r6 = errors.Errorf("no audio, %v, %v", m.String(), str)
} else if a.CodecName != "mp3" {
r7 = errors.Errorf("invalid audio codec=%v, %v, %v", a.CodecName, m.String(), str)
}
}
}
func TestFast_RtmpPublish_HlsPlay_CodecMP3_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_SERVER_ENABLED=on",
"SRS_VHOST_HLS_ENABLED=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vcodec", "copy", "-acodec", "libmp3lame", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.m3u8", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
// Note that HLS score is low, so we only check duration. Note that only check half of duration, because we
// might get only some pieces of segments.
if dv := m.Duration(); dv < duration/2 {
r4 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration/2, m.String(), str)
}
if a := m.Audio(); a == nil {
r5 = errors.Errorf("no audio, %v, %v", m.String(), str)
} else if a.CodecName != "mp3" {
r6 = errors.Errorf("invalid audio codec=%v, %v, %v", a.CodecName, m.String(), str)
}
}
}

View File

@ -0,0 +1,356 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"math/rand"
"os"
"path"
"sync"
"testing"
"time"
)
func TestFast_RtmpPublish_RtmpPlay_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer()
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.flv", streamID))
v.streamURL, v.duration, v.timeout = streamURL, duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}
func TestFast_RtmpPublish_HttpFlvPlay_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_HTTP_SERVER_ENABLED=on",
"SRS_VHOST_HTTP_REMUX_ENABLED=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.flv", streamID))
v.streamURL = fmt.Sprintf("http://localhost:%v/live/%v.flv", svr.HTTPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}
func TestFast_RtmpPublish_RtmpPlay_ChunkSize128(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_CHUNK_SIZE=128",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.flv", streamID))
v.streamURL, v.duration, v.timeout = streamURL, duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}
func TestFast_RtmpPublish_RtmpPlay_EnableATC(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_VHOST_PLAY_ATC=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.flv", streamID))
v.streamURL, v.duration, v.timeout = streamURL, duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}

View File

@ -0,0 +1,116 @@
// The MIT License (MIT)
//
// # Copyright (c) 2025 Winlin
//
// 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.
package blackbox
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"math/rand"
"os"
"path"
"sync"
"testing"
"time"
)
func TestFast_SrtPublish_SrtPlay_Basic(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_SRT_SERVER_ENABLED=on",
"SRS_VHOST_SRT_ENABLED=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("srt://localhost:%v?streamid=#!::r=live/%v,m=publish", svr.SRTPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy",
"-pes_payload_size", "0", "-f", "mpegts", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.ts", streamID))
v.streamURL = fmt.Sprintf("srt://localhost:%v?streamid=#!::r=live/%v,m=request", svr.SRTPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
// Note that SRT score is low, so we only check duration.
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}

1299
trunk/3rdparty/srs-bench/blackbox/util.go vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -24,12 +24,13 @@ import (
"context"
"flag"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"io"
"os"
"strings"
"time"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
)
type gbMainConfig struct {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -21,10 +21,11 @@
package gb28181
import (
"github.com/ossrs/go-oryx-lib/logger"
"io/ioutil"
"os"
"testing"
"github.com/ossrs/go-oryx-lib/logger"
)
func TestMain(m *testing.M) {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -23,11 +23,12 @@ package gb28181
import (
"context"
"fmt"
"github.com/ghettovoice/gosip/sip"
"github.com/ossrs/go-oryx-lib/logger"
"github.com/ossrs/go-oryx-lib/errors"
"testing"
"time"
"github.com/ghettovoice/gosip/sip"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
)
func TestGbPublishRegularly(t *testing.T) {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -22,16 +22,17 @@ package gb28181
import (
"context"
"github.com/ghettovoice/gosip/sip"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"github.com/pion/webrtc/v3/pkg/media/h264reader"
"io"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/ghettovoice/gosip/sip"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"github.com/pion/webrtc/v3/pkg/media/h264reader"
)
type GBSessionConfig struct {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -23,14 +23,15 @@ package gb28181
import (
"context"
"fmt"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/pion/rtp"
"github.com/yapingcat/gomedia/codec"
"github.com/yapingcat/gomedia/mpeg2"
"math"
"net"
"net/url"
"strings"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/pion/rtp"
"github.com/yapingcat/gomedia/codec"
"github.com/yapingcat/gomedia/mpeg2"
)
type PSConfig struct {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -23,16 +23,17 @@ package gb28181
import (
"context"
"fmt"
"github.com/ghettovoice/gosip/log"
"github.com/ghettovoice/gosip/sip"
"github.com/ghettovoice/gosip/transport"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
"math/rand"
"net/url"
"strings"
"sync"
"time"
"github.com/ghettovoice/gosip/log"
"github.com/ghettovoice/gosip/sip"
"github.com/ghettovoice/gosip/transport"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/ossrs/go-oryx-lib/logger"
)
type SIPConfig struct {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2022 Winlin
// # Copyright (c) 2022-2025 Winlin
//
// 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
@ -25,10 +25,6 @@ import (
"context"
"flag"
"fmt"
"github.com/ghettovoice/gosip/sip"
"github.com/ossrs/go-oryx-lib/aac"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/yapingcat/gomedia/mpeg2"
"io"
"net"
"net/url"
@ -36,6 +32,11 @@ import (
"path"
"strings"
"time"
"github.com/ghettovoice/gosip/sip"
"github.com/ossrs/go-oryx-lib/aac"
"github.com/ossrs/go-oryx-lib/errors"
"github.com/yapingcat/gomedia/mpeg2"
)
var srsLog *bool

View File

@ -1,17 +1,50 @@
module github.com/ossrs/srs-bench
go 1.15
go 1.17
require (
github.com/ghettovoice/gosip v0.0.0-20220929080231-de8ba881be83
github.com/ossrs/go-oryx-lib v0.0.9
github.com/pion/interceptor v0.0.10
github.com/pion/ice/v2 v2.3.6
github.com/pion/interceptor v0.1.17
github.com/pion/logging v0.2.2
github.com/pion/rtcp v1.2.6
github.com/pion/rtp v1.6.2
github.com/pion/sdp/v3 v3.0.4
github.com/pion/transport v0.12.2
github.com/pion/webrtc/v3 v3.0.13
github.com/pion/rtcp v1.2.10
github.com/pion/rtp v1.7.13
github.com/pion/sdp/v3 v3.0.6
github.com/pion/transport/v2 v2.2.1
github.com/pion/webrtc/v3 v3.2.9
github.com/pkg/errors v0.9.1
github.com/yapingcat/gomedia/codec v0.0.0-20220617074658-94762898dc25
github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.1.0-rc.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.8 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/mdns v0.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/sctp v1.8.7 // indirect
github.com/pion/srtp/v2 v2.0.15 // indirect
github.com/pion/stun v0.6.0 // indirect
github.com/pion/turn/v2 v2.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -7,6 +7,7 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghettovoice/gosip v0.0.0-20220929080231-de8ba881be83 h1:4v14bwSGZH2usyuG9XWZgMbGkVU33ayg0cb68nvKfj0=
github.com/ghettovoice/gosip v0.0.0-20220929080231-de8ba881be83/go.mod h1:yTr3BEYSFe9As6XM7ldyrVgqsPwlnw8Ahc4N28VFM2g=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
@ -19,14 +20,15 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I=
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
@ -43,59 +45,61 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.5 h1:obHEce3upls1IBn1gTw/o7bCv7OJb6Ib/o7wNO+4eKw=
github.com/nxadm/tail v1.4.5/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U=
github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/ossrs/go-oryx-lib v0.0.9 h1:piZkzit/1hqAcXP31/mvDEDpHVjCmBMmvzF3hN8hUuQ=
github.com/ossrs/go-oryx-lib v0.0.9/go.mod h1:i2tH4TZBzAw5h+HwGrNOKvP/nmZgSQz0OEnLLdzcT/8=
github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI=
github.com/pion/dtls/v2 v2.0.8 h1:reGe8rNIMfO/UAeFLqO61tl64t154Qfkr4U3Gzu1tsg=
github.com/pion/dtls/v2 v2.0.8/go.mod h1:QuDII+8FVvk9Dp5t5vYIMTo7hh7uBkra+8QIm7QGm10=
github.com/pion/ice/v2 v2.0.15 h1:KZrwa2ciL9od8+TUVJiYTNsCW9J5lktBjGwW1MacEnQ=
github.com/pion/ice/v2 v2.0.15/go.mod h1:ZIiVGevpgAxF/cXiIVmuIUtCb3Xs4gCzCbXB6+nFkSI=
github.com/pion/interceptor v0.0.10 h1:dXFyFWRJFwmzQqyn0U8dUAbOJu+JJnMVAqxmvTu30B4=
github.com/pion/interceptor v0.0.10/go.mod h1:qzeuWuD/ZXvPqOnxNcnhWfkCZ2e1kwwslicyyPnhoK4=
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/ice/v2 v2.3.6 h1:Jgqw36cAud47iD+N6rNX225uHvrgWtAlHfVyOQc3Heg=
github.com/pion/ice/v2 v2.3.6/go.mod h1:9/TzKDRwBVAPsC+YOrKH/e3xDrubeTRACU9/sHQarsU=
github.com/pion/interceptor v0.1.17 h1:prJtgwFh/gB8zMqGZoOgJPHivOwVAp61i2aG61Du/1w=
github.com/pion/interceptor v0.1.17/go.mod h1:SY8kpmfVBvrbUzvj2bsXz7OJt5JvmVNZ+4Kjq7FcwrI=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U=
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.11 h1:UCnj7MsobLKLuP/Hh+JMiI/6W5Bs/VF45lWKgHFjSIE=
github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/srtp/v2 v2.0.1 h1:kgfh65ob3EcnFYA4kUBvU/menCp9u7qaJLXwWgpobzs=
github.com/pion/srtp/v2 v2.0.1/go.mod h1:c8NWHhhkFf/drmHTAblkdu8++lsISEBBdAuiyxgqIsE=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
github.com/pion/transport v0.12.1/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.2 h1:WYEjhloRHt1R86LhUKjC5y+P52Y11/QqEUalvtzVoys=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
github.com/pion/udp v0.1.0 h1:uGxQsNyrqG3GLINv36Ff60covYmfrLoxzwnCsIYspXI=
github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
github.com/pion/webrtc/v3 v3.0.13 h1:iyR3xf4eQLLatfvAOhjf/vHBi8x9y1TGeJqOHq7TjE4=
github.com/pion/webrtc/v3 v3.0.13/go.mod h1:+7cDZgV7jKkm4H+f0ki2wiMSuZtyFlezKLfBR2hntcQ=
github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
github.com/pion/sctp v1.8.7 h1:JnABvFakZueGAn4KU/4PSKg+GWbF6QWbKTWZOSGJjXw=
github.com/pion/sctp v1.8.7/go.mod h1:g1Ul+ARqZq5JEmoFy87Q/4CePtKnTJ1QCL9dBBdN6AU=
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
github.com/pion/srtp/v2 v2.0.15 h1:+tqRtXGsGwHC0G0IUIAzRmdkHvriF79IHVfZGfHrQoA=
github.com/pion/srtp/v2 v2.0.15/go.mod h1:b/pQOlDrbB0HEH5EUAQXzSYxikFbNcNuKmF8tM0hCtw=
github.com/pion/stun v0.4.0/go.mod h1:QPsh1/SbXASntw3zkkrIk3ZJVKz4saBY2G7S10P3wCw=
github.com/pion/stun v0.6.0 h1:JHT/2iyGDPrFWE8NNC15wnddBN8KifsEDw8swQmrEmU=
github.com/pion/stun v0.6.0/go.mod h1:HPqcfoeqQn9cuaet7AOmB5e5xkObu9DwBdurwLKO9oA=
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
github.com/pion/transport/v2 v2.1.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
github.com/pion/transport/v2 v2.2.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/turn/v2 v2.1.0 h1:5wGHSgGhJhP/RpabkUb/T9PdsAjkGLS6toYz5HNzoSI=
github.com/pion/turn/v2 v2.1.0/go.mod h1:yrT5XbXSGX1VFSF31A3c1kCNB5bBZgk/uu5LET162qs=
github.com/pion/webrtc/v3 v3.2.9 h1:U8NSjQDlZZ+Iy/hg42Q/u6mhEVSXYvKrOIZiZwYTfLc=
github.com/pion/webrtc/v3 v3.2.9/go.mod h1:gjQLMZeyN3jXBGdxGmUYCyKjOuYX/c99BDjGqmadq0A=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -107,12 +111,17 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0=
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
@ -122,24 +131,39 @@ github.com/yapingcat/gomedia/codec v0.0.0-20220617074658-94762898dc25 h1:1mq/skG
github.com/yapingcat/gomedia/codec v0.0.0-20220617074658-94762898dc25/go.mod h1:obSECV6X3NPUsLL0olA7DurvQHKMq7J3iBTNQ4bL/vQ=
github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25 h1:51qjqT2jsOESm/jDi0k0AdQX33Sg4vhw8X6eooj7c8A=
github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25/go.mod h1:bvxj2Oi5Rwj7eHm2OjqgOIs8x2T0j+V068eS/SAyZLA=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -147,33 +171,63 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b h1:tv7/y4pd+sR8bcNb2D6o7BNU6zjWm0VjQLac+w7fNNM=
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -182,7 +236,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -28,6 +28,14 @@ import (
type rtpInterceptorOptionFunc func(i *rtpInterceptor)
type rtpInteceptorFactory struct {
p *rtpInterceptor
}
func (v *rtpInteceptorFactory) NewInterceptor(id string) (interceptor.Interceptor, error) {
return v.p, nil
}
// Common RTP packet interceptor for benchmark.
// @remark Should never merge with rtcpInterceptor, because they has the same Write interface.
type rtpInterceptor struct {
@ -41,12 +49,12 @@ type rtpInterceptor struct {
bypassInterceptor
}
func newRTPInterceptor(options ...rtpInterceptorOptionFunc) *rtpInterceptor {
func newRTPInterceptor(options ...rtpInterceptorOptionFunc) *rtpInteceptorFactory {
v := &rtpInterceptor{}
for _, opt := range options {
opt(v)
}
return v
return &rtpInteceptorFactory{v}
}
func (v *rtpInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
@ -81,6 +89,14 @@ func (v *rtpInterceptor) UnbindRemoteStream(info *interceptor.StreamInfo) {
type rtcpInterceptorOptionFunc func(i *rtcpInterceptor)
type rtcpInteceptorFactory struct {
p *rtcpInterceptor
}
func (v *rtcpInteceptorFactory) NewInterceptor(id string) (interceptor.Interceptor, error) {
return v.p, nil
}
// Common RTCP packet interceptor for benchmark.
// @remark Should never merge with rtpInterceptor, because they has the same Write interface.
type rtcpInterceptor struct {
@ -94,12 +110,12 @@ type rtcpInterceptor struct {
bypassInterceptor
}
func newRTCPInterceptor(options ...rtcpInterceptorOptionFunc) *rtcpInterceptor {
func newRTCPInterceptor(options ...rtcpInterceptorOptionFunc) *rtcpInteceptorFactory {
v := &rtcpInterceptor{}
for _, opt := range options {
opt(v)
}
return v
return &rtcpInteceptorFactory{v}
}
func (v *rtcpInterceptor) BindRTCPReader(reader interceptor.RTCPReader) interceptor.RTCPReader {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -97,11 +97,11 @@ func startPublish(ctx context.Context, r, sourceAudio, sourceVideo string, fps i
if sourceAudio != "" {
aIngester = newAudioIngester(sourceAudio)
registry.Add(aIngester.audioLevelInterceptor)
registry.Add(&rtpInteceptorFactory{aIngester.audioLevelInterceptor})
}
if sourceVideo != "" {
vIngester = newVideoIngester(sourceVideo)
registry.Add(vIngester.markerInterceptor)
registry.Add(&rtpInteceptorFactory{vIngester.markerInterceptor})
}
api := webrtc.NewAPI(webrtc.WithMediaEngine(m), webrtc.WithInterceptorRegistry(registry))

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -44,7 +44,7 @@ import (
"github.com/pion/interceptor"
"github.com/pion/logging"
"github.com/pion/rtcp"
"github.com/pion/transport/vnet"
"github.com/pion/transport/v2/vnet"
"github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/pkg/media/h264reader"
)
@ -636,9 +636,12 @@ func (v *testWebRTCAPI) Setup(vnetClientIP string, options ...testWebRTCAPIOptio
// Each api should bind to a network, however, it's possible to share it
// for different apis.
v.network = vnet.NewNet(&vnet.NetConfig{
v.network, err = vnet.NewNet(&vnet.NetConfig{
StaticIP: vnetClientIP,
})
if err != nil {
return errors.Wrapf(err, "create network for api")
}
if err = v.router.AddNet(v.network); err != nil {
return errors.Wrapf(err, "create network for api")
@ -892,14 +895,14 @@ func newTestPublisher(options ...testPublisherOptionFunc) (*testPublisher, error
rtcpInterceptor.rtcpWriter = func(pkts []rtcp.Packet, attributes interceptor.Attributes) (int, error) {
return rtcpInterceptor.nextRTCPWriter.Write(pkts, attributes)
}
api.registry.Add(rtcpInterceptor)
api.registry.Add(&rtcpInteceptorFactory{rtcpInterceptor})
// Filter for ingesters.
if sourceAudio != "" {
api.registry.Add(v.aIngester.audioLevelInterceptor)
api.registry.Add(&rtpInteceptorFactory{v.aIngester.audioLevelInterceptor})
}
if sourceVideo != "" {
api.registry.Add(v.vIngester.markerInterceptor)
api.registry.Add(&rtpInteceptorFactory{v.vIngester.markerInterceptor})
}
})

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -28,6 +28,14 @@ import (
type rtpInterceptorOptionFunc func(i *rtpInterceptor)
type rtpInteceptorFactory struct {
p *rtpInterceptor
}
func (v *rtpInteceptorFactory) NewInterceptor(id string) (interceptor.Interceptor, error) {
return v.p, nil
}
// Common RTP packet interceptor for benchmark.
// @remark Should never merge with rtcpInterceptor, because they has the same Write interface.
type rtpInterceptor struct {
@ -41,12 +49,12 @@ type rtpInterceptor struct {
bypassInterceptor
}
func newRTPInterceptor(options ...rtpInterceptorOptionFunc) *rtpInterceptor {
func newRTPInterceptor(options ...rtpInterceptorOptionFunc) *rtpInteceptorFactory {
v := &rtpInterceptor{}
for _, opt := range options {
opt(v)
}
return v
return &rtpInteceptorFactory{v}
}
func (v *rtpInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
@ -81,6 +89,14 @@ func (v *rtpInterceptor) UnbindRemoteStream(info *interceptor.StreamInfo) {
type rtcpInterceptorOptionFunc func(i *rtcpInterceptor)
type rtcpInteceptorFactory struct {
p *rtcpInterceptor
}
func (v *rtcpInteceptorFactory) NewInterceptor(id string) (interceptor.Interceptor, error) {
return v.p, nil
}
// Common RTCP packet interceptor for benchmark.
// @remark Should never merge with rtpInterceptor, because they has the same Write interface.
type rtcpInterceptor struct {
@ -94,12 +110,12 @@ type rtcpInterceptor struct {
bypassInterceptor
}
func newRTCPInterceptor(options ...rtcpInterceptorOptionFunc) *rtcpInterceptor {
func newRTCPInterceptor(options ...rtcpInterceptorOptionFunc) *rtcpInteceptorFactory {
v := &rtcpInterceptor{}
for _, opt := range options {
opt(v)
}
return v
return &rtcpInteceptorFactory{v}
}
func (v *rtcpInterceptor) BindRTCPReader(reader interceptor.RTCPReader) interceptor.RTCPReader {

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -79,11 +79,11 @@ func startPublish(ctx context.Context, r, sourceAudio, sourceVideo string, fps i
if sourceAudio != "" {
aIngester = newAudioIngester(sourceAudio)
registry.Add(aIngester.audioLevelInterceptor)
registry.Add(&rtpInteceptorFactory{aIngester.audioLevelInterceptor})
}
if sourceVideo != "" {
vIngester = newVideoIngester(sourceVideo)
registry.Add(vIngester.markerInterceptor)
registry.Add(&rtpInteceptorFactory{vIngester.markerInterceptor})
}
api := webrtc.NewAPI(webrtc.WithMediaEngine(m), webrtc.WithInterceptorRegistry(registry))

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -34,7 +34,7 @@ import (
"testing"
"time"
"github.com/pion/transport/vnet"
"github.com/pion/transport/v2/vnet"
"github.com/pion/webrtc/v3"
"github.com/ossrs/go-oryx-lib/errors"
@ -623,10 +623,11 @@ func TestRtcBasic_PublishPlay(t *testing.T) {
}
// The srs-server is DTLS server(passive), srs-bench is DTLS client which is active mode.
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-server: ChangeCipherSpec, Finished
//
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-server: ChangeCipherSpec, Finished
func TestRtcDTLS_ClientActive_Default(t *testing.T) {
if err := filterTestError(func() error {
streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int())
@ -678,10 +679,11 @@ func TestRtcDTLS_ClientActive_Default(t *testing.T) {
}
// The srs-server is DTLS client(client), srs-bench is DTLS server which is passive mode.
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-bench: ChangeCipherSpec, Finished
//
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-bench: ChangeCipherSpec, Finished
func TestRtcDTLS_ClientPassive_Default(t *testing.T) {
if err := filterTestError(func() error {
streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int())
@ -732,6 +734,238 @@ func TestRtcDTLS_ClientPassive_Default(t *testing.T) {
}
}
// The srs-server is DTLS server(passive), srs-bench is DTLS client which is active mode.
//
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-server: ChangeCipherSpec, Finished
//
// We utilized a large certificate to evaluate DTLS, which resulted in the fragmentation of the protocol.
func TestRtcDTLS_ClientActive_With_Large_Rsa_Certificate(t *testing.T) {
if err := filterTestError(func() error {
streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int())
p, err := newTestPublisher(registerDefaultCodecs, func(p *testPublisher) error {
p.streamSuffix = streamSuffix
p.onOffer = testUtilSetupActive
return nil
}, createLargeRsaCertificate)
if err != nil {
return err
}
defer p.Close()
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
if err := p.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
var nnRTCP, nnRTP int64
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
nnRTP++
return i.nextRTPWriter.Write(header, payload, attributes)
}
}))
api.registry.Add(newRTCPInterceptor(func(i *rtcpInterceptor) {
i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) {
cancel() // Send enough packets, done.
}
logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP)
return i.nextRTCPReader.Read(buf, attributes)
}
}))
}, func(api *testWebRTCAPI) {
api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) {
chunk, parsed := newChunkMessageType(c)
if !parsed {
return true
}
logger.Tf(ctx, "Chunk %v, ok=%v %v bytes", chunk, ok, len(c.UserData()))
return true
})
}); err != nil {
return err
}
return p.Run(ctx, cancel)
}()); err != nil {
t.Errorf("err %+v", err)
}
}
// The srs-server is DTLS client(client), srs-bench is DTLS server which is passive mode.
//
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-bench: ChangeCipherSpec, Finished
//
// We utilized a large certificate to evaluate DTLS, which resulted in the fragmentation of the protocol.
func TestRtcDTLS_ClientPassive_With_Large_Rsa_Certificate(t *testing.T) {
if err := filterTestError(func() error {
streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int())
p, err := newTestPublisher(registerDefaultCodecs, func(p *testPublisher) error {
p.streamSuffix = streamSuffix
p.onOffer = testUtilSetupPassive
return nil
}, createLargeRsaCertificate)
if err != nil {
return err
}
defer p.Close()
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
if err := p.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
var nnRTCP, nnRTP int64
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
nnRTP++
return i.nextRTPWriter.Write(header, payload, attributes)
}
}))
api.registry.Add(newRTCPInterceptor(func(i *rtcpInterceptor) {
i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) {
cancel() // Send enough packets, done.
}
logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP)
return i.nextRTCPReader.Read(buf, attributes)
}
}))
}, func(api *testWebRTCAPI) {
api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) {
chunk, parsed := newChunkMessageType(c)
if !parsed {
return true
}
logger.Tf(ctx, "Chunk %v, ok=%v %v bytes", chunk, ok, len(c.UserData()))
return true
})
}); err != nil {
return err
}
return p.Run(ctx, cancel)
}()); err != nil {
t.Errorf("err %+v", err)
}
}
// The srs-server is DTLS server(passive), srs-bench is DTLS client which is active mode.
//
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-server: ChangeCipherSpec, Finished
//
// We utilized a large certificate to evaluate DTLS, which resulted in the fragmentation of the protocol.
func TestRtcDTLS_ClientActive_With_Large_Ecdsa_Certificate(t *testing.T) {
if err := filterTestError(func() error {
streamSuffix := fmt.Sprintf("dtls-passive-no-arq-%v-%v", os.Getpid(), rand.Int())
p, err := newTestPublisher(registerDefaultCodecs, func(p *testPublisher) error {
p.streamSuffix = streamSuffix
p.onOffer = testUtilSetupActive
return nil
}, createLargeEcdsaCertificate)
if err != nil {
return err
}
defer p.Close()
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
if err := p.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
var nnRTCP, nnRTP int64
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
nnRTP++
return i.nextRTPWriter.Write(header, payload, attributes)
}
}))
api.registry.Add(newRTCPInterceptor(func(i *rtcpInterceptor) {
i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) {
cancel() // Send enough packets, done.
}
logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP)
return i.nextRTCPReader.Read(buf, attributes)
}
}))
}, func(api *testWebRTCAPI) {
api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) {
chunk, parsed := newChunkMessageType(c)
if !parsed {
return true
}
logger.Tf(ctx, "Chunk %v, ok=%v %v bytes", chunk, ok, len(c.UserData()))
return true
})
}); err != nil {
return err
}
return p.Run(ctx, cancel)
}()); err != nil {
t.Errorf("err %+v", err)
}
}
// The srs-server is DTLS client(client), srs-bench is DTLS server which is passive mode.
//
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-bench: ChangeCipherSpec, Finished
//
// We utilized a large certificate to evaluate DTLS, which resulted in the fragmentation of the protocol.
func TestRtcDTLS_ClientPassive_With_Large_Ecdsa_Certificate(t *testing.T) {
if err := filterTestError(func() error {
streamSuffix := fmt.Sprintf("dtls-active-no-arq-%v-%v", os.Getpid(), rand.Int())
p, err := newTestPublisher(registerDefaultCodecs, func(p *testPublisher) error {
p.streamSuffix = streamSuffix
p.onOffer = testUtilSetupPassive
return nil
}, createLargeEcdsaCertificate)
if err != nil {
return err
}
defer p.Close()
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
if err := p.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
var nnRTCP, nnRTP int64
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
i.rtpWriter = func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
nnRTP++
return i.nextRTPWriter.Write(header, payload, attributes)
}
}))
api.registry.Add(newRTCPInterceptor(func(i *rtcpInterceptor) {
i.rtcpReader = func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
if nnRTCP++; nnRTCP >= int64(*srsPublishOKPackets) && nnRTP >= int64(*srsPublishOKPackets) {
cancel() // Send enough packets, done.
}
logger.Tf(ctx, "publish write %v RTP read %v RTCP packets", nnRTP, nnRTCP)
return i.nextRTCPReader.Read(buf, attributes)
}
}))
}, func(api *testWebRTCAPI) {
api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) {
chunk, parsed := newChunkMessageType(c)
if !parsed {
return true
}
logger.Tf(ctx, "Chunk %v, ok=%v %v bytes", chunk, ok, len(c.UserData()))
return true
})
}); err != nil {
return err
}
return p.Run(ctx, cancel)
}()); err != nil {
t.Errorf("err %+v", err)
}
}
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// When srs-bench close the PC, it will send DTLS alert and might retransmit it.
func TestRtcDTLS_ClientActive_Duplicated_Alert(t *testing.T) {
@ -853,9 +1087,10 @@ func TestRtcDTLS_ClientPassive_Duplicated_Alert(t *testing.T) {
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// [Drop] No.1 srs-bench: ClientHello(Epoch=0, Sequence=0)
// [ARQ] No.2 srs-bench: ClientHello(Epoch=0, Sequence=1)
// No.3 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.4 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-server: ChangeCipherSpec, Finished
//
// No.3 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.4 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-server: ChangeCipherSpec, Finished
//
// @remark The pion is active, so it can be consider a benchmark for DTLS server.
func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T) {
@ -931,9 +1166,10 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.T
// The srs-server is DTLS client, srs-bench is DTLS server which is passive mode.
// [Drop] No.1 srs-server: ClientHello(Epoch=0, Sequence=0)
// [ARQ] No.2 srs-server: ClientHello(Epoch=0, Sequence=1)
// No.3 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.4 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-bench: ChangeCipherSpec, Finished
//
// No.3 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.4 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-bench: ChangeCipherSpec, Finished
//
// @remark If retransmit the ClientHello, with the same epoch+sequence, peer will request HelloVerifyRequest, then
// openssl will create a new ClientHello with increased sequence. It's ok, but waste a lots of duplicated ClientHello
@ -1009,12 +1245,15 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ClientHello(t *testing.
}
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// No.1 srs-bench: ClientHello(Epoch=0, Sequence=0)
//
// No.1 srs-bench: ClientHello(Epoch=0, Sequence=0)
//
// [Drop] No.2 srs-server: ServerHello(Epoch=0, Sequence=0), Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// [ARQ] No.2 srs-bench: ClientHello(Epoch=0, Sequence=1)
// [ARQ] No.3 srs-server: ServerHello(Epoch=0, Sequence=5), Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.4 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-server: ChangeCipherSpec, Finished
//
// No.4 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-server: ChangeCipherSpec, Finished
//
// @remark The pion is active, so it can be consider a benchmark for DTLS server.
func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T) {
@ -1097,12 +1336,15 @@ func TestRtcDTLS_ClientActive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.T
}
// The srs-server is DTLS client, srs-bench is DTLS server which is passive mode.
// No.1 srs-server: ClientHello(Epoch=0, Sequence=0)
//
// No.1 srs-server: ClientHello(Epoch=0, Sequence=0)
//
// [Drop] No.2 srs-bench: ServerHello(Epoch=0, Sequence=0), Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// [ARQ] No.2 srs-server: ClientHello(Epoch=0, Sequence=1)
// [ARQ] No.3 srs-bench: ServerHello(Epoch=0, Sequence=5), Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.4 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-bench: ChangeCipherSpec, Finished
//
// No.4 srs-server: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-bench: ChangeCipherSpec, Finished
//
// @remark If retransmit the ClientHello, with the same epoch+sequence, peer will request HelloVerifyRequest, then
// openssl will create a new ClientHello with increased sequence. It's ok, but waste a lots of duplicated ClientHello
@ -1187,11 +1429,14 @@ func TestRtcDTLS_ClientPassive_ARQ_ClientHello_ByDropped_ServerHello(t *testing.
}
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
//
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
//
// [Drop] No.3 srs-bench: Certificate(Epoch=0, Sequence=0), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// [ARQ] No.4 srs-bench: Certificate(Epoch=0, Sequence=5), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-server: ChangeCipherSpec, Finished
//
// No.5 srs-server: ChangeCipherSpec, Finished
//
// @remark The pion is active, so it can be consider a benchmark for DTLS server.
func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T) {
@ -1265,11 +1510,14 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_Certificate(t *testing.T
}
// The srs-server is DTLS client, srs-bench is DTLS server which is passive mode.
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
//
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
//
// [Drop] No.3 srs-server: Certificate(Epoch=0, Sequence=0), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// [ARQ] No.4 srs-server: Certificate(Epoch=0, Sequence=5), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.5 srs-bench: ChangeCipherSpec, Finished
//
// No.5 srs-bench: ChangeCipherSpec, Finished
//
// @remark If retransmit the Certificate, with the same epoch+sequence, peer will drop the message. It's ok right now, but
// wast some packets, so we check the epoch+sequence which should never dup, even for ARQ.
@ -1344,9 +1592,11 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_ByDropped_Certificate(t *testing.
}
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-bench: Certificate(Epoch=0, Sequence=0), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
//
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-bench: Certificate(Epoch=0, Sequence=0), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
//
// [Drop] No.5 srs-server: ChangeCipherSpec, Finished
// [ARQ] No.6 srs-bench: Certificate(Epoch=0, Sequence=5), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// [ARQ] No.7 srs-server: ChangeCipherSpec, Finished
@ -1431,9 +1681,11 @@ func TestRtcDTLS_ClientActive_ARQ_Certificate_ByDropped_ChangeCipherSpec(t *test
}
// The srs-server is DTLS client, srs-bench is DTLS server which is passive mode.
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-server: Certificate(Epoch=0, Sequence=0), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
//
// No.1 srs-server: ClientHello
// No.2 srs-bench: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// No.3 srs-server: Certificate(Epoch=0, Sequence=0), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
//
// [Drop] No.5 srs-bench: ChangeCipherSpec, Finished
// [ARQ] No.6 srs-server: Certificate(Epoch=0, Sequence=5), ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// [ARQ] No.7 srs-bench: ChangeCipherSpec, Finished
@ -1896,6 +2148,122 @@ func TestRtcDTLS_ClientPassive_ARQ_Certificate_After_ClientHello(t *testing.T) {
}
}
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// This case is used to test the corruption of DTLS packets, which is expected to result in a failed handshake. In this
// case, we corrupt the ClientHello packet sent by srs-bench.
// Note that the passive mode is not being tested as the focus is solely on testing srs-server.
//
// [Corrupt] No.1 srs-bench: ClientHello(Epoch=0, Sequence=0), change length from 129 to 0xf.
// No.2 srs-server: Alert (Level: Fatal, Description: Illegal Parameter)
func TestRtcDTLS_ClientActive_Corrupt_ClientHello(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
r0 := fmt.Errorf("DTLS should failed.")
err := func() error {
streamSuffix := fmt.Sprintf("dtls-active-corrupt-client-hello-%v-%v", os.Getpid(), rand.Int())
p, err := newTestPublisher(registerDefaultCodecs, func(p *testPublisher) error {
p.streamSuffix = streamSuffix
p.onOffer = testUtilSetupActive
return nil
})
if err != nil {
return err
}
defer p.Close()
p.onDTLSStateChange = func(state webrtc.DTLSTransportState) {
if state == webrtc.DTLSTransportStateFailed {
logger.Tf(ctx, "Got expected DTLS failed message, reset err to ok")
r0, p.ignorePCStateError, p.ignoreDTLSStateError = nil, true, true
cancel()
}
}
if err := p.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
nnClientHello := 0
api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) {
b, chunk, parsed, record, err := newChunkAll(c)
if !parsed || chunk.chunk != chunkTypeDTLS || chunk.content != dtlsContentTypeHandshake ||
chunk.handshake != dtlsHandshakeTypeClientHello || err != nil {
return true
}
b[14], b[15], b[16], nnClientHello = 0, 0, 0xf, nnClientHello+1
logger.Tf(ctx, "NN=%v, Chunk %v, %v, %v bytes", nnClientHello, chunk, record, len(c.UserData()))
return true
})
}); err != nil {
return err
}
return p.Run(ctx, cancel)
}()
if err := filterTestError(ctx.Err(), err, r0); err != nil {
t.Errorf("err %+v", err)
}
}
// The srs-server is DTLS server, srs-bench is DTLS client which is active mode.
// This case is used to test the corruption of DTLS packets, which is expected to result in a failed handshake. In this
// case, we corrupt the ClientHello packet sent by srs-bench.
// Note that the passive mode is not being tested as the focus is solely on testing srs-server.
//
// No.1 srs-bench: ClientHello
// No.2 srs-server: ServerHello, Certificate, ServerKeyExchange, CertificateRequest, ServerHelloDone
// [Corrupt] No.3 srs-bench: Certificate, ClientKeyExchange, CertificateVerify, ChangeCipherSpec, Finished
// No.4 srs-server: Alert (Level: Fatal, Description: Illegal Parameter)
// [Corrupt] No.1 srs-bench: ClientHello(Epoch=0, Sequence=0), change length from 129 to 0xf.
// No.2 srs-server: Alert (Level: Fatal, Description: Illegal Parameter)
func TestRtcDTLS_ClientActive_Corrupt_Certificate(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
r0 := fmt.Errorf("DTLS should failed.")
err := func() error {
streamSuffix := fmt.Sprintf("dtls-active-corrupt-certificate-%v-%v", os.Getpid(), rand.Int())
p, err := newTestPublisher(registerDefaultCodecs, func(p *testPublisher) error {
p.streamSuffix = streamSuffix
p.onOffer = testUtilSetupActive
return nil
})
if err != nil {
return err
}
defer p.Close()
p.onDTLSStateChange = func(state webrtc.DTLSTransportState) {
if state == webrtc.DTLSTransportStateFailed {
logger.Tf(ctx, "Got expected DTLS failed message, reset err to ok")
r0, p.ignorePCStateError, p.ignoreDTLSStateError = nil, true, true
cancel()
}
}
if err := p.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
nnClientHello := 0
api.router.AddChunkFilter(func(c vnet.Chunk) (ok bool) {
b, chunk, parsed, record, err := newChunkAll(c)
if !parsed || chunk.chunk != chunkTypeDTLS || chunk.content != dtlsContentTypeHandshake ||
chunk.handshake != dtlsHandshakeTypeCertificate || err != nil {
return true
}
b[14], b[15], b[16], nnClientHello = 0, 0, 0xf, nnClientHello+1
logger.Tf(ctx, "NN=%v, Chunk %v, %v, %v bytes", nnClientHello, chunk, record, len(c.UserData()))
return true
})
}); err != nil {
return err
}
return p.Run(ctx, cancel)
}()
if err := filterTestError(ctx.Err(), err, r0); err != nil {
t.Errorf("err %+v", err)
}
}
func TestRTCServerVersion(t *testing.T) {
api := fmt.Sprintf("http://%v:1985/api/v1/versions", *srsServer)
req, err := http.NewRequest("POST", api, nil)
@ -1940,7 +2308,7 @@ func TestRTCServerVersion(t *testing.T) {
}
}
func TestRtcPublish_FlvPlay(t *testing.T) {
func TestRtcPublish_HttpFlvPlay(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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
@ -395,7 +395,7 @@ func TestRtmpPublish_MultipleSequences_RtcPlay(t *testing.T) {
}
}
func TestRtmpPublish_FlvPlay(t *testing.T) {
func TestRtmpPublish_HttpFlvPlay(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
@ -472,7 +472,7 @@ func TestRtmpPublish_FlvPlay(t *testing.T) {
}
}
func TestRtmpPublish_FlvPlayNoAudio(t *testing.T) {
func TestRtmpPublish_HttpFlvPlayNoAudio(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
@ -555,7 +555,7 @@ func TestRtmpPublish_FlvPlayNoAudio(t *testing.T) {
}
}
func TestRtmpPublish_FlvPlayNoVideo(t *testing.T) {
func TestRtmpPublish_HttpFlvPlayNoVideo(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2021 Winlin
// # Copyright (c) 2025 Winlin
//
// 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

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