Compare commits

..

9 Commits

Author SHA1 Message Date
Valentin Cocaud
896ab2d264 Allow to enable frame copy on a video track 2022-05-13 17:08:17 +02:00
Valentin Cocaud
280bc2de13 updating go.mod 2022-03-01 15:30:05 +01:00
Valentin Cocaud
58767d8fb4 🚧 replace by fork 2022-03-01 15:10:52 +01:00
Valentin Cocaud
662d1ac3a7 fix dependency errors 2022-03-01 15:01:08 +01:00
Valentin Cocaud
b1f7693135 remove idea files 2022-03-01 14:46:58 +01:00
Valentin Cocaud
d8ff6be0f3 Write test instead of type checking hack 2022-03-01 14:46:55 +01:00
Valentin Cocaud
41da6ab56a Update pkg/codec/codec.go
Co-authored-by: Atsushi Watanabe <atsushi.w@ieee.org>
2022-03-01 14:39:12 +01:00
Valentin Cocaud
419afd453a Add an interface for easier customization of the EncoderController
Making the ReadCloser an Controllable allows to uncouple
the controller implementation from the encoder.
This is not needed for the 2 codec controller already implemented (openh264 and vpx)
but is more future proof in case it required for other codecs.
2022-03-01 14:39:12 +01:00
Valentin Cocaud
80be2a7a57 Force key frame on PLI 2022-03-01 14:39:12 +01:00
65 changed files with 418 additions and 1541 deletions

View File

@@ -13,15 +13,13 @@ jobs:
strategy:
fail-fast: false
matrix:
go:
- '1.18'
- '1.19'
go: [ '1.16', '1.15' ]
name: Linux Go ${{ matrix.go }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Install dependencies
@@ -34,53 +32,24 @@ jobs:
libx264-dev
- name: Run Test Suite
run: make test
- uses: codecov/codecov-action@v3
if: matrix.go == '1.19'
- uses: codecov/codecov-action@v2
if: matrix.go == '1.16'
build-darwin:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
runs-on:
- macos-latest
- ['self-hosted', 'macOS', 'ARM64']
go:
- '1.18'
- '1.19'
runs-on: ${{ matrix.runs-on }}
name: Darwin Go ${{ matrix.go }} ${{ join(matrix.runs-on, ' ') }}
go: [ '1.16', '1.15' ]
name: Darwin Go ${{ matrix.go }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Checkout Homebrew
if: matrix.runs-on != 'macos-latest'
uses: actions/checkout@v3
with:
repository: Homebrew/brew
path: homebrew
- name: Set up brew to install deps under temporary dir
if: matrix.runs-on != 'macos-latest' # set up local brew only on self-hosted
run: |
dir="${GITHUB_WORKSPACE}/homebrew"
cd "${dir}"
echo "Set up shellenv" >&2
env="$(./bin/brew shellenv)"
echo "${env}" | tee -a ${GITHUB_ENV}
eval "${env}"
echo "Set up paths" >&2
echo "${dir}/bin" | tee -a ${GITHUB_PATH}
echo "Brew update" >&2
brew update --force --quiet
chmod -R go-w "$(brew --prefix)/share/zsh"
- name: Install dependencies
run: |
which brew
brew install \
pkg-config \
opus \
@@ -93,12 +62,12 @@ jobs:
name: Check Licenses
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@v2
with:
go-version: '1.19'
go-version: '1.16'
- name: Installing go-licenses
run: go install github.com/google/go-licenses@latest
run: go get github.com/google/go-licenses
- name: Checking licenses
run: go-licenses check ./...

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
fetch-depth: 2
- name: fix

2
.gitignore vendored
View File

@@ -13,5 +13,3 @@
scripts/cross
coverage.txt
.idea

10
.idea/mediadevices.iml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mediadevices.iml" filepath="$PROJECT_DIR$/.idea/mediadevices.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

63
.idea/workspace.xml generated Normal file
View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="8804a8cb-7b92-421b-8786-b7715667b867" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.idea/mediadevices.iml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="GOROOT" url="file:///usr/local/opt/go/libexec" />
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="GoLibraries">
<option name="indexEntireGoPath" value="false" />
</component>
<component name="KubernetesApiPersistence">
<option name="context" value="crane-nts-0" />
<option name="namespace" value="default" />
</component>
<component name="ProjectId" id="25msmAX4e3Virjg5KBrchpLrlbl" />
<component name="ProjectViewState">
<option name="autoscrollFromSource" value="true" />
<option name="autoscrollToSource" value="true" />
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="go.formatter.settings.were.checked" value="true" />
<property name="go.import.settings.migrated" value="true" />
<property name="go.sdk.automatically.set" value="true" />
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="8804a8cb-7b92-421b-8786-b7715667b867" name="Changes" comment="" />
<created>1646143753802</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1646143753802</updated>
<workItem from="1646143757180" duration="56000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VgoProject">
<integration-enabled>true</integration-enabled>
</component>
</project>

View File

@@ -16,8 +16,7 @@ supported_platforms := \
linux-arm64 \
linux-x64 \
windows-x64 \
darwin-x64 \
darwin-arm64
darwin-x64
cmd_build := build
cmd_test := test
examples_dir := examples
@@ -25,7 +24,7 @@ codec_dir := pkg/codec
codec_list := $(shell ls $(codec_dir)/*/Makefile)
codec_list := $(codec_list:$(codec_dir)/%/Makefile=%)
targets := $(foreach codec, $(codec_list), $(addprefix $(cmd_build)-$(codec)-, $(supported_platforms)))
pkgs_without_ext_device := $(shell go list ./... | grep -v mmal | grep -v vaapi)
pkgs_without_mmal := $(shell go list ./... | grep -v mmal)
pkgs_without_cgo := $(shell go list ./... | grep -v pkg/codec | grep -v pkg/driver | grep -v pkg/avfoundation)
define BUILD_TEMPLATE
@@ -73,11 +72,11 @@ $(foreach codec, $(codec_list), \
# Description:
# Run a series of tests
$(cmd_test):
go vet $(pkgs_without_ext_device)
go build $(pkgs_without_ext_device)
go vet $(pkgs_without_mmal)
go build $(pkgs_without_mmal)
# go build without CGO
CGO_ENABLED=0 go build $(pkgs_without_cgo)
# go build with CGO
CGO_ENABLED=1 go build $(pkgs_without_ext_device)
CGO_ENABLED=1 go build $(pkgs_without_mmal)
$(MAKE) --directory=$(examples_dir)
go test -v -race -coverprofile=coverage.txt -covermode=atomic $(pkgs_without_ext_device)
go test -v -race -coverprofile=coverage.txt -covermode=atomic $(pkgs_without_mmal)

View File

@@ -1,47 +0,0 @@
FROM dockercore/golang-cross as m1cross
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qq && apt-get install -y -q --no-install-recommends \
cmake \
git \
libssl-dev \
libxml2-dev \
libz-dev \
&& rm -rf /var/lib/apt/lists/*
ENV SDK_VERSION=11.3 \
TARGET_DIR=/osxcross/target \
UNATTENDED=1
WORKDIR /work
RUN git clone --depth=1 https://github.com/tpoechtrager/osxcross.git /work \
&& cd /work/tarballs \
&& wget -q https://github.com/phracker/MacOSX-SDKs/releases/download/${SDK_VERSION}/MacOSX${SDK_VERSION}.sdk.tar.xz
# Build cross compile toolchain for Apple silicon
RUN ./build.sh
FROM dockcross/base
ENV OSX_CROSS_PATH=/osxcross
COPY --from=m1cross "${OSX_CROSS_PATH}/." "${OSX_CROSS_PATH}/"
ENV PATH=${OSX_CROSS_PATH}/target/bin:$PATH
COPY init.sh /tmp/init.sh
RUN bash /tmp/init.sh
ENV CC=arm64-apple-darwin20.4-clang \
CXX=arm64-apple-darwin20.4-clang++ \
CPP=arm64-apple-darwin20.4-clang++ \
AR=arm64-apple-darwin20.4-ar \
AS=arm64-apple-darwin20.4-as \
LD=arm64-apple-darwin20.4-ld
COPY darwin-arm64.cmake ${OSX_CROSS_PATH}/
ENV CMAKE_TOOLCHAIN_FILE ${OSX_CROSS_PATH}/darwin-arm64.cmake
ARG IMAGE=lherman/cross-darwin-arm64
ARG VERSION=latest
ENV DEFAULT_DOCKCROSS_IMAGE ${IMAGE}:${VERSION}

View File

@@ -1,8 +0,0 @@
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR arm64)
set(CMAKE_C_COMPILER $ENV{CC})
set(CMAKE_CXX_COMPILER $ENV{CXX})
set(CMAKE_AR $ENV{AR})
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})

View File

@@ -3,9 +3,9 @@ module github.com/pion/mediadevices/examples
go 1.14
require (
github.com/esimov/pigo v1.4.6
github.com/esimov/pigo v1.4.3
github.com/pion/mediadevices v0.0.0
github.com/pion/webrtc/v3 v3.1.48
github.com/pion/webrtc/v3 v3.0.20
)
replace github.com/pion/mediadevices v0.0.0 => ../

View File

@@ -1,16 +1,17 @@
github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165 h1:QsIbRyO2tn5eSJZ/skuDqSTo0GWI5H4G1AT7Mm2H0Nw=
github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165/go.mod h1:G0X+rEqYPWSq0dG8OMf8M446MtKytzpPjgS3HbdOJZ4=
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539 h1:1aIqYfg9s9RETAJHGfVKZW4ok0b22p4QTwk8MsdRtPs=
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539/go.mod h1:G0X+rEqYPWSq0dG8OMf8M446MtKytzpPjgS3HbdOJZ4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/esimov/pigo v1.4.6 h1:wpB9FstbqeGP/CZP+nTR52tUJe7XErq8buG+k4xCXlw=
github.com/esimov/pigo v1.4.6/go.mod h1:uqj9Y3+3IRYhFK071rxz1QYq0ePhA6+R9jrUZavi46M=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/disintegration/imaging v1.6.1/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ=
github.com/esimov/pigo v1.4.3 h1:xl098Z9CHmouywvyRZepuKx8aSWHBs/0lZtp7Yt5g28=
github.com/esimov/pigo v1.4.3/go.mod h1:aOTYpOWsqniACzXKdSOGkqI6CnWQpP8tFjgtUOARoEs=
github.com/fogleman/gg v1.0.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gen2brain/malgo v0.11.10 h1:u41QchDBS7Z2rwEVPu7uycK6HA8IyzKoUOhLU7IvYW4=
github.com/gen2brain/malgo v0.11.10/go.mod h1:f9TtuN7DVrXMiV/yIceMeWpvanyVzJQMlBecJFVMxww=
github.com/gen2brain/malgo v0.10.29 h1:bTYiUTUKJsEomNby+W0hgyLrOttUXIk4lTEnKA54iqM=
github.com/gen2brain/malgo v0.10.29/go.mod h1:zHSUNZAXfCeNsZou0RtQ6Zk7gDYLIcKOrUWtAdksnEs=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
@@ -21,17 +22,14 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240/go.mod h1:3P4UH/k22rXyHIJD2w4h2XMqPX4Of/eySEZq9L6wqc4=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4=
github.com/kbinani/screenshot v0.0.0-20210326165202-b96eb3309bb0/go.mod h1:ZceVWGtzUZmxyN+/1I+oG31oOm1dOA2QUNbua9TLVdE=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -43,96 +41,83 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c=
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
github.com/pion/ice/v2 v2.2.11 h1:wiAy7TSrVZ4KdyjC0CcNTkwltz9ywetbe4wbHLKUbIg=
github.com/pion/ice/v2 v2.2.11/go.mod h1:NqUDUao6SjSs1+4jrqpexDmFlptlVhGxQjcymXLaVvE=
github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8=
github.com/pion/interceptor v0.1.12 h1:CslaNriCFUItiXS5o+hh5lpL0t0ytQkFnUcbbCs2Zq8=
github.com/pion/interceptor v0.1.12/go.mod h1:bDtgAD9dRkBZpWHGKaoKb42FhDHTG2rX8Ii9LRALLVA=
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
github.com/pion/dtls/v2 v2.0.9 h1:7Ow+V++YSZQMYzggI0P9vLJz/hUFcffsfGMfT/Qy+u8=
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
github.com/pion/ice/v2 v2.1.7 h1:FjgDfUNrVYTxQabJrkBX6ld12tvYbgzHenqPh3PJF6E=
github.com/pion/ice/v2 v2.1.7/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0=
github.com/pion/interceptor v0.0.12 h1:eC1iVneBIAQJEfaNAfDqAncJWhMDAnaXPRCJsltdokE=
github.com/pion/interceptor v0.0.12/go.mod h1:qzeuWuD/ZXvPqOnxNcnhWfkCZ2e1kwwslicyyPnhoK4=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.3 h1:LWcciN2ptLkw9Ugp/Ks2E76fiWy7yk3Wm79D6oFbFNo=
github.com/pion/sctp v1.8.3/go.mod h1:OHbDjdk7kg+L+7TJim9q/qGVefdEJohuA2SZyihccgI=
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
github.com/pion/srtp/v2 v2.0.10 h1:b8ZvEuI+mrL8hbr/f1YiJFB34UMrOac3R3N1yq2UN0w=
github.com/pion/srtp/v2 v2.0.10/go.mod h1:XEeSWaK9PfuMs7zxXyiN252AHPbH12NX5q/CFDWtUuA=
github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U=
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.6.5 h1:o2cZf8OascA5HF/b0PAbTxRKvOWxTQxWYt7SlToxFGI=
github.com/pion/rtp v1.6.5/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
github.com/pion/sctp v1.7.12 h1:GsatLufywVruXbZZT1CKg+Jr8ZTkwiPnmUC/oO9+uuY=
github.com/pion/sctp v1.7.12/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/srtp/v2 v2.0.2 h1:664iGzVmaY7KYS5M0gleY0DscRo9ReDfTxQrq4UgGoU=
github.com/pion/srtp/v2 v2.0.2/go.mod h1:VEyLv4CuxrwGY8cxM+Ng3bmVy8ckz/1t6A0q/msKOw0=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.3 h1:vdBfvfU/0Wq8kd2yhUMSDB/x+O4Z9MYVl2fJ5BT4JZw=
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA=
github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg=
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.48 h1:lRAdRAewrcQTlj2n7pDUbJcuiQpHwwMq61edwhTkVq4=
github.com/pion/webrtc/v3 v3.1.48/go.mod h1:JOk9h4pOtogTAWM1SCoEG2opDQmEOR0QZcbEo9vy0Xc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210420210106-798c2154c571 h1:Q6Bg8xzKzpFPU4Oi1sBnBTHBwlMsLeEXpu4hYBY8rAg=
golang.org/x/net v0.0.0-20210420210106-798c2154c571/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -143,35 +128,23 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe h1:WdX7u8s3yOigWAhHEaDl8r9G+4XwFQEQFtBMYyN+kXQ=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -179,8 +152,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

View File

@@ -1 +0,0 @@
vnc

15
go.mod
View File

@@ -2,16 +2,17 @@ module github.com/pion/mediadevices
go 1.13
replace github.com/pion/webrtc/v3 => github.com/EmrysMyrddin/webrtc/v3 v3.1.25-0.20220301142221-d92d68ff068f
require (
github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165
github.com/gen2brain/malgo v0.11.10
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539
github.com/gen2brain/malgo v0.10.35
github.com/google/uuid v1.3.0
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329
github.com/pion/interceptor v0.1.12
github.com/pion/logging v0.2.2
github.com/pion/rtcp v1.2.10
github.com/pion/rtp v1.7.13
github.com/pion/webrtc/v3 v3.1.48
golang.org/x/image v0.1.0
github.com/pion/rtcp v1.2.9
github.com/pion/rtp v1.7.4
github.com/pion/webrtc/v3 v3.1.10
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)

87
go.sum
View File

@@ -1,12 +1,14 @@
github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165 h1:QsIbRyO2tn5eSJZ/skuDqSTo0GWI5H4G1AT7Mm2H0Nw=
github.com/blackjack/webcam v0.0.0-20220329180758-ba064708e165/go.mod h1:G0X+rEqYPWSq0dG8OMf8M446MtKytzpPjgS3HbdOJZ4=
github.com/EmrysMyrddin/webrtc/v3 v3.1.25-0.20220301142221-d92d68ff068f h1:o7MCxR85nZxyOgjkmjtnXHsmPmchX3AEbWb/Bgpy3aI=
github.com/EmrysMyrddin/webrtc/v3 v3.1.25-0.20220301142221-d92d68ff068f/go.mod h1:mO/yv7fBN3Lp7YNlnYcTj1jtpvNvssJG+7eh6itZ4xM=
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539 h1:1aIqYfg9s9RETAJHGfVKZW4ok0b22p4QTwk8MsdRtPs=
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539/go.mod h1:G0X+rEqYPWSq0dG8OMf8M446MtKytzpPjgS3HbdOJZ4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gen2brain/malgo v0.11.10 h1:u41QchDBS7Z2rwEVPu7uycK6HA8IyzKoUOhLU7IvYW4=
github.com/gen2brain/malgo v0.11.10/go.mod h1:f9TtuN7DVrXMiV/yIceMeWpvanyVzJQMlBecJFVMxww=
github.com/gen2brain/malgo v0.10.35 h1:D6aNo/Q0SnzQLHomTydTXxj4AJFdGJcVoE7I8JxPoUo=
github.com/gen2brain/malgo v0.10.35/go.mod h1:zHSUNZAXfCeNsZou0RtQ6Zk7gDYLIcKOrUWtAdksnEs=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@@ -49,66 +51,59 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c=
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
github.com/pion/ice/v2 v2.2.11 h1:wiAy7TSrVZ4KdyjC0CcNTkwltz9ywetbe4wbHLKUbIg=
github.com/pion/ice/v2 v2.2.11/go.mod h1:NqUDUao6SjSs1+4jrqpexDmFlptlVhGxQjcymXLaVvE=
github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8=
github.com/pion/interceptor v0.1.12 h1:CslaNriCFUItiXS5o+hh5lpL0t0ytQkFnUcbbCs2Zq8=
github.com/pion/interceptor v0.1.12/go.mod h1:bDtgAD9dRkBZpWHGKaoKb42FhDHTG2rX8Ii9LRALLVA=
github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
github.com/pion/dtls/v2 v2.1.3 h1:3UF7udADqous+M2R5Uo2q/YaP4EzUoWKdfX2oscCUio=
github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
github.com/pion/ice/v2 v2.2.1 h1:R3MeuJZpU1ty3diPqpD5OxaxcZ15eprAc+EtUiSoFxg=
github.com/pion/ice/v2 v2.2.1/go.mod h1:Op8jlPtjeiycsXh93Cs4jK82C9j/kh7vef6ztIOvtIQ=
github.com/pion/interceptor v0.1.7 h1:HThW0tIIKT9RRoDWGURe8rlZVOx0fJHxBHpA0ej0+bo=
github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sctp v1.8.3 h1:LWcciN2ptLkw9Ugp/Ks2E76fiWy7yk3Wm79D6oFbFNo=
github.com/pion/sctp v1.8.3/go.mod h1:OHbDjdk7kg+L+7TJim9q/qGVefdEJohuA2SZyihccgI=
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
github.com/pion/srtp/v2 v2.0.10 h1:b8ZvEuI+mrL8hbr/f1YiJFB34UMrOac3R3N1yq2UN0w=
github.com/pion/srtp/v2 v2.0.10/go.mod h1:XEeSWaK9PfuMs7zxXyiN252AHPbH12NX5q/CFDWtUuA=
github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA=
github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA=
github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg=
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pion/webrtc/v3 v3.1.48 h1:lRAdRAewrcQTlj2n7pDUbJcuiQpHwwMq61edwhTkVq4=
github.com/pion/webrtc/v3 v3.1.48/go.mod h1:JOk9h4pOtogTAWM1SCoEG2opDQmEOR0QZcbEo9vy0Xc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -116,20 +111,14 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -143,29 +132,21 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=

View File

@@ -8,7 +8,6 @@ import (
"github.com/pion/mediadevices/pkg/driver"
_ "github.com/pion/mediadevices/pkg/driver/audiotest"
_ "github.com/pion/mediadevices/pkg/driver/videotest"
"github.com/pion/mediadevices/pkg/frame"
"github.com/pion/mediadevices/pkg/prop"
)
@@ -98,145 +97,37 @@ func TestSelectBestDriverConstraintsResultIsSetProperly(t *testing.T) {
t.Fatal("expect to get at least 1 property")
}
expectedProp := driver.Properties()[0]
// Since this is a continuous value, bestConstraints should be set with the value that user specified
expectedProp.FrameRate = 30.0
// By reducing the value from the driver by a tiny amount, this property should be chosen.
// At the same time, we'll be able to find out if the return constraints will be properly set
// to the best constraints.
cases := map[string]struct {
width, height int
frameFormat frame.Format
frameRate float32
}{
"DifferentWidth": {
width: expectedProp.Width - 1,
height: expectedProp.Height,
frameFormat: expectedProp.FrameFormat,
frameRate: expectedProp.FrameRate,
},
"DifferentHeight": {
width: expectedProp.Width,
height: expectedProp.Height - 1,
frameFormat: expectedProp.FrameFormat,
frameRate: expectedProp.FrameRate,
},
"DifferentFrameFormat": {
width: expectedProp.Width,
height: expectedProp.Height,
frameFormat: frame.FormatI420,
frameRate: expectedProp.FrameRate,
wantConstraints := MediaTrackConstraints{
MediaConstraints: prop.MediaConstraints{
VideoConstraints: prop.VideoConstraints{
// By reducing the width from the driver by a tiny amount, this property should be chosen.
// At the same time, we'll be able to find out if the return constraints will be properly set
// to the best constraints.
Width: prop.Int(expectedProp.Width - 1),
Height: prop.Int(expectedProp.Width),
FrameFormat: prop.FrameFormat(expectedProp.FrameFormat),
FrameRate: prop.Float(30.0),
},
},
}
for name, c := range cases {
c := c
t.Run(name, func(t *testing.T) {
var vc prop.VideoConstraints
if c.frameRate >= 0 {
vc = prop.VideoConstraints{
Width: prop.Int(c.width),
Height: prop.Int(c.height),
FrameFormat: prop.FrameFormat(c.frameFormat),
FrameRate: prop.Float(c.frameRate),
}
} else {
// do not specify the framerate
vc = prop.VideoConstraints{
Width: prop.Int(c.width),
Height: prop.Int(c.height),
FrameFormat: prop.FrameFormat(c.frameFormat),
}
}
wantConstraints := MediaTrackConstraints{
MediaConstraints: prop.MediaConstraints{
VideoConstraints: vc,
},
}
bestDriver, bestConstraints, err := selectBestDriver(filterFn, wantConstraints)
if err != nil {
t.Fatal(err)
}
if driver != bestDriver {
t.Fatal("best driver is not expected")
}
s := bestConstraints.selectedMedia
if s.Width != expectedProp.Width ||
s.Height != expectedProp.Height ||
s.FrameFormat != expectedProp.FrameFormat ||
s.FrameRate != expectedProp.FrameRate {
t.Fatalf("failed to return best constraints\nexpected:\n%v\n\ngot:\n%v", expectedProp, bestConstraints.selectedMedia)
}
})
}
}
func TestSelectBestDriverConstraintsNoFit(t *testing.T) {
filterFn := driver.FilterVideoRecorder()
drivers := driver.GetManager().Query(filterFn)
if len(drivers) == 0 {
t.Fatal("expect to get at least 1 driver")
}
driver := drivers[0]
err := driver.Open()
bestDriver, bestConstraints, err := selectBestDriver(filterFn, wantConstraints)
if err != nil {
t.Fatal("expect to open driver successfully")
}
defer driver.Close()
if len(driver.Properties()) == 0 {
t.Fatal("expect to get at least 1 property")
}
expectedProp := driver.Properties()[0]
cases := map[string]struct {
width, height int
frameFormat frame.Format
frameRate float32
}{
"DifferentWidth": {
width: expectedProp.Width - 1,
height: expectedProp.Height,
frameFormat: expectedProp.FrameFormat,
frameRate: expectedProp.FrameRate,
},
"DifferentHeight": {
width: expectedProp.Width,
height: expectedProp.Height - 1,
frameFormat: expectedProp.FrameFormat,
frameRate: expectedProp.FrameRate,
},
"DifferentFrameFormat": {
width: expectedProp.Width,
height: expectedProp.Height,
frameFormat: frame.FormatI420,
frameRate: expectedProp.FrameRate,
},
t.Fatal(err)
}
for name, c := range cases {
c := c
t.Run(name, func(t *testing.T) {
wantConstraints := MediaTrackConstraints{
MediaConstraints: prop.MediaConstraints{
VideoConstraints: prop.VideoConstraints{
Width: prop.IntExact(c.width),
Height: prop.IntExact(c.height),
FrameFormat: prop.FrameFormatExact(c.frameFormat),
FrameRate: prop.FloatExact(c.frameRate),
},
},
}
if driver != bestDriver {
t.Fatal("best driver is not expected")
}
_, _, err := selectBestDriver(filterFn, wantConstraints)
if err == nil {
t.Fatal("expect to not find a driver that fits the constraints")
}
})
s := bestConstraints.selectedMedia
if s.Width != expectedProp.Width ||
s.Height != expectedProp.Height ||
s.FrameFormat != expectedProp.FrameFormat ||
s.FrameRate != expectedProp.FrameRate {
t.Fatalf("failed to return best constraints\nexpected:\n%v\n\ngot:\n%v", expectedProp, bestConstraints.selectedMedia)
}
}

View File

@@ -11,10 +11,8 @@ package avfoundation
// }
import "C"
import (
"context"
"fmt"
"io"
"sync"
"unsafe"
"github.com/pion/mediadevices/pkg/frame"
@@ -95,13 +93,9 @@ func Devices(mediaType MediaType) ([]Device, error) {
// ReadCloser is a wrapper around the data callback from AVFoundation. The data received from the
// the underlying callback can be retrieved by calling Read.
type ReadCloser struct {
dataChan chan []byte
id handleID
onClose func()
cancelCtx context.Context
cancelFunc func()
closeWG sync.WaitGroup
lock sync.Mutex
dataChan chan []byte
id handleID
onClose func()
}
func newReadCloser(onClose func()) *ReadCloser {
@@ -109,25 +103,12 @@ func newReadCloser(onClose func()) *ReadCloser {
rc.dataChan = make(chan []byte, 1)
rc.onClose = onClose
rc.id = register(rc.dataCb)
cancelCtx, cancelFunc := context.WithCancel(context.Background())
rc.cancelCtx = cancelCtx
rc.cancelFunc = cancelFunc
return &rc
}
func (rc *ReadCloser) dataCb(data []byte) {
rc.closeWG.Add(1)
defer rc.closeWG.Done()
// TODO: add a policy for slow reader
if rc.cancelCtx.Err() != nil {
return
}
select {
// Use the Done channel to avoid waiting for new data from closed camera
case <-rc.cancelCtx.Done():
case rc.dataChan <- data:
}
rc.dataChan <- data
}
// Read reads raw data, the format is determined by the media type and property:
@@ -143,28 +124,17 @@ func (rc *ReadCloser) Read() ([]byte, func(), error) {
// Close closes the capturing session, and no data will flow anymore
func (rc *ReadCloser) Close() {
rc.lock.Lock()
defer rc.lock.Unlock()
if rc.cancelCtx.Err() != nil {
return // already closed
}
if rc.onClose != nil {
rc.onClose()
}
rc.cancelFunc()
unregister(rc.id)
rc.closeWG.Wait()
close(rc.dataChan)
unregister(rc.id)
}
// Session represents a capturing session.
type Session struct {
device Device
cSession C.PAVBindSession
lock sync.Mutex
closed bool
}
// NewSession creates a new capturing session
@@ -182,13 +152,6 @@ func NewSession(device Device) (*Session, error) {
// Close stops capturing session and frees up resources
func (session *Session) Close() error {
session.lock.Lock()
defer session.lock.Unlock()
if session.closed {
return nil
}
session.closed = true
if session.cSession == nil {
return nil
}

View File

@@ -119,41 +119,3 @@ func VideoEncoderCloseTwiceTest(t *testing.T, c codec.VideoEncoderBuilder, p pro
t.Fatal(err)
}
}
func AudioEncoderReadAfterCloseTest(t *testing.T, c codec.AudioEncoderBuilder, p prop.Media, w wave.Audio) {
enc, err := c.BuildAudioEncoder(audio.ReaderFunc(func() (wave.Audio, func(), error) {
return w, nil, nil
}), p)
if err != nil {
t.Fatal(err)
}
if err := assertNoPanic(t, enc.Close, "on Close()"); err != nil {
t.Fatal(err)
}
if err := assertNoPanic(t, func() error {
_, _, err := enc.Read()
return err
}, "on Read()"); err != io.EOF {
t.Fatalf("Expected: %v, got: %v", io.EOF, err)
}
}
func VideoEncoderReadAfterCloseTest(t *testing.T, c codec.VideoEncoderBuilder, p prop.Media, img image.Image) {
enc, err := c.BuildVideoEncoder(video.ReaderFunc(func() (image.Image, func(), error) {
return img, nil, nil
}), p)
if err != nil {
t.Fatal(err)
}
if err := assertNoPanic(t, enc.Close, "on Close()"); err != nil {
t.Fatal(err)
}
if err := assertNoPanic(t, func() error {
_, _, err := enc.Read()
return err
}, "on Read()"); err != io.EOF {
t.Fatalf("Expected: %v, got: %v", io.EOF, err)
}
}

View File

@@ -44,25 +44,6 @@ func TestEncoder(t *testing.T) {
},
})
})
t.Run("ReadAfterClose", func(t *testing.T) {
p, err := NewParams()
if err != nil {
t.Fatal(err)
}
codectest.VideoEncoderReadAfterCloseTest(t, &p,
prop.Media{
Video: prop.Video{
Width: 256,
Height: 144,
FrameFormat: frame.FormatI420,
},
},
image.NewYCbCr(
image.Rect(0, 0, 256, 144),
image.YCbCrSubsampleRatio420,
),
)
})
}
func TestShouldImplementBitRateControl(t *testing.T) {

View File

@@ -21,26 +21,29 @@ Encoder *enc_new(const EncoderOptions opts, int *eresult) {
return NULL;
}
params.iUsageType = opts.usage_type;
// TODO: Remove hardcoded values
params.iUsageType = CAMERA_VIDEO_REAL_TIME;
params.iPicWidth = opts.width;
params.iPicHeight = opts.height;
params.iTargetBitrate = opts.target_bitrate;
params.iMaxBitrate = opts.target_bitrate;
params.iRCMode = opts.rc_mode;
params.iRCMode = RC_BITRATE_MODE;
params.fMaxFrameRate = opts.max_fps;
params.bEnableFrameSkip = opts.enable_frame_skip;
params.uiMaxNalSize = opts.max_nal_size;
params.uiIntraPeriod = opts.intra_period;
params.iMultipleThreadIdc = opts.multiple_thread_idc;
params.bEnableFrameSkip = true;
params.uiMaxNalSize = 0;
params.uiIntraPeriod = 30;
// set to 0, so that it'll automatically use multi threads when needed
params.iMultipleThreadIdc = 0;
// The base spatial layer 0 is the only one we use.
params.sSpatialLayers[0].iVideoWidth = params.iPicWidth;
params.sSpatialLayers[0].iVideoHeight = params.iPicHeight;
params.sSpatialLayers[0].fFrameRate = params.fMaxFrameRate;
params.sSpatialLayers[0].iSpatialBitrate = params.iTargetBitrate;
params.sSpatialLayers[0].iMaxSpatialBitrate = params.iTargetBitrate;
params.sSpatialLayers[0].sSliceArgument.uiSliceNum = opts.slice_num;
params.sSpatialLayers[0].sSliceArgument.uiSliceMode = opts.slice_mode;
params.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = opts.slice_size_constraint;
// Single NAL unit mode
params.sSpatialLayers[0].sSliceArgument.uiSliceNum = 1;
params.sSpatialLayers[0].sSliceArgument.uiSliceMode = SM_SIZELIMITED_SLICE;
params.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = 12800;
rv = engine->InitializeExt(&params);
if (rv != 0) {
@@ -78,15 +81,16 @@ Slice enc_encode(Encoder *e, Frame f, int *eresult) {
Slice payload = {0};
if(e->force_key_frame == 1) {
e->engine->ForceIntraFrame(true);
info.eFrameType = videoFrameTypeI;
e->force_key_frame = 0;
}
pic.iPicWidth = f.width;
pic.iPicHeight = f.height;
pic.iColorFormat = videoFormatI420;
pic.iStride[0] = f.ystride;
pic.iStride[1] = pic.iStride[2] = f.cstride;
// We always received I420 format
pic.iStride[0] = pic.iPicWidth;
pic.iStride[1] = pic.iStride[2] = pic.iPicWidth / 2;
pic.pData[0] = (unsigned char *)f.y;
pic.pData[1] = (unsigned char *)f.u;
pic.pData[2] = (unsigned char *)f.v;

View File

@@ -12,8 +12,6 @@ typedef struct Slice {
typedef struct Frame {
void *y, *u, *v;
int ystride;
int cstride;
int height;
int width;
} Frame;
@@ -22,15 +20,6 @@ typedef struct EncoderOptions {
int width, height;
int target_bitrate;
float max_fps;
EUsageType usage_type;
RC_MODES rc_mode;
bool enable_frame_skip;
unsigned int max_nal_size;
unsigned int intra_period;
int multiple_thread_idc;
unsigned int slice_num;
SliceModeEnum slice_mode;
unsigned int slice_size_constraint;
} EncoderOptions;
typedef struct Encoder {

View File

@@ -33,19 +33,10 @@ func newEncoder(r video.Reader, p prop.Media, params Params) (codec.ReadCloser,
var rv C.int
cEncoder := C.enc_new(C.EncoderOptions{
width: C.int(p.Width),
height: C.int(p.Height),
target_bitrate: C.int(params.BitRate),
max_fps: C.float(p.FrameRate),
usage_type: C.EUsageType(params.UsageType),
rc_mode: C.RC_MODES(params.RCMode),
enable_frame_skip: C.bool(params.EnableFrameSkip),
max_nal_size: C.uint(params.MaxNalSize),
intra_period: C.uint(params.IntraPeriod),
multiple_thread_idc: C.int(params.MultipleThreadIdc),
slice_num: C.uint(params.SliceNum),
slice_mode: C.SliceModeEnum(params.SliceMode),
slice_size_constraint: C.uint(params.SliceSizeConstraint),
width: C.int(p.Width),
height: C.int(p.Height),
target_bitrate: C.int(params.BitRate),
max_fps: C.float(p.FrameRate),
}, &rv)
if err := errResult(rv); err != nil {
return nil, fmt.Errorf("failed in creating encoder: %v", err)
@@ -74,13 +65,11 @@ func (e *encoder) Read() ([]byte, func(), error) {
bounds := yuvImg.Bounds()
var rv C.int
s := C.enc_encode(e.engine, C.Frame{
y: unsafe.Pointer(&yuvImg.Y[0]),
u: unsafe.Pointer(&yuvImg.Cb[0]),
v: unsafe.Pointer(&yuvImg.Cr[0]),
ystride: C.int(yuvImg.YStride),
cstride: C.int(yuvImg.CStride),
height: C.int(bounds.Max.Y - bounds.Min.Y),
width: C.int(bounds.Max.X - bounds.Min.X),
y: unsafe.Pointer(&yuvImg.Y[0]),
u: unsafe.Pointer(&yuvImg.Cb[0]),
v: unsafe.Pointer(&yuvImg.Cr[0]),
height: C.int(bounds.Max.Y - bounds.Min.Y),
width: C.int(bounds.Max.X - bounds.Min.X),
}, &rv)
if err := errResult(rv); err != nil {
return nil, func() {}, fmt.Errorf("failed in encoding: %v", err)

View File

@@ -8,6 +8,5 @@ package openh264
//#cgo linux,arm64 LDFLAGS: ${SRCDIR}/lib/libopenh264-linux-arm64.a
//#cgo linux,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264-linux-x64.a
//#cgo darwin,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264-darwin-x64.a
//#cgo darwin,arm64 LDFLAGS: ${SRCDIR}/lib/libopenh264-darwin-arm64.a
//#cgo windows,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264-windows-x64.a -lssp
import "C"

View File

@@ -60,23 +60,4 @@ func TestEncoder(t *testing.T) {
},
})
})
t.Run("ReadAfterClose", func(t *testing.T) {
p, err := NewParams()
if err != nil {
t.Fatal(err)
}
codectest.VideoEncoderReadAfterCloseTest(t, &p,
prop.Media{
Video: prop.Video{
Width: 256,
Height: 144,
FrameFormat: frame.FormatI420,
},
},
image.NewYCbCr(
image.Rect(0, 0, 256, 144),
image.YCbCrSubsampleRatio420,
),
)
})
}

View File

@@ -1,8 +1,5 @@
package openh264
// #include <openh264/codec_api.h>
import "C"
import (
"github.com/pion/mediadevices/pkg/codec"
"github.com/pion/mediadevices/pkg/io/video"
@@ -12,62 +9,14 @@ import (
// Params stores libopenh264 specific encoding parameters.
type Params struct {
codec.BaseParams
UsageType UsageTypeEnum
RCMode RCModeEnum
EnableFrameSkip bool
MaxNalSize uint
IntraPeriod uint
MultipleThreadIdc int
SliceNum uint
SliceMode SliceModeEnum
SliceSizeConstraint uint
}
type UsageTypeEnum int
const (
CameraVideoRealTime UsageTypeEnum = C.CAMERA_VIDEO_REAL_TIME ///< camera video for real-time communication
ScreenContentRealTime UsageTypeEnum = C.SCREEN_CONTENT_REAL_TIME ///< screen content signal
CameraVideoNonRealTime UsageTypeEnum = C.CAMERA_VIDEO_NON_REAL_TIME
ScreenContentNonRealTime UsageTypeEnum = C.SCREEN_CONTENT_NON_REAL_TIME
InputContentTypeAll UsageTypeEnum = C.INPUT_CONTENT_TYPE_ALL
)
type RCModeEnum int
const (
RCQualityMode RCModeEnum = C.RC_QUALITY_MODE ///< quality mode
RCBitrateMode RCModeEnum = C.RC_BITRATE_MODE ///< bitrate mode
RCBufferbaseedMode RCModeEnum = C.RC_BUFFERBASED_MODE ///< no bitrate control,only using buffer status,adjust the video quality
RCTimestampMode RCModeEnum = C.RC_TIMESTAMP_MODE //rate control based timestamp
RCBitrateModePostSkip RCModeEnum = C.RC_BITRATE_MODE_POST_SKIP ///< this is in-building RC MODE, WILL BE DELETED after algorithm tuning!
RCOffMode RCModeEnum = C.RC_OFF_MODE ///< rate control off mode
)
type SliceModeEnum uint
const (
SMSingleSlice SliceModeEnum = C.SM_SINGLE_SLICE ///< | SliceNum==1
SMFixedslcnumSlice SliceModeEnum = C.SM_FIXEDSLCNUM_SLICE ///< | according to SliceNum | enabled dynamic slicing for multi-thread
SMRasterSlice SliceModeEnum = C.SM_RASTER_SLICE ///< | according to SlicesAssign | need input of MB numbers each slice. In addition, if other constraint in SSliceArgument is presented, need to follow the constraints. Typically if MB num and slice size are both constrained, re-encoding may be involved.
SMSizelimitedSlice SliceModeEnum = C.SM_SIZELIMITED_SLICE ///< | according to SliceSize | slicing according to size, the slicing will be dynamic(have no idea about slice_nums until encoding current frame)
)
// NewParams returns default openh264 codec specific parameters.
func NewParams() (Params, error) {
return Params{
BaseParams: codec.BaseParams{
BitRate: 100000,
},
UsageType: CameraVideoRealTime,
RCMode: RCBitrateMode,
EnableFrameSkip: true,
MaxNalSize: 0,
IntraPeriod: 30,
MultipleThreadIdc: 0, // Defaults to 0, so that it'll automatically use multi threads when needed
SliceNum: 1, // Defaults to single NAL unit mode
SliceMode: SMSizelimitedSlice,
SliceSizeConstraint: 12800,
}, nil
}

View File

@@ -3,8 +3,6 @@ package opus
import (
"errors"
"fmt"
"io"
"sync"
"github.com/pion/mediadevices/pkg/codec"
"github.com/pion/mediadevices/pkg/io/audio"
@@ -16,7 +14,7 @@ import (
/*
#include <opus.h>
int pion_set_encoder_bitrate(OpusEncoder *e, opus_int32 bitrate)
int bridge_encoder_set_bitrate(OpusEncoder *e, opus_int32 bitrate)
{
return opus_encoder_ctl(e, OPUS_SET_BITRATE(bitrate));
}
@@ -27,8 +25,6 @@ type encoder struct {
inBuff wave.Audio
reader audio.Reader
engine *C.OpusEncoder
mu sync.Mutex
}
func newEncoder(r audio.Reader, p prop.Media, params Params) (codec.ReadCloser, error) {
@@ -83,12 +79,6 @@ func (e *encoder) Read() ([]byte, func(), error) {
return nil, func() {}, err
}
e.mu.Lock()
defer e.mu.Unlock()
if e.engine == nil {
return nil, nil, io.EOF
}
encoded := make([]byte, 1024)
var n C.opus_int32
switch b := buff.(type) {
@@ -120,7 +110,7 @@ func (e *encoder) Read() ([]byte, func(), error) {
}
func (e *encoder) SetBitRate(bitRate int) error {
cerror := C.pion_set_encoder_bitrate(
cerror := C.bridge_encoder_set_bitrate(
e.engine,
C.int(bitRate),
)
@@ -136,8 +126,6 @@ func (e *encoder) Controller() codec.EncoderController {
}
func (e *encoder) Close() error {
e.mu.Lock()
defer e.mu.Unlock()
if e.engine == nil {
return nil
}

View File

@@ -8,6 +8,5 @@ package opus
//#cgo linux,arm64 LDFLAGS: ${SRCDIR}/lib/libopus-linux-arm64.a -lm
//#cgo linux,amd64 LDFLAGS: ${SRCDIR}/lib/libopus-linux-x64.a -lm
//#cgo darwin,amd64 LDFLAGS: ${SRCDIR}/lib/libopus-darwin-x64.a
//#cgo darwin,arm64 LDFLAGS: ${SRCDIR}/lib/libopus-darwin-arm64.a
//#cgo windows,amd64 LDFLAGS: ${SRCDIR}/lib/libopus-windows-x64.a
import "C"

View File

@@ -57,23 +57,4 @@ func TestEncoder(t *testing.T) {
},
})
})
t.Run("ReadAfterClose", func(t *testing.T) {
p, err := NewParams()
if err != nil {
t.Fatal(err)
}
codectest.AudioEncoderReadAfterCloseTest(t, &p,
prop.Media{
Audio: prop.Audio{
SampleRate: 48000,
ChannelCount: 2,
},
},
wave.NewInt16Interleaved(wave.ChunkInfo{
Len: 960,
SamplingRate: 48000,
Channels: 2,
}),
)
})
}

View File

@@ -65,25 +65,6 @@ func TestEncoder(t *testing.T) {
},
})
})
t.Run("ReadAfterClose", func(t *testing.T) {
p, err := factory()
if err != nil {
t.Fatal(err)
}
codectest.VideoEncoderReadAfterCloseTest(t, p,
prop.Media{
Video: prop.Video{
Width: 256,
Height: 144,
FrameFormat: frame.FormatI420,
},
},
image.NewYCbCr(
image.Rect(0, 0, 256, 144),
image.YCbCrSubsampleRatio420,
),
)
})
})
}
}

View File

@@ -541,7 +541,7 @@ func (e *encoderVP8) Read() ([]byte, func(), error) {
return encoded, func() {}, err
}
func (e *encoderVP8) Controller() codec.EncoderController {
func (e *encoder) Controller() codec.EncoderController {
return e
}

View File

@@ -8,7 +8,7 @@ import (
"testing"
)
func TestVP8ShouldImplementBitRateControl(t *testing.T) {
func TestShouldImplementBitRateControl(t *testing.T) {
t.SkipNow() // TODO: Implement bit rate control
e := &encoderVP8{}
@@ -17,7 +17,7 @@ func TestVP8ShouldImplementBitRateControl(t *testing.T) {
}
}
func TestVP8ShouldImplementKeyFrameControl(t *testing.T) {
func TestShouldImplementKeyFrameControl(t *testing.T) {
t.SkipNow() // TODO: Implement key frame control
e := &encoderVP8{}

View File

@@ -476,7 +476,7 @@ func (e *encoderVP9) Read() ([]byte, func(), error) {
return encoded, func() {}, err
}
func (e *encoderVP9) Controller() codec.EncoderController {
func (e *encoder) Controller() codec.EncoderController {
return e
}

View File

@@ -3,12 +3,7 @@
package vaapi
import (
"github.com/pion/mediadevices/pkg/codec"
"testing"
)
func TestVP9ShouldImplementBitRateControl(t *testing.T) {
func TestShouldImplementBitRateControl(t *testing.T) {
t.SkipNow() // TODO: Implement bit rate control
e := &encoderVP9{}
@@ -17,7 +12,7 @@ func TestVP9ShouldImplementBitRateControl(t *testing.T) {
}
}
func TestVP9ShouldImplementKeyFrameControl(t *testing.T) {
func TestShouldImplementKeyFrameControl(t *testing.T) {
t.SkipNow() // TODO: Implement key frame control
e := &encoderVP9{}

View File

@@ -60,25 +60,6 @@ func TestEncoder(t *testing.T) {
},
})
})
t.Run("ReadAfterClose", func(t *testing.T) {
p, err := factory()
if err != nil {
t.Fatal(err)
}
codectest.VideoEncoderReadAfterCloseTest(t, p,
prop.Media{
Video: prop.Video{
Width: 256,
Height: 144,
FrameFormat: frame.FormatI420,
},
},
image.NewYCbCr(
image.Rect(0, 0, 256, 144),
image.YCbCrSubsampleRatio420,
),
)
})
})
}
}

View File

@@ -18,7 +18,6 @@ typedef struct Encoder {
x264_t *h;
x264_picture_t pic_in;
x264_param_t param;
int force_key_frame;
} Encoder;
Encoder *enc_new(x264_param_t param, char *preset, int *rc) {
@@ -86,14 +85,8 @@ Slice enc_encode(Encoder *e, uint8_t *y, uint8_t *cb, uint8_t *cr, int *rc) {
e->pic_in.img.plane[0] = y;
e->pic_in.img.plane[1] = cb;
e->pic_in.img.plane[2] = cr;
if (e->force_key_frame) {
e->pic_in.i_type = X264_TYPE_IDR;
} else {
e->pic_in.i_type = X264_TYPE_AUTO;
}
int frame_size = x264_encoder_encode(e->h, &nal, &i_nal, &e->pic_in, &pic_out);
e->force_key_frame = 0;
Slice s = {.data_len = frame_size};
if (frame_size <= 0) {
*rc = ERR_ENCODE;

View File

@@ -124,14 +124,6 @@ func (e *encoder) Read() ([]byte, func(), error) {
return encoded, func() {}, err
}
// TODO: Implement bit rate control
//var _ codec.BitRateController = (*encoder)(nil)
func (e *encoder) ForceKeyFrame() error {
e.engine.force_key_frame = C.int(1)
return nil
}
func (e *encoder) Controller() codec.EncoderController {
return e
}

View File

@@ -46,26 +46,6 @@ func TestEncoder(t *testing.T) {
},
})
})
t.Run("ReadAfterClose", func(t *testing.T) {
p, err := NewParams()
if err != nil {
t.Fatal(err)
}
p.BitRate = 200000
codectest.VideoEncoderReadAfterCloseTest(t, &p,
prop.Media{
Video: prop.Video{
Width: 256,
Height: 144,
FrameFormat: frame.FormatI420,
},
},
image.NewYCbCr(
image.Rect(0, 0, 256, 144),
image.YCbCrSubsampleRatio420,
),
)
})
}
func TestShouldImplementKeyFrameControl(t *testing.T) {

View File

@@ -13,7 +13,6 @@ import (
type camera struct {
device avfoundation.Device
session *avfoundation.Session
rcClose func()
}
func init() {
@@ -44,9 +43,6 @@ func (cam *camera) Open() error {
}
func (cam *camera) Close() error {
if cam.rcClose != nil {
cam.rcClose()
}
return cam.session.Close()
}
@@ -60,7 +56,6 @@ func (cam *camera) VideoRecord(property prop.Media) (video.Reader, error) {
if err != nil {
return nil, err
}
cam.rcClose = rc.Close
r := video.ReaderFunc(func() (image.Image, func(), error) {
frame, _, err := rc.Read()
if err != nil {

View File

@@ -10,7 +10,6 @@ import (
"io"
"os"
"path/filepath"
"strconv"
"sync"
"github.com/blackjack/webcam"
@@ -134,19 +133,6 @@ func newCamera(path string) *camera {
return c
}
func getCameraReadTimeout() uint32 {
// default to 5 seconds
var readTimeoutSec uint32 = 5
if val, ok := os.LookupEnv("PION_MEDIADEVICES_CAMERA_READ_TIMEOUT"); ok {
if valInt, err := strconv.Atoi(val); err == nil {
if valInt > 0 {
readTimeoutSec = uint32(valInt)
}
}
}
return readTimeoutSec
}
func (c *camera) Open() error {
cam, err := webcam.Open(c.path)
if err != nil {
@@ -193,21 +179,12 @@ func (c *camera) VideoRecord(p prop.Media) (video.Reader, error) {
return nil, err
}
if p.FrameRate > 0 {
err = c.cam.SetFramerate(float32(p.FrameRate))
if err != nil {
return nil, err
}
}
if err := c.cam.StartStreaming(); err != nil {
return nil, err
}
cam := c.cam
readTimeoutSec := getCameraReadTimeout()
ctx, cancel := context.WithCancel(context.Background())
c.cancel = cancel
var buf []byte
@@ -223,7 +200,7 @@ func (c *camera) VideoRecord(p prop.Media) (video.Reader, error) {
return nil, func() {}, io.EOF
}
err := cam.WaitForFrame(readTimeoutSec)
err := cam.WaitForFrame(5) // 5 seconds
switch err.(type) {
case nil:
case *webcam.Timeout:

View File

@@ -70,31 +70,3 @@ func TestDiscover(t *testing.T) {
t.Errorf("Expected label: %s, got: %s", expectedNoLink, label)
}
}
func TestGetCameraReadTimeout(t *testing.T) {
var expected uint32 = 5
value := getCameraReadTimeout()
if value != expected {
t.Errorf("Expected: %d, got: %d", expected, value)
}
envVarName := "PION_MEDIADEVICES_CAMERA_READ_TIMEOUT"
os.Setenv(envVarName, "text")
value = getCameraReadTimeout()
if value != expected {
t.Errorf("Expected: %d, got: %d", expected, value)
}
os.Setenv(envVarName, "-1")
value = getCameraReadTimeout()
if value != expected {
t.Errorf("Expected: %d, got: %d", expected, value)
}
os.Setenv(envVarName, "1")
expected = 1
value = getCameraReadTimeout()
if value != expected {
t.Errorf("Expected: %d, got: %d", expected, value)
}
}

View File

@@ -76,7 +76,6 @@ int listCamera(cameraList* list, const char** errstr)
{
list->name[i] = getCameraName(moniker);
moniker->Release();
i++;
}
}

View File

@@ -1,12 +1,10 @@
package microphone
import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"sync"
"time"
"unsafe"
@@ -34,8 +32,7 @@ var (
type microphone struct {
malgo.DeviceInfo
chunkChan chan []byte
deviceCloseFunc func()
chunkChan chan []byte
}
func init() {
@@ -90,8 +87,9 @@ func (m *microphone) Open() error {
}
func (m *microphone) Close() error {
if m.deviceCloseFunc != nil {
m.deviceCloseFunc()
if m.chunkChan != nil {
close(m.chunkChan)
m.chunkChan = nil
}
return nil
}
@@ -113,9 +111,6 @@ func (m *microphone) AudioRecord(inputProp prop.Media) (audio.Reader, error) {
config.PerformanceProfile = malgo.LowLatency
config.Capture.Channels = uint32(inputProp.ChannelCount)
config.SampleRate = uint32(inputProp.SampleRate)
config.PeriodSizeInMilliseconds = uint32(inputProp.Latency.Milliseconds())
//FIX: Turn on the microphone with the current device id
config.Capture.DeviceID = m.ID.Pointer()
if inputProp.SampleSize == 4 && inputProp.IsFloat {
config.Capture.Format = malgo.FormatF32
} else if inputProp.SampleSize == 2 && !inputProp.IsFloat {
@@ -124,44 +119,26 @@ func (m *microphone) AudioRecord(inputProp prop.Media) (audio.Reader, error) {
return nil, errUnsupportedFormat
}
cancelCtx, cancel := context.WithCancel(context.Background())
onRecvChunk := func(_, chunk []byte, framecount uint32) {
select {
case <-cancelCtx.Done():
case m.chunkChan <- chunk:
}
m.chunkChan <- chunk
}
callbacks.Data = onRecvChunk
device, err := malgo.InitDevice(ctx.Context, config, callbacks)
if err != nil {
cancel()
return nil, err
}
err = device.Start()
if err != nil {
cancel()
return nil, err
}
var closeDeviceOnce sync.Once
m.deviceCloseFunc = func() {
closeDeviceOnce.Do(func() {
cancel() // Unblock onRecvChunk
device.Uninit()
if m.chunkChan != nil {
close(m.chunkChan)
m.chunkChan = nil
}
})
}
var reader audio.Reader = audio.ReaderFunc(func() (wave.Audio, func(), error) {
chunk, ok := <-m.chunkChan
if !ok {
m.deviceCloseFunc()
device.Stop()
device.Uninit()
return nil, func() {}, io.EOF
}
@@ -191,32 +168,36 @@ func (m *microphone) Properties() []prop.Media {
isBigEndian = true
}
for _, format := range m.Formats {
for ch := m.MinChannels; ch <= m.MaxChannels; ch++ {
// FIXME: Currently support 48kHz only. We need to implement a resampler first.
// for sampleRate := m.MinSampleRate; sampleRate <= m.MaxSampleRate; sampleRate += sampleRateStep {
sampleRate := 48000
supportedProp := prop.Media{
Audio: prop.Audio{
ChannelCount: int(format.Channels),
SampleRate: int(sampleRate),
IsBigEndian: isBigEndian,
// miniaudio only supports interleaved at the moment
IsInterleaved: true,
// FIXME: should change this to a less discrete value
Latency: time.Millisecond * 20,
},
}
for i := 0; i < int(m.FormatCount); i++ {
format := m.Formats[i]
switch malgo.FormatType(format.Format) {
case malgo.FormatF32:
supportedProp.SampleSize = 4
supportedProp.IsFloat = true
case malgo.FormatS16:
supportedProp.SampleSize = 2
supportedProp.IsFloat = false
}
supportedProp := prop.Media{
Audio: prop.Audio{
ChannelCount: int(ch),
SampleRate: int(sampleRate),
IsBigEndian: isBigEndian,
// miniaudio only supports interleaved at the moment
IsInterleaved: true,
// FIXME: should change this to a less discrete value
Latency: time.Millisecond * 20,
},
}
supportedProps = append(supportedProps, supportedProp)
switch malgo.FormatType(format) {
case malgo.FormatF32:
supportedProp.SampleSize = 4
supportedProp.IsFloat = true
case malgo.FormatS16:
supportedProp.SampleSize = 2
supportedProp.IsFloat = false
}
supportedProps = append(supportedProps, supportedProp)
}
// }
}
return supportedProps

View File

@@ -47,6 +47,10 @@ func (d *dummy) Close() error {
}
func (d *dummy) VideoRecord(p prop.Media) (video.Reader, error) {
if p.FrameRate == 0 {
p.FrameRate = 30
}
colors := [][3]byte{
{235, 128, 128},
{210, 16, 146},
@@ -139,7 +143,6 @@ func (d dummy) Properties() []prop.Media {
Width: 640,
Height: 480,
FrameFormat: frame.FormatYUYV,
FrameRate: 30,
},
},
}

View File

@@ -18,32 +18,13 @@ type Encoding interface {
// the proper data.
Read(*ClientConn, *Rectangle, io.Reader) (Encoding, error)
}
type CursorEncoding struct {
}
func (*CursorEncoding) Type() int32 {
return -239
}
func (*CursorEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
size := int(rect.Height) * int(rect.Width) * int(c.PixelFormat.BPP) / 8
pixelBytes := make([]uint8, size)
if _, err := io.ReadFull(r, pixelBytes); err != nil {
return nil, err
}
mask := ((int(rect.Width) + 7) / 8) * int(rect.Height)
maskBytes := make([]uint8, mask)
if _, err := io.ReadFull(r, maskBytes); err != nil {
return nil, err
}
return &CursorEncoding{}, nil
}
// RawEncoding is raw pixel data sent by the server.
//
// See RFC 6143 Section 7.7.1
type RawEncoding struct {
Colors []Color
RawPixel []uint32 //RGBA
Colors []Color
RawPixel []uint32 //RGBA
}
func (*RawEncoding) Type() int32 {
@@ -51,7 +32,6 @@ func (*RawEncoding) Type() int32 {
}
func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
//fmt.Println("RawEncoding")
bytesPerPixel := c.PixelFormat.BPP / 8
pixelBytes := make([]uint8, bytesPerPixel)
@@ -61,7 +41,7 @@ func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding,
}
colors := make([]Color, int(rect.Height)*int(rect.Width))
rawPixels := make([]uint32, int(rect.Height)*int(rect.Width))
rawPixels:=make([]uint32,int(rect.Height)*int(rect.Width))
for y := uint16(0); y < rect.Height; y++ {
for x := uint16(0); x < rect.Width; x++ {
if _, err := io.ReadFull(r, pixelBytes); err != nil {
@@ -82,30 +62,24 @@ func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding,
color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax))
color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax))
color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax))
if c.PixelFormat.BPP == 16 {
color.B = color.B<<3 | color.B>>2
color.G = color.G<<2 | color.G>>2
color.R = color.R<<3 | color.R>>2
}
} else {
*color = c.ColorMap[rawPixel]
}
rawPixels[int(y)*int(rect.Width)+int(x)] = uint32(0xff)<<24 | uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
rawPixels[int(y)*int(rect.Width)+int(x)]=uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
//fmt.Printf("%x %x",rawPixel,rawPixels[int(y)*int(rect.Width)+int(x)])
}
}
return &RawEncoding{colors, rawPixels}, nil
return &RawEncoding{colors,rawPixels}, nil
}
// ZlibEncoding is raw pixel data sent by the server compressed by Zlib.
//
// A single Zlib stream is created. There is only a single header for a framebuffer request response.
type ZlibEncoding struct {
Colors []Color
RawPixel []uint32
ZStream *bytes.Buffer
ZReader io.ReadCloser
Colors []Color
RawPixel[] uint32
ZStream *bytes.Buffer
ZReader io.ReadCloser
}
func (*ZlibEncoding) Type() int32 {
@@ -113,7 +87,6 @@ func (*ZlibEncoding) Type() int32 {
}
func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
//fmt.Println("ZlibEncoding")
bytesPerPixel := c.PixelFormat.BPP / 8
pixelBytes := make([]uint8, bytesPerPixel)
@@ -125,6 +98,7 @@ func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encod
// Format
// 4 bytes | uint32 | length
// 'length' bytes | []byte | zlibData
// Read zlib length
var zipLength uint32
err := binary.Read(r, binary.BigEndian, &zipLength)
@@ -172,7 +146,7 @@ func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encod
colorReader := bytes.NewReader(colorBytes)
colors := make([]Color, int(rect.Height)*int(rect.Width))
rawPixels := make([]uint32, int(rect.Height)*int(rect.Width))
rawPixels:=make([]uint32,int(rect.Height)*int(rect.Width))
for y := uint16(0); y < rect.Height; y++ {
for x := uint16(0); x < rect.Width; x++ {
if _, err := io.ReadFull(colorReader, pixelBytes); err != nil {
@@ -193,19 +167,14 @@ func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encod
color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax))
color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax))
color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax))
if c.PixelFormat.BPP == 16 {
color.B = color.B<<3 | color.B>>2
color.G = color.G<<2 | color.G>>2
color.R = color.R<<3 | color.R>>2
}
} else {
*color = c.ColorMap[rawPixel]
}
rawPixels[int(y)*int(rect.Width)+int(x)] = uint32(0xff)<<24 | uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
rawPixels[int(y)*int(rect.Width)+int(x)]=uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
}
}
return &ZlibEncoding{Colors: colors, RawPixel: rawPixels}, nil
return &ZlibEncoding{Colors: colors,RawPixel: rawPixels}, nil
}
func (ze *ZlibEncoding) Close() {
@@ -214,4 +183,4 @@ func (ze *ZlibEncoding) Close() {
ze.ZReader.Close()
ze.ZReader = nil
}
}
}

View File

@@ -5,14 +5,13 @@ import (
"context"
"encoding/binary"
"fmt"
"github.com/pion/mediadevices/pkg/driver/vncdriver/vnc"
"image"
"io"
"net"
"sync"
"time"
"github.com/pion/mediadevices/pkg/driver/vncdriver/vnc"
"github.com/pion/mediadevices/pkg/frame"
"github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop"
@@ -33,12 +32,12 @@ func NewVnc(vncAddr string) *vncDevice {
return &vncDevice{vncAddr: vncAddr}
}
func (d *vncDevice) PointerEvent(mask uint8, x, y uint16) {
if d.vClient != nil {
if d.vClient!=nil{
d.vClient.PointerEvent(vnc.ButtonMask(mask), x, y)
}
}
func (d *vncDevice) KeyEvent(keysym uint32, down bool) {
if d.vClient != nil {
if d.vClient!=nil {
d.vClient.KeyEvent(keysym, down)
}
}
@@ -50,10 +49,7 @@ func (d *vncDevice) Open() error {
d.closed = ctx.Done()
d.cancel = cancel
msg := make(chan vnc.ServerMessage, 1)
//auth:=new(vnc.PasswordAuth)
//auth.Password="####"
conf := vnc.ClientConfig{
//Auth: []vnc.ClientAuth{auth},
ServerMessageCh: msg,
Exclusive: false,
}
@@ -70,7 +66,6 @@ func (d *vncDevice) Open() error {
d.vClient.SetEncodings([]vnc.Encoding{
&vnc.ZlibEncoding{},
&vnc.RawEncoding{},
&vnc.CursorEncoding{},
})
d.w = int(d.vClient.FrameBufferWidth)
d.h = int(d.vClient.FrameBufferHeight)
@@ -94,9 +89,6 @@ func (d *vncDevice) Open() error {
for _, rect := range t.Rectangles {
var pix []uint32
switch t := rect.Enc.(type) {
case *vnc.CursorEncoding:
//ignore remote cursor messages
continue
case *vnc.RawEncoding:
pix = t.RawPixel
case *vnc.ZlibEncoding:
@@ -105,16 +97,19 @@ func (d *vncDevice) Open() error {
for y := int(rect.Y); y < int(rect.Height+rect.Y); y++ {
for x := int(rect.X); x < int(rect.Width+rect.X); x++ {
binary.LittleEndian.PutUint32(d.rawPixel[(y*d.w+x)*4:], pix[(y-int(rect.Y))*int(rect.Width)+(x-int(rect.X))])
//BigEndian
}
}
}
//time.Sleep(33 * time.Millisecond)
d.vClient.FramebufferUpdateRequest(true, 0, 0, uint16(d.w), uint16(d.h))
break
default:
}
case <-time.After(10 * time.Second):
//fmt.Println("Timeout FramebufferUpdate")
if d.vClient.FramebufferUpdateRequest(true, 0, 0, uint16(d.w), uint16(d.h)) != nil {
d.cancel()
return
@@ -142,12 +137,13 @@ func (d *vncDevice) Close() error {
func (d *vncDevice) VideoRecord(p prop.Media) (video.Reader, error) {
if p.FrameRate == 0 {
p.FrameRate = 30
p.FrameRate = 15
}
tick := time.NewTicker(time.Duration(float32(time.Second) / p.FrameRate))
d.tick = tick
closed := d.closed
pixs := make([]byte, d.h*d.w*4)
r := video.ReaderFunc(func() (image.Image, func(), error) {
select {
case <-closed:
@@ -157,8 +153,9 @@ func (d *vncDevice) VideoRecord(p prop.Media) (video.Reader, error) {
}
<-tick.C
copy(pixs, d.rawPixel)
return &image.RGBA{
Pix: d.rawPixel,
Pix: pixs,
Stride: 4,
Rect: image.Rect(0, 0, d.w, d.h),
}, func() {}, nil

View File

@@ -141,9 +141,7 @@ func (broadcaster *Broadcaster) NewReader(copyFn func(interface{}) interface{})
data, err, currentCount = ringData.data, ringData.err, ringData.count
}
if data != nil { // data is nil if an error occurred during reading
data = copyFn(data)
}
data = copyFn(data)
return
})
}

View File

@@ -1,7 +1,6 @@
package video
import (
"errors"
"image"
"reflect"
"testing"
@@ -48,21 +47,3 @@ func TestBroadcast(t *testing.T) {
t.Fatal("Expected actual frame without copy to be the same with the original")
}
}
func TestBroadcastWithCopyOnReadError(t *testing.T) {
expectedError := errors.New("expected error")
source := ReaderFunc(func() (image.Image, func(), error) {
return nil, func() {}, expectedError
})
broadcaster := NewBroadcaster(source, nil)
readerWithCopy := broadcaster.NewReader(true)
actualWithCopy, _, err := readerWithCopy.Read()
if actualWithCopy != nil {
t.Fatal("Expected actual frame with copy to be nil")
}
if err != expectedError {
t.Fatal("Expected error to be the same")
}
}

View File

@@ -73,15 +73,16 @@ func ToI420(r Reader) Reader {
// Covert pixel format to I420
switch yuvImg.SubsampleRatio {
case image.YCbCrSubsampleRatio420:
case image.YCbCrSubsampleRatio444:
yuvImg = i444ToI420(yuvImg)
i444ToI420(&yuvImg)
case image.YCbCrSubsampleRatio422:
yuvImg = i422ToI420(yuvImg)
i422ToI420(&yuvImg)
case image.YCbCrSubsampleRatio420:
default:
return nil, func() {}, fmt.Errorf("unsupported pixel format: %s", yuvImg.SubsampleRatio)
}
yuvImg.SubsampleRatio = image.YCbCrSubsampleRatio420
return &yuvImg, func() {}, nil
})
}

View File

@@ -3,8 +3,6 @@
#include "_cgo_export.h"
void i444ToI420CGO(
unsigned char *cb_dst,
unsigned char *cr_dst,
unsigned char* cb,
unsigned char* cr,
const int stride, const int h)
@@ -24,8 +22,8 @@ void i444ToI420CGO(
((uint16_t)cr[isrc0] + (uint16_t)cr[isrc1] +
(uint16_t)cr[isrc0 + 1] + (uint16_t)cr[isrc1 + 1]) /
4;
cb_dst[idst] = cb2;
cr_dst[idst] = cr2;
cb[idst] = cb2;
cr[idst] = cr2;
isrc0 += 2;
isrc1 += 2;
idst++;
@@ -36,8 +34,6 @@ void i444ToI420CGO(
}
void i422ToI420CGO(
unsigned char *cb_dst,
unsigned char *cr_dst,
unsigned char* cb,
unsigned char* cr,
const int stride, const int h)
@@ -50,8 +46,8 @@ void i422ToI420CGO(
{
const uint8_t cb2 = ((uint16_t)cb[isrc] + (uint16_t)cb[isrc + stride]) / 2;
const uint8_t cr2 = ((uint16_t)cr[isrc] + (uint16_t)cr[isrc + stride]) / 2;
cb_dst[idst] = cb2;
cr_dst[idst] = cr2;
cb[idst] = cb2;
cr[idst] = cr2;
isrc++;
idst++;
}

View File

@@ -1,4 +1,3 @@
//go:build cgo
// +build cgo
package video
@@ -15,35 +14,27 @@ import "C"
// All functions switched at runtime must be declared also in convert_nocgo.go.
const hasCGOConvert = true
func i444ToI420(img image.YCbCr) image.YCbCr {
func i444ToI420(img *image.YCbCr) {
h := img.Rect.Dy()
cLen := img.CStride * h / 4
cbDst, crDst := make([]uint8, cLen), make([]uint8, cLen)
C.i444ToI420CGO(
(*C.uchar)(&cbDst[0]), (*C.uchar)(&crDst[0]),
(*C.uchar)(&img.Cb[0]), (*C.uchar)(&img.Cr[0]),
C.int(img.CStride), C.int(h),
)
img.CStride = img.CStride / 2
img.Cb = cbDst
img.Cr = crDst
img.SubsampleRatio = image.YCbCrSubsampleRatio420
return img
cLen := img.CStride * (h / 2)
img.Cb = img.Cb[:cLen]
img.Cr = img.Cr[:cLen]
}
func i422ToI420(img image.YCbCr) image.YCbCr {
func i422ToI420(img *image.YCbCr) {
h := img.Rect.Dy()
cLen := img.CStride * (h / 2)
cbDst, crDst := make([]uint8, cLen), make([]uint8, cLen)
C.i422ToI420CGO(
(*C.uchar)(&cbDst[0]), (*C.uchar)(&crDst[0]),
(*C.uchar)(&img.Cb[0]), (*C.uchar)(&img.Cr[0]),
C.int(img.CStride), C.int(h),
)
img.Cb = cbDst
img.Cr = crDst
img.SubsampleRatio = image.YCbCrSubsampleRatio420
return img
cLen := img.CStride * (h / 2)
img.Cb = img.Cb[:cLen]
img.Cr = img.Cr[:cLen]
}
func rgbToYCbCrCGO(y, cb, cr *uint8, r, g, b uint8) { // For testing

View File

@@ -1,13 +1,9 @@
void i444ToI420CGO(
unsigned char *cb_dst,
unsigned char *cr_dst,
unsigned char* cb,
unsigned char* cr,
const int stride, const int h);
void i422ToI420CGO(
unsigned char *cb_dst,
unsigned char *cr_dst,
unsigned char* cb,
unsigned char* cr,
const int stride, const int h);

View File

@@ -1,4 +1,3 @@
//go:build !cgo
// +build !cgo
package video
@@ -10,22 +9,19 @@ import (
const hasCGOConvert = false
func i444ToI420(img image.YCbCr) image.YCbCr {
func i444ToI420(img *image.YCbCr) {
h := img.Rect.Dy()
addrSrc0 := 0
addrSrc1 := img.CStride
cLen := img.CStride * (h / 2)
addrDst := 0
cbDst, crDst := make([]uint8, cLen), make([]uint8, cLen)
for i := 0; i < h/2; i++ {
for j := 0; j < img.CStride/2; j++ {
cb := uint16(img.Cb[addrSrc0]) + uint16(img.Cb[addrSrc1]) +
uint16(img.Cb[addrSrc0+1]) + uint16(img.Cb[addrSrc1+1])
cr := uint16(img.Cr[addrSrc0]) + uint16(img.Cr[addrSrc1]) +
uint16(img.Cr[addrSrc0+1]) + uint16(img.Cr[addrSrc1+1])
cbDst[addrDst] = uint8(cb / 4)
crDst[addrDst] = uint8(cr / 4)
img.Cb[addrDst] = uint8(cb / 4)
img.Cr[addrDst] = uint8(cr / 4)
addrSrc0 += 2
addrSrc1 += 2
addrDst++
@@ -34,34 +30,29 @@ func i444ToI420(img image.YCbCr) image.YCbCr {
addrSrc1 += img.CStride
}
img.CStride = img.CStride / 2
img.Cb = cbDst
img.Cr = crDst
img.SubsampleRatio = image.YCbCrSubsampleRatio420
return img
cLen := img.CStride * (h / 2)
img.Cb = img.Cb[:cLen]
img.Cr = img.Cr[:cLen]
}
func i422ToI420(img image.YCbCr) image.YCbCr {
func i422ToI420(img *image.YCbCr) {
h := img.Rect.Dy()
addrSrc := 0
cLen := img.CStride * (h / 2)
cbDst, crDst := make([]uint8, cLen), make([]uint8, cLen)
addrDst := 0
for i := 0; i < h/2; i++ {
for j := 0; j < img.CStride; j++ {
cb := uint16(img.Cb[addrSrc]) + uint16(img.Cb[addrSrc+img.CStride])
cr := uint16(img.Cr[addrSrc]) + uint16(img.Cr[addrSrc+img.CStride])
cbDst[addrDst] = uint8(cb / 4)
crDst[addrDst] = uint8(cr / 4)
addrSrc++
img.Cb[addrDst] = uint8(cb / 2)
img.Cr[addrDst] = uint8(cr / 2)
addrDst++
addrSrc++
}
addrSrc += img.CStride
}
img.Cb = cbDst
img.Cr = crDst
img.SubsampleRatio = image.YCbCrSubsampleRatio420
return img
cLen := img.CStride * (h / 2)
img.Cb = img.Cb[:cLen]
img.Cr = img.Cr[:cLen]
}
func i444ToRGBA(dst *image.RGBA, src *image.YCbCr) {

View File

@@ -222,8 +222,8 @@ func BenchmarkToI420(b *testing.B) {
"RGBA": image.NewRGBA(image.Rect(0, 0, sz[0], sz[1])),
}
b.Run(name, func(b *testing.B) {
for _, name := range [...]string{"I444", "I422", "I420", "RGBA"} {
img := cases[name]
for name, img := range cases {
img := img
b.Run(name, func(b *testing.B) {
r := ToI420(ReaderFunc(func() (image.Image, func(), error) {
return img, func() {}, nil

View File

@@ -109,7 +109,7 @@ func Scale(width, height int, scaler Scaler) TransformFunc {
yDy := rect.Dy()
cRect := fixedRect(rect, i1.SubsampleRatio)
cDx := cRect.Dx()
cDy := cRect.Dy()
cDy := cRect.Dx()
yLen := yDx * yDy
cLen := cDx * cDy
if len(imgDst.Y) < yLen {

View File

@@ -36,32 +36,6 @@ func TestScale(t *testing.T) {
Rect: image.Rect(0, 0, 2, 2),
},
},
"RGBASameSize": {
src: &image.RGBA{
Pix: []uint8{
// R G B A | R G B A | R G B A | R G B A
0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x40, 0x00, 0xFF, 0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x60, 0xFF,
0x00, 0x40, 0x00, 0xFF, 0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x60, 0xFF,
},
Stride: 16,
Rect: image.Rect(0, 0, 4, 4),
},
width: 4,
height: 4,
expected: &image.RGBA{
Pix: []uint8{
// R G B A | R G B A | R G B A | R G B A
0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x40, 0x00, 0xFF, 0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x60, 0xFF,
0x00, 0x40, 0x00, 0xFF, 0x00, 0x40, 0x00, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x60, 0xFF,
},
Stride: 16,
Rect: image.Rect(0, 0, 4, 4),
},
},
"I444": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio444,
@@ -117,70 +91,6 @@ func TestScale(t *testing.T) {
Rect: image.Rect(0, 0, 3, 3),
},
},
"I444SameSize": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio444,
Y: []uint8{
0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80, 0x80, 0x80,
0x20, 0x20, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0,
0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80, 0x80, 0x80,
0xE0, 0xE0, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x40, 0x40, 0x80, 0x80,
0x80, 0x80, 0x40, 0x40, 0x80, 0x80,
},
YStride: 6,
CStride: 6,
Rect: image.Rect(0, 0, 6, 6),
},
width: 6,
height: 6,
expected: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio444,
Y: []uint8{
0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80, 0x80, 0x80,
0x20, 0x20, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0,
0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80, 0x80, 0x80,
0xE0, 0xE0, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x40, 0x40, 0x80, 0x80,
0x80, 0x80, 0x40, 0x40, 0x80, 0x80,
},
YStride: 6,
CStride: 6,
Rect: image.Rect(0, 0, 6, 6),
},
},
"I422": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio422,
@@ -245,82 +155,6 @@ func TestScale(t *testing.T) {
Rect: image.Rect(0, 0, 4, 4),
},
},
"I422SameSize": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio422,
Y: []uint8{
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80,
0x20, 0x20, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0xE0, 0xE0,
0x80, 0x80, 0xE0, 0xE0,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80,
0xE0, 0xE0, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0xF0, 0xF0, 0x40, 0x40,
0xF0, 0xF0, 0x40, 0x40,
},
YStride: 8,
CStride: 4,
Rect: image.Rect(0, 0, 8, 8),
},
width: 8,
height: 8,
expected: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio422,
Y: []uint8{
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80,
0x20, 0x20, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0xE0, 0xE0,
0x80, 0x80, 0xE0, 0xE0,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80,
0xE0, 0xE0, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0xF0, 0xF0, 0x40, 0x40,
0xF0, 0xF0, 0x40, 0x40,
},
YStride: 8,
CStride: 4,
Rect: image.Rect(0, 0, 8, 8),
},
},
"I420": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
@@ -373,118 +207,6 @@ func TestScale(t *testing.T) {
Rect: image.Rect(0, 0, 4, 4),
},
},
"I420SameSize": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
Y: []uint8{
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80,
0x20, 0x20, 0x80, 0x80,
0x80, 0x80, 0xE0, 0xE0,
0x80, 0x80, 0xE0, 0xE0,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80,
0xE0, 0xE0, 0x80, 0x80,
0xF0, 0xF0, 0x40, 0x40,
0xF0, 0xF0, 0x40, 0x40,
},
YStride: 8,
CStride: 4,
Rect: image.Rect(0, 0, 8, 8),
},
width: 8,
height: 8,
expected: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
Y: []uint8{
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80,
0x20, 0x20, 0x80, 0x80,
0x80, 0x80, 0xE0, 0xE0,
0x80, 0x80, 0xE0, 0xE0,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80,
0xE0, 0xE0, 0x80, 0x80,
0xF0, 0xF0, 0x40, 0x40,
0xF0, 0xF0, 0x40, 0x40,
},
YStride: 8,
CStride: 4,
Rect: image.Rect(0, 0, 8, 8),
},
},
"I420NonSquareImage": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
Y: []uint8{
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10,
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80, 0x50, 0x50,
0x20, 0x20, 0x80, 0x80, 0x50, 0x50,
0x80, 0x80, 0xE0, 0xE0, 0x30, 0x30,
0x80, 0x80, 0xE0, 0xE0, 0x30, 0x30,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80, 0xB0, 0xB0,
0xE0, 0xE0, 0x80, 0x80, 0xB0, 0xB0,
0xF0, 0xF0, 0x40, 0x40, 0xC0, 0xC0,
0xF0, 0xF0, 0x40, 0x40, 0xC0, 0xC0,
},
YStride: 12,
CStride: 6,
Rect: image.Rect(0, 0, 12, 8),
},
width: 6,
height: 4,
expected: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
Y: []uint8{
0xF0, 0x10, 0x00, 0x00, 0xF0, 0x10,
0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x30, 0x00, 0x30, 0x00,
},
Cb: []uint8{
0x20, 0x80, 0x50,
0x80, 0xE0, 0x30,
},
Cr: []uint8{
0xE0, 0x80, 0xB0,
0xF0, 0x40, 0xC0,
},
YStride: 6,
CStride: 3,
Rect: image.Rect(0, 0, 6, 4),
},
},
}
for name, algo := range scalerTestAlgos {
algo := algo
@@ -525,100 +247,6 @@ func TestScale(t *testing.T) {
}
}
func TestScaleFastBoxSampling(t *testing.T) {
cases := map[string]struct {
src image.Image
width, height int
expected image.Image
}{
"I420NonSquareImage": {
src: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
Y: []uint8{
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10,
0xF0, 0xF0, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00,
},
Cb: []uint8{
0x20, 0x20, 0x80, 0x80, 0x50, 0x50,
0x20, 0x20, 0x80, 0x80, 0x50, 0x50,
0x80, 0x80, 0xE0, 0xE0, 0x30, 0x30,
0x80, 0x80, 0xE0, 0xE0, 0x30, 0x30,
},
Cr: []uint8{
0xE0, 0xE0, 0x80, 0x80, 0xB0, 0xB0,
0xE0, 0xE0, 0x80, 0x80, 0xB0, 0xB0,
0xF0, 0xF0, 0x40, 0x40, 0xC0, 0xC0,
0xF0, 0xF0, 0x40, 0x40, 0xC0, 0xC0,
},
YStride: 12,
CStride: 6,
Rect: image.Rect(0, 0, 12, 8),
},
width: 6,
height: 4,
expected: &image.YCbCr{
SubsampleRatio: image.YCbCrSubsampleRatio420,
Y: []uint8{
0xF0, 0x80, 0x08, 0x00, 0x78, 0x80,
0x08, 0x00, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x58, 0x18, 0x18, 0x18,
},
Cb: []uint8{
0x20, 0x50, 0x68,
0x68, 0xB0, 0x88,
},
Cr: []uint8{
0xE0, 0xB0, 0x98,
0xD0, 0x98, 0x80,
},
YStride: 6,
CStride: 3,
Rect: image.Rect(0, 0, 6, 4),
},
},
}
for name, c := range cases {
c := c
t.Run(name, func(t *testing.T) {
trans := Scale(c.width, c.height, ScalerFastBoxSampling)
r := trans(ReaderFunc(func() (image.Image, func(), error) {
return c.src, func() {}, nil
}))
for i := 0; i < 4; i++ {
out, _, err := r.Read()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(c.expected, out) {
t.Errorf("Expected output image:\n%v\ngot:\n%v\nrepeat: %d", c.expected, out, i)
}
// Destroy output contents
switch v := out.(type) {
case *image.RGBA:
v.Stride = 10
v.Pix = v.Pix[:1]
v.Rect.Max.X = 1
case *image.YCbCr:
v.YStride = 10
v.CStride = 100
v.Y = v.Y[:1]
v.Cb = v.Cb[:2]
v.Cr = v.Cr[:1]
v.Rect.Max.X = 1
}
}
})
}
}
func BenchmarkScale(b *testing.B) {
for name, algo := range scalerBenchAlgos {
algo := algo

View File

@@ -29,7 +29,7 @@ void fastBoxSampling(
const int sw, const int sh, const int sstride,
uint32_t* tmp)
{
memset(tmp, 0, dw * dh * ch * sizeof(tmp[0]));
memset(tmp, 0, dw * dh * ch);
for (int sy = 0; sy < sh; sy++)
{

View File

@@ -30,18 +30,10 @@ func (p *rgbLikeYCbCr) At(x, y int) color.Color {
}
func (p *rgbLikeYCbCr) Set(x, y int, c color.Color) {
switch v := c.(type) {
case color.RGBA:
p.y.SetGray(x, y, color.Gray{v.R})
if (image.Point{x, y}.In(p.cb.Rect)) {
p.cb.SetGray(x, y, color.Gray{v.G})
p.cr.SetGray(x, y, color.Gray{v.B})
}
case *color.RGBA64:
p.y.SetGray(x, y, color.Gray{uint8(v.R / 0x100)})
if (image.Point{x, y}.In(p.cb.Rect)) {
p.cb.SetGray(x, y, color.Gray{uint8(v.G / 0x100)})
p.cr.SetGray(x, y, color.Gray{uint8(v.B / 0x100)})
}
rgb := c.(*color.RGBA64)
p.y.SetGray(x, y, color.Gray{uint8(rgb.R / 0x100)})
if (image.Point{x, y}.In(p.cb.Rect)) {
p.cb.SetGray(x, y, color.Gray{uint8(rgb.G / 0x100)})
p.cr.SetGray(x, y, color.Gray{uint8(rgb.B / 0x100)})
}
}

View File

@@ -145,17 +145,13 @@ func (p *MediaConstraints) FitnessDistance(o Media) (float64, bool) {
cmps.add(p.Width, o.Width)
cmps.add(p.Height, o.Height)
cmps.add(p.FrameFormat, o.FrameFormat)
// The next line is comment out for now to not include framerate in the fitness function.
// As camera.Properties does not have access to the list of available framerate at the moment,
// no driver can be matched with a framerate constraint.
// Note this also affect screen caputre as screen.Properties does not fill in the Framerate field.
// cmps.add(p.FrameRate, o.FrameRate)
cmps.add(p.SampleRate, o.SampleRate)
cmps.add(p.Latency, o.Latency)
cmps.add(p.ChannelCount, o.ChannelCount)
cmps.add(p.IsBigEndian, o.IsBigEndian)
cmps.add(p.IsFloat, o.IsFloat)
cmps.add(p.IsInterleaved, o.IsInterleaved)
return cmps.fitnessDistance()
}

View File

@@ -53,7 +53,7 @@ func TestBufferStoreCopyAndLoad(t *testing.T) {
for i := range cloneReal.Data {
if reflect.ValueOf(originalReal.Data[i]).Pointer() == reflect.ValueOf(cloneReal.Data[i]).Pointer() {
err := fmt.Errorf("Channel %d memory address should be different", i)
t.Errorf("%v: %s", errIdenticalAddress, err)
t.Errorf("%v: %w", errIdenticalAddress, err)
}
}
},
@@ -89,7 +89,7 @@ func TestBufferStoreCopyAndLoad(t *testing.T) {
for i := range cloneReal.Data {
if reflect.ValueOf(originalReal.Data[i]).Pointer() == reflect.ValueOf(cloneReal.Data[i]).Pointer() {
err := fmt.Errorf("Channel %d memory address should be different", i)
t.Errorf("%v: %s", errIdenticalAddress, err)
t.Errorf("%v: %w", errIdenticalAddress, err)
}
}
},

View File

@@ -11,16 +11,6 @@
{
"packagePatterns": ["^golang.org/x/"],
"schedule": ["on the first day of the month"]
},
{
"description": "Disable updating minimum Go version: https://github.com/renovatebot/renovate/issues/16715",
"matchManagers": ["gomod"],
"matchDepTypes": ["golang"],
"enabled": false
}
],
"ignorePaths": [],
"ignoreDeps": [
"github.com/pion/mediadevices"
]
}

106
track.go
View File

@@ -3,14 +3,12 @@ package mediadevices
import (
"errors"
"fmt"
"github.com/pion/rtcp"
"image"
"io"
"strings"
"sync"
"github.com/pion/interceptor"
"github.com/pion/rtcp"
"github.com/google/uuid"
"github.com/pion/mediadevices/pkg/codec"
"github.com/pion/mediadevices/pkg/driver"
@@ -23,7 +21,6 @@ import (
const (
rtpOutboundMTU = 1200
rtcpInboundMTU = 1500
)
var (
@@ -190,8 +187,7 @@ func (track *baseTrack) bind(ctx webrtc.TrackLocalContext, specializedTrack Trac
close(stopRead)
encodedReader.Close()
// When there's another call to unbind, it won't block since we remove the current ctx from active connections
track.removeActivePeerConnection(ctx.ID())
// When there's another call to unbind, it won't block since we mark the signalCh to be closed
close(signalCh)
if doneCh != nil {
close(doneCh)
@@ -224,55 +220,41 @@ func (track *baseTrack) bind(ctx webrtc.TrackLocalContext, specializedTrack Trac
keyFrameController, ok := encodedReader.Controller().(codec.KeyFrameController)
if ok {
stopRead = make(chan struct{})
go track.rtcpReadLoop(ctx.RTCPReader(), keyFrameController, stopRead)
go func() {
reader := ctx.ReadStream()
for {
select {
case <-stopRead:
return
default:
}
pkts, _, err := reader.ReadRTCP()
if err != nil {
track.onError(err)
return
}
for _, pkt := range pkts {
switch pkt.(type) {
case *rtcp.PictureLossIndication, *rtcp.FullIntraRequest:
if err := keyFrameController.ForceKeyFrame(); err != nil {
track.onError(err)
return
}
}
}
}
}()
}
return selectedCodec, nil
}
func (track *baseTrack) rtcpReadLoop(reader interceptor.RTCPReader, keyFrameController codec.KeyFrameController, stopRead chan struct{}) {
readerBuffer := make([]byte, rtcpInboundMTU)
readLoop:
for {
select {
case <-stopRead:
return
default:
}
readLength, _, err := reader.Read(readerBuffer, interceptor.Attributes{})
if err != nil {
if errors.Is(err, io.EOF) {
return
}
logger.Warnf("failed to read rtcp packet: %s", err)
continue
}
pkts, err := rtcp.Unmarshal(readerBuffer[:readLength])
if err != nil {
logger.Warnf("failed to unmarshal rtcp packet: %s", err)
continue
}
for _, pkt := range pkts {
switch pkt.(type) {
case *rtcp.PictureLossIndication, *rtcp.FullIntraRequest:
if err := keyFrameController.ForceKeyFrame(); err != nil {
logger.Warnf("failed to force key frame: %s", err)
continue readLoop
}
}
}
}
}
func (track *baseTrack) unbind(ctx webrtc.TrackLocalContext) error {
ch := track.removeActivePeerConnection(ctx.ID())
// If there isn't a registered chanel for this ctx, it means it has already been unbound
if ch == nil {
return nil
ch, err := track.removeActivePeerConnection(ctx.ID())
if err != err {
return err
}
doneCh := make(chan struct{})
@@ -281,17 +263,17 @@ func (track *baseTrack) unbind(ctx webrtc.TrackLocalContext) error {
return nil
}
func (track *baseTrack) removeActivePeerConnection(id string) chan<- chan<- struct{} {
func (track *baseTrack) removeActivePeerConnection(id string) (chan<- chan<- struct{}, error) {
track.mu.Lock()
defer track.mu.Unlock()
ch, ok := track.activePeerConnections[id]
if !ok {
return nil
return nil, errNotFoundPeerConnection
}
delete(track.activePeerConnections, id)
return ch
return ch, nil
}
func newTrackFromDriver(d driver.Driver, constraints MediaTrackConstraints, selector *CodecSelector) (Track, error) {
@@ -313,7 +295,7 @@ func newTrackFromDriver(d driver.Driver, constraints MediaTrackConstraints, sele
type VideoTrack struct {
*baseTrack
*video.Broadcaster
shouldCopyFrames bool
ShouldCopyFrames bool
}
// NewVideoTrack constructs a new VideoTrack
@@ -321,16 +303,6 @@ func NewVideoTrack(source VideoSource, selector *CodecSelector) Track {
return newVideoTrackFromReader(source, source, selector)
}
// ShouldCopyFrames indicates if readers on this track should receive a clopy of the read buffer instead of sharing one.
func (track *VideoTrack) ShouldCopyFrames() bool {
return track.shouldCopyFrames
}
// SetShouldCopyFrames enables frame copy for this track, sending each reader a different read buffer instead of sharing one.
func (track *VideoTrack) SetShouldCopyFrames(shouldCopyFrames bool) {
track.shouldCopyFrames = shouldCopyFrames
}
func newVideoTrackFromReader(source Source, reader video.Reader, selector *CodecSelector) Track {
base := newBaseTrack(source, VideoInput, selector)
wrappedReader := video.ReaderFunc(func() (img image.Image, release func(), err error) {
@@ -375,7 +347,7 @@ func (track *VideoTrack) Unbind(ctx webrtc.TrackLocalContext) error {
}
func (track *VideoTrack) newEncodedReader(codecNames ...string) (EncodedReadCloser, *codec.RTPCodec, error) {
reader := track.NewReader(track.shouldCopyFrames)
reader := track.NewReader(track.ShouldCopyFrames)
inputProp, err := detectCurrentVideoProp(track.Broadcaster)
if err != nil {
return nil, nil, err
@@ -519,8 +491,7 @@ func (track *AudioTrack) newEncodedReader(codecNames ...string) (EncodedReadClos
}
return buffer, release, err
},
closeFn: encodedReader.Close,
controllerFn: encodedReader.Controller,
closeFn: encodedReader.Close,
}, selectedCodec, nil
}
@@ -558,7 +529,6 @@ func (track *AudioTrack) NewRTPReader(codecName string, ssrc uint32, mtu int) (R
pkts := packetizer.Packetize(encoded.Data, encoded.Samples)
return pkts, release, err
},
closeFn: encodedReader.Close,
controllerFn: encodedReader.Controller,
closeFn: encodedReader.Close,
}, nil
}

View File

@@ -2,8 +2,6 @@ package mediadevices
import (
"errors"
"github.com/pion/interceptor"
"io"
"testing"
"time"
)
@@ -55,101 +53,3 @@ func TestOnEnded(t *testing.T) {
}
})
}
type fakeRTCPReader struct {
mockReturn chan []byte
end chan struct{}
}
func (mock *fakeRTCPReader) Read(buffer []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
select {
case <-mock.end:
return 0, nil, io.EOF
case mockReturn := <-mock.mockReturn:
if len(buffer) < len(mock.mockReturn) {
return 0, nil, io.ErrShortBuffer
}
return copy(buffer, mockReturn), attributes, nil
}
}
type fakeKeyFrameController struct {
called chan struct{}
}
func (mock *fakeKeyFrameController) ForceKeyFrame() error {
mock.called <- struct{}{}
return nil
}
func TestRtcpHandler(t *testing.T) {
t.Run("ShouldStopReading", func(t *testing.T) {
tr := &baseTrack{}
stop := make(chan struct{}, 1)
stopped := make(chan struct{})
go func() {
tr.rtcpReadLoop(&fakeRTCPReader{end: stop}, &fakeKeyFrameController{}, stop)
stopped <- struct{}{}
}()
stop <- struct{}{}
select {
case <-time.After(100 * time.Millisecond):
t.Error("Timeout")
case <-stopped:
}
})
t.Run("ShouldForceKeyFrame", func(t *testing.T) {
for packetType, packet := range map[string][]byte{
"PLI": {
// v=2, p=0, FMT=1, PSFB, len=1
0x81, 0xce, 0x00, 0x02,
// ssrc=0x0
0x00, 0x00, 0x00, 0x00,
// ssrc=0x4bc4fcb4
0x4b, 0xc4, 0xfc, 0xb4,
},
"FIR": {
// v=2, p=0, FMT=4, PSFB, len=3
0x84, 0xce, 0x00, 0x04,
// ssrc=0x0
0x00, 0x00, 0x00, 0x00,
// ssrc=0x4bc4fcb4
0x4b, 0xc4, 0xfc, 0xb4,
// ssrc=0x12345678
0x12, 0x34, 0x56, 0x78,
// Seqno=0x42
0x42, 0x00, 0x00, 0x00,
},
} {
t.Run(packetType, func(t *testing.T) {
tr := &baseTrack{}
tr.OnEnded(func(err error) {
if err != io.EOF {
t.Error(err)
}
})
stop := make(chan struct{}, 1)
defer func() {
stop <- struct{}{}
}()
mockKeyFrameController := &fakeKeyFrameController{called: make(chan struct{}, 1)}
mockRTCPReader := &fakeRTCPReader{end: stop, mockReturn: make(chan []byte, 1)}
go tr.rtcpReadLoop(mockRTCPReader, mockKeyFrameController, stop)
mockRTCPReader.mockReturn <- packet
select {
case <-time.After(1000 * time.Millisecond):
t.Error("Timeout")
case <-mockKeyFrameController.called:
}
})
}
})
}