mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
SRS5: DVR: Support blackbox test based on hooks. v5.0.132 (#3365)
PICK e655948e96
This commit is contained in:
parent
3c6ade8721
commit
f06a2d61f7
31 changed files with 4704 additions and 3925 deletions
43
.github/workflows/test.yml
vendored
43
.github/workflows/test.yml
vendored
|
@ -4,6 +4,7 @@ name: "Test"
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
# The dependency graph:
|
# The dependency graph:
|
||||||
|
# test(6m)
|
||||||
# multiple-arch-armv7(13m)
|
# multiple-arch-armv7(13m)
|
||||||
# multiple-arch-aarch64(7m)
|
# multiple-arch-aarch64(7m)
|
||||||
# cygwin64-cache(1m)
|
# cygwin64-cache(1m)
|
||||||
|
@ -16,9 +17,7 @@ on: [push, pull_request]
|
||||||
# build-cross-arm(3m)
|
# build-cross-arm(3m)
|
||||||
# build-cross-aarch64(3m)
|
# build-cross-aarch64(3m)
|
||||||
# multiple-arch-amd64(2m)
|
# multiple-arch-amd64(2m)
|
||||||
# utest(3m)
|
|
||||||
# coverage(3m)
|
# coverage(3m)
|
||||||
# blackbox(3m)
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cygwin64-cache:
|
cygwin64-cache:
|
||||||
|
@ -163,30 +162,8 @@ jobs:
|
||||||
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-cross-aarch64 .
|
run: DOCKER_BUILDKIT=1 docker build -f trunk/Dockerfile.builds --target ubuntu20-cross-aarch64 .
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
utest:
|
test:
|
||||||
name: utest
|
name: utest-regression-blackbox-test
|
||||||
needs:
|
|
||||||
- fast
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
# Tests
|
|
||||||
- name: Build test image
|
|
||||||
run: docker build --tag srs:test --build-arg MAKEARGS='-j2' -f trunk/Dockerfile.test .
|
|
||||||
# For utest
|
|
||||||
- name: Run 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 './objs/srs -c conf/regression-test.conf && \
|
|
||||||
cd 3rdparty/srs-bench && ./objs/srs_test -test.v && ./objs/srs_gb28181_test -test.v'
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
|
|
||||||
blackbox:
|
|
||||||
name: blackbox
|
|
||||||
needs:
|
|
||||||
- fast
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
@ -196,10 +173,21 @@ jobs:
|
||||||
# For blackbox-test
|
# For blackbox-test
|
||||||
- name: Run SRS blackbox-test
|
- name: Run SRS blackbox-test
|
||||||
run: |
|
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 \
|
docker run --rm -w /srs/trunk/3rdparty/srs-bench srs:test \
|
||||||
./objs/srs_blackbox_test -test.v -test.run '^TestFast' -test.parallel 64
|
./objs/srs_blackbox_test -test.v -test.run '^TestFast' -test.parallel 64
|
||||||
docker run --rm -w /srs/trunk/3rdparty/srs-bench srs:test \
|
docker run --rm -w /srs/trunk/3rdparty/srs-bench srs:test \
|
||||||
./objs/srs_blackbox_test -test.v -test.run '^TestSlow' -test.parallel 4
|
./objs/srs_blackbox_test -test.v -test.run '^TestSlow' -test.parallel 4
|
||||||
|
# For utest
|
||||||
|
- name: Run 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 './objs/srs -c conf/regression-test.conf && \
|
||||||
|
cd 3rdparty/srs-bench && ./objs/srs_test -test.v && ./objs/srs_gb28181_test -test.v'
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
|
@ -312,8 +300,7 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- cygwin64
|
- cygwin64
|
||||||
- coverage
|
- coverage
|
||||||
- blackbox
|
- test
|
||||||
- utest
|
|
||||||
- build-centos7
|
- build-centos7
|
||||||
- build-ubuntu16
|
- build-ubuntu16
|
||||||
- build-ubuntu18
|
- build-ubuntu18
|
||||||
|
|
143
trunk/3rdparty/srs-bench/blackbox/dvr_test.go
vendored
Normal file
143
trunk/3rdparty/srs-bench/blackbox/dvr_test.go
vendored
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// # Copyright (c) 2023 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
305
trunk/3rdparty/srs-bench/blackbox/util.go
vendored
305
trunk/3rdparty/srs-bench/blackbox/util.go
vendored
|
@ -27,6 +27,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ossrs/go-oryx-lib/errors"
|
"github.com/ossrs/go-oryx-lib/errors"
|
||||||
|
ohttp "github.com/ossrs/go-oryx-lib/http"
|
||||||
"github.com/ossrs/go-oryx-lib/logger"
|
"github.com/ossrs/go-oryx-lib/logger"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
@ -200,6 +201,8 @@ type backendService struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
env []string
|
env []string
|
||||||
|
// If timeout, kill the process.
|
||||||
|
duration time.Duration
|
||||||
|
|
||||||
// The process stdout and stderr.
|
// The process stdout and stderr.
|
||||||
stdout bytes.Buffer
|
stdout bytes.Buffer
|
||||||
|
@ -315,6 +318,22 @@ func (v *backendService) Run(ctx context.Context, cancel context.CancelFunc) err
|
||||||
// The context for SRS process.
|
// The context for SRS process.
|
||||||
processDone, processDoneCancel := context.WithCancel(context.Background())
|
processDone, processDoneCancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
// If exceed timeout, kill the process.
|
||||||
|
v.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer v.wg.Done()
|
||||||
|
if v.duration <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <- ctx.Done():
|
||||||
|
case <-time.After(v.duration):
|
||||||
|
logger.Tf(ctx, "Process killed duration=%v, pid=%v, name=%v, args=%v", v.duration, v.pid, v.name, v.args)
|
||||||
|
cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// If SRS process terminated, notify case to stop.
|
// If SRS process terminated, notify case to stop.
|
||||||
v.wg.Add(1)
|
v.wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -327,12 +346,12 @@ func (v *backendService) Run(ctx context.Context, cancel context.CancelFunc) err
|
||||||
defer processDoneCancel()
|
defer processDoneCancel()
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil && !v.ignoreExitStatusError {
|
if err := cmd.Wait(); err != nil && !v.ignoreExitStatusError {
|
||||||
v.r0 = errors.Wrapf(err, "Process wait err, name=%v, args=%v", v.name, v.args)
|
v.r0 = errors.Wrapf(err, "Process wait err, pid=%v, name=%v, args=%v", v.pid, v.name, v.args)
|
||||||
}
|
}
|
||||||
if v.onStop != nil {
|
if v.onStop != nil {
|
||||||
if err := v.onStop(ctx, v, cmd, v.r0, &v.stdout, &v.stderr); err != nil {
|
if err := v.onStop(ctx, v, cmd, v.r0, &v.stdout, &v.stderr); err != nil {
|
||||||
if v.r0 == nil {
|
if v.r0 == nil {
|
||||||
v.r0 = errors.Wrapf(err, "Process onStop err, name=%v, args=%v", v.name, v.args)
|
v.r0 = errors.Wrapf(err, "Process onStop err, pid=%v, name=%v, args=%v", v.pid, v.name, v.args)
|
||||||
} else {
|
} else {
|
||||||
logger.Ef(ctx, "Process onStop err %v", err)
|
logger.Ef(ctx, "Process onStop err %v", err)
|
||||||
}
|
}
|
||||||
|
@ -435,7 +454,7 @@ type srsServer struct {
|
||||||
func NewSRSServer(opts ...func(v *srsServer)) SRSServer {
|
func NewSRSServer(opts ...func(v *srsServer)) SRSServer {
|
||||||
rid := fmt.Sprintf("%v-%v", os.Getpid(), rand.Int())
|
rid := fmt.Sprintf("%v-%v", os.Getpid(), rand.Int())
|
||||||
v := &srsServer{
|
v := &srsServer{
|
||||||
workDir: "./",
|
workDir: path.Join("objs", fmt.Sprintf("%v", rand.Int())),
|
||||||
srsID: fmt.Sprintf("srs-id-%v", rid),
|
srsID: fmt.Sprintf("srs-id-%v", rid),
|
||||||
process: newBackendService(),
|
process: newBackendService(),
|
||||||
}
|
}
|
||||||
|
@ -443,7 +462,7 @@ func NewSRSServer(opts ...func(v *srsServer)) SRSServer {
|
||||||
|
|
||||||
// If we run in GoLand, the current directory is in blackbox, so we use parent directory.
|
// If we run in GoLand, the current directory is in blackbox, so we use parent directory.
|
||||||
if _, err := os.Stat("objs"); err != nil {
|
if _, err := os.Stat("objs"); err != nil {
|
||||||
v.workDir = "../"
|
v.workDir = path.Join("..", "objs", fmt.Sprintf("%v", rand.Int()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do allocate resource.
|
// Do allocate resource.
|
||||||
|
@ -461,22 +480,12 @@ func NewSRSServer(opts ...func(v *srsServer)) SRSServer {
|
||||||
allocator.Free(v.httpListen)
|
allocator.Free(v.httpListen)
|
||||||
allocator.Free(v.srtListen)
|
allocator.Free(v.srtListen)
|
||||||
|
|
||||||
pidFile := path.Join(v.workDir, v.srsRelativePidFile)
|
if _, err := os.Stat(v.workDir); err == nil {
|
||||||
if _, err := os.Stat(pidFile); err == nil {
|
os.RemoveAll(v.workDir)
|
||||||
os.Remove(pidFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idFile := path.Join(v.workDir, v.srsRelativeIDFile)
|
logger.Tf(ctx, "SRS server is closed, id=%v, pid=%v, cleanup=%v r0=%v",
|
||||||
if _, err := os.Stat(idFile); err == nil {
|
v.srsID, bs.pid, v.workDir, bs.r0)
|
||||||
os.Remove(idFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
hlsFiles := path.Join(v.workDir, "objs", "live")
|
|
||||||
if _, err := os.Stat(hlsFiles); err == nil {
|
|
||||||
os.RemoveAll(hlsFiles)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Tf(ctx, "SRS server is closed, id=%v, pid=%v, r0=%v", v.srsID, bs.pid, bs.r0)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,20 +521,39 @@ func (v *srsServer) Run(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
v.workDir, *srsBinary, v.srsID, v.srsRelativePidFile, v.rtmpListen,
|
v.workDir, *srsBinary, v.srsID, v.srsRelativePidFile, v.rtmpListen,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Create directories.
|
||||||
|
if err := os.MkdirAll(path.Join(v.workDir, "./objs/nginx/html"), os.FileMode(0755) | os.ModeDir); err != nil {
|
||||||
|
return errors.Wrapf(err, "SRS create directory %v", path.Join(v.workDir, "./objs/nginx/html"))
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the name and args of process.
|
// Setup the name and args of process.
|
||||||
v.process.name = *srsBinary
|
v.process.name = *srsBinary
|
||||||
v.process.args = []string{"-e"}
|
v.process.args = []string{"-e"}
|
||||||
|
|
||||||
// Setup the envrionment variables.
|
// Setup the constant values.
|
||||||
v.process.env = []string{
|
v.process.env = []string{
|
||||||
// SRS working directory.
|
|
||||||
fmt.Sprintf("SRS_WORK_DIR=%v", v.workDir),
|
|
||||||
// Run in frontend.
|
// Run in frontend.
|
||||||
"SRS_DAEMON=off",
|
"SRS_DAEMON=off",
|
||||||
// Write logs to stdout and stderr.
|
// Write logs to stdout and stderr.
|
||||||
"SRS_SRS_LOG_FILE=console",
|
"SRS_SRS_LOG_FILE=console",
|
||||||
// Disable warning for asan.
|
// Disable warning for asan.
|
||||||
"MallocNanoZone=0",
|
"MallocNanoZone=0",
|
||||||
|
// Avoid error for macOS, which ulimit to 256.
|
||||||
|
"SRS_MAX_CONNECTIONS=100",
|
||||||
|
}
|
||||||
|
// For directories.
|
||||||
|
v.process.env = append(v.process.env, []string{
|
||||||
|
// SRS working directory.
|
||||||
|
fmt.Sprintf("SRS_WORK_DIR=%v", v.workDir),
|
||||||
|
// Setup the default directory for HTTP server.
|
||||||
|
"SRS_HTTP_SERVER_DIR=./objs/nginx/html",
|
||||||
|
// Setup the default directory for HLS stream.
|
||||||
|
"SRS_VHOST_HLS_HLS_PATH=./objs/nginx/html",
|
||||||
|
"SRS_VHOST_HLS_HLS_M3U8_FILE=[app]/[stream].m3u8",
|
||||||
|
"SRS_VHOST_HLS_HLS_TS_FILE=[app]/[stream]-[seq].ts",
|
||||||
|
}...)
|
||||||
|
// For variables.
|
||||||
|
v.process.env = append(v.process.env, []string{
|
||||||
// SRS PID file.
|
// SRS PID file.
|
||||||
fmt.Sprintf("SRS_PID=%v", v.srsRelativePidFile),
|
fmt.Sprintf("SRS_PID=%v", v.srsRelativePidFile),
|
||||||
// SRS ID file.
|
// SRS ID file.
|
||||||
|
@ -533,19 +561,13 @@ func (v *srsServer) Run(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
// HTTP API to detect the service.
|
// HTTP API to detect the service.
|
||||||
fmt.Sprintf("SRS_HTTP_API_ENABLED=on"),
|
fmt.Sprintf("SRS_HTTP_API_ENABLED=on"),
|
||||||
fmt.Sprintf("SRS_HTTP_API_LISTEN=%v", v.apiListen),
|
fmt.Sprintf("SRS_HTTP_API_LISTEN=%v", v.apiListen),
|
||||||
// Avoid error for macOS, which ulimit to 256.
|
|
||||||
"SRS_MAX_CONNECTIONS=100",
|
|
||||||
// Setup the default directory for HTTP server.
|
|
||||||
"SRS_HTTP_SERVER_DIR=objs",
|
|
||||||
// Setup the default directory for HLS stream.
|
|
||||||
"SRS_VHOST_HLS_HLS_PATH=objs",
|
|
||||||
// Setup the RTMP listen port.
|
// Setup the RTMP listen port.
|
||||||
fmt.Sprintf("SRS_LISTEN=%v", v.rtmpListen),
|
fmt.Sprintf("SRS_LISTEN=%v", v.rtmpListen),
|
||||||
// Setup the HTTP sever listen port.
|
// Setup the HTTP sever listen port.
|
||||||
fmt.Sprintf("SRS_HTTP_SERVER_LISTEN=%v", v.httpListen),
|
fmt.Sprintf("SRS_HTTP_SERVER_LISTEN=%v", v.httpListen),
|
||||||
// Setup the SRT server listen port.
|
// Setup the SRT server listen port.
|
||||||
fmt.Sprintf("SRS_SRT_SERVER_LISTEN=%v", v.srtListen),
|
fmt.Sprintf("SRS_SRT_SERVER_LISTEN=%v", v.srtListen),
|
||||||
}
|
}...)
|
||||||
// Rewrite envs by case.
|
// Rewrite envs by case.
|
||||||
if v.envs != nil {
|
if v.envs != nil {
|
||||||
v.process.env = append(v.process.env, v.envs...)
|
v.process.env = append(v.process.env, v.envs...)
|
||||||
|
@ -588,8 +610,8 @@ func (v *srsServer) Run(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
|
|
||||||
// Hooks for process.
|
// Hooks for process.
|
||||||
v.process.onBeforeStart = func(ctx context.Context, bs *backendService, cmd *exec.Cmd) error {
|
v.process.onBeforeStart = func(ctx context.Context, bs *backendService, cmd *exec.Cmd) error {
|
||||||
logger.Tf(ctx, "SRS id=%v, env=%v, cmd is %v %v",
|
logger.Tf(ctx, "SRS id=%v, env %v %v %v",
|
||||||
v.srsID, cmd.Env, bs.name, strings.Join(bs.args, " "))
|
v.srsID, strings.Join(cmd.Env, " "), bs.name, strings.Join(bs.args, " "))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
v.process.onAfterStart = func(ctx context.Context, bs *backendService, cmd *exec.Cmd) error {
|
v.process.onAfterStart = func(ctx context.Context, bs *backendService, cmd *exec.Cmd) error {
|
||||||
|
@ -625,11 +647,16 @@ type ffmpegClient struct {
|
||||||
|
|
||||||
// FFmpeg cli args, without ffmpeg binary.
|
// FFmpeg cli args, without ffmpeg binary.
|
||||||
args []string
|
args []string
|
||||||
|
// Let the process quit, do not cancel the case.
|
||||||
|
cancelCaseWhenQuit bool
|
||||||
|
// When timeout, stop FFmpeg, sometimes the '-t' does not work.
|
||||||
|
ffmpegDuration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFFmpeg(opts ...func(v *ffmpegClient)) FFmpegClient {
|
func NewFFmpeg(opts ...func(v *ffmpegClient)) FFmpegClient {
|
||||||
v := &ffmpegClient{
|
v := &ffmpegClient{
|
||||||
process: newBackendService(),
|
process: newBackendService(),
|
||||||
|
cancelCaseWhenQuit: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do cleanup.
|
// Do cleanup.
|
||||||
|
@ -657,6 +684,7 @@ func (v *ffmpegClient) Run(ctx context.Context, cancel context.CancelFunc) error
|
||||||
v.process.name = *srsFFmpeg
|
v.process.name = *srsFFmpeg
|
||||||
v.process.args = v.args
|
v.process.args = v.args
|
||||||
v.process.env = os.Environ()
|
v.process.env = os.Environ()
|
||||||
|
v.process.duration = v.ffmpegDuration
|
||||||
|
|
||||||
v.process.onStop = func(ctx context.Context, bs *backendService, cmd *exec.Cmd, r0 error, stdout, stderr *bytes.Buffer) error {
|
v.process.onStop = func(ctx context.Context, bs *backendService, cmd *exec.Cmd, r0 error, stdout, stderr *bytes.Buffer) error {
|
||||||
logger.Tf(ctx, "FFmpeg process pid=%v exit, r0=%v, stdout=%v", bs.pid, r0, stdout.String())
|
logger.Tf(ctx, "FFmpeg process pid=%v exit, r0=%v, stdout=%v", bs.pid, r0, stdout.String())
|
||||||
|
@ -666,7 +694,20 @@ func (v *ffmpegClient) Run(ctx context.Context, cancel context.CancelFunc) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.process.Run(ctx, cancel)
|
// We might not want to cancel the case, for example, when check DVR by session, we just let the FFmpeg process to
|
||||||
|
// quit and we should check the callback and DVR file.
|
||||||
|
ffCtx, ffCancel := context.WithCancel(ctx)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <- ctx.Done():
|
||||||
|
case <-ffCtx.Done():
|
||||||
|
if v.cancelCaseWhenQuit {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return v.process.Run(ffCtx, ffCancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FFprobeClient interface {
|
type FFprobeClient interface {
|
||||||
|
@ -678,16 +719,19 @@ type FFprobeClient interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ffprobeClient struct {
|
type ffprobeClient struct {
|
||||||
// The stream to probe.
|
// The DVR file for ffprobe. Stream should be DVR to file, then use ffprobe to detect it. If DVR by FFmpeg, we will
|
||||||
streamURL string
|
// start a FFmpeg process to do the DVR, or the DVR should be done by other tools.
|
||||||
|
|
||||||
// The DVR file for ffprobe. We DVR stream to file, then use ffprobe to detect it.
|
|
||||||
dvrFile string
|
dvrFile string
|
||||||
// The duration of video file for DVR.
|
|
||||||
duration time.Duration
|
|
||||||
// The timeout to wait for task to done.
|
// The timeout to wait for task to done.
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
|
||||||
|
// Whether do DVR by FFmpeg, if using SRS DVR, please set to false.
|
||||||
|
dvrByFFmpeg bool
|
||||||
|
// The stream to DVR for probing. Ignore if not DVR by ffmpeg
|
||||||
|
streamURL string
|
||||||
|
// The duration of video file for DVR and probing.
|
||||||
|
duration time.Duration
|
||||||
|
|
||||||
// When probe stream metadata object.
|
// When probe stream metadata object.
|
||||||
doneCtx context.Context
|
doneCtx context.Context
|
||||||
doneCancel context.CancelFunc
|
doneCancel context.CancelFunc
|
||||||
|
@ -699,7 +743,8 @@ type ffprobeClient struct {
|
||||||
|
|
||||||
func NewFFprobe(opts ...func(v *ffprobeClient)) FFprobeClient {
|
func NewFFprobe(opts ...func(v *ffprobeClient)) FFprobeClient {
|
||||||
v := &ffprobeClient{
|
v := &ffprobeClient{
|
||||||
metadata: &ffprobeObject{},
|
metadata: &ffprobeObject{},
|
||||||
|
dvrByFFmpeg: true,
|
||||||
}
|
}
|
||||||
v.doneCtx, v.doneCancel = context.WithCancel(context.Background())
|
v.doneCtx, v.doneCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
@ -728,9 +773,12 @@ func (v *ffprobeClient) Run(ctxCase context.Context, cancelCase context.CancelFu
|
||||||
|
|
||||||
// Try to start a DVR process.
|
// Try to start a DVR process.
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
// If error, just ignore and retry, because the stream might not be ready. For example, for HLS, the DVR process
|
// If not DVR by FFmpeg, we just wait the DVR file to be ready, and it should be done by SRS or other tools.
|
||||||
// might need to wait for a duration of segment, 10s as such.
|
if v.dvrByFFmpeg {
|
||||||
_ = v.doDVR(ctx)
|
// If error, just ignore and retry, because the stream might not be ready. For example, for HLS, the DVR process
|
||||||
|
// might need to wait for a duration of segment, 10s as such.
|
||||||
|
_ = v.doDVR(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether DVR file is ok.
|
// Check whether DVR file is ok.
|
||||||
if fs, err := os.Stat(v.dvrFile); err == nil && fs.Size() > 1024 {
|
if fs, err := os.Stat(v.dvrFile); err == nil && fs.Size() > 1024 {
|
||||||
|
@ -738,9 +786,14 @@ func (v *ffprobeClient) Run(ctxCase context.Context, cancelCase context.CancelFu
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not DVR by FFmpeg, must be by other tools, only need to wait.
|
||||||
|
if !v.dvrByFFmpeg {
|
||||||
|
logger.Tf(ctx, "Waiting stream=%v to be DVR", v.streamURL)
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for a while and retry. Use larger timeout for HLS.
|
// Wait for a while and retry. Use larger timeout for HLS.
|
||||||
retryTimeout := 1 * time.Second
|
retryTimeout := 1 * time.Second
|
||||||
if strings.Contains(v.streamURL, ".m3u8") {
|
if strings.Contains(v.streamURL, ".m3u8") || v.dvrFile == "" {
|
||||||
retryTimeout = 3 * time.Second
|
retryTimeout = 3 * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,6 +816,10 @@ func (v *ffprobeClient) Run(ctxCase context.Context, cancelCase context.CancelFu
|
||||||
func (v *ffprobeClient) doDVR(ctx context.Context) error {
|
func (v *ffprobeClient) doDVR(ctx context.Context) error {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
|
if !v.dvrByFFmpeg {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
process := newBackendService()
|
process := newBackendService()
|
||||||
process.name = *srsFFmpeg
|
process.name = *srsFFmpeg
|
||||||
process.args = []string{
|
process.args = []string{
|
||||||
|
@ -1070,3 +1127,167 @@ func (v *ffprobeObject) Audio() *ffprobeObjectMedia {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HooksEvent interface {
|
||||||
|
HookAction() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HooksEventBase struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *HooksEventBase) HookAction() string {
|
||||||
|
return v.Action
|
||||||
|
}
|
||||||
|
|
||||||
|
type HooksEventOnDvr struct {
|
||||||
|
HooksEventBase
|
||||||
|
Stream string `json:"stream"`
|
||||||
|
StreamUrl string `json:"stream_url"`
|
||||||
|
StreamID string `json:"stream_id"`
|
||||||
|
CWD string `json:"cwd"`
|
||||||
|
File string `json:"file"`
|
||||||
|
TcUrl string `json:"tcUrl"`
|
||||||
|
App string `json:"app"`
|
||||||
|
Vhost string `json:"vhost"`
|
||||||
|
IP string `json:"ip"`
|
||||||
|
ClientIP string `json:"client_id"`
|
||||||
|
ServerID string `json:"server_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HooksService interface {
|
||||||
|
ServiceRunner
|
||||||
|
ServiceReadyQuerier
|
||||||
|
HooksAPI() int
|
||||||
|
HooksEvents() <-chan HooksEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
type hooksService struct {
|
||||||
|
readyCtx context.Context
|
||||||
|
readyCancel context.CancelFunc
|
||||||
|
|
||||||
|
httpPort int
|
||||||
|
dispose func()
|
||||||
|
|
||||||
|
r0 error
|
||||||
|
hooksOnDvr chan HooksEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHooksService(opts ...func(v *hooksService)) HooksService {
|
||||||
|
v := &hooksService{}
|
||||||
|
|
||||||
|
v.httpPort = allocator.Allocate()
|
||||||
|
v.dispose = func() {
|
||||||
|
allocator.Free(v.httpPort)
|
||||||
|
close(v.hooksOnDvr)
|
||||||
|
}
|
||||||
|
v.hooksOnDvr = make(chan HooksEvent, 64)
|
||||||
|
v.readyCtx, v.readyCancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *hooksService) ReadyCtx() context.Context {
|
||||||
|
return v.readyCtx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *hooksService) HooksAPI() int {
|
||||||
|
return v.httpPort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *hooksService) HooksEvents() <-chan HooksEvent {
|
||||||
|
return v.hooksOnDvr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *hooksService) Run(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
|
defer func() {
|
||||||
|
v.readyCancel()
|
||||||
|
v.dispose()
|
||||||
|
}()
|
||||||
|
|
||||||
|
handler := http.ServeMux{}
|
||||||
|
handler.HandleFunc("/api/v1/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ohttp.WriteData(ctx, w, r, "pong")
|
||||||
|
})
|
||||||
|
|
||||||
|
handler.HandleFunc("/api/v1/dvrs", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
b, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
ohttp.WriteError(ctx, w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
evt := HooksEventOnDvr{}
|
||||||
|
if err := json.Unmarshal(b, &evt); err != nil {
|
||||||
|
ohttp.WriteError(ctx, w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case v.hooksOnDvr <- &evt:
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Tf(ctx, "Callback: Got on_dvr request %v", string(b))
|
||||||
|
ohttp.WriteData(ctx, w, r, nil)
|
||||||
|
})
|
||||||
|
|
||||||
|
server := &http.Server{Addr: fmt.Sprintf(":%v", v.httpPort), Handler: &handler}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
logger.Tf(ctx, "Callback: Start hooks server, listen=%v", v.httpPort)
|
||||||
|
|
||||||
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
logger.Wf(ctx, "Callback: Service listen=%v, err %v", v.httpPort, err)
|
||||||
|
v.r0 = errors.Wrapf(err, "server listen=%v", v.httpPort)
|
||||||
|
cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Tf(ctx, "Callback: Hooks done, listen=%v", v.httpPort)
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
<-ctx.Done()
|
||||||
|
|
||||||
|
go server.Shutdown(context.Background())
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
for ctx.Err() == nil {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
r := fmt.Sprintf("http://localhost:%v/api/v1/ping", v.httpPort)
|
||||||
|
res, err := http.Get(r)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Tf(ctx, "Callback: API is ready, %v %v", r, string(b))
|
||||||
|
v.readyCancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
return v.r0
|
||||||
|
}
|
||||||
|
|
1
trunk/3rdparty/srs-bench/go.mod
vendored
1
trunk/3rdparty/srs-bench/go.mod
vendored
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/pion/sdp/v3 v3.0.4
|
github.com/pion/sdp/v3 v3.0.4
|
||||||
github.com/pion/transport v0.12.2
|
github.com/pion/transport v0.12.2
|
||||||
github.com/pion/webrtc/v3 v3.0.13
|
github.com/pion/webrtc/v3 v3.0.13
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/yapingcat/gomedia/codec v0.0.0-20220617074658-94762898dc25
|
github.com/yapingcat/gomedia/codec v0.0.0-20220617074658-94762898dc25
|
||||||
github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25
|
github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25
|
||||||
)
|
)
|
||||||
|
|
4
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/error.go
generated
vendored
4
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/sip/parser/error.go
generated
vendored
|
@ -11,9 +11,7 @@ type InvalidStartLineError string
|
||||||
func (err InvalidStartLineError) Syntax() bool { return true }
|
func (err InvalidStartLineError) Syntax() bool { return true }
|
||||||
func (err InvalidStartLineError) Malformed() bool { return false }
|
func (err InvalidStartLineError) Malformed() bool { return false }
|
||||||
func (err InvalidStartLineError) Broken() bool { return true }
|
func (err InvalidStartLineError) Broken() bool { return true }
|
||||||
func (err InvalidStartLineError) Error() string {
|
func (err InvalidStartLineError) Error() string { return "parser.InvalidStartLineError: " + string(err) }
|
||||||
return "parser.InvalidStartLineError: " + string(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InvalidMessageFormat string
|
type InvalidMessageFormat string
|
||||||
|
|
||||||
|
|
87
trunk/3rdparty/srs-bench/vendor/github.com/ossrs/go-oryx-lib/http/api.go
generated
vendored
Normal file
87
trunk/3rdparty/srs-bench/vendor/github.com/ossrs/go-oryx-lib/http/api.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Oryx(ossrs)
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// The oryx http package, the response parse service.
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read http api by HTTP GET and parse the code/data.
|
||||||
|
func ApiRequest(url string) (code int, body []byte, err error) {
|
||||||
|
if body, err = apiGet(url); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if code, _, err = apiParse(url, body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read http api by HTTP GET.
|
||||||
|
func apiGet(url string) (body []byte, err error) {
|
||||||
|
var resp *http.Response
|
||||||
|
if resp, err = http.Get(url); err != nil {
|
||||||
|
err = fmt.Errorf("api get failed, url=%v, err is %v", url, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if body, err = ioutil.ReadAll(resp.Body); err != nil {
|
||||||
|
err = fmt.Errorf("api read failed, url=%v, err is %v", url, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the standard response {code:int,data:object}.
|
||||||
|
func apiParse(url string, body []byte) (code int, data interface{}, err error) {
|
||||||
|
obj := make(map[string]interface{})
|
||||||
|
if err = json.Unmarshal(body, &obj); err != nil {
|
||||||
|
err = fmt.Errorf("api parse failed, url=%v, body=%v, err is %v", url, string(body), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := obj["code"]; !ok {
|
||||||
|
err = fmt.Errorf("api no code, url=%v, body=%v", url, string(body))
|
||||||
|
return
|
||||||
|
} else if value, ok := value.(float64); !ok {
|
||||||
|
err = fmt.Errorf("api code not number, code=%v, url=%v, body=%v", value, url, string(body))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
code = int(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, _ = obj["data"]
|
||||||
|
if code != 0 {
|
||||||
|
err = fmt.Errorf("api error, code=%v, url=%v, body=%v, data=%v", code, url, string(body), data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
274
trunk/3rdparty/srs-bench/vendor/github.com/ossrs/go-oryx-lib/http/http.go
generated
vendored
Normal file
274
trunk/3rdparty/srs-bench/vendor/github.com/ossrs/go-oryx-lib/http/http.go
generated
vendored
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2017 Oryx(ossrs)
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// The oryx http package provides standard request and response in json.
|
||||||
|
// Error, when error, use this handler.
|
||||||
|
// CplxError, for complex error, use this handler.
|
||||||
|
// Data, when no error, use this handler.
|
||||||
|
// SystemError, application level error code.
|
||||||
|
// SetHeader, for direclty response the raw stream.
|
||||||
|
// The standard server response:
|
||||||
|
// code, an int error code.
|
||||||
|
// data, specifies the data.
|
||||||
|
// The api for simple api:
|
||||||
|
// WriteVersion, to directly response the version.
|
||||||
|
// WriteData, to directly write the data in json.
|
||||||
|
// WriteError, to directly write the error.
|
||||||
|
// WriteCplxError, to directly write the complex error.
|
||||||
|
// The global variables:
|
||||||
|
// oh.Server, to set the response header["Server"].
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
ol "github.com/ossrs/go-oryx-lib/logger"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// header["Content-Type"] in response.
|
||||||
|
const (
|
||||||
|
HttpJson = "application/json"
|
||||||
|
HttpJavaScript = "application/javascript"
|
||||||
|
)
|
||||||
|
|
||||||
|
// header["Server"] in response.
|
||||||
|
var Server = "Oryx"
|
||||||
|
|
||||||
|
// system int error.
|
||||||
|
type SystemError int
|
||||||
|
|
||||||
|
func (v SystemError) Error() string {
|
||||||
|
return fmt.Sprintf("System error=%d", int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// system conplex error.
|
||||||
|
type SystemComplexError struct {
|
||||||
|
// the system error code.
|
||||||
|
Code SystemError `json:"code"`
|
||||||
|
// the description for this error.
|
||||||
|
Message string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v SystemComplexError) Error() string {
|
||||||
|
return fmt.Sprintf("%v, %v", v.Code.Error(), v.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// application level, with code.
|
||||||
|
type AppError interface {
|
||||||
|
Code() int
|
||||||
|
error
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP Status Code
|
||||||
|
type HTTPStatus interface {
|
||||||
|
Status() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// http standard error response.
|
||||||
|
// @remark for not SystemError, we will use logger.E to print it.
|
||||||
|
// @remark user can use WriteError() for simple api.
|
||||||
|
func Error(ctx ol.Context, err error) http.Handler {
|
||||||
|
// for complex error, use code instead.
|
||||||
|
if v, ok := err.(SystemComplexError); ok {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
jsonHandler(ctx, FilterCplxSystemError(ctx, w, r, v)).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// for int error, use code instead.
|
||||||
|
if v, ok := err.(SystemError); ok {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
jsonHandler(ctx, FilterSystemError(ctx, w, r, v)).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// for application error, use code instead.
|
||||||
|
if v, ok := err.(AppError); ok {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
jsonHandler(ctx, FilterAppError(ctx, w, r, v)).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown error, log and response detail
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
SetHeader(w)
|
||||||
|
w.Header().Set("Content-Type", HttpJson)
|
||||||
|
|
||||||
|
status := http.StatusInternalServerError
|
||||||
|
if v, ok := err.(HTTPStatus); ok {
|
||||||
|
status = v.Status()
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Error(w, FilterError(ctx, w, r, err), status)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for complex error use Error(ctx, SystemComplexError{})
|
||||||
|
// @remark user can use WriteCplxError() for simple api.
|
||||||
|
func CplxError(ctx ol.Context, code SystemError, message string) http.Handler {
|
||||||
|
return Error(ctx, SystemComplexError{code, message})
|
||||||
|
}
|
||||||
|
|
||||||
|
// http normal response.
|
||||||
|
// @remark user can use nil v to response success, which data is null.
|
||||||
|
// @remark user can use WriteData() for simple api.
|
||||||
|
func Data(ctx ol.Context, v interface{}) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
jsonHandler(ctx, FilterData(ctx, w, r, v)).ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// set http header, for directly use the w,
|
||||||
|
// for example, user want to directly write raw text.
|
||||||
|
func SetHeader(w http.ResponseWriter) {
|
||||||
|
w.Header().Set("Server", Server)
|
||||||
|
}
|
||||||
|
|
||||||
|
// response json directly.
|
||||||
|
func jsonHandler(ctx ol.Context, rv interface{}) http.Handler {
|
||||||
|
var err error
|
||||||
|
var b []byte
|
||||||
|
if b, err = json.Marshal(rv); err != nil {
|
||||||
|
return Error(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
status := http.StatusOK
|
||||||
|
if v, ok := rv.(HTTPStatus); ok {
|
||||||
|
status = v.Status()
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
SetHeader(w)
|
||||||
|
|
||||||
|
q := r.URL.Query()
|
||||||
|
if cb := q.Get("callback"); cb != "" {
|
||||||
|
w.Header().Set("Content-Type", HttpJavaScript)
|
||||||
|
if status != http.StatusOK {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle error.
|
||||||
|
fmt.Fprintf(w, "%s(%s)", cb, string(b))
|
||||||
|
} else {
|
||||||
|
w.Header().Set("Content-Type", HttpJson)
|
||||||
|
if status != http.StatusOK {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
}
|
||||||
|
// TODO: Handle error.
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// response the standard version info:
|
||||||
|
// {code, server, data} where server is the server pid, and data is below object:
|
||||||
|
// {major, minor, revision, extra, version, signature}
|
||||||
|
// @param version in {major.minor.revision-extra}, where -extra is optional,
|
||||||
|
// for example: 1.0.0 or 1.0.0-0 or 1.0.0-1
|
||||||
|
func WriteVersion(w http.ResponseWriter, r *http.Request, version string) {
|
||||||
|
var major, minor, revision, extra int
|
||||||
|
|
||||||
|
versions := strings.Split(version, "-")
|
||||||
|
if len(versions) > 1 {
|
||||||
|
extra, _ = strconv.Atoi(versions[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
versions = strings.Split(versions[0], ".")
|
||||||
|
if len(versions) > 0 {
|
||||||
|
major, _ = strconv.Atoi(versions[0])
|
||||||
|
}
|
||||||
|
if len(versions) > 1 {
|
||||||
|
minor, _ = strconv.Atoi(versions[1])
|
||||||
|
}
|
||||||
|
if len(versions) > 2 {
|
||||||
|
revision, _ = strconv.Atoi(versions[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
Data(nil, map[string]interface{}{
|
||||||
|
"major": major,
|
||||||
|
"minor": minor,
|
||||||
|
"revision": revision,
|
||||||
|
"extra": extra,
|
||||||
|
"version": version,
|
||||||
|
"signature": Server,
|
||||||
|
}).ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directly write json data, a wrapper for Data().
|
||||||
|
// @remark user can use Data() for group of complex apis.
|
||||||
|
func WriteData(ctx ol.Context, w http.ResponseWriter, r *http.Request, v interface{}) {
|
||||||
|
Data(ctx, v).ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directly write success json response, same to WriteData(ctx, w, r, nil).
|
||||||
|
func Success(ctx ol.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
WriteData(ctx, w, r, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directly write error, a wrapper for Error().
|
||||||
|
// @remark user can use Error() for group of complex apis.
|
||||||
|
func WriteError(ctx ol.Context, w http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
Error(ctx, err).ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directly write complex error, a wrappter for CplxError().
|
||||||
|
// @remark user can use CplxError() for group of complex apis.
|
||||||
|
func WriteCplxError(ctx ol.Context, w http.ResponseWriter, r *http.Request, code SystemError, message string) {
|
||||||
|
CplxError(ctx, code, message).ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for hijack to define the response structure.
|
||||||
|
// user can redefine these functions for special response.
|
||||||
|
var FilterCplxSystemError = func(ctx ol.Context, w http.ResponseWriter, r *http.Request, o SystemComplexError) interface{} {
|
||||||
|
ol.Ef(ctx, "Serve %v failed, err is %+v", r.URL, o)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
var FilterSystemError = func(ctx ol.Context, w http.ResponseWriter, r *http.Request, o SystemError) interface{} {
|
||||||
|
ol.Ef(ctx, "Serve %v failed, err is %+v", r.URL, o)
|
||||||
|
return map[string]int{"code": int(o)}
|
||||||
|
}
|
||||||
|
var FilterAppError = func(ctx ol.Context, w http.ResponseWriter, r *http.Request, err AppError) interface{} {
|
||||||
|
ol.Ef(ctx, "Serve %v failed, err is %+v", r.URL, err)
|
||||||
|
return map[string]interface{}{"code": err.Code(), "data": err.Error()}
|
||||||
|
}
|
||||||
|
var FilterError = func(ctx ol.Context, w http.ResponseWriter, r *http.Request, err error) string {
|
||||||
|
ol.Ef(ctx, "Serve %v failed, err is %+v", r.URL, err)
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
var FilterData = func(ctx ol.Context, w http.ResponseWriter, r *http.Request, o interface{}) interface{} {
|
||||||
|
rv := map[string]interface{}{
|
||||||
|
"code": 0,
|
||||||
|
"server": os.Getpid(),
|
||||||
|
"data": o,
|
||||||
|
}
|
||||||
|
|
||||||
|
// for string, directly use it without convert,
|
||||||
|
// for the type covert by golang maybe modify the content.
|
||||||
|
if v, ok := o.(string); ok {
|
||||||
|
rv["data"] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv
|
||||||
|
}
|
1
trunk/3rdparty/srs-bench/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
generated
vendored
1
trunk/3rdparty/srs-bench/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
generated
vendored
|
@ -10,3 +10,4 @@ func isTerminal(fd int) bool {
|
||||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
trunk/3rdparty/srs-bench/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
generated
vendored
1
trunk/3rdparty/srs-bench/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
generated
vendored
|
@ -10,3 +10,4 @@ func isTerminal(fd int) bool {
|
||||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mgutz/ansi"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/mgutz/ansi"
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
274
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/aac.go
generated
vendored
274
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/aac.go
generated
vendored
|
@ -12,25 +12,25 @@ import "errors"
|
||||||
type AAC_PROFILE int
|
type AAC_PROFILE int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MAIN AAC_PROFILE = iota
|
MAIN AAC_PROFILE = iota
|
||||||
LC
|
LC
|
||||||
SSR
|
SSR
|
||||||
)
|
)
|
||||||
|
|
||||||
type AAC_SAMPLING_FREQUENCY int
|
type AAC_SAMPLING_FREQUENCY int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AAC_SAMPLE_96000 AAC_SAMPLING_FREQUENCY = iota
|
AAC_SAMPLE_96000 AAC_SAMPLING_FREQUENCY = iota
|
||||||
AAC_SAMPLE_88200
|
AAC_SAMPLE_88200
|
||||||
AAC_SAMPLE_64000
|
AAC_SAMPLE_64000
|
||||||
AAC_SAMPLE_48000
|
AAC_SAMPLE_48000
|
||||||
AAC_SAMPLE_44100
|
AAC_SAMPLE_44100
|
||||||
AAC_SAMPLE_32000
|
AAC_SAMPLE_32000
|
||||||
AAC_SAMPLE_24000
|
AAC_SAMPLE_24000
|
||||||
AAC_SAMPLE_22050
|
AAC_SAMPLE_22050
|
||||||
AAC_SAMPLE_16000
|
AAC_SAMPLE_16000
|
||||||
AAC_SAMPLE_11025
|
AAC_SAMPLE_11025
|
||||||
AAC_SAMPLE_8000
|
AAC_SAMPLE_8000
|
||||||
)
|
)
|
||||||
|
|
||||||
var AAC_Sampling_Idx [11]int = [11]int{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}
|
var AAC_Sampling_Idx [11]int = [11]int{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}
|
||||||
|
@ -73,15 +73,15 @@ var AAC_Sampling_Idx [11]int = [11]int{96000, 88200, 64000, 48000, 44100, 32000,
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type ADTS_Fix_Header struct {
|
type ADTS_Fix_Header struct {
|
||||||
ID uint8
|
ID uint8
|
||||||
Layer uint8
|
Layer uint8
|
||||||
Protection_absent uint8
|
Protection_absent uint8
|
||||||
Profile uint8
|
Profile uint8
|
||||||
Sampling_frequency_index uint8
|
Sampling_frequency_index uint8
|
||||||
Private_bit uint8
|
Private_bit uint8
|
||||||
Channel_configuration uint8
|
Channel_configuration uint8
|
||||||
Originalorcopy uint8
|
Originalorcopy uint8
|
||||||
Home uint8
|
Home uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// adts_variable_header() {
|
// adts_variable_header() {
|
||||||
|
@ -93,91 +93,91 @@ type ADTS_Fix_Header struct {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type ADTS_Variable_Header struct {
|
type ADTS_Variable_Header struct {
|
||||||
Copyright_identification_bit uint8
|
Copyright_identification_bit uint8
|
||||||
copyright_identification_start uint8
|
copyright_identification_start uint8
|
||||||
Frame_length uint16
|
Frame_length uint16
|
||||||
Adts_buffer_fullness uint16
|
Adts_buffer_fullness uint16
|
||||||
Number_of_raw_data_blocks_in_frame uint8
|
Number_of_raw_data_blocks_in_frame uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type ADTS_Frame_Header struct {
|
type ADTS_Frame_Header struct {
|
||||||
Fix_Header ADTS_Fix_Header
|
Fix_Header ADTS_Fix_Header
|
||||||
Variable_Header ADTS_Variable_Header
|
Variable_Header ADTS_Variable_Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAdtsFrameHeader() *ADTS_Frame_Header {
|
func NewAdtsFrameHeader() *ADTS_Frame_Header {
|
||||||
return &ADTS_Frame_Header{
|
return &ADTS_Frame_Header{
|
||||||
Fix_Header: ADTS_Fix_Header{
|
Fix_Header: ADTS_Fix_Header{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
Layer: 0,
|
Layer: 0,
|
||||||
Protection_absent: 1,
|
Protection_absent: 1,
|
||||||
Profile: uint8(MAIN),
|
Profile: uint8(MAIN),
|
||||||
Sampling_frequency_index: uint8(AAC_SAMPLE_44100),
|
Sampling_frequency_index: uint8(AAC_SAMPLE_44100),
|
||||||
Private_bit: 0,
|
Private_bit: 0,
|
||||||
Channel_configuration: 0,
|
Channel_configuration: 0,
|
||||||
Originalorcopy: 0,
|
Originalorcopy: 0,
|
||||||
Home: 0,
|
Home: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
Variable_Header: ADTS_Variable_Header{
|
Variable_Header: ADTS_Variable_Header{
|
||||||
copyright_identification_start: 0,
|
copyright_identification_start: 0,
|
||||||
Copyright_identification_bit: 0,
|
Copyright_identification_bit: 0,
|
||||||
Frame_length: 0,
|
Frame_length: 0,
|
||||||
Adts_buffer_fullness: 0,
|
Adts_buffer_fullness: 0,
|
||||||
Number_of_raw_data_blocks_in_frame: 0,
|
Number_of_raw_data_blocks_in_frame: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (frame *ADTS_Frame_Header) Decode(aac []byte) error {
|
func (frame *ADTS_Frame_Header) Decode(aac []byte) error {
|
||||||
_ = aac[6]
|
_ = aac[6]
|
||||||
frame.Fix_Header.ID = aac[1] >> 3
|
frame.Fix_Header.ID = aac[1] >> 3
|
||||||
frame.Fix_Header.Layer = aac[1] >> 1 & 0x03
|
frame.Fix_Header.Layer = aac[1] >> 1 & 0x03
|
||||||
frame.Fix_Header.Protection_absent = aac[1] & 0x01
|
frame.Fix_Header.Protection_absent = aac[1] & 0x01
|
||||||
frame.Fix_Header.Profile = aac[2] >> 6 & 0x03
|
frame.Fix_Header.Profile = aac[2] >> 6 & 0x03
|
||||||
frame.Fix_Header.Sampling_frequency_index = aac[2] >> 2 & 0x0F
|
frame.Fix_Header.Sampling_frequency_index = aac[2] >> 2 & 0x0F
|
||||||
frame.Fix_Header.Private_bit = aac[2] >> 1 & 0x01
|
frame.Fix_Header.Private_bit = aac[2] >> 1 & 0x01
|
||||||
frame.Fix_Header.Channel_configuration = (aac[2] & 0x01 << 2) | (aac[3] >> 6)
|
frame.Fix_Header.Channel_configuration = (aac[2] & 0x01 << 2) | (aac[3] >> 6)
|
||||||
frame.Fix_Header.Originalorcopy = aac[3] >> 5 & 0x01
|
frame.Fix_Header.Originalorcopy = aac[3] >> 5 & 0x01
|
||||||
frame.Fix_Header.Home = aac[3] >> 4 & 0x01
|
frame.Fix_Header.Home = aac[3] >> 4 & 0x01
|
||||||
frame.Variable_Header.Copyright_identification_bit = aac[3] >> 3 & 0x01
|
frame.Variable_Header.Copyright_identification_bit = aac[3] >> 3 & 0x01
|
||||||
frame.Variable_Header.copyright_identification_start = aac[3] >> 2 & 0x01
|
frame.Variable_Header.copyright_identification_start = aac[3] >> 2 & 0x01
|
||||||
frame.Variable_Header.Frame_length = (uint16(aac[3]&0x03) << 11) | (uint16(aac[4]) << 3) | (uint16(aac[5]>>5) & 0x07)
|
frame.Variable_Header.Frame_length = (uint16(aac[3]&0x03) << 11) | (uint16(aac[4]) << 3) | (uint16(aac[5]>>5) & 0x07)
|
||||||
frame.Variable_Header.Adts_buffer_fullness = (uint16(aac[5]&0x1F) << 6) | uint16(aac[6]>>2)
|
frame.Variable_Header.Adts_buffer_fullness = (uint16(aac[5]&0x1F) << 6) | uint16(aac[6]>>2)
|
||||||
frame.Variable_Header.Number_of_raw_data_blocks_in_frame = aac[6] & 0x03
|
frame.Variable_Header.Number_of_raw_data_blocks_in_frame = aac[6] & 0x03
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (frame *ADTS_Frame_Header) Encode() []byte {
|
func (frame *ADTS_Frame_Header) Encode() []byte {
|
||||||
var hdr []byte
|
var hdr []byte
|
||||||
if frame.Fix_Header.Protection_absent == 1 {
|
if frame.Fix_Header.Protection_absent == 1 {
|
||||||
hdr = make([]byte, 7)
|
hdr = make([]byte, 7)
|
||||||
} else {
|
} else {
|
||||||
hdr = make([]byte, 9)
|
hdr = make([]byte, 9)
|
||||||
}
|
}
|
||||||
hdr[0] = 0xFF
|
hdr[0] = 0xFF
|
||||||
hdr[1] = 0xF0
|
hdr[1] = 0xF0
|
||||||
hdr[1] = hdr[1] | (frame.Fix_Header.ID << 3) | (frame.Fix_Header.Layer << 1) | frame.Fix_Header.Protection_absent
|
hdr[1] = hdr[1] | (frame.Fix_Header.ID << 3) | (frame.Fix_Header.Layer << 1) | frame.Fix_Header.Protection_absent
|
||||||
hdr[2] = frame.Fix_Header.Profile<<6 | frame.Fix_Header.Sampling_frequency_index<<2 | frame.Fix_Header.Private_bit<<1 | frame.Fix_Header.Channel_configuration>>2
|
hdr[2] = frame.Fix_Header.Profile<<6 | frame.Fix_Header.Sampling_frequency_index<<2 | frame.Fix_Header.Private_bit<<1 | frame.Fix_Header.Channel_configuration>>2
|
||||||
hdr[3] = frame.Fix_Header.Channel_configuration<<6 | frame.Fix_Header.Originalorcopy<<5 | frame.Fix_Header.Home<<4
|
hdr[3] = frame.Fix_Header.Channel_configuration<<6 | frame.Fix_Header.Originalorcopy<<5 | frame.Fix_Header.Home<<4
|
||||||
hdr[3] = hdr[3] | frame.Variable_Header.copyright_identification_start<<3 | frame.Variable_Header.Copyright_identification_bit<<2 | byte(frame.Variable_Header.Frame_length<<11)
|
hdr[3] = hdr[3] | frame.Variable_Header.copyright_identification_start<<3 | frame.Variable_Header.Copyright_identification_bit<<2 | byte(frame.Variable_Header.Frame_length<<11)
|
||||||
hdr[4] = byte(frame.Variable_Header.Frame_length >> 3)
|
hdr[4] = byte(frame.Variable_Header.Frame_length >> 3)
|
||||||
hdr[5] = byte((frame.Variable_Header.Frame_length&0x07)<<5) | byte(frame.Variable_Header.Adts_buffer_fullness>>3)
|
hdr[5] = byte((frame.Variable_Header.Frame_length&0x07)<<5) | byte(frame.Variable_Header.Adts_buffer_fullness>>3)
|
||||||
hdr[6] = byte(frame.Variable_Header.Adts_buffer_fullness&0x3F<<2) | frame.Variable_Header.Number_of_raw_data_blocks_in_frame
|
hdr[6] = byte(frame.Variable_Header.Adts_buffer_fullness&0x3F<<2) | frame.Variable_Header.Number_of_raw_data_blocks_in_frame
|
||||||
return hdr
|
return hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
func SampleToAACSampleIndex(sampling int) int {
|
func SampleToAACSampleIndex(sampling int) int {
|
||||||
for i, v := range AAC_Sampling_Idx {
|
for i, v := range AAC_Sampling_Idx {
|
||||||
if v == sampling {
|
if v == sampling {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("not Found AAC Sample Index")
|
panic("not Found AAC Sample Index")
|
||||||
}
|
}
|
||||||
|
|
||||||
func AACSampleIdxToSample(idx int) int {
|
func AACSampleIdxToSample(idx int) int {
|
||||||
return AAC_Sampling_Idx[idx]
|
return AAC_Sampling_Idx[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
// +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
@ -185,71 +185,71 @@ func AACSampleIdxToSample(idx int) int {
|
||||||
// +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
// +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
type AudioSpecificConfiguration struct {
|
type AudioSpecificConfiguration struct {
|
||||||
Audio_object_type uint8
|
Audio_object_type uint8
|
||||||
Sample_freq_index uint8
|
Sample_freq_index uint8
|
||||||
Channel_configuration uint8
|
Channel_configuration uint8
|
||||||
GA_framelength_flag uint8
|
GA_framelength_flag uint8
|
||||||
GA_depends_on_core_coder uint8
|
GA_depends_on_core_coder uint8
|
||||||
GA_extension_flag uint8
|
GA_extension_flag uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAudioSpecificConfiguration() *AudioSpecificConfiguration {
|
func NewAudioSpecificConfiguration() *AudioSpecificConfiguration {
|
||||||
return &AudioSpecificConfiguration{
|
return &AudioSpecificConfiguration{
|
||||||
Audio_object_type: 0,
|
Audio_object_type: 0,
|
||||||
Sample_freq_index: 0,
|
Sample_freq_index: 0,
|
||||||
Channel_configuration: 0,
|
Channel_configuration: 0,
|
||||||
GA_framelength_flag: 0,
|
GA_framelength_flag: 0,
|
||||||
GA_depends_on_core_coder: 0,
|
GA_depends_on_core_coder: 0,
|
||||||
GA_extension_flag: 0,
|
GA_extension_flag: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (asc *AudioSpecificConfiguration) Encode() []byte {
|
func (asc *AudioSpecificConfiguration) Encode() []byte {
|
||||||
buf := make([]byte, 2)
|
buf := make([]byte, 2)
|
||||||
buf[0] = (asc.Audio_object_type & 0x1f << 3) | (asc.Sample_freq_index & 0x0F >> 1)
|
buf[0] = (asc.Audio_object_type & 0x1f << 3) | (asc.Sample_freq_index & 0x0F >> 1)
|
||||||
buf[1] = (asc.Sample_freq_index & 0x0F << 7) | (asc.Channel_configuration & 0x0F << 3) | (asc.GA_framelength_flag & 0x01 << 2) | (asc.GA_depends_on_core_coder & 0x01 << 1) | (asc.GA_extension_flag & 0x01)
|
buf[1] = (asc.Sample_freq_index & 0x0F << 7) | (asc.Channel_configuration & 0x0F << 3) | (asc.GA_framelength_flag & 0x01 << 2) | (asc.GA_depends_on_core_coder & 0x01 << 1) | (asc.GA_extension_flag & 0x01)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (asc *AudioSpecificConfiguration) Decode(buf []byte) error {
|
func (asc *AudioSpecificConfiguration) Decode(buf []byte) error {
|
||||||
|
|
||||||
if len(buf) < 2 {
|
if len(buf) < 2 {
|
||||||
return errors.New("len of buf < 2 ")
|
return errors.New("len of buf < 2 ")
|
||||||
}
|
}
|
||||||
|
|
||||||
asc.Audio_object_type = buf[0] >> 3
|
asc.Audio_object_type = buf[0] >> 3
|
||||||
asc.Sample_freq_index = (buf[0] & 0x07 << 1) | (buf[1] >> 7)
|
asc.Sample_freq_index = (buf[0] & 0x07 << 1) | (buf[1] >> 7)
|
||||||
asc.Channel_configuration = buf[1] >> 3 & 0x0F
|
asc.Channel_configuration = buf[1] >> 3 & 0x0F
|
||||||
asc.GA_framelength_flag = buf[1] >> 2 & 0x01
|
asc.GA_framelength_flag = buf[1] >> 2 & 0x01
|
||||||
asc.GA_depends_on_core_coder = buf[1] >> 1 & 0x01
|
asc.GA_depends_on_core_coder = buf[1] >> 1 & 0x01
|
||||||
asc.GA_extension_flag = buf[1] & 0x01
|
asc.GA_extension_flag = buf[1] & 0x01
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertADTSToASC(frame []byte) ([]byte, error) {
|
func ConvertADTSToASC(frame []byte) ([]byte, error) {
|
||||||
|
|
||||||
if len(frame) < 7 {
|
if len(frame) < 7 {
|
||||||
return nil, errors.New("len of frame < 7")
|
return nil, errors.New("len of frame < 7")
|
||||||
}
|
}
|
||||||
|
|
||||||
adts := NewAdtsFrameHeader()
|
adts := NewAdtsFrameHeader()
|
||||||
adts.Decode(frame)
|
adts.Decode(frame)
|
||||||
asc := NewAudioSpecificConfiguration()
|
asc := NewAudioSpecificConfiguration()
|
||||||
asc.Audio_object_type = adts.Fix_Header.Profile + 1
|
asc.Audio_object_type = adts.Fix_Header.Profile + 1
|
||||||
asc.Channel_configuration = adts.Fix_Header.Channel_configuration
|
asc.Channel_configuration = adts.Fix_Header.Channel_configuration
|
||||||
asc.Sample_freq_index = adts.Fix_Header.Sampling_frequency_index
|
asc.Sample_freq_index = adts.Fix_Header.Sampling_frequency_index
|
||||||
return asc.Encode(), nil
|
return asc.Encode(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertASCToADTS(asc []byte, aacbytes int) []byte {
|
func ConvertASCToADTS(asc []byte, aacbytes int) []byte {
|
||||||
aac_asc := NewAudioSpecificConfiguration()
|
aac_asc := NewAudioSpecificConfiguration()
|
||||||
aac_asc.Decode(asc)
|
aac_asc.Decode(asc)
|
||||||
aac_adts := NewAdtsFrameHeader()
|
aac_adts := NewAdtsFrameHeader()
|
||||||
aac_adts.Fix_Header.Profile = aac_asc.Audio_object_type - 1
|
aac_adts.Fix_Header.Profile = aac_asc.Audio_object_type - 1
|
||||||
aac_adts.Fix_Header.Channel_configuration = aac_asc.Channel_configuration
|
aac_adts.Fix_Header.Channel_configuration = aac_asc.Channel_configuration
|
||||||
aac_adts.Fix_Header.Sampling_frequency_index = aac_asc.Sample_freq_index
|
aac_adts.Fix_Header.Sampling_frequency_index = aac_asc.Sample_freq_index
|
||||||
aac_adts.Fix_Header.Protection_absent = 1
|
aac_adts.Fix_Header.Protection_absent = 1
|
||||||
aac_adts.Variable_Header.Adts_buffer_fullness = 0x3F
|
aac_adts.Variable_Header.Adts_buffer_fullness = 0x3F
|
||||||
aac_adts.Variable_Header.Frame_length = uint16(aacbytes)
|
aac_adts.Variable_Header.Frame_length = uint16(aacbytes)
|
||||||
return aac_adts.Encode()
|
return aac_adts.Encode()
|
||||||
}
|
}
|
||||||
|
|
454
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/bitstream.go
generated
vendored
454
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/bitstream.go
generated
vendored
|
@ -1,358 +1,358 @@
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
)
|
)
|
||||||
|
|
||||||
var BitMask [8]byte = [8]byte{0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}
|
var BitMask [8]byte = [8]byte{0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}
|
||||||
|
|
||||||
type BitStream struct {
|
type BitStream struct {
|
||||||
bits []byte
|
bits []byte
|
||||||
bytesOffset int
|
bytesOffset int
|
||||||
bitsOffset int
|
bitsOffset int
|
||||||
bitsmark int
|
bitsmark int
|
||||||
bytemark int
|
bytemark int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBitStream(buf []byte) *BitStream {
|
func NewBitStream(buf []byte) *BitStream {
|
||||||
return &BitStream{
|
return &BitStream{
|
||||||
bits: buf,
|
bits: buf,
|
||||||
bytesOffset: 0,
|
bytesOffset: 0,
|
||||||
bitsOffset: 0,
|
bitsOffset: 0,
|
||||||
bitsmark: 0,
|
bitsmark: 0,
|
||||||
bytemark: 0,
|
bytemark: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) Uint8(n int) uint8 {
|
func (bs *BitStream) Uint8(n int) uint8 {
|
||||||
return uint8(bs.GetBits(n))
|
return uint8(bs.GetBits(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) Uint16(n int) uint16 {
|
func (bs *BitStream) Uint16(n int) uint16 {
|
||||||
return uint16(bs.GetBits(n))
|
return uint16(bs.GetBits(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) Uint32(n int) uint32 {
|
func (bs *BitStream) Uint32(n int) uint32 {
|
||||||
return uint32(bs.GetBits(n))
|
return uint32(bs.GetBits(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) GetBytes(n int) []byte {
|
func (bs *BitStream) GetBytes(n int) []byte {
|
||||||
if bs.bytesOffset+n > len(bs.bits) {
|
if bs.bytesOffset+n > len(bs.bits) {
|
||||||
panic("OUT OF RANGE")
|
panic("OUT OF RANGE")
|
||||||
}
|
}
|
||||||
if bs.bitsOffset != 0 {
|
if bs.bitsOffset != 0 {
|
||||||
panic("invaild operation")
|
panic("invaild operation")
|
||||||
}
|
}
|
||||||
data := make([]byte, n)
|
data := make([]byte, n)
|
||||||
copy(data, bs.bits[bs.bytesOffset:bs.bytesOffset+n])
|
copy(data, bs.bits[bs.bytesOffset:bs.bytesOffset+n])
|
||||||
bs.bytesOffset += n
|
bs.bytesOffset += n
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
//n <= 64
|
//n <= 64
|
||||||
func (bs *BitStream) GetBits(n int) uint64 {
|
func (bs *BitStream) GetBits(n int) uint64 {
|
||||||
if bs.bytesOffset >= len(bs.bits) {
|
if bs.bytesOffset >= len(bs.bits) {
|
||||||
panic("OUT OF RANGE")
|
panic("OUT OF RANGE")
|
||||||
}
|
}
|
||||||
var ret uint64 = 0
|
var ret uint64 = 0
|
||||||
if 8-bs.bitsOffset >= n {
|
if 8-bs.bitsOffset >= n {
|
||||||
ret = uint64((bs.bits[bs.bytesOffset] >> (8 - bs.bitsOffset - n)) & BitMask[n-1])
|
ret = uint64((bs.bits[bs.bytesOffset] >> (8 - bs.bitsOffset - n)) & BitMask[n-1])
|
||||||
bs.bitsOffset += n
|
bs.bitsOffset += n
|
||||||
if bs.bitsOffset == 8 {
|
if bs.bitsOffset == 8 {
|
||||||
bs.bytesOffset++
|
bs.bytesOffset++
|
||||||
bs.bitsOffset = 0
|
bs.bitsOffset = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = uint64(bs.bits[bs.bytesOffset] & BitMask[8-bs.bitsOffset-1])
|
ret = uint64(bs.bits[bs.bytesOffset] & BitMask[8-bs.bitsOffset-1])
|
||||||
bs.bytesOffset++
|
bs.bytesOffset++
|
||||||
n -= 8 - bs.bitsOffset
|
n -= 8 - bs.bitsOffset
|
||||||
bs.bitsOffset = 0
|
bs.bitsOffset = 0
|
||||||
for n > 0 {
|
for n > 0 {
|
||||||
if bs.bytesOffset >= len(bs.bits) {
|
if bs.bytesOffset >= len(bs.bits) {
|
||||||
panic("OUT OF RANGE")
|
panic("OUT OF RANGE")
|
||||||
}
|
}
|
||||||
if n >= 8 {
|
if n >= 8 {
|
||||||
ret = ret<<8 | uint64(bs.bits[bs.bytesOffset])
|
ret = ret<<8 | uint64(bs.bits[bs.bytesOffset])
|
||||||
bs.bytesOffset++
|
bs.bytesOffset++
|
||||||
n -= 8
|
n -= 8
|
||||||
} else {
|
} else {
|
||||||
ret = (ret << n) | uint64((bs.bits[bs.bytesOffset]>>(8-n))&BitMask[n-1])
|
ret = (ret << n) | uint64((bs.bits[bs.bytesOffset]>>(8-n))&BitMask[n-1])
|
||||||
bs.bitsOffset = n
|
bs.bitsOffset = n
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) GetBit() uint8 {
|
func (bs *BitStream) GetBit() uint8 {
|
||||||
if bs.bytesOffset >= len(bs.bits) {
|
if bs.bytesOffset >= len(bs.bits) {
|
||||||
panic("OUT OF RANGE")
|
panic("OUT OF RANGE")
|
||||||
}
|
}
|
||||||
ret := bs.bits[bs.bytesOffset] >> (7 - bs.bitsOffset) & 0x01
|
ret := bs.bits[bs.bytesOffset] >> (7 - bs.bitsOffset) & 0x01
|
||||||
bs.bitsOffset++
|
bs.bitsOffset++
|
||||||
if bs.bitsOffset >= 8 {
|
if bs.bitsOffset >= 8 {
|
||||||
bs.bytesOffset++
|
bs.bytesOffset++
|
||||||
bs.bitsOffset = 0
|
bs.bitsOffset = 0
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) SkipBits(n int) {
|
func (bs *BitStream) SkipBits(n int) {
|
||||||
bytecount := n / 8
|
bytecount := n / 8
|
||||||
bitscount := n % 8
|
bitscount := n % 8
|
||||||
bs.bytesOffset += bytecount
|
bs.bytesOffset += bytecount
|
||||||
if bs.bitsOffset+bitscount < 8 {
|
if bs.bitsOffset+bitscount < 8 {
|
||||||
bs.bitsOffset += bitscount
|
bs.bitsOffset += bitscount
|
||||||
} else {
|
} else {
|
||||||
bs.bytesOffset += 1
|
bs.bytesOffset += 1
|
||||||
bs.bitsOffset += bitscount - 8
|
bs.bitsOffset += bitscount - 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) Markdot() {
|
func (bs *BitStream) Markdot() {
|
||||||
bs.bitsmark = bs.bitsOffset
|
bs.bitsmark = bs.bitsOffset
|
||||||
bs.bytemark = bs.bytesOffset
|
bs.bytemark = bs.bytesOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) DistanceFromMarkDot() int {
|
func (bs *BitStream) DistanceFromMarkDot() int {
|
||||||
bytecount := bs.bytesOffset - bs.bytemark - 1
|
bytecount := bs.bytesOffset - bs.bytemark - 1
|
||||||
bitscount := bs.bitsOffset + (8 - bs.bitsmark)
|
bitscount := bs.bitsOffset + (8 - bs.bitsmark)
|
||||||
return bytecount*8 + bitscount
|
return bytecount*8 + bitscount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) RemainBytes() int {
|
func (bs *BitStream) RemainBytes() int {
|
||||||
if bs.bitsOffset > 0 {
|
if bs.bitsOffset > 0 {
|
||||||
return len(bs.bits) - bs.bytesOffset - 1
|
return len(bs.bits) - bs.bytesOffset - 1
|
||||||
} else {
|
} else {
|
||||||
return len(bs.bits) - bs.bytesOffset
|
return len(bs.bits) - bs.bytesOffset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) RemainBits() int {
|
func (bs *BitStream) RemainBits() int {
|
||||||
if bs.bitsOffset > 0 {
|
if bs.bitsOffset > 0 {
|
||||||
return bs.RemainBytes()*8 + 8 - bs.bitsOffset
|
return bs.RemainBytes()*8 + 8 - bs.bitsOffset
|
||||||
} else {
|
} else {
|
||||||
return bs.RemainBytes() * 8
|
return bs.RemainBytes() * 8
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) Bits() []byte {
|
func (bs *BitStream) Bits() []byte {
|
||||||
return bs.bits
|
return bs.bits
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) RemainData() []byte {
|
func (bs *BitStream) RemainData() []byte {
|
||||||
return bs.bits[bs.bytesOffset:]
|
return bs.bits[bs.bytesOffset:]
|
||||||
}
|
}
|
||||||
|
|
||||||
//无符号哥伦布熵编码
|
//无符号哥伦布熵编码
|
||||||
func (bs *BitStream) ReadUE() uint64 {
|
func (bs *BitStream) ReadUE() uint64 {
|
||||||
leadingZeroBits := 0
|
leadingZeroBits := 0
|
||||||
for bs.GetBit() == 0 {
|
for bs.GetBit() == 0 {
|
||||||
leadingZeroBits++
|
leadingZeroBits++
|
||||||
}
|
}
|
||||||
if leadingZeroBits == 0 {
|
if leadingZeroBits == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
info := bs.GetBits(leadingZeroBits)
|
info := bs.GetBits(leadingZeroBits)
|
||||||
return uint64(1)<<leadingZeroBits - 1 + info
|
return uint64(1)<<leadingZeroBits - 1 + info
|
||||||
}
|
}
|
||||||
|
|
||||||
//有符号哥伦布熵编码
|
//有符号哥伦布熵编码
|
||||||
func (bs *BitStream) ReadSE() int64 {
|
func (bs *BitStream) ReadSE() int64 {
|
||||||
v := bs.ReadUE()
|
v := bs.ReadUE()
|
||||||
if v%2 == 0 {
|
if v%2 == 0 {
|
||||||
return -1 * int64(v/2)
|
return -1 * int64(v/2)
|
||||||
} else {
|
} else {
|
||||||
return int64(v+1) / 2
|
return int64(v+1) / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) ByteOffset() int {
|
func (bs *BitStream) ByteOffset() int {
|
||||||
return bs.bytesOffset
|
return bs.bytesOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) UnRead(n int) {
|
func (bs *BitStream) UnRead(n int) {
|
||||||
if n-bs.bitsOffset <= 0 {
|
if n-bs.bitsOffset <= 0 {
|
||||||
bs.bitsOffset -= n
|
bs.bitsOffset -= n
|
||||||
} else {
|
} else {
|
||||||
least := n - bs.bitsOffset
|
least := n - bs.bitsOffset
|
||||||
for least >= 8 {
|
for least >= 8 {
|
||||||
bs.bytesOffset--
|
bs.bytesOffset--
|
||||||
least -= 8
|
least -= 8
|
||||||
}
|
}
|
||||||
if least > 0 {
|
if least > 0 {
|
||||||
bs.bytesOffset--
|
bs.bytesOffset--
|
||||||
bs.bitsOffset = 8 - least
|
bs.bitsOffset = 8 - least
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) NextBits(n int) uint64 {
|
func (bs *BitStream) NextBits(n int) uint64 {
|
||||||
r := bs.GetBits(n)
|
r := bs.GetBits(n)
|
||||||
bs.UnRead(n)
|
bs.UnRead(n)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BitStream) EOS() bool {
|
func (bs *BitStream) EOS() bool {
|
||||||
return bs.bytesOffset == len(bs.bits) && bs.bitsOffset == 0
|
return bs.bytesOffset == len(bs.bits) && bs.bitsOffset == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type BitStreamWriter struct {
|
type BitStreamWriter struct {
|
||||||
bits []byte
|
bits []byte
|
||||||
byteoffset int
|
byteoffset int
|
||||||
bitsoffset int
|
bitsoffset int
|
||||||
bitsmark int
|
bitsmark int
|
||||||
bytemark int
|
bytemark int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBitStreamWriter(n int) *BitStreamWriter {
|
func NewBitStreamWriter(n int) *BitStreamWriter {
|
||||||
return &BitStreamWriter{
|
return &BitStreamWriter{
|
||||||
bits: make([]byte, n),
|
bits: make([]byte, n),
|
||||||
byteoffset: 0,
|
byteoffset: 0,
|
||||||
bitsoffset: 0,
|
bitsoffset: 0,
|
||||||
bitsmark: 0,
|
bitsmark: 0,
|
||||||
bytemark: 0,
|
bytemark: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) expandSpace(n int) {
|
func (bsw *BitStreamWriter) expandSpace(n int) {
|
||||||
if (len(bsw.bits)-bsw.byteoffset-1)*8+8-bsw.bitsoffset < n {
|
if (len(bsw.bits)-bsw.byteoffset-1)*8+8-bsw.bitsoffset < n {
|
||||||
newlen := 0
|
newlen := 0
|
||||||
if len(bsw.bits)*8 < n {
|
if len(bsw.bits)*8 < n {
|
||||||
newlen = len(bsw.bits) + n/8 + 1
|
newlen = len(bsw.bits) + n/8 + 1
|
||||||
} else {
|
} else {
|
||||||
newlen = len(bsw.bits) * 2
|
newlen = len(bsw.bits) * 2
|
||||||
}
|
}
|
||||||
tmp := make([]byte, newlen)
|
tmp := make([]byte, newlen)
|
||||||
copy(tmp, bsw.bits)
|
copy(tmp, bsw.bits)
|
||||||
bsw.bits = tmp
|
bsw.bits = tmp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) ByteOffset() int {
|
func (bsw *BitStreamWriter) ByteOffset() int {
|
||||||
return bsw.byteoffset
|
return bsw.byteoffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) BitOffset() int {
|
func (bsw *BitStreamWriter) BitOffset() int {
|
||||||
return bsw.bitsoffset
|
return bsw.bitsoffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) Markdot() {
|
func (bsw *BitStreamWriter) Markdot() {
|
||||||
bsw.bitsmark = bsw.bitsoffset
|
bsw.bitsmark = bsw.bitsoffset
|
||||||
bsw.bytemark = bsw.byteoffset
|
bsw.bytemark = bsw.byteoffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) DistanceFromMarkDot() int {
|
func (bsw *BitStreamWriter) DistanceFromMarkDot() int {
|
||||||
bytecount := bsw.byteoffset - bsw.bytemark - 1
|
bytecount := bsw.byteoffset - bsw.bytemark - 1
|
||||||
bitscount := bsw.bitsoffset + (8 - bsw.bitsmark)
|
bitscount := bsw.bitsoffset + (8 - bsw.bitsmark)
|
||||||
return bytecount*8 + bitscount
|
return bytecount*8 + bitscount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutByte(v byte) {
|
func (bsw *BitStreamWriter) PutByte(v byte) {
|
||||||
bsw.expandSpace(8)
|
bsw.expandSpace(8)
|
||||||
if bsw.bitsoffset == 0 {
|
if bsw.bitsoffset == 0 {
|
||||||
bsw.bits[bsw.byteoffset] = v
|
bsw.bits[bsw.byteoffset] = v
|
||||||
bsw.byteoffset++
|
bsw.byteoffset++
|
||||||
} else {
|
} else {
|
||||||
bsw.bits[bsw.byteoffset] |= v >> byte(bsw.bitsoffset)
|
bsw.bits[bsw.byteoffset] |= v >> byte(bsw.bitsoffset)
|
||||||
bsw.byteoffset++
|
bsw.byteoffset++
|
||||||
bsw.bits[bsw.byteoffset] = v & BitMask[bsw.bitsoffset-1]
|
bsw.bits[bsw.byteoffset] = v & BitMask[bsw.bitsoffset-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutBytes(v []byte) {
|
func (bsw *BitStreamWriter) PutBytes(v []byte) {
|
||||||
if bsw.bitsoffset != 0 {
|
if bsw.bitsoffset != 0 {
|
||||||
panic("bsw.bitsoffset > 0")
|
panic("bsw.bitsoffset > 0")
|
||||||
}
|
}
|
||||||
bsw.expandSpace(8 * len(v))
|
bsw.expandSpace(8 * len(v))
|
||||||
copy(bsw.bits[bsw.byteoffset:], v)
|
copy(bsw.bits[bsw.byteoffset:], v)
|
||||||
bsw.byteoffset += len(v)
|
bsw.byteoffset += len(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutRepetValue(v byte, n int) {
|
func (bsw *BitStreamWriter) PutRepetValue(v byte, n int) {
|
||||||
if bsw.bitsoffset != 0 {
|
if bsw.bitsoffset != 0 {
|
||||||
panic("bsw.bitsoffset > 0")
|
panic("bsw.bitsoffset > 0")
|
||||||
}
|
}
|
||||||
bsw.expandSpace(8 * n)
|
bsw.expandSpace(8 * n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
bsw.bits[bsw.byteoffset] = v
|
bsw.bits[bsw.byteoffset] = v
|
||||||
bsw.byteoffset++
|
bsw.byteoffset++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutUint8(v uint8, n int) {
|
func (bsw *BitStreamWriter) PutUint8(v uint8, n int) {
|
||||||
bsw.PutUint64(uint64(v), n)
|
bsw.PutUint64(uint64(v), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutUint16(v uint16, n int) {
|
func (bsw *BitStreamWriter) PutUint16(v uint16, n int) {
|
||||||
bsw.PutUint64(uint64(v), n)
|
bsw.PutUint64(uint64(v), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutUint32(v uint32, n int) {
|
func (bsw *BitStreamWriter) PutUint32(v uint32, n int) {
|
||||||
bsw.PutUint64(uint64(v), n)
|
bsw.PutUint64(uint64(v), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) PutUint64(v uint64, n int) {
|
func (bsw *BitStreamWriter) PutUint64(v uint64, n int) {
|
||||||
bsw.expandSpace(n)
|
bsw.expandSpace(n)
|
||||||
if 8-bsw.bitsoffset >= n {
|
if 8-bsw.bitsoffset >= n {
|
||||||
bsw.bits[bsw.byteoffset] |= uint8(v) & BitMask[n-1] << (8 - bsw.bitsoffset - n)
|
bsw.bits[bsw.byteoffset] |= uint8(v) & BitMask[n-1] << (8 - bsw.bitsoffset - n)
|
||||||
bsw.bitsoffset += n
|
bsw.bitsoffset += n
|
||||||
if bsw.bitsoffset == 8 {
|
if bsw.bitsoffset == 8 {
|
||||||
bsw.bitsoffset = 0
|
bsw.bitsoffset = 0
|
||||||
bsw.byteoffset++
|
bsw.byteoffset++
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bsw.bits[bsw.byteoffset] |= uint8(v>>(n-int(8-bsw.bitsoffset))) & BitMask[8-bsw.bitsoffset-1]
|
bsw.bits[bsw.byteoffset] |= uint8(v>>(n-int(8-bsw.bitsoffset))) & BitMask[8-bsw.bitsoffset-1]
|
||||||
bsw.byteoffset++
|
bsw.byteoffset++
|
||||||
n -= 8 - bsw.bitsoffset
|
n -= 8 - bsw.bitsoffset
|
||||||
for n-8 >= 0 {
|
for n-8 >= 0 {
|
||||||
bsw.bits[bsw.byteoffset] = uint8(v>>(n-8)) & 0xFF
|
bsw.bits[bsw.byteoffset] = uint8(v>>(n-8)) & 0xFF
|
||||||
bsw.byteoffset++
|
bsw.byteoffset++
|
||||||
n -= 8
|
n -= 8
|
||||||
}
|
}
|
||||||
bsw.bitsoffset = n
|
bsw.bitsoffset = n
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
bsw.bits[bsw.byteoffset] |= (uint8(v) & BitMask[n-1]) << (8 - n)
|
bsw.bits[bsw.byteoffset] |= (uint8(v) & BitMask[n-1]) << (8 - n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) SetByte(v byte, where int) {
|
func (bsw *BitStreamWriter) SetByte(v byte, where int) {
|
||||||
bsw.bits[where] = v
|
bsw.bits[where] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) SetUint16(v uint16, where int) {
|
func (bsw *BitStreamWriter) SetUint16(v uint16, where int) {
|
||||||
binary.BigEndian.PutUint16(bsw.bits[where:where+2], v)
|
binary.BigEndian.PutUint16(bsw.bits[where:where+2], v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) Bits() []byte {
|
func (bsw *BitStreamWriter) Bits() []byte {
|
||||||
if bsw.byteoffset == len(bsw.bits) {
|
if bsw.byteoffset == len(bsw.bits) {
|
||||||
return bsw.bits
|
return bsw.bits
|
||||||
}
|
}
|
||||||
if bsw.bitsoffset > 0 {
|
if bsw.bitsoffset > 0 {
|
||||||
return bsw.bits[0 : bsw.byteoffset+1]
|
return bsw.bits[0 : bsw.byteoffset+1]
|
||||||
} else {
|
} else {
|
||||||
return bsw.bits[0:bsw.byteoffset]
|
return bsw.bits[0:bsw.byteoffset]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//用v 填充剩余字节
|
//用v 填充剩余字节
|
||||||
func (bsw *BitStreamWriter) FillRemainData(v byte) {
|
func (bsw *BitStreamWriter) FillRemainData(v byte) {
|
||||||
for i := bsw.byteoffset; i < len(bsw.bits); i++ {
|
for i := bsw.byteoffset; i < len(bsw.bits); i++ {
|
||||||
bsw.bits[i] = v
|
bsw.bits[i] = v
|
||||||
}
|
}
|
||||||
bsw.byteoffset = len(bsw.bits)
|
bsw.byteoffset = len(bsw.bits)
|
||||||
bsw.bitsoffset = 0
|
bsw.bitsoffset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsw *BitStreamWriter) Reset() {
|
func (bsw *BitStreamWriter) Reset() {
|
||||||
for i := 0; i < len(bsw.bits); i++ {
|
for i := 0; i < len(bsw.bits); i++ {
|
||||||
bsw.bits[i] = 0
|
bsw.bits[i] = 0
|
||||||
}
|
}
|
||||||
bsw.bitsmark = 0
|
bsw.bitsmark = 0
|
||||||
bsw.bytemark = 0
|
bsw.bytemark = 0
|
||||||
bsw.bitsoffset = 0
|
bsw.bitsoffset = 0
|
||||||
bsw.byteoffset = 0
|
bsw.byteoffset = 0
|
||||||
}
|
}
|
||||||
|
|
86
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/codec.go
generated
vendored
86
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/codec.go
generated
vendored
|
@ -3,62 +3,62 @@ package codec
|
||||||
type CodecID int
|
type CodecID int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CODECID_VIDEO_H264 CodecID = iota
|
CODECID_VIDEO_H264 CodecID = iota
|
||||||
CODECID_VIDEO_H265
|
CODECID_VIDEO_H265
|
||||||
CODECID_VIDEO_VP8
|
CODECID_VIDEO_VP8
|
||||||
|
|
||||||
CODECID_AUDIO_AAC CodecID = iota + 98
|
CODECID_AUDIO_AAC CodecID = iota + 98
|
||||||
CODECID_AUDIO_G711A
|
CODECID_AUDIO_G711A
|
||||||
CODECID_AUDIO_G711U
|
CODECID_AUDIO_G711U
|
||||||
CODECID_AUDIO_OPUS
|
CODECID_AUDIO_OPUS
|
||||||
|
|
||||||
CODECID_UNRECOGNIZED = 999
|
CODECID_UNRECOGNIZED = 999
|
||||||
)
|
)
|
||||||
|
|
||||||
type H264_NAL_TYPE int
|
type H264_NAL_TYPE int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
H264_NAL_RESERVED H264_NAL_TYPE = iota
|
H264_NAL_RESERVED H264_NAL_TYPE = iota
|
||||||
H264_NAL_P_SLICE
|
H264_NAL_P_SLICE
|
||||||
H264_NAL_SLICE_A
|
H264_NAL_SLICE_A
|
||||||
H264_NAL_SLICE_B
|
H264_NAL_SLICE_B
|
||||||
H264_NAL_SLICE_C
|
H264_NAL_SLICE_C
|
||||||
H264_NAL_I_SLICE
|
H264_NAL_I_SLICE
|
||||||
H264_NAL_SEI
|
H264_NAL_SEI
|
||||||
H264_NAL_SPS
|
H264_NAL_SPS
|
||||||
H264_NAL_PPS
|
H264_NAL_PPS
|
||||||
H264_NAL_AUD
|
H264_NAL_AUD
|
||||||
)
|
)
|
||||||
|
|
||||||
type H265_NAL_TYPE int
|
type H265_NAL_TYPE int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
H265_NAL_Slice_TRAIL_N H265_NAL_TYPE = iota
|
H265_NAL_Slice_TRAIL_N H265_NAL_TYPE = iota
|
||||||
H265_NAL_LICE_TRAIL_R
|
H265_NAL_LICE_TRAIL_R
|
||||||
H265_NAL_SLICE_TSA_N
|
H265_NAL_SLICE_TSA_N
|
||||||
H265_NAL_SLICE_TSA_R
|
H265_NAL_SLICE_TSA_R
|
||||||
H265_NAL_SLICE_STSA_N
|
H265_NAL_SLICE_STSA_N
|
||||||
H265_NAL_SLICE_STSA_R
|
H265_NAL_SLICE_STSA_R
|
||||||
H265_NAL_SLICE_RADL_N
|
H265_NAL_SLICE_RADL_N
|
||||||
H265_NAL_SLICE_RADL_R
|
H265_NAL_SLICE_RADL_R
|
||||||
H265_NAL_SLICE_RASL_N
|
H265_NAL_SLICE_RASL_N
|
||||||
H265_NAL_SLICE_RASL_R
|
H265_NAL_SLICE_RASL_R
|
||||||
|
|
||||||
//IDR
|
//IDR
|
||||||
H265_NAL_SLICE_BLA_W_LP H265_NAL_TYPE = iota + 6
|
H265_NAL_SLICE_BLA_W_LP H265_NAL_TYPE = iota + 6
|
||||||
H265_NAL_SLICE_BLA_W_RADL
|
H265_NAL_SLICE_BLA_W_RADL
|
||||||
H265_NAL_SLICE_BLA_N_LP
|
H265_NAL_SLICE_BLA_N_LP
|
||||||
H265_NAL_SLICE_IDR_W_RADL
|
H265_NAL_SLICE_IDR_W_RADL
|
||||||
H265_NAL_SLICE_IDR_N_LP
|
H265_NAL_SLICE_IDR_N_LP
|
||||||
H265_NAL_SLICE_CRA
|
H265_NAL_SLICE_CRA
|
||||||
|
|
||||||
//vps pps sps
|
//vps pps sps
|
||||||
H265_NAL_VPS H265_NAL_TYPE = iota + 16
|
H265_NAL_VPS H265_NAL_TYPE = iota + 16
|
||||||
H265_NAL_SPS
|
H265_NAL_SPS
|
||||||
H265_NAL_PPS
|
H265_NAL_PPS
|
||||||
H265_NAL_AUD
|
H265_NAL_AUD
|
||||||
|
|
||||||
//SEI
|
//SEI
|
||||||
H265_NAL_SEI H265_NAL_TYPE = iota + 19
|
H265_NAL_SEI H265_NAL_TYPE = iota + 19
|
||||||
H265_NAL_SEI_SUFFIX
|
H265_NAL_SEI_SUFFIX
|
||||||
)
|
)
|
||||||
|
|
500
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h264.go
generated
vendored
500
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h264.go
generated
vendored
|
@ -9,241 +9,241 @@ import "encoding/binary"
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type H264NaluHdr struct {
|
type H264NaluHdr struct {
|
||||||
Forbidden_zero_bit uint8
|
Forbidden_zero_bit uint8
|
||||||
Nal_ref_idc uint8
|
Nal_ref_idc uint8
|
||||||
Nal_unit_type uint8
|
Nal_unit_type uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hdr *H264NaluHdr) Decode(bs *BitStream) {
|
func (hdr *H264NaluHdr) Decode(bs *BitStream) {
|
||||||
hdr.Forbidden_zero_bit = bs.GetBit()
|
hdr.Forbidden_zero_bit = bs.GetBit()
|
||||||
hdr.Nal_ref_idc = bs.Uint8(2)
|
hdr.Nal_ref_idc = bs.Uint8(2)
|
||||||
hdr.Nal_unit_type = bs.Uint8(5)
|
hdr.Nal_unit_type = bs.Uint8(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SliceHeader struct {
|
type SliceHeader struct {
|
||||||
First_mb_in_slice uint64
|
First_mb_in_slice uint64
|
||||||
Slice_type uint64
|
Slice_type uint64
|
||||||
Pic_parameter_set_id uint64
|
Pic_parameter_set_id uint64
|
||||||
Frame_num uint64
|
Frame_num uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
//调用方根据sps中的log2_max_frame_num_minus4的值来解析Frame_num
|
//调用方根据sps中的log2_max_frame_num_minus4的值来解析Frame_num
|
||||||
func (sh *SliceHeader) Decode(bs *BitStream) {
|
func (sh *SliceHeader) Decode(bs *BitStream) {
|
||||||
sh.First_mb_in_slice = bs.ReadUE()
|
sh.First_mb_in_slice = bs.ReadUE()
|
||||||
sh.Slice_type = bs.ReadUE()
|
sh.Slice_type = bs.ReadUE()
|
||||||
sh.Pic_parameter_set_id = bs.ReadUE()
|
sh.Pic_parameter_set_id = bs.ReadUE()
|
||||||
}
|
}
|
||||||
|
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
Profile_idc uint8
|
Profile_idc uint8
|
||||||
Constraint_set0_flag uint8
|
Constraint_set0_flag uint8
|
||||||
Constraint_set1_flag uint8
|
Constraint_set1_flag uint8
|
||||||
Constraint_set2_flag uint8
|
Constraint_set2_flag uint8
|
||||||
Constraint_set3_flag uint8
|
Constraint_set3_flag uint8
|
||||||
Constraint_set4_flag uint8
|
Constraint_set4_flag uint8
|
||||||
Constraint_set5_flag uint8
|
Constraint_set5_flag uint8
|
||||||
Reserved_zero_2bits uint8
|
Reserved_zero_2bits uint8
|
||||||
Level_idc uint8
|
Level_idc uint8
|
||||||
Seq_parameter_set_id uint64
|
Seq_parameter_set_id uint64
|
||||||
Chroma_format_idc uint64
|
Chroma_format_idc uint64
|
||||||
Separate_colour_plane_flag uint8
|
Separate_colour_plane_flag uint8
|
||||||
Bit_depth_luma_minus8 uint64
|
Bit_depth_luma_minus8 uint64
|
||||||
Bit_depth_chroma_minus8 uint64
|
Bit_depth_chroma_minus8 uint64
|
||||||
Log2_max_frame_num_minus4 uint64
|
Log2_max_frame_num_minus4 uint64
|
||||||
Pic_order_cnt_type uint64
|
Pic_order_cnt_type uint64
|
||||||
Max_num_ref_frames uint64
|
Max_num_ref_frames uint64
|
||||||
Gaps_in_frame_num_value_allowed_flag uint8
|
Gaps_in_frame_num_value_allowed_flag uint8
|
||||||
Pic_width_in_mbs_minus1 uint64
|
Pic_width_in_mbs_minus1 uint64
|
||||||
Pic_height_in_map_units_minus1 uint64
|
Pic_height_in_map_units_minus1 uint64
|
||||||
Frame_mbs_only_flag uint8
|
Frame_mbs_only_flag uint8
|
||||||
Direct_8x8_inference_flag uint8
|
Direct_8x8_inference_flag uint8
|
||||||
Frame_cropping_flag uint8
|
Frame_cropping_flag uint8
|
||||||
Frame_crop_left_offset uint64
|
Frame_crop_left_offset uint64
|
||||||
Frame_crop_right_offset uint64
|
Frame_crop_right_offset uint64
|
||||||
Frame_crop_top_offset uint64
|
Frame_crop_top_offset uint64
|
||||||
Frame_crop_bottom_offset uint64
|
Frame_crop_bottom_offset uint64
|
||||||
Vui_parameters_present_flag uint8
|
Vui_parameters_present_flag uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sps *SPS) Decode(bs *BitStream) {
|
func (sps *SPS) Decode(bs *BitStream) {
|
||||||
sps.Profile_idc = bs.Uint8(8)
|
sps.Profile_idc = bs.Uint8(8)
|
||||||
sps.Constraint_set0_flag = bs.GetBit()
|
sps.Constraint_set0_flag = bs.GetBit()
|
||||||
sps.Constraint_set1_flag = bs.GetBit()
|
sps.Constraint_set1_flag = bs.GetBit()
|
||||||
sps.Constraint_set2_flag = bs.GetBit()
|
sps.Constraint_set2_flag = bs.GetBit()
|
||||||
sps.Constraint_set3_flag = bs.GetBit()
|
sps.Constraint_set3_flag = bs.GetBit()
|
||||||
sps.Constraint_set4_flag = bs.GetBit()
|
sps.Constraint_set4_flag = bs.GetBit()
|
||||||
sps.Constraint_set5_flag = bs.GetBit()
|
sps.Constraint_set5_flag = bs.GetBit()
|
||||||
sps.Reserved_zero_2bits = bs.Uint8(2)
|
sps.Reserved_zero_2bits = bs.Uint8(2)
|
||||||
sps.Level_idc = bs.Uint8(8)
|
sps.Level_idc = bs.Uint8(8)
|
||||||
sps.Seq_parameter_set_id = bs.ReadUE()
|
sps.Seq_parameter_set_id = bs.ReadUE()
|
||||||
if sps.Profile_idc == 100 || sps.Profile_idc == 110 ||
|
if sps.Profile_idc == 100 || sps.Profile_idc == 110 ||
|
||||||
sps.Profile_idc == 122 || sps.Profile_idc == 244 ||
|
sps.Profile_idc == 122 || sps.Profile_idc == 244 ||
|
||||||
sps.Profile_idc == 44 || sps.Profile_idc == 83 ||
|
sps.Profile_idc == 44 || sps.Profile_idc == 83 ||
|
||||||
sps.Profile_idc == 86 || sps.Profile_idc == 118 || sps.Profile_idc == 128 {
|
sps.Profile_idc == 86 || sps.Profile_idc == 118 || sps.Profile_idc == 128 {
|
||||||
sps.Chroma_format_idc = bs.ReadUE()
|
sps.Chroma_format_idc = bs.ReadUE()
|
||||||
if sps.Chroma_format_idc == 3 {
|
if sps.Chroma_format_idc == 3 {
|
||||||
sps.Separate_colour_plane_flag = bs.Uint8(1) //separate_colour_plane_flag
|
sps.Separate_colour_plane_flag = bs.Uint8(1) //separate_colour_plane_flag
|
||||||
}
|
}
|
||||||
sps.Bit_depth_luma_minus8 = bs.ReadUE() //bit_depth_luma_minus8
|
sps.Bit_depth_luma_minus8 = bs.ReadUE() //bit_depth_luma_minus8
|
||||||
sps.Bit_depth_chroma_minus8 = bs.ReadUE() //bit_depth_chroma_minus8
|
sps.Bit_depth_chroma_minus8 = bs.ReadUE() //bit_depth_chroma_minus8
|
||||||
bs.SkipBits(1) //qpprime_y_zero_transform_bypass_flag
|
bs.SkipBits(1) //qpprime_y_zero_transform_bypass_flag
|
||||||
seq_scaling_matrix_present_flag := bs.GetBit()
|
seq_scaling_matrix_present_flag := bs.GetBit()
|
||||||
if seq_scaling_matrix_present_flag == 1 {
|
if seq_scaling_matrix_present_flag == 1 {
|
||||||
//seq_scaling_list_present_flag[i]
|
//seq_scaling_list_present_flag[i]
|
||||||
if sps.Chroma_format_idc == 3 {
|
if sps.Chroma_format_idc == 3 {
|
||||||
bs.SkipBits(12)
|
bs.SkipBits(12)
|
||||||
} else {
|
} else {
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sps.Log2_max_frame_num_minus4 = bs.ReadUE()
|
sps.Log2_max_frame_num_minus4 = bs.ReadUE()
|
||||||
sps.Pic_order_cnt_type = bs.ReadUE()
|
sps.Pic_order_cnt_type = bs.ReadUE()
|
||||||
if sps.Pic_order_cnt_type == 0 {
|
if sps.Pic_order_cnt_type == 0 {
|
||||||
bs.ReadUE() // log2_max_pic_order_cnt_lsb_minus4
|
bs.ReadUE() // log2_max_pic_order_cnt_lsb_minus4
|
||||||
} else if sps.Pic_order_cnt_type == 1 {
|
} else if sps.Pic_order_cnt_type == 1 {
|
||||||
bs.SkipBits(1) //delta_pic_order_always_zero_flag
|
bs.SkipBits(1) //delta_pic_order_always_zero_flag
|
||||||
bs.ReadSE() //offset_for_non_ref_pic
|
bs.ReadSE() //offset_for_non_ref_pic
|
||||||
bs.ReadSE() //offset_for_top_to_bottom_field
|
bs.ReadSE() //offset_for_top_to_bottom_field
|
||||||
num_ref_frames_in_pic_order_cnt_cycle := bs.ReadUE()
|
num_ref_frames_in_pic_order_cnt_cycle := bs.ReadUE()
|
||||||
for i := 0; i < int(num_ref_frames_in_pic_order_cnt_cycle); i++ {
|
for i := 0; i < int(num_ref_frames_in_pic_order_cnt_cycle); i++ {
|
||||||
bs.ReadSE() //offset_for_ref_frame
|
bs.ReadSE() //offset_for_ref_frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sps.Max_num_ref_frames = bs.ReadUE()
|
sps.Max_num_ref_frames = bs.ReadUE()
|
||||||
sps.Gaps_in_frame_num_value_allowed_flag = bs.GetBit()
|
sps.Gaps_in_frame_num_value_allowed_flag = bs.GetBit()
|
||||||
sps.Pic_width_in_mbs_minus1 = bs.ReadUE()
|
sps.Pic_width_in_mbs_minus1 = bs.ReadUE()
|
||||||
sps.Pic_height_in_map_units_minus1 = bs.ReadUE()
|
sps.Pic_height_in_map_units_minus1 = bs.ReadUE()
|
||||||
sps.Frame_mbs_only_flag = bs.GetBit()
|
sps.Frame_mbs_only_flag = bs.GetBit()
|
||||||
if sps.Frame_mbs_only_flag == 0 {
|
if sps.Frame_mbs_only_flag == 0 {
|
||||||
bs.SkipBits(1) // mb_adaptive_frame_field_flag
|
bs.SkipBits(1) // mb_adaptive_frame_field_flag
|
||||||
}
|
}
|
||||||
sps.Direct_8x8_inference_flag = bs.GetBit()
|
sps.Direct_8x8_inference_flag = bs.GetBit()
|
||||||
sps.Frame_cropping_flag = bs.GetBit()
|
sps.Frame_cropping_flag = bs.GetBit()
|
||||||
if sps.Frame_cropping_flag == 1 {
|
if sps.Frame_cropping_flag == 1 {
|
||||||
sps.Frame_crop_left_offset = bs.ReadUE() //frame_crop_left_offset
|
sps.Frame_crop_left_offset = bs.ReadUE() //frame_crop_left_offset
|
||||||
sps.Frame_crop_right_offset = bs.ReadUE() //frame_crop_right_offset
|
sps.Frame_crop_right_offset = bs.ReadUE() //frame_crop_right_offset
|
||||||
sps.Frame_crop_top_offset = bs.ReadUE() //frame_crop_top_offset
|
sps.Frame_crop_top_offset = bs.ReadUE() //frame_crop_top_offset
|
||||||
sps.Frame_crop_bottom_offset = bs.ReadUE() //frame_crop_bottom_offset
|
sps.Frame_crop_bottom_offset = bs.ReadUE() //frame_crop_bottom_offset
|
||||||
}
|
}
|
||||||
sps.Vui_parameters_present_flag = bs.GetBit()
|
sps.Vui_parameters_present_flag = bs.GetBit()
|
||||||
}
|
}
|
||||||
|
|
||||||
type PPS struct {
|
type PPS struct {
|
||||||
Pic_parameter_set_id uint64
|
Pic_parameter_set_id uint64
|
||||||
Seq_parameter_set_id uint64
|
Seq_parameter_set_id uint64
|
||||||
Entropy_coding_mode_flag uint8
|
Entropy_coding_mode_flag uint8
|
||||||
Bottom_field_pic_order_in_frame_present_flag uint8
|
Bottom_field_pic_order_in_frame_present_flag uint8
|
||||||
Num_slice_groups_minus1 uint64
|
Num_slice_groups_minus1 uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pps *PPS) Decode(bs *BitStream) {
|
func (pps *PPS) Decode(bs *BitStream) {
|
||||||
pps.Pic_parameter_set_id = bs.ReadUE()
|
pps.Pic_parameter_set_id = bs.ReadUE()
|
||||||
pps.Seq_parameter_set_id = bs.ReadUE()
|
pps.Seq_parameter_set_id = bs.ReadUE()
|
||||||
pps.Entropy_coding_mode_flag = bs.GetBit()
|
pps.Entropy_coding_mode_flag = bs.GetBit()
|
||||||
pps.Bottom_field_pic_order_in_frame_present_flag = bs.GetBit()
|
pps.Bottom_field_pic_order_in_frame_present_flag = bs.GetBit()
|
||||||
pps.Num_slice_groups_minus1 = bs.ReadUE()
|
pps.Num_slice_groups_minus1 = bs.ReadUE()
|
||||||
}
|
}
|
||||||
|
|
||||||
type SEIReaderWriter interface {
|
type SEIReaderWriter interface {
|
||||||
Read(size uint16, bs *BitStream)
|
Read(size uint16, bs *BitStream)
|
||||||
Write(bsw *BitStreamWriter)
|
Write(bsw *BitStreamWriter)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserDataUnregistered struct {
|
type UserDataUnregistered struct {
|
||||||
UUID []byte
|
UUID []byte
|
||||||
UserData []byte
|
UserData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (udu *UserDataUnregistered) Read(size uint16, bs *BitStream) {
|
func (udu *UserDataUnregistered) Read(size uint16, bs *BitStream) {
|
||||||
udu.UUID = bs.GetBytes(16)
|
udu.UUID = bs.GetBytes(16)
|
||||||
udu.UserData = bs.GetBytes(int(size - 16))
|
udu.UserData = bs.GetBytes(int(size - 16))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (udu *UserDataUnregistered) Write(bsw *BitStreamWriter) {
|
func (udu *UserDataUnregistered) Write(bsw *BitStreamWriter) {
|
||||||
bsw.PutBytes(udu.UUID)
|
bsw.PutBytes(udu.UUID)
|
||||||
bsw.PutBytes(udu.UserData)
|
bsw.PutBytes(udu.UserData)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SEI struct {
|
type SEI struct {
|
||||||
PayloadType uint16
|
PayloadType uint16
|
||||||
PayloadSize uint16
|
PayloadSize uint16
|
||||||
Sei_payload SEIReaderWriter
|
Sei_payload SEIReaderWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sei *SEI) Decode(bs *BitStream) {
|
func (sei *SEI) Decode(bs *BitStream) {
|
||||||
for bs.NextBits(8) == 0xFF {
|
for bs.NextBits(8) == 0xFF {
|
||||||
sei.PayloadType += 255
|
sei.PayloadType += 255
|
||||||
}
|
}
|
||||||
sei.PayloadType += uint16(bs.Uint8(8))
|
sei.PayloadType += uint16(bs.Uint8(8))
|
||||||
for bs.NextBits(8) == 0xFF {
|
for bs.NextBits(8) == 0xFF {
|
||||||
sei.PayloadSize += 255
|
sei.PayloadSize += 255
|
||||||
}
|
}
|
||||||
sei.PayloadSize += uint16(bs.Uint8(8))
|
sei.PayloadSize += uint16(bs.Uint8(8))
|
||||||
if sei.PayloadType == 5 {
|
if sei.PayloadType == 5 {
|
||||||
sei.Sei_payload = new(UserDataUnregistered)
|
sei.Sei_payload = new(UserDataUnregistered)
|
||||||
sei.Sei_payload.Read(sei.PayloadSize, bs)
|
sei.Sei_payload.Read(sei.PayloadSize, bs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sei *SEI) Encode(bsw *BitStreamWriter) []byte {
|
func (sei *SEI) Encode(bsw *BitStreamWriter) []byte {
|
||||||
payloadType := sei.PayloadType
|
payloadType := sei.PayloadType
|
||||||
payloadSize := sei.PayloadSize
|
payloadSize := sei.PayloadSize
|
||||||
for payloadType >= 0xFF {
|
for payloadType >= 0xFF {
|
||||||
bsw.PutByte(0xFF)
|
bsw.PutByte(0xFF)
|
||||||
payloadType -= 255
|
payloadType -= 255
|
||||||
}
|
}
|
||||||
bsw.PutByte(uint8(payloadType))
|
bsw.PutByte(uint8(payloadType))
|
||||||
for payloadSize >= 0xFF {
|
for payloadSize >= 0xFF {
|
||||||
bsw.PutByte(0xFF)
|
bsw.PutByte(0xFF)
|
||||||
payloadSize -= 255
|
payloadSize -= 255
|
||||||
}
|
}
|
||||||
bsw.PutByte(uint8(payloadSize))
|
bsw.PutByte(uint8(payloadSize))
|
||||||
sei.Sei_payload.Write(bsw)
|
sei.Sei_payload.Write(bsw)
|
||||||
return bsw.Bits()
|
return bsw.Bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSPSIdWithStartCode(sps []byte) uint64 {
|
func GetSPSIdWithStartCode(sps []byte) uint64 {
|
||||||
start, sc := FindStartCode(sps, 0)
|
start, sc := FindStartCode(sps, 0)
|
||||||
return GetSPSId(sps[start+int(sc):])
|
return GetSPSId(sps[start+int(sc):])
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSPSId(sps []byte) uint64 {
|
func GetSPSId(sps []byte) uint64 {
|
||||||
sps = sps[1:]
|
sps = sps[1:]
|
||||||
bs := NewBitStream(sps)
|
bs := NewBitStream(sps)
|
||||||
bs.SkipBits(24)
|
bs.SkipBits(24)
|
||||||
return bs.ReadUE()
|
return bs.ReadUE()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPPSIdWithStartCode(pps []byte) uint64 {
|
func GetPPSIdWithStartCode(pps []byte) uint64 {
|
||||||
start, sc := FindStartCode(pps, 0)
|
start, sc := FindStartCode(pps, 0)
|
||||||
return GetPPSId(pps[start+int(sc):])
|
return GetPPSId(pps[start+int(sc):])
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPPSId(pps []byte) uint64 {
|
func GetPPSId(pps []byte) uint64 {
|
||||||
pps = pps[1:]
|
pps = pps[1:]
|
||||||
bs := NewBitStream(pps)
|
bs := NewBitStream(pps)
|
||||||
return bs.ReadUE()
|
return bs.ReadUE()
|
||||||
}
|
}
|
||||||
|
|
||||||
//https://stackoverflow.com/questions/12018535/get-the-width-height-of-the-video-from-h-264-nalu
|
//https://stackoverflow.com/questions/12018535/get-the-width-height-of-the-video-from-h-264-nalu
|
||||||
//int Width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_right_offset *2 - frame_crop_left_offset *2;
|
//int Width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_right_offset *2 - frame_crop_left_offset *2;
|
||||||
//int Height = ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - (frame_crop_bottom_offset* 2) - (frame_crop_top_offset* 2);
|
//int Height = ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - (frame_crop_bottom_offset* 2) - (frame_crop_top_offset* 2);
|
||||||
func GetH264Resolution(sps []byte) (width uint32, height uint32) {
|
func GetH264Resolution(sps []byte) (width uint32, height uint32) {
|
||||||
start, sc := FindStartCode(sps, 0)
|
start, sc := FindStartCode(sps, 0)
|
||||||
bs := NewBitStream(sps[start+int(sc)+1:])
|
bs := NewBitStream(sps[start+int(sc)+1:])
|
||||||
var s SPS
|
var s SPS
|
||||||
s.Decode(bs)
|
s.Decode(bs)
|
||||||
|
|
||||||
widthInSample := (uint32(s.Pic_width_in_mbs_minus1) + 1) * 16
|
widthInSample := (uint32(s.Pic_width_in_mbs_minus1) + 1) * 16
|
||||||
widthCrop := uint32(s.Frame_crop_left_offset)*2 - uint32(s.Frame_crop_right_offset)*2
|
widthCrop := uint32(s.Frame_crop_left_offset)*2 - uint32(s.Frame_crop_right_offset)*2
|
||||||
width = widthInSample - widthCrop
|
width = widthInSample - widthCrop
|
||||||
|
|
||||||
heightInSample := ((2 - uint32(s.Frame_mbs_only_flag)) * (uint32(s.Pic_height_in_map_units_minus1) + 1) * 16)
|
heightInSample := ((2 - uint32(s.Frame_mbs_only_flag)) * (uint32(s.Pic_height_in_map_units_minus1) + 1) * 16)
|
||||||
heightCrop := uint32(s.Frame_crop_bottom_offset)*2 - uint32(s.Frame_crop_top_offset)*2
|
heightCrop := uint32(s.Frame_crop_bottom_offset)*2 - uint32(s.Frame_crop_top_offset)*2
|
||||||
height = heightInSample - heightCrop
|
height = heightInSample - heightCrop
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// aligned(8) class AVCDecoderConfigurationRecord {
|
// aligned(8) class AVCDecoderConfigurationRecord {
|
||||||
|
@ -302,95 +302,95 @@ func GetH264Resolution(sps []byte) (width uint32, height uint32) {
|
||||||
// variable PPS NALU data
|
// variable PPS NALU data
|
||||||
|
|
||||||
func CreateH264AVCCExtradata(spss [][]byte, ppss [][]byte) []byte {
|
func CreateH264AVCCExtradata(spss [][]byte, ppss [][]byte) []byte {
|
||||||
extradata := make([]byte, 6, 256)
|
extradata := make([]byte, 6, 256)
|
||||||
for i, sps := range spss {
|
for i, sps := range spss {
|
||||||
start, sc := FindStartCode(sps, 0)
|
start, sc := FindStartCode(sps, 0)
|
||||||
spss[i] = sps[start+int(sc):]
|
spss[i] = sps[start+int(sc):]
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, pps := range ppss {
|
for i, pps := range ppss {
|
||||||
start, sc := FindStartCode(pps, 0)
|
start, sc := FindStartCode(pps, 0)
|
||||||
ppss[i] = pps[start+int(sc):]
|
ppss[i] = pps[start+int(sc):]
|
||||||
}
|
}
|
||||||
|
|
||||||
extradata[0] = 0x01
|
extradata[0] = 0x01
|
||||||
extradata[1] = spss[0][1]
|
extradata[1] = spss[0][1]
|
||||||
extradata[2] = spss[0][2]
|
extradata[2] = spss[0][2]
|
||||||
extradata[3] = spss[0][3]
|
extradata[3] = spss[0][3]
|
||||||
extradata[4] = 0xFF
|
extradata[4] = 0xFF
|
||||||
extradata[5] = 0xE0 | uint8(len(spss))
|
extradata[5] = 0xE0 | uint8(len(spss))
|
||||||
for _, sps := range spss {
|
for _, sps := range spss {
|
||||||
spssize := make([]byte, 2)
|
spssize := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(spssize, uint16(len(sps)))
|
binary.BigEndian.PutUint16(spssize, uint16(len(sps)))
|
||||||
extradata = append(extradata, spssize...)
|
extradata = append(extradata, spssize...)
|
||||||
extradata = append(extradata, sps...)
|
extradata = append(extradata, sps...)
|
||||||
}
|
}
|
||||||
extradata = append(extradata, uint8(len(ppss)))
|
extradata = append(extradata, uint8(len(ppss)))
|
||||||
for _, pps := range ppss {
|
for _, pps := range ppss {
|
||||||
ppssize := make([]byte, 2)
|
ppssize := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(ppssize, uint16(len(pps)))
|
binary.BigEndian.PutUint16(ppssize, uint16(len(pps)))
|
||||||
extradata = append(extradata, ppssize...)
|
extradata = append(extradata, ppssize...)
|
||||||
extradata = append(extradata, pps...)
|
extradata = append(extradata, pps...)
|
||||||
}
|
}
|
||||||
var h264sps SPS
|
var h264sps SPS
|
||||||
h264sps.Decode(NewBitStream(spss[0][1:]))
|
h264sps.Decode(NewBitStream(spss[0][1:]))
|
||||||
if h264sps.Profile_idc == 100 ||
|
if h264sps.Profile_idc == 100 ||
|
||||||
h264sps.Profile_idc == 110 ||
|
h264sps.Profile_idc == 110 ||
|
||||||
h264sps.Profile_idc == 122 ||
|
h264sps.Profile_idc == 122 ||
|
||||||
h264sps.Profile_idc == 144 {
|
h264sps.Profile_idc == 144 {
|
||||||
tmp := make([]byte, 4)
|
tmp := make([]byte, 4)
|
||||||
tmp[0] = 0xFC | uint8(h264sps.Chroma_format_idc&0x03)
|
tmp[0] = 0xFC | uint8(h264sps.Chroma_format_idc&0x03)
|
||||||
tmp[1] = 0xF8 | uint8(h264sps.Bit_depth_luma_minus8&0x07)
|
tmp[1] = 0xF8 | uint8(h264sps.Bit_depth_luma_minus8&0x07)
|
||||||
tmp[2] = 0xF8 | uint8(h264sps.Bit_depth_chroma_minus8&0x07)
|
tmp[2] = 0xF8 | uint8(h264sps.Bit_depth_chroma_minus8&0x07)
|
||||||
tmp[3] = 0
|
tmp[3] = 0
|
||||||
extradata = append(extradata, tmp...)
|
extradata = append(extradata, tmp...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return extradata
|
return extradata
|
||||||
}
|
}
|
||||||
|
|
||||||
func CovertExtradata(extraData []byte) ([][]byte, [][]byte) {
|
func CovertExtradata(extraData []byte) ([][]byte, [][]byte) {
|
||||||
spsnum := extraData[5] & 0x1F
|
spsnum := extraData[5] & 0x1F
|
||||||
spss := make([][]byte, spsnum)
|
spss := make([][]byte, spsnum)
|
||||||
offset := 6
|
offset := 6
|
||||||
for i := 0; i < int(spsnum); i++ {
|
for i := 0; i < int(spsnum); i++ {
|
||||||
spssize := binary.BigEndian.Uint16(extraData[offset:])
|
spssize := binary.BigEndian.Uint16(extraData[offset:])
|
||||||
sps := make([]byte, spssize+4)
|
sps := make([]byte, spssize+4)
|
||||||
copy(sps, []byte{0x00, 0x00, 0x00, 0x01})
|
copy(sps, []byte{0x00, 0x00, 0x00, 0x01})
|
||||||
copy(sps[4:], extraData[offset+2:offset+2+int(spssize)])
|
copy(sps[4:], extraData[offset+2:offset+2+int(spssize)])
|
||||||
offset += 2 + int(spssize)
|
offset += 2 + int(spssize)
|
||||||
spss[i] = sps
|
spss[i] = sps
|
||||||
}
|
}
|
||||||
ppsnum := extraData[offset]
|
ppsnum := extraData[offset]
|
||||||
ppss := make([][]byte, ppsnum)
|
ppss := make([][]byte, ppsnum)
|
||||||
offset++
|
offset++
|
||||||
for i := 0; i < int(ppsnum); i++ {
|
for i := 0; i < int(ppsnum); i++ {
|
||||||
ppssize := binary.BigEndian.Uint16(extraData[offset:])
|
ppssize := binary.BigEndian.Uint16(extraData[offset:])
|
||||||
pps := make([]byte, ppssize+4)
|
pps := make([]byte, ppssize+4)
|
||||||
copy(pps, []byte{0x00, 0x00, 0x00, 0x01})
|
copy(pps, []byte{0x00, 0x00, 0x00, 0x01})
|
||||||
copy(pps[4:], extraData[offset+2:offset+2+int(ppssize)])
|
copy(pps[4:], extraData[offset+2:offset+2+int(ppssize)])
|
||||||
offset += 2 + int(ppssize)
|
offset += 2 + int(ppssize)
|
||||||
ppss[i] = pps
|
ppss[i] = pps
|
||||||
}
|
}
|
||||||
return spss, ppss
|
return spss, ppss
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertAnnexBToAVCC(annexb []byte) []byte {
|
func ConvertAnnexBToAVCC(annexb []byte) []byte {
|
||||||
start, sc := FindStartCode(annexb, 0)
|
start, sc := FindStartCode(annexb, 0)
|
||||||
if sc == START_CODE_4 {
|
if sc == START_CODE_4 {
|
||||||
binary.BigEndian.PutUint32(annexb[start:], uint32(len(annexb)-4))
|
binary.BigEndian.PutUint32(annexb[start:], uint32(len(annexb)-4))
|
||||||
return annexb
|
return annexb
|
||||||
} else {
|
} else {
|
||||||
avcc := make([]byte, 1+len(annexb))
|
avcc := make([]byte, 1+len(annexb))
|
||||||
binary.BigEndian.PutUint32(avcc, uint32(len(annexb)-3))
|
binary.BigEndian.PutUint32(avcc, uint32(len(annexb)-3))
|
||||||
copy(avcc[4:], annexb[start+3:])
|
copy(avcc[4:], annexb[start+3:])
|
||||||
return avcc
|
return avcc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CovertAVCCToAnnexB(avcc []byte) {
|
func CovertAVCCToAnnexB(avcc []byte) {
|
||||||
avcc[0] = 0x00
|
avcc[0] = 0x00
|
||||||
avcc[1] = 0x00
|
avcc[1] = 0x00
|
||||||
avcc[2] = 0x00
|
avcc[2] = 0x00
|
||||||
avcc[3] = 0x01
|
avcc[3] = 0x01
|
||||||
}
|
}
|
||||||
|
|
1652
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h265.go
generated
vendored
1652
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h265.go
generated
vendored
File diff suppressed because it is too large
Load diff
398
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/opus.go
generated
vendored
398
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/opus.go
generated
vendored
|
@ -1,8 +1,8 @@
|
||||||
package codec
|
package codec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rfc6716 https://datatracker.ietf.org/doc/html/rfc6716
|
// rfc6716 https://datatracker.ietf.org/doc/html/rfc6716
|
||||||
|
@ -157,169 +157,169 @@ import (
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
var (
|
var (
|
||||||
/// 10ms,20ms,40ms,60ms, samplerate 48000
|
/// 10ms,20ms,40ms,60ms, samplerate 48000
|
||||||
// sample num per millisecond
|
// sample num per millisecond
|
||||||
// 48000 / 1000ms * 10 = 480 ...
|
// 48000 / 1000ms * 10 = 480 ...
|
||||||
SLKOpusSampleSize [4]int = [4]int{480, 960, 1920, 2880}
|
SLKOpusSampleSize [4]int = [4]int{480, 960, 1920, 2880}
|
||||||
HybridOpusSampleSize [4]int = [4]int{480, 960}
|
HybridOpusSampleSize [4]int = [4]int{480, 960}
|
||||||
CELTOpusSampleSize [4]int = [4]int{120, 210, 480, 960}
|
CELTOpusSampleSize [4]int = [4]int{120, 210, 480, 960}
|
||||||
)
|
)
|
||||||
|
|
||||||
func OpusPacketDuration(packet []byte) uint64 {
|
func OpusPacketDuration(packet []byte) uint64 {
|
||||||
config := int(packet[0] >> 3)
|
config := int(packet[0] >> 3)
|
||||||
code := packet[0] & 0x03
|
code := packet[0] & 0x03
|
||||||
frameCount := 0
|
frameCount := 0
|
||||||
var duration uint64
|
var duration uint64
|
||||||
if code == 0 {
|
if code == 0 {
|
||||||
frameCount = 1
|
frameCount = 1
|
||||||
} else if code == 1 || code == 2 {
|
} else if code == 1 || code == 2 {
|
||||||
frameCount = 2
|
frameCount = 2
|
||||||
} else if code == 3 {
|
} else if code == 3 {
|
||||||
frameCount = int(packet[1] & 0x1F)
|
frameCount = int(packet[1] & 0x1F)
|
||||||
} else {
|
} else {
|
||||||
panic("code must <= 3")
|
panic("code must <= 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config >= 0 && config < 12:
|
case config >= 0 && config < 12:
|
||||||
duration = uint64(frameCount * SLKOpusSampleSize[config%4])
|
duration = uint64(frameCount * SLKOpusSampleSize[config%4])
|
||||||
case config >= 12 && config < 16:
|
case config >= 12 && config < 16:
|
||||||
duration = uint64(frameCount * HybridOpusSampleSize[config%2])
|
duration = uint64(frameCount * HybridOpusSampleSize[config%2])
|
||||||
case config >= 16 && config < 32:
|
case config >= 16 && config < 32:
|
||||||
duration = uint64(frameCount * CELTOpusSampleSize[config%4])
|
duration = uint64(frameCount * CELTOpusSampleSize[config%4])
|
||||||
default:
|
default:
|
||||||
panic("unkown opus config")
|
panic("unkown opus config")
|
||||||
}
|
}
|
||||||
|
|
||||||
return duration
|
return duration
|
||||||
}
|
}
|
||||||
|
|
||||||
//ffmpeg opus.h OpusPacket
|
//ffmpeg opus.h OpusPacket
|
||||||
type OpusPacket struct {
|
type OpusPacket struct {
|
||||||
Code int
|
Code int
|
||||||
Config int
|
Config int
|
||||||
Stereo int
|
Stereo int
|
||||||
Vbr int
|
Vbr int
|
||||||
FrameCount int
|
FrameCount int
|
||||||
FrameLen []uint16
|
FrameLen []uint16
|
||||||
Frame []byte
|
Frame []byte
|
||||||
Duration uint64
|
Duration uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeOpusPacket(packet []byte) *OpusPacket {
|
func DecodeOpusPacket(packet []byte) *OpusPacket {
|
||||||
pkt := &OpusPacket{}
|
pkt := &OpusPacket{}
|
||||||
pkt.Code = int(packet[0] & 0x03)
|
pkt.Code = int(packet[0] & 0x03)
|
||||||
pkt.Stereo = int((packet[0] >> 2) & 0x01)
|
pkt.Stereo = int((packet[0] >> 2) & 0x01)
|
||||||
pkt.Config = int(packet[0] >> 3)
|
pkt.Config = int(packet[0] >> 3)
|
||||||
|
|
||||||
switch pkt.Code {
|
switch pkt.Code {
|
||||||
case 0:
|
case 0:
|
||||||
pkt.FrameCount = 1
|
pkt.FrameCount = 1
|
||||||
pkt.FrameLen = make([]uint16, 1)
|
pkt.FrameLen = make([]uint16, 1)
|
||||||
pkt.FrameLen[0] = uint16(len(packet) - 1)
|
pkt.FrameLen[0] = uint16(len(packet) - 1)
|
||||||
pkt.Frame = packet[1:]
|
pkt.Frame = packet[1:]
|
||||||
case 1:
|
case 1:
|
||||||
pkt.FrameCount = 2
|
pkt.FrameCount = 2
|
||||||
pkt.FrameLen = make([]uint16, 1)
|
pkt.FrameLen = make([]uint16, 1)
|
||||||
pkt.FrameLen[0] = uint16(len(packet)-1) / 2
|
pkt.FrameLen[0] = uint16(len(packet)-1) / 2
|
||||||
pkt.Frame = packet[1:]
|
pkt.Frame = packet[1:]
|
||||||
case 2:
|
case 2:
|
||||||
pkt.FrameCount = 2
|
pkt.FrameCount = 2
|
||||||
hdr := 1
|
hdr := 1
|
||||||
N1 := int(packet[1])
|
N1 := int(packet[1])
|
||||||
if N1 >= 252 {
|
if N1 >= 252 {
|
||||||
N1 = N1 + int(packet[2]*4)
|
N1 = N1 + int(packet[2]*4)
|
||||||
hdr = 2
|
hdr = 2
|
||||||
}
|
}
|
||||||
pkt.FrameLen = make([]uint16, 2)
|
pkt.FrameLen = make([]uint16, 2)
|
||||||
pkt.FrameLen[0] = uint16(N1)
|
pkt.FrameLen[0] = uint16(N1)
|
||||||
pkt.FrameLen[1] = uint16(len(packet)-hdr) - uint16(N1)
|
pkt.FrameLen[1] = uint16(len(packet)-hdr) - uint16(N1)
|
||||||
case 3:
|
case 3:
|
||||||
hdr := 2
|
hdr := 2
|
||||||
pkt.Vbr = int(packet[1] >> 7)
|
pkt.Vbr = int(packet[1] >> 7)
|
||||||
padding := packet[1] >> 6
|
padding := packet[1] >> 6
|
||||||
pkt.FrameCount = int(packet[1] & 0x1F)
|
pkt.FrameCount = int(packet[1] & 0x1F)
|
||||||
paddingLen := 0
|
paddingLen := 0
|
||||||
if padding == 1 {
|
if padding == 1 {
|
||||||
for packet[hdr] == 255 {
|
for packet[hdr] == 255 {
|
||||||
paddingLen += 254
|
paddingLen += 254
|
||||||
hdr++
|
hdr++
|
||||||
}
|
}
|
||||||
paddingLen += int(packet[hdr])
|
paddingLen += int(packet[hdr])
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkt.Vbr == 0 {
|
if pkt.Vbr == 0 {
|
||||||
pkt.FrameLen = make([]uint16, 1)
|
pkt.FrameLen = make([]uint16, 1)
|
||||||
pkt.FrameLen[0] = uint16(len(packet)-hdr-paddingLen) / uint16(pkt.FrameCount)
|
pkt.FrameLen[0] = uint16(len(packet)-hdr-paddingLen) / uint16(pkt.FrameCount)
|
||||||
pkt.Frame = packet[hdr : hdr+int(pkt.FrameLen[0]*uint16(pkt.FrameCount))]
|
pkt.Frame = packet[hdr : hdr+int(pkt.FrameLen[0]*uint16(pkt.FrameCount))]
|
||||||
} else {
|
} else {
|
||||||
n := 0
|
n := 0
|
||||||
for i := 0; i < int(pkt.FrameCount)-1; i++ {
|
for i := 0; i < int(pkt.FrameCount)-1; i++ {
|
||||||
N1 := int(packet[hdr])
|
N1 := int(packet[hdr])
|
||||||
hdr += 1
|
hdr += 1
|
||||||
if N1 >= 252 {
|
if N1 >= 252 {
|
||||||
N1 = N1 + int(packet[hdr]*4)
|
N1 = N1 + int(packet[hdr]*4)
|
||||||
hdr += 1
|
hdr += 1
|
||||||
}
|
}
|
||||||
n += N1
|
n += N1
|
||||||
pkt.FrameLen = append(pkt.FrameLen, uint16(N1))
|
pkt.FrameLen = append(pkt.FrameLen, uint16(N1))
|
||||||
}
|
}
|
||||||
lastFrameLen := len(packet) - hdr - paddingLen - n
|
lastFrameLen := len(packet) - hdr - paddingLen - n
|
||||||
pkt.FrameLen = append(pkt.FrameLen, uint16(lastFrameLen))
|
pkt.FrameLen = append(pkt.FrameLen, uint16(lastFrameLen))
|
||||||
pkt.Frame = packet[hdr : hdr+n+lastFrameLen]
|
pkt.Frame = packet[hdr : hdr+n+lastFrameLen]
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("Error C must <= 3")
|
panic("Error C must <= 3")
|
||||||
}
|
}
|
||||||
OpusPacketDuration(packet)
|
OpusPacketDuration(packet)
|
||||||
return pkt
|
return pkt
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LEFT_CHANNEL = 0
|
LEFT_CHANNEL = 0
|
||||||
RIGHT_CHANNEL = 1
|
RIGHT_CHANNEL = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
vorbisChanLayoutOffset [8][8]byte = [8][8]byte{
|
vorbisChanLayoutOffset [8][8]byte = [8][8]byte{
|
||||||
{0},
|
{0},
|
||||||
{0, 1},
|
{0, 1},
|
||||||
{0, 2, 1},
|
{0, 2, 1},
|
||||||
{0, 1, 2, 3},
|
{0, 1, 2, 3},
|
||||||
{0, 2, 1, 3, 4},
|
{0, 2, 1, 3, 4},
|
||||||
{0, 2, 1, 5, 3, 4},
|
{0, 2, 1, 5, 3, 4},
|
||||||
{0, 2, 1, 6, 5, 3, 4},
|
{0, 2, 1, 6, 5, 3, 4},
|
||||||
{0, 2, 1, 7, 5, 6, 3, 4},
|
{0, 2, 1, 7, 5, 6, 3, 4},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChannelOrder func(channels int, idx int) int
|
type ChannelOrder func(channels int, idx int) int
|
||||||
|
|
||||||
func defalutOrder(channels int, idx int) int {
|
func defalutOrder(channels int, idx int) int {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
func vorbisOrder(channels int, idx int) int {
|
func vorbisOrder(channels int, idx int) int {
|
||||||
return int(vorbisChanLayoutOffset[channels-1][idx])
|
return int(vorbisChanLayoutOffset[channels-1][idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelMap struct {
|
type ChannelMap struct {
|
||||||
StreamIdx int
|
StreamIdx int
|
||||||
ChannelIdx int
|
ChannelIdx int
|
||||||
Silence bool
|
Silence bool
|
||||||
Copy bool
|
Copy bool
|
||||||
CopyFrom int
|
CopyFrom int
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpusContext struct {
|
type OpusContext struct {
|
||||||
Preskip int
|
Preskip int
|
||||||
SampleRate int
|
SampleRate int
|
||||||
ChannelCount int
|
ChannelCount int
|
||||||
StreamCount int
|
StreamCount int
|
||||||
StereoStreamCount int
|
StereoStreamCount int
|
||||||
OutputGain uint16
|
OutputGain uint16
|
||||||
MapType uint8
|
MapType uint8
|
||||||
ChannelMaps []ChannelMap
|
ChannelMaps []ChannelMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// opus ID Head
|
// opus ID Head
|
||||||
|
@ -348,83 +348,83 @@ type OpusContext struct {
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
//
|
//
|
||||||
func (ctx *OpusContext) ParseExtranData(extraData []byte) error {
|
func (ctx *OpusContext) ParseExtranData(extraData []byte) error {
|
||||||
if string(extraData[0:8]) != "OpusHead" {
|
if string(extraData[0:8]) != "OpusHead" {
|
||||||
return errors.New("magic signature must equal OpusHead")
|
return errors.New("magic signature must equal OpusHead")
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = extraData[8] // version
|
_ = extraData[8] // version
|
||||||
ctx.ChannelCount = int(extraData[9])
|
ctx.ChannelCount = int(extraData[9])
|
||||||
ctx.Preskip = int(binary.LittleEndian.Uint16(extraData[10:]))
|
ctx.Preskip = int(binary.LittleEndian.Uint16(extraData[10:]))
|
||||||
ctx.SampleRate = int(binary.LittleEndian.Uint32(extraData[12:]))
|
ctx.SampleRate = int(binary.LittleEndian.Uint32(extraData[12:]))
|
||||||
ctx.OutputGain = binary.LittleEndian.Uint16(extraData[16:])
|
ctx.OutputGain = binary.LittleEndian.Uint16(extraData[16:])
|
||||||
ctx.MapType = extraData[18]
|
ctx.MapType = extraData[18]
|
||||||
var channel []byte
|
var channel []byte
|
||||||
var order ChannelOrder
|
var order ChannelOrder
|
||||||
if ctx.MapType == 0 {
|
if ctx.MapType == 0 {
|
||||||
ctx.StreamCount = 1
|
ctx.StreamCount = 1
|
||||||
ctx.StereoStreamCount = ctx.ChannelCount - 1
|
ctx.StereoStreamCount = ctx.ChannelCount - 1
|
||||||
channel = []byte{0, 1}
|
channel = []byte{0, 1}
|
||||||
order = defalutOrder
|
order = defalutOrder
|
||||||
} else if ctx.MapType == 1 || ctx.MapType == 2 || ctx.MapType == 255 {
|
} else if ctx.MapType == 1 || ctx.MapType == 2 || ctx.MapType == 255 {
|
||||||
ctx.StreamCount = int(extraData[19])
|
ctx.StreamCount = int(extraData[19])
|
||||||
ctx.StereoStreamCount = int(extraData[20])
|
ctx.StereoStreamCount = int(extraData[20])
|
||||||
if ctx.MapType == 1 {
|
if ctx.MapType == 1 {
|
||||||
channel = extraData[21 : 21+ctx.ChannelCount]
|
channel = extraData[21 : 21+ctx.ChannelCount]
|
||||||
order = vorbisOrder
|
order = vorbisOrder
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return errors.New("unsupport map type 255")
|
return errors.New("unsupport map type 255")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < ctx.ChannelCount; i++ {
|
for i := 0; i < ctx.ChannelCount; i++ {
|
||||||
cm := ChannelMap{}
|
cm := ChannelMap{}
|
||||||
index := channel[order(ctx.ChannelCount, i)]
|
index := channel[order(ctx.ChannelCount, i)]
|
||||||
if index == 255 {
|
if index == 255 {
|
||||||
cm.Silence = true
|
cm.Silence = true
|
||||||
continue
|
continue
|
||||||
} else if index > byte(ctx.StereoStreamCount)+byte(ctx.StreamCount) {
|
} else if index > byte(ctx.StereoStreamCount)+byte(ctx.StreamCount) {
|
||||||
return errors.New("index must < (streamcount + stereo streamcount)")
|
return errors.New("index must < (streamcount + stereo streamcount)")
|
||||||
}
|
}
|
||||||
|
|
||||||
for j := 0; j < i; j++ {
|
for j := 0; j < i; j++ {
|
||||||
if channel[order(ctx.ChannelCount, i)] == index {
|
if channel[order(ctx.ChannelCount, i)] == index {
|
||||||
cm.Copy = true
|
cm.Copy = true
|
||||||
cm.CopyFrom = j
|
cm.CopyFrom = j
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(index) < 2*ctx.StereoStreamCount {
|
if int(index) < 2*ctx.StereoStreamCount {
|
||||||
cm.StreamIdx = int(index) / 2
|
cm.StreamIdx = int(index) / 2
|
||||||
if index&1 == 0 {
|
if index&1 == 0 {
|
||||||
cm.ChannelIdx = LEFT_CHANNEL
|
cm.ChannelIdx = LEFT_CHANNEL
|
||||||
} else {
|
} else {
|
||||||
cm.ChannelIdx = RIGHT_CHANNEL
|
cm.ChannelIdx = RIGHT_CHANNEL
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cm.StreamIdx = int(index) - ctx.StereoStreamCount
|
cm.StreamIdx = int(index) - ctx.StereoStreamCount
|
||||||
cm.ChannelIdx = 0
|
cm.ChannelIdx = 0
|
||||||
}
|
}
|
||||||
ctx.ChannelMaps = append(ctx.ChannelMaps, cm)
|
ctx.ChannelMaps = append(ctx.ChannelMaps, cm)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *OpusContext) WriteOpusExtraData() []byte {
|
func (ctx *OpusContext) WriteOpusExtraData() []byte {
|
||||||
extraData := make([]byte, 19)
|
extraData := make([]byte, 19)
|
||||||
copy(extraData, string("OpusHead"))
|
copy(extraData, string("OpusHead"))
|
||||||
extraData[8] = 0x01
|
extraData[8] = 0x01
|
||||||
extraData[9] = byte(ctx.ChannelCount)
|
extraData[9] = byte(ctx.ChannelCount)
|
||||||
binary.LittleEndian.PutUint16(extraData[10:], uint16(ctx.Preskip))
|
binary.LittleEndian.PutUint16(extraData[10:], uint16(ctx.Preskip))
|
||||||
binary.LittleEndian.PutUint32(extraData[12:], uint32(ctx.SampleRate))
|
binary.LittleEndian.PutUint32(extraData[12:], uint32(ctx.SampleRate))
|
||||||
return extraData
|
return extraData
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteDefaultOpusExtraData() []byte {
|
func WriteDefaultOpusExtraData() []byte {
|
||||||
return []byte{
|
return []byte{
|
||||||
'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',
|
'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',
|
||||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
1, 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
370
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/util.go
generated
vendored
370
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/util.go
generated
vendored
|
@ -5,253 +5,253 @@ import "fmt"
|
||||||
type START_CODE_TYPE int
|
type START_CODE_TYPE int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
START_CODE_3 START_CODE_TYPE = 3
|
START_CODE_3 START_CODE_TYPE = 3
|
||||||
START_CODE_4 = 4
|
START_CODE_4 = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
func FindStartCode(nalu []byte, offset int) (int, START_CODE_TYPE) {
|
func FindStartCode(nalu []byte, offset int) (int, START_CODE_TYPE) {
|
||||||
for i := offset; i < len(nalu)-4; i++ {
|
for i := offset; i < len(nalu)-4; i++ {
|
||||||
if nalu[i] == 0x00 && nalu[i+1] == 0x00 {
|
if nalu[i] == 0x00 && nalu[i+1] == 0x00 {
|
||||||
if nalu[i+2] == 0x01 {
|
if nalu[i+2] == 0x01 {
|
||||||
return i, START_CODE_3
|
return i, START_CODE_3
|
||||||
} else if nalu[i+2] == 0x00 && nalu[i+3] == 0x01 {
|
} else if nalu[i+2] == 0x00 && nalu[i+3] == 0x01 {
|
||||||
return i, START_CODE_4
|
return i, START_CODE_4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1, START_CODE_3
|
return -1, START_CODE_3
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindSyncword(aac []byte, offset int) int {
|
func FindSyncword(aac []byte, offset int) int {
|
||||||
for i := offset; i < len(aac); i++ {
|
for i := offset; i < len(aac); i++ {
|
||||||
if aac[i] == 0xFF && aac[i+1]&0xF0 == 0xF0 {
|
if aac[i] == 0xFF && aac[i+1]&0xF0 == 0xF0 {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func SplitFrame(frames []byte, onFrame func(nalu []byte) bool) {
|
func SplitFrame(frames []byte, onFrame func(nalu []byte) bool) {
|
||||||
beg, sc := FindStartCode(frames, 0)
|
beg, sc := FindStartCode(frames, 0)
|
||||||
for beg >= 0 {
|
for beg >= 0 {
|
||||||
end, sc2 := FindStartCode(frames, beg+int(sc))
|
end, sc2 := FindStartCode(frames, beg+int(sc))
|
||||||
if end == -1 {
|
if end == -1 {
|
||||||
if onFrame != nil {
|
if onFrame != nil {
|
||||||
onFrame(frames[beg+int(sc):])
|
onFrame(frames[beg+int(sc):])
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if onFrame != nil && onFrame(frames[beg+int(sc):end]) == false {
|
if onFrame != nil && onFrame(frames[beg+int(sc):end]) == false {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
beg = end
|
beg = end
|
||||||
sc = sc2
|
sc = sc2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SplitFrameWithStartCode(frames []byte, onFrame func(nalu []byte) bool) {
|
func SplitFrameWithStartCode(frames []byte, onFrame func(nalu []byte) bool) {
|
||||||
beg, sc := FindStartCode(frames, 0)
|
beg, sc := FindStartCode(frames, 0)
|
||||||
for beg >= 0 {
|
for beg >= 0 {
|
||||||
end, sc2 := FindStartCode(frames, beg+int(sc))
|
end, sc2 := FindStartCode(frames, beg+int(sc))
|
||||||
if end == -1 {
|
if end == -1 {
|
||||||
if onFrame != nil {
|
if onFrame != nil {
|
||||||
onFrame(frames[beg:])
|
onFrame(frames[beg:])
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if onFrame != nil && onFrame(frames[beg:end]) == false {
|
if onFrame != nil && onFrame(frames[beg:end]) == false {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
beg = end
|
beg = end
|
||||||
sc = sc2
|
sc = sc2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SplitAACFrame(frames []byte, onFrame func(aac []byte)) {
|
func SplitAACFrame(frames []byte, onFrame func(aac []byte)) {
|
||||||
var adts ADTS_Frame_Header
|
var adts ADTS_Frame_Header
|
||||||
start := FindSyncword(frames, 0)
|
start := FindSyncword(frames, 0)
|
||||||
for start >= 0 {
|
for start >= 0 {
|
||||||
adts.Decode(frames[start:])
|
adts.Decode(frames[start:])
|
||||||
onFrame(frames[start : start+int(adts.Variable_Header.Frame_length)])
|
onFrame(frames[start : start+int(adts.Variable_Header.Frame_length)])
|
||||||
start = FindSyncword(frames, start+int(adts.Variable_Header.Frame_length))
|
start = FindSyncword(frames, start+int(adts.Variable_Header.Frame_length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func H264NaluType(h264 []byte) H264_NAL_TYPE {
|
func H264NaluType(h264 []byte) H264_NAL_TYPE {
|
||||||
loc, sc := FindStartCode(h264, 0)
|
loc, sc := FindStartCode(h264, 0)
|
||||||
return H264_NAL_TYPE(h264[loc+int(sc)] & 0x1F)
|
return H264_NAL_TYPE(h264[loc+int(sc)] & 0x1F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func H264NaluTypeWithoutStartCode(h264 []byte) H264_NAL_TYPE {
|
func H264NaluTypeWithoutStartCode(h264 []byte) H264_NAL_TYPE {
|
||||||
return H264_NAL_TYPE(h264[0] & 0x1F)
|
return H264_NAL_TYPE(h264[0] & 0x1F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func H265NaluType(h265 []byte) H265_NAL_TYPE {
|
func H265NaluType(h265 []byte) H265_NAL_TYPE {
|
||||||
loc, sc := FindStartCode(h265, 0)
|
loc, sc := FindStartCode(h265, 0)
|
||||||
return H265_NAL_TYPE((h265[loc+int(sc)] >> 1) & 0x3F)
|
return H265_NAL_TYPE((h265[loc+int(sc)] >> 1) & 0x3F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func H265NaluTypeWithoutStartCode(h265 []byte) H265_NAL_TYPE {
|
func H265NaluTypeWithoutStartCode(h265 []byte) H265_NAL_TYPE {
|
||||||
return H265_NAL_TYPE((h265[0] >> 1) & 0x3F)
|
return H265_NAL_TYPE((h265[0] >> 1) & 0x3F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetH264FirstMbInSlice(nalu []byte) uint64 {
|
func GetH264FirstMbInSlice(nalu []byte) uint64 {
|
||||||
start, sc := FindStartCode(nalu, 0)
|
start, sc := FindStartCode(nalu, 0)
|
||||||
bs := NewBitStream(nalu[start+int(sc)+1:])
|
bs := NewBitStream(nalu[start+int(sc)+1:])
|
||||||
sliceHdr := &SliceHeader{}
|
sliceHdr := &SliceHeader{}
|
||||||
sliceHdr.Decode(bs)
|
sliceHdr.Decode(bs)
|
||||||
return sliceHdr.First_mb_in_slice
|
return sliceHdr.First_mb_in_slice
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetH265FirstMbInSlice(nalu []byte) uint64 {
|
func GetH265FirstMbInSlice(nalu []byte) uint64 {
|
||||||
start, sc := FindStartCode(nalu, 0)
|
start, sc := FindStartCode(nalu, 0)
|
||||||
bs := NewBitStream(nalu[start+int(sc)+2:])
|
bs := NewBitStream(nalu[start+int(sc)+2:])
|
||||||
sliceHdr := &SliceHeader{}
|
sliceHdr := &SliceHeader{}
|
||||||
sliceHdr.Decode(bs)
|
sliceHdr.Decode(bs)
|
||||||
return sliceHdr.First_mb_in_slice
|
return sliceHdr.First_mb_in_slice
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsH264IDRFrame(h264 []byte) bool {
|
func IsH264IDRFrame(h264 []byte) bool {
|
||||||
|
|
||||||
ret := false
|
ret := false
|
||||||
onnalu := func(nalu []byte) bool {
|
onnalu := func(nalu []byte) bool {
|
||||||
nal_type := H264NaluTypeWithoutStartCode(nalu)
|
nal_type := H264NaluTypeWithoutStartCode(nalu)
|
||||||
if nal_type < 5 {
|
if nal_type < 5 {
|
||||||
return false
|
return false
|
||||||
} else if nal_type == 5 {
|
} else if nal_type == 5 {
|
||||||
ret = true
|
ret = true
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SplitFrame(h264, onnalu)
|
SplitFrame(h264, onnalu)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsH264VCLNaluType(nal_type H264_NAL_TYPE) bool {
|
func IsH264VCLNaluType(nal_type H264_NAL_TYPE) bool {
|
||||||
if nal_type <= H264_NAL_I_SLICE && nal_type > H264_NAL_RESERVED {
|
if nal_type <= H264_NAL_I_SLICE && nal_type > H264_NAL_RESERVED {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsH265VCLNaluType(nal_type H265_NAL_TYPE) bool {
|
func IsH265VCLNaluType(nal_type H265_NAL_TYPE) bool {
|
||||||
if (nal_type <= H265_NAL_SLICE_CRA && nal_type >= H265_NAL_SLICE_BLA_W_LP) ||
|
if (nal_type <= H265_NAL_SLICE_CRA && nal_type >= H265_NAL_SLICE_BLA_W_LP) ||
|
||||||
(nal_type <= H265_NAL_SLICE_RASL_R && nal_type >= H265_NAL_Slice_TRAIL_N) {
|
(nal_type <= H265_NAL_SLICE_RASL_R && nal_type >= H265_NAL_Slice_TRAIL_N) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsH265IDRFrame(h265 []byte) bool {
|
func IsH265IDRFrame(h265 []byte) bool {
|
||||||
ret := false
|
ret := false
|
||||||
onnalu := func(nalu []byte) bool {
|
onnalu := func(nalu []byte) bool {
|
||||||
nal_type := H264NaluTypeWithoutStartCode(nalu)
|
nal_type := H264NaluTypeWithoutStartCode(nalu)
|
||||||
if nal_type <= 9 && nal_type >= 0 {
|
if nal_type <= 9 && nal_type >= 0 {
|
||||||
return false
|
return false
|
||||||
} else if nal_type >= 16 && nal_type <= 21 {
|
} else if nal_type >= 16 && nal_type <= 21 {
|
||||||
ret = true
|
ret = true
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SplitFrame(h265, onnalu)
|
SplitFrame(h265, onnalu)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func Max(x, y int) int {
|
func Max(x, y int) int {
|
||||||
if x > y {
|
if x > y {
|
||||||
return x
|
return x
|
||||||
} else {
|
} else {
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Min(x, y int) int {
|
func Min(x, y int) int {
|
||||||
if x > y {
|
if x > y {
|
||||||
return y
|
return y
|
||||||
} else {
|
} else {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShowPacketHexdump(data []byte) {
|
func ShowPacketHexdump(data []byte) {
|
||||||
for k := 0; k < len(data); k++ {
|
for k := 0; k < len(data); k++ {
|
||||||
if k%8 == 0 && k != 0 {
|
if k%8 == 0 && k != 0 {
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
fmt.Printf("%02x ", data[k])
|
fmt.Printf("%02x ", data[k])
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
var crc32table [256]uint32 = [256]uint32{
|
var crc32table [256]uint32 = [256]uint32{
|
||||||
0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517,
|
0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517,
|
||||||
0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B,
|
0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B,
|
||||||
0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048,
|
0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048,
|
||||||
0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652,
|
0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652,
|
||||||
0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D,
|
0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D,
|
||||||
0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095,
|
0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095,
|
||||||
0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA,
|
0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA,
|
||||||
0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0,
|
0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0,
|
||||||
0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3,
|
0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3,
|
||||||
0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF,
|
0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF,
|
||||||
0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730,
|
0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730,
|
||||||
0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A,
|
0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A,
|
||||||
0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05,
|
0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05,
|
||||||
0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475,
|
0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475,
|
||||||
0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A,
|
0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A,
|
||||||
0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840,
|
0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840,
|
||||||
0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB,
|
0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB,
|
||||||
0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87,
|
0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87,
|
||||||
0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4,
|
0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4,
|
||||||
0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE,
|
0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE,
|
||||||
0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1,
|
0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1,
|
||||||
0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64,
|
0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64,
|
||||||
0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B,
|
0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B,
|
||||||
0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351,
|
0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351,
|
||||||
0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832,
|
0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832,
|
||||||
0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E,
|
0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E,
|
||||||
0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5,
|
0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5,
|
||||||
0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF,
|
0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF,
|
||||||
0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0,
|
0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0,
|
||||||
0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0,
|
0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0,
|
||||||
0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F,
|
0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F,
|
||||||
0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185,
|
0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185,
|
||||||
0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A,
|
0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A,
|
||||||
0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176,
|
0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176,
|
||||||
0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15,
|
0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15,
|
||||||
0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F,
|
0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F,
|
||||||
0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620,
|
0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620,
|
||||||
0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8,
|
0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8,
|
||||||
0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7,
|
0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7,
|
||||||
0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD,
|
0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD,
|
||||||
0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E,
|
0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E,
|
||||||
0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2,
|
0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2,
|
||||||
0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1,
|
0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1,
|
||||||
}
|
}
|
||||||
|
|
||||||
func CalcCrc32(crc uint32, buffer []byte) uint32 {
|
func CalcCrc32(crc uint32, buffer []byte) uint32 {
|
||||||
var i int = 0
|
var i int = 0
|
||||||
for i = 0; i < len(buffer); i++ {
|
for i = 0; i < len(buffer); i++ {
|
||||||
crc = crc32table[(crc^uint32(buffer[i]))&0xff] ^ (crc >> 8)
|
crc = crc32table[(crc^uint32(buffer[i]))&0xff] ^ (crc >> 8)
|
||||||
}
|
}
|
||||||
return crc
|
return crc
|
||||||
}
|
}
|
||||||
|
|
||||||
func CovertRbspToSodb(rbsp []byte) []byte {
|
func CovertRbspToSodb(rbsp []byte) []byte {
|
||||||
bs := NewBitStream(rbsp)
|
bs := NewBitStream(rbsp)
|
||||||
bsw := NewBitStreamWriter(len(rbsp))
|
bsw := NewBitStreamWriter(len(rbsp))
|
||||||
for !bs.EOS() {
|
for !bs.EOS() {
|
||||||
if bs.RemainBytes() > 3 && bs.NextBits(24) == 0x000003 {
|
if bs.RemainBytes() > 3 && bs.NextBits(24) == 0x000003 {
|
||||||
bsw.PutByte(bs.Uint8(8))
|
bsw.PutByte(bs.Uint8(8))
|
||||||
bsw.PutByte(bs.Uint8(8))
|
bsw.PutByte(bs.Uint8(8))
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
} else {
|
} else {
|
||||||
bsw.PutByte(bs.Uint8(8))
|
bsw.PutByte(bs.Uint8(8))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bsw.Bits()
|
return bsw.Bits()
|
||||||
}
|
}
|
||||||
|
|
94
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/vp8.go
generated
vendored
94
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/vp8.go
generated
vendored
|
@ -3,70 +3,70 @@ package codec
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
type VP8FrameTag struct {
|
type VP8FrameTag struct {
|
||||||
FrameType uint32 //0: I frame , 1: P frame
|
FrameType uint32 //0: I frame , 1: P frame
|
||||||
Version uint32
|
Version uint32
|
||||||
Display uint32
|
Display uint32
|
||||||
FirstPartSize uint32
|
FirstPartSize uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type VP8KeyFrameHead struct {
|
type VP8KeyFrameHead struct {
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
HorizScale int
|
HorizScale int
|
||||||
VertScale int
|
VertScale int
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeFrameTag(frame []byte) (*VP8FrameTag, error) {
|
func DecodeFrameTag(frame []byte) (*VP8FrameTag, error) {
|
||||||
if len(frame) < 3 {
|
if len(frame) < 3 {
|
||||||
return nil, errors.New("frame bytes < 3")
|
return nil, errors.New("frame bytes < 3")
|
||||||
}
|
}
|
||||||
var tmp uint32 = (uint32(frame[2]) << 16) | (uint32(frame[1]) << 8) | uint32(frame[0])
|
var tmp uint32 = (uint32(frame[2]) << 16) | (uint32(frame[1]) << 8) | uint32(frame[0])
|
||||||
tag := &VP8FrameTag{}
|
tag := &VP8FrameTag{}
|
||||||
tag.FrameType = tmp & 0x01
|
tag.FrameType = tmp & 0x01
|
||||||
tag.Version = (tmp >> 1) & 0x07
|
tag.Version = (tmp >> 1) & 0x07
|
||||||
tag.Display = (tmp >> 4) & 0x01
|
tag.Display = (tmp >> 4) & 0x01
|
||||||
tag.FirstPartSize = (tmp >> 5) & 0x7FFFF
|
tag.FirstPartSize = (tmp >> 5) & 0x7FFFF
|
||||||
return tag, nil
|
return tag, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeKeyFrameHead(frame []byte) (*VP8KeyFrameHead, error) {
|
func DecodeKeyFrameHead(frame []byte) (*VP8KeyFrameHead, error) {
|
||||||
if len(frame) < 7 {
|
if len(frame) < 7 {
|
||||||
return nil, errors.New("frame bytes < 3")
|
return nil, errors.New("frame bytes < 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
if frame[0] != 0x9d || frame[1] != 0x01 || frame[2] != 0x2a {
|
if frame[0] != 0x9d || frame[1] != 0x01 || frame[2] != 0x2a {
|
||||||
return nil, errors.New("not find Start code")
|
return nil, errors.New("not find Start code")
|
||||||
}
|
}
|
||||||
|
|
||||||
head := &VP8KeyFrameHead{}
|
head := &VP8KeyFrameHead{}
|
||||||
head.Width = int(uint16(frame[4]&0x3f)<<8 | uint16(frame[3]))
|
head.Width = int(uint16(frame[4]&0x3f)<<8 | uint16(frame[3]))
|
||||||
head.HorizScale = int(frame[4] >> 6)
|
head.HorizScale = int(frame[4] >> 6)
|
||||||
head.Height = int(uint16(frame[6]&0x3f)<<8 | uint16(frame[5]))
|
head.Height = int(uint16(frame[6]&0x3f)<<8 | uint16(frame[5]))
|
||||||
head.VertScale = int(frame[6] >> 6)
|
head.VertScale = int(frame[6] >> 6)
|
||||||
return head, nil
|
return head, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsKeyFrame(frame []byte) bool {
|
func IsKeyFrame(frame []byte) bool {
|
||||||
tag, err := DecodeFrameTag(frame)
|
tag, err := DecodeFrameTag(frame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if tag.FrameType == 0 {
|
if tag.FrameType == 0 {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetResloution(frame []byte) (width int, height int, err error) {
|
func GetResloution(frame []byte) (width int, height int, err error) {
|
||||||
if !IsKeyFrame(frame) {
|
if !IsKeyFrame(frame) {
|
||||||
return 0, 0, errors.New("the frame is not Key frame")
|
return 0, 0, errors.New("the frame is not Key frame")
|
||||||
}
|
}
|
||||||
|
|
||||||
head, err := DecodeKeyFrameHead(frame[3:])
|
head, err := DecodeKeyFrameHead(frame[3:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
return head.Width, head.Height, nil
|
return head.Width, head.Height, nil
|
||||||
}
|
}
|
||||||
|
|
596
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/pes-proto.go
generated
vendored
596
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/pes-proto.go
generated
vendored
|
@ -1,10 +1,10 @@
|
||||||
package mpeg2
|
package mpeg2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
var H264_AUD_NALU []byte = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0} //ffmpeg mpegtsenc.c mpegts_write_packet_internal
|
var H264_AUD_NALU []byte = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0} //ffmpeg mpegtsenc.c mpegts_write_packet_internal
|
||||||
|
@ -13,337 +13,337 @@ var H265_AUD_NALU []byte = []byte{0x00, 0x00, 0x00, 0x01, 0x46, 0x01, 0x50}
|
||||||
type PES_STREMA_ID int
|
type PES_STREMA_ID int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PES_STREAM_END PES_STREMA_ID = 0xB9
|
PES_STREAM_END PES_STREMA_ID = 0xB9
|
||||||
PES_STREAM_START PES_STREMA_ID = 0xBA
|
PES_STREAM_START PES_STREMA_ID = 0xBA
|
||||||
PES_STREAM_SYSTEM_HEAD PES_STREMA_ID = 0xBB
|
PES_STREAM_SYSTEM_HEAD PES_STREMA_ID = 0xBB
|
||||||
PES_STREAM_MAP PES_STREMA_ID = 0xBC
|
PES_STREAM_MAP PES_STREMA_ID = 0xBC
|
||||||
PES_STREAM_PRIVATE PES_STREMA_ID = 0xBD
|
PES_STREAM_PRIVATE PES_STREMA_ID = 0xBD
|
||||||
PES_STREAM_AUDIO PES_STREMA_ID = 0xC0
|
PES_STREAM_AUDIO PES_STREMA_ID = 0xC0
|
||||||
PES_STREAM_VIDEO PES_STREMA_ID = 0xE0
|
PES_STREAM_VIDEO PES_STREMA_ID = 0xE0
|
||||||
)
|
)
|
||||||
|
|
||||||
func findPESIDByStreamType(cid TS_STREAM_TYPE) PES_STREMA_ID {
|
func findPESIDByStreamType(cid TS_STREAM_TYPE) PES_STREMA_ID {
|
||||||
if cid == TS_STREAM_AAC {
|
if cid == TS_STREAM_AAC {
|
||||||
return PES_STREAM_AUDIO
|
return PES_STREAM_AUDIO
|
||||||
} else if cid == TS_STREAM_H264 || cid == TS_STREAM_H265 {
|
} else if cid == TS_STREAM_H264 || cid == TS_STREAM_H265 {
|
||||||
return PES_STREAM_VIDEO
|
return PES_STREAM_VIDEO
|
||||||
} else {
|
} else {
|
||||||
return PES_STREAM_PRIVATE
|
return PES_STREAM_PRIVATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PesPacket struct {
|
type PesPacket struct {
|
||||||
Stream_id uint8
|
Stream_id uint8
|
||||||
PES_packet_length uint16
|
PES_packet_length uint16
|
||||||
PES_scrambling_control uint8
|
PES_scrambling_control uint8
|
||||||
PES_priority uint8
|
PES_priority uint8
|
||||||
Data_alignment_indicator uint8
|
Data_alignment_indicator uint8
|
||||||
Copyright uint8
|
Copyright uint8
|
||||||
Original_or_copy uint8
|
Original_or_copy uint8
|
||||||
PTS_DTS_flags uint8
|
PTS_DTS_flags uint8
|
||||||
ESCR_flag uint8
|
ESCR_flag uint8
|
||||||
ES_rate_flag uint8
|
ES_rate_flag uint8
|
||||||
DSM_trick_mode_flag uint8
|
DSM_trick_mode_flag uint8
|
||||||
Additional_copy_info_flag uint8
|
Additional_copy_info_flag uint8
|
||||||
PES_CRC_flag uint8
|
PES_CRC_flag uint8
|
||||||
PES_extension_flag uint8
|
PES_extension_flag uint8
|
||||||
PES_header_data_length uint8
|
PES_header_data_length uint8
|
||||||
Pts uint64
|
Pts uint64
|
||||||
Dts uint64
|
Dts uint64
|
||||||
ESCR_base uint64
|
ESCR_base uint64
|
||||||
ESCR_extension uint16
|
ESCR_extension uint16
|
||||||
ES_rate uint32
|
ES_rate uint32
|
||||||
Trick_mode_control uint8
|
Trick_mode_control uint8
|
||||||
Trick_value uint8
|
Trick_value uint8
|
||||||
Additional_copy_info uint8
|
Additional_copy_info uint8
|
||||||
Previous_PES_packet_CRC uint16
|
Previous_PES_packet_CRC uint16
|
||||||
Pes_payload []byte
|
Pes_payload []byte
|
||||||
//TODO
|
//TODO
|
||||||
//if ( PES_extension_flag == '1')
|
//if ( PES_extension_flag == '1')
|
||||||
// PES_private_data_flag uint8
|
// PES_private_data_flag uint8
|
||||||
// pack_header_field_flag uint8
|
// pack_header_field_flag uint8
|
||||||
// program_packet_sequence_counter_flag uint8
|
// program_packet_sequence_counter_flag uint8
|
||||||
// P_STD_buffer_flag uint8
|
// P_STD_buffer_flag uint8
|
||||||
// PES_extension_flag_2 uint8
|
// PES_extension_flag_2 uint8
|
||||||
// PES_private_data [16]byte
|
// PES_private_data [16]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPesPacket() *PesPacket {
|
func NewPesPacket() *PesPacket {
|
||||||
return new(PesPacket)
|
return new(PesPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *PesPacket) PrettyPrint(file *os.File) {
|
func (pkg *PesPacket) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("stream_id:%d\n", pkg.Stream_id))
|
file.WriteString(fmt.Sprintf("stream_id:%d\n", pkg.Stream_id))
|
||||||
file.WriteString(fmt.Sprintf("PES_packet_length:%d\n", pkg.PES_packet_length))
|
file.WriteString(fmt.Sprintf("PES_packet_length:%d\n", pkg.PES_packet_length))
|
||||||
file.WriteString(fmt.Sprintf("PES_scrambling_control:%d\n", pkg.PES_scrambling_control))
|
file.WriteString(fmt.Sprintf("PES_scrambling_control:%d\n", pkg.PES_scrambling_control))
|
||||||
file.WriteString(fmt.Sprintf("PES_priority:%d\n", pkg.PES_priority))
|
file.WriteString(fmt.Sprintf("PES_priority:%d\n", pkg.PES_priority))
|
||||||
file.WriteString(fmt.Sprintf("data_alignment_indicator:%d\n", pkg.Data_alignment_indicator))
|
file.WriteString(fmt.Sprintf("data_alignment_indicator:%d\n", pkg.Data_alignment_indicator))
|
||||||
file.WriteString(fmt.Sprintf("copyright:%d\n", pkg.Copyright))
|
file.WriteString(fmt.Sprintf("copyright:%d\n", pkg.Copyright))
|
||||||
file.WriteString(fmt.Sprintf("original_or_copy:%d\n", pkg.Original_or_copy))
|
file.WriteString(fmt.Sprintf("original_or_copy:%d\n", pkg.Original_or_copy))
|
||||||
file.WriteString(fmt.Sprintf("PTS_DTS_flags:%d\n", pkg.PTS_DTS_flags))
|
file.WriteString(fmt.Sprintf("PTS_DTS_flags:%d\n", pkg.PTS_DTS_flags))
|
||||||
file.WriteString(fmt.Sprintf("ESCR_flag:%d\n", pkg.ESCR_flag))
|
file.WriteString(fmt.Sprintf("ESCR_flag:%d\n", pkg.ESCR_flag))
|
||||||
file.WriteString(fmt.Sprintf("ES_rate_flag:%d\n", pkg.ES_rate_flag))
|
file.WriteString(fmt.Sprintf("ES_rate_flag:%d\n", pkg.ES_rate_flag))
|
||||||
file.WriteString(fmt.Sprintf("DSM_trick_mode_flag:%d\n", pkg.DSM_trick_mode_flag))
|
file.WriteString(fmt.Sprintf("DSM_trick_mode_flag:%d\n", pkg.DSM_trick_mode_flag))
|
||||||
file.WriteString(fmt.Sprintf("additional_copy_info_flag:%d\n", pkg.Additional_copy_info_flag))
|
file.WriteString(fmt.Sprintf("additional_copy_info_flag:%d\n", pkg.Additional_copy_info_flag))
|
||||||
file.WriteString(fmt.Sprintf("PES_CRC_flag:%d\n", pkg.PES_CRC_flag))
|
file.WriteString(fmt.Sprintf("PES_CRC_flag:%d\n", pkg.PES_CRC_flag))
|
||||||
file.WriteString(fmt.Sprintf("PES_extension_flag:%d\n", pkg.PES_extension_flag))
|
file.WriteString(fmt.Sprintf("PES_extension_flag:%d\n", pkg.PES_extension_flag))
|
||||||
file.WriteString(fmt.Sprintf("PES_header_data_length:%d\n", pkg.PES_header_data_length))
|
file.WriteString(fmt.Sprintf("PES_header_data_length:%d\n", pkg.PES_header_data_length))
|
||||||
if pkg.PTS_DTS_flags&0x02 == 0x02 {
|
if pkg.PTS_DTS_flags&0x02 == 0x02 {
|
||||||
file.WriteString(fmt.Sprintf("PTS:%d\n", pkg.Pts))
|
file.WriteString(fmt.Sprintf("PTS:%d\n", pkg.Pts))
|
||||||
}
|
}
|
||||||
if pkg.PTS_DTS_flags&0x03 == 0x03 {
|
if pkg.PTS_DTS_flags&0x03 == 0x03 {
|
||||||
file.WriteString(fmt.Sprintf("DTS:%d\n", pkg.Dts))
|
file.WriteString(fmt.Sprintf("DTS:%d\n", pkg.Dts))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.ESCR_flag == 1 {
|
if pkg.ESCR_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("ESCR_base:%d\n", pkg.ESCR_base))
|
file.WriteString(fmt.Sprintf("ESCR_base:%d\n", pkg.ESCR_base))
|
||||||
file.WriteString(fmt.Sprintf("ESCR_extension:%d\n", pkg.ESCR_extension))
|
file.WriteString(fmt.Sprintf("ESCR_extension:%d\n", pkg.ESCR_extension))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.ES_rate_flag == 1 {
|
if pkg.ES_rate_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("ES_rate:%d\n", pkg.ES_rate))
|
file.WriteString(fmt.Sprintf("ES_rate:%d\n", pkg.ES_rate))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.DSM_trick_mode_flag == 1 {
|
if pkg.DSM_trick_mode_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("trick_mode_control:%d\n", pkg.Trick_mode_control))
|
file.WriteString(fmt.Sprintf("trick_mode_control:%d\n", pkg.Trick_mode_control))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.Additional_copy_info_flag == 1 {
|
if pkg.Additional_copy_info_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("additional_copy_info:%d\n", pkg.Additional_copy_info))
|
file.WriteString(fmt.Sprintf("additional_copy_info:%d\n", pkg.Additional_copy_info))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.PES_CRC_flag == 1 {
|
if pkg.PES_CRC_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("previous_PES_packet_CRC:%d\n", pkg.Previous_PES_packet_CRC))
|
file.WriteString(fmt.Sprintf("previous_PES_packet_CRC:%d\n", pkg.Previous_PES_packet_CRC))
|
||||||
}
|
}
|
||||||
file.WriteString("PES_packet_data_byte:\n")
|
file.WriteString("PES_packet_data_byte:\n")
|
||||||
file.WriteString(fmt.Sprintf(" Size: %d\n", len(pkg.Pes_payload)))
|
file.WriteString(fmt.Sprintf(" Size: %d\n", len(pkg.Pes_payload)))
|
||||||
file.WriteString(" data:")
|
file.WriteString(" data:")
|
||||||
for i := 0; i < 12 && i < len(pkg.Pes_payload); i++ {
|
for i := 0; i < 12 && i < len(pkg.Pes_payload); i++ {
|
||||||
if i%4 == 0 {
|
if i%4 == 0 {
|
||||||
file.WriteString("\n")
|
file.WriteString("\n")
|
||||||
file.WriteString(" ")
|
file.WriteString(" ")
|
||||||
}
|
}
|
||||||
file.WriteString(fmt.Sprintf("0x%02x ", pkg.Pes_payload[i]))
|
file.WriteString(fmt.Sprintf("0x%02x ", pkg.Pes_payload[i]))
|
||||||
}
|
}
|
||||||
file.WriteString("\n")
|
file.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *PesPacket) Decode(bs *codec.BitStream) error {
|
func (pkg *PesPacket) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 9 {
|
if bs.RemainBytes() < 9 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.SkipBits(24) //packet_start_code_prefix
|
bs.SkipBits(24) //packet_start_code_prefix
|
||||||
pkg.Stream_id = bs.Uint8(8) //stream_id
|
pkg.Stream_id = bs.Uint8(8) //stream_id
|
||||||
pkg.PES_packet_length = bs.Uint16(16)
|
pkg.PES_packet_length = bs.Uint16(16)
|
||||||
bs.SkipBits(2) //'10'
|
bs.SkipBits(2) //'10'
|
||||||
pkg.PES_scrambling_control = bs.Uint8(2)
|
pkg.PES_scrambling_control = bs.Uint8(2)
|
||||||
pkg.PES_priority = bs.Uint8(1)
|
pkg.PES_priority = bs.Uint8(1)
|
||||||
pkg.Data_alignment_indicator = bs.Uint8(1)
|
pkg.Data_alignment_indicator = bs.Uint8(1)
|
||||||
pkg.Copyright = bs.Uint8(1)
|
pkg.Copyright = bs.Uint8(1)
|
||||||
pkg.Original_or_copy = bs.Uint8(1)
|
pkg.Original_or_copy = bs.Uint8(1)
|
||||||
pkg.PTS_DTS_flags = bs.Uint8(2)
|
pkg.PTS_DTS_flags = bs.Uint8(2)
|
||||||
pkg.ESCR_flag = bs.Uint8(1)
|
pkg.ESCR_flag = bs.Uint8(1)
|
||||||
pkg.ES_rate_flag = bs.Uint8(1)
|
pkg.ES_rate_flag = bs.Uint8(1)
|
||||||
pkg.DSM_trick_mode_flag = bs.Uint8(1)
|
pkg.DSM_trick_mode_flag = bs.Uint8(1)
|
||||||
pkg.Additional_copy_info_flag = bs.Uint8(1)
|
pkg.Additional_copy_info_flag = bs.Uint8(1)
|
||||||
pkg.PES_CRC_flag = bs.Uint8(1)
|
pkg.PES_CRC_flag = bs.Uint8(1)
|
||||||
pkg.PES_extension_flag = bs.Uint8(1)
|
pkg.PES_extension_flag = bs.Uint8(1)
|
||||||
pkg.PES_header_data_length = bs.Uint8(8)
|
pkg.PES_header_data_length = bs.Uint8(8)
|
||||||
if bs.RemainBytes() < int(pkg.PES_header_data_length) {
|
if bs.RemainBytes() < int(pkg.PES_header_data_length) {
|
||||||
bs.UnRead(9 * 8)
|
bs.UnRead(9 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.Markdot()
|
bs.Markdot()
|
||||||
if pkg.PTS_DTS_flags&0x02 == 0x02 {
|
if pkg.PTS_DTS_flags&0x02 == 0x02 {
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
pkg.Pts = bs.GetBits(3)
|
pkg.Pts = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Pts = (pkg.Pts << 15) | bs.GetBits(15)
|
pkg.Pts = (pkg.Pts << 15) | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Pts = (pkg.Pts << 15) | bs.GetBits(15)
|
pkg.Pts = (pkg.Pts << 15) | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
}
|
}
|
||||||
if pkg.PTS_DTS_flags&0x03 == 0x03 {
|
if pkg.PTS_DTS_flags&0x03 == 0x03 {
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
pkg.Dts = bs.GetBits(3)
|
pkg.Dts = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Dts = (pkg.Dts << 15) | bs.GetBits(15)
|
pkg.Dts = (pkg.Dts << 15) | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Dts = (pkg.Dts << 15) | bs.GetBits(15)
|
pkg.Dts = (pkg.Dts << 15) | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
} else {
|
} else {
|
||||||
pkg.Dts = pkg.Pts
|
pkg.Dts = pkg.Pts
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.ESCR_flag == 1 {
|
if pkg.ESCR_flag == 1 {
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
pkg.ESCR_base = bs.GetBits(3)
|
pkg.ESCR_base = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.ESCR_base = (pkg.Pts << 15) | bs.GetBits(15)
|
pkg.ESCR_base = (pkg.Pts << 15) | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.ESCR_base = (pkg.Pts << 15) | bs.GetBits(15)
|
pkg.ESCR_base = (pkg.Pts << 15) | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.ESCR_extension = bs.Uint16(9)
|
pkg.ESCR_extension = bs.Uint16(9)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.ES_rate_flag == 1 {
|
if pkg.ES_rate_flag == 1 {
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.ES_rate = bs.Uint32(22)
|
pkg.ES_rate = bs.Uint32(22)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.DSM_trick_mode_flag == 1 {
|
if pkg.DSM_trick_mode_flag == 1 {
|
||||||
pkg.Trick_mode_control = bs.Uint8(3)
|
pkg.Trick_mode_control = bs.Uint8(3)
|
||||||
pkg.Trick_value = bs.Uint8(5)
|
pkg.Trick_value = bs.Uint8(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.Additional_copy_info_flag == 1 {
|
if pkg.Additional_copy_info_flag == 1 {
|
||||||
pkg.Additional_copy_info = bs.Uint8(7)
|
pkg.Additional_copy_info = bs.Uint8(7)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.PES_CRC_flag == 1 {
|
if pkg.PES_CRC_flag == 1 {
|
||||||
pkg.Previous_PES_packet_CRC = bs.Uint16(16)
|
pkg.Previous_PES_packet_CRC = bs.Uint16(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
loc := bs.DistanceFromMarkDot()
|
loc := bs.DistanceFromMarkDot()
|
||||||
bs.SkipBits(int(pkg.PES_header_data_length)*8 - loc) // skip remaining header
|
bs.SkipBits(int(pkg.PES_header_data_length)*8 - loc) // skip remaining header
|
||||||
|
|
||||||
// the -3 bytes are the combined lengths
|
// the -3 bytes are the combined lengths
|
||||||
// of all fields between PES_packet_length and PES_header_data_length (2 bytes)
|
// of all fields between PES_packet_length and PES_header_data_length (2 bytes)
|
||||||
// and the PES_header_data_length itself (1 byte)
|
// and the PES_header_data_length itself (1 byte)
|
||||||
dataLen := int(pkg.PES_packet_length - 3 - uint16(pkg.PES_header_data_length))
|
dataLen := int(pkg.PES_packet_length - 3 - uint16(pkg.PES_header_data_length))
|
||||||
|
|
||||||
if bs.RemainBytes() < dataLen {
|
if bs.RemainBytes() < dataLen {
|
||||||
pkg.Pes_payload = bs.RemainData()
|
pkg.Pes_payload = bs.RemainData()
|
||||||
bs.UnRead((9 + int(pkg.PES_header_data_length)) * 8)
|
bs.UnRead((9 + int(pkg.PES_header_data_length)) * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.PES_packet_length == 0 || bs.RemainBytes() <= dataLen {
|
if pkg.PES_packet_length == 0 || bs.RemainBytes() <= dataLen {
|
||||||
pkg.Pes_payload = bs.RemainData()
|
pkg.Pes_payload = bs.RemainData()
|
||||||
bs.SkipBits(bs.RemainBits())
|
bs.SkipBits(bs.RemainBits())
|
||||||
} else {
|
} else {
|
||||||
pkg.Pes_payload = bs.RemainData()[:dataLen]
|
pkg.Pes_payload = bs.RemainData()[:dataLen]
|
||||||
bs.SkipBits(dataLen * 8)
|
bs.SkipBits(dataLen * 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *PesPacket) DecodeMpeg1(bs *codec.BitStream) error {
|
func (pkg *PesPacket) DecodeMpeg1(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 6 {
|
if bs.RemainBytes() < 6 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.SkipBits(24) //packet_start_code_prefix
|
bs.SkipBits(24) //packet_start_code_prefix
|
||||||
pkg.Stream_id = bs.Uint8(8) //stream_id
|
pkg.Stream_id = bs.Uint8(8) //stream_id
|
||||||
pkg.PES_packet_length = bs.Uint16(16)
|
pkg.PES_packet_length = bs.Uint16(16)
|
||||||
if pkg.PES_packet_length != 0 && bs.RemainBytes() < int(pkg.PES_packet_length) {
|
if pkg.PES_packet_length != 0 && bs.RemainBytes() < int(pkg.PES_packet_length) {
|
||||||
bs.UnRead(6 * 8)
|
bs.UnRead(6 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.Markdot()
|
bs.Markdot()
|
||||||
for bs.NextBits(8) == 0xFF {
|
for bs.NextBits(8) == 0xFF {
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
}
|
}
|
||||||
if bs.NextBits(2) == 0x01 {
|
if bs.NextBits(2) == 0x01 {
|
||||||
bs.SkipBits(16)
|
bs.SkipBits(16)
|
||||||
}
|
}
|
||||||
if bs.NextBits(4) == 0x02 {
|
if bs.NextBits(4) == 0x02 {
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
pkg.Pts = bs.GetBits(3)
|
pkg.Pts = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
} else if bs.NextBits(4) == 0x03 {
|
} else if bs.NextBits(4) == 0x03 {
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
pkg.Pts = bs.GetBits(3)
|
pkg.Pts = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Dts = bs.GetBits(3)
|
pkg.Dts = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Dts = pkg.Pts<<15 | bs.GetBits(15)
|
pkg.Dts = pkg.Pts<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
pkg.Dts = pkg.Pts<<15 | bs.GetBits(15)
|
pkg.Dts = pkg.Pts<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
} else if bs.NextBits(8) == 0x0F {
|
} else if bs.NextBits(8) == 0x0F {
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
} else {
|
} else {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
loc := bs.DistanceFromMarkDot() / 8
|
loc := bs.DistanceFromMarkDot() / 8
|
||||||
if pkg.PES_packet_length < uint16(loc) {
|
if pkg.PES_packet_length < uint16(loc) {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
if pkg.PES_packet_length == 0 ||
|
if pkg.PES_packet_length == 0 ||
|
||||||
bs.RemainBits() <= int(pkg.PES_packet_length-uint16(loc))*8 {
|
bs.RemainBits() <= int(pkg.PES_packet_length-uint16(loc))*8 {
|
||||||
pkg.Pes_payload = bs.RemainData()
|
pkg.Pes_payload = bs.RemainData()
|
||||||
bs.SkipBits(bs.RemainBits())
|
bs.SkipBits(bs.RemainBits())
|
||||||
} else {
|
} else {
|
||||||
pkg.Pes_payload = bs.RemainData()[:pkg.PES_packet_length-uint16(loc)]
|
pkg.Pes_payload = bs.RemainData()[:pkg.PES_packet_length-uint16(loc)]
|
||||||
bs.SkipBits(int(pkg.PES_packet_length-uint16(loc)) * 8)
|
bs.SkipBits(int(pkg.PES_packet_length-uint16(loc)) * 8)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *PesPacket) Encode(bsw *codec.BitStreamWriter) {
|
func (pkg *PesPacket) Encode(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01})
|
bsw.PutBytes([]byte{0x00, 0x00, 0x01})
|
||||||
bsw.PutByte(pkg.Stream_id)
|
bsw.PutByte(pkg.Stream_id)
|
||||||
bsw.PutUint16(pkg.PES_packet_length, 16)
|
bsw.PutUint16(pkg.PES_packet_length, 16)
|
||||||
bsw.PutUint8(0x02, 2)
|
bsw.PutUint8(0x02, 2)
|
||||||
bsw.PutUint8(pkg.PES_scrambling_control, 2)
|
bsw.PutUint8(pkg.PES_scrambling_control, 2)
|
||||||
bsw.PutUint8(pkg.PES_priority, 1)
|
bsw.PutUint8(pkg.PES_priority, 1)
|
||||||
bsw.PutUint8(pkg.Data_alignment_indicator, 1)
|
bsw.PutUint8(pkg.Data_alignment_indicator, 1)
|
||||||
bsw.PutUint8(pkg.Copyright, 1)
|
bsw.PutUint8(pkg.Copyright, 1)
|
||||||
bsw.PutUint8(pkg.Original_or_copy, 1)
|
bsw.PutUint8(pkg.Original_or_copy, 1)
|
||||||
bsw.PutUint8(pkg.PTS_DTS_flags, 2)
|
bsw.PutUint8(pkg.PTS_DTS_flags, 2)
|
||||||
bsw.PutUint8(pkg.ESCR_flag, 1)
|
bsw.PutUint8(pkg.ESCR_flag, 1)
|
||||||
bsw.PutUint8(pkg.ES_rate_flag, 1)
|
bsw.PutUint8(pkg.ES_rate_flag, 1)
|
||||||
bsw.PutUint8(pkg.DSM_trick_mode_flag, 1)
|
bsw.PutUint8(pkg.DSM_trick_mode_flag, 1)
|
||||||
bsw.PutUint8(pkg.Additional_copy_info_flag, 1)
|
bsw.PutUint8(pkg.Additional_copy_info_flag, 1)
|
||||||
bsw.PutUint8(pkg.PES_CRC_flag, 1)
|
bsw.PutUint8(pkg.PES_CRC_flag, 1)
|
||||||
bsw.PutUint8(pkg.PES_extension_flag, 1)
|
bsw.PutUint8(pkg.PES_extension_flag, 1)
|
||||||
bsw.PutByte(pkg.PES_header_data_length)
|
bsw.PutByte(pkg.PES_header_data_length)
|
||||||
if pkg.PTS_DTS_flags == 0x02 {
|
if pkg.PTS_DTS_flags == 0x02 {
|
||||||
bsw.PutUint8(0x02, 4)
|
bsw.PutUint8(0x02, 4)
|
||||||
bsw.PutUint64(pkg.Pts>>30, 3)
|
bsw.PutUint64(pkg.Pts>>30, 3)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.Pts>>15, 15)
|
bsw.PutUint64(pkg.Pts>>15, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.Pts, 15)
|
bsw.PutUint64(pkg.Pts, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.PTS_DTS_flags == 0x03 {
|
if pkg.PTS_DTS_flags == 0x03 {
|
||||||
bsw.PutUint8(0x03, 4)
|
bsw.PutUint8(0x03, 4)
|
||||||
bsw.PutUint64(pkg.Pts>>30, 3)
|
bsw.PutUint64(pkg.Pts>>30, 3)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.Pts>>15, 15)
|
bsw.PutUint64(pkg.Pts>>15, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.Pts, 15)
|
bsw.PutUint64(pkg.Pts, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint8(0x01, 4)
|
bsw.PutUint8(0x01, 4)
|
||||||
bsw.PutUint64(pkg.Dts>>30, 3)
|
bsw.PutUint64(pkg.Dts>>30, 3)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.Dts>>15, 15)
|
bsw.PutUint64(pkg.Dts>>15, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.Dts, 15)
|
bsw.PutUint64(pkg.Dts, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.ESCR_flag == 1 {
|
if pkg.ESCR_flag == 1 {
|
||||||
bsw.PutUint8(0x03, 2)
|
bsw.PutUint8(0x03, 2)
|
||||||
bsw.PutUint64(pkg.ESCR_base>>30, 3)
|
bsw.PutUint64(pkg.ESCR_base>>30, 3)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.ESCR_base>>15, 15)
|
bsw.PutUint64(pkg.ESCR_base>>15, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
bsw.PutUint64(pkg.ESCR_base, 15)
|
bsw.PutUint64(pkg.ESCR_base, 15)
|
||||||
bsw.PutUint8(0x01, 1)
|
bsw.PutUint8(0x01, 1)
|
||||||
}
|
}
|
||||||
bsw.PutBytes(pkg.Pes_payload)
|
bsw.PutBytes(pkg.Pes_payload)
|
||||||
}
|
}
|
||||||
|
|
482
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-demuxer.go
generated
vendored
482
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-demuxer.go
generated
vendored
|
@ -1,280 +1,280 @@
|
||||||
package mpeg2
|
package mpeg2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type psstream struct {
|
type psstream struct {
|
||||||
sid uint8
|
sid uint8
|
||||||
cid PS_STREAM_TYPE
|
cid PS_STREAM_TYPE
|
||||||
pts uint64
|
pts uint64
|
||||||
dts uint64
|
dts uint64
|
||||||
streamBuf []byte
|
streamBuf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func newpsstream(sid uint8, cid PS_STREAM_TYPE) *psstream {
|
func newpsstream(sid uint8, cid PS_STREAM_TYPE) *psstream {
|
||||||
return &psstream{
|
return &psstream{
|
||||||
sid: sid,
|
sid: sid,
|
||||||
cid: cid,
|
cid: cid,
|
||||||
streamBuf: make([]byte, 0, 4096),
|
streamBuf: make([]byte, 0, 4096),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PSDemuxer struct {
|
type PSDemuxer struct {
|
||||||
streamMap map[uint8]*psstream
|
streamMap map[uint8]*psstream
|
||||||
pkg *PSPacket
|
pkg *PSPacket
|
||||||
mpeg1 bool
|
mpeg1 bool
|
||||||
cache []byte
|
cache []byte
|
||||||
OnFrame func(frame []byte, cid PS_STREAM_TYPE, pts uint64, dts uint64)
|
OnFrame func(frame []byte, cid PS_STREAM_TYPE, pts uint64, dts uint64)
|
||||||
//解ps包过程中,解码回调psm,system header,pes包等
|
//解ps包过程中,解码回调psm,system header,pes包等
|
||||||
//decodeResult 解码ps包时的产生的错误
|
//decodeResult 解码ps包时的产生的错误
|
||||||
//这个回调主要用于debug,查看是否ps包存在问题
|
//这个回调主要用于debug,查看是否ps包存在问题
|
||||||
OnPacket func(pkg Display, decodeResult error)
|
OnPacket func(pkg Display, decodeResult error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPSDemuxer() *PSDemuxer {
|
func NewPSDemuxer() *PSDemuxer {
|
||||||
return &PSDemuxer{
|
return &PSDemuxer{
|
||||||
streamMap: make(map[uint8]*psstream),
|
streamMap: make(map[uint8]*psstream),
|
||||||
pkg: new(PSPacket),
|
pkg: new(PSPacket),
|
||||||
cache: make([]byte, 0, 256),
|
cache: make([]byte, 0, 256),
|
||||||
OnFrame: nil,
|
OnFrame: nil,
|
||||||
OnPacket: nil,
|
OnPacket: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psdemuxer *PSDemuxer) Input(data []byte) error {
|
func (psdemuxer *PSDemuxer) Input(data []byte) error {
|
||||||
var bs *codec.BitStream
|
var bs *codec.BitStream
|
||||||
if len(psdemuxer.cache) > 0 {
|
if len(psdemuxer.cache) > 0 {
|
||||||
psdemuxer.cache = append(psdemuxer.cache, data...)
|
psdemuxer.cache = append(psdemuxer.cache, data...)
|
||||||
bs = codec.NewBitStream(psdemuxer.cache)
|
bs = codec.NewBitStream(psdemuxer.cache)
|
||||||
} else {
|
} else {
|
||||||
bs = codec.NewBitStream(data)
|
bs = codec.NewBitStream(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
saveReseved := func() {
|
saveReseved := func() {
|
||||||
tmpcache := make([]byte, bs.RemainBytes())
|
tmpcache := make([]byte, bs.RemainBytes())
|
||||||
copy(tmpcache, bs.RemainData())
|
copy(tmpcache, bs.RemainData())
|
||||||
psdemuxer.cache = tmpcache
|
psdemuxer.cache = tmpcache
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret error = nil
|
var ret error = nil
|
||||||
for !bs.EOS() {
|
for !bs.EOS() {
|
||||||
if mpegerr, ok := ret.(Error); ok {
|
if mpegerr, ok := ret.(Error); ok {
|
||||||
if mpegerr.NeedMore() {
|
if mpegerr.NeedMore() {
|
||||||
saveReseved()
|
saveReseved()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if bs.RemainBits() < 32 {
|
if bs.RemainBits() < 32 {
|
||||||
ret = errNeedMore
|
ret = errNeedMore
|
||||||
saveReseved()
|
saveReseved()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
prefix_code := bs.NextBits(32)
|
prefix_code := bs.NextBits(32)
|
||||||
switch prefix_code {
|
switch prefix_code {
|
||||||
case 0x000001BA: //pack header
|
case 0x000001BA: //pack header
|
||||||
if psdemuxer.pkg.Header == nil {
|
if psdemuxer.pkg.Header == nil {
|
||||||
psdemuxer.pkg.Header = new(PSPackHeader)
|
psdemuxer.pkg.Header = new(PSPackHeader)
|
||||||
}
|
}
|
||||||
ret = psdemuxer.pkg.Header.Decode(bs)
|
ret = psdemuxer.pkg.Header.Decode(bs)
|
||||||
psdemuxer.mpeg1 = psdemuxer.pkg.Header.IsMpeg1
|
psdemuxer.mpeg1 = psdemuxer.pkg.Header.IsMpeg1
|
||||||
if psdemuxer.OnPacket != nil {
|
if psdemuxer.OnPacket != nil {
|
||||||
psdemuxer.OnPacket(psdemuxer.pkg.Header, ret)
|
psdemuxer.OnPacket(psdemuxer.pkg.Header, ret)
|
||||||
}
|
}
|
||||||
case 0x000001BB: //system header
|
case 0x000001BB: //system header
|
||||||
if psdemuxer.pkg.Header == nil {
|
if psdemuxer.pkg.Header == nil {
|
||||||
panic("psdemuxer.pkg.Header must not be nil")
|
panic("psdemuxer.pkg.Header must not be nil")
|
||||||
}
|
}
|
||||||
if psdemuxer.pkg.System == nil {
|
if psdemuxer.pkg.System == nil {
|
||||||
psdemuxer.pkg.System = new(System_header)
|
psdemuxer.pkg.System = new(System_header)
|
||||||
}
|
}
|
||||||
ret = psdemuxer.pkg.System.Decode(bs)
|
ret = psdemuxer.pkg.System.Decode(bs)
|
||||||
if psdemuxer.OnPacket != nil {
|
if psdemuxer.OnPacket != nil {
|
||||||
psdemuxer.OnPacket(psdemuxer.pkg.System, ret)
|
psdemuxer.OnPacket(psdemuxer.pkg.System, ret)
|
||||||
}
|
}
|
||||||
case 0x000001BC: //program stream map
|
case 0x000001BC: //program stream map
|
||||||
if psdemuxer.pkg.Psm == nil {
|
if psdemuxer.pkg.Psm == nil {
|
||||||
psdemuxer.pkg.Psm = new(Program_stream_map)
|
psdemuxer.pkg.Psm = new(Program_stream_map)
|
||||||
}
|
}
|
||||||
if ret = psdemuxer.pkg.Psm.Decode(bs); ret == nil {
|
if ret = psdemuxer.pkg.Psm.Decode(bs); ret == nil {
|
||||||
for _, streaminfo := range psdemuxer.pkg.Psm.Stream_map {
|
for _, streaminfo := range psdemuxer.pkg.Psm.Stream_map {
|
||||||
if _, found := psdemuxer.streamMap[streaminfo.Elementary_stream_id]; !found {
|
if _, found := psdemuxer.streamMap[streaminfo.Elementary_stream_id]; !found {
|
||||||
stream := newpsstream(streaminfo.Elementary_stream_id, PS_STREAM_TYPE(streaminfo.Stream_type))
|
stream := newpsstream(streaminfo.Elementary_stream_id, PS_STREAM_TYPE(streaminfo.Stream_type))
|
||||||
psdemuxer.streamMap[stream.sid] = stream
|
psdemuxer.streamMap[stream.sid] = stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if psdemuxer.OnPacket != nil {
|
if psdemuxer.OnPacket != nil {
|
||||||
psdemuxer.OnPacket(psdemuxer.pkg.Psm, ret)
|
psdemuxer.OnPacket(psdemuxer.pkg.Psm, ret)
|
||||||
}
|
}
|
||||||
case 0x000001BD, 0x000001BE, 0x000001BF, 0x000001F0, 0x000001F1,
|
case 0x000001BD, 0x000001BE, 0x000001BF, 0x000001F0, 0x000001F1,
|
||||||
0x000001F2, 0x000001F3, 0x000001F4, 0x000001F5, 0x000001F6,
|
0x000001F2, 0x000001F3, 0x000001F4, 0x000001F5, 0x000001F6,
|
||||||
0x000001F7, 0x000001F8, 0x000001F9, 0x000001FA, 0x000001FB:
|
0x000001F7, 0x000001F8, 0x000001F9, 0x000001FA, 0x000001FB:
|
||||||
if psdemuxer.pkg.CommPes == nil {
|
if psdemuxer.pkg.CommPes == nil {
|
||||||
psdemuxer.pkg.CommPes = new(CommonPesPacket)
|
psdemuxer.pkg.CommPes = new(CommonPesPacket)
|
||||||
}
|
}
|
||||||
ret = psdemuxer.pkg.CommPes.Decode(bs)
|
ret = psdemuxer.pkg.CommPes.Decode(bs)
|
||||||
case 0x000001FF: //program stream directory
|
case 0x000001FF: //program stream directory
|
||||||
if psdemuxer.pkg.Psd == nil {
|
if psdemuxer.pkg.Psd == nil {
|
||||||
psdemuxer.pkg.Psd = new(Program_stream_directory)
|
psdemuxer.pkg.Psd = new(Program_stream_directory)
|
||||||
}
|
}
|
||||||
ret = psdemuxer.pkg.Psd.Decode(bs)
|
ret = psdemuxer.pkg.Psd.Decode(bs)
|
||||||
case 0x000001B9: //MPEG_program_end_code
|
case 0x000001B9: //MPEG_program_end_code
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
if prefix_code&0xFFFFFFE0 == 0x000001C0 || prefix_code&0xFFFFFFE0 == 0x000001E0 {
|
if prefix_code&0xFFFFFFE0 == 0x000001C0 || prefix_code&0xFFFFFFE0 == 0x000001E0 {
|
||||||
if psdemuxer.pkg.Pes == nil {
|
if psdemuxer.pkg.Pes == nil {
|
||||||
psdemuxer.pkg.Pes = NewPesPacket()
|
psdemuxer.pkg.Pes = NewPesPacket()
|
||||||
}
|
}
|
||||||
if psdemuxer.mpeg1 {
|
if psdemuxer.mpeg1 {
|
||||||
ret = psdemuxer.pkg.Pes.DecodeMpeg1(bs)
|
ret = psdemuxer.pkg.Pes.DecodeMpeg1(bs)
|
||||||
} else {
|
} else {
|
||||||
ret = psdemuxer.pkg.Pes.Decode(bs)
|
ret = psdemuxer.pkg.Pes.Decode(bs)
|
||||||
}
|
}
|
||||||
if psdemuxer.OnPacket != nil {
|
if psdemuxer.OnPacket != nil {
|
||||||
psdemuxer.OnPacket(psdemuxer.pkg.Pes, ret)
|
psdemuxer.OnPacket(psdemuxer.pkg.Pes, ret)
|
||||||
}
|
}
|
||||||
if ret == nil {
|
if ret == nil {
|
||||||
if stream, found := psdemuxer.streamMap[psdemuxer.pkg.Pes.Stream_id]; found {
|
if stream, found := psdemuxer.streamMap[psdemuxer.pkg.Pes.Stream_id]; found {
|
||||||
if psdemuxer.mpeg1 && stream.cid == PS_STREAM_UNKNOW {
|
if psdemuxer.mpeg1 && stream.cid == PS_STREAM_UNKNOW {
|
||||||
psdemuxer.guessCodecid(stream)
|
psdemuxer.guessCodecid(stream)
|
||||||
}
|
}
|
||||||
psdemuxer.demuxPespacket(stream, psdemuxer.pkg.Pes)
|
psdemuxer.demuxPespacket(stream, psdemuxer.pkg.Pes)
|
||||||
} else {
|
} else {
|
||||||
if psdemuxer.mpeg1 {
|
if psdemuxer.mpeg1 {
|
||||||
stream := newpsstream(psdemuxer.pkg.Pes.Stream_id, PS_STREAM_UNKNOW)
|
stream := newpsstream(psdemuxer.pkg.Pes.Stream_id, PS_STREAM_UNKNOW)
|
||||||
psdemuxer.streamMap[stream.sid] = stream
|
psdemuxer.streamMap[stream.sid] = stream
|
||||||
stream.streamBuf = append(stream.streamBuf, psdemuxer.pkg.Pes.Pes_payload...)
|
stream.streamBuf = append(stream.streamBuf, psdemuxer.pkg.Pes.Pes_payload...)
|
||||||
stream.pts = psdemuxer.pkg.Pes.Pts
|
stream.pts = psdemuxer.pkg.Pes.Pts
|
||||||
stream.dts = psdemuxer.pkg.Pes.Dts
|
stream.dts = psdemuxer.pkg.Pes.Dts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret == nil && len(psdemuxer.cache) > 0 {
|
if ret == nil && len(psdemuxer.cache) > 0 {
|
||||||
psdemuxer.cache = nil
|
psdemuxer.cache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psdemuxer *PSDemuxer) Flush() {
|
func (psdemuxer *PSDemuxer) Flush() {
|
||||||
for _, stream := range psdemuxer.streamMap {
|
for _, stream := range psdemuxer.streamMap {
|
||||||
if len(stream.streamBuf) == 0 {
|
if len(stream.streamBuf) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if psdemuxer.OnFrame != nil {
|
if psdemuxer.OnFrame != nil {
|
||||||
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
|
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psdemuxer *PSDemuxer) guessCodecid(stream *psstream) {
|
func (psdemuxer *PSDemuxer) guessCodecid(stream *psstream) {
|
||||||
if stream.sid&0xE0 == uint8(PES_STREAM_AUDIO) {
|
if stream.sid&0xE0 == uint8(PES_STREAM_AUDIO) {
|
||||||
stream.cid = PS_STREAM_AAC
|
stream.cid = PS_STREAM_AAC
|
||||||
} else if stream.sid&0xE0 == uint8(PES_STREAM_VIDEO) {
|
} else if stream.sid&0xE0 == uint8(PES_STREAM_VIDEO) {
|
||||||
h264score := 0
|
h264score := 0
|
||||||
h265score := 0
|
h265score := 0
|
||||||
codec.SplitFrame(stream.streamBuf, func(nalu []byte) bool {
|
codec.SplitFrame(stream.streamBuf, func(nalu []byte) bool {
|
||||||
h264nalutype := codec.H264NaluTypeWithoutStartCode(nalu)
|
h264nalutype := codec.H264NaluTypeWithoutStartCode(nalu)
|
||||||
h265nalutype := codec.H265NaluTypeWithoutStartCode(nalu)
|
h265nalutype := codec.H265NaluTypeWithoutStartCode(nalu)
|
||||||
if h264nalutype == codec.H264_NAL_PPS ||
|
if h264nalutype == codec.H264_NAL_PPS ||
|
||||||
h264nalutype == codec.H264_NAL_SPS ||
|
h264nalutype == codec.H264_NAL_SPS ||
|
||||||
h264nalutype == codec.H264_NAL_I_SLICE {
|
h264nalutype == codec.H264_NAL_I_SLICE {
|
||||||
h264score += 2
|
h264score += 2
|
||||||
} else if h264nalutype < 5 {
|
} else if h264nalutype < 5 {
|
||||||
h264score += 1
|
h264score += 1
|
||||||
} else if h264nalutype > 20 {
|
} else if h264nalutype > 20 {
|
||||||
h264score -= 1
|
h264score -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if h265nalutype == codec.H265_NAL_PPS ||
|
if h265nalutype == codec.H265_NAL_PPS ||
|
||||||
h265nalutype == codec.H265_NAL_SPS ||
|
h265nalutype == codec.H265_NAL_SPS ||
|
||||||
h265nalutype == codec.H265_NAL_VPS ||
|
h265nalutype == codec.H265_NAL_VPS ||
|
||||||
(h265nalutype >= codec.H265_NAL_SLICE_BLA_W_LP && h265nalutype <= codec.H265_NAL_SLICE_CRA) {
|
(h265nalutype >= codec.H265_NAL_SLICE_BLA_W_LP && h265nalutype <= codec.H265_NAL_SLICE_CRA) {
|
||||||
h265score += 2
|
h265score += 2
|
||||||
} else if h265nalutype >= codec.H265_NAL_Slice_TRAIL_N && h265nalutype <= codec.H265_NAL_SLICE_RASL_R {
|
} else if h265nalutype >= codec.H265_NAL_Slice_TRAIL_N && h265nalutype <= codec.H265_NAL_SLICE_RASL_R {
|
||||||
h265score += 1
|
h265score += 1
|
||||||
} else if h265nalutype > 40 {
|
} else if h265nalutype > 40 {
|
||||||
h265score -= 1
|
h265score -= 1
|
||||||
}
|
}
|
||||||
if h264score > h265score && h264score >= 4 {
|
if h264score > h265score && h264score >= 4 {
|
||||||
stream.cid = PS_STREAM_H264
|
stream.cid = PS_STREAM_H264
|
||||||
} else if h264score < h265score && h265score >= 4 {
|
} else if h264score < h265score && h265score >= 4 {
|
||||||
stream.cid = PS_STREAM_H265
|
stream.cid = PS_STREAM_H265
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psdemuxer *PSDemuxer) demuxPespacket(stream *psstream, pes *PesPacket) error {
|
func (psdemuxer *PSDemuxer) demuxPespacket(stream *psstream, pes *PesPacket) error {
|
||||||
switch stream.cid {
|
switch stream.cid {
|
||||||
case PS_STREAM_AAC, PS_STREAM_G711A, PS_STREAM_G711U:
|
case PS_STREAM_AAC, PS_STREAM_G711A, PS_STREAM_G711U:
|
||||||
return psdemuxer.demuxAudio(stream, pes)
|
return psdemuxer.demuxAudio(stream, pes)
|
||||||
case PS_STREAM_H264, PS_STREAM_H265:
|
case PS_STREAM_H264, PS_STREAM_H265:
|
||||||
return psdemuxer.demuxH26x(stream, pes)
|
return psdemuxer.demuxH26x(stream, pes)
|
||||||
case PS_STREAM_UNKNOW:
|
case PS_STREAM_UNKNOW:
|
||||||
if stream.pts != pes.Pts {
|
if stream.pts != pes.Pts {
|
||||||
stream.streamBuf = nil
|
stream.streamBuf = nil
|
||||||
}
|
}
|
||||||
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
||||||
stream.pts = pes.Pts
|
stream.pts = pes.Pts
|
||||||
stream.dts = pes.Dts
|
stream.dts = pes.Dts
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psdemuxer *PSDemuxer) demuxAudio(stream *psstream, pes *PesPacket) error {
|
func (psdemuxer *PSDemuxer) demuxAudio(stream *psstream, pes *PesPacket) error {
|
||||||
if stream.pts != pes.Pts && len(stream.streamBuf) > 0 {
|
if stream.pts != pes.Pts && len(stream.streamBuf) > 0 {
|
||||||
if psdemuxer.OnFrame != nil {
|
if psdemuxer.OnFrame != nil {
|
||||||
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
|
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
|
||||||
}
|
}
|
||||||
stream.streamBuf = stream.streamBuf[:0]
|
stream.streamBuf = stream.streamBuf[:0]
|
||||||
}
|
}
|
||||||
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
||||||
stream.pts = pes.Pts
|
stream.pts = pes.Pts
|
||||||
stream.dts = pes.Dts
|
stream.dts = pes.Dts
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psdemuxer *PSDemuxer) demuxH26x(stream *psstream, pes *PesPacket) error {
|
func (psdemuxer *PSDemuxer) demuxH26x(stream *psstream, pes *PesPacket) error {
|
||||||
if len(stream.streamBuf) == 0 {
|
if len(stream.streamBuf) == 0 {
|
||||||
stream.pts = pes.Pts
|
stream.pts = pes.Pts
|
||||||
stream.dts = pes.Dts
|
stream.dts = pes.Dts
|
||||||
}
|
}
|
||||||
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
||||||
start, sc := codec.FindStartCode(stream.streamBuf, 0)
|
start, sc := codec.FindStartCode(stream.streamBuf, 0)
|
||||||
for start >= 0 {
|
for start >= 0 {
|
||||||
end, sc2 := codec.FindStartCode(stream.streamBuf, start+int(sc))
|
end, sc2 := codec.FindStartCode(stream.streamBuf, start+int(sc))
|
||||||
if end < 0 {
|
if end < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if stream.cid == PS_STREAM_H264 {
|
if stream.cid == PS_STREAM_H264 {
|
||||||
naluType := codec.H264NaluType(stream.streamBuf[start:])
|
naluType := codec.H264NaluType(stream.streamBuf[start:])
|
||||||
if naluType != codec.H264_NAL_AUD {
|
if naluType != codec.H264_NAL_AUD {
|
||||||
if psdemuxer.OnFrame != nil {
|
if psdemuxer.OnFrame != nil {
|
||||||
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
|
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if stream.cid == PS_STREAM_H265 {
|
} else if stream.cid == PS_STREAM_H265 {
|
||||||
naluType := codec.H265NaluType(stream.streamBuf[start:])
|
naluType := codec.H265NaluType(stream.streamBuf[start:])
|
||||||
if naluType != codec.H265_NAL_AUD {
|
if naluType != codec.H265_NAL_AUD {
|
||||||
if psdemuxer.OnFrame != nil {
|
if psdemuxer.OnFrame != nil {
|
||||||
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
|
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
start = end
|
start = end
|
||||||
sc = sc2
|
sc = sc2
|
||||||
}
|
}
|
||||||
stream.streamBuf = stream.streamBuf[start:]
|
stream.streamBuf = stream.streamBuf[start:]
|
||||||
stream.pts = pes.Pts
|
stream.pts = pes.Pts
|
||||||
stream.dts = pes.Dts
|
stream.dts = pes.Dts
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
264
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-muxer.go
generated
vendored
264
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-muxer.go
generated
vendored
|
@ -3,146 +3,146 @@ package mpeg2
|
||||||
import "github.com/yapingcat/gomedia/codec"
|
import "github.com/yapingcat/gomedia/codec"
|
||||||
|
|
||||||
type PSMuxer struct {
|
type PSMuxer struct {
|
||||||
system *System_header
|
system *System_header
|
||||||
psm *Program_stream_map
|
psm *Program_stream_map
|
||||||
OnPacket func(pkg []byte)
|
OnPacket func(pkg []byte)
|
||||||
firstframe bool
|
firstframe bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPsMuxer() *PSMuxer {
|
func NewPsMuxer() *PSMuxer {
|
||||||
muxer := new(PSMuxer)
|
muxer := new(PSMuxer)
|
||||||
muxer.firstframe = true
|
muxer.firstframe = true
|
||||||
muxer.system = new(System_header)
|
muxer.system = new(System_header)
|
||||||
muxer.system.Rate_bound = 26234
|
muxer.system.Rate_bound = 26234
|
||||||
muxer.psm = new(Program_stream_map)
|
muxer.psm = new(Program_stream_map)
|
||||||
muxer.psm.Current_next_indicator = 1
|
muxer.psm.Current_next_indicator = 1
|
||||||
muxer.psm.Program_stream_map_version = 1
|
muxer.psm.Program_stream_map_version = 1
|
||||||
muxer.OnPacket = nil
|
muxer.OnPacket = nil
|
||||||
return muxer
|
return muxer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (muxer *PSMuxer) AddStream(cid PS_STREAM_TYPE) uint8 {
|
func (muxer *PSMuxer) AddStream(cid PS_STREAM_TYPE) uint8 {
|
||||||
if cid == PS_STREAM_H265 || cid == PS_STREAM_H264 {
|
if cid == PS_STREAM_H265 || cid == PS_STREAM_H264 {
|
||||||
es := NewElementary_Stream(uint8(PES_STREAM_VIDEO) + muxer.system.Video_bound)
|
es := NewElementary_Stream(uint8(PES_STREAM_VIDEO) + muxer.system.Video_bound)
|
||||||
es.P_STD_buffer_bound_scale = 1
|
es.P_STD_buffer_bound_scale = 1
|
||||||
es.P_STD_buffer_size_bound = 400
|
es.P_STD_buffer_size_bound = 400
|
||||||
muxer.system.Streams = append(muxer.system.Streams, es)
|
muxer.system.Streams = append(muxer.system.Streams, es)
|
||||||
muxer.system.Video_bound++
|
muxer.system.Video_bound++
|
||||||
muxer.psm.Stream_map = append(muxer.psm.Stream_map, NewElementary_stream_elem(uint8(cid), es.Stream_id))
|
muxer.psm.Stream_map = append(muxer.psm.Stream_map, NewElementary_stream_elem(uint8(cid), es.Stream_id))
|
||||||
muxer.psm.Program_stream_map_version++
|
muxer.psm.Program_stream_map_version++
|
||||||
return es.Stream_id
|
return es.Stream_id
|
||||||
} else {
|
} else {
|
||||||
es := NewElementary_Stream(uint8(PES_STREAM_AUDIO) + muxer.system.Audio_bound)
|
es := NewElementary_Stream(uint8(PES_STREAM_AUDIO) + muxer.system.Audio_bound)
|
||||||
es.P_STD_buffer_bound_scale = 0
|
es.P_STD_buffer_bound_scale = 0
|
||||||
es.P_STD_buffer_size_bound = 32
|
es.P_STD_buffer_size_bound = 32
|
||||||
muxer.system.Streams = append(muxer.system.Streams, es)
|
muxer.system.Streams = append(muxer.system.Streams, es)
|
||||||
muxer.system.Audio_bound++
|
muxer.system.Audio_bound++
|
||||||
muxer.psm.Stream_map = append(muxer.psm.Stream_map, NewElementary_stream_elem(uint8(cid), es.Stream_id))
|
muxer.psm.Stream_map = append(muxer.psm.Stream_map, NewElementary_stream_elem(uint8(cid), es.Stream_id))
|
||||||
muxer.psm.Program_stream_map_version++
|
muxer.psm.Program_stream_map_version++
|
||||||
return es.Stream_id
|
return es.Stream_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (muxer *PSMuxer) Write(sid uint8, frame []byte, pts uint64, dts uint64) error {
|
func (muxer *PSMuxer) Write(sid uint8, frame []byte, pts uint64, dts uint64) error {
|
||||||
var stream *Elementary_stream_elem = nil
|
var stream *Elementary_stream_elem = nil
|
||||||
for _, es := range muxer.psm.Stream_map {
|
for _, es := range muxer.psm.Stream_map {
|
||||||
if es.Elementary_stream_id == sid {
|
if es.Elementary_stream_id == sid {
|
||||||
stream = es
|
stream = es
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if stream == nil {
|
if stream == nil {
|
||||||
return errNotFound
|
return errNotFound
|
||||||
}
|
}
|
||||||
var withaud bool = false
|
var withaud bool = false
|
||||||
var idr_flag bool = false
|
var idr_flag bool = false
|
||||||
var first bool = true
|
var first bool = true
|
||||||
var vcl bool = false
|
var vcl bool = false
|
||||||
if stream.Stream_type == uint8(PS_STREAM_H264) || stream.Stream_type == uint8(PS_STREAM_H265) {
|
if stream.Stream_type == uint8(PS_STREAM_H264) || stream.Stream_type == uint8(PS_STREAM_H265) {
|
||||||
codec.SplitFrame(frame, func(nalu []byte) bool {
|
codec.SplitFrame(frame, func(nalu []byte) bool {
|
||||||
if stream.Stream_type == uint8(PS_STREAM_H264) {
|
if stream.Stream_type == uint8(PS_STREAM_H264) {
|
||||||
nalu_type := codec.H264NaluTypeWithoutStartCode(nalu)
|
nalu_type := codec.H264NaluTypeWithoutStartCode(nalu)
|
||||||
if nalu_type == codec.H264_NAL_AUD {
|
if nalu_type == codec.H264_NAL_AUD {
|
||||||
withaud = true
|
withaud = true
|
||||||
return false
|
return false
|
||||||
} else if codec.IsH264VCLNaluType(nalu_type) {
|
} else if codec.IsH264VCLNaluType(nalu_type) {
|
||||||
if nalu_type == codec.H264_NAL_I_SLICE {
|
if nalu_type == codec.H264_NAL_I_SLICE {
|
||||||
idr_flag = true
|
idr_flag = true
|
||||||
}
|
}
|
||||||
vcl = true
|
vcl = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
nalu_type := codec.H265NaluTypeWithoutStartCode(nalu)
|
nalu_type := codec.H265NaluTypeWithoutStartCode(nalu)
|
||||||
if nalu_type == codec.H265_NAL_AUD {
|
if nalu_type == codec.H265_NAL_AUD {
|
||||||
withaud = true
|
withaud = true
|
||||||
return false
|
return false
|
||||||
} else if codec.IsH265VCLNaluType(nalu_type) {
|
} else if codec.IsH265VCLNaluType(nalu_type) {
|
||||||
if nalu_type >= codec.H265_NAL_SLICE_BLA_W_LP && nalu_type <= codec.H265_NAL_SLICE_CRA {
|
if nalu_type >= codec.H265_NAL_SLICE_BLA_W_LP && nalu_type <= codec.H265_NAL_SLICE_CRA {
|
||||||
idr_flag = true
|
idr_flag = true
|
||||||
}
|
}
|
||||||
vcl = true
|
vcl = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
dts = dts * 90
|
dts = dts * 90
|
||||||
pts = pts * 90
|
pts = pts * 90
|
||||||
bsw := codec.NewBitStreamWriter(1024)
|
bsw := codec.NewBitStreamWriter(1024)
|
||||||
var pack PSPackHeader
|
var pack PSPackHeader
|
||||||
pack.System_clock_reference_base = dts - 3600
|
pack.System_clock_reference_base = dts - 3600
|
||||||
pack.System_clock_reference_extension = 0
|
pack.System_clock_reference_extension = 0
|
||||||
pack.Program_mux_rate = 6106
|
pack.Program_mux_rate = 6106
|
||||||
pack.Encode(bsw)
|
pack.Encode(bsw)
|
||||||
if muxer.firstframe || idr_flag {
|
if muxer.firstframe || idr_flag {
|
||||||
muxer.system.Encode(bsw)
|
muxer.system.Encode(bsw)
|
||||||
muxer.psm.Encode(bsw)
|
muxer.psm.Encode(bsw)
|
||||||
muxer.firstframe = false
|
muxer.firstframe = false
|
||||||
}
|
}
|
||||||
if muxer.OnPacket != nil {
|
if muxer.OnPacket != nil {
|
||||||
muxer.OnPacket(bsw.Bits())
|
muxer.OnPacket(bsw.Bits())
|
||||||
}
|
}
|
||||||
bsw.Reset()
|
bsw.Reset()
|
||||||
pespkg := NewPesPacket()
|
pespkg := NewPesPacket()
|
||||||
for len(frame) > 0 {
|
for len(frame) > 0 {
|
||||||
peshdrlen := 13
|
peshdrlen := 13
|
||||||
pespkg.Stream_id = sid
|
pespkg.Stream_id = sid
|
||||||
pespkg.PTS_DTS_flags = 0x03
|
pespkg.PTS_DTS_flags = 0x03
|
||||||
pespkg.PES_header_data_length = 10
|
pespkg.PES_header_data_length = 10
|
||||||
pespkg.Pts = pts
|
pespkg.Pts = pts
|
||||||
pespkg.Dts = dts
|
pespkg.Dts = dts
|
||||||
if idr_flag {
|
if idr_flag {
|
||||||
pespkg.Data_alignment_indicator = 1
|
pespkg.Data_alignment_indicator = 1
|
||||||
}
|
}
|
||||||
if first && !withaud && vcl {
|
if first && !withaud && vcl {
|
||||||
if stream.Stream_type == uint8(PS_STREAM_H264) {
|
if stream.Stream_type == uint8(PS_STREAM_H264) {
|
||||||
pespkg.Pes_payload = append(pespkg.Pes_payload, H264_AUD_NALU...)
|
pespkg.Pes_payload = append(pespkg.Pes_payload, H264_AUD_NALU...)
|
||||||
peshdrlen += 6
|
peshdrlen += 6
|
||||||
} else if stream.Stream_type == uint8(PS_STREAM_H265) {
|
} else if stream.Stream_type == uint8(PS_STREAM_H265) {
|
||||||
pespkg.Pes_payload = append(pespkg.Pes_payload, H265_AUD_NALU...)
|
pespkg.Pes_payload = append(pespkg.Pes_payload, H265_AUD_NALU...)
|
||||||
peshdrlen += 7
|
peshdrlen += 7
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if peshdrlen+len(frame) >= 0xFFFF {
|
if peshdrlen+len(frame) >= 0xFFFF {
|
||||||
pespkg.PES_packet_length = 0xFFFF
|
pespkg.PES_packet_length = 0xFFFF
|
||||||
pespkg.Pes_payload = append(pespkg.Pes_payload, frame[0:0xFFFF-peshdrlen]...)
|
pespkg.Pes_payload = append(pespkg.Pes_payload, frame[0:0xFFFF-peshdrlen]...)
|
||||||
frame = frame[0xFFFF-peshdrlen:]
|
frame = frame[0xFFFF-peshdrlen:]
|
||||||
} else {
|
} else {
|
||||||
pespkg.PES_packet_length = uint16(peshdrlen + len(frame))
|
pespkg.PES_packet_length = uint16(peshdrlen + len(frame))
|
||||||
pespkg.Pes_payload = append(pespkg.Pes_payload, frame[0:]...)
|
pespkg.Pes_payload = append(pespkg.Pes_payload, frame[0:]...)
|
||||||
frame = frame[:0]
|
frame = frame[:0]
|
||||||
}
|
}
|
||||||
pespkg.Encode(bsw)
|
pespkg.Encode(bsw)
|
||||||
pespkg.Pes_payload = pespkg.Pes_payload[:0]
|
pespkg.Pes_payload = pespkg.Pes_payload[:0]
|
||||||
if muxer.OnPacket != nil {
|
if muxer.OnPacket != nil {
|
||||||
muxer.OnPacket(bsw.Bits())
|
muxer.OnPacket(bsw.Bits())
|
||||||
}
|
}
|
||||||
bsw.Reset()
|
bsw.Reset()
|
||||||
first = false
|
first = false
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
670
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-proto.go
generated
vendored
670
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-proto.go
generated
vendored
|
@ -1,17 +1,17 @@
|
||||||
package mpeg2
|
package mpeg2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Error interface {
|
type Error interface {
|
||||||
NeedMore() bool
|
NeedMore() bool
|
||||||
ParserError() bool
|
ParserError() bool
|
||||||
StreamIdNotFound() bool
|
StreamIdNotFound() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var errNeedMore error = &needmoreError{}
|
var errNeedMore error = &needmoreError{}
|
||||||
|
@ -44,12 +44,12 @@ func (e *sidNotFoundError) StreamIdNotFound() bool { return true }
|
||||||
type PS_STREAM_TYPE int
|
type PS_STREAM_TYPE int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PS_STREAM_UNKNOW PS_STREAM_TYPE = 0xFF
|
PS_STREAM_UNKNOW PS_STREAM_TYPE = 0xFF
|
||||||
PS_STREAM_AAC PS_STREAM_TYPE = 0x0F
|
PS_STREAM_AAC PS_STREAM_TYPE = 0x0F
|
||||||
PS_STREAM_H264 PS_STREAM_TYPE = 0x1B
|
PS_STREAM_H264 PS_STREAM_TYPE = 0x1B
|
||||||
PS_STREAM_H265 PS_STREAM_TYPE = 0x24
|
PS_STREAM_H265 PS_STREAM_TYPE = 0x24
|
||||||
PS_STREAM_G711A PS_STREAM_TYPE = 0x90
|
PS_STREAM_G711A PS_STREAM_TYPE = 0x90
|
||||||
PS_STREAM_G711U PS_STREAM_TYPE = 0x91
|
PS_STREAM_G711U PS_STREAM_TYPE = 0x91
|
||||||
)
|
)
|
||||||
|
|
||||||
// Table 2-33 – Program Stream pack header
|
// Table 2-33 – Program Stream pack header
|
||||||
|
@ -78,113 +78,113 @@ const (
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type PSPackHeader struct {
|
type PSPackHeader struct {
|
||||||
IsMpeg1 bool
|
IsMpeg1 bool
|
||||||
System_clock_reference_base uint64 //33 bits
|
System_clock_reference_base uint64 //33 bits
|
||||||
System_clock_reference_extension uint16 //9 bits
|
System_clock_reference_extension uint16 //9 bits
|
||||||
Program_mux_rate uint32 //22 bits
|
Program_mux_rate uint32 //22 bits
|
||||||
Pack_stuffing_length uint8 //3 bitss
|
Pack_stuffing_length uint8 //3 bitss
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps_pkg_hdr *PSPackHeader) PrettyPrint(file *os.File) {
|
func (ps_pkg_hdr *PSPackHeader) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("IsMpeg1:%t\n", ps_pkg_hdr.IsMpeg1))
|
file.WriteString(fmt.Sprintf("IsMpeg1:%t\n", ps_pkg_hdr.IsMpeg1))
|
||||||
file.WriteString(fmt.Sprintf("System_clock_reference_base:%d\n", ps_pkg_hdr.System_clock_reference_base))
|
file.WriteString(fmt.Sprintf("System_clock_reference_base:%d\n", ps_pkg_hdr.System_clock_reference_base))
|
||||||
file.WriteString(fmt.Sprintf("System_clock_reference_extension:%d\n", ps_pkg_hdr.System_clock_reference_extension))
|
file.WriteString(fmt.Sprintf("System_clock_reference_extension:%d\n", ps_pkg_hdr.System_clock_reference_extension))
|
||||||
file.WriteString(fmt.Sprintf("Program_mux_rate:%d\n", ps_pkg_hdr.Program_mux_rate))
|
file.WriteString(fmt.Sprintf("Program_mux_rate:%d\n", ps_pkg_hdr.Program_mux_rate))
|
||||||
file.WriteString(fmt.Sprintf("Pack_stuffing_length:%d\n", ps_pkg_hdr.Pack_stuffing_length))
|
file.WriteString(fmt.Sprintf("Pack_stuffing_length:%d\n", ps_pkg_hdr.Pack_stuffing_length))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps_pkg_hdr *PSPackHeader) Decode(bs *codec.BitStream) error {
|
func (ps_pkg_hdr *PSPackHeader) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 5 {
|
if bs.RemainBytes() < 5 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
if bs.Uint32(32) != 0x000001BA {
|
if bs.Uint32(32) != 0x000001BA {
|
||||||
panic("ps header must start with 000001BA")
|
panic("ps header must start with 000001BA")
|
||||||
}
|
}
|
||||||
|
|
||||||
if bs.NextBits(2) == 0x01 { //mpeg2
|
if bs.NextBits(2) == 0x01 { //mpeg2
|
||||||
if bs.RemainBytes() < 10 {
|
if bs.RemainBytes() < 10 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
return ps_pkg_hdr.decodeMpeg2(bs)
|
return ps_pkg_hdr.decodeMpeg2(bs)
|
||||||
} else if bs.NextBits(4) == 0x02 { //mpeg1
|
} else if bs.NextBits(4) == 0x02 { //mpeg1
|
||||||
if bs.RemainBytes() < 8 {
|
if bs.RemainBytes() < 8 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
ps_pkg_hdr.IsMpeg1 = true
|
ps_pkg_hdr.IsMpeg1 = true
|
||||||
return ps_pkg_hdr.decodeMpeg1(bs)
|
return ps_pkg_hdr.decodeMpeg1(bs)
|
||||||
} else {
|
} else {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps_pkg_hdr *PSPackHeader) decodeMpeg2(bs *codec.BitStream) error {
|
func (ps_pkg_hdr *PSPackHeader) decodeMpeg2(bs *codec.BitStream) error {
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
ps_pkg_hdr.System_clock_reference_base = bs.GetBits(3)
|
ps_pkg_hdr.System_clock_reference_base = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.System_clock_reference_extension = bs.Uint16(9)
|
ps_pkg_hdr.System_clock_reference_extension = bs.Uint16(9)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.Program_mux_rate = bs.Uint32(22)
|
ps_pkg_hdr.Program_mux_rate = bs.Uint32(22)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
bs.SkipBits(5)
|
bs.SkipBits(5)
|
||||||
ps_pkg_hdr.Pack_stuffing_length = bs.Uint8(3)
|
ps_pkg_hdr.Pack_stuffing_length = bs.Uint8(3)
|
||||||
if bs.RemainBytes() < int(ps_pkg_hdr.Pack_stuffing_length) {
|
if bs.RemainBytes() < int(ps_pkg_hdr.Pack_stuffing_length) {
|
||||||
bs.UnRead(10 * 8)
|
bs.UnRead(10 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.SkipBits(int(ps_pkg_hdr.Pack_stuffing_length) * 8)
|
bs.SkipBits(int(ps_pkg_hdr.Pack_stuffing_length) * 8)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps_pkg_hdr *PSPackHeader) decodeMpeg1(bs *codec.BitStream) error {
|
func (ps_pkg_hdr *PSPackHeader) decodeMpeg1(bs *codec.BitStream) error {
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
ps_pkg_hdr.System_clock_reference_base = bs.GetBits(3)
|
ps_pkg_hdr.System_clock_reference_base = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.System_clock_reference_extension = 1
|
ps_pkg_hdr.System_clock_reference_extension = 1
|
||||||
ps_pkg_hdr.Program_mux_rate = bs.Uint32(7)
|
ps_pkg_hdr.Program_mux_rate = bs.Uint32(7)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
ps_pkg_hdr.Program_mux_rate = ps_pkg_hdr.Program_mux_rate<<15 | bs.Uint32(15)
|
ps_pkg_hdr.Program_mux_rate = ps_pkg_hdr.Program_mux_rate<<15 | bs.Uint32(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps_pkg_hdr *PSPackHeader) Encode(bsw *codec.BitStreamWriter) {
|
func (ps_pkg_hdr *PSPackHeader) Encode(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBA})
|
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBA})
|
||||||
bsw.PutUint8(1, 2)
|
bsw.PutUint8(1, 2)
|
||||||
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base>>30, 3)
|
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base>>30, 3)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base>>15, 15)
|
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base>>15, 15)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base, 15)
|
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base, 15)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint16(ps_pkg_hdr.System_clock_reference_extension, 9)
|
bsw.PutUint16(ps_pkg_hdr.System_clock_reference_extension, 9)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint32(ps_pkg_hdr.Program_mux_rate, 22)
|
bsw.PutUint32(ps_pkg_hdr.Program_mux_rate, 22)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint8(0x1F, 5)
|
bsw.PutUint8(0x1F, 5)
|
||||||
bsw.PutUint8(ps_pkg_hdr.Pack_stuffing_length, 3)
|
bsw.PutUint8(ps_pkg_hdr.Pack_stuffing_length, 3)
|
||||||
bsw.PutRepetValue(0xFF, int(ps_pkg_hdr.Pack_stuffing_length))
|
bsw.PutRepetValue(0xFF, int(ps_pkg_hdr.Pack_stuffing_length))
|
||||||
}
|
}
|
||||||
|
|
||||||
type Elementary_Stream struct {
|
type Elementary_Stream struct {
|
||||||
Stream_id uint8
|
Stream_id uint8
|
||||||
P_STD_buffer_bound_scale uint8
|
P_STD_buffer_bound_scale uint8
|
||||||
P_STD_buffer_size_bound uint16
|
P_STD_buffer_size_bound uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewElementary_Stream(sid uint8) *Elementary_Stream {
|
func NewElementary_Stream(sid uint8) *Elementary_Stream {
|
||||||
return &Elementary_Stream{
|
return &Elementary_Stream{
|
||||||
Stream_id: sid,
|
Stream_id: sid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// system_header () {
|
// system_header () {
|
||||||
|
@ -211,118 +211,118 @@ func NewElementary_Stream(sid uint8) *Elementary_Stream {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type System_header struct {
|
type System_header struct {
|
||||||
Header_length uint16
|
Header_length uint16
|
||||||
Rate_bound uint32
|
Rate_bound uint32
|
||||||
Audio_bound uint8
|
Audio_bound uint8
|
||||||
Fixed_flag uint8
|
Fixed_flag uint8
|
||||||
CSPS_flag uint8
|
CSPS_flag uint8
|
||||||
System_audio_lock_flag uint8
|
System_audio_lock_flag uint8
|
||||||
System_video_lock_flag uint8
|
System_video_lock_flag uint8
|
||||||
Video_bound uint8
|
Video_bound uint8
|
||||||
Packet_rate_restriction_flag uint8
|
Packet_rate_restriction_flag uint8
|
||||||
Streams []*Elementary_Stream
|
Streams []*Elementary_Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *System_header) PrettyPrint(file *os.File) {
|
func (sh *System_header) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("Header_length:%d\n", sh.Header_length))
|
file.WriteString(fmt.Sprintf("Header_length:%d\n", sh.Header_length))
|
||||||
file.WriteString(fmt.Sprintf("Rate_bound:%d\n", sh.Rate_bound))
|
file.WriteString(fmt.Sprintf("Rate_bound:%d\n", sh.Rate_bound))
|
||||||
file.WriteString(fmt.Sprintf("Audio_bound:%d\n", sh.Audio_bound))
|
file.WriteString(fmt.Sprintf("Audio_bound:%d\n", sh.Audio_bound))
|
||||||
file.WriteString(fmt.Sprintf("Fixed_flag:%d\n", sh.Fixed_flag))
|
file.WriteString(fmt.Sprintf("Fixed_flag:%d\n", sh.Fixed_flag))
|
||||||
file.WriteString(fmt.Sprintf("CSPS_flag:%d\n", sh.CSPS_flag))
|
file.WriteString(fmt.Sprintf("CSPS_flag:%d\n", sh.CSPS_flag))
|
||||||
file.WriteString(fmt.Sprintf("System_audio_lock_flag:%d\n", sh.System_audio_lock_flag))
|
file.WriteString(fmt.Sprintf("System_audio_lock_flag:%d\n", sh.System_audio_lock_flag))
|
||||||
file.WriteString(fmt.Sprintf("System_video_lock_flag:%d\n", sh.System_video_lock_flag))
|
file.WriteString(fmt.Sprintf("System_video_lock_flag:%d\n", sh.System_video_lock_flag))
|
||||||
file.WriteString(fmt.Sprintf("Video_bound:%d\n", sh.Video_bound))
|
file.WriteString(fmt.Sprintf("Video_bound:%d\n", sh.Video_bound))
|
||||||
file.WriteString(fmt.Sprintf("Packet_rate_restriction_flag:%d\n", sh.Packet_rate_restriction_flag))
|
file.WriteString(fmt.Sprintf("Packet_rate_restriction_flag:%d\n", sh.Packet_rate_restriction_flag))
|
||||||
for i, es := range sh.Streams {
|
for i, es := range sh.Streams {
|
||||||
file.WriteString(fmt.Sprintf("----streams %d\n", i))
|
file.WriteString(fmt.Sprintf("----streams %d\n", i))
|
||||||
file.WriteString(fmt.Sprintf(" Stream_id:%d\n", es.Stream_id))
|
file.WriteString(fmt.Sprintf(" Stream_id:%d\n", es.Stream_id))
|
||||||
file.WriteString(fmt.Sprintf(" P_STD_buffer_bound_scale:%d\n", es.P_STD_buffer_bound_scale))
|
file.WriteString(fmt.Sprintf(" P_STD_buffer_bound_scale:%d\n", es.P_STD_buffer_bound_scale))
|
||||||
file.WriteString(fmt.Sprintf(" P_STD_buffer_size_bound:%d\n", es.P_STD_buffer_size_bound))
|
file.WriteString(fmt.Sprintf(" P_STD_buffer_size_bound:%d\n", es.P_STD_buffer_size_bound))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *System_header) Encode(bsw *codec.BitStreamWriter) {
|
func (sh *System_header) Encode(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBB})
|
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBB})
|
||||||
loc := bsw.ByteOffset()
|
loc := bsw.ByteOffset()
|
||||||
bsw.PutUint16(0, 16)
|
bsw.PutUint16(0, 16)
|
||||||
bsw.Markdot()
|
bsw.Markdot()
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint32(sh.Rate_bound, 22)
|
bsw.PutUint32(sh.Rate_bound, 22)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint8(sh.Audio_bound, 6)
|
bsw.PutUint8(sh.Audio_bound, 6)
|
||||||
bsw.PutUint8(sh.Fixed_flag, 1)
|
bsw.PutUint8(sh.Fixed_flag, 1)
|
||||||
bsw.PutUint8(sh.CSPS_flag, 1)
|
bsw.PutUint8(sh.CSPS_flag, 1)
|
||||||
bsw.PutUint8(sh.System_audio_lock_flag, 1)
|
bsw.PutUint8(sh.System_audio_lock_flag, 1)
|
||||||
bsw.PutUint8(sh.System_video_lock_flag, 1)
|
bsw.PutUint8(sh.System_video_lock_flag, 1)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint8(sh.Video_bound, 5)
|
bsw.PutUint8(sh.Video_bound, 5)
|
||||||
bsw.PutUint8(sh.Packet_rate_restriction_flag, 1)
|
bsw.PutUint8(sh.Packet_rate_restriction_flag, 1)
|
||||||
bsw.PutUint8(0x7F, 7)
|
bsw.PutUint8(0x7F, 7)
|
||||||
for _, stream := range sh.Streams {
|
for _, stream := range sh.Streams {
|
||||||
bsw.PutUint8(stream.Stream_id, 8)
|
bsw.PutUint8(stream.Stream_id, 8)
|
||||||
bsw.PutUint8(3, 2)
|
bsw.PutUint8(3, 2)
|
||||||
bsw.PutUint8(stream.P_STD_buffer_bound_scale, 1)
|
bsw.PutUint8(stream.P_STD_buffer_bound_scale, 1)
|
||||||
bsw.PutUint16(stream.P_STD_buffer_size_bound, 13)
|
bsw.PutUint16(stream.P_STD_buffer_size_bound, 13)
|
||||||
}
|
}
|
||||||
length := bsw.DistanceFromMarkDot() / 8
|
length := bsw.DistanceFromMarkDot() / 8
|
||||||
bsw.SetUint16(uint16(length), loc)
|
bsw.SetUint16(uint16(length), loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *System_header) Decode(bs *codec.BitStream) error {
|
func (sh *System_header) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 12 {
|
if bs.RemainBytes() < 12 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
if bs.Uint32(32) != 0x000001BB {
|
if bs.Uint32(32) != 0x000001BB {
|
||||||
panic("system header must start with 000001BB")
|
panic("system header must start with 000001BB")
|
||||||
}
|
}
|
||||||
sh.Header_length = bs.Uint16(16)
|
sh.Header_length = bs.Uint16(16)
|
||||||
if bs.RemainBytes() < int(sh.Header_length) {
|
if bs.RemainBytes() < int(sh.Header_length) {
|
||||||
bs.UnRead(6 * 8)
|
bs.UnRead(6 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
if sh.Header_length < 6 || (sh.Header_length-6)%3 != 0 {
|
if sh.Header_length < 6 || (sh.Header_length-6)%3 != 0 {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
sh.Rate_bound = bs.Uint32(22)
|
sh.Rate_bound = bs.Uint32(22)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
sh.Audio_bound = bs.Uint8(6)
|
sh.Audio_bound = bs.Uint8(6)
|
||||||
sh.Fixed_flag = bs.Uint8(1)
|
sh.Fixed_flag = bs.Uint8(1)
|
||||||
sh.CSPS_flag = bs.Uint8(1)
|
sh.CSPS_flag = bs.Uint8(1)
|
||||||
sh.System_audio_lock_flag = bs.Uint8(1)
|
sh.System_audio_lock_flag = bs.Uint8(1)
|
||||||
sh.System_video_lock_flag = bs.Uint8(1)
|
sh.System_video_lock_flag = bs.Uint8(1)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
sh.Video_bound = bs.Uint8(5)
|
sh.Video_bound = bs.Uint8(5)
|
||||||
sh.Packet_rate_restriction_flag = bs.Uint8(1)
|
sh.Packet_rate_restriction_flag = bs.Uint8(1)
|
||||||
bs.SkipBits(7)
|
bs.SkipBits(7)
|
||||||
sh.Streams = sh.Streams[:0]
|
sh.Streams = sh.Streams[:0]
|
||||||
least := sh.Header_length - 6
|
least := sh.Header_length - 6
|
||||||
for least > 0 && bs.NextBits(1) == 0x01 {
|
for least > 0 && bs.NextBits(1) == 0x01 {
|
||||||
es := new(Elementary_Stream)
|
es := new(Elementary_Stream)
|
||||||
es.Stream_id = bs.Uint8(8)
|
es.Stream_id = bs.Uint8(8)
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
es.P_STD_buffer_bound_scale = bs.GetBit()
|
es.P_STD_buffer_bound_scale = bs.GetBit()
|
||||||
es.P_STD_buffer_size_bound = bs.Uint16(13)
|
es.P_STD_buffer_size_bound = bs.Uint16(13)
|
||||||
sh.Streams = append(sh.Streams, es)
|
sh.Streams = append(sh.Streams, es)
|
||||||
least -= 3
|
least -= 3
|
||||||
}
|
}
|
||||||
if least > 0 {
|
if least > 0 {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Elementary_stream_elem struct {
|
type Elementary_stream_elem struct {
|
||||||
Stream_type uint8
|
Stream_type uint8
|
||||||
Elementary_stream_id uint8
|
Elementary_stream_id uint8
|
||||||
Elementary_stream_info_length uint16
|
Elementary_stream_info_length uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewElementary_stream_elem(stype uint8, esid uint8) *Elementary_stream_elem {
|
func NewElementary_stream_elem(stype uint8, esid uint8) *Elementary_stream_elem {
|
||||||
return &Elementary_stream_elem{
|
return &Elementary_stream_elem{
|
||||||
Stream_type: stype,
|
Stream_type: stype,
|
||||||
Elementary_stream_id: esid,
|
Elementary_stream_id: esid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// program_stream_map() {
|
// program_stream_map() {
|
||||||
|
@ -351,171 +351,171 @@ func NewElementary_stream_elem(stype uint8, esid uint8) *Elementary_stream_elem
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type Program_stream_map struct {
|
type Program_stream_map struct {
|
||||||
Map_stream_id uint8
|
Map_stream_id uint8
|
||||||
Program_stream_map_length uint16
|
Program_stream_map_length uint16
|
||||||
Current_next_indicator uint8
|
Current_next_indicator uint8
|
||||||
Program_stream_map_version uint8
|
Program_stream_map_version uint8
|
||||||
Program_stream_info_length uint16
|
Program_stream_info_length uint16
|
||||||
Elementary_stream_map_length uint16
|
Elementary_stream_map_length uint16
|
||||||
Stream_map []*Elementary_stream_elem
|
Stream_map []*Elementary_stream_elem
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psm *Program_stream_map) PrettyPrint(file *os.File) {
|
func (psm *Program_stream_map) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("map_stream_id:%d\n", psm.Map_stream_id))
|
file.WriteString(fmt.Sprintf("map_stream_id:%d\n", psm.Map_stream_id))
|
||||||
file.WriteString(fmt.Sprintf("program_stream_map_length:%d\n", psm.Program_stream_map_length))
|
file.WriteString(fmt.Sprintf("program_stream_map_length:%d\n", psm.Program_stream_map_length))
|
||||||
file.WriteString(fmt.Sprintf("current_next_indicator:%d\n", psm.Current_next_indicator))
|
file.WriteString(fmt.Sprintf("current_next_indicator:%d\n", psm.Current_next_indicator))
|
||||||
file.WriteString(fmt.Sprintf("program_stream_map_version:%d\n", psm.Program_stream_map_version))
|
file.WriteString(fmt.Sprintf("program_stream_map_version:%d\n", psm.Program_stream_map_version))
|
||||||
file.WriteString(fmt.Sprintf("program_stream_info_length:%d\n", psm.Program_stream_info_length))
|
file.WriteString(fmt.Sprintf("program_stream_info_length:%d\n", psm.Program_stream_info_length))
|
||||||
file.WriteString(fmt.Sprintf("elementary_stream_map_length:%d\n", psm.Elementary_stream_map_length))
|
file.WriteString(fmt.Sprintf("elementary_stream_map_length:%d\n", psm.Elementary_stream_map_length))
|
||||||
for i, es := range psm.Stream_map {
|
for i, es := range psm.Stream_map {
|
||||||
file.WriteString(fmt.Sprintf("----ES stream %d\n", i))
|
file.WriteString(fmt.Sprintf("----ES stream %d\n", i))
|
||||||
if es.Stream_type == uint8(PS_STREAM_AAC) {
|
if es.Stream_type == uint8(PS_STREAM_AAC) {
|
||||||
file.WriteString(" stream_type:AAC\n")
|
file.WriteString(" stream_type:AAC\n")
|
||||||
} else if es.Stream_type == uint8(PS_STREAM_G711A) {
|
} else if es.Stream_type == uint8(PS_STREAM_G711A) {
|
||||||
file.WriteString(" stream_type:G711A\n")
|
file.WriteString(" stream_type:G711A\n")
|
||||||
} else if es.Stream_type == uint8(PS_STREAM_G711U) {
|
} else if es.Stream_type == uint8(PS_STREAM_G711U) {
|
||||||
file.WriteString(" stream_type:G711U\n")
|
file.WriteString(" stream_type:G711U\n")
|
||||||
} else if es.Stream_type == uint8(PS_STREAM_H264) {
|
} else if es.Stream_type == uint8(PS_STREAM_H264) {
|
||||||
file.WriteString(" stream_type:H264\n")
|
file.WriteString(" stream_type:H264\n")
|
||||||
} else if es.Stream_type == uint8(PS_STREAM_H265) {
|
} else if es.Stream_type == uint8(PS_STREAM_H265) {
|
||||||
file.WriteString(" stream_type:H265\n")
|
file.WriteString(" stream_type:H265\n")
|
||||||
}
|
}
|
||||||
file.WriteString(fmt.Sprintf(" elementary_stream_id:%d\n", es.Elementary_stream_id))
|
file.WriteString(fmt.Sprintf(" elementary_stream_id:%d\n", es.Elementary_stream_id))
|
||||||
file.WriteString(fmt.Sprintf(" elementary_stream_info_length:%d\n", es.Elementary_stream_info_length))
|
file.WriteString(fmt.Sprintf(" elementary_stream_info_length:%d\n", es.Elementary_stream_info_length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psm *Program_stream_map) Encode(bsw *codec.BitStreamWriter) {
|
func (psm *Program_stream_map) Encode(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBC})
|
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBC})
|
||||||
loc := bsw.ByteOffset()
|
loc := bsw.ByteOffset()
|
||||||
bsw.PutUint16(psm.Program_stream_map_length, 16)
|
bsw.PutUint16(psm.Program_stream_map_length, 16)
|
||||||
bsw.Markdot()
|
bsw.Markdot()
|
||||||
bsw.PutUint8(psm.Current_next_indicator, 1)
|
bsw.PutUint8(psm.Current_next_indicator, 1)
|
||||||
bsw.PutUint8(3, 2)
|
bsw.PutUint8(3, 2)
|
||||||
bsw.PutUint8(psm.Program_stream_map_version, 5)
|
bsw.PutUint8(psm.Program_stream_map_version, 5)
|
||||||
bsw.PutUint8(0x7F, 7)
|
bsw.PutUint8(0x7F, 7)
|
||||||
bsw.PutUint8(1, 1)
|
bsw.PutUint8(1, 1)
|
||||||
bsw.PutUint16(0, 16)
|
bsw.PutUint16(0, 16)
|
||||||
psm.Elementary_stream_map_length = uint16(len(psm.Stream_map) * 4)
|
psm.Elementary_stream_map_length = uint16(len(psm.Stream_map) * 4)
|
||||||
bsw.PutUint16(psm.Elementary_stream_map_length, 16)
|
bsw.PutUint16(psm.Elementary_stream_map_length, 16)
|
||||||
for _, streaminfo := range psm.Stream_map {
|
for _, streaminfo := range psm.Stream_map {
|
||||||
bsw.PutUint8(streaminfo.Stream_type, 8)
|
bsw.PutUint8(streaminfo.Stream_type, 8)
|
||||||
bsw.PutUint8(streaminfo.Elementary_stream_id, 8)
|
bsw.PutUint8(streaminfo.Elementary_stream_id, 8)
|
||||||
bsw.PutUint16(0, 16)
|
bsw.PutUint16(0, 16)
|
||||||
}
|
}
|
||||||
length := bsw.DistanceFromMarkDot()/8 + 4
|
length := bsw.DistanceFromMarkDot()/8 + 4
|
||||||
bsw.SetUint16(uint16(length), loc)
|
bsw.SetUint16(uint16(length), loc)
|
||||||
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(length-4)-4:bsw.ByteOffset()])
|
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(length-4)-4:bsw.ByteOffset()])
|
||||||
tmpcrc := make([]byte, 4)
|
tmpcrc := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
||||||
bsw.PutBytes(tmpcrc)
|
bsw.PutBytes(tmpcrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psm *Program_stream_map) Decode(bs *codec.BitStream) error {
|
func (psm *Program_stream_map) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 16 {
|
if bs.RemainBytes() < 16 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
if bs.Uint32(24) != 0x000001 {
|
if bs.Uint32(24) != 0x000001 {
|
||||||
panic("program stream map must startwith 0x000001")
|
panic("program stream map must startwith 0x000001")
|
||||||
}
|
}
|
||||||
psm.Map_stream_id = bs.Uint8(8)
|
psm.Map_stream_id = bs.Uint8(8)
|
||||||
if psm.Map_stream_id != 0xBC {
|
if psm.Map_stream_id != 0xBC {
|
||||||
panic("map stream id must be 0xBC")
|
panic("map stream id must be 0xBC")
|
||||||
}
|
}
|
||||||
psm.Program_stream_map_length = bs.Uint16(16)
|
psm.Program_stream_map_length = bs.Uint16(16)
|
||||||
if bs.RemainBytes() < int(psm.Program_stream_map_length) {
|
if bs.RemainBytes() < int(psm.Program_stream_map_length) {
|
||||||
bs.UnRead(6 * 8)
|
bs.UnRead(6 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
psm.Current_next_indicator = bs.Uint8(1)
|
psm.Current_next_indicator = bs.Uint8(1)
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
psm.Program_stream_map_version = bs.Uint8(5)
|
psm.Program_stream_map_version = bs.Uint8(5)
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
psm.Program_stream_info_length = bs.Uint16(16)
|
psm.Program_stream_info_length = bs.Uint16(16)
|
||||||
if bs.RemainBytes() < int(psm.Program_stream_info_length)+2 {
|
if bs.RemainBytes() < int(psm.Program_stream_info_length)+2 {
|
||||||
bs.UnRead(10 * 8)
|
bs.UnRead(10 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.SkipBits(int(psm.Program_stream_info_length) * 8)
|
bs.SkipBits(int(psm.Program_stream_info_length) * 8)
|
||||||
psm.Elementary_stream_map_length = bs.Uint16(16)
|
psm.Elementary_stream_map_length = bs.Uint16(16)
|
||||||
if psm.Program_stream_map_length != 6+psm.Program_stream_info_length+psm.Elementary_stream_map_length+4 {
|
if psm.Program_stream_map_length != 6+psm.Program_stream_info_length+psm.Elementary_stream_map_length+4 {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
if bs.RemainBytes() < int(psm.Elementary_stream_map_length)+4 {
|
if bs.RemainBytes() < int(psm.Elementary_stream_map_length)+4 {
|
||||||
bs.UnRead(12*8 + int(psm.Program_stream_info_length)*8)
|
bs.UnRead(12*8 + int(psm.Program_stream_info_length)*8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
psm.Stream_map = psm.Stream_map[:0]
|
psm.Stream_map = psm.Stream_map[:0]
|
||||||
for i < int(psm.Elementary_stream_map_length) {
|
for i < int(psm.Elementary_stream_map_length) {
|
||||||
elem := new(Elementary_stream_elem)
|
elem := new(Elementary_stream_elem)
|
||||||
elem.Stream_type = bs.Uint8(8)
|
elem.Stream_type = bs.Uint8(8)
|
||||||
elem.Elementary_stream_id = bs.Uint8(8)
|
elem.Elementary_stream_id = bs.Uint8(8)
|
||||||
elem.Elementary_stream_info_length = bs.Uint16(16)
|
elem.Elementary_stream_info_length = bs.Uint16(16)
|
||||||
//TODO Parser descriptor
|
//TODO Parser descriptor
|
||||||
if bs.RemainBytes() < int(elem.Elementary_stream_info_length) {
|
if bs.RemainBytes() < int(elem.Elementary_stream_info_length) {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
bs.SkipBits(int(elem.Elementary_stream_info_length) * 8)
|
bs.SkipBits(int(elem.Elementary_stream_info_length) * 8)
|
||||||
i += int(4 + elem.Elementary_stream_info_length)
|
i += int(4 + elem.Elementary_stream_info_length)
|
||||||
psm.Stream_map = append(psm.Stream_map, elem)
|
psm.Stream_map = append(psm.Stream_map, elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
if i != int(psm.Elementary_stream_map_length) {
|
if i != int(psm.Elementary_stream_map_length) {
|
||||||
return errParser
|
return errParser
|
||||||
}
|
}
|
||||||
|
|
||||||
bs.SkipBits(32)
|
bs.SkipBits(32)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Program_stream_directory struct {
|
type Program_stream_directory struct {
|
||||||
PES_packet_length uint16
|
PES_packet_length uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psd *Program_stream_directory) Decode(bs *codec.BitStream) error {
|
func (psd *Program_stream_directory) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 6 {
|
if bs.RemainBytes() < 6 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
if bs.Uint32(32) != 0x000001FF {
|
if bs.Uint32(32) != 0x000001FF {
|
||||||
panic("program stream directory 000001FF")
|
panic("program stream directory 000001FF")
|
||||||
}
|
}
|
||||||
psd.PES_packet_length = bs.Uint16(16)
|
psd.PES_packet_length = bs.Uint16(16)
|
||||||
if bs.RemainBytes() < int(psd.PES_packet_length) {
|
if bs.RemainBytes() < int(psd.PES_packet_length) {
|
||||||
bs.UnRead(6 * 8)
|
bs.UnRead(6 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
//TODO Program Stream directory
|
//TODO Program Stream directory
|
||||||
bs.SkipBits(int(psd.PES_packet_length) * 8)
|
bs.SkipBits(int(psd.PES_packet_length) * 8)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonPesPacket struct {
|
type CommonPesPacket struct {
|
||||||
Stream_id uint8
|
Stream_id uint8
|
||||||
PES_packet_length uint16
|
PES_packet_length uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (compes *CommonPesPacket) Decode(bs *codec.BitStream) error {
|
func (compes *CommonPesPacket) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 6 {
|
if bs.RemainBytes() < 6 {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.SkipBits(24)
|
bs.SkipBits(24)
|
||||||
compes.Stream_id = bs.Uint8(8)
|
compes.Stream_id = bs.Uint8(8)
|
||||||
compes.PES_packet_length = bs.Uint16(16)
|
compes.PES_packet_length = bs.Uint16(16)
|
||||||
if bs.RemainBytes() < int(compes.PES_packet_length) {
|
if bs.RemainBytes() < int(compes.PES_packet_length) {
|
||||||
bs.UnRead(6 * 8)
|
bs.UnRead(6 * 8)
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
bs.SkipBits(int(compes.PES_packet_length) * 8)
|
bs.SkipBits(int(compes.PES_packet_length) * 8)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type PSPacket struct {
|
type PSPacket struct {
|
||||||
Header *PSPackHeader
|
Header *PSPackHeader
|
||||||
System *System_header
|
System *System_header
|
||||||
Psm *Program_stream_map
|
Psm *Program_stream_map
|
||||||
Psd *Program_stream_directory
|
Psd *Program_stream_directory
|
||||||
CommPes *CommonPesPacket
|
CommPes *CommonPesPacket
|
||||||
Pes *PesPacket
|
Pes *PesPacket
|
||||||
}
|
}
|
||||||
|
|
356
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-demuxer.go
generated
vendored
356
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-demuxer.go
generated
vendored
|
@ -1,218 +1,218 @@
|
||||||
package mpeg2
|
package mpeg2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pakcet_t struct {
|
type pakcet_t struct {
|
||||||
payload []byte
|
payload []byte
|
||||||
pts uint64
|
pts uint64
|
||||||
dts uint64
|
dts uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPacket_t(size uint32) *pakcet_t {
|
func newPacket_t(size uint32) *pakcet_t {
|
||||||
return &pakcet_t{
|
return &pakcet_t{
|
||||||
payload: make([]byte, 0, size),
|
payload: make([]byte, 0, size),
|
||||||
pts: 0,
|
pts: 0,
|
||||||
dts: 0,
|
dts: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type tsstream struct {
|
type tsstream struct {
|
||||||
cid TS_STREAM_TYPE
|
cid TS_STREAM_TYPE
|
||||||
pes_sid PES_STREMA_ID
|
pes_sid PES_STREMA_ID
|
||||||
pes_pkg *PesPacket
|
pes_pkg *PesPacket
|
||||||
pkg *pakcet_t
|
pkg *pakcet_t
|
||||||
}
|
}
|
||||||
|
|
||||||
type tsprogram struct {
|
type tsprogram struct {
|
||||||
pn uint16
|
pn uint16
|
||||||
streams map[uint16]*tsstream
|
streams map[uint16]*tsstream
|
||||||
}
|
}
|
||||||
|
|
||||||
type TSDemuxer struct {
|
type TSDemuxer struct {
|
||||||
programs map[uint16]*tsprogram
|
programs map[uint16]*tsprogram
|
||||||
OnFrame func(cid TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64)
|
OnFrame func(cid TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64)
|
||||||
OnTSPacket func(pkg *TSPacket)
|
OnTSPacket func(pkg *TSPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTSDemuxer() *TSDemuxer {
|
func NewTSDemuxer() *TSDemuxer {
|
||||||
return &TSDemuxer{
|
return &TSDemuxer{
|
||||||
programs: make(map[uint16]*tsprogram),
|
programs: make(map[uint16]*tsprogram),
|
||||||
OnFrame: nil,
|
OnFrame: nil,
|
||||||
OnTSPacket: nil,
|
OnTSPacket: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (demuxer *TSDemuxer) Input(r io.Reader) error {
|
func (demuxer *TSDemuxer) Input(r io.Reader) error {
|
||||||
buf := make([]byte, TS_PAKCET_SIZE)
|
buf := make([]byte, TS_PAKCET_SIZE)
|
||||||
_, err := io.ReadFull(r, buf)
|
_, err := io.ReadFull(r, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
bs := codec.NewBitStream(buf)
|
bs := codec.NewBitStream(buf)
|
||||||
var pkg TSPacket
|
var pkg TSPacket
|
||||||
if err := pkg.DecodeHeader(bs); err != nil {
|
if err := pkg.DecodeHeader(bs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if pkg.PID == uint16(TS_PID_PAT) {
|
if pkg.PID == uint16(TS_PID_PAT) {
|
||||||
if pkg.Payload_unit_start_indicator == 1 {
|
if pkg.Payload_unit_start_indicator == 1 {
|
||||||
bs.SkipBits(8)
|
bs.SkipBits(8)
|
||||||
}
|
}
|
||||||
pat := NewPat()
|
pat := NewPat()
|
||||||
if err := pat.Decode(bs); err != nil {
|
if err := pat.Decode(bs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pkg.Payload = pat
|
pkg.Payload = pat
|
||||||
if pat.Table_id != uint8(TS_TID_PAS) {
|
if pat.Table_id != uint8(TS_TID_PAS) {
|
||||||
return errors.New("pat table id is wrong")
|
return errors.New("pat table id is wrong")
|
||||||
}
|
}
|
||||||
for _, pmt := range pat.Pmts {
|
for _, pmt := range pat.Pmts {
|
||||||
if pmt.Program_number != 0x0000 {
|
if pmt.Program_number != 0x0000 {
|
||||||
if _, found := demuxer.programs[pmt.PID]; !found {
|
if _, found := demuxer.programs[pmt.PID]; !found {
|
||||||
demuxer.programs[pmt.PID] = &tsprogram{pn: 0, streams: make(map[uint16]*tsstream)}
|
demuxer.programs[pmt.PID] = &tsprogram{pn: 0, streams: make(map[uint16]*tsstream)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for p, s := range demuxer.programs {
|
for p, s := range demuxer.programs {
|
||||||
if p == pkg.PID { // pmt table
|
if p == pkg.PID { // pmt table
|
||||||
if pkg.Payload_unit_start_indicator == 1 {
|
if pkg.Payload_unit_start_indicator == 1 {
|
||||||
bs.SkipBits(8) //pointer filed
|
bs.SkipBits(8) //pointer filed
|
||||||
}
|
}
|
||||||
pmt := NewPmt()
|
pmt := NewPmt()
|
||||||
if err := pmt.Decode(bs); err != nil {
|
if err := pmt.Decode(bs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pkg.Payload = pmt
|
pkg.Payload = pmt
|
||||||
s.pn = pmt.Program_number
|
s.pn = pmt.Program_number
|
||||||
for _, ps := range pmt.Streams {
|
for _, ps := range pmt.Streams {
|
||||||
if _, found := s.streams[ps.Elementary_PID]; !found {
|
if _, found := s.streams[ps.Elementary_PID]; !found {
|
||||||
s.streams[ps.Elementary_PID] = &tsstream{
|
s.streams[ps.Elementary_PID] = &tsstream{
|
||||||
cid: TS_STREAM_TYPE(ps.StreamType),
|
cid: TS_STREAM_TYPE(ps.StreamType),
|
||||||
pes_sid: findPESIDByStreamType(TS_STREAM_TYPE(ps.StreamType)),
|
pes_sid: findPESIDByStreamType(TS_STREAM_TYPE(ps.StreamType)),
|
||||||
pes_pkg: NewPesPacket(),
|
pes_pkg: NewPesPacket(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for sid, stream := range s.streams {
|
for sid, stream := range s.streams {
|
||||||
if sid != pkg.PID {
|
if sid != pkg.PID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pkg.Payload_unit_start_indicator == 1 {
|
if pkg.Payload_unit_start_indicator == 1 {
|
||||||
err := stream.pes_pkg.Decode(bs)
|
err := stream.pes_pkg.Decode(bs)
|
||||||
// ignore error if it was a short payload read, next ts packet should append missing data
|
// ignore error if it was a short payload read, next ts packet should append missing data
|
||||||
if err != nil && !(errors.Is(err, errNeedMore) && stream.pes_pkg.Pes_payload != nil) {
|
if err != nil && !(errors.Is(err, errNeedMore) && stream.pes_pkg.Pes_payload != nil) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pkg.Payload = stream.pes_pkg
|
pkg.Payload = stream.pes_pkg
|
||||||
} else {
|
} else {
|
||||||
stream.pes_pkg.Pes_payload = bs.RemainData()
|
stream.pes_pkg.Pes_payload = bs.RemainData()
|
||||||
pkg.Payload = bs.RemainData()
|
pkg.Payload = bs.RemainData()
|
||||||
}
|
}
|
||||||
stype := findPESIDByStreamType(stream.cid)
|
stype := findPESIDByStreamType(stream.cid)
|
||||||
if stype == PES_STREAM_AUDIO {
|
if stype == PES_STREAM_AUDIO {
|
||||||
demuxer.doAudioPesPacket(stream, pkg.Payload_unit_start_indicator)
|
demuxer.doAudioPesPacket(stream, pkg.Payload_unit_start_indicator)
|
||||||
} else if stype == PES_STREAM_VIDEO {
|
} else if stype == PES_STREAM_VIDEO {
|
||||||
demuxer.doVideoPesPacket(stream, pkg.Payload_unit_start_indicator)
|
demuxer.doVideoPesPacket(stream, pkg.Payload_unit_start_indicator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if demuxer.OnTSPacket != nil {
|
if demuxer.OnTSPacket != nil {
|
||||||
demuxer.OnTSPacket(&pkg)
|
demuxer.OnTSPacket(&pkg)
|
||||||
}
|
}
|
||||||
_, err := io.ReadFull(r, buf)
|
_, err := io.ReadFull(r, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, io.EOF) {
|
if errors.Is(err, io.EOF) {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
return errNeedMore
|
return errNeedMore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
demuxer.flush()
|
demuxer.flush()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (demuxer *TSDemuxer) flush() {
|
func (demuxer *TSDemuxer) flush() {
|
||||||
for _, pm := range demuxer.programs {
|
for _, pm := range demuxer.programs {
|
||||||
for _, stream := range pm.streams {
|
for _, stream := range pm.streams {
|
||||||
if stream.pkg == nil || len(stream.pkg.payload) == 0 {
|
if stream.pkg == nil || len(stream.pkg.payload) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if demuxer.OnFrame != nil {
|
if demuxer.OnFrame != nil {
|
||||||
demuxer.OnFrame(stream.cid, stream.pkg.payload, stream.pkg.pts/90, stream.pkg.dts/90)
|
demuxer.OnFrame(stream.cid, stream.pkg.payload, stream.pkg.pts/90, stream.pkg.dts/90)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (demuxer *TSDemuxer) doVideoPesPacket(stream *tsstream, start uint8) {
|
func (demuxer *TSDemuxer) doVideoPesPacket(stream *tsstream, start uint8) {
|
||||||
if stream.cid != TS_STREAM_H264 && stream.cid != TS_STREAM_H265 {
|
if stream.cid != TS_STREAM_H264 && stream.cid != TS_STREAM_H265 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if stream.pkg == nil {
|
if stream.pkg == nil {
|
||||||
stream.pkg = newPacket_t(1024)
|
stream.pkg = newPacket_t(1024)
|
||||||
stream.pkg.pts = stream.pes_pkg.Pts
|
stream.pkg.pts = stream.pes_pkg.Pts
|
||||||
stream.pkg.dts = stream.pes_pkg.Dts
|
stream.pkg.dts = stream.pes_pkg.Dts
|
||||||
}
|
}
|
||||||
stream.pkg.payload = append(stream.pkg.payload, stream.pes_pkg.Pes_payload...)
|
stream.pkg.payload = append(stream.pkg.payload, stream.pes_pkg.Pes_payload...)
|
||||||
demuxer.splitH26XFrame(stream)
|
demuxer.splitH26XFrame(stream)
|
||||||
stream.pkg.pts = stream.pes_pkg.Pts
|
stream.pkg.pts = stream.pes_pkg.Pts
|
||||||
stream.pkg.dts = stream.pes_pkg.Dts
|
stream.pkg.dts = stream.pes_pkg.Dts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (demuxer *TSDemuxer) doAudioPesPacket(stream *tsstream, start uint8) {
|
func (demuxer *TSDemuxer) doAudioPesPacket(stream *tsstream, start uint8) {
|
||||||
if stream.cid != TS_STREAM_AAC {
|
if stream.cid != TS_STREAM_AAC {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if stream.pkg == nil {
|
if stream.pkg == nil {
|
||||||
stream.pkg = newPacket_t(1024)
|
stream.pkg = newPacket_t(1024)
|
||||||
stream.pkg.pts = stream.pes_pkg.Pts
|
stream.pkg.pts = stream.pes_pkg.Pts
|
||||||
stream.pkg.dts = stream.pes_pkg.Dts
|
stream.pkg.dts = stream.pes_pkg.Dts
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(stream.pkg.payload) > 0 && (start == 1 || stream.pes_pkg.Pts != stream.pkg.pts) {
|
if len(stream.pkg.payload) > 0 && (start == 1 || stream.pes_pkg.Pts != stream.pkg.pts) {
|
||||||
if demuxer.OnFrame != nil {
|
if demuxer.OnFrame != nil {
|
||||||
demuxer.OnFrame(stream.cid, stream.pkg.payload, stream.pkg.pts/90, stream.pkg.dts/90)
|
demuxer.OnFrame(stream.cid, stream.pkg.payload, stream.pkg.pts/90, stream.pkg.dts/90)
|
||||||
}
|
}
|
||||||
stream.pkg.payload = stream.pkg.payload[:0]
|
stream.pkg.payload = stream.pkg.payload[:0]
|
||||||
}
|
}
|
||||||
stream.pkg.payload = append(stream.pkg.payload, stream.pes_pkg.Pes_payload...)
|
stream.pkg.payload = append(stream.pkg.payload, stream.pes_pkg.Pes_payload...)
|
||||||
stream.pkg.pts = stream.pes_pkg.Pts
|
stream.pkg.pts = stream.pes_pkg.Pts
|
||||||
stream.pkg.dts = stream.pes_pkg.Dts
|
stream.pkg.dts = stream.pes_pkg.Dts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (demuxer *TSDemuxer) splitH26XFrame(stream *tsstream) {
|
func (demuxer *TSDemuxer) splitH26XFrame(stream *tsstream) {
|
||||||
data := stream.pkg.payload
|
data := stream.pkg.payload
|
||||||
start, _ := codec.FindStartCode(data, 0)
|
start, _ := codec.FindStartCode(data, 0)
|
||||||
datalen := len(data)
|
datalen := len(data)
|
||||||
for start < datalen {
|
for start < datalen {
|
||||||
end, _ := codec.FindStartCode(data, start+3)
|
end, _ := codec.FindStartCode(data, start+3)
|
||||||
if end < 0 {
|
if end < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (stream.cid == TS_STREAM_H264 && codec.H264NaluTypeWithoutStartCode(data[start:end]) == codec.H264_NAL_AUD) ||
|
if (stream.cid == TS_STREAM_H264 && codec.H264NaluTypeWithoutStartCode(data[start:end]) == codec.H264_NAL_AUD) ||
|
||||||
(stream.cid == TS_STREAM_H265 && codec.H265NaluTypeWithoutStartCode(data[start:end]) == codec.H265_NAL_AUD) {
|
(stream.cid == TS_STREAM_H265 && codec.H265NaluTypeWithoutStartCode(data[start:end]) == codec.H265_NAL_AUD) {
|
||||||
start = end
|
start = end
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if demuxer.OnFrame != nil {
|
if demuxer.OnFrame != nil {
|
||||||
demuxer.OnFrame(stream.cid, data[start:end], stream.pkg.pts/90, stream.pkg.dts/90)
|
demuxer.OnFrame(stream.cid, data[start:end], stream.pkg.pts/90, stream.pkg.dts/90)
|
||||||
}
|
}
|
||||||
start = end
|
start = end
|
||||||
}
|
}
|
||||||
if start == 0 {
|
if start == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(stream.pkg.payload, data[start:datalen])
|
copy(stream.pkg.payload, data[start:datalen])
|
||||||
stream.pkg.payload = stream.pkg.payload[0 : datalen-start]
|
stream.pkg.payload = stream.pkg.payload[0 : datalen-start]
|
||||||
}
|
}
|
||||||
|
|
548
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-muxer.go
generated
vendored
548
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-muxer.go
generated
vendored
|
@ -1,93 +1,93 @@
|
||||||
package mpeg2
|
package mpeg2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pes_stream struct {
|
type pes_stream struct {
|
||||||
pid uint16
|
pid uint16
|
||||||
cc uint8
|
cc uint8
|
||||||
streamtype TS_STREAM_TYPE
|
streamtype TS_STREAM_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPESStream(pid uint16, cid TS_STREAM_TYPE) *pes_stream {
|
func NewPESStream(pid uint16, cid TS_STREAM_TYPE) *pes_stream {
|
||||||
return &pes_stream{
|
return &pes_stream{
|
||||||
pid: pid,
|
pid: pid,
|
||||||
cc: 0,
|
cc: 0,
|
||||||
streamtype: cid,
|
streamtype: cid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type table_pmt struct {
|
type table_pmt struct {
|
||||||
pid uint16
|
pid uint16
|
||||||
cc uint8
|
cc uint8
|
||||||
pcr_pid uint16
|
pcr_pid uint16
|
||||||
version_number uint8
|
version_number uint8
|
||||||
pm uint16
|
pm uint16
|
||||||
streams []*pes_stream
|
streams []*pes_stream
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTablePmt() *table_pmt {
|
func NewTablePmt() *table_pmt {
|
||||||
return &table_pmt{
|
return &table_pmt{
|
||||||
pid: 0,
|
pid: 0,
|
||||||
cc: 0,
|
cc: 0,
|
||||||
pcr_pid: 0,
|
pcr_pid: 0,
|
||||||
version_number: 0,
|
version_number: 0,
|
||||||
pm: 0,
|
pm: 0,
|
||||||
streams: make([]*pes_stream, 0, 2),
|
streams: make([]*pes_stream, 0, 2),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type table_pat struct {
|
type table_pat struct {
|
||||||
cc uint8
|
cc uint8
|
||||||
version_number uint8
|
version_number uint8
|
||||||
pmts []*table_pmt
|
pmts []*table_pmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTablePat() *table_pat {
|
func NewTablePat() *table_pat {
|
||||||
return &table_pat{
|
return &table_pat{
|
||||||
cc: 0,
|
cc: 0,
|
||||||
version_number: 0,
|
version_number: 0,
|
||||||
pmts: make([]*table_pmt, 0, 8),
|
pmts: make([]*table_pmt, 0, 8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TSMuxer struct {
|
type TSMuxer struct {
|
||||||
pat *table_pat
|
pat *table_pat
|
||||||
stream_pid uint16
|
stream_pid uint16
|
||||||
pmt_pid uint16
|
pmt_pid uint16
|
||||||
pat_period uint64
|
pat_period uint64
|
||||||
OnPacket func(pkg []byte)
|
OnPacket func(pkg []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTSMuxer() *TSMuxer {
|
func NewTSMuxer() *TSMuxer {
|
||||||
return &TSMuxer{
|
return &TSMuxer{
|
||||||
pat: NewTablePat(),
|
pat: NewTablePat(),
|
||||||
stream_pid: 0x100,
|
stream_pid: 0x100,
|
||||||
pmt_pid: 0x200,
|
pmt_pid: 0x200,
|
||||||
pat_period: 0,
|
pat_period: 0,
|
||||||
OnPacket: nil,
|
OnPacket: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mux *TSMuxer) AddStream(cid TS_STREAM_TYPE) uint16 {
|
func (mux *TSMuxer) AddStream(cid TS_STREAM_TYPE) uint16 {
|
||||||
if mux.pat == nil {
|
if mux.pat == nil {
|
||||||
mux.pat = NewTablePat()
|
mux.pat = NewTablePat()
|
||||||
}
|
}
|
||||||
if len(mux.pat.pmts) == 0 {
|
if len(mux.pat.pmts) == 0 {
|
||||||
tmppmt := NewTablePmt()
|
tmppmt := NewTablePmt()
|
||||||
tmppmt.pid = mux.pmt_pid
|
tmppmt.pid = mux.pmt_pid
|
||||||
tmppmt.pm = 1
|
tmppmt.pm = 1
|
||||||
mux.pmt_pid++
|
mux.pmt_pid++
|
||||||
mux.pat.pmts = append(mux.pat.pmts, tmppmt)
|
mux.pat.pmts = append(mux.pat.pmts, tmppmt)
|
||||||
}
|
}
|
||||||
sid := mux.stream_pid
|
sid := mux.stream_pid
|
||||||
tmpstream := NewPESStream(sid, cid)
|
tmpstream := NewPESStream(sid, cid)
|
||||||
mux.stream_pid++
|
mux.stream_pid++
|
||||||
mux.pat.pmts[0].streams = append(mux.pat.pmts[0].streams, tmpstream)
|
mux.pat.pmts[0].streams = append(mux.pat.pmts[0].streams, tmpstream)
|
||||||
return sid
|
return sid
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Muxer audio/video stream data
|
/// Muxer audio/video stream data
|
||||||
|
@ -95,239 +95,239 @@ func (mux *TSMuxer) AddStream(cid TS_STREAM_TYPE) uint16 {
|
||||||
/// pts: audio/video stream timestamp in ms
|
/// pts: audio/video stream timestamp in ms
|
||||||
/// dts: audio/video stream timestamp in ms
|
/// dts: audio/video stream timestamp in ms
|
||||||
func (mux *TSMuxer) Write(pid uint16, data []byte, pts uint64, dts uint64) error {
|
func (mux *TSMuxer) Write(pid uint16, data []byte, pts uint64, dts uint64) error {
|
||||||
var whichpmt *table_pmt = nil
|
var whichpmt *table_pmt = nil
|
||||||
var whichstream *pes_stream = nil
|
var whichstream *pes_stream = nil
|
||||||
for _, pmt := range mux.pat.pmts {
|
for _, pmt := range mux.pat.pmts {
|
||||||
for _, stream := range pmt.streams {
|
for _, stream := range pmt.streams {
|
||||||
if stream.pid == pid {
|
if stream.pid == pid {
|
||||||
whichpmt = pmt
|
whichpmt = pmt
|
||||||
whichstream = stream
|
whichstream = stream
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if whichpmt == nil || whichstream == nil {
|
if whichpmt == nil || whichstream == nil {
|
||||||
return errors.New("not Found pid stream")
|
return errors.New("not Found pid stream")
|
||||||
}
|
}
|
||||||
if whichpmt.pcr_pid == 0 || (findPESIDByStreamType(whichstream.streamtype) == PES_STREAM_VIDEO && whichpmt.pcr_pid != pid) {
|
if whichpmt.pcr_pid == 0 || (findPESIDByStreamType(whichstream.streamtype) == PES_STREAM_VIDEO && whichpmt.pcr_pid != pid) {
|
||||||
whichpmt.pcr_pid = pid
|
whichpmt.pcr_pid = pid
|
||||||
}
|
}
|
||||||
|
|
||||||
var withaud bool = false
|
var withaud bool = false
|
||||||
|
|
||||||
if whichstream.streamtype == TS_STREAM_H264 || whichstream.streamtype == TS_STREAM_H265 {
|
if whichstream.streamtype == TS_STREAM_H264 || whichstream.streamtype == TS_STREAM_H265 {
|
||||||
codec.SplitFrame(data, func(nalu []byte) bool {
|
codec.SplitFrame(data, func(nalu []byte) bool {
|
||||||
if whichstream.streamtype == TS_STREAM_H264 {
|
if whichstream.streamtype == TS_STREAM_H264 {
|
||||||
nalu_type := codec.H264NaluTypeWithoutStartCode(nalu)
|
nalu_type := codec.H264NaluTypeWithoutStartCode(nalu)
|
||||||
if nalu_type == codec.H264_NAL_AUD {
|
if nalu_type == codec.H264_NAL_AUD {
|
||||||
withaud = true
|
withaud = true
|
||||||
return false
|
return false
|
||||||
} else if codec.IsH264VCLNaluType(nalu_type) {
|
} else if codec.IsH264VCLNaluType(nalu_type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
nalu_type := codec.H265NaluTypeWithoutStartCode(nalu)
|
nalu_type := codec.H265NaluTypeWithoutStartCode(nalu)
|
||||||
if nalu_type == codec.H265_NAL_AUD {
|
if nalu_type == codec.H265_NAL_AUD {
|
||||||
withaud = true
|
withaud = true
|
||||||
return false
|
return false
|
||||||
} else if codec.IsH265VCLNaluType(nalu_type) {
|
} else if codec.IsH265VCLNaluType(nalu_type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if mux.pat_period == 0 || mux.pat_period+400 < dts {
|
if mux.pat_period == 0 || mux.pat_period+400 < dts {
|
||||||
mux.pat_period = dts
|
mux.pat_period = dts
|
||||||
if mux.pat_period == 0 {
|
if mux.pat_period == 0 {
|
||||||
mux.pat_period = 1 //avoid write pat twice
|
mux.pat_period = 1 //avoid write pat twice
|
||||||
}
|
}
|
||||||
tmppat := NewPat()
|
tmppat := NewPat()
|
||||||
tmppat.Version_number = mux.pat.version_number
|
tmppat.Version_number = mux.pat.version_number
|
||||||
for _, pmt := range mux.pat.pmts {
|
for _, pmt := range mux.pat.pmts {
|
||||||
tmppm := PmtPair{
|
tmppm := PmtPair{
|
||||||
Program_number: pmt.pm,
|
Program_number: pmt.pm,
|
||||||
PID: pmt.pid,
|
PID: pmt.pid,
|
||||||
}
|
}
|
||||||
tmppat.Pmts = append(tmppat.Pmts, tmppm)
|
tmppat.Pmts = append(tmppat.Pmts, tmppm)
|
||||||
}
|
}
|
||||||
mux.writePat(tmppat)
|
mux.writePat(tmppat)
|
||||||
|
|
||||||
for _, pmt := range mux.pat.pmts {
|
for _, pmt := range mux.pat.pmts {
|
||||||
tmppmt := NewPmt()
|
tmppmt := NewPmt()
|
||||||
tmppmt.Program_number = pmt.pm
|
tmppmt.Program_number = pmt.pm
|
||||||
tmppmt.Version_number = pmt.version_number
|
tmppmt.Version_number = pmt.version_number
|
||||||
tmppmt.PCR_PID = pmt.pcr_pid
|
tmppmt.PCR_PID = pmt.pcr_pid
|
||||||
for _, stream := range pmt.streams {
|
for _, stream := range pmt.streams {
|
||||||
var sp StreamPair
|
var sp StreamPair
|
||||||
sp.StreamType = uint8(stream.streamtype)
|
sp.StreamType = uint8(stream.streamtype)
|
||||||
sp.Elementary_PID = stream.pid
|
sp.Elementary_PID = stream.pid
|
||||||
sp.ES_Info_Length = 0
|
sp.ES_Info_Length = 0
|
||||||
tmppmt.Streams = append(tmppmt.Streams, sp)
|
tmppmt.Streams = append(tmppmt.Streams, sp)
|
||||||
}
|
}
|
||||||
mux.writePmt(tmppmt, pmt)
|
mux.writePmt(tmppmt, pmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flag := false
|
flag := false
|
||||||
switch whichstream.streamtype {
|
switch whichstream.streamtype {
|
||||||
case TS_STREAM_H264:
|
case TS_STREAM_H264:
|
||||||
flag = codec.IsH264IDRFrame(data)
|
flag = codec.IsH264IDRFrame(data)
|
||||||
case TS_STREAM_H265:
|
case TS_STREAM_H265:
|
||||||
flag = codec.IsH265IDRFrame(data)
|
flag = codec.IsH265IDRFrame(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
mux.writePES(whichstream, whichpmt, data, pts*90, dts*90, flag, withaud)
|
mux.writePES(whichstream, whichpmt, data, pts*90, dts*90, flag, withaud)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mux *TSMuxer) writePat(pat *Pat) {
|
func (mux *TSMuxer) writePat(pat *Pat) {
|
||||||
var tshdr TSPacket
|
var tshdr TSPacket
|
||||||
tshdr.Payload_unit_start_indicator = 1
|
tshdr.Payload_unit_start_indicator = 1
|
||||||
tshdr.PID = 0
|
tshdr.PID = 0
|
||||||
tshdr.Adaptation_field_control = 0x01
|
tshdr.Adaptation_field_control = 0x01
|
||||||
tshdr.Continuity_counter = mux.pat.cc
|
tshdr.Continuity_counter = mux.pat.cc
|
||||||
mux.pat.cc++
|
mux.pat.cc++
|
||||||
mux.pat.cc = (mux.pat.cc + 1) % 16
|
mux.pat.cc = (mux.pat.cc + 1) % 16
|
||||||
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
||||||
tshdr.EncodeHeader(bsw)
|
tshdr.EncodeHeader(bsw)
|
||||||
bsw.PutByte(0x00) //pointer
|
bsw.PutByte(0x00) //pointer
|
||||||
pat.Encode(bsw)
|
pat.Encode(bsw)
|
||||||
bsw.FillRemainData(0xff)
|
bsw.FillRemainData(0xff)
|
||||||
if mux.OnPacket != nil {
|
if mux.OnPacket != nil {
|
||||||
mux.OnPacket(bsw.Bits())
|
mux.OnPacket(bsw.Bits())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mux *TSMuxer) writePmt(pmt *Pmt, t_pmt *table_pmt) {
|
func (mux *TSMuxer) writePmt(pmt *Pmt, t_pmt *table_pmt) {
|
||||||
var tshdr TSPacket
|
var tshdr TSPacket
|
||||||
tshdr.Payload_unit_start_indicator = 1
|
tshdr.Payload_unit_start_indicator = 1
|
||||||
tshdr.PID = t_pmt.pid
|
tshdr.PID = t_pmt.pid
|
||||||
tshdr.Adaptation_field_control = 0x01
|
tshdr.Adaptation_field_control = 0x01
|
||||||
tshdr.Continuity_counter = t_pmt.cc
|
tshdr.Continuity_counter = t_pmt.cc
|
||||||
t_pmt.cc = (t_pmt.cc + 1) % 16
|
t_pmt.cc = (t_pmt.cc + 1) % 16
|
||||||
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
||||||
tshdr.EncodeHeader(bsw)
|
tshdr.EncodeHeader(bsw)
|
||||||
bsw.PutByte(0x00) //pointer
|
bsw.PutByte(0x00) //pointer
|
||||||
pmt.Encode(bsw)
|
pmt.Encode(bsw)
|
||||||
bsw.FillRemainData(0xff)
|
bsw.FillRemainData(0xff)
|
||||||
if mux.OnPacket != nil {
|
if mux.OnPacket != nil {
|
||||||
mux.OnPacket(bsw.Bits())
|
mux.OnPacket(bsw.Bits())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mux *TSMuxer) writePES(pes *pes_stream, pmt *table_pmt, data []byte, pts uint64, dts uint64, idr_flag bool, withaud bool) {
|
func (mux *TSMuxer) writePES(pes *pes_stream, pmt *table_pmt, data []byte, pts uint64, dts uint64, idr_flag bool, withaud bool) {
|
||||||
var firstPesPacket bool = true
|
var firstPesPacket bool = true
|
||||||
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
||||||
for {
|
for {
|
||||||
bsw.Reset()
|
bsw.Reset()
|
||||||
var tshdr TSPacket
|
var tshdr TSPacket
|
||||||
if firstPesPacket {
|
if firstPesPacket {
|
||||||
tshdr.Payload_unit_start_indicator = 1
|
tshdr.Payload_unit_start_indicator = 1
|
||||||
}
|
}
|
||||||
tshdr.PID = pes.pid
|
tshdr.PID = pes.pid
|
||||||
tshdr.Adaptation_field_control = 0x01
|
tshdr.Adaptation_field_control = 0x01
|
||||||
tshdr.Continuity_counter = pes.cc
|
tshdr.Continuity_counter = pes.cc
|
||||||
headlen := 4
|
headlen := 4
|
||||||
pes.cc = (pes.cc + 1) % 16
|
pes.cc = (pes.cc + 1) % 16
|
||||||
var adaptation *Adaptation_field = nil
|
var adaptation *Adaptation_field = nil
|
||||||
if firstPesPacket && idr_flag {
|
if firstPesPacket && idr_flag {
|
||||||
adaptation = new(Adaptation_field)
|
adaptation = new(Adaptation_field)
|
||||||
tshdr.Adaptation_field_control = tshdr.Adaptation_field_control | 0x20
|
tshdr.Adaptation_field_control = tshdr.Adaptation_field_control | 0x20
|
||||||
adaptation.Random_access_indicator = 1
|
adaptation.Random_access_indicator = 1
|
||||||
headlen += 2
|
headlen += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
if firstPesPacket && pes.pid == pmt.pcr_pid {
|
if firstPesPacket && pes.pid == pmt.pcr_pid {
|
||||||
if adaptation == nil {
|
if adaptation == nil {
|
||||||
adaptation = new(Adaptation_field)
|
adaptation = new(Adaptation_field)
|
||||||
headlen += 2
|
headlen += 2
|
||||||
}
|
}
|
||||||
tshdr.Adaptation_field_control = tshdr.Adaptation_field_control | 0x20
|
tshdr.Adaptation_field_control = tshdr.Adaptation_field_control | 0x20
|
||||||
adaptation.PCR_flag = 1
|
adaptation.PCR_flag = 1
|
||||||
var pcr_base uint64 = 0
|
var pcr_base uint64 = 0
|
||||||
var pcr_ext uint16 = 0
|
var pcr_ext uint16 = 0
|
||||||
if dts == 0 {
|
if dts == 0 {
|
||||||
pcr_base = pts * 300 / 300
|
pcr_base = pts * 300 / 300
|
||||||
pcr_ext = uint16(pts * 300 % 300)
|
pcr_ext = uint16(pts * 300 % 300)
|
||||||
} else {
|
} else {
|
||||||
pcr_base = dts * 300 / 300
|
pcr_base = dts * 300 / 300
|
||||||
pcr_ext = uint16(dts * 300 % 300)
|
pcr_ext = uint16(dts * 300 % 300)
|
||||||
}
|
}
|
||||||
adaptation.Program_clock_reference_base = pcr_base
|
adaptation.Program_clock_reference_base = pcr_base
|
||||||
adaptation.Program_clock_reference_extension = pcr_ext
|
adaptation.Program_clock_reference_extension = pcr_ext
|
||||||
headlen += 6
|
headlen += 6
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload []byte
|
var payload []byte
|
||||||
var pespkg *PesPacket = nil
|
var pespkg *PesPacket = nil
|
||||||
if firstPesPacket {
|
if firstPesPacket {
|
||||||
oldheadlen := headlen
|
oldheadlen := headlen
|
||||||
headlen += 19
|
headlen += 19
|
||||||
if !withaud && pes.streamtype == TS_STREAM_H264 {
|
if !withaud && pes.streamtype == TS_STREAM_H264 {
|
||||||
headlen += 6
|
headlen += 6
|
||||||
payload = append(payload, H264_AUD_NALU...)
|
payload = append(payload, H264_AUD_NALU...)
|
||||||
} else if !withaud && pes.streamtype == TS_STREAM_H265 {
|
} else if !withaud && pes.streamtype == TS_STREAM_H265 {
|
||||||
payload = append(payload, H265_AUD_NALU...)
|
payload = append(payload, H265_AUD_NALU...)
|
||||||
headlen += 7
|
headlen += 7
|
||||||
}
|
}
|
||||||
pespkg = NewPesPacket()
|
pespkg = NewPesPacket()
|
||||||
pespkg.PTS_DTS_flags = 0x03
|
pespkg.PTS_DTS_flags = 0x03
|
||||||
pespkg.PES_header_data_length = 10
|
pespkg.PES_header_data_length = 10
|
||||||
pespkg.Pts = pts
|
pespkg.Pts = pts
|
||||||
pespkg.Dts = dts
|
pespkg.Dts = dts
|
||||||
pespkg.Stream_id = uint8(findPESIDByStreamType(pes.streamtype))
|
pespkg.Stream_id = uint8(findPESIDByStreamType(pes.streamtype))
|
||||||
if idr_flag {
|
if idr_flag {
|
||||||
pespkg.Data_alignment_indicator = 1
|
pespkg.Data_alignment_indicator = 1
|
||||||
}
|
}
|
||||||
if headlen-oldheadlen-6+len(data) > 0xFFFF {
|
if headlen-oldheadlen-6+len(data) > 0xFFFF {
|
||||||
pespkg.PES_packet_length = 0
|
pespkg.PES_packet_length = 0
|
||||||
} else {
|
} else {
|
||||||
pespkg.PES_packet_length = uint16(len(data) + headlen - oldheadlen - 6)
|
pespkg.PES_packet_length = uint16(len(data) + headlen - oldheadlen - 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data)+headlen < TS_PAKCET_SIZE {
|
if len(data)+headlen < TS_PAKCET_SIZE {
|
||||||
if adaptation == nil {
|
if adaptation == nil {
|
||||||
adaptation = new(Adaptation_field)
|
adaptation = new(Adaptation_field)
|
||||||
headlen += 1
|
headlen += 1
|
||||||
if TS_PAKCET_SIZE-len(data)-headlen >= 1 {
|
if TS_PAKCET_SIZE-len(data)-headlen >= 1 {
|
||||||
headlen += 1
|
headlen += 1
|
||||||
} else {
|
} else {
|
||||||
adaptation.SingleStuffingByte = true
|
adaptation.SingleStuffingByte = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
adaptation.Stuffing_byte = uint8(TS_PAKCET_SIZE - len(data) - headlen)
|
adaptation.Stuffing_byte = uint8(TS_PAKCET_SIZE - len(data) - headlen)
|
||||||
payload = append(payload, data...)
|
payload = append(payload, data...)
|
||||||
data = data[:0]
|
data = data[:0]
|
||||||
} else {
|
} else {
|
||||||
payload = append(payload, data[0:TS_PAKCET_SIZE-headlen]...)
|
payload = append(payload, data[0:TS_PAKCET_SIZE-headlen]...)
|
||||||
data = data[TS_PAKCET_SIZE-headlen:]
|
data = data[TS_PAKCET_SIZE-headlen:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if adaptation != nil {
|
if adaptation != nil {
|
||||||
tshdr.Field = adaptation
|
tshdr.Field = adaptation
|
||||||
tshdr.Adaptation_field_control |= 0x02
|
tshdr.Adaptation_field_control |= 0x02
|
||||||
}
|
}
|
||||||
tshdr.EncodeHeader(bsw)
|
tshdr.EncodeHeader(bsw)
|
||||||
if pespkg != nil {
|
if pespkg != nil {
|
||||||
pespkg.Pes_payload = payload
|
pespkg.Pes_payload = payload
|
||||||
pespkg.Encode(bsw)
|
pespkg.Encode(bsw)
|
||||||
} else {
|
} else {
|
||||||
bsw.PutBytes(payload)
|
bsw.PutBytes(payload)
|
||||||
}
|
}
|
||||||
firstPesPacket = false
|
firstPesPacket = false
|
||||||
if mux.OnPacket != nil {
|
if mux.OnPacket != nil {
|
||||||
if len(bsw.Bits()) != TS_PAKCET_SIZE {
|
if len(bsw.Bits()) != TS_PAKCET_SIZE {
|
||||||
panic("packet ts packet failed")
|
panic("packet ts packet failed")
|
||||||
}
|
}
|
||||||
mux.OnPacket(bsw.Bits())
|
mux.OnPacket(bsw.Bits())
|
||||||
}
|
}
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
864
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-proto.go
generated
vendored
864
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-proto.go
generated
vendored
|
@ -1,50 +1,50 @@
|
||||||
package mpeg2
|
package mpeg2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/yapingcat/gomedia/codec"
|
"github.com/yapingcat/gomedia/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
//PID
|
//PID
|
||||||
type TS_PID int
|
type TS_PID int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TS_PID_PAT TS_PID = 0x0000
|
TS_PID_PAT TS_PID = 0x0000
|
||||||
TS_PID_CAT
|
TS_PID_CAT
|
||||||
TS_PID_TSDT
|
TS_PID_TSDT
|
||||||
TS_PID_IPMP
|
TS_PID_IPMP
|
||||||
TS_PID_Nil = 0x1FFFF
|
TS_PID_Nil = 0x1FFFF
|
||||||
)
|
)
|
||||||
|
|
||||||
//Table id
|
//Table id
|
||||||
type PAT_TID int
|
type PAT_TID int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TS_TID_PAS PAT_TID = 0x00 // program_association_section
|
TS_TID_PAS PAT_TID = 0x00 // program_association_section
|
||||||
TS_TID_CAS = 0x01 // conditional_access_section(CA_section)
|
TS_TID_CAS = 0x01 // conditional_access_section(CA_section)
|
||||||
TS_TID_PMS = 0x02 // TS_program_map_section
|
TS_TID_PMS = 0x02 // TS_program_map_section
|
||||||
TS_TID_SDS = 0x03 //TS_description_section
|
TS_TID_SDS = 0x03 //TS_description_section
|
||||||
TS_TID_FORBIDDEN PAT_TID = 0xFF
|
TS_TID_FORBIDDEN PAT_TID = 0xFF
|
||||||
)
|
)
|
||||||
|
|
||||||
type TS_STREAM_TYPE int
|
type TS_STREAM_TYPE int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TS_STREAM_AAC TS_STREAM_TYPE = 0x0F
|
TS_STREAM_AAC TS_STREAM_TYPE = 0x0F
|
||||||
TS_STREAM_H264 TS_STREAM_TYPE = 0x1B
|
TS_STREAM_H264 TS_STREAM_TYPE = 0x1B
|
||||||
TS_STREAM_H265 TS_STREAM_TYPE = 0x24
|
TS_STREAM_H265 TS_STREAM_TYPE = 0x24
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TS_PAKCET_SIZE = 188
|
TS_PAKCET_SIZE = 188
|
||||||
)
|
)
|
||||||
|
|
||||||
type Display interface {
|
type Display interface {
|
||||||
PrettyPrint(file *os.File)
|
PrettyPrint(file *os.File)
|
||||||
}
|
}
|
||||||
|
|
||||||
// transport_packet(){
|
// transport_packet(){
|
||||||
|
@ -67,63 +67,63 @@ type Display interface {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type TSPacket struct {
|
type TSPacket struct {
|
||||||
Transport_error_indicator uint8
|
Transport_error_indicator uint8
|
||||||
Payload_unit_start_indicator uint8
|
Payload_unit_start_indicator uint8
|
||||||
Transport_priority uint8
|
Transport_priority uint8
|
||||||
PID uint16
|
PID uint16
|
||||||
Transport_scrambling_control uint8
|
Transport_scrambling_control uint8
|
||||||
Adaptation_field_control uint8
|
Adaptation_field_control uint8
|
||||||
Continuity_counter uint8
|
Continuity_counter uint8
|
||||||
Field *Adaptation_field
|
Field *Adaptation_field
|
||||||
Payload interface{}
|
Payload interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *TSPacket) PrettyPrint(file *os.File) {
|
func (pkg *TSPacket) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("Transport_error_indicator:%d\n", pkg.Transport_error_indicator))
|
file.WriteString(fmt.Sprintf("Transport_error_indicator:%d\n", pkg.Transport_error_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Payload_unit_start_indicator:%d\n", pkg.Payload_unit_start_indicator))
|
file.WriteString(fmt.Sprintf("Payload_unit_start_indicator:%d\n", pkg.Payload_unit_start_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Transport_priority:%d\n", pkg.Transport_priority))
|
file.WriteString(fmt.Sprintf("Transport_priority:%d\n", pkg.Transport_priority))
|
||||||
file.WriteString(fmt.Sprintf("PID:%d\n", pkg.PID))
|
file.WriteString(fmt.Sprintf("PID:%d\n", pkg.PID))
|
||||||
file.WriteString(fmt.Sprintf("Transport_scrambling_control:%d\n", pkg.Transport_scrambling_control))
|
file.WriteString(fmt.Sprintf("Transport_scrambling_control:%d\n", pkg.Transport_scrambling_control))
|
||||||
file.WriteString(fmt.Sprintf("Adaptation_field_control:%d\n", pkg.Adaptation_field_control))
|
file.WriteString(fmt.Sprintf("Adaptation_field_control:%d\n", pkg.Adaptation_field_control))
|
||||||
file.WriteString(fmt.Sprintf("Continuity_counter:%d\n", pkg.Continuity_counter))
|
file.WriteString(fmt.Sprintf("Continuity_counter:%d\n", pkg.Continuity_counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *TSPacket) EncodeHeader(bsw *codec.BitStreamWriter) {
|
func (pkg *TSPacket) EncodeHeader(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutByte(0x47)
|
bsw.PutByte(0x47)
|
||||||
bsw.PutUint8(pkg.Transport_error_indicator, 1)
|
bsw.PutUint8(pkg.Transport_error_indicator, 1)
|
||||||
bsw.PutUint8(pkg.Payload_unit_start_indicator, 1)
|
bsw.PutUint8(pkg.Payload_unit_start_indicator, 1)
|
||||||
bsw.PutUint8(pkg.Transport_priority, 1)
|
bsw.PutUint8(pkg.Transport_priority, 1)
|
||||||
bsw.PutUint16(pkg.PID, 13)
|
bsw.PutUint16(pkg.PID, 13)
|
||||||
bsw.PutUint8(pkg.Transport_scrambling_control, 2)
|
bsw.PutUint8(pkg.Transport_scrambling_control, 2)
|
||||||
bsw.PutUint8(pkg.Adaptation_field_control, 2)
|
bsw.PutUint8(pkg.Adaptation_field_control, 2)
|
||||||
bsw.PutUint8(pkg.Continuity_counter, 4)
|
bsw.PutUint8(pkg.Continuity_counter, 4)
|
||||||
if pkg.Field != nil && (pkg.Adaptation_field_control&0x02) != 0 {
|
if pkg.Field != nil && (pkg.Adaptation_field_control&0x02) != 0 {
|
||||||
pkg.Field.Encode(bsw)
|
pkg.Field.Encode(bsw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *TSPacket) DecodeHeader(bs *codec.BitStream) error {
|
func (pkg *TSPacket) DecodeHeader(bs *codec.BitStream) error {
|
||||||
sync_byte := bs.Uint8(8)
|
sync_byte := bs.Uint8(8)
|
||||||
if sync_byte != 0x47 {
|
if sync_byte != 0x47 {
|
||||||
return errors.New("ts packet must start with 0x47")
|
return errors.New("ts packet must start with 0x47")
|
||||||
}
|
}
|
||||||
pkg.Transport_error_indicator = bs.GetBit()
|
pkg.Transport_error_indicator = bs.GetBit()
|
||||||
pkg.Payload_unit_start_indicator = bs.GetBit()
|
pkg.Payload_unit_start_indicator = bs.GetBit()
|
||||||
pkg.Transport_priority = bs.GetBit()
|
pkg.Transport_priority = bs.GetBit()
|
||||||
pkg.PID = bs.Uint16(13)
|
pkg.PID = bs.Uint16(13)
|
||||||
pkg.Transport_scrambling_control = bs.Uint8(2)
|
pkg.Transport_scrambling_control = bs.Uint8(2)
|
||||||
pkg.Adaptation_field_control = bs.Uint8(2)
|
pkg.Adaptation_field_control = bs.Uint8(2)
|
||||||
pkg.Continuity_counter = bs.Uint8(4)
|
pkg.Continuity_counter = bs.Uint8(4)
|
||||||
if pkg.Adaptation_field_control == 0x02 || pkg.Adaptation_field_control == 0x03 {
|
if pkg.Adaptation_field_control == 0x02 || pkg.Adaptation_field_control == 0x03 {
|
||||||
if pkg.Field == nil {
|
if pkg.Field == nil {
|
||||||
pkg.Field = new(Adaptation_field)
|
pkg.Field = new(Adaptation_field)
|
||||||
}
|
}
|
||||||
err := pkg.Field.Decode(bs)
|
err := pkg.Field.Decode(bs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -189,414 +189,414 @@ func (pkg *TSPacket) DecodeHeader(bs *codec.BitStream) error {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type Adaptation_field struct {
|
type Adaptation_field struct {
|
||||||
SingleStuffingByte bool // The value 0 is for inserting a single stuffing byte in a Transport Stream packet
|
SingleStuffingByte bool // The value 0 is for inserting a single stuffing byte in a Transport Stream packet
|
||||||
Adaptation_field_length uint8 //8 uimsbf
|
Adaptation_field_length uint8 //8 uimsbf
|
||||||
Discontinuity_indicator uint8 //1 bslbf
|
Discontinuity_indicator uint8 //1 bslbf
|
||||||
Random_access_indicator uint8 //1 bslbf
|
Random_access_indicator uint8 //1 bslbf
|
||||||
Elementary_stream_priority_indicator uint8 //1 bslbf
|
Elementary_stream_priority_indicator uint8 //1 bslbf
|
||||||
PCR_flag uint8 //1 bslbf
|
PCR_flag uint8 //1 bslbf
|
||||||
OPCR_flag uint8 //1 bslbf
|
OPCR_flag uint8 //1 bslbf
|
||||||
Splicing_point_flag uint8 //1 bslbf
|
Splicing_point_flag uint8 //1 bslbf
|
||||||
Transport_private_data_flag uint8 //1 bslbf
|
Transport_private_data_flag uint8 //1 bslbf
|
||||||
Adaptation_field_extension_flag uint8 //1 bslbf
|
Adaptation_field_extension_flag uint8 //1 bslbf
|
||||||
Program_clock_reference_base uint64 //33 uimsbf
|
Program_clock_reference_base uint64 //33 uimsbf
|
||||||
Program_clock_reference_extension uint16 //9 uimsbf
|
Program_clock_reference_extension uint16 //9 uimsbf
|
||||||
Original_program_clock_reference_base uint64 //33 uimsbf
|
Original_program_clock_reference_base uint64 //33 uimsbf
|
||||||
Original_program_clock_reference_extension uint16 //9 uimsbf
|
Original_program_clock_reference_extension uint16 //9 uimsbf
|
||||||
Splice_countdown uint8 //8 uimsbf
|
Splice_countdown uint8 //8 uimsbf
|
||||||
Transport_private_data_length uint8 //8 uimsbf
|
Transport_private_data_length uint8 //8 uimsbf
|
||||||
Adaptation_field_extension_length uint8 //8 uimsbf
|
Adaptation_field_extension_length uint8 //8 uimsbf
|
||||||
Ltw_flag uint8 //1 bslbf
|
Ltw_flag uint8 //1 bslbf
|
||||||
Piecewise_rate_flag uint8 //1 bslbf
|
Piecewise_rate_flag uint8 //1 bslbf
|
||||||
Seamless_splice_flag uint8 //1 bslbf
|
Seamless_splice_flag uint8 //1 bslbf
|
||||||
Ltw_valid_flag uint8 //1 bslbf
|
Ltw_valid_flag uint8 //1 bslbf
|
||||||
Ltw_offset uint16 //15 uimsbf
|
Ltw_offset uint16 //15 uimsbf
|
||||||
Piecewise_rate uint32 //22 uimsbf
|
Piecewise_rate uint32 //22 uimsbf
|
||||||
Splice_type uint8 //4 uimsbf
|
Splice_type uint8 //4 uimsbf
|
||||||
DTS_next_AU uint64
|
DTS_next_AU uint64
|
||||||
Stuffing_byte uint8
|
Stuffing_byte uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adaptation *Adaptation_field) PrettyPrint(file *os.File) {
|
func (adaptation *Adaptation_field) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("Adaptation_field_length:%d\n", adaptation.Adaptation_field_length))
|
file.WriteString(fmt.Sprintf("Adaptation_field_length:%d\n", adaptation.Adaptation_field_length))
|
||||||
file.WriteString(fmt.Sprintf("Discontinuity_indicator:%d\n", adaptation.Discontinuity_indicator))
|
file.WriteString(fmt.Sprintf("Discontinuity_indicator:%d\n", adaptation.Discontinuity_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Random_access_indicator:%d\n", adaptation.Random_access_indicator))
|
file.WriteString(fmt.Sprintf("Random_access_indicator:%d\n", adaptation.Random_access_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Elementary_stream_priority_indicator:%d\n", adaptation.Elementary_stream_priority_indicator))
|
file.WriteString(fmt.Sprintf("Elementary_stream_priority_indicator:%d\n", adaptation.Elementary_stream_priority_indicator))
|
||||||
file.WriteString(fmt.Sprintf("PCR_flag:%d\n", adaptation.PCR_flag))
|
file.WriteString(fmt.Sprintf("PCR_flag:%d\n", adaptation.PCR_flag))
|
||||||
file.WriteString(fmt.Sprintf("OPCR_flag:%d\n", adaptation.OPCR_flag))
|
file.WriteString(fmt.Sprintf("OPCR_flag:%d\n", adaptation.OPCR_flag))
|
||||||
file.WriteString(fmt.Sprintf("Splicing_point_flag:%d\n", adaptation.Splicing_point_flag))
|
file.WriteString(fmt.Sprintf("Splicing_point_flag:%d\n", adaptation.Splicing_point_flag))
|
||||||
file.WriteString(fmt.Sprintf("Transport_private_data_flag:%d\n", adaptation.Transport_private_data_flag))
|
file.WriteString(fmt.Sprintf("Transport_private_data_flag:%d\n", adaptation.Transport_private_data_flag))
|
||||||
file.WriteString(fmt.Sprintf("Adaptation_field_extension_flag:%d\n", adaptation.Adaptation_field_extension_flag))
|
file.WriteString(fmt.Sprintf("Adaptation_field_extension_flag:%d\n", adaptation.Adaptation_field_extension_flag))
|
||||||
if adaptation.PCR_flag == 1 {
|
if adaptation.PCR_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Program_clock_reference_base:%d\n", adaptation.Program_clock_reference_base))
|
file.WriteString(fmt.Sprintf("Program_clock_reference_base:%d\n", adaptation.Program_clock_reference_base))
|
||||||
file.WriteString(fmt.Sprintf("Program_clock_reference_extension:%d\n", adaptation.Program_clock_reference_extension))
|
file.WriteString(fmt.Sprintf("Program_clock_reference_extension:%d\n", adaptation.Program_clock_reference_extension))
|
||||||
}
|
}
|
||||||
if adaptation.OPCR_flag == 1 {
|
if adaptation.OPCR_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Original_program_clock_reference_base:%d\n", adaptation.Original_program_clock_reference_base))
|
file.WriteString(fmt.Sprintf("Original_program_clock_reference_base:%d\n", adaptation.Original_program_clock_reference_base))
|
||||||
file.WriteString(fmt.Sprintf("Original_program_clock_reference_extension:%d\n", adaptation.Original_program_clock_reference_extension))
|
file.WriteString(fmt.Sprintf("Original_program_clock_reference_extension:%d\n", adaptation.Original_program_clock_reference_extension))
|
||||||
}
|
}
|
||||||
if adaptation.Splicing_point_flag == 1 {
|
if adaptation.Splicing_point_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Splice_countdown:%d\n", adaptation.Splice_countdown))
|
file.WriteString(fmt.Sprintf("Splice_countdown:%d\n", adaptation.Splice_countdown))
|
||||||
}
|
}
|
||||||
if adaptation.Transport_private_data_flag == 1 {
|
if adaptation.Transport_private_data_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Transport_private_data_length:%d\n", adaptation.Transport_private_data_length))
|
file.WriteString(fmt.Sprintf("Transport_private_data_length:%d\n", adaptation.Transport_private_data_length))
|
||||||
}
|
}
|
||||||
if adaptation.Adaptation_field_extension_flag == 1 {
|
if adaptation.Adaptation_field_extension_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Adaptation_field_extension_length:%d\n", adaptation.Adaptation_field_extension_length))
|
file.WriteString(fmt.Sprintf("Adaptation_field_extension_length:%d\n", adaptation.Adaptation_field_extension_length))
|
||||||
file.WriteString(fmt.Sprintf("Ltw_flag:%d\n", adaptation.Ltw_flag))
|
file.WriteString(fmt.Sprintf("Ltw_flag:%d\n", adaptation.Ltw_flag))
|
||||||
file.WriteString(fmt.Sprintf("Piecewise_rate_flag:%d\n", adaptation.Piecewise_rate_flag))
|
file.WriteString(fmt.Sprintf("Piecewise_rate_flag:%d\n", adaptation.Piecewise_rate_flag))
|
||||||
file.WriteString(fmt.Sprintf("Seamless_splice_flag:%d\n", adaptation.Seamless_splice_flag))
|
file.WriteString(fmt.Sprintf("Seamless_splice_flag:%d\n", adaptation.Seamless_splice_flag))
|
||||||
if adaptation.Ltw_flag == 1 {
|
if adaptation.Ltw_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Ltw_valid_flag:%d\n", adaptation.Ltw_valid_flag))
|
file.WriteString(fmt.Sprintf("Ltw_valid_flag:%d\n", adaptation.Ltw_valid_flag))
|
||||||
file.WriteString(fmt.Sprintf("Ltw_offset:%d\n", adaptation.Ltw_offset))
|
file.WriteString(fmt.Sprintf("Ltw_offset:%d\n", adaptation.Ltw_offset))
|
||||||
}
|
}
|
||||||
if adaptation.Piecewise_rate_flag == 1 {
|
if adaptation.Piecewise_rate_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Piecewise_rate:%d\n", adaptation.Piecewise_rate))
|
file.WriteString(fmt.Sprintf("Piecewise_rate:%d\n", adaptation.Piecewise_rate))
|
||||||
}
|
}
|
||||||
if adaptation.Seamless_splice_flag == 1 {
|
if adaptation.Seamless_splice_flag == 1 {
|
||||||
file.WriteString(fmt.Sprintf("Splice_type:%d\n", adaptation.Splice_type))
|
file.WriteString(fmt.Sprintf("Splice_type:%d\n", adaptation.Splice_type))
|
||||||
file.WriteString(fmt.Sprintf("DTS_next_AU:%d\n", adaptation.DTS_next_AU))
|
file.WriteString(fmt.Sprintf("DTS_next_AU:%d\n", adaptation.DTS_next_AU))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adaptation *Adaptation_field) Encode(bsw *codec.BitStreamWriter) {
|
func (adaptation *Adaptation_field) Encode(bsw *codec.BitStreamWriter) {
|
||||||
loc := bsw.ByteOffset()
|
loc := bsw.ByteOffset()
|
||||||
bsw.PutUint8(adaptation.Adaptation_field_length, 8)
|
bsw.PutUint8(adaptation.Adaptation_field_length, 8)
|
||||||
if adaptation.SingleStuffingByte {
|
if adaptation.SingleStuffingByte {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bsw.Markdot()
|
bsw.Markdot()
|
||||||
bsw.PutUint8(adaptation.Discontinuity_indicator, 1)
|
bsw.PutUint8(adaptation.Discontinuity_indicator, 1)
|
||||||
bsw.PutUint8(adaptation.Random_access_indicator, 1)
|
bsw.PutUint8(adaptation.Random_access_indicator, 1)
|
||||||
bsw.PutUint8(adaptation.Elementary_stream_priority_indicator, 1)
|
bsw.PutUint8(adaptation.Elementary_stream_priority_indicator, 1)
|
||||||
bsw.PutUint8(adaptation.PCR_flag, 1)
|
bsw.PutUint8(adaptation.PCR_flag, 1)
|
||||||
bsw.PutUint8(adaptation.OPCR_flag, 1)
|
bsw.PutUint8(adaptation.OPCR_flag, 1)
|
||||||
bsw.PutUint8(adaptation.Splicing_point_flag, 1)
|
bsw.PutUint8(adaptation.Splicing_point_flag, 1)
|
||||||
bsw.PutUint8(0 /*adaptation.Transport_private_data_flag*/, 1)
|
bsw.PutUint8(0 /*adaptation.Transport_private_data_flag*/, 1)
|
||||||
bsw.PutUint8(0 /*adaptation.Adaptation_field_extension_flag*/, 1)
|
bsw.PutUint8(0 /*adaptation.Adaptation_field_extension_flag*/, 1)
|
||||||
if adaptation.PCR_flag == 1 {
|
if adaptation.PCR_flag == 1 {
|
||||||
bsw.PutUint64(adaptation.Program_clock_reference_base, 33)
|
bsw.PutUint64(adaptation.Program_clock_reference_base, 33)
|
||||||
bsw.PutUint8(0, 6)
|
bsw.PutUint8(0, 6)
|
||||||
bsw.PutUint16(adaptation.Program_clock_reference_extension, 9)
|
bsw.PutUint16(adaptation.Program_clock_reference_extension, 9)
|
||||||
}
|
}
|
||||||
if adaptation.OPCR_flag == 1 {
|
if adaptation.OPCR_flag == 1 {
|
||||||
bsw.PutUint64(adaptation.Original_program_clock_reference_base, 33)
|
bsw.PutUint64(adaptation.Original_program_clock_reference_base, 33)
|
||||||
bsw.PutUint8(0, 6)
|
bsw.PutUint8(0, 6)
|
||||||
bsw.PutUint16(adaptation.Original_program_clock_reference_extension, 9)
|
bsw.PutUint16(adaptation.Original_program_clock_reference_extension, 9)
|
||||||
}
|
}
|
||||||
if adaptation.Splicing_point_flag == 1 {
|
if adaptation.Splicing_point_flag == 1 {
|
||||||
bsw.PutUint8(adaptation.Splice_countdown, 8)
|
bsw.PutUint8(adaptation.Splice_countdown, 8)
|
||||||
}
|
}
|
||||||
//TODO
|
//TODO
|
||||||
// if adaptation.Transport_private_data_flag == 0 {
|
// if adaptation.Transport_private_data_flag == 0 {
|
||||||
// }
|
// }
|
||||||
// if adaptation.Adaptation_field_extension_flag == 0 {
|
// if adaptation.Adaptation_field_extension_flag == 0 {
|
||||||
// }
|
// }
|
||||||
adaptation.Adaptation_field_length = uint8(bsw.DistanceFromMarkDot() / 8)
|
adaptation.Adaptation_field_length = uint8(bsw.DistanceFromMarkDot() / 8)
|
||||||
bsw.PutRepetValue(0xff, int(adaptation.Stuffing_byte))
|
bsw.PutRepetValue(0xff, int(adaptation.Stuffing_byte))
|
||||||
adaptation.Adaptation_field_length += adaptation.Stuffing_byte
|
adaptation.Adaptation_field_length += adaptation.Stuffing_byte
|
||||||
bsw.SetByte(adaptation.Adaptation_field_length, loc)
|
bsw.SetByte(adaptation.Adaptation_field_length, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (adaptation *Adaptation_field) Decode(bs *codec.BitStream) error {
|
func (adaptation *Adaptation_field) Decode(bs *codec.BitStream) error {
|
||||||
if bs.RemainBytes() < 1 {
|
if bs.RemainBytes() < 1 {
|
||||||
return errors.New("len of data < 1 byte")
|
return errors.New("len of data < 1 byte")
|
||||||
}
|
}
|
||||||
adaptation.Adaptation_field_length = bs.Uint8(8)
|
adaptation.Adaptation_field_length = bs.Uint8(8)
|
||||||
startoffset := bs.ByteOffset()
|
startoffset := bs.ByteOffset()
|
||||||
//fmt.Printf("Adaptation_field_length=%d\n", adaptation.Adaptation_field_length)
|
//fmt.Printf("Adaptation_field_length=%d\n", adaptation.Adaptation_field_length)
|
||||||
if bs.RemainBytes() < int(adaptation.Adaptation_field_length) {
|
if bs.RemainBytes() < int(adaptation.Adaptation_field_length) {
|
||||||
return errors.New("len of data < Adaptation_field_length")
|
return errors.New("len of data < Adaptation_field_length")
|
||||||
}
|
}
|
||||||
if adaptation.Adaptation_field_length == 0 {
|
if adaptation.Adaptation_field_length == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
adaptation.Discontinuity_indicator = bs.GetBit()
|
adaptation.Discontinuity_indicator = bs.GetBit()
|
||||||
adaptation.Random_access_indicator = bs.GetBit()
|
adaptation.Random_access_indicator = bs.GetBit()
|
||||||
adaptation.Elementary_stream_priority_indicator = bs.GetBit()
|
adaptation.Elementary_stream_priority_indicator = bs.GetBit()
|
||||||
adaptation.PCR_flag = bs.GetBit()
|
adaptation.PCR_flag = bs.GetBit()
|
||||||
adaptation.OPCR_flag = bs.GetBit()
|
adaptation.OPCR_flag = bs.GetBit()
|
||||||
adaptation.Splicing_point_flag = bs.GetBit()
|
adaptation.Splicing_point_flag = bs.GetBit()
|
||||||
adaptation.Transport_private_data_flag = bs.GetBit()
|
adaptation.Transport_private_data_flag = bs.GetBit()
|
||||||
adaptation.Adaptation_field_extension_flag = bs.GetBit()
|
adaptation.Adaptation_field_extension_flag = bs.GetBit()
|
||||||
if adaptation.PCR_flag == 1 {
|
if adaptation.PCR_flag == 1 {
|
||||||
adaptation.Program_clock_reference_base = bs.GetBits(33)
|
adaptation.Program_clock_reference_base = bs.GetBits(33)
|
||||||
bs.SkipBits(6)
|
bs.SkipBits(6)
|
||||||
adaptation.Program_clock_reference_extension = uint16(bs.GetBits(9))
|
adaptation.Program_clock_reference_extension = uint16(bs.GetBits(9))
|
||||||
}
|
}
|
||||||
if adaptation.OPCR_flag == 1 {
|
if adaptation.OPCR_flag == 1 {
|
||||||
adaptation.Original_program_clock_reference_base = bs.GetBits(33)
|
adaptation.Original_program_clock_reference_base = bs.GetBits(33)
|
||||||
bs.SkipBits(6)
|
bs.SkipBits(6)
|
||||||
adaptation.Original_program_clock_reference_extension = uint16(bs.GetBits(9))
|
adaptation.Original_program_clock_reference_extension = uint16(bs.GetBits(9))
|
||||||
}
|
}
|
||||||
if adaptation.Splicing_point_flag == 1 {
|
if adaptation.Splicing_point_flag == 1 {
|
||||||
adaptation.Splice_countdown = bs.Uint8(8)
|
adaptation.Splice_countdown = bs.Uint8(8)
|
||||||
}
|
}
|
||||||
if adaptation.Transport_private_data_flag == 1 {
|
if adaptation.Transport_private_data_flag == 1 {
|
||||||
adaptation.Transport_private_data_length = bs.Uint8(8)
|
adaptation.Transport_private_data_length = bs.Uint8(8)
|
||||||
bs.SkipBits(8 * int(adaptation.Transport_private_data_length))
|
bs.SkipBits(8 * int(adaptation.Transport_private_data_length))
|
||||||
}
|
}
|
||||||
if adaptation.Adaptation_field_extension_flag == 1 {
|
if adaptation.Adaptation_field_extension_flag == 1 {
|
||||||
adaptation.Adaptation_field_extension_length = bs.Uint8(8)
|
adaptation.Adaptation_field_extension_length = bs.Uint8(8)
|
||||||
bs.Markdot()
|
bs.Markdot()
|
||||||
adaptation.Ltw_flag = bs.GetBit()
|
adaptation.Ltw_flag = bs.GetBit()
|
||||||
adaptation.Piecewise_rate_flag = bs.GetBit()
|
adaptation.Piecewise_rate_flag = bs.GetBit()
|
||||||
adaptation.Seamless_splice_flag = bs.GetBit()
|
adaptation.Seamless_splice_flag = bs.GetBit()
|
||||||
bs.SkipBits(5)
|
bs.SkipBits(5)
|
||||||
if adaptation.Ltw_flag == 1 {
|
if adaptation.Ltw_flag == 1 {
|
||||||
adaptation.Ltw_valid_flag = bs.GetBit()
|
adaptation.Ltw_valid_flag = bs.GetBit()
|
||||||
adaptation.Ltw_offset = uint16(bs.GetBits(15))
|
adaptation.Ltw_offset = uint16(bs.GetBits(15))
|
||||||
}
|
}
|
||||||
if adaptation.Piecewise_rate_flag == 1 {
|
if adaptation.Piecewise_rate_flag == 1 {
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
adaptation.Piecewise_rate = uint32(bs.GetBits(22))
|
adaptation.Piecewise_rate = uint32(bs.GetBits(22))
|
||||||
}
|
}
|
||||||
if adaptation.Seamless_splice_flag == 1 {
|
if adaptation.Seamless_splice_flag == 1 {
|
||||||
adaptation.Splice_type = uint8(bs.GetBits(4))
|
adaptation.Splice_type = uint8(bs.GetBits(4))
|
||||||
adaptation.DTS_next_AU = bs.GetBits(3)
|
adaptation.DTS_next_AU = bs.GetBits(3)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
adaptation.DTS_next_AU = adaptation.DTS_next_AU<<15 | bs.GetBits(15)
|
adaptation.DTS_next_AU = adaptation.DTS_next_AU<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
adaptation.DTS_next_AU = adaptation.DTS_next_AU<<15 | bs.GetBits(15)
|
adaptation.DTS_next_AU = adaptation.DTS_next_AU<<15 | bs.GetBits(15)
|
||||||
bs.SkipBits(1)
|
bs.SkipBits(1)
|
||||||
}
|
}
|
||||||
bitscount := bs.DistanceFromMarkDot()
|
bitscount := bs.DistanceFromMarkDot()
|
||||||
if bitscount%8 > 0 {
|
if bitscount%8 > 0 {
|
||||||
panic("maybe parser ts file failed")
|
panic("maybe parser ts file failed")
|
||||||
}
|
}
|
||||||
bs.SkipBits(int(adaptation.Adaptation_field_extension_length*8 - uint8(bitscount)))
|
bs.SkipBits(int(adaptation.Adaptation_field_extension_length*8 - uint8(bitscount)))
|
||||||
}
|
}
|
||||||
endoffset := bs.ByteOffset()
|
endoffset := bs.ByteOffset()
|
||||||
bs.SkipBits((int(adaptation.Adaptation_field_length) - (endoffset - startoffset)) * 8)
|
bs.SkipBits((int(adaptation.Adaptation_field_length) - (endoffset - startoffset)) * 8)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type PmtPair struct {
|
type PmtPair struct {
|
||||||
Program_number uint16
|
Program_number uint16
|
||||||
PID uint16
|
PID uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pat struct {
|
type Pat struct {
|
||||||
Table_id uint8 //8 uimsbf
|
Table_id uint8 //8 uimsbf
|
||||||
Section_syntax_indicator uint8 //1 bslbf
|
Section_syntax_indicator uint8 //1 bslbf
|
||||||
Section_length uint16 //12 uimsbf
|
Section_length uint16 //12 uimsbf
|
||||||
Transport_stream_id uint16 //16 uimsbf
|
Transport_stream_id uint16 //16 uimsbf
|
||||||
Version_number uint8 //5 uimsbf
|
Version_number uint8 //5 uimsbf
|
||||||
Current_next_indicator uint8 //1 bslbf
|
Current_next_indicator uint8 //1 bslbf
|
||||||
Section_number uint8 //8 uimsbf
|
Section_number uint8 //8 uimsbf
|
||||||
Last_section_number uint8 //8 uimsbf
|
Last_section_number uint8 //8 uimsbf
|
||||||
Pmts []PmtPair
|
Pmts []PmtPair
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPat() *Pat {
|
func NewPat() *Pat {
|
||||||
return &Pat{
|
return &Pat{
|
||||||
Table_id: uint8(TS_TID_PAS),
|
Table_id: uint8(TS_TID_PAS),
|
||||||
Pmts: make([]PmtPair, 0, 8),
|
Pmts: make([]PmtPair, 0, 8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pat *Pat) PrettyPrint(file *os.File) {
|
func (pat *Pat) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("Table id:%d\n", pat.Table_id))
|
file.WriteString(fmt.Sprintf("Table id:%d\n", pat.Table_id))
|
||||||
file.WriteString(fmt.Sprintf("Section_syntax_indicator:%d\n", pat.Section_syntax_indicator))
|
file.WriteString(fmt.Sprintf("Section_syntax_indicator:%d\n", pat.Section_syntax_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Section_length:%d\n", pat.Section_length))
|
file.WriteString(fmt.Sprintf("Section_length:%d\n", pat.Section_length))
|
||||||
file.WriteString(fmt.Sprintf("Transport_stream_id:%d\n", pat.Transport_stream_id))
|
file.WriteString(fmt.Sprintf("Transport_stream_id:%d\n", pat.Transport_stream_id))
|
||||||
file.WriteString(fmt.Sprintf("Version_number:%d\n", pat.Version_number))
|
file.WriteString(fmt.Sprintf("Version_number:%d\n", pat.Version_number))
|
||||||
file.WriteString(fmt.Sprintf("Current_next_indicator:%d\n", pat.Current_next_indicator))
|
file.WriteString(fmt.Sprintf("Current_next_indicator:%d\n", pat.Current_next_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Section_number:%d\n", pat.Section_number))
|
file.WriteString(fmt.Sprintf("Section_number:%d\n", pat.Section_number))
|
||||||
file.WriteString(fmt.Sprintf("Last_section_number:%d\n", pat.Last_section_number))
|
file.WriteString(fmt.Sprintf("Last_section_number:%d\n", pat.Last_section_number))
|
||||||
for i, pmt := range pat.Pmts {
|
for i, pmt := range pat.Pmts {
|
||||||
file.WriteString(fmt.Sprintf("----pmt %d\n", i))
|
file.WriteString(fmt.Sprintf("----pmt %d\n", i))
|
||||||
file.WriteString(fmt.Sprintf(" program_number:%d\n", pmt.Program_number))
|
file.WriteString(fmt.Sprintf(" program_number:%d\n", pmt.Program_number))
|
||||||
if pmt.Program_number == 0x0000 {
|
if pmt.Program_number == 0x0000 {
|
||||||
file.WriteString(fmt.Sprintf(" network_PID:%d\n", pmt.PID))
|
file.WriteString(fmt.Sprintf(" network_PID:%d\n", pmt.PID))
|
||||||
} else {
|
} else {
|
||||||
file.WriteString(fmt.Sprintf(" program_map_PID:%d\n", pmt.PID))
|
file.WriteString(fmt.Sprintf(" program_map_PID:%d\n", pmt.PID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pat *Pat) Encode(bsw *codec.BitStreamWriter) {
|
func (pat *Pat) Encode(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutUint8(0x00, 8)
|
bsw.PutUint8(0x00, 8)
|
||||||
loc := bsw.ByteOffset()
|
loc := bsw.ByteOffset()
|
||||||
bsw.PutUint8(pat.Section_syntax_indicator, 1)
|
bsw.PutUint8(pat.Section_syntax_indicator, 1)
|
||||||
bsw.PutUint8(0x00, 1)
|
bsw.PutUint8(0x00, 1)
|
||||||
bsw.PutUint8(0x03, 2)
|
bsw.PutUint8(0x03, 2)
|
||||||
bsw.PutUint16(0, 12)
|
bsw.PutUint16(0, 12)
|
||||||
bsw.Markdot()
|
bsw.Markdot()
|
||||||
bsw.PutUint16(pat.Transport_stream_id, 16)
|
bsw.PutUint16(pat.Transport_stream_id, 16)
|
||||||
bsw.PutUint8(0x03, 2)
|
bsw.PutUint8(0x03, 2)
|
||||||
bsw.PutUint8(pat.Version_number, 5)
|
bsw.PutUint8(pat.Version_number, 5)
|
||||||
bsw.PutUint8(pat.Current_next_indicator, 1)
|
bsw.PutUint8(pat.Current_next_indicator, 1)
|
||||||
bsw.PutUint8(pat.Section_number, 8)
|
bsw.PutUint8(pat.Section_number, 8)
|
||||||
bsw.PutUint8(pat.Last_section_number, 8)
|
bsw.PutUint8(pat.Last_section_number, 8)
|
||||||
for _, pms := range pat.Pmts {
|
for _, pms := range pat.Pmts {
|
||||||
bsw.PutUint16(pms.Program_number, 16)
|
bsw.PutUint16(pms.Program_number, 16)
|
||||||
bsw.PutUint8(0x07, 3)
|
bsw.PutUint8(0x07, 3)
|
||||||
bsw.PutUint16(pms.PID, 13)
|
bsw.PutUint16(pms.PID, 13)
|
||||||
}
|
}
|
||||||
length := bsw.DistanceFromMarkDot()
|
length := bsw.DistanceFromMarkDot()
|
||||||
//|Section_syntax_indicator|'0'|reserved|Section_length|
|
//|Section_syntax_indicator|'0'|reserved|Section_length|
|
||||||
pat.Section_length = uint16(length)/8 + 4
|
pat.Section_length = uint16(length)/8 + 4
|
||||||
bsw.SetUint16(pat.Section_length&0x0FFF|(uint16(pat.Section_syntax_indicator)<<15)|0x3000, loc)
|
bsw.SetUint16(pat.Section_length&0x0FFF|(uint16(pat.Section_syntax_indicator)<<15)|0x3000, loc)
|
||||||
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(pat.Section_length-4)-3:bsw.ByteOffset()])
|
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(pat.Section_length-4)-3:bsw.ByteOffset()])
|
||||||
tmpcrc := make([]byte, 4)
|
tmpcrc := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
||||||
bsw.PutBytes(tmpcrc)
|
bsw.PutBytes(tmpcrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pat *Pat) Decode(bs *codec.BitStream) error {
|
func (pat *Pat) Decode(bs *codec.BitStream) error {
|
||||||
pat.Table_id = bs.Uint8(8)
|
pat.Table_id = bs.Uint8(8)
|
||||||
|
|
||||||
if pat.Table_id != uint8(TS_TID_PAS) {
|
if pat.Table_id != uint8(TS_TID_PAS) {
|
||||||
return errors.New("table id is Not TS_TID_PAS")
|
return errors.New("table id is Not TS_TID_PAS")
|
||||||
}
|
}
|
||||||
pat.Section_syntax_indicator = bs.Uint8(1)
|
pat.Section_syntax_indicator = bs.Uint8(1)
|
||||||
bs.SkipBits(3)
|
bs.SkipBits(3)
|
||||||
pat.Section_length = bs.Uint16(12)
|
pat.Section_length = bs.Uint16(12)
|
||||||
pat.Transport_stream_id = bs.Uint16(16)
|
pat.Transport_stream_id = bs.Uint16(16)
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
pat.Version_number = bs.Uint8(5)
|
pat.Version_number = bs.Uint8(5)
|
||||||
pat.Current_next_indicator = bs.Uint8(1)
|
pat.Current_next_indicator = bs.Uint8(1)
|
||||||
pat.Section_number = bs.Uint8(8)
|
pat.Section_number = bs.Uint8(8)
|
||||||
pat.Last_section_number = bs.Uint8(8)
|
pat.Last_section_number = bs.Uint8(8)
|
||||||
for i := 0; i+4 <= int(pat.Section_length)-5-4; i = i + 4 {
|
for i := 0; i+4 <= int(pat.Section_length)-5-4; i = i + 4 {
|
||||||
tmp := PmtPair{
|
tmp := PmtPair{
|
||||||
Program_number: 0,
|
Program_number: 0,
|
||||||
PID: 0,
|
PID: 0,
|
||||||
}
|
}
|
||||||
tmp.Program_number = bs.Uint16(16)
|
tmp.Program_number = bs.Uint16(16)
|
||||||
bs.SkipBits(3)
|
bs.SkipBits(3)
|
||||||
tmp.PID = bs.Uint16(13)
|
tmp.PID = bs.Uint16(13)
|
||||||
pat.Pmts = append(pat.Pmts, tmp)
|
pat.Pmts = append(pat.Pmts, tmp)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamPair struct {
|
type StreamPair struct {
|
||||||
StreamType uint8 //8 uimsbf
|
StreamType uint8 //8 uimsbf
|
||||||
Elementary_PID uint16 //13 uimsbf
|
Elementary_PID uint16 //13 uimsbf
|
||||||
ES_Info_Length uint16 //12 uimsbf
|
ES_Info_Length uint16 //12 uimsbf
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pmt struct {
|
type Pmt struct {
|
||||||
Table_id uint8 //8 uimsbf
|
Table_id uint8 //8 uimsbf
|
||||||
Section_syntax_indicator uint8 //1 bslbf
|
Section_syntax_indicator uint8 //1 bslbf
|
||||||
Section_length uint16 //12 uimsbf
|
Section_length uint16 //12 uimsbf
|
||||||
Program_number uint16 //16 uimsbf
|
Program_number uint16 //16 uimsbf
|
||||||
Version_number uint8 //5 uimsbf
|
Version_number uint8 //5 uimsbf
|
||||||
Current_next_indicator uint8 //1 bslbf
|
Current_next_indicator uint8 //1 bslbf
|
||||||
Section_number uint8 //8 uimsbf
|
Section_number uint8 //8 uimsbf
|
||||||
Last_section_number uint8 //8 uimsbf
|
Last_section_number uint8 //8 uimsbf
|
||||||
PCR_PID uint16 //13 uimsbf
|
PCR_PID uint16 //13 uimsbf
|
||||||
Program_info_length uint16 //12 uimsbf
|
Program_info_length uint16 //12 uimsbf
|
||||||
Streams []StreamPair
|
Streams []StreamPair
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPmt() *Pmt {
|
func NewPmt() *Pmt {
|
||||||
return &Pmt{
|
return &Pmt{
|
||||||
Table_id: uint8(TS_TID_PMS),
|
Table_id: uint8(TS_TID_PMS),
|
||||||
Streams: make([]StreamPair, 0, 8),
|
Streams: make([]StreamPair, 0, 8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pmt *Pmt) PrettyPrint(file *os.File) {
|
func (pmt *Pmt) PrettyPrint(file *os.File) {
|
||||||
file.WriteString(fmt.Sprintf("Table id:%d\n", pmt.Table_id))
|
file.WriteString(fmt.Sprintf("Table id:%d\n", pmt.Table_id))
|
||||||
file.WriteString(fmt.Sprintf("Section_syntax_indicator:%d\n", pmt.Section_syntax_indicator))
|
file.WriteString(fmt.Sprintf("Section_syntax_indicator:%d\n", pmt.Section_syntax_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Section_length:%d\n", pmt.Section_length))
|
file.WriteString(fmt.Sprintf("Section_length:%d\n", pmt.Section_length))
|
||||||
file.WriteString(fmt.Sprintf("Program_number:%d\n", pmt.Program_number))
|
file.WriteString(fmt.Sprintf("Program_number:%d\n", pmt.Program_number))
|
||||||
file.WriteString(fmt.Sprintf("Version_number:%d\n", pmt.Version_number))
|
file.WriteString(fmt.Sprintf("Version_number:%d\n", pmt.Version_number))
|
||||||
file.WriteString(fmt.Sprintf("Current_next_indicator:%d\n", pmt.Current_next_indicator))
|
file.WriteString(fmt.Sprintf("Current_next_indicator:%d\n", pmt.Current_next_indicator))
|
||||||
file.WriteString(fmt.Sprintf("Section_number:%d\n", pmt.Section_number))
|
file.WriteString(fmt.Sprintf("Section_number:%d\n", pmt.Section_number))
|
||||||
file.WriteString(fmt.Sprintf("Last_section_number:%d\n", pmt.Last_section_number))
|
file.WriteString(fmt.Sprintf("Last_section_number:%d\n", pmt.Last_section_number))
|
||||||
file.WriteString(fmt.Sprintf("PCR_PID:%d\n", pmt.PCR_PID))
|
file.WriteString(fmt.Sprintf("PCR_PID:%d\n", pmt.PCR_PID))
|
||||||
file.WriteString(fmt.Sprintf("program_info_length:%d\n", pmt.Program_info_length))
|
file.WriteString(fmt.Sprintf("program_info_length:%d\n", pmt.Program_info_length))
|
||||||
for i, stream := range pmt.Streams {
|
for i, stream := range pmt.Streams {
|
||||||
file.WriteString(fmt.Sprintf("----stream %d\n", i))
|
file.WriteString(fmt.Sprintf("----stream %d\n", i))
|
||||||
if stream.StreamType == uint8(TS_STREAM_AAC) {
|
if stream.StreamType == uint8(TS_STREAM_AAC) {
|
||||||
file.WriteString(" stream_type:AAC\n")
|
file.WriteString(" stream_type:AAC\n")
|
||||||
} else if stream.StreamType == uint8(TS_STREAM_H264) {
|
} else if stream.StreamType == uint8(TS_STREAM_H264) {
|
||||||
file.WriteString(" stream_type:H264\n")
|
file.WriteString(" stream_type:H264\n")
|
||||||
} else if stream.StreamType == uint8(TS_STREAM_H265) {
|
} else if stream.StreamType == uint8(TS_STREAM_H265) {
|
||||||
file.WriteString(" stream_type:H265\n")
|
file.WriteString(" stream_type:H265\n")
|
||||||
}
|
}
|
||||||
file.WriteString(fmt.Sprintf(" elementary_PID:%d\n", stream.Elementary_PID))
|
file.WriteString(fmt.Sprintf(" elementary_PID:%d\n", stream.Elementary_PID))
|
||||||
file.WriteString(fmt.Sprintf(" ES_info_length:%d\n", stream.ES_Info_Length))
|
file.WriteString(fmt.Sprintf(" ES_info_length:%d\n", stream.ES_Info_Length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pmt *Pmt) Encode(bsw *codec.BitStreamWriter) {
|
func (pmt *Pmt) Encode(bsw *codec.BitStreamWriter) {
|
||||||
bsw.PutUint8(pmt.Table_id, 8)
|
bsw.PutUint8(pmt.Table_id, 8)
|
||||||
loc := bsw.ByteOffset()
|
loc := bsw.ByteOffset()
|
||||||
bsw.PutUint8(pmt.Section_syntax_indicator, 1)
|
bsw.PutUint8(pmt.Section_syntax_indicator, 1)
|
||||||
bsw.PutUint8(0x00, 1)
|
bsw.PutUint8(0x00, 1)
|
||||||
bsw.PutUint8(0x03, 2)
|
bsw.PutUint8(0x03, 2)
|
||||||
bsw.PutUint16(pmt.Section_length, 12)
|
bsw.PutUint16(pmt.Section_length, 12)
|
||||||
bsw.Markdot()
|
bsw.Markdot()
|
||||||
bsw.PutUint16(pmt.Program_number, 16)
|
bsw.PutUint16(pmt.Program_number, 16)
|
||||||
bsw.PutUint8(0x03, 2)
|
bsw.PutUint8(0x03, 2)
|
||||||
bsw.PutUint8(pmt.Version_number, 5)
|
bsw.PutUint8(pmt.Version_number, 5)
|
||||||
bsw.PutUint8(pmt.Current_next_indicator, 1)
|
bsw.PutUint8(pmt.Current_next_indicator, 1)
|
||||||
bsw.PutUint8(pmt.Section_number, 8)
|
bsw.PutUint8(pmt.Section_number, 8)
|
||||||
bsw.PutUint8(pmt.Last_section_number, 8)
|
bsw.PutUint8(pmt.Last_section_number, 8)
|
||||||
bsw.PutUint8(0x07, 3)
|
bsw.PutUint8(0x07, 3)
|
||||||
bsw.PutUint16(pmt.PCR_PID, 13)
|
bsw.PutUint16(pmt.PCR_PID, 13)
|
||||||
bsw.PutUint8(0x0f, 4)
|
bsw.PutUint8(0x0f, 4)
|
||||||
//TODO Program info length
|
//TODO Program info length
|
||||||
bsw.PutUint16(0x0000 /*pmt.Program_info_length*/, 12)
|
bsw.PutUint16(0x0000 /*pmt.Program_info_length*/, 12)
|
||||||
for _, stream := range pmt.Streams {
|
for _, stream := range pmt.Streams {
|
||||||
bsw.PutUint8(stream.StreamType, 8)
|
bsw.PutUint8(stream.StreamType, 8)
|
||||||
bsw.PutUint8(0x00, 3)
|
bsw.PutUint8(0x00, 3)
|
||||||
bsw.PutUint16(stream.Elementary_PID, 13)
|
bsw.PutUint16(stream.Elementary_PID, 13)
|
||||||
bsw.PutUint8(0x00, 4)
|
bsw.PutUint8(0x00, 4)
|
||||||
//TODO ES_info
|
//TODO ES_info
|
||||||
bsw.PutUint8(0 /*ES_info_length*/, 12)
|
bsw.PutUint8(0 /*ES_info_length*/, 12)
|
||||||
}
|
}
|
||||||
length := bsw.DistanceFromMarkDot()
|
length := bsw.DistanceFromMarkDot()
|
||||||
pmt.Section_length = uint16(length)/8 + 4
|
pmt.Section_length = uint16(length)/8 + 4
|
||||||
bsw.SetUint16(pmt.Section_length&0x0FFF|(uint16(pmt.Section_syntax_indicator)<<15)|0x3000, loc)
|
bsw.SetUint16(pmt.Section_length&0x0FFF|(uint16(pmt.Section_syntax_indicator)<<15)|0x3000, loc)
|
||||||
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(pmt.Section_length-4)-3:bsw.ByteOffset()])
|
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(pmt.Section_length-4)-3:bsw.ByteOffset()])
|
||||||
tmpcrc := make([]byte, 4)
|
tmpcrc := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
||||||
bsw.PutBytes(tmpcrc)
|
bsw.PutBytes(tmpcrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pmt *Pmt) Decode(bs *codec.BitStream) error {
|
func (pmt *Pmt) Decode(bs *codec.BitStream) error {
|
||||||
pmt.Table_id = bs.Uint8(8)
|
pmt.Table_id = bs.Uint8(8)
|
||||||
if pmt.Table_id != uint8(TS_TID_PMS) {
|
if pmt.Table_id != uint8(TS_TID_PMS) {
|
||||||
return errors.New("table id is Not TS_TID_PAS")
|
return errors.New("table id is Not TS_TID_PAS")
|
||||||
}
|
}
|
||||||
pmt.Section_syntax_indicator = bs.Uint8(1)
|
pmt.Section_syntax_indicator = bs.Uint8(1)
|
||||||
bs.SkipBits(3)
|
bs.SkipBits(3)
|
||||||
pmt.Section_length = bs.Uint16(12)
|
pmt.Section_length = bs.Uint16(12)
|
||||||
pmt.Program_number = bs.Uint16(16)
|
pmt.Program_number = bs.Uint16(16)
|
||||||
bs.SkipBits(2)
|
bs.SkipBits(2)
|
||||||
pmt.Version_number = bs.Uint8(5)
|
pmt.Version_number = bs.Uint8(5)
|
||||||
pmt.Current_next_indicator = bs.Uint8(1)
|
pmt.Current_next_indicator = bs.Uint8(1)
|
||||||
pmt.Section_number = bs.Uint8(8)
|
pmt.Section_number = bs.Uint8(8)
|
||||||
pmt.Last_section_number = bs.Uint8(8)
|
pmt.Last_section_number = bs.Uint8(8)
|
||||||
bs.SkipBits(3)
|
bs.SkipBits(3)
|
||||||
pmt.PCR_PID = bs.Uint16(13)
|
pmt.PCR_PID = bs.Uint16(13)
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
pmt.Program_info_length = bs.Uint16(12)
|
pmt.Program_info_length = bs.Uint16(12)
|
||||||
//TODO N loop descriptors
|
//TODO N loop descriptors
|
||||||
bs.SkipBits(int(pmt.Program_info_length) * 8)
|
bs.SkipBits(int(pmt.Program_info_length) * 8)
|
||||||
//fmt.Printf("section length %d pmt.Pogram_info_length=%d\n", pmt.Section_length, pmt.Pogram_info_length)
|
//fmt.Printf("section length %d pmt.Pogram_info_length=%d\n", pmt.Section_length, pmt.Pogram_info_length)
|
||||||
for i := 0; i < int(pmt.Section_length)-9-int(pmt.Program_info_length)-4; {
|
for i := 0; i < int(pmt.Section_length)-9-int(pmt.Program_info_length)-4; {
|
||||||
tmp := StreamPair{
|
tmp := StreamPair{
|
||||||
StreamType: 0,
|
StreamType: 0,
|
||||||
Elementary_PID: 0,
|
Elementary_PID: 0,
|
||||||
ES_Info_Length: 0,
|
ES_Info_Length: 0,
|
||||||
}
|
}
|
||||||
tmp.StreamType = bs.Uint8(8)
|
tmp.StreamType = bs.Uint8(8)
|
||||||
bs.SkipBits(3)
|
bs.SkipBits(3)
|
||||||
tmp.Elementary_PID = bs.Uint16(13)
|
tmp.Elementary_PID = bs.Uint16(13)
|
||||||
bs.SkipBits(4)
|
bs.SkipBits(4)
|
||||||
tmp.ES_Info_Length = bs.Uint16(12)
|
tmp.ES_Info_Length = bs.Uint16(12)
|
||||||
//TODO N loop descriptors
|
//TODO N loop descriptors
|
||||||
bs.SkipBits(int(tmp.ES_Info_Length) * 8)
|
bs.SkipBits(int(tmp.ES_Info_Length) * 8)
|
||||||
pmt.Streams = append(pmt.Streams, tmp)
|
pmt.Streams = append(pmt.Streams, tmp)
|
||||||
i += 5 + int(tmp.ES_Info_Length)
|
i += 5 + int(tmp.ES_Info_Length)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
2
trunk/3rdparty/srs-bench/vendor/modules.txt
vendored
2
trunk/3rdparty/srs-bench/vendor/modules.txt
vendored
|
@ -33,6 +33,7 @@ github.com/ossrs/go-oryx-lib/amf0
|
||||||
github.com/ossrs/go-oryx-lib/avc
|
github.com/ossrs/go-oryx-lib/avc
|
||||||
github.com/ossrs/go-oryx-lib/errors
|
github.com/ossrs/go-oryx-lib/errors
|
||||||
github.com/ossrs/go-oryx-lib/flv
|
github.com/ossrs/go-oryx-lib/flv
|
||||||
|
github.com/ossrs/go-oryx-lib/http
|
||||||
github.com/ossrs/go-oryx-lib/logger
|
github.com/ossrs/go-oryx-lib/logger
|
||||||
github.com/ossrs/go-oryx-lib/rtmp
|
github.com/ossrs/go-oryx-lib/rtmp
|
||||||
# github.com/pion/datachannel v1.4.21
|
# github.com/pion/datachannel v1.4.21
|
||||||
|
@ -116,6 +117,7 @@ github.com/pion/webrtc/v3/pkg/media/oggreader
|
||||||
github.com/pion/webrtc/v3/pkg/media/oggwriter
|
github.com/pion/webrtc/v3/pkg/media/oggwriter
|
||||||
github.com/pion/webrtc/v3/pkg/rtcerr
|
github.com/pion/webrtc/v3/pkg/rtcerr
|
||||||
# github.com/pkg/errors v0.9.1
|
# github.com/pkg/errors v0.9.1
|
||||||
|
## explicit
|
||||||
github.com/pkg/errors
|
github.com/pkg/errors
|
||||||
# github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
|
# github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
|
||||||
github.com/satori/go.uuid
|
github.com/satori/go.uuid
|
||||||
|
|
|
@ -1515,6 +1515,7 @@ vhost http.remux.srs.com {
|
||||||
vhost hooks.callback.srs.com {
|
vhost hooks.callback.srs.com {
|
||||||
http_hooks {
|
http_hooks {
|
||||||
# whether the http hooks enable.
|
# whether the http hooks enable.
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ENABLED for all vhosts.
|
||||||
# default off.
|
# default off.
|
||||||
enabled on;
|
enabled on;
|
||||||
# when client(encoder) publish to vhost/app/stream, call the hook,
|
# when client(encoder) publish to vhost/app/stream, call the hook,
|
||||||
|
@ -1533,6 +1534,7 @@ vhost hooks.callback.srs.com {
|
||||||
# on_publish http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
# on_publish http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
||||||
# @remark For SRS4, the HTTPS url is supported, for example:
|
# @remark For SRS4, the HTTPS url is supported, for example:
|
||||||
# on_publish https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
# on_publish https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_PUBLISH for all vhosts.
|
||||||
on_publish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
|
on_publish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
|
||||||
# when client(encoder) stop publish to vhost/app/stream, call the hook,
|
# when client(encoder) stop publish to vhost/app/stream, call the hook,
|
||||||
# the request in the POST data string is a object encode by json:
|
# the request in the POST data string is a object encode by json:
|
||||||
|
@ -1550,6 +1552,7 @@ vhost hooks.callback.srs.com {
|
||||||
# on_unpublish http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
# on_unpublish http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
||||||
# @remark For SRS4, the HTTPS url is supported, for example:
|
# @remark For SRS4, the HTTPS url is supported, for example:
|
||||||
# on_unpublish https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
# on_unpublish https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_UNPUBLISH for all vhosts.
|
||||||
on_unpublish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
|
on_unpublish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
|
||||||
# when client start to play vhost/app/stream, call the hook,
|
# when client start to play vhost/app/stream, call the hook,
|
||||||
# the request in the POST data string is a object encode by json:
|
# the request in the POST data string is a object encode by json:
|
||||||
|
@ -1568,6 +1571,7 @@ vhost hooks.callback.srs.com {
|
||||||
# on_play http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
# on_play http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
||||||
# @remark For SRS4, the HTTPS url is supported, for example:
|
# @remark For SRS4, the HTTPS url is supported, for example:
|
||||||
# on_play https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
# on_play https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_PLAY for all vhosts.
|
||||||
on_play http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
|
on_play http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
|
||||||
# when client stop to play vhost/app/stream, call the hook,
|
# when client stop to play vhost/app/stream, call the hook,
|
||||||
# the request in the POST data string is a object encode by json:
|
# the request in the POST data string is a object encode by json:
|
||||||
|
@ -1585,6 +1589,7 @@ vhost hooks.callback.srs.com {
|
||||||
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
||||||
# @remark For SRS4, the HTTPS url is supported, for example:
|
# @remark For SRS4, the HTTPS url is supported, for example:
|
||||||
# on_stop https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
# on_stop https://xxx/api0 https://xxx/api1 https://xxx/apiN
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_STOP for all vhosts.
|
||||||
on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
|
on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
|
||||||
# when srs reap a dvr file, call the hook,
|
# when srs reap a dvr file, call the hook,
|
||||||
# the request in the POST data string is a object encode by json:
|
# the request in the POST data string is a object encode by json:
|
||||||
|
@ -1600,6 +1605,7 @@ vhost hooks.callback.srs.com {
|
||||||
# if valid, the hook must return HTTP code 200(Status OK) and response
|
# if valid, the hook must return HTTP code 200(Status OK) and response
|
||||||
# an int value specifies the error code(0 corresponding to success):
|
# an int value specifies the error code(0 corresponding to success):
|
||||||
# 0
|
# 0
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_DVR for all vhosts.
|
||||||
on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
|
on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
|
||||||
# when srs reap a ts file of hls, call the hook,
|
# when srs reap a ts file of hls, call the hook,
|
||||||
# the request in the POST data string is a object encode by json:
|
# the request in the POST data string is a object encode by json:
|
||||||
|
@ -1620,6 +1626,7 @@ vhost hooks.callback.srs.com {
|
||||||
# if valid, the hook must return HTTP code 200(Status OK) and response
|
# if valid, the hook must return HTTP code 200(Status OK) and response
|
||||||
# an int value specifies the error code(0 corresponding to success):
|
# an int value specifies the error code(0 corresponding to success):
|
||||||
# 0
|
# 0
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_HLS for all vhosts.
|
||||||
on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls;
|
on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls;
|
||||||
# when srs reap a ts file of hls, call this hook,
|
# when srs reap a ts file of hls, call this hook,
|
||||||
# used to push file to cdn network, by get the ts file from cdn network.
|
# used to push file to cdn network, by get the ts file from cdn network.
|
||||||
|
@ -1631,6 +1638,7 @@ vhost hooks.callback.srs.com {
|
||||||
# [ts_url], replace with the ts url.
|
# [ts_url], replace with the ts url.
|
||||||
# ignore any return data of server.
|
# ignore any return data of server.
|
||||||
# @remark random select a url to report, not report all.
|
# @remark random select a url to report, not report all.
|
||||||
|
# Overwrite by env SRS_VHOST_HTTP_HOOKS_ON_HLS_NOTIFY for all vhosts.
|
||||||
on_hls_notify http://127.0.0.1:8085/api/v1/hls/[server_id]/[app]/[stream]/[ts_url][param];
|
on_hls_notify http://127.0.0.1:8085/api/v1/hls/[server_id]/[app]/[stream]/[ts_url][param];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ The changelog for SRS.
|
||||||
|
|
||||||
## SRS 5.0 Changelog
|
## SRS 5.0 Changelog
|
||||||
|
|
||||||
* v5.0, 2023-01-05, FFmpeg: Support build with FFmpeg native opus. v5.0.131 (#3140)
|
* v5.0, 2023-01-06, DVR: Support blackbox test based on hooks. v5.0.132
|
||||||
|
* v5.0, 2023-01-06, FFmpeg: Support build with FFmpeg native opus. v5.0.131 (#3140)
|
||||||
* v5.0, 2023-01-05, CORS: Refine HTTP CORS headers. v5.0.130
|
* v5.0, 2023-01-05, CORS: Refine HTTP CORS headers. v5.0.130
|
||||||
* v5.0, 2023-01-03, Add blackbox test for HLS and MP3 codec. v5.0.129
|
* v5.0, 2023-01-03, Add blackbox test for HLS and MP3 codec. v5.0.129
|
||||||
* v5.0, 2023-01-02, Merge [#3355](https://github.com/ossrs/srs/pull/3355): Test: Support blackbox test by FFmpeg. v5.0.128
|
* v5.0, 2023-01-02, Merge [#3355](https://github.com/ossrs/srs/pull/3355): Test: Support blackbox test by FFmpeg. v5.0.128
|
||||||
|
|
|
@ -68,6 +68,16 @@ const char* _srs_version = "XCORE-" RTMP_SIG_SRS_SERVER;
|
||||||
#define SRS_OVERWRITE_BY_ENV_MILLISECONDS(key) if (!srs_getenv(key).empty()) return (srs_utime_t)(::atoi(srs_getenv(key).c_str()) * SRS_UTIME_MILLISECONDS)
|
#define SRS_OVERWRITE_BY_ENV_MILLISECONDS(key) if (!srs_getenv(key).empty()) return (srs_utime_t)(::atoi(srs_getenv(key).c_str()) * SRS_UTIME_MILLISECONDS)
|
||||||
#define SRS_OVERWRITE_BY_ENV_FLOAT_SECONDS(key) if (!srs_getenv(key).empty()) return srs_utime_t(::atof(srs_getenv(key).c_str()) * SRS_UTIME_SECONDS)
|
#define SRS_OVERWRITE_BY_ENV_FLOAT_SECONDS(key) if (!srs_getenv(key).empty()) return srs_utime_t(::atof(srs_getenv(key).c_str()) * SRS_UTIME_SECONDS)
|
||||||
#define SRS_OVERWRITE_BY_ENV_FLOAT_MILLISECONDS(key) if (!srs_getenv(key).empty()) return srs_utime_t(::atof(srs_getenv(key).c_str()) * SRS_UTIME_MILLISECONDS)
|
#define SRS_OVERWRITE_BY_ENV_FLOAT_MILLISECONDS(key) if (!srs_getenv(key).empty()) return srs_utime_t(::atof(srs_getenv(key).c_str()) * SRS_UTIME_MILLISECONDS)
|
||||||
|
#define SRS_OVERWRITE_BY_ENV_DIRECTIVE(key) { \
|
||||||
|
static SrsConfDirective* dir = NULL; \
|
||||||
|
if (!dir && !srs_getenv(key).empty()) { \
|
||||||
|
string v = srs_getenv(key); \
|
||||||
|
dir = new SrsConfDirective(); \
|
||||||
|
dir->name = key; \
|
||||||
|
dir->args.push_back(v); \
|
||||||
|
} \
|
||||||
|
if (dir) return dir; \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dumps the ingest/transcode-engine in @param dir to amf0 object @param engine.
|
* dumps the ingest/transcode-engine in @param dir to amf0 object @param engine.
|
||||||
|
@ -5359,6 +5369,8 @@ SrsConfDirective* SrsConfig::get_vhost_http_hooks(string vhost)
|
||||||
|
|
||||||
bool SrsConfig::get_vhost_http_hooks_enabled(string vhost)
|
bool SrsConfig::get_vhost_http_hooks_enabled(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.http_hooks.enabled"); // SRS_VHOST_HTTP_HOOKS_ENABLED
|
||||||
|
|
||||||
static bool DEFAULT = false;
|
static bool DEFAULT = false;
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost(vhost);
|
SrsConfDirective* conf = get_vhost(vhost);
|
||||||
|
@ -5371,6 +5383,8 @@ bool SrsConfig::get_vhost_http_hooks_enabled(string vhost)
|
||||||
|
|
||||||
bool SrsConfig::get_vhost_http_hooks_enabled(SrsConfDirective* vhost)
|
bool SrsConfig::get_vhost_http_hooks_enabled(SrsConfDirective* vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_BOOL("srs.vhost.http_hooks.enabled"); // SRS_VHOST_HTTP_HOOKS_ENABLED
|
||||||
|
|
||||||
static bool DEFAULT = false;
|
static bool DEFAULT = false;
|
||||||
|
|
||||||
SrsConfDirective* conf = vhost->get("http_hooks");
|
SrsConfDirective* conf = vhost->get("http_hooks");
|
||||||
|
@ -5388,6 +5402,8 @@ bool SrsConfig::get_vhost_http_hooks_enabled(SrsConfDirective* vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_connect"); // SRS_VHOST_HTTP_HOOKS_ON_CONNECT
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5398,6 +5414,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_close"); // SRS_VHOST_HTTP_HOOKS_ON_CLOSE
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5408,6 +5426,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_publish"); // SRS_VHOST_HTTP_HOOKS_ON_PUBLISH
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5418,6 +5438,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_unpublish"); // SRS_VHOST_HTTP_HOOKS_ON_UNPUBLISH
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5428,6 +5450,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_play"); // SRS_VHOST_HTTP_HOOKS_ON_PLAY
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5438,6 +5462,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_stop"); // SRS_VHOST_HTTP_HOOKS_ON_STOP
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5448,6 +5474,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_dvr"); // SRS_VHOST_HTTP_HOOKS_ON_DVR
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5458,6 +5486,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_hls"); // SRS_VHOST_HTTP_HOOKS_ON_HLS
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -5468,6 +5498,8 @@ SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_hls_notify(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_hls_notify(string vhost)
|
||||||
{
|
{
|
||||||
|
SRS_OVERWRITE_BY_ENV_DIRECTIVE("srs.vhost.http_hooks.on_hls_notify"); // SRS_VHOST_HTTP_HOOKS_ON_HLS_NOTIFY
|
||||||
|
|
||||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
#define VERSION_MAJOR 5
|
#define VERSION_MAJOR 5
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_REVISION 131
|
#define VERSION_REVISION 132
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3937,8 +3937,6 @@ VOID TEST(ConfigMainTest, SrtServerTlpktDrop)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesGlobal)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesGlobal)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4035,8 +4033,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesGlobal)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesthreads)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesthreads)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4047,8 +4043,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesthreads)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesRtmp)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesRtmp)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4082,8 +4076,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesRtmp)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpApi)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpApi)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4126,8 +4118,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHttpApi)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpServer)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpServer)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4163,8 +4153,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHttpServer)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesSrtServer)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesSrtServer)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4220,8 +4208,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesSrtServer)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostSrt)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostSrt)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4235,8 +4221,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesVhostSrt)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesRtcServer)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesRtcServer)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4303,8 +4287,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesRtcServer)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostRtc)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostRtc)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4362,8 +4344,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesVhostRtc)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostPlay)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostPlay)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4433,8 +4413,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesVhostPlay)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostPublish)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesVhostPublish)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4460,8 +4438,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesVhostPublish)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesCircuitBreaker)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesCircuitBreaker)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4490,8 +4466,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesCircuitBreaker)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesTencentcloudCls)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesTencentcloudCls)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4539,8 +4513,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesTencentcloudCls)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesTencentcloudApm)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesTencentcloudApm)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4566,8 +4538,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesTencentcloudApm)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesExporter)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesExporter)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4587,8 +4557,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesExporter)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesHeartbeat)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHeartbeat)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4611,8 +4579,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHeartbeat)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesScope)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesScope)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4646,8 +4612,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesScope)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpStatic)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpStatic)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4664,8 +4628,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHttpStatic)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpRemux)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHttpRemux)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
@ -4722,8 +4684,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHttpRemux)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesDash)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesDash)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4776,8 +4736,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHds)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesDvr)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesDvr)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4806,8 +4764,6 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesDvr)
|
||||||
|
|
||||||
VOID TEST(ConfigEnvTest, CheckEnvValuesHls)
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHls)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
@ -4886,4 +4842,71 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHls)
|
||||||
SrsSetEnvConfig(hls_dts_directly, "SRS_VHOST_HLS_HLS_DTS_DIRECTLY", "off");
|
SrsSetEnvConfig(hls_dts_directly, "SRS_VHOST_HLS_HLS_DTS_DIRECTLY", "off");
|
||||||
EXPECT_FALSE(conf.get_vhost_hls_dts_directly("__defaultVhost__"));
|
EXPECT_FALSE(conf.get_vhost_hls_dts_directly("__defaultVhost__"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID TEST(ConfigEnvTest, CheckEnvValuesHooks)
|
||||||
|
{
|
||||||
|
MockSrsConfig conf;
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ENABLED", "on");
|
||||||
|
EXPECT_TRUE(conf.get_vhost_http_hooks_enabled("__defaultVhost__"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_PUBLISH", "http://server/api/publish");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_publish("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/publish", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_UNPUBLISH", "http://server/api/unpublish");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_unpublish("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/unpublish", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_PLAY", "http://server/api/play");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_play("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/play", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_STOP", "http://server/api/stop");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_stop("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/stop", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_DVR", "http://server/api/dvr");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_dvr("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/dvr", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_HLS", "http://server/api/hls");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_hls("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/hls", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsSetEnvConfig(hooks, "SRS_VHOST_HTTP_HOOKS_ON_HLS_NOTIFY", "http://server/api/hls_notify");
|
||||||
|
SrsConfDirective* dir = conf.get_vhost_on_hls_notify("__defaultVhost__");
|
||||||
|
ASSERT_TRUE(dir != NULL);
|
||||||
|
ASSERT_TRUE((int)dir->args.size() == 1);
|
||||||
|
ASSERT_STREQ("http://server/api/hls_notify", dir->arg0().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue