mirror of
https://github.com/pion/mediadevices.git
synced 2025-09-27 21:02:17 +08:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b5b0653697 | ||
![]() |
a1087f7f4e | ||
![]() |
217e634f7e | ||
![]() |
60b8e3ae1b | ||
![]() |
7df3114cdc | ||
![]() |
9741508d2b | ||
![]() |
7a569f0901 | ||
![]() |
ee40fcd070 | ||
![]() |
499c08d513 | ||
![]() |
5a1bd11087 | ||
![]() |
7ce935eac8 | ||
![]() |
a359005a7d | ||
![]() |
ca4116b5ce | ||
![]() |
8a4e0779d7 | ||
![]() |
d222ff3d74 | ||
![]() |
b9bb4fdc34 | ||
![]() |
cc823958e1 | ||
![]() |
64f39187b8 | ||
![]() |
c56cc487a3 | ||
![]() |
d86fc4a3e9 | ||
![]() |
2f21d9e738 | ||
![]() |
3316476b30 | ||
![]() |
0b1a19f343 |
34
.github/workflows/ci.yaml
vendored
34
.github/workflows/ci.yaml
vendored
@@ -30,22 +30,10 @@ jobs:
|
|||||||
libva-dev \
|
libva-dev \
|
||||||
libvpx-dev \
|
libvpx-dev \
|
||||||
libx264-dev
|
libx264-dev
|
||||||
- name: go vet
|
- name: Run Test Suite
|
||||||
run: go vet $(go list ./... | grep -v mmal)
|
run: make test
|
||||||
- name: go build
|
- uses: codecov/codecov-action@v1
|
||||||
run: go build $(go list ./... | grep -v mmal)
|
|
||||||
- name: go build without CGO
|
|
||||||
run: go build . pkg/...
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
- name: go test
|
|
||||||
run: go test -v -race -coverprofile=coverage.txt -covermode=atomic $(go list ./... | grep -v mmal)
|
|
||||||
- uses: codecov/codecov-action@v1
|
|
||||||
if: matrix.go == '1.15'
|
if: matrix.go == '1.15'
|
||||||
- name: go test without CGO
|
|
||||||
run: go test . pkg/... -v
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
build-darwin:
|
build-darwin:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -67,20 +55,8 @@ jobs:
|
|||||||
opus \
|
opus \
|
||||||
libvpx \
|
libvpx \
|
||||||
x264
|
x264
|
||||||
- name: go vet
|
- name: Run Test Suite
|
||||||
run: go vet $(go list ./... | grep -v mmal)
|
run: make test
|
||||||
- name: go build
|
|
||||||
run: go build $(go list ./... | grep -v mmal)
|
|
||||||
- name: go build without CGO
|
|
||||||
run: go build . pkg/...
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
- name: go test
|
|
||||||
run: go test -v -race $(go list ./... | grep -v mmal)
|
|
||||||
- name: go test without CGO
|
|
||||||
run: go test . pkg/... -v
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
check-licenses:
|
check-licenses:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Check Licenses
|
name: Check Licenses
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@
|
|||||||
*.out
|
*.out
|
||||||
|
|
||||||
scripts/cross
|
scripts/cross
|
||||||
|
coverage.txt
|
||||||
|
81
Makefile
Normal file
81
Makefile
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
docker_owner := lherman
|
||||||
|
docker_prefix := cross
|
||||||
|
toolchain_dockerfiles := dockerfiles
|
||||||
|
script_path := $(realpath scripts)
|
||||||
|
toolchain_path := $(script_path)/$(docker_prefix)
|
||||||
|
os_list := \
|
||||||
|
linux \
|
||||||
|
windows \
|
||||||
|
darwin
|
||||||
|
arch_list := \
|
||||||
|
armv7 \
|
||||||
|
arm64 \
|
||||||
|
x64
|
||||||
|
supported_platforms := \
|
||||||
|
linux-armv7 \
|
||||||
|
linux-arm64 \
|
||||||
|
linux-x64 \
|
||||||
|
windows-x64 \
|
||||||
|
darwin-x64
|
||||||
|
cmd_build := build
|
||||||
|
cmd_test := test
|
||||||
|
examples_dir := examples
|
||||||
|
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_mmal := $(shell go list ./... | grep -v mmal)
|
||||||
|
|
||||||
|
define BUILD_TEMPLATE
|
||||||
|
ifneq (,$$(findstring $(2)-$(3),$$(supported_platforms)))
|
||||||
|
$$(cmd_build)-$(1)-$(2)-$(3): toolchain-$(2)-$(3)
|
||||||
|
$$(MAKE) --directory=$$(codec_dir)/$(1) \
|
||||||
|
MEDIADEVICES_TOOLCHAIN_BIN=$$(toolchain_path)/$(docker_prefix)-$(2)-$(3) \
|
||||||
|
MEDIADEVICES_TARGET_PLATFORM=$(2)-$(3) \
|
||||||
|
MEDIADEVICES_TARGET_OS=$(2) \
|
||||||
|
MEDIADEVICES_TARGET_ARCH=$(3)
|
||||||
|
endif
|
||||||
|
endef
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(cmd_test) $(cmd_build)
|
||||||
|
|
||||||
|
# Subcommand:
|
||||||
|
# make build[-<codec_name>-<os>-<arch>]
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Build codec dependencies to multiple platforms.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# * make build: build all codecs for all supported platforms
|
||||||
|
# * make build-opus-darwin-x64: only build opus for darwin-x64 platform
|
||||||
|
$(cmd_build): $(targets)
|
||||||
|
|
||||||
|
toolchain-%: $(toolchain_dockerfiles)
|
||||||
|
$(MAKE) --directory=$< "$*" \
|
||||||
|
MEDIADEVICES_DOCKER_OWNER=$(docker_owner) \
|
||||||
|
MEDIADEVICES_DOCKER_PREFIX=$(docker_prefix)
|
||||||
|
@mkdir -p $(toolchain_path)
|
||||||
|
@docker run $(docker_owner)/$(docker_prefix)-$* > \
|
||||||
|
$(toolchain_path)/$(docker_prefix)-$*
|
||||||
|
@chmod +x $(toolchain_path)/$(docker_prefix)-$*
|
||||||
|
|
||||||
|
$(foreach codec, $(codec_list), \
|
||||||
|
$(foreach os, $(os_list), \
|
||||||
|
$(foreach arch, $(arch_list), \
|
||||||
|
$(eval $(call BUILD_TEMPLATE,$(codec),$(os),$(arch))))))
|
||||||
|
|
||||||
|
# Subcommand:
|
||||||
|
# make test
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# Run a series of tests
|
||||||
|
$(cmd_test):
|
||||||
|
go vet $(pkgs_without_mmal)
|
||||||
|
go build $(pkgs_without_mmal)
|
||||||
|
# go build without CGO
|
||||||
|
CGO_ENABLED=0 go build . pkg/...
|
||||||
|
# go build with CGO
|
||||||
|
CGO_ENABLED=1 go build $(pkgs_without_mmal)
|
||||||
|
$(MAKE) --directory=$(examples_dir)
|
||||||
|
go test -v -race -coverprofile=coverage.txt -covermode=atomic $(pkgs_without_mmal)
|
@@ -87,7 +87,7 @@ func main() {
|
|||||||
| Microphone | ✔️ | ✔️ | ✔️ |
|
| Microphone | ✔️ | ✔️ | ✔️ |
|
||||||
| Screen | ✔️ | ✔️ | ✔️ |
|
| Screen | ✔️ | ✔️ | ✔️ |
|
||||||
|
|
||||||
By default, there's no media input registered. This decision was made to allow you to pay what you need. Therefore, you need to import the associated packages for the media inputs. For example, if you want to use a camera, you need to import the camera package as a side effect:
|
By default, there's no media input registered. This decision was made to allow you to play only what you need. Therefore, you need to import the associated packages for the media inputs. For example, if you want to use a camera, you need to import the camera package as a side effect:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
|
70
build.sh
70
build.sh
@@ -1,70 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
MEDIADEVICES_TOOLCHAIN_OWNER=lherman
|
|
||||||
MEDIADEVICES_TOOLCHAIN_PREFIX=cross
|
|
||||||
MEDIADEVICES_SCRIPT_PATH=$(realpath ./scripts)
|
|
||||||
MEDIADEVICES_TOOLCHAIN_PATH=${MEDIADEVICES_SCRIPT_PATH}/${MEDIADEVICES_TOOLCHAIN_PREFIX}
|
|
||||||
MEDIADEVICES_DOCKERFILES_PATH=dockerfiles
|
|
||||||
|
|
||||||
# Reference: https://github.com/dockcross/dockcross#cross-compilers
|
|
||||||
MEDIADEVICES_TARGET_PLATFORMS=(
|
|
||||||
linux-armv7
|
|
||||||
linux-arm64
|
|
||||||
linux-x64
|
|
||||||
windows-x64
|
|
||||||
darwin-x64
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ -z ${VERBOSE} ]]; then
|
|
||||||
MEDIADEVICES_OUTPUT=/dev/null
|
|
||||||
else
|
|
||||||
MEDIADEVICES_OUTPUT=/dev/stdout
|
|
||||||
fi
|
|
||||||
|
|
||||||
install_toolchains() {
|
|
||||||
bash ${MEDIADEVICES_DOCKERFILES_PATH}/build.sh &> ${MEDIADEVICES_OUTPUT}
|
|
||||||
for platform in ${MEDIADEVICES_TARGET_PLATFORMS[@]}
|
|
||||||
do
|
|
||||||
mkdir -p ${MEDIADEVICES_TOOLCHAIN_PATH}
|
|
||||||
image=${MEDIADEVICES_TOOLCHAIN_OWNER}/${MEDIADEVICES_TOOLCHAIN_PREFIX}-${platform}
|
|
||||||
bin_path=${MEDIADEVICES_TOOLCHAIN_PATH}/${MEDIADEVICES_TOOLCHAIN_PREFIX}-${platform}
|
|
||||||
docker run ${image} > ${bin_path}
|
|
||||||
chmod +x ${bin_path}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
sub_builds=$(find pkg -type f -name "build.sh")
|
|
||||||
for sub_build in ${sub_builds[@]}
|
|
||||||
do
|
|
||||||
sub_build=$(realpath ${sub_build})
|
|
||||||
sub_build_dir=$(dirname ${sub_build})
|
|
||||||
current_dir=${PWD}
|
|
||||||
cd $sub_build_dir
|
|
||||||
for platform in ${MEDIADEVICES_TARGET_PLATFORMS[@]}
|
|
||||||
do
|
|
||||||
export MEDIADEVICES_TOOLCHAIN_BIN=${MEDIADEVICES_TOOLCHAIN_PATH}/${MEDIADEVICES_TOOLCHAIN_PREFIX}-${platform}
|
|
||||||
# convert '-' to '_' since '_' is more common in library names
|
|
||||||
export MEDIADEVICES_TARGET_PLATFORM=${platform//-/_}
|
|
||||||
export MEDIADEVICES_TARGET_OS=$(echo $MEDIADEVICES_TARGET_PLATFORM | cut -d'_' -f1)
|
|
||||||
export MEDIADEVICES_TARGET_ARCH=${platform//${MEDIADEVICES_TARGET_OS}-/}
|
|
||||||
|
|
||||||
echo "Building ${sub_build_dir}:"
|
|
||||||
echo " PLATFORM : ${MEDIADEVICES_TARGET_PLATFORM}"
|
|
||||||
echo " OS : ${MEDIADEVICES_TARGET_OS}"
|
|
||||||
echo " ARCH : ${MEDIADEVICES_TARGET_ARCH}"
|
|
||||||
echo " TOOLCHAIN_BIN : ${MEDIADEVICES_TOOLCHAIN_BIN}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
${sub_build} &> ${MEDIADEVICES_OUTPUT}
|
|
||||||
done
|
|
||||||
cd ${current_dir}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ $# > 0 && $1 != "all" ]]; then
|
|
||||||
MEDIADEVICES_TARGET_PLATFORMS=($1)
|
|
||||||
fi
|
|
||||||
|
|
||||||
install_toolchains
|
|
||||||
build
|
|
11
dockerfiles/Makefile
Normal file
11
dockerfiles/Makefile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
dockerfiles := $(wildcard *.Dockerfile)
|
||||||
|
supported_platforms := $(dockerfiles:.Dockerfile=)
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(supported_platforms)
|
||||||
|
|
||||||
|
%: %.Dockerfile guard-MEDIADEVICES_DOCKER_OWNER guard-MEDIADEVICES_DOCKER_PREFIX
|
||||||
|
docker build -t "$(MEDIADEVICES_DOCKER_OWNER)/$(MEDIADEVICES_DOCKER_PREFIX)-$@" -f "$<" .
|
||||||
|
|
||||||
|
guard-%:
|
||||||
|
@if [ -z ${$*} ]; then echo "$* is a required environment variable"; exit 1; fi
|
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd $(dirname $0)
|
|
||||||
|
|
||||||
OWNER=lherman
|
|
||||||
PREFIX=cross
|
|
||||||
IMAGES=$(ls *.Dockerfile)
|
|
||||||
|
|
||||||
for image in ${IMAGES[@]}
|
|
||||||
do
|
|
||||||
tag=${OWNER}/cross-${image//.Dockerfile/}
|
|
||||||
docker build -t "${tag}" -f "$image" .
|
|
||||||
done
|
|
8
examples/Makefile
Normal file
8
examples/Makefile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
examples := $(shell find * -maxdepth 0 -type d)
|
||||||
|
examples := $(filter-out internal,$(examples))
|
||||||
|
|
||||||
|
.PHONY: all $(examples)
|
||||||
|
all: $(examples)
|
||||||
|
|
||||||
|
$(examples):
|
||||||
|
cd $@ && go build
|
@@ -43,7 +43,7 @@ func main() {
|
|||||||
|
|
||||||
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
||||||
Video: func(c *mediadevices.MediaTrackConstraints) {
|
Video: func(c *mediadevices.MediaTrackConstraints) {
|
||||||
c.FrameFormat = prop.FrameFormat(frame.FormatYUY2)
|
c.FrameFormat = prop.FrameFormat(frame.FormatI420)
|
||||||
c.Width = prop.Int(640)
|
c.Width = prop.Int(640)
|
||||||
c.Height = prop.Int(480)
|
c.Height = prop.Int(480)
|
||||||
},
|
},
|
||||||
|
@@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
pigo "github.com/esimov/pigo/core"
|
pigo "github.com/esimov/pigo/core"
|
||||||
"github.com/pion/mediadevices"
|
"github.com/pion/mediadevices"
|
||||||
_ "github.com/pion/mediadevices/pkg/driver/camera" // This is required to register camera adapter
|
|
||||||
"github.com/pion/mediadevices/pkg/frame"
|
"github.com/pion/mediadevices/pkg/frame"
|
||||||
|
_ "github.com/pion/mediadevices/pkg/driver/camera" // This is required to register camera adapter
|
||||||
"github.com/pion/mediadevices/pkg/prop"
|
"github.com/pion/mediadevices/pkg/prop"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ func main() {
|
|||||||
|
|
||||||
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
||||||
Video: func(c *mediadevices.MediaTrackConstraints) {
|
Video: func(c *mediadevices.MediaTrackConstraints) {
|
||||||
c.FrameFormat = prop.FrameFormatExact(frame.FormatUYVY)
|
c.FrameFormat = prop.FrameFormatOneOf{frame.FormatI420, frame.FormatYUY2}
|
||||||
c.Width = prop.Int(640)
|
c.Width = prop.Int(640)
|
||||||
c.Height = prop.Int(480)
|
c.Height = prop.Int(480)
|
||||||
},
|
},
|
||||||
@@ -97,7 +97,7 @@ func main() {
|
|||||||
frame, release, err := videoReader.Read()
|
frame, release, err := videoReader.Read()
|
||||||
must(err)
|
must(err)
|
||||||
|
|
||||||
// Since we asked the frame format to be exactly YUY2 in GetUserMedia, we can guarantee that it must be YCbCr
|
// Since we asked the frame format to be exactly I420/YUY2 in GetUserMedia, we can guarantee that it must be YCbCr
|
||||||
if detectFace(frame.(*image.YCbCr)) {
|
if detectFace(frame.(*image.YCbCr)) {
|
||||||
log.Println("Detect a face")
|
log.Println("Detect a face")
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ func main() {
|
|||||||
|
|
||||||
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
||||||
Video: func(c *mediadevices.MediaTrackConstraints) {
|
Video: func(c *mediadevices.MediaTrackConstraints) {
|
||||||
c.FrameFormat = prop.FrameFormat(frame.FormatYUY2)
|
c.FrameFormat = prop.FrameFormat(frame.FormatI420)
|
||||||
c.Width = prop.Int(640)
|
c.Width = prop.Int(640)
|
||||||
c.Height = prop.Int(480)
|
c.Height = prop.Int(480)
|
||||||
},
|
},
|
||||||
|
@@ -71,7 +71,7 @@ func main() {
|
|||||||
|
|
||||||
s, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
s, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
|
||||||
Video: func(c *mediadevices.MediaTrackConstraints) {
|
Video: func(c *mediadevices.MediaTrackConstraints) {
|
||||||
c.FrameFormat = prop.FrameFormat(frame.FormatYUY2)
|
c.FrameFormat = prop.FrameFormat(frame.FormatI420)
|
||||||
c.Width = prop.Int(640)
|
c.Width = prop.Int(640)
|
||||||
c.Height = prop.Int(480)
|
c.Height = prop.Int(480)
|
||||||
},
|
},
|
||||||
@@ -111,13 +111,23 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create channel that is blocked until ICE Gathering is complete
|
||||||
|
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
|
||||||
|
|
||||||
// Sets the LocalDescription, and starts our UDP listeners
|
// Sets the LocalDescription, and starts our UDP listeners
|
||||||
err = peerConnection.SetLocalDescription(answer)
|
err = peerConnection.SetLocalDescription(answer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Block until ICE Gathering is complete, disabling trickle ICE
|
||||||
|
// we do this because we only can exchange one signaling message
|
||||||
|
// in a production application you should exchange ICE Candidates via OnICECandidate
|
||||||
|
<-gatherComplete
|
||||||
|
|
||||||
// Output the answer in base64 so we can paste it in browser
|
// Output the answer in base64 so we can paste it in browser
|
||||||
fmt.Println(signal.Encode(answer))
|
fmt.Println(signal.Encode(*peerConnection.LocalDescription()))
|
||||||
|
|
||||||
|
// Block forever
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
9
go.mod
9
go.mod
@@ -5,16 +5,15 @@ go 1.13
|
|||||||
require (
|
require (
|
||||||
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd // indirect
|
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd // indirect
|
||||||
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539
|
github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539
|
||||||
github.com/gen2brain/malgo v0.10.27
|
github.com/gen2brain/malgo v0.10.29
|
||||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
|
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
|
||||||
github.com/google/uuid v1.1.2
|
github.com/google/uuid v1.2.0
|
||||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||||
github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55 // indirect
|
github.com/lxn/win v0.0.0-20201111105847-2a20daff6a55 // indirect
|
||||||
github.com/pion/logging v0.2.2
|
github.com/pion/logging v0.2.2
|
||||||
github.com/pion/rtp v1.6.2
|
github.com/pion/rtp v1.6.2
|
||||||
github.com/pion/webrtc/v3 v3.0.0
|
github.com/pion/webrtc/v3 v3.0.5
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5
|
golang.org/x/image v0.0.0-20201208152932-35266b937fa6
|
||||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 // indirect
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
49
go.sum
49
go.sum
@@ -7,8 +7,8 @@ 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/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.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/gen2brain/malgo v0.10.27 h1:KlNitZIO8V4W2VnjtTM8AGMy/XBb2pN+fnIB5bEps8E=
|
github.com/gen2brain/malgo v0.10.29 h1:bTYiUTUKJsEomNby+W0hgyLrOttUXIk4lTEnKA54iqM=
|
||||||
github.com/gen2brain/malgo v0.10.27/go.mod h1:zHSUNZAXfCeNsZou0RtQ6Zk7gDYLIcKOrUWtAdksnEs=
|
github.com/gen2brain/malgo v0.10.29/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 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
|
||||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@@ -21,8 +21,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
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.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.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f h1:5hWo+DzJQSOBl6X+TDac0SPWffRonuRJ2///OYtYRT8=
|
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f h1:5hWo+DzJQSOBl6X+TDac0SPWffRonuRJ2///OYtYRT8=
|
||||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5V3lRzakvEyr49P7hHRYoHtPr8zvj/7JodCoRzw=
|
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5V3lRzakvEyr49P7hHRYoHtPr8zvj/7JodCoRzw=
|
||||||
@@ -45,42 +46,41 @@ github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXm
|
|||||||
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
|
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
|
||||||
github.com/pion/dtls/v2 v2.0.4 h1:WuUcqi6oYMu/noNTz92QrF1DaFj4eXbhQ6dzaaAwOiI=
|
github.com/pion/dtls/v2 v2.0.4 h1:WuUcqi6oYMu/noNTz92QrF1DaFj4eXbhQ6dzaaAwOiI=
|
||||||
github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI=
|
github.com/pion/dtls/v2 v2.0.4/go.mod h1:qAkFscX0ZHoI1E07RfYPoRw3manThveu+mlTDdOxoGI=
|
||||||
github.com/pion/ice/v2 v2.0.14 h1:FxXxauyykf89SWAtkQCfnHkno6G8+bhRkNguSh9zU+4=
|
github.com/pion/ice/v2 v2.0.15 h1:KZrwa2ciL9od8+TUVJiYTNsCW9J5lktBjGwW1MacEnQ=
|
||||||
github.com/pion/ice/v2 v2.0.14/go.mod h1:wqaUbOq5ObDNU5ox1hRsEst0rWfsKuH1zXjQFEWiZwM=
|
github.com/pion/ice/v2 v2.0.15/go.mod h1:ZIiVGevpgAxF/cXiIVmuIUtCb3Xs4gCzCbXB6+nFkSI=
|
||||||
github.com/pion/interceptor v0.0.8 h1:qsVJv9RF7mPq/RUnUV5iZCzxwGizO880FuiFKkEGQaE=
|
github.com/pion/interceptor v0.0.9 h1:fk5hTdyLO3KURQsf/+RjMpEm4NE3yeTY9Kh97b5BvwA=
|
||||||
github.com/pion/interceptor v0.0.8/go.mod h1:dHgEP5dtxOTf21MObuBAjJeAayPxLUAZjerGH8Xr07c=
|
github.com/pion/interceptor v0.0.9/go.mod h1:dHgEP5dtxOTf21MObuBAjJeAayPxLUAZjerGH8Xr07c=
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
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/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||||
github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
|
github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
|
||||||
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
|
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
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/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
|
|
||||||
github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
|
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/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
|
||||||
github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
|
||||||
github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U=
|
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.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||||
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
||||||
github.com/pion/sctp v1.7.11 h1:UCnj7MsobLKLuP/Hh+JMiI/6W5Bs/VF45lWKgHFjSIE=
|
github.com/pion/sctp v1.7.11 h1:UCnj7MsobLKLuP/Hh+JMiI/6W5Bs/VF45lWKgHFjSIE=
|
||||||
github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
github.com/pion/sctp v1.7.11/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
||||||
github.com/pion/sdp/v3 v3.0.3 h1:gJK9hk+JFD2NGIM1nXmqNCq1DkVaIZ9dlA3u3otnkaw=
|
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
|
||||||
github.com/pion/sdp/v3 v3.0.3/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
|
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
|
||||||
github.com/pion/srtp/v2 v2.0.0-rc.3 h1:1fPiK1nJlNyh235tSGgBnXrPc99wK1/D707f6ntb3qY=
|
github.com/pion/srtp/v2 v2.0.1 h1:kgfh65ob3EcnFYA4kUBvU/menCp9u7qaJLXwWgpobzs=
|
||||||
github.com/pion/srtp/v2 v2.0.0-rc.3/go.mod h1:S6J9oY6ahAXdU3ni4nUwhWTJuBfssFjPxoB0u41TBpY=
|
github.com/pion/srtp/v2 v2.0.1/go.mod h1:c8NWHhhkFf/drmHTAblkdu8++lsISEBBdAuiyxgqIsE=
|
||||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
||||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
||||||
github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
|
github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
|
||||||
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
|
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
|
||||||
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
|
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
|
||||||
github.com/pion/transport v0.12.0 h1:UFmOBBZkTZ3LgvLRf/NGrfWdZEubcU6zkLU3PsA9YvU=
|
github.com/pion/transport v0.12.1/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
||||||
github.com/pion/transport v0.12.0/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
github.com/pion/transport v0.12.2 h1:WYEjhloRHt1R86LhUKjC5y+P52Y11/QqEUalvtzVoys=
|
||||||
|
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
||||||
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
|
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
|
||||||
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
|
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
|
||||||
github.com/pion/udp v0.1.0 h1:uGxQsNyrqG3GLINv36Ff60covYmfrLoxzwnCsIYspXI=
|
github.com/pion/udp v0.1.0 h1:uGxQsNyrqG3GLINv36Ff60covYmfrLoxzwnCsIYspXI=
|
||||||
github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
|
github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
|
||||||
github.com/pion/webrtc/v3 v3.0.0 h1:/eTiY3NbfpKj5op8cqtCZlpTv9/yumd17YRinDNOUX0=
|
github.com/pion/webrtc/v3 v3.0.5 h1:utennp7RwX+2mtyMzoOXE03IUIckiHBigjarRJZ2DqY=
|
||||||
github.com/pion/webrtc/v3 v3.0.0/go.mod h1:/xwKHOAk1Y8dspJcxMwuTtxpi8t/Gzks37iB3W6hNuM=
|
github.com/pion/webrtc/v3 v3.0.5/go.mod h1:/EDCREM8y+JrJSkoCRHpoz//qtuBCOYV4E96vEK3bz0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -93,12 +93,14 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
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=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -109,6 +111,8 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8=
|
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8=
|
||||||
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/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 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||||
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -120,8 +124,9 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-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-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
@@ -45,6 +45,7 @@ typedef enum AVBindMediaType {
|
|||||||
typedef enum AVBindFrameFormat {
|
typedef enum AVBindFrameFormat {
|
||||||
AVBindFrameFormatI420,
|
AVBindFrameFormatI420,
|
||||||
AVBindFrameFormatNV21,
|
AVBindFrameFormatNV21,
|
||||||
|
AVBindFrameFormatNV12,
|
||||||
AVBindFrameFormatYUY2,
|
AVBindFrameFormatYUY2,
|
||||||
AVBindFrameFormatUYVY,
|
AVBindFrameFormatUYVY,
|
||||||
} AVBindFrameFormat;
|
} AVBindFrameFormat;
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// Copyright (c) 2019-2020 Pion
|
// Copyright (c) 2019-2020 Pion
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
// in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
// furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
// copies or substantial portions of the Software.
|
// copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@@ -76,29 +76,23 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
|||||||
!CMSampleBufferDataIsReady(sampleBuffer)) {
|
!CMSampleBufferDataIsReady(sampleBuffer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||||
if (imageBuffer == NULL) {
|
if (imageBuffer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
imageBuffer = CVBufferRetain(imageBuffer);
|
imageBuffer = CVBufferRetain(imageBuffer);
|
||||||
CVReturn ret =
|
CVReturn ret =
|
||||||
CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
|
CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
|
||||||
if (ret != kCVReturnSuccess) {
|
if (ret != kCVReturnSuccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t heightY = CVPixelBufferGetHeightOfPlane(imageBuffer, 0);
|
|
||||||
size_t bytesPerRowY = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);
|
|
||||||
|
|
||||||
size_t heightUV = CVPixelBufferGetHeightOfPlane(imageBuffer, 1);
|
|
||||||
size_t bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 1);
|
|
||||||
|
|
||||||
int len = (int)((heightY * bytesPerRowY) + (2 * heightUV * bytesPerRowUV));
|
|
||||||
void *buf = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
|
void *buf = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
|
||||||
_mCallback(_mPUserData, buf, len);
|
size_t dataSize = CVPixelBufferGetDataSize(imageBuffer);
|
||||||
|
_mCallback(_mPUserData, buf, (int)dataSize);
|
||||||
|
|
||||||
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
|
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
|
||||||
CVBufferRelease(imageBuffer);
|
CVBufferRelease(imageBuffer);
|
||||||
}
|
}
|
||||||
@@ -133,13 +127,24 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
|||||||
|
|
||||||
STATUS frameFormatToFourCC(AVBindFrameFormat format, FourCharCode *pFourCC) {
|
STATUS frameFormatToFourCC(AVBindFrameFormat format, FourCharCode *pFourCC) {
|
||||||
STATUS retStatus = STATUS_OK;
|
STATUS retStatus = STATUS_OK;
|
||||||
|
// Useful mapping reference from ffmpeg:
|
||||||
|
// https://github.com/FFmpeg/FFmpeg/blob/c810a9502cebe32e1dd08ee3d0d17053dde44aa9/libavdevice/avfoundation.m#L53-L80
|
||||||
switch (format) {
|
switch (format) {
|
||||||
|
case AVBindFrameFormatI420:
|
||||||
|
*pFourCC = kCVPixelFormatType_420YpCbCr8Planar;
|
||||||
|
break;
|
||||||
case AVBindFrameFormatNV21:
|
case AVBindFrameFormatNV21:
|
||||||
*pFourCC = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
|
*pFourCC = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
|
||||||
break;
|
break;
|
||||||
|
case AVBindFrameFormatNV12:
|
||||||
|
*pFourCC = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
|
||||||
|
break;
|
||||||
case AVBindFrameFormatUYVY:
|
case AVBindFrameFormatUYVY:
|
||||||
*pFourCC = kCVPixelFormatType_422YpCbCr8;
|
*pFourCC = kCVPixelFormatType_422YpCbCr8;
|
||||||
break;
|
break;
|
||||||
|
case AVBindFrameFormatYUY2:
|
||||||
|
*pFourCC = kCVPixelFormatType_422YpCbCr8_yuvs;
|
||||||
|
break;
|
||||||
// TODO: Add the rest of frame formats
|
// TODO: Add the rest of frame formats
|
||||||
default:
|
default:
|
||||||
retStatus = STATUS_UNSUPPORTED_FRAME_FORMAT;
|
retStatus = STATUS_UNSUPPORTED_FRAME_FORMAT;
|
||||||
@@ -150,12 +155,21 @@ STATUS frameFormatToFourCC(AVBindFrameFormat format, FourCharCode *pFourCC) {
|
|||||||
STATUS frameFormatFromFourCC(FourCharCode fourCC, AVBindFrameFormat *pFormat) {
|
STATUS frameFormatFromFourCC(FourCharCode fourCC, AVBindFrameFormat *pFormat) {
|
||||||
STATUS retStatus = STATUS_OK;
|
STATUS retStatus = STATUS_OK;
|
||||||
switch (fourCC) {
|
switch (fourCC) {
|
||||||
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
|
case kCVPixelFormatType_420YpCbCr8Planar:
|
||||||
*pFormat = AVBindFrameFormatNV21;
|
*pFormat = AVBindFrameFormatI420;
|
||||||
break;
|
break;
|
||||||
case kCVPixelFormatType_422YpCbCr8:
|
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
|
||||||
*pFormat = AVBindFrameFormatUYVY;
|
*pFormat = AVBindFrameFormatNV21;
|
||||||
break;
|
break;
|
||||||
|
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
|
||||||
|
*pFormat = AVBindFrameFormatNV12;
|
||||||
|
break;
|
||||||
|
case kCVPixelFormatType_422YpCbCr8:
|
||||||
|
*pFormat = AVBindFrameFormatUYVY;
|
||||||
|
break;
|
||||||
|
case kCVPixelFormatType_422YpCbCr8_yuvs:
|
||||||
|
*pFormat = AVBindFrameFormatYUY2;
|
||||||
|
break;
|
||||||
// TODO: Add the rest of frame formats
|
// TODO: Add the rest of frame formats
|
||||||
default:
|
default:
|
||||||
retStatus = STATUS_UNSUPPORTED_FRAME_FORMAT;
|
retStatus = STATUS_UNSUPPORTED_FRAME_FORMAT;
|
||||||
@@ -170,7 +184,7 @@ STATUS AVBindDevices(AVBindMediaType mediaType, PAVBindDevice *ppDevices, int *p
|
|||||||
NSAutoreleasePool *refPool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool *refPool = [[NSAutoreleasePool alloc] init];
|
||||||
CHK(mediaType == AVBindMediaTypeVideo || mediaType == AVBindMediaTypeAudio, STATUS_UNSUPPORTED_MEDIA_TYPE);
|
CHK(mediaType == AVBindMediaTypeVideo || mediaType == AVBindMediaTypeAudio, STATUS_UNSUPPORTED_MEDIA_TYPE);
|
||||||
CHK(ppDevices != NULL && pLen != NULL, STATUS_NULL_ARG);
|
CHK(ppDevices != NULL && pLen != NULL, STATUS_NULL_ARG);
|
||||||
|
|
||||||
PAVBindDevice pDevice;
|
PAVBindDevice pDevice;
|
||||||
AVMediaType _mediaType = mediaType == AVBindMediaTypeVideo ? AVMediaTypeVideo : AVMediaTypeAudio;
|
AVMediaType _mediaType = mediaType == AVBindMediaTypeVideo ? AVMediaTypeVideo : AVMediaTypeAudio;
|
||||||
NSArray *refAllTypes = @[
|
NSArray *refAllTypes = @[
|
||||||
@@ -182,22 +196,22 @@ STATUS AVBindDevices(AVBindMediaType mediaType, PAVBindDevice *ppDevices, int *p
|
|||||||
discoverySessionWithDeviceTypes: refAllTypes
|
discoverySessionWithDeviceTypes: refAllTypes
|
||||||
mediaType: _mediaType
|
mediaType: _mediaType
|
||||||
position: AVCaptureDevicePositionUnspecified];
|
position: AVCaptureDevicePositionUnspecified];
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (AVCaptureDevice *refDevice in refSession.devices) {
|
for (AVCaptureDevice *refDevice in refSession.devices) {
|
||||||
if (i >= MAX_DEVICES) {
|
if (i >= MAX_DEVICES) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDevice = devices + i;
|
pDevice = devices + i;
|
||||||
strncpy(pDevice->uid, refDevice.uniqueID.UTF8String, MAX_DEVICE_UID_CHARS);
|
strncpy(pDevice->uid, refDevice.uniqueID.UTF8String, MAX_DEVICE_UID_CHARS);
|
||||||
pDevice->uid[MAX_DEVICE_UID_CHARS] = '\0';
|
pDevice->uid[MAX_DEVICE_UID_CHARS] = '\0';
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ppDevices = devices;
|
*ppDevices = devices;
|
||||||
*pLen = i;
|
*pLen = i;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
[refPool drain];
|
[refPool drain];
|
||||||
return retStatus;
|
return retStatus;
|
||||||
@@ -217,7 +231,7 @@ STATUS AVBindSessionInit(AVBindDevice device, PAVBindSession *ppSessionResult) {
|
|||||||
pSession->device = device;
|
pSession->device = device;
|
||||||
pSession->refCaptureSession = NULL;
|
pSession->refCaptureSession = NULL;
|
||||||
*ppSessionResult = pSession;
|
*ppSessionResult = pSession;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
return retStatus;
|
return retStatus;
|
||||||
}
|
}
|
||||||
@@ -244,15 +258,15 @@ STATUS AVBindSessionOpen(PAVBindSession pSession,
|
|||||||
STATUS retStatus = STATUS_OK;
|
STATUS retStatus = STATUS_OK;
|
||||||
NSAutoreleasePool *refPool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool *refPool = [[NSAutoreleasePool alloc] init];
|
||||||
CHK(pSession != NULL && dataCallback != NULL, STATUS_NULL_ARG);
|
CHK(pSession != NULL && dataCallback != NULL, STATUS_NULL_ARG);
|
||||||
|
|
||||||
AVCaptureDeviceInput *refInput;
|
AVCaptureDeviceInput *refInput;
|
||||||
NSError *refErr = NULL;
|
NSError *refErr = NULL;
|
||||||
NSString *refUID = [NSString stringWithUTF8String: pSession->device.uid];
|
NSString *refUID = [NSString stringWithUTF8String: pSession->device.uid];
|
||||||
AVCaptureDevice *refDevice = [AVCaptureDevice deviceWithUniqueID: refUID];
|
AVCaptureDevice *refDevice = [AVCaptureDevice deviceWithUniqueID: refUID];
|
||||||
|
|
||||||
refInput = [[AVCaptureDeviceInput alloc] initWithDevice: refDevice error: &refErr];
|
refInput = [[AVCaptureDeviceInput alloc] initWithDevice: refDevice error: &refErr];
|
||||||
CHK(refErr == NULL, STATUS_DEVICE_INIT_FAILED);
|
CHK(refErr == NULL, STATUS_DEVICE_INIT_FAILED);
|
||||||
|
|
||||||
AVCaptureSession *refCaptureSession = [[AVCaptureSession alloc] init];
|
AVCaptureSession *refCaptureSession = [[AVCaptureSession alloc] init];
|
||||||
refCaptureSession.sessionPreset = AVCaptureSessionPresetMedium;
|
refCaptureSession.sessionPreset = AVCaptureSessionPresetMedium;
|
||||||
[refCaptureSession addInput: refInput];
|
[refCaptureSession addInput: refInput];
|
||||||
@@ -261,7 +275,7 @@ STATUS AVBindSessionOpen(PAVBindSession pSession,
|
|||||||
VideoDataDelegate *pDelegate = [[VideoDataDelegate alloc]
|
VideoDataDelegate *pDelegate = [[VideoDataDelegate alloc]
|
||||||
init: dataCallback
|
init: dataCallback
|
||||||
withUserData: pUserData];
|
withUserData: pUserData];
|
||||||
|
|
||||||
AVCaptureVideoDataOutput *pOutput = [[AVCaptureVideoDataOutput alloc] init];
|
AVCaptureVideoDataOutput *pOutput = [[AVCaptureVideoDataOutput alloc] init];
|
||||||
FourCharCode fourCC;
|
FourCharCode fourCC;
|
||||||
CHK_STATUS(frameFormatToFourCC(property.frameFormat, &fourCC));
|
CHK_STATUS(frameFormatToFourCC(property.frameFormat, &fourCC));
|
||||||
@@ -279,10 +293,10 @@ STATUS AVBindSessionOpen(PAVBindSession pSession,
|
|||||||
} else {
|
} else {
|
||||||
// TODO: implement audio pipeline
|
// TODO: implement audio pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
pSession->refCaptureSession = [refCaptureSession retain];
|
pSession->refCaptureSession = [refCaptureSession retain];
|
||||||
[refCaptureSession startRunning];
|
[refCaptureSession startRunning];
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
[refPool drain];
|
[refPool drain];
|
||||||
return retStatus;
|
return retStatus;
|
||||||
@@ -293,20 +307,30 @@ STATUS AVBindSessionClose(PAVBindSession pSession) {
|
|||||||
STATUS retStatus = STATUS_OK;
|
STATUS retStatus = STATUS_OK;
|
||||||
CHK(pSession != NULL, STATUS_NULL_ARG);
|
CHK(pSession != NULL, STATUS_NULL_ARG);
|
||||||
CHK(pSession->refCaptureSession != NULL, STATUS_OK);
|
CHK(pSession->refCaptureSession != NULL, STATUS_OK);
|
||||||
|
|
||||||
[pSession->refCaptureSession stopRunning];
|
[pSession->refCaptureSession stopRunning];
|
||||||
[pSession->refCaptureSession release];
|
[pSession->refCaptureSession release];
|
||||||
pSession->refCaptureSession = NULL;
|
pSession->refCaptureSession = NULL;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
return retStatus;
|
return retStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NSString* FourCCString(FourCharCode code) {
|
||||||
|
NSString *result = [NSString stringWithFormat:@"%c%c%c%c",
|
||||||
|
(code >> 24) & 0xff,
|
||||||
|
(code >> 16) & 0xff,
|
||||||
|
(code >> 8) & 0xff,
|
||||||
|
code & 0xff];
|
||||||
|
NSCharacterSet *characterSet = [NSCharacterSet whitespaceCharacterSet];
|
||||||
|
return [result stringByTrimmingCharactersInSet:characterSet];
|
||||||
|
}
|
||||||
|
|
||||||
STATUS AVBindSessionProperties(PAVBindSession pSession, PAVBindMediaProperty *ppProperties, int *pLen) {
|
STATUS AVBindSessionProperties(PAVBindSession pSession, PAVBindMediaProperty *ppProperties, int *pLen) {
|
||||||
STATUS retStatus = STATUS_OK;
|
STATUS retStatus = STATUS_OK;
|
||||||
NSAutoreleasePool *refPool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool *refPool = [[NSAutoreleasePool alloc] init];
|
||||||
CHK(pSession != NULL && ppProperties != NULL && pLen != NULL, STATUS_NULL_ARG);
|
CHK(pSession != NULL && ppProperties != NULL && pLen != NULL, STATUS_NULL_ARG);
|
||||||
|
|
||||||
NSString *refDeviceUID = [NSString stringWithUTF8String: pSession->device.uid];
|
NSString *refDeviceUID = [NSString stringWithUTF8String: pSession->device.uid];
|
||||||
AVCaptureDevice *refDevice = [AVCaptureDevice deviceWithUniqueID: refDeviceUID];
|
AVCaptureDevice *refDevice = [AVCaptureDevice deviceWithUniqueID: refDeviceUID];
|
||||||
FourCharCode fourCC;
|
FourCharCode fourCC;
|
||||||
@@ -319,15 +343,17 @@ STATUS AVBindSessionProperties(PAVBindSession pSession, PAVBindMediaProperty *pp
|
|||||||
for (AVCaptureDeviceFormat *refFormat in refDevice.formats) {
|
for (AVCaptureDeviceFormat *refFormat in refDevice.formats) {
|
||||||
// TODO: Probably gives a warn to the user
|
// TODO: Probably gives a warn to the user
|
||||||
if (len >= MAX_PROPERTIES) {
|
if (len >= MAX_PROPERTIES) {
|
||||||
|
NSLog(@"[WARNING] skipping the rest of properties due to MAX_PROPERTIES");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([refFormat.mediaType isEqual:AVMediaTypeVideo]) {
|
if ([refFormat.mediaType isEqual:AVMediaTypeVideo]) {
|
||||||
fourCC = CMFormatDescriptionGetMediaSubType(refFormat.formatDescription);
|
fourCC = CMFormatDescriptionGetMediaSubType(refFormat.formatDescription);
|
||||||
if (frameFormatFromFourCC(fourCC, &pProperty->frameFormat) != STATUS_OK) {
|
if (frameFormatFromFourCC(fourCC, &pProperty->frameFormat) != STATUS_OK) {
|
||||||
|
NSLog(@"[WARNING] skipping %@ %dx%d since it's not supported", FourCCString(fourCC), videoDimensions.width, videoDimensions.height);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
videoFormat = (CMVideoFormatDescriptionRef) refFormat.formatDescription;
|
videoFormat = (CMVideoFormatDescriptionRef) refFormat.formatDescription;
|
||||||
videoDimensions = CMVideoFormatDescriptionGetDimensions(videoFormat);
|
videoDimensions = CMVideoFormatDescriptionGetDimensions(videoFormat);
|
||||||
pProperty->height = videoDimensions.height;
|
pProperty->height = videoDimensions.height;
|
||||||
@@ -335,16 +361,16 @@ STATUS AVBindSessionProperties(PAVBindSession pSession, PAVBindMediaProperty *pp
|
|||||||
} else {
|
} else {
|
||||||
// TODO: Get audio properties
|
// TODO: Get audio properties
|
||||||
}
|
}
|
||||||
|
|
||||||
pProperty++;
|
pProperty++;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ppProperties = pSession->properties;
|
*ppProperties = pSession->properties;
|
||||||
*pLen = len;
|
*pLen = len;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
||||||
[refPool drain];
|
[refPool drain];
|
||||||
return retStatus;
|
return retStatus;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package avfoundation
|
package avfoundation
|
||||||
|
|
||||||
// extern void onData(void*, void*, int);
|
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
@@ -18,11 +17,10 @@ type handleID int
|
|||||||
|
|
||||||
//export onData
|
//export onData
|
||||||
func onData(userData unsafe.Pointer, buf unsafe.Pointer, length C.int) {
|
func onData(userData unsafe.Pointer, buf unsafe.Pointer, length C.int) {
|
||||||
data := C.GoBytes(buf, length)
|
|
||||||
|
|
||||||
handleNum := (*C.int)(userData)
|
handleNum := (*C.int)(userData)
|
||||||
cb, ok := lookup(handleID(*handleNum))
|
cb, ok := lookup(handleID(*handleNum))
|
||||||
if ok {
|
if ok {
|
||||||
|
data := C.GoBytes(buf, length)
|
||||||
cb(data)
|
cb(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,8 @@ func frameFormatToAVBind(f frame.Format) (C.AVBindFrameFormat, bool) {
|
|||||||
return C.AVBindFrameFormatI420, true
|
return C.AVBindFrameFormatI420, true
|
||||||
case frame.FormatNV21:
|
case frame.FormatNV21:
|
||||||
return C.AVBindFrameFormatNV21, true
|
return C.AVBindFrameFormatNV21, true
|
||||||
|
case frame.FormatNV12:
|
||||||
|
return C.AVBindFrameFormatNV12, true
|
||||||
case frame.FormatYUY2:
|
case frame.FormatYUY2:
|
||||||
return C.AVBindFrameFormatYUY2, true
|
return C.AVBindFrameFormatYUY2, true
|
||||||
case frame.FormatUYVY:
|
case frame.FormatUYVY:
|
||||||
@@ -55,6 +57,8 @@ func frameFormatFromAVBind(f C.AVBindFrameFormat) (frame.Format, bool) {
|
|||||||
return frame.FormatI420, true
|
return frame.FormatI420, true
|
||||||
case C.AVBindFrameFormatNV21:
|
case C.AVBindFrameFormatNV21:
|
||||||
return frame.FormatNV21, true
|
return frame.FormatNV21, true
|
||||||
|
case C.AVBindFrameFormatNV12:
|
||||||
|
return frame.FormatNV12, true
|
||||||
case C.AVBindFrameFormatYUY2:
|
case C.AVBindFrameFormatYUY2:
|
||||||
return frame.FormatYUY2, true
|
return frame.FormatYUY2, true
|
||||||
case C.AVBindFrameFormatUYVY:
|
case C.AVBindFrameFormatUYVY:
|
||||||
|
47
pkg/codec/openh264/Makefile
Normal file
47
pkg/codec/openh264/Makefile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
git_url := https://github.com/cisco/openh264.git
|
||||||
|
version := v2.1.1
|
||||||
|
src_root_dir := src
|
||||||
|
lib_dir := lib
|
||||||
|
include_dir := include/openh264
|
||||||
|
lib_prefix := libopenh264
|
||||||
|
src_dir := $(src_root_dir)/$(MEDIADEVICES_TARGET_PLATFORM)
|
||||||
|
output_path := $(lib_dir)/$(lib_prefix)-$(MEDIADEVICES_TARGET_PLATFORM).a
|
||||||
|
|
||||||
|
# OS and Arch mapping to OpenH264 parameters
|
||||||
|
ifeq (windows,$(MEDIADEVICES_TARGET_OS))
|
||||||
|
os := mingw_nt
|
||||||
|
else
|
||||||
|
os := $(MEDIADEVICES_TARGET_OS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring $(MEDIADEVICES_TARGET_ARCH),armv6 armv7 armv8))
|
||||||
|
arch := arm
|
||||||
|
else ifeq (x64,$(MEDIADEVICES_TARGET_ARCH))
|
||||||
|
arch := x86_64
|
||||||
|
else
|
||||||
|
arch := $(MEDIADEVICES_TARGET_ARCH)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: guard-MEDIADEVICES_TARGET_PLATFORM guard-MEDIADEVICES_TARGET_PLATFORM \
|
||||||
|
guard-MEDIADEVICES_TARGET_OS guard-MEDIADEVICES_TARGET_ARCH \
|
||||||
|
$(output_path) headers
|
||||||
|
|
||||||
|
headers: | $(src_dir) $(include_dir)
|
||||||
|
@cp $(src_dir)/codec/api/svc/*.h $(include_dir)
|
||||||
|
|
||||||
|
$(output_path): $(src_dir)/$(lib_prefix).a | $(lib_dir)
|
||||||
|
@cp $< $@
|
||||||
|
|
||||||
|
$(src_dir)/$(lib_prefix).a: | $(src_dir)
|
||||||
|
$(MEDIADEVICES_TOOLCHAIN_BIN) make --directory=$(src_dir) $(lib_prefix).a \
|
||||||
|
OS=$(os) ARCH=$(arch)
|
||||||
|
|
||||||
|
$(src_dir): | $(src_root_dir)
|
||||||
|
git clone --depth=1 --branch=$(version) $(git_url) $@
|
||||||
|
|
||||||
|
$(src_root_dir) $(lib_dir) $(include_dir):
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
guard-%:
|
||||||
|
@if [ -z ${$*} ]; then echo "$* is a required environment variable"; exit 1; fi
|
@@ -1,36 +0,0 @@
|
|||||||
GIT_URL=https://github.com/cisco/openh264.git
|
|
||||||
VERSION=v2.1.1
|
|
||||||
SRC_DIR=src
|
|
||||||
LIB_DIR=lib
|
|
||||||
INCLUDE_DIR=include/openh264
|
|
||||||
ROOT_DIR=${PWD}
|
|
||||||
LIB_PREFIX=libopenh264
|
|
||||||
|
|
||||||
OS=${MEDIADEVICES_TARGET_OS}
|
|
||||||
ARCH=${MEDIADEVICES_TARGET_ARCH}
|
|
||||||
|
|
||||||
case ${MEDIADEVICES_TARGET_OS} in
|
|
||||||
windows)
|
|
||||||
OS=mingw_nt
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case ${MEDIADEVICES_TARGET_ARCH} in
|
|
||||||
armv6 | armv7 | armv8)
|
|
||||||
ARCH=arm
|
|
||||||
;;
|
|
||||||
x64)
|
|
||||||
ARCH=x86_64
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
mkdir -p ${LIB_DIR} ${INCLUDE_DIR}
|
|
||||||
|
|
||||||
git clone --depth=1 --branch=${VERSION} ${GIT_URL} ${SRC_DIR}
|
|
||||||
cd ${SRC_DIR}
|
|
||||||
${MEDIADEVICES_TOOLCHAIN_BIN} make -j2 ${LIB_PREFIX}.a OS=${OS} ARCH=${ARCH}
|
|
||||||
${MEDIADEVICES_TOOLCHAIN_BIN} echo $PATH
|
|
||||||
mv ${LIB_PREFIX}.a ${ROOT_DIR}/${LIB_DIR}/${LIB_PREFIX}_${MEDIADEVICES_TARGET_PLATFORM}.a
|
|
||||||
mkdir -p ${ROOT_DIR}/${INCLUDE_DIR}
|
|
||||||
cp codec/api/svc/*.h ${ROOT_DIR}/${INCLUDE_DIR}
|
|
||||||
make clean
|
|
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
#include "codec_app_def.h"
|
#include "codec_app_def.h"
|
||||||
|
|
||||||
static const OpenH264Version g_stCodecVersion = {2, 1, 0, 2002};
|
static const OpenH264Version g_stCodecVersion = {2, 1, 1, 2005};
|
||||||
static const char* const g_strCodecVer = "OpenH264 version:2.1.0.2002";
|
static const char* const g_strCodecVer = "OpenH264 version:2.1.1.2005";
|
||||||
|
|
||||||
#define OPENH264_MAJOR (2)
|
#define OPENH264_MAJOR (2)
|
||||||
#define OPENH264_MINOR (1)
|
#define OPENH264_MINOR (1)
|
||||||
#define OPENH264_REVISION (0)
|
#define OPENH264_REVISION (1)
|
||||||
#define OPENH264_RESERVED (2002)
|
#define OPENH264_RESERVED (2005)
|
||||||
|
|
||||||
#endif // CODEC_VER_H
|
#endif // CODEC_VER_H
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,9 +4,9 @@ package openh264
|
|||||||
|
|
||||||
//#cgo CFLAGS: -I${SRCDIR}/include
|
//#cgo CFLAGS: -I${SRCDIR}/include
|
||||||
//#cgo CXXFLAGS: -I${SRCDIR}/include
|
//#cgo CXXFLAGS: -I${SRCDIR}/include
|
||||||
//#cgo linux,arm LDFLAGS: ${SRCDIR}/lib/libopenh264_linux_armv7.a
|
//#cgo linux,arm LDFLAGS: ${SRCDIR}/lib/libopenh264-linux-armv7.a
|
||||||
//#cgo linux,arm64 LDFLAGS: ${SRCDIR}/lib/libopenh264_linux_arm64.a
|
//#cgo linux,arm64 LDFLAGS: ${SRCDIR}/lib/libopenh264-linux-arm64.a
|
||||||
//#cgo linux,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264_linux_x64.a
|
//#cgo linux,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264-linux-x64.a
|
||||||
//#cgo darwin,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264_darwin_x64.a
|
//#cgo darwin,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264-darwin-x64.a
|
||||||
//#cgo windows,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264_windows_x64.a -lssp
|
//#cgo windows,amd64 LDFLAGS: ${SRCDIR}/lib/libopenh264-windows-x64.a -lssp
|
||||||
import "C"
|
import "C"
|
||||||
|
31
pkg/codec/opus/Makefile
Normal file
31
pkg/codec/opus/Makefile
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
git_url := https://github.com/xiph/opus.git
|
||||||
|
version := v1.3.1
|
||||||
|
src_root_dir := src
|
||||||
|
lib_dir := lib
|
||||||
|
include_dir := include
|
||||||
|
lib_prefix := libopus
|
||||||
|
src_dir := $(src_root_dir)/$(MEDIADEVICES_TARGET_PLATFORM)
|
||||||
|
output_path := $(lib_dir)/$(lib_prefix)-$(MEDIADEVICES_TARGET_PLATFORM).a
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: guard-MEDIADEVICES_TARGET_PLATFORM guard-MEDIADEVICES_TOOLCHAIN_BIN $(output_path) headers
|
||||||
|
|
||||||
|
headers: | $(src_dir) $(include_dir)
|
||||||
|
@cp $(src_dir)/include/*.h $(include_dir)
|
||||||
|
|
||||||
|
$(output_path): $(src_dir)/$(lib_prefix).a | $(lib_dir)
|
||||||
|
@cp $< $@
|
||||||
|
|
||||||
|
$(src_dir)/$(lib_prefix).a: | $(src_dir)
|
||||||
|
cd $(src_dir) && \
|
||||||
|
$(MEDIADEVICES_TOOLCHAIN_BIN) cmake -DOPUS_STACK_PROTECTOR=OFF -DCMAKE_C_FLAGS="-fpic" && \
|
||||||
|
$(MEDIADEVICES_TOOLCHAIN_BIN) make VERBOSE=1
|
||||||
|
|
||||||
|
$(src_dir): | $(src_root_dir)
|
||||||
|
git clone --depth=1 --branch=$(version) $(git_url) $@
|
||||||
|
|
||||||
|
$(src_root_dir) $(lib_dir) $(include_dir):
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
guard-%:
|
||||||
|
@if [ -z ${$*} ]; then echo "$* is a required environment variable"; exit 1; fi
|
@@ -1,19 +0,0 @@
|
|||||||
GIT_URL=https://github.com/xiph/opus.git
|
|
||||||
VERSION=v1.3.1
|
|
||||||
SRC_DIR=src
|
|
||||||
LIB_DIR=lib
|
|
||||||
INCLUDE_DIR=include
|
|
||||||
ROOT_DIR=${PWD}
|
|
||||||
LIB_PREFIX=libopus
|
|
||||||
|
|
||||||
mkdir -p ${LIB_DIR} ${INCLUDE_DIR}
|
|
||||||
|
|
||||||
git clone --depth=1 --branch=${VERSION} ${GIT_URL} ${SRC_DIR}
|
|
||||||
cd ${SRC_DIR}
|
|
||||||
${MEDIADEVICES_TOOLCHAIN_BIN} cmake -DOPUS_STACK_PROTECTOR=OFF .
|
|
||||||
${MEDIADEVICES_TOOLCHAIN_BIN} make -j2
|
|
||||||
mv ${LIB_PREFIX}.a ${ROOT_DIR}/${LIB_DIR}/${LIB_PREFIX}_${MEDIADEVICES_TARGET_PLATFORM}.a
|
|
||||||
mkdir -p ${ROOT_DIR}/${INCLUDE_DIR}
|
|
||||||
cp include/*.h ${ROOT_DIR}/${INCLUDE_DIR}
|
|
||||||
git clean -dfx
|
|
||||||
git reset --hard
|
|
Binary file not shown.
Binary file not shown.
BIN
pkg/codec/opus/lib/libopus-linux-armv7.a
Normal file
BIN
pkg/codec/opus/lib/libopus-linux-armv7.a
Normal file
Binary file not shown.
BIN
pkg/codec/opus/lib/libopus-windows-x64.a
Normal file
BIN
pkg/codec/opus/lib/libopus-windows-x64.a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,9 +4,9 @@ package opus
|
|||||||
|
|
||||||
//#cgo CFLAGS: -I${SRCDIR}/include
|
//#cgo CFLAGS: -I${SRCDIR}/include
|
||||||
//#cgo CXXFLAGS: -I${SRCDIR}/include
|
//#cgo CXXFLAGS: -I${SRCDIR}/include
|
||||||
//#cgo linux,arm LDFLAGS: ${SRCDIR}/lib/libopus_linux_armv7.a -lm
|
//#cgo linux,arm LDFLAGS: ${SRCDIR}/lib/libopus-linux-armv7.a -lm
|
||||||
//#cgo linux,arm64 LDFLAGS: ${SRCDIR}/lib/libopus_linux_arm64.a -lm
|
//#cgo linux,arm64 LDFLAGS: ${SRCDIR}/lib/libopus-linux-arm64.a -lm
|
||||||
//#cgo linux,amd64 LDFLAGS: ${SRCDIR}/lib/libopus_linux_x64.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,amd64 LDFLAGS: ${SRCDIR}/lib/libopus-darwin-x64.a
|
||||||
//#cgo windows,amd64 LDFLAGS: ${SRCDIR}/lib/libopus_windows_x64.a
|
//#cgo windows,amd64 LDFLAGS: ${SRCDIR}/lib/libopus-windows-x64.a
|
||||||
import "C"
|
import "C"
|
||||||
|
@@ -229,9 +229,16 @@ func (e *encoder) Read() ([]byte, func(), error) {
|
|||||||
|
|
||||||
if e.cfg.g_w != C.uint(width) || e.cfg.g_h != C.uint(height) {
|
if e.cfg.g_w != C.uint(width) || e.cfg.g_h != C.uint(height) {
|
||||||
e.cfg.g_w, e.cfg.g_h = C.uint(width), C.uint(height)
|
e.cfg.g_w, e.cfg.g_h = C.uint(width), C.uint(height)
|
||||||
if ec := C.vpx_codec_enc_config_set(e.codec, e.cfg); ec != C.VPX_CODEC_OK {
|
|
||||||
return nil, func() {}, fmt.Errorf("vpx_codec_enc_config_set failed (%d)", ec)
|
newCodec := C.newCtx()
|
||||||
|
if ec := C.vpx_codec_enc_init_ver(
|
||||||
|
newCodec, e.codec.iface, e.cfg, 0, C.VPX_ENCODER_ABI_VERSION,
|
||||||
|
); ec != 0 {
|
||||||
|
return nil, func() {}, fmt.Errorf("vpx_codec_enc_init failed (%d)", ec)
|
||||||
}
|
}
|
||||||
|
C.free(unsafe.Pointer(e.codec))
|
||||||
|
e.codec = newCodec
|
||||||
|
|
||||||
e.raw.w, e.raw.h = C.uint(width), C.uint(height)
|
e.raw.w, e.raw.h = C.uint(width), C.uint(height)
|
||||||
e.raw.r_w, e.raw.r_h = C.uint(width), C.uint(height)
|
e.raw.r_w, e.raw.r_h = C.uint(width), C.uint(height)
|
||||||
e.raw.d_w, e.raw.d_h = C.uint(width), C.uint(height)
|
e.raw.d_w, e.raw.d_h = C.uint(width), C.uint(height)
|
||||||
|
89
pkg/codec/vpx/vpx_test.go
Normal file
89
pkg/codec/vpx/vpx_test.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package vpx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"io"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pion/mediadevices/pkg/codec"
|
||||||
|
"github.com/pion/mediadevices/pkg/frame"
|
||||||
|
"github.com/pion/mediadevices/pkg/io/video"
|
||||||
|
"github.com/pion/mediadevices/pkg/prop"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImageSizeChange(t *testing.T) {
|
||||||
|
for name, factory := range map[string]func() (codec.VideoEncoderBuilder, error){
|
||||||
|
"VP8": func() (codec.VideoEncoderBuilder, error) {
|
||||||
|
p, err := NewVP8Params()
|
||||||
|
return &p, err
|
||||||
|
},
|
||||||
|
"VP9": func() (codec.VideoEncoderBuilder, error) {
|
||||||
|
p, err := NewVP9Params()
|
||||||
|
return &p, err
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
factory := factory
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
param, err := factory()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range map[string]struct {
|
||||||
|
initialWidth, initialHeight int
|
||||||
|
width, height int
|
||||||
|
}{
|
||||||
|
"NoChange": {
|
||||||
|
320, 240,
|
||||||
|
320, 240,
|
||||||
|
},
|
||||||
|
"Enlarge": {
|
||||||
|
320, 240,
|
||||||
|
640, 480,
|
||||||
|
},
|
||||||
|
"Shrink": {
|
||||||
|
640, 480,
|
||||||
|
320, 240,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
var cnt uint32
|
||||||
|
r, err := param.BuildVideoEncoder(
|
||||||
|
video.ReaderFunc(func() (image.Image, func(), error) {
|
||||||
|
i := atomic.AddUint32(&cnt, 1)
|
||||||
|
if i == 1 {
|
||||||
|
return image.NewYCbCr(
|
||||||
|
image.Rect(0, 0, testCase.width, testCase.height),
|
||||||
|
image.YCbCrSubsampleRatio420,
|
||||||
|
), func() {}, nil
|
||||||
|
}
|
||||||
|
return nil, nil, io.EOF
|
||||||
|
}),
|
||||||
|
prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: testCase.initialWidth,
|
||||||
|
Height: testCase.initialHeight,
|
||||||
|
FrameRate: 1,
|
||||||
|
FrameFormat: frame.FormatI420,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, rel, err := r.Read()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
rel()
|
||||||
|
_, _, err = r.Read()
|
||||||
|
if err != io.EOF {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -56,7 +56,7 @@ func BenchmarkRead(b *testing.B) {
|
|||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := r.Read()
|
_, _, err := r.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Failed to read: %v", err)
|
b.Fatalf("Failed to read: %v", err)
|
||||||
}
|
}
|
||||||
|
63
pkg/driver/camera/camera_darwin_test.go
Normal file
63
pkg/driver/camera/camera_darwin_test.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// +build darwin
|
||||||
|
|
||||||
|
// $ go test -v . -tags darwin -run="^TestCameraFrameFormatSupport$"
|
||||||
|
|
||||||
|
package camera
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pion/mediadevices/pkg/avfoundation"
|
||||||
|
"github.com/pion/mediadevices/pkg/frame"
|
||||||
|
"github.com/pion/mediadevices/pkg/prop"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCameraFrameFormatSupport(t *testing.T) {
|
||||||
|
devices, err := avfoundation.Devices(avfoundation.Video)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(devices) > 0 {
|
||||||
|
c := newCamera(devices[0])
|
||||||
|
if err := c.Open(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
supportedFormats := make(map[frame.Format]struct{})
|
||||||
|
for _, p := range c.Properties() {
|
||||||
|
supportedFormats[p.FrameFormat] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, format := range []frame.Format{
|
||||||
|
frame.FormatI420,
|
||||||
|
frame.FormatNV12,
|
||||||
|
frame.FormatNV21,
|
||||||
|
frame.FormatYUY2,
|
||||||
|
frame.FormatUYVY,
|
||||||
|
} {
|
||||||
|
if _, ok := supportedFormats[format]; !ok {
|
||||||
|
t.Logf("[%v] UNSUPPORTED", format)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r, err := c.VideoRecord(prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: 640,
|
||||||
|
Height: 480,
|
||||||
|
FrameFormat: format,
|
||||||
|
}})
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("[%v] Failed to capture image: %v", format, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
_, _, err := r.Read()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("[%v] Failed to read: %v", format, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("[%v] OK", format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,24 +0,0 @@
|
|||||||
package frame
|
|
||||||
|
|
||||||
type Format string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// FormatI420 https://www.fourcc.org/pixel-format/yuv-i420/
|
|
||||||
FormatI420 Format = "I420"
|
|
||||||
// FormatI444 is a YUV format without sub-sampling
|
|
||||||
FormatI444 Format = "I444"
|
|
||||||
// FormatNV21 https://www.fourcc.org/pixel-format/yuv-nv21/
|
|
||||||
FormatNV21 = "NV21"
|
|
||||||
// FormatYUY2 https://www.fourcc.org/pixel-format/yuv-yuy2/
|
|
||||||
FormatYUY2 = "YUY2"
|
|
||||||
// FormatUYVY https://www.fourcc.org/pixel-format/yuv-uyvy/
|
|
||||||
FormatUYVY = "UYVY"
|
|
||||||
|
|
||||||
// FormatRGBA https://www.fourcc.org/pixel-format/rgb-rgba/
|
|
||||||
FormatRGBA Format = "RGBA"
|
|
||||||
|
|
||||||
// FormatMJPEG https://www.fourcc.org/mjpg/
|
|
||||||
FormatMJPEG = "MJPEG"
|
|
||||||
)
|
|
||||||
|
|
||||||
const FormatYUYV = FormatYUY2
|
|
@@ -4,21 +4,44 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewDecoder(f Format) (Decoder, error) {
|
type Format string
|
||||||
var decoder decoderFunc
|
|
||||||
|
|
||||||
switch f {
|
const (
|
||||||
case FormatI420:
|
// FormatI420 https://www.fourcc.org/pixel-format/yuv-i420/
|
||||||
decoder = decodeI420
|
FormatI420 Format = "I420"
|
||||||
case FormatNV21:
|
// FormatI444 is a YUV format without sub-sampling
|
||||||
decoder = decodeNV21
|
FormatI444 Format = "I444"
|
||||||
case FormatYUY2:
|
// FormatNV21 https://www.fourcc.org/pixel-format/yuv-nv21/
|
||||||
decoder = decodeYUY2
|
FormatNV21 = "NV21"
|
||||||
case FormatUYVY:
|
// FormatNV12 https://www.fourcc.org/pixel-format/yuv-nv12/
|
||||||
decoder = decodeUYVY
|
FormatNV12 = "NV12"
|
||||||
case FormatMJPEG:
|
// FormatYUY2 https://www.fourcc.org/pixel-format/yuv-yuy2/
|
||||||
decoder = decodeMJPEG
|
FormatYUY2 = "YUY2"
|
||||||
default:
|
// FormatUYVY https://www.fourcc.org/pixel-format/yuv-uyvy/
|
||||||
|
FormatUYVY = "UYVY"
|
||||||
|
|
||||||
|
// FormatRGBA https://www.fourcc.org/pixel-format/rgb-rgba/
|
||||||
|
FormatRGBA Format = "RGBA"
|
||||||
|
|
||||||
|
// FormatMJPEG https://www.fourcc.org/mjpg/
|
||||||
|
FormatMJPEG = "MJPEG"
|
||||||
|
)
|
||||||
|
|
||||||
|
const FormatYUYV = FormatYUY2
|
||||||
|
|
||||||
|
var decoderMap = map[Format]decoderFunc{
|
||||||
|
FormatI420: decodeI420,
|
||||||
|
FormatNV21: decodeNV21,
|
||||||
|
FormatNV12: decodeNV12,
|
||||||
|
FormatYUY2: decodeYUY2,
|
||||||
|
FormatUYVY: decodeUYVY,
|
||||||
|
FormatMJPEG: decodeMJPEG,
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDecoder(f Format) (Decoder, error) {
|
||||||
|
decoder, ok := decoderMap[f]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not supported", f)
|
return nil, fmt.Errorf("%s is not supported", f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,8 +35,8 @@ func decodeNV21(frame []byte, width, height int) (image.Image, func(), error) {
|
|||||||
|
|
||||||
var cb, cr []byte
|
var cb, cr []byte
|
||||||
for i := yi; i < ci; i += 2 {
|
for i := yi; i < ci; i += 2 {
|
||||||
cb = append(cb, frame[i])
|
cr = append(cr, frame[i])
|
||||||
cr = append(cr, frame[i+1])
|
cb = append(cb, frame[i+1])
|
||||||
}
|
}
|
||||||
|
|
||||||
return &image.YCbCr{
|
return &image.YCbCr{
|
||||||
@@ -49,3 +49,15 @@ func decodeNV21(frame []byte, width, height int) (image.Image, func(), error) {
|
|||||||
Rect: image.Rect(0, 0, width, height),
|
Rect: image.Rect(0, 0, width, height),
|
||||||
}, func() {}, nil
|
}, func() {}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeNV12(frame []byte, width, height int) (image.Image, func(), error) {
|
||||||
|
img, release, err := decodeNV21(frame, width, height)
|
||||||
|
if err != nil {
|
||||||
|
return img, release, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The only difference between NV21 and NV12 is the chroma order, so simply swap them
|
||||||
|
yuv := img.(*image.YCbCr)
|
||||||
|
yuv.Cb, yuv.Cr = yuv.Cr, yuv.Cb
|
||||||
|
return yuv, release, err
|
||||||
|
}
|
||||||
|
@@ -17,7 +17,7 @@ func decodeYUY2(frame []byte, width, height int) (image.Image, func(), error) {
|
|||||||
ci := yi / 2
|
ci := yi / 2
|
||||||
fi := yi + 2*ci
|
fi := yi + 2*ci
|
||||||
|
|
||||||
if len(frame) != fi {
|
if len(frame) < fi {
|
||||||
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ func decodeUYVY(frame []byte, width, height int) (image.Image, func(), error) {
|
|||||||
ci := yi / 2
|
ci := yi / 2
|
||||||
fi := yi + 2*ci
|
fi := yi + 2*ci
|
||||||
|
|
||||||
if len(frame) != fi {
|
if len(frame) < fi {
|
||||||
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ func decodeYUY2(frame []byte, width, height int) (image.Image, func(), error) {
|
|||||||
ci := yi / 2
|
ci := yi / 2
|
||||||
fi := yi + 2*ci
|
fi := yi + 2*ci
|
||||||
|
|
||||||
if len(frame) != fi {
|
if len(frame) < fi {
|
||||||
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ func decodeUYVY(frame []byte, width, height int) (image.Image, func(), error) {
|
|||||||
ci := yi / 2
|
ci := yi / 2
|
||||||
fi := yi + 2*ci
|
fi := yi + 2*ci
|
||||||
|
|
||||||
if len(frame) != fi {
|
if len(frame) < fi {
|
||||||
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
return nil, func() {}, fmt.Errorf("frame length (%d) less than expected (%d)", len(frame), fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,11 @@ func TestDecodeYUY2(t *testing.T) {
|
|||||||
Rect: image.Rect(0, 0, width, height),
|
Rect: image.Rect(0, 0, width, height),
|
||||||
}
|
}
|
||||||
|
|
||||||
img, _, err := decodeYUY2(input, width, height)
|
decoder, err := NewDecoder(FormatYUY2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
img, _, err := decoder.Decode(input, width, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -56,7 +60,77 @@ func TestDecodeUYVY(t *testing.T) {
|
|||||||
Rect: image.Rect(0, 0, width, height),
|
Rect: image.Rect(0, 0, width, height),
|
||||||
}
|
}
|
||||||
|
|
||||||
img, _, err := decodeUYVY(input, width, height)
|
decoder, err := NewDecoder(FormatUYVY)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
img, _, err := decoder.Decode(input, width, height)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(expected, img) {
|
||||||
|
t.Errorf("Wrong decode result,\nexpected:\n%+v\ngot:\n%+v", expected, img)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeNV21(t *testing.T) {
|
||||||
|
const (
|
||||||
|
width = 2
|
||||||
|
height = 2
|
||||||
|
)
|
||||||
|
input := []byte{
|
||||||
|
0x01, 0x03, 0x05, 0x07, // Y
|
||||||
|
// Cr Cb
|
||||||
|
0x82, 0x84,
|
||||||
|
}
|
||||||
|
expected := &image.YCbCr{
|
||||||
|
Y: []byte{0x01, 0x03, 0x05, 0x07},
|
||||||
|
YStride: width,
|
||||||
|
Cb: []byte{0x84},
|
||||||
|
Cr: []byte{0x82},
|
||||||
|
CStride: width / 2,
|
||||||
|
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||||
|
Rect: image.Rect(0, 0, width, height),
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(FormatNV21)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
img, _, err := decoder.Decode(input, width, height)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(expected, img) {
|
||||||
|
t.Errorf("Wrong decode result,\nexpected:\n%+v\ngot:\n%+v", expected, img)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeNV12(t *testing.T) {
|
||||||
|
const (
|
||||||
|
width = 2
|
||||||
|
height = 2
|
||||||
|
)
|
||||||
|
input := []byte{
|
||||||
|
0x01, 0x03, 0x05, 0x07, // Y
|
||||||
|
// Cb Cr
|
||||||
|
0x84, 0x82,
|
||||||
|
}
|
||||||
|
expected := &image.YCbCr{
|
||||||
|
Y: []byte{0x01, 0x03, 0x05, 0x07},
|
||||||
|
YStride: width,
|
||||||
|
Cb: []byte{0x84},
|
||||||
|
Cr: []byte{0x82},
|
||||||
|
CStride: width / 2,
|
||||||
|
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||||
|
Rect: image.Rect(0, 0, width, height),
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(FormatNV12)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
img, _, err := decoder.Decode(input, width, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// #include "convert_cgo.h"
|
// #include "convert_cgo.h"
|
||||||
|
// #cgo CFLAGS: -std=c11
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// CGO version of the functions will be selected at runtime.
|
// CGO version of the functions will be selected at runtime.
|
||||||
|
0
scripts/.gitkeep
Normal file
0
scripts/.gitkeep
Normal file
Reference in New Issue
Block a user