Update vendor and makefile (#76)

* Update dependencies

* Update vendor

* Update vendor with C package

* Update Make file
This commit is contained in:
giongto35 2019-09-01 04:56:27 +08:00 committed by GitHub
parent 6cab7c3c62
commit 5d3a716e2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
558 changed files with 100173 additions and 8634 deletions

14
Makefile vendored
View file

@ -4,14 +4,14 @@ dep:
go mod tidy
build: dep
go build -o build/klog ./cmd
go build -o build/cloudretro ./cmd
run: build
# Run coordinator first
./build/klog -overlordhost overlord &
./build/cloudretro -overlordhost overlord &
# Wait till overlord finish initialized
# Run a worker connecting to overload
./build/klog -overlordhost ws://localhost:8000/wso
./build/cloudretro -overlordhost ws://localhost:8000/wso
run-docker:
docker build . -t cloud-game-local
@ -19,3 +19,11 @@ run-docker:
docker rm cloud-game-local
# Overlord and worker should be run separately. Local is for demo purpose
docker run --privileged -v $PWD/games:/cloud-game/games -d --name cloud-game-local -p 8000:8000 -p 9000:9000 cloud-game-local bash -c "cmd -overlordhost ws://localhost:8000/wso & cmd -overlordhost overlord"
build-vendor:
go build -o build/cloudretro -mod=vendor ./cmd
#run with vendor so it is faster
run-fast: build-vendor
./build/cloudretro -overlordhost overlord &
./build/cloudretro -overlordhost ws://localhost:8000/wso

BIN
build/klog vendored

Binary file not shown.

2
go.mod vendored
View file

@ -5,7 +5,7 @@ go 1.12
require (
cloud.google.com/go v0.43.0
github.com/gen2brain/x264-go v0.0.0-20180306035800-58f586137654
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 // indirect
github.com/gofrs/uuid v3.2.0+incompatible
github.com/gorilla/websocket v1.4.0
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

20
go.sum vendored
View file

@ -11,10 +11,13 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
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 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gen2brain/x264-go v0.0.0-20180306035800-58f586137654 h1:RNpogAT5Qz69YLIu6+92q5sSw61PjjhDj4upH2el5pk=
github.com/gen2brain/x264-go v0.0.0-20180306035800-58f586137654/go.mod h1:17kvfYQKi9/QHiKPeqmJW0YuDPZEgy72tSBVmweSyiE=
@ -27,9 +30,11 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -38,8 +43,10 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -51,6 +58,7 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -58,7 +66,9 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9 h1:tbuodUh2vuhOVZAdW3NEUvosFHUMJwUNl7jk/VSEiwc=
github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -68,7 +78,9 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pion/datachannel v1.4.5 h1:paz18kYAetpTdK8tlMAtDY+Ayxrv5fndZ5XPZwiZHrU=
github.com/pion/datachannel v1.4.5/go.mod h1:SpMJbuu8v+qbA94m6lWQwSdCf8JKQvgmdSHDNtcbe+w=
@ -81,6 +93,7 @@ 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.3 h1:DxdOYd0pgwLKiDlIIxfU0qdG5iWh1Xn6CsS9vc6cMAY=
github.com/pion/mdns v0.0.3/go.mod h1:VrN3wefVgtfL8QgpEblPUC46ag1reLIfpqekCnKunLE=
github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA=
github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k=
github.com/pion/rtcp v1.2.1 h1:S3yG4KpYAiSmBVqKAfgRa5JdwBNj4zK3RLUa8JYdhak=
github.com/pion/rtcp v1.2.1/go.mod h1:a5dj2d6BKIKHl43EnAOIrCczcjESrtPuMgfmL6/K6QM=
@ -106,6 +119,7 @@ github.com/pion/webrtc/v2 v2.1.2/go.mod h1:6+ovIHxDUZVgCVGP3JTEAyiy9Aa45q8u7/Feb
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@ -125,6 +139,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
@ -207,6 +222,7 @@ google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -220,11 +236,15 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/hraban/opus.v2 v2.0.0-20180426093920-0f2e0b4fc6cd h1:oAcaGkUcXajq9yi+UKvzJMSKEb++XegVTSQjOlu3MVU=
gopkg.in/hraban/opus.v2 v2.0.0-20180426093920-0f2e0b4fc6cd/go.mod h1:/L5E7a21VWl8DeuCPKxQBdVG5cy+L0MRZ08B1wnqt7g=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -15,7 +15,6 @@ import (
"unsafe"
"github.com/giongto35/cloud-game/emulator"
"github.com/go-gl/gl/v2.1/gl"
)
/*
@ -89,6 +88,15 @@ var bindRetroKeys = map[int]int{
9: C.RETRO_DEVICE_ID_JOYPAD_RIGHT,
}
const (
// BIT_FORMAT_SHORT_5_5_5_1 has 5 bits R, 5 bits G, 5 bits B, 1 bit alpha
BIT_FORMAT_SHORT_5_5_5_1 = iota
// BIT_FORMAT_INT_8_8_8_8_REV has 8 bits R, 8 bits G, 8 bits B, 8 bit alpha
BIT_FORMAT_INT_8_8_8_8_REV
// BIT_FORMAT_SHORT_5_6_5 has 5 bits R, 6 bits G, 5 bits
BIT_FORMAT_SHORT_5_6_5
)
type CloudEmulator interface {
SetView(view *emulator.GameView)
Start(path string)
@ -141,9 +149,9 @@ func toImageRGBA(data unsafe.Pointer, bytesPerRow int) *image.RGBA {
sh.Len = bytesPerRow * eheight * 4
sh.Cap = bytesPerRow * eheight * 4
if video.pixFmt == gl.UNSIGNED_SHORT_5_6_5 {
if video.pixFmt == BIT_FORMAT_SHORT_5_6_5 {
return to565Image(data, bytes, bytesPerRow)
} else if video.pixFmt == gl.UNSIGNED_INT_8_8_8_8_REV {
} else if video.pixFmt == BIT_FORMAT_INT_8_8_8_8_REV {
return to8888Image(data, bytes, bytesPerRow)
}
return nil
@ -485,18 +493,15 @@ func nanoarchRun() {
func videoSetPixelFormat(format uint32) C.bool {
switch format {
case C.RETRO_PIXEL_FORMAT_0RGB1555:
video.pixFmt = gl.UNSIGNED_SHORT_5_5_5_1
video.pixType = gl.BGRA
video.pixFmt = BIT_FORMAT_SHORT_5_5_5_1
video.bpp = 2
break
case C.RETRO_PIXEL_FORMAT_XRGB8888:
video.pixFmt = gl.UNSIGNED_INT_8_8_8_8_REV
video.pixType = gl.BGRA
video.pixFmt = BIT_FORMAT_INT_8_8_8_8_REV
video.bpp = 4
break
case C.RETRO_PIXEL_FORMAT_RGB565:
video.pixFmt = gl.UNSIGNED_SHORT_5_6_5
video.pixType = gl.RGB
video.pixFmt = BIT_FORMAT_SHORT_5_6_5
video.bpp = 2
break
default:

32
vendor/cloud.google.com/go/storage/README.md generated vendored Normal file
View file

@ -0,0 +1,32 @@
## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage)
- [About Cloud Storage](https://cloud.google.com/storage/)
- [API documentation](https://cloud.google.com/storage/docs)
- [Go client documentation](https://godoc.org/cloud.google.com/go/storage)
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage)
### Example Usage
First create a `storage.Client` to use throughout your application:
[snip]:# (storage-1)
```go
client, err := storage.NewClient(ctx)
if err != nil {
log.Fatal(err)
}
```
[snip]:# (storage-2)
```go
// Read the object1 from bucket.
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
if err != nil {
log.Fatal(err)
}
defer rc.Close()
body, err := ioutil.ReadAll(rc)
if err != nil {
log.Fatal(err)
}
```

View file

@ -317,6 +317,11 @@ type BucketAttrs struct {
// Etag is the HTTP/1.1 Entity tag for the bucket.
// This field is read-only.
Etag string
// LocationType describes how data is stored and replicated.
// Typical values are "multi-region", "region" and "dual-region".
// This field is read-only.
LocationType string
}
// BucketPolicyOnly configures access checks to use only bucket-level IAM
@ -506,6 +511,7 @@ func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
Website: toBucketWebsite(b.Website),
BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration),
Etag: b.Etag,
LocationType: b.LocationType,
}, nil
}

22
vendor/github.com/gen2brain/x264-go/.appveyor.yml generated vendored Normal file
View file

@ -0,0 +1,22 @@
version: "{build}"
clone_depth: 1
clone_folder: c:\gopath\src\github.com\gen2brain\x264-go
environment:
GOPATH: c:\gopath
MSYS_PATH: c:\msys64
CGO_ENABLED: 1
GOARCH: 386
CC: i686-w64-mingw32-gcc
install:
- echo %GOPATH%
- echo %MSYS_PATH%
- set PATH=%GOPATH%\bin;c:\go\bin;%MSYS_PATH%\usr\bin;%MSYS_PATH%\mingw32\bin;%PATH%
- go version
- go env
build_script:
- bash -lc "cd /c/gopath/src/github.com/gen2brain/x264-go && go build"

12
vendor/github.com/gen2brain/x264-go/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,12 @@
language: go
go:
- 1.9.x
gobuild_args: "-tags extlib"
before_install:
- sudo apt-get install libx264-dev
script:
- go test -tags extlib -v ./

1
vendor/github.com/gen2brain/x264-go/AUTHORS generated vendored Normal file
View file

@ -0,0 +1 @@
Milan Nikolic <gen2brain@gmail.com>

340
vendor/github.com/gen2brain/x264-go/COPYING generated vendored Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

77
vendor/github.com/gen2brain/x264-go/README.md generated vendored Normal file
View file

@ -0,0 +1,77 @@
## x264-go
[![TravisCI Build Status](https://travis-ci.org/gen2brain/x264-go.svg?branch=master)](https://travis-ci.org/gen2brain/x264-go)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/wfkqlac5ffwk5xgb?svg=true)](https://ci.appveyor.com/project/gen2brain/x264-go)
[![GoDoc](https://godoc.org/github.com/gen2brain/x264-go?status.svg)](https://godoc.org/github.com/gen2brain/x264-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/gen2brain/x264-go?branch=master)](https://goreportcard.com/report/github.com/gen2brain/x264-go)
`x264-go` provides H.264/MPEG-4 AVC codec encoder based on [x264](https://www.videolan.org/developers/x264.html) library.
C source code is included in package. If you want to use external shared/static library (i.e. built with asm and/or OpenCL) use `-tags extlib`.
### Installation
go get -u github.com/gen2brain/x264-go
### Examples
See [screengrab](https://github.com/gen2brain/x264-go/blob/master/examples/screengrab/screengrab.go) example.
### Usage
```go
package main
import (
"bytes"
"image"
"image/color"
"image/draw"
"github.com/gen2brain/x264-go"
)
func main() {
buf := bytes.NewBuffer(make([]byte, 0))
opts := &x264.Options{
Width: 640,
Height: 480,
FrameRate: 25,
Tune: "zerolatency",
Preset: "veryfast",
Profile: "baseline",
LogLevel: x264.LogDebug,
}
enc, err := x264.NewEncoder(buf, opts)
if err != nil {
panic(err)
}
img := x264.NewYCbCr(image.Rect(0, 0, opts.Width, opts.Height))
draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src)
for i := 0; i < opts.Width/2; i++ {
img.Set(i, opts.Height/2, color.RGBA{255, 0, 0, 255})
err = enc.Encode(img)
if err != nil {
panic(err)
}
}
err = enc.Flush()
if err != nil {
panic(err)
}
err = enc.Close()
if err != nil {
panic(err)
}
}
```
## More
For AAC encoder see [aac-go](https://github.com/gen2brain/aac-go).

View file

@ -0,0 +1,212 @@
// Package x264 provides H.264/MPEG-4 AVC codec encoder based on [x264](https://www.videolan.org/developers/x264.html) library.
package x264
import "C"
import (
"fmt"
"image"
"io"
"github.com/gen2brain/x264-go/x264c"
)
// Logging constants.
const (
LogNone int32 = iota - 1
LogError
LogWarning
LogInfo
LogDebug
)
// Options represent encoding options.
type Options struct {
// Frame width.
Width int
// Frame height.
Height int
// Frame rate.
FrameRate int
// Tunings: film, animation, grain, stillimage, psnr, ssim, fastdecode, zerolatency.
Tune string
// Presets: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo.
Preset string
// Profiles: baseline, main, high, high10, high422, high444.
Profile string
// Log level.
LogLevel int32
}
// Encoder type.
type Encoder struct {
e *x264c.T
w io.Writer
img *YCbCr
opts *Options
csp int32
pts int64
nnals int32
nals []*x264c.Nal
}
// NewEncoder returns new x264 encoder.
func NewEncoder(w io.Writer, opts *Options) (e *Encoder, err error) {
e = &Encoder{}
e.w = w
e.pts = 0
e.opts = opts
e.csp = x264c.CspI420
e.nals = make([]*x264c.Nal, 3)
e.img = NewYCbCr(image.Rect(0, 0, e.opts.Width, e.opts.Height))
param := x264c.Param{}
if e.opts.Preset != "" && e.opts.Profile != "" {
ret := x264c.ParamDefaultPreset(&param, e.opts.Preset, e.opts.Tune)
if ret < 0 {
err = fmt.Errorf("x264: invalid preset/tune name")
return
}
} else {
x264c.ParamDefault(&param)
}
param.IWidth = int32(e.opts.Width)
param.IHeight = int32(e.opts.Height)
param.ICsp = e.csp
param.BVfrInput = 0
param.BRepeatHeaders = 1
param.BAnnexb = 1
param.ILogLevel = e.opts.LogLevel
if e.opts.FrameRate > 0 {
param.IFpsNum = uint32(e.opts.FrameRate)
param.IFpsDen = 1
param.IKeyintMax = int32(e.opts.FrameRate)
param.BIntraRefresh = 1
}
if e.opts.Profile != "" {
ret := x264c.ParamApplyProfile(&param, e.opts.Profile)
if ret < 0 {
err = fmt.Errorf("x264: invalid profile name")
return
}
}
e.e = x264c.EncoderOpen(&param)
if e.e == nil {
err = fmt.Errorf("x264: cannot open the encoder")
return
}
ret := x264c.EncoderHeaders(e.e, e.nals, &e.nnals)
if ret < 0 {
err = fmt.Errorf("x264: cannot encode headers")
return
}
if ret > 0 {
b := C.GoBytes(e.nals[0].PPayload, C.int(ret))
n, er := e.w.Write(b)
if er != nil {
err = er
return
}
if int(ret) != n {
err = fmt.Errorf("x264: error writing headers, size=%d, n=%d", ret, n)
}
}
return
}
// Encode encodes image.
func (e *Encoder) Encode(im image.Image) (err error) {
var picIn, picOut x264c.Picture
e.img.ToYCbCr(im)
ret := x264c.PictureAlloc(&picIn, e.csp, int32(e.opts.Width), int32(e.opts.Height))
if ret < 0 {
err = fmt.Errorf("x264: cannot allocate picture")
return
}
defer x264c.PictureClean(&picIn)
picIn.Img.Plane[0] = C.CBytes(e.img.Y)
picIn.Img.Plane[1] = C.CBytes(e.img.Cb)
picIn.Img.Plane[2] = C.CBytes(e.img.Cr)
picIn.IPts = e.pts
e.pts++
ret = x264c.EncoderEncode(e.e, e.nals, &e.nnals, &picIn, &picOut)
if ret < 0 {
err = fmt.Errorf("x264: cannot encode picture")
return
}
if ret > 0 {
b := C.GoBytes(e.nals[0].PPayload, C.int(ret))
n, er := e.w.Write(b)
if er != nil {
err = er
return
}
if int(ret) != n {
err = fmt.Errorf("x264: error writing payload, size=%d, n=%d", ret, n)
}
}
return
}
// Flush flushes encoder.
func (e *Encoder) Flush() (err error) {
var picOut x264c.Picture
for x264c.EncoderDelayedFrames(e.e) > 0 {
ret := x264c.EncoderEncode(e.e, e.nals, &e.nnals, nil, &picOut)
if ret < 0 {
err = fmt.Errorf("x264: cannot encode picture")
return
}
if ret > 0 {
b := C.GoBytes(e.nals[0].PPayload, C.int(ret))
n, er := e.w.Write(b)
if er != nil {
err = er
return
}
if int(ret) != n {
err = fmt.Errorf("x264: error writing payload, size=%d, n=%d", ret, n)
}
}
}
return
}
// Close closes encoder.
func (e *Encoder) Close() error {
x264c.EncoderClose(e.e)
return nil
}

View file

@ -0,0 +1,42 @@
/*****************************************************************************
* asm-offsets.c: check asm offsets for aarch64
*****************************************************************************
* Copyright (C) 2014-2017 x264 project
*
* Authors: Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "asm-offsets.h"
#define X264_CHECK_OFFSET(s, m, o) struct check_##s##_##m \
{ \
int m_##m[2 * (offsetof(s, m) == o) - 1]; \
}
X264_CHECK_OFFSET(x264_cabac_t, i_low, CABAC_I_LOW);
X264_CHECK_OFFSET(x264_cabac_t, i_range, CABAC_I_RANGE);
X264_CHECK_OFFSET(x264_cabac_t, i_queue, CABAC_I_QUEUE);
X264_CHECK_OFFSET(x264_cabac_t, i_bytes_outstanding, CABAC_I_BYTES_OUTSTANDING);
X264_CHECK_OFFSET(x264_cabac_t, p_start, CABAC_P_START);
X264_CHECK_OFFSET(x264_cabac_t, p, CABAC_P);
X264_CHECK_OFFSET(x264_cabac_t, p_end, CABAC_P_END);
X264_CHECK_OFFSET(x264_cabac_t, f8_bits_encoded, CABAC_F8_BITS_ENCODED);
X264_CHECK_OFFSET(x264_cabac_t, state, CABAC_STATE);

View file

@ -0,0 +1,39 @@
/*****************************************************************************
* asm-offsets.h: asm offsets for aarch64
*****************************************************************************
* Copyright (C) 2014-2017 x264 project
*
* Authors: Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_AARCH64_ASM_OFFSETS_H
#define X264_AARCH64_ASM_OFFSETS_H
#define CABAC_I_LOW 0x00
#define CABAC_I_RANGE 0x04
#define CABAC_I_QUEUE 0x08
#define CABAC_I_BYTES_OUTSTANDING 0x0c
#define CABAC_P_START 0x10
#define CABAC_P 0x18
#define CABAC_P_END 0x20
#define CABAC_F8_BITS_ENCODED 0x30
#define CABAC_STATE 0x34
#endif

View file

@ -0,0 +1,67 @@
/*****************************************************************************
* dct.h: aarch64 transform and zigzag
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_AARCH64_DCT_H
#define X264_AARCH64_DCT_H
void x264_dct4x4dc_neon( int16_t d[16] );
void x264_idct4x4dc_neon( int16_t d[16] );
void x264_sub4x4_dct_neon( int16_t dct[16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_neon( int16_t dct[4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_neon( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_add4x4_idct_neon( uint8_t *p_dst, int16_t dct[16] );
void x264_add8x8_idct_neon( uint8_t *p_dst, int16_t dct[4][16] );
void x264_add16x16_idct_neon( uint8_t *p_dst, int16_t dct[16][16] );
void x264_add8x8_idct_dc_neon( uint8_t *p_dst, int16_t dct[4] );
void x264_add16x16_idct_dc_neon( uint8_t *p_dst, int16_t dct[16] );
void x264_sub8x8_dct_dc_neon( int16_t dct[4], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x16_dct_dc_neon( int16_t dct[8], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct8_neon( int16_t dct[64], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct8_neon( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 );
void x264_add8x8_idct8_neon( uint8_t *p_dst, int16_t dct[64] );
void x264_add16x16_idct8_neon( uint8_t *p_dst, int16_t dct[4][64] );
void x264_zigzag_scan_4x4_frame_neon( int16_t level[16], int16_t dct[16] );
void x264_zigzag_scan_4x4_field_neon( int16_t level[16], int16_t dct[16] );
void x264_zigzag_scan_8x8_frame_neon( int16_t level[64], int16_t dct[64] );
void x264_zigzag_scan_8x8_field_neon( int16_t level[64], int16_t dct[64] );
int x264_zigzag_sub_4x4_field_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst );
int x264_zigzag_sub_4x4ac_field_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc );
int x264_zigzag_sub_4x4_frame_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst );
int x264_zigzag_sub_4x4ac_frame_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc );
int x264_zigzag_sub_8x8_field_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst );
int x264_zigzag_sub_8x8_frame_neon( dctcoef level[16], const pixel *p_src, pixel *p_dst );
void x264_zigzag_interleave_8x8_cavlc_neon( dctcoef *dst, dctcoef *src, uint8_t *nnz );
#endif

View file

@ -0,0 +1,281 @@
/*****************************************************************************
* mc-c.c: aarch64 motion compensation
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "mc.h"
void x264_prefetch_ref_aarch64( uint8_t *, intptr_t, int );
void x264_prefetch_fenc_420_aarch64( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_prefetch_fenc_422_aarch64( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void *x264_memcpy_aligned_neon( void *dst, const void *src, size_t n );
void x264_memzero_aligned_neon( void *dst, size_t n );
void x264_pixel_avg_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_16x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_8x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_8x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x2_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg2_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_pixel_avg2_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_pixel_avg2_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_pixel_avg2_w20_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_plane_copy_core_neon( pixel *dst, intptr_t i_dst,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_swap_core_neon( pixel *dst, intptr_t i_dst,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_neon( pixel *dstu, intptr_t i_dstu,
pixel *dstv, intptr_t i_dstv,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_rgb_neon( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc,
pixel *src, intptr_t i_src, int pw, int w, int h );
void x264_plane_copy_interleave_core_neon( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
void x264_store_interleave_chroma_neon( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height );
void x264_load_deinterleave_chroma_fdec_neon( pixel *dst, pixel *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fenc_neon( pixel *dst, pixel *src, intptr_t i_src, int height );
#define MC_WEIGHT(func)\
void x264_mc_weight_w20##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
void x264_mc_weight_w16##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
void x264_mc_weight_w8##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
void x264_mc_weight_w4##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
\
static void (* x264_mc##func##_wtab_neon[6])( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int ) =\
{\
x264_mc_weight_w4##func##_neon,\
x264_mc_weight_w4##func##_neon,\
x264_mc_weight_w8##func##_neon,\
x264_mc_weight_w16##func##_neon,\
x264_mc_weight_w16##func##_neon,\
x264_mc_weight_w20##func##_neon,\
};
MC_WEIGHT()
MC_WEIGHT(_nodenom)
MC_WEIGHT(_offsetadd)
MC_WEIGHT(_offsetsub)
void x264_mc_copy_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_copy_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_copy_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_chroma_neon( uint8_t *, uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, int, int );
void x264_integral_init4h_neon( uint16_t *, uint8_t *, intptr_t );
void x264_integral_init4v_neon( uint16_t *, uint16_t *, intptr_t );
void x264_integral_init8h_neon( uint16_t *, uint8_t *, intptr_t );
void x264_integral_init8v_neon( uint16_t *, intptr_t );
void x264_frame_init_lowres_core_neon( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, intptr_t, int, int );
void x264_mbtree_propagate_cost_neon( int16_t *, uint16_t *, uint16_t *, uint16_t *, uint16_t *, float *, int );
void x264_mbtree_fix8_pack_neon( uint16_t *dst, float *src, int count );
void x264_mbtree_fix8_unpack_neon( float *dst, uint16_t *src, int count );
#if !HIGH_BIT_DEPTH
static void x264_weight_cache_neon( x264_t *h, x264_weight_t *w )
{
if( w->i_scale == 1<<w->i_denom )
{
if( w->i_offset < 0 )
{
w->weightfn = x264_mc_offsetsub_wtab_neon;
w->cachea[0] = -w->i_offset;
}
else
{
w->weightfn = x264_mc_offsetadd_wtab_neon;
w->cachea[0] = w->i_offset;
}
}
else if( !w->i_denom )
w->weightfn = x264_mc_nodenom_wtab_neon;
else
w->weightfn = x264_mc_wtab_neon;
}
static void (* const x264_pixel_avg_wtab_neon[6])( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ) =
{
NULL,
x264_pixel_avg2_w4_neon,
x264_pixel_avg2_w8_neon,
x264_pixel_avg2_w16_neon, // no slower than w12, so no point in a separate function
x264_pixel_avg2_w16_neon,
x264_pixel_avg2_w20_neon,
};
static void (* const x264_mc_copy_wtab_neon[5])( uint8_t *, intptr_t, uint8_t *, intptr_t, int ) =
{
NULL,
x264_mc_copy_w4_neon,
x264_mc_copy_w8_neon,
NULL,
x264_mc_copy_w16_neon,
};
static void mc_luma_neon( uint8_t *dst, intptr_t i_dst_stride,
uint8_t *src[4], intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height, const x264_weight_t *weight )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2);
uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset;
if( (mvy&3) == 3 ) // explict if() to force conditional add
src1 += i_src_stride;
if( qpel_idx & 5 ) /* qpel interpolation needed */
{
uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
x264_pixel_avg_wtab_neon[i_width>>2](
dst, i_dst_stride, src1, i_src_stride,
src2, i_height );
if( weight->weightfn )
weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height );
}
else if( weight->weightfn )
weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height );
else
x264_mc_copy_wtab_neon[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, i_height );
}
static uint8_t *get_ref_neon( uint8_t *dst, intptr_t *i_dst_stride,
uint8_t *src[4], intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height, const x264_weight_t *weight )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2);
uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset;
if( (mvy&3) == 3 ) // explict if() to force conditional add
src1 += i_src_stride;
if( qpel_idx & 5 ) /* qpel interpolation needed */
{
uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
x264_pixel_avg_wtab_neon[i_width>>2](
dst, *i_dst_stride, src1, i_src_stride,
src2, i_height );
if( weight->weightfn )
weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height );
return dst;
}
else if( weight->weightfn )
{
weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height );
return dst;
}
else
{
*i_dst_stride = i_src_stride;
return src1;
}
}
void x264_hpel_filter_neon( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc,
uint8_t *src, intptr_t stride, int width,
int height, int16_t *buf );
PLANE_COPY(16, neon)
PLANE_COPY_SWAP(16, neon)
PLANE_INTERLEAVE(neon)
#endif // !HIGH_BIT_DEPTH
PROPAGATE_LIST(neon)
void x264_mc_init_aarch64( int cpu, x264_mc_functions_t *pf )
{
#if !HIGH_BIT_DEPTH
if( cpu&X264_CPU_ARMV8 )
{
pf->prefetch_fenc_420 = x264_prefetch_fenc_420_aarch64;
pf->prefetch_fenc_422 = x264_prefetch_fenc_422_aarch64;
pf->prefetch_ref = x264_prefetch_ref_aarch64;
}
if( !(cpu&X264_CPU_NEON) )
return;
pf->copy_16x16_unaligned = x264_mc_copy_w16_neon;
pf->copy[PIXEL_16x16] = x264_mc_copy_w16_neon;
pf->copy[PIXEL_8x8] = x264_mc_copy_w8_neon;
pf->copy[PIXEL_4x4] = x264_mc_copy_w4_neon;
pf->plane_copy = x264_plane_copy_neon;
pf->plane_copy_swap = x264_plane_copy_swap_neon;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_neon;
pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_neon;
pf->plane_copy_interleave = x264_plane_copy_interleave_neon;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_neon;
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_neon;
pf->store_interleave_chroma = x264_store_interleave_chroma_neon;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_neon;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_neon;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_neon;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_neon;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_neon;
pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_neon;
pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_neon;
pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_neon;
pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_neon;
pf->weight = x264_mc_wtab_neon;
pf->offsetadd = x264_mc_offsetadd_wtab_neon;
pf->offsetsub = x264_mc_offsetsub_wtab_neon;
pf->weight_cache = x264_weight_cache_neon;
pf->mc_chroma = x264_mc_chroma_neon;
pf->mc_luma = mc_luma_neon;
pf->get_ref = get_ref_neon;
pf->hpel_filter = x264_hpel_filter_neon;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_neon;
pf->integral_init4h = x264_integral_init4h_neon;
pf->integral_init8h = x264_integral_init8h_neon;
pf->integral_init4v = x264_integral_init4v_neon;
pf->integral_init8v = x264_integral_init8v_neon;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_neon;
pf->mbtree_propagate_list = x264_mbtree_propagate_list_neon;
pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_neon;
pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_neon;
pf->memcpy_aligned = x264_memcpy_aligned_neon;
pf->memzero_aligned = x264_memzero_aligned_neon;
#endif // !HIGH_BIT_DEPTH
}

View file

@ -0,0 +1,31 @@
/*****************************************************************************
* mc.h: aarch64 motion compensation
*****************************************************************************
* Copyright (C) 2014-2017 x264 project
*
* Authors: Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_AARCH64_MC_H
#define X264_AARCH64_MC_H
void x264_mc_init_aarch64( int cpu, x264_mc_functions_t *pf );
#endif

View file

@ -0,0 +1,79 @@
/*****************************************************************************
* pixel.h: aarch64 pixel metrics
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_AARCH64_PIXEL_H
#define X264_AARCH64_PIXEL_H
#define DECL_PIXELS( ret, name, suffix, args ) \
ret x264_pixel_##name##_16x16_##suffix args;\
ret x264_pixel_##name##_16x8_##suffix args;\
ret x264_pixel_##name##_8x16_##suffix args;\
ret x264_pixel_##name##_8x8_##suffix args;\
ret x264_pixel_##name##_8x4_##suffix args;\
ret x264_pixel_##name##_4x16_##suffix args;\
ret x264_pixel_##name##_4x8_##suffix args;\
ret x264_pixel_##name##_4x4_##suffix args;\
#define DECL_X1( name, suffix ) \
DECL_PIXELS( int, name, suffix, ( uint8_t *, intptr_t, uint8_t *, intptr_t ) )
#define DECL_X4( name, suffix ) \
DECL_PIXELS( void, name##_x3, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) )\
DECL_PIXELS( void, name##_x4, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) )
DECL_X1( sad, neon )
DECL_X4( sad, neon )
DECL_X1( satd, neon )
DECL_X1( ssd, neon )
void x264_pixel_ssd_nv12_core_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, uint64_t *, uint64_t * );
int x264_pixel_vsad_neon( uint8_t *, intptr_t, int );
int x264_pixel_sa8d_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t );
int x264_pixel_sa8d_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t );
uint64_t x264_pixel_sa8d_satd_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t );
uint64_t x264_pixel_var_8x8_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_var_8x16_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_var_16x16_neon( uint8_t *, intptr_t );
int x264_pixel_var2_8x8_neon ( uint8_t *, uint8_t *, int * );
int x264_pixel_var2_8x16_neon( uint8_t *, uint8_t *, int * );
uint64_t x264_pixel_hadamard_ac_8x8_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_hadamard_ac_8x16_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_hadamard_ac_16x8_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_hadamard_ac_16x16_neon( uint8_t *, intptr_t );
void x264_pixel_ssim_4x4x2_core_neon( const uint8_t *, intptr_t,
const uint8_t *, intptr_t,
int sums[2][4] );
float x264_pixel_ssim_end4_neon( int sum0[5][4], int sum1[5][4], int width );
int x264_pixel_asd8_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
#endif

View file

@ -0,0 +1,139 @@
/*****************************************************************************
* predict.c: aarch64 intra prediction
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "predict.h"
#include "pixel.h"
void x264_predict_4x4_dc_top_neon( uint8_t *src );
void x264_predict_4x4_ddr_neon( uint8_t *src );
void x264_predict_4x4_ddl_neon( uint8_t *src );
void x264_predict_8x8c_dc_top_neon( uint8_t *src );
void x264_predict_8x8c_dc_left_neon( uint8_t *src );
void x264_predict_8x8c_p_neon( uint8_t *src );
void x264_predict_8x16c_dc_left_neon( uint8_t *src );
void x264_predict_8x16c_dc_top_neon( uint8_t *src );
void x264_predict_8x16c_p_neon( uint8_t *src );
void x264_predict_8x8_ddl_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_ddr_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_vl_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_vr_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_hd_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_hu_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_16x16_dc_top_neon( uint8_t *src );
void x264_predict_16x16_dc_left_neon( uint8_t *src );
void x264_predict_16x16_p_neon( uint8_t *src );
void x264_predict_4x4_init_aarch64( int cpu, x264_predict_t pf[12] )
{
#if !HIGH_BIT_DEPTH
if( cpu&X264_CPU_ARMV8 )
{
pf[I_PRED_4x4_H] = x264_predict_4x4_h_aarch64;
pf[I_PRED_4x4_V] = x264_predict_4x4_v_aarch64;
}
if( cpu&X264_CPU_NEON )
{
pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_neon;
pf[I_PRED_4x4_DC_TOP] = x264_predict_4x4_dc_top_neon;
pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_neon;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_neon;
}
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_8x8c_init_aarch64( int cpu, x264_predict_t pf[7] )
{
#if !HIGH_BIT_DEPTH
if( cpu&X264_CPU_ARMV8 )
{
pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_aarch64;
}
if( !(cpu&X264_CPU_NEON) )
return;
pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_neon;
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_neon;
pf[I_PRED_CHROMA_DC_LEFT] = x264_predict_8x8c_dc_left_neon;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_neon;
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_8x16c_init_aarch64( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_CHROMA_V ] = x264_predict_8x16c_v_neon;
pf[I_PRED_CHROMA_H ] = x264_predict_8x16c_h_neon;
pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_neon;
pf[I_PRED_CHROMA_P ] = x264_predict_8x16c_p_neon;
pf[I_PRED_CHROMA_DC_LEFT]= x264_predict_8x16c_dc_left_neon;
pf[I_PRED_CHROMA_DC_TOP ]= x264_predict_8x16c_dc_top_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_8x8_init_aarch64( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_neon;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_neon;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_neon;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_neon;
pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_neon;
pf[I_PRED_8x8_H] = x264_predict_8x8_h_neon;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_neon;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_neon;
pf[I_PRED_8x8_V] = x264_predict_8x8_v_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_16x16_init_aarch64( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_16x16_DC ] = x264_predict_16x16_dc_neon;
pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_neon;
pf[I_PRED_16x16_DC_LEFT]= x264_predict_16x16_dc_left_neon;
pf[I_PRED_16x16_H ] = x264_predict_16x16_h_neon;
pf[I_PRED_16x16_V ] = x264_predict_16x16_v_neon;
pf[I_PRED_16x16_P ] = x264_predict_16x16_p_neon;
#endif // !HIGH_BIT_DEPTH
}

View file

@ -0,0 +1,58 @@
/*****************************************************************************
* predict.h: aarch64 intra prediction
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_AARCH64_PREDICT_H
#define X264_AARCH64_PREDICT_H
void x264_predict_4x4_h_aarch64( uint8_t *src );
void x264_predict_4x4_v_aarch64( uint8_t *src );
void x264_predict_8x8c_v_aarch64( uint8_t *src );
// for the merged 4x4 intra sad/satd which expects unified suffix
#define x264_predict_4x4_h_neon x264_predict_4x4_h_aarch64
#define x264_predict_4x4_v_neon x264_predict_4x4_v_aarch64
#define x264_predict_8x8c_v_neon x264_predict_8x8c_v_aarch64
void x264_predict_4x4_dc_neon( uint8_t *src );
void x264_predict_8x8_v_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_h_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_dc_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8c_dc_neon( uint8_t *src );
void x264_predict_8x8c_h_neon( uint8_t *src );
void x264_predict_8x16c_v_neon( uint8_t *src );
void x264_predict_8x16c_h_neon( uint8_t *src );
void x264_predict_8x16c_dc_neon( uint8_t *src );
void x264_predict_16x16_v_neon( uint8_t *src );
void x264_predict_16x16_h_neon( uint8_t *src );
void x264_predict_16x16_dc_neon( uint8_t *src );
void x264_predict_4x4_init_aarch64( int cpu, x264_predict_t pf[12] );
void x264_predict_8x8_init_aarch64( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter );
void x264_predict_8x8c_init_aarch64( int cpu, x264_predict_t pf[7] );
void x264_predict_8x16c_init_aarch64( int cpu, x264_predict_t pf[7] );
void x264_predict_16x16_init_aarch64( int cpu, x264_predict_t pf[7] );
#endif /* X264_AARCH64_PREDICT_H */

View file

@ -0,0 +1,59 @@
/*****************************************************************************
* quant.h: arm quantization and level-run
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_AARCH64_QUANT_H
#define X264_AARCH64_QUANT_H
int x264_quant_2x2_dc_aarch64( int16_t dct[4], int mf, int bias );
int x264_quant_2x2_dc_neon( int16_t dct[4], int mf, int bias );
int x264_quant_4x4_dc_neon( int16_t dct[16], int mf, int bias );
int x264_quant_4x4_neon( int16_t dct[16], uint16_t mf[16], uint16_t bias[16] );
int x264_quant_4x4x4_neon( int16_t dct[4][16], uint16_t mf[16], uint16_t bias[16] );
int x264_quant_8x8_neon( int16_t dct[64], uint16_t mf[64], uint16_t bias[64] );
void x264_dequant_4x4_dc_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_neon( int16_t dct[64], int dequant_mf[6][64], int i_qp );
int x264_decimate_score15_neon( int16_t * );
int x264_decimate_score16_neon( int16_t * );
int x264_decimate_score64_neon( int16_t * );
int x264_coeff_last4_aarch64( int16_t * );
int x264_coeff_last8_aarch64( int16_t * );
int x264_coeff_last15_neon( int16_t * );
int x264_coeff_last16_neon( int16_t * );
int x264_coeff_last64_neon( int16_t * );
int x264_coeff_level_run4_aarch64( int16_t *, x264_run_level_t * );
int x264_coeff_level_run8_neon( int16_t *, x264_run_level_t * );
int x264_coeff_level_run15_neon( int16_t *, x264_run_level_t * );
int x264_coeff_level_run16_neon( int16_t *, x264_run_level_t * );
void x264_denoise_dct_neon( dctcoef *, uint32_t *, udctcoef *, int );
#endif

View file

@ -0,0 +1,53 @@
/*****************************************************************************
* dct.h: arm transform and zigzag
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ARM_DCT_H
#define X264_ARM_DCT_H
void x264_dct4x4dc_neon( int16_t d[16] );
void x264_idct4x4dc_neon( int16_t d[16] );
void x264_sub4x4_dct_neon( int16_t dct[16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_neon( int16_t dct[4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_neon( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_add4x4_idct_neon( uint8_t *p_dst, int16_t dct[16] );
void x264_add8x8_idct_neon( uint8_t *p_dst, int16_t dct[4][16] );
void x264_add16x16_idct_neon( uint8_t *p_dst, int16_t dct[16][16] );
void x264_add8x8_idct_dc_neon( uint8_t *p_dst, int16_t dct[4] );
void x264_add16x16_idct_dc_neon( uint8_t *p_dst, int16_t dct[16] );
void x264_sub8x8_dct_dc_neon( int16_t dct[4], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x16_dct_dc_neon( int16_t dct[8], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct8_neon( int16_t dct[64], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct8_neon( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 );
void x264_add8x8_idct8_neon( uint8_t *p_dst, int16_t dct[64] );
void x264_add16x16_idct8_neon( uint8_t *p_dst, int16_t dct[4][64] );
void x264_zigzag_scan_4x4_frame_neon( int16_t level[16], int16_t dct[16] );
#endif

View file

@ -0,0 +1,310 @@
/*****************************************************************************
* mc-c.c: arm motion compensation
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
* Janne Grunau <janne-x264@jannau.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "mc.h"
void x264_prefetch_ref_arm( uint8_t *, intptr_t, int );
void x264_prefetch_fenc_arm( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void *x264_memcpy_aligned_neon( void *dst, const void *src, size_t n );
void x264_memzero_aligned_neon( void *dst, size_t n );
void x264_pixel_avg_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_16x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_8x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_8x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x16_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg_4x2_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_pixel_avg2_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_pixel_avg2_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_pixel_avg2_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_pixel_avg2_w20_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int );
void x264_plane_copy_core_neon( pixel *dst, intptr_t i_dst,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_neon( pixel *dstu, intptr_t i_dstu,
pixel *dstv, intptr_t i_dstv,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_rgb_neon( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc,
pixel *src, intptr_t i_src, int pw, int w, int h );
void x264_plane_copy_interleave_core_neon( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
void x264_plane_copy_swap_core_neon( pixel *dst, intptr_t i_dst,
pixel *src, intptr_t i_src, int w, int h );
void x264_store_interleave_chroma_neon( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height );
void x264_load_deinterleave_chroma_fdec_neon( pixel *dst, pixel *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fenc_neon( pixel *dst, pixel *src, intptr_t i_src, int height );
#if !HIGH_BIT_DEPTH
#define MC_WEIGHT(func)\
void x264_mc_weight_w20##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
void x264_mc_weight_w16##func##_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
void x264_mc_weight_w8##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
void x264_mc_weight_w4##func##_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, const x264_weight_t *, int );\
\
static weight_fn_t x264_mc##func##_wtab_neon[6] =\
{\
x264_mc_weight_w4##func##_neon,\
x264_mc_weight_w4##func##_neon,\
x264_mc_weight_w8##func##_neon,\
x264_mc_weight_w16##func##_neon,\
x264_mc_weight_w16##func##_neon,\
x264_mc_weight_w20##func##_neon,\
};
MC_WEIGHT()
MC_WEIGHT(_nodenom)
MC_WEIGHT(_offsetadd)
MC_WEIGHT(_offsetsub)
#endif
void x264_mc_copy_w4_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_copy_w8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_copy_w16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_copy_w16_aligned_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
void x264_mc_chroma_neon( uint8_t *, uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, int, int );
void x264_frame_init_lowres_core_neon( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, intptr_t, int, int );
void x264_hpel_filter_v_neon( uint8_t *, uint8_t *, int16_t *, intptr_t, int );
void x264_hpel_filter_c_neon( uint8_t *, int16_t *, int );
void x264_hpel_filter_h_neon( uint8_t *, uint8_t *, int );
void x264_integral_init4h_neon( uint16_t *, uint8_t *, intptr_t );
void x264_integral_init4v_neon( uint16_t *, uint16_t *, intptr_t );
void x264_integral_init8h_neon( uint16_t *, uint8_t *, intptr_t );
void x264_integral_init8v_neon( uint16_t *, intptr_t );
void x264_mbtree_propagate_cost_neon( int16_t *, uint16_t *, uint16_t *, uint16_t *, uint16_t *, float *, int );
void x264_mbtree_fix8_pack_neon( uint16_t *dst, float *src, int count );
void x264_mbtree_fix8_unpack_neon( float *dst, uint16_t *src, int count );
#if !HIGH_BIT_DEPTH
static void x264_weight_cache_neon( x264_t *h, x264_weight_t *w )
{
if( w->i_scale == 1<<w->i_denom )
{
if( w->i_offset < 0 )
{
w->weightfn = x264_mc_offsetsub_wtab_neon;
w->cachea[0] = -w->i_offset;
}
else
{
w->weightfn = x264_mc_offsetadd_wtab_neon;
w->cachea[0] = w->i_offset;
}
}
else if( !w->i_denom )
w->weightfn = x264_mc_nodenom_wtab_neon;
else
w->weightfn = x264_mc_wtab_neon;
}
static void (* const x264_pixel_avg_wtab_neon[6])( uint8_t *, intptr_t, uint8_t *, intptr_t, uint8_t *, int ) =
{
NULL,
x264_pixel_avg2_w4_neon,
x264_pixel_avg2_w8_neon,
x264_pixel_avg2_w16_neon, // no slower than w12, so no point in a separate function
x264_pixel_avg2_w16_neon,
x264_pixel_avg2_w20_neon,
};
static void (* const x264_mc_copy_wtab_neon[5])( uint8_t *, intptr_t, uint8_t *, intptr_t, int ) =
{
NULL,
x264_mc_copy_w4_neon,
x264_mc_copy_w8_neon,
NULL,
x264_mc_copy_w16_neon,
};
static void mc_luma_neon( uint8_t *dst, intptr_t i_dst_stride,
uint8_t *src[4], intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height, const x264_weight_t *weight )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2);
uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset;
if( (mvy&3) == 3 ) // explict if() to force conditional add
src1 += i_src_stride;
if( qpel_idx & 5 ) /* qpel interpolation needed */
{
uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
x264_pixel_avg_wtab_neon[i_width>>2](
dst, i_dst_stride, src1, i_src_stride,
src2, i_height );
if( weight->weightfn )
weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height );
}
else if( weight->weightfn )
weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height );
else
x264_mc_copy_wtab_neon[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, i_height );
}
static uint8_t *get_ref_neon( uint8_t *dst, intptr_t *i_dst_stride,
uint8_t *src[4], intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height, const x264_weight_t *weight )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
intptr_t offset = (mvy>>2)*i_src_stride + (mvx>>2);
uint8_t *src1 = src[x264_hpel_ref0[qpel_idx]] + offset;
if( (mvy&3) == 3 ) // explict if() to force conditional add
src1 += i_src_stride;
if( qpel_idx & 5 ) /* qpel interpolation needed */
{
uint8_t *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
x264_pixel_avg_wtab_neon[i_width>>2](
dst, *i_dst_stride, src1, i_src_stride,
src2, i_height );
if( weight->weightfn )
weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height );
return dst;
}
else if( weight->weightfn )
{
weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height );
return dst;
}
else
{
*i_dst_stride = i_src_stride;
return src1;
}
}
static void hpel_filter_neon( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src,
intptr_t stride, int width, int height, int16_t *buf )
{
intptr_t realign = (intptr_t)src & 15;
src -= realign;
dstv -= realign;
dstc -= realign;
dsth -= realign;
width += realign;
while( height-- )
{
x264_hpel_filter_v_neon( dstv, src, buf+8, stride, width );
x264_hpel_filter_c_neon( dstc, buf+8, width );
x264_hpel_filter_h_neon( dsth, src, width );
dsth += stride;
dstv += stride;
dstc += stride;
src += stride;
}
}
PLANE_COPY(16, neon)
PLANE_COPY_SWAP(16, neon)
PLANE_INTERLEAVE(neon)
#endif // !HIGH_BIT_DEPTH
PROPAGATE_LIST(neon)
void x264_mc_init_arm( int cpu, x264_mc_functions_t *pf )
{
if( !(cpu&X264_CPU_ARMV6) )
return;
#if !HIGH_BIT_DEPTH
pf->prefetch_fenc_420 = x264_prefetch_fenc_arm;
pf->prefetch_fenc_422 = x264_prefetch_fenc_arm; /* FIXME */
pf->prefetch_ref = x264_prefetch_ref_arm;
#endif // !HIGH_BIT_DEPTH
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf->copy_16x16_unaligned = x264_mc_copy_w16_neon;
pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_neon;
pf->copy[PIXEL_8x8] = x264_mc_copy_w8_neon;
pf->copy[PIXEL_4x4] = x264_mc_copy_w4_neon;
pf->plane_copy = x264_plane_copy_neon;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_neon;
pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_neon;
pf->plane_copy_interleave = x264_plane_copy_interleave_neon;
pf->plane_copy_swap = x264_plane_copy_swap_neon;
pf->store_interleave_chroma = x264_store_interleave_chroma_neon;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_neon;
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_neon;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_neon;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_neon;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_neon;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_neon;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_neon;
pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_neon;
pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_neon;
pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_neon;
pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_neon;
pf->weight = x264_mc_wtab_neon;
pf->offsetadd = x264_mc_offsetadd_wtab_neon;
pf->offsetsub = x264_mc_offsetsub_wtab_neon;
pf->weight_cache = x264_weight_cache_neon;
pf->mc_chroma = x264_mc_chroma_neon;
pf->mc_luma = mc_luma_neon;
pf->get_ref = get_ref_neon;
pf->hpel_filter = hpel_filter_neon;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_neon;
pf->integral_init4h = x264_integral_init4h_neon;
pf->integral_init8h = x264_integral_init8h_neon;
pf->integral_init4v = x264_integral_init4v_neon;
pf->integral_init8v = x264_integral_init8v_neon;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_neon;
pf->mbtree_propagate_list = x264_mbtree_propagate_list_neon;
pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_neon;
pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_neon;
#endif // !HIGH_BIT_DEPTH
// Apple's gcc stupidly cannot align stack variables, and ALIGNED_ARRAY can't work on structs
#ifndef SYS_MACOSX
pf->memcpy_aligned = x264_memcpy_aligned_neon;
#endif
pf->memzero_aligned = x264_memzero_aligned_neon;
}

View file

@ -0,0 +1,31 @@
/*****************************************************************************
* mc.h: arm motion compensation
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ARM_MC_H
#define X264_ARM_MC_H
void x264_mc_init_arm( int cpu, x264_mc_functions_t *pf );
#endif

View file

@ -0,0 +1,81 @@
/*****************************************************************************
* pixel.h: arm pixel metrics
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ARM_PIXEL_H
#define X264_ARM_PIXEL_H
#define DECL_PIXELS( ret, name, suffix, args ) \
ret x264_pixel_##name##_16x16_##suffix args;\
ret x264_pixel_##name##_16x8_##suffix args;\
ret x264_pixel_##name##_8x16_##suffix args;\
ret x264_pixel_##name##_8x8_##suffix args;\
ret x264_pixel_##name##_8x4_##suffix args;\
ret x264_pixel_##name##_4x8_##suffix args;\
ret x264_pixel_##name##_4x4_##suffix args;\
#define DECL_X1( name, suffix ) \
DECL_PIXELS( int, name, suffix, ( uint8_t *, int, uint8_t *, int ) )
#define DECL_X4( name, suffix ) \
DECL_PIXELS( void, name##_x3, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) )\
DECL_PIXELS( void, name##_x4, suffix, ( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, intptr_t, int * ) )
int x264_pixel_sad_4x4_armv6( uint8_t *, intptr_t, uint8_t *, intptr_t );
int x264_pixel_sad_4x8_armv6( uint8_t *, intptr_t, uint8_t *, intptr_t );
DECL_X1( sad, neon )
DECL_X1( sad_aligned, neon )
DECL_X1( sad_aligned, neon_dual )
DECL_X4( sad, neon )
DECL_X1( satd, neon )
DECL_X1( ssd, neon )
void x264_pixel_ssd_nv12_core_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int, int, uint64_t *, uint64_t * );
int x264_pixel_vsad_neon( uint8_t *, intptr_t, int );
int x264_pixel_sa8d_8x8_neon ( uint8_t *, intptr_t, uint8_t *, intptr_t );
int x264_pixel_sa8d_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t );
uint64_t x264_pixel_sa8d_satd_16x16_neon( uint8_t *, intptr_t, uint8_t *, intptr_t );
uint64_t x264_pixel_var_8x8_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_var_8x16_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_var_16x16_neon( uint8_t *, intptr_t );
int x264_pixel_var2_8x8_neon ( uint8_t *, uint8_t *, int * );
int x264_pixel_var2_8x16_neon( uint8_t *, uint8_t *, int * );
uint64_t x264_pixel_hadamard_ac_8x8_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_hadamard_ac_8x16_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_hadamard_ac_16x8_neon ( uint8_t *, intptr_t );
uint64_t x264_pixel_hadamard_ac_16x16_neon( uint8_t *, intptr_t );
void x264_pixel_ssim_4x4x2_core_neon( const uint8_t *, intptr_t,
const uint8_t *, intptr_t,
int sums[2][4] );
float x264_pixel_ssim_end4_neon( int sum0[5][4], int sum1[5][4], int width );
int x264_pixel_asd8_neon( uint8_t *, intptr_t, uint8_t *, intptr_t, int );
#endif

View file

@ -0,0 +1,108 @@
/*****************************************************************************
* predict.c: arm intra prediction
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "predict.h"
#include "pixel.h"
void x264_predict_4x4_init_arm( int cpu, x264_predict_t pf[12] )
{
if( !(cpu&X264_CPU_ARMV6) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_4x4_H] = x264_predict_4x4_h_armv6;
pf[I_PRED_4x4_V] = x264_predict_4x4_v_armv6;
pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_armv6;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_armv6;
if( !(cpu&X264_CPU_NEON) )
return;
pf[I_PRED_4x4_DC_TOP] = x264_predict_4x4_dc_top_neon;
pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_8x8c_init_arm( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_neon;
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_neon;
pf[I_PRED_CHROMA_DC_LEFT] = x264_predict_8x8c_dc_left_neon;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_neon;
pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_neon;
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_8x16c_init_arm( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
/* The other functions weren't faster than C (gcc 4.7.3) on Cortex A8 and A9. */
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_neon;
pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_neon;
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_8x8_init_arm( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_neon;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_neon;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_neon;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_neon;
pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_neon;
pf[I_PRED_8x8_H] = x264_predict_8x8_h_neon;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_neon;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_neon;
pf[I_PRED_8x8_V] = x264_predict_8x8_v_neon;
#endif // !HIGH_BIT_DEPTH
}
void x264_predict_16x16_init_arm( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_NEON) )
return;
#if !HIGH_BIT_DEPTH
pf[I_PRED_16x16_DC ] = x264_predict_16x16_dc_neon;
pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_neon;
pf[I_PRED_16x16_DC_LEFT]= x264_predict_16x16_dc_left_neon;
pf[I_PRED_16x16_H ] = x264_predict_16x16_h_neon;
pf[I_PRED_16x16_V ] = x264_predict_16x16_v_neon;
pf[I_PRED_16x16_P ] = x264_predict_16x16_p_neon;
#endif // !HIGH_BIT_DEPTH
}

View file

@ -0,0 +1,70 @@
/*****************************************************************************
* predict.h: arm intra prediction
*****************************************************************************
* Copyright (C) 2009-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ARM_PREDICT_H
#define X264_ARM_PREDICT_H
void x264_predict_4x4_dc_armv6( uint8_t *src );
void x264_predict_4x4_dc_top_neon( uint8_t *src );
void x264_predict_4x4_v_armv6( uint8_t *src );
void x264_predict_4x4_h_armv6( uint8_t *src );
void x264_predict_4x4_ddr_armv6( uint8_t *src );
void x264_predict_4x4_ddl_neon( uint8_t *src );
void x264_predict_8x8c_dc_neon( uint8_t *src );
void x264_predict_8x8c_dc_top_neon( uint8_t *src );
void x264_predict_8x8c_dc_left_neon( uint8_t *src );
void x264_predict_8x8c_h_neon( uint8_t *src );
void x264_predict_8x8c_v_neon( uint8_t *src );
void x264_predict_8x8c_p_neon( uint8_t *src );
void x264_predict_8x16c_h_neon( uint8_t *src );
void x264_predict_8x16c_dc_top_neon( uint8_t *src );
void x264_predict_8x16c_p_neon( uint8_t *src );
void x264_predict_8x8_dc_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_ddl_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_ddr_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_vl_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_vr_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_v_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_h_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_hd_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_hu_neon( uint8_t *src, uint8_t edge[36] );
void x264_predict_16x16_dc_neon( uint8_t *src );
void x264_predict_16x16_dc_top_neon( uint8_t *src );
void x264_predict_16x16_dc_left_neon( uint8_t *src );
void x264_predict_16x16_h_neon( uint8_t *src );
void x264_predict_16x16_v_neon( uint8_t *src );
void x264_predict_16x16_p_neon( uint8_t *src );
void x264_predict_4x4_init_arm( int cpu, x264_predict_t pf[12] );
void x264_predict_8x8_init_arm( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter );
void x264_predict_8x8c_init_arm( int cpu, x264_predict_t pf[7] );
void x264_predict_8x16c_init_arm( int cpu, x264_predict_t pf[7] );
void x264_predict_16x16_init_arm( int cpu, x264_predict_t pf[7] );
#endif

View file

@ -0,0 +1,53 @@
/*****************************************************************************
* quant.h: arm quantization and level-run
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: David Conrad <lessen42@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ARM_QUANT_H
#define X264_ARM_QUANT_H
int x264_quant_2x2_dc_armv6( int16_t dct[4], int mf, int bias );
int x264_quant_2x2_dc_neon( int16_t dct[4], int mf, int bias );
int x264_quant_4x4_dc_neon( int16_t dct[16], int mf, int bias );
int x264_quant_4x4_neon( int16_t dct[16], uint16_t mf[16], uint16_t bias[16] );
int x264_quant_4x4x4_neon( int16_t dct[4][16], uint16_t mf[16], uint16_t bias[16] );
int x264_quant_8x8_neon( int16_t dct[64], uint16_t mf[64], uint16_t bias[64] );
void x264_dequant_4x4_dc_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_neon( int16_t dct[64], int dequant_mf[6][64], int i_qp );
int x264_decimate_score15_neon( int16_t * );
int x264_decimate_score16_neon( int16_t * );
int x264_decimate_score64_neon( int16_t * );
int x264_coeff_last4_arm( int16_t * );
int x264_coeff_last8_arm( int16_t * );
int x264_coeff_last15_neon( int16_t * );
int x264_coeff_last16_neon( int16_t * );
int x264_coeff_last64_neon( int16_t * );
void x264_denoise_dct_neon( dctcoef *, uint32_t *, udctcoef *, int );
#endif

View file

@ -0,0 +1,176 @@
/*****************************************************************************
* bitstream.c: bitstream writing
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
static uint8_t *x264_nal_escape_c( uint8_t *dst, uint8_t *src, uint8_t *end )
{
if( src < end ) *dst++ = *src++;
if( src < end ) *dst++ = *src++;
while( src < end )
{
if( src[0] <= 0x03 && !dst[-2] && !dst[-1] )
*dst++ = 0x03;
*dst++ = *src++;
}
return dst;
}
uint8_t *x264_nal_escape_mmx2( uint8_t *dst, uint8_t *src, uint8_t *end );
uint8_t *x264_nal_escape_sse2( uint8_t *dst, uint8_t *src, uint8_t *end );
uint8_t *x264_nal_escape_avx2( uint8_t *dst, uint8_t *src, uint8_t *end );
void x264_cabac_block_residual_rd_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_rd_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_rd_internal_ssse3 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_rd_internal_ssse3_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_rd_internal_avx512 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_8x8_rd_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_8x8_rd_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_8x8_rd_internal_ssse3 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_8x8_rd_internal_ssse3_lzcnt( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_8x8_rd_internal_avx512 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_internal_sse2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_internal_lzcnt ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_internal_avx2 ( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
void x264_cabac_block_residual_internal_avx512( dctcoef *l, int b_interlaced, intptr_t ctx_block_cat, x264_cabac_t *cb );
uint8_t *x264_nal_escape_neon( uint8_t *dst, uint8_t *src, uint8_t *end );
/****************************************************************************
* x264_nal_encode:
****************************************************************************/
void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal )
{
uint8_t *src = nal->p_payload;
uint8_t *end = nal->p_payload + nal->i_payload;
uint8_t *orig_dst = dst;
if( h->param.b_annexb )
{
if( nal->b_long_startcode )
*dst++ = 0x00;
*dst++ = 0x00;
*dst++ = 0x00;
*dst++ = 0x01;
}
else /* save room for size later */
dst += 4;
/* nal header */
*dst++ = ( 0x00 << 7 ) | ( nal->i_ref_idc << 5 ) | nal->i_type;
dst = h->bsf.nal_escape( dst, src, end );
int size = dst - orig_dst;
/* Apply AVC-Intra padding */
if( h->param.i_avcintra_class )
{
int padding = nal->i_payload + nal->i_padding + NALU_OVERHEAD - size;
if( padding > 0 )
{
memset( dst, 0, padding );
size += padding;
}
nal->i_padding = X264_MAX( padding, 0 );
}
/* Write the size header for mp4/etc */
if( !h->param.b_annexb )
{
/* Size doesn't include the size of the header we're writing now. */
int chunk_size = size - 4;
orig_dst[0] = chunk_size >> 24;
orig_dst[1] = chunk_size >> 16;
orig_dst[2] = chunk_size >> 8;
orig_dst[3] = chunk_size >> 0;
}
nal->i_payload = size;
nal->p_payload = orig_dst;
x264_emms();
}
void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf )
{
memset( pf, 0, sizeof(*pf) );
pf->nal_escape = x264_nal_escape_c;
#if HAVE_MMX
#if ARCH_X86_64 && !defined( __MACH__ )
pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_sse2;
pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_sse2;
pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_sse2;
#endif
if( cpu&X264_CPU_MMX2 )
pf->nal_escape = x264_nal_escape_mmx2;
if( cpu&X264_CPU_SSE2 )
{
if( cpu&X264_CPU_SSE2_IS_FAST )
pf->nal_escape = x264_nal_escape_sse2;
}
#if ARCH_X86_64 && !defined( __MACH__ )
if( cpu&X264_CPU_LZCNT )
{
pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_lzcnt;
pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_lzcnt;
pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_lzcnt;
}
if( cpu&X264_CPU_SSSE3 )
{
pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_ssse3;
pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_ssse3;
if( cpu&X264_CPU_LZCNT )
{
pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_ssse3_lzcnt;
pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_ssse3_lzcnt;
}
}
if( cpu&X264_CPU_AVX2 )
{
pf->nal_escape = x264_nal_escape_avx2;
pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx2;
}
if( cpu&X264_CPU_AVX512 )
{
pf->cabac_block_residual_internal = x264_cabac_block_residual_internal_avx512;
pf->cabac_block_residual_rd_internal = x264_cabac_block_residual_rd_internal_avx512;
pf->cabac_block_residual_8x8_rd_internal = x264_cabac_block_residual_8x8_rd_internal_avx512;
}
#endif
#endif
#if HAVE_ARMV6
if( cpu&X264_CPU_NEON )
pf->nal_escape = x264_nal_escape_neon;
#endif
#if ARCH_AARCH64
if( cpu&X264_CPU_NEON )
pf->nal_escape = x264_nal_escape_neon;
#endif
}

View file

@ -0,0 +1,312 @@
/*****************************************************************************
* bitstream.h: bitstream writing
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_BS_H
#define X264_BS_H
typedef struct
{
uint8_t i_bits;
uint8_t i_size;
} vlc_t;
typedef struct
{
uint16_t i_bits;
uint8_t i_size;
/* Next level table to use */
uint8_t i_next;
} vlc_large_t;
typedef struct bs_s
{
uint8_t *p_start;
uint8_t *p;
uint8_t *p_end;
uintptr_t cur_bits;
int i_left; /* i_count number of available bits */
int i_bits_encoded; /* RD only */
} bs_t;
typedef struct
{
int32_t last;
int32_t mask;
ALIGNED_16( dctcoef level[18] );
} x264_run_level_t;
extern const vlc_t x264_coeff0_token[6];
extern const vlc_t x264_coeff_token[6][16][4];
extern const vlc_t x264_total_zeros[15][16];
extern const vlc_t x264_total_zeros_2x2_dc[3][4];
extern const vlc_t x264_total_zeros_2x4_dc[7][8];
typedef struct
{
uint8_t *(*nal_escape)( uint8_t *dst, uint8_t *src, uint8_t *end );
void (*cabac_block_residual_internal)( dctcoef *l, int b_interlaced,
intptr_t ctx_block_cat, x264_cabac_t *cb );
void (*cabac_block_residual_rd_internal)( dctcoef *l, int b_interlaced,
intptr_t ctx_block_cat, x264_cabac_t *cb );
void (*cabac_block_residual_8x8_rd_internal)( dctcoef *l, int b_interlaced,
intptr_t ctx_block_cat, x264_cabac_t *cb );
} x264_bitstream_function_t;
void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf );
/* A larger level table size theoretically could help a bit at extremely
* high bitrates, but the cost in cache is usually too high for it to be
* useful.
* This size appears to be optimal for QP18 encoding on a Nehalem CPU.
* FIXME: Do further testing? */
#define LEVEL_TABLE_SIZE 128
extern vlc_large_t x264_level_token[7][LEVEL_TABLE_SIZE];
/* The longest possible set of zero run codes sums to 25 bits. This leaves
* plenty of room for both the code (25 bits) and size (5 bits) in a uint32_t. */
extern uint32_t x264_run_before[1<<16];
static inline void bs_init( bs_t *s, void *p_data, int i_data )
{
int offset = ((intptr_t)p_data & 3);
s->p = s->p_start = (uint8_t*)p_data - offset;
s->p_end = (uint8_t*)p_data + i_data;
s->i_left = (WORD_SIZE - offset)*8;
s->cur_bits = endian_fix32( M32(s->p) );
s->cur_bits >>= (4-offset)*8;
}
static inline int bs_pos( bs_t *s )
{
return( 8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left );
}
/* Write the rest of cur_bits to the bitstream; results in a bitstream no longer 32-bit aligned. */
static inline void bs_flush( bs_t *s )
{
M32( s->p ) = endian_fix32( s->cur_bits << (s->i_left&31) );
s->p += WORD_SIZE - (s->i_left >> 3);
s->i_left = WORD_SIZE*8;
}
/* The inverse of bs_flush: prepare the bitstream to be written to again. */
static inline void bs_realign( bs_t *s )
{
int offset = ((intptr_t)s->p & 3);
if( offset )
{
s->p = (uint8_t*)s->p - offset;
s->i_left = (WORD_SIZE - offset)*8;
s->cur_bits = endian_fix32( M32(s->p) );
s->cur_bits >>= (4-offset)*8;
}
}
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
{
if( WORD_SIZE == 8 )
{
s->cur_bits = (s->cur_bits << i_count) | i_bits;
s->i_left -= i_count;
if( s->i_left <= 32 )
{
#if WORDS_BIGENDIAN
M32( s->p ) = s->cur_bits >> (32 - s->i_left);
#else
M32( s->p ) = endian_fix( s->cur_bits << s->i_left );
#endif
s->i_left += 32;
s->p += 4;
}
}
else
{
if( i_count < s->i_left )
{
s->cur_bits = (s->cur_bits << i_count) | i_bits;
s->i_left -= i_count;
}
else
{
i_count -= s->i_left;
s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count);
M32( s->p ) = endian_fix( s->cur_bits );
s->p += 4;
s->cur_bits = i_bits;
s->i_left = 32 - i_count;
}
}
}
/* Special case to eliminate branch in normal bs_write. */
/* Golomb never writes an even-size code, so this is only used in slice headers. */
static inline void bs_write32( bs_t *s, uint32_t i_bits )
{
bs_write( s, 16, i_bits >> 16 );
bs_write( s, 16, i_bits );
}
static inline void bs_write1( bs_t *s, uint32_t i_bit )
{
s->cur_bits <<= 1;
s->cur_bits |= i_bit;
s->i_left--;
if( s->i_left == WORD_SIZE*8-32 )
{
M32( s->p ) = endian_fix32( s->cur_bits );
s->p += 4;
s->i_left = WORD_SIZE*8;
}
}
static inline void bs_align_0( bs_t *s )
{
bs_write( s, s->i_left&7, 0 );
bs_flush( s );
}
static inline void bs_align_1( bs_t *s )
{
bs_write( s, s->i_left&7, (1 << (s->i_left&7)) - 1 );
bs_flush( s );
}
static inline void bs_align_10( bs_t *s )
{
if( s->i_left&7 )
bs_write( s, s->i_left&7, 1 << ( (s->i_left&7) - 1 ) );
}
/* golomb functions */
static const uint8_t x264_ue_size_tab[256] =
{
1, 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
};
static inline void bs_write_ue_big( bs_t *s, unsigned int val )
{
int size = 0;
int tmp = ++val;
if( tmp >= 0x10000 )
{
size = 32;
tmp >>= 16;
}
if( tmp >= 0x100 )
{
size += 16;
tmp >>= 8;
}
size += x264_ue_size_tab[tmp];
bs_write( s, size>>1, 0 );
bs_write( s, (size>>1)+1, val );
}
/* Only works on values under 255. */
static inline void bs_write_ue( bs_t *s, int val )
{
bs_write( s, x264_ue_size_tab[val+1], val+1 );
}
static inline void bs_write_se( bs_t *s, int val )
{
int size = 0;
/* Faster than (val <= 0 ? -val*2+1 : val*2) */
/* 4 instructions on x86, 3 on ARM */
int tmp = 1 - val*2;
if( tmp < 0 ) tmp = val*2;
val = tmp;
if( tmp >= 0x100 )
{
size = 16;
tmp >>= 8;
}
size += x264_ue_size_tab[tmp];
bs_write( s, size, val );
}
static inline void bs_write_te( bs_t *s, int x, int val )
{
if( x == 1 )
bs_write1( s, 1^val );
else //if( x > 1 )
bs_write_ue( s, val );
}
static inline void bs_rbsp_trailing( bs_t *s )
{
bs_write1( s, 1 );
bs_write( s, s->i_left&7, 0 );
}
static ALWAYS_INLINE int bs_size_ue( unsigned int val )
{
return x264_ue_size_tab[val+1];
}
static ALWAYS_INLINE int bs_size_ue_big( unsigned int val )
{
if( val < 255 )
return x264_ue_size_tab[val+1];
else
return x264_ue_size_tab[(val+1)>>8] + 16;
}
static ALWAYS_INLINE int bs_size_se( int val )
{
int tmp = 1 - val*2;
if( tmp < 0 ) tmp = val*2;
if( tmp < 256 )
return x264_ue_size_tab[tmp];
else
return x264_ue_size_tab[tmp>>8]+16;
}
static ALWAYS_INLINE int bs_size_te( int x, int val )
{
if( x == 1 )
return 1;
else //if( x > 1 )
return x264_ue_size_tab[val+1];
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,118 @@
/*****************************************************************************
* cabac.h: arithmetic coder
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_CABAC_H
#define X264_CABAC_H
typedef struct
{
/* state */
int i_low;
int i_range;
/* bit stream */
int i_queue; //stored with an offset of -8 for faster asm
int i_bytes_outstanding;
uint8_t *p_start;
uint8_t *p;
uint8_t *p_end;
/* aligned for memcpy_aligned starting here */
ALIGNED_64( int f8_bits_encoded ); // only if using x264_cabac_size_decision()
/* context */
uint8_t state[1024];
/* for 16-byte alignment */
uint8_t padding[12];
} x264_cabac_t;
extern const uint8_t x264_cabac_transition[128][2];
extern const uint16_t x264_cabac_entropy[128];
/* init the contexts given i_slice_type, the quantif and the model */
void x264_cabac_context_init( x264_t *h, x264_cabac_t *cb, int i_slice_type, int i_qp, int i_model );
void x264_cabac_encode_init_core( x264_cabac_t *cb );
void x264_cabac_encode_init( x264_cabac_t *cb, uint8_t *p_data, uint8_t *p_end );
void x264_cabac_encode_decision_c( x264_cabac_t *cb, int i_ctx, int b );
void x264_cabac_encode_decision_asm( x264_cabac_t *cb, int i_ctx, int b );
void x264_cabac_encode_bypass_c( x264_cabac_t *cb, int b );
void x264_cabac_encode_bypass_asm( x264_cabac_t *cb, int b );
void x264_cabac_encode_terminal_c( x264_cabac_t *cb );
void x264_cabac_encode_terminal_asm( x264_cabac_t *cb );
void x264_cabac_encode_ue_bypass( x264_cabac_t *cb, int exp_bits, int val );
void x264_cabac_encode_flush( x264_t *h, x264_cabac_t *cb );
#if HAVE_MMX
#define x264_cabac_encode_decision x264_cabac_encode_decision_asm
#define x264_cabac_encode_bypass x264_cabac_encode_bypass_asm
#define x264_cabac_encode_terminal x264_cabac_encode_terminal_asm
#elif defined(ARCH_AARCH64)
#define x264_cabac_encode_decision x264_cabac_encode_decision_asm
#define x264_cabac_encode_bypass x264_cabac_encode_bypass_asm
#define x264_cabac_encode_terminal x264_cabac_encode_terminal_asm
#else
#define x264_cabac_encode_decision x264_cabac_encode_decision_c
#define x264_cabac_encode_bypass x264_cabac_encode_bypass_c
#define x264_cabac_encode_terminal x264_cabac_encode_terminal_c
#endif
#define x264_cabac_encode_decision_noup x264_cabac_encode_decision
static ALWAYS_INLINE int x264_cabac_pos( x264_cabac_t *cb )
{
return (cb->p - cb->p_start + cb->i_bytes_outstanding) * 8 + cb->i_queue;
}
/* internal only. these don't write the bitstream, just calculate bit cost: */
static ALWAYS_INLINE void x264_cabac_size_decision( x264_cabac_t *cb, long i_ctx, long b )
{
int i_state = cb->state[i_ctx];
cb->state[i_ctx] = x264_cabac_transition[i_state][b];
cb->f8_bits_encoded += x264_cabac_entropy[i_state^b];
}
static ALWAYS_INLINE int x264_cabac_size_decision2( uint8_t *state, long b )
{
int i_state = *state;
*state = x264_cabac_transition[i_state][b];
return x264_cabac_entropy[i_state^b];
}
static ALWAYS_INLINE void x264_cabac_size_decision_noup( x264_cabac_t *cb, long i_ctx, long b )
{
int i_state = cb->state[i_ctx];
cb->f8_bits_encoded += x264_cabac_entropy[i_state^b];
}
static ALWAYS_INLINE int x264_cabac_size_decision_noup2( uint8_t *state, long b )
{
return x264_cabac_entropy[*state^b];
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,490 @@
/*****************************************************************************
* cpu.c: cpu detection
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#if HAVE_POSIXTHREAD && SYS_LINUX
#include <sched.h>
#endif
#if SYS_BEOS
#include <kernel/OS.h>
#endif
#if SYS_MACOSX || SYS_FREEBSD
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
#if SYS_OPENBSD
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
#endif
const x264_cpu_name_t x264_cpu_names[] =
{
#if HAVE_MMX
// {"MMX", X264_CPU_MMX}, // we don't support asm on mmx1 cpus anymore
#define MMX2 X264_CPU_MMX|X264_CPU_MMX2
{"MMX2", MMX2},
{"MMXEXT", MMX2},
{"SSE", MMX2|X264_CPU_SSE},
#define SSE2 MMX2|X264_CPU_SSE|X264_CPU_SSE2
{"SSE2Slow", SSE2|X264_CPU_SSE2_IS_SLOW},
{"SSE2", SSE2},
{"SSE2Fast", SSE2|X264_CPU_SSE2_IS_FAST},
{"LZCNT", SSE2|X264_CPU_LZCNT},
{"SSE3", SSE2|X264_CPU_SSE3},
{"SSSE3", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3},
{"SSE4.1", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4},
{"SSE4", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4},
{"SSE4.2", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4|X264_CPU_SSE42},
#define AVX SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4|X264_CPU_SSE42|X264_CPU_AVX
{"AVX", AVX},
{"XOP", AVX|X264_CPU_XOP},
{"FMA4", AVX|X264_CPU_FMA4},
{"FMA3", AVX|X264_CPU_FMA3},
{"BMI1", AVX|X264_CPU_LZCNT|X264_CPU_BMI1},
{"BMI2", AVX|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2},
#define AVX2 AVX|X264_CPU_FMA3|X264_CPU_LZCNT|X264_CPU_BMI1|X264_CPU_BMI2|X264_CPU_AVX2
{"AVX2", AVX2},
{"AVX512", AVX2|X264_CPU_AVX512},
#undef AVX2
#undef AVX
#undef SSE2
#undef MMX2
{"Cache32", X264_CPU_CACHELINE_32},
{"Cache64", X264_CPU_CACHELINE_64},
{"SlowAtom", X264_CPU_SLOW_ATOM},
{"SlowPshufb", X264_CPU_SLOW_PSHUFB},
{"SlowPalignr", X264_CPU_SLOW_PALIGNR},
{"SlowShuffle", X264_CPU_SLOW_SHUFFLE},
{"UnalignedStack", X264_CPU_STACK_MOD4},
#elif ARCH_PPC
{"Altivec", X264_CPU_ALTIVEC},
#elif ARCH_ARM
{"ARMv6", X264_CPU_ARMV6},
{"NEON", X264_CPU_NEON},
{"FastNeonMRC", X264_CPU_FAST_NEON_MRC},
#elif ARCH_AARCH64
{"ARMv8", X264_CPU_ARMV8},
{"NEON", X264_CPU_NEON},
#elif ARCH_MIPS
{"MSA", X264_CPU_MSA},
#endif
{"", 0},
};
#if (ARCH_PPC && SYS_LINUX) || (ARCH_ARM && !HAVE_NEON)
#include <signal.h>
#include <setjmp.h>
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump = 0;
static void sigill_handler( int sig )
{
if( !canjump )
{
signal( sig, SIG_DFL );
raise( sig );
}
canjump = 0;
siglongjmp( jmpbuf, 1 );
}
#endif
#if HAVE_MMX
int x264_cpu_cpuid_test( void );
void x264_cpu_cpuid( uint32_t op, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx );
uint64_t x264_cpu_xgetbv( int xcr );
uint32_t x264_cpu_detect( void )
{
uint32_t cpu = 0;
uint32_t eax, ebx, ecx, edx;
uint32_t vendor[4] = {0};
uint32_t max_extended_cap, max_basic_cap;
#if !ARCH_X86_64
if( !x264_cpu_cpuid_test() )
return 0;
#endif
x264_cpu_cpuid( 0, &max_basic_cap, vendor+0, vendor+2, vendor+1 );
if( max_basic_cap == 0 )
return 0;
x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx );
if( edx&0x00800000 )
cpu |= X264_CPU_MMX;
else
return cpu;
if( edx&0x02000000 )
cpu |= X264_CPU_MMX2|X264_CPU_SSE;
if( edx&0x04000000 )
cpu |= X264_CPU_SSE2;
if( ecx&0x00000001 )
cpu |= X264_CPU_SSE3;
if( ecx&0x00000200 )
cpu |= X264_CPU_SSSE3|X264_CPU_SSE2_IS_FAST;
if( ecx&0x00080000 )
cpu |= X264_CPU_SSE4;
if( ecx&0x00100000 )
cpu |= X264_CPU_SSE42;
if( ecx&0x08000000 ) /* XGETBV supported and XSAVE enabled by OS */
{
uint64_t xcr0 = x264_cpu_xgetbv( 0 );
if( (xcr0&0x6) == 0x6 ) /* XMM/YMM state */
{
if( ecx&0x10000000 )
cpu |= X264_CPU_AVX;
if( ecx&0x00001000 )
cpu |= X264_CPU_FMA3;
if( max_basic_cap >= 7 )
{
x264_cpu_cpuid( 7, &eax, &ebx, &ecx, &edx );
if( ebx&0x00000008 )
cpu |= X264_CPU_BMI1;
if( ebx&0x00000100 )
cpu |= X264_CPU_BMI2;
if( ebx&0x00000020 )
cpu |= X264_CPU_AVX2;
if( (xcr0&0xE0) == 0xE0 ) /* OPMASK/ZMM state */
{
if( (ebx&0xD0030000) == 0xD0030000 )
cpu |= X264_CPU_AVX512;
}
}
}
}
x264_cpu_cpuid( 0x80000000, &eax, &ebx, &ecx, &edx );
max_extended_cap = eax;
if( max_extended_cap >= 0x80000001 )
{
x264_cpu_cpuid( 0x80000001, &eax, &ebx, &ecx, &edx );
if( ecx&0x00000020 )
cpu |= X264_CPU_LZCNT; /* Supported by Intel chips starting with Haswell */
if( ecx&0x00000040 ) /* SSE4a, AMD only */
{
int family = ((eax>>8)&0xf) + ((eax>>20)&0xff);
cpu |= X264_CPU_SSE2_IS_FAST; /* Phenom and later CPUs have fast SSE units */
if( family == 0x14 )
{
cpu &= ~X264_CPU_SSE2_IS_FAST; /* SSSE3 doesn't imply fast SSE anymore... */
cpu |= X264_CPU_SSE2_IS_SLOW; /* Bobcat has 64-bit SIMD units */
cpu |= X264_CPU_SLOW_PALIGNR; /* palignr is insanely slow on Bobcat */
}
if( family == 0x16 )
{
cpu |= X264_CPU_SLOW_PSHUFB; /* Jaguar's pshufb isn't that slow, but it's slow enough
* compared to alternate instruction sequences that this
* is equal or faster on almost all such functions. */
}
}
if( cpu & X264_CPU_AVX )
{
if( ecx&0x00000800 ) /* XOP */
cpu |= X264_CPU_XOP;
if( ecx&0x00010000 ) /* FMA4 */
cpu |= X264_CPU_FMA4;
}
if( !strcmp((char*)vendor, "AuthenticAMD") )
{
if( edx&0x00400000 )
cpu |= X264_CPU_MMX2;
if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_FAST) )
cpu |= X264_CPU_SSE2_IS_SLOW; /* AMD CPUs come in two types: terrible at SSE and great at it */
}
}
if( !strcmp((char*)vendor, "GenuineIntel") )
{
x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx );
int family = ((eax>>8)&0xf) + ((eax>>20)&0xff);
int model = ((eax>>4)&0xf) + ((eax>>12)&0xf0);
if( family == 6 )
{
/* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and 6/14 (core1 "yonah")
* theoretically support sse2, but it's significantly slower than mmx for
* almost all of x264's functions, so let's just pretend they don't. */
if( model == 9 || model == 13 || model == 14 )
{
cpu &= ~(X264_CPU_SSE2|X264_CPU_SSE3);
assert(!(cpu&(X264_CPU_SSSE3|X264_CPU_SSE4)));
}
/* Detect Atom CPU */
else if( model == 28 )
{
cpu |= X264_CPU_SLOW_ATOM;
cpu |= X264_CPU_SLOW_PSHUFB;
}
/* Conroe has a slow shuffle unit. Check the model number to make sure not
* to include crippled low-end Penryns and Nehalems that don't have SSE4. */
else if( (cpu&X264_CPU_SSSE3) && !(cpu&X264_CPU_SSE4) && model < 23 )
cpu |= X264_CPU_SLOW_SHUFFLE;
}
}
if( (!strcmp((char*)vendor, "GenuineIntel") || !strcmp((char*)vendor, "CyrixInstead")) && !(cpu&X264_CPU_SSE42))
{
/* cacheline size is specified in 3 places, any of which may be missing */
x264_cpu_cpuid( 1, &eax, &ebx, &ecx, &edx );
int cache = (ebx&0xff00)>>5; // cflush size
if( !cache && max_extended_cap >= 0x80000006 )
{
x264_cpu_cpuid( 0x80000006, &eax, &ebx, &ecx, &edx );
cache = ecx&0xff; // cacheline size
}
if( !cache && max_basic_cap >= 2 )
{
// Cache and TLB Information
static const char cache32_ids[] = { 0x0a, 0x0c, 0x41, 0x42, 0x43, 0x44, 0x45, 0x82, 0x83, 0x84, 0x85, 0 };
static const char cache64_ids[] = { 0x22, 0x23, 0x25, 0x29, 0x2c, 0x46, 0x47, 0x49, 0x60, 0x66, 0x67,
0x68, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7c, 0x7f, 0x86, 0x87, 0 };
uint32_t buf[4];
int max, i = 0;
do {
x264_cpu_cpuid( 2, buf+0, buf+1, buf+2, buf+3 );
max = buf[0]&0xff;
buf[0] &= ~0xff;
for( int j = 0; j < 4; j++ )
if( !(buf[j]>>31) )
while( buf[j] )
{
if( strchr( cache32_ids, buf[j]&0xff ) )
cache = 32;
if( strchr( cache64_ids, buf[j]&0xff ) )
cache = 64;
buf[j] >>= 8;
}
} while( ++i < max );
}
if( cache == 32 )
cpu |= X264_CPU_CACHELINE_32;
else if( cache == 64 )
cpu |= X264_CPU_CACHELINE_64;
else
x264_log( NULL, X264_LOG_WARNING, "unable to determine cacheline size\n" );
}
#if STACK_ALIGNMENT < 16
cpu |= X264_CPU_STACK_MOD4;
#endif
return cpu;
}
#elif ARCH_PPC && HAVE_ALTIVEC
#if SYS_MACOSX || SYS_OPENBSD || SYS_FREEBSD
#include <sys/sysctl.h>
uint32_t x264_cpu_detect( void )
{
/* Thank you VLC */
uint32_t cpu = 0;
#if SYS_OPENBSD
int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
#elif SYS_MACOSX
int selectors[2] = { CTL_HW, HW_VECTORUNIT };
#endif
int has_altivec = 0;
size_t length = sizeof( has_altivec );
#if SYS_MACOSX || SYS_OPENBSD
int error = sysctl( selectors, 2, &has_altivec, &length, NULL, 0 );
#else
int error = sysctlbyname( "hw.altivec", &has_altivec, &length, NULL, 0 );
#endif
if( error == 0 && has_altivec != 0 )
cpu |= X264_CPU_ALTIVEC;
return cpu;
}
#elif SYS_LINUX
uint32_t x264_cpu_detect( void )
{
#ifdef __NO_FPRS__
return 0;
#else
static void (*oldsig)( int );
oldsig = signal( SIGILL, sigill_handler );
if( sigsetjmp( jmpbuf, 1 ) )
{
signal( SIGILL, oldsig );
return 0;
}
canjump = 1;
asm volatile( "mtspr 256, %0\n\t"
"vand 0, 0, 0\n\t"
:
: "r"(-1) );
canjump = 0;
signal( SIGILL, oldsig );
return X264_CPU_ALTIVEC;
#endif
}
#endif
#elif ARCH_ARM
void x264_cpu_neon_test( void );
int x264_cpu_fast_neon_mrc_test( void );
uint32_t x264_cpu_detect( void )
{
int flags = 0;
#if HAVE_ARMV6
flags |= X264_CPU_ARMV6;
// don't do this hack if compiled with -mfpu=neon
#if !HAVE_NEON
static void (* oldsig)( int );
oldsig = signal( SIGILL, sigill_handler );
if( sigsetjmp( jmpbuf, 1 ) )
{
signal( SIGILL, oldsig );
return flags;
}
canjump = 1;
x264_cpu_neon_test();
canjump = 0;
signal( SIGILL, oldsig );
#endif
flags |= X264_CPU_NEON;
// fast neon -> arm (Cortex-A9) detection relies on user access to the
// cycle counter; this assumes ARMv7 performance counters.
// NEON requires at least ARMv7, ARMv8 may require changes here, but
// hopefully this hacky detection method will have been replaced by then.
// Note that there is potential for a race condition if another program or
// x264 instance disables or reinits the counters while x264 is using them,
// which may result in incorrect detection and the counters stuck enabled.
// right now Apple does not seem to support performance counters for this test
#ifndef __MACH__
flags |= x264_cpu_fast_neon_mrc_test() ? X264_CPU_FAST_NEON_MRC : 0;
#endif
// TODO: write dual issue test? currently it's A8 (dual issue) vs. A9 (fast mrc)
#endif
return flags;
}
#elif ARCH_AARCH64
uint32_t x264_cpu_detect( void )
{
return X264_CPU_ARMV8 | X264_CPU_NEON;
}
#elif ARCH_MIPS
uint32_t x264_cpu_detect( void )
{
uint32_t flags = 0;
#if HAVE_MSA
flags |= X264_CPU_MSA;
#endif
return flags;
}
#else
uint32_t x264_cpu_detect( void )
{
return 0;
}
#endif
int x264_cpu_num_processors( void )
{
#if !HAVE_THREAD
return 1;
#elif SYS_WINDOWS
return x264_pthread_num_processors_np();
#elif SYS_CYGWIN || SYS_SunOS
return sysconf( _SC_NPROCESSORS_ONLN );
#elif SYS_LINUX
#ifdef __ANDROID__
// Android NDK does not expose sched_getaffinity
return sysconf( _SC_NPROCESSORS_CONF );
#else
cpu_set_t p_aff;
memset( &p_aff, 0, sizeof(p_aff) );
if( sched_getaffinity( 0, sizeof(p_aff), &p_aff ) )
return 1;
#if HAVE_CPU_COUNT
return CPU_COUNT(&p_aff);
#else
int np = 0;
for( unsigned int bit = 0; bit < 8 * sizeof(p_aff); bit++ )
np += (((uint8_t *)&p_aff)[bit / 8] >> (bit % 8)) & 1;
return np;
#endif
#endif
#elif SYS_BEOS
system_info info;
get_system_info( &info );
return info.cpu_count;
#elif SYS_MACOSX || SYS_FREEBSD || SYS_OPENBSD
int ncpu;
size_t length = sizeof( ncpu );
#if SYS_OPENBSD
int mib[2] = { CTL_HW, HW_NCPU };
if( sysctl(mib, 2, &ncpu, &length, NULL, 0) )
#else
if( sysctlbyname("hw.ncpu", &ncpu, &length, NULL, 0) )
#endif
{
ncpu = 1;
}
return ncpu;
#else
return 1;
#endif
}

View file

@ -0,0 +1,73 @@
/*****************************************************************************
* cpu.h: cpu detection
*****************************************************************************
* Copyright (C) 2004-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_CPU_H
#define X264_CPU_H
uint32_t x264_cpu_detect( void );
int x264_cpu_num_processors( void );
void x264_cpu_emms( void );
void x264_cpu_sfence( void );
#if HAVE_MMX
/* There is no way to forbid the compiler from using float instructions
* before the emms so miscompilation could theoretically occur in the
* unlikely event that the compiler reorders emms and float instructions. */
#if HAVE_X86_INLINE_ASM
/* Clobbering memory makes the compiler less likely to reorder code. */
#define x264_emms() asm volatile( "emms":::"memory","st","st(1)","st(2)", \
"st(3)","st(4)","st(5)","st(6)","st(7)" )
#else
#define x264_emms() x264_cpu_emms()
#endif
#else
#define x264_emms()
#endif
#define x264_sfence x264_cpu_sfence
/* kludge:
* gcc can't give variables any greater alignment than the stack frame has.
* We need 32 byte alignment for AVX2, so here we make sure that the stack is
* aligned to 32 bytes.
* gcc 4.2 introduced __attribute__((force_align_arg_pointer)) to fix this
* problem, but I don't want to require such a new version.
* aligning to 32 bytes only works if the compiler supports keeping that
* alignment between functions (osdep.h handles manual alignment of arrays
* if it doesn't).
*/
#if HAVE_MMX && (STACK_ALIGNMENT > 16 || (ARCH_X86 && STACK_ALIGNMENT > 4))
intptr_t x264_stack_align( void (*func)(), ... );
#define x264_stack_align(func,...) x264_stack_align((void (*)())func, __VA_ARGS__)
#else
#define x264_stack_align(func,...) func(__VA_ARGS__)
#endif
typedef struct
{
const char *name;
uint32_t flags;
} x264_cpu_name_t;
extern const x264_cpu_name_t x264_cpu_names[];
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,80 @@
/*****************************************************************************
* dct.h: transform and zigzag
*****************************************************************************
* Copyright (C) 2004-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_DCT_H
#define X264_DCT_H
extern const uint32_t x264_dct4_weight_tab[16];
extern const uint32_t x264_dct8_weight_tab[64];
extern const uint32_t x264_dct4_weight2_tab[16];
extern const uint32_t x264_dct8_weight2_tab[64];
typedef struct
{
// pix1 stride = FENC_STRIDE
// pix2 stride = FDEC_STRIDE
// p_dst stride = FDEC_STRIDE
void (*sub4x4_dct) ( dctcoef dct[16], pixel *pix1, pixel *pix2 );
void (*add4x4_idct)( pixel *p_dst, dctcoef dct[16] );
void (*sub8x8_dct) ( dctcoef dct[4][16], pixel *pix1, pixel *pix2 );
void (*sub8x8_dct_dc) ( dctcoef dct[4], pixel *pix1, pixel *pix2 );
void (*add8x8_idct) ( pixel *p_dst, dctcoef dct[4][16] );
void (*add8x8_idct_dc)( pixel *p_dst, dctcoef dct[4] );
void (*sub8x16_dct_dc)( dctcoef dct[8], pixel *pix1, pixel *pix2 );
void (*sub16x16_dct) ( dctcoef dct[16][16], pixel *pix1, pixel *pix2 );
void (*add16x16_idct) ( pixel *p_dst, dctcoef dct[16][16] );
void (*add16x16_idct_dc)( pixel *p_dst, dctcoef dct[16] );
void (*sub8x8_dct8) ( dctcoef dct[64], pixel *pix1, pixel *pix2 );
void (*add8x8_idct8)( pixel *p_dst, dctcoef dct[64] );
void (*sub16x16_dct8) ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 );
void (*add16x16_idct8)( pixel *p_dst, dctcoef dct[4][64] );
void (*dct4x4dc) ( dctcoef d[16] );
void (*idct4x4dc)( dctcoef d[16] );
void (*dct2x4dc)( dctcoef dct[8], dctcoef dct4x4[8][16] );
} x264_dct_function_t;
typedef struct
{
void (*scan_8x8)( dctcoef level[64], dctcoef dct[64] );
void (*scan_4x4)( dctcoef level[16], dctcoef dct[16] );
int (*sub_8x8) ( dctcoef level[64], const pixel *p_src, pixel *p_dst );
int (*sub_4x4) ( dctcoef level[16], const pixel *p_src, pixel *p_dst );
int (*sub_4x4ac)( dctcoef level[16], const pixel *p_src, pixel *p_dst, dctcoef *dc );
void (*interleave_8x8_cavlc)( dctcoef *dst, dctcoef *src, uint8_t *nnz );
} x264_zigzag_function_t;
void x264_dct_init( int cpu, x264_dct_function_t *dctf );
void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zigzag_function_t *pf_interlaced );
#endif

View file

@ -0,0 +1,908 @@
/*****************************************************************************
* deblock.c: deblocking
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
/* Deblocking filter */
static const uint8_t i_alpha_table[52+12*3] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 4, 4, 5, 6,
7, 8, 9, 10, 12, 13, 15, 17, 20, 22,
25, 28, 32, 36, 40, 45, 50, 56, 63, 71,
80, 90,101,113,127,144,162,182,203,226,
255,255,
255,255,255,255,255,255,255,255,255,255,255,255,
};
static const uint8_t i_beta_table[52+12*3] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 2, 2, 3,
3, 3, 3, 4, 4, 4, 6, 6, 7, 7,
8, 8, 9, 9, 10, 10, 11, 11, 12, 12,
13, 13, 14, 14, 15, 15, 16, 16, 17, 17,
18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
};
static const int8_t i_tc0_table[52+12*3][4] =
{
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 },
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 },
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 },
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 },
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 },
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 },
{-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 0 }, {-1, 0, 0, 1 },
{-1, 0, 0, 1 }, {-1, 0, 0, 1 }, {-1, 0, 0, 1 }, {-1, 0, 1, 1 }, {-1, 0, 1, 1 }, {-1, 1, 1, 1 },
{-1, 1, 1, 1 }, {-1, 1, 1, 1 }, {-1, 1, 1, 1 }, {-1, 1, 1, 2 }, {-1, 1, 1, 2 }, {-1, 1, 1, 2 },
{-1, 1, 1, 2 }, {-1, 1, 2, 3 }, {-1, 1, 2, 3 }, {-1, 2, 2, 3 }, {-1, 2, 2, 4 }, {-1, 2, 3, 4 },
{-1, 2, 3, 4 }, {-1, 3, 3, 5 }, {-1, 3, 4, 6 }, {-1, 3, 4, 6 }, {-1, 4, 5, 7 }, {-1, 4, 5, 8 },
{-1, 4, 6, 9 }, {-1, 5, 7,10 }, {-1, 6, 8,11 }, {-1, 6, 8,13 }, {-1, 7,10,14 }, {-1, 8,11,16 },
{-1, 9,12,18 }, {-1,10,13,20 }, {-1,11,15,23 }, {-1,13,17,25 },
{-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 },
{-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 }, {-1,13,17,25 },
};
#define alpha_table(x) i_alpha_table[(x)+24]
#define beta_table(x) i_beta_table[(x)+24]
#define tc0_table(x) i_tc0_table[(x)+24]
/* From ffmpeg */
static ALWAYS_INLINE void deblock_edge_luma_c( pixel *pix, intptr_t xstride, int alpha, int beta, int8_t tc0 )
{
int p2 = pix[-3*xstride];
int p1 = pix[-2*xstride];
int p0 = pix[-1*xstride];
int q0 = pix[ 0*xstride];
int q1 = pix[ 1*xstride];
int q2 = pix[ 2*xstride];
if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )
{
int tc = tc0;
int delta;
if( abs( p2 - p0 ) < beta )
{
if( tc0 )
pix[-2*xstride] = p1 + x264_clip3( (( p2 + ((p0 + q0 + 1) >> 1)) >> 1) - p1, -tc0, tc0 );
tc++;
}
if( abs( q2 - q0 ) < beta )
{
if( tc0 )
pix[ 1*xstride] = q1 + x264_clip3( (( q2 + ((p0 + q0 + 1) >> 1)) >> 1) - q1, -tc0, tc0 );
tc++;
}
delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc );
pix[-1*xstride] = x264_clip_pixel( p0 + delta ); /* p0' */
pix[ 0*xstride] = x264_clip_pixel( q0 - delta ); /* q0' */
}
}
static inline void deblock_luma_c( pixel *pix, intptr_t xstride, intptr_t ystride, int alpha, int beta, int8_t *tc0 )
{
for( int i = 0; i < 4; i++ )
{
if( tc0[i] < 0 )
{
pix += 4*ystride;
continue;
}
for( int d = 0; d < 4; d++, pix += ystride )
deblock_edge_luma_c( pix, xstride, alpha, beta, tc0[i] );
}
}
static void deblock_h_luma_mbaff_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
for( int d = 0; d < 8; d++, pix += stride )
deblock_edge_luma_c( pix, 1, alpha, beta, tc0[d>>1] );
}
static void deblock_v_luma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
deblock_luma_c( pix, stride, 1, alpha, beta, tc0 );
}
static void deblock_h_luma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
deblock_luma_c( pix, 1, stride, alpha, beta, tc0 );
}
static ALWAYS_INLINE void deblock_edge_chroma_c( pixel *pix, intptr_t xstride, int alpha, int beta, int8_t tc )
{
int p1 = pix[-2*xstride];
int p0 = pix[-1*xstride];
int q0 = pix[ 0*xstride];
int q1 = pix[ 1*xstride];
if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )
{
int delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc );
pix[-1*xstride] = x264_clip_pixel( p0 + delta ); /* p0' */
pix[ 0*xstride] = x264_clip_pixel( q0 - delta ); /* q0' */
}
}
static ALWAYS_INLINE void deblock_chroma_c( pixel *pix, int height, intptr_t xstride, intptr_t ystride, int alpha, int beta, int8_t *tc0 )
{
for( int i = 0; i < 4; i++ )
{
int tc = tc0[i];
if( tc <= 0 )
{
pix += height*ystride;
continue;
}
for( int d = 0; d < height; d++, pix += ystride-2 )
for( int e = 0; e < 2; e++, pix++ )
deblock_edge_chroma_c( pix, xstride, alpha, beta, tc0[i] );
}
}
static void deblock_h_chroma_mbaff_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
deblock_chroma_c( pix, 1, 2, stride, alpha, beta, tc0 );
}
static void deblock_v_chroma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
deblock_chroma_c( pix, 2, stride, 2, alpha, beta, tc0 );
}
static void deblock_h_chroma_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
deblock_chroma_c( pix, 2, 2, stride, alpha, beta, tc0 );
}
static void deblock_h_chroma_422_c( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
deblock_chroma_c( pix, 4, 2, stride, alpha, beta, tc0 );
}
static ALWAYS_INLINE void deblock_edge_luma_intra_c( pixel *pix, intptr_t xstride, int alpha, int beta )
{
int p2 = pix[-3*xstride];
int p1 = pix[-2*xstride];
int p0 = pix[-1*xstride];
int q0 = pix[ 0*xstride];
int q1 = pix[ 1*xstride];
int q2 = pix[ 2*xstride];
if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )
{
if( abs( p0 - q0 ) < ((alpha >> 2) + 2) )
{
if( abs( p2 - p0 ) < beta ) /* p0', p1', p2' */
{
const int p3 = pix[-4*xstride];
pix[-1*xstride] = ( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3;
pix[-2*xstride] = ( p2 + p1 + p0 + q0 + 2 ) >> 2;
pix[-3*xstride] = ( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3;
}
else /* p0' */
pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2;
if( abs( q2 - q0 ) < beta ) /* q0', q1', q2' */
{
const int q3 = pix[3*xstride];
pix[0*xstride] = ( p1 + 2*p0 + 2*q0 + 2*q1 + q2 + 4 ) >> 3;
pix[1*xstride] = ( p0 + q0 + q1 + q2 + 2 ) >> 2;
pix[2*xstride] = ( 2*q3 + 3*q2 + q1 + q0 + p0 + 4 ) >> 3;
}
else /* q0' */
pix[0*xstride] = ( 2*q1 + q0 + p1 + 2 ) >> 2;
}
else /* p0', q0' */
{
pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2;
pix[ 0*xstride] = ( 2*q1 + q0 + p1 + 2 ) >> 2;
}
}
}
static inline void deblock_luma_intra_c( pixel *pix, intptr_t xstride, intptr_t ystride, int alpha, int beta )
{
for( int d = 0; d < 16; d++, pix += ystride )
deblock_edge_luma_intra_c( pix, xstride, alpha, beta );
}
static void deblock_h_luma_intra_mbaff_c( pixel *pix, intptr_t ystride, int alpha, int beta )
{
for( int d = 0; d < 8; d++, pix += ystride )
deblock_edge_luma_intra_c( pix, 1, alpha, beta );
}
static void deblock_v_luma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta )
{
deblock_luma_intra_c( pix, stride, 1, alpha, beta );
}
static void deblock_h_luma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta )
{
deblock_luma_intra_c( pix, 1, stride, alpha, beta );
}
static ALWAYS_INLINE void deblock_edge_chroma_intra_c( pixel *pix, intptr_t xstride, int alpha, int beta )
{
int p1 = pix[-2*xstride];
int p0 = pix[-1*xstride];
int q0 = pix[ 0*xstride];
int q1 = pix[ 1*xstride];
if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )
{
pix[-1*xstride] = (2*p1 + p0 + q1 + 2) >> 2; /* p0' */
pix[ 0*xstride] = (2*q1 + q0 + p1 + 2) >> 2; /* q0' */
}
}
static ALWAYS_INLINE void deblock_chroma_intra_c( pixel *pix, int width, int height, intptr_t xstride, intptr_t ystride, int alpha, int beta )
{
for( int d = 0; d < height; d++, pix += ystride-2 )
for( int e = 0; e < width; e++, pix++ )
deblock_edge_chroma_intra_c( pix, xstride, alpha, beta );
}
static void deblock_h_chroma_intra_mbaff_c( pixel *pix, intptr_t stride, int alpha, int beta )
{
deblock_chroma_intra_c( pix, 2, 4, 2, stride, alpha, beta );
}
static void deblock_v_chroma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta )
{
deblock_chroma_intra_c( pix, 1, 16, stride, 2, alpha, beta );
}
static void deblock_h_chroma_intra_c( pixel *pix, intptr_t stride, int alpha, int beta )
{
deblock_chroma_intra_c( pix, 2, 8, 2, stride, alpha, beta );
}
static void deblock_h_chroma_422_intra_c( pixel *pix, intptr_t stride, int alpha, int beta )
{
deblock_chroma_intra_c( pix, 2, 16, 2, stride, alpha, beta );
}
static void deblock_strength_c( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], int mvy_limit,
int bframe )
{
for( int dir = 0; dir < 2; dir++ )
{
int s1 = dir ? 1 : 8;
int s2 = dir ? 8 : 1;
for( int edge = 0; edge < 4; edge++ )
for( int i = 0, loc = X264_SCAN8_0+edge*s2; i < 4; i++, loc += s1 )
{
int locn = loc - s2;
if( nnz[loc] || nnz[locn] )
bs[dir][edge][i] = 2;
else if( ref[0][loc] != ref[0][locn] ||
abs( mv[0][loc][0] - mv[0][locn][0] ) >= 4 ||
abs( mv[0][loc][1] - mv[0][locn][1] ) >= mvy_limit ||
(bframe && (ref[1][loc] != ref[1][locn] ||
abs( mv[1][loc][0] - mv[1][locn][0] ) >= 4 ||
abs( mv[1][loc][1] - mv[1][locn][1] ) >= mvy_limit )))
{
bs[dir][edge][i] = 1;
}
else
bs[dir][edge][i] = 0;
}
}
}
static ALWAYS_INLINE void deblock_edge( x264_t *h, pixel *pix, intptr_t i_stride, uint8_t bS[4], int i_qp,
int a, int b, int b_chroma, x264_deblock_inter_t pf_inter )
{
int index_a = i_qp + a;
int index_b = i_qp + b;
int alpha = alpha_table(index_a) << (BIT_DEPTH-8);
int beta = beta_table(index_b) << (BIT_DEPTH-8);
int8_t tc[4];
if( !M32(bS) || !alpha || !beta )
return;
tc[0] = (tc0_table(index_a)[bS[0]] << (BIT_DEPTH-8)) + b_chroma;
tc[1] = (tc0_table(index_a)[bS[1]] << (BIT_DEPTH-8)) + b_chroma;
tc[2] = (tc0_table(index_a)[bS[2]] << (BIT_DEPTH-8)) + b_chroma;
tc[3] = (tc0_table(index_a)[bS[3]] << (BIT_DEPTH-8)) + b_chroma;
pf_inter( pix, i_stride, alpha, beta, tc );
}
static ALWAYS_INLINE void deblock_edge_intra( x264_t *h, pixel *pix, intptr_t i_stride, uint8_t bS[4], int i_qp,
int a, int b, int b_chroma, x264_deblock_intra_t pf_intra )
{
int index_a = i_qp + a;
int index_b = i_qp + b;
int alpha = alpha_table(index_a) << (BIT_DEPTH-8);
int beta = beta_table(index_b) << (BIT_DEPTH-8);
if( !alpha || !beta )
return;
pf_intra( pix, i_stride, alpha, beta );
}
static ALWAYS_INLINE void x264_macroblock_cache_load_neighbours_deblock( x264_t *h, int mb_x, int mb_y )
{
int deblock_on_slice_edges = h->sh.i_disable_deblocking_filter_idc != 2;
h->mb.i_neighbour = 0;
h->mb.i_mb_xy = mb_y * h->mb.i_mb_stride + mb_x;
h->mb.b_interlaced = PARAM_INTERLACED && h->mb.field[h->mb.i_mb_xy];
h->mb.i_mb_top_y = mb_y - (1 << MB_INTERLACED);
h->mb.i_mb_top_xy = mb_x + h->mb.i_mb_stride*h->mb.i_mb_top_y;
h->mb.i_mb_left_xy[1] =
h->mb.i_mb_left_xy[0] = h->mb.i_mb_xy - 1;
if( SLICE_MBAFF )
{
if( mb_y&1 )
{
if( mb_x && h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED )
h->mb.i_mb_left_xy[0] -= h->mb.i_mb_stride;
}
else
{
if( h->mb.i_mb_top_xy >= 0 && MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy] )
{
h->mb.i_mb_top_xy += h->mb.i_mb_stride;
h->mb.i_mb_top_y++;
}
if( mb_x && h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED )
h->mb.i_mb_left_xy[1] += h->mb.i_mb_stride;
}
}
if( mb_x > 0 && (deblock_on_slice_edges ||
h->mb.slice_table[h->mb.i_mb_left_xy[0]] == h->mb.slice_table[h->mb.i_mb_xy]) )
h->mb.i_neighbour |= MB_LEFT;
if( mb_y > MB_INTERLACED && (deblock_on_slice_edges
|| h->mb.slice_table[h->mb.i_mb_top_xy] == h->mb.slice_table[h->mb.i_mb_xy]) )
h->mb.i_neighbour |= MB_TOP;
}
void x264_frame_deblock_row( x264_t *h, int mb_y )
{
int b_interlaced = SLICE_MBAFF;
int a = h->sh.i_alpha_c0_offset - QP_BD_OFFSET;
int b = h->sh.i_beta_offset - QP_BD_OFFSET;
int qp_thresh = 15 - X264_MIN( a, b ) - X264_MAX( 0, h->pps->i_chroma_qp_index_offset );
int stridey = h->fdec->i_stride[0];
int strideuv = h->fdec->i_stride[1];
int chroma444 = CHROMA444;
int chroma_height = 16 >> CHROMA_V_SHIFT;
intptr_t uvdiff = chroma444 ? h->fdec->plane[2] - h->fdec->plane[1] : 1;
for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x += (~b_interlaced | mb_y)&1, mb_y ^= b_interlaced )
{
x264_prefetch_fenc( h, h->fdec, mb_x, mb_y );
x264_macroblock_cache_load_neighbours_deblock( h, mb_x, mb_y );
int mb_xy = h->mb.i_mb_xy;
int transform_8x8 = h->mb.mb_transform_size[mb_xy];
int intra_cur = IS_INTRA( h->mb.type[mb_xy] );
uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x];
pixel *pixy = h->fdec->plane[0] + 16*mb_y*stridey + 16*mb_x;
pixel *pixuv = h->fdec->plane[1] + chroma_height*mb_y*strideuv + 16*mb_x;
if( mb_y & MB_INTERLACED )
{
pixy -= 15*stridey;
pixuv -= (chroma_height-1)*strideuv;
}
int stride2y = stridey << MB_INTERLACED;
int stride2uv = strideuv << MB_INTERLACED;
int qp = h->mb.qp[mb_xy];
int qpc = h->chroma_qp_table[qp];
int first_edge_only = (h->mb.partition[mb_xy] == D_16x16 && !h->mb.cbp[mb_xy] && !intra_cur) || qp <= qp_thresh;
#define FILTER( intra, dir, edge, qp, chroma_qp )\
do\
{\
if( !(edge & 1) || !transform_8x8 )\
{\
deblock_edge##intra( h, pixy + 4*edge*(dir?stride2y:1),\
stride2y, bs[dir][edge], qp, a, b, 0,\
h->loopf.deblock_luma##intra[dir] );\
if( CHROMA_FORMAT == CHROMA_444 )\
{\
deblock_edge##intra( h, pixuv + 4*edge*(dir?stride2uv:1),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\
h->loopf.deblock_luma##intra[dir] );\
deblock_edge##intra( h, pixuv + uvdiff + 4*edge*(dir?stride2uv:1),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\
h->loopf.deblock_luma##intra[dir] );\
}\
else if( CHROMA_FORMAT == CHROMA_420 && !(edge & 1) )\
{\
deblock_edge##intra( h, pixuv + edge*(dir?2*stride2uv:4),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\
h->loopf.deblock_chroma##intra[dir] );\
}\
}\
if( CHROMA_FORMAT == CHROMA_422 && (dir || !(edge & 1)) )\
{\
deblock_edge##intra( h, pixuv + edge*(dir?4*stride2uv:4),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\
h->loopf.deblock_chroma##intra[dir] );\
}\
} while( 0 )
if( h->mb.i_neighbour & MB_LEFT )
{
if( b_interlaced && h->mb.field[h->mb.i_mb_left_xy[0]] != MB_INTERLACED )
{
int luma_qp[2];
int chroma_qp[2];
int left_qp[2];
x264_deblock_inter_t luma_deblock = h->loopf.deblock_luma_mbaff;
x264_deblock_inter_t chroma_deblock = h->loopf.deblock_chroma_mbaff;
x264_deblock_intra_t luma_intra_deblock = h->loopf.deblock_luma_intra_mbaff;
x264_deblock_intra_t chroma_intra_deblock = h->loopf.deblock_chroma_intra_mbaff;
int c = chroma444 ? 0 : 1;
left_qp[0] = h->mb.qp[h->mb.i_mb_left_xy[0]];
luma_qp[0] = (qp + left_qp[0] + 1) >> 1;
chroma_qp[0] = (qpc + h->chroma_qp_table[left_qp[0]] + 1) >> 1;
if( intra_cur || IS_INTRA( h->mb.type[h->mb.i_mb_left_xy[0]] ) )
{
deblock_edge_intra( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_intra_deblock );
deblock_edge_intra( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock );
if( chroma444 )
deblock_edge_intra( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock );
}
else
{
deblock_edge( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_deblock );
deblock_edge( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock );
if( chroma444 )
deblock_edge( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock );
}
int offy = MB_INTERLACED ? 4 : 0;
int offuv = MB_INTERLACED ? 4-CHROMA_V_SHIFT : 0;
left_qp[1] = h->mb.qp[h->mb.i_mb_left_xy[1]];
luma_qp[1] = (qp + left_qp[1] + 1) >> 1;
chroma_qp[1] = (qpc + h->chroma_qp_table[left_qp[1]] + 1) >> 1;
if( intra_cur || IS_INTRA( h->mb.type[h->mb.i_mb_left_xy[1]] ) )
{
deblock_edge_intra( h, pixy + (stridey<<offy), 2*stridey, bs[0][4], luma_qp[1], a, b, 0, luma_intra_deblock );
deblock_edge_intra( h, pixuv + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_intra_deblock );
if( chroma444 )
deblock_edge_intra( h, pixuv + uvdiff + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_intra_deblock );
}
else
{
deblock_edge( h, pixy + (stridey<<offy), 2*stridey, bs[0][4], luma_qp[1], a, b, 0, luma_deblock );
deblock_edge( h, pixuv + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_deblock );
if( chroma444 )
deblock_edge( h, pixuv + uvdiff + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_deblock );
}
}
else
{
int qpl = h->mb.qp[h->mb.i_mb_xy-1];
int qp_left = (qp + qpl + 1) >> 1;
int qpc_left = (qpc + h->chroma_qp_table[qpl] + 1) >> 1;
int intra_left = IS_INTRA( h->mb.type[h->mb.i_mb_xy-1] );
int intra_deblock = intra_cur || intra_left;
/* Any MB that was coded, or that analysis decided to skip, has quality commensurate with its QP.
* But if deblocking affects neighboring MBs that were force-skipped, blur might accumulate there.
* So reset their effective QP to max, to indicate that lack of guarantee. */
if( h->fdec->mb_info && M32( bs[0][0] ) )
{
#define RESET_EFFECTIVE_QP(xy) h->fdec->effective_qp[xy] |= 0xff * !!(h->fdec->mb_info[xy] & X264_MBINFO_CONSTANT);
RESET_EFFECTIVE_QP(mb_xy);
RESET_EFFECTIVE_QP(h->mb.i_mb_left_xy[0]);
}
if( intra_deblock )
FILTER( _intra, 0, 0, qp_left, qpc_left );
else
FILTER( , 0, 0, qp_left, qpc_left );
}
}
if( !first_edge_only )
{
FILTER( , 0, 1, qp, qpc );
FILTER( , 0, 2, qp, qpc );
FILTER( , 0, 3, qp, qpc );
}
if( h->mb.i_neighbour & MB_TOP )
{
if( b_interlaced && !(mb_y&1) && !MB_INTERLACED && h->mb.field[h->mb.i_mb_top_xy] )
{
int mbn_xy = mb_xy - 2 * h->mb.i_mb_stride;
for( int j = 0; j < 2; j++, mbn_xy += h->mb.i_mb_stride )
{
int qpt = h->mb.qp[mbn_xy];
int qp_top = (qp + qpt + 1) >> 1;
int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1;
int intra_top = IS_INTRA( h->mb.type[mbn_xy] );
if( intra_cur || intra_top )
M32( bs[1][4*j] ) = 0x03030303;
// deblock the first horizontal edge of the even rows, then the first horizontal edge of the odd rows
deblock_edge( h, pixy + j*stridey, 2* stridey, bs[1][4*j], qp_top, a, b, 0, h->loopf.deblock_luma[1] );
if( chroma444 )
{
deblock_edge( h, pixuv + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 0, h->loopf.deblock_luma[1] );
deblock_edge( h, pixuv + uvdiff + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 0, h->loopf.deblock_luma[1] );
}
else
deblock_edge( h, pixuv + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 1, h->loopf.deblock_chroma[1] );
}
}
else
{
int qpt = h->mb.qp[h->mb.i_mb_top_xy];
int qp_top = (qp + qpt + 1) >> 1;
int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1;
int intra_top = IS_INTRA( h->mb.type[h->mb.i_mb_top_xy] );
int intra_deblock = intra_cur || intra_top;
/* This edge has been modified, reset effective qp to max. */
if( h->fdec->mb_info && M32( bs[1][0] ) )
{
RESET_EFFECTIVE_QP(mb_xy);
RESET_EFFECTIVE_QP(h->mb.i_mb_top_xy);
}
if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) && intra_deblock )
{
FILTER( _intra, 1, 0, qp_top, qpc_top );
}
else
{
if( intra_deblock )
M32( bs[1][0] ) = 0x03030303;
FILTER( , 1, 0, qp_top, qpc_top );
}
}
}
if( !first_edge_only )
{
FILTER( , 1, 1, qp, qpc );
FILTER( , 1, 2, qp, qpc );
FILTER( , 1, 3, qp, qpc );
}
#undef FILTER
}
}
/* For deblock-aware RD.
* TODO:
* deblock macroblock edges
* support analysis partitions smaller than 16x16
* deblock chroma for 4:2:0/4:2:2
* handle duplicate refs correctly
*/
void x264_macroblock_deblock( x264_t *h )
{
int a = h->sh.i_alpha_c0_offset - QP_BD_OFFSET;
int b = h->sh.i_beta_offset - QP_BD_OFFSET;
int qp_thresh = 15 - X264_MIN( a, b ) - X264_MAX( 0, h->pps->i_chroma_qp_index_offset );
int intra_cur = IS_INTRA( h->mb.i_type );
int qp = h->mb.i_qp;
int qpc = h->mb.i_chroma_qp;
if( (h->mb.i_partition == D_16x16 && !h->mb.i_cbp_luma && !intra_cur) || qp <= qp_thresh )
return;
uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength;
if( intra_cur )
{
M32( bs[0][1] ) = 0x03030303;
M64( bs[0][2] ) = 0x0303030303030303ULL;
M32( bs[1][1] ) = 0x03030303;
M64( bs[1][2] ) = 0x0303030303030303ULL;
}
else
h->loopf.deblock_strength( h->mb.cache.non_zero_count, h->mb.cache.ref, h->mb.cache.mv,
bs, 4 >> MB_INTERLACED, h->sh.i_type == SLICE_TYPE_B );
int transform_8x8 = h->mb.b_transform_8x8;
#define FILTER( dir, edge )\
do\
{\
deblock_edge( h, h->mb.pic.p_fdec[0] + 4*edge*(dir?FDEC_STRIDE:1),\
FDEC_STRIDE, bs[dir][edge], qp, a, b, 0,\
h->loopf.deblock_luma[dir] );\
if( CHROMA444 )\
{\
deblock_edge( h, h->mb.pic.p_fdec[1] + 4*edge*(dir?FDEC_STRIDE:1),\
FDEC_STRIDE, bs[dir][edge], qpc, a, b, 0,\
h->loopf.deblock_luma[dir] );\
deblock_edge( h, h->mb.pic.p_fdec[2] + 4*edge*(dir?FDEC_STRIDE:1),\
FDEC_STRIDE, bs[dir][edge], qpc, a, b, 0,\
h->loopf.deblock_luma[dir] );\
}\
} while( 0 )
if( !transform_8x8 ) FILTER( 0, 1 );
FILTER( 0, 2 );
if( !transform_8x8 ) FILTER( 0, 3 );
if( !transform_8x8 ) FILTER( 1, 1 );
FILTER( 1, 2 );
if( !transform_8x8 ) FILTER( 1, 3 );
#undef FILTER
}
#if HAVE_MMX
void x264_deblock_v_luma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_luma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_chroma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_chroma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_mbaff_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_mbaff_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_422_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_422_sse2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_422_avx ( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_luma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_luma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_luma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_luma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_chroma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_chroma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_422_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_422_intra_sse2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_422_intra_avx ( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_strength_sse2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4],
int mvy_limit, int bframe );
void x264_deblock_strength_ssse3 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4],
int mvy_limit, int bframe );
void x264_deblock_strength_avx ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4],
int mvy_limit, int bframe );
void x264_deblock_strength_avx2 ( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4],
int mvy_limit, int bframe );
void x264_deblock_strength_avx512( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4],
int mvy_limit, int bframe );
void x264_deblock_h_chroma_intra_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_mbaff_sse2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_mbaff_avx ( pixel *pix, intptr_t stride, int alpha, int beta );
#if ARCH_X86
void x264_deblock_h_luma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v8_luma_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_chroma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v8_luma_intra_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_chroma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_mbaff_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
#if HIGH_BIT_DEPTH
void x264_deblock_v_luma_mmx2( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_luma_intra_mmx2( pixel *pix, intptr_t stride, int alpha, int beta );
#else
// FIXME this wrapper has a significant cpu cost
static void x264_deblock_v_luma_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 )
{
x264_deblock_v8_luma_mmx2( pix, stride, alpha, beta, tc0 );
x264_deblock_v8_luma_mmx2( pix+8, stride, alpha, beta, tc0+2 );
}
static void x264_deblock_v_luma_intra_mmx2( uint8_t *pix, intptr_t stride, int alpha, int beta )
{
x264_deblock_v8_luma_intra_mmx2( pix, stride, alpha, beta );
x264_deblock_v8_luma_intra_mmx2( pix+8, stride, alpha, beta );
}
#endif // HIGH_BIT_DEPTH
#endif
#endif
#if ARCH_PPC
void x264_deblock_v_luma_altivec( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_altivec( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
#endif // ARCH_PPC
#if HAVE_ARMV6 || ARCH_AARCH64
void x264_deblock_v_luma_neon ( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_neon ( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_chroma_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_strength_neon( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4],
int mvy_limit, int bframe );
void x264_deblock_h_chroma_422_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_mbaff_neon( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_intra_mbaff_neon( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_422_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_chroma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_luma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_luma_intra_neon( uint8_t *pix, intptr_t stride, int alpha, int beta );
#endif
#if !HIGH_BIT_DEPTH
#if HAVE_MSA
void x264_deblock_v_luma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_luma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_chroma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_h_chroma_msa( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
void x264_deblock_v_luma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_luma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_v_chroma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_h_chroma_intra_msa( uint8_t *pix, intptr_t stride, int alpha, int beta );
void x264_deblock_strength_msa( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], int mvy_limit,
int bframe );
#endif
#endif
void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff )
{
pf->deblock_luma[1] = deblock_v_luma_c;
pf->deblock_luma[0] = deblock_h_luma_c;
pf->deblock_chroma[1] = deblock_v_chroma_c;
pf->deblock_h_chroma_420 = deblock_h_chroma_c;
pf->deblock_h_chroma_422 = deblock_h_chroma_422_c;
pf->deblock_luma_intra[1] = deblock_v_luma_intra_c;
pf->deblock_luma_intra[0] = deblock_h_luma_intra_c;
pf->deblock_chroma_intra[1] = deblock_v_chroma_intra_c;
pf->deblock_h_chroma_420_intra = deblock_h_chroma_intra_c;
pf->deblock_h_chroma_422_intra = deblock_h_chroma_422_intra_c;
pf->deblock_luma_mbaff = deblock_h_luma_mbaff_c;
pf->deblock_chroma_420_mbaff = deblock_h_chroma_mbaff_c;
pf->deblock_luma_intra_mbaff = deblock_h_luma_intra_mbaff_c;
pf->deblock_chroma_420_intra_mbaff = deblock_h_chroma_intra_mbaff_c;
pf->deblock_strength = deblock_strength_c;
#if HAVE_MMX
if( cpu&X264_CPU_MMX2 )
{
#if ARCH_X86
pf->deblock_luma[1] = x264_deblock_v_luma_mmx2;
pf->deblock_luma[0] = x264_deblock_h_luma_mmx2;
pf->deblock_chroma[1] = x264_deblock_v_chroma_mmx2;
pf->deblock_h_chroma_420 = x264_deblock_h_chroma_mmx2;
pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_mmx2;
pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_mmx2;
pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_mmx2;
pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_mmx2;
pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_mmx2;
pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_mmx2;
pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_mmx2;
pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_mmx2;
#endif
#if !HIGH_BIT_DEPTH
pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_mmx2;
#endif
if( cpu&X264_CPU_SSE2 )
{
pf->deblock_strength = x264_deblock_strength_sse2;
pf->deblock_h_chroma_420 = x264_deblock_h_chroma_sse2;
pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_sse2;
pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_sse2;
pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_sse2;
pf->deblock_luma[1] = x264_deblock_v_luma_sse2;
pf->deblock_luma[0] = x264_deblock_h_luma_sse2;
pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_sse2;
pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_sse2;
if( !(cpu&X264_CPU_STACK_MOD4) )
{
pf->deblock_chroma[1] = x264_deblock_v_chroma_sse2;
pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_sse2;
pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_sse2;
#if HIGH_BIT_DEPTH
pf->deblock_chroma_420_intra_mbaff= x264_deblock_h_chroma_intra_mbaff_sse2;
#endif
}
}
if( cpu&X264_CPU_SSSE3 )
pf->deblock_strength = x264_deblock_strength_ssse3;
if( cpu&X264_CPU_AVX )
{
pf->deblock_strength = x264_deblock_strength_avx;
pf->deblock_h_chroma_420 = x264_deblock_h_chroma_avx;
pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_avx;
pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_avx;
pf->deblock_luma[1] = x264_deblock_v_luma_avx;
pf->deblock_luma[0] = x264_deblock_h_luma_avx;
pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_avx;
pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_avx;
if( !(cpu&X264_CPU_STACK_MOD4) )
{
pf->deblock_chroma[1] = x264_deblock_v_chroma_avx;
pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_avx;
pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_avx;
#if HIGH_BIT_DEPTH
pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_avx;
pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_avx;
#endif
}
}
if( cpu&X264_CPU_AVX2 )
{
pf->deblock_strength = x264_deblock_strength_avx2;
}
if( cpu&X264_CPU_AVX512 )
{
pf->deblock_strength = x264_deblock_strength_avx512;
}
}
#endif
#if !HIGH_BIT_DEPTH
#if HAVE_ALTIVEC
if( cpu&X264_CPU_ALTIVEC )
{
pf->deblock_luma[1] = x264_deblock_v_luma_altivec;
pf->deblock_luma[0] = x264_deblock_h_luma_altivec;
}
#endif // HAVE_ALTIVEC
#if HAVE_ARMV6 || ARCH_AARCH64
if( cpu&X264_CPU_NEON )
{
pf->deblock_luma[1] = x264_deblock_v_luma_neon;
pf->deblock_luma[0] = x264_deblock_h_luma_neon;
pf->deblock_chroma[1] = x264_deblock_v_chroma_neon;
pf->deblock_h_chroma_420 = x264_deblock_h_chroma_neon;
pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_neon;
pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_neon;
pf->deblock_chroma_420_intra_mbaff = x264_deblock_h_chroma_intra_mbaff_neon;
pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_neon;
pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_neon;
pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_neon;
pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_neon;
pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_neon;
pf->deblock_strength = x264_deblock_strength_neon;
}
#endif
#if HAVE_MSA
if( cpu&X264_CPU_MSA )
{
pf->deblock_luma[1] = x264_deblock_v_luma_msa;
pf->deblock_luma[0] = x264_deblock_h_luma_msa;
pf->deblock_chroma[1] = x264_deblock_v_chroma_msa;
pf->deblock_h_chroma_420 = x264_deblock_h_chroma_msa;
pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_msa;
pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_msa;
pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_msa;
pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_msa;
pf->deblock_strength = x264_deblock_strength_msa;
}
#endif
#endif // !HIGH_BIT_DEPTH
/* These functions are equivalent, so don't duplicate them. */
pf->deblock_chroma_422_mbaff = pf->deblock_h_chroma_420;
pf->deblock_chroma_422_intra_mbaff = pf->deblock_h_chroma_420_intra;
}

View file

@ -0,0 +1,899 @@
/*****************************************************************************
* frame.c: frame handling
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
static int align_stride( int x, int align, int disalign )
{
x = ALIGN( x, align );
if( !(x&(disalign-1)) )
x += align;
return x;
}
static int align_plane_size( int x, int disalign )
{
if( !(x&(disalign-1)) )
x += 128;
return x;
}
static int x264_frame_internal_csp( int external_csp )
{
switch( external_csp & X264_CSP_MASK )
{
case X264_CSP_NV12:
case X264_CSP_NV21:
case X264_CSP_I420:
case X264_CSP_YV12:
return X264_CSP_NV12;
case X264_CSP_NV16:
case X264_CSP_I422:
case X264_CSP_YV16:
case X264_CSP_YUYV:
case X264_CSP_UYVY:
case X264_CSP_V210:
return X264_CSP_NV16;
case X264_CSP_I444:
case X264_CSP_YV24:
case X264_CSP_BGR:
case X264_CSP_BGRA:
case X264_CSP_RGB:
return X264_CSP_I444;
default:
return X264_CSP_NONE;
}
}
static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec )
{
x264_frame_t *frame;
int i_csp = x264_frame_internal_csp( h->param.i_csp );
int i_mb_count = h->mb.i_mb_count;
int i_stride, i_width, i_lines, luma_plane_count;
int i_padv = PADV << PARAM_INTERLACED;
int align = 16;
#if ARCH_X86 || ARCH_X86_64
if( h->param.cpu&X264_CPU_CACHELINE_64 || h->param.cpu&X264_CPU_AVX512 )
align = 64;
else if( h->param.cpu&X264_CPU_CACHELINE_32 || h->param.cpu&X264_CPU_AVX )
align = 32;
#endif
#if ARCH_PPC
int disalign = 1<<9;
#else
int disalign = 1<<10;
#endif
CHECKED_MALLOCZERO( frame, sizeof(x264_frame_t) );
PREALLOC_INIT
/* allocate frame data (+64 for extra data for me) */
i_width = h->mb.i_mb_width*16;
i_lines = h->mb.i_mb_height*16;
i_stride = align_stride( i_width + 2*PADH, align, disalign );
if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 )
{
luma_plane_count = 1;
frame->i_plane = 2;
for( int i = 0; i < 2; i++ )
{
frame->i_width[i] = i_width >> i;
frame->i_lines[i] = i_lines >> (i && i_csp == X264_CSP_NV12);
frame->i_stride[i] = i_stride;
}
}
else if( i_csp == X264_CSP_I444 )
{
luma_plane_count = 3;
frame->i_plane = 3;
for( int i = 0; i < 3; i++ )
{
frame->i_width[i] = i_width;
frame->i_lines[i] = i_lines;
frame->i_stride[i] = i_stride;
}
}
else
goto fail;
frame->i_csp = i_csp;
frame->i_width_lowres = frame->i_width[0]/2;
frame->i_lines_lowres = frame->i_lines[0]/2;
frame->i_stride_lowres = align_stride( frame->i_width_lowres + 2*PADH, align, disalign<<1 );
for( int i = 0; i < h->param.i_bframe + 2; i++ )
for( int j = 0; j < h->param.i_bframe + 2; j++ )
PREALLOC( frame->i_row_satds[i][j], i_lines/16 * sizeof(int) );
frame->i_poc = -1;
frame->i_type = X264_TYPE_AUTO;
frame->i_qpplus1 = X264_QP_AUTO;
frame->i_pts = -1;
frame->i_frame = -1;
frame->i_frame_num = -1;
frame->i_lines_completed = -1;
frame->b_fdec = b_fdec;
frame->i_pic_struct = PIC_STRUCT_AUTO;
frame->i_field_cnt = -1;
frame->i_duration =
frame->i_cpb_duration =
frame->i_dpb_output_delay =
frame->i_cpb_delay = 0;
frame->i_coded_fields_lookahead =
frame->i_cpb_delay_lookahead = -1;
frame->orig = frame;
if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 )
{
int chroma_padv = i_padv >> (i_csp == X264_CSP_NV12);
int chroma_plane_size = (frame->i_stride[1] * (frame->i_lines[1] + 2*chroma_padv));
PREALLOC( frame->buffer[1], chroma_plane_size * sizeof(pixel) );
if( PARAM_INTERLACED )
PREALLOC( frame->buffer_fld[1], chroma_plane_size * sizeof(pixel) );
}
/* all 4 luma planes allocated together, since the cacheline split code
* requires them to be in-phase wrt cacheline alignment. */
for( int p = 0; p < luma_plane_count; p++ )
{
int luma_plane_size = align_plane_size( frame->i_stride[p] * (frame->i_lines[p] + 2*i_padv), disalign );
if( h->param.analyse.i_subpel_refine && b_fdec )
{
/* FIXME: Don't allocate both buffers in non-adaptive MBAFF. */
PREALLOC( frame->buffer[p], 4*luma_plane_size * sizeof(pixel) );
if( PARAM_INTERLACED )
PREALLOC( frame->buffer_fld[p], 4*luma_plane_size * sizeof(pixel) );
}
else
{
PREALLOC( frame->buffer[p], luma_plane_size * sizeof(pixel) );
if( PARAM_INTERLACED )
PREALLOC( frame->buffer_fld[p], luma_plane_size * sizeof(pixel) );
}
}
frame->b_duplicate = 0;
if( b_fdec ) /* fdec frame */
{
PREALLOC( frame->mb_type, i_mb_count * sizeof(int8_t) );
PREALLOC( frame->mb_partition, i_mb_count * sizeof(uint8_t) );
PREALLOC( frame->mv[0], 2*16 * i_mb_count * sizeof(int16_t) );
PREALLOC( frame->mv16x16, 2*(i_mb_count+1) * sizeof(int16_t) );
PREALLOC( frame->ref[0], 4 * i_mb_count * sizeof(int8_t) );
if( h->param.i_bframe )
{
PREALLOC( frame->mv[1], 2*16 * i_mb_count * sizeof(int16_t) );
PREALLOC( frame->ref[1], 4 * i_mb_count * sizeof(int8_t) );
}
else
{
frame->mv[1] = NULL;
frame->ref[1] = NULL;
}
PREALLOC( frame->i_row_bits, i_lines/16 * sizeof(int) );
PREALLOC( frame->f_row_qp, i_lines/16 * sizeof(float) );
PREALLOC( frame->f_row_qscale, i_lines/16 * sizeof(float) );
if( h->param.analyse.i_me_method >= X264_ME_ESA )
PREALLOC( frame->buffer[3], frame->i_stride[0] * (frame->i_lines[0] + 2*i_padv) * sizeof(uint16_t) << h->frames.b_have_sub8x8_esa );
if( PARAM_INTERLACED )
PREALLOC( frame->field, i_mb_count * sizeof(uint8_t) );
if( h->param.analyse.b_mb_info )
PREALLOC( frame->effective_qp, i_mb_count * sizeof(uint8_t) );
}
else /* fenc frame */
{
if( h->frames.b_have_lowres )
{
int luma_plane_size = align_plane_size( frame->i_stride_lowres * (frame->i_lines[0]/2 + 2*PADV), disalign );
PREALLOC( frame->buffer_lowres[0], 4 * luma_plane_size * sizeof(pixel) );
for( int j = 0; j <= !!h->param.i_bframe; j++ )
for( int i = 0; i <= h->param.i_bframe; i++ )
{
PREALLOC( frame->lowres_mvs[j][i], 2*h->mb.i_mb_count*sizeof(int16_t) );
PREALLOC( frame->lowres_mv_costs[j][i], h->mb.i_mb_count*sizeof(int) );
}
PREALLOC( frame->i_propagate_cost, i_mb_count * sizeof(uint16_t) );
for( int j = 0; j <= h->param.i_bframe+1; j++ )
for( int i = 0; i <= h->param.i_bframe+1; i++ )
PREALLOC( frame->lowres_costs[j][i], i_mb_count * sizeof(uint16_t) );
/* mbtree asm can overread the input buffers, make sure we don't read outside of allocated memory. */
prealloc_size += NATIVE_ALIGN;
}
if( h->param.rc.i_aq_mode )
{
PREALLOC( frame->f_qp_offset, h->mb.i_mb_count * sizeof(float) );
PREALLOC( frame->f_qp_offset_aq, h->mb.i_mb_count * sizeof(float) );
if( h->frames.b_have_lowres )
PREALLOC( frame->i_inv_qscale_factor, (h->mb.i_mb_count+3) * sizeof(uint16_t) );
}
}
PREALLOC_END( frame->base );
if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 )
{
int chroma_padv = i_padv >> (i_csp == X264_CSP_NV12);
frame->plane[1] = frame->buffer[1] + frame->i_stride[1] * chroma_padv + PADH;
if( PARAM_INTERLACED )
frame->plane_fld[1] = frame->buffer_fld[1] + frame->i_stride[1] * chroma_padv + PADH;
}
for( int p = 0; p < luma_plane_count; p++ )
{
int luma_plane_size = align_plane_size( frame->i_stride[p] * (frame->i_lines[p] + 2*i_padv), disalign );
if( h->param.analyse.i_subpel_refine && b_fdec )
{
for( int i = 0; i < 4; i++ )
{
frame->filtered[p][i] = frame->buffer[p] + i*luma_plane_size + frame->i_stride[p] * i_padv + PADH;
frame->filtered_fld[p][i] = frame->buffer_fld[p] + i*luma_plane_size + frame->i_stride[p] * i_padv + PADH;
}
frame->plane[p] = frame->filtered[p][0];
frame->plane_fld[p] = frame->filtered_fld[p][0];
}
else
{
frame->filtered[p][0] = frame->plane[p] = frame->buffer[p] + frame->i_stride[p] * i_padv + PADH;
frame->filtered_fld[p][0] = frame->plane_fld[p] = frame->buffer_fld[p] + frame->i_stride[p] * i_padv + PADH;
}
}
if( b_fdec )
{
M32( frame->mv16x16[0] ) = 0;
frame->mv16x16++;
if( h->param.analyse.i_me_method >= X264_ME_ESA )
frame->integral = (uint16_t*)frame->buffer[3] + frame->i_stride[0] * i_padv + PADH;
}
else
{
if( h->frames.b_have_lowres )
{
int luma_plane_size = align_plane_size( frame->i_stride_lowres * (frame->i_lines[0]/2 + 2*PADV), disalign );
for( int i = 0; i < 4; i++ )
frame->lowres[i] = frame->buffer_lowres[0] + (frame->i_stride_lowres * PADV + PADH) + i * luma_plane_size;
for( int j = 0; j <= !!h->param.i_bframe; j++ )
for( int i = 0; i <= h->param.i_bframe; i++ )
memset( frame->lowres_mvs[j][i], 0, 2*h->mb.i_mb_count*sizeof(int16_t) );
frame->i_intra_cost = frame->lowres_costs[0][0];
memset( frame->i_intra_cost, -1, (i_mb_count+3) * sizeof(uint16_t) );
if( h->param.rc.i_aq_mode )
/* shouldn't really be initialized, just silences a valgrind false-positive in x264_mbtree_propagate_cost_sse2 */
memset( frame->i_inv_qscale_factor, 0, (h->mb.i_mb_count+3) * sizeof(uint16_t) );
}
}
if( x264_pthread_mutex_init( &frame->mutex, NULL ) )
goto fail;
if( x264_pthread_cond_init( &frame->cv, NULL ) )
goto fail;
#if HAVE_OPENCL
frame->opencl.ocl = h->opencl.ocl;
#endif
return frame;
fail:
x264_free( frame );
return NULL;
}
void x264_frame_delete( x264_frame_t *frame )
{
/* Duplicate frames are blank copies of real frames (including pointers),
* so freeing those pointers would cause a double free later. */
if( !frame->b_duplicate )
{
x264_free( frame->base );
if( frame->param && frame->param->param_free )
frame->param->param_free( frame->param );
if( frame->mb_info_free )
frame->mb_info_free( frame->mb_info );
if( frame->extra_sei.sei_free )
{
for( int i = 0; i < frame->extra_sei.num_payloads; i++ )
frame->extra_sei.sei_free( frame->extra_sei.payloads[i].payload );
frame->extra_sei.sei_free( frame->extra_sei.payloads );
}
x264_pthread_mutex_destroy( &frame->mutex );
x264_pthread_cond_destroy( &frame->cv );
#if HAVE_OPENCL
x264_opencl_frame_delete( frame );
#endif
}
x264_free( frame );
}
static int get_plane_ptr( x264_t *h, x264_picture_t *src, uint8_t **pix, int *stride, int plane, int xshift, int yshift )
{
int width = h->param.i_width >> xshift;
int height = h->param.i_height >> yshift;
*pix = src->img.plane[plane];
*stride = src->img.i_stride[plane];
if( src->img.i_csp & X264_CSP_VFLIP )
{
*pix += (height-1) * *stride;
*stride = -*stride;
}
if( width > abs(*stride) )
{
x264_log( h, X264_LOG_ERROR, "Input picture width (%d) is greater than stride (%d)\n", width, *stride );
return -1;
}
return 0;
}
#define get_plane_ptr(...) do { if( get_plane_ptr(__VA_ARGS__) < 0 ) return -1; } while( 0 )
int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src )
{
int i_csp = src->img.i_csp & X264_CSP_MASK;
if( dst->i_csp != x264_frame_internal_csp( i_csp ) )
{
x264_log( h, X264_LOG_ERROR, "Invalid input colorspace\n" );
return -1;
}
#if HIGH_BIT_DEPTH
if( !(src->img.i_csp & X264_CSP_HIGH_DEPTH) )
{
x264_log( h, X264_LOG_ERROR, "This build of x264 requires high depth input. Rebuild to support 8-bit input.\n" );
return -1;
}
#else
if( src->img.i_csp & X264_CSP_HIGH_DEPTH )
{
x264_log( h, X264_LOG_ERROR, "This build of x264 requires 8-bit input. Rebuild to support high depth input.\n" );
return -1;
}
#endif
if( BIT_DEPTH != 10 && i_csp == X264_CSP_V210 )
{
x264_log( h, X264_LOG_ERROR, "v210 input is only compatible with bit-depth of 10 bits\n" );
return -1;
}
if( src->i_type < X264_TYPE_AUTO || src->i_type > X264_TYPE_KEYFRAME )
{
x264_log( h, X264_LOG_WARNING, "forced frame type (%d) at %d is unknown\n", src->i_type, h->frames.i_input );
dst->i_forced_type = X264_TYPE_AUTO;
}
else
dst->i_forced_type = src->i_type;
dst->i_type = dst->i_forced_type;
dst->i_qpplus1 = src->i_qpplus1;
dst->i_pts = dst->i_reordered_pts = src->i_pts;
dst->param = src->param;
dst->i_pic_struct = src->i_pic_struct;
dst->extra_sei = src->extra_sei;
dst->opaque = src->opaque;
dst->mb_info = h->param.analyse.b_mb_info ? src->prop.mb_info : NULL;
dst->mb_info_free = h->param.analyse.b_mb_info ? src->prop.mb_info_free : NULL;
uint8_t *pix[3];
int stride[3];
if( i_csp == X264_CSP_YUYV || i_csp == X264_CSP_UYVY )
{
int p = i_csp == X264_CSP_UYVY;
h->mc.plane_copy_deinterleave_yuyv( dst->plane[p], dst->i_stride[p], dst->plane[p^1], dst->i_stride[p^1],
(pixel*)src->img.plane[0], src->img.i_stride[0], h->param.i_width, h->param.i_height );
}
else if( i_csp == X264_CSP_V210 )
{
stride[0] = src->img.i_stride[0];
pix[0] = src->img.plane[0];
h->mc.plane_copy_deinterleave_v210( dst->plane[0], dst->i_stride[0],
dst->plane[1], dst->i_stride[1],
(uint32_t *)pix[0], stride[0]/sizeof(uint32_t), h->param.i_width, h->param.i_height );
}
else if( i_csp >= X264_CSP_BGR )
{
stride[0] = src->img.i_stride[0];
pix[0] = src->img.plane[0];
if( src->img.i_csp & X264_CSP_VFLIP )
{
pix[0] += (h->param.i_height-1) * stride[0];
stride[0] = -stride[0];
}
int b = i_csp==X264_CSP_RGB;
h->mc.plane_copy_deinterleave_rgb( dst->plane[1+b], dst->i_stride[1+b],
dst->plane[0], dst->i_stride[0],
dst->plane[2-b], dst->i_stride[2-b],
(pixel*)pix[0], stride[0]/sizeof(pixel), i_csp==X264_CSP_BGRA ? 4 : 3, h->param.i_width, h->param.i_height );
}
else
{
int v_shift = CHROMA_V_SHIFT;
get_plane_ptr( h, src, &pix[0], &stride[0], 0, 0, 0 );
h->mc.plane_copy( dst->plane[0], dst->i_stride[0], (pixel*)pix[0],
stride[0]/sizeof(pixel), h->param.i_width, h->param.i_height );
if( i_csp == X264_CSP_NV12 || i_csp == X264_CSP_NV16 )
{
get_plane_ptr( h, src, &pix[1], &stride[1], 1, 0, v_shift );
h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1],
stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height>>v_shift );
}
else if( i_csp == X264_CSP_NV21 )
{
get_plane_ptr( h, src, &pix[1], &stride[1], 1, 0, v_shift );
h->mc.plane_copy_swap( dst->plane[1], dst->i_stride[1], (pixel*)pix[1],
stride[1]/sizeof(pixel), h->param.i_width>>1, h->param.i_height>>v_shift );
}
else if( i_csp == X264_CSP_I420 || i_csp == X264_CSP_I422 || i_csp == X264_CSP_YV12 || i_csp == X264_CSP_YV16 )
{
int uv_swap = i_csp == X264_CSP_YV12 || i_csp == X264_CSP_YV16;
get_plane_ptr( h, src, &pix[1], &stride[1], uv_swap ? 2 : 1, 1, v_shift );
get_plane_ptr( h, src, &pix[2], &stride[2], uv_swap ? 1 : 2, 1, v_shift );
h->mc.plane_copy_interleave( dst->plane[1], dst->i_stride[1],
(pixel*)pix[1], stride[1]/sizeof(pixel),
(pixel*)pix[2], stride[2]/sizeof(pixel),
h->param.i_width>>1, h->param.i_height>>v_shift );
}
else //if( i_csp == X264_CSP_I444 || i_csp == X264_CSP_YV24 )
{
get_plane_ptr( h, src, &pix[1], &stride[1], i_csp==X264_CSP_I444 ? 1 : 2, 0, 0 );
get_plane_ptr( h, src, &pix[2], &stride[2], i_csp==X264_CSP_I444 ? 2 : 1, 0, 0 );
h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1],
stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height );
h->mc.plane_copy( dst->plane[2], dst->i_stride[2], (pixel*)pix[2],
stride[2]/sizeof(pixel), h->param.i_width, h->param.i_height );
}
}
return 0;
}
static void ALWAYS_INLINE pixel_memset( pixel *dst, pixel *src, int len, int size )
{
uint8_t *dstp = (uint8_t*)dst;
uint32_t v1 = *src;
uint32_t v2 = size == 1 ? v1 + (v1 << 8) : M16( src );
uint32_t v4 = size <= 2 ? v2 + (v2 << 16) : M32( src );
int i = 0;
len *= size;
/* Align the input pointer if it isn't already */
if( (intptr_t)dstp & (WORD_SIZE - 1) )
{
if( size <= 2 && ((intptr_t)dstp & 3) )
{
if( size == 1 && ((intptr_t)dstp & 1) )
dstp[i++] = v1;
if( (intptr_t)dstp & 2 )
{
M16( dstp+i ) = v2;
i += 2;
}
}
if( WORD_SIZE == 8 && (intptr_t)dstp & 4 )
{
M32( dstp+i ) = v4;
i += 4;
}
}
/* Main copy loop */
if( WORD_SIZE == 8 )
{
uint64_t v8 = v4 + ((uint64_t)v4<<32);
for( ; i < len - 7; i+=8 )
M64( dstp+i ) = v8;
}
for( ; i < len - 3; i+=4 )
M32( dstp+i ) = v4;
/* Finish up the last few bytes */
if( size <= 2 )
{
if( i < len - 1 )
{
M16( dstp+i ) = v2;
i += 2;
}
if( size == 1 && i != len )
dstp[i] = v1;
}
}
static void ALWAYS_INLINE plane_expand_border( pixel *pix, int i_stride, int i_width, int i_height, int i_padh, int i_padv, int b_pad_top, int b_pad_bottom, int b_chroma )
{
#define PPIXEL(x, y) ( pix + (x) + (y)*i_stride )
for( int y = 0; y < i_height; y++ )
{
/* left band */
pixel_memset( PPIXEL(-i_padh, y), PPIXEL(0, y), i_padh>>b_chroma, sizeof(pixel)<<b_chroma );
/* right band */
pixel_memset( PPIXEL(i_width, y), PPIXEL(i_width-1-b_chroma, y), i_padh>>b_chroma, sizeof(pixel)<<b_chroma );
}
/* upper band */
if( b_pad_top )
for( int y = 0; y < i_padv; y++ )
memcpy( PPIXEL(-i_padh, -y-1), PPIXEL(-i_padh, 0), (i_width+2*i_padh) * sizeof(pixel) );
/* lower band */
if( b_pad_bottom )
for( int y = 0; y < i_padv; y++ )
memcpy( PPIXEL(-i_padh, i_height+y), PPIXEL(-i_padh, i_height-1), (i_width+2*i_padh) * sizeof(pixel) );
#undef PPIXEL
}
void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y )
{
int pad_top = mb_y == 0;
int pad_bot = mb_y == h->mb.i_mb_height - (1 << SLICE_MBAFF);
int b_start = mb_y == h->i_threadslice_start;
int b_end = mb_y == h->i_threadslice_end - (1 << SLICE_MBAFF);
if( mb_y & SLICE_MBAFF )
return;
for( int i = 0; i < frame->i_plane; i++ )
{
int h_shift = i && CHROMA_H_SHIFT;
int v_shift = i && CHROMA_V_SHIFT;
int stride = frame->i_stride[i];
int width = 16*h->mb.i_mb_width;
int height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF : 16) >> v_shift;
int padh = PADH;
int padv = PADV >> v_shift;
// buffer: 2 chroma, 3 luma (rounded to 4) because deblocking goes beyond the top of the mb
if( b_end && !b_start )
height += 4 >> (v_shift + SLICE_MBAFF);
pixel *pix;
int starty = 16*mb_y - 4*!b_start;
if( SLICE_MBAFF )
{
// border samples for each field are extended separately
pix = frame->plane_fld[i] + (starty*stride >> v_shift);
plane_expand_border( pix, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift );
plane_expand_border( pix+stride, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift );
height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) : 32) >> v_shift;
if( b_end && !b_start )
height += 4 >> v_shift;
pix = frame->plane[i] + (starty*stride >> v_shift);
plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift );
}
else
{
pix = frame->plane[i] + (starty*stride >> v_shift);
plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift );
}
}
}
void x264_frame_expand_border_filtered( x264_t *h, x264_frame_t *frame, int mb_y, int b_end )
{
/* during filtering, 8 extra pixels were filtered on each edge,
* but up to 3 of the horizontal ones may be wrong.
we want to expand border from the last filtered pixel */
int b_start = !mb_y;
int width = 16*h->mb.i_mb_width + 8;
int height = b_end ? (16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF) + 16 : 16;
int padh = PADH - 4;
int padv = PADV - 8;
for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ )
for( int i = 1; i < 4; i++ )
{
int stride = frame->i_stride[p];
// buffer: 8 luma, to match the hpel filter
pixel *pix;
if( SLICE_MBAFF )
{
pix = frame->filtered_fld[p][i] + (16*mb_y - 16) * stride - 4;
plane_expand_border( pix, stride*2, width, height, padh, padv, b_start, b_end, 0 );
plane_expand_border( pix+stride, stride*2, width, height, padh, padv, b_start, b_end, 0 );
}
pix = frame->filtered[p][i] + (16*mb_y - 8) * stride - 4;
plane_expand_border( pix, stride, width, height << SLICE_MBAFF, padh, padv, b_start, b_end, 0 );
}
}
void x264_frame_expand_border_lowres( x264_frame_t *frame )
{
for( int i = 0; i < 4; i++ )
plane_expand_border( frame->lowres[i], frame->i_stride_lowres, frame->i_width_lowres, frame->i_lines_lowres, PADH, PADV, 1, 1, 0 );
}
void x264_frame_expand_border_chroma( x264_t *h, x264_frame_t *frame, int plane )
{
int v_shift = CHROMA_V_SHIFT;
plane_expand_border( frame->plane[plane], frame->i_stride[plane], 16*h->mb.i_mb_width, 16*h->mb.i_mb_height>>v_shift,
PADH, PADV>>v_shift, 1, 1, CHROMA_H_SHIFT );
}
void x264_frame_expand_border_mod16( x264_t *h, x264_frame_t *frame )
{
for( int i = 0; i < frame->i_plane; i++ )
{
int i_width = h->param.i_width;
int h_shift = i && CHROMA_H_SHIFT;
int v_shift = i && CHROMA_V_SHIFT;
int i_height = h->param.i_height >> v_shift;
int i_padx = (h->mb.i_mb_width * 16 - h->param.i_width);
int i_pady = (h->mb.i_mb_height * 16 - h->param.i_height) >> v_shift;
if( i_padx )
{
for( int y = 0; y < i_height; y++ )
pixel_memset( &frame->plane[i][y*frame->i_stride[i] + i_width],
&frame->plane[i][y*frame->i_stride[i] + i_width - 1-h_shift],
i_padx>>h_shift, sizeof(pixel)<<h_shift );
}
if( i_pady )
{
for( int y = i_height; y < i_height + i_pady; y++ )
memcpy( &frame->plane[i][y*frame->i_stride[i]],
&frame->plane[i][(i_height-(~y&PARAM_INTERLACED)-1)*frame->i_stride[i]],
(i_width + i_padx) * sizeof(pixel) );
}
}
}
void x264_expand_border_mbpair( x264_t *h, int mb_x, int mb_y )
{
for( int i = 0; i < h->fenc->i_plane; i++ )
{
int v_shift = i && CHROMA_V_SHIFT;
int stride = h->fenc->i_stride[i];
int height = h->param.i_height >> v_shift;
int pady = (h->mb.i_mb_height * 16 - h->param.i_height) >> v_shift;
pixel *fenc = h->fenc->plane[i] + 16*mb_x;
for( int y = height; y < height + pady; y++ )
memcpy( fenc + y*stride, fenc + (height-1)*stride, 16*sizeof(pixel) );
}
}
/* threading */
void x264_frame_cond_broadcast( x264_frame_t *frame, int i_lines_completed )
{
x264_pthread_mutex_lock( &frame->mutex );
frame->i_lines_completed = i_lines_completed;
x264_pthread_cond_broadcast( &frame->cv );
x264_pthread_mutex_unlock( &frame->mutex );
}
void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed )
{
x264_pthread_mutex_lock( &frame->mutex );
while( frame->i_lines_completed < i_lines_completed )
x264_pthread_cond_wait( &frame->cv, &frame->mutex );
x264_pthread_mutex_unlock( &frame->mutex );
}
void x264_threadslice_cond_broadcast( x264_t *h, int pass )
{
x264_pthread_mutex_lock( &h->mutex );
h->i_threadslice_pass = pass;
if( pass > 0 )
x264_pthread_cond_broadcast( &h->cv );
x264_pthread_mutex_unlock( &h->mutex );
}
void x264_threadslice_cond_wait( x264_t *h, int pass )
{
x264_pthread_mutex_lock( &h->mutex );
while( h->i_threadslice_pass < pass )
x264_pthread_cond_wait( &h->cv, &h->mutex );
x264_pthread_mutex_unlock( &h->mutex );
}
int x264_frame_new_slice( x264_t *h, x264_frame_t *frame )
{
if( h->param.i_slice_count_max )
{
int slice_count;
if( h->param.b_sliced_threads )
slice_count = x264_pthread_fetch_and_add( &frame->i_slice_count, 1, &frame->mutex );
else
slice_count = frame->i_slice_count++;
if( slice_count >= h->param.i_slice_count_max )
return -1;
}
return 0;
}
/* list operators */
void x264_frame_push( x264_frame_t **list, x264_frame_t *frame )
{
int i = 0;
while( list[i] ) i++;
list[i] = frame;
}
x264_frame_t *x264_frame_pop( x264_frame_t **list )
{
x264_frame_t *frame;
int i = 0;
assert( list[0] );
while( list[i+1] ) i++;
frame = list[i];
list[i] = NULL;
return frame;
}
void x264_frame_unshift( x264_frame_t **list, x264_frame_t *frame )
{
int i = 0;
while( list[i] ) i++;
while( i-- )
list[i+1] = list[i];
list[0] = frame;
}
x264_frame_t *x264_frame_shift( x264_frame_t **list )
{
x264_frame_t *frame = list[0];
int i;
for( i = 0; list[i]; i++ )
list[i] = list[i+1];
assert(frame);
return frame;
}
void x264_frame_push_unused( x264_t *h, x264_frame_t *frame )
{
assert( frame->i_reference_count > 0 );
frame->i_reference_count--;
if( frame->i_reference_count == 0 )
x264_frame_push( h->frames.unused[frame->b_fdec], frame );
}
x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec )
{
x264_frame_t *frame;
if( h->frames.unused[b_fdec][0] )
frame = x264_frame_pop( h->frames.unused[b_fdec] );
else
frame = x264_frame_new( h, b_fdec );
if( !frame )
return NULL;
frame->b_last_minigop_bframe = 0;
frame->i_reference_count = 1;
frame->b_intra_calculated = 0;
frame->b_scenecut = 1;
frame->b_keyframe = 0;
frame->b_corrupt = 0;
frame->i_slice_count = h->param.b_sliced_threads ? h->param.i_threads : 1;
memset( frame->weight, 0, sizeof(frame->weight) );
memset( frame->f_weighted_cost_delta, 0, sizeof(frame->f_weighted_cost_delta) );
return frame;
}
void x264_frame_push_blank_unused( x264_t *h, x264_frame_t *frame )
{
assert( frame->i_reference_count > 0 );
frame->i_reference_count--;
if( frame->i_reference_count == 0 )
x264_frame_push( h->frames.blank_unused, frame );
}
x264_frame_t *x264_frame_pop_blank_unused( x264_t *h )
{
x264_frame_t *frame;
if( h->frames.blank_unused[0] )
frame = x264_frame_pop( h->frames.blank_unused );
else
frame = x264_malloc( sizeof(x264_frame_t) );
if( !frame )
return NULL;
frame->b_duplicate = 1;
frame->i_reference_count = 1;
return frame;
}
void x264_weight_scale_plane( x264_t *h, pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride,
int i_width, int i_height, x264_weight_t *w )
{
/* Weight horizontal strips of height 16. This was found to be the optimal height
* in terms of the cache loads. */
while( i_height > 0 )
{
int x;
for( x = 0; x < i_width-8; x += 16 )
w->weightfn[16>>2]( dst+x, i_dst_stride, src+x, i_src_stride, w, X264_MIN( i_height, 16 ) );
if( x < i_width )
w->weightfn[ 8>>2]( dst+x, i_dst_stride, src+x, i_src_stride, w, X264_MIN( i_height, 16 ) );
i_height -= 16;
dst += 16 * i_dst_stride;
src += 16 * i_src_stride;
}
}
void x264_frame_delete_list( x264_frame_t **list )
{
int i = 0;
if( !list )
return;
while( list[i] )
x264_frame_delete( list[i++] );
x264_free( list );
}
int x264_sync_frame_list_init( x264_sync_frame_list_t *slist, int max_size )
{
if( max_size < 0 )
return -1;
slist->i_max_size = max_size;
slist->i_size = 0;
CHECKED_MALLOCZERO( slist->list, (max_size+1) * sizeof(x264_frame_t*) );
if( x264_pthread_mutex_init( &slist->mutex, NULL ) ||
x264_pthread_cond_init( &slist->cv_fill, NULL ) ||
x264_pthread_cond_init( &slist->cv_empty, NULL ) )
return -1;
return 0;
fail:
return -1;
}
void x264_sync_frame_list_delete( x264_sync_frame_list_t *slist )
{
x264_pthread_mutex_destroy( &slist->mutex );
x264_pthread_cond_destroy( &slist->cv_fill );
x264_pthread_cond_destroy( &slist->cv_empty );
x264_frame_delete_list( slist->list );
}
void x264_sync_frame_list_push( x264_sync_frame_list_t *slist, x264_frame_t *frame )
{
x264_pthread_mutex_lock( &slist->mutex );
while( slist->i_size == slist->i_max_size )
x264_pthread_cond_wait( &slist->cv_empty, &slist->mutex );
slist->list[ slist->i_size++ ] = frame;
x264_pthread_mutex_unlock( &slist->mutex );
x264_pthread_cond_broadcast( &slist->cv_fill );
}
x264_frame_t *x264_sync_frame_list_pop( x264_sync_frame_list_t *slist )
{
x264_frame_t *frame;
x264_pthread_mutex_lock( &slist->mutex );
while( !slist->i_size )
x264_pthread_cond_wait( &slist->cv_fill, &slist->mutex );
frame = slist->list[ --slist->i_size ];
slist->list[ slist->i_size ] = NULL;
x264_pthread_cond_broadcast( &slist->cv_empty );
x264_pthread_mutex_unlock( &slist->mutex );
return frame;
}

View file

@ -0,0 +1,262 @@
/*****************************************************************************
* frame.h: frame handling
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_FRAME_H
#define X264_FRAME_H
/* number of pixels past the edge of the frame, for motion estimation/compensation */
#define PADH 32
#define PADV 32
typedef struct x264_frame
{
/* */
uint8_t *base; /* Base pointer for all malloced data in this frame. */
int i_poc;
int i_delta_poc[2];
int i_type;
int i_forced_type;
int i_qpplus1;
int64_t i_pts;
int64_t i_dts;
int64_t i_reordered_pts;
int64_t i_duration; /* in SPS time_scale units (i.e 2 * timebase units) used for vfr */
float f_duration; /* in seconds */
int64_t i_cpb_duration;
int64_t i_cpb_delay; /* in SPS time_scale units (i.e 2 * timebase units) */
int64_t i_dpb_output_delay;
x264_param_t *param;
int i_frame; /* Presentation frame number */
int i_coded; /* Coded frame number */
int64_t i_field_cnt; /* Presentation field count */
int i_frame_num; /* 7.4.3 frame_num */
int b_kept_as_ref;
int i_pic_struct;
int b_keyframe;
uint8_t b_fdec;
uint8_t b_last_minigop_bframe; /* this frame is the last b in a sequence of bframes */
uint8_t i_bframes; /* number of bframes following this nonb in coded order */
float f_qp_avg_rc; /* QPs as decided by ratecontrol */
float f_qp_avg_aq; /* QPs as decided by AQ in addition to ratecontrol */
float f_crf_avg; /* Average effective CRF for this frame */
int i_poc_l0ref0; /* poc of first refframe in L0, used to check if direct temporal is possible */
/* YUV buffer */
int i_csp; /* Internal csp */
int i_plane;
int i_stride[3];
int i_width[3];
int i_lines[3];
int i_stride_lowres;
int i_width_lowres;
int i_lines_lowres;
pixel *plane[3];
pixel *plane_fld[3];
pixel *filtered[3][4]; /* plane[0], H, V, HV */
pixel *filtered_fld[3][4];
pixel *lowres[4]; /* half-size copy of input frame: Orig, H, V, HV */
uint16_t *integral;
/* for unrestricted mv we allocate more data than needed
* allocated data are stored in buffer */
pixel *buffer[4];
pixel *buffer_fld[4];
pixel *buffer_lowres[4];
x264_weight_t weight[X264_REF_MAX][3]; /* [ref_index][plane] */
pixel *weighted[X264_REF_MAX]; /* plane[0] weighted of the reference frames */
int b_duplicate;
struct x264_frame *orig;
/* motion data */
int8_t *mb_type;
uint8_t *mb_partition;
int16_t (*mv[2])[2];
int16_t (*mv16x16)[2];
int16_t (*lowres_mvs[2][X264_BFRAME_MAX+1])[2];
uint8_t *field;
uint8_t *effective_qp;
/* Stored as (lists_used << LOWRES_COST_SHIFT) + (cost).
* Doesn't need special addressing for intra cost because
* lists_used is guaranteed to be zero in that cast. */
uint16_t (*lowres_costs[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2]);
#define LOWRES_COST_MASK ((1<<14)-1)
#define LOWRES_COST_SHIFT 14
int *lowres_mv_costs[2][X264_BFRAME_MAX+1];
int8_t *ref[2];
int i_ref[2];
int ref_poc[2][X264_REF_MAX];
int16_t inv_ref_poc[2]; // inverse values of ref0 poc to avoid divisions in temporal MV prediction
/* for adaptive B-frame decision.
* contains the SATD cost of the lowres frame encoded in various modes
* FIXME: how big an array do we need? */
int i_cost_est[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2];
int i_cost_est_aq[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2];
int i_satd; // the i_cost_est of the selected frametype
int i_intra_mbs[X264_BFRAME_MAX+2];
int *i_row_satds[X264_BFRAME_MAX+2][X264_BFRAME_MAX+2];
int *i_row_satd;
int *i_row_bits;
float *f_row_qp;
float *f_row_qscale;
float *f_qp_offset;
float *f_qp_offset_aq;
int b_intra_calculated;
uint16_t *i_intra_cost;
uint16_t *i_propagate_cost;
uint16_t *i_inv_qscale_factor;
int b_scenecut; /* Set to zero if the frame cannot possibly be part of a real scenecut. */
float f_weighted_cost_delta[X264_BFRAME_MAX+2];
uint32_t i_pixel_sum[3];
uint64_t i_pixel_ssd[3];
/* hrd */
x264_hrd_t hrd_timing;
/* vbv */
uint8_t i_planned_type[X264_LOOKAHEAD_MAX+1];
int i_planned_satd[X264_LOOKAHEAD_MAX+1];
double f_planned_cpb_duration[X264_LOOKAHEAD_MAX+1];
int64_t i_coded_fields_lookahead;
int64_t i_cpb_delay_lookahead;
/* threading */
int i_lines_completed; /* in pixels */
int i_lines_weighted; /* FIXME: this only supports weighting of one reference frame */
int i_reference_count; /* number of threads using this frame (not necessarily the number of pointers) */
x264_pthread_mutex_t mutex;
x264_pthread_cond_t cv;
int i_slice_count; /* Atomically written to/read from with slice threads */
/* periodic intra refresh */
float f_pir_position;
int i_pir_start_col;
int i_pir_end_col;
int i_frames_since_pir;
/* interactive encoder control */
int b_corrupt;
/* user sei */
x264_sei_t extra_sei;
/* user data */
void *opaque;
/* user frame properties */
uint8_t *mb_info;
void (*mb_info_free)( void* );
#if HAVE_OPENCL
x264_frame_opencl_t opencl;
#endif
} x264_frame_t;
/* synchronized frame list */
typedef struct
{
x264_frame_t **list;
int i_max_size;
int i_size;
x264_pthread_mutex_t mutex;
x264_pthread_cond_t cv_fill; /* event signaling that the list became fuller */
x264_pthread_cond_t cv_empty; /* event signaling that the list became emptier */
} x264_sync_frame_list_t;
typedef void (*x264_deblock_inter_t)( pixel *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 );
typedef void (*x264_deblock_intra_t)( pixel *pix, intptr_t stride, int alpha, int beta );
typedef struct
{
x264_deblock_inter_t deblock_luma[2];
x264_deblock_inter_t deblock_chroma[2];
x264_deblock_inter_t deblock_h_chroma_420;
x264_deblock_inter_t deblock_h_chroma_422;
x264_deblock_intra_t deblock_luma_intra[2];
x264_deblock_intra_t deblock_chroma_intra[2];
x264_deblock_intra_t deblock_h_chroma_420_intra;
x264_deblock_intra_t deblock_h_chroma_422_intra;
x264_deblock_inter_t deblock_luma_mbaff;
x264_deblock_inter_t deblock_chroma_mbaff;
x264_deblock_inter_t deblock_chroma_420_mbaff;
x264_deblock_inter_t deblock_chroma_422_mbaff;
x264_deblock_intra_t deblock_luma_intra_mbaff;
x264_deblock_intra_t deblock_chroma_intra_mbaff;
x264_deblock_intra_t deblock_chroma_420_intra_mbaff;
x264_deblock_intra_t deblock_chroma_422_intra_mbaff;
void (*deblock_strength)( uint8_t nnz[X264_SCAN8_SIZE], int8_t ref[2][X264_SCAN8_LUMA_SIZE],
int16_t mv[2][X264_SCAN8_LUMA_SIZE][2], uint8_t bs[2][8][4], int mvy_limit,
int bframe );
} x264_deblock_function_t;
void x264_frame_delete( x264_frame_t *frame );
int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src );
void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y );
void x264_frame_expand_border_filtered( x264_t *h, x264_frame_t *frame, int mb_y, int b_end );
void x264_frame_expand_border_lowres( x264_frame_t *frame );
void x264_frame_expand_border_chroma( x264_t *h, x264_frame_t *frame, int plane );
void x264_frame_expand_border_mod16( x264_t *h, x264_frame_t *frame );
void x264_expand_border_mbpair( x264_t *h, int mb_x, int mb_y );
void x264_frame_deblock_row( x264_t *h, int mb_y );
void x264_macroblock_deblock( x264_t *h );
void x264_frame_filter( x264_t *h, x264_frame_t *frame, int mb_y, int b_end );
void x264_frame_init_lowres( x264_t *h, x264_frame_t *frame );
void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff );
void x264_frame_cond_broadcast( x264_frame_t *frame, int i_lines_completed );
void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed );
int x264_frame_new_slice( x264_t *h, x264_frame_t *frame );
void x264_threadslice_cond_broadcast( x264_t *h, int pass );
void x264_threadslice_cond_wait( x264_t *h, int pass );
void x264_frame_push( x264_frame_t **list, x264_frame_t *frame );
x264_frame_t *x264_frame_pop( x264_frame_t **list );
void x264_frame_unshift( x264_frame_t **list, x264_frame_t *frame );
x264_frame_t *x264_frame_shift( x264_frame_t **list );
void x264_frame_push_unused( x264_t *h, x264_frame_t *frame );
void x264_frame_push_blank_unused( x264_t *h, x264_frame_t *frame );
x264_frame_t *x264_frame_pop_blank_unused( x264_t *h );
void x264_weight_scale_plane( x264_t *h, pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride,
int i_width, int i_height, x264_weight_t *w );
x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec );
void x264_frame_delete_list( x264_frame_t **list );
int x264_sync_frame_list_init( x264_sync_frame_list_t *slist, int nelem );
void x264_sync_frame_list_delete( x264_sync_frame_list_t *slist );
void x264_sync_frame_list_push( x264_sync_frame_list_t *slist, x264_frame_t *frame );
x264_frame_t *x264_sync_frame_list_pop( x264_sync_frame_list_t *slist );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,444 @@
/*****************************************************************************
* macroblock.h: macroblock common functions
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_MACROBLOCK_H
#define X264_MACROBLOCK_H
enum macroblock_position_e
{
MB_LEFT = 0x01,
MB_TOP = 0x02,
MB_TOPRIGHT = 0x04,
MB_TOPLEFT = 0x08,
MB_PRIVATE = 0x10,
ALL_NEIGHBORS = 0xf,
};
static const uint8_t x264_pred_i4x4_neighbors[12] =
{
MB_TOP, // I_PRED_4x4_V
MB_LEFT, // I_PRED_4x4_H
MB_LEFT | MB_TOP, // I_PRED_4x4_DC
MB_TOP | MB_TOPRIGHT, // I_PRED_4x4_DDL
MB_LEFT | MB_TOPLEFT | MB_TOP, // I_PRED_4x4_DDR
MB_LEFT | MB_TOPLEFT | MB_TOP, // I_PRED_4x4_VR
MB_LEFT | MB_TOPLEFT | MB_TOP, // I_PRED_4x4_HD
MB_TOP | MB_TOPRIGHT, // I_PRED_4x4_VL
MB_LEFT, // I_PRED_4x4_HU
MB_LEFT, // I_PRED_4x4_DC_LEFT
MB_TOP, // I_PRED_4x4_DC_TOP
0 // I_PRED_4x4_DC_128
};
/* XXX mb_type isn't the one written in the bitstream -> only internal usage */
#define IS_INTRA(type) ( (type) == I_4x4 || (type) == I_8x8 || (type) == I_16x16 || (type) == I_PCM )
#define IS_SKIP(type) ( (type) == P_SKIP || (type) == B_SKIP )
#define IS_DIRECT(type) ( (type) == B_DIRECT )
enum mb_class_e
{
I_4x4 = 0,
I_8x8 = 1,
I_16x16 = 2,
I_PCM = 3,
P_L0 = 4,
P_8x8 = 5,
P_SKIP = 6,
B_DIRECT = 7,
B_L0_L0 = 8,
B_L0_L1 = 9,
B_L0_BI = 10,
B_L1_L0 = 11,
B_L1_L1 = 12,
B_L1_BI = 13,
B_BI_L0 = 14,
B_BI_L1 = 15,
B_BI_BI = 16,
B_8x8 = 17,
B_SKIP = 18,
X264_MBTYPE_MAX = 19
};
static const uint8_t x264_mb_type_fix[X264_MBTYPE_MAX] =
{
I_4x4, I_4x4, I_16x16, I_PCM,
P_L0, P_8x8, P_SKIP,
B_DIRECT, B_L0_L0, B_L0_L1, B_L0_BI, B_L1_L0, B_L1_L1,
B_L1_BI, B_BI_L0, B_BI_L1, B_BI_BI, B_8x8, B_SKIP
};
static const uint8_t x264_mb_type_list_table[X264_MBTYPE_MAX][2][2] =
{
{{0,0},{0,0}}, {{0,0},{0,0}}, {{0,0},{0,0}}, {{0,0},{0,0}}, /* INTRA */
{{1,1},{0,0}}, /* P_L0 */
{{0,0},{0,0}}, /* P_8x8 */
{{1,1},{0,0}}, /* P_SKIP */
{{0,0},{0,0}}, /* B_DIRECT */
{{1,1},{0,0}}, {{1,0},{0,1}}, {{1,1},{0,1}}, /* B_L0_* */
{{0,1},{1,0}}, {{0,0},{1,1}}, {{0,1},{1,1}}, /* B_L1_* */
{{1,1},{1,0}}, {{1,0},{1,1}}, {{1,1},{1,1}}, /* B_BI_* */
{{0,0},{0,0}}, /* B_8x8 */
{{0,0},{0,0}} /* B_SKIP */
};
#define IS_SUB4x4(type) ( (type == D_L0_4x4)||(type == D_L1_4x4)||(type == D_BI_4x4) )
#define IS_SUB4x8(type) ( (type == D_L0_4x8)||(type == D_L1_4x8)||(type == D_BI_4x8) )
#define IS_SUB8x4(type) ( (type == D_L0_8x4)||(type == D_L1_8x4)||(type == D_BI_8x4) )
#define IS_SUB8x8(type) ( (type == D_L0_8x8)||(type == D_L1_8x8)||(type == D_BI_8x8)||(type == D_DIRECT_8x8) )
enum mb_partition_e
{
/* sub partition type for P_8x8 and B_8x8 */
D_L0_4x4 = 0,
D_L0_8x4 = 1,
D_L0_4x8 = 2,
D_L0_8x8 = 3,
/* sub partition type for B_8x8 only */
D_L1_4x4 = 4,
D_L1_8x4 = 5,
D_L1_4x8 = 6,
D_L1_8x8 = 7,
D_BI_4x4 = 8,
D_BI_8x4 = 9,
D_BI_4x8 = 10,
D_BI_8x8 = 11,
D_DIRECT_8x8 = 12,
/* partition */
D_8x8 = 13,
D_16x8 = 14,
D_8x16 = 15,
D_16x16 = 16,
X264_PARTTYPE_MAX = 17,
};
static const uint8_t x264_mb_partition_listX_table[2][17] =
{{
1, 1, 1, 1, /* D_L0_* */
0, 0, 0, 0, /* D_L1_* */
1, 1, 1, 1, /* D_BI_* */
0, /* D_DIRECT_8x8 */
0, 0, 0, 0 /* 8x8 .. 16x16 */
},
{
0, 0, 0, 0, /* D_L0_* */
1, 1, 1, 1, /* D_L1_* */
1, 1, 1, 1, /* D_BI_* */
0, /* D_DIRECT_8x8 */
0, 0, 0, 0 /* 8x8 .. 16x16 */
}};
static const uint8_t x264_mb_partition_count_table[17] =
{
/* sub L0 */
4, 2, 2, 1,
/* sub L1 */
4, 2, 2, 1,
/* sub BI */
4, 2, 2, 1,
/* Direct */
1,
/* Partition */
4, 2, 2, 1
};
static const uint8_t x264_mb_partition_pixel_table[17] =
{
PIXEL_4x4, PIXEL_8x4, PIXEL_4x8, PIXEL_8x8, /* D_L0_* */
PIXEL_4x4, PIXEL_8x4, PIXEL_4x8, PIXEL_8x8, /* D_L1_* */
PIXEL_4x4, PIXEL_8x4, PIXEL_4x8, PIXEL_8x8, /* D_BI_* */
PIXEL_8x8, /* D_DIRECT_8x8 */
PIXEL_8x8, PIXEL_16x8, PIXEL_8x16, PIXEL_16x16, /* 8x8 .. 16x16 */
};
/* zigzags are transposed with respect to the tables in the standard */
static const uint8_t x264_zigzag_scan4[2][16] =
{{ // frame
0, 4, 1, 2, 5, 8, 12, 9, 6, 3, 7, 10, 13, 14, 11, 15
},
{ // field
0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
}};
static const uint8_t x264_zigzag_scan8[2][64] =
{{
0, 8, 1, 2, 9, 16, 24, 17, 10, 3, 4, 11, 18, 25, 32, 40,
33, 26, 19, 12, 5, 6, 13, 20, 27, 34, 41, 48, 56, 49, 42, 35,
28, 21, 14, 7, 15, 22, 29, 36, 43, 50, 57, 58, 51, 44, 37, 30,
23, 31, 38, 45, 52, 59, 60, 53, 46, 39, 47, 54, 61, 62, 55, 63
},
{
0, 1, 2, 8, 9, 3, 4, 10, 16, 11, 5, 6, 7, 12, 17, 24,
18, 13, 14, 15, 19, 25, 32, 26, 20, 21, 22, 23, 27, 33, 40, 34,
28, 29, 30, 31, 35, 41, 48, 42, 36, 37, 38, 39, 43, 49, 50, 44,
45, 46, 47, 51, 56, 57, 52, 53, 54, 55, 58, 59, 60, 61, 62, 63
}};
static const uint8_t block_idx_x[16] =
{
0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3
};
static const uint8_t block_idx_y[16] =
{
0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 3, 3
};
static const uint8_t block_idx_xy[4][4] =
{
{ 0, 2, 8, 10 },
{ 1, 3, 9, 11 },
{ 4, 6, 12, 14 },
{ 5, 7, 13, 15 }
};
static const uint8_t block_idx_xy_1d[16] =
{
0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15
};
static const uint8_t block_idx_yx_1d[16] =
{
0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15
};
static const uint8_t block_idx_xy_fenc[16] =
{
0*4 + 0*4*FENC_STRIDE, 1*4 + 0*4*FENC_STRIDE,
0*4 + 1*4*FENC_STRIDE, 1*4 + 1*4*FENC_STRIDE,
2*4 + 0*4*FENC_STRIDE, 3*4 + 0*4*FENC_STRIDE,
2*4 + 1*4*FENC_STRIDE, 3*4 + 1*4*FENC_STRIDE,
0*4 + 2*4*FENC_STRIDE, 1*4 + 2*4*FENC_STRIDE,
0*4 + 3*4*FENC_STRIDE, 1*4 + 3*4*FENC_STRIDE,
2*4 + 2*4*FENC_STRIDE, 3*4 + 2*4*FENC_STRIDE,
2*4 + 3*4*FENC_STRIDE, 3*4 + 3*4*FENC_STRIDE
};
static const uint16_t block_idx_xy_fdec[16] =
{
0*4 + 0*4*FDEC_STRIDE, 1*4 + 0*4*FDEC_STRIDE,
0*4 + 1*4*FDEC_STRIDE, 1*4 + 1*4*FDEC_STRIDE,
2*4 + 0*4*FDEC_STRIDE, 3*4 + 0*4*FDEC_STRIDE,
2*4 + 1*4*FDEC_STRIDE, 3*4 + 1*4*FDEC_STRIDE,
0*4 + 2*4*FDEC_STRIDE, 1*4 + 2*4*FDEC_STRIDE,
0*4 + 3*4*FDEC_STRIDE, 1*4 + 3*4*FDEC_STRIDE,
2*4 + 2*4*FDEC_STRIDE, 3*4 + 2*4*FDEC_STRIDE,
2*4 + 3*4*FDEC_STRIDE, 3*4 + 3*4*FDEC_STRIDE
};
#define QP(qP) ( (qP)+QP_BD_OFFSET )
static const uint8_t i_chroma_qp_table[QP_MAX+1+12*2] =
{
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
#if BIT_DEPTH > 9
QP(-12),QP(-11),QP(-10), QP(-9), QP(-8), QP(-7),
#endif
#if BIT_DEPTH > 8
QP(-6), QP(-5), QP(-4), QP(-3), QP(-2), QP(-1),
#endif
QP(0), QP(1), QP(2), QP(3), QP(4), QP(5),
QP(6), QP(7), QP(8), QP(9), QP(10), QP(11),
QP(12), QP(13), QP(14), QP(15), QP(16), QP(17),
QP(18), QP(19), QP(20), QP(21), QP(22), QP(23),
QP(24), QP(25), QP(26), QP(27), QP(28), QP(29),
QP(29), QP(30), QP(31), QP(32), QP(32), QP(33),
QP(34), QP(34), QP(35), QP(35), QP(36), QP(36),
QP(37), QP(37), QP(37), QP(38), QP(38), QP(38),
QP(39), QP(39), QP(39), QP(39),
QP(39), QP(39), QP(39), QP(39), QP(39), QP(39),
QP(39), QP(39), QP(39), QP(39), QP(39), QP(39),
};
#undef QP
enum cabac_ctx_block_cat_e
{
DCT_LUMA_DC = 0,
DCT_LUMA_AC = 1,
DCT_LUMA_4x4 = 2,
DCT_CHROMA_DC = 3,
DCT_CHROMA_AC = 4,
DCT_LUMA_8x8 = 5,
DCT_CHROMAU_DC = 6,
DCT_CHROMAU_AC = 7,
DCT_CHROMAU_4x4 = 8,
DCT_CHROMAU_8x8 = 9,
DCT_CHROMAV_DC = 10,
DCT_CHROMAV_AC = 11,
DCT_CHROMAV_4x4 = 12,
DCT_CHROMAV_8x8 = 13,
};
static const uint8_t ctx_cat_plane[6][3] =
{
{ DCT_LUMA_DC, DCT_CHROMAU_DC, DCT_CHROMAV_DC},
{ DCT_LUMA_AC, DCT_CHROMAU_AC, DCT_CHROMAV_AC},
{DCT_LUMA_4x4, DCT_CHROMAU_4x4, DCT_CHROMAV_4x4},
{0},
{0},
{DCT_LUMA_8x8, DCT_CHROMAU_8x8, DCT_CHROMAV_8x8}
};
/* Per-frame allocation: is allocated per-thread only in frame-threads mode. */
int x264_macroblock_cache_allocate( x264_t *h );
void x264_macroblock_cache_free( x264_t *h );
/* Per-thread allocation: is allocated per-thread even in sliced-threads mode. */
int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead );
void x264_macroblock_thread_free( x264_t *h, int b_lookahead );
void x264_macroblock_slice_init( x264_t *h );
void x264_macroblock_thread_init( x264_t *h );
void x264_macroblock_cache_load_progressive( x264_t *h, int mb_x, int mb_y );
void x264_macroblock_cache_load_interlaced( x264_t *h, int mb_x, int mb_y );
void x264_macroblock_deblock_strength( x264_t *h );
void x264_macroblock_cache_save( x264_t *h );
void x264_macroblock_bipred_init( x264_t *h );
void x264_prefetch_fenc( x264_t *h, x264_frame_t *fenc, int i_mb_x, int i_mb_y );
void x264_copy_column8( pixel *dst, pixel *src );
/* x264_mb_predict_mv_16x16:
* set mvp with predicted mv for D_16x16 block
* h->mb. need only valid values from other blocks */
void x264_mb_predict_mv_16x16( x264_t *h, int i_list, int i_ref, int16_t mvp[2] );
/* x264_mb_predict_mv_pskip:
* set mvp with predicted mv for P_SKIP
* h->mb. need only valid values from other blocks */
void x264_mb_predict_mv_pskip( x264_t *h, int16_t mv[2] );
/* x264_mb_predict_mv:
* set mvp with predicted mv for all blocks except SKIP and DIRECT
* h->mb. need valid ref/partition/sub of current block to be valid
* and valid mv/ref from other blocks. */
void x264_mb_predict_mv( x264_t *h, int i_list, int idx, int i_width, int16_t mvp[2] );
/* x264_mb_predict_mv_direct16x16:
* set h->mb.cache.mv and h->mb.cache.ref for B_SKIP or B_DIRECT
* h->mb. need only valid values from other blocks.
* return 1 on success, 0 on failure.
* if b_changed != NULL, set it to whether refs or mvs differ from
* before this functioncall. */
int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed );
/* x264_mb_predict_mv_ref16x16:
* set mvc with D_16x16 prediction.
* uses all neighbors, even those that didn't end up using this ref.
* h->mb. need only valid values from other blocks */
void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[8][2], int *i_mvc );
void x264_mb_mc( x264_t *h );
void x264_mb_mc_8x8( x264_t *h, int i8 );
static ALWAYS_INLINE uint32_t pack16to32( uint32_t a, uint32_t b )
{
#if WORDS_BIGENDIAN
return b + (a<<16);
#else
return a + (b<<16);
#endif
}
static ALWAYS_INLINE uint32_t pack8to16( uint32_t a, uint32_t b )
{
#if WORDS_BIGENDIAN
return b + (a<<8);
#else
return a + (b<<8);
#endif
}
static ALWAYS_INLINE uint32_t pack8to32( uint32_t a, uint32_t b, uint32_t c, uint32_t d )
{
#if WORDS_BIGENDIAN
return d + (c<<8) + (b<<16) + (a<<24);
#else
return a + (b<<8) + (c<<16) + (d<<24);
#endif
}
static ALWAYS_INLINE uint32_t pack16to32_mask( int a, int b )
{
#if WORDS_BIGENDIAN
return (b&0xFFFF) + (a<<16);
#else
return (a&0xFFFF) + (b<<16);
#endif
}
static ALWAYS_INLINE uint64_t pack32to64( uint32_t a, uint32_t b )
{
#if WORDS_BIGENDIAN
return b + ((uint64_t)a<<32);
#else
return a + ((uint64_t)b<<32);
#endif
}
#if HIGH_BIT_DEPTH
# define pack_pixel_1to2 pack16to32
# define pack_pixel_2to4 pack32to64
#else
# define pack_pixel_1to2 pack8to16
# define pack_pixel_2to4 pack16to32
#endif
static ALWAYS_INLINE int x264_mb_predict_intra4x4_mode( x264_t *h, int idx )
{
const int ma = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 1];
const int mb = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 8];
const int m = X264_MIN( x264_mb_pred_mode4x4_fix(ma),
x264_mb_pred_mode4x4_fix(mb) );
if( m < 0 )
return I_PRED_4x4_DC;
return m;
}
static ALWAYS_INLINE int x264_mb_predict_non_zero_code( x264_t *h, int idx )
{
const int za = h->mb.cache.non_zero_count[x264_scan8[idx] - 1];
const int zb = h->mb.cache.non_zero_count[x264_scan8[idx] - 8];
int i_ret = za + zb;
if( i_ret < 0x80 )
i_ret = ( i_ret + 1 ) >> 1;
return i_ret & 0x7f;
}
/* intra and skip are disallowed, p8x8 is conditional. */
static const uint8_t x264_transform_allowed[X264_MBTYPE_MAX] =
{
0,0,0,0,1,2,0,1,1,1,1,1,1,1,1,1,1,1,0
};
/* x264_mb_transform_8x8_allowed:
* check whether any partition is smaller than 8x8 (or at least
* might be, according to just partition type.)
* doesn't check for cbp */
static ALWAYS_INLINE int x264_mb_transform_8x8_allowed( x264_t *h )
{
if( !h->pps->b_transform_8x8_mode )
return 0;
if( h->mb.i_type != P_8x8 )
return x264_transform_allowed[h->mb.i_type];
return M32( h->mb.i_sub_partition ) == D_L0_8x8*0x01010101;
}
#endif

View file

@ -0,0 +1,779 @@
/*****************************************************************************
* mc.c: motion compensation
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#if HAVE_MMX
#include "x86/mc.h"
#endif
#if ARCH_PPC
#include "ppc/mc.h"
#endif
#if ARCH_ARM
#include "arm/mc.h"
#endif
#if ARCH_AARCH64
#include "aarch64/mc.h"
#endif
#if ARCH_MIPS
#include "mips/mc.h"
#endif
static inline void pixel_avg( pixel *dst, intptr_t i_dst_stride,
pixel *src1, intptr_t i_src1_stride,
pixel *src2, intptr_t i_src2_stride, int i_width, int i_height )
{
for( int y = 0; y < i_height; y++ )
{
for( int x = 0; x < i_width; x++ )
dst[x] = ( src1[x] + src2[x] + 1 ) >> 1;
dst += i_dst_stride;
src1 += i_src1_stride;
src2 += i_src2_stride;
}
}
static inline void pixel_avg_wxh( pixel *dst, intptr_t i_dst,
pixel *src1, intptr_t i_src1,
pixel *src2, intptr_t i_src2, int width, int height )
{
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
dst[x] = ( src1[x] + src2[x] + 1 ) >> 1;
src1 += i_src1;
src2 += i_src2;
dst += i_dst;
}
}
/* Implicit weighted bipred only:
* assumes log2_denom = 5, offset = 0, weight1 + weight2 = 64 */
static inline void pixel_avg_weight_wxh( pixel *dst, intptr_t i_dst,
pixel *src1, intptr_t i_src1,
pixel *src2, intptr_t i_src2, int width, int height, int i_weight1 )
{
int i_weight2 = 64 - i_weight1;
for( int y = 0; y<height; y++, dst += i_dst, src1 += i_src1, src2 += i_src2 )
for( int x = 0; x<width; x++ )
dst[x] = x264_clip_pixel( (src1[x]*i_weight1 + src2[x]*i_weight2 + (1<<5)) >> 6 );
}
#undef op_scale2
#define PIXEL_AVG_C( name, width, height ) \
static void name( pixel *pix1, intptr_t i_stride_pix1, \
pixel *pix2, intptr_t i_stride_pix2, \
pixel *pix3, intptr_t i_stride_pix3, int weight ) \
{ \
if( weight == 32 ) \
pixel_avg_wxh( pix1, i_stride_pix1, pix2, i_stride_pix2, pix3, i_stride_pix3, width, height ); \
else \
pixel_avg_weight_wxh( pix1, i_stride_pix1, pix2, i_stride_pix2, pix3, i_stride_pix3, width, height, weight ); \
}
PIXEL_AVG_C( pixel_avg_16x16, 16, 16 )
PIXEL_AVG_C( pixel_avg_16x8, 16, 8 )
PIXEL_AVG_C( pixel_avg_8x16, 8, 16 )
PIXEL_AVG_C( pixel_avg_8x8, 8, 8 )
PIXEL_AVG_C( pixel_avg_8x4, 8, 4 )
PIXEL_AVG_C( pixel_avg_4x16, 4, 16 )
PIXEL_AVG_C( pixel_avg_4x8, 4, 8 )
PIXEL_AVG_C( pixel_avg_4x4, 4, 4 )
PIXEL_AVG_C( pixel_avg_4x2, 4, 2 )
PIXEL_AVG_C( pixel_avg_2x8, 2, 8 )
PIXEL_AVG_C( pixel_avg_2x4, 2, 4 )
PIXEL_AVG_C( pixel_avg_2x2, 2, 2 )
static void x264_weight_cache( x264_t *h, x264_weight_t *w )
{
w->weightfn = h->mc.weight;
}
#define opscale(x) dst[x] = x264_clip_pixel( ((src[x] * scale + (1<<(denom - 1))) >> denom) + offset )
#define opscale_noden(x) dst[x] = x264_clip_pixel( src[x] * scale + offset )
static void mc_weight( pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride,
const x264_weight_t *weight, int i_width, int i_height )
{
int offset = weight->i_offset << (BIT_DEPTH-8);
int scale = weight->i_scale;
int denom = weight->i_denom;
if( denom >= 1 )
{
for( int y = 0; y < i_height; y++, dst += i_dst_stride, src += i_src_stride )
for( int x = 0; x < i_width; x++ )
opscale( x );
}
else
{
for( int y = 0; y < i_height; y++, dst += i_dst_stride, src += i_src_stride )
for( int x = 0; x < i_width; x++ )
opscale_noden( x );
}
}
#define MC_WEIGHT_C( name, width ) \
static void name( pixel *dst, intptr_t i_dst_stride, pixel *src, intptr_t i_src_stride, const x264_weight_t *weight, int height ) \
{ \
mc_weight( dst, i_dst_stride, src, i_src_stride, weight, width, height );\
}
MC_WEIGHT_C( mc_weight_w20, 20 )
MC_WEIGHT_C( mc_weight_w16, 16 )
MC_WEIGHT_C( mc_weight_w12, 12 )
MC_WEIGHT_C( mc_weight_w8, 8 )
MC_WEIGHT_C( mc_weight_w4, 4 )
MC_WEIGHT_C( mc_weight_w2, 2 )
static weight_fn_t x264_mc_weight_wtab[6] =
{
mc_weight_w2,
mc_weight_w4,
mc_weight_w8,
mc_weight_w12,
mc_weight_w16,
mc_weight_w20,
};
const x264_weight_t x264_weight_none[3] = { {{0}} };
static void mc_copy( pixel *src, intptr_t i_src_stride, pixel *dst, intptr_t i_dst_stride, int i_width, int i_height )
{
for( int y = 0; y < i_height; y++ )
{
memcpy( dst, src, i_width * sizeof(pixel) );
src += i_src_stride;
dst += i_dst_stride;
}
}
#define TAPFILTER(pix, d) ((pix)[x-2*d] + (pix)[x+3*d] - 5*((pix)[x-d] + (pix)[x+2*d]) + 20*((pix)[x] + (pix)[x+d]))
static void hpel_filter( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src,
intptr_t stride, int width, int height, int16_t *buf )
{
const int pad = (BIT_DEPTH > 9) ? (-10 * PIXEL_MAX) : 0;
for( int y = 0; y < height; y++ )
{
for( int x = -2; x < width+3; x++ )
{
int v = TAPFILTER(src,stride);
dstv[x] = x264_clip_pixel( (v + 16) >> 5 );
/* transform v for storage in a 16-bit integer */
buf[x+2] = v + pad;
}
for( int x = 0; x < width; x++ )
dstc[x] = x264_clip_pixel( (TAPFILTER(buf+2,1) - 32*pad + 512) >> 10 );
for( int x = 0; x < width; x++ )
dsth[x] = x264_clip_pixel( (TAPFILTER(src,1) + 16) >> 5 );
dsth += stride;
dstv += stride;
dstc += stride;
src += stride;
}
}
const uint8_t x264_hpel_ref0[16] = {0,1,1,1,0,1,1,1,2,3,3,3,0,1,1,1};
const uint8_t x264_hpel_ref1[16] = {0,0,1,0,2,2,3,2,2,2,3,2,2,2,3,2};
static void mc_luma( pixel *dst, intptr_t i_dst_stride,
pixel *src[4], intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height, const x264_weight_t *weight )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
int offset = (mvy>>2)*i_src_stride + (mvx>>2);
pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;
if( qpel_idx & 5 ) /* qpel interpolation needed */
{
pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
pixel_avg( dst, i_dst_stride, src1, i_src_stride,
src2, i_src_stride, i_width, i_height );
if( weight->weightfn )
mc_weight( dst, i_dst_stride, dst, i_dst_stride, weight, i_width, i_height );
}
else if( weight->weightfn )
mc_weight( dst, i_dst_stride, src1, i_src_stride, weight, i_width, i_height );
else
mc_copy( src1, i_src_stride, dst, i_dst_stride, i_width, i_height );
}
static pixel *get_ref( pixel *dst, intptr_t *i_dst_stride,
pixel *src[4], intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height, const x264_weight_t *weight )
{
int qpel_idx = ((mvy&3)<<2) + (mvx&3);
int offset = (mvy>>2)*i_src_stride + (mvx>>2);
pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;
if( qpel_idx & 5 ) /* qpel interpolation needed */
{
pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
pixel_avg( dst, *i_dst_stride, src1, i_src_stride,
src2, i_src_stride, i_width, i_height );
if( weight->weightfn )
mc_weight( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_width, i_height );
return dst;
}
else if( weight->weightfn )
{
mc_weight( dst, *i_dst_stride, src1, i_src_stride, weight, i_width, i_height );
return dst;
}
else
{
*i_dst_stride = i_src_stride;
return src1;
}
}
/* full chroma mc (ie until 1/8 pixel)*/
static void mc_chroma( pixel *dstu, pixel *dstv, intptr_t i_dst_stride,
pixel *src, intptr_t i_src_stride,
int mvx, int mvy,
int i_width, int i_height )
{
pixel *srcp;
int d8x = mvx&0x07;
int d8y = mvy&0x07;
int cA = (8-d8x)*(8-d8y);
int cB = d8x *(8-d8y);
int cC = (8-d8x)*d8y;
int cD = d8x *d8y;
src += (mvy >> 3) * i_src_stride + (mvx >> 3)*2;
srcp = &src[i_src_stride];
for( int y = 0; y < i_height; y++ )
{
for( int x = 0; x < i_width; x++ )
{
dstu[x] = ( cA*src[2*x] + cB*src[2*x+2] +
cC*srcp[2*x] + cD*srcp[2*x+2] + 32 ) >> 6;
dstv[x] = ( cA*src[2*x+1] + cB*src[2*x+3] +
cC*srcp[2*x+1] + cD*srcp[2*x+3] + 32 ) >> 6;
}
dstu += i_dst_stride;
dstv += i_dst_stride;
src = srcp;
srcp += i_src_stride;
}
}
#define MC_COPY(W) \
static void mc_copy_w##W( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int i_height ) \
{ \
mc_copy( src, i_src, dst, i_dst, W, i_height ); \
}
MC_COPY( 16 )
MC_COPY( 8 )
MC_COPY( 4 )
void x264_plane_copy_c( pixel *dst, intptr_t i_dst,
pixel *src, intptr_t i_src, int w, int h )
{
while( h-- )
{
memcpy( dst, src, w * sizeof(pixel) );
dst += i_dst;
src += i_src;
}
}
void x264_plane_copy_swap_c( pixel *dst, intptr_t i_dst,
pixel *src, intptr_t i_src, int w, int h )
{
for( int y=0; y<h; y++, dst+=i_dst, src+=i_src )
for( int x=0; x<2*w; x+=2 )
{
dst[x] = src[x+1];
dst[x+1] = src[x];
}
}
void x264_plane_copy_interleave_c( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h )
{
for( int y=0; y<h; y++, dst+=i_dst, srcu+=i_srcu, srcv+=i_srcv )
for( int x=0; x<w; x++ )
{
dst[2*x] = srcu[x];
dst[2*x+1] = srcv[x];
}
}
void x264_plane_copy_deinterleave_c( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,
pixel *src, intptr_t i_src, int w, int h )
{
for( int y=0; y<h; y++, dsta+=i_dsta, dstb+=i_dstb, src+=i_src )
for( int x=0; x<w; x++ )
{
dsta[x] = src[2*x];
dstb[x] = src[2*x+1];
}
}
static void x264_plane_copy_deinterleave_rgb_c( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc,
pixel *src, intptr_t i_src, int pw, int w, int h )
{
for( int y=0; y<h; y++, dsta+=i_dsta, dstb+=i_dstb, dstc+=i_dstc, src+=i_src )
{
for( int x=0; x<w; x++ )
{
dsta[x] = src[x*pw];
dstb[x] = src[x*pw+1];
dstc[x] = src[x*pw+2];
}
}
}
#if WORDS_BIGENDIAN
static ALWAYS_INLINE uint32_t v210_endian_fix32( uint32_t x )
{
return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24);
}
#else
#define v210_endian_fix32(x) (x)
#endif
static void x264_plane_copy_deinterleave_v210_c( pixel *dsty, intptr_t i_dsty,
pixel *dstc, intptr_t i_dstc,
uint32_t *src, intptr_t i_src, int w, int h )
{
for( int l = 0; l < h; l++ )
{
pixel *dsty0 = dsty;
pixel *dstc0 = dstc;
uint32_t *src0 = src;
for( int n = 0; n < w; n += 3 )
{
uint32_t s = v210_endian_fix32( *src0++ );
*dstc0++ = s & 0x03FF;
*dsty0++ = (s >> 10) & 0x03FF;
*dstc0++ = (s >> 20) & 0x03FF;
s = v210_endian_fix32( *src0++ );
*dsty0++ = s & 0x03FF;
*dstc0++ = (s >> 10) & 0x03FF;
*dsty0++ = (s >> 20) & 0x03FF;
}
dsty += i_dsty;
dstc += i_dstc;
src += i_src;
}
}
static void store_interleave_chroma( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height )
{
for( int y=0; y<height; y++, dst+=i_dst, srcu+=FDEC_STRIDE, srcv+=FDEC_STRIDE )
for( int x=0; x<8; x++ )
{
dst[2*x] = srcu[x];
dst[2*x+1] = srcv[x];
}
}
static void load_deinterleave_chroma_fenc( pixel *dst, pixel *src, intptr_t i_src, int height )
{
x264_plane_copy_deinterleave_c( dst, FENC_STRIDE, dst+FENC_STRIDE/2, FENC_STRIDE, src, i_src, 8, height );
}
static void load_deinterleave_chroma_fdec( pixel *dst, pixel *src, intptr_t i_src, int height )
{
x264_plane_copy_deinterleave_c( dst, FDEC_STRIDE, dst+FDEC_STRIDE/2, FDEC_STRIDE, src, i_src, 8, height );
}
static void prefetch_fenc_null( pixel *pix_y, intptr_t stride_y,
pixel *pix_uv, intptr_t stride_uv, int mb_x )
{}
static void prefetch_ref_null( pixel *pix, intptr_t stride, int parity )
{}
static void memzero_aligned( void * dst, size_t n )
{
memset( dst, 0, n );
}
static void integral_init4h( uint16_t *sum, pixel *pix, intptr_t stride )
{
int v = pix[0]+pix[1]+pix[2]+pix[3];
for( int x = 0; x < stride-4; x++ )
{
sum[x] = v + sum[x-stride];
v += pix[x+4] - pix[x];
}
}
static void integral_init8h( uint16_t *sum, pixel *pix, intptr_t stride )
{
int v = pix[0]+pix[1]+pix[2]+pix[3]+pix[4]+pix[5]+pix[6]+pix[7];
for( int x = 0; x < stride-8; x++ )
{
sum[x] = v + sum[x-stride];
v += pix[x+8] - pix[x];
}
}
static void integral_init4v( uint16_t *sum8, uint16_t *sum4, intptr_t stride )
{
for( int x = 0; x < stride-8; x++ )
sum4[x] = sum8[x+4*stride] - sum8[x];
for( int x = 0; x < stride-8; x++ )
sum8[x] = sum8[x+8*stride] + sum8[x+8*stride+4] - sum8[x] - sum8[x+4];
}
static void integral_init8v( uint16_t *sum8, intptr_t stride )
{
for( int x = 0; x < stride-8; x++ )
sum8[x] = sum8[x+8*stride] - sum8[x];
}
void x264_frame_init_lowres( x264_t *h, x264_frame_t *frame )
{
pixel *src = frame->plane[0];
int i_stride = frame->i_stride[0];
int i_height = frame->i_lines[0];
int i_width = frame->i_width[0];
// duplicate last row and column so that their interpolation doesn't have to be special-cased
for( int y = 0; y < i_height; y++ )
src[i_width+y*i_stride] = src[i_width-1+y*i_stride];
memcpy( src+i_stride*i_height, src+i_stride*(i_height-1), (i_width+1) * sizeof(pixel) );
h->mc.frame_init_lowres_core( src, frame->lowres[0], frame->lowres[1], frame->lowres[2], frame->lowres[3],
i_stride, frame->i_stride_lowres, frame->i_width_lowres, frame->i_lines_lowres );
x264_frame_expand_border_lowres( frame );
memset( frame->i_cost_est, -1, sizeof(frame->i_cost_est) );
for( int y = 0; y < h->param.i_bframe + 2; y++ )
for( int x = 0; x < h->param.i_bframe + 2; x++ )
frame->i_row_satds[y][x][0] = -1;
for( int y = 0; y <= !!h->param.i_bframe; y++ )
for( int x = 0; x <= h->param.i_bframe; x++ )
frame->lowres_mvs[y][x][0][0] = 0x7FFF;
}
static void frame_init_lowres_core( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc,
intptr_t src_stride, intptr_t dst_stride, int width, int height )
{
for( int y = 0; y < height; y++ )
{
pixel *src1 = src0+src_stride;
pixel *src2 = src1+src_stride;
for( int x = 0; x<width; x++ )
{
// slower than naive bilinear, but matches asm
#define FILTER(a,b,c,d) ((((a+b+1)>>1)+((c+d+1)>>1)+1)>>1)
dst0[x] = FILTER(src0[2*x ], src1[2*x ], src0[2*x+1], src1[2*x+1]);
dsth[x] = FILTER(src0[2*x+1], src1[2*x+1], src0[2*x+2], src1[2*x+2]);
dstv[x] = FILTER(src1[2*x ], src2[2*x ], src1[2*x+1], src2[2*x+1]);
dstc[x] = FILTER(src1[2*x+1], src2[2*x+1], src1[2*x+2], src2[2*x+2]);
#undef FILTER
}
src0 += src_stride*2;
dst0 += dst_stride;
dsth += dst_stride;
dstv += dst_stride;
dstc += dst_stride;
}
}
/* Estimate the total amount of influence on future quality that could be had if we
* were to improve the reference samples used to inter predict any given macroblock. */
static void mbtree_propagate_cost( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len )
{
float fps = *fps_factor;
for( int i = 0; i < len; i++ )
{
int intra_cost = intra_costs[i];
int inter_cost = X264_MIN(intra_costs[i], inter_costs[i] & LOWRES_COST_MASK);
float propagate_intra = intra_cost * inv_qscales[i];
float propagate_amount = propagate_in[i] + propagate_intra*fps;
float propagate_num = intra_cost - inter_cost;
float propagate_denom = intra_cost;
dst[i] = X264_MIN((int)(propagate_amount * propagate_num / propagate_denom + 0.5f), 32767);
}
}
static void mbtree_propagate_list( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2],
int16_t *propagate_amount, uint16_t *lowres_costs,
int bipred_weight, int mb_y, int len, int list )
{
unsigned stride = h->mb.i_mb_stride;
unsigned width = h->mb.i_mb_width;
unsigned height = h->mb.i_mb_height;
for( unsigned i = 0; i < len; i++ )
{
int lists_used = lowres_costs[i]>>LOWRES_COST_SHIFT;
if( !(lists_used & (1 << list)) )
continue;
int listamount = propagate_amount[i];
/* Apply bipred weighting. */
if( lists_used == 3 )
listamount = (listamount * bipred_weight + 32) >> 6;
/* Early termination for simple case of mv0. */
if( !M32( mvs[i] ) )
{
MC_CLIP_ADD( ref_costs[mb_y*stride + i], listamount );
continue;
}
int x = mvs[i][0];
int y = mvs[i][1];
unsigned mbx = (x>>5)+i;
unsigned mby = (y>>5)+mb_y;
unsigned idx0 = mbx + mby * stride;
unsigned idx2 = idx0 + stride;
x &= 31;
y &= 31;
int idx0weight = (32-y)*(32-x);
int idx1weight = (32-y)*x;
int idx2weight = y*(32-x);
int idx3weight = y*x;
idx0weight = (idx0weight * listamount + 512) >> 10;
idx1weight = (idx1weight * listamount + 512) >> 10;
idx2weight = (idx2weight * listamount + 512) >> 10;
idx3weight = (idx3weight * listamount + 512) >> 10;
if( mbx < width-1 && mby < height-1 )
{
MC_CLIP_ADD( ref_costs[idx0+0], idx0weight );
MC_CLIP_ADD( ref_costs[idx0+1], idx1weight );
MC_CLIP_ADD( ref_costs[idx2+0], idx2weight );
MC_CLIP_ADD( ref_costs[idx2+1], idx3weight );
}
else
{
/* Note: this takes advantage of unsigned representation to
* catch negative mbx/mby. */
if( mby < height )
{
if( mbx < width )
MC_CLIP_ADD( ref_costs[idx0+0], idx0weight );
if( mbx+1 < width )
MC_CLIP_ADD( ref_costs[idx0+1], idx1weight );
}
if( mby+1 < height )
{
if( mbx < width )
MC_CLIP_ADD( ref_costs[idx2+0], idx2weight );
if( mbx+1 < width )
MC_CLIP_ADD( ref_costs[idx2+1], idx3weight );
}
}
}
}
/* Conversion between float and Q8.8 fixed point (big-endian) for storage */
static void mbtree_fix8_pack( uint16_t *dst, float *src, int count )
{
for( int i = 0; i < count; i++ )
dst[i] = endian_fix16( (int16_t)(src[i] * 256.0f) );
}
static void mbtree_fix8_unpack( float *dst, uint16_t *src, int count )
{
for( int i = 0; i < count; i++ )
dst[i] = (int16_t)endian_fix16( src[i] ) * (1.0f/256.0f);
}
void x264_mc_init( int cpu, x264_mc_functions_t *pf, int cpu_independent )
{
pf->mc_luma = mc_luma;
pf->get_ref = get_ref;
pf->mc_chroma = mc_chroma;
pf->avg[PIXEL_16x16]= pixel_avg_16x16;
pf->avg[PIXEL_16x8] = pixel_avg_16x8;
pf->avg[PIXEL_8x16] = pixel_avg_8x16;
pf->avg[PIXEL_8x8] = pixel_avg_8x8;
pf->avg[PIXEL_8x4] = pixel_avg_8x4;
pf->avg[PIXEL_4x16] = pixel_avg_4x16;
pf->avg[PIXEL_4x8] = pixel_avg_4x8;
pf->avg[PIXEL_4x4] = pixel_avg_4x4;
pf->avg[PIXEL_4x2] = pixel_avg_4x2;
pf->avg[PIXEL_2x8] = pixel_avg_2x8;
pf->avg[PIXEL_2x4] = pixel_avg_2x4;
pf->avg[PIXEL_2x2] = pixel_avg_2x2;
pf->weight = x264_mc_weight_wtab;
pf->offsetadd = x264_mc_weight_wtab;
pf->offsetsub = x264_mc_weight_wtab;
pf->weight_cache = x264_weight_cache;
pf->copy_16x16_unaligned = mc_copy_w16;
pf->copy[PIXEL_16x16] = mc_copy_w16;
pf->copy[PIXEL_8x8] = mc_copy_w8;
pf->copy[PIXEL_4x4] = mc_copy_w4;
pf->store_interleave_chroma = store_interleave_chroma;
pf->load_deinterleave_chroma_fenc = load_deinterleave_chroma_fenc;
pf->load_deinterleave_chroma_fdec = load_deinterleave_chroma_fdec;
pf->plane_copy = x264_plane_copy_c;
pf->plane_copy_swap = x264_plane_copy_swap_c;
pf->plane_copy_interleave = x264_plane_copy_interleave_c;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_c;
pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_c;
pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_c;
pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_c;
pf->hpel_filter = hpel_filter;
pf->prefetch_fenc_420 = prefetch_fenc_null;
pf->prefetch_fenc_422 = prefetch_fenc_null;
pf->prefetch_ref = prefetch_ref_null;
pf->memcpy_aligned = memcpy;
pf->memzero_aligned = memzero_aligned;
pf->frame_init_lowres_core = frame_init_lowres_core;
pf->integral_init4h = integral_init4h;
pf->integral_init8h = integral_init8h;
pf->integral_init4v = integral_init4v;
pf->integral_init8v = integral_init8v;
pf->mbtree_propagate_cost = mbtree_propagate_cost;
pf->mbtree_propagate_list = mbtree_propagate_list;
pf->mbtree_fix8_pack = mbtree_fix8_pack;
pf->mbtree_fix8_unpack = mbtree_fix8_unpack;
#if HAVE_MMX
x264_mc_init_mmx( cpu, pf );
#endif
#if HAVE_ALTIVEC
if( cpu&X264_CPU_ALTIVEC )
x264_mc_init_altivec( pf );
#endif
#if HAVE_ARMV6
x264_mc_init_arm( cpu, pf );
#endif
#if ARCH_AARCH64
x264_mc_init_aarch64( cpu, pf );
#endif
#if HAVE_MSA
if( cpu&X264_CPU_MSA )
x264_mc_init_mips( cpu, pf );
#endif
if( cpu_independent )
{
pf->mbtree_propagate_cost = mbtree_propagate_cost;
pf->mbtree_propagate_list = mbtree_propagate_list;
}
}
void x264_frame_filter( x264_t *h, x264_frame_t *frame, int mb_y, int b_end )
{
const int b_interlaced = PARAM_INTERLACED;
int start = mb_y*16 - 8; // buffer = 4 for deblock + 3 for 6tap, rounded to 8
int height = (b_end ? frame->i_lines[0] + 16*PARAM_INTERLACED : (mb_y+b_interlaced)*16) + 8;
if( mb_y & b_interlaced )
return;
for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ )
{
int stride = frame->i_stride[p];
const int width = frame->i_width[p];
int offs = start*stride - 8; // buffer = 3 for 6tap, aligned to 8 for simd
if( !b_interlaced || h->mb.b_adaptive_mbaff )
h->mc.hpel_filter(
frame->filtered[p][1] + offs,
frame->filtered[p][2] + offs,
frame->filtered[p][3] + offs,
frame->plane[p] + offs,
stride, width + 16, height - start,
h->scratch_buffer );
if( b_interlaced )
{
/* MC must happen between pixels in the same field. */
stride = frame->i_stride[p] << 1;
start = (mb_y*16 >> 1) - 8;
int height_fld = ((b_end ? frame->i_lines[p] : mb_y*16) >> 1) + 8;
offs = start*stride - 8;
for( int i = 0; i < 2; i++, offs += frame->i_stride[p] )
{
h->mc.hpel_filter(
frame->filtered_fld[p][1] + offs,
frame->filtered_fld[p][2] + offs,
frame->filtered_fld[p][3] + offs,
frame->plane_fld[p] + offs,
stride, width + 16, height_fld - start,
h->scratch_buffer );
}
}
}
/* generate integral image:
* frame->integral contains 2 planes. in the upper plane, each element is
* the sum of an 8x8 pixel region with top-left corner on that point.
* in the lower plane, 4x4 sums (needed only with --partitions p4x4). */
if( frame->integral )
{
int stride = frame->i_stride[0];
if( start < 0 )
{
memset( frame->integral - PADV * stride - PADH, 0, stride * sizeof(uint16_t) );
start = -PADV;
}
if( b_end )
height += PADV-9;
for( int y = start; y < height; y++ )
{
pixel *pix = frame->plane[0] + y * stride - PADH;
uint16_t *sum8 = frame->integral + (y+1) * stride - PADH;
uint16_t *sum4;
if( h->frames.b_have_sub8x8_esa )
{
h->mc.integral_init4h( sum8, pix, stride );
sum8 -= 8*stride;
sum4 = sum8 + stride * (frame->i_lines[0] + PADV*2);
if( y >= 8-PADV )
h->mc.integral_init4v( sum8, sum4, stride );
}
else
{
h->mc.integral_init8h( sum8, pix, stride );
if( y >= 8-PADV )
h->mc.integral_init8v( sum8-8*stride, stride );
}
}
}
}

View file

@ -0,0 +1,340 @@
/*****************************************************************************
* mc.h: motion compensation
*****************************************************************************
* Copyright (C) 2004-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_MC_H
#define X264_MC_H
#define MC_CLIP_ADD(s,x) (s) = X264_MIN((s)+(x),(1<<15)-1)
#define MC_CLIP_ADD2(s,x)\
do\
{\
MC_CLIP_ADD((s)[0], (x)[0]);\
MC_CLIP_ADD((s)[1], (x)[1]);\
} while( 0 )
#define PROPAGATE_LIST(cpu)\
void x264_mbtree_propagate_list_internal_##cpu( int16_t (*mvs)[2], int16_t *propagate_amount,\
uint16_t *lowres_costs, int16_t *output,\
int bipred_weight, int mb_y, int len );\
\
static void x264_mbtree_propagate_list_##cpu( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2],\
int16_t *propagate_amount, uint16_t *lowres_costs,\
int bipred_weight, int mb_y, int len, int list )\
{\
int16_t *current = h->scratch_buffer2;\
\
x264_mbtree_propagate_list_internal_##cpu( mvs, propagate_amount, lowres_costs,\
current, bipred_weight, mb_y, len );\
\
unsigned stride = h->mb.i_mb_stride;\
unsigned width = h->mb.i_mb_width;\
unsigned height = h->mb.i_mb_height;\
\
for( unsigned i = 0; i < len; current += 32 )\
{\
int end = X264_MIN( i+8, len );\
for( ; i < end; i++, current += 2 )\
{\
if( !(lowres_costs[i] & (1 << (list+LOWRES_COST_SHIFT))) )\
continue;\
\
unsigned mbx = current[0];\
unsigned mby = current[1];\
unsigned idx0 = mbx + mby * stride;\
unsigned idx2 = idx0 + stride;\
\
/* Shortcut for the simple/common case of zero MV */\
if( !M32( mvs[i] ) )\
{\
MC_CLIP_ADD( ref_costs[idx0], current[16] );\
continue;\
}\
\
if( mbx < width-1 && mby < height-1 )\
{\
MC_CLIP_ADD2( ref_costs+idx0, current+16 );\
MC_CLIP_ADD2( ref_costs+idx2, current+32 );\
}\
else\
{\
/* Note: this takes advantage of unsigned representation to\
* catch negative mbx/mby. */\
if( mby < height )\
{\
if( mbx < width )\
MC_CLIP_ADD( ref_costs[idx0+0], current[16] );\
if( mbx+1 < width )\
MC_CLIP_ADD( ref_costs[idx0+1], current[17] );\
}\
if( mby+1 < height )\
{\
if( mbx < width )\
MC_CLIP_ADD( ref_costs[idx2+0], current[32] );\
if( mbx+1 < width )\
MC_CLIP_ADD( ref_costs[idx2+1], current[33] );\
}\
}\
}\
}\
}
void x264_plane_copy_c( pixel *, intptr_t, pixel *, intptr_t, int w, int h );
#define PLANE_COPY(align, cpu)\
static void x264_plane_copy_##cpu( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h )\
{\
int c_w = (align) / sizeof(pixel) - 1;\
if( w < 256 ) /* tiny resolutions don't want non-temporal hints. dunno the exact threshold. */\
x264_plane_copy_c( dst, i_dst, src, i_src, w, h );\
else if( !(w&c_w) )\
x264_plane_copy_core_##cpu( dst, i_dst, src, i_src, w, h );\
else\
{\
if( --h > 0 )\
{\
if( i_src > 0 )\
{\
x264_plane_copy_core_##cpu( dst, i_dst, src, i_src, (w+c_w)&~c_w, h );\
dst += i_dst * h;\
src += i_src * h;\
}\
else\
x264_plane_copy_core_##cpu( dst+i_dst, i_dst, src+i_src, i_src, (w+c_w)&~c_w, h );\
}\
/* use plain memcpy on the last line (in memory order) to avoid overreading src. */\
memcpy( dst, src, w*sizeof(pixel) );\
}\
}
void x264_plane_copy_swap_c( pixel *, intptr_t, pixel *, intptr_t, int w, int h );
#define PLANE_COPY_SWAP(align, cpu)\
static void x264_plane_copy_swap_##cpu( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h )\
{\
int c_w = (align>>1) / sizeof(pixel) - 1;\
if( !(w&c_w) )\
x264_plane_copy_swap_core_##cpu( dst, i_dst, src, i_src, w, h );\
else if( w > c_w )\
{\
if( --h > 0 )\
{\
if( i_src > 0 )\
{\
x264_plane_copy_swap_core_##cpu( dst, i_dst, src, i_src, (w+c_w)&~c_w, h );\
dst += i_dst * h;\
src += i_src * h;\
}\
else\
x264_plane_copy_swap_core_##cpu( dst+i_dst, i_dst, src+i_src, i_src, (w+c_w)&~c_w, h );\
}\
x264_plane_copy_swap_core_##cpu( dst, 0, src, 0, w&~c_w, 1 );\
for( int x = 2*(w&~c_w); x < 2*w; x += 2 )\
{\
dst[x] = src[x+1];\
dst[x+1] = src[x];\
}\
}\
else\
x264_plane_copy_swap_c( dst, i_dst, src, i_src, w, h );\
}
void x264_plane_copy_deinterleave_c( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,
pixel *src, intptr_t i_src, int w, int h );
/* We can utilize existing plane_copy_deinterleave() functions for YUYV/UYUV
* input with the additional constraint that we cannot overread src. */
#define PLANE_COPY_YUYV(align, cpu)\
static void x264_plane_copy_deinterleave_yuyv_##cpu( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,\
pixel *src, intptr_t i_src, int w, int h )\
{\
int c_w = (align>>1) / sizeof(pixel) - 1;\
if( !(w&c_w) )\
x264_plane_copy_deinterleave_##cpu( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\
else if( w > c_w )\
{\
if( --h > 0 )\
{\
if( i_src > 0 )\
{\
x264_plane_copy_deinterleave_##cpu( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\
dsta += i_dsta * h;\
dstb += i_dstb * h;\
src += i_src * h;\
}\
else\
x264_plane_copy_deinterleave_##cpu( dsta+i_dsta, i_dsta, dstb+i_dstb, i_dstb,\
src+i_src, i_src, w, h );\
}\
x264_plane_copy_deinterleave_c( dsta, 0, dstb, 0, src, 0, w, 1 );\
}\
else\
x264_plane_copy_deinterleave_c( dsta, i_dsta, dstb, i_dstb, src, i_src, w, h );\
}
void x264_plane_copy_interleave_c( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
#define PLANE_INTERLEAVE(cpu) \
static void x264_plane_copy_interleave_##cpu( pixel *dst, intptr_t i_dst,\
pixel *srcu, intptr_t i_srcu,\
pixel *srcv, intptr_t i_srcv, int w, int h )\
{\
int c_w = 16 / sizeof(pixel) - 1;\
if( !(w&c_w) )\
x264_plane_copy_interleave_core_##cpu( dst, i_dst, srcu, i_srcu, srcv, i_srcv, w, h );\
else if( w > c_w && (i_srcu ^ i_srcv) >= 0 ) /* only works correctly for strides with identical signs */\
{\
if( --h > 0 )\
{\
if( i_srcu > 0 )\
{\
x264_plane_copy_interleave_core_##cpu( dst, i_dst, srcu, i_srcu, srcv, i_srcv, (w+c_w)&~c_w, h );\
dst += i_dst * h;\
srcu += i_srcu * h;\
srcv += i_srcv * h;\
}\
else\
x264_plane_copy_interleave_core_##cpu( dst+i_dst, i_dst, srcu+i_srcu, i_srcu, srcv+i_srcv, i_srcv, (w+c_w)&~c_w, h );\
}\
x264_plane_copy_interleave_c( dst, 0, srcu, 0, srcv, 0, w, 1 );\
}\
else\
x264_plane_copy_interleave_c( dst, i_dst, srcu, i_srcu, srcv, i_srcv, w, h );\
}
struct x264_weight_t;
typedef void (* weight_fn_t)( pixel *, intptr_t, pixel *,intptr_t, const struct x264_weight_t *, int );
typedef struct x264_weight_t
{
/* aligning the first member is a gcc hack to force the struct to be
* 16 byte aligned, as well as force sizeof(struct) to be a multiple of 16 */
ALIGNED_16( int16_t cachea[8] );
int16_t cacheb[8];
int32_t i_denom;
int32_t i_scale;
int32_t i_offset;
weight_fn_t *weightfn;
} ALIGNED_16( x264_weight_t );
extern const x264_weight_t x264_weight_none[3];
extern const uint8_t x264_hpel_ref0[16];
extern const uint8_t x264_hpel_ref1[16];
#define SET_WEIGHT( w, b, s, d, o )\
{\
(w).i_scale = (s);\
(w).i_denom = (d);\
(w).i_offset = (o);\
if( b )\
h->mc.weight_cache( h, &w );\
else\
w.weightfn = NULL;\
}
/* Do the MC
* XXX: Only width = 4, 8 or 16 are valid
* width == 4 -> height == 4 or 8
* width == 8 -> height == 4 or 8 or 16
* width == 16-> height == 8 or 16
* */
typedef struct
{
void (*mc_luma)( pixel *dst, intptr_t i_dst, pixel **src, intptr_t i_src,
int mvx, int mvy, int i_width, int i_height, const x264_weight_t *weight );
/* may round up the dimensions if they're not a power of 2 */
pixel* (*get_ref)( pixel *dst, intptr_t *i_dst, pixel **src, intptr_t i_src,
int mvx, int mvy, int i_width, int i_height, const x264_weight_t *weight );
/* mc_chroma may write up to 2 bytes of garbage to the right of dst,
* so it must be run from left to right. */
void (*mc_chroma)( pixel *dstu, pixel *dstv, intptr_t i_dst, pixel *src, intptr_t i_src,
int mvx, int mvy, int i_width, int i_height );
void (*avg[12])( pixel *dst, intptr_t dst_stride, pixel *src1, intptr_t src1_stride,
pixel *src2, intptr_t src2_stride, int i_weight );
/* only 16x16, 8x8, and 4x4 defined */
void (*copy[7])( pixel *dst, intptr_t dst_stride, pixel *src, intptr_t src_stride, int i_height );
void (*copy_16x16_unaligned)( pixel *dst, intptr_t dst_stride, pixel *src, intptr_t src_stride, int i_height );
void (*store_interleave_chroma)( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height );
void (*load_deinterleave_chroma_fenc)( pixel *dst, pixel *src, intptr_t i_src, int height );
void (*load_deinterleave_chroma_fdec)( pixel *dst, pixel *src, intptr_t i_src, int height );
void (*plane_copy)( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h );
void (*plane_copy_swap)( pixel *dst, intptr_t i_dst, pixel *src, intptr_t i_src, int w, int h );
void (*plane_copy_interleave)( pixel *dst, intptr_t i_dst, pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
/* may write up to 15 pixels off the end of each plane */
void (*plane_copy_deinterleave)( pixel *dstu, intptr_t i_dstu, pixel *dstv, intptr_t i_dstv,
pixel *src, intptr_t i_src, int w, int h );
void (*plane_copy_deinterleave_yuyv)( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,
pixel *src, intptr_t i_src, int w, int h );
void (*plane_copy_deinterleave_rgb)( pixel *dsta, intptr_t i_dsta, pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc, pixel *src, intptr_t i_src, int pw, int w, int h );
void (*plane_copy_deinterleave_v210)( pixel *dsty, intptr_t i_dsty,
pixel *dstc, intptr_t i_dstc,
uint32_t *src, intptr_t i_src, int w, int h );
void (*hpel_filter)( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src,
intptr_t i_stride, int i_width, int i_height, int16_t *buf );
/* prefetch the next few macroblocks of fenc or fdec */
void (*prefetch_fenc) ( pixel *pix_y, intptr_t stride_y, pixel *pix_uv, intptr_t stride_uv, int mb_x );
void (*prefetch_fenc_420)( pixel *pix_y, intptr_t stride_y, pixel *pix_uv, intptr_t stride_uv, int mb_x );
void (*prefetch_fenc_422)( pixel *pix_y, intptr_t stride_y, pixel *pix_uv, intptr_t stride_uv, int mb_x );
/* prefetch the next few macroblocks of a hpel reference frame */
void (*prefetch_ref)( pixel *pix, intptr_t stride, int parity );
void *(*memcpy_aligned)( void *dst, const void *src, size_t n );
void (*memzero_aligned)( void *dst, size_t n );
/* successive elimination prefilter */
void (*integral_init4h)( uint16_t *sum, pixel *pix, intptr_t stride );
void (*integral_init8h)( uint16_t *sum, pixel *pix, intptr_t stride );
void (*integral_init4v)( uint16_t *sum8, uint16_t *sum4, intptr_t stride );
void (*integral_init8v)( uint16_t *sum8, intptr_t stride );
void (*frame_init_lowres_core)( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc,
intptr_t src_stride, intptr_t dst_stride, int width, int height );
weight_fn_t *weight;
weight_fn_t *offsetadd;
weight_fn_t *offsetsub;
void (*weight_cache)( x264_t *, x264_weight_t * );
void (*mbtree_propagate_cost)( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len );
void (*mbtree_propagate_list)( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2],
int16_t *propagate_amount, uint16_t *lowres_costs,
int bipred_weight, int mb_y, int len, int list );
void (*mbtree_fix8_pack)( uint16_t *dst, float *src, int count );
void (*mbtree_fix8_unpack)( float *dst, uint16_t *src, int count );
} x264_mc_functions_t;
void x264_mc_init( int cpu, x264_mc_functions_t *pf, int cpu_independent );
#endif

View file

@ -0,0 +1,607 @@
/*****************************************************************************
* mvpred.c: motion vector prediction
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
void x264_mb_predict_mv( x264_t *h, int i_list, int idx, int i_width, int16_t mvp[2] )
{
const int i8 = x264_scan8[idx];
const int i_ref= h->mb.cache.ref[i_list][i8];
int i_refa = h->mb.cache.ref[i_list][i8 - 1];
int16_t *mv_a = h->mb.cache.mv[i_list][i8 - 1];
int i_refb = h->mb.cache.ref[i_list][i8 - 8];
int16_t *mv_b = h->mb.cache.mv[i_list][i8 - 8];
int i_refc = h->mb.cache.ref[i_list][i8 - 8 + i_width];
int16_t *mv_c = h->mb.cache.mv[i_list][i8 - 8 + i_width];
// Partitions not yet reached in scan order are unavailable.
if( (idx&3) >= 2 + (i_width&1) || i_refc == -2 )
{
i_refc = h->mb.cache.ref[i_list][i8 - 8 - 1];
mv_c = h->mb.cache.mv[i_list][i8 - 8 - 1];
if( SLICE_MBAFF
&& h->mb.cache.ref[i_list][x264_scan8[0]-1] != -2
&& MB_INTERLACED != h->mb.field[h->mb.i_mb_left_xy[0]] )
{
if( idx == 2 )
{
mv_c = h->mb.cache.topright_mv[i_list][0];
i_refc = h->mb.cache.topright_ref[i_list][0];
}
else if( idx == 8 )
{
mv_c = h->mb.cache.topright_mv[i_list][1];
i_refc = h->mb.cache.topright_ref[i_list][1];
}
else if( idx == 10 )
{
mv_c = h->mb.cache.topright_mv[i_list][2];
i_refc = h->mb.cache.topright_ref[i_list][2];
}
}
}
if( h->mb.i_partition == D_16x8 )
{
if( idx == 0 )
{
if( i_refb == i_ref )
{
CP32( mvp, mv_b );
return;
}
}
else
{
if( i_refa == i_ref )
{
CP32( mvp, mv_a );
return;
}
}
}
else if( h->mb.i_partition == D_8x16 )
{
if( idx == 0 )
{
if( i_refa == i_ref )
{
CP32( mvp, mv_a );
return;
}
}
else
{
if( i_refc == i_ref )
{
CP32( mvp, mv_c );
return;
}
}
}
int i_count = (i_refa == i_ref) + (i_refb == i_ref) + (i_refc == i_ref);
if( i_count > 1 )
{
median:
x264_median_mv( mvp, mv_a, mv_b, mv_c );
}
else if( i_count == 1 )
{
if( i_refa == i_ref )
CP32( mvp, mv_a );
else if( i_refb == i_ref )
CP32( mvp, mv_b );
else
CP32( mvp, mv_c );
}
else if( i_refb == -2 && i_refc == -2 && i_refa != -2 )
CP32( mvp, mv_a );
else
goto median;
}
void x264_mb_predict_mv_16x16( x264_t *h, int i_list, int i_ref, int16_t mvp[2] )
{
int i_refa = h->mb.cache.ref[i_list][X264_SCAN8_0 - 1];
int16_t *mv_a = h->mb.cache.mv[i_list][X264_SCAN8_0 - 1];
int i_refb = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8];
int16_t *mv_b = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8];
int i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 + 4];
int16_t *mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 + 4];
if( i_refc == -2 )
{
i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 - 1];
mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 - 1];
}
int i_count = (i_refa == i_ref) + (i_refb == i_ref) + (i_refc == i_ref);
if( i_count > 1 )
{
median:
x264_median_mv( mvp, mv_a, mv_b, mv_c );
}
else if( i_count == 1 )
{
if( i_refa == i_ref )
CP32( mvp, mv_a );
else if( i_refb == i_ref )
CP32( mvp, mv_b );
else
CP32( mvp, mv_c );
}
else if( i_refb == -2 && i_refc == -2 && i_refa != -2 )
CP32( mvp, mv_a );
else
goto median;
}
void x264_mb_predict_mv_pskip( x264_t *h, int16_t mv[2] )
{
int i_refa = h->mb.cache.ref[0][X264_SCAN8_0 - 1];
int i_refb = h->mb.cache.ref[0][X264_SCAN8_0 - 8];
int16_t *mv_a = h->mb.cache.mv[0][X264_SCAN8_0 - 1];
int16_t *mv_b = h->mb.cache.mv[0][X264_SCAN8_0 - 8];
if( i_refa == -2 || i_refb == -2 ||
!( i_refa | M32( mv_a ) ) ||
!( i_refb | M32( mv_b ) ) )
{
M32( mv ) = 0;
}
else
x264_mb_predict_mv_16x16( h, 0, 0, mv );
}
static int x264_mb_predict_mv_direct16x16_temporal( x264_t *h )
{
int mb_x = h->mb.i_mb_x;
int mb_y = h->mb.i_mb_y;
int mb_xy = h->mb.i_mb_xy;
int type_col[2] = { h->fref[1][0]->mb_type[mb_xy], h->fref[1][0]->mb_type[mb_xy] };
int partition_col[2] = { h->fref[1][0]->mb_partition[mb_xy], h->fref[1][0]->mb_partition[mb_xy] };
int preshift = MB_INTERLACED;
int postshift = MB_INTERLACED;
int offset = 1;
int yshift = 1;
h->mb.i_partition = partition_col[0];
if( PARAM_INTERLACED && h->fref[1][0]->field[mb_xy] != MB_INTERLACED )
{
if( MB_INTERLACED )
{
mb_y = h->mb.i_mb_y&~1;
mb_xy = mb_x + h->mb.i_mb_stride * mb_y;
type_col[0] = h->fref[1][0]->mb_type[mb_xy];
type_col[1] = h->fref[1][0]->mb_type[mb_xy + h->mb.i_mb_stride];
partition_col[0] = h->fref[1][0]->mb_partition[mb_xy];
partition_col[1] = h->fref[1][0]->mb_partition[mb_xy + h->mb.i_mb_stride];
preshift = 0;
yshift = 0;
if( (IS_INTRA(type_col[0]) || partition_col[0] == D_16x16) &&
(IS_INTRA(type_col[1]) || partition_col[1] == D_16x16) &&
partition_col[0] != D_8x8 )
h->mb.i_partition = D_16x8;
else
h->mb.i_partition = D_8x8;
}
else
{
int cur_poc = h->fdec->i_poc + h->fdec->i_delta_poc[MB_INTERLACED&h->mb.i_mb_y&1];
int col_parity = abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[0] - cur_poc)
>= abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[1] - cur_poc);
mb_y = (h->mb.i_mb_y&~1) + col_parity;
mb_xy = mb_x + h->mb.i_mb_stride * mb_y;
type_col[0] = type_col[1] = h->fref[1][0]->mb_type[mb_xy];
partition_col[0] = partition_col[1] = h->fref[1][0]->mb_partition[mb_xy];
preshift = 1;
yshift = 2;
h->mb.i_partition = partition_col[0];
}
offset = 0;
}
int i_mb_4x4 = 16 * h->mb.i_mb_stride * mb_y + 4 * mb_x;
int i_mb_8x8 = 4 * h->mb.i_mb_stride * mb_y + 2 * mb_x;
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, 0 );
/* Don't do any checks other than the ones we have to, based
* on the size of the colocated partitions.
* Depends on the enum order: D_8x8, D_16x8, D_8x16, D_16x16 */
int max_i8 = (D_16x16 - h->mb.i_partition) + 1;
int step = (h->mb.i_partition == D_16x8) + 1;
int width = 4 >> ((D_16x16 - h->mb.i_partition)&1);
int height = 4 >> ((D_16x16 - h->mb.i_partition)>>1);
for( int i8 = 0; i8 < max_i8; i8 += step )
{
int x8 = i8&1;
int y8 = i8>>1;
int ypart = (SLICE_MBAFF && h->fref[1][0]->field[mb_xy] != MB_INTERLACED) ?
MB_INTERLACED ? y8*6 : 2*(h->mb.i_mb_y&1) + y8 :
3*y8;
if( IS_INTRA( type_col[y8] ) )
{
x264_macroblock_cache_ref( h, 2*x8, 2*y8, width, height, 0, 0 );
x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 0, 0 );
x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 1, 0 );
continue;
}
int i_part_8x8 = i_mb_8x8 + x8 + (ypart>>1) * h->mb.i_b8_stride;
int i_ref1_ref = h->fref[1][0]->ref[0][i_part_8x8];
int i_ref = (map_col_to_list0(i_ref1_ref>>preshift) << postshift) + (offset&i_ref1_ref&MB_INTERLACED);
if( i_ref >= 0 )
{
int dist_scale_factor = h->mb.dist_scale_factor[i_ref][0];
int16_t *mv_col = h->fref[1][0]->mv[0][i_mb_4x4 + 3*x8 + ypart * h->mb.i_b4_stride];
int16_t mv_y = (mv_col[1]<<yshift)/2;
int l0x = ( dist_scale_factor * mv_col[0] + 128 ) >> 8;
int l0y = ( dist_scale_factor * mv_y + 128 ) >> 8;
if( h->param.i_threads > 1 && (l0y > h->mb.mv_max_spel[1] || l0y-mv_y > h->mb.mv_max_spel[1]) )
return 0;
x264_macroblock_cache_ref( h, 2*x8, 2*y8, width, height, 0, i_ref );
x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 0, pack16to32_mask(l0x, l0y) );
x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 1, pack16to32_mask(l0x-mv_col[0], l0y-mv_y) );
}
else
{
/* the collocated ref isn't in the current list0 */
/* FIXME: we might still be able to use direct_8x8 on some partitions */
/* FIXME: with B-pyramid + extensive ref list reordering
* (not currently used), we would also have to check
* l1mv1 like in spatial mode */
return 0;
}
}
return 1;
}
static ALWAYS_INLINE int x264_mb_predict_mv_direct16x16_spatial( x264_t *h, int b_interlaced )
{
int8_t ref[2];
ALIGNED_ARRAY_8( int16_t, mv,[2],[2] );
for( int i_list = 0; i_list < 2; i_list++ )
{
int i_refa = h->mb.cache.ref[i_list][X264_SCAN8_0 - 1];
int16_t *mv_a = h->mb.cache.mv[i_list][X264_SCAN8_0 - 1];
int i_refb = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8];
int16_t *mv_b = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8];
int i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 + 4];
int16_t *mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 + 4];
if( i_refc == -2 )
{
i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 - 1];
mv_c = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 - 1];
}
int i_ref = X264_MIN3( (unsigned)i_refa, (unsigned)i_refb, (unsigned)i_refc );
if( i_ref < 0 )
{
i_ref = -1;
M32( mv[i_list] ) = 0;
}
else
{
/* Same as x264_mb_predict_mv_16x16, but simplified to eliminate cases
* not relevant to spatial direct. */
int i_count = (i_refa == i_ref) + (i_refb == i_ref) + (i_refc == i_ref);
if( i_count > 1 )
x264_median_mv( mv[i_list], mv_a, mv_b, mv_c );
else
{
if( i_refa == i_ref )
CP32( mv[i_list], mv_a );
else if( i_refb == i_ref )
CP32( mv[i_list], mv_b );
else
CP32( mv[i_list], mv_c );
}
}
x264_macroblock_cache_ref( h, 0, 0, 4, 4, i_list, i_ref );
x264_macroblock_cache_mv_ptr( h, 0, 0, 4, 4, i_list, mv[i_list] );
ref[i_list] = i_ref;
}
int mb_x = h->mb.i_mb_x;
int mb_y = h->mb.i_mb_y;
int mb_xy = h->mb.i_mb_xy;
int type_col[2] = { h->fref[1][0]->mb_type[mb_xy], h->fref[1][0]->mb_type[mb_xy] };
int partition_col[2] = { h->fref[1][0]->mb_partition[mb_xy], h->fref[1][0]->mb_partition[mb_xy] };
h->mb.i_partition = partition_col[0];
if( b_interlaced && h->fref[1][0]->field[mb_xy] != MB_INTERLACED )
{
if( MB_INTERLACED )
{
mb_y = h->mb.i_mb_y&~1;
mb_xy = mb_x + h->mb.i_mb_stride * mb_y;
type_col[0] = h->fref[1][0]->mb_type[mb_xy];
type_col[1] = h->fref[1][0]->mb_type[mb_xy + h->mb.i_mb_stride];
partition_col[0] = h->fref[1][0]->mb_partition[mb_xy];
partition_col[1] = h->fref[1][0]->mb_partition[mb_xy + h->mb.i_mb_stride];
if( (IS_INTRA(type_col[0]) || partition_col[0] == D_16x16) &&
(IS_INTRA(type_col[1]) || partition_col[1] == D_16x16) &&
partition_col[0] != D_8x8 )
h->mb.i_partition = D_16x8;
else
h->mb.i_partition = D_8x8;
}
else
{
int cur_poc = h->fdec->i_poc + h->fdec->i_delta_poc[MB_INTERLACED&h->mb.i_mb_y&1];
int col_parity = abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[0] - cur_poc)
>= abs(h->fref[1][0]->i_poc + h->fref[1][0]->i_delta_poc[1] - cur_poc);
mb_y = (h->mb.i_mb_y&~1) + col_parity;
mb_xy = mb_x + h->mb.i_mb_stride * mb_y;
type_col[0] = type_col[1] = h->fref[1][0]->mb_type[mb_xy];
partition_col[0] = partition_col[1] = h->fref[1][0]->mb_partition[mb_xy];
h->mb.i_partition = partition_col[0];
}
}
int i_mb_4x4 = b_interlaced ? 4 * (h->mb.i_b4_stride*mb_y + mb_x) : h->mb.i_b4_xy;
int i_mb_8x8 = b_interlaced ? 2 * (h->mb.i_b8_stride*mb_y + mb_x) : h->mb.i_b8_xy;
int8_t *l1ref0 = &h->fref[1][0]->ref[0][i_mb_8x8];
int8_t *l1ref1 = &h->fref[1][0]->ref[1][i_mb_8x8];
int16_t (*l1mv[2])[2] = { (int16_t (*)[2]) &h->fref[1][0]->mv[0][i_mb_4x4],
(int16_t (*)[2]) &h->fref[1][0]->mv[1][i_mb_4x4] };
if( (M16( ref ) & 0x8080) == 0x8080 ) /* if( ref[0] < 0 && ref[1] < 0 ) */
{
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, 0 );
x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, 0 );
return 1;
}
if( h->param.i_threads > 1
&& ( mv[0][1] > h->mb.mv_max_spel[1]
|| mv[1][1] > h->mb.mv_max_spel[1] ) )
{
#if 0
fprintf(stderr, "direct_spatial: (%d,%d) (%d,%d) > %d \n",
mv[0][0], mv[0][1], mv[1][0], mv[1][1],
h->mb.mv_max_spel[1]);
#endif
return 0;
}
if( !M64( mv ) || (!b_interlaced && IS_INTRA( type_col[0] )) || (ref[0]&&ref[1]) )
return 1;
/* Don't do any checks other than the ones we have to, based
* on the size of the colocated partitions.
* Depends on the enum order: D_8x8, D_16x8, D_8x16, D_16x16 */
int max_i8 = (D_16x16 - h->mb.i_partition) + 1;
int step = (h->mb.i_partition == D_16x8) + 1;
int width = 4 >> ((D_16x16 - h->mb.i_partition)&1);
int height = 4 >> ((D_16x16 - h->mb.i_partition)>>1);
/* col_zero_flag */
for( int i8 = 0; i8 < max_i8; i8 += step )
{
const int x8 = i8&1;
const int y8 = i8>>1;
int ypart = (b_interlaced && h->fref[1][0]->field[mb_xy] != MB_INTERLACED) ?
MB_INTERLACED ? y8*6 : 2*(h->mb.i_mb_y&1) + y8 :
3*y8;
int o8 = x8 + (ypart>>1) * h->mb.i_b8_stride;
int o4 = 3*x8 + ypart * h->mb.i_b4_stride;
if( b_interlaced && IS_INTRA( type_col[y8] ) )
continue;
int idx;
if( l1ref0[o8] == 0 )
idx = 0;
else if( l1ref0[o8] < 0 && l1ref1[o8] == 0 )
idx = 1;
else
continue;
if( abs( l1mv[idx][o4][0] ) <= 1 && abs( l1mv[idx][o4][1] ) <= 1 )
{
if( ref[0] == 0 ) x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 0, 0 );
if( ref[1] == 0 ) x264_macroblock_cache_mv( h, 2*x8, 2*y8, width, height, 1, 0 );
}
}
return 1;
}
static int x264_mb_predict_mv_direct16x16_spatial_interlaced( x264_t *h )
{
return x264_mb_predict_mv_direct16x16_spatial( h, 1 );
}
static int x264_mb_predict_mv_direct16x16_spatial_progressive( x264_t *h )
{
return x264_mb_predict_mv_direct16x16_spatial( h, 0 );
}
int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed )
{
int b_available;
if( h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_NONE )
return 0;
else if( h->sh.b_direct_spatial_mv_pred )
{
if( SLICE_MBAFF )
b_available = x264_mb_predict_mv_direct16x16_spatial_interlaced( h );
else
b_available = x264_mb_predict_mv_direct16x16_spatial_progressive( h );
}
else
b_available = x264_mb_predict_mv_direct16x16_temporal( h );
if( b_changed != NULL && b_available )
{
int changed;
changed = M32( h->mb.cache.direct_mv[0][0] ) ^ M32( h->mb.cache.mv[0][x264_scan8[0]] );
changed |= M32( h->mb.cache.direct_mv[1][0] ) ^ M32( h->mb.cache.mv[1][x264_scan8[0]] );
changed |= h->mb.cache.direct_ref[0][0] ^ h->mb.cache.ref[0][x264_scan8[0]];
changed |= h->mb.cache.direct_ref[1][0] ^ h->mb.cache.ref[1][x264_scan8[0]];
if( !changed && h->mb.i_partition != D_16x16 )
{
changed |= M32( h->mb.cache.direct_mv[0][3] ) ^ M32( h->mb.cache.mv[0][x264_scan8[12]] );
changed |= M32( h->mb.cache.direct_mv[1][3] ) ^ M32( h->mb.cache.mv[1][x264_scan8[12]] );
changed |= h->mb.cache.direct_ref[0][3] ^ h->mb.cache.ref[0][x264_scan8[12]];
changed |= h->mb.cache.direct_ref[1][3] ^ h->mb.cache.ref[1][x264_scan8[12]];
}
if( !changed && h->mb.i_partition == D_8x8 )
{
changed |= M32( h->mb.cache.direct_mv[0][1] ) ^ M32( h->mb.cache.mv[0][x264_scan8[4]] );
changed |= M32( h->mb.cache.direct_mv[1][1] ) ^ M32( h->mb.cache.mv[1][x264_scan8[4]] );
changed |= M32( h->mb.cache.direct_mv[0][2] ) ^ M32( h->mb.cache.mv[0][x264_scan8[8]] );
changed |= M32( h->mb.cache.direct_mv[1][2] ) ^ M32( h->mb.cache.mv[1][x264_scan8[8]] );
changed |= h->mb.cache.direct_ref[0][1] ^ h->mb.cache.ref[0][x264_scan8[4]];
changed |= h->mb.cache.direct_ref[1][1] ^ h->mb.cache.ref[1][x264_scan8[4]];
changed |= h->mb.cache.direct_ref[0][2] ^ h->mb.cache.ref[0][x264_scan8[8]];
changed |= h->mb.cache.direct_ref[1][2] ^ h->mb.cache.ref[1][x264_scan8[8]];
}
*b_changed = changed;
if( !changed )
return b_available;
}
/* cache ref & mv */
if( b_available )
for( int l = 0; l < 2; l++ )
{
CP32( h->mb.cache.direct_mv[l][0], h->mb.cache.mv[l][x264_scan8[ 0]] );
CP32( h->mb.cache.direct_mv[l][1], h->mb.cache.mv[l][x264_scan8[ 4]] );
CP32( h->mb.cache.direct_mv[l][2], h->mb.cache.mv[l][x264_scan8[ 8]] );
CP32( h->mb.cache.direct_mv[l][3], h->mb.cache.mv[l][x264_scan8[12]] );
h->mb.cache.direct_ref[l][0] = h->mb.cache.ref[l][x264_scan8[ 0]];
h->mb.cache.direct_ref[l][1] = h->mb.cache.ref[l][x264_scan8[ 4]];
h->mb.cache.direct_ref[l][2] = h->mb.cache.ref[l][x264_scan8[ 8]];
h->mb.cache.direct_ref[l][3] = h->mb.cache.ref[l][x264_scan8[12]];
h->mb.cache.direct_partition = h->mb.i_partition;
}
return b_available;
}
/* This just improves encoder performance, it's not part of the spec */
void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[9][2], int *i_mvc )
{
int16_t (*mvr)[2] = h->mb.mvr[i_list][i_ref];
int i = 0;
#define SET_MVP(mvp) \
{ \
CP32( mvc[i], mvp ); \
i++; \
}
#define SET_IMVP(xy) \
if( xy >= 0 ) \
{ \
int shift = 1 + MB_INTERLACED - h->mb.field[xy]; \
int16_t *mvp = h->mb.mvr[i_list][i_ref<<1>>shift][xy]; \
mvc[i][0] = mvp[0]; \
mvc[i][1] = mvp[1]<<1>>shift; \
i++; \
}
/* b_direct */
if( h->sh.i_type == SLICE_TYPE_B
&& h->mb.cache.ref[i_list][x264_scan8[12]] == i_ref )
{
SET_MVP( h->mb.cache.mv[i_list][x264_scan8[12]] );
}
if( i_ref == 0 && h->frames.b_have_lowres )
{
int idx = i_list ? h->fref[1][0]->i_frame-h->fenc->i_frame-1
: h->fenc->i_frame-h->fref[0][0]->i_frame-1;
if( idx <= h->param.i_bframe )
{
int16_t (*lowres_mv)[2] = h->fenc->lowres_mvs[i_list][idx];
if( lowres_mv[0][0] != 0x7fff )
{
M32( mvc[i] ) = (M32( lowres_mv[h->mb.i_mb_xy] )*2)&0xfffeffff;
i++;
}
}
}
/* spatial predictors */
if( SLICE_MBAFF )
{
SET_IMVP( h->mb.i_mb_left_xy[0] );
SET_IMVP( h->mb.i_mb_top_xy );
SET_IMVP( h->mb.i_mb_topleft_xy );
SET_IMVP( h->mb.i_mb_topright_xy );
}
else
{
SET_MVP( mvr[h->mb.i_mb_left_xy[0]] );
SET_MVP( mvr[h->mb.i_mb_top_xy] );
SET_MVP( mvr[h->mb.i_mb_topleft_xy] );
SET_MVP( mvr[h->mb.i_mb_topright_xy] );
}
#undef SET_IMVP
#undef SET_MVP
/* temporal predictors */
if( h->fref[0][0]->i_ref[0] > 0 )
{
x264_frame_t *l0 = h->fref[0][0];
int field = h->mb.i_mb_y&1;
int curpoc = h->fdec->i_poc + h->fdec->i_delta_poc[field];
int refpoc = h->fref[i_list][i_ref>>SLICE_MBAFF]->i_poc;
refpoc += l0->i_delta_poc[field^(i_ref&1)];
#define SET_TMVP( dx, dy ) \
{ \
int mb_index = h->mb.i_mb_xy + dx + dy*h->mb.i_mb_stride; \
int scale = (curpoc - refpoc) * l0->inv_ref_poc[MB_INTERLACED&field]; \
mvc[i][0] = (l0->mv16x16[mb_index][0]*scale + 128) >> 8; \
mvc[i][1] = (l0->mv16x16[mb_index][1]*scale + 128) >> 8; \
i++; \
}
SET_TMVP(0,0);
if( h->mb.i_mb_x < h->mb.i_mb_width-1 )
SET_TMVP(1,0);
if( h->mb.i_mb_y < h->mb.i_mb_height-1 )
SET_TMVP(0,1);
#undef SET_TMVP
}
*i_mvc = i;
}

View file

@ -0,0 +1,719 @@
/*****************************************************************************
* opencl.c: OpenCL initialization and kernel compilation
*****************************************************************************
* Copyright (C) 2012-2017 x264 project
*
* Authors: Steve Borho <sborho@multicorewareinc.com>
* Anton Mitrofanov <BugMaster@narod.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#ifdef _WIN32
#include <windows.h>
#define ocl_open LoadLibraryW( L"OpenCL" )
#define ocl_close FreeLibrary
#define ocl_address GetProcAddress
#else
#include <dlfcn.h> //dlopen, dlsym, dlclose
#if SYS_MACOSX
#define ocl_open dlopen( "/System/Library/Frameworks/OpenCL.framework/OpenCL", RTLD_NOW )
#else
#define ocl_open dlopen( "libOpenCL.so", RTLD_NOW )
#endif
#define ocl_close dlclose
#define ocl_address dlsym
#endif
#define LOAD_OCL_FUNC(name, continue_on_fail)\
{\
ocl->name = (void*)ocl_address( ocl->library, #name );\
if( !continue_on_fail && !ocl->name )\
goto fail;\
}
/* load the library and functions we require from it */
x264_opencl_function_t *x264_opencl_load_library( void )
{
x264_opencl_function_t *ocl;
#undef fail
#define fail fail0
CHECKED_MALLOCZERO( ocl, sizeof(x264_opencl_function_t) );
#undef fail
#define fail fail1
ocl->library = ocl_open;
if( !ocl->library )
goto fail;
#undef fail
#define fail fail2
LOAD_OCL_FUNC( clBuildProgram, 0 );
LOAD_OCL_FUNC( clCreateBuffer, 0 );
LOAD_OCL_FUNC( clCreateCommandQueue, 0 );
LOAD_OCL_FUNC( clCreateContext, 0 );
LOAD_OCL_FUNC( clCreateImage2D, 0 );
LOAD_OCL_FUNC( clCreateKernel, 0 );
LOAD_OCL_FUNC( clCreateProgramWithBinary, 0 );
LOAD_OCL_FUNC( clCreateProgramWithSource, 0 );
LOAD_OCL_FUNC( clEnqueueCopyBuffer, 0 );
LOAD_OCL_FUNC( clEnqueueMapBuffer, 0 );
LOAD_OCL_FUNC( clEnqueueNDRangeKernel, 0 );
LOAD_OCL_FUNC( clEnqueueReadBuffer, 0 );
LOAD_OCL_FUNC( clEnqueueWriteBuffer, 0 );
LOAD_OCL_FUNC( clFinish, 0 );
LOAD_OCL_FUNC( clGetCommandQueueInfo, 0 );
LOAD_OCL_FUNC( clGetDeviceIDs, 0 );
LOAD_OCL_FUNC( clGetDeviceInfo, 0 );
LOAD_OCL_FUNC( clGetKernelWorkGroupInfo, 0 );
LOAD_OCL_FUNC( clGetPlatformIDs, 0 );
LOAD_OCL_FUNC( clGetProgramBuildInfo, 0 );
LOAD_OCL_FUNC( clGetProgramInfo, 0 );
LOAD_OCL_FUNC( clGetSupportedImageFormats, 0 );
LOAD_OCL_FUNC( clReleaseCommandQueue, 0 );
LOAD_OCL_FUNC( clReleaseContext, 0 );
LOAD_OCL_FUNC( clReleaseKernel, 0 );
LOAD_OCL_FUNC( clReleaseMemObject, 0 );
LOAD_OCL_FUNC( clReleaseProgram, 0 );
LOAD_OCL_FUNC( clSetKernelArg, 0 );
return ocl;
#undef fail
fail2:
ocl_close( ocl->library );
fail1:
x264_free( ocl );
fail0:
return NULL;
}
void x264_opencl_close_library( x264_opencl_function_t *ocl )
{
if( !ocl )
return;
ocl_close( ocl->library );
x264_free( ocl );
}
/* define from recent cl_ext.h, copied here in case headers are old */
#define CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD 0x4042
/* Requires full include path in case of out-of-tree builds */
#include "common/oclobj.h"
static int x264_detect_switchable_graphics( void );
/* Try to load the cached compiled program binary, verify the device context is
* still valid before reuse */
static cl_program x264_opencl_cache_load( x264_t *h, const char *dev_name, const char *dev_vendor, const char *driver_version )
{
/* try to load cached program binary */
FILE *fp = x264_fopen( h->param.psz_clbin_file, "rb" );
if( !fp )
return NULL;
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_program program = NULL;
uint8_t *binary = NULL;
fseek( fp, 0, SEEK_END );
size_t size = ftell( fp );
rewind( fp );
CHECKED_MALLOC( binary, size );
if( fread( binary, 1, size, fp ) != size )
goto fail;
const uint8_t *ptr = (const uint8_t*)binary;
#define CHECK_STRING( STR )\
do {\
size_t len = strlen( STR );\
if( size <= len || strncmp( (char*)ptr, STR, len ) )\
goto fail;\
else {\
size -= (len+1); ptr += (len+1);\
}\
} while( 0 )
CHECK_STRING( dev_name );
CHECK_STRING( dev_vendor );
CHECK_STRING( driver_version );
CHECK_STRING( x264_opencl_source_hash );
#undef CHECK_STRING
cl_int status;
program = ocl->clCreateProgramWithBinary( h->opencl.context, 1, &h->opencl.device, &size, &ptr, NULL, &status );
if( status != CL_SUCCESS )
program = NULL;
fail:
fclose( fp );
x264_free( binary );
return program;
}
/* Save the compiled program binary to a file for later reuse. Device context
* is also saved in the cache file so we do not reuse stale binaries */
static void x264_opencl_cache_save( x264_t *h, cl_program program, const char *dev_name, const char *dev_vendor, const char *driver_version )
{
FILE *fp = x264_fopen( h->param.psz_clbin_file, "wb" );
if( !fp )
{
x264_log( h, X264_LOG_INFO, "OpenCL: unable to open clbin file for write\n" );
return;
}
x264_opencl_function_t *ocl = h->opencl.ocl;
uint8_t *binary = NULL;
size_t size = 0;
cl_int status = ocl->clGetProgramInfo( program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL );
if( status != CL_SUCCESS || !size )
{
x264_log( h, X264_LOG_INFO, "OpenCL: Unable to query program binary size, no cache file generated\n" );
goto fail;
}
CHECKED_MALLOC( binary, size );
status = ocl->clGetProgramInfo( program, CL_PROGRAM_BINARIES, sizeof(uint8_t *), &binary, NULL );
if( status != CL_SUCCESS )
{
x264_log( h, X264_LOG_INFO, "OpenCL: Unable to query program binary, no cache file generated\n" );
goto fail;
}
fputs( dev_name, fp );
fputc( '\n', fp );
fputs( dev_vendor, fp );
fputc( '\n', fp );
fputs( driver_version, fp );
fputc( '\n', fp );
fputs( x264_opencl_source_hash, fp );
fputc( '\n', fp );
fwrite( binary, 1, size, fp );
fail:
fclose( fp );
x264_free( binary );
return;
}
/* The OpenCL source under common/opencl will be merged into common/oclobj.h by
* the Makefile. It defines a x264_opencl_source byte array which we will pass
* to clCreateProgramWithSource(). We also attempt to use a cache file for the
* compiled binary, stored in the current working folder. */
static cl_program x264_opencl_compile( x264_t *h )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_program program = NULL;
char *build_log = NULL;
char dev_name[64];
char dev_vendor[64];
char driver_version[64];
cl_int status;
status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_NAME, sizeof(dev_name), dev_name, NULL );
status |= ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_VENDOR, sizeof(dev_vendor), dev_vendor, NULL );
status |= ocl->clGetDeviceInfo( h->opencl.device, CL_DRIVER_VERSION, sizeof(driver_version), driver_version, NULL );
if( status != CL_SUCCESS )
return NULL;
// Most AMD GPUs have vector registers
int vectorize = !strcmp( dev_vendor, "Advanced Micro Devices, Inc." );
h->opencl.b_device_AMD_SI = 0;
if( vectorize )
{
/* Disable OpenCL on Intel/AMD switchable graphics devices */
if( x264_detect_switchable_graphics() )
{
x264_log( h, X264_LOG_INFO, "OpenCL acceleration disabled, switchable graphics detected\n" );
return NULL;
}
/* Detect AMD SouthernIsland or newer device (single-width registers) */
cl_uint simdwidth = 4;
status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, sizeof(cl_uint), &simdwidth, NULL );
if( status == CL_SUCCESS && simdwidth == 1 )
{
vectorize = 0;
h->opencl.b_device_AMD_SI = 1;
}
}
x264_log( h, X264_LOG_INFO, "OpenCL acceleration enabled with %s %s %s\n", dev_vendor, dev_name, h->opencl.b_device_AMD_SI ? "(SI)" : "" );
program = x264_opencl_cache_load( h, dev_name, dev_vendor, driver_version );
if( !program )
{
/* clCreateProgramWithSource() requires a pointer variable, you cannot just use &x264_opencl_source */
x264_log( h, X264_LOG_INFO, "Compiling OpenCL kernels...\n" );
const char *strptr = (const char*)x264_opencl_source;
size_t size = sizeof(x264_opencl_source);
program = ocl->clCreateProgramWithSource( h->opencl.context, 1, &strptr, &size, &status );
if( status != CL_SUCCESS || !program )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: unable to create program\n" );
return NULL;
}
}
/* Build the program binary for the OpenCL device */
const char *buildopts = vectorize ? "-DVECTORIZE=1" : "";
status = ocl->clBuildProgram( program, 1, &h->opencl.device, buildopts, NULL, NULL );
if( status == CL_SUCCESS )
{
x264_opencl_cache_save( h, program, dev_name, dev_vendor, driver_version );
return program;
}
/* Compile failure, should not happen with production code. */
size_t build_log_len = 0;
status = ocl->clGetProgramBuildInfo( program, h->opencl.device, CL_PROGRAM_BUILD_LOG, 0, NULL, &build_log_len );
if( status != CL_SUCCESS || !build_log_len )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to query build log\n" );
goto fail;
}
build_log = x264_malloc( build_log_len );
if( !build_log )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to alloc build log\n" );
goto fail;
}
status = ocl->clGetProgramBuildInfo( program, h->opencl.device, CL_PROGRAM_BUILD_LOG, build_log_len, build_log, NULL );
if( status != CL_SUCCESS )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to get build log\n" );
goto fail;
}
FILE *log_file = x264_fopen( "x264_kernel_build_log.txt", "w" );
if( !log_file )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to create file x264_kernel_build_log.txt\n" );
goto fail;
}
fwrite( build_log, 1, build_log_len, log_file );
fclose( log_file );
x264_log( h, X264_LOG_WARNING, "OpenCL: kernel build errors written to x264_kernel_build_log.txt\n" );
fail:
x264_free( build_log );
if( program )
ocl->clReleaseProgram( program );
return NULL;
}
static int x264_opencl_lookahead_alloc( x264_t *h )
{
if( !h->param.rc.i_lookahead )
return -1;
static const char *kernelnames[] = {
"mb_intra_cost_satd_8x8",
"sum_intra_cost",
"downscale_hpel",
"downscale1",
"downscale2",
"memset_int16",
"weightp_scaled_images",
"weightp_hpel",
"hierarchical_motion",
"subpel_refine",
"mode_selection",
"sum_inter_cost"
};
cl_kernel *kernels[] = {
&h->opencl.intra_kernel,
&h->opencl.rowsum_intra_kernel,
&h->opencl.downscale_hpel_kernel,
&h->opencl.downscale_kernel1,
&h->opencl.downscale_kernel2,
&h->opencl.memset_kernel,
&h->opencl.weightp_scaled_images_kernel,
&h->opencl.weightp_hpel_kernel,
&h->opencl.hme_kernel,
&h->opencl.subpel_refine_kernel,
&h->opencl.mode_select_kernel,
&h->opencl.rowsum_inter_kernel
};
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_int status;
h->opencl.lookahead_program = x264_opencl_compile( h );
if( !h->opencl.lookahead_program )
goto fail;
for( int i = 0; i < ARRAY_SIZE(kernelnames); i++ )
{
*kernels[i] = ocl->clCreateKernel( h->opencl.lookahead_program, kernelnames[i], &status );
if( status != CL_SUCCESS )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to compile kernel '%s' (%d)\n", kernelnames[i], status );
goto fail;
}
}
h->opencl.page_locked_buffer = ocl->clCreateBuffer( h->opencl.context, CL_MEM_WRITE_ONLY|CL_MEM_ALLOC_HOST_PTR, PAGE_LOCKED_BUF_SIZE, NULL, &status );
if( status != CL_SUCCESS )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to allocate page-locked buffer, error '%d'\n", status );
goto fail;
}
h->opencl.page_locked_ptr = ocl->clEnqueueMapBuffer( h->opencl.queue, h->opencl.page_locked_buffer, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE,
0, PAGE_LOCKED_BUF_SIZE, 0, NULL, NULL, &status );
if( status != CL_SUCCESS )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to map page-locked buffer, error '%d'\n", status );
goto fail;
}
return 0;
fail:
x264_opencl_lookahead_delete( h );
return -1;
}
static void CL_CALLBACK x264_opencl_error_notify( const char *errinfo, const void *private_info, size_t cb, void *user_data )
{
/* Any error notification can be assumed to be fatal to the OpenCL context.
* We need to stop using it immediately to prevent further damage. */
x264_t *h = (x264_t*)user_data;
h->param.b_opencl = 0;
h->opencl.b_fatal_error = 1;
x264_log( h, X264_LOG_ERROR, "OpenCL: %s\n", errinfo );
x264_log( h, X264_LOG_ERROR, "OpenCL: fatal error, aborting encode\n" );
}
int x264_opencl_lookahead_init( x264_t *h )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_platform_id *platforms = NULL;
cl_device_id *devices = NULL;
cl_image_format *imageType = NULL;
cl_context context = NULL;
int ret = -1;
cl_uint numPlatforms = 0;
cl_int status = ocl->clGetPlatformIDs( 0, NULL, &numPlatforms );
if( status != CL_SUCCESS || !numPlatforms )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to query installed platforms\n" );
goto fail;
}
platforms = (cl_platform_id*)x264_malloc( sizeof(cl_platform_id) * numPlatforms );
if( !platforms )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: malloc of installed platforms buffer failed\n" );
goto fail;
}
status = ocl->clGetPlatformIDs( numPlatforms, platforms, NULL );
if( status != CL_SUCCESS )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to query installed platforms\n" );
goto fail;
}
/* Select the first OpenCL platform with a GPU device that supports our
* required image (texture) formats */
for( cl_uint i = 0; i < numPlatforms; i++ )
{
cl_uint gpu_count = 0;
status = ocl->clGetDeviceIDs( platforms[i], CL_DEVICE_TYPE_GPU, 0, NULL, &gpu_count );
if( status != CL_SUCCESS || !gpu_count )
continue;
x264_free( devices );
devices = x264_malloc( sizeof(cl_device_id) * gpu_count );
if( !devices )
continue;
status = ocl->clGetDeviceIDs( platforms[i], CL_DEVICE_TYPE_GPU, gpu_count, devices, NULL );
if( status != CL_SUCCESS )
continue;
/* Find a GPU device that supports our image formats */
for( cl_uint gpu = 0; gpu < gpu_count; gpu++ )
{
h->opencl.device = devices[gpu];
/* if the user has specified an exact device ID, skip all other
* GPUs. If this device matches, allow it to continue through the
* checks for supported images, etc. */
if( h->param.opencl_device_id && devices[gpu] != (cl_device_id)h->param.opencl_device_id )
continue;
cl_bool image_support = 0;
status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL );
if( status != CL_SUCCESS || !image_support )
continue;
if( context )
ocl->clReleaseContext( context );
context = ocl->clCreateContext( NULL, 1, &h->opencl.device, (void*)x264_opencl_error_notify, (void*)h, &status );
if( status != CL_SUCCESS || !context )
continue;
cl_uint imagecount = 0;
status = ocl->clGetSupportedImageFormats( context, CL_MEM_READ_WRITE, CL_MEM_OBJECT_IMAGE2D, 0, NULL, &imagecount );
if( status != CL_SUCCESS || !imagecount )
continue;
x264_free( imageType );
imageType = x264_malloc( sizeof(cl_image_format) * imagecount );
if( !imageType )
continue;
status = ocl->clGetSupportedImageFormats( context, CL_MEM_READ_WRITE, CL_MEM_OBJECT_IMAGE2D, imagecount, imageType, NULL );
if( status != CL_SUCCESS )
continue;
int b_has_r = 0;
int b_has_rgba = 0;
for( cl_uint j = 0; j < imagecount; j++ )
{
if( imageType[j].image_channel_order == CL_R &&
imageType[j].image_channel_data_type == CL_UNSIGNED_INT32 )
b_has_r = 1;
else if( imageType[j].image_channel_order == CL_RGBA &&
imageType[j].image_channel_data_type == CL_UNSIGNED_INT8 )
b_has_rgba = 1;
}
if( !b_has_r || !b_has_rgba )
{
char dev_name[64];
status = ocl->clGetDeviceInfo( h->opencl.device, CL_DEVICE_NAME, sizeof(dev_name), dev_name, NULL );
if( status == CL_SUCCESS )
{
/* emit warning if we are discarding the user's explicit choice */
int level = h->param.opencl_device_id ? X264_LOG_WARNING : X264_LOG_DEBUG;
x264_log( h, level, "OpenCL: %s does not support required image formats\n", dev_name );
}
continue;
}
/* user selection of GPU device, skip N first matches */
if( h->param.i_opencl_device )
{
h->param.i_opencl_device--;
continue;
}
h->opencl.queue = ocl->clCreateCommandQueue( context, h->opencl.device, 0, &status );
if( status != CL_SUCCESS || !h->opencl.queue )
continue;
h->opencl.context = context;
context = NULL;
ret = 0;
break;
}
if( !ret )
break;
}
if( !h->param.psz_clbin_file )
h->param.psz_clbin_file = "x264_lookahead.clbin";
if( ret )
x264_log( h, X264_LOG_WARNING, "OpenCL: Unable to find a compatible device\n" );
else
ret = x264_opencl_lookahead_alloc( h );
fail:
if( context )
ocl->clReleaseContext( context );
x264_free( imageType );
x264_free( devices );
x264_free( platforms );
return ret;
}
static void x264_opencl_lookahead_free( x264_t *h )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
#define RELEASE( a, f ) do { if( a ) { ocl->f( a ); a = NULL; } } while( 0 )
RELEASE( h->opencl.downscale_hpel_kernel, clReleaseKernel );
RELEASE( h->opencl.downscale_kernel1, clReleaseKernel );
RELEASE( h->opencl.downscale_kernel2, clReleaseKernel );
RELEASE( h->opencl.weightp_hpel_kernel, clReleaseKernel );
RELEASE( h->opencl.weightp_scaled_images_kernel, clReleaseKernel );
RELEASE( h->opencl.memset_kernel, clReleaseKernel );
RELEASE( h->opencl.intra_kernel, clReleaseKernel );
RELEASE( h->opencl.rowsum_intra_kernel, clReleaseKernel );
RELEASE( h->opencl.hme_kernel, clReleaseKernel );
RELEASE( h->opencl.subpel_refine_kernel, clReleaseKernel );
RELEASE( h->opencl.mode_select_kernel, clReleaseKernel );
RELEASE( h->opencl.rowsum_inter_kernel, clReleaseKernel );
RELEASE( h->opencl.lookahead_program, clReleaseProgram );
RELEASE( h->opencl.page_locked_buffer, clReleaseMemObject );
RELEASE( h->opencl.luma_16x16_image[0], clReleaseMemObject );
RELEASE( h->opencl.luma_16x16_image[1], clReleaseMemObject );
for( int i = 0; i < NUM_IMAGE_SCALES; i++ )
RELEASE( h->opencl.weighted_scaled_images[i], clReleaseMemObject );
RELEASE( h->opencl.weighted_luma_hpel, clReleaseMemObject );
RELEASE( h->opencl.row_satds[0], clReleaseMemObject );
RELEASE( h->opencl.row_satds[1], clReleaseMemObject );
RELEASE( h->opencl.mv_buffers[0], clReleaseMemObject );
RELEASE( h->opencl.mv_buffers[1], clReleaseMemObject );
RELEASE( h->opencl.lowres_mv_costs, clReleaseMemObject );
RELEASE( h->opencl.mvp_buffer, clReleaseMemObject );
RELEASE( h->opencl.lowres_costs[0], clReleaseMemObject );
RELEASE( h->opencl.lowres_costs[1], clReleaseMemObject );
RELEASE( h->opencl.frame_stats[0], clReleaseMemObject );
RELEASE( h->opencl.frame_stats[1], clReleaseMemObject );
#undef RELEASE
}
void x264_opencl_lookahead_delete( x264_t *h )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
if( !ocl )
return;
if( h->opencl.queue )
ocl->clFinish( h->opencl.queue );
x264_opencl_lookahead_free( h );
if( h->opencl.queue )
{
ocl->clReleaseCommandQueue( h->opencl.queue );
h->opencl.queue = NULL;
}
if( h->opencl.context )
{
ocl->clReleaseContext( h->opencl.context );
h->opencl.context = NULL;
}
}
void x264_opencl_frame_delete( x264_frame_t *frame )
{
x264_opencl_function_t *ocl = frame->opencl.ocl;
if( !ocl )
return;
#define RELEASEBUF(mem) do { if( mem ) { ocl->clReleaseMemObject( mem ); mem = NULL; } } while( 0 )
for( int j = 0; j < NUM_IMAGE_SCALES; j++ )
RELEASEBUF( frame->opencl.scaled_image2Ds[j] );
RELEASEBUF( frame->opencl.luma_hpel );
RELEASEBUF( frame->opencl.inv_qscale_factor );
RELEASEBUF( frame->opencl.intra_cost );
RELEASEBUF( frame->opencl.lowres_mvs0 );
RELEASEBUF( frame->opencl.lowres_mvs1 );
RELEASEBUF( frame->opencl.lowres_mv_costs0 );
RELEASEBUF( frame->opencl.lowres_mv_costs1 );
#undef RELEASEBUF
}
/* OpenCL misbehaves on hybrid laptops with Intel iGPU and AMD dGPU, so
* we consult AMD's ADL interface to detect this situation and disable
* OpenCL on these machines (Linux and Windows) */
#ifdef _WIN32
#define ADL_API_CALL
#define ADL_CALLBACK __stdcall
#define adl_close FreeLibrary
#define adl_address GetProcAddress
#else
#define ADL_API_CALL
#define ADL_CALLBACK
#define adl_close dlclose
#define adl_address dlsym
#endif
typedef void* ( ADL_CALLBACK *ADL_MAIN_MALLOC_CALLBACK )( int );
typedef int ( ADL_API_CALL *ADL_MAIN_CONTROL_CREATE )( ADL_MAIN_MALLOC_CALLBACK, int );
typedef int ( ADL_API_CALL *ADL_ADAPTER_NUMBEROFADAPTERS_GET )( int * );
typedef int ( ADL_API_CALL *ADL_POWERXPRESS_SCHEME_GET )( int, int *, int *, int * );
typedef int ( ADL_API_CALL *ADL_MAIN_CONTROL_DESTROY )( void );
#define ADL_OK 0
#define ADL_PX_SCHEME_DYNAMIC 2
static void* ADL_CALLBACK adl_malloc_wrapper( int iSize )
{
return x264_malloc( iSize );
}
static int x264_detect_switchable_graphics( void )
{
void *hDLL;
ADL_MAIN_CONTROL_CREATE ADL_Main_Control_Create;
ADL_ADAPTER_NUMBEROFADAPTERS_GET ADL_Adapter_NumberOfAdapters_Get;
ADL_POWERXPRESS_SCHEME_GET ADL_PowerXpress_Scheme_Get;
ADL_MAIN_CONTROL_DESTROY ADL_Main_Control_Destroy;
int ret = 0;
#ifdef _WIN32
hDLL = LoadLibraryW( L"atiadlxx.dll" );
if( !hDLL )
hDLL = LoadLibraryW( L"atiadlxy.dll" );
#else
hDLL = dlopen( "libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL );
#endif
if( !hDLL )
goto fail0;
ADL_Main_Control_Create = (ADL_MAIN_CONTROL_CREATE)adl_address(hDLL, "ADL_Main_Control_Create");
ADL_Main_Control_Destroy = (ADL_MAIN_CONTROL_DESTROY)adl_address(hDLL, "ADL_Main_Control_Destroy");
ADL_Adapter_NumberOfAdapters_Get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)adl_address(hDLL, "ADL_Adapter_NumberOfAdapters_Get");
ADL_PowerXpress_Scheme_Get = (ADL_POWERXPRESS_SCHEME_GET)adl_address(hDLL, "ADL_PowerXpress_Scheme_Get");
if( !ADL_Main_Control_Create || !ADL_Main_Control_Destroy || !ADL_Adapter_NumberOfAdapters_Get ||
!ADL_PowerXpress_Scheme_Get )
goto fail1;
if( ADL_OK != ADL_Main_Control_Create( adl_malloc_wrapper, 1 ) )
goto fail1;
int numAdapters = 0;
if( ADL_OK != ADL_Adapter_NumberOfAdapters_Get( &numAdapters ) )
goto fail2;
for( int i = 0; i < numAdapters; i++ )
{
int PXSchemeRange, PXSchemeCurrentState, PXSchemeDefaultState;
if( ADL_OK != ADL_PowerXpress_Scheme_Get( i, &PXSchemeRange, &PXSchemeCurrentState, &PXSchemeDefaultState) )
break;
if( PXSchemeRange >= ADL_PX_SCHEME_DYNAMIC )
{
ret = 1;
break;
}
}
fail2:
ADL_Main_Control_Destroy();
fail1:
adl_close( hDLL );
fail0:
return ret;
}

View file

@ -0,0 +1,804 @@
/*****************************************************************************
* opencl.h: OpenCL structures and defines
*****************************************************************************
* Copyright (C) 2012-2017 x264 project
*
* Authors: Steve Borho <sborho@multicorewareinc.com>
* Anton Mitrofanov <BugMaster@narod.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_OPENCL_H
#define X264_OPENCL_H
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
#include "extras/cl.h"
#define OCL_API(ret, attr, name) typedef ret (attr *name##_func)
/* Platform API */
OCL_API(cl_int, CL_API_CALL, clGetPlatformIDs)
( cl_uint /* num_entries */,
cl_platform_id * /* platforms */,
cl_uint * /* num_platforms */);
OCL_API(cl_int, CL_API_CALL, clGetPlatformInfo)
( cl_platform_id /* platform */,
cl_platform_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Device APIs */
OCL_API(cl_int, CL_API_CALL, clGetDeviceIDs)
( cl_platform_id /* platform */,
cl_device_type /* device_type */,
cl_uint /* num_entries */,
cl_device_id * /* devices */,
cl_uint * /* num_devices */);
OCL_API(cl_int, CL_API_CALL, clGetDeviceInfo)
( cl_device_id /* device */,
cl_device_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_int, CL_API_CALL, clCreateSubDevices)
( cl_device_id /* in_device */,
const cl_device_partition_property * /* properties */,
cl_uint /* num_devices */,
cl_device_id * /* out_devices */,
cl_uint * /* num_devices_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainDevice)
( cl_device_id /* device */);
OCL_API(cl_int, CL_API_CALL, clReleaseDevice)
( cl_device_id /* device */);
/* Context APIs */
OCL_API(cl_context, CL_API_CALL, clCreateContext)
( const cl_context_properties * /* properties */,
cl_uint /* num_devices */,
const cl_device_id * /* devices */,
void (CL_CALLBACK * /* pfn_notify */)(const char *, const void *, size_t, void *),
void * /* user_data */,
cl_int * /* errcode_ret */);
OCL_API(cl_context, CL_API_CALL, clCreateContextFromType)
( const cl_context_properties * /* properties */,
cl_device_type /* device_type */,
void (CL_CALLBACK * /* pfn_notify*/ )(const char *, const void *, size_t, void *),
void * /* user_data */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainContext)
( cl_context /* context */);
OCL_API(cl_int, CL_API_CALL, clReleaseContext)
( cl_context /* context */);
OCL_API(cl_int, CL_API_CALL, clGetContextInfo)
( cl_context /* context */,
cl_context_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Command Queue APIs */
OCL_API(cl_command_queue, CL_API_CALL, clCreateCommandQueue)
( cl_context /* context */,
cl_device_id /* device */,
cl_command_queue_properties /* properties */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainCommandQueue)
( cl_command_queue /* command_queue */);
OCL_API(cl_int, CL_API_CALL, clReleaseCommandQueue)
( cl_command_queue /* command_queue */);
OCL_API(cl_int, CL_API_CALL, clGetCommandQueueInfo)
( cl_command_queue /* command_queue */,
cl_command_queue_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Memory Object APIs */
OCL_API(cl_mem, CL_API_CALL, clCreateBuffer)
( cl_context /* context */,
cl_mem_flags /* flags */,
size_t /* size */,
void * /* host_ptr */,
cl_int * /* errcode_ret */);
OCL_API(cl_mem, CL_API_CALL, clCreateSubBuffer)
( cl_mem /* buffer */,
cl_mem_flags /* flags */,
cl_buffer_create_type /* buffer_create_type */,
const void * /* buffer_create_info */,
cl_int * /* errcode_ret */);
OCL_API(cl_mem, CL_API_CALL, clCreateImage)
( cl_context /* context */,
cl_mem_flags /* flags */,
const cl_image_format * /* image_format */,
const cl_image_desc * /* image_desc */,
void * /* host_ptr */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainMemObject)
( cl_mem /* memobj */);
OCL_API(cl_int, CL_API_CALL, clReleaseMemObject)
( cl_mem /* memobj */);
OCL_API(cl_int, CL_API_CALL, clGetSupportedImageFormats)
( cl_context /* context */,
cl_mem_flags /* flags */,
cl_mem_object_type /* image_type */,
cl_uint /* num_entries */,
cl_image_format * /* image_formats */,
cl_uint * /* num_image_formats */);
OCL_API(cl_int, CL_API_CALL, clGetMemObjectInfo)
( cl_mem /* memobj */,
cl_mem_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_int, CL_API_CALL, clGetImageInfo)
( cl_mem /* image */,
cl_image_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_int, CL_API_CALL, clSetMemObjectDestructorCallback)
( cl_mem /* memobj */,
void (CL_CALLBACK * /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/),
void * /*user_data */ );
/* Sampler APIs */
OCL_API(cl_sampler, CL_API_CALL, clCreateSampler)
( cl_context /* context */,
cl_bool /* normalized_coords */,
cl_addressing_mode /* addressing_mode */,
cl_filter_mode /* filter_mode */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainSampler)
( cl_sampler /* sampler */);
OCL_API(cl_int, CL_API_CALL, clReleaseSampler)
( cl_sampler /* sampler */);
OCL_API(cl_int, CL_API_CALL, clGetSamplerInfo)
( cl_sampler /* sampler */,
cl_sampler_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Program Object APIs */
OCL_API(cl_program, CL_API_CALL, clCreateProgramWithSource)
( cl_context /* context */,
cl_uint /* count */,
const char ** /* strings */,
const size_t * /* lengths */,
cl_int * /* errcode_ret */);
OCL_API(cl_program, CL_API_CALL, clCreateProgramWithBinary)
( cl_context /* context */,
cl_uint /* num_devices */,
const cl_device_id * /* device_list */,
const size_t * /* lengths */,
const unsigned char ** /* binaries */,
cl_int * /* binary_status */,
cl_int * /* errcode_ret */);
OCL_API(cl_program, CL_API_CALL, clCreateProgramWithBuiltInKernels)
( cl_context /* context */,
cl_uint /* num_devices */,
const cl_device_id * /* device_list */,
const char * /* kernel_names */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainProgram)
( cl_program /* program */);
OCL_API(cl_int, CL_API_CALL, clReleaseProgram)
( cl_program /* program */);
OCL_API(cl_int, CL_API_CALL, clBuildProgram)
( cl_program /* program */,
cl_uint /* num_devices */,
const cl_device_id * /* device_list */,
const char * /* options */,
void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */),
void * /* user_data */);
OCL_API(cl_int, CL_API_CALL, clCompileProgram)
( cl_program /* program */,
cl_uint /* num_devices */,
const cl_device_id * /* device_list */,
const char * /* options */,
cl_uint /* num_input_headers */,
const cl_program * /* input_headers */,
const char ** /* header_include_names */,
void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */),
void * /* user_data */);
OCL_API(cl_program, CL_API_CALL, clLinkProgram)
( cl_context /* context */,
cl_uint /* num_devices */,
const cl_device_id * /* device_list */,
const char * /* options */,
cl_uint /* num_input_programs */,
const cl_program * /* input_programs */,
void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */),
void * /* user_data */,
cl_int * /* errcode_ret */ );
OCL_API(cl_int, CL_API_CALL, clUnloadPlatformCompiler)
( cl_platform_id /* platform */);
OCL_API(cl_int, CL_API_CALL, clGetProgramInfo)
( cl_program /* program */,
cl_program_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_int, CL_API_CALL, clGetProgramBuildInfo)
( cl_program /* program */,
cl_device_id /* device */,
cl_program_build_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Kernel Object APIs */
OCL_API(cl_kernel, CL_API_CALL, clCreateKernel)
( cl_program /* program */,
const char * /* kernel_name */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clCreateKernelsInProgram)
( cl_program /* program */,
cl_uint /* num_kernels */,
cl_kernel * /* kernels */,
cl_uint * /* num_kernels_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainKernel)
( cl_kernel /* kernel */);
OCL_API(cl_int, CL_API_CALL, clReleaseKernel)
( cl_kernel /* kernel */);
OCL_API(cl_int, CL_API_CALL, clSetKernelArg)
( cl_kernel /* kernel */,
cl_uint /* arg_index */,
size_t /* arg_size */,
const void * /* arg_value */);
OCL_API(cl_int, CL_API_CALL, clGetKernelInfo)
( cl_kernel /* kernel */,
cl_kernel_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_int, CL_API_CALL, clGetKernelArgInfo)
( cl_kernel /* kernel */,
cl_uint /* arg_indx */,
cl_kernel_arg_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_int, CL_API_CALL, clGetKernelWorkGroupInfo)
( cl_kernel /* kernel */,
cl_device_id /* device */,
cl_kernel_work_group_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Event Object APIs */
OCL_API(cl_int, CL_API_CALL, clWaitForEvents)
( cl_uint /* num_events */,
const cl_event * /* event_list */);
OCL_API(cl_int, CL_API_CALL, clGetEventInfo)
( cl_event /* event */,
cl_event_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
OCL_API(cl_event, CL_API_CALL, clCreateUserEvent)
( cl_context /* context */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clRetainEvent)
( cl_event /* event */);
OCL_API(cl_int, CL_API_CALL, clReleaseEvent)
( cl_event /* event */);
OCL_API(cl_int, CL_API_CALL, clSetUserEventStatus)
( cl_event /* event */,
cl_int /* execution_status */);
OCL_API(cl_int, CL_API_CALL, clSetEventCallback)
( cl_event /* event */,
cl_int /* command_exec_callback_type */,
void (CL_CALLBACK * /* pfn_notify */)(cl_event, cl_int, void *),
void * /* user_data */);
/* Profiling APIs */
OCL_API(cl_int, CL_API_CALL, clGetEventProfilingInfo)
( cl_event /* event */,
cl_profiling_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */);
/* Flush and Finish APIs */
OCL_API(cl_int, CL_API_CALL, clFlush)
( cl_command_queue /* command_queue */);
OCL_API(cl_int, CL_API_CALL, clFinish)
( cl_command_queue /* command_queue */);
/* Enqueued Commands APIs */
OCL_API(cl_int, CL_API_CALL, clEnqueueReadBuffer)
( cl_command_queue /* command_queue */,
cl_mem /* buffer */,
cl_bool /* blocking_read */,
size_t /* offset */,
size_t /* size */,
void * /* ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueReadBufferRect)
( cl_command_queue /* command_queue */,
cl_mem /* buffer */,
cl_bool /* blocking_read */,
const size_t * /* buffer_offset */,
const size_t * /* host_offset */,
const size_t * /* region */,
size_t /* buffer_row_pitch */,
size_t /* buffer_slice_pitch */,
size_t /* host_row_pitch */,
size_t /* host_slice_pitch */,
void * /* ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueWriteBuffer)
( cl_command_queue /* command_queue */,
cl_mem /* buffer */,
cl_bool /* blocking_write */,
size_t /* offset */,
size_t /* size */,
const void * /* ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueWriteBufferRect)
( cl_command_queue /* command_queue */,
cl_mem /* buffer */,
cl_bool /* blocking_write */,
const size_t * /* buffer_offset */,
const size_t * /* host_offset */,
const size_t * /* region */,
size_t /* buffer_row_pitch */,
size_t /* buffer_slice_pitch */,
size_t /* host_row_pitch */,
size_t /* host_slice_pitch */,
const void * /* ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueFillBuffer)
( cl_command_queue /* command_queue */,
cl_mem /* buffer */,
const void * /* pattern */,
size_t /* pattern_size */,
size_t /* offset */,
size_t /* size */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueCopyBuffer)
( cl_command_queue /* command_queue */,
cl_mem /* src_buffer */,
cl_mem /* dst_buffer */,
size_t /* src_offset */,
size_t /* dst_offset */,
size_t /* size */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueCopyBufferRect)
( cl_command_queue /* command_queue */,
cl_mem /* src_buffer */,
cl_mem /* dst_buffer */,
const size_t * /* src_origin */,
const size_t * /* dst_origin */,
const size_t * /* region */,
size_t /* src_row_pitch */,
size_t /* src_slice_pitch */,
size_t /* dst_row_pitch */,
size_t /* dst_slice_pitch */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueReadImage)
( cl_command_queue /* command_queue */,
cl_mem /* image */,
cl_bool /* blocking_read */,
const size_t * /* origin[3] */,
const size_t * /* region[3] */,
size_t /* row_pitch */,
size_t /* slice_pitch */,
void * /* ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueWriteImage)
( cl_command_queue /* command_queue */,
cl_mem /* image */,
cl_bool /* blocking_write */,
const size_t * /* origin[3] */,
const size_t * /* region[3] */,
size_t /* input_row_pitch */,
size_t /* input_slice_pitch */,
const void * /* ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueFillImage)
( cl_command_queue /* command_queue */,
cl_mem /* image */,
const void * /* fill_color */,
const size_t * /* origin[3] */,
const size_t * /* region[3] */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueCopyImage)
( cl_command_queue /* command_queue */,
cl_mem /* src_image */,
cl_mem /* dst_image */,
const size_t * /* src_origin[3] */,
const size_t * /* dst_origin[3] */,
const size_t * /* region[3] */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueCopyImageToBuffer)
( cl_command_queue /* command_queue */,
cl_mem /* src_image */,
cl_mem /* dst_buffer */,
const size_t * /* src_origin[3] */,
const size_t * /* region[3] */,
size_t /* dst_offset */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueCopyBufferToImage)
( cl_command_queue /* command_queue */,
cl_mem /* src_buffer */,
cl_mem /* dst_image */,
size_t /* src_offset */,
const size_t * /* dst_origin[3] */,
const size_t * /* region[3] */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(void *, CL_API_CALL, clEnqueueMapBuffer)
( cl_command_queue /* command_queue */,
cl_mem /* buffer */,
cl_bool /* blocking_map */,
cl_map_flags /* map_flags */,
size_t /* offset */,
size_t /* size */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */,
cl_int * /* errcode_ret */);
OCL_API(void *, CL_API_CALL, clEnqueueMapImage)
( cl_command_queue /* command_queue */,
cl_mem /* image */,
cl_bool /* blocking_map */,
cl_map_flags /* map_flags */,
const size_t * /* origin[3] */,
const size_t * /* region[3] */,
size_t * /* image_row_pitch */,
size_t * /* image_slice_pitch */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clEnqueueUnmapMemObject)
( cl_command_queue /* command_queue */,
cl_mem /* memobj */,
void * /* mapped_ptr */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueMigrateMemObjects)
( cl_command_queue /* command_queue */,
cl_uint /* num_mem_objects */,
const cl_mem * /* mem_objects */,
cl_mem_migration_flags /* flags */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueNDRangeKernel)
( cl_command_queue /* command_queue */,
cl_kernel /* kernel */,
cl_uint /* work_dim */,
const size_t * /* global_work_offset */,
const size_t * /* global_work_size */,
const size_t * /* local_work_size */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueTask)
( cl_command_queue /* command_queue */,
cl_kernel /* kernel */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueNativeKernel)
( cl_command_queue /* command_queue */,
void (CL_CALLBACK * /*user_func*/)(void *),
void * /* args */,
size_t /* cb_args */,
cl_uint /* num_mem_objects */,
const cl_mem * /* mem_list */,
const void ** /* args_mem_loc */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueMarkerWithWaitList)
( cl_command_queue /* command_queue */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueBarrierWithWaitList)
( cl_command_queue /* command_queue */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */);
/* Extension function access
*
* Returns the extension function address for the given function name,
* or NULL if a valid function can not be found. The client must
* check to make sure the address is not NULL, before using or
* calling the returned function address.
*/
OCL_API(void *, CL_API_CALL, clGetExtensionFunctionAddressForPlatform)
( cl_platform_id /* platform */,
const char * /* func_name */);
// Deprecated OpenCL 1.1 APIs
OCL_API(cl_mem, CL_API_CALL, clCreateImage2D)
( cl_context /* context */,
cl_mem_flags /* flags */,
const cl_image_format * /* image_format */,
size_t /* image_width */,
size_t /* image_height */,
size_t /* image_row_pitch */,
void * /* host_ptr */,
cl_int * /* errcode_ret */);
OCL_API(cl_mem, CL_API_CALL, clCreateImage3D)
( cl_context /* context */,
cl_mem_flags /* flags */,
const cl_image_format * /* image_format */,
size_t /* image_width */,
size_t /* image_height */,
size_t /* image_depth */,
size_t /* image_row_pitch */,
size_t /* image_slice_pitch */,
void * /* host_ptr */,
cl_int * /* errcode_ret */);
OCL_API(cl_int, CL_API_CALL, clEnqueueMarker)
( cl_command_queue /* command_queue */,
cl_event * /* event */);
OCL_API(cl_int, CL_API_CALL, clEnqueueWaitForEvents)
( cl_command_queue /* command_queue */,
cl_uint /* num_events */,
const cl_event * /* event_list */);
OCL_API(cl_int, CL_API_CALL, clEnqueueBarrier)
( cl_command_queue /* command_queue */);
OCL_API(cl_int, CL_API_CALL, clUnloadCompiler)
( void);
OCL_API(void *, CL_API_CALL, clGetExtensionFunctionAddress)
( const char * /* func_name */);
#define OCL_DECLARE_FUNC(name) name##_func name
typedef struct
{
void *library;
OCL_DECLARE_FUNC( clBuildProgram );
OCL_DECLARE_FUNC( clCreateBuffer );
OCL_DECLARE_FUNC( clCreateCommandQueue );
OCL_DECLARE_FUNC( clCreateContext );
OCL_DECLARE_FUNC( clCreateImage2D );
OCL_DECLARE_FUNC( clCreateKernel );
OCL_DECLARE_FUNC( clCreateProgramWithBinary );
OCL_DECLARE_FUNC( clCreateProgramWithSource );
OCL_DECLARE_FUNC( clEnqueueCopyBuffer );
OCL_DECLARE_FUNC( clEnqueueMapBuffer );
OCL_DECLARE_FUNC( clEnqueueNDRangeKernel );
OCL_DECLARE_FUNC( clEnqueueReadBuffer );
OCL_DECLARE_FUNC( clEnqueueWriteBuffer );
OCL_DECLARE_FUNC( clFinish );
OCL_DECLARE_FUNC( clGetCommandQueueInfo );
OCL_DECLARE_FUNC( clGetDeviceIDs );
OCL_DECLARE_FUNC( clGetDeviceInfo );
OCL_DECLARE_FUNC( clGetKernelWorkGroupInfo );
OCL_DECLARE_FUNC( clGetPlatformIDs );
OCL_DECLARE_FUNC( clGetProgramBuildInfo );
OCL_DECLARE_FUNC( clGetProgramInfo );
OCL_DECLARE_FUNC( clGetSupportedImageFormats );
OCL_DECLARE_FUNC( clReleaseCommandQueue );
OCL_DECLARE_FUNC( clReleaseContext );
OCL_DECLARE_FUNC( clReleaseKernel );
OCL_DECLARE_FUNC( clReleaseMemObject );
OCL_DECLARE_FUNC( clReleaseProgram );
OCL_DECLARE_FUNC( clSetKernelArg );
} x264_opencl_function_t;
/* Number of downscale resolutions to use for motion search */
#define NUM_IMAGE_SCALES 4
/* Number of PCIe copies that can be queued before requiring a flush */
#define MAX_FINISH_COPIES 1024
/* Size (in bytes) of the page-locked buffer used for PCIe xfers */
#define PAGE_LOCKED_BUF_SIZE 32 * 1024 * 1024
typedef struct
{
x264_opencl_function_t *ocl;
cl_context context;
cl_device_id device;
cl_command_queue queue;
cl_program lookahead_program;
cl_int last_buf;
cl_mem page_locked_buffer;
char *page_locked_ptr;
int pl_occupancy;
struct
{
void *src;
void *dest;
int bytes;
} copies[MAX_FINISH_COPIES];
int num_copies;
int b_device_AMD_SI;
int b_fatal_error;
int lookahead_thread_pri;
int opencl_thread_pri;
/* downscale lowres luma */
cl_kernel downscale_hpel_kernel;
cl_kernel downscale_kernel1;
cl_kernel downscale_kernel2;
cl_mem luma_16x16_image[2];
/* weightp filtering */
cl_kernel weightp_hpel_kernel;
cl_kernel weightp_scaled_images_kernel;
cl_mem weighted_scaled_images[NUM_IMAGE_SCALES];
cl_mem weighted_luma_hpel;
/* intra */
cl_kernel memset_kernel;
cl_kernel intra_kernel;
cl_kernel rowsum_intra_kernel;
cl_mem row_satds[2];
/* hierarchical motion estimation */
cl_kernel hme_kernel;
cl_kernel subpel_refine_kernel;
cl_mem mv_buffers[2];
cl_mem lowres_mv_costs;
cl_mem mvp_buffer;
/* bidir */
cl_kernel mode_select_kernel;
cl_kernel rowsum_inter_kernel;
cl_mem lowres_costs[2];
cl_mem frame_stats[2]; /* cost_est, cost_est_aq, intra_mbs */
} x264_opencl_t;
typedef struct
{
x264_opencl_function_t *ocl;
cl_mem scaled_image2Ds[NUM_IMAGE_SCALES];
cl_mem luma_hpel;
cl_mem inv_qscale_factor;
cl_mem intra_cost;
cl_mem lowres_mvs0;
cl_mem lowres_mvs1;
cl_mem lowres_mv_costs0;
cl_mem lowres_mv_costs1;
} x264_frame_opencl_t;
typedef struct x264_frame x264_frame;
x264_opencl_function_t *x264_opencl_load_library( void );
void x264_opencl_close_library( x264_opencl_function_t *ocl );
int x264_opencl_lookahead_init( x264_t *h );
void x264_opencl_lookahead_delete( x264_t *h );
void x264_opencl_frame_delete( x264_frame *frame );
#endif

View file

@ -0,0 +1,206 @@
/*****************************************************************************
* osdep.c: platform-specific code
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Steven Walters <kemuri9@gmail.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#endif
#if SYS_WINDOWS
#include <sys/types.h>
#include <sys/timeb.h>
#else
#include <sys/time.h>
#endif
#include <time.h>
#if PTW32_STATIC_LIB
/* this is a global in pthread-win32 to indicate if it has been initialized or not */
extern int ptw32_processInitialized;
#endif
int64_t x264_mdate( void )
{
#if SYS_WINDOWS
struct timeb tb;
ftime( &tb );
return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000;
#else
struct timeval tv_date;
gettimeofday( &tv_date, NULL );
return (int64_t)tv_date.tv_sec * 1000000 + (int64_t)tv_date.tv_usec;
#endif
}
#if HAVE_WIN32THREAD || PTW32_STATIC_LIB
/* state of the threading library being initialized */
static volatile LONG x264_threading_is_init = 0;
static void x264_threading_destroy( void )
{
#if PTW32_STATIC_LIB
pthread_win32_thread_detach_np();
pthread_win32_process_detach_np();
#else
x264_win32_threading_destroy();
#endif
}
int x264_threading_init( void )
{
/* if already init, then do nothing */
if( InterlockedCompareExchange( &x264_threading_is_init, 1, 0 ) )
return 0;
#if PTW32_STATIC_LIB
/* if static pthread-win32 is already initialized, then do nothing */
if( ptw32_processInitialized )
return 0;
if( !pthread_win32_process_attach_np() )
return -1;
#else
if( x264_win32_threading_init() )
return -1;
#endif
/* register cleanup to run at process termination */
atexit( x264_threading_destroy );
return 0;
}
#endif
#ifdef _WIN32
/* Functions for dealing with Unicode on Windows. */
FILE *x264_fopen( const char *filename, const char *mode )
{
wchar_t filename_utf16[MAX_PATH];
wchar_t mode_utf16[16];
if( utf8_to_utf16( filename, filename_utf16 ) && utf8_to_utf16( mode, mode_utf16 ) )
return _wfopen( filename_utf16, mode_utf16 );
return NULL;
}
int x264_rename( const char *oldname, const char *newname )
{
wchar_t oldname_utf16[MAX_PATH];
wchar_t newname_utf16[MAX_PATH];
if( utf8_to_utf16( oldname, oldname_utf16 ) && utf8_to_utf16( newname, newname_utf16 ) )
{
/* POSIX says that rename() removes the destination, but Win32 doesn't. */
_wunlink( newname_utf16 );
return _wrename( oldname_utf16, newname_utf16 );
}
return -1;
}
int x264_stat( const char *path, x264_struct_stat *buf )
{
wchar_t path_utf16[MAX_PATH];
if( utf8_to_utf16( path, path_utf16 ) )
return _wstati64( path_utf16, buf );
return -1;
}
#if !HAVE_WINRT
int x264_vfprintf( FILE *stream, const char *format, va_list arg )
{
HANDLE console = NULL;
DWORD mode;
if( stream == stdout )
console = GetStdHandle( STD_OUTPUT_HANDLE );
else if( stream == stderr )
console = GetStdHandle( STD_ERROR_HANDLE );
/* Only attempt to convert to UTF-16 when writing to a non-redirected console screen buffer. */
if( GetConsoleMode( console, &mode ) )
{
char buf[4096];
wchar_t buf_utf16[4096];
va_list arg2;
va_copy( arg2, arg );
int length = vsnprintf( buf, sizeof(buf), format, arg2 );
va_end( arg2 );
if( length > 0 && length < sizeof(buf) )
{
/* WriteConsoleW is the most reliable way to output Unicode to a console. */
int length_utf16 = MultiByteToWideChar( CP_UTF8, 0, buf, length, buf_utf16, sizeof(buf_utf16)/sizeof(wchar_t) );
DWORD written;
WriteConsoleW( console, buf_utf16, length_utf16, &written, NULL );
return length;
}
}
return vfprintf( stream, format, arg );
}
int x264_is_pipe( const char *path )
{
wchar_t path_utf16[MAX_PATH];
if( utf8_to_utf16( path, path_utf16 ) )
return WaitNamedPipeW( path_utf16, 0 );
return 0;
}
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
/* MSVC pre-VS2015 has broken snprintf/vsnprintf implementations which are incompatible with C99. */
int x264_snprintf( char *s, size_t n, const char *fmt, ... )
{
va_list arg;
va_start( arg, fmt );
int length = x264_vsnprintf( s, n, fmt, arg );
va_end( arg );
return length;
}
int x264_vsnprintf( char *s, size_t n, const char *fmt, va_list arg )
{
int length = -1;
if( n )
{
va_list arg2;
va_copy( arg2, arg );
length = _vsnprintf( s, n, fmt, arg2 );
va_end( arg2 );
/* _(v)snprintf adds a null-terminator only if the length is less than the buffer size. */
if( length < 0 || length >= n )
s[n-1] = '\0';
}
/* _(v)snprintf returns a negative number if the length is greater than the buffer size. */
if( length < 0 )
return _vscprintf( fmt, arg );
return length;
}
#endif
#endif

View file

@ -0,0 +1,414 @@
/*****************************************************************************
* osdep.h: platform-specific code
*****************************************************************************
* Copyright (C) 2007-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_OSDEP_H
#define X264_OSDEP_H
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <stdarg.h>
//#include "config.h"
#ifdef __INTEL_COMPILER
#include <mathimf.h>
#else
#include <math.h>
#endif
#if !HAVE_LOG2F
#define log2f(x) (logf(x)/0.693147180559945f)
#define log2(x) (log(x)/0.693147180559945)
#endif
#ifdef _MSC_VER
#define inline __inline
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#define strtok_r strtok_s
#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
#if _MSC_VER < 1900
int x264_snprintf( char *s, size_t n, const char *fmt, ... );
int x264_vsnprintf( char *s, size_t n, const char *fmt, va_list arg );
#define snprintf x264_snprintf
#define vsnprintf x264_vsnprintf
#endif
#else
#include <strings.h>
#endif
#if !defined(va_copy) && defined(__INTEL_COMPILER)
#define va_copy(dst, src) ((dst) = (src))
#endif
#if !defined(isfinite) && (SYS_OPENBSD || SYS_SunOS)
#define isfinite finite
#endif
#ifdef _WIN32
#ifndef strtok_r
#define strtok_r(str,delim,save) strtok(str,delim)
#endif
#define utf8_to_utf16( utf8, utf16 )\
MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8, -1, utf16, sizeof(utf16)/sizeof(wchar_t) )
FILE *x264_fopen( const char *filename, const char *mode );
int x264_rename( const char *oldname, const char *newname );
#define x264_struct_stat struct _stati64
#define x264_fstat _fstati64
int x264_stat( const char *path, x264_struct_stat *buf );
#else
#define x264_fopen fopen
#define x264_rename rename
#define x264_struct_stat struct stat
#define x264_fstat fstat
#define x264_stat stat
#endif
/* mdate: return the current date in microsecond */
int64_t x264_mdate( void );
#if defined(_WIN32) && !HAVE_WINRT
int x264_vfprintf( FILE *stream, const char *format, va_list arg );
int x264_is_pipe( const char *path );
#else
#define x264_vfprintf vfprintf
#define x264_is_pipe(x) 0
#endif
#ifdef _MSC_VER
#define DECLARE_ALIGNED( var, n ) __declspec(align(n)) var
#else
#define DECLARE_ALIGNED( var, n ) var __attribute__((aligned(n)))
#endif
#define ALIGNED_4( var ) DECLARE_ALIGNED( var, 4 )
#define ALIGNED_8( var ) DECLARE_ALIGNED( var, 8 )
#define ALIGNED_16( var ) DECLARE_ALIGNED( var, 16 )
// ARM compiliers don't reliably align stack variables
// - EABI requires only 8 byte stack alignment to be maintained
// - gcc can't align stack variables to more even if the stack were to be correctly aligned outside the function
// - armcc can't either, but is nice enough to actually tell you so
// - Apple gcc only maintains 4 byte alignment
// - llvm can align the stack, but only in svn and (unrelated) it exposes bugs in all released GNU binutils...
#define ALIGNED_ARRAY_EMU( mask, type, name, sub1, ... )\
uint8_t name##_u [sizeof(type sub1 __VA_ARGS__) + mask]; \
type (*name) __VA_ARGS__ = (void*)((intptr_t)(name##_u+mask) & ~mask)
#if ARCH_ARM && SYS_MACOSX
#define ALIGNED_ARRAY_8( ... ) EXPAND( ALIGNED_ARRAY_EMU( 7, __VA_ARGS__ ) )
#else
#define ALIGNED_ARRAY_8( type, name, sub1, ... ) ALIGNED_8( type name sub1 __VA_ARGS__ )
#endif
#if ARCH_ARM
#define ALIGNED_ARRAY_16( ... ) EXPAND( ALIGNED_ARRAY_EMU( 15, __VA_ARGS__ ) )
#else
#define ALIGNED_ARRAY_16( type, name, sub1, ... ) ALIGNED_16( type name sub1 __VA_ARGS__ )
#endif
#define EXPAND(x) x
#if ARCH_X86 || ARCH_X86_64
#define NATIVE_ALIGN 64
#define ALIGNED_32( var ) DECLARE_ALIGNED( var, 32 )
#define ALIGNED_64( var ) DECLARE_ALIGNED( var, 64 )
#if STACK_ALIGNMENT >= 32
#define ALIGNED_ARRAY_32( type, name, sub1, ... ) ALIGNED_32( type name sub1 __VA_ARGS__ )
#else
#define ALIGNED_ARRAY_32( ... ) EXPAND( ALIGNED_ARRAY_EMU( 31, __VA_ARGS__ ) )
#endif
#if STACK_ALIGNMENT >= 64
#define ALIGNED_ARRAY_64( type, name, sub1, ... ) ALIGNED_64( type name sub1 __VA_ARGS__ )
#else
#define ALIGNED_ARRAY_64( ... ) EXPAND( ALIGNED_ARRAY_EMU( 63, __VA_ARGS__ ) )
#endif
#else
#define NATIVE_ALIGN 16
#define ALIGNED_32 ALIGNED_16
#define ALIGNED_64 ALIGNED_16
#define ALIGNED_ARRAY_32 ALIGNED_ARRAY_16
#define ALIGNED_ARRAY_64 ALIGNED_ARRAY_16
#endif
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
#define UNUSED __attribute__((unused))
#define ALWAYS_INLINE __attribute__((always_inline)) inline
#define NOINLINE __attribute__((noinline))
#define MAY_ALIAS __attribute__((may_alias))
#define x264_constant_p(x) __builtin_constant_p(x)
#define x264_nonconstant_p(x) (!__builtin_constant_p(x))
#else
#ifdef _MSC_VER
#define ALWAYS_INLINE __forceinline
#define NOINLINE __declspec(noinline)
#else
#define ALWAYS_INLINE inline
#define NOINLINE
#endif
#define UNUSED
#define MAY_ALIAS
#define x264_constant_p(x) 0
#define x264_nonconstant_p(x) 0
#endif
/* threads */
#if HAVE_BEOSTHREAD
#include <kernel/OS.h>
#define x264_pthread_t thread_id
static inline int x264_pthread_create( x264_pthread_t *t, void *a, void *(*f)(void *), void *d )
{
*t = spawn_thread( f, "", 10, d );
if( *t < B_NO_ERROR )
return -1;
resume_thread( *t );
return 0;
}
#define x264_pthread_join(t,s) { long tmp; \
wait_for_thread(t,(s)?(long*)(s):&tmp); }
#elif HAVE_POSIXTHREAD
#include <pthread.h>
#define x264_pthread_t pthread_t
#define x264_pthread_create pthread_create
#define x264_pthread_join pthread_join
#define x264_pthread_mutex_t pthread_mutex_t
#define x264_pthread_mutex_init pthread_mutex_init
#define x264_pthread_mutex_destroy pthread_mutex_destroy
#define x264_pthread_mutex_lock pthread_mutex_lock
#define x264_pthread_mutex_unlock pthread_mutex_unlock
#define x264_pthread_cond_t pthread_cond_t
#define x264_pthread_cond_init pthread_cond_init
#define x264_pthread_cond_destroy pthread_cond_destroy
#define x264_pthread_cond_broadcast pthread_cond_broadcast
#define x264_pthread_cond_wait pthread_cond_wait
#define x264_pthread_attr_t pthread_attr_t
#define x264_pthread_attr_init pthread_attr_init
#define x264_pthread_attr_destroy pthread_attr_destroy
#define x264_pthread_num_processors_np pthread_num_processors_np
#define X264_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif HAVE_WIN32THREAD
#include "win32thread.h"
#else
#define x264_pthread_t int
#define x264_pthread_create(t,u,f,d) 0
#define x264_pthread_join(t,s)
#endif //HAVE_*THREAD
#if !HAVE_POSIXTHREAD && !HAVE_WIN32THREAD
#define x264_pthread_mutex_t int
#define x264_pthread_mutex_init(m,f) 0
#define x264_pthread_mutex_destroy(m)
#define x264_pthread_mutex_lock(m)
#define x264_pthread_mutex_unlock(m)
#define x264_pthread_cond_t int
#define x264_pthread_cond_init(c,f) 0
#define x264_pthread_cond_destroy(c)
#define x264_pthread_cond_broadcast(c)
#define x264_pthread_cond_wait(c,m)
#define x264_pthread_attr_t int
#define x264_pthread_attr_init(a) 0
#define x264_pthread_attr_destroy(a)
#define X264_PTHREAD_MUTEX_INITIALIZER 0
#endif
#if HAVE_WIN32THREAD || PTW32_STATIC_LIB
int x264_threading_init( void );
#else
#define x264_threading_init() 0
#endif
static ALWAYS_INLINE int x264_pthread_fetch_and_add( int *val, int add, x264_pthread_mutex_t *mutex )
{
#if HAVE_THREAD
#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0) && (ARCH_X86 || ARCH_X86_64)
return __sync_fetch_and_add( val, add );
#else
x264_pthread_mutex_lock( mutex );
int res = *val;
*val += add;
x264_pthread_mutex_unlock( mutex );
return res;
#endif
#else
int res = *val;
*val += add;
return res;
#endif
}
#define WORD_SIZE sizeof(void*)
#define asm __asm__
#if WORDS_BIGENDIAN
#define endian_fix(x) (x)
#define endian_fix64(x) (x)
#define endian_fix32(x) (x)
#define endian_fix16(x) (x)
#else
#if HAVE_X86_INLINE_ASM && HAVE_MMX
static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x )
{
asm("bswap %0":"+r"(x));
return x;
}
#elif defined(__GNUC__) && HAVE_ARMV6
static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x )
{
asm("rev %0, %0":"+r"(x));
return x;
}
#else
static ALWAYS_INLINE uint32_t endian_fix32( uint32_t x )
{
return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24);
}
#endif
#if HAVE_X86_INLINE_ASM && ARCH_X86_64
static ALWAYS_INLINE uint64_t endian_fix64( uint64_t x )
{
asm("bswap %0":"+r"(x));
return x;
}
#else
static ALWAYS_INLINE uint64_t endian_fix64( uint64_t x )
{
return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32);
}
#endif
static ALWAYS_INLINE intptr_t endian_fix( intptr_t x )
{
return WORD_SIZE == 8 ? endian_fix64(x) : endian_fix32(x);
}
static ALWAYS_INLINE uint16_t endian_fix16( uint16_t x )
{
return (x<<8)|(x>>8);
}
#endif
/* For values with 4 bits or less. */
static int ALWAYS_INLINE x264_ctz_4bit( uint32_t x )
{
static uint8_t lut[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
return lut[x];
}
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 3)
#define x264_clz(x) __builtin_clz(x)
#define x264_ctz(x) __builtin_ctz(x)
#else
static int ALWAYS_INLINE x264_clz( uint32_t x )
{
static uint8_t lut[16] = {4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0};
int y, z = (((x >> 16) - 1) >> 27) & 16;
x >>= z^16;
z += y = ((x - 0x100) >> 28) & 8;
x >>= y^8;
z += y = ((x - 0x10) >> 29) & 4;
x >>= y^4;
return z + lut[x];
}
static int ALWAYS_INLINE x264_ctz( uint32_t x )
{
static uint8_t lut[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
int y, z = (((x & 0xffff) - 1) >> 27) & 16;
x >>= z;
z += y = (((x & 0xff) - 1) >> 28) & 8;
x >>= y;
z += y = (((x & 0xf) - 1) >> 29) & 4;
x >>= y;
return z + lut[x&0xf];
}
#endif
#if HAVE_X86_INLINE_ASM && HAVE_MMX
/* Don't use __builtin_prefetch; even as recent as 4.3.4, GCC seems incapable of
* using complex address modes properly unless we use inline asm. */
static ALWAYS_INLINE void x264_prefetch( void *p )
{
asm volatile( "prefetcht0 %0"::"m"(*(uint8_t*)p) );
}
/* We require that prefetch not fault on invalid reads, so we only enable it on
* known architectures. */
#elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 1) &&\
(ARCH_X86 || ARCH_X86_64 || ARCH_ARM || ARCH_PPC)
#define x264_prefetch(x) __builtin_prefetch(x)
#else
#define x264_prefetch(x)
#endif
#if HAVE_POSIXTHREAD
#if SYS_WINDOWS
#define x264_lower_thread_priority(p)\
{\
x264_pthread_t handle = pthread_self();\
struct sched_param sp;\
int policy = SCHED_OTHER;\
pthread_getschedparam( handle, &policy, &sp );\
sp.sched_priority -= p;\
pthread_setschedparam( handle, policy, &sp );\
}
#elif SYS_HAIKU
#include <OS.h>
#define x264_lower_thread_priority(p)\
{ UNUSED status_t nice_ret = set_thread_priority( find_thread( NULL ), B_LOW_PRIORITY ); }
#else
#include <unistd.h>
#define x264_lower_thread_priority(p) { UNUSED int nice_ret = nice(p); }
#endif /* SYS_WINDOWS */
#elif HAVE_WIN32THREAD
#define x264_lower_thread_priority(p) SetThreadPriority( GetCurrentThread(), X264_MAX( -2, -p ) )
#else
#define x264_lower_thread_priority(p)
#endif
static inline int x264_is_regular_file( FILE *filehandle )
{
x264_struct_stat file_stat;
if( x264_fstat( fileno( filehandle ), &file_stat ) )
return 1;
return S_ISREG( file_stat.st_mode );
}
static inline int x264_is_regular_file_path( const char *filename )
{
x264_struct_stat file_stat;
if( x264_stat( filename, &file_stat ) )
return !x264_is_pipe( filename );
return S_ISREG( file_stat.st_mode );
}
#endif /* X264_OSDEP_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,155 @@
/*****************************************************************************
* pixel.c: pixel metrics
*****************************************************************************
* Copyright (C) 2004-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_PIXEL_H
#define X264_PIXEL_H
// SSD assumes all args aligned
// other cmp functions assume first arg aligned
typedef int (*x264_pixel_cmp_t)( pixel *, intptr_t, pixel *, intptr_t );
typedef void (*x264_pixel_cmp_x3_t)( pixel *, pixel *, pixel *, pixel *, intptr_t, int[3] );
typedef void (*x264_pixel_cmp_x4_t)( pixel *, pixel *, pixel *, pixel *, pixel *, intptr_t, int[4] );
enum
{
PIXEL_16x16 = 0,
PIXEL_16x8 = 1,
PIXEL_8x16 = 2,
PIXEL_8x8 = 3,
PIXEL_8x4 = 4,
PIXEL_4x8 = 5,
PIXEL_4x4 = 6,
/* Subsampled chroma only */
PIXEL_4x16 = 7, /* 4:2:2 */
PIXEL_4x2 = 8,
PIXEL_2x8 = 9, /* 4:2:2 */
PIXEL_2x4 = 10,
PIXEL_2x2 = 11,
};
static const struct { uint8_t w, h; } x264_pixel_size[12] =
{
{ 16, 16 }, { 16, 8 }, { 8, 16 }, { 8, 8 }, { 8, 4 }, { 4, 8 }, { 4, 4 },
{ 4, 16 }, { 4, 2 }, { 2, 8 }, { 2, 4 }, { 2, 2 },
};
static const uint8_t x264_size2pixel[5][5] =
{
{ 0, },
{ 0, PIXEL_4x4, PIXEL_8x4, 0, 0 },
{ 0, PIXEL_4x8, PIXEL_8x8, 0, PIXEL_16x8 },
{ 0, },
{ 0, 0, PIXEL_8x16, 0, PIXEL_16x16 }
};
static const uint8_t x264_luma2chroma_pixel[4][7] =
{
{ 0 },
{ PIXEL_8x8, PIXEL_8x4, PIXEL_4x8, PIXEL_4x4, PIXEL_4x2, PIXEL_2x4, PIXEL_2x2 }, /* 4:2:0 */
{ PIXEL_8x16, PIXEL_8x8, PIXEL_4x16, PIXEL_4x8, PIXEL_4x4, PIXEL_2x8, PIXEL_2x4 }, /* 4:2:2 */
{ PIXEL_16x16, PIXEL_16x8, PIXEL_8x16, PIXEL_8x8, PIXEL_8x4, PIXEL_4x8, PIXEL_4x4 }, /* 4:4:4 */
};
typedef struct
{
x264_pixel_cmp_t sad[8];
x264_pixel_cmp_t ssd[8];
x264_pixel_cmp_t satd[8];
x264_pixel_cmp_t ssim[7];
x264_pixel_cmp_t sa8d[4];
x264_pixel_cmp_t mbcmp[8]; /* either satd or sad for subpel refine and mode decision */
x264_pixel_cmp_t mbcmp_unaligned[8]; /* unaligned mbcmp for subpel */
x264_pixel_cmp_t fpelcmp[8]; /* either satd or sad for fullpel motion search */
x264_pixel_cmp_x3_t fpelcmp_x3[7];
x264_pixel_cmp_x4_t fpelcmp_x4[7];
x264_pixel_cmp_t sad_aligned[8]; /* Aligned SAD for mbcmp */
int (*vsad)( pixel *, intptr_t, int );
int (*asd8)( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height );
uint64_t (*sa8d_satd[1])( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t (*var[4])( pixel *pix, intptr_t stride );
int (*var2[4])( pixel *fenc, pixel *fdec, int ssd[2] );
uint64_t (*hadamard_ac[4])( pixel *pix, intptr_t stride );
void (*ssd_nv12_core)( pixel *pixuv1, intptr_t stride1,
pixel *pixuv2, intptr_t stride2, int width, int height,
uint64_t *ssd_u, uint64_t *ssd_v );
void (*ssim_4x4x2_core)( const pixel *pix1, intptr_t stride1,
const pixel *pix2, intptr_t stride2, int sums[2][4] );
float (*ssim_end4)( int sum0[5][4], int sum1[5][4], int width );
/* multiple parallel calls to cmp. */
x264_pixel_cmp_x3_t sad_x3[7];
x264_pixel_cmp_x4_t sad_x4[7];
x264_pixel_cmp_x3_t satd_x3[7];
x264_pixel_cmp_x4_t satd_x4[7];
/* abs-diff-sum for successive elimination.
* may round width up to a multiple of 16. */
int (*ads[7])( int enc_dc[4], uint16_t *sums, int delta,
uint16_t *cost_mvx, int16_t *mvs, int width, int thresh );
/* calculate satd or sad of V, H, and DC modes. */
void (*intra_mbcmp_x3_16x16)( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_satd_x3_16x16) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_sad_x3_16x16) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_mbcmp_x3_4x4) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_satd_x3_4x4) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_sad_x3_4x4) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_mbcmp_x3_chroma)( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_satd_x3_chroma) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_sad_x3_chroma) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_mbcmp_x3_8x16c) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_satd_x3_8x16c) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_sad_x3_8x16c) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_mbcmp_x3_8x8c) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_satd_x3_8x8c) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_sad_x3_8x8c) ( pixel *fenc, pixel *fdec, int res[3] );
void (*intra_mbcmp_x3_8x8) ( pixel *fenc, pixel edge[36], int res[3] );
void (*intra_sa8d_x3_8x8) ( pixel *fenc, pixel edge[36], int res[3] );
void (*intra_sad_x3_8x8) ( pixel *fenc, pixel edge[36], int res[3] );
/* find minimum satd or sad of all modes, and set fdec.
* may be NULL, in which case just use pred+satd instead. */
int (*intra_mbcmp_x9_4x4)( pixel *fenc, pixel *fdec, uint16_t *bitcosts );
int (*intra_satd_x9_4x4) ( pixel *fenc, pixel *fdec, uint16_t *bitcosts );
int (*intra_sad_x9_4x4) ( pixel *fenc, pixel *fdec, uint16_t *bitcosts );
int (*intra_mbcmp_x9_8x8)( pixel *fenc, pixel *fdec, pixel edge[36], uint16_t *bitcosts, uint16_t *satds );
int (*intra_sa8d_x9_8x8) ( pixel *fenc, pixel *fdec, pixel edge[36], uint16_t *bitcosts, uint16_t *satds );
int (*intra_sad_x9_8x8) ( pixel *fenc, pixel *fdec, pixel edge[36], uint16_t *bitcosts, uint16_t *satds );
} x264_pixel_function_t;
void x264_pixel_init( int cpu, x264_pixel_function_t *pixf );
void x264_pixel_ssd_nv12 ( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2,
int i_width, int i_height, uint64_t *ssd_u, uint64_t *ssd_v );
uint64_t x264_pixel_ssd_wxh( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2,
int i_width, int i_height );
float x264_pixel_ssim_wxh ( x264_pixel_function_t *pf, pixel *pix1, intptr_t i_pix1, pixel *pix2, intptr_t i_pix2,
int i_width, int i_height, void *buf, int *cnt );
int x264_field_vsad( x264_t *h, int mb_x, int mb_y );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,138 @@
/*****************************************************************************
* predict.h: intra prediction
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_PREDICT_H
#define X264_PREDICT_H
typedef void (*x264_predict_t)( pixel *src );
typedef void (*x264_predict8x8_t)( pixel *src, pixel edge[36] );
typedef void (*x264_predict_8x8_filter_t)( pixel *src, pixel edge[36], int i_neighbor, int i_filters );
enum intra_chroma_pred_e
{
I_PRED_CHROMA_DC = 0,
I_PRED_CHROMA_H = 1,
I_PRED_CHROMA_V = 2,
I_PRED_CHROMA_P = 3,
I_PRED_CHROMA_DC_LEFT = 4,
I_PRED_CHROMA_DC_TOP = 5,
I_PRED_CHROMA_DC_128 = 6
};
static const uint8_t x264_mb_chroma_pred_mode_fix[7] =
{
I_PRED_CHROMA_DC, I_PRED_CHROMA_H, I_PRED_CHROMA_V, I_PRED_CHROMA_P,
I_PRED_CHROMA_DC, I_PRED_CHROMA_DC,I_PRED_CHROMA_DC
};
enum intra16x16_pred_e
{
I_PRED_16x16_V = 0,
I_PRED_16x16_H = 1,
I_PRED_16x16_DC = 2,
I_PRED_16x16_P = 3,
I_PRED_16x16_DC_LEFT = 4,
I_PRED_16x16_DC_TOP = 5,
I_PRED_16x16_DC_128 = 6,
};
static const uint8_t x264_mb_pred_mode16x16_fix[7] =
{
I_PRED_16x16_V, I_PRED_16x16_H, I_PRED_16x16_DC, I_PRED_16x16_P,
I_PRED_16x16_DC,I_PRED_16x16_DC,I_PRED_16x16_DC
};
enum intra4x4_pred_e
{
I_PRED_4x4_V = 0,
I_PRED_4x4_H = 1,
I_PRED_4x4_DC = 2,
I_PRED_4x4_DDL= 3,
I_PRED_4x4_DDR= 4,
I_PRED_4x4_VR = 5,
I_PRED_4x4_HD = 6,
I_PRED_4x4_VL = 7,
I_PRED_4x4_HU = 8,
I_PRED_4x4_DC_LEFT = 9,
I_PRED_4x4_DC_TOP = 10,
I_PRED_4x4_DC_128 = 11,
};
static const int8_t x264_mb_pred_mode4x4_fix[13] =
{
-1,
I_PRED_4x4_V, I_PRED_4x4_H, I_PRED_4x4_DC,
I_PRED_4x4_DDL, I_PRED_4x4_DDR, I_PRED_4x4_VR,
I_PRED_4x4_HD, I_PRED_4x4_VL, I_PRED_4x4_HU,
I_PRED_4x4_DC, I_PRED_4x4_DC, I_PRED_4x4_DC
};
#define x264_mb_pred_mode4x4_fix(t) x264_mb_pred_mode4x4_fix[(t)+1]
/* must use the same numbering as intra4x4_pred_e */
enum intra8x8_pred_e
{
I_PRED_8x8_V = 0,
I_PRED_8x8_H = 1,
I_PRED_8x8_DC = 2,
I_PRED_8x8_DDL= 3,
I_PRED_8x8_DDR= 4,
I_PRED_8x8_VR = 5,
I_PRED_8x8_HD = 6,
I_PRED_8x8_VL = 7,
I_PRED_8x8_HU = 8,
I_PRED_8x8_DC_LEFT = 9,
I_PRED_8x8_DC_TOP = 10,
I_PRED_8x8_DC_128 = 11,
};
void x264_predict_8x8_dc_c ( pixel *src, pixel edge[36] );
void x264_predict_8x8_h_c ( pixel *src, pixel edge[36] );
void x264_predict_8x8_v_c ( pixel *src, pixel edge[36] );
void x264_predict_4x4_dc_c ( pixel *src );
void x264_predict_4x4_h_c ( pixel *src );
void x264_predict_4x4_v_c ( pixel *src );
void x264_predict_16x16_dc_c( pixel *src );
void x264_predict_16x16_h_c ( pixel *src );
void x264_predict_16x16_v_c ( pixel *src );
void x264_predict_16x16_p_c ( pixel *src );
void x264_predict_8x8c_dc_c ( pixel *src );
void x264_predict_8x8c_h_c ( pixel *src );
void x264_predict_8x8c_v_c ( pixel *src );
void x264_predict_8x8c_p_c ( pixel *src );
void x264_predict_8x16c_dc_c( pixel *src );
void x264_predict_8x16c_h_c ( pixel *src );
void x264_predict_8x16c_v_c ( pixel *src );
void x264_predict_8x16c_p_c ( pixel *src );
void x264_predict_16x16_init ( int cpu, x264_predict_t pf[7] );
void x264_predict_8x8c_init ( int cpu, x264_predict_t pf[7] );
void x264_predict_8x16c_init ( int cpu, x264_predict_t pf[7] );
void x264_predict_4x4_init ( int cpu, x264_predict_t pf[12] );
void x264_predict_8x8_init ( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_filter );
#endif

View file

@ -0,0 +1,830 @@
/*****************************************************************************
* quant.c: quantization and level-run
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
* Christian Heine <sennindemokrit@gmx.net>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#if HAVE_MMX
#include "x86/quant.h"
#endif
#if ARCH_PPC
# include "ppc/quant.h"
#endif
#if ARCH_ARM
# include "arm/quant.h"
#endif
#if ARCH_AARCH64
# include "aarch64/quant.h"
#endif
#if ARCH_MIPS
# include "mips/quant.h"
#endif
#define QUANT_ONE( coef, mf, f ) \
{ \
if( (coef) > 0 ) \
(coef) = (f + (coef)) * (mf) >> 16; \
else \
(coef) = - ((f - (coef)) * (mf) >> 16); \
nz |= (coef); \
}
static int quant_8x8( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] )
{
int nz = 0;
for( int i = 0; i < 64; i++ )
QUANT_ONE( dct[i], mf[i], bias[i] );
return !!nz;
}
static int quant_4x4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] )
{
int nz = 0;
for( int i = 0; i < 16; i++ )
QUANT_ONE( dct[i], mf[i], bias[i] );
return !!nz;
}
static int quant_4x4x4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] )
{
int nza = 0;
for( int j = 0; j < 4; j++ )
{
int nz = 0;
for( int i = 0; i < 16; i++ )
QUANT_ONE( dct[j][i], mf[i], bias[i] );
nza |= (!!nz)<<j;
}
return nza;
}
static int quant_4x4_dc( dctcoef dct[16], int mf, int bias )
{
int nz = 0;
for( int i = 0; i < 16; i++ )
QUANT_ONE( dct[i], mf, bias );
return !!nz;
}
static int quant_2x2_dc( dctcoef dct[4], int mf, int bias )
{
int nz = 0;
QUANT_ONE( dct[0], mf, bias );
QUANT_ONE( dct[1], mf, bias );
QUANT_ONE( dct[2], mf, bias );
QUANT_ONE( dct[3], mf, bias );
return !!nz;
}
#define DEQUANT_SHL( x ) \
dct[x] = ( dct[x] * dequant_mf[i_mf][x] ) << i_qbits
#define DEQUANT_SHR( x ) \
dct[x] = ( dct[x] * dequant_mf[i_mf][x] + f ) >> (-i_qbits)
static void dequant_4x4( dctcoef dct[16], int dequant_mf[6][16], int i_qp )
{
const int i_mf = i_qp%6;
const int i_qbits = i_qp/6 - 4;
if( i_qbits >= 0 )
{
for( int i = 0; i < 16; i++ )
DEQUANT_SHL( i );
}
else
{
const int f = 1 << (-i_qbits-1);
for( int i = 0; i < 16; i++ )
DEQUANT_SHR( i );
}
}
static void dequant_8x8( dctcoef dct[64], int dequant_mf[6][64], int i_qp )
{
const int i_mf = i_qp%6;
const int i_qbits = i_qp/6 - 6;
if( i_qbits >= 0 )
{
for( int i = 0; i < 64; i++ )
DEQUANT_SHL( i );
}
else
{
const int f = 1 << (-i_qbits-1);
for( int i = 0; i < 64; i++ )
DEQUANT_SHR( i );
}
}
static void dequant_4x4_dc( dctcoef dct[16], int dequant_mf[6][16], int i_qp )
{
const int i_qbits = i_qp/6 - 6;
if( i_qbits >= 0 )
{
const int i_dmf = dequant_mf[i_qp%6][0] << i_qbits;
for( int i = 0; i < 16; i++ )
dct[i] *= i_dmf;
}
else
{
const int i_dmf = dequant_mf[i_qp%6][0];
const int f = 1 << (-i_qbits-1);
for( int i = 0; i < 16; i++ )
dct[i] = ( dct[i] * i_dmf + f ) >> (-i_qbits);
}
}
#define IDCT_DEQUANT_2X4_START \
int a0 = dct[0] + dct[1]; \
int a1 = dct[2] + dct[3]; \
int a2 = dct[4] + dct[5]; \
int a3 = dct[6] + dct[7]; \
int a4 = dct[0] - dct[1]; \
int a5 = dct[2] - dct[3]; \
int a6 = dct[4] - dct[5]; \
int a7 = dct[6] - dct[7]; \
int b0 = a0 + a1; \
int b1 = a2 + a3; \
int b2 = a4 + a5; \
int b3 = a6 + a7; \
int b4 = a0 - a1; \
int b5 = a2 - a3; \
int b6 = a4 - a5; \
int b7 = a6 - a7;
static void idct_dequant_2x4_dc( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp )
{
IDCT_DEQUANT_2X4_START
int dmf = dequant_mf[i_qp%6][0] << i_qp/6;
dct4x4[0][0] = ((b0 + b1) * dmf + 32) >> 6;
dct4x4[1][0] = ((b2 + b3) * dmf + 32) >> 6;
dct4x4[2][0] = ((b0 - b1) * dmf + 32) >> 6;
dct4x4[3][0] = ((b2 - b3) * dmf + 32) >> 6;
dct4x4[4][0] = ((b4 - b5) * dmf + 32) >> 6;
dct4x4[5][0] = ((b6 - b7) * dmf + 32) >> 6;
dct4x4[6][0] = ((b4 + b5) * dmf + 32) >> 6;
dct4x4[7][0] = ((b6 + b7) * dmf + 32) >> 6;
}
static void idct_dequant_2x4_dconly( dctcoef dct[8], int dequant_mf[6][16], int i_qp )
{
IDCT_DEQUANT_2X4_START
int dmf = dequant_mf[i_qp%6][0] << i_qp/6;
dct[0] = ((b0 + b1) * dmf + 32) >> 6;
dct[1] = ((b2 + b3) * dmf + 32) >> 6;
dct[2] = ((b0 - b1) * dmf + 32) >> 6;
dct[3] = ((b2 - b3) * dmf + 32) >> 6;
dct[4] = ((b4 - b5) * dmf + 32) >> 6;
dct[5] = ((b6 - b7) * dmf + 32) >> 6;
dct[6] = ((b4 + b5) * dmf + 32) >> 6;
dct[7] = ((b6 + b7) * dmf + 32) >> 6;
}
static ALWAYS_INLINE void optimize_chroma_idct_dequant_2x4( dctcoef out[8], dctcoef dct[8], int dmf )
{
IDCT_DEQUANT_2X4_START
out[0] = ((b0 + b1) * dmf + 2080) >> 6; /* 2080 = 32 + (32<<6) */
out[1] = ((b2 + b3) * dmf + 2080) >> 6;
out[2] = ((b0 - b1) * dmf + 2080) >> 6;
out[3] = ((b2 - b3) * dmf + 2080) >> 6;
out[4] = ((b4 - b5) * dmf + 2080) >> 6;
out[5] = ((b6 - b7) * dmf + 2080) >> 6;
out[6] = ((b4 + b5) * dmf + 2080) >> 6;
out[7] = ((b6 + b7) * dmf + 2080) >> 6;
}
#undef IDCT_DEQUANT_2X4_START
static ALWAYS_INLINE void optimize_chroma_idct_dequant_2x2( dctcoef out[4], dctcoef dct[4], int dmf )
{
int d0 = dct[0] + dct[1];
int d1 = dct[2] + dct[3];
int d2 = dct[0] - dct[1];
int d3 = dct[2] - dct[3];
out[0] = ((d0 + d1) * dmf >> 5) + 32;
out[1] = ((d0 - d1) * dmf >> 5) + 32;
out[2] = ((d2 + d3) * dmf >> 5) + 32;
out[3] = ((d2 - d3) * dmf >> 5) + 32;
}
static ALWAYS_INLINE int optimize_chroma_round( dctcoef *ref, dctcoef *dct, int dequant_mf, int chroma422 )
{
dctcoef out[8];
if( chroma422 )
optimize_chroma_idct_dequant_2x4( out, dct, dequant_mf );
else
optimize_chroma_idct_dequant_2x2( out, dct, dequant_mf );
int sum = 0;
for( int i = 0; i < (chroma422?8:4); i++ )
sum |= ref[i] ^ out[i];
return sum >> 6;
}
static ALWAYS_INLINE int optimize_chroma_dc_internal( dctcoef *dct, int dequant_mf, int chroma422 )
{
/* dequant_mf = h->dequant4_mf[CQM_4IC + b_inter][i_qp%6][0] << i_qp/6, max 32*64 */
dctcoef dct_orig[8];
int coeff, nz;
if( chroma422 )
optimize_chroma_idct_dequant_2x4( dct_orig, dct, dequant_mf );
else
optimize_chroma_idct_dequant_2x2( dct_orig, dct, dequant_mf );
/* If the DC coefficients already round to zero, terminate early. */
int sum = 0;
for( int i = 0; i < (chroma422?8:4); i++ )
sum |= dct_orig[i];
if( !(sum >> 6) )
return 0;
/* Start with the highest frequency coefficient... is this the best option? */
for( nz = 0, coeff = (chroma422?7:3); coeff >= 0; coeff-- )
{
int level = dct[coeff];
int sign = level>>31 | 1; /* dct[coeff] < 0 ? -1 : 1 */
while( level )
{
dct[coeff] = level - sign;
if( optimize_chroma_round( dct_orig, dct, dequant_mf, chroma422 ) )
{
nz = 1;
dct[coeff] = level;
break;
}
level -= sign;
}
}
return nz;
}
static int optimize_chroma_2x2_dc( dctcoef dct[4], int dequant_mf )
{
return optimize_chroma_dc_internal( dct, dequant_mf, 0 );
}
static int optimize_chroma_2x4_dc( dctcoef dct[8], int dequant_mf )
{
return optimize_chroma_dc_internal( dct, dequant_mf, 1 );
}
static void x264_denoise_dct( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size )
{
for( int i = 0; i < size; i++ )
{
int level = dct[i];
int sign = level>>31;
level = (level+sign)^sign;
sum[i] += level;
level -= offset[i];
dct[i] = level<0 ? 0 : (level^sign)-sign;
}
}
/* (ref: JVT-B118)
* x264_mb_decimate_score: given dct coeffs it returns a score to see if we could empty this dct coeffs
* to 0 (low score means set it to null)
* Used in inter macroblock (luma and chroma)
* luma: for a 8x8 block: if score < 4 -> null
* for the complete mb: if score < 6 -> null
* chroma: for the complete mb: if score < 7 -> null
*/
const uint8_t x264_decimate_table4[16] =
{
3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0
};
const uint8_t x264_decimate_table8[64] =
{
3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,
1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static int ALWAYS_INLINE x264_decimate_score_internal( dctcoef *dct, int i_max )
{
const uint8_t *ds_table = (i_max == 64) ? x264_decimate_table8 : x264_decimate_table4;
int i_score = 0;
int idx = i_max - 1;
while( idx >= 0 && dct[idx] == 0 )
idx--;
while( idx >= 0 )
{
int i_run;
if( (unsigned)(dct[idx--] + 1) > 2 )
return 9;
i_run = 0;
while( idx >= 0 && dct[idx] == 0 )
{
idx--;
i_run++;
}
i_score += ds_table[i_run];
}
return i_score;
}
static int x264_decimate_score15( dctcoef *dct )
{
return x264_decimate_score_internal( dct+1, 15 );
}
static int x264_decimate_score16( dctcoef *dct )
{
return x264_decimate_score_internal( dct, 16 );
}
static int x264_decimate_score64( dctcoef *dct )
{
return x264_decimate_score_internal( dct, 64 );
}
#define last(num)\
static int x264_coeff_last##num( dctcoef *l )\
{\
int i_last = num-1;\
while( i_last >= 0 && l[i_last] == 0 )\
i_last--;\
return i_last;\
}
last(4)
last(8)
last(15)
last(16)
last(64)
#define level_run(num)\
static int x264_coeff_level_run##num( dctcoef *dct, x264_run_level_t *runlevel )\
{\
int i_last = runlevel->last = x264_coeff_last##num(dct);\
int i_total = 0;\
int mask = 0;\
do\
{\
runlevel->level[i_total++] = dct[i_last];\
mask |= 1 << (i_last);\
while( --i_last >= 0 && dct[i_last] == 0 );\
} while( i_last >= 0 );\
runlevel->mask = mask;\
return i_total;\
}
level_run(4)
level_run(8)
level_run(15)
level_run(16)
#if ARCH_X86_64
#define INIT_TRELLIS(cpu)\
pf->trellis_cabac_4x4 = x264_trellis_cabac_4x4_##cpu;\
pf->trellis_cabac_8x8 = x264_trellis_cabac_8x8_##cpu;\
pf->trellis_cabac_4x4_psy = x264_trellis_cabac_4x4_psy_##cpu;\
pf->trellis_cabac_8x8_psy = x264_trellis_cabac_8x8_psy_##cpu;\
pf->trellis_cabac_dc = x264_trellis_cabac_dc_##cpu;\
pf->trellis_cabac_chroma_422_dc = x264_trellis_cabac_chroma_422_dc_##cpu;
#else
#define INIT_TRELLIS(...)
#endif
void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf )
{
pf->quant_8x8 = quant_8x8;
pf->quant_4x4 = quant_4x4;
pf->quant_4x4x4 = quant_4x4x4;
pf->quant_4x4_dc = quant_4x4_dc;
pf->quant_2x2_dc = quant_2x2_dc;
pf->dequant_4x4 = dequant_4x4;
pf->dequant_4x4_dc = dequant_4x4_dc;
pf->dequant_8x8 = dequant_8x8;
pf->idct_dequant_2x4_dc = idct_dequant_2x4_dc;
pf->idct_dequant_2x4_dconly = idct_dequant_2x4_dconly;
pf->optimize_chroma_2x2_dc = optimize_chroma_2x2_dc;
pf->optimize_chroma_2x4_dc = optimize_chroma_2x4_dc;
pf->denoise_dct = x264_denoise_dct;
pf->decimate_score15 = x264_decimate_score15;
pf->decimate_score16 = x264_decimate_score16;
pf->decimate_score64 = x264_decimate_score64;
pf->coeff_last4 = x264_coeff_last4;
pf->coeff_last8 = x264_coeff_last8;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15;
pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16;
pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64;
pf->coeff_level_run4 = x264_coeff_level_run4;
pf->coeff_level_run8 = x264_coeff_level_run8;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15;
pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16;
#if HIGH_BIT_DEPTH
#if HAVE_MMX
INIT_TRELLIS( sse2 );
if( cpu&X264_CPU_MMX2 )
{
#if ARCH_X86
pf->denoise_dct = x264_denoise_dct_mmx;
pf->coeff_last8 = x264_coeff_last8_mmx2;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2;
pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2;
pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2;
pf->coeff_level_run8 = x264_coeff_level_run8_mmx2;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_mmx2;
pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_mmx2;
#endif
pf->coeff_last4 = x264_coeff_last4_mmx2;
pf->coeff_level_run4 = x264_coeff_level_run4_mmx2;
}
if( cpu&X264_CPU_SSE2 )
{
pf->quant_4x4 = x264_quant_4x4_sse2;
pf->quant_4x4x4 = x264_quant_4x4x4_sse2;
pf->quant_8x8 = x264_quant_8x8_sse2;
pf->quant_2x2_dc = x264_quant_2x2_dc_sse2;
pf->quant_4x4_dc = x264_quant_4x4_dc_sse2;
pf->dequant_4x4 = x264_dequant_4x4_sse2;
pf->dequant_8x8 = x264_dequant_8x8_sse2;
pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2;
pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_sse2;
pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_sse2;
pf->denoise_dct = x264_denoise_dct_sse2;
pf->decimate_score15 = x264_decimate_score15_sse2;
pf->decimate_score16 = x264_decimate_score16_sse2;
pf->decimate_score64 = x264_decimate_score64_sse2;
pf->coeff_last8 = x264_coeff_last8_sse2;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2;
pf->coeff_level_run8 = x264_coeff_level_run8_sse2;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2;
}
if( cpu&X264_CPU_LZCNT )
{
pf->coeff_last4 = x264_coeff_last4_lzcnt;
pf->coeff_last8 = x264_coeff_last8_lzcnt;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_lzcnt;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_lzcnt;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_lzcnt;
pf->coeff_level_run4 = x264_coeff_level_run4_lzcnt;
pf->coeff_level_run8 = x264_coeff_level_run8_lzcnt;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_lzcnt;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_lzcnt;
}
if( cpu&X264_CPU_SSSE3 )
{
pf->quant_4x4 = x264_quant_4x4_ssse3;
pf->quant_4x4x4 = x264_quant_4x4x4_ssse3;
pf->quant_8x8 = x264_quant_8x8_ssse3;
pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3;
pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3;
pf->denoise_dct = x264_denoise_dct_ssse3;
pf->decimate_score15 = x264_decimate_score15_ssse3;
pf->decimate_score16 = x264_decimate_score16_ssse3;
pf->decimate_score64 = x264_decimate_score64_ssse3;
INIT_TRELLIS( ssse3 );
}
if( cpu&X264_CPU_SSE4 )
{
pf->quant_2x2_dc = x264_quant_2x2_dc_sse4;
pf->quant_4x4_dc = x264_quant_4x4_dc_sse4;
pf->quant_4x4 = x264_quant_4x4_sse4;
pf->quant_4x4x4 = x264_quant_4x4x4_sse4;
pf->quant_8x8 = x264_quant_8x8_sse4;
}
if( cpu&X264_CPU_AVX )
{
pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_avx;
pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_avx;
pf->denoise_dct = x264_denoise_dct_avx;
}
if( cpu&X264_CPU_XOP )
{
pf->dequant_4x4_dc = x264_dequant_4x4dc_xop;
if( h->param.i_cqm_preset != X264_CQM_FLAT )
{
pf->dequant_4x4 = x264_dequant_4x4_xop;
pf->dequant_8x8 = x264_dequant_8x8_xop;
}
}
if( cpu&X264_CPU_AVX2 )
{
pf->quant_4x4 = x264_quant_4x4_avx2;
pf->quant_4x4_dc = x264_quant_4x4_dc_avx2;
pf->quant_8x8 = x264_quant_8x8_avx2;
pf->quant_4x4x4 = x264_quant_4x4x4_avx2;
pf->dequant_4x4 = x264_dequant_4x4_avx2;
pf->dequant_8x8 = x264_dequant_8x8_avx2;
pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2;
pf->denoise_dct = x264_denoise_dct_avx2;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2;
}
if( cpu&X264_CPU_AVX512 )
{
pf->dequant_4x4 = x264_dequant_4x4_avx512;
pf->dequant_8x8 = x264_dequant_8x8_avx512;
pf->decimate_score15 = x264_decimate_score15_avx512;
pf->decimate_score16 = x264_decimate_score16_avx512;
pf->decimate_score64 = x264_decimate_score64_avx512;
pf->coeff_last4 = x264_coeff_last4_avx512;
pf->coeff_last8 = x264_coeff_last8_avx512;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_avx512;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_avx512;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx512;
}
#endif // HAVE_MMX
#else // !HIGH_BIT_DEPTH
#if HAVE_MMX
INIT_TRELLIS( sse2 );
if( cpu&X264_CPU_MMX )
{
#if ARCH_X86
pf->dequant_4x4 = x264_dequant_4x4_mmx;
pf->dequant_4x4_dc = x264_dequant_4x4dc_mmx2;
pf->dequant_8x8 = x264_dequant_8x8_mmx;
if( h->param.i_cqm_preset == X264_CQM_FLAT )
{
pf->dequant_4x4 = x264_dequant_4x4_flat16_mmx;
pf->dequant_8x8 = x264_dequant_8x8_flat16_mmx;
}
pf->denoise_dct = x264_denoise_dct_mmx;
#endif
}
if( cpu&X264_CPU_MMX2 )
{
pf->quant_2x2_dc = x264_quant_2x2_dc_mmx2;
#if ARCH_X86
pf->quant_4x4 = x264_quant_4x4_mmx2;
pf->quant_8x8 = x264_quant_8x8_mmx2;
pf->quant_4x4_dc = x264_quant_4x4_dc_mmx2;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_mmx2;
pf->coeff_last[ DCT_LUMA_4x4] = x264_coeff_last16_mmx2;
pf->coeff_last[ DCT_LUMA_8x8] = x264_coeff_last64_mmx2;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_mmx2;
pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_mmx2;
#endif
pf->coeff_last4 = x264_coeff_last4_mmx2;
pf->coeff_last8 = x264_coeff_last8_mmx2;
pf->coeff_level_run4 = x264_coeff_level_run4_mmx2;
pf->coeff_level_run8 = x264_coeff_level_run8_mmx2;
}
if( cpu&X264_CPU_SSE2 )
{
pf->quant_4x4_dc = x264_quant_4x4_dc_sse2;
pf->quant_4x4 = x264_quant_4x4_sse2;
pf->quant_4x4x4 = x264_quant_4x4x4_sse2;
pf->quant_8x8 = x264_quant_8x8_sse2;
pf->dequant_4x4 = x264_dequant_4x4_sse2;
pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2;
pf->dequant_8x8 = x264_dequant_8x8_sse2;
if( h->param.i_cqm_preset == X264_CQM_FLAT )
{
pf->dequant_4x4 = x264_dequant_4x4_flat16_sse2;
pf->dequant_8x8 = x264_dequant_8x8_flat16_sse2;
}
pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_sse2;
pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_sse2;
pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_sse2;
pf->denoise_dct = x264_denoise_dct_sse2;
pf->decimate_score15 = x264_decimate_score15_sse2;
pf->decimate_score16 = x264_decimate_score16_sse2;
pf->decimate_score64 = x264_decimate_score64_sse2;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_sse2;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_sse2;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_sse2;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_sse2;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_sse2;
}
if( cpu&X264_CPU_LZCNT )
{
pf->coeff_last4 = x264_coeff_last4_lzcnt;
pf->coeff_last8 = x264_coeff_last8_lzcnt;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_lzcnt;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_lzcnt;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_lzcnt;
pf->coeff_level_run4 = x264_coeff_level_run4_lzcnt;
pf->coeff_level_run8 = x264_coeff_level_run8_lzcnt;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_lzcnt;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_lzcnt;
}
if( cpu&X264_CPU_SSSE3 )
{
pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3;
pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3;
pf->quant_4x4 = x264_quant_4x4_ssse3;
pf->quant_4x4x4 = x264_quant_4x4x4_ssse3;
pf->quant_8x8 = x264_quant_8x8_ssse3;
pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_ssse3;
pf->denoise_dct = x264_denoise_dct_ssse3;
pf->decimate_score15 = x264_decimate_score15_ssse3;
pf->decimate_score16 = x264_decimate_score16_ssse3;
pf->decimate_score64 = x264_decimate_score64_ssse3;
INIT_TRELLIS( ssse3 );
#if ARCH_X86 || !defined( __MACH__ )
pf->coeff_level_run4 = x264_coeff_level_run4_ssse3;
pf->coeff_level_run8 = x264_coeff_level_run8_ssse3;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3;
if( cpu&X264_CPU_LZCNT )
{
pf->coeff_level_run4 = x264_coeff_level_run4_ssse3_lzcnt;
pf->coeff_level_run8 = x264_coeff_level_run8_ssse3_lzcnt;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_ssse3_lzcnt;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_ssse3_lzcnt;
}
#endif
}
if( cpu&X264_CPU_SSE4 )
{
pf->quant_4x4_dc = x264_quant_4x4_dc_sse4;
pf->quant_4x4 = x264_quant_4x4_sse4;
pf->quant_8x8 = x264_quant_8x8_sse4;
pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_sse4;
}
if( cpu&X264_CPU_AVX )
{
pf->dequant_4x4_dc = x264_dequant_4x4dc_avx;
if( h->param.i_cqm_preset != X264_CQM_FLAT )
{
pf->dequant_4x4 = x264_dequant_4x4_avx;
pf->dequant_8x8 = x264_dequant_8x8_avx;
}
pf->idct_dequant_2x4_dc = x264_idct_dequant_2x4_dc_avx;
pf->idct_dequant_2x4_dconly = x264_idct_dequant_2x4_dconly_avx;
pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_avx;
pf->denoise_dct = x264_denoise_dct_avx;
}
if( cpu&X264_CPU_XOP )
{
if( h->param.i_cqm_preset != X264_CQM_FLAT )
{
pf->dequant_4x4 = x264_dequant_4x4_xop;
pf->dequant_8x8 = x264_dequant_8x8_xop;
}
}
if( cpu&X264_CPU_AVX2 )
{
pf->quant_4x4 = x264_quant_4x4_avx2;
pf->quant_4x4_dc = x264_quant_4x4_dc_avx2;
pf->quant_8x8 = x264_quant_8x8_avx2;
pf->quant_4x4x4 = x264_quant_4x4x4_avx2;
pf->dequant_4x4 = x264_dequant_4x4_avx2;
pf->dequant_8x8 = x264_dequant_8x8_avx2;
pf->dequant_4x4_dc = x264_dequant_4x4dc_avx2;
if( h->param.i_cqm_preset == X264_CQM_FLAT )
{
pf->dequant_4x4 = x264_dequant_4x4_flat16_avx2;
pf->dequant_8x8 = x264_dequant_8x8_flat16_avx2;
}
pf->decimate_score64 = x264_decimate_score64_avx2;
pf->denoise_dct = x264_denoise_dct_avx2;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx2;
#if ARCH_X86 || !defined( __MACH__ )
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_avx2;
pf->coeff_level_run[DCT_LUMA_4x4] = x264_coeff_level_run16_avx2;
#endif
}
if( cpu&X264_CPU_AVX512 )
{
if( h->param.i_cqm_preset == X264_CQM_FLAT )
pf->dequant_8x8 = x264_dequant_8x8_flat16_avx512;
else
{
pf->dequant_4x4 = x264_dequant_4x4_avx512;
pf->dequant_8x8 = x264_dequant_8x8_avx512;
}
pf->decimate_score15 = x264_decimate_score15_avx512;
pf->decimate_score16 = x264_decimate_score16_avx512;
pf->decimate_score64 = x264_decimate_score64_avx512;
pf->coeff_last8 = x264_coeff_last8_avx512;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_avx512;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_avx512;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_avx512;
}
#endif // HAVE_MMX
#if HAVE_ALTIVEC
if( cpu&X264_CPU_ALTIVEC )
{
pf->quant_2x2_dc = x264_quant_2x2_dc_altivec;
pf->quant_4x4_dc = x264_quant_4x4_dc_altivec;
pf->quant_4x4 = x264_quant_4x4_altivec;
pf->quant_8x8 = x264_quant_8x8_altivec;
pf->dequant_4x4 = x264_dequant_4x4_altivec;
pf->dequant_8x8 = x264_dequant_8x8_altivec;
}
#endif
#if HAVE_ARMV6
if( cpu&X264_CPU_ARMV6 )
{
pf->coeff_last4 = x264_coeff_last4_arm;
pf->coeff_last8 = x264_coeff_last8_arm;
}
#endif
#if HAVE_ARMV6 || ARCH_AARCH64
if( cpu&X264_CPU_NEON )
{
pf->quant_2x2_dc = x264_quant_2x2_dc_neon;
pf->quant_4x4 = x264_quant_4x4_neon;
pf->quant_4x4_dc = x264_quant_4x4_dc_neon;
pf->quant_4x4x4 = x264_quant_4x4x4_neon;
pf->quant_8x8 = x264_quant_8x8_neon;
pf->dequant_4x4 = x264_dequant_4x4_neon;
pf->dequant_4x4_dc = x264_dequant_4x4_dc_neon;
pf->dequant_8x8 = x264_dequant_8x8_neon;
pf->coeff_last[ DCT_LUMA_AC] = x264_coeff_last15_neon;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_neon;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_neon;
pf->denoise_dct = x264_denoise_dct_neon;
pf->decimate_score15 = x264_decimate_score15_neon;
pf->decimate_score16 = x264_decimate_score16_neon;
pf->decimate_score64 = x264_decimate_score64_neon;
}
#endif
#if ARCH_AARCH64
if( cpu&X264_CPU_ARMV8 )
{
pf->coeff_last4 = x264_coeff_last4_aarch64;
pf->coeff_last8 = x264_coeff_last8_aarch64;
pf->coeff_level_run4 = x264_coeff_level_run4_aarch64;
}
if( cpu&X264_CPU_NEON )
{
pf->coeff_level_run8 = x264_coeff_level_run8_neon;
pf->coeff_level_run[ DCT_LUMA_AC] = x264_coeff_level_run15_neon;
pf->coeff_level_run[ DCT_LUMA_4x4] = x264_coeff_level_run16_neon;
}
#endif
#if HAVE_MSA
if( cpu&X264_CPU_MSA )
{
pf->quant_4x4 = x264_quant_4x4_msa;
pf->quant_4x4_dc = x264_quant_4x4_dc_msa;
pf->quant_4x4x4 = x264_quant_4x4x4_msa;
pf->quant_8x8 = x264_quant_8x8_msa;
pf->dequant_4x4 = x264_dequant_4x4_msa;
pf->dequant_4x4_dc = x264_dequant_4x4_dc_msa;
pf->dequant_8x8 = x264_dequant_8x8_msa;
pf->coeff_last[DCT_LUMA_4x4] = x264_coeff_last16_msa;
pf->coeff_last[DCT_LUMA_8x8] = x264_coeff_last64_msa;
}
#endif
#endif // HIGH_BIT_DEPTH
pf->coeff_last[DCT_LUMA_DC] = pf->coeff_last[DCT_CHROMAU_DC] = pf->coeff_last[DCT_CHROMAV_DC] =
pf->coeff_last[DCT_CHROMAU_4x4] = pf->coeff_last[DCT_CHROMAV_4x4] = pf->coeff_last[DCT_LUMA_4x4];
pf->coeff_last[DCT_CHROMA_AC] = pf->coeff_last[DCT_CHROMAU_AC] =
pf->coeff_last[DCT_CHROMAV_AC] = pf->coeff_last[DCT_LUMA_AC];
pf->coeff_last[DCT_CHROMAU_8x8] = pf->coeff_last[DCT_CHROMAV_8x8] = pf->coeff_last[DCT_LUMA_8x8];
pf->coeff_level_run[DCT_LUMA_DC] = pf->coeff_level_run[DCT_CHROMAU_DC] = pf->coeff_level_run[DCT_CHROMAV_DC] =
pf->coeff_level_run[DCT_CHROMAU_4x4] = pf->coeff_level_run[DCT_CHROMAV_4x4] = pf->coeff_level_run[DCT_LUMA_4x4];
pf->coeff_level_run[DCT_CHROMA_AC] = pf->coeff_level_run[DCT_CHROMAU_AC] =
pf->coeff_level_run[DCT_CHROMAV_AC] = pf->coeff_level_run[DCT_LUMA_AC];
}

View file

@ -0,0 +1,74 @@
/*****************************************************************************
* quant.h: quantization and level-run
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_QUANT_H
#define X264_QUANT_H
typedef struct
{
int (*quant_8x8) ( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] );
int (*quant_4x4) ( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] );
int (*quant_4x4x4)( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] );
int (*quant_4x4_dc)( dctcoef dct[16], int mf, int bias );
int (*quant_2x2_dc)( dctcoef dct[4], int mf, int bias );
void (*dequant_8x8)( dctcoef dct[64], int dequant_mf[6][64], int i_qp );
void (*dequant_4x4)( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void (*dequant_4x4_dc)( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void (*idct_dequant_2x4_dc)( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp );
void (*idct_dequant_2x4_dconly)( dctcoef dct[8], int dequant_mf[6][16], int i_qp );
int (*optimize_chroma_2x2_dc)( dctcoef dct[4], int dequant_mf );
int (*optimize_chroma_2x4_dc)( dctcoef dct[8], int dequant_mf );
void (*denoise_dct)( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size );
int (*decimate_score15)( dctcoef *dct );
int (*decimate_score16)( dctcoef *dct );
int (*decimate_score64)( dctcoef *dct );
int (*coeff_last[14])( dctcoef *dct );
int (*coeff_last4)( dctcoef *dct );
int (*coeff_last8)( dctcoef *dct );
int (*coeff_level_run[13])( dctcoef *dct, x264_run_level_t *runlevel );
int (*coeff_level_run4)( dctcoef *dct, x264_run_level_t *runlevel );
int (*coeff_level_run8)( dctcoef *dct, x264_run_level_t *runlevel );
#define TRELLIS_PARAMS const int *unquant_mf, const uint8_t *zigzag, int lambda2,\
int last_nnz, dctcoef *coefs, dctcoef *quant_coefs, dctcoef *dct,\
uint8_t *cabac_state_sig, uint8_t *cabac_state_last,\
uint64_t level_state0, uint16_t level_state1
int (*trellis_cabac_4x4)( TRELLIS_PARAMS, int b_ac );
int (*trellis_cabac_8x8)( TRELLIS_PARAMS, int b_interlaced );
int (*trellis_cabac_4x4_psy)( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int psy_trellis );
int (*trellis_cabac_8x8_psy)( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int psy_trellis );
int (*trellis_cabac_dc)( TRELLIS_PARAMS, int num_coefs );
int (*trellis_cabac_chroma_422_dc)( TRELLIS_PARAMS );
} x264_quant_function_t;
void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf );
#endif

View file

@ -0,0 +1,58 @@
/*****************************************************************************
* rectangle.c: rectangle filling
*****************************************************************************
* Copyright (C) 2010-2017 x264 project
*
* Authors: Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#define CACHE_FUNC(name,size,width,height)\
static void x264_macroblock_cache_##name##_##width##_##height( void *target, uint32_t val )\
{\
x264_macroblock_cache_rect( target, width*size, height, size, val );\
}
#define CACHE_FUNCS(name,size)\
CACHE_FUNC(name,size,4,4)\
CACHE_FUNC(name,size,2,4)\
CACHE_FUNC(name,size,4,2)\
CACHE_FUNC(name,size,2,2)\
CACHE_FUNC(name,size,2,1)\
CACHE_FUNC(name,size,1,2)\
CACHE_FUNC(name,size,1,1)\
void (*x264_cache_##name##_func_table[10])(void *, uint32_t) =\
{\
x264_macroblock_cache_##name##_1_1,\
x264_macroblock_cache_##name##_2_1,\
x264_macroblock_cache_##name##_1_2,\
x264_macroblock_cache_##name##_2_2,\
NULL,\
x264_macroblock_cache_##name##_4_2,\
NULL,\
x264_macroblock_cache_##name##_2_4,\
NULL,\
x264_macroblock_cache_##name##_4_4\
};\
CACHE_FUNCS(mv, 4)
CACHE_FUNCS(mvd, 2)
CACHE_FUNCS(ref, 1)

View file

@ -0,0 +1,157 @@
/*****************************************************************************
* rectangle.h: rectangle filling
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Fiona Glaser <fiona@x264.com>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
/* This function should only be called with constant w / h / s arguments! */
static ALWAYS_INLINE void x264_macroblock_cache_rect( void *dst, int w, int h, int s, uint32_t v )
{
uint8_t *d = dst;
uint16_t v2 = s == 2 ? v : v * 0x101;
uint32_t v4 = s == 4 ? v : s == 2 ? v * 0x10001 : v * 0x1010101;
uint64_t v8 = v4 + ((uint64_t)v4 << 32);
s *= 8;
if( w == 2 )
{
M16( d+s*0 ) = v2;
if( h == 1 ) return;
M16( d+s*1 ) = v2;
if( h == 2 ) return;
M16( d+s*2 ) = v2;
M16( d+s*3 ) = v2;
}
else if( w == 4 )
{
M32( d+s*0 ) = v4;
if( h == 1 ) return;
M32( d+s*1 ) = v4;
if( h == 2 ) return;
M32( d+s*2 ) = v4;
M32( d+s*3 ) = v4;
}
else if( w == 8 )
{
if( WORD_SIZE == 8 )
{
M64( d+s*0 ) = v8;
if( h == 1 ) return;
M64( d+s*1 ) = v8;
if( h == 2 ) return;
M64( d+s*2 ) = v8;
M64( d+s*3 ) = v8;
}
else
{
M32( d+s*0+0 ) = v4;
M32( d+s*0+4 ) = v4;
if( h == 1 ) return;
M32( d+s*1+0 ) = v4;
M32( d+s*1+4 ) = v4;
if( h == 2 ) return;
M32( d+s*2+0 ) = v4;
M32( d+s*2+4 ) = v4;
M32( d+s*3+0 ) = v4;
M32( d+s*3+4 ) = v4;
}
}
else if( w == 16 )
{
/* height 1, width 16 doesn't occur */
assert( h != 1 );
#if HAVE_VECTOREXT && defined(__SSE__)
v4si v16 = {v,v,v,v};
M128( d+s*0+0 ) = (__m128)v16;
M128( d+s*1+0 ) = (__m128)v16;
if( h == 2 ) return;
M128( d+s*2+0 ) = (__m128)v16;
M128( d+s*3+0 ) = (__m128)v16;
#else
if( WORD_SIZE == 8 )
{
do
{
M64( d+s*0+0 ) = v8;
M64( d+s*0+8 ) = v8;
M64( d+s*1+0 ) = v8;
M64( d+s*1+8 ) = v8;
h -= 2;
d += s*2;
} while( h );
}
else
{
do
{
M32( d+ 0 ) = v4;
M32( d+ 4 ) = v4;
M32( d+ 8 ) = v4;
M32( d+12 ) = v4;
d += s;
} while( --h );
}
#endif
}
else
assert(0);
}
extern void (*x264_cache_mv_func_table[10])(void *, uint32_t);\
extern void (*x264_cache_mvd_func_table[10])(void *, uint32_t);\
extern void (*x264_cache_ref_func_table[10])(void *, uint32_t);\
#define x264_macroblock_cache_mv_ptr( a, x, y, w, h, l, mv ) x264_macroblock_cache_mv( a, x, y, w, h, l, M32( mv ) )
static ALWAYS_INLINE void x264_macroblock_cache_mv( x264_t *h, int x, int y, int width, int height, int i_list, uint32_t mv )
{
void *mv_cache = &h->mb.cache.mv[i_list][X264_SCAN8_0+x+8*y];
if( x264_nonconstant_p( width ) || x264_nonconstant_p( height ) )
x264_cache_mv_func_table[width + (height<<1)-3]( mv_cache, mv );
else
x264_macroblock_cache_rect( mv_cache, width*4, height, 4, mv );
}
static ALWAYS_INLINE void x264_macroblock_cache_mvd( x264_t *h, int x, int y, int width, int height, int i_list, uint16_t mvd )
{
void *mvd_cache = &h->mb.cache.mvd[i_list][X264_SCAN8_0+x+8*y];
if( x264_nonconstant_p( width ) || x264_nonconstant_p( height ) )
x264_cache_mvd_func_table[width + (height<<1)-3]( mvd_cache, mvd );
else
x264_macroblock_cache_rect( mvd_cache, width*2, height, 2, mvd );
}
static ALWAYS_INLINE void x264_macroblock_cache_ref( x264_t *h, int x, int y, int width, int height, int i_list, uint8_t ref )
{
void *ref_cache = &h->mb.cache.ref[i_list][X264_SCAN8_0+x+8*y];
if( x264_nonconstant_p( width ) || x264_nonconstant_p( height ) )
x264_cache_ref_func_table[width + (height<<1)-3]( ref_cache, ref );
else
x264_macroblock_cache_rect( ref_cache, width, height, 1, ref );
}
static ALWAYS_INLINE void x264_macroblock_cache_skip( x264_t *h, int x, int y, int width, int height, int b_skip )
{
x264_macroblock_cache_rect( &h->mb.cache.skip[X264_SCAN8_0+x+8*y], width, height, 1, b_skip );
}
static ALWAYS_INLINE void x264_macroblock_cache_intra8x8_pred( x264_t *h, int x, int y, int i_mode )
{
x264_macroblock_cache_rect( &h->mb.cache.intra4x4_pred_mode[X264_SCAN8_0+x+8*y], 2, 2, 1, i_mode );
}

View file

@ -0,0 +1,379 @@
/*****************************************************************************
* set.c: quantization init
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
#define SHIFT(x,s) ((s)<=0 ? (x)<<-(s) : ((x)+(1<<((s)-1)))>>(s))
#define DIV(n,d) (((n) + ((d)>>1)) / (d))
static const uint8_t dequant4_scale[6][3] =
{
{ 10, 13, 16 },
{ 11, 14, 18 },
{ 13, 16, 20 },
{ 14, 18, 23 },
{ 16, 20, 25 },
{ 18, 23, 29 }
};
static const uint16_t quant4_scale[6][3] =
{
{ 13107, 8066, 5243 },
{ 11916, 7490, 4660 },
{ 10082, 6554, 4194 },
{ 9362, 5825, 3647 },
{ 8192, 5243, 3355 },
{ 7282, 4559, 2893 },
};
static const uint8_t quant8_scan[16] =
{
0,3,4,3, 3,1,5,1, 4,5,2,5, 3,1,5,1
};
static const uint8_t dequant8_scale[6][6] =
{
{ 20, 18, 32, 19, 25, 24 },
{ 22, 19, 35, 21, 28, 26 },
{ 26, 23, 42, 24, 33, 31 },
{ 28, 25, 45, 26, 35, 33 },
{ 32, 28, 51, 30, 40, 38 },
{ 36, 32, 58, 34, 46, 43 },
};
static const uint16_t quant8_scale[6][6] =
{
{ 13107, 11428, 20972, 12222, 16777, 15481 },
{ 11916, 10826, 19174, 11058, 14980, 14290 },
{ 10082, 8943, 15978, 9675, 12710, 11985 },
{ 9362, 8228, 14913, 8931, 11984, 11259 },
{ 8192, 7346, 13159, 7740, 10486, 9777 },
{ 7282, 6428, 11570, 6830, 9118, 8640 }
};
int x264_cqm_init( x264_t *h )
{
int def_quant4[6][16];
int def_quant8[6][64];
int def_dequant4[6][16];
int def_dequant8[6][64];
int quant4_mf[4][6][16];
int quant8_mf[4][6][64];
int deadzone[4] = { 32 - h->param.analyse.i_luma_deadzone[1],
32 - h->param.analyse.i_luma_deadzone[0],
32 - 11, 32 - 21 };
int max_qp_err = -1;
int max_chroma_qp_err = -1;
int min_qp_err = QP_MAX+1;
int num_8x8_lists = h->sps->i_chroma_format_idc == CHROMA_444 ? 4
: h->param.analyse.b_transform_8x8 ? 2 : 0; /* Checkasm may segfault if optimized out by --chroma-format */
#define CQM_ALLOC( w, count )\
for( int i = 0; i < count; i++ )\
{\
int size = w*w;\
int start = w == 8 ? 4 : 0;\
int j;\
for( j = 0; j < i; j++ )\
if( !memcmp( h->pps->scaling_list[i+start], h->pps->scaling_list[j+start], size*sizeof(uint8_t) ) )\
break;\
if( j < i )\
{\
h-> quant##w##_mf[i] = h-> quant##w##_mf[j];\
h->dequant##w##_mf[i] = h->dequant##w##_mf[j];\
h->unquant##w##_mf[i] = h->unquant##w##_mf[j];\
}\
else\
{\
CHECKED_MALLOC( h-> quant##w##_mf[i], (QP_MAX_SPEC+1)*size*sizeof(udctcoef) );\
CHECKED_MALLOC( h->dequant##w##_mf[i], 6*size*sizeof(int) );\
CHECKED_MALLOC( h->unquant##w##_mf[i], (QP_MAX_SPEC+1)*size*sizeof(int) );\
}\
for( j = 0; j < i; j++ )\
if( deadzone[j] == deadzone[i] &&\
!memcmp( h->pps->scaling_list[i+start], h->pps->scaling_list[j+start], size*sizeof(uint8_t) ) )\
break;\
if( j < i )\
{\
h->quant##w##_bias[i] = h->quant##w##_bias[j];\
h->quant##w##_bias0[i] = h->quant##w##_bias0[j];\
}\
else\
{\
CHECKED_MALLOC( h->quant##w##_bias[i], (QP_MAX_SPEC+1)*size*sizeof(udctcoef) );\
CHECKED_MALLOC( h->quant##w##_bias0[i], (QP_MAX_SPEC+1)*size*sizeof(udctcoef) );\
}\
}
CQM_ALLOC( 4, 4 )
CQM_ALLOC( 8, num_8x8_lists )
for( int q = 0; q < 6; q++ )
{
for( int i = 0; i < 16; i++ )
{
int j = (i&1) + ((i>>2)&1);
def_dequant4[q][i] = dequant4_scale[q][j];
def_quant4[q][i] = quant4_scale[q][j];
}
for( int i = 0; i < 64; i++ )
{
int j = quant8_scan[((i>>1)&12) | (i&3)];
def_dequant8[q][i] = dequant8_scale[q][j];
def_quant8[q][i] = quant8_scale[q][j];
}
}
for( int q = 0; q < 6; q++ )
{
for( int i_list = 0; i_list < 4; i_list++ )
for( int i = 0; i < 16; i++ )
{
h->dequant4_mf[i_list][q][i] = def_dequant4[q][i] * h->pps->scaling_list[i_list][i];
quant4_mf[i_list][q][i] = DIV(def_quant4[q][i] * 16, h->pps->scaling_list[i_list][i]);
}
for( int i_list = 0; i_list < num_8x8_lists; i_list++ )
for( int i = 0; i < 64; i++ )
{
h->dequant8_mf[i_list][q][i] = def_dequant8[q][i] * h->pps->scaling_list[4+i_list][i];
quant8_mf[i_list][q][i] = DIV(def_quant8[q][i] * 16, h->pps->scaling_list[4+i_list][i]);
}
}
for( int q = 0; q <= QP_MAX_SPEC; q++ )
{
int j;
for( int i_list = 0; i_list < 4; i_list++ )
for( int i = 0; i < 16; i++ )
{
h->unquant4_mf[i_list][q][i] = (1ULL << (q/6 + 15 + 8)) / quant4_mf[i_list][q%6][i];
h->quant4_mf[i_list][q][i] = j = SHIFT(quant4_mf[i_list][q%6][i], q/6 - 1);
if( !j )
{
min_qp_err = X264_MIN( min_qp_err, q );
continue;
}
// round to nearest, unless that would cause the deadzone to be negative
h->quant4_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j );
h->quant4_bias0[i_list][q][i] = (1<<15)/j;
if( j > 0xffff && q > max_qp_err && (i_list == CQM_4IY || i_list == CQM_4PY) )
max_qp_err = q;
if( j > 0xffff && q > max_chroma_qp_err && (i_list == CQM_4IC || i_list == CQM_4PC) )
max_chroma_qp_err = q;
}
if( h->param.analyse.b_transform_8x8 )
for( int i_list = 0; i_list < num_8x8_lists; i_list++ )
for( int i = 0; i < 64; i++ )
{
h->unquant8_mf[i_list][q][i] = (1ULL << (q/6 + 16 + 8)) / quant8_mf[i_list][q%6][i];
j = SHIFT(quant8_mf[i_list][q%6][i], q/6);
h->quant8_mf[i_list][q][i] = (uint16_t)j;
if( !j )
{
min_qp_err = X264_MIN( min_qp_err, q );
continue;
}
h->quant8_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j );
h->quant8_bias0[i_list][q][i] = (1<<15)/j;
if( j > 0xffff && q > max_qp_err && (i_list == CQM_8IY || i_list == CQM_8PY) )
max_qp_err = q;
if( j > 0xffff && q > max_chroma_qp_err && (i_list == CQM_8IC || i_list == CQM_8PC) )
max_chroma_qp_err = q;
}
}
/* Emergency mode denoising. */
x264_emms();
CHECKED_MALLOC( h->nr_offset_emergency, sizeof(*h->nr_offset_emergency)*(QP_MAX-QP_MAX_SPEC) );
for( int q = 0; q < QP_MAX - QP_MAX_SPEC; q++ )
for( int cat = 0; cat < 3 + CHROMA444; cat++ )
{
int dct8x8 = cat&1;
if( !h->param.analyse.b_transform_8x8 && dct8x8 )
continue;
int size = dct8x8 ? 64 : 16;
udctcoef *nr_offset = h->nr_offset_emergency[q][cat];
/* Denoise chroma first (due to h264's chroma QP offset), then luma, then DC. */
int dc_threshold = (QP_MAX-QP_MAX_SPEC)*2/3;
int luma_threshold = (QP_MAX-QP_MAX_SPEC)*2/3;
int chroma_threshold = 0;
for( int i = 0; i < size; i++ )
{
int max = (1 << (7 + BIT_DEPTH)) - 1;
/* True "emergency mode": remove all DCT coefficients */
if( q == QP_MAX - QP_MAX_SPEC - 1 )
{
nr_offset[i] = max;
continue;
}
int thresh = i == 0 ? dc_threshold : cat >= 2 ? chroma_threshold : luma_threshold;
if( q < thresh )
{
nr_offset[i] = 0;
continue;
}
double pos = (double)(q-thresh+1) / (QP_MAX - QP_MAX_SPEC - thresh);
/* XXX: this math is largely tuned for /dev/random input. */
double start = dct8x8 ? h->unquant8_mf[CQM_8PY][QP_MAX_SPEC][i]
: h->unquant4_mf[CQM_4PY][QP_MAX_SPEC][i];
/* Formula chosen as an exponential scale to vaguely mimic the effects
* of a higher quantizer. */
double bias = (pow( 2, pos*(QP_MAX - QP_MAX_SPEC)/10. )*0.003-0.003) * start;
nr_offset[i] = X264_MIN( bias + 0.5, max );
}
}
if( !h->mb.b_lossless )
{
while( h->chroma_qp_table[SPEC_QP(h->param.rc.i_qp_min)] <= max_chroma_qp_err )
h->param.rc.i_qp_min++;
if( min_qp_err <= h->param.rc.i_qp_max )
h->param.rc.i_qp_max = min_qp_err-1;
if( max_qp_err >= h->param.rc.i_qp_min )
h->param.rc.i_qp_min = max_qp_err+1;
/* If long level-codes aren't allowed, we need to allow QP high enough to avoid them. */
if( !h->param.b_cabac && h->sps->i_profile_idc < PROFILE_HIGH )
while( h->chroma_qp_table[SPEC_QP(h->param.rc.i_qp_max)] <= 12 || h->param.rc.i_qp_max <= 12 )
h->param.rc.i_qp_max++;
if( h->param.rc.i_qp_min > h->param.rc.i_qp_max )
{
x264_log( h, X264_LOG_ERROR, "Impossible QP constraints for CQM (min=%d, max=%d)\n", h->param.rc.i_qp_min, h->param.rc.i_qp_max );
return -1;
}
}
return 0;
fail:
x264_cqm_delete( h );
return -1;
}
#define CQM_DELETE( n, max )\
for( int i = 0; i < (max); i++ )\
{\
int j;\
for( j = 0; j < i; j++ )\
if( h->quant##n##_mf[i] == h->quant##n##_mf[j] )\
break;\
if( j == i )\
{\
x264_free( h-> quant##n##_mf[i] );\
x264_free( h->dequant##n##_mf[i] );\
x264_free( h->unquant##n##_mf[i] );\
}\
for( j = 0; j < i; j++ )\
if( h->quant##n##_bias[i] == h->quant##n##_bias[j] )\
break;\
if( j == i )\
{\
x264_free( h->quant##n##_bias[i] );\
x264_free( h->quant##n##_bias0[i] );\
}\
}
void x264_cqm_delete( x264_t *h )
{
CQM_DELETE( 4, 4 );
CQM_DELETE( 8, CHROMA444 ? 4 : 2 );
x264_free( h->nr_offset_emergency );
}
static int x264_cqm_parse_jmlist( x264_t *h, const char *buf, const char *name,
uint8_t *cqm, const uint8_t *jvt, int length )
{
int i;
char *p = strstr( buf, name );
if( !p )
{
memset( cqm, 16, length );
return 0;
}
p += strlen( name );
if( *p == 'U' || *p == 'V' )
p++;
char *nextvar = strstr( p, "INT" );
for( i = 0; i < length && (p = strpbrk( p, " \t\n," )) && (p = strpbrk( p, "0123456789" )); i++ )
{
int coef = -1;
sscanf( p, "%d", &coef );
if( i == 0 && coef == 0 )
{
memcpy( cqm, jvt, length );
return 0;
}
if( coef < 1 || coef > 255 )
{
x264_log( h, X264_LOG_ERROR, "bad coefficient in list '%s'\n", name );
return -1;
}
cqm[i] = coef;
}
if( (nextvar && p > nextvar) || i != length )
{
x264_log( h, X264_LOG_ERROR, "not enough coefficients in list '%s'\n", name );
return -1;
}
return 0;
}
int x264_cqm_parse_file( x264_t *h, const char *filename )
{
char *p;
int b_error = 0;
h->param.i_cqm_preset = X264_CQM_CUSTOM;
char *buf = x264_slurp_file( filename );
if( !buf )
{
x264_log( h, X264_LOG_ERROR, "can't open file '%s'\n", filename );
return -1;
}
while( (p = strchr( buf, '#' )) != NULL )
memset( p, ' ', strcspn( p, "\n" ) );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA4X4_LUMA", h->param.cqm_4iy, x264_cqm_jvt4i, 16 );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTER4X4_LUMA", h->param.cqm_4py, x264_cqm_jvt4p, 16 );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA4X4_CHROMA", h->param.cqm_4ic, x264_cqm_jvt4i, 16 );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTER4X4_CHROMA", h->param.cqm_4pc, x264_cqm_jvt4p, 16 );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA8X8_LUMA", h->param.cqm_8iy, x264_cqm_jvt8i, 64 );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTER8X8_LUMA", h->param.cqm_8py, x264_cqm_jvt8p, 64 );
if( CHROMA444 )
{
b_error |= x264_cqm_parse_jmlist( h, buf, "INTRA8X8_CHROMA", h->param.cqm_8ic, x264_cqm_jvt8i, 64 );
b_error |= x264_cqm_parse_jmlist( h, buf, "INTER8X8_CHROMA", h->param.cqm_8pc, x264_cqm_jvt8p, 64 );
}
x264_free( buf );
return b_error;
}

View file

@ -0,0 +1,347 @@
/*****************************************************************************
* set.h: quantization init
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_SET_H
#define X264_SET_H
enum profile_e
{
PROFILE_BASELINE = 66,
PROFILE_MAIN = 77,
PROFILE_HIGH = 100,
PROFILE_HIGH10 = 110,
PROFILE_HIGH422 = 122,
PROFILE_HIGH444_PREDICTIVE = 244,
};
enum chroma_format_e
{
CHROMA_400 = 0,
CHROMA_420 = 1,
CHROMA_422 = 2,
CHROMA_444 = 3,
};
enum cqm4_e
{
CQM_4IY = 0,
CQM_4PY = 1,
CQM_4IC = 2,
CQM_4PC = 3
};
enum cqm8_e
{
CQM_8IY = 0,
CQM_8PY = 1,
CQM_8IC = 2,
CQM_8PC = 3,
};
typedef struct
{
int i_id;
int i_profile_idc;
int i_level_idc;
int b_constraint_set0;
int b_constraint_set1;
int b_constraint_set2;
int b_constraint_set3;
int i_log2_max_frame_num;
int i_poc_type;
/* poc 0 */
int i_log2_max_poc_lsb;
int i_num_ref_frames;
int b_gaps_in_frame_num_value_allowed;
int i_mb_width;
int i_mb_height;
int b_frame_mbs_only;
int b_mb_adaptive_frame_field;
int b_direct8x8_inference;
int b_crop;
struct
{
int i_left;
int i_right;
int i_top;
int i_bottom;
} crop;
int b_vui;
struct
{
int b_aspect_ratio_info_present;
int i_sar_width;
int i_sar_height;
int b_overscan_info_present;
int b_overscan_info;
int b_signal_type_present;
int i_vidformat;
int b_fullrange;
int b_color_description_present;
int i_colorprim;
int i_transfer;
int i_colmatrix;
int b_chroma_loc_info_present;
int i_chroma_loc_top;
int i_chroma_loc_bottom;
int b_timing_info_present;
uint32_t i_num_units_in_tick;
uint32_t i_time_scale;
int b_fixed_frame_rate;
int b_nal_hrd_parameters_present;
int b_vcl_hrd_parameters_present;
struct
{
int i_cpb_cnt;
int i_bit_rate_scale;
int i_cpb_size_scale;
int i_bit_rate_value;
int i_cpb_size_value;
int i_bit_rate_unscaled;
int i_cpb_size_unscaled;
int b_cbr_hrd;
int i_initial_cpb_removal_delay_length;
int i_cpb_removal_delay_length;
int i_dpb_output_delay_length;
int i_time_offset_length;
} hrd;
int b_pic_struct_present;
int b_bitstream_restriction;
int b_motion_vectors_over_pic_boundaries;
int i_max_bytes_per_pic_denom;
int i_max_bits_per_mb_denom;
int i_log2_max_mv_length_horizontal;
int i_log2_max_mv_length_vertical;
int i_num_reorder_frames;
int i_max_dec_frame_buffering;
/* FIXME to complete */
} vui;
int b_qpprime_y_zero_transform_bypass;
int i_chroma_format_idc;
} x264_sps_t;
typedef struct
{
int i_id;
int i_sps_id;
int b_cabac;
int b_pic_order;
int i_num_slice_groups;
int i_num_ref_idx_l0_default_active;
int i_num_ref_idx_l1_default_active;
int b_weighted_pred;
int b_weighted_bipred;
int i_pic_init_qp;
int i_pic_init_qs;
int i_chroma_qp_index_offset;
int b_deblocking_filter_control;
int b_constrained_intra_pred;
int b_redundant_pic_cnt;
int b_transform_8x8_mode;
int i_cqm_preset;
const uint8_t *scaling_list[8]; /* could be 12, but we don't allow separate Cb/Cr lists */
} x264_pps_t;
/* default quant matrices */
static const uint8_t x264_cqm_jvt4i[16] =
{
6,13,20,28,
13,20,28,32,
20,28,32,37,
28,32,37,42
};
static const uint8_t x264_cqm_jvt4p[16] =
{
10,14,20,24,
14,20,24,27,
20,24,27,30,
24,27,30,34
};
static const uint8_t x264_cqm_jvt8i[64] =
{
6,10,13,16,18,23,25,27,
10,11,16,18,23,25,27,29,
13,16,18,23,25,27,29,31,
16,18,23,25,27,29,31,33,
18,23,25,27,29,31,33,36,
23,25,27,29,31,33,36,38,
25,27,29,31,33,36,38,40,
27,29,31,33,36,38,40,42
};
static const uint8_t x264_cqm_jvt8p[64] =
{
9,13,15,17,19,21,22,24,
13,13,17,19,21,22,24,25,
15,17,19,21,22,24,25,27,
17,19,21,22,24,25,27,28,
19,21,22,24,25,27,28,30,
21,22,24,25,27,28,30,32,
22,24,25,27,28,30,32,33,
24,25,27,28,30,32,33,35
};
static const uint8_t x264_cqm_flat16[64] =
{
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16
};
static const uint8_t * const x264_cqm_jvt[8] =
{
x264_cqm_jvt4i, x264_cqm_jvt4p,
x264_cqm_jvt4i, x264_cqm_jvt4p,
x264_cqm_jvt8i, x264_cqm_jvt8p,
x264_cqm_jvt8i, x264_cqm_jvt8p
};
// 1080i25_avci50, 1080p25_avci50
static const uint8_t x264_cqm_avci50_4ic[16] =
{
16,22,28,40,
22,28,40,44,
28,40,44,48,
40,44,48,60
};
// 1080i25_avci50,
static const uint8_t x264_cqm_avci50_1080i_8iy[64] =
{
16,18,19,21,27,33,81,87,
18,19,21,24,30,33,81,87,
19,21,24,27,30,78,84,90,
21,24,27,30,33,78,84,90,
24,27,30,33,78,81,84,90,
24,27,30,33,78,81,84,93,
27,30,33,78,78,81,87,93,
30,33,33,78,81,84,87,96
};
// 1080p25_avci50, 720p25_avci50, 720p50_avci50
static const uint8_t x264_cqm_avci50_p_8iy[64] =
{
16,18,19,21,24,27,30,33,
18,19,21,24,27,30,33,78,
19,21,24,27,30,33,78,81,
21,24,27,30,33,78,81,84,
24,27,30,33,78,81,84,87,
27,30,33,78,81,84,87,90,
30,33,78,81,84,87,90,93,
33,78,81,84,87,90,93,96
};
// 1080i25_avci100, 1080p25_avci100
static const uint8_t x264_cqm_avci100_1080_4ic[16] =
{
16,20,26,32,
20,26,32,38,
26,32,38,44,
32,38,44,50
};
// 720p25_avci100, 720p50_avci100
static const uint8_t x264_cqm_avci100_720p_4ic[16] =
{
16,21,27,34,
21,27,34,41,
27,34,41,46,
34,41,46,54
};
// 1080i25_avci100,
static const uint8_t x264_cqm_avci100_1080i_8iy[64] =
{
16,19,20,23,24,26,32,42,
18,19,22,24,26,32,36,42,
18,20,23,24,26,32,36,63,
19,20,23,26,32,36,42,63,
20,22,24,26,32,36,59,63,
22,23,24,26,32,36,59,68,
22,23,24,26,32,42,59,68,
22,23,24,26,36,42,59,72
};
// 1080p25_avci100,
static const uint8_t x264_cqm_avci100_1080p_8iy[64] =
{
16,18,19,20,22,23,24,26,
18,19,20,22,23,24,26,32,
19,20,22,23,24,26,32,36,
20,22,23,24,26,32,36,42,
22,23,24,26,32,36,42,59,
23,24,26,32,36,42,59,63,
24,26,32,36,42,59,63,68,
26,32,36,42,59,63,68,72
};
// 720p25_avci100, 720p50_avci100
static const uint8_t x264_cqm_avci100_720p_8iy[64] =
{
16,18,19,21,22,24,26,32,
18,19,19,21,22,24,26,32,
19,19,21,22,22,24,26,32,
21,21,22,22,23,24,26,34,
22,22,22,23,24,25,26,34,
24,24,24,24,25,26,34,36,
26,26,26,26,26,34,36,38,
32,32,32,34,34,36,38,42
};
int x264_cqm_init( x264_t *h );
void x264_cqm_delete( x264_t *h );
int x264_cqm_parse_file( x264_t *h, const char *filename );
#endif

View file

@ -0,0 +1,164 @@
/*****************************************************************************
* threadpool.c: thread pooling
*****************************************************************************
* Copyright (C) 2010-2017 x264 project
*
* Authors: Steven Walters <kemuri9@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
typedef struct
{
void *(*func)(void *);
void *arg;
void *ret;
} x264_threadpool_job_t;
struct x264_threadpool_t
{
int exit;
int threads;
x264_pthread_t *thread_handle;
void (*init_func)(void *);
void *init_arg;
/* requires a synchronized list structure and associated methods,
so use what is already implemented for frames */
x264_sync_frame_list_t uninit; /* list of jobs that are awaiting use */
x264_sync_frame_list_t run; /* list of jobs that are queued for processing by the pool */
x264_sync_frame_list_t done; /* list of jobs that have finished processing */
};
static void *x264_threadpool_thread( x264_threadpool_t *pool )
{
if( pool->init_func )
pool->init_func( pool->init_arg );
while( !pool->exit )
{
x264_threadpool_job_t *job = NULL;
x264_pthread_mutex_lock( &pool->run.mutex );
while( !pool->exit && !pool->run.i_size )
x264_pthread_cond_wait( &pool->run.cv_fill, &pool->run.mutex );
if( pool->run.i_size )
{
job = (void*)x264_frame_shift( pool->run.list );
pool->run.i_size--;
}
x264_pthread_mutex_unlock( &pool->run.mutex );
if( !job )
continue;
job->ret = (void*)x264_stack_align( job->func, job->arg ); /* execute the function */
x264_sync_frame_list_push( &pool->done, (void*)job );
}
return NULL;
}
int x264_threadpool_init( x264_threadpool_t **p_pool, int threads,
void (*init_func)(void *), void *init_arg )
{
if( threads <= 0 )
return -1;
x264_threadpool_t *pool;
CHECKED_MALLOCZERO( pool, sizeof(x264_threadpool_t) );
*p_pool = pool;
pool->init_func = init_func;
pool->init_arg = init_arg;
pool->threads = threads;
CHECKED_MALLOC( pool->thread_handle, pool->threads * sizeof(x264_pthread_t) );
if( x264_sync_frame_list_init( &pool->uninit, pool->threads ) ||
x264_sync_frame_list_init( &pool->run, pool->threads ) ||
x264_sync_frame_list_init( &pool->done, pool->threads ) )
goto fail;
for( int i = 0; i < pool->threads; i++ )
{
x264_threadpool_job_t *job;
CHECKED_MALLOC( job, sizeof(x264_threadpool_job_t) );
x264_sync_frame_list_push( &pool->uninit, (void*)job );
}
for( int i = 0; i < pool->threads; i++ )
if( x264_pthread_create( pool->thread_handle+i, NULL, (void*)x264_threadpool_thread, pool ) )
goto fail;
return 0;
fail:
return -1;
}
void x264_threadpool_run( x264_threadpool_t *pool, void *(*func)(void *), void *arg )
{
x264_threadpool_job_t *job = (void*)x264_sync_frame_list_pop( &pool->uninit );
job->func = func;
job->arg = arg;
x264_sync_frame_list_push( &pool->run, (void*)job );
}
void *x264_threadpool_wait( x264_threadpool_t *pool, void *arg )
{
x264_pthread_mutex_lock( &pool->done.mutex );
while( 1 )
{
for( int i = 0; i < pool->done.i_size; i++ )
if( ((x264_threadpool_job_t*)pool->done.list[i])->arg == arg )
{
x264_threadpool_job_t *job = (void*)x264_frame_shift( pool->done.list+i );
pool->done.i_size--;
x264_pthread_mutex_unlock( &pool->done.mutex );
void *ret = job->ret;
x264_sync_frame_list_push( &pool->uninit, (void*)job );
return ret;
}
x264_pthread_cond_wait( &pool->done.cv_fill, &pool->done.mutex );
}
}
static void x264_threadpool_list_delete( x264_sync_frame_list_t *slist )
{
for( int i = 0; slist->list[i]; i++ )
{
x264_free( slist->list[i] );
slist->list[i] = NULL;
}
x264_sync_frame_list_delete( slist );
}
void x264_threadpool_delete( x264_threadpool_t *pool )
{
x264_pthread_mutex_lock( &pool->run.mutex );
pool->exit = 1;
x264_pthread_cond_broadcast( &pool->run.cv_fill );
x264_pthread_mutex_unlock( &pool->run.mutex );
for( int i = 0; i < pool->threads; i++ )
x264_pthread_join( pool->thread_handle[i], NULL );
x264_threadpool_list_delete( &pool->uninit );
x264_threadpool_list_delete( &pool->run );
x264_threadpool_list_delete( &pool->done );
x264_free( pool->thread_handle );
x264_free( pool );
}

View file

@ -0,0 +1,44 @@
/*****************************************************************************
* threadpool.h: thread pooling
*****************************************************************************
* Copyright (C) 2010-2017 x264 project
*
* Authors: Steven Walters <kemuri9@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_THREADPOOL_H
#define X264_THREADPOOL_H
typedef struct x264_threadpool_t x264_threadpool_t;
#if HAVE_THREAD
int x264_threadpool_init( x264_threadpool_t **p_pool, int threads,
void (*init_func)(void *), void *init_arg );
void x264_threadpool_run( x264_threadpool_t *pool, void *(*func)(void *), void *arg );
void *x264_threadpool_wait( x264_threadpool_t *pool, void *arg );
void x264_threadpool_delete( x264_threadpool_t *pool );
#else
#define x264_threadpool_init(p,t,f,a) -1
#define x264_threadpool_run(p,f,a)
#define x264_threadpool_wait(p,a) NULL
#define x264_threadpool_delete(p)
#endif
#endif

View file

@ -0,0 +1,869 @@
/*****************************************************************************
* vlc.c : vlc tables
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Fiona Glaser <fiona@x264.com>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common.h"
/* [nC] */
const vlc_t x264_coeff0_token[6] =
{
{ 0x1, 1 }, /* str=1 */
{ 0x3, 2 }, /* str=11 */
{ 0xf, 4 }, /* str=1111 */
{ 0x3, 6 }, /* str=000011 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 1 }, /* str=1 */
};
/* [nC][i_total_coeff-1][i_trailing] */
const vlc_t x264_coeff_token[6][16][4] =
{
{ /* table 0 */
{ /* i_total 1 */
{ 0x5, 6 }, /* str=000101 */
{ 0x1, 2 }, /* str=01 */
},
{ /* i_total 2 */
{ 0x7, 8 }, /* str=00000111 */
{ 0x4, 6 }, /* str=000100 */
{ 0x1, 3 }, /* str=001 */
},
{ /* i_total 3 */
{ 0x7, 9 }, /* str=000000111 */
{ 0x6, 8 }, /* str=00000110 */
{ 0x5, 7 }, /* str=0000101 */
{ 0x3, 5 }, /* str=00011 */
},
{ /* i_total 4 */
{ 0x7, 10 }, /* str=0000000111 */
{ 0x6, 9 }, /* str=000000110 */
{ 0x5, 8 }, /* str=00000101 */
{ 0x3, 6 }, /* str=000011 */
},
{ /* i_total 5 */
{ 0x7, 11 }, /* str=00000000111 */
{ 0x6, 10 }, /* str=0000000110 */
{ 0x5, 9 }, /* str=000000101 */
{ 0x4, 7 }, /* str=0000100 */
},
{ /* i_total 6 */
{ 0xf, 13 }, /* str=0000000001111 */
{ 0x6, 11 }, /* str=00000000110 */
{ 0x5, 10 }, /* str=0000000101 */
{ 0x4, 8 }, /* str=00000100 */
},
{ /* i_total 7 */
{ 0xb, 13 }, /* str=0000000001011 */
{ 0xe, 13 }, /* str=0000000001110 */
{ 0x5, 11 }, /* str=00000000101 */
{ 0x4, 9 }, /* str=000000100 */
},
{ /* i_total 8 */
{ 0x8, 13 }, /* str=0000000001000 */
{ 0xa, 13 }, /* str=0000000001010 */
{ 0xd, 13 }, /* str=0000000001101 */
{ 0x4, 10 }, /* str=0000000100 */
},
{ /* i_total 9 */
{ 0xf, 14 }, /* str=00000000001111 */
{ 0xe, 14 }, /* str=00000000001110 */
{ 0x9, 13 }, /* str=0000000001001 */
{ 0x4, 11 }, /* str=00000000100 */
},
{ /* i_total 10 */
{ 0xb, 14 }, /* str=00000000001011 */
{ 0xa, 14 }, /* str=00000000001010 */
{ 0xd, 14 }, /* str=00000000001101 */
{ 0xc, 13 }, /* str=0000000001100 */
},
{ /* i_total 14 */
{ 0xf, 15 }, /* str=000000000001111 */
{ 0xe, 15 }, /* str=000000000001110 */
{ 0x9, 14 }, /* str=00000000001001 */
{ 0xc, 14 }, /* str=00000000001100 */
},
{ /* i_total 12 */
{ 0xb, 15 }, /* str=000000000001011 */
{ 0xa, 15 }, /* str=000000000001010 */
{ 0xd, 15 }, /* str=000000000001101 */
{ 0x8, 14 }, /* str=00000000001000 */
},
{ /* i_total 13 */
{ 0xf, 16 }, /* str=0000000000001111 */
{ 0x1, 15 }, /* str=000000000000001 */
{ 0x9, 15 }, /* str=000000000001001 */
{ 0xc, 15 }, /* str=000000000001100 */
},
{ /* i_total 14 */
{ 0xb, 16 }, /* str=0000000000001011 */
{ 0xe, 16 }, /* str=0000000000001110 */
{ 0xd, 16 }, /* str=0000000000001101 */
{ 0x8, 15 }, /* str=000000000001000 */
},
{ /* i_total 15 */
{ 0x7, 16 }, /* str=0000000000000111 */
{ 0xa, 16 }, /* str=0000000000001010 */
{ 0x9, 16 }, /* str=0000000000001001 */
{ 0xc, 16 }, /* str=0000000000001100 */
},
{ /* i_total 16 */
{ 0x4, 16 }, /* str=0000000000000100 */
{ 0x6, 16 }, /* str=0000000000000110 */
{ 0x5, 16 }, /* str=0000000000000101 */
{ 0x8, 16 }, /* str=0000000000001000 */
},
},
{ /* table 1 */
{ /* i_total 1 */
{ 0xb, 6 }, /* str=001011 */
{ 0x2, 2 }, /* str=10 */
},
{ /* i_total 2 */
{ 0x7, 6 }, /* str=000111 */
{ 0x7, 5 }, /* str=00111 */
{ 0x3, 3 }, /* str=011 */
},
{ /* i_total 3 */
{ 0x7, 7 }, /* str=0000111 */
{ 0xa, 6 }, /* str=001010 */
{ 0x9, 6 }, /* str=001001 */
{ 0x5, 4 }, /* str=0101 */
},
{ /* i_total 4 */
{ 0x7, 8 }, /* str=00000111 */
{ 0x6, 6 }, /* str=000110 */
{ 0x5, 6 }, /* str=000101 */
{ 0x4, 4 }, /* str=0100 */
},
{ /* i_total 5 */
{ 0x4, 8 }, /* str=00000100 */
{ 0x6, 7 }, /* str=0000110 */
{ 0x5, 7 }, /* str=0000101 */
{ 0x6, 5 }, /* str=00110 */
},
{ /* i_total 6 */
{ 0x7, 9 }, /* str=000000111 */
{ 0x6, 8 }, /* str=00000110 */
{ 0x5, 8 }, /* str=00000101 */
{ 0x8, 6 }, /* str=001000 */
},
{ /* i_total 7 */
{ 0xf, 11 }, /* str=00000001111 */
{ 0x6, 9 }, /* str=000000110 */
{ 0x5, 9 }, /* str=000000101 */
{ 0x4, 6 }, /* str=000100 */
},
{ /* i_total 8 */
{ 0xb, 11 }, /* str=00000001011 */
{ 0xe, 11 }, /* str=00000001110 */
{ 0xd, 11 }, /* str=00000001101 */
{ 0x4, 7 }, /* str=0000100 */
},
{ /* i_total 9 */
{ 0xf, 12 }, /* str=000000001111 */
{ 0xa, 11 }, /* str=00000001010 */
{ 0x9, 11 }, /* str=00000001001 */
{ 0x4, 9 }, /* str=000000100 */
},
{ /* i_total 10 */
{ 0xb, 12 }, /* str=000000001011 */
{ 0xe, 12 }, /* str=000000001110 */
{ 0xd, 12 }, /* str=000000001101 */
{ 0xc, 11 }, /* str=00000001100 */
},
{ /* i_total 11 */
{ 0x8, 12 }, /* str=000000001000 */
{ 0xa, 12 }, /* str=000000001010 */
{ 0x9, 12 }, /* str=000000001001 */
{ 0x8, 11 }, /* str=00000001000 */
},
{ /* i_total 12 */
{ 0xf, 13 }, /* str=0000000001111 */
{ 0xe, 13 }, /* str=0000000001110 */
{ 0xd, 13 }, /* str=0000000001101 */
{ 0xc, 12 }, /* str=000000001100 */
},
{ /* i_total 13 */
{ 0xb, 13 }, /* str=0000000001011 */
{ 0xa, 13 }, /* str=0000000001010 */
{ 0x9, 13 }, /* str=0000000001001 */
{ 0xc, 13 }, /* str=0000000001100 */
},
{ /* i_total 14 */
{ 0x7, 13 }, /* str=0000000000111 */
{ 0xb, 14 }, /* str=00000000001011 */
{ 0x6, 13 }, /* str=0000000000110 */
{ 0x8, 13 }, /* str=0000000001000 */
},
{ /* i_total 15 */
{ 0x9, 14 }, /* str=00000000001001 */
{ 0x8, 14 }, /* str=00000000001000 */
{ 0xa, 14 }, /* str=00000000001010 */
{ 0x1, 13 }, /* str=0000000000001 */
},
{ /* i_total 16 */
{ 0x7, 14 }, /* str=00000000000111 */
{ 0x6, 14 }, /* str=00000000000110 */
{ 0x5, 14 }, /* str=00000000000101 */
{ 0x4, 14 }, /* str=00000000000100 */
},
},
{ /* table 2 */
{ /* i_total 1 */
{ 0xf, 6 }, /* str=001111 */
{ 0xe, 4 }, /* str=1110 */
},
{ /* i_total 2 */
{ 0xb, 6 }, /* str=001011 */
{ 0xf, 5 }, /* str=01111 */
{ 0xd, 4 }, /* str=1101 */
},
{ /* i_total 3 */
{ 0x8, 6 }, /* str=001000 */
{ 0xc, 5 }, /* str=01100 */
{ 0xe, 5 }, /* str=01110 */
{ 0xc, 4 }, /* str=1100 */
},
{ /* i_total 4 */
{ 0xf, 7 }, /* str=0001111 */
{ 0xa, 5 }, /* str=01010 */
{ 0xb, 5 }, /* str=01011 */
{ 0xb, 4 }, /* str=1011 */
},
{ /* i_total 5 */
{ 0xb, 7 }, /* str=0001011 */
{ 0x8, 5 }, /* str=01000 */
{ 0x9, 5 }, /* str=01001 */
{ 0xa, 4 }, /* str=1010 */
},
{ /* i_total 6 */
{ 0x9, 7 }, /* str=0001001 */
{ 0xe, 6 }, /* str=001110 */
{ 0xd, 6 }, /* str=001101 */
{ 0x9, 4 }, /* str=1001 */
},
{ /* i_total 7 */
{ 0x8, 7 }, /* str=0001000 */
{ 0xa, 6 }, /* str=001010 */
{ 0x9, 6 }, /* str=001001 */
{ 0x8, 4 }, /* str=1000 */
},
{ /* i_total 8 */
{ 0xf, 8 }, /* str=00001111 */
{ 0xe, 7 }, /* str=0001110 */
{ 0xd, 7 }, /* str=0001101 */
{ 0xd, 5 }, /* str=01101 */
},
{ /* i_total 9 */
{ 0xb, 8 }, /* str=00001011 */
{ 0xe, 8 }, /* str=00001110 */
{ 0xa, 7 }, /* str=0001010 */
{ 0xc, 6 }, /* str=001100 */
},
{ /* i_total 10 */
{ 0xf, 9 }, /* str=000001111 */
{ 0xa, 8 }, /* str=00001010 */
{ 0xd, 8 }, /* str=00001101 */
{ 0xc, 7 }, /* str=0001100 */
},
{ /* i_total 11 */
{ 0xb, 9 }, /* str=000001011 */
{ 0xe, 9 }, /* str=000001110 */
{ 0x9, 8 }, /* str=00001001 */
{ 0xc, 8 }, /* str=00001100 */
},
{ /* i_total 12 */
{ 0x8, 9 }, /* str=000001000 */
{ 0xa, 9 }, /* str=000001010 */
{ 0xd, 9 }, /* str=000001101 */
{ 0x8, 8 }, /* str=00001000 */
},
{ /* i_total 13 */
{ 0xd, 10 }, /* str=0000001101 */
{ 0x7, 9 }, /* str=000000111 */
{ 0x9, 9 }, /* str=000001001 */
{ 0xc, 9 }, /* str=000001100 */
},
{ /* i_total 14 */
{ 0x9, 10 }, /* str=0000001001 */
{ 0xc, 10 }, /* str=0000001100 */
{ 0xb, 10 }, /* str=0000001011 */
{ 0xa, 10 }, /* str=0000001010 */
},
{ /* i_total 15 */
{ 0x5, 10 }, /* str=0000000101 */
{ 0x8, 10 }, /* str=0000001000 */
{ 0x7, 10 }, /* str=0000000111 */
{ 0x6, 10 }, /* str=0000000110 */
},
{ /* i_total 16 */
{ 0x1, 10 }, /* str=0000000001 */
{ 0x4, 10 }, /* str=0000000100 */
{ 0x3, 10 }, /* str=0000000011 */
{ 0x2, 10 }, /* str=0000000010 */
},
},
{ /* table 3 */
{ /* i_total 1 */
{ 0x0, 6 }, /* str=000000 */
{ 0x1, 6 }, /* str=000001 */
},
{ /* i_total 2 */
{ 0x4, 6 }, /* str=000100 */
{ 0x5, 6 }, /* str=000101 */
{ 0x6, 6 }, /* str=000110 */
},
{ /* i_total 3 */
{ 0x8, 6 }, /* str=001000 */
{ 0x9, 6 }, /* str=001001 */
{ 0xa, 6 }, /* str=001010 */
{ 0xb, 6 }, /* str=001011 */
},
{ /* i_total 4 */
{ 0xc, 6 }, /* str=001100 */
{ 0xd, 6 }, /* str=001101 */
{ 0xe, 6 }, /* str=001110 */
{ 0xf, 6 }, /* str=001111 */
},
{ /* i_total 5 */
{ 0x10, 6 }, /* str=010000 */
{ 0x11, 6 }, /* str=010001 */
{ 0x12, 6 }, /* str=010010 */
{ 0x13, 6 }, /* str=010011 */
},
{ /* i_total 6 */
{ 0x14, 6 }, /* str=010100 */
{ 0x15, 6 }, /* str=010101 */
{ 0x16, 6 }, /* str=010110 */
{ 0x17, 6 }, /* str=010111 */
},
{ /* i_total 7 */
{ 0x18, 6 }, /* str=011000 */
{ 0x19, 6 }, /* str=011001 */
{ 0x1a, 6 }, /* str=011010 */
{ 0x1b, 6 }, /* str=011011 */
},
{ /* i_total 8 */
{ 0x1c, 6 }, /* str=011100 */
{ 0x1d, 6 }, /* str=011101 */
{ 0x1e, 6 }, /* str=011110 */
{ 0x1f, 6 }, /* str=011111 */
},
{ /* i_total 9 */
{ 0x20, 6 }, /* str=100000 */
{ 0x21, 6 }, /* str=100001 */
{ 0x22, 6 }, /* str=100010 */
{ 0x23, 6 }, /* str=100011 */
},
{ /* i_total 10 */
{ 0x24, 6 }, /* str=100100 */
{ 0x25, 6 }, /* str=100101 */
{ 0x26, 6 }, /* str=100110 */
{ 0x27, 6 }, /* str=100111 */
},
{ /* i_total 11 */
{ 0x28, 6 }, /* str=101000 */
{ 0x29, 6 }, /* str=101001 */
{ 0x2a, 6 }, /* str=101010 */
{ 0x2b, 6 }, /* str=101011 */
},
{ /* i_total 12 */
{ 0x2c, 6 }, /* str=101100 */
{ 0x2d, 6 }, /* str=101101 */
{ 0x2e, 6 }, /* str=101110 */
{ 0x2f, 6 }, /* str=101111 */
},
{ /* i_total 13 */
{ 0x30, 6 }, /* str=110000 */
{ 0x31, 6 }, /* str=110001 */
{ 0x32, 6 }, /* str=110010 */
{ 0x33, 6 }, /* str=110011 */
},
{ /* i_total 14 */
{ 0x34, 6 }, /* str=110100 */
{ 0x35, 6 }, /* str=110101 */
{ 0x36, 6 }, /* str=110110 */
{ 0x37, 6 }, /* str=110111 */
},
{ /* i_total 15 */
{ 0x38, 6 }, /* str=111000 */
{ 0x39, 6 }, /* str=111001 */
{ 0x3a, 6 }, /* str=111010 */
{ 0x3b, 6 }, /* str=111011 */
},
{ /* i_total 16 */
{ 0x3c, 6 }, /* str=111100 */
{ 0x3d, 6 }, /* str=111101 */
{ 0x3e, 6 }, /* str=111110 */
{ 0x3f, 6 }, /* str=111111 */
},
},
{ /* table 4 */
{ /* i_total 1 */
{ 0x7, 6 }, /* str=000111 */
{ 0x1, 1 }, /* str=1 */
},
{ /* i_total 2 */
{ 0x4, 6 }, /* str=000100 */
{ 0x6, 6 }, /* str=000110 */
{ 0x1, 3 }, /* str=001 */
},
{ /* i_total 3 */
{ 0x3, 6 }, /* str=000011 */
{ 0x3, 7 }, /* str=0000011 */
{ 0x2, 7 }, /* str=0000010 */
{ 0x5, 6 }, /* str=000101 */
},
{ /* i_total 4 */
{ 0x2, 6 }, /* str=000010 */
{ 0x3, 8 }, /* str=00000011 */
{ 0x2, 8 }, /* str=00000010 */
{ 0x0, 7 }, /* str=0000000 */
},
},
{ /* table 5 */
{ /* i_total 1 */
{ 0xf, 7 }, /* str=0001111 */
{ 0x1, 2 }, /* str=01 */
},
{ /* i_total 2 */
{ 0xe, 7 }, /* str=0001110 */
{ 0xd, 7 }, /* str=0001101 */
{ 0x1, 3 }, /* str=001 */
},
{ /* i_total 3 */
{ 0x7, 9 }, /* str=000000111 */
{ 0xc, 7 }, /* str=0001100 */
{ 0xb, 7 }, /* str=0001011 */
{ 0x1, 5 }, /* str=00001 */
},
{ /* i_total 4 */
{ 0x6, 9 }, /* str=000000110 */
{ 0x5, 9 }, /* str=000000101 */
{ 0xa, 7 }, /* str=0001010 */
{ 0x1, 6 }, /* str=000001 */
},
{ /* i_total 5 */
{ 0x7, 10 }, /* str=0000000111 */
{ 0x6, 10 }, /* str=0000000110 */
{ 0x4, 9 }, /* str=000000100 */
{ 0x9, 7 }, /* str=0001001 */
},
{ /* i_total 6 */
{ 0x7, 11 }, /* str=00000000111 */
{ 0x6, 11 }, /* str=00000000110 */
{ 0x5, 10 }, /* str=0000000101 */
{ 0x8, 7 }, /* str=0001000 */
},
{ /* i_total 7 */
{ 0x7, 12 }, /* str=000000000111 */
{ 0x6, 12 }, /* str=000000000110 */
{ 0x5, 11 }, /* str=00000000101 */
{ 0x4, 10 }, /* str=0000000100 */
},
{ /* i_total 8 */
{ 0x7, 13 }, /* str=0000000000111 */
{ 0x5, 12 }, /* str=000000000101 */
{ 0x4, 12 }, /* str=000000000100 */
{ 0x4, 11 }, /* str=00000000100 */
},
},
};
/* [i_total_coeff-1][i_total_zeros] */
const vlc_t x264_total_zeros[15][16] =
{
{ /* i_total 1 */
{ 0x1, 1 }, /* str=1 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 3 }, /* str=010 */
{ 0x3, 4 }, /* str=0011 */
{ 0x2, 4 }, /* str=0010 */
{ 0x3, 5 }, /* str=00011 */
{ 0x2, 5 }, /* str=00010 */
{ 0x3, 6 }, /* str=000011 */
{ 0x2, 6 }, /* str=000010 */
{ 0x3, 7 }, /* str=0000011 */
{ 0x2, 7 }, /* str=0000010 */
{ 0x3, 8 }, /* str=00000011 */
{ 0x2, 8 }, /* str=00000010 */
{ 0x3, 9 }, /* str=000000011 */
{ 0x2, 9 }, /* str=000000010 */
{ 0x1, 9 }, /* str=000000001 */
},
{ /* i_total 2 */
{ 0x7, 3 }, /* str=111 */
{ 0x6, 3 }, /* str=110 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 3 }, /* str=011 */
{ 0x5, 4 }, /* str=0101 */
{ 0x4, 4 }, /* str=0100 */
{ 0x3, 4 }, /* str=0011 */
{ 0x2, 4 }, /* str=0010 */
{ 0x3, 5 }, /* str=00011 */
{ 0x2, 5 }, /* str=00010 */
{ 0x3, 6 }, /* str=000011 */
{ 0x2, 6 }, /* str=000010 */
{ 0x1, 6 }, /* str=000001 */
{ 0x0, 6 }, /* str=000000 */
},
{ /* i_total 3 */
{ 0x5, 4 }, /* str=0101 */
{ 0x7, 3 }, /* str=111 */
{ 0x6, 3 }, /* str=110 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 4 }, /* str=0100 */
{ 0x3, 4 }, /* str=0011 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 4 }, /* str=0010 */
{ 0x3, 5 }, /* str=00011 */
{ 0x2, 5 }, /* str=00010 */
{ 0x1, 6 }, /* str=000001 */
{ 0x1, 5 }, /* str=00001 */
{ 0x0, 6 }, /* str=000000 */
},
{ /* i_total 4 */
{ 0x3, 5 }, /* str=00011 */
{ 0x7, 3 }, /* str=111 */
{ 0x5, 4 }, /* str=0101 */
{ 0x4, 4 }, /* str=0100 */
{ 0x6, 3 }, /* str=110 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 4 }, /* str=0011 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 4 }, /* str=0010 */
{ 0x2, 5 }, /* str=00010 */
{ 0x1, 5 }, /* str=00001 */
{ 0x0, 5 }, /* str=00000 */
},
{ /* i_total 5 */
{ 0x5, 4 }, /* str=0101 */
{ 0x4, 4 }, /* str=0100 */
{ 0x3, 4 }, /* str=0011 */
{ 0x7, 3 }, /* str=111 */
{ 0x6, 3 }, /* str=110 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 4 }, /* str=0010 */
{ 0x1, 5 }, /* str=00001 */
{ 0x1, 4 }, /* str=0001 */
{ 0x0, 5 }, /* str=00000 */
},
{ /* i_total 6 */
{ 0x1, 6 }, /* str=000001 */
{ 0x1, 5 }, /* str=00001 */
{ 0x7, 3 }, /* str=111 */
{ 0x6, 3 }, /* str=110 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 3 }, /* str=010 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 3 }, /* str=001 */
{ 0x0, 6 }, /* str=000000 */
},
{ /* i_total 7 */
{ 0x1, 6 }, /* str=000001 */
{ 0x1, 5 }, /* str=00001 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 3 }, /* str=011 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 3 }, /* str=010 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 3 }, /* str=001 */
{ 0x0, 6 }, /* str=000000 */
},
{ /* i_total 8 */
{ 0x1, 6 }, /* str=000001 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 5 }, /* str=00001 */
{ 0x3, 3 }, /* str=011 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 2 }, /* str=10 */
{ 0x2, 3 }, /* str=010 */
{ 0x1, 3 }, /* str=001 */
{ 0x0, 6 }, /* str=000000 */
},
{ /* i_total 9 */
{ 0x1, 6 }, /* str=000001 */
{ 0x0, 6 }, /* str=000000 */
{ 0x1, 4 }, /* str=0001 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 2 }, /* str=10 */
{ 0x1, 3 }, /* str=001 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 5 }, /* str=00001 */
},
{ /* i_total 10 */
{ 0x1, 5 }, /* str=00001 */
{ 0x0, 5 }, /* str=00000 */
{ 0x1, 3 }, /* str=001 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 2 }, /* str=10 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 4 }, /* str=0001 */
},
{ /* i_total 11 */
{ 0x0, 4 }, /* str=0000 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 3 }, /* str=001 */
{ 0x2, 3 }, /* str=010 */
{ 0x1, 1 }, /* str=1 */
{ 0x3, 3 }, /* str=011 */
},
{ /* i_total 12 */
{ 0x0, 4 }, /* str=0000 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 1 }, /* str=1 */
{ 0x1, 3 }, /* str=001 */
},
{ /* i_total 13 */
{ 0x0, 3 }, /* str=000 */
{ 0x1, 3 }, /* str=001 */
{ 0x1, 1 }, /* str=1 */
{ 0x1, 2 }, /* str=01 */
},
{ /* i_total 14 */
{ 0x0, 2 }, /* str=00 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 1 }, /* str=1 */
},
{ /* i_total 15 */
{ 0x0, 1 }, /* str=0 */
{ 0x1, 1 }, /* str=1 */
},
};
/* [i_total_coeff-1][i_total_zeros] */
const vlc_t x264_total_zeros_2x2_dc[3][4] =
{
{ /* i_total 1 */
{ 0x1, 1 }, /* str=1 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 3 }, /* str=001 */
{ 0x0, 3 } /* str=000 */
},
{ /* i_total 2 */
{ 0x1, 1 }, /* str=1 */
{ 0x1, 2 }, /* str=01 */
{ 0x0, 2 }, /* str=00 */
},
{ /* i_total 3 */
{ 0x1, 1 }, /* str=1 */
{ 0x0, 1 }, /* str=0 */
},
};
/* [i_total_coeff-1][i_total_zeros] */
const vlc_t x264_total_zeros_2x4_dc[7][8] =
{
{ /* i_total 1 */
{ 0x1, 1 }, /* str=1 */
{ 0x2, 3 }, /* str=010 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 4 }, /* str=0010 */
{ 0x3, 4 }, /* str=0011 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 5 }, /* str=00001 */
{ 0x0, 5 }, /* str=00000 */
},
{ /* i_total 2 */
{ 0x0, 3 }, /* str=000 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 3 }, /* str=001 */
{ 0x4, 3 }, /* str=100 */
{ 0x5, 3 }, /* str=101 */
{ 0x6, 3 }, /* str=110 */
{ 0x7, 3 }, /* str=111 */
},
{ /* i_total 3 */
{ 0x0, 3 }, /* str=000 */
{ 0x1, 3 }, /* str=001 */
{ 0x1, 2 }, /* str=01 */
{ 0x2, 2 }, /* str=10 */
{ 0x6, 3 }, /* str=110 */
{ 0x7, 3 }, /* str=111 */
},
{ /* i_total 4 */
{ 0x6, 3 }, /* str=110 */
{ 0x0, 2 }, /* str=00 */
{ 0x1, 2 }, /* str=01 */
{ 0x2, 2 }, /* str=10 */
{ 0x7, 3 }, /* str=111 */
},
{ /* i_total 5 */
{ 0x0, 2 }, /* str=00 */
{ 0x1, 2 }, /* str=01 */
{ 0x2, 2 }, /* str=10 */
{ 0x3, 2 }, /* str=11 */
},
{ /* i_total 6 */
{ 0x0, 2 }, /* str=00 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 1 }, /* str=1 */
},
{ /* i_total 7 */
{ 0x0, 1 }, /* str=0 */
{ 0x1, 1 }, /* str=1 */
}
};
/* [MIN( i_zero_left-1, 6 )][run_before] */
static const vlc_t run_before[7][16] =
{
{ /* i_zero_left 1 */
{ 0x1, 1 }, /* str=1 */
{ 0x0, 1 }, /* str=0 */
},
{ /* i_zero_left 2 */
{ 0x1, 1 }, /* str=1 */
{ 0x1, 2 }, /* str=01 */
{ 0x0, 2 }, /* str=00 */
},
{ /* i_zero_left 3 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 2 }, /* str=10 */
{ 0x1, 2 }, /* str=01 */
{ 0x0, 2 }, /* str=00 */
},
{ /* i_zero_left 4 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 2 }, /* str=10 */
{ 0x1, 2 }, /* str=01 */
{ 0x1, 3 }, /* str=001 */
{ 0x0, 3 }, /* str=000 */
},
{ /* i_zero_left 5 */
{ 0x3, 2 }, /* str=11 */
{ 0x2, 2 }, /* str=10 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 3 }, /* str=010 */
{ 0x1, 3 }, /* str=001 */
{ 0x0, 3 }, /* str=000 */
},
{ /* i_zero_left 6 */
{ 0x3, 2 }, /* str=11 */
{ 0x0, 3 }, /* str=000 */
{ 0x1, 3 }, /* str=001 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 3 }, /* str=010 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
},
{ /* i_zero_left >6 */
{ 0x7, 3 }, /* str=111 */
{ 0x6, 3 }, /* str=110 */
{ 0x5, 3 }, /* str=101 */
{ 0x4, 3 }, /* str=100 */
{ 0x3, 3 }, /* str=011 */
{ 0x2, 3 }, /* str=010 */
{ 0x1, 3 }, /* str=001 */
{ 0x1, 4 }, /* str=0001 */
{ 0x1, 5 }, /* str=00001 */
{ 0x1, 6 }, /* str=000001 */
{ 0x1, 7 }, /* str=0000001 */
{ 0x1, 8 }, /* str=00000001 */
{ 0x1, 9 }, /* str=000000001 */
{ 0x1, 10 }, /* str=0000000001 */
{ 0x1, 11 }, /* str=00000000001 */
},
};
vlc_large_t x264_level_token[7][LEVEL_TABLE_SIZE];
uint32_t x264_run_before[1<<16];
void x264_cavlc_init( x264_t *h )
{
for( int i_suffix = 0; i_suffix < 7; i_suffix++ )
for( int16_t level = -LEVEL_TABLE_SIZE/2; level < LEVEL_TABLE_SIZE/2; level++ )
{
int mask = level >> 15;
int abs_level = (level^mask)-mask;
int i_level_code = abs_level*2-mask-2;
int i_next = i_suffix;
vlc_large_t *vlc = &x264_level_token[i_suffix][level+LEVEL_TABLE_SIZE/2];
if( ( i_level_code >> i_suffix ) < 14 )
{
vlc->i_size = (i_level_code >> i_suffix) + 1 + i_suffix;
vlc->i_bits = (1<<i_suffix) + (i_level_code & ((1<<i_suffix)-1));
}
else if( i_suffix == 0 && i_level_code < 30 )
{
vlc->i_size = 19;
vlc->i_bits = (1<<4) + (i_level_code - 14);
}
else if( i_suffix > 0 && ( i_level_code >> i_suffix ) == 14 )
{
vlc->i_size = 15 + i_suffix;
vlc->i_bits = (1<<i_suffix) + (i_level_code & ((1<<i_suffix)-1));
}
else
{
i_level_code -= 15 << i_suffix;
if( i_suffix == 0 )
i_level_code -= 15;
vlc->i_size = 28;
vlc->i_bits = (1<<12) + i_level_code;
}
if( i_next == 0 )
i_next++;
if( abs_level > (3 << (i_next-1)) && i_next < 6 )
i_next++;
vlc->i_next = i_next;
}
for( int i = 1; i < (1<<16); i++ )
{
x264_run_level_t runlevel;
ALIGNED_ARRAY_16( dctcoef, dct, [16] );
int size = 0;
int bits = 0;
for( int j = 0; j < 16; j++ )
dct[j] = i&(1<<j);
int total = h->quantf.coeff_level_run[DCT_LUMA_4x4]( dct, &runlevel );
int zeros = runlevel.last + 1 - total;
uint32_t mask = i << (x264_clz( i ) + 1);
for( int j = 0; j < total-1 && zeros > 0; j++ )
{
int idx = X264_MIN(zeros, 7) - 1;
int run = x264_clz( mask );
int len = run_before[idx][run].i_size;
size += len;
bits <<= len;
bits |= run_before[idx][run].i_bits;
zeros -= run;
mask <<= run + 1;
}
x264_run_before[i] = (bits << 5) + size;
}
}

View file

@ -0,0 +1,357 @@
/*****************************************************************************
* win32thread.c: windows threading
*****************************************************************************
* Copyright (C) 2010-2017 x264 project
*
* Authors: Steven Walters <kemuri9@gmail.com>
* Pegasys Inc. <http://www.pegasys-inc.com>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
/* Microsoft's way of supporting systems with >64 logical cpus can be found at
* http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx */
/* Based on the agreed standing that x264 does not need to utilize >64 logical cpus,
* this API does not detect nor utilize more than 64 cpus for systems that have them. */
#include "common.h"
#if HAVE_WINRT
/* _beginthreadex() is technically the correct option, but it's only available for Desktop applications.
* Using CreateThread() as an alternative works on Windows Store and Windows Phone 8.1+ as long as we're
* using a dynamically linked MSVCRT which happens to be a requirement for WinRT applications anyway */
#define _beginthreadex CreateThread
#define InitializeCriticalSectionAndSpinCount(a, b) InitializeCriticalSectionEx(a, b, CRITICAL_SECTION_NO_DEBUG_INFO)
#define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE)
#else
#include <process.h>
#endif
/* number of times to spin a thread about to block on a locked mutex before retrying and sleeping if still locked */
#define X264_SPIN_COUNT 0
/* global mutex for replacing MUTEX_INITIALIZER instances */
static x264_pthread_mutex_t static_mutex;
/* _beginthreadex requires that the start routine is __stdcall */
static unsigned __stdcall x264_win32thread_worker( void *arg )
{
x264_pthread_t *h = arg;
*h->p_ret = h->func( h->arg );
return 0;
}
int x264_pthread_create( x264_pthread_t *thread, const x264_pthread_attr_t *attr,
void *(*start_routine)( void* ), void *arg )
{
thread->func = start_routine;
thread->arg = arg;
thread->p_ret = &thread->ret;
thread->ret = NULL;
thread->handle = (void*)_beginthreadex( NULL, 0, x264_win32thread_worker, thread, 0, NULL );
return !thread->handle;
}
int x264_pthread_join( x264_pthread_t thread, void **value_ptr )
{
DWORD ret = WaitForSingleObject( thread.handle, INFINITE );
if( ret != WAIT_OBJECT_0 )
return -1;
if( value_ptr )
*value_ptr = *thread.p_ret;
CloseHandle( thread.handle );
return 0;
}
int x264_pthread_mutex_init( x264_pthread_mutex_t *mutex, const x264_pthread_mutexattr_t *attr )
{
return !InitializeCriticalSectionAndSpinCount( mutex, X264_SPIN_COUNT );
}
int x264_pthread_mutex_destroy( x264_pthread_mutex_t *mutex )
{
DeleteCriticalSection( mutex );
return 0;
}
int x264_pthread_mutex_lock( x264_pthread_mutex_t *mutex )
{
static const x264_pthread_mutex_t init = X264_PTHREAD_MUTEX_INITIALIZER;
if( !memcmp( mutex, &init, sizeof(x264_pthread_mutex_t) ) )
*mutex = static_mutex;
EnterCriticalSection( mutex );
return 0;
}
int x264_pthread_mutex_unlock( x264_pthread_mutex_t *mutex )
{
LeaveCriticalSection( mutex );
return 0;
}
void x264_win32_threading_destroy( void )
{
x264_pthread_mutex_destroy( &static_mutex );
memset( &static_mutex, 0, sizeof(static_mutex) );
}
#if HAVE_WINRT
int x264_pthread_cond_init( x264_pthread_cond_t *cond, const x264_pthread_condattr_t *attr )
{
InitializeConditionVariable( cond );
return 0;
}
int x264_pthread_cond_destroy( x264_pthread_cond_t *cond )
{
return 0;
}
int x264_pthread_cond_broadcast( x264_pthread_cond_t *cond )
{
WakeAllConditionVariable( cond );
return 0;
}
int x264_pthread_cond_signal( x264_pthread_cond_t *cond )
{
WakeConditionVariable( cond );
return 0;
}
int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex )
{
return !SleepConditionVariableCS( cond, mutex, INFINITE );
}
int x264_win32_threading_init( void )
{
return x264_pthread_mutex_init( &static_mutex, NULL );
}
int x264_pthread_num_processors_np( void )
{
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
return si.dwNumberOfProcessors;
}
#else
static struct
{
/* function pointers to conditional variable API on windows 6.0+ kernels */
void (WINAPI *cond_broadcast)( x264_pthread_cond_t *cond );
void (WINAPI *cond_init)( x264_pthread_cond_t *cond );
void (WINAPI *cond_signal)( x264_pthread_cond_t *cond );
BOOL (WINAPI *cond_wait)( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex, DWORD milliseconds );
} thread_control;
/* for pre-Windows 6.0 platforms we need to define and use our own condition variable and api */
typedef struct
{
x264_pthread_mutex_t mtx_broadcast;
x264_pthread_mutex_t mtx_waiter_count;
volatile int waiter_count;
HANDLE semaphore;
HANDLE waiters_done;
volatile int is_broadcast;
} x264_win32_cond_t;
int x264_pthread_cond_init( x264_pthread_cond_t *cond, const x264_pthread_condattr_t *attr )
{
if( thread_control.cond_init )
{
thread_control.cond_init( cond );
return 0;
}
/* non native condition variables */
x264_win32_cond_t *win32_cond = calloc( 1, sizeof(x264_win32_cond_t) );
if( !win32_cond )
return -1;
cond->Ptr = win32_cond;
win32_cond->semaphore = CreateSemaphoreW( NULL, 0, 0x7fffffff, NULL );
if( !win32_cond->semaphore )
return -1;
if( x264_pthread_mutex_init( &win32_cond->mtx_waiter_count, NULL ) )
return -1;
if( x264_pthread_mutex_init( &win32_cond->mtx_broadcast, NULL ) )
return -1;
win32_cond->waiters_done = CreateEventW( NULL, FALSE, FALSE, NULL );
if( !win32_cond->waiters_done )
return -1;
return 0;
}
int x264_pthread_cond_destroy( x264_pthread_cond_t *cond )
{
/* native condition variables do not destroy */
if( thread_control.cond_init )
return 0;
/* non native condition variables */
x264_win32_cond_t *win32_cond = cond->Ptr;
CloseHandle( win32_cond->semaphore );
CloseHandle( win32_cond->waiters_done );
x264_pthread_mutex_destroy( &win32_cond->mtx_broadcast );
x264_pthread_mutex_destroy( &win32_cond->mtx_waiter_count );
free( win32_cond );
return 0;
}
int x264_pthread_cond_broadcast( x264_pthread_cond_t *cond )
{
if( thread_control.cond_broadcast )
{
thread_control.cond_broadcast( cond );
return 0;
}
/* non native condition variables */
x264_win32_cond_t *win32_cond = cond->Ptr;
x264_pthread_mutex_lock( &win32_cond->mtx_broadcast );
x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count );
int have_waiter = 0;
if( win32_cond->waiter_count )
{
win32_cond->is_broadcast = 1;
have_waiter = 1;
}
if( have_waiter )
{
ReleaseSemaphore( win32_cond->semaphore, win32_cond->waiter_count, NULL );
x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count );
WaitForSingleObject( win32_cond->waiters_done, INFINITE );
win32_cond->is_broadcast = 0;
}
else
x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count );
return x264_pthread_mutex_unlock( &win32_cond->mtx_broadcast );
}
int x264_pthread_cond_signal( x264_pthread_cond_t *cond )
{
if( thread_control.cond_signal )
{
thread_control.cond_signal( cond );
return 0;
}
/* non-native condition variables */
x264_win32_cond_t *win32_cond = cond->Ptr;
x264_pthread_mutex_lock( &win32_cond->mtx_broadcast );
x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count );
int have_waiter = win32_cond->waiter_count;
x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count );
if( have_waiter )
{
ReleaseSemaphore( win32_cond->semaphore, 1, NULL );
WaitForSingleObject( win32_cond->waiters_done, INFINITE );
}
return x264_pthread_mutex_unlock( &win32_cond->mtx_broadcast );
}
int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex )
{
if( thread_control.cond_wait )
return !thread_control.cond_wait( cond, mutex, INFINITE );
/* non native condition variables */
x264_win32_cond_t *win32_cond = cond->Ptr;
x264_pthread_mutex_lock( &win32_cond->mtx_broadcast );
x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count );
win32_cond->waiter_count++;
x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count );
x264_pthread_mutex_unlock( &win32_cond->mtx_broadcast );
// unlock the external mutex
x264_pthread_mutex_unlock( mutex );
WaitForSingleObject( win32_cond->semaphore, INFINITE );
x264_pthread_mutex_lock( &win32_cond->mtx_waiter_count );
win32_cond->waiter_count--;
int last_waiter = !win32_cond->waiter_count || !win32_cond->is_broadcast;
x264_pthread_mutex_unlock( &win32_cond->mtx_waiter_count );
if( last_waiter )
SetEvent( win32_cond->waiters_done );
// lock the external mutex
return x264_pthread_mutex_lock( mutex );
}
int x264_win32_threading_init( void )
{
/* find function pointers to API functions, if they exist */
HANDLE kernel_dll = GetModuleHandleW( L"kernel32.dll" );
thread_control.cond_init = (void*)GetProcAddress( kernel_dll, "InitializeConditionVariable" );
if( thread_control.cond_init )
{
/* we're on a windows 6.0+ kernel, acquire the rest of the functions */
thread_control.cond_broadcast = (void*)GetProcAddress( kernel_dll, "WakeAllConditionVariable" );
thread_control.cond_signal = (void*)GetProcAddress( kernel_dll, "WakeConditionVariable" );
thread_control.cond_wait = (void*)GetProcAddress( kernel_dll, "SleepConditionVariableCS" );
}
return x264_pthread_mutex_init( &static_mutex, NULL );
}
int x264_pthread_num_processors_np( void )
{
DWORD_PTR system_cpus, process_cpus = 0;
int cpus = 0;
/* GetProcessAffinityMask returns affinities of 0 when the process has threads in multiple processor groups.
* On platforms that support processor grouping, use GetThreadGroupAffinity to get the current thread's affinity instead. */
#if ARCH_X86_64
/* find function pointers to API functions specific to x86_64 platforms, if they exist */
HANDLE kernel_dll = GetModuleHandleW( L"kernel32.dll" );
BOOL (*get_thread_affinity)( HANDLE thread, void *group_affinity ) = (void*)GetProcAddress( kernel_dll, "GetThreadGroupAffinity" );
if( get_thread_affinity )
{
/* running on a platform that supports >64 logical cpus */
struct /* GROUP_AFFINITY */
{
ULONG_PTR mask; // KAFFINITY = ULONG_PTR
USHORT group;
USHORT reserved[3];
} thread_affinity;
if( get_thread_affinity( GetCurrentThread(), &thread_affinity ) )
process_cpus = thread_affinity.mask;
}
#endif
if( !process_cpus )
GetProcessAffinityMask( GetCurrentProcess(), &process_cpus, &system_cpus );
for( DWORD_PTR bit = 1; bit; bit <<= 1 )
cpus += !!(process_cpus & bit);
return cpus ? cpus : 1;
}
#endif

View file

@ -0,0 +1,81 @@
/*****************************************************************************
* win32thread.h: windows threading
*****************************************************************************
* Copyright (C) 2010-2017 x264 project
*
* Authors: Steven Walters <kemuri9@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_WIN32THREAD_H
#define X264_WIN32THREAD_H
#include <windows.h>
/* the following macro is used within x264 */
#undef ERROR
typedef struct
{
void *handle;
void *(*func)( void* arg );
void *arg;
void **p_ret;
void *ret;
} x264_pthread_t;
#define x264_pthread_attr_t int
/* the conditional variable api for windows 6.0+ uses critical sections and not mutexes */
typedef CRITICAL_SECTION x264_pthread_mutex_t;
#define X264_PTHREAD_MUTEX_INITIALIZER {0}
#define x264_pthread_mutexattr_t int
#if HAVE_WINRT
typedef CONDITION_VARIABLE x264_pthread_cond_t;
#else
typedef struct
{
void *Ptr;
} x264_pthread_cond_t;
#endif
#define x264_pthread_condattr_t int
int x264_pthread_create( x264_pthread_t *thread, const x264_pthread_attr_t *attr,
void *(*start_routine)( void* ), void *arg );
int x264_pthread_join( x264_pthread_t thread, void **value_ptr );
int x264_pthread_mutex_init( x264_pthread_mutex_t *mutex, const x264_pthread_mutexattr_t *attr );
int x264_pthread_mutex_destroy( x264_pthread_mutex_t *mutex );
int x264_pthread_mutex_lock( x264_pthread_mutex_t *mutex );
int x264_pthread_mutex_unlock( x264_pthread_mutex_t *mutex );
int x264_pthread_cond_init( x264_pthread_cond_t *cond, const x264_pthread_condattr_t *attr );
int x264_pthread_cond_destroy( x264_pthread_cond_t *cond );
int x264_pthread_cond_broadcast( x264_pthread_cond_t *cond );
int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mutex );
int x264_pthread_cond_signal( x264_pthread_cond_t *cond );
#define x264_pthread_attr_init(a) 0
#define x264_pthread_attr_destroy(a) 0
int x264_win32_threading_init( void );
void x264_win32_threading_destroy( void );
int x264_pthread_num_processors_np( void );
#endif

View file

@ -0,0 +1,144 @@
/*****************************************************************************
* dct.h: x86 transform and zigzag
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_I386_DCT_H
#define X264_I386_DCT_H
void x264_sub4x4_dct_mmx ( dctcoef dct [16], pixel *pix1, pixel *pix2 );
void x264_sub8x8_dct_mmx ( dctcoef dct[ 4][16], pixel *pix1, pixel *pix2 );
void x264_sub16x16_dct_mmx ( dctcoef dct[16][16], pixel *pix1, pixel *pix2 );
void x264_sub8x8_dct_sse2 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_sse2 ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub4x4_dct_ssse3 ( int16_t dct [16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub4x4_dct_avx512 ( int16_t dct [16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_ssse3 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_ssse3( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_avx ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_avx ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_xop ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_xop ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_avx2 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_avx512 ( int16_t dct[ 4][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_avx2 ( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct_avx512( int16_t dct[16][16], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_dc_mmx2 ( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct_dc_sse2 ( dctcoef dct [ 4], pixel *pix1, pixel *pix2 );
void x264_sub8x8_dct_dc_avx512 ( int16_t dct [ 4], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x16_dct_dc_sse2 ( dctcoef dct [ 8], pixel *pix1, pixel *pix2 );
void x264_sub8x16_dct_dc_ssse3 ( int16_t dct [ 8], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x16_dct_dc_avx ( dctcoef dct [ 8], pixel *pix1, pixel *pix2 );
void x264_sub8x16_dct_dc_avx512( int16_t dct [ 8], uint8_t *pix1, uint8_t *pix2 );
void x264_add4x4_idct_mmx ( uint8_t *p_dst, int16_t dct [16] );
void x264_add4x4_idct_sse2 ( uint16_t *p_dst, int32_t dct [16] );
void x264_add4x4_idct_sse4 ( uint8_t *p_dst, int16_t dct [16] );
void x264_add4x4_idct_avx ( pixel *p_dst, dctcoef dct [16] );
void x264_add8x8_idct_mmx ( uint8_t *p_dst, int16_t dct[ 4][16] );
void x264_add8x8_idct_dc_mmx2 ( uint8_t *p_dst, int16_t dct [ 4] );
void x264_add16x16_idct_mmx ( uint8_t *p_dst, int16_t dct[16][16] );
void x264_add16x16_idct_dc_mmx2 ( uint8_t *p_dst, int16_t dct [16] );
void x264_add8x8_idct_sse2 ( pixel *p_dst, dctcoef dct[ 4][16] );
void x264_add8x8_idct_avx ( pixel *p_dst, dctcoef dct[ 4][16] );
void x264_add8x8_idct_avx2 ( pixel *p_dst, dctcoef dct[ 4][16] );
void x264_add8x8_idct_avx512 ( uint8_t *p_dst, int16_t dct[ 4][16] );
void x264_add16x16_idct_sse2 ( pixel *p_dst, dctcoef dct[16][16] );
void x264_add16x16_idct_avx ( pixel *p_dst, dctcoef dct[16][16] );
void x264_add16x16_idct_avx2 ( pixel *p_dst, dctcoef dct[16][16] );
void x264_add8x8_idct_dc_sse2 ( pixel *p_dst, dctcoef dct [ 4] );
void x264_add16x16_idct_dc_sse2 ( pixel *p_dst, dctcoef dct [16] );
void x264_add8x8_idct_dc_ssse3 ( uint8_t *p_dst, int16_t dct [ 4] );
void x264_add16x16_idct_dc_ssse3( uint8_t *p_dst, int16_t dct [16] );
void x264_add8x8_idct_dc_avx ( pixel *p_dst, dctcoef dct [ 4] );
void x264_add16x16_idct_dc_avx ( pixel *p_dst, dctcoef dct [16] );
void x264_add16x16_idct_dc_avx2 ( uint8_t *p_dst, int16_t dct [16] );
void x264_dct4x4dc_mmx2 ( int16_t d[16] );
void x264_dct4x4dc_sse2 ( int32_t d[16] );
void x264_dct4x4dc_avx ( int32_t d[16] );
void x264_idct4x4dc_mmx ( int16_t d[16] );
void x264_idct4x4dc_sse2 ( int32_t d[16] );
void x264_idct4x4dc_avx ( int32_t d[16] );
void x264_dct2x4dc_mmx2( dctcoef dct[8], dctcoef dct4x4[8][16] );
void x264_dct2x4dc_sse2( dctcoef dct[8], dctcoef dct4x4[8][16] );
void x264_dct2x4dc_avx ( dctcoef dct[8], dctcoef dct4x4[8][16] );
void x264_sub8x8_dct8_mmx ( int16_t dct [64], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct8_mmx ( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct8_sse2 ( dctcoef dct [64], pixel *pix1, pixel *pix2 );
void x264_sub16x16_dct8_sse2 ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 );
void x264_sub8x8_dct8_ssse3 ( int16_t dct [64], uint8_t *pix1, uint8_t *pix2 );
void x264_sub16x16_dct8_ssse3( int16_t dct[4][64], uint8_t *pix1, uint8_t *pix2 );
void x264_sub8x8_dct8_sse4 ( int32_t dct [64], uint16_t *pix1, uint16_t *pix2 );
void x264_sub16x16_dct8_sse4 ( int32_t dct[4][64], uint16_t *pix1, uint16_t *pix2 );
void x264_sub8x8_dct8_avx ( dctcoef dct [64], pixel *pix1, pixel *pix2 );
void x264_sub16x16_dct8_avx ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 );
void x264_sub16x16_dct8_avx2 ( dctcoef dct[4][64], pixel *pix1, pixel *pix2 );
void x264_add8x8_idct8_mmx ( uint8_t *dst, int16_t dct [64] );
void x264_add16x16_idct8_mmx ( uint8_t *dst, int16_t dct[4][64] );
void x264_add8x8_idct8_sse2 ( pixel *dst, dctcoef dct [64] );
void x264_add16x16_idct8_sse2( pixel *dst, dctcoef dct[4][64] );
void x264_add8x8_idct8_avx ( pixel *dst, dctcoef dct [64] );
void x264_add16x16_idct8_avx ( pixel *dst, dctcoef dct[4][64] );
void x264_zigzag_scan_8x8_frame_mmx2 ( int16_t level[64], int16_t dct[64] );
void x264_zigzag_scan_8x8_frame_sse2 ( dctcoef level[64], dctcoef dct[64] );
void x264_zigzag_scan_8x8_frame_ssse3 ( int16_t level[64], int16_t dct[64] );
void x264_zigzag_scan_8x8_frame_avx ( dctcoef level[64], dctcoef dct[64] );
void x264_zigzag_scan_8x8_frame_xop ( int16_t level[64], int16_t dct[64] );
void x264_zigzag_scan_8x8_frame_avx512( dctcoef level[64], dctcoef dct[64] );
void x264_zigzag_scan_4x4_frame_mmx ( int16_t level[16], int16_t dct[16] );
void x264_zigzag_scan_4x4_frame_sse2 ( int32_t level[16], int32_t dct[16] );
void x264_zigzag_scan_4x4_frame_ssse3 ( int16_t level[16], int16_t dct[16] );
void x264_zigzag_scan_4x4_frame_avx ( dctcoef level[16], dctcoef dct[16] );
void x264_zigzag_scan_4x4_frame_xop ( dctcoef level[16], dctcoef dct[16] );
void x264_zigzag_scan_4x4_frame_avx512( dctcoef level[16], dctcoef dct[16] );
void x264_zigzag_scan_4x4_field_sse ( int16_t level[16], int16_t dct[16] );
void x264_zigzag_scan_4x4_field_sse2 ( int32_t level[16], int32_t dct[16] );
void x264_zigzag_scan_4x4_field_avx512( dctcoef level[16], dctcoef dct[16] );
void x264_zigzag_scan_8x8_field_mmx2 ( int16_t level[64], int16_t dct[64] );
void x264_zigzag_scan_8x8_field_sse4 ( int32_t level[64], int32_t dct[64] );
void x264_zigzag_scan_8x8_field_avx ( int32_t level[64], int32_t dct[64] );
void x264_zigzag_scan_8x8_field_xop ( int16_t level[64], int16_t dct[64] );
void x264_zigzag_scan_8x8_field_avx512( dctcoef level[64], dctcoef dct[64] );
int x264_zigzag_sub_4x4_frame_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst );
int x264_zigzag_sub_4x4_frame_ssse3 ( int16_t level[16], const uint8_t *src, uint8_t *dst );
int x264_zigzag_sub_4x4ac_frame_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc );
int x264_zigzag_sub_4x4ac_frame_ssse3( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc );
int x264_zigzag_sub_4x4_field_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst );
int x264_zigzag_sub_4x4_field_ssse3 ( int16_t level[16], const uint8_t *src, uint8_t *dst );
int x264_zigzag_sub_4x4ac_field_avx ( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc );
int x264_zigzag_sub_4x4ac_field_ssse3( int16_t level[16], const uint8_t *src, uint8_t *dst, int16_t *dc );
void x264_zigzag_interleave_8x8_cavlc_mmx ( int16_t *dst, int16_t *src, uint8_t *nnz );
void x264_zigzag_interleave_8x8_cavlc_sse2 ( dctcoef *dst, dctcoef *src, uint8_t *nnz );
void x264_zigzag_interleave_8x8_cavlc_avx ( dctcoef *dst, dctcoef *src, uint8_t *nnz );
void x264_zigzag_interleave_8x8_cavlc_avx2 ( int16_t *dst, int16_t *src, uint8_t *nnz );
void x264_zigzag_interleave_8x8_cavlc_avx512( dctcoef *dst, dctcoef *src, uint8_t *nnz );
#endif

View file

@ -0,0 +1,911 @@
/*****************************************************************************
* mc-c.c: x86 motion compensation
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "mc.h"
#define DECL_SUF( func, args )\
void func##_mmx2 args;\
void func##_sse2 args;\
void func##_ssse3 args;\
void func##_avx2 args;\
void func##_avx512 args;
DECL_SUF( x264_pixel_avg_16x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_16x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_8x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_8x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_8x4, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_4x16, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_4x8, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_4x4, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
DECL_SUF( x264_pixel_avg_4x2, ( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t, int ))
#define MC_WEIGHT(w,type) \
void x264_mc_weight_w##w##_##type( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int );
#define MC_WEIGHT_OFFSET(w,type) \
void x264_mc_offsetadd_w##w##_##type( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ); \
void x264_mc_offsetsub_w##w##_##type( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ); \
MC_WEIGHT(w,type)
MC_WEIGHT_OFFSET( 4, mmx2 )
MC_WEIGHT_OFFSET( 8, mmx2 )
MC_WEIGHT_OFFSET( 12, mmx2 )
MC_WEIGHT_OFFSET( 16, mmx2 )
MC_WEIGHT_OFFSET( 20, mmx2 )
MC_WEIGHT_OFFSET( 12, sse2 )
MC_WEIGHT_OFFSET( 16, sse2 )
MC_WEIGHT_OFFSET( 20, sse2 )
#if HIGH_BIT_DEPTH
MC_WEIGHT_OFFSET( 8, sse2 )
#endif
MC_WEIGHT( 8, sse2 )
MC_WEIGHT( 4, ssse3 )
MC_WEIGHT( 8, ssse3 )
MC_WEIGHT( 12, ssse3 )
MC_WEIGHT( 16, ssse3 )
MC_WEIGHT( 20, ssse3 )
MC_WEIGHT( 8, avx2 )
MC_WEIGHT( 16, avx2 )
MC_WEIGHT( 20, avx2 )
#undef MC_OFFSET
#undef MC_WEIGHT
void x264_mc_copy_w4_mmx ( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_mc_copy_w8_mmx ( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_mc_copy_w8_sse ( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_mc_copy_w16_mmx( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_mc_copy_w16_sse( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_mc_copy_w16_aligned_sse( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_mc_copy_w16_avx( uint16_t *, intptr_t, uint16_t *, intptr_t, int );
void x264_mc_copy_w16_aligned_avx( uint16_t *, intptr_t, uint16_t *, intptr_t, int );
void x264_prefetch_fenc_420_mmx2( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_prefetch_fenc_422_mmx2( pixel *, intptr_t, pixel *, intptr_t, int );
void x264_prefetch_ref_mmx2( pixel *, intptr_t, int );
void x264_plane_copy_core_sse( pixel *, intptr_t, pixel *, intptr_t, int w, int h );
void x264_plane_copy_core_avx( pixel *, intptr_t, pixel *, intptr_t, int w, int h );
void x264_plane_copy_swap_core_ssse3( pixel *, intptr_t, pixel *, intptr_t, int w, int h );
void x264_plane_copy_swap_core_avx2 ( pixel *, intptr_t, pixel *, intptr_t, int w, int h );
void x264_plane_copy_interleave_core_mmx2( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
void x264_plane_copy_interleave_core_sse2( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
void x264_plane_copy_interleave_core_avx( pixel *dst, intptr_t i_dst,
pixel *srcu, intptr_t i_srcu,
pixel *srcv, intptr_t i_srcv, int w, int h );
void x264_plane_copy_deinterleave_sse2( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_ssse3( uint8_t *dsta, intptr_t i_dsta,
uint8_t *dstb, intptr_t i_dstb,
uint8_t *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_avx( uint16_t *dsta, intptr_t i_dsta,
uint16_t *dstb, intptr_t i_dstb,
uint16_t *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_avx2( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_rgb_sse2 ( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc,
pixel *src, intptr_t i_src, int pw, int w, int h );
void x264_plane_copy_deinterleave_rgb_ssse3( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc,
pixel *src, intptr_t i_src, int pw, int w, int h );
void x264_plane_copy_deinterleave_rgb_avx2 ( pixel *dsta, intptr_t i_dsta,
pixel *dstb, intptr_t i_dstb,
pixel *dstc, intptr_t i_dstc,
pixel *src, intptr_t i_src, int pw, int w, int h );
void x264_plane_copy_deinterleave_v210_ssse3 ( uint16_t *dstu, intptr_t i_dstu,
uint16_t *dstv, intptr_t i_dstv,
uint32_t *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_v210_avx ( uint16_t *dstu, intptr_t i_dstu,
uint16_t *dstv, intptr_t i_dstv,
uint32_t *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_v210_avx2 ( uint16_t *dstu, intptr_t i_dstu,
uint16_t *dstv, intptr_t i_dstv,
uint32_t *src, intptr_t i_src, int w, int h );
void x264_plane_copy_deinterleave_v210_avx512( uint16_t *dstu, intptr_t i_dstu,
uint16_t *dstv, intptr_t i_dstv,
uint32_t *src, intptr_t i_src, int w, int h );
void x264_store_interleave_chroma_mmx2( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height );
void x264_store_interleave_chroma_sse2( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height );
void x264_store_interleave_chroma_avx ( pixel *dst, intptr_t i_dst, pixel *srcu, pixel *srcv, int height );
void x264_load_deinterleave_chroma_fenc_sse2( pixel *dst, pixel *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fenc_ssse3( uint8_t *dst, uint8_t *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fenc_avx( uint16_t *dst, uint16_t *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fenc_avx2( pixel *dst, pixel *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fdec_sse2( pixel *dst, pixel *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fdec_ssse3( uint8_t *dst, uint8_t *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fdec_avx( uint16_t *dst, uint16_t *src, intptr_t i_src, int height );
void x264_load_deinterleave_chroma_fdec_avx2( uint16_t *dst, uint16_t *src, intptr_t i_src, int height );
void *x264_memcpy_aligned_sse ( void *dst, const void *src, size_t n );
void *x264_memcpy_aligned_avx ( void *dst, const void *src, size_t n );
void *x264_memcpy_aligned_avx512( void *dst, const void *src, size_t n );
void x264_memzero_aligned_sse ( void *dst, size_t n );
void x264_memzero_aligned_avx ( void *dst, size_t n );
void x264_memzero_aligned_avx512( void *dst, size_t n );
void x264_integral_init4h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride );
void x264_integral_init4h_avx2( uint16_t *sum, uint8_t *pix, intptr_t stride );
void x264_integral_init8h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride );
void x264_integral_init8h_avx ( uint16_t *sum, uint8_t *pix, intptr_t stride );
void x264_integral_init8h_avx2( uint16_t *sum, uint8_t *pix, intptr_t stride );
void x264_integral_init4v_mmx ( uint16_t *sum8, uint16_t *sum4, intptr_t stride );
void x264_integral_init4v_sse2 ( uint16_t *sum8, uint16_t *sum4, intptr_t stride );
void x264_integral_init4v_ssse3( uint16_t *sum8, uint16_t *sum4, intptr_t stride );
void x264_integral_init4v_avx2( uint16_t *sum8, uint16_t *sum4, intptr_t stride );
void x264_integral_init8v_mmx ( uint16_t *sum8, intptr_t stride );
void x264_integral_init8v_sse2( uint16_t *sum8, intptr_t stride );
void x264_integral_init8v_avx2( uint16_t *sum8, intptr_t stride );
void x264_mbtree_propagate_cost_sse2 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len );
void x264_mbtree_propagate_cost_avx ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len );
void x264_mbtree_propagate_cost_fma4 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len );
void x264_mbtree_propagate_cost_avx2 ( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len );
void x264_mbtree_propagate_cost_avx512( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len );
void x264_mbtree_fix8_pack_ssse3( uint16_t *dst, float *src, int count );
void x264_mbtree_fix8_pack_avx2 ( uint16_t *dst, float *src, int count );
void x264_mbtree_fix8_unpack_ssse3( float *dst, uint16_t *src, int count );
void x264_mbtree_fix8_unpack_avx2 ( float *dst, uint16_t *src, int count );
#define MC_CHROMA(cpu)\
void x264_mc_chroma_##cpu( pixel *dstu, pixel *dstv, intptr_t i_dst, pixel *src, intptr_t i_src,\
int dx, int dy, int i_width, int i_height );
MC_CHROMA(mmx2)
MC_CHROMA(sse2)
MC_CHROMA(ssse3)
MC_CHROMA(cache64_ssse3)
MC_CHROMA(avx)
MC_CHROMA(avx2)
#define LOWRES(cpu)\
void x264_frame_init_lowres_core_##cpu( pixel *src0, pixel *dst0, pixel *dsth, pixel *dstv, pixel *dstc,\
intptr_t src_stride, intptr_t dst_stride, int width, int height );
LOWRES(mmx2)
LOWRES(cache32_mmx2)
LOWRES(sse2)
LOWRES(ssse3)
LOWRES(avx)
LOWRES(xop)
LOWRES(avx2)
#define PIXEL_AVG_W(width,cpu)\
void x264_pixel_avg2_w##width##_##cpu( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t );
/* This declares some functions that don't exist, but that isn't a problem. */
#define PIXEL_AVG_WALL(cpu)\
PIXEL_AVG_W(4,cpu); PIXEL_AVG_W(8,cpu); PIXEL_AVG_W(10,cpu); PIXEL_AVG_W(12,cpu); PIXEL_AVG_W(16,cpu); PIXEL_AVG_W(18,cpu); PIXEL_AVG_W(20,cpu);
PIXEL_AVG_WALL(mmx2)
PIXEL_AVG_WALL(cache32_mmx2)
PIXEL_AVG_WALL(cache64_mmx2)
PIXEL_AVG_WALL(cache64_sse2)
PIXEL_AVG_WALL(sse2)
PIXEL_AVG_WALL(cache64_ssse3)
PIXEL_AVG_WALL(avx2)
#define PIXEL_AVG_WTAB(instr, name1, name2, name3, name4, name5)\
static void (* const x264_pixel_avg_wtab_##instr[6])( pixel *, intptr_t, pixel *, intptr_t, pixel *, intptr_t ) =\
{\
NULL,\
x264_pixel_avg2_w4_##name1,\
x264_pixel_avg2_w8_##name2,\
x264_pixel_avg2_w12_##name3,\
x264_pixel_avg2_w16_##name4,\
x264_pixel_avg2_w20_##name5,\
};
#if HIGH_BIT_DEPTH
/* we can replace w12/w20 with w10/w18 as only 9/17 pixels in fact are important */
#define x264_pixel_avg2_w12_mmx2 x264_pixel_avg2_w10_mmx2
#define x264_pixel_avg2_w20_mmx2 x264_pixel_avg2_w18_mmx2
#define x264_pixel_avg2_w12_sse2 x264_pixel_avg2_w10_sse2
#define x264_pixel_avg2_w20_sse2 x264_pixel_avg2_w18_sse2
#define x264_pixel_avg2_w12_avx2 x264_pixel_avg2_w16_avx2
#define x264_pixel_avg2_w20_avx2 x264_pixel_avg2_w18_avx2
#else
/* w16 sse2 is faster than w12 mmx as long as the cacheline issue is resolved */
#define x264_pixel_avg2_w12_cache64_ssse3 x264_pixel_avg2_w16_cache64_ssse3
#define x264_pixel_avg2_w12_cache64_sse2 x264_pixel_avg2_w16_cache64_sse2
#define x264_pixel_avg2_w12_sse3 x264_pixel_avg2_w16_sse3
#define x264_pixel_avg2_w12_sse2 x264_pixel_avg2_w16_sse2
#endif // HIGH_BIT_DEPTH
PIXEL_AVG_WTAB(mmx2, mmx2, mmx2, mmx2, mmx2, mmx2)
#if HIGH_BIT_DEPTH
PIXEL_AVG_WTAB(sse2, mmx2, sse2, sse2, sse2, sse2)
PIXEL_AVG_WTAB(avx2, mmx2, sse2, avx2, avx2, avx2)
#else // !HIGH_BIT_DEPTH
#if ARCH_X86
PIXEL_AVG_WTAB(cache32_mmx2, mmx2, cache32_mmx2, cache32_mmx2, cache32_mmx2, cache32_mmx2)
PIXEL_AVG_WTAB(cache64_mmx2, mmx2, cache64_mmx2, cache64_mmx2, cache64_mmx2, cache64_mmx2)
#endif
PIXEL_AVG_WTAB(sse2, mmx2, mmx2, sse2, sse2, sse2)
PIXEL_AVG_WTAB(cache64_sse2, mmx2, cache64_mmx2, cache64_sse2, cache64_sse2, cache64_sse2)
PIXEL_AVG_WTAB(cache64_ssse3, mmx2, cache64_mmx2, cache64_ssse3, cache64_ssse3, cache64_sse2)
PIXEL_AVG_WTAB(cache64_ssse3_atom, mmx2, mmx2, cache64_ssse3, cache64_ssse3, sse2)
PIXEL_AVG_WTAB(avx2, mmx2, mmx2, sse2, sse2, avx2)
#endif // HIGH_BIT_DEPTH
#define MC_COPY_WTAB(instr, name1, name2, name3)\
static void (* const x264_mc_copy_wtab_##instr[5])( pixel *, intptr_t, pixel *, intptr_t, int ) =\
{\
NULL,\
x264_mc_copy_w4_##name1,\
x264_mc_copy_w8_##name2,\
NULL,\
x264_mc_copy_w16_##name3,\
};
MC_COPY_WTAB(mmx,mmx,mmx,mmx)
#if HIGH_BIT_DEPTH
MC_COPY_WTAB(sse,mmx,sse,sse)
MC_COPY_WTAB(avx,mmx,sse,avx)
#else
MC_COPY_WTAB(sse,mmx,mmx,sse)
#endif
#define MC_WEIGHT_WTAB(function, instr, name1, name2, w12version)\
static void (* x264_mc_##function##_wtab_##instr[6])( pixel *, intptr_t, pixel *, intptr_t, const x264_weight_t *, int ) =\
{\
x264_mc_##function##_w4_##name1,\
x264_mc_##function##_w4_##name1,\
x264_mc_##function##_w8_##name2,\
x264_mc_##function##_w##w12version##_##instr,\
x264_mc_##function##_w16_##instr,\
x264_mc_##function##_w20_##instr,\
};
#if HIGH_BIT_DEPTH
MC_WEIGHT_WTAB(weight,mmx2,mmx2,mmx2,12)
MC_WEIGHT_WTAB(offsetadd,mmx2,mmx2,mmx2,12)
MC_WEIGHT_WTAB(offsetsub,mmx2,mmx2,mmx2,12)
MC_WEIGHT_WTAB(weight,sse2,mmx2,sse2,12)
MC_WEIGHT_WTAB(offsetadd,sse2,mmx2,sse2,16)
MC_WEIGHT_WTAB(offsetsub,sse2,mmx2,sse2,16)
static void x264_weight_cache_mmx2( x264_t *h, x264_weight_t *w )
{
if( w->i_scale == 1<<w->i_denom )
{
if( w->i_offset < 0 )
w->weightfn = h->mc.offsetsub;
else
w->weightfn = h->mc.offsetadd;
for( int i = 0; i < 8; i++ )
w->cachea[i] = abs(w->i_offset<<(BIT_DEPTH-8));
return;
}
w->weightfn = h->mc.weight;
int den1 = 1<<w->i_denom;
int den2 = w->i_scale<<1;
int den3 = 1+(w->i_offset<<(BIT_DEPTH-8+1));
for( int i = 0; i < 8; i++ )
{
w->cachea[i] = den1;
w->cacheb[i] = i&1 ? den3 : den2;
}
}
#else
MC_WEIGHT_WTAB(weight,mmx2,mmx2,mmx2,12)
MC_WEIGHT_WTAB(offsetadd,mmx2,mmx2,mmx2,12)
MC_WEIGHT_WTAB(offsetsub,mmx2,mmx2,mmx2,12)
MC_WEIGHT_WTAB(weight,sse2,mmx2,sse2,16)
MC_WEIGHT_WTAB(offsetadd,sse2,mmx2,mmx2,16)
MC_WEIGHT_WTAB(offsetsub,sse2,mmx2,mmx2,16)
MC_WEIGHT_WTAB(weight,ssse3,ssse3,ssse3,16)
MC_WEIGHT_WTAB(weight,avx2,ssse3,avx2,16)
static void x264_weight_cache_mmx2( x264_t *h, x264_weight_t *w )
{
int i;
int16_t den1;
if( w->i_scale == 1<<w->i_denom )
{
if( w->i_offset < 0 )
w->weightfn = h->mc.offsetsub;
else
w->weightfn = h->mc.offsetadd;
memset( w->cachea, abs(w->i_offset), sizeof(w->cachea) );
return;
}
w->weightfn = h->mc.weight;
den1 = 1 << (w->i_denom - 1) | w->i_offset << w->i_denom;
for( i = 0; i < 8; i++ )
{
w->cachea[i] = w->i_scale;
w->cacheb[i] = den1;
}
}
static void x264_weight_cache_ssse3( x264_t *h, x264_weight_t *w )
{
int i, den1;
if( w->i_scale == 1<<w->i_denom )
{
if( w->i_offset < 0 )
w->weightfn = h->mc.offsetsub;
else
w->weightfn = h->mc.offsetadd;
memset( w->cachea, abs( w->i_offset ), sizeof(w->cachea) );
return;
}
w->weightfn = h->mc.weight;
den1 = w->i_scale << (8 - w->i_denom);
for( i = 0; i < 8; i++ )
{
w->cachea[i] = den1;
w->cacheb[i] = w->i_offset;
}
}
#endif // !HIGH_BIT_DEPTH
#define MC_LUMA(name,instr1,instr2)\
static void mc_luma_##name( pixel *dst, intptr_t i_dst_stride,\
pixel *src[4], intptr_t i_src_stride,\
int mvx, int mvy,\
int i_width, int i_height, const x264_weight_t *weight )\
{\
int qpel_idx = ((mvy&3)<<2) + (mvx&3);\
int offset = (mvy>>2)*i_src_stride + (mvx>>2);\
pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;\
if( qpel_idx & 5 ) /* qpel interpolation needed */\
{\
pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);\
x264_pixel_avg_wtab_##instr1[i_width>>2](\
dst, i_dst_stride, src1, i_src_stride,\
src2, i_height );\
if( weight->weightfn )\
weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height );\
}\
else if( weight->weightfn )\
weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height );\
else\
x264_mc_copy_wtab_##instr2[i_width>>2](dst, i_dst_stride, src1, i_src_stride, i_height );\
}
MC_LUMA(mmx2,mmx2,mmx)
MC_LUMA(sse2,sse2,sse)
#if HIGH_BIT_DEPTH
MC_LUMA(avx2,avx2,avx)
#else
#if ARCH_X86
MC_LUMA(cache32_mmx2,cache32_mmx2,mmx)
MC_LUMA(cache64_mmx2,cache64_mmx2,mmx)
#endif
MC_LUMA(cache64_sse2,cache64_sse2,sse)
MC_LUMA(cache64_ssse3,cache64_ssse3,sse)
MC_LUMA(cache64_ssse3_atom,cache64_ssse3_atom,sse)
#endif // !HIGH_BIT_DEPTH
#define GET_REF(name)\
static pixel *get_ref_##name( pixel *dst, intptr_t *i_dst_stride,\
pixel *src[4], intptr_t i_src_stride,\
int mvx, int mvy,\
int i_width, int i_height, const x264_weight_t *weight )\
{\
int qpel_idx = ((mvy&3)<<2) + (mvx&3);\
int offset = (mvy>>2)*i_src_stride + (mvx>>2);\
pixel *src1 = src[x264_hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;\
if( qpel_idx & 5 ) /* qpel interpolation needed */\
{\
pixel *src2 = src[x264_hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);\
x264_pixel_avg_wtab_##name[i_width>>2](\
dst, *i_dst_stride, src1, i_src_stride,\
src2, i_height );\
if( weight->weightfn )\
weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height );\
return dst;\
}\
else if( weight->weightfn )\
{\
weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height );\
return dst;\
}\
else\
{\
*i_dst_stride = i_src_stride;\
return src1;\
}\
}
GET_REF(mmx2)
GET_REF(sse2)
GET_REF(avx2)
#if !HIGH_BIT_DEPTH
#if ARCH_X86
GET_REF(cache32_mmx2)
GET_REF(cache64_mmx2)
#endif
GET_REF(cache64_sse2)
GET_REF(cache64_ssse3)
GET_REF(cache64_ssse3_atom)
#endif // !HIGH_BIT_DEPTH
#define HPEL(align, cpu, cpuv, cpuc, cpuh)\
void x264_hpel_filter_v_##cpuv( pixel *dst, pixel *src, int16_t *buf, intptr_t stride, intptr_t width);\
void x264_hpel_filter_c_##cpuc( pixel *dst, int16_t *buf, intptr_t width );\
void x264_hpel_filter_h_##cpuh( pixel *dst, pixel *src, intptr_t width );\
static void x264_hpel_filter_##cpu( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src,\
intptr_t stride, int width, int height, int16_t *buf )\
{\
intptr_t realign = (intptr_t)src & (align-1);\
src -= realign;\
dstv -= realign;\
dstc -= realign;\
dsth -= realign;\
width += realign;\
while( height-- )\
{\
x264_hpel_filter_v_##cpuv( dstv, src, buf+16, stride, width );\
x264_hpel_filter_c_##cpuc( dstc, buf+16, width );\
x264_hpel_filter_h_##cpuh( dsth, src, width );\
dsth += stride;\
dstv += stride;\
dstc += stride;\
src += stride;\
}\
x264_sfence();\
}
HPEL(8, mmx2, mmx2, mmx2, mmx2)
#if HIGH_BIT_DEPTH
HPEL(16, sse2, sse2, sse2, sse2)
#else // !HIGH_BIT_DEPTH
HPEL(16, sse2_amd, mmx2, mmx2, sse2)
#if ARCH_X86_64
void x264_hpel_filter_sse2 ( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf );
void x264_hpel_filter_ssse3( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf );
void x264_hpel_filter_avx ( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf );
void x264_hpel_filter_avx2 ( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, intptr_t stride, int width, int height, int16_t *buf );
#else
HPEL(16, sse2, sse2, sse2, sse2)
HPEL(16, ssse3, ssse3, ssse3, ssse3)
HPEL(16, avx, avx, avx, avx)
HPEL(32, avx2, avx2, avx2, avx2)
#endif
#endif // HIGH_BIT_DEPTH
PLANE_COPY(16, sse)
PLANE_COPY(32, avx)
PLANE_COPY_SWAP(16, ssse3)
PLANE_COPY_SWAP(32, avx2)
#if HIGH_BIT_DEPTH
PLANE_COPY_YUYV(64, sse2)
PLANE_COPY_YUYV(64, avx)
#else
PLANE_COPY_YUYV(32, sse2)
PLANE_COPY_YUYV(32, ssse3)
#endif
PLANE_COPY_YUYV(64, avx2)
PLANE_INTERLEAVE(mmx2)
PLANE_INTERLEAVE(sse2)
#if HIGH_BIT_DEPTH
PLANE_INTERLEAVE(avx)
#endif
#if HAVE_X86_INLINE_ASM
#undef MC_CLIP_ADD
#define MC_CLIP_ADD(s,x)\
do\
{\
int temp;\
asm("movd %0, %%xmm0 \n"\
"movd %2, %%xmm1 \n"\
"paddsw %%xmm1, %%xmm0 \n"\
"movd %%xmm0, %1 \n"\
:"+m"(s), "=&r"(temp)\
:"m"(x)\
);\
s = temp;\
} while( 0 )
#undef MC_CLIP_ADD2
#define MC_CLIP_ADD2(s,x)\
do\
{\
asm("movd %0, %%xmm0 \n"\
"movd %1, %%xmm1 \n"\
"paddsw %%xmm1, %%xmm0 \n"\
"movd %%xmm0, %0 \n"\
:"+m"(M32(s))\
:"m"(M32(x))\
);\
} while( 0 )
#endif
PROPAGATE_LIST(ssse3)
PROPAGATE_LIST(avx)
PROPAGATE_LIST(avx2)
#if ARCH_X86_64
void x264_mbtree_propagate_list_internal_avx512( size_t len, uint16_t *ref_costs, int16_t (*mvs)[2], int16_t *propagate_amount,
uint16_t *lowres_costs, int bipred_weight, int mb_y,
int width, int height, int stride, int list_mask );
static void x264_mbtree_propagate_list_avx512( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[2],
int16_t *propagate_amount, uint16_t *lowres_costs,
int bipred_weight, int mb_y, int len, int list )
{
x264_mbtree_propagate_list_internal_avx512( len, ref_costs, mvs, propagate_amount, lowres_costs, bipred_weight << 9,
mb_y << 16, h->mb.i_mb_width, h->mb.i_mb_height, h->mb.i_mb_stride,
(1 << LOWRES_COST_SHIFT) << list );
}
#endif
void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf )
{
if( !(cpu&X264_CPU_MMX) )
return;
pf->copy_16x16_unaligned = x264_mc_copy_w16_mmx;
pf->copy[PIXEL_16x16] = x264_mc_copy_w16_mmx;
pf->copy[PIXEL_8x8] = x264_mc_copy_w8_mmx;
pf->copy[PIXEL_4x4] = x264_mc_copy_w4_mmx;
pf->integral_init4v = x264_integral_init4v_mmx;
pf->integral_init8v = x264_integral_init8v_mmx;
if( !(cpu&X264_CPU_MMX2) )
return;
pf->prefetch_fenc_420 = x264_prefetch_fenc_420_mmx2;
pf->prefetch_fenc_422 = x264_prefetch_fenc_422_mmx2;
pf->prefetch_ref = x264_prefetch_ref_mmx2;
pf->plane_copy_interleave = x264_plane_copy_interleave_mmx2;
pf->store_interleave_chroma = x264_store_interleave_chroma_mmx2;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_mmx2;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_mmx2;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_mmx2;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_mmx2;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_mmx2;
pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_mmx2;
pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_mmx2;
pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_mmx2;
pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_mmx2;
pf->mc_luma = mc_luma_mmx2;
pf->get_ref = get_ref_mmx2;
pf->mc_chroma = x264_mc_chroma_mmx2;
pf->hpel_filter = x264_hpel_filter_mmx2;
pf->weight = x264_mc_weight_wtab_mmx2;
pf->weight_cache = x264_weight_cache_mmx2;
pf->offsetadd = x264_mc_offsetadd_wtab_mmx2;
pf->offsetsub = x264_mc_offsetsub_wtab_mmx2;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_mmx2;
if( cpu&X264_CPU_SSE )
{
pf->memcpy_aligned = x264_memcpy_aligned_sse;
pf->memzero_aligned = x264_memzero_aligned_sse;
pf->plane_copy = x264_plane_copy_sse;
}
#if HIGH_BIT_DEPTH
#if ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead
if( cpu&(X264_CPU_CACHELINE_32|X264_CPU_CACHELINE_64) )
pf->frame_init_lowres_core = x264_frame_init_lowres_core_cache32_mmx2;
#endif
if( !(cpu&X264_CPU_SSE2) )
return;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_sse2;
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2;
pf->plane_copy_interleave = x264_plane_copy_interleave_sse2;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2;
pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_sse2;
if( cpu&X264_CPU_SSE2_IS_FAST )
{
pf->get_ref = get_ref_sse2;
pf->mc_luma = mc_luma_sse2;
pf->hpel_filter = x264_hpel_filter_sse2;
}
pf->integral_init4v = x264_integral_init4v_sse2;
pf->integral_init8v = x264_integral_init8v_sse2;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2;
pf->store_interleave_chroma = x264_store_interleave_chroma_sse2;
pf->offsetadd = x264_mc_offsetadd_wtab_sse2;
pf->offsetsub = x264_mc_offsetsub_wtab_sse2;
if( cpu&X264_CPU_SSE2_IS_SLOW )
return;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_sse2;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_sse2;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_sse2;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_sse2;
pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_sse2;
pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_sse2;
pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_sse2;
pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_sse2;
pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse;
pf->weight = x264_mc_weight_wtab_sse2;
if( !(cpu&X264_CPU_STACK_MOD4) )
pf->mc_chroma = x264_mc_chroma_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3;
pf->plane_copy_swap = x264_plane_copy_swap_ssse3;
pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_ssse3;
pf->mbtree_propagate_list = x264_mbtree_propagate_list_ssse3;
pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_ssse3;
pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_ssse3;
if( !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SLOW_ATOM|X264_CPU_SLOW_PALIGNR)) )
pf->integral_init4v = x264_integral_init4v_ssse3;
if( !(cpu&X264_CPU_AVX) )
return;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx;
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_avx;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_avx;
pf->plane_copy_interleave = x264_plane_copy_interleave_avx;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_avx;
pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_avx;
pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx;
pf->store_interleave_chroma = x264_store_interleave_chroma_avx;
pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_avx;
if( !(cpu&X264_CPU_STACK_MOD4) )
pf->mc_chroma = x264_mc_chroma_avx;
if( cpu&X264_CPU_XOP )
pf->frame_init_lowres_core = x264_frame_init_lowres_core_xop;
if( cpu&X264_CPU_AVX2 )
{
pf->mc_luma = mc_luma_avx2;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_avx2;
pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx2;
}
if( cpu&X264_CPU_AVX512 )
{
pf->plane_copy_deinterleave_v210 = x264_plane_copy_deinterleave_v210_avx512;
}
#else // !HIGH_BIT_DEPTH
#if ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead
if( cpu&X264_CPU_CACHELINE_32 )
{
pf->mc_luma = mc_luma_cache32_mmx2;
pf->get_ref = get_ref_cache32_mmx2;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_cache32_mmx2;
}
else if( cpu&X264_CPU_CACHELINE_64 )
{
pf->mc_luma = mc_luma_cache64_mmx2;
pf->get_ref = get_ref_cache64_mmx2;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_cache32_mmx2;
}
#endif
if( !(cpu&X264_CPU_SSE2) )
return;
pf->integral_init4v = x264_integral_init4v_sse2;
pf->integral_init8v = x264_integral_init8v_sse2;
pf->hpel_filter = x264_hpel_filter_sse2_amd;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2;
pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_sse2;
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2;
pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_sse2;
if( !(cpu&X264_CPU_SSE2_IS_SLOW) )
{
pf->weight = x264_mc_weight_wtab_sse2;
if( !(cpu&X264_CPU_SLOW_ATOM) )
{
pf->offsetadd = x264_mc_offsetadd_wtab_sse2;
pf->offsetsub = x264_mc_offsetsub_wtab_sse2;
}
pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_sse2;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_sse2;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_sse2;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_sse2;
pf->hpel_filter = x264_hpel_filter_sse2;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_sse2;
if( !(cpu&X264_CPU_STACK_MOD4) )
pf->mc_chroma = x264_mc_chroma_sse2;
if( cpu&X264_CPU_SSE2_IS_FAST )
{
pf->store_interleave_chroma = x264_store_interleave_chroma_sse2; // FIXME sse2fast? sse2medium?
pf->plane_copy_interleave = x264_plane_copy_interleave_sse2;
pf->mc_luma = mc_luma_sse2;
pf->get_ref = get_ref_sse2;
if( cpu&X264_CPU_CACHELINE_64 )
{
pf->mc_luma = mc_luma_cache64_sse2;
pf->get_ref = get_ref_cache64_sse2;
}
}
}
if( !(cpu&X264_CPU_SSSE3) )
return;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_ssse3;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_ssse3;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_ssse3;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_ssse3;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_ssse3;
pf->avg[PIXEL_4x16] = x264_pixel_avg_4x16_ssse3;
pf->avg[PIXEL_4x8] = x264_pixel_avg_4x8_ssse3;
pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_ssse3;
pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_ssse3;
pf->plane_copy_swap = x264_plane_copy_swap_ssse3;
pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_ssse3;
pf->mbtree_propagate_list = x264_mbtree_propagate_list_ssse3;
pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_ssse3;
pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_ssse3;
if( !(cpu&X264_CPU_SLOW_PSHUFB) )
{
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_ssse3;
pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_ssse3;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_ssse3;
pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_ssse3;
}
if( !(cpu&X264_CPU_SLOW_PALIGNR) )
{
#if ARCH_X86_64
if( !(cpu&X264_CPU_SLOW_ATOM) ) /* The 64-bit version is slower, but the 32-bit version is faster? */
#endif
pf->hpel_filter = x264_hpel_filter_ssse3;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3;
}
if( !(cpu&X264_CPU_STACK_MOD4) )
pf->mc_chroma = x264_mc_chroma_ssse3;
if( cpu&X264_CPU_CACHELINE_64 )
{
if( !(cpu&X264_CPU_STACK_MOD4) )
pf->mc_chroma = x264_mc_chroma_cache64_ssse3;
pf->mc_luma = mc_luma_cache64_ssse3;
pf->get_ref = get_ref_cache64_ssse3;
if( cpu&X264_CPU_SLOW_ATOM )
{
pf->mc_luma = mc_luma_cache64_ssse3_atom;
pf->get_ref = get_ref_cache64_ssse3_atom;
}
}
pf->weight_cache = x264_weight_cache_ssse3;
pf->weight = x264_mc_weight_wtab_ssse3;
if( !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SLOW_ATOM|X264_CPU_SLOW_PALIGNR)) )
pf->integral_init4v = x264_integral_init4v_ssse3;
if( !(cpu&X264_CPU_SSE4) )
return;
pf->integral_init4h = x264_integral_init4h_sse4;
pf->integral_init8h = x264_integral_init8h_sse4;
if( !(cpu&X264_CPU_AVX) )
return;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx;
pf->integral_init8h = x264_integral_init8h_avx;
pf->hpel_filter = x264_hpel_filter_avx;
if( !(cpu&X264_CPU_STACK_MOD4) )
pf->mc_chroma = x264_mc_chroma_avx;
if( cpu&X264_CPU_XOP )
pf->frame_init_lowres_core = x264_frame_init_lowres_core_xop;
if( cpu&X264_CPU_AVX2 )
{
pf->hpel_filter = x264_hpel_filter_avx2;
pf->mc_chroma = x264_mc_chroma_avx2;
pf->weight = x264_mc_weight_wtab_avx2;
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_avx2;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_avx2;
pf->integral_init8v = x264_integral_init8v_avx2;
pf->integral_init4v = x264_integral_init4v_avx2;
pf->integral_init8h = x264_integral_init8h_avx2;
pf->integral_init4h = x264_integral_init4h_avx2;
pf->frame_init_lowres_core = x264_frame_init_lowres_core_avx2;
pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_avx2;
}
if( cpu&X264_CPU_AVX512 )
{
pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_avx512;
pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_avx512;
pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_avx512;
pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_avx512;
pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_avx512;
}
#endif // HIGH_BIT_DEPTH
if( !(cpu&X264_CPU_AVX) )
return;
pf->memcpy_aligned = x264_memcpy_aligned_avx;
pf->memzero_aligned = x264_memzero_aligned_avx;
pf->plane_copy = x264_plane_copy_avx;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx;
pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx;
if( cpu&X264_CPU_FMA4 )
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_fma4;
if( !(cpu&X264_CPU_AVX2) )
return;
pf->plane_copy_swap = x264_plane_copy_swap_avx2;
pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_avx2;
pf->plane_copy_deinterleave_yuyv = x264_plane_copy_deinterleave_yuyv_avx2;
pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_avx2;
pf->get_ref = get_ref_avx2;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx2;
pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx2;
pf->mbtree_fix8_pack = x264_mbtree_fix8_pack_avx2;
pf->mbtree_fix8_unpack = x264_mbtree_fix8_unpack_avx2;
if( !(cpu&X264_CPU_AVX512) )
return;
pf->memcpy_aligned = x264_memcpy_aligned_avx512;
pf->memzero_aligned = x264_memzero_aligned_avx512;
pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx512;
#if ARCH_X86_64
pf->mbtree_propagate_list = x264_mbtree_propagate_list_avx512;
#endif
}

View file

@ -0,0 +1,32 @@
/*****************************************************************************
* mc.h: x86 motion compensation
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_I386_MC_H
#define X264_I386_MC_H
void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf );
#endif

View file

@ -0,0 +1,220 @@
/*****************************************************************************
* pixel.h: x86 pixel metrics
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_I386_PIXEL_H
#define X264_I386_PIXEL_H
#define DECL_PIXELS( ret, name, suffix, args ) \
ret x264_pixel_##name##_16x16_##suffix args;\
ret x264_pixel_##name##_16x8_##suffix args;\
ret x264_pixel_##name##_8x16_##suffix args;\
ret x264_pixel_##name##_8x8_##suffix args;\
ret x264_pixel_##name##_8x4_##suffix args;\
ret x264_pixel_##name##_4x16_##suffix args;\
ret x264_pixel_##name##_4x8_##suffix args;\
ret x264_pixel_##name##_4x4_##suffix args;\
#define DECL_X1( name, suffix ) \
DECL_PIXELS( int, name, suffix, ( pixel *, intptr_t, pixel *, intptr_t ) )
#define DECL_X4( name, suffix ) \
DECL_PIXELS( void, name##_x3, suffix, ( pixel *, pixel *, pixel *, pixel *, intptr_t, int * ) )\
DECL_PIXELS( void, name##_x4, suffix, ( pixel *, pixel *, pixel *, pixel *, pixel *, intptr_t, int * ) )
DECL_X1( sad, mmx2 )
DECL_X1( sad, sse2 )
DECL_X1( sad, sse3 )
DECL_X1( sad, sse2_aligned )
DECL_X1( sad, ssse3 )
DECL_X1( sad, ssse3_aligned )
DECL_X1( sad, avx2 )
DECL_X1( sad, avx512 )
DECL_X4( sad, mmx2 )
DECL_X4( sad, sse2 )
DECL_X4( sad, sse3 )
DECL_X4( sad, ssse3 )
DECL_X4( sad, xop )
DECL_X4( sad, avx )
DECL_X4( sad, avx2 )
DECL_X4( sad, avx512 )
DECL_X1( ssd, mmx )
DECL_X1( ssd, mmx2 )
DECL_X1( ssd, sse2slow )
DECL_X1( ssd, sse2 )
DECL_X1( ssd, ssse3 )
DECL_X1( ssd, avx )
DECL_X1( ssd, xop )
DECL_X1( ssd, avx2 )
DECL_X1( satd, mmx2 )
DECL_X1( satd, sse2 )
DECL_X1( satd, ssse3 )
DECL_X1( satd, ssse3_atom )
DECL_X1( satd, sse4 )
DECL_X1( satd, avx )
DECL_X1( satd, xop )
DECL_X1( satd, avx2 )
DECL_X1( satd, avx512 )
DECL_X1( sa8d, mmx2 )
DECL_X1( sa8d, sse2 )
DECL_X1( sa8d, ssse3 )
DECL_X1( sa8d, ssse3_atom )
DECL_X1( sa8d, sse4 )
DECL_X1( sa8d, avx )
DECL_X1( sa8d, xop )
DECL_X1( sa8d, avx2 )
DECL_X1( sa8d, avx512 )
DECL_X1( sad, cache32_mmx2 );
DECL_X1( sad, cache64_mmx2 );
DECL_X1( sad, cache64_sse2 );
DECL_X1( sad, cache64_ssse3 );
DECL_X4( sad, cache32_mmx2 );
DECL_X4( sad, cache64_mmx2 );
DECL_X4( sad, cache64_sse2 );
DECL_X4( sad, cache64_ssse3 );
DECL_PIXELS( uint64_t, var, sse2, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, var, avx, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, var, avx2, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, var, avx512, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, mmx2, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, sse2, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, ssse3, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, ssse3_atom, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, sse4, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, avx, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, xop, ( pixel *pix, intptr_t i_stride ))
DECL_PIXELS( uint64_t, hadamard_ac, avx2, ( pixel *pix, intptr_t i_stride ))
void x264_intra_satd_x3_4x4_mmx2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_4x4_mmx2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_4x4_sse2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_4x4_ssse3 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_4x4_avx ( pixel *, pixel *, int * );
void x264_intra_satd_x3_8x8c_mmx2 ( pixel *, pixel *, int * );
void x264_intra_satd_x3_8x8c_ssse3 ( uint8_t *, uint8_t *, int * );
void x264_intra_sad_x3_8x8c_mmx2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8c_sse2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8c_ssse3 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8c_avx2 ( pixel *, pixel *, int * );
void x264_intra_satd_x3_16x16_mmx2 ( pixel *, pixel *, int * );
void x264_intra_satd_x3_16x16_ssse3( uint8_t *, uint8_t *, int * );
void x264_intra_sad_x3_16x16_mmx2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_16x16_sse2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_16x16_ssse3 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_16x16_avx2 ( pixel *, pixel *, int * );
void x264_intra_sa8d_x3_8x8_mmx2 ( uint8_t *, uint8_t *, int * );
void x264_intra_sa8d_x3_8x8_sse2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8_mmx2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8_sse2 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8_ssse3 ( pixel *, pixel *, int * );
void x264_intra_sad_x3_8x8_avx2 ( uint16_t*, uint16_t*, int * );
int x264_intra_satd_x9_4x4_ssse3( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_satd_x9_4x4_sse4 ( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_satd_x9_4x4_avx ( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_satd_x9_4x4_xop ( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_sad_x9_4x4_ssse3 ( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_sad_x9_4x4_sse4 ( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_sad_x9_4x4_avx ( uint8_t *, uint8_t *, uint16_t * );
int x264_intra_sa8d_x9_8x8_ssse3( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
int x264_intra_sa8d_x9_8x8_sse4 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
int x264_intra_sa8d_x9_8x8_avx ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
int x264_intra_sad_x9_8x8_ssse3 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
int x264_intra_sad_x9_8x8_sse4 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
int x264_intra_sad_x9_8x8_avx ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
int x264_intra_sad_x9_8x8_avx2 ( uint8_t *, uint8_t *, uint8_t *, uint16_t *, uint16_t * );
void x264_pixel_ssd_nv12_core_sse2( pixel *pixuv1, intptr_t stride1,
pixel *pixuv2, intptr_t stride2, int width,
int height, uint64_t *ssd_u, uint64_t *ssd_v );
void x264_pixel_ssd_nv12_core_avx ( pixel *pixuv1, intptr_t stride1,
pixel *pixuv2, intptr_t stride2, int width,
int height, uint64_t *ssd_u, uint64_t *ssd_v );
void x264_pixel_ssd_nv12_core_xop ( pixel *pixuv1, intptr_t stride1,
pixel *pixuv2, intptr_t stride2, int width,
int height, uint64_t *ssd_u, uint64_t *ssd_v );
void x264_pixel_ssd_nv12_core_avx2( pixel *pixuv1, intptr_t stride1,
pixel *pixuv2, intptr_t stride2, int width,
int height, uint64_t *ssd_u, uint64_t *ssd_v );
void x264_pixel_ssim_4x4x2_core_mmx2( const uint8_t *pix1, intptr_t stride1,
const uint8_t *pix2, intptr_t stride2, int sums[2][4] );
void x264_pixel_ssim_4x4x2_core_sse2( const pixel *pix1, intptr_t stride1,
const pixel *pix2, intptr_t stride2, int sums[2][4] );
void x264_pixel_ssim_4x4x2_core_avx ( const pixel *pix1, intptr_t stride1,
const pixel *pix2, intptr_t stride2, int sums[2][4] );
float x264_pixel_ssim_end4_sse2( int sum0[5][4], int sum1[5][4], int width );
float x264_pixel_ssim_end4_avx ( int sum0[5][4], int sum1[5][4], int width );
int x264_pixel_var2_8x8_sse2 ( pixel *fenc, pixel *fdec, int ssd[2] );
int x264_pixel_var2_8x8_ssse3 ( uint8_t *fenc, uint8_t *fdec, int ssd[2] );
int x264_pixel_var2_8x8_avx2 ( pixel *fenc, pixel *fdec, int ssd[2] );
int x264_pixel_var2_8x8_avx512 ( pixel *fenc, pixel *fdec, int ssd[2] );
int x264_pixel_var2_8x16_sse2 ( pixel *fenc, pixel *fdec, int ssd[2] );
int x264_pixel_var2_8x16_ssse3 ( uint8_t *fenc, uint8_t *fdec, int ssd[2] );
int x264_pixel_var2_8x16_avx2 ( pixel *fenc, pixel *fdec, int ssd[2] );
int x264_pixel_var2_8x16_avx512( pixel *fenc, pixel *fdec, int ssd[2] );
int x264_pixel_vsad_mmx2 ( pixel *src, intptr_t stride, int height );
int x264_pixel_vsad_sse2 ( pixel *src, intptr_t stride, int height );
int x264_pixel_vsad_ssse3( pixel *src, intptr_t stride, int height );
int x264_pixel_vsad_xop ( pixel *src, intptr_t stride, int height );
int x264_pixel_vsad_avx2 ( uint16_t *src, intptr_t stride, int height );
int x264_pixel_asd8_sse2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height );
int x264_pixel_asd8_ssse3( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height );
int x264_pixel_asd8_xop ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height );
uint64_t x264_pixel_sa8d_satd_16x16_sse2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t x264_pixel_sa8d_satd_16x16_ssse3 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t x264_pixel_sa8d_satd_16x16_ssse3_atom( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t x264_pixel_sa8d_satd_16x16_sse4 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t x264_pixel_sa8d_satd_16x16_avx ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t x264_pixel_sa8d_satd_16x16_xop ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
uint64_t x264_pixel_sa8d_satd_16x16_avx2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 );
#define DECL_ADS( size, suffix ) \
int x264_pixel_ads##size##_##suffix( int enc_dc[size], uint16_t *sums, int delta,\
uint16_t *cost_mvx, int16_t *mvs, int width, int thresh );
DECL_ADS( 4, mmx2 )
DECL_ADS( 2, mmx2 )
DECL_ADS( 1, mmx2 )
DECL_ADS( 4, sse2 )
DECL_ADS( 2, sse2 )
DECL_ADS( 1, sse2 )
DECL_ADS( 4, ssse3 )
DECL_ADS( 2, ssse3 )
DECL_ADS( 1, ssse3 )
DECL_ADS( 4, avx )
DECL_ADS( 2, avx )
DECL_ADS( 1, avx )
DECL_ADS( 4, avx2 )
DECL_ADS( 2, avx2 )
DECL_ADS( 1, avx2 )
#undef DECL_PIXELS
#undef DECL_X1
#undef DECL_X4
#undef DECL_ADS
#endif

View file

@ -0,0 +1,609 @@
/*****************************************************************************
* predict-c.c: intra prediction
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "predict.h"
#include "pixel.h"
#define PREDICT_P_SUM(j,i)\
H += i * ( src[j+i - FDEC_STRIDE ] - src[j-i - FDEC_STRIDE ] );\
V += i * ( src[(j+i)*FDEC_STRIDE -1] - src[(j-i)*FDEC_STRIDE -1] );
#if HAVE_X86_INLINE_ASM
#if HIGH_BIT_DEPTH
ALIGNED_16( static const int16_t pw_12345678[8] ) = {1,2,3,4,5,6,7,8};
ALIGNED_16( static const int16_t pw_m87654321[8] ) = {-8,-7,-6,-5,-4,-3,-2,-1};
ALIGNED_16( static const int16_t pw_m32101234[8] ) = {-3,-2,-1,0,1,2,3,4};
#else // !HIGH_BIT_DEPTH
ALIGNED_8( static const int8_t pb_12345678[8] ) = {1,2,3,4,5,6,7,8};
ALIGNED_8( static const int8_t pb_m87654321[8] ) = {-8,-7,-6,-5,-4,-3,-2,-1};
ALIGNED_8( static const int8_t pb_m32101234[8] ) = {-3,-2,-1,0,1,2,3,4};
#endif // HIGH_BIT_DEPTH
#endif // HAVE_X86_INLINE_ASM
#define PREDICT_16x16_P_CORE\
int H = 0;\
int V = 0;\
PREDICT_P_SUM(7,1)\
PREDICT_P_SUM(7,2)\
PREDICT_P_SUM(7,3)\
PREDICT_P_SUM(7,4)\
PREDICT_P_SUM(7,5)\
PREDICT_P_SUM(7,6)\
PREDICT_P_SUM(7,7)\
PREDICT_P_SUM(7,8)
#define PREDICT_16x16_P_END(name)\
int a = 16 * ( src[15*FDEC_STRIDE -1] + src[15 - FDEC_STRIDE] );\
int b = ( 5 * H + 32 ) >> 6;\
int c = ( 5 * V + 32 ) >> 6;\
int i00 = a - b * 7 - c * 7 + 16;\
/* b*15 + c*15 can overflow: it's easier to just branch away in this rare case
* than to try to consider it in the asm. */\
if( BIT_DEPTH > 8 && (i00 > 0x7fff || abs(b) > 1092 || abs(c) > 1092) )\
x264_predict_16x16_p_c( src );\
else\
x264_predict_16x16_p_core_##name( src, i00, b, c );
#define PREDICT_16x16_P(name, name2)\
static void x264_predict_16x16_p_##name( pixel *src )\
{\
PREDICT_16x16_P_CORE\
PREDICT_16x16_P_END(name2)\
}
#if HAVE_X86_INLINE_ASM
#if HIGH_BIT_DEPTH
#define PREDICT_16x16_P_ASM\
asm (\
"movdqu %1, %%xmm1 \n"\
"movdqa %2, %%xmm0 \n"\
"pmaddwd %3, %%xmm0 \n"\
"pmaddwd %4, %%xmm1 \n"\
"paddd %%xmm1, %%xmm0 \n"\
"movhlps %%xmm0, %%xmm1 \n"\
"paddd %%xmm1, %%xmm0 \n"\
"pshuflw $14, %%xmm0, %%xmm1 \n"\
"paddd %%xmm1, %%xmm0 \n"\
"movd %%xmm0, %0 \n"\
:"=r"(H)\
:"m"(src[-FDEC_STRIDE-1]), "m"(src[-FDEC_STRIDE+8]),\
"m"(*pw_12345678), "m"(*pw_m87654321)\
);
#else // !HIGH_BIT_DEPTH
#define PREDICT_16x16_P_ASM\
asm (\
"movq %1, %%mm1 \n"\
"movq %2, %%mm0 \n"\
"palignr $7, %3, %%mm1 \n"\
"pmaddubsw %4, %%mm0 \n"\
"pmaddubsw %5, %%mm1 \n"\
"paddw %%mm1, %%mm0 \n"\
"pshufw $14, %%mm0, %%mm1 \n"\
"paddw %%mm1, %%mm0 \n"\
"pshufw $1, %%mm0, %%mm1 \n"\
"paddw %%mm1, %%mm0 \n"\
"movd %%mm0, %0 \n"\
"movswl %w0, %0 \n"\
:"=r"(H)\
:"m"(src[-FDEC_STRIDE]), "m"(src[-FDEC_STRIDE+8]),\
"m"(src[-FDEC_STRIDE-8]), "m"(*pb_12345678), "m"(*pb_m87654321)\
);
#endif // HIGH_BIT_DEPTH
#define PREDICT_16x16_P_CORE_INLINE\
int H, V;\
PREDICT_16x16_P_ASM\
V = 8 * ( src[15*FDEC_STRIDE-1] - src[-1*FDEC_STRIDE-1] )\
+ 7 * ( src[14*FDEC_STRIDE-1] - src[ 0*FDEC_STRIDE-1] )\
+ 6 * ( src[13*FDEC_STRIDE-1] - src[ 1*FDEC_STRIDE-1] )\
+ 5 * ( src[12*FDEC_STRIDE-1] - src[ 2*FDEC_STRIDE-1] )\
+ 4 * ( src[11*FDEC_STRIDE-1] - src[ 3*FDEC_STRIDE-1] )\
+ 3 * ( src[10*FDEC_STRIDE-1] - src[ 4*FDEC_STRIDE-1] )\
+ 2 * ( src[ 9*FDEC_STRIDE-1] - src[ 5*FDEC_STRIDE-1] )\
+ 1 * ( src[ 8*FDEC_STRIDE-1] - src[ 6*FDEC_STRIDE-1] );
#define PREDICT_16x16_P_INLINE(name, name2)\
static void x264_predict_16x16_p_##name( pixel *src )\
{\
PREDICT_16x16_P_CORE_INLINE\
PREDICT_16x16_P_END(name2)\
}
#else // !HAVE_X86_INLINE_ASM
#define PREDICT_16x16_P_INLINE(name, name2) PREDICT_16x16_P(name, name2)
#endif // HAVE_X86_INLINE_ASM
#if HIGH_BIT_DEPTH
PREDICT_16x16_P_INLINE( sse2, sse2 )
#else // !HIGH_BIT_DEPTH
#if !ARCH_X86_64
PREDICT_16x16_P( mmx2, mmx2 )
#endif // !ARCH_X86_64
PREDICT_16x16_P( sse2, sse2 )
#if HAVE_X86_INLINE_ASM
PREDICT_16x16_P_INLINE( ssse3, sse2 )
#endif // HAVE_X86_INLINE_ASM
PREDICT_16x16_P_INLINE( avx, avx )
#endif // HIGH_BIT_DEPTH
PREDICT_16x16_P_INLINE( avx2, avx2 )
#define PREDICT_8x16C_P_CORE\
int H = 0, V = 0;\
for( int i = 0; i < 4; i++ )\
H += ( i + 1 ) * ( src[4 + i - FDEC_STRIDE] - src[2 - i - FDEC_STRIDE] );\
for( int i = 0; i < 8; i++ )\
V += ( i + 1 ) * ( src[-1 + (i+8)*FDEC_STRIDE] - src[-1 + (6-i)*FDEC_STRIDE] );
#if HIGH_BIT_DEPTH
#define PREDICT_8x16C_P_END(name)\
int a = 16 * ( src[-1 + 15*FDEC_STRIDE] + src[7 - FDEC_STRIDE] );\
int b = ( 17 * H + 16 ) >> 5;\
int c = ( 5 * V + 32 ) >> 6;\
x264_predict_8x16c_p_core_##name( src, a, b, c );
#else // !HIGH_BIT_DEPTH
#define PREDICT_8x16C_P_END(name)\
int a = 16 * ( src[-1 + 15*FDEC_STRIDE] + src[7 - FDEC_STRIDE] );\
int b = ( 17 * H + 16 ) >> 5;\
int c = ( 5 * V + 32 ) >> 6;\
int i00 = a -3*b -7*c + 16;\
x264_predict_8x16c_p_core_##name( src, i00, b, c );
#endif // HIGH_BIT_DEPTH
#define PREDICT_8x16C_P(name)\
static void x264_predict_8x16c_p_##name( pixel *src )\
{\
PREDICT_8x16C_P_CORE\
PREDICT_8x16C_P_END(name)\
}
#if !ARCH_X86_64 && !HIGH_BIT_DEPTH
PREDICT_8x16C_P( mmx2 )
#endif // !ARCH_X86_64 && !HIGH_BIT_DEPTH
PREDICT_8x16C_P( sse2 )
PREDICT_8x16C_P( avx )
PREDICT_8x16C_P( avx2 )
#define PREDICT_8x8C_P_CORE\
int H = 0;\
int V = 0;\
PREDICT_P_SUM(3,1)\
PREDICT_P_SUM(3,2)\
PREDICT_P_SUM(3,3)\
PREDICT_P_SUM(3,4)
#if HIGH_BIT_DEPTH
#define PREDICT_8x8C_P_END(name)\
int a = 16 * ( src[7*FDEC_STRIDE -1] + src[7 - FDEC_STRIDE] );\
int b = ( 17 * H + 16 ) >> 5;\
int c = ( 17 * V + 16 ) >> 5;\
x264_predict_8x8c_p_core_##name( src, a, b, c );
#else // !HIGH_BIT_DEPTH
#define PREDICT_8x8C_P_END(name)\
int a = 16 * ( src[7*FDEC_STRIDE -1] + src[7 - FDEC_STRIDE] );\
int b = ( 17 * H + 16 ) >> 5;\
int c = ( 17 * V + 16 ) >> 5;\
int i00 = a -3*b -3*c + 16;\
x264_predict_8x8c_p_core_##name( src, i00, b, c );
#endif // HIGH_BIT_DEPTH
#define PREDICT_8x8C_P(name, name2)\
static void x264_predict_8x8c_p_##name( pixel *src )\
{\
PREDICT_8x8C_P_CORE\
PREDICT_8x8C_P_END(name2)\
}
#if HAVE_X86_INLINE_ASM
#if HIGH_BIT_DEPTH
#define PREDICT_8x8C_P_ASM\
asm (\
"movdqa %1, %%xmm0 \n"\
"pmaddwd %2, %%xmm0 \n"\
"movhlps %%xmm0, %%xmm1 \n"\
"paddd %%xmm1, %%xmm0 \n"\
"pshuflw $14, %%xmm0, %%xmm1 \n"\
"paddd %%xmm1, %%xmm0 \n"\
"movd %%xmm0, %0 \n"\
:"=r"(H)\
:"m"(src[-FDEC_STRIDE]), "m"(*pw_m32101234)\
);
#else // !HIGH_BIT_DEPTH
#define PREDICT_8x8C_P_ASM\
asm (\
"movq %1, %%mm0 \n"\
"pmaddubsw %2, %%mm0 \n"\
"pshufw $14, %%mm0, %%mm1 \n"\
"paddw %%mm1, %%mm0 \n"\
"pshufw $1, %%mm0, %%mm1 \n"\
"paddw %%mm1, %%mm0 \n"\
"movd %%mm0, %0 \n"\
"movswl %w0, %0 \n"\
:"=r"(H)\
:"m"(src[-FDEC_STRIDE]), "m"(*pb_m32101234)\
);
#endif // HIGH_BIT_DEPTH
#define PREDICT_8x8C_P_CORE_INLINE\
int H, V;\
PREDICT_8x8C_P_ASM\
V = 1 * ( src[4*FDEC_STRIDE -1] - src[ 2*FDEC_STRIDE -1] )\
+ 2 * ( src[5*FDEC_STRIDE -1] - src[ 1*FDEC_STRIDE -1] )\
+ 3 * ( src[6*FDEC_STRIDE -1] - src[ 0*FDEC_STRIDE -1] )\
+ 4 * ( src[7*FDEC_STRIDE -1] - src[-1*FDEC_STRIDE -1] );\
H += -4 * src[-1*FDEC_STRIDE -1];
#define PREDICT_8x8C_P_INLINE(name, name2)\
static void x264_predict_8x8c_p_##name( pixel *src )\
{\
PREDICT_8x8C_P_CORE_INLINE\
PREDICT_8x8C_P_END(name2)\
}
#else // !HAVE_X86_INLINE_ASM
#define PREDICT_8x8C_P_INLINE(name, name2) PREDICT_8x8C_P(name, name2)
#endif // HAVE_X86_INLINE_ASM
#if HIGH_BIT_DEPTH
PREDICT_8x8C_P_INLINE( sse2, sse2 )
#else //!HIGH_BIT_DEPTH
#if !ARCH_X86_64
PREDICT_8x8C_P( mmx2, mmx2 )
#endif // !ARCH_X86_64
PREDICT_8x8C_P( sse2, sse2 )
#if HAVE_X86_INLINE_ASM
PREDICT_8x8C_P_INLINE( ssse3, sse2 )
#endif // HAVE_X86_INLINE_ASM
#endif // HIGH_BIT_DEPTH
PREDICT_8x8C_P_INLINE( avx, avx )
PREDICT_8x8C_P_INLINE( avx2, avx2 )
#if ARCH_X86_64 && !HIGH_BIT_DEPTH
static void x264_predict_8x8c_dc_left( uint8_t *src )
{
int y;
uint32_t s0 = 0, s1 = 0;
uint64_t dc0, dc1;
for( y = 0; y < 4; y++ )
{
s0 += src[y * FDEC_STRIDE - 1];
s1 += src[(y+4) * FDEC_STRIDE - 1];
}
dc0 = (( s0 + 2 ) >> 2) * 0x0101010101010101ULL;
dc1 = (( s1 + 2 ) >> 2) * 0x0101010101010101ULL;
for( y = 0; y < 4; y++ )
{
M64( src ) = dc0;
src += FDEC_STRIDE;
}
for( y = 0; y < 4; y++ )
{
M64( src ) = dc1;
src += FDEC_STRIDE;
}
}
#endif // ARCH_X86_64 && !HIGH_BIT_DEPTH
/****************************************************************************
* Exported functions:
****************************************************************************/
void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_MMX2) )
return;
pf[I_PRED_16x16_V] = x264_predict_16x16_v_mmx2;
pf[I_PRED_16x16_H] = x264_predict_16x16_h_mmx2;
#if HIGH_BIT_DEPTH
if( !(cpu&X264_CPU_SSE) )
return;
pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse;
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_sse2;
pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_sse2;
pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_sse2;
pf[I_PRED_16x16_H] = x264_predict_16x16_h_sse2;
pf[I_PRED_16x16_P] = x264_predict_16x16_p_sse2;
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_16x16_V] = x264_predict_16x16_v_avx;
if( !(cpu&X264_CPU_AVX2) )
return;
pf[I_PRED_16x16_H] = x264_predict_16x16_h_avx2;
#else
#if !ARCH_X86_64
pf[I_PRED_16x16_P] = x264_predict_16x16_p_mmx2;
#endif
if( !(cpu&X264_CPU_SSE) )
return;
pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse;
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_sse2;
if( cpu&X264_CPU_SSE2_IS_SLOW )
return;
pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_sse2;
pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_sse2;
pf[I_PRED_16x16_P] = x264_predict_16x16_p_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
if( !(cpu&X264_CPU_SLOW_PSHUFB) )
pf[I_PRED_16x16_H] = x264_predict_16x16_h_ssse3;
#if HAVE_X86_INLINE_ASM
pf[I_PRED_16x16_P] = x264_predict_16x16_p_ssse3;
#endif
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_16x16_P] = x264_predict_16x16_p_avx;
#endif // HIGH_BIT_DEPTH
if( cpu&X264_CPU_AVX2 )
{
pf[I_PRED_16x16_P] = x264_predict_16x16_p_avx2;
pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_avx2;
pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_avx2;
pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_avx2;
}
}
void x264_predict_8x8c_init_mmx( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_MMX) )
return;
#if HIGH_BIT_DEPTH
pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_mmx;
if( !(cpu&X264_CPU_MMX2) )
return;
pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_mmx2;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_mmx2;
if( !(cpu&X264_CPU_SSE) )
return;
pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_sse;
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_sse2;
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_sse2;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_sse2;
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_sse2;
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_avx;
if( !(cpu&X264_CPU_AVX2) )
return;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_avx2;
#else
#if ARCH_X86_64
pf[I_PRED_CHROMA_DC_LEFT] = x264_predict_8x8c_dc_left;
#endif
pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_mmx;
if( !(cpu&X264_CPU_MMX2) )
return;
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_mmx2;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_mmx2;
#if !ARCH_X86_64
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_mmx2;
#endif
pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_mmx2;
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_ssse3;
#if HAVE_X86_INLINE_ASM
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_ssse3;
#endif
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_avx;
#endif // HIGH_BIT_DEPTH
if( cpu&X264_CPU_AVX2 )
{
pf[I_PRED_CHROMA_P] = x264_predict_8x8c_p_avx2;
}
}
void x264_predict_8x16c_init_mmx( int cpu, x264_predict_t pf[7] )
{
if( !(cpu&X264_CPU_MMX) )
return;
#if HIGH_BIT_DEPTH
if( !(cpu&X264_CPU_MMX2) )
return;
pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_mmx2;
pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_mmx2;
if( !(cpu&X264_CPU_SSE) )
return;
pf[I_PRED_CHROMA_V] = x264_predict_8x16c_v_sse;
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_sse2;
pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_sse2;
pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_sse2;
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_sse2;
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_avx;
if( !(cpu&X264_CPU_AVX2) )
return;
pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_avx2;
#else
pf[I_PRED_CHROMA_V] = x264_predict_8x16c_v_mmx;
if( !(cpu&X264_CPU_MMX2) )
return;
pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_mmx2;
pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_mmx2;
pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_mmx2;
#if !ARCH_X86_64
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_mmx2;
#endif
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_ssse3;
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_avx;
#endif // HIGH_BIT_DEPTH
if( cpu&X264_CPU_AVX2 )
{
pf[I_PRED_CHROMA_P] = x264_predict_8x16c_p_avx2;
}
}
void x264_predict_8x8_init_mmx( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_8x8_filter )
{
if( !(cpu&X264_CPU_MMX2) )
return;
#if HIGH_BIT_DEPTH
if( !(cpu&X264_CPU_SSE) )
return;
pf[I_PRED_8x8_V] = x264_predict_8x8_v_sse;
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_8x8_H] = x264_predict_8x8_h_sse2;
pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_sse2;
pf[I_PRED_8x8_DC_TOP] = x264_predict_8x8_dc_top_sse2;
pf[I_PRED_8x8_DC_LEFT]= x264_predict_8x8_dc_left_sse2;
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_sse2;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_sse2;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_sse2;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_sse2;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_sse2;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_sse2;
*predict_8x8_filter = x264_predict_8x8_filter_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_ssse3;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_ssse3;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_ssse3;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_ssse3;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_ssse3;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_ssse3;
*predict_8x8_filter = x264_predict_8x8_filter_ssse3;
if( cpu&X264_CPU_CACHELINE_64 )
{
pf[I_PRED_8x8_DDL]= x264_predict_8x8_ddl_cache64_ssse3;
pf[I_PRED_8x8_DDR]= x264_predict_8x8_ddr_cache64_ssse3;
}
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_avx;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_avx;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_avx;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_avx;
*predict_8x8_filter = x264_predict_8x8_filter_avx;
#else
pf[I_PRED_8x8_V] = x264_predict_8x8_v_mmx2;
pf[I_PRED_8x8_H] = x264_predict_8x8_h_mmx2;
pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_mmx2;
pf[I_PRED_8x8_DC_TOP] = x264_predict_8x8_dc_top_mmx2;
pf[I_PRED_8x8_DC_LEFT]= x264_predict_8x8_dc_left_mmx2;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_mmx2;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_mmx2;
*predict_8x8_filter = x264_predict_8x8_filter_mmx2;
#if ARCH_X86
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_mmx2;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_mmx2;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_mmx2;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_mmx2;
#endif
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_sse2;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_sse2;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_sse2;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_sse2;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_sse2;
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
if( !(cpu&X264_CPU_SLOW_PALIGNR) )
{
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_ssse3;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_ssse3;
}
pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_ssse3;
*predict_8x8_filter = x264_predict_8x8_filter_ssse3;
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_avx;
pf[I_PRED_8x8_DDR] = x264_predict_8x8_ddr_avx;
pf[I_PRED_8x8_VL] = x264_predict_8x8_vl_avx;
pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_avx;
pf[I_PRED_8x8_HD] = x264_predict_8x8_hd_avx;
#endif // HIGH_BIT_DEPTH
}
void x264_predict_4x4_init_mmx( int cpu, x264_predict_t pf[12] )
{
if( !(cpu&X264_CPU_MMX2) )
return;
pf[I_PRED_4x4_DC] = x264_predict_4x4_dc_mmx2;
pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_mmx2;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_mmx2;
pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_mmx2;
pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_mmx2;
pf[I_PRED_4x4_HU] = x264_predict_4x4_hu_mmx2;
#if HIGH_BIT_DEPTH
if( !(cpu&X264_CPU_SSE2) )
return;
pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_sse2;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_sse2;
pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_sse2;
pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_sse2;
pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_sse2;
if( !(cpu&X264_CPU_SSSE3) )
return;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_ssse3;
pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_ssse3;
pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_ssse3;
if( !(cpu&X264_CPU_AVX) )
return;
pf[I_PRED_4x4_DDL] = x264_predict_4x4_ddl_avx;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_avx;
pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_avx;
pf[I_PRED_4x4_VL] = x264_predict_4x4_vl_avx;
pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_avx;
if( !(cpu&X264_CPU_AVX2) )
return;
pf[I_PRED_4x4_H] = x264_predict_4x4_h_avx2;
#else
pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_mmx2;
if( !(cpu&X264_CPU_SSSE3) )
return;
pf[I_PRED_4x4_DDR] = x264_predict_4x4_ddr_ssse3;
pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_ssse3;
pf[I_PRED_4x4_HD] = x264_predict_4x4_hd_ssse3;
if( cpu&X264_CPU_CACHELINE_64 )
pf[I_PRED_4x4_VR] = x264_predict_4x4_vr_cache64_ssse3;
#endif // HIGH_BIT_DEPTH
}

View file

@ -0,0 +1,144 @@
/*****************************************************************************
* predict.h: x86 intra prediction
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_I386_PREDICT_H
#define X264_I386_PREDICT_H
void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] );
void x264_predict_8x16c_init_mmx( int cpu, x264_predict_t pf[7] );
void x264_predict_8x8c_init_mmx ( int cpu, x264_predict_t pf[7] );
void x264_predict_4x4_init_mmx ( int cpu, x264_predict_t pf[12] );
void x264_predict_8x8_init_mmx ( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_8x8_filter );
void x264_predict_16x16_v_mmx2( pixel *src );
void x264_predict_16x16_v_sse ( pixel *src );
void x264_predict_16x16_v_avx ( uint16_t *src );
void x264_predict_16x16_h_mmx2( pixel *src );
void x264_predict_16x16_h_sse2( uint16_t *src );
void x264_predict_16x16_h_ssse3( uint8_t *src );
void x264_predict_16x16_h_avx2( uint16_t *src );
void x264_predict_16x16_dc_sse2( pixel *src );
void x264_predict_16x16_dc_avx2( pixel *src );
void x264_predict_16x16_dc_left_sse2( pixel *src );
void x264_predict_16x16_dc_left_avx2( pixel *src );
void x264_predict_16x16_dc_top_sse2( pixel *src );
void x264_predict_16x16_dc_top_avx2( pixel *src );
void x264_predict_16x16_p_core_mmx2( uint8_t *src, int i00, int b, int c );
void x264_predict_16x16_p_core_sse2( pixel *src, int i00, int b, int c );
void x264_predict_16x16_p_core_avx( pixel *src, int i00, int b, int c );
void x264_predict_16x16_p_core_avx2( pixel *src, int i00, int b, int c );
void x264_predict_8x16c_dc_mmx2( pixel *src );
void x264_predict_8x16c_dc_sse2( uint16_t *src );
void x264_predict_8x16c_dc_top_mmx2( uint8_t *src );
void x264_predict_8x16c_dc_top_sse2( uint16_t *src );
void x264_predict_8x16c_v_mmx( uint8_t *src );
void x264_predict_8x16c_v_sse( uint16_t *src );
void x264_predict_8x16c_h_mmx2( pixel *src );
void x264_predict_8x16c_h_sse2( uint16_t *src );
void x264_predict_8x16c_h_ssse3( uint8_t *src );
void x264_predict_8x16c_h_avx2( uint16_t *src );
void x264_predict_8x16c_p_core_mmx2( uint8_t *src, int i00, int b, int c );
void x264_predict_8x16c_p_core_sse2( pixel *src, int i00, int b, int c );
void x264_predict_8x16c_p_core_avx ( pixel *src, int i00, int b, int c );
void x264_predict_8x16c_p_core_avx2( pixel *src, int i00, int b, int c );
void x264_predict_8x8c_p_core_mmx2( uint8_t *src, int i00, int b, int c );
void x264_predict_8x8c_p_core_sse2( pixel *src, int i00, int b, int c );
void x264_predict_8x8c_p_core_avx ( pixel *src, int i00, int b, int c );
void x264_predict_8x8c_p_core_avx2( pixel *src, int i00, int b, int c );
void x264_predict_8x8c_dc_mmx2( pixel *src );
void x264_predict_8x8c_dc_sse2( uint16_t *src );
void x264_predict_8x8c_dc_top_mmx2( uint8_t *src );
void x264_predict_8x8c_dc_top_sse2( uint16_t *src );
void x264_predict_8x8c_v_mmx( pixel *src );
void x264_predict_8x8c_v_sse( uint16_t *src );
void x264_predict_8x8c_h_mmx2( pixel *src );
void x264_predict_8x8c_h_sse2( uint16_t *src );
void x264_predict_8x8c_h_ssse3( uint8_t *src );
void x264_predict_8x8c_h_avx2( uint16_t *src );
void x264_predict_8x8_v_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_v_sse ( uint16_t *src, uint16_t edge[36] );
void x264_predict_8x8_h_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_h_sse2( uint16_t *src, uint16_t edge[36] );
void x264_predict_8x8_hd_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_hu_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_dc_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_dc_sse2( uint16_t *src, uint16_t edge[36] );
void x264_predict_8x8_dc_top_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_dc_top_sse2( uint16_t *src, uint16_t edge[36] );
void x264_predict_8x8_dc_left_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_dc_left_sse2( uint16_t *src, uint16_t edge[36] );
void x264_predict_8x8_ddl_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_ddl_sse2( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddl_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddl_cache64_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddl_avx( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddr_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_ddr_sse2( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddr_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddr_cache64_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_ddr_avx( pixel *src, pixel edge[36] );
void x264_predict_8x8_vl_sse2( pixel *src, pixel edge[36] );
void x264_predict_8x8_vl_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_vl_avx( pixel *src, pixel edge[36] );
void x264_predict_8x8_vl_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_vr_mmx2( uint8_t *src, uint8_t edge[36] );
void x264_predict_8x8_vr_sse2( pixel *src, pixel edge[36] );
void x264_predict_8x8_vr_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_vr_avx( pixel *src, pixel edge[36] );
void x264_predict_8x8_hu_sse2( pixel *src, pixel edge[36] );
void x264_predict_8x8_hu_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_hu_avx( pixel *src, pixel edge[36] );
void x264_predict_8x8_hd_sse2( pixel *src, pixel edge[36] );
void x264_predict_8x8_hd_ssse3( pixel *src, pixel edge[36] );
void x264_predict_8x8_hd_avx( pixel *src, pixel edge[36] );
void x264_predict_8x8_filter_mmx2( uint8_t *src, uint8_t edge[36], int i_neighbor, int i_filters );
void x264_predict_8x8_filter_sse2( uint16_t *src, uint16_t edge[36], int i_neighbor, int i_filters );
void x264_predict_8x8_filter_ssse3( pixel *src, pixel edge[36], int i_neighbor, int i_filters );
void x264_predict_8x8_filter_avx( uint16_t *src, uint16_t edge[36], int i_neighbor, int i_filters );
void x264_predict_4x4_h_avx2( uint16_t *src );
void x264_predict_4x4_ddl_mmx2( pixel *src );
void x264_predict_4x4_ddl_sse2( uint16_t *src );
void x264_predict_4x4_ddl_avx( uint16_t *src );
void x264_predict_4x4_ddr_mmx2( pixel *src );
void x264_predict_4x4_vl_mmx2( pixel *src );
void x264_predict_4x4_vl_sse2( uint16_t *src );
void x264_predict_4x4_vl_avx( uint16_t *src );
void x264_predict_4x4_vr_mmx2( uint8_t *src );
void x264_predict_4x4_vr_sse2( uint16_t *src );
void x264_predict_4x4_vr_ssse3( pixel *src );
void x264_predict_4x4_vr_cache64_ssse3( uint8_t *src );
void x264_predict_4x4_vr_avx( uint16_t *src );
void x264_predict_4x4_hd_mmx2( pixel *src );
void x264_predict_4x4_hd_sse2( uint16_t *src );
void x264_predict_4x4_hd_ssse3( pixel *src );
void x264_predict_4x4_hd_avx( uint16_t *src );
void x264_predict_4x4_dc_mmx2( pixel *src );
void x264_predict_4x4_ddr_sse2( uint16_t *src );
void x264_predict_4x4_ddr_ssse3( pixel *src );
void x264_predict_4x4_ddr_avx( uint16_t *src );
void x264_predict_4x4_hu_mmx2( pixel *src );
#endif

View file

@ -0,0 +1,156 @@
/*****************************************************************************
* quant.h: x86 quantization and level-run
*****************************************************************************
* Copyright (C) 2005-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
* Christian Heine <sennindemokrit@gmx.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_I386_QUANT_H
#define X264_I386_QUANT_H
int x264_quant_2x2_dc_mmx2( dctcoef dct[4], int mf, int bias );
int x264_quant_4x4_dc_mmx2( dctcoef dct[16], int mf, int bias );
int x264_quant_4x4_mmx2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_8x8_mmx2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] );
int x264_quant_2x2_dc_sse2( dctcoef dct[16], int mf, int bias );
int x264_quant_4x4_dc_sse2( dctcoef dct[16], int mf, int bias );
int x264_quant_4x4_sse2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_4x4x4_sse2( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_8x8_sse2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] );
int x264_quant_2x2_dc_ssse3( dctcoef dct[4], int mf, int bias );
int x264_quant_4x4_dc_ssse3( dctcoef dct[16], int mf, int bias );
int x264_quant_4x4_ssse3( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_4x4x4_ssse3( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_8x8_ssse3( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] );
int x264_quant_2x2_dc_sse4( dctcoef dct[16], int mf, int bias );
int x264_quant_4x4_dc_sse4( dctcoef dct[16], int mf, int bias );
int x264_quant_4x4_sse4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_4x4x4_sse4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_8x8_sse4( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] );
int x264_quant_4x4_avx2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] );
int x264_quant_4x4_dc_avx2( dctcoef dct[16], int mf, int bias );
int x264_quant_8x8_avx2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] );
int x264_quant_4x4x4_avx2( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] );
void x264_dequant_4x4_mmx( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4dc_mmx2( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_mmx( int16_t dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_sse2( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4dc_sse2( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_sse2( dctcoef dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_avx( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4dc_avx( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_avx( dctcoef dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_xop( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4dc_xop( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_xop( dctcoef dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_avx2( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_4x4dc_avx2( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_avx2( dctcoef dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_avx512( dctcoef dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_avx512( dctcoef dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_flat16_mmx( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_flat16_mmx( int16_t dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_flat16_sse2( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_flat16_sse2( int16_t dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_4x4_flat16_avx2( int16_t dct[16], int dequant_mf[6][16], int i_qp );
void x264_dequant_8x8_flat16_avx2( int16_t dct[64], int dequant_mf[6][64], int i_qp );
void x264_dequant_8x8_flat16_avx512( int16_t dct[64], int dequant_mf[6][64], int i_qp );
void x264_idct_dequant_2x4_dc_sse2( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp );
void x264_idct_dequant_2x4_dc_avx ( dctcoef dct[8], dctcoef dct4x4[8][16], int dequant_mf[6][16], int i_qp );
void x264_idct_dequant_2x4_dconly_sse2( dctcoef dct[8], int dequant_mf[6][16], int i_qp );
void x264_idct_dequant_2x4_dconly_avx ( dctcoef dct[8], int dequant_mf[6][16], int i_qp );
int x264_optimize_chroma_2x2_dc_sse2( dctcoef dct[4], int dequant_mf );
int x264_optimize_chroma_2x2_dc_ssse3( dctcoef dct[4], int dequant_mf );
int x264_optimize_chroma_2x2_dc_sse4( dctcoef dct[4], int dequant_mf );
int x264_optimize_chroma_2x2_dc_avx( dctcoef dct[4], int dequant_mf );
void x264_denoise_dct_mmx ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size );
void x264_denoise_dct_sse2 ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size );
void x264_denoise_dct_ssse3( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size );
void x264_denoise_dct_avx ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size );
void x264_denoise_dct_avx2 ( dctcoef *dct, uint32_t *sum, udctcoef *offset, int size );
int x264_decimate_score15_sse2( dctcoef *dct );
int x264_decimate_score15_ssse3( dctcoef *dct );
int x264_decimate_score15_avx512( dctcoef *dct );
int x264_decimate_score16_sse2( dctcoef *dct );
int x264_decimate_score16_ssse3( dctcoef *dct );
int x264_decimate_score16_avx512( dctcoef *dct );
int x264_decimate_score64_sse2( dctcoef *dct );
int x264_decimate_score64_ssse3( dctcoef *dct );
int x264_decimate_score64_avx2( int16_t *dct );
int x264_decimate_score64_avx512( dctcoef *dct );
int x264_coeff_last4_mmx2( dctcoef *dct );
int x264_coeff_last8_mmx2( dctcoef *dct );
int x264_coeff_last15_mmx2( dctcoef *dct );
int x264_coeff_last16_mmx2( dctcoef *dct );
int x264_coeff_last64_mmx2( dctcoef *dct );
int x264_coeff_last8_sse2( dctcoef *dct );
int x264_coeff_last15_sse2( dctcoef *dct );
int x264_coeff_last16_sse2( dctcoef *dct );
int x264_coeff_last64_sse2( dctcoef *dct );
int x264_coeff_last4_lzcnt( dctcoef *dct );
int x264_coeff_last8_lzcnt( dctcoef *dct );
int x264_coeff_last15_lzcnt( dctcoef *dct );
int x264_coeff_last16_lzcnt( dctcoef *dct );
int x264_coeff_last64_lzcnt( dctcoef *dct );
int x264_coeff_last64_avx2 ( dctcoef *dct );
int x264_coeff_last4_avx512( int32_t *dct );
int x264_coeff_last8_avx512( dctcoef *dct );
int x264_coeff_last15_avx512( dctcoef *dct );
int x264_coeff_last16_avx512( dctcoef *dct );
int x264_coeff_last64_avx512( dctcoef *dct );
int x264_coeff_level_run16_mmx2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run16_sse2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run16_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run16_ssse3( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run16_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run16_avx2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run15_mmx2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run15_sse2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run15_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run15_ssse3( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run15_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run15_avx2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run4_mmx2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run4_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run4_ssse3( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run4_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run8_mmx2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run8_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run8_sse2( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run8_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run8_ssse3( dctcoef *dct, x264_run_level_t *runlevel );
int x264_coeff_level_run8_ssse3_lzcnt( dctcoef *dct, x264_run_level_t *runlevel );
int x264_trellis_cabac_4x4_sse2 ( TRELLIS_PARAMS, int b_ac );
int x264_trellis_cabac_4x4_ssse3( TRELLIS_PARAMS, int b_ac );
int x264_trellis_cabac_8x8_sse2 ( TRELLIS_PARAMS, int b_interlaced );
int x264_trellis_cabac_8x8_ssse3( TRELLIS_PARAMS, int b_interlaced );
int x264_trellis_cabac_4x4_psy_sse2 ( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int i_psy_trellis );
int x264_trellis_cabac_4x4_psy_ssse3( TRELLIS_PARAMS, int b_ac, dctcoef *fenc_dct, int i_psy_trellis );
int x264_trellis_cabac_8x8_psy_sse2 ( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int i_psy_trellis );
int x264_trellis_cabac_8x8_psy_ssse3( TRELLIS_PARAMS, int b_interlaced, dctcoef *fenc_dct, int i_psy_trellis );
int x264_trellis_cabac_dc_sse2 ( TRELLIS_PARAMS, int i_coefs );
int x264_trellis_cabac_dc_ssse3( TRELLIS_PARAMS, int i_coefs );
int x264_trellis_cabac_chroma_422_dc_sse2 ( TRELLIS_PARAMS );
int x264_trellis_cabac_chroma_422_dc_ssse3( TRELLIS_PARAMS );
#endif

View file

@ -0,0 +1,254 @@
/*****************************************************************************
* util.h: x86 inline asm
*****************************************************************************
* Copyright (C) 2008-2017 x264 project
*
* Authors: Fiona Glaser <fiona@x264.com>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_X86_UTIL_H
#define X264_X86_UTIL_H
#ifdef __SSE__
#include <xmmintrin.h>
#undef M128_ZERO
#define M128_ZERO ((__m128){0,0,0,0})
#define x264_union128_t x264_union128_sse_t
typedef union { __m128 i; uint64_t a[2]; uint32_t b[4]; uint16_t c[8]; uint8_t d[16]; } MAY_ALIAS x264_union128_sse_t;
#if HAVE_VECTOREXT
typedef uint32_t v4si __attribute__((vector_size (16)));
#endif
#endif // __SSE__
#if HAVE_X86_INLINE_ASM && HAVE_MMX
#define x264_median_mv x264_median_mv_mmx2
static ALWAYS_INLINE void x264_median_mv_mmx2( int16_t *dst, int16_t *a, int16_t *b, int16_t *c )
{
asm(
"movd %1, %%mm0 \n"
"movd %2, %%mm1 \n"
"movq %%mm0, %%mm3 \n"
"movd %3, %%mm2 \n"
"pmaxsw %%mm1, %%mm0 \n"
"pminsw %%mm3, %%mm1 \n"
"pminsw %%mm2, %%mm0 \n"
"pmaxsw %%mm1, %%mm0 \n"
"movd %%mm0, %0 \n"
:"=m"(*(x264_union32_t*)dst)
:"m"(M32( a )), "m"(M32( b )), "m"(M32( c ))
);
}
#define x264_predictor_difference x264_predictor_difference_mmx2
static ALWAYS_INLINE int x264_predictor_difference_mmx2( int16_t (*mvc)[2], intptr_t i_mvc )
{
int sum;
static const uint64_t pw_1 = 0x0001000100010001ULL;
asm(
"pxor %%mm4, %%mm4 \n"
"test $1, %1 \n"
"jnz 3f \n"
"movd -8(%2,%1,4), %%mm0 \n"
"movd -4(%2,%1,4), %%mm3 \n"
"psubw %%mm3, %%mm0 \n"
"jmp 2f \n"
"3: \n"
"dec %1 \n"
"1: \n"
"movq -8(%2,%1,4), %%mm0 \n"
"psubw -4(%2,%1,4), %%mm0 \n"
"2: \n"
"sub $2, %1 \n"
"pxor %%mm2, %%mm2 \n"
"psubw %%mm0, %%mm2 \n"
"pmaxsw %%mm2, %%mm0 \n"
"paddusw %%mm0, %%mm4 \n"
"jg 1b \n"
"pmaddwd %4, %%mm4 \n"
"pshufw $14, %%mm4, %%mm0 \n"
"paddd %%mm0, %%mm4 \n"
"movd %%mm4, %0 \n"
:"=r"(sum), "+r"(i_mvc)
:"r"(mvc), "m"(M64( mvc )), "m"(pw_1)
);
return sum;
}
#define x264_cabac_mvd_sum x264_cabac_mvd_sum_mmx2
static ALWAYS_INLINE uint16_t x264_cabac_mvd_sum_mmx2(uint8_t *mvdleft, uint8_t *mvdtop)
{
static const uint64_t pb_2 = 0x0202020202020202ULL;
static const uint64_t pb_32 = 0x2020202020202020ULL;
static const uint64_t pb_33 = 0x2121212121212121ULL;
int amvd;
asm(
"movd %1, %%mm0 \n"
"movd %2, %%mm1 \n"
"paddusb %%mm1, %%mm0 \n"
"pminub %5, %%mm0 \n"
"pxor %%mm2, %%mm2 \n"
"movq %%mm0, %%mm1 \n"
"pcmpgtb %3, %%mm0 \n"
"pcmpgtb %4, %%mm1 \n"
"psubb %%mm0, %%mm2 \n"
"psubb %%mm1, %%mm2 \n"
"movd %%mm2, %0 \n"
:"=r"(amvd)
:"m"(M16( mvdleft )),"m"(M16( mvdtop )),
"m"(pb_2),"m"(pb_32),"m"(pb_33)
);
return amvd;
}
#define x264_predictor_clip x264_predictor_clip_mmx2
static int ALWAYS_INLINE x264_predictor_clip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv )
{
static const uint32_t pd_32 = 0x20;
intptr_t tmp = (intptr_t)mv_limit, mvc_max = i_mvc, i = 0;
asm(
"movq (%2), %%mm5 \n"
"movd %6, %%mm3 \n"
"psllw $2, %%mm5 \n" // Convert to subpel
"pshufw $0xEE, %%mm5, %%mm6 \n"
"dec %k3 \n"
"jz 2f \n" // if( i_mvc == 1 ) {do the last iteration}
"punpckldq %%mm3, %%mm3 \n"
"punpckldq %%mm5, %%mm5 \n"
"movd %7, %%mm4 \n"
"lea (%0,%3,4), %3 \n"
"1: \n"
"movq (%0), %%mm0 \n"
"add $8, %0 \n"
"movq %%mm3, %%mm1 \n"
"pxor %%mm2, %%mm2 \n"
"pcmpeqd %%mm0, %%mm1 \n" // mv == pmv
"pcmpeqd %%mm0, %%mm2 \n" // mv == 0
"por %%mm1, %%mm2 \n" // (mv == pmv || mv == 0) * -1
"pmovmskb %%mm2, %k2 \n" // (mv == pmv || mv == 0) * 0xf
"pmaxsw %%mm5, %%mm0 \n"
"pminsw %%mm6, %%mm0 \n"
"pand %%mm4, %%mm2 \n" // (mv0 == pmv || mv0 == 0) * 32
"psrlq %%mm2, %%mm0 \n" // drop mv0 if it's skipped
"movq %%mm0, (%5,%4,4) \n"
"and $24, %k2 \n"
"add $2, %4 \n"
"add $8, %k2 \n"
"shr $4, %k2 \n" // (4-val)>>1
"sub %2, %4 \n" // +1 for each valid motion vector
"cmp %3, %0 \n"
"jl 1b \n"
"jg 3f \n" // if( i == i_mvc - 1 ) {do the last iteration}
/* Do the last iteration */
"2: \n"
"movd (%0), %%mm0 \n"
"pxor %%mm2, %%mm2 \n"
"pcmpeqd %%mm0, %%mm3 \n"
"pcmpeqd %%mm0, %%mm2 \n"
"por %%mm3, %%mm2 \n"
"pmovmskb %%mm2, %k2 \n"
"pmaxsw %%mm5, %%mm0 \n"
"pminsw %%mm6, %%mm0 \n"
"movd %%mm0, (%5,%4,4) \n"
"inc %4 \n"
"and $1, %k2 \n"
"sub %2, %4 \n" // output += !(mv == pmv || mv == 0)
"3: \n"
:"+r"(mvc), "=m"(M64( dst )), "+r"(tmp), "+r"(mvc_max), "+r"(i)
:"r"(dst), "g"(pmv), "m"(pd_32), "m"(M64( mvc ))
);
return i;
}
/* Same as the above, except we do (mv + 2) >> 2 on the input. */
#define x264_predictor_roundclip x264_predictor_roundclip_mmx2
static int ALWAYS_INLINE x264_predictor_roundclip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv )
{
static const uint64_t pw_2 = 0x0002000200020002ULL;
static const uint32_t pd_32 = 0x20;
intptr_t tmp = (intptr_t)mv_limit, mvc_max = i_mvc, i = 0;
asm(
"movq (%2), %%mm5 \n"
"movq %6, %%mm7 \n"
"movd %7, %%mm3 \n"
"pshufw $0xEE, %%mm5, %%mm6 \n"
"dec %k3 \n"
"jz 2f \n"
"punpckldq %%mm3, %%mm3 \n"
"punpckldq %%mm5, %%mm5 \n"
"movd %8, %%mm4 \n"
"lea (%0,%3,4), %3 \n"
"1: \n"
"movq (%0), %%mm0 \n"
"add $8, %0 \n"
"paddw %%mm7, %%mm0 \n"
"psraw $2, %%mm0 \n"
"movq %%mm3, %%mm1 \n"
"pxor %%mm2, %%mm2 \n"
"pcmpeqd %%mm0, %%mm1 \n"
"pcmpeqd %%mm0, %%mm2 \n"
"por %%mm1, %%mm2 \n"
"pmovmskb %%mm2, %k2 \n"
"pmaxsw %%mm5, %%mm0 \n"
"pminsw %%mm6, %%mm0 \n"
"pand %%mm4, %%mm2 \n"
"psrlq %%mm2, %%mm0 \n"
"movq %%mm0, (%5,%4,4) \n"
"and $24, %k2 \n"
"add $2, %4 \n"
"add $8, %k2 \n"
"shr $4, %k2 \n"
"sub %2, %4 \n"
"cmp %3, %0 \n"
"jl 1b \n"
"jg 3f \n"
/* Do the last iteration */
"2: \n"
"movd (%0), %%mm0 \n"
"paddw %%mm7, %%mm0 \n"
"psraw $2, %%mm0 \n"
"pxor %%mm2, %%mm2 \n"
"pcmpeqd %%mm0, %%mm3 \n"
"pcmpeqd %%mm0, %%mm2 \n"
"por %%mm3, %%mm2 \n"
"pmovmskb %%mm2, %k2 \n"
"pmaxsw %%mm5, %%mm0 \n"
"pminsw %%mm6, %%mm0 \n"
"movd %%mm0, (%5,%4,4) \n"
"inc %4 \n"
"and $1, %k2 \n"
"sub %2, %4 \n"
"3: \n"
:"+r"(mvc), "=m"(M64( dst )), "+r"(tmp), "+r"(mvc_max), "+r"(i)
:"r"(dst), "m"(pw_2), "g"(pmv), "m"(pd_32), "m"(M64( mvc ))
);
return i;
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
/*****************************************************************************
* analyse.h: macroblock analysis
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ANALYSE_H
#define X264_ANALYSE_H
int x264_analyse_init_costs( x264_t *h );
void x264_analyse_free_costs( x264_t *h );
void x264_analyse_weight_frame( x264_t *h, int end );
void x264_macroblock_analyse( x264_t *h );
void x264_slicetype_decide( x264_t *h );
void x264_slicetype_analyse( x264_t *h, int intra_minigop );
int x264_lookahead_init( x264_t *h, int i_slicetype_length );
int x264_lookahead_is_empty( x264_t *h );
void x264_lookahead_put_frame( x264_t *h, x264_frame_t *frame );
void x264_lookahead_get_frames( x264_t *h );
void x264_lookahead_delete( x264_t *h );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,722 @@
/*****************************************************************************
* cavlc.c: cavlc bitstream writing
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "macroblock.h"
#ifndef RDO_SKIP_BS
#define RDO_SKIP_BS 0
#endif
/* [400,420][inter,intra] */
static const uint8_t cbp_to_golomb[2][2][48] =
{
{{ 0, 1, 2, 5, 3, 6, 14, 10, 4, 15, 7, 11, 8, 12, 13, 9 },
{ 1, 10, 11, 6, 12, 7, 14, 2, 13, 15, 8, 3, 9, 4, 5, 0 }},
{{ 0, 2, 3, 7, 4, 8, 17, 13, 5, 18, 9, 14, 10, 15, 16, 11,
1, 32, 33, 36, 34, 37, 44, 40, 35, 45, 38, 41, 39, 42, 43, 19,
6, 24, 25, 20, 26, 21, 46, 28, 27, 47, 22, 29, 23, 30, 31, 12 },
{ 3, 29, 30, 17, 31, 18, 37, 8, 32, 38, 19, 9, 20, 10, 11, 2,
16, 33, 34, 21, 35, 22, 39, 4, 36, 40, 23, 5, 24, 6, 7, 1,
41, 42, 43, 25, 44, 26, 46, 12, 45, 47, 27, 13, 28, 14, 15, 0 }}
};
static const uint8_t mb_type_b_to_golomb[3][9]=
{
{ 4, 8, 12, 10, 6, 14, 16, 18, 20 }, /* D_16x8 */
{ 5, 9, 13, 11, 7, 15, 17, 19, 21 }, /* D_8x16 */
{ 1, -1, -1, -1, 2, -1, -1, -1, 3 } /* D_16x16 */
};
static const uint8_t subpartition_p_to_golomb[4]=
{
3, 1, 2, 0
};
static const uint8_t subpartition_b_to_golomb[13]=
{
10, 4, 5, 1, 11, 6, 7, 2, 12, 8, 9, 3, 0
};
#define bs_write_vlc(s,v) bs_write( s, (v).i_size, (v).i_bits )
/****************************************************************************
* x264_cavlc_block_residual:
****************************************************************************/
static inline int x264_cavlc_block_residual_escape( x264_t *h, int i_suffix_length, int level )
{
bs_t *s = &h->out.bs;
static const uint16_t next_suffix[7] = { 0, 3, 6, 12, 24, 48, 0xffff };
int i_level_prefix = 15;
int mask = level >> 31;
int abs_level = (level^mask)-mask;
int i_level_code = abs_level*2-mask-2;
if( ( i_level_code >> i_suffix_length ) < 15 )
{
bs_write( s, (i_level_code >> i_suffix_length) + 1 + i_suffix_length,
(1<<i_suffix_length) + (i_level_code & ((1<<i_suffix_length)-1)) );
}
else
{
i_level_code -= 15 << i_suffix_length;
if( i_suffix_length == 0 )
i_level_code -= 15;
/* If the prefix size exceeds 15, High Profile is required. */
if( i_level_code >= 1<<12 )
{
if( h->sps->i_profile_idc >= PROFILE_HIGH )
{
while( i_level_code > 1<<(i_level_prefix-3) )
{
i_level_code -= 1<<(i_level_prefix-3);
i_level_prefix++;
}
}
else
{
#if RDO_SKIP_BS
/* Weight highly against overflows. */
s->i_bits_encoded += 2000;
#else
/* We've had an overflow; note it down and re-encode the MB later. */
h->mb.b_overflow = 1;
#endif
}
}
bs_write( s, i_level_prefix + 1, 1 );
bs_write( s, i_level_prefix - 3, i_level_code & ((1<<(i_level_prefix-3))-1) );
}
if( i_suffix_length == 0 )
i_suffix_length++;
if( abs_level > next_suffix[i_suffix_length] )
i_suffix_length++;
return i_suffix_length;
}
static int x264_cavlc_block_residual_internal( x264_t *h, int ctx_block_cat, dctcoef *l, int nC )
{
bs_t *s = &h->out.bs;
static const uint8_t ctz_index[8] = {3,0,1,0,2,0,1,0};
static const uint8_t count_cat[14] = {16, 15, 16, 0, 15, 64, 16, 15, 16, 64, 16, 15, 16, 64};
x264_run_level_t runlevel;
int i_total, i_trailing, i_total_zero, i_suffix_length;
unsigned int i_sign;
/* level and run and total */
i_total = h->quantf.coeff_level_run[ctx_block_cat]( l, &runlevel );
x264_prefetch( &x264_run_before[runlevel.mask] );
i_total_zero = runlevel.last + 1 - i_total;
/* branchless i_trailing calculation */
runlevel.level[i_total+0] = 2;
runlevel.level[i_total+1] = 2;
i_trailing = ((((runlevel.level[0]+1) | (1-runlevel.level[0])) >> 31) & 1) // abs(runlevel.level[0])>1
| ((((runlevel.level[1]+1) | (1-runlevel.level[1])) >> 31) & 2)
| ((((runlevel.level[2]+1) | (1-runlevel.level[2])) >> 31) & 4);
i_trailing = ctz_index[i_trailing];
i_sign = ((runlevel.level[2] >> 31) & 1)
| ((runlevel.level[1] >> 31) & 2)
| ((runlevel.level[0] >> 31) & 4);
i_sign >>= 3-i_trailing;
/* total/trailing */
bs_write_vlc( s, x264_coeff_token[nC][i_total-1][i_trailing] );
i_suffix_length = i_total > 10 && i_trailing < 3;
bs_write( s, i_trailing, i_sign );
if( i_trailing < i_total )
{
int val = runlevel.level[i_trailing];
int val_original = runlevel.level[i_trailing]+LEVEL_TABLE_SIZE/2;
val -= ((val>>31)|1) & -(i_trailing < 3); /* as runlevel.level[i] can't be 1 for the first one if i_trailing < 3 */
val += LEVEL_TABLE_SIZE/2;
if( (unsigned)val_original < LEVEL_TABLE_SIZE )
{
bs_write_vlc( s, x264_level_token[i_suffix_length][val] );
i_suffix_length = x264_level_token[i_suffix_length][val_original].i_next;
}
else
i_suffix_length = x264_cavlc_block_residual_escape( h, i_suffix_length, val-LEVEL_TABLE_SIZE/2 );
for( int i = i_trailing+1; i < i_total; i++ )
{
val = runlevel.level[i] + LEVEL_TABLE_SIZE/2;
if( (unsigned)val < LEVEL_TABLE_SIZE )
{
bs_write_vlc( s, x264_level_token[i_suffix_length][val] );
i_suffix_length = x264_level_token[i_suffix_length][val].i_next;
}
else
i_suffix_length = x264_cavlc_block_residual_escape( h, i_suffix_length, val-LEVEL_TABLE_SIZE/2 );
}
}
if( ctx_block_cat == DCT_CHROMA_DC )
{
if( i_total < 8>>CHROMA_V_SHIFT )
{
vlc_t total_zeros = CHROMA_FORMAT == CHROMA_420 ? x264_total_zeros_2x2_dc[i_total-1][i_total_zero]
: x264_total_zeros_2x4_dc[i_total-1][i_total_zero];
bs_write_vlc( s, total_zeros );
}
}
else if( (uint8_t)i_total < count_cat[ctx_block_cat] )
bs_write_vlc( s, x264_total_zeros[i_total-1][i_total_zero] );
int zero_run_code = x264_run_before[runlevel.mask];
bs_write( s, zero_run_code&0x1f, zero_run_code>>5 );
return i_total;
}
static const uint8_t ct_index[17] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3};
#define x264_cavlc_block_residual(h,cat,idx,l)\
{\
int nC = cat == DCT_CHROMA_DC ? 5 - CHROMA_V_SHIFT\
: ct_index[x264_mb_predict_non_zero_code( h, cat == DCT_LUMA_DC ? (idx - LUMA_DC)*16 : idx )];\
uint8_t *nnz = &h->mb.cache.non_zero_count[x264_scan8[idx]];\
if( !*nnz )\
bs_write_vlc( &h->out.bs, x264_coeff0_token[nC] );\
else\
*nnz = x264_cavlc_block_residual_internal(h,cat,l,nC);\
}
static void x264_cavlc_qp_delta( x264_t *h )
{
bs_t *s = &h->out.bs;
int i_dqp = h->mb.i_qp - h->mb.i_last_qp;
/* Avoid writing a delta quant if we have an empty i16x16 block, e.g. in a completely
* flat background area. Don't do this if it would raise the quantizer, since that could
* cause unexpected deblocking artifacts. */
if( h->mb.i_type == I_16x16 && !(h->mb.i_cbp_luma | h->mb.i_cbp_chroma)
&& !h->mb.cache.non_zero_count[x264_scan8[LUMA_DC]]
&& !h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]]
&& !h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]]
&& h->mb.i_qp > h->mb.i_last_qp )
{
#if !RDO_SKIP_BS
h->mb.i_qp = h->mb.i_last_qp;
#endif
i_dqp = 0;
}
if( i_dqp )
{
if( i_dqp < -(QP_MAX_SPEC+1)/2 )
i_dqp += QP_MAX_SPEC+1;
else if( i_dqp > QP_MAX_SPEC/2 )
i_dqp -= QP_MAX_SPEC+1;
}
bs_write_se( s, i_dqp );
}
static void x264_cavlc_mvd( x264_t *h, int i_list, int idx, int width )
{
bs_t *s = &h->out.bs;
ALIGNED_4( int16_t mvp[2] );
x264_mb_predict_mv( h, i_list, idx, width, mvp );
bs_write_se( s, h->mb.cache.mv[i_list][x264_scan8[idx]][0] - mvp[0] );
bs_write_se( s, h->mb.cache.mv[i_list][x264_scan8[idx]][1] - mvp[1] );
}
static inline void x264_cavlc_8x8_mvd( x264_t *h, int i )
{
switch( h->mb.i_sub_partition[i] )
{
case D_L0_8x8:
x264_cavlc_mvd( h, 0, 4*i, 2 );
break;
case D_L0_8x4:
x264_cavlc_mvd( h, 0, 4*i+0, 2 );
x264_cavlc_mvd( h, 0, 4*i+2, 2 );
break;
case D_L0_4x8:
x264_cavlc_mvd( h, 0, 4*i+0, 1 );
x264_cavlc_mvd( h, 0, 4*i+1, 1 );
break;
case D_L0_4x4:
x264_cavlc_mvd( h, 0, 4*i+0, 1 );
x264_cavlc_mvd( h, 0, 4*i+1, 1 );
x264_cavlc_mvd( h, 0, 4*i+2, 1 );
x264_cavlc_mvd( h, 0, 4*i+3, 1 );
break;
}
}
static ALWAYS_INLINE void x264_cavlc_macroblock_luma_residual( x264_t *h, int plane_count )
{
if( h->mb.b_transform_8x8 )
{
/* shuffle 8x8 dct coeffs into 4x4 lists */
for( int p = 0; p < plane_count; p++ )
for( int i8 = 0; i8 < 4; i8++ )
if( h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] )
h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[p*16+i8*4], h->dct.luma8x8[p*4+i8],
&h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] );
}
for( int p = 0; p < plane_count; p++ )
FOREACH_BIT( i8, 0, h->mb.i_cbp_luma )
for( int i4 = 0; i4 < 4; i4++ )
x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] );
}
#if RDO_SKIP_BS
static ALWAYS_INLINE void x264_cavlc_partition_luma_residual( x264_t *h, int i8, int p )
{
if( h->mb.b_transform_8x8 && h->mb.cache.non_zero_count[x264_scan8[i8*4]] )
h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[i8*4+p*16], h->dct.luma8x8[i8+p*4],
&h->mb.cache.non_zero_count[x264_scan8[i8*4+p*16]] );
if( h->mb.i_cbp_luma & (1 << i8) )
for( int i4 = 0; i4 < 4; i4++ )
x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] );
}
#endif
static void x264_cavlc_mb_header_i( x264_t *h, int i_mb_type, int i_mb_i_offset, int chroma )
{
bs_t *s = &h->out.bs;
if( i_mb_type == I_16x16 )
{
bs_write_ue( s, i_mb_i_offset + 1 + x264_mb_pred_mode16x16_fix[h->mb.i_intra16x16_pred_mode] +
h->mb.i_cbp_chroma * 4 + ( h->mb.i_cbp_luma == 0 ? 0 : 12 ) );
}
else //if( i_mb_type == I_4x4 || i_mb_type == I_8x8 )
{
int di = i_mb_type == I_8x8 ? 4 : 1;
bs_write_ue( s, i_mb_i_offset + 0 );
if( h->pps->b_transform_8x8_mode )
bs_write1( s, h->mb.b_transform_8x8 );
/* Prediction: Luma */
for( int i = 0; i < 16; i += di )
{
int i_pred = x264_mb_predict_intra4x4_mode( h, i );
int i_mode = x264_mb_pred_mode4x4_fix( h->mb.cache.intra4x4_pred_mode[x264_scan8[i]] );
if( i_pred == i_mode )
bs_write1( s, 1 ); /* b_prev_intra4x4_pred_mode */
else
bs_write( s, 4, i_mode - (i_mode > i_pred) );
}
}
if( chroma )
bs_write_ue( s, x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode] );
}
static ALWAYS_INLINE void x264_cavlc_mb_header_p( x264_t *h, int i_mb_type, int chroma )
{
bs_t *s = &h->out.bs;
if( i_mb_type == P_L0 )
{
if( h->mb.i_partition == D_16x16 )
{
bs_write1( s, 1 );
if( h->mb.pic.i_fref[0] > 1 )
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] );
x264_cavlc_mvd( h, 0, 0, 4 );
}
else if( h->mb.i_partition == D_16x8 )
{
bs_write_ue( s, 1 );
if( h->mb.pic.i_fref[0] > 1 )
{
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] );
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[8]] );
}
x264_cavlc_mvd( h, 0, 0, 4 );
x264_cavlc_mvd( h, 0, 8, 4 );
}
else if( h->mb.i_partition == D_8x16 )
{
bs_write_ue( s, 2 );
if( h->mb.pic.i_fref[0] > 1 )
{
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] );
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[4]] );
}
x264_cavlc_mvd( h, 0, 0, 2 );
x264_cavlc_mvd( h, 0, 4, 2 );
}
}
else if( i_mb_type == P_8x8 )
{
int b_sub_ref;
if( (h->mb.cache.ref[0][x264_scan8[0]] | h->mb.cache.ref[0][x264_scan8[ 4]] |
h->mb.cache.ref[0][x264_scan8[8]] | h->mb.cache.ref[0][x264_scan8[12]]) == 0 )
{
bs_write_ue( s, 4 );
b_sub_ref = 0;
}
else
{
bs_write_ue( s, 3 );
b_sub_ref = 1;
}
/* sub mb type */
if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 )
for( int i = 0; i < 4; i++ )
bs_write_ue( s, subpartition_p_to_golomb[ h->mb.i_sub_partition[i] ] );
else
bs_write( s, 4, 0xf );
/* ref0 */
if( b_sub_ref )
{
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[0]] );
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[4]] );
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[8]] );
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[12]] );
}
for( int i = 0; i < 4; i++ )
x264_cavlc_8x8_mvd( h, i );
}
else //if( IS_INTRA( i_mb_type ) )
x264_cavlc_mb_header_i( h, i_mb_type, 5, chroma );
}
static ALWAYS_INLINE void x264_cavlc_mb_header_b( x264_t *h, int i_mb_type, int chroma )
{
bs_t *s = &h->out.bs;
if( i_mb_type == B_8x8 )
{
bs_write_ue( s, 22 );
/* sub mb type */
for( int i = 0; i < 4; i++ )
bs_write_ue( s, subpartition_b_to_golomb[ h->mb.i_sub_partition[i] ] );
/* ref */
if( h->mb.pic.i_fref[0] > 1 )
for( int i = 0; i < 4; i++ )
if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] )
bs_write_te( s, h->mb.pic.i_fref[0] - 1, h->mb.cache.ref[0][x264_scan8[i*4]] );
if( h->mb.pic.i_fref[1] > 1 )
for( int i = 0; i < 4; i++ )
if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i] ] )
bs_write_te( s, h->mb.pic.i_fref[1] - 1, h->mb.cache.ref[1][x264_scan8[i*4]] );
/* mvd */
for( int i = 0; i < 4; i++ )
if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] )
x264_cavlc_mvd( h, 0, 4*i, 2 );
for( int i = 0; i < 4; i++ )
if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i] ] )
x264_cavlc_mvd( h, 1, 4*i, 2 );
}
else if( i_mb_type >= B_L0_L0 && i_mb_type <= B_BI_BI )
{
/* All B mode */
/* Motion Vector */
const uint8_t (*b_list)[2] = x264_mb_type_list_table[i_mb_type];
const int i_ref0_max = h->mb.pic.i_fref[0] - 1;
const int i_ref1_max = h->mb.pic.i_fref[1] - 1;
bs_write_ue( s, mb_type_b_to_golomb[ h->mb.i_partition - D_16x8 ][ i_mb_type - B_L0_L0 ] );
if( h->mb.i_partition == D_16x16 )
{
if( i_ref0_max && b_list[0][0] ) bs_write_te( s, i_ref0_max, h->mb.cache.ref[0][x264_scan8[0]] );
if( i_ref1_max && b_list[1][0] ) bs_write_te( s, i_ref1_max, h->mb.cache.ref[1][x264_scan8[0]] );
if( b_list[0][0] ) x264_cavlc_mvd( h, 0, 0, 4 );
if( b_list[1][0] ) x264_cavlc_mvd( h, 1, 0, 4 );
}
else
{
if( i_ref0_max && b_list[0][0] ) bs_write_te( s, i_ref0_max, h->mb.cache.ref[0][x264_scan8[ 0]] );
if( i_ref0_max && b_list[0][1] ) bs_write_te( s, i_ref0_max, h->mb.cache.ref[0][x264_scan8[12]] );
if( i_ref1_max && b_list[1][0] ) bs_write_te( s, i_ref1_max, h->mb.cache.ref[1][x264_scan8[ 0]] );
if( i_ref1_max && b_list[1][1] ) bs_write_te( s, i_ref1_max, h->mb.cache.ref[1][x264_scan8[12]] );
if( h->mb.i_partition == D_16x8 )
{
if( b_list[0][0] ) x264_cavlc_mvd( h, 0, 0, 4 );
if( b_list[0][1] ) x264_cavlc_mvd( h, 0, 8, 4 );
if( b_list[1][0] ) x264_cavlc_mvd( h, 1, 0, 4 );
if( b_list[1][1] ) x264_cavlc_mvd( h, 1, 8, 4 );
}
else //if( h->mb.i_partition == D_8x16 )
{
if( b_list[0][0] ) x264_cavlc_mvd( h, 0, 0, 2 );
if( b_list[0][1] ) x264_cavlc_mvd( h, 0, 4, 2 );
if( b_list[1][0] ) x264_cavlc_mvd( h, 1, 0, 2 );
if( b_list[1][1] ) x264_cavlc_mvd( h, 1, 4, 2 );
}
}
}
else if( i_mb_type == B_DIRECT )
bs_write1( s, 1 );
else //if( IS_INTRA( i_mb_type ) )
x264_cavlc_mb_header_i( h, i_mb_type, 23, chroma );
}
/*****************************************************************************
* x264_macroblock_write:
*****************************************************************************/
void x264_macroblock_write_cavlc( x264_t *h )
{
bs_t *s = &h->out.bs;
const int i_mb_type = h->mb.i_type;
int plane_count = CHROMA444 ? 3 : 1;
int chroma = !CHROMA444;
#if RDO_SKIP_BS
s->i_bits_encoded = 0;
#else
const int i_mb_pos_start = bs_pos( s );
int i_mb_pos_tex;
#endif
if( SLICE_MBAFF
&& (!(h->mb.i_mb_y & 1) || IS_SKIP(h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride])) )
{
bs_write1( s, MB_INTERLACED );
#if !RDO_SKIP_BS
h->mb.field_decoding_flag = MB_INTERLACED;
#endif
}
#if !RDO_SKIP_BS
if( i_mb_type == I_PCM )
{
static const uint8_t i_offsets[3] = {5,23,0};
uint8_t *p_start = s->p_start;
bs_write_ue( s, i_offsets[h->sh.i_type] + 25 );
i_mb_pos_tex = bs_pos( s );
h->stat.frame.i_mv_bits += i_mb_pos_tex - i_mb_pos_start;
bs_align_0( s );
for( int p = 0; p < plane_count; p++ )
for( int i = 0; i < 256; i++ )
bs_write( s, BIT_DEPTH, h->mb.pic.p_fenc[p][i] );
if( chroma )
for( int ch = 1; ch < 3; ch++ )
for( int i = 0; i < 16>>CHROMA_V_SHIFT; i++ )
for( int j = 0; j < 8; j++ )
bs_write( s, BIT_DEPTH, h->mb.pic.p_fenc[ch][i*FENC_STRIDE+j] );
bs_init( s, s->p, s->p_end - s->p );
s->p_start = p_start;
h->stat.frame.i_tex_bits += bs_pos(s) - i_mb_pos_tex;
return;
}
#endif
if( h->sh.i_type == SLICE_TYPE_P )
x264_cavlc_mb_header_p( h, i_mb_type, chroma );
else if( h->sh.i_type == SLICE_TYPE_B )
x264_cavlc_mb_header_b( h, i_mb_type, chroma );
else //if( h->sh.i_type == SLICE_TYPE_I )
x264_cavlc_mb_header_i( h, i_mb_type, 0, chroma );
#if !RDO_SKIP_BS
i_mb_pos_tex = bs_pos( s );
h->stat.frame.i_mv_bits += i_mb_pos_tex - i_mb_pos_start;
#endif
/* Coded block pattern */
if( i_mb_type != I_16x16 )
bs_write_ue( s, cbp_to_golomb[chroma][IS_INTRA(i_mb_type)][(h->mb.i_cbp_chroma << 4)|h->mb.i_cbp_luma] );
/* transform size 8x8 flag */
if( x264_mb_transform_8x8_allowed( h ) && h->mb.i_cbp_luma )
bs_write1( s, h->mb.b_transform_8x8 );
if( i_mb_type == I_16x16 )
{
x264_cavlc_qp_delta( h );
/* DC Luma */
for( int p = 0; p < plane_count; p++ )
{
x264_cavlc_block_residual( h, DCT_LUMA_DC, LUMA_DC+p, h->dct.luma16x16_dc[p] );
/* AC Luma */
if( h->mb.i_cbp_luma )
for( int i = p*16; i < p*16+16; i++ )
x264_cavlc_block_residual( h, DCT_LUMA_AC, i, h->dct.luma4x4[i]+1 );
}
}
else if( h->mb.i_cbp_luma | h->mb.i_cbp_chroma )
{
x264_cavlc_qp_delta( h );
x264_cavlc_macroblock_luma_residual( h, plane_count );
}
if( h->mb.i_cbp_chroma )
{
/* Chroma DC residual present */
x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+0, h->dct.chroma_dc[0] );
x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+1, h->dct.chroma_dc[1] );
if( h->mb.i_cbp_chroma == 2 ) /* Chroma AC residual present */
{
int step = 8 << CHROMA_V_SHIFT;
for( int i = 16; i < 3*16; i += step )
for( int j = i; j < i+4; j++ )
x264_cavlc_block_residual( h, DCT_CHROMA_AC, j, h->dct.luma4x4[j]+1 );
}
}
#if !RDO_SKIP_BS
h->stat.frame.i_tex_bits += bs_pos(s) - i_mb_pos_tex;
#endif
}
#if RDO_SKIP_BS
/*****************************************************************************
* RD only; doesn't generate a valid bitstream
* doesn't write cbp or chroma dc (I don't know how much this matters)
* doesn't write ref (never varies between calls, so no point in doing so)
* only writes subpartition for p8x8, needed for sub-8x8 mode decision RDO
* works on all partition sizes except 16x16
*****************************************************************************/
static int x264_partition_size_cavlc( x264_t *h, int i8, int i_pixel )
{
bs_t *s = &h->out.bs;
const int i_mb_type = h->mb.i_type;
int b_8x16 = h->mb.i_partition == D_8x16;
int plane_count = CHROMA444 ? 3 : 1;
int j;
h->out.bs.i_bits_encoded = 0;
if( i_mb_type == P_8x8 )
{
x264_cavlc_8x8_mvd( h, i8 );
bs_write_ue( s, subpartition_p_to_golomb[ h->mb.i_sub_partition[i8] ] );
}
else if( i_mb_type == P_L0 )
x264_cavlc_mvd( h, 0, 4*i8, 4>>b_8x16 );
else if( i_mb_type > B_DIRECT && i_mb_type < B_8x8 )
{
if( x264_mb_type_list_table[ i_mb_type ][0][!!i8] ) x264_cavlc_mvd( h, 0, 4*i8, 4>>b_8x16 );
if( x264_mb_type_list_table[ i_mb_type ][1][!!i8] ) x264_cavlc_mvd( h, 1, 4*i8, 4>>b_8x16 );
}
else //if( i_mb_type == B_8x8 )
{
if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i8] ] )
x264_cavlc_mvd( h, 0, 4*i8, 2 );
if( x264_mb_partition_listX_table[1][ h->mb.i_sub_partition[i8] ] )
x264_cavlc_mvd( h, 1, 4*i8, 2 );
}
for( j = (i_pixel < PIXEL_8x8); j >= 0; j-- )
{
for( int p = 0; p < plane_count; p++ )
x264_cavlc_partition_luma_residual( h, i8, p );
if( h->mb.i_cbp_chroma )
{
if( CHROMA_FORMAT == CHROMA_422 )
{
int offset = (5*i8) & 0x09;
x264_cavlc_block_residual( h, DCT_CHROMA_AC, 16+offset, h->dct.luma4x4[16+offset]+1 );
x264_cavlc_block_residual( h, DCT_CHROMA_AC, 18+offset, h->dct.luma4x4[18+offset]+1 );
x264_cavlc_block_residual( h, DCT_CHROMA_AC, 32+offset, h->dct.luma4x4[32+offset]+1 );
x264_cavlc_block_residual( h, DCT_CHROMA_AC, 34+offset, h->dct.luma4x4[34+offset]+1 );
}
else
{
x264_cavlc_block_residual( h, DCT_CHROMA_AC, 16+i8, h->dct.luma4x4[16+i8]+1 );
x264_cavlc_block_residual( h, DCT_CHROMA_AC, 32+i8, h->dct.luma4x4[32+i8]+1 );
}
}
i8 += x264_pixel_size[i_pixel].h >> 3;
}
return h->out.bs.i_bits_encoded;
}
static int x264_subpartition_size_cavlc( x264_t *h, int i4, int i_pixel )
{
int plane_count = CHROMA444 ? 3 : 1;
int b_8x4 = i_pixel == PIXEL_8x4;
h->out.bs.i_bits_encoded = 0;
x264_cavlc_mvd( h, 0, i4, 1+b_8x4 );
for( int p = 0; p < plane_count; p++ )
{
x264_cavlc_block_residual( h, DCT_LUMA_4x4, p*16+i4, h->dct.luma4x4[p*16+i4] );
if( i_pixel != PIXEL_4x4 )
x264_cavlc_block_residual( h, DCT_LUMA_4x4, p*16+i4+2-b_8x4, h->dct.luma4x4[p*16+i4+2-b_8x4] );
}
return h->out.bs.i_bits_encoded;
}
static int x264_cavlc_intra4x4_pred_size( x264_t *h, int i4, int i_mode )
{
if( x264_mb_predict_intra4x4_mode( h, i4 ) == x264_mb_pred_mode4x4_fix( i_mode ) )
return 1;
else
return 4;
}
static int x264_partition_i8x8_size_cavlc( x264_t *h, int i8, int i_mode )
{
int plane_count = CHROMA444 ? 3 : 1;
h->out.bs.i_bits_encoded = x264_cavlc_intra4x4_pred_size( h, 4*i8, i_mode );
bs_write_ue( &h->out.bs, cbp_to_golomb[!CHROMA444][1][(h->mb.i_cbp_chroma << 4)|h->mb.i_cbp_luma] );
for( int p = 0; p < plane_count; p++ )
x264_cavlc_partition_luma_residual( h, i8, p );
return h->out.bs.i_bits_encoded;
}
static int x264_partition_i4x4_size_cavlc( x264_t *h, int i4, int i_mode )
{
int plane_count = CHROMA444 ? 3 : 1;
h->out.bs.i_bits_encoded = x264_cavlc_intra4x4_pred_size( h, i4, i_mode );
for( int p = 0; p < plane_count; p++ )
x264_cavlc_block_residual( h, DCT_LUMA_4x4, p*16+i4, h->dct.luma4x4[p*16+i4] );
return h->out.bs.i_bits_encoded;
}
static int x264_chroma_size_cavlc( x264_t *h )
{
h->out.bs.i_bits_encoded = bs_size_ue( x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode] );
if( h->mb.i_cbp_chroma )
{
x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+0, h->dct.chroma_dc[0] );
x264_cavlc_block_residual( h, DCT_CHROMA_DC, CHROMA_DC+1, h->dct.chroma_dc[1] );
if( h->mb.i_cbp_chroma == 2 )
{
int step = 8 << CHROMA_V_SHIFT;
for( int i = 16; i < 3*16; i += step )
for( int j = i; j < i+4; j++ )
x264_cavlc_block_residual( h, DCT_CHROMA_AC, j, h->dct.luma4x4[j]+1 );
}
}
return h->out.bs.i_bits_encoded;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,244 @@
/*****************************************************************************
* lookahead.c: high-level lookahead functions
*****************************************************************************
* Copyright (C) 2010-2017 Avail Media and x264 project
*
* Authors: Michael Kazmier <mkazmier@availmedia.com>
* Alex Giladi <agiladi@availmedia.com>
* Steven Walters <kemuri9@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
/* LOOKAHEAD (threaded and non-threaded mode)
*
* Lookahead types:
* [1] Slice type / scene cut;
*
* In non-threaded mode, we run the existing slicetype decision code as it was.
* In threaded mode, we run in a separate thread, that lives between the calls
* to x264_encoder_open() and x264_encoder_close(), and performs lookahead for
* the number of frames specified in rc_lookahead. Recommended setting is
* # of bframes + # of threads.
*/
#include "common/common.h"
#include "analyse.h"
static void x264_lookahead_shift( x264_sync_frame_list_t *dst, x264_sync_frame_list_t *src, int count )
{
int i = count;
while( i-- )
{
assert( dst->i_size < dst->i_max_size );
assert( src->i_size );
dst->list[ dst->i_size++ ] = x264_frame_shift( src->list );
src->i_size--;
}
if( count )
{
x264_pthread_cond_broadcast( &dst->cv_fill );
x264_pthread_cond_broadcast( &src->cv_empty );
}
}
static void x264_lookahead_update_last_nonb( x264_t *h, x264_frame_t *new_nonb )
{
if( h->lookahead->last_nonb )
x264_frame_push_unused( h, h->lookahead->last_nonb );
h->lookahead->last_nonb = new_nonb;
new_nonb->i_reference_count++;
}
#if HAVE_THREAD
static void x264_lookahead_slicetype_decide( x264_t *h )
{
x264_stack_align( x264_slicetype_decide, h );
x264_lookahead_update_last_nonb( h, h->lookahead->next.list[0] );
int shift_frames = h->lookahead->next.list[0]->i_bframes + 1;
x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex );
while( h->lookahead->ofbuf.i_size == h->lookahead->ofbuf.i_max_size )
x264_pthread_cond_wait( &h->lookahead->ofbuf.cv_empty, &h->lookahead->ofbuf.mutex );
x264_pthread_mutex_lock( &h->lookahead->next.mutex );
x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames );
x264_pthread_mutex_unlock( &h->lookahead->next.mutex );
/* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */
if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) )
x264_stack_align( x264_slicetype_analyse, h, shift_frames );
x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex );
}
static void *x264_lookahead_thread( x264_t *h )
{
while( !h->lookahead->b_exit_thread )
{
x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex );
x264_pthread_mutex_lock( &h->lookahead->next.mutex );
int shift = X264_MIN( h->lookahead->next.i_max_size - h->lookahead->next.i_size, h->lookahead->ifbuf.i_size );
x264_lookahead_shift( &h->lookahead->next, &h->lookahead->ifbuf, shift );
x264_pthread_mutex_unlock( &h->lookahead->next.mutex );
if( h->lookahead->next.i_size <= h->lookahead->i_slicetype_length + h->param.b_vfr_input )
{
while( !h->lookahead->ifbuf.i_size && !h->lookahead->b_exit_thread )
x264_pthread_cond_wait( &h->lookahead->ifbuf.cv_fill, &h->lookahead->ifbuf.mutex );
x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex );
}
else
{
x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex );
x264_lookahead_slicetype_decide( h );
}
} /* end of input frames */
x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex );
x264_pthread_mutex_lock( &h->lookahead->next.mutex );
x264_lookahead_shift( &h->lookahead->next, &h->lookahead->ifbuf, h->lookahead->ifbuf.i_size );
x264_pthread_mutex_unlock( &h->lookahead->next.mutex );
x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex );
while( h->lookahead->next.i_size )
x264_lookahead_slicetype_decide( h );
x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex );
h->lookahead->b_thread_active = 0;
x264_pthread_cond_broadcast( &h->lookahead->ofbuf.cv_fill );
x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex );
return NULL;
}
#endif
int x264_lookahead_init( x264_t *h, int i_slicetype_length )
{
x264_lookahead_t *look;
CHECKED_MALLOCZERO( look, sizeof(x264_lookahead_t) );
for( int i = 0; i < h->param.i_threads; i++ )
h->thread[i]->lookahead = look;
look->i_last_keyframe = - h->param.i_keyint_max;
look->b_analyse_keyframe = (h->param.rc.b_mb_tree || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead))
&& !h->param.rc.b_stat_read;
look->i_slicetype_length = i_slicetype_length;
/* init frame lists */
if( x264_sync_frame_list_init( &look->ifbuf, h->param.i_sync_lookahead+3 ) ||
x264_sync_frame_list_init( &look->next, h->frames.i_delay+3 ) ||
x264_sync_frame_list_init( &look->ofbuf, h->frames.i_delay+3 ) )
goto fail;
if( !h->param.i_sync_lookahead )
return 0;
x264_t *look_h = h->thread[h->param.i_threads];
*look_h = *h;
if( x264_macroblock_cache_allocate( look_h ) )
goto fail;
if( x264_macroblock_thread_allocate( look_h, 1 ) < 0 )
goto fail;
if( x264_pthread_create( &look->thread_handle, NULL, (void*)x264_lookahead_thread, look_h ) )
goto fail;
look->b_thread_active = 1;
return 0;
fail:
x264_free( look );
return -1;
}
void x264_lookahead_delete( x264_t *h )
{
if( h->param.i_sync_lookahead )
{
x264_pthread_mutex_lock( &h->lookahead->ifbuf.mutex );
h->lookahead->b_exit_thread = 1;
x264_pthread_cond_broadcast( &h->lookahead->ifbuf.cv_fill );
x264_pthread_mutex_unlock( &h->lookahead->ifbuf.mutex );
x264_pthread_join( h->lookahead->thread_handle, NULL );
x264_macroblock_cache_free( h->thread[h->param.i_threads] );
x264_macroblock_thread_free( h->thread[h->param.i_threads], 1 );
x264_free( h->thread[h->param.i_threads] );
}
x264_sync_frame_list_delete( &h->lookahead->ifbuf );
x264_sync_frame_list_delete( &h->lookahead->next );
if( h->lookahead->last_nonb )
x264_frame_push_unused( h, h->lookahead->last_nonb );
x264_sync_frame_list_delete( &h->lookahead->ofbuf );
x264_free( h->lookahead );
}
void x264_lookahead_put_frame( x264_t *h, x264_frame_t *frame )
{
if( h->param.i_sync_lookahead )
x264_sync_frame_list_push( &h->lookahead->ifbuf, frame );
else
x264_sync_frame_list_push( &h->lookahead->next, frame );
}
int x264_lookahead_is_empty( x264_t *h )
{
x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex );
x264_pthread_mutex_lock( &h->lookahead->next.mutex );
int b_empty = !h->lookahead->next.i_size && !h->lookahead->ofbuf.i_size;
x264_pthread_mutex_unlock( &h->lookahead->next.mutex );
x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex );
return b_empty;
}
static void x264_lookahead_encoder_shift( x264_t *h )
{
if( !h->lookahead->ofbuf.i_size )
return;
int i_frames = h->lookahead->ofbuf.list[0]->i_bframes + 1;
while( i_frames-- )
{
x264_frame_push( h->frames.current, x264_frame_shift( h->lookahead->ofbuf.list ) );
h->lookahead->ofbuf.i_size--;
}
x264_pthread_cond_broadcast( &h->lookahead->ofbuf.cv_empty );
}
void x264_lookahead_get_frames( x264_t *h )
{
if( h->param.i_sync_lookahead )
{ /* We have a lookahead thread, so get frames from there */
x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex );
while( !h->lookahead->ofbuf.i_size && h->lookahead->b_thread_active )
x264_pthread_cond_wait( &h->lookahead->ofbuf.cv_fill, &h->lookahead->ofbuf.mutex );
x264_lookahead_encoder_shift( h );
x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex );
}
else
{ /* We are not running a lookahead thread, so perform all the slicetype decide on the fly */
if( h->frames.current[0] || !h->lookahead->next.i_size )
return;
x264_stack_align( x264_slicetype_decide, h );
x264_lookahead_update_last_nonb( h, h->lookahead->next.list[0] );
int shift_frames = h->lookahead->next.list[0]->i_bframes + 1;
x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames );
/* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */
if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) )
x264_stack_align( x264_slicetype_analyse, h, shift_frames );
x264_lookahead_encoder_shift( h );
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,198 @@
/*****************************************************************************
* macroblock.h: macroblock encoding
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ENCODER_MACROBLOCK_H
#define X264_ENCODER_MACROBLOCK_H
#include "common/macroblock.h"
extern const int x264_lambda2_tab[QP_MAX_MAX+1];
extern const uint16_t x264_lambda_tab[QP_MAX_MAX+1];
void x264_rdo_init( void );
int x264_macroblock_probe_skip( x264_t *h, int b_bidir );
#define x264_macroblock_probe_pskip( h )\
x264_macroblock_probe_skip( h, 0 )
#define x264_macroblock_probe_bskip( h )\
x264_macroblock_probe_skip( h, 1 )
void x264_predict_lossless_4x4( x264_t *h, pixel *p_dst, int p, int idx, int i_mode );
void x264_predict_lossless_8x8( x264_t *h, pixel *p_dst, int p, int idx, int i_mode, pixel edge[36] );
void x264_predict_lossless_16x16( x264_t *h, int p, int i_mode );
void x264_predict_lossless_chroma( x264_t *h, int i_mode );
void x264_macroblock_encode ( x264_t *h );
void x264_macroblock_write_cabac ( x264_t *h, x264_cabac_t *cb );
void x264_macroblock_write_cavlc ( x264_t *h );
void x264_macroblock_encode_p8x8( x264_t *h, int i8 );
void x264_macroblock_encode_p4x4( x264_t *h, int i4 );
void x264_mb_encode_chroma( x264_t *h, int b_inter, int i_qp );
void x264_cabac_mb_skip( x264_t *h, int b_skip );
void x264_cabac_block_residual_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l );
void x264_cabac_block_residual_8x8_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l );
void x264_cabac_block_residual_rd_c( x264_t *h, x264_cabac_t *cb, int ctx_block_cat, dctcoef *l );
int x264_quant_luma_dc_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, int i_qp,
int ctx_block_cat, int b_intra, int idx );
int x264_quant_chroma_dc_trellis( x264_t *h, dctcoef *dct, int i_qp, int b_intra, int idx );
int x264_quant_4x4_trellis( x264_t *h, dctcoef *dct, int i_quant_cat,
int i_qp, int ctx_block_cat, int b_intra, int b_chroma, int idx );
int x264_quant_8x8_trellis( x264_t *h, dctcoef *dct, int i_quant_cat,
int i_qp, int ctx_block_cat, int b_intra, int b_chroma, int idx );
void x264_noise_reduction_update( x264_t *h );
static ALWAYS_INLINE int x264_quant_4x4( x264_t *h, dctcoef dct[16], int i_qp, int ctx_block_cat, int b_intra, int p, int idx )
{
int i_quant_cat = b_intra ? (p?CQM_4IC:CQM_4IY) : (p?CQM_4PC:CQM_4PY);
if( h->mb.b_noise_reduction )
h->quantf.denoise_dct( dct, h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 );
if( h->mb.b_trellis )
return x264_quant_4x4_trellis( h, dct, i_quant_cat, i_qp, ctx_block_cat, b_intra, !!p, idx+p*16 );
else
return h->quantf.quant_4x4( dct, h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias[i_quant_cat][i_qp] );
}
static ALWAYS_INLINE int x264_quant_8x8( x264_t *h, dctcoef dct[64], int i_qp, int ctx_block_cat, int b_intra, int p, int idx )
{
int i_quant_cat = b_intra ? (p?CQM_8IC:CQM_8IY) : (p?CQM_8PC:CQM_8PY);
if( h->mb.b_noise_reduction )
h->quantf.denoise_dct( dct, h->nr_residual_sum[1+!!p*2], h->nr_offset[1+!!p*2], 64 );
if( h->mb.b_trellis )
return x264_quant_8x8_trellis( h, dct, i_quant_cat, i_qp, ctx_block_cat, b_intra, !!p, idx+p*4 );
else
return h->quantf.quant_8x8( dct, h->quant8_mf[i_quant_cat][i_qp], h->quant8_bias[i_quant_cat][i_qp] );
}
#define STORE_8x8_NNZ( p, idx, nz )\
do\
{\
M16( &h->mb.cache.non_zero_count[x264_scan8[p*16+idx*4]+0] ) = (nz) * 0x0101;\
M16( &h->mb.cache.non_zero_count[x264_scan8[p*16+idx*4]+8] ) = (nz) * 0x0101;\
} while( 0 )
#define CLEAR_16x16_NNZ( p ) \
do\
{\
M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 0*8] ) = 0;\
M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 1*8] ) = 0;\
M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 2*8] ) = 0;\
M32( &h->mb.cache.non_zero_count[x264_scan8[16*p] + 3*8] ) = 0;\
} while( 0 )
/* A special for loop that iterates branchlessly over each set
* bit in a 4-bit input. */
#define FOREACH_BIT(idx,start,mask) for( int idx = start, msk = mask, skip; msk && (skip = x264_ctz_4bit(msk), idx += skip, msk >>= skip+1, 1); idx++ )
static ALWAYS_INLINE void x264_mb_encode_i4x4( x264_t *h, int p, int idx, int i_qp, int i_mode, int b_predict )
{
int nz;
pixel *p_src = &h->mb.pic.p_fenc[p][block_idx_xy_fenc[idx]];
pixel *p_dst = &h->mb.pic.p_fdec[p][block_idx_xy_fdec[idx]];
ALIGNED_ARRAY_64( dctcoef, dct4x4,[16] );
if( b_predict )
{
if( h->mb.b_lossless )
x264_predict_lossless_4x4( h, p_dst, p, idx, i_mode );
else
h->predict_4x4[i_mode]( p_dst );
}
if( h->mb.b_lossless )
{
nz = h->zigzagf.sub_4x4( h->dct.luma4x4[p*16+idx], p_src, p_dst );
h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = nz;
h->mb.i_cbp_luma |= nz<<(idx>>2);
return;
}
h->dctf.sub4x4_dct( dct4x4, p_src, p_dst );
nz = x264_quant_4x4( h, dct4x4, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 1, p, idx );
h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = nz;
if( nz )
{
h->mb.i_cbp_luma |= 1<<(idx>>2);
h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4 );
h->quantf.dequant_4x4( dct4x4, h->dequant4_mf[p?CQM_4IC:CQM_4IY], i_qp );
h->dctf.add4x4_idct( p_dst, dct4x4 );
}
}
static ALWAYS_INLINE void x264_mb_encode_i8x8( x264_t *h, int p, int idx, int i_qp, int i_mode, pixel *edge, int b_predict )
{
int x = idx&1;
int y = idx>>1;
int nz;
pixel *p_src = &h->mb.pic.p_fenc[p][8*x + 8*y*FENC_STRIDE];
pixel *p_dst = &h->mb.pic.p_fdec[p][8*x + 8*y*FDEC_STRIDE];
ALIGNED_ARRAY_64( dctcoef, dct8x8,[64] );
ALIGNED_ARRAY_32( pixel, edge_buf,[36] );
if( b_predict )
{
if( !edge )
{
h->predict_8x8_filter( p_dst, edge_buf, h->mb.i_neighbour8[idx], x264_pred_i4x4_neighbors[i_mode] );
edge = edge_buf;
}
if( h->mb.b_lossless )
x264_predict_lossless_8x8( h, p_dst, p, idx, i_mode, edge );
else
h->predict_8x8[i_mode]( p_dst, edge );
}
if( h->mb.b_lossless )
{
nz = h->zigzagf.sub_8x8( h->dct.luma8x8[p*4+idx], p_src, p_dst );
STORE_8x8_NNZ( p, idx, nz );
h->mb.i_cbp_luma |= nz<<idx;
return;
}
h->dctf.sub8x8_dct8( dct8x8, p_src, p_dst );
nz = x264_quant_8x8( h, dct8x8, i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 1, p, idx );
if( nz )
{
h->mb.i_cbp_luma |= 1<<idx;
h->zigzagf.scan_8x8( h->dct.luma8x8[p*4+idx], dct8x8 );
h->quantf.dequant_8x8( dct8x8, h->dequant8_mf[p?CQM_8IC:CQM_8IY], i_qp );
h->dctf.add8x8_idct8( p_dst, dct8x8 );
STORE_8x8_NNZ( p, idx, 1 );
}
else
STORE_8x8_NNZ( p, idx, 0 );
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
/*****************************************************************************
* me.h: motion estimation
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ME_H
#define X264_ME_H
#define COST_MAX (1<<28)
#define COST_MAX64 (1ULL<<60)
typedef struct
{
/* aligning the first member is a gcc hack to force the struct to be aligned,
* as well as force sizeof(struct) to be a multiple of the alignment. */
/* input */
ALIGNED_64( int i_pixel ); /* PIXEL_WxH */
uint16_t *p_cost_mv; /* lambda * nbits for each possible mv */
int i_ref_cost;
int i_ref;
const x264_weight_t *weight;
pixel *p_fref[12];
pixel *p_fref_w;
pixel *p_fenc[3];
uint16_t *integral;
int i_stride[3];
ALIGNED_4( int16_t mvp[2] );
/* output */
int cost_mv; /* lambda * nbits for the chosen mv */
int cost; /* satd + lambda * nbits */
ALIGNED_4( int16_t mv[2] );
} ALIGNED_64( x264_me_t );
void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int *p_fullpel_thresh );
#define x264_me_search( h, m, mvc, i_mvc )\
x264_me_search_ref( h, m, mvc, i_mvc, NULL )
void x264_me_refine_qpel( x264_t *h, x264_me_t *m );
void x264_me_refine_qpel_refdupe( x264_t *h, x264_me_t *m, int *p_halfpel_thresh );
void x264_me_refine_qpel_rd( x264_t *h, x264_me_t *m, int i_lambda2, int i4, int i_list );
void x264_me_refine_bidir_rd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight, int i8, int i_lambda2 );
void x264_me_refine_bidir_satd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight );
uint64_t x264_rd_cost_part( x264_t *h, int i_lambda2, int i8, int i_pixel );
#define COPY1_IF_LT(x,y)\
if( (y) < (x) )\
(x) = (y);
#define COPY2_IF_LT(x,y,a,b)\
if( (y) < (x) )\
{\
(x) = (y);\
(a) = (b);\
}
#define COPY3_IF_LT(x,y,a,b,c,d)\
if( (y) < (x) )\
{\
(x) = (y);\
(a) = (b);\
(c) = (d);\
}
#define COPY4_IF_LT(x,y,a,b,c,d,e,f)\
if( (y) < (x) )\
{\
(x) = (y);\
(a) = (b);\
(c) = (d);\
(e) = (f);\
}
#define COPY2_IF_GT(x,y,a,b)\
if( (y) > (x) )\
{\
(x) = (y);\
(a) = (b);\
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,66 @@
/*****************************************************************************
* ratecontrol.h: ratecontrol
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_RATECONTROL_H
#define X264_RATECONTROL_H
/* Completely arbitrary. Ratecontrol lowers relative quality at higher framerates
* and the reverse at lower framerates; this serves as the center of the curve.
* Halve all the values for frame-packed 3D to compensate for the "doubled"
* framerate. */
#define BASE_FRAME_DURATION (0.04f / ((h->param.i_frame_packing == 5)+1))
/* Arbitrary limitations as a sanity check. */
#define MAX_FRAME_DURATION (1.00f / ((h->param.i_frame_packing == 5)+1))
#define MIN_FRAME_DURATION (0.01f / ((h->param.i_frame_packing == 5)+1))
#define CLIP_DURATION(f) x264_clip3f(f,MIN_FRAME_DURATION,MAX_FRAME_DURATION)
int x264_ratecontrol_new ( x264_t * );
void x264_ratecontrol_delete( x264_t * );
void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init );
int x264_encoder_reconfig_apply( x264_t *h, x264_param_t *param );
void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_offsets );
int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets );
int x264_reference_build_list_optimal( x264_t *h );
void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next );
void x264_ratecontrol_zone_init( x264_t * );
void x264_ratecontrol_start( x264_t *, int i_force_qp, int overhead );
int x264_ratecontrol_slice_type( x264_t *, int i_frame );
void x264_ratecontrol_set_weights( x264_t *h, x264_frame_t *frm );
int x264_ratecontrol_mb( x264_t *, int bits );
int x264_ratecontrol_qp( x264_t * );
int x264_ratecontrol_mb_qp( x264_t *h );
int x264_ratecontrol_end( x264_t *, int bits, int *filler );
void x264_ratecontrol_summary( x264_t * );
int x264_rc_analyse_slice( x264_t *h );
void x264_threads_distribute_ratecontrol( x264_t *h );
void x264_threads_merge_ratecontrol( x264_t *h );
void x264_hrd_fullness( x264_t *h );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,853 @@
/*****************************************************************************
* set: header writing
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "set.h"
#define bs_write_ue bs_write_ue_big
// Indexed by pic_struct values
static const uint8_t num_clock_ts[10] = { 0, 1, 1, 1, 2, 2, 3, 3, 2, 3 };
const static uint8_t avcintra_uuid[] = {0xF7, 0x49, 0x3E, 0xB3, 0xD4, 0x00, 0x47, 0x96, 0x86, 0x86, 0xC9, 0x70, 0x7B, 0x64, 0x37, 0x2A};
static void transpose( uint8_t *buf, int w )
{
for( int i = 0; i < w; i++ )
for( int j = 0; j < i; j++ )
XCHG( uint8_t, buf[w*i+j], buf[w*j+i] );
}
static void scaling_list_write( bs_t *s, x264_pps_t *pps, int idx )
{
const int len = idx<4 ? 16 : 64;
const uint8_t *zigzag = idx<4 ? x264_zigzag_scan4[0] : x264_zigzag_scan8[0];
const uint8_t *list = pps->scaling_list[idx];
const uint8_t *def_list = (idx==CQM_4IC) ? pps->scaling_list[CQM_4IY]
: (idx==CQM_4PC) ? pps->scaling_list[CQM_4PY]
: (idx==CQM_8IC+4) ? pps->scaling_list[CQM_8IY+4]
: (idx==CQM_8PC+4) ? pps->scaling_list[CQM_8PY+4]
: x264_cqm_jvt[idx];
if( !memcmp( list, def_list, len ) )
bs_write1( s, 0 ); // scaling_list_present_flag
else if( !memcmp( list, x264_cqm_jvt[idx], len ) )
{
bs_write1( s, 1 ); // scaling_list_present_flag
bs_write_se( s, -8 ); // use jvt list
}
else
{
int run;
bs_write1( s, 1 ); // scaling_list_present_flag
// try run-length compression of trailing values
for( run = len; run > 1; run-- )
if( list[zigzag[run-1]] != list[zigzag[run-2]] )
break;
if( run < len && len - run < bs_size_se( (int8_t)-list[zigzag[run]] ) )
run = len;
for( int j = 0; j < run; j++ )
bs_write_se( s, (int8_t)(list[zigzag[j]] - (j>0 ? list[zigzag[j-1]] : 8)) ); // delta
if( run < len )
bs_write_se( s, (int8_t)-list[zigzag[run]] );
}
}
void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type )
{
int i;
bs_realign( s );
for( i = 0; i <= payload_type-255; i += 255 )
bs_write( s, 8, 255 );
bs_write( s, 8, payload_type-i );
for( i = 0; i <= payload_size-255; i += 255 )
bs_write( s, 8, 255 );
bs_write( s, 8, payload_size-i );
for( i = 0; i < payload_size; i++ )
bs_write( s, 8, payload[i] );
bs_rbsp_trailing( s );
bs_flush( s );
}
void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
{
int csp = param->i_csp & X264_CSP_MASK;
sps->i_id = i_id;
sps->i_mb_width = ( param->i_width + 15 ) / 16;
sps->i_mb_height= ( param->i_height + 15 ) / 16;
sps->i_chroma_format_idc = csp >= X264_CSP_I444 ? CHROMA_444 :
csp >= X264_CSP_I422 ? CHROMA_422 : CHROMA_420;
sps->b_qpprime_y_zero_transform_bypass = param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0;
if( sps->b_qpprime_y_zero_transform_bypass || sps->i_chroma_format_idc == CHROMA_444 )
sps->i_profile_idc = PROFILE_HIGH444_PREDICTIVE;
else if( sps->i_chroma_format_idc == CHROMA_422 )
sps->i_profile_idc = PROFILE_HIGH422;
else if( BIT_DEPTH > 8 )
sps->i_profile_idc = PROFILE_HIGH10;
else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT )
sps->i_profile_idc = PROFILE_HIGH;
else if( param->b_cabac || param->i_bframe > 0 || param->b_interlaced || param->b_fake_interlaced || param->analyse.i_weighted_pred > 0 )
sps->i_profile_idc = PROFILE_MAIN;
else
sps->i_profile_idc = PROFILE_BASELINE;
sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE;
/* x264 doesn't support the features that are in Baseline and not in Main,
* namely arbitrary_slice_order and slice_groups. */
sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN;
/* Never set constraint_set2, it is not necessary and not used in real world. */
sps->b_constraint_set2 = 0;
sps->b_constraint_set3 = 0;
sps->i_level_idc = param->i_level_idc;
if( param->i_level_idc == 9 && ( sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN ) )
{
sps->b_constraint_set3 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */
sps->i_level_idc = 11;
}
/* Intra profiles */
if( param->i_keyint_max == 1 && sps->i_profile_idc >= PROFILE_HIGH )
sps->b_constraint_set3 = 1;
sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0;
/* extra slot with pyramid so that we don't have to override the
* order of forgetting old pictures */
sps->vui.i_max_dec_frame_buffering =
sps->i_num_ref_frames = X264_MIN(X264_REF_MAX, X264_MAX4(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames,
param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size));
sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT;
if( param->i_keyint_max == 1 )
{
sps->i_num_ref_frames = 0;
sps->vui.i_max_dec_frame_buffering = 0;
}
/* number of refs + current frame */
int max_frame_num = sps->vui.i_max_dec_frame_buffering * (!!param->i_bframe_pyramid+1) + 1;
/* Intra refresh cannot write a recovery time greater than max frame num-1 */
if( param->b_intra_refresh )
{
int time_to_recovery = X264_MIN( sps->i_mb_width - 1, param->i_keyint_max ) + param->i_bframe - 1;
max_frame_num = X264_MAX( max_frame_num, time_to_recovery+1 );
}
sps->i_log2_max_frame_num = 4;
while( (1 << sps->i_log2_max_frame_num) <= max_frame_num )
sps->i_log2_max_frame_num++;
sps->i_poc_type = param->i_bframe || param->b_interlaced || param->i_avcintra_class ? 0 : 2;
if( sps->i_poc_type == 0 )
{
int max_delta_poc = (param->i_bframe + 2) * (!!param->i_bframe_pyramid + 1) * 2;
sps->i_log2_max_poc_lsb = 4;
while( (1 << sps->i_log2_max_poc_lsb) <= max_delta_poc * 2 )
sps->i_log2_max_poc_lsb++;
}
sps->b_vui = 1;
sps->b_gaps_in_frame_num_value_allowed = 0;
sps->b_frame_mbs_only = !(param->b_interlaced || param->b_fake_interlaced);
if( !sps->b_frame_mbs_only )
sps->i_mb_height = ( sps->i_mb_height + 1 ) & ~1;
sps->b_mb_adaptive_frame_field = param->b_interlaced;
sps->b_direct8x8_inference = 1;
x264_sps_init_reconfigurable( sps, param );
sps->vui.b_overscan_info_present = param->vui.i_overscan > 0 && param->vui.i_overscan <= 2;
if( sps->vui.b_overscan_info_present )
sps->vui.b_overscan_info = ( param->vui.i_overscan == 2 ? 1 : 0 );
sps->vui.b_signal_type_present = 0;
sps->vui.i_vidformat = ( param->vui.i_vidformat >= 0 && param->vui.i_vidformat <= 5 ? param->vui.i_vidformat : 5 );
sps->vui.b_fullrange = ( param->vui.b_fullrange >= 0 && param->vui.b_fullrange <= 1 ? param->vui.b_fullrange :
( csp >= X264_CSP_BGR ? 1 : 0 ) );
sps->vui.b_color_description_present = 0;
sps->vui.i_colorprim = ( param->vui.i_colorprim >= 0 && param->vui.i_colorprim <= 12 ? param->vui.i_colorprim : 2 );
sps->vui.i_transfer = ( param->vui.i_transfer >= 0 && param->vui.i_transfer <= 17 ? param->vui.i_transfer : 2 );
sps->vui.i_colmatrix = ( param->vui.i_colmatrix >= 0 && param->vui.i_colmatrix <= 11 ? param->vui.i_colmatrix :
( csp >= X264_CSP_BGR ? 0 : 2 ) );
if( sps->vui.i_colorprim != 2 ||
sps->vui.i_transfer != 2 ||
sps->vui.i_colmatrix != 2 )
{
sps->vui.b_color_description_present = 1;
}
if( sps->vui.i_vidformat != 5 ||
sps->vui.b_fullrange ||
sps->vui.b_color_description_present )
{
sps->vui.b_signal_type_present = 1;
}
/* FIXME: not sufficient for interlaced video */
sps->vui.b_chroma_loc_info_present = param->vui.i_chroma_loc > 0 && param->vui.i_chroma_loc <= 5 &&
sps->i_chroma_format_idc == CHROMA_420;
if( sps->vui.b_chroma_loc_info_present )
{
sps->vui.i_chroma_loc_top = param->vui.i_chroma_loc;
sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc;
}
sps->vui.b_timing_info_present = param->i_timebase_num > 0 && param->i_timebase_den > 0;
if( sps->vui.b_timing_info_present )
{
sps->vui.i_num_units_in_tick = param->i_timebase_num;
sps->vui.i_time_scale = param->i_timebase_den * 2;
sps->vui.b_fixed_frame_rate = !param->b_vfr_input;
}
sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD
sps->vui.b_nal_hrd_parameters_present = !!param->i_nal_hrd;
sps->vui.b_pic_struct_present = param->b_pic_struct;
// NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable
sps->vui.b_bitstream_restriction = !(sps->b_constraint_set3 && sps->i_profile_idc >= PROFILE_HIGH);
if( sps->vui.b_bitstream_restriction )
{
sps->vui.b_motion_vectors_over_pic_boundaries = 1;
sps->vui.i_max_bytes_per_pic_denom = 0;
sps->vui.i_max_bits_per_mb_denom = 0;
sps->vui.i_log2_max_mv_length_horizontal =
sps->vui.i_log2_max_mv_length_vertical = (int)log2f( X264_MAX( 1, param->analyse.i_mv_range*4-1 ) ) + 1;
}
}
void x264_sps_init_reconfigurable( x264_sps_t *sps, x264_param_t *param )
{
sps->crop.i_left = param->crop_rect.i_left;
sps->crop.i_top = param->crop_rect.i_top;
sps->crop.i_right = param->crop_rect.i_right + sps->i_mb_width*16 - param->i_width;
sps->crop.i_bottom = (param->crop_rect.i_bottom + sps->i_mb_height*16 - param->i_height) >> !sps->b_frame_mbs_only;
sps->b_crop = sps->crop.i_left || sps->crop.i_top ||
sps->crop.i_right || sps->crop.i_bottom;
sps->vui.b_aspect_ratio_info_present = 0;
if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 )
{
sps->vui.b_aspect_ratio_info_present = 1;
sps->vui.i_sar_width = param->vui.i_sar_width;
sps->vui.i_sar_height= param->vui.i_sar_height;
}
}
void x264_sps_write( bs_t *s, x264_sps_t *sps )
{
bs_realign( s );
bs_write( s, 8, sps->i_profile_idc );
bs_write1( s, sps->b_constraint_set0 );
bs_write1( s, sps->b_constraint_set1 );
bs_write1( s, sps->b_constraint_set2 );
bs_write1( s, sps->b_constraint_set3 );
bs_write( s, 4, 0 ); /* reserved */
bs_write( s, 8, sps->i_level_idc );
bs_write_ue( s, sps->i_id );
if( sps->i_profile_idc >= PROFILE_HIGH )
{
bs_write_ue( s, sps->i_chroma_format_idc );
if( sps->i_chroma_format_idc == CHROMA_444 )
bs_write1( s, 0 ); // separate_colour_plane_flag
bs_write_ue( s, BIT_DEPTH-8 ); // bit_depth_luma_minus8
bs_write_ue( s, BIT_DEPTH-8 ); // bit_depth_chroma_minus8
bs_write1( s, sps->b_qpprime_y_zero_transform_bypass );
bs_write1( s, 0 ); // seq_scaling_matrix_present_flag
}
bs_write_ue( s, sps->i_log2_max_frame_num - 4 );
bs_write_ue( s, sps->i_poc_type );
if( sps->i_poc_type == 0 )
bs_write_ue( s, sps->i_log2_max_poc_lsb - 4 );
bs_write_ue( s, sps->i_num_ref_frames );
bs_write1( s, sps->b_gaps_in_frame_num_value_allowed );
bs_write_ue( s, sps->i_mb_width - 1 );
bs_write_ue( s, (sps->i_mb_height >> !sps->b_frame_mbs_only) - 1);
bs_write1( s, sps->b_frame_mbs_only );
if( !sps->b_frame_mbs_only )
bs_write1( s, sps->b_mb_adaptive_frame_field );
bs_write1( s, sps->b_direct8x8_inference );
bs_write1( s, sps->b_crop );
if( sps->b_crop )
{
int h_shift = sps->i_chroma_format_idc == CHROMA_420 || sps->i_chroma_format_idc == CHROMA_422;
int v_shift = sps->i_chroma_format_idc == CHROMA_420;
bs_write_ue( s, sps->crop.i_left >> h_shift );
bs_write_ue( s, sps->crop.i_right >> h_shift );
bs_write_ue( s, sps->crop.i_top >> v_shift );
bs_write_ue( s, sps->crop.i_bottom >> v_shift );
}
bs_write1( s, sps->b_vui );
if( sps->b_vui )
{
bs_write1( s, sps->vui.b_aspect_ratio_info_present );
if( sps->vui.b_aspect_ratio_info_present )
{
int i;
static const struct { uint8_t w, h, sar; } sar[] =
{
// aspect_ratio_idc = 0 -> unspecified
{ 1, 1, 1 }, { 12, 11, 2 }, { 10, 11, 3 }, { 16, 11, 4 },
{ 40, 33, 5 }, { 24, 11, 6 }, { 20, 11, 7 }, { 32, 11, 8 },
{ 80, 33, 9 }, { 18, 11, 10}, { 15, 11, 11}, { 64, 33, 12},
{160, 99, 13}, { 4, 3, 14}, { 3, 2, 15}, { 2, 1, 16},
// aspect_ratio_idc = [17..254] -> reserved
{ 0, 0, 255 }
};
for( i = 0; sar[i].sar != 255; i++ )
{
if( sar[i].w == sps->vui.i_sar_width &&
sar[i].h == sps->vui.i_sar_height )
break;
}
bs_write( s, 8, sar[i].sar );
if( sar[i].sar == 255 ) /* aspect_ratio_idc (extended) */
{
bs_write( s, 16, sps->vui.i_sar_width );
bs_write( s, 16, sps->vui.i_sar_height );
}
}
bs_write1( s, sps->vui.b_overscan_info_present );
if( sps->vui.b_overscan_info_present )
bs_write1( s, sps->vui.b_overscan_info );
bs_write1( s, sps->vui.b_signal_type_present );
if( sps->vui.b_signal_type_present )
{
bs_write( s, 3, sps->vui.i_vidformat );
bs_write1( s, sps->vui.b_fullrange );
bs_write1( s, sps->vui.b_color_description_present );
if( sps->vui.b_color_description_present )
{
bs_write( s, 8, sps->vui.i_colorprim );
bs_write( s, 8, sps->vui.i_transfer );
bs_write( s, 8, sps->vui.i_colmatrix );
}
}
bs_write1( s, sps->vui.b_chroma_loc_info_present );
if( sps->vui.b_chroma_loc_info_present )
{
bs_write_ue( s, sps->vui.i_chroma_loc_top );
bs_write_ue( s, sps->vui.i_chroma_loc_bottom );
}
bs_write1( s, sps->vui.b_timing_info_present );
if( sps->vui.b_timing_info_present )
{
bs_write32( s, sps->vui.i_num_units_in_tick );
bs_write32( s, sps->vui.i_time_scale );
bs_write1( s, sps->vui.b_fixed_frame_rate );
}
bs_write1( s, sps->vui.b_nal_hrd_parameters_present );
if( sps->vui.b_nal_hrd_parameters_present )
{
bs_write_ue( s, sps->vui.hrd.i_cpb_cnt - 1 );
bs_write( s, 4, sps->vui.hrd.i_bit_rate_scale );
bs_write( s, 4, sps->vui.hrd.i_cpb_size_scale );
bs_write_ue( s, sps->vui.hrd.i_bit_rate_value - 1 );
bs_write_ue( s, sps->vui.hrd.i_cpb_size_value - 1 );
bs_write1( s, sps->vui.hrd.b_cbr_hrd );
bs_write( s, 5, sps->vui.hrd.i_initial_cpb_removal_delay_length - 1 );
bs_write( s, 5, sps->vui.hrd.i_cpb_removal_delay_length - 1 );
bs_write( s, 5, sps->vui.hrd.i_dpb_output_delay_length - 1 );
bs_write( s, 5, sps->vui.hrd.i_time_offset_length );
}
bs_write1( s, sps->vui.b_vcl_hrd_parameters_present );
if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present )
bs_write1( s, 0 ); /* low_delay_hrd_flag */
bs_write1( s, sps->vui.b_pic_struct_present );
bs_write1( s, sps->vui.b_bitstream_restriction );
if( sps->vui.b_bitstream_restriction )
{
bs_write1( s, sps->vui.b_motion_vectors_over_pic_boundaries );
bs_write_ue( s, sps->vui.i_max_bytes_per_pic_denom );
bs_write_ue( s, sps->vui.i_max_bits_per_mb_denom );
bs_write_ue( s, sps->vui.i_log2_max_mv_length_horizontal );
bs_write_ue( s, sps->vui.i_log2_max_mv_length_vertical );
bs_write_ue( s, sps->vui.i_num_reorder_frames );
bs_write_ue( s, sps->vui.i_max_dec_frame_buffering );
}
}
bs_rbsp_trailing( s );
bs_flush( s );
}
void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps )
{
pps->i_id = i_id;
pps->i_sps_id = sps->i_id;
pps->b_cabac = param->b_cabac;
pps->b_pic_order = !param->i_avcintra_class && param->b_interlaced;
pps->i_num_slice_groups = 1;
pps->i_num_ref_idx_l0_default_active = param->i_frame_reference;
pps->i_num_ref_idx_l1_default_active = 1;
pps->b_weighted_pred = param->analyse.i_weighted_pred > 0;
pps->b_weighted_bipred = param->analyse.b_weighted_bipred ? 2 : 0;
pps->i_pic_init_qp = param->rc.i_rc_method == X264_RC_ABR || param->b_stitchable ? 26 + QP_BD_OFFSET : SPEC_QP( param->rc.i_qp_constant );
pps->i_pic_init_qs = 26 + QP_BD_OFFSET;
pps->i_chroma_qp_index_offset = param->analyse.i_chroma_qp_offset;
pps->b_deblocking_filter_control = 1;
pps->b_constrained_intra_pred = param->b_constrained_intra;
pps->b_redundant_pic_cnt = 0;
pps->b_transform_8x8_mode = param->analyse.b_transform_8x8 ? 1 : 0;
pps->i_cqm_preset = param->i_cqm_preset;
switch( pps->i_cqm_preset )
{
case X264_CQM_FLAT:
for( int i = 0; i < 8; i++ )
pps->scaling_list[i] = x264_cqm_flat16;
break;
case X264_CQM_JVT:
for( int i = 0; i < 8; i++ )
pps->scaling_list[i] = x264_cqm_jvt[i];
break;
case X264_CQM_CUSTOM:
/* match the transposed DCT & zigzag */
transpose( param->cqm_4iy, 4 );
transpose( param->cqm_4py, 4 );
transpose( param->cqm_4ic, 4 );
transpose( param->cqm_4pc, 4 );
transpose( param->cqm_8iy, 8 );
transpose( param->cqm_8py, 8 );
transpose( param->cqm_8ic, 8 );
transpose( param->cqm_8pc, 8 );
pps->scaling_list[CQM_4IY] = param->cqm_4iy;
pps->scaling_list[CQM_4PY] = param->cqm_4py;
pps->scaling_list[CQM_4IC] = param->cqm_4ic;
pps->scaling_list[CQM_4PC] = param->cqm_4pc;
pps->scaling_list[CQM_8IY+4] = param->cqm_8iy;
pps->scaling_list[CQM_8PY+4] = param->cqm_8py;
pps->scaling_list[CQM_8IC+4] = param->cqm_8ic;
pps->scaling_list[CQM_8PC+4] = param->cqm_8pc;
for( int i = 0; i < 8; i++ )
for( int j = 0; j < (i < 4 ? 16 : 64); j++ )
if( pps->scaling_list[i][j] == 0 )
pps->scaling_list[i] = x264_cqm_jvt[i];
break;
}
}
void x264_pps_write( bs_t *s, x264_sps_t *sps, x264_pps_t *pps )
{
bs_realign( s );
bs_write_ue( s, pps->i_id );
bs_write_ue( s, pps->i_sps_id );
bs_write1( s, pps->b_cabac );
bs_write1( s, pps->b_pic_order );
bs_write_ue( s, pps->i_num_slice_groups - 1 );
bs_write_ue( s, pps->i_num_ref_idx_l0_default_active - 1 );
bs_write_ue( s, pps->i_num_ref_idx_l1_default_active - 1 );
bs_write1( s, pps->b_weighted_pred );
bs_write( s, 2, pps->b_weighted_bipred );
bs_write_se( s, pps->i_pic_init_qp - 26 - QP_BD_OFFSET );
bs_write_se( s, pps->i_pic_init_qs - 26 - QP_BD_OFFSET );
bs_write_se( s, pps->i_chroma_qp_index_offset );
bs_write1( s, pps->b_deblocking_filter_control );
bs_write1( s, pps->b_constrained_intra_pred );
bs_write1( s, pps->b_redundant_pic_cnt );
if( pps->b_transform_8x8_mode || pps->i_cqm_preset != X264_CQM_FLAT )
{
bs_write1( s, pps->b_transform_8x8_mode );
bs_write1( s, (pps->i_cqm_preset != X264_CQM_FLAT) );
if( pps->i_cqm_preset != X264_CQM_FLAT )
{
scaling_list_write( s, pps, CQM_4IY );
scaling_list_write( s, pps, CQM_4IC );
bs_write1( s, 0 ); // Cr = Cb
scaling_list_write( s, pps, CQM_4PY );
scaling_list_write( s, pps, CQM_4PC );
bs_write1( s, 0 ); // Cr = Cb
if( pps->b_transform_8x8_mode )
{
scaling_list_write( s, pps, CQM_8IY+4 );
scaling_list_write( s, pps, CQM_8PY+4 );
if( sps->i_chroma_format_idc == CHROMA_444 )
{
scaling_list_write( s, pps, CQM_8IC+4 );
scaling_list_write( s, pps, CQM_8PC+4 );
bs_write1( s, 0 ); // Cr = Cb
bs_write1( s, 0 ); // Cr = Cb
}
}
}
bs_write_se( s, pps->i_chroma_qp_index_offset );
}
bs_rbsp_trailing( s );
bs_flush( s );
}
void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt )
{
bs_t q;
ALIGNED_4( uint8_t tmp_buf[100] );
M32( tmp_buf ) = 0; // shut up gcc
bs_init( &q, tmp_buf, 100 );
bs_realign( &q );
bs_write_ue( &q, recovery_frame_cnt ); // recovery_frame_cnt
bs_write1( &q, 1 ); //exact_match_flag 1
bs_write1( &q, 0 ); //broken_link_flag 0
bs_write( &q, 2, 0 ); //changing_slice_group 0
bs_align_10( &q );
bs_flush( &q );
x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_RECOVERY_POINT );
}
int x264_sei_version_write( x264_t *h, bs_t *s )
{
// random ID number generated according to ISO-11578
static const uint8_t uuid[16] =
{
0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7,
0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef
};
char *opts = x264_param2string( &h->param, 0 );
char *payload;
int length;
if( !opts )
return -1;
CHECKED_MALLOC( payload, 200 + strlen( opts ) );
memcpy( payload, uuid, 16 );
sprintf( payload+16, "x264 - core %d%s - H.264/MPEG-4 AVC codec - "
"Copy%s 2003-2017 - http://www.videolan.org/x264.html - options: %s",
X264_BUILD, X264_VERSION, HAVE_GPL?"left":"right", opts );
length = strlen(payload)+1;
x264_sei_write( s, (uint8_t *)payload, length, SEI_USER_DATA_UNREGISTERED );
x264_free( opts );
x264_free( payload );
return 0;
fail:
x264_free( opts );
return -1;
}
void x264_sei_buffering_period_write( x264_t *h, bs_t *s )
{
x264_sps_t *sps = h->sps;
bs_t q;
ALIGNED_4( uint8_t tmp_buf[100] );
M32( tmp_buf ) = 0; // shut up gcc
bs_init( &q, tmp_buf, 100 );
bs_realign( &q );
bs_write_ue( &q, sps->i_id );
if( sps->vui.b_nal_hrd_parameters_present )
{
bs_write( &q, sps->vui.hrd.i_initial_cpb_removal_delay_length, h->initial_cpb_removal_delay );
bs_write( &q, sps->vui.hrd.i_initial_cpb_removal_delay_length, h->initial_cpb_removal_delay_offset );
}
bs_align_10( &q );
bs_flush( &q );
x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_BUFFERING_PERIOD );
}
void x264_sei_pic_timing_write( x264_t *h, bs_t *s )
{
x264_sps_t *sps = h->sps;
bs_t q;
ALIGNED_4( uint8_t tmp_buf[100] );
M32( tmp_buf ) = 0; // shut up gcc
bs_init( &q, tmp_buf, 100 );
bs_realign( &q );
if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present )
{
bs_write( &q, sps->vui.hrd.i_cpb_removal_delay_length, h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset );
bs_write( &q, sps->vui.hrd.i_dpb_output_delay_length, h->fenc->i_dpb_output_delay );
}
if( sps->vui.b_pic_struct_present )
{
bs_write( &q, 4, h->fenc->i_pic_struct-1 ); // We use index 0 for "Auto"
// These clock timestamps are not standardised so we don't set them
// They could be time of origin, capture or alternative ideal display
for( int i = 0; i < num_clock_ts[h->fenc->i_pic_struct]; i++ )
bs_write1( &q, 0 ); // clock_timestamp_flag
}
bs_align_10( &q );
bs_flush( &q );
x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_PIC_TIMING );
}
void x264_sei_frame_packing_write( x264_t *h, bs_t *s )
{
int quincunx_sampling_flag = h->param.i_frame_packing == 0;
bs_t q;
ALIGNED_4( uint8_t tmp_buf[100] );
M32( tmp_buf ) = 0; // shut up gcc
bs_init( &q, tmp_buf, 100 );
bs_realign( &q );
bs_write_ue( &q, 0 ); // frame_packing_arrangement_id
bs_write1( &q, 0 ); // frame_packing_arrangement_cancel_flag
bs_write ( &q, 7, h->param.i_frame_packing ); // frame_packing_arrangement_type
bs_write1( &q, quincunx_sampling_flag ); // quincunx_sampling_flag
// 0: views are unrelated, 1: left view is on the left, 2: left view is on the right
bs_write ( &q, 6, h->param.i_frame_packing != 6 ); // content_interpretation_type
bs_write1( &q, 0 ); // spatial_flipping_flag
bs_write1( &q, 0 ); // frame0_flipped_flag
bs_write1( &q, 0 ); // field_views_flag
bs_write1( &q, h->param.i_frame_packing == 5 && !(h->fenc->i_frame&1) ); // current_frame_is_frame0_flag
bs_write1( &q, 0 ); // frame0_self_contained_flag
bs_write1( &q, 0 ); // frame1_self_contained_flag
if( quincunx_sampling_flag == 0 && h->param.i_frame_packing != 5 )
{
bs_write( &q, 4, 0 ); // frame0_grid_position_x
bs_write( &q, 4, 0 ); // frame0_grid_position_y
bs_write( &q, 4, 0 ); // frame1_grid_position_x
bs_write( &q, 4, 0 ); // frame1_grid_position_y
}
bs_write( &q, 8, 0 ); // frame_packing_arrangement_reserved_byte
// "frame_packing_arrangement_repetition_period equal to 1 specifies that the frame packing arrangement SEI message persists in output"
// for (i_frame_packing == 5) this will undermine current_frame_is_frame0_flag which must alternate every view sequence
bs_write_ue( &q, h->param.i_frame_packing != 5 ); // frame_packing_arrangement_repetition_period
bs_write1( &q, 0 ); // frame_packing_arrangement_extension_flag
bs_align_10( &q );
bs_flush( &q );
x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_FRAME_PACKING );
}
void x264_filler_write( x264_t *h, bs_t *s, int filler )
{
bs_realign( s );
for( int i = 0; i < filler; i++ )
bs_write( s, 8, 0xff );
bs_rbsp_trailing( s );
bs_flush( s );
}
void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s )
{
x264_slice_header_t *sh = &h->sh_backup;
bs_t q;
ALIGNED_4( uint8_t tmp_buf[100] );
M32( tmp_buf ) = 0; // shut up gcc
bs_init( &q, tmp_buf, 100 );
bs_realign( &q );
/* We currently only use this for repeating B-refs, as required by Blu-ray. */
bs_write1( &q, 0 ); //original_idr_flag
bs_write_ue( &q, sh->i_frame_num ); //original_frame_num
if( !h->sps->b_frame_mbs_only )
bs_write1( &q, 0 ); //original_field_pic_flag
bs_write1( &q, sh->i_mmco_command_count > 0 );
if( sh->i_mmco_command_count > 0 )
{
for( int i = 0; i < sh->i_mmco_command_count; i++ )
{
bs_write_ue( &q, 1 );
bs_write_ue( &q, sh->mmco[i].i_difference_of_pic_nums - 1 );
}
bs_write_ue( &q, 0 );
}
bs_align_10( &q );
bs_flush( &q );
x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_DEC_REF_PIC_MARKING );
}
int x264_sei_avcintra_umid_write( x264_t *h, bs_t *s )
{
uint8_t data[512];
const char *msg = "UMID";
const int len = 497;
memset( data, 0xff, len );
memcpy( data, avcintra_uuid, sizeof(avcintra_uuid) );
memcpy( data+16, msg, strlen(msg) );
data[20] = 0x13;
/* These bytes appear to be some sort of frame/seconds counter in certain applications,
* but others jump around, so leave them as zero for now */
data[22] = data[23] = data[25] = data[26] = 0;
data[28] = 0x14;
data[30] = data[31] = data[33] = data[34] = 0;
data[36] = 0x60;
data[41] = 0x22; /* Believed to be some sort of end of basic UMID identifier */
data[60] = 0x62;
data[62] = data[63] = data[65] = data[66] = 0;
data[68] = 0x63;
data[70] = data[71] = data[73] = data[74] = 0;
x264_sei_write( &h->out.bs, data, len, SEI_USER_DATA_UNREGISTERED );
return 0;
}
int x264_sei_avcintra_vanc_write( x264_t *h, bs_t *s, int len )
{
uint8_t data[6000];
const char *msg = "VANC";
if( len > sizeof(data) )
{
x264_log( h, X264_LOG_ERROR, "AVC-Intra SEI is too large (%d)\n", len );
return -1;
}
memset( data, 0xff, len );
memcpy( data, avcintra_uuid, sizeof(avcintra_uuid) );
memcpy( data+16, msg, strlen(msg) );
x264_sei_write( &h->out.bs, data, len, SEI_USER_DATA_UNREGISTERED );
return 0;
}
const x264_level_t x264_levels[] =
{
{ 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 },
{ 9, 1485, 99, 396, 128, 350, 64, 64, 0, 2, 0, 0, 1 }, /* "1b" */
{ 11, 3000, 396, 900, 192, 500, 128, 64, 0, 2, 0, 0, 1 },
{ 12, 6000, 396, 2376, 384, 1000, 128, 64, 0, 2, 0, 0, 1 },
{ 13, 11880, 396, 2376, 768, 2000, 128, 64, 0, 2, 0, 0, 1 },
{ 20, 11880, 396, 2376, 2000, 2000, 128, 64, 0, 2, 0, 0, 1 },
{ 21, 19800, 792, 4752, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 },
{ 22, 20250, 1620, 8100, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 },
{ 30, 40500, 1620, 8100, 10000, 10000, 256, 32, 22, 2, 0, 1, 0 },
{ 31, 108000, 3600, 18000, 14000, 14000, 512, 16, 60, 4, 1, 1, 0 },
{ 32, 216000, 5120, 20480, 20000, 20000, 512, 16, 60, 4, 1, 1, 0 },
{ 40, 245760, 8192, 32768, 20000, 25000, 512, 16, 60, 4, 1, 1, 0 },
{ 41, 245760, 8192, 32768, 50000, 62500, 512, 16, 24, 2, 1, 1, 0 },
{ 42, 522240, 8704, 34816, 50000, 62500, 512, 16, 24, 2, 1, 1, 1 },
{ 50, 589824, 22080, 110400, 135000, 135000, 512, 16, 24, 2, 1, 1, 1 },
{ 51, 983040, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 },
{ 52, 2073600, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 },
{ 60, 4177920, 139264, 696320, 240000, 240000, 8192, 16, 24, 2, 1, 1, 1 },
{ 61, 8355840, 139264, 696320, 480000, 480000, 8192, 16, 24, 2, 1, 1, 1 },
{ 62, 16711680, 139264, 696320, 800000, 800000, 8192, 16, 24, 2, 1, 1, 1 },
{ 0 }
};
#define ERROR(...)\
{\
if( verbose )\
x264_log( h, X264_LOG_WARNING, __VA_ARGS__ );\
ret = 1;\
}
int x264_validate_levels( x264_t *h, int verbose )
{
int ret = 0;
int mbs = h->sps->i_mb_width * h->sps->i_mb_height;
int dpb = mbs * h->sps->vui.i_max_dec_frame_buffering;
int cbp_factor = h->sps->i_profile_idc>=PROFILE_HIGH422 ? 16 :
h->sps->i_profile_idc==PROFILE_HIGH10 ? 12 :
h->sps->i_profile_idc==PROFILE_HIGH ? 5 : 4;
const x264_level_t *l = x264_levels;
while( l->level_idc != 0 && l->level_idc != h->param.i_level_idc )
l++;
if( l->frame_size < mbs
|| l->frame_size*8 < h->sps->i_mb_width * h->sps->i_mb_width
|| l->frame_size*8 < h->sps->i_mb_height * h->sps->i_mb_height )
ERROR( "frame MB size (%dx%d) > level limit (%d)\n",
h->sps->i_mb_width, h->sps->i_mb_height, l->frame_size );
if( dpb > l->dpb )
ERROR( "DPB size (%d frames, %d mbs) > level limit (%d frames, %d mbs)\n",
h->sps->vui.i_max_dec_frame_buffering, dpb, l->dpb / mbs, l->dpb );
#define CHECK( name, limit, val ) \
if( (val) > (limit) ) \
ERROR( name " (%"PRId64") > level limit (%d)\n", (int64_t)(val), (limit) );
CHECK( "VBV bitrate", (l->bitrate * cbp_factor) / 4, h->param.rc.i_vbv_max_bitrate );
CHECK( "VBV buffer", (l->cpb * cbp_factor) / 4, h->param.rc.i_vbv_buffer_size );
CHECK( "MV range", l->mv_range, h->param.analyse.i_mv_range );
CHECK( "interlaced", !l->frame_only, h->param.b_interlaced );
CHECK( "fake interlaced", !l->frame_only, h->param.b_fake_interlaced );
if( h->param.i_fps_den > 0 )
CHECK( "MB rate", l->mbps, (int64_t)mbs * h->param.i_fps_num / h->param.i_fps_den );
/* TODO check the rest of the limits */
return ret;
}

View file

@ -0,0 +1,47 @@
/*****************************************************************************
* set.h: header writing
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_ENCODER_SET_H
#define X264_ENCODER_SET_H
void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param );
void x264_sps_init_reconfigurable( x264_sps_t *sps, x264_param_t *param );
void x264_sps_write( bs_t *s, x264_sps_t *sps );
void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps );
void x264_pps_write( bs_t *s, x264_sps_t *sps, x264_pps_t *pps );
void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt );
int x264_sei_version_write( x264_t *h, bs_t *s );
int x264_validate_levels( x264_t *h, int verbose );
void x264_sei_buffering_period_write( x264_t *h, bs_t *s );
void x264_sei_pic_timing_write( x264_t *h, bs_t *s );
void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s );
void x264_sei_frame_packing_write( x264_t *h, bs_t *s );
int x264_sei_avcintra_umid_write( x264_t *h, bs_t *s );
int x264_sei_avcintra_vanc_write( x264_t *h, bs_t *s, int len );
void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type );
void x264_filler_write( x264_t *h, bs_t *s, int filler );
#endif

View file

@ -0,0 +1,780 @@
/*****************************************************************************
* slicetype-cl.c: OpenCL slicetype decision code (lowres lookahead)
*****************************************************************************
* Copyright (C) 2012-2017 x264 project
*
* Authors: Steve Borho <sborho@multicorewareinc.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "common/common.h"
#include "macroblock.h"
#include "me.h"
#if HAVE_OPENCL
#ifdef _WIN32
#include <windows.h>
#endif
void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, int b_lookahead );
/* We define CL_QUEUE_THREAD_HANDLE_AMD here because it is not defined
* in the OpenCL headers shipped with NVIDIA drivers. We need to be
* able to compile on an NVIDIA machine and run optimally on an AMD GPU. */
#define CL_QUEUE_THREAD_HANDLE_AMD 0x403E
#define OCLCHECK( method, ... )\
do\
{\
if( h->opencl.b_fatal_error )\
return -1;\
status = ocl->method( __VA_ARGS__ );\
if( status != CL_SUCCESS ) {\
h->param.b_opencl = 0;\
h->opencl.b_fatal_error = 1;\
x264_log( h, X264_LOG_ERROR, # method " error '%d'\n", status );\
return -1;\
}\
} while( 0 )
void x264_opencl_flush( x264_t *h )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
ocl->clFinish( h->opencl.queue );
/* Finish copies from the GPU by copying from the page-locked buffer to
* their final destination */
for( int i = 0; i < h->opencl.num_copies; i++ )
memcpy( h->opencl.copies[i].dest, h->opencl.copies[i].src, h->opencl.copies[i].bytes );
h->opencl.num_copies = 0;
h->opencl.pl_occupancy = 0;
}
static void *x264_opencl_alloc_locked( x264_t *h, int bytes )
{
if( h->opencl.pl_occupancy + bytes >= PAGE_LOCKED_BUF_SIZE )
x264_opencl_flush( h );
assert( bytes < PAGE_LOCKED_BUF_SIZE );
char *ptr = h->opencl.page_locked_ptr + h->opencl.pl_occupancy;
h->opencl.pl_occupancy += bytes;
return ptr;
}
int x264_opencl_lowres_init( x264_t *h, x264_frame_t *fenc, int lambda )
{
if( fenc->b_intra_calculated )
return 0;
fenc->b_intra_calculated = 1;
x264_opencl_function_t *ocl = h->opencl.ocl;
int luma_length = fenc->i_stride[0] * fenc->i_lines[0];
#define CREATEBUF( out, flags, size )\
out = ocl->clCreateBuffer( h->opencl.context, (flags), (size), NULL, &status );\
if( status != CL_SUCCESS ) { h->param.b_opencl = 0; x264_log( h, X264_LOG_ERROR, "clCreateBuffer error '%d'\n", status ); return -1; }
#define CREATEIMAGE( out, flags, pf, width, height )\
out = ocl->clCreateImage2D( h->opencl.context, (flags), &pf, width, height, 0, NULL, &status );\
if( status != CL_SUCCESS ) { h->param.b_opencl = 0; x264_log( h, X264_LOG_ERROR, "clCreateImage2D error '%d'\n", status ); return -1; }
int mb_count = h->mb.i_mb_count;
cl_int status;
if( !h->opencl.lowres_mv_costs )
{
/* Allocate shared memory buffers */
int width = h->mb.i_mb_width * 8 * sizeof(pixel);
int height = h->mb.i_mb_height * 8 * sizeof(pixel);
cl_image_format pixel_format;
pixel_format.image_channel_order = CL_R;
pixel_format.image_channel_data_type = CL_UNSIGNED_INT32;
CREATEIMAGE( h->opencl.weighted_luma_hpel, CL_MEM_READ_WRITE, pixel_format, width, height );
for( int i = 0; i < NUM_IMAGE_SCALES; i++ )
{
pixel_format.image_channel_order = CL_RGBA;
pixel_format.image_channel_data_type = CL_UNSIGNED_INT8;
CREATEIMAGE( h->opencl.weighted_scaled_images[i], CL_MEM_READ_WRITE, pixel_format, width, height );
width >>= 1;
height >>= 1;
}
CREATEBUF( h->opencl.lowres_mv_costs, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) );
CREATEBUF( h->opencl.lowres_costs[0], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) );
CREATEBUF( h->opencl.lowres_costs[1], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) );
CREATEBUF( h->opencl.mv_buffers[0], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * 2 );
CREATEBUF( h->opencl.mv_buffers[1], CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * 2 );
CREATEBUF( h->opencl.mvp_buffer, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * 2 );
CREATEBUF( h->opencl.frame_stats[0], CL_MEM_WRITE_ONLY, 4 * sizeof(int) );
CREATEBUF( h->opencl.frame_stats[1], CL_MEM_WRITE_ONLY, 4 * sizeof(int) );
CREATEBUF( h->opencl.row_satds[0], CL_MEM_WRITE_ONLY, h->mb.i_mb_height * sizeof(int) );
CREATEBUF( h->opencl.row_satds[1], CL_MEM_WRITE_ONLY, h->mb.i_mb_height * sizeof(int) );
CREATEBUF( h->opencl.luma_16x16_image[0], CL_MEM_READ_ONLY, luma_length );
CREATEBUF( h->opencl.luma_16x16_image[1], CL_MEM_READ_ONLY, luma_length );
}
if( !fenc->opencl.intra_cost )
{
/* Allocate per-frame buffers */
int width = h->mb.i_mb_width * 8 * sizeof(pixel);
int height = h->mb.i_mb_height * 8 * sizeof(pixel);
cl_image_format pixel_format;
pixel_format.image_channel_order = CL_R;
pixel_format.image_channel_data_type = CL_UNSIGNED_INT32;
CREATEIMAGE( fenc->opencl.luma_hpel, CL_MEM_READ_WRITE, pixel_format, width, height );
for( int i = 0; i < NUM_IMAGE_SCALES; i++ )
{
pixel_format.image_channel_order = CL_RGBA;
pixel_format.image_channel_data_type = CL_UNSIGNED_INT8;
CREATEIMAGE( fenc->opencl.scaled_image2Ds[i], CL_MEM_READ_WRITE, pixel_format, width, height );
width >>= 1;
height >>= 1;
}
CREATEBUF( fenc->opencl.inv_qscale_factor, CL_MEM_READ_ONLY, mb_count * sizeof(int16_t) );
CREATEBUF( fenc->opencl.intra_cost, CL_MEM_WRITE_ONLY, mb_count * sizeof(int16_t) );
CREATEBUF( fenc->opencl.lowres_mvs0, CL_MEM_READ_WRITE, mb_count * 2 * sizeof(int16_t) * (h->param.i_bframe + 1) );
CREATEBUF( fenc->opencl.lowres_mvs1, CL_MEM_READ_WRITE, mb_count * 2 * sizeof(int16_t) * (h->param.i_bframe + 1) );
CREATEBUF( fenc->opencl.lowres_mv_costs0, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * (h->param.i_bframe + 1) );
CREATEBUF( fenc->opencl.lowres_mv_costs1, CL_MEM_READ_WRITE, mb_count * sizeof(int16_t) * (h->param.i_bframe + 1) );
}
#undef CREATEBUF
#undef CREATEIMAGE
/* Copy image to the GPU, downscale to unpadded 8x8, then continue for all scales */
char *locked = x264_opencl_alloc_locked( h, luma_length );
memcpy( locked, fenc->plane[0], luma_length );
OCLCHECK( clEnqueueWriteBuffer, h->opencl.queue, h->opencl.luma_16x16_image[h->opencl.last_buf], CL_FALSE, 0, luma_length, locked, 0, NULL, NULL );
size_t gdim[2];
if( h->param.rc.i_aq_mode && fenc->i_inv_qscale_factor )
{
int size = h->mb.i_mb_count * sizeof(int16_t);
locked = x264_opencl_alloc_locked( h, size );
memcpy( locked, fenc->i_inv_qscale_factor, size );
OCLCHECK( clEnqueueWriteBuffer, h->opencl.queue, fenc->opencl.inv_qscale_factor, CL_FALSE, 0, size, locked, 0, NULL, NULL );
}
else
{
/* Fill fenc->opencl.inv_qscale_factor with NOP (256) */
cl_uint arg = 0;
int16_t value = 256;
OCLCHECK( clSetKernelArg, h->opencl.memset_kernel, arg++, sizeof(cl_mem), &fenc->opencl.inv_qscale_factor );
OCLCHECK( clSetKernelArg, h->opencl.memset_kernel, arg++, sizeof(int16_t), &value );
gdim[0] = h->mb.i_mb_count;
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.memset_kernel, 1, NULL, gdim, NULL, 0, NULL, NULL );
}
int stride = fenc->i_stride[0];
cl_uint arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(cl_mem), &h->opencl.luma_16x16_image[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] );
OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(cl_mem), &fenc->opencl.luma_hpel );
OCLCHECK( clSetKernelArg, h->opencl.downscale_hpel_kernel, arg++, sizeof(int), &stride );
gdim[0] = 8 * h->mb.i_mb_width;
gdim[1] = 8 * h->mb.i_mb_height;
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.downscale_hpel_kernel, 2, NULL, gdim, NULL, 0, NULL, NULL );
for( int i = 0; i < NUM_IMAGE_SCALES - 1; i++ )
{
/* Workaround for AMD Southern Island:
*
* Alternate kernel instances. No perf impact to this, so we do it for
* all GPUs. It prevents the same kernel from being enqueued
* back-to-back, avoiding a dependency calculation bug in the driver.
*/
cl_kernel kern = i & 1 ? h->opencl.downscale_kernel1 : h->opencl.downscale_kernel2;
arg = 0;
OCLCHECK( clSetKernelArg, kern, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[i] );
OCLCHECK( clSetKernelArg, kern, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[i+1] );
gdim[0] >>= 1;
gdim[1] >>= 1;
if( gdim[0] < 16 || gdim[1] < 16 )
break;
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, kern, 2, NULL, gdim, NULL, 0, NULL, NULL );
}
size_t ldim[2];
gdim[0] = ((h->mb.i_mb_width + 31)>>5)<<5;
gdim[1] = 8*h->mb.i_mb_height;
ldim[0] = 32;
ldim[1] = 8;
arg = 0;
/* For presets slow, slower, and placebo, check all 10 intra modes that the
* C lookahead supports. For faster presets, only check the most frequent 8
* modes
*/
int slow = h->param.analyse.i_subpel_refine > 7;
OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] );
OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.intra_cost );
OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(int), &lambda );
OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(int), &h->mb.i_mb_width );
OCLCHECK( clSetKernelArg, h->opencl.intra_kernel, arg++, sizeof(int), &slow );
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.intra_kernel, 2, NULL, gdim, ldim, 0, NULL, NULL );
gdim[0] = 256;
gdim[1] = h->mb.i_mb_height;
ldim[0] = 256;
ldim[1] = 1;
arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.intra_cost );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &fenc->opencl.inv_qscale_factor );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &h->opencl.row_satds[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_intra_kernel, arg++, sizeof(int), &h->mb.i_mb_width );
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.rowsum_intra_kernel, 2, NULL, gdim, ldim, 0, NULL, NULL );
if( h->opencl.num_copies >= MAX_FINISH_COPIES - 4 )
x264_opencl_flush( h );
int size = h->mb.i_mb_count * sizeof(int16_t);
locked = x264_opencl_alloc_locked( h, size );
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, fenc->opencl.intra_cost, CL_FALSE, 0, size, locked, 0, NULL, NULL );
h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_costs[0][0];
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].bytes = size;
h->opencl.num_copies++;
size = h->mb.i_mb_height * sizeof(int);
locked = x264_opencl_alloc_locked( h, size );
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.row_satds[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL );
h->opencl.copies[h->opencl.num_copies].dest = fenc->i_row_satds[0][0];
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].bytes = size;
h->opencl.num_copies++;
size = sizeof(int) * 4;
locked = x264_opencl_alloc_locked( h, size );
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.frame_stats[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL );
h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est[0][0];
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int);
h->opencl.num_copies++;
h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est_aq[0][0];
h->opencl.copies[h->opencl.num_copies].src = locked + sizeof(int);
h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int);
h->opencl.num_copies++;
h->opencl.last_buf = !h->opencl.last_buf;
return 0;
}
/* This function was tested emprically on a number of AMD and NV GPUs. Making a
* function which returns perfect launch dimensions is impossible; some
* applications will have self-tuning code to try many possible variables and
* measure the runtime. Here we simply make an educated guess based on what we
* know GPUs typically prefer. */
static void x264_optimal_launch_dims( x264_t *h, size_t *gdims, size_t *ldims, const cl_kernel kernel, const cl_device_id device )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
size_t max_work_group = 256; /* reasonable defaults for OpenCL 1.0 devices, below APIs may fail */
size_t preferred_multiple = 64;
cl_uint num_cus = 6;
ocl->clGetKernelWorkGroupInfo( kernel, device, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &max_work_group, NULL );
ocl->clGetKernelWorkGroupInfo( kernel, device, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, sizeof(size_t), &preferred_multiple, NULL );
ocl->clGetDeviceInfo( device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &num_cus, NULL );
ldims[0] = preferred_multiple;
ldims[1] = 8;
/* make ldims[1] an even divisor of gdims[1] */
while( gdims[1] & (ldims[1] - 1) )
{
ldims[0] <<= 1;
ldims[1] >>= 1;
}
/* make total ldims fit under the max work-group dimensions for the device */
while( ldims[0] * ldims[1] > max_work_group )
{
if( (ldims[0] <= preferred_multiple) && (ldims[1] > 1) )
ldims[1] >>= 1;
else
ldims[0] >>= 1;
}
if( ldims[0] > gdims[0] )
{
/* remove preferred multiples until we're close to gdims[0] */
while( gdims[0] + preferred_multiple < ldims[0] )
ldims[0] -= preferred_multiple;
gdims[0] = ldims[0];
}
else
{
/* make gdims an even multiple of ldims */
gdims[0] = (gdims[0]+ldims[0]-1)/ldims[0];
gdims[0] *= ldims[0];
}
/* make ldims smaller to spread work across compute units */
while( (gdims[0]/ldims[0]) * (gdims[1]/ldims[1]) * 2 <= num_cus )
{
if( ldims[0] > preferred_multiple )
ldims[0] >>= 1;
else if( ldims[1] > 1 )
ldims[1] >>= 1;
else
break;
}
/* for smaller GPUs, try not to abuse their texture cache */
if( num_cus == 6 && ldims[0] == 64 && ldims[1] == 4 )
ldims[0] = 32;
}
int x264_opencl_motionsearch( x264_t *h, x264_frame_t **frames, int b, int ref, int b_islist1, int lambda, const x264_weight_t *w )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
x264_frame_t *fenc = frames[b];
x264_frame_t *fref = frames[ref];
cl_mem ref_scaled_images[NUM_IMAGE_SCALES];
cl_mem ref_luma_hpel;
cl_int status;
if( w && w->weightfn )
{
size_t gdims[2];
gdims[0] = 8 * h->mb.i_mb_width;
gdims[1] = 8 * h->mb.i_mb_height;
/* WeightP: Perform a filter on fref->opencl.scaled_image2Ds[] and fref->opencl.luma_hpel */
for( int i = 0; i < NUM_IMAGE_SCALES; i++ )
{
cl_uint arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(cl_mem), &fref->opencl.scaled_image2Ds[i] );
OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(cl_mem), &h->opencl.weighted_scaled_images[i] );
OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(int32_t), &w->i_offset );
OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(int32_t), &w->i_scale );
OCLCHECK( clSetKernelArg, h->opencl.weightp_scaled_images_kernel, arg++, sizeof(int32_t), &w->i_denom );
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.weightp_scaled_images_kernel, 2, NULL, gdims, NULL, 0, NULL, NULL );
gdims[0] >>= 1;
gdims[1] >>= 1;
if( gdims[0] < 16 || gdims[1] < 16 )
break;
}
cl_uint arg = 0;
gdims[0] = 8 * h->mb.i_mb_width;
gdims[1] = 8 * h->mb.i_mb_height;
OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(cl_mem), &fref->opencl.luma_hpel );
OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(cl_mem), &h->opencl.weighted_luma_hpel );
OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(int32_t), &w->i_offset );
OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(int32_t), &w->i_scale );
OCLCHECK( clSetKernelArg, h->opencl.weightp_hpel_kernel, arg++, sizeof(int32_t), &w->i_denom );
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.weightp_hpel_kernel, 2, NULL, gdims, NULL, 0, NULL, NULL );
/* Use weighted reference planes for motion search */
for( int i = 0; i < NUM_IMAGE_SCALES; i++ )
ref_scaled_images[i] = h->opencl.weighted_scaled_images[i];
ref_luma_hpel = h->opencl.weighted_luma_hpel;
}
else
{
/* Use unweighted reference planes for motion search */
for( int i = 0; i < NUM_IMAGE_SCALES; i++ )
ref_scaled_images[i] = fref->opencl.scaled_image2Ds[i];
ref_luma_hpel = fref->opencl.luma_hpel;
}
const int num_iterations[NUM_IMAGE_SCALES] = { 1, 1, 2, 3 };
int b_first_iteration = 1;
int b_reverse_references = 1;
int A = 1;
int mb_per_group = 0;
int cost_local_size = 0;
int mvc_local_size = 0;
int mb_width;
size_t gdims[2];
size_t ldims[2];
/* scale 0 is 8x8 */
for( int scale = NUM_IMAGE_SCALES-1; scale >= 0; scale-- )
{
mb_width = h->mb.i_mb_width >> scale;
gdims[0] = mb_width;
gdims[1] = h->mb.i_mb_height >> scale;
if( gdims[0] < 2 || gdims[1] < 2 )
continue;
gdims[0] <<= 2;
x264_optimal_launch_dims( h, gdims, ldims, h->opencl.hme_kernel, h->opencl.device );
mb_per_group = (ldims[0] >> 2) * ldims[1];
cost_local_size = 4 * mb_per_group * sizeof(int16_t);
mvc_local_size = 4 * mb_per_group * sizeof(int16_t) * 2;
int scaled_me_range = h->param.analyse.i_me_range >> scale;
int b_shift_index = 1;
cl_uint arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[scale] );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &ref_scaled_images[scale] );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &h->opencl.mv_buffers[A] );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &h->opencl.mv_buffers[!A] );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_mv_costs );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(cl_mem), (void*)&h->opencl.mvp_buffer );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, cost_local_size, NULL );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, mvc_local_size, NULL );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &mb_width );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &lambda );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &scaled_me_range );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &scale );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &b_shift_index );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &b_first_iteration );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg++, sizeof(int), &b_reverse_references );
for( int iter = 0; iter < num_iterations[scale]; iter++ )
{
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.hme_kernel, 2, NULL, gdims, ldims, 0, NULL, NULL );
b_shift_index = 0;
b_first_iteration = 0;
/* alternate top-left vs bot-right MB references at lower scales, so
* motion field smooths more quickly. */
if( scale > 2 )
b_reverse_references ^= 1;
else
b_reverse_references = 0;
A = !A;
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, 2, sizeof(cl_mem), &h->opencl.mv_buffers[A] );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, 3, sizeof(cl_mem), &h->opencl.mv_buffers[!A] );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg - 3, sizeof(int), &b_shift_index );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg - 2, sizeof(int), &b_first_iteration );
OCLCHECK( clSetKernelArg, h->opencl.hme_kernel, arg - 1, sizeof(int), &b_reverse_references );
}
}
int satd_local_size = mb_per_group * sizeof(uint32_t) * 16;
cl_uint arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &ref_luma_hpel );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &h->opencl.mv_buffers[A] );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_mv_costs );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, cost_local_size, NULL );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, satd_local_size, NULL );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, mvc_local_size, NULL );
if( b_islist1 )
{
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs1 );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs1 );
}
else
{
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs0 );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs0 );
}
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &mb_width );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &lambda );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &b );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &ref );
OCLCHECK( clSetKernelArg, h->opencl.subpel_refine_kernel, arg++, sizeof(int), &b_islist1 );
if( h->opencl.b_device_AMD_SI )
{
/* workaround for AMD Southern Island driver scheduling bug (fixed in
* July 2012), perform meaningless small copy to add a data dependency */
OCLCHECK( clEnqueueCopyBuffer, h->opencl.queue, h->opencl.mv_buffers[A], h->opencl.mv_buffers[!A], 0, 0, 20, 0, NULL, NULL );
}
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.subpel_refine_kernel, 2, NULL, gdims, ldims, 0, NULL, NULL );
int mvlen = 2 * sizeof(int16_t) * h->mb.i_mb_count;
if( h->opencl.num_copies >= MAX_FINISH_COPIES - 1 )
x264_opencl_flush( h );
char *locked = x264_opencl_alloc_locked( h, mvlen );
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].bytes = mvlen;
if( b_islist1 )
{
int mvs_offset = mvlen * (ref - b - 1);
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, fenc->opencl.lowres_mvs1, CL_FALSE, mvs_offset, mvlen, locked, 0, NULL, NULL );
h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_mvs[1][ref - b - 1];
}
else
{
int mvs_offset = mvlen * (b - ref - 1);
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, fenc->opencl.lowres_mvs0, CL_FALSE, mvs_offset, mvlen, locked, 0, NULL, NULL );
h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_mvs[0][b - ref - 1];
}
h->opencl.num_copies++;
return 0;
}
int x264_opencl_finalize_cost( x264_t *h, int lambda, x264_frame_t **frames, int p0, int p1, int b, int dist_scale_factor )
{
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_int status;
x264_frame_t *fenc = frames[b];
x264_frame_t *fref0 = frames[p0];
x264_frame_t *fref1 = frames[p1];
int bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor >> 2) : 32;
/* Tasks for this kernel:
* 1. Select least cost mode (intra, ref0, ref1)
* list_used 0, 1, 2, or 3. if B frame, do not allow intra
* 2. if B frame, try bidir predictions.
* 3. lowres_costs[i_mb_xy] = X264_MIN( bcost, LOWRES_COST_MASK ) + (list_used << LOWRES_COST_SHIFT); */
size_t gdims[2] = { h->mb.i_mb_width, h->mb.i_mb_height };
size_t ldim_bidir[2];
size_t *ldims = NULL;
int cost_local_size = 4;
int satd_local_size = 4;
if( b < p1 )
{
/* For B frames, use 4 threads per MB for BIDIR checks */
ldims = ldim_bidir;
gdims[0] <<= 2;
x264_optimal_launch_dims( h, gdims, ldims, h->opencl.mode_select_kernel, h->opencl.device );
int mb_per_group = (ldims[0] >> 2) * ldims[1];
cost_local_size = 4 * mb_per_group * sizeof(int16_t);
satd_local_size = 16 * mb_per_group * sizeof(uint32_t);
}
cl_uint arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.scaled_image2Ds[0] );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fref0->opencl.luma_hpel );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fref1->opencl.luma_hpel );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs0 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mvs1 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fref1->opencl.lowres_mvs0 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs0 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.lowres_mv_costs1 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &fenc->opencl.intra_cost );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_costs[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, cost_local_size, NULL );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, satd_local_size, NULL );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &h->mb.i_mb_width );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &bipred_weight );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &dist_scale_factor );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &b );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &p0 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &p1 );
OCLCHECK( clSetKernelArg, h->opencl.mode_select_kernel, arg++, sizeof(int), &lambda );
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.mode_select_kernel, 2, NULL, gdims, ldims, 0, NULL, NULL );
/* Sum costs across rows, atomicAdd down frame */
size_t gdim[2] = { 256, h->mb.i_mb_height };
size_t ldim[2] = { 256, 1 };
arg = 0;
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &h->opencl.lowres_costs[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &fenc->opencl.inv_qscale_factor );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &h->opencl.row_satds[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(cl_mem), &h->opencl.frame_stats[h->opencl.last_buf] );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &h->mb.i_mb_width );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &h->param.i_bframe_bias );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &b );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &p0 );
OCLCHECK( clSetKernelArg, h->opencl.rowsum_inter_kernel, arg++, sizeof(int), &p1 );
OCLCHECK( clEnqueueNDRangeKernel, h->opencl.queue, h->opencl.rowsum_inter_kernel, 2, NULL, gdim, ldim, 0, NULL, NULL );
if( h->opencl.num_copies >= MAX_FINISH_COPIES - 4 )
x264_opencl_flush( h );
int size = h->mb.i_mb_count * sizeof(int16_t);
char *locked = x264_opencl_alloc_locked( h, size );
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].dest = fenc->lowres_costs[b - p0][p1 - b];
h->opencl.copies[h->opencl.num_copies].bytes = size;
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.lowres_costs[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL );
h->opencl.num_copies++;
size = h->mb.i_mb_height * sizeof(int);
locked = x264_opencl_alloc_locked( h, size );
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].dest = fenc->i_row_satds[b - p0][p1 - b];
h->opencl.copies[h->opencl.num_copies].bytes = size;
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.row_satds[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL );
h->opencl.num_copies++;
size = 4 * sizeof(int);
locked = x264_opencl_alloc_locked( h, size );
OCLCHECK( clEnqueueReadBuffer, h->opencl.queue, h->opencl.frame_stats[h->opencl.last_buf], CL_FALSE, 0, size, locked, 0, NULL, NULL );
h->opencl.last_buf = !h->opencl.last_buf;
h->opencl.copies[h->opencl.num_copies].src = locked;
h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est[b - p0][p1 - b];
h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int);
h->opencl.num_copies++;
h->opencl.copies[h->opencl.num_copies].src = locked + sizeof(int);
h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_cost_est_aq[b - p0][p1 - b];
h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int);
h->opencl.num_copies++;
if( b == p1 ) // P frames only
{
h->opencl.copies[h->opencl.num_copies].src = locked + 2 * sizeof(int);
h->opencl.copies[h->opencl.num_copies].dest = &fenc->i_intra_mbs[b - p0];
h->opencl.copies[h->opencl.num_copies].bytes = sizeof(int);
h->opencl.num_copies++;
}
return 0;
}
void x264_opencl_slicetype_prep( x264_t *h, x264_frame_t **frames, int num_frames, int lambda )
{
if( h->param.b_opencl )
{
#ifdef _WIN32
/* Temporarily boost priority of this lookahead thread and the OpenCL
* driver's thread until the end of this function. On AMD GPUs this
* greatly reduces the latency of enqueuing kernels and getting results
* on Windows. */
HANDLE id = GetCurrentThread();
h->opencl.lookahead_thread_pri = GetThreadPriority( id );
SetThreadPriority( id, THREAD_PRIORITY_ABOVE_NORMAL );
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_int status = ocl->clGetCommandQueueInfo( h->opencl.queue, CL_QUEUE_THREAD_HANDLE_AMD, sizeof(HANDLE), &id, NULL );
if( status == CL_SUCCESS )
{
h->opencl.opencl_thread_pri = GetThreadPriority( id );
SetThreadPriority( id, THREAD_PRIORITY_ABOVE_NORMAL );
}
#endif
/* precalculate intra and I frames */
for( int i = 0; i <= num_frames; i++ )
x264_opencl_lowres_init( h, frames[i], lambda );
x264_opencl_flush( h );
if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS && h->param.i_bframe )
{
/* For trellis B-Adapt, precompute exhaustive motion searches */
for( int b = 0; b <= num_frames; b++ )
{
for( int j = 1; j < h->param.i_bframe; j++ )
{
int p0 = b - j;
if( p0 >= 0 && frames[b]->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF )
{
const x264_weight_t *w = x264_weight_none;
if( h->param.analyse.i_weighted_pred )
{
x264_emms();
x264_weights_analyse( h, frames[b], frames[p0], 1 );
w = frames[b]->weight[0];
}
frames[b]->lowres_mvs[0][b-p0-1][0][0] = 0;
x264_opencl_motionsearch( h, frames, b, p0, 0, lambda, w );
}
int p1 = b + j;
if( p1 <= num_frames && frames[b]->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF )
{
frames[b]->lowres_mvs[1][p1-b-1][0][0] = 0;
x264_opencl_motionsearch( h, frames, b, p1, 1, lambda, NULL );
}
}
}
x264_opencl_flush( h );
}
}
}
void x264_opencl_slicetype_end( x264_t *h )
{
#ifdef _WIN32
if( h->param.b_opencl )
{
HANDLE id = GetCurrentThread();
SetThreadPriority( id, h->opencl.lookahead_thread_pri );
x264_opencl_function_t *ocl = h->opencl.ocl;
cl_int status = ocl->clGetCommandQueueInfo( h->opencl.queue, CL_QUEUE_THREAD_HANDLE_AMD, sizeof(HANDLE), &id, NULL );
if( status == CL_SUCCESS )
SetThreadPriority( id, h->opencl.opencl_thread_pri );
}
#endif
}
int x264_opencl_precalculate_frame_cost( x264_t *h, x264_frame_t **frames, int lambda, int p0, int p1, int b )
{
if( (frames[b]->i_cost_est[b-p0][p1-b] >= 0) || (b == p0 && b == p1) )
return 0;
else
{
int do_search[2];
int dist_scale_factor = 128;
const x264_weight_t *w = x264_weight_none;
// avoid duplicating work
frames[b]->i_cost_est[b-p0][p1-b] = 0;
do_search[0] = b != p0 && frames[b]->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF;
do_search[1] = b != p1 && frames[b]->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF;
if( do_search[0] )
{
if( h->param.analyse.i_weighted_pred && b == p1 )
{
x264_emms();
x264_weights_analyse( h, frames[b], frames[p0], 1 );
w = frames[b]->weight[0];
}
frames[b]->lowres_mvs[0][b-p0-1][0][0] = 0;
}
if( do_search[1] )
frames[b]->lowres_mvs[1][p1-b-1][0][0] = 0;
if( b == p1 )
frames[b]->i_intra_mbs[b-p0] = 0;
if( p1 != p0 )
dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0);
frames[b]->i_cost_est[b-p0][p1-b] = 0;
frames[b]->i_cost_est_aq[b-p0][p1-b] = 0;
x264_opencl_lowres_init( h, frames[b], lambda );
if( do_search[0] )
{
x264_opencl_lowres_init( h, frames[p0], lambda );
x264_opencl_motionsearch( h, frames, b, p0, 0, lambda, w );
}
if( do_search[1] )
{
x264_opencl_lowres_init( h, frames[p1], lambda );
x264_opencl_motionsearch( h, frames, b, p1, 1, lambda, NULL );
}
x264_opencl_finalize_cost( h, lambda, frames, p0, p1, b, dist_scale_factor );
return 1;
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,964 @@
/*****************************************************************************
* x264.h: x264 public header
*****************************************************************************
* Copyright (C) 2003-2017 x264 project
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Loren Merritt <lorenm@u.washington.edu>
* Fiona Glaser <fiona@x264.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifndef X264_X264_H
#define X264_X264_H
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(_STDINT_H) && !defined(_STDINT_H_) && !defined(_STDINT_H_INCLUDED) && !defined(_STDINT) &&\
!defined(_SYS_STDINT_H_) && !defined(_INTTYPES_H) && !defined(_INTTYPES_H_) && !defined(_INTTYPES)
# ifdef _MSC_VER
# pragma message("You must include stdint.h or inttypes.h before x264.h")
# else
# warning You must include stdint.h or inttypes.h before x264.h
# endif
#endif
#include <stdarg.h>
//#include "x264_config.h"
#define X264_VERSION ""
#define X264_BUILD 152
/* Application developers planning to link against a shared library version of
* libx264 from a Microsoft Visual Studio or similar development environment
* will need to define X264_API_IMPORTS before including this header.
* This clause does not apply to MinGW, similar development environments, or non
* Windows platforms. */
#ifdef X264_API_IMPORTS
#define X264_API __declspec(dllimport)
#else
#define X264_API
#endif
/* x264_t:
* opaque handler for encoder */
typedef struct x264_t x264_t;
/****************************************************************************
* NAL structure and functions
****************************************************************************/
enum nal_unit_type_e
{
NAL_UNKNOWN = 0,
NAL_SLICE = 1,
NAL_SLICE_DPA = 2,
NAL_SLICE_DPB = 3,
NAL_SLICE_DPC = 4,
NAL_SLICE_IDR = 5, /* ref_idc != 0 */
NAL_SEI = 6, /* ref_idc == 0 */
NAL_SPS = 7,
NAL_PPS = 8,
NAL_AUD = 9,
NAL_FILLER = 12,
/* ref_idc == 0 for 6,9,10,11,12 */
};
enum nal_priority_e
{
NAL_PRIORITY_DISPOSABLE = 0,
NAL_PRIORITY_LOW = 1,
NAL_PRIORITY_HIGH = 2,
NAL_PRIORITY_HIGHEST = 3,
};
/* The data within the payload is already NAL-encapsulated; the ref_idc and type
* are merely in the struct for easy access by the calling application.
* All data returned in an x264_nal_t, including the data in p_payload, is no longer
* valid after the next call to x264_encoder_encode. Thus it must be used or copied
* before calling x264_encoder_encode or x264_encoder_headers again. */
typedef struct x264_nal_t
{
int i_ref_idc; /* nal_priority_e */
int i_type; /* nal_unit_type_e */
int b_long_startcode;
int i_first_mb; /* If this NAL is a slice, the index of the first MB in the slice. */
int i_last_mb; /* If this NAL is a slice, the index of the last MB in the slice. */
/* Size of payload (including any padding) in bytes. */
int i_payload;
/* If param->b_annexb is set, Annex-B bytestream with startcode.
* Otherwise, startcode is replaced with a 4-byte size.
* This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */
uint8_t *p_payload;
/* Size of padding in bytes. */
int i_padding;
} x264_nal_t;
/****************************************************************************
* Encoder parameters
****************************************************************************/
/* CPU flags */
/* x86 */
#define X264_CPU_MMX (1<<0)
#define X264_CPU_MMX2 (1<<1) /* MMX2 aka MMXEXT aka ISSE */
#define X264_CPU_MMXEXT X264_CPU_MMX2
#define X264_CPU_SSE (1<<2)
#define X264_CPU_SSE2 (1<<3)
#define X264_CPU_LZCNT (1<<4)
#define X264_CPU_SSE3 (1<<5)
#define X264_CPU_SSSE3 (1<<6)
#define X264_CPU_SSE4 (1<<7) /* SSE4.1 */
#define X264_CPU_SSE42 (1<<8) /* SSE4.2 */
#define X264_CPU_AVX (1<<9) /* Requires OS support even if YMM registers aren't used */
#define X264_CPU_XOP (1<<10) /* AMD XOP */
#define X264_CPU_FMA4 (1<<11) /* AMD FMA4 */
#define X264_CPU_FMA3 (1<<12)
#define X264_CPU_BMI1 (1<<13)
#define X264_CPU_BMI2 (1<<14)
#define X264_CPU_AVX2 (1<<15)
#define X264_CPU_AVX512 (1<<16) /* AVX-512 {F, CD, BW, DQ, VL}, requires OS support */
/* x86 modifiers */
#define X264_CPU_CACHELINE_32 (1<<17) /* avoid memory loads that span the border between two cachelines */
#define X264_CPU_CACHELINE_64 (1<<18) /* 32/64 is the size of a cacheline in bytes */
#define X264_CPU_SSE2_IS_SLOW (1<<19) /* avoid most SSE2 functions on Athlon64 */
#define X264_CPU_SSE2_IS_FAST (1<<20) /* a few functions are only faster on Core2 and Phenom */
#define X264_CPU_SLOW_SHUFFLE (1<<21) /* The Conroe has a slow shuffle unit (relative to overall SSE performance) */
#define X264_CPU_STACK_MOD4 (1<<22) /* if stack is only mod4 and not mod16 */
#define X264_CPU_SLOW_ATOM (1<<23) /* The Atom is terrible: slow SSE unaligned loads, slow
* SIMD multiplies, slow SIMD variable shifts, slow pshufb,
* cacheline split penalties -- gather everything here that
* isn't shared by other CPUs to avoid making half a dozen
* new SLOW flags. */
#define X264_CPU_SLOW_PSHUFB (1<<24) /* such as on the Intel Atom */
#define X264_CPU_SLOW_PALIGNR (1<<25) /* such as on the AMD Bobcat */
/* PowerPC */
#define X264_CPU_ALTIVEC 0x0000001
/* ARM and AArch64 */
#define X264_CPU_ARMV6 0x0000001
#define X264_CPU_NEON 0x0000002 /* ARM NEON */
#define X264_CPU_FAST_NEON_MRC 0x0000004 /* Transfer from NEON to ARM register is fast (Cortex-A9) */
#define X264_CPU_ARMV8 0x0000008
/* MIPS */
#define X264_CPU_MSA 0x0000001 /* MIPS MSA */
/* Analyse flags */
#define X264_ANALYSE_I4x4 0x0001 /* Analyse i4x4 */
#define X264_ANALYSE_I8x8 0x0002 /* Analyse i8x8 (requires 8x8 transform) */
#define X264_ANALYSE_PSUB16x16 0x0010 /* Analyse p16x8, p8x16 and p8x8 */
#define X264_ANALYSE_PSUB8x8 0x0020 /* Analyse p8x4, p4x8, p4x4 */
#define X264_ANALYSE_BSUB16x16 0x0100 /* Analyse b16x8, b8x16 and b8x8 */
#define X264_DIRECT_PRED_NONE 0
#define X264_DIRECT_PRED_SPATIAL 1
#define X264_DIRECT_PRED_TEMPORAL 2
#define X264_DIRECT_PRED_AUTO 3
#define X264_ME_DIA 0
#define X264_ME_HEX 1
#define X264_ME_UMH 2
#define X264_ME_ESA 3
#define X264_ME_TESA 4
#define X264_CQM_FLAT 0
#define X264_CQM_JVT 1
#define X264_CQM_CUSTOM 2
#define X264_RC_CQP 0
#define X264_RC_CRF 1
#define X264_RC_ABR 2
#define X264_QP_AUTO 0
#define X264_AQ_NONE 0
#define X264_AQ_VARIANCE 1
#define X264_AQ_AUTOVARIANCE 2
#define X264_AQ_AUTOVARIANCE_BIASED 3
#define X264_B_ADAPT_NONE 0
#define X264_B_ADAPT_FAST 1
#define X264_B_ADAPT_TRELLIS 2
#define X264_WEIGHTP_NONE 0
#define X264_WEIGHTP_SIMPLE 1
#define X264_WEIGHTP_SMART 2
#define X264_B_PYRAMID_NONE 0
#define X264_B_PYRAMID_STRICT 1
#define X264_B_PYRAMID_NORMAL 2
#define X264_KEYINT_MIN_AUTO 0
#define X264_KEYINT_MAX_INFINITE (1<<30)
static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 };
static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 };
static const char * const x264_b_pyramid_names[] = { "none", "strict", "normal", 0 };
static const char * const x264_overscan_names[] = { "undef", "show", "crop", 0 };
static const char * const x264_vidformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", 0 };
static const char * const x264_fullrange_names[] = { "off", "on", 0 };
static const char * const x264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020", "smpte428",
"smpte431", "smpte432", 0 };
static const char * const x264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316",
"iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", "smpte2084", "smpte428", 0 };
static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c",
"smpte2085", 0 };
static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 };
/* Colorspace type */
#define X264_CSP_MASK 0x00ff /* */
#define X264_CSP_NONE 0x0000 /* Invalid mode */
#define X264_CSP_I420 0x0001 /* yuv 4:2:0 planar */
#define X264_CSP_YV12 0x0002 /* yvu 4:2:0 planar */
#define X264_CSP_NV12 0x0003 /* yuv 4:2:0, with one y plane and one packed u+v */
#define X264_CSP_NV21 0x0004 /* yuv 4:2:0, with one y plane and one packed v+u */
#define X264_CSP_I422 0x0005 /* yuv 4:2:2 planar */
#define X264_CSP_YV16 0x0006 /* yvu 4:2:2 planar */
#define X264_CSP_NV16 0x0007 /* yuv 4:2:2, with one y plane and one packed u+v */
#define X264_CSP_YUYV 0x0008 /* yuyv 4:2:2 packed */
#define X264_CSP_UYVY 0x0009 /* uyvy 4:2:2 packed */
#define X264_CSP_V210 0x000a /* 10-bit yuv 4:2:2 packed in 32 */
#define X264_CSP_I444 0x000b /* yuv 4:4:4 planar */
#define X264_CSP_YV24 0x000c /* yvu 4:4:4 planar */
#define X264_CSP_BGR 0x000d /* packed bgr 24bits */
#define X264_CSP_BGRA 0x000e /* packed bgr 32bits */
#define X264_CSP_RGB 0x000f /* packed rgb 24bits */
#define X264_CSP_MAX 0x0010 /* end of list */
#define X264_CSP_VFLIP 0x1000 /* the csp is vertically flipped */
#define X264_CSP_HIGH_DEPTH 0x2000 /* the csp has a depth of 16 bits per pixel component */
/* Slice type */
#define X264_TYPE_AUTO 0x0000 /* Let x264 choose the right type */
#define X264_TYPE_IDR 0x0001
#define X264_TYPE_I 0x0002
#define X264_TYPE_P 0x0003
#define X264_TYPE_BREF 0x0004 /* Non-disposable B-frame */
#define X264_TYPE_B 0x0005
#define X264_TYPE_KEYFRAME 0x0006 /* IDR or I depending on b_open_gop option */
#define IS_X264_TYPE_I(x) ((x)==X264_TYPE_I || (x)==X264_TYPE_IDR || (x)==X264_TYPE_KEYFRAME)
#define IS_X264_TYPE_B(x) ((x)==X264_TYPE_B || (x)==X264_TYPE_BREF)
/* Log level */
#define X264_LOG_NONE (-1)
#define X264_LOG_ERROR 0
#define X264_LOG_WARNING 1
#define X264_LOG_INFO 2
#define X264_LOG_DEBUG 3
/* Threading */
#define X264_THREADS_AUTO 0 /* Automatically select optimal number of threads */
#define X264_SYNC_LOOKAHEAD_AUTO (-1) /* Automatically select optimal lookahead thread buffer size */
/* HRD */
#define X264_NAL_HRD_NONE 0
#define X264_NAL_HRD_VBR 1
#define X264_NAL_HRD_CBR 2
/* Zones: override ratecontrol or other options for specific sections of the video.
* See x264_encoder_reconfig() for which options can be changed.
* If zones overlap, whichever comes later in the list takes precedence. */
typedef struct x264_zone_t
{
int i_start, i_end; /* range of frame numbers */
int b_force_qp; /* whether to use qp vs bitrate factor */
int i_qp;
float f_bitrate_factor;
struct x264_param_t *param;
} x264_zone_t;
typedef struct x264_param_t
{
/* CPU flags */
unsigned int cpu;
int i_threads; /* encode multiple frames in parallel */
int i_lookahead_threads; /* multiple threads for lookahead analysis */
int b_sliced_threads; /* Whether to use slice-based threading. */
int b_deterministic; /* whether to allow non-deterministic optimizations when threaded */
int b_cpu_independent; /* force canonical behavior rather than cpu-dependent optimal algorithms */
int i_sync_lookahead; /* threaded lookahead buffer */
/* Video Properties */
int i_width;
int i_height;
int i_csp; /* CSP of encoded bitstream */
int i_level_idc;
int i_frame_total; /* number of frames to encode if known, else 0 */
/* NAL HRD
* Uses Buffering and Picture Timing SEIs to signal HRD
* The HRD in H.264 was not designed with VFR in mind.
* It is therefore not recommendeded to use NAL HRD with VFR.
* Furthermore, reconfiguring the VBV (via x264_encoder_reconfig)
* will currently generate invalid HRD. */
int i_nal_hrd;
struct
{
/* they will be reduced to be 0 < x <= 65535 and prime */
int i_sar_height;
int i_sar_width;
int i_overscan; /* 0=undef, 1=no overscan, 2=overscan */
/* see h264 annex E for the values of the following */
int i_vidformat;
int b_fullrange;
int i_colorprim;
int i_transfer;
int i_colmatrix;
int i_chroma_loc; /* both top & bottom */
} vui;
/* Bitstream parameters */
int i_frame_reference; /* Maximum number of reference frames */
int i_dpb_size; /* Force a DPB size larger than that implied by B-frames and reference frames.
* Useful in combination with interactive error resilience. */
int i_keyint_max; /* Force an IDR keyframe at this interval */
int i_keyint_min; /* Scenecuts closer together than this are coded as I, not IDR. */
int i_scenecut_threshold; /* how aggressively to insert extra I frames */
int b_intra_refresh; /* Whether or not to use periodic intra refresh instead of IDR frames. */
int i_bframe; /* how many b-frame between 2 references pictures */
int i_bframe_adaptive;
int i_bframe_bias;
int i_bframe_pyramid; /* Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal */
int b_open_gop;
int b_bluray_compat;
int i_avcintra_class;
int b_deblocking_filter;
int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */
int i_deblocking_filter_beta; /* [-6, 6] idem */
int b_cabac;
int i_cabac_init_idc;
int b_interlaced;
int b_constrained_intra;
int i_cqm_preset;
char *psz_cqm_file; /* filename (in UTF-8) of CQM file, JM format */
uint8_t cqm_4iy[16]; /* used only if i_cqm_preset == X264_CQM_CUSTOM */
uint8_t cqm_4py[16];
uint8_t cqm_4ic[16];
uint8_t cqm_4pc[16];
uint8_t cqm_8iy[64];
uint8_t cqm_8py[64];
uint8_t cqm_8ic[64];
uint8_t cqm_8pc[64];
/* Log */
void (*pf_log)( void *, int i_level, const char *psz, va_list );
void *p_log_private;
int i_log_level;
int b_full_recon; /* fully reconstruct frames, even when not necessary for encoding. Implied by psz_dump_yuv */
char *psz_dump_yuv; /* filename (in UTF-8) for reconstructed frames */
/* Encoder analyser parameters */
struct
{
unsigned int intra; /* intra partitions */
unsigned int inter; /* inter partitions */
int b_transform_8x8;
int i_weighted_pred; /* weighting for P-frames */
int b_weighted_bipred; /* implicit weighting for B-frames */
int i_direct_mv_pred; /* spatial vs temporal mv prediction */
int i_chroma_qp_offset;
int i_me_method; /* motion estimation algorithm to use (X264_ME_*) */
int i_me_range; /* integer pixel motion estimation search range (from predicted mv) */
int i_mv_range; /* maximum length of a mv (in pixels). -1 = auto, based on level */
int i_mv_range_thread; /* minimum space between threads. -1 = auto, based on number of threads. */
int i_subpel_refine; /* subpixel motion estimation quality */
int b_chroma_me; /* chroma ME for subpel and mode decision in P-frames */
int b_mixed_references; /* allow each mb partition to have its own reference number */
int i_trellis; /* trellis RD quantization */
int b_fast_pskip; /* early SKIP detection on P-frames */
int b_dct_decimate; /* transform coefficient thresholding on P-frames */
int i_noise_reduction; /* adaptive pseudo-deadzone */
float f_psy_rd; /* Psy RD strength */
float f_psy_trellis; /* Psy trellis strength */
int b_psy; /* Toggle all psy optimizations */
int b_mb_info; /* Use input mb_info data in x264_picture_t */
int b_mb_info_update; /* Update the values in mb_info according to the results of encoding. */
/* the deadzone size that will be used in luma quantization */
int i_luma_deadzone[2]; /* {inter, intra} */
int b_psnr; /* compute and print PSNR stats */
int b_ssim; /* compute and print SSIM stats */
} analyse;
/* Rate control parameters */
struct
{
int i_rc_method; /* X264_RC_* */
int i_qp_constant; /* 0 to (51 + 6*(x264_bit_depth-8)). 0=lossless */
int i_qp_min; /* min allowed QP value */
int i_qp_max; /* max allowed QP value */
int i_qp_step; /* max QP step between frames */
int i_bitrate;
float f_rf_constant; /* 1pass VBR, nominal QP */
float f_rf_constant_max; /* In CRF mode, maximum CRF as caused by VBV */
float f_rate_tolerance;
int i_vbv_max_bitrate;
int i_vbv_buffer_size;
float f_vbv_buffer_init; /* <=1: fraction of buffer_size. >1: kbit */
float f_ip_factor;
float f_pb_factor;
/* VBV filler: force CBR VBV and use filler bytes to ensure hard-CBR.
* Implied by NAL-HRD CBR. */
int b_filler;
int i_aq_mode; /* psy adaptive QP. (X264_AQ_*) */
float f_aq_strength;
int b_mb_tree; /* Macroblock-tree ratecontrol. */
int i_lookahead;
/* 2pass */
int b_stat_write; /* Enable stat writing in psz_stat_out */
char *psz_stat_out; /* output filename (in UTF-8) of the 2pass stats file */
int b_stat_read; /* Read stat from psz_stat_in and use it */
char *psz_stat_in; /* input filename (in UTF-8) of the 2pass stats file */
/* 2pass params (same as ffmpeg ones) */
float f_qcompress; /* 0.0 => cbr, 1.0 => constant qp */
float f_qblur; /* temporally blur quants */
float f_complexity_blur; /* temporally blur complexity */
x264_zone_t *zones; /* ratecontrol overrides */
int i_zones; /* number of zone_t's */
char *psz_zones; /* alternate method of specifying zones */
} rc;
/* Cropping Rectangle parameters: added to those implicitly defined by
non-mod16 video resolutions. */
struct
{
unsigned int i_left;
unsigned int i_top;
unsigned int i_right;
unsigned int i_bottom;
} crop_rect;
/* frame packing arrangement flag */
int i_frame_packing;
/* Muxing parameters */
int b_aud; /* generate access unit delimiters */
int b_repeat_headers; /* put SPS/PPS before each keyframe */
int b_annexb; /* if set, place start codes (4 bytes) before NAL units,
* otherwise place size (4 bytes) before NAL units. */
int i_sps_id; /* SPS and PPS id number */
int b_vfr_input; /* VFR input. If 1, use timebase and timestamps for ratecontrol purposes.
* If 0, use fps only. */
int b_pulldown; /* use explicity set timebase for CFR */
uint32_t i_fps_num;
uint32_t i_fps_den;
uint32_t i_timebase_num; /* Timebase numerator */
uint32_t i_timebase_den; /* Timebase denominator */
int b_tff;
/* Pulldown:
* The correct pic_struct must be passed with each input frame.
* The input timebase should be the timebase corresponding to the output framerate. This should be constant.
* e.g. for 3:2 pulldown timebase should be 1001/30000
* The PTS passed with each frame must be the PTS of the frame after pulldown is applied.
* Frame doubling and tripling require b_vfr_input set to zero (see H.264 Table D-1)
*
* Pulldown changes are not clearly defined in H.264. Therefore, it is the calling app's responsibility to manage this.
*/
int b_pic_struct;
/* Fake Interlaced.
*
* Used only when b_interlaced=0. Setting this flag makes it possible to flag the stream as PAFF interlaced yet
* encode all frames progessively. It is useful for encoding 25p and 30p Blu-Ray streams.
*/
int b_fake_interlaced;
/* Don't optimize header parameters based on video content, e.g. ensure that splitting an input video, compressing
* each part, and stitching them back together will result in identical SPS/PPS. This is necessary for stitching
* with container formats that don't allow multiple SPS/PPS. */
int b_stitchable;
int b_opencl; /* use OpenCL when available */
int i_opencl_device; /* specify count of GPU devices to skip, for CLI users */
void *opencl_device_id; /* pass explicit cl_device_id as void*, for API users */
char *psz_clbin_file; /* filename (in UTF-8) of the compiled OpenCL kernel cache file */
/* Slicing parameters */
int i_slice_max_size; /* Max size per slice in bytes; includes estimated NAL overhead. */
int i_slice_max_mbs; /* Max number of MBs per slice; overrides i_slice_count. */
int i_slice_min_mbs; /* Min number of MBs per slice */
int i_slice_count; /* Number of slices per frame: forces rectangular slices. */
int i_slice_count_max; /* Absolute cap on slices per frame; stops applying slice-max-size
* and slice-max-mbs if this is reached. */
/* Optional callback for freeing this x264_param_t when it is done being used.
* Only used when the x264_param_t sits in memory for an indefinite period of time,
* i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones.
* Not used when x264_encoder_reconfig is called directly. */
void (*param_free)( void* );
/* Optional low-level callback for low-latency encoding. Called for each output NAL unit
* immediately after the NAL unit is finished encoding. This allows the calling application
* to begin processing video data (e.g. by sending packets over a network) before the frame
* is done encoding.
*
* This callback MUST do the following in order to work correctly:
* 1) Have available an output buffer of at least size nal->i_payload*3/2 + 5 + 64.
* 2) Call x264_nal_encode( h, dst, nal ), where dst is the output buffer.
* After these steps, the content of nal is valid and can be used in the same way as if
* the NAL unit were output by x264_encoder_encode.
*
* This does not need to be synchronous with the encoding process: the data pointed to
* by nal (both before and after x264_nal_encode) will remain valid until the next
* x264_encoder_encode call. The callback must be re-entrant.
*
* This callback does not work with frame-based threads; threads must be disabled
* or sliced-threads enabled. This callback also does not work as one would expect
* with HRD -- since the buffering period SEI cannot be calculated until the frame
* is finished encoding, it will not be sent via this callback.
*
* Note also that the NALs are not necessarily returned in order when sliced threads is
* enabled. Accordingly, the variable i_first_mb and i_last_mb are available in
* x264_nal_t to help the calling application reorder the slices if necessary.
*
* When this callback is enabled, x264_encoder_encode does not return valid NALs;
* the calling application is expected to acquire all output NALs through the callback.
*
* It is generally sensible to combine this callback with a use of slice-max-mbs or
* slice-max-size.
*
* The opaque pointer is the opaque pointer from the input frame associated with this
* NAL unit. This helps distinguish between nalu_process calls from different sources,
* e.g. if doing multiple encodes in one process.
*/
void (*nalu_process)( x264_t *h, x264_nal_t *nal, void *opaque );
} x264_param_t;
void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal );
/****************************************************************************
* H.264 level restriction information
****************************************************************************/
typedef struct x264_level_t
{
uint8_t level_idc;
uint32_t mbps; /* max macroblock processing rate (macroblocks/sec) */
uint32_t frame_size; /* max frame size (macroblocks) */
uint32_t dpb; /* max decoded picture buffer (mbs) */
uint32_t bitrate; /* max bitrate (kbit/sec) */
uint32_t cpb; /* max vbv buffer (kbit) */
uint16_t mv_range; /* max vertical mv component range (pixels) */
uint8_t mvs_per_2mb; /* max mvs per 2 consecutive mbs. */
uint8_t slice_rate; /* ?? */
uint8_t mincr; /* min compression ratio */
uint8_t bipred8x8; /* limit bipred to >=8x8 */
uint8_t direct8x8; /* limit b_direct to >=8x8 */
uint8_t frame_only; /* forbid interlacing */
} x264_level_t;
/* all of the levels defined in the standard, terminated by .level_idc=0 */
X264_API extern const x264_level_t x264_levels[];
/****************************************************************************
* Basic parameter handling functions
****************************************************************************/
/* x264_param_default:
* fill x264_param_t with default values and do CPU detection */
void x264_param_default( x264_param_t * );
/* x264_param_parse:
* set one parameter by name.
* returns 0 on success, or returns one of the following errors.
* note: BAD_VALUE occurs only if it can't even parse the value,
* numerical range is not checked until x264_encoder_open() or
* x264_encoder_reconfig().
* value=NULL means "true" for boolean options, but is a BAD_VALUE for non-booleans. */
#define X264_PARAM_BAD_NAME (-1)
#define X264_PARAM_BAD_VALUE (-2)
int x264_param_parse( x264_param_t *, const char *name, const char *value );
/****************************************************************************
* Advanced parameter handling functions
****************************************************************************/
/* These functions expose the full power of x264's preset-tune-profile system for
* easy adjustment of large numbers of internal parameters.
*
* In order to replicate x264CLI's option handling, these functions MUST be called
* in the following order:
* 1) x264_param_default_preset
* 2) Custom user options (via param_parse or directly assigned variables)
* 3) x264_param_apply_fastfirstpass
* 4) x264_param_apply_profile
*
* Additionally, x264CLI does not apply step 3 if the preset chosen is "placebo"
* or --slow-firstpass is set. */
/* x264_param_default_preset:
* The same as x264_param_default, but also use the passed preset and tune
* to modify the default settings.
* (either can be NULL, which implies no preset or no tune, respectively)
*
* Currently available presets are, ordered from fastest to slowest: */
static const char * const x264_preset_names[] = { "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo", 0 };
/* The presets can also be indexed numerically, as in:
* x264_param_default_preset( &param, "3", ... )
* with ultrafast mapping to "0" and placebo mapping to "9". This mapping may
* of course change if new presets are added in between, but will always be
* ordered from fastest to slowest.
*
* Warning: the speed of these presets scales dramatically. Ultrafast is a full
* 100 times faster than placebo!
*
* Currently available tunings are: */
static const char * const x264_tune_names[] = { "film", "animation", "grain", "stillimage", "psnr", "ssim", "fastdecode", "zerolatency", 0 };
/* Multiple tunings can be used if separated by a delimiter in ",./-+",
* however multiple psy tunings cannot be used.
* film, animation, grain, stillimage, psnr, and ssim are psy tunings.
*
* returns 0 on success, negative on failure (e.g. invalid preset/tune name). */
int x264_param_default_preset( x264_param_t *, const char *preset, const char *tune );
/* x264_param_apply_fastfirstpass:
* If first-pass mode is set (rc.b_stat_read == 0, rc.b_stat_write == 1),
* modify the encoder settings to disable options generally not useful on
* the first pass. */
void x264_param_apply_fastfirstpass( x264_param_t * );
/* x264_param_apply_profile:
* Applies the restrictions of the given profile.
* Currently available profiles are, from most to least restrictive: */
static const char * const x264_profile_names[] = { "baseline", "main", "high", "high10", "high422", "high444", 0 };
/* (can be NULL, in which case the function will do nothing)
*
* Does NOT guarantee that the given profile will be used: if the restrictions
* of "High" are applied to settings that are already Baseline-compatible, the
* stream will remain baseline. In short, it does not increase settings, only
* decrease them.
*
* returns 0 on success, negative on failure (e.g. invalid profile name). */
int x264_param_apply_profile( x264_param_t *, const char *profile );
/****************************************************************************
* Picture structures and functions
****************************************************************************/
/* x264_bit_depth:
* Specifies the number of bits per pixel that x264 uses. This is also the
* bit depth that x264 encodes in. If this value is > 8, x264 will read
* two bytes of input data for each pixel sample, and expect the upper
* (16-x264_bit_depth) bits to be zero.
* Note: The flag X264_CSP_HIGH_DEPTH must be used to specify the
* colorspace depth as well. */
X264_API extern const int x264_bit_depth;
/* x264_chroma_format:
* Specifies the chroma formats that x264 supports encoding. When this
* value is non-zero, then it represents a X264_CSP_* that is the only
* chroma format that x264 supports encoding. If the value is 0 then
* there are no restrictions. */
X264_API extern const int x264_chroma_format;
enum pic_struct_e
{
PIC_STRUCT_AUTO = 0, // automatically decide (default)
PIC_STRUCT_PROGRESSIVE = 1, // progressive frame
// "TOP" and "BOTTOM" are not supported in x264 (PAFF only)
PIC_STRUCT_TOP_BOTTOM = 4, // top field followed by bottom
PIC_STRUCT_BOTTOM_TOP = 5, // bottom field followed by top
PIC_STRUCT_TOP_BOTTOM_TOP = 6, // top field, bottom field, top field repeated
PIC_STRUCT_BOTTOM_TOP_BOTTOM = 7, // bottom field, top field, bottom field repeated
PIC_STRUCT_DOUBLE = 8, // double frame
PIC_STRUCT_TRIPLE = 9, // triple frame
};
typedef struct x264_hrd_t
{
double cpb_initial_arrival_time;
double cpb_final_arrival_time;
double cpb_removal_time;
double dpb_output_time;
} x264_hrd_t;
/* Arbitrary user SEI:
* Payload size is in bytes and the payload pointer must be valid.
* Payload types and syntax can be found in Annex D of the H.264 Specification.
* SEI payload alignment bits as described in Annex D must be included at the
* end of the payload if needed.
* The payload should not be NAL-encapsulated.
* Payloads are written first in order of input, apart from in the case when HRD
* is enabled where payloads are written after the Buffering Period SEI. */
typedef struct x264_sei_payload_t
{
int payload_size;
int payload_type;
uint8_t *payload;
} x264_sei_payload_t;
typedef struct x264_sei_t
{
int num_payloads;
x264_sei_payload_t *payloads;
/* In: optional callback to free each payload AND x264_sei_payload_t when used. */
void (*sei_free)( void* );
} x264_sei_t;
typedef struct x264_image_t
{
int i_csp; /* Colorspace */
int i_plane; /* Number of image planes */
int i_stride[4]; /* Strides for each plane */
uint8_t *plane[4]; /* Pointers to each plane */
} x264_image_t;
typedef struct x264_image_properties_t
{
/* All arrays of data here are ordered as follows:
* each array contains one offset per macroblock, in raster scan order. In interlaced
* mode, top-field MBs and bottom-field MBs are interleaved at the row level.
* Macroblocks are 16x16 blocks of pixels (with respect to the luma plane). For the
* purposes of calculating the number of macroblocks, width and height are rounded up to
* the nearest 16. If in interlaced mode, height is rounded up to the nearest 32 instead. */
/* In: an array of quantizer offsets to be applied to this image during encoding.
* These are added on top of the decisions made by x264.
* Offsets can be fractional; they are added before QPs are rounded to integer.
* Adaptive quantization must be enabled to use this feature. Behavior if quant
* offsets differ between encoding passes is undefined. */
float *quant_offsets;
/* In: optional callback to free quant_offsets when used.
* Useful if one wants to use a different quant_offset array for each frame. */
void (*quant_offsets_free)( void* );
/* In: optional array of flags for each macroblock.
* Allows specifying additional information for the encoder such as which macroblocks
* remain unchanged. Usable flags are listed below.
* x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track
* extra data internally to make full use of this information.
*
* Out: if b_mb_info_update is set, x264 will update this array as a result of encoding.
*
* For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded
* pixels have changed. This can be useful for e.g. noting which areas of the
* frame need to actually be blitted. Note: this intentionally ignores the effects
* of deblocking for the current frame, which should be fine unless one needs exact
* pixel-perfect accuracy.
*
* Results for MBINFO_CONSTANT are currently only set for P-frames, and are not
* guaranteed to enumerate all blocks which haven't changed. (There may be false
* negatives, but no false positives.)
*/
uint8_t *mb_info;
/* In: optional callback to free mb_info when used. */
void (*mb_info_free)( void* );
/* The macroblock is constant and remains unchanged from the previous frame. */
#define X264_MBINFO_CONSTANT (1<<0)
/* More flags may be added in the future. */
/* Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set) */
double f_ssim;
/* Out: Average PSNR of the frame (if x264_param_t.b_psnr is set) */
double f_psnr_avg;
/* Out: PSNR of Y, U, and V (if x264_param_t.b_psnr is set) */
double f_psnr[3];
/* Out: Average effective CRF of the encoded frame */
double f_crf_avg;
} x264_image_properties_t;
typedef struct x264_picture_t
{
/* In: force picture type (if not auto)
* If x264 encoding parameters are violated in the forcing of picture types,
* x264 will correct the input picture type and log a warning.
* Out: type of the picture encoded */
int i_type;
/* In: force quantizer for != X264_QP_AUTO */
int i_qpplus1;
/* In: pic_struct, for pulldown/doubling/etc...used only if b_pic_struct=1.
* use pic_struct_e for pic_struct inputs
* Out: pic_struct element associated with frame */
int i_pic_struct;
/* Out: whether this frame is a keyframe. Important when using modes that result in
* SEI recovery points being used instead of IDR frames. */
int b_keyframe;
/* In: user pts, Out: pts of encoded picture (user)*/
int64_t i_pts;
/* Out: frame dts. When the pts of the first frame is close to zero,
* initial frames may have a negative dts which must be dealt with by any muxer */
int64_t i_dts;
/* In: custom encoding parameters to be set from this frame forwards
(in coded order, not display order). If NULL, continue using
parameters from the previous frame. Some parameters, such as
aspect ratio, can only be changed per-GOP due to the limitations
of H.264 itself; in this case, the caller must force an IDR frame
if it needs the changed parameter to apply immediately. */
x264_param_t *param;
/* In: raw image data */
/* Out: reconstructed image data. x264 may skip part of the reconstruction process,
e.g. deblocking, in frames where it isn't necessary. To force complete
reconstruction, at a small speed cost, set b_full_recon. */
x264_image_t img;
/* In: optional information to modify encoder decisions for this frame
* Out: information about the encoded frame */
x264_image_properties_t prop;
/* Out: HRD timing information. Output only when i_nal_hrd is set. */
x264_hrd_t hrd_timing;
/* In: arbitrary user SEI (e.g subtitles, AFDs) */
x264_sei_t extra_sei;
/* private user data. copied from input to output frames. */
void *opaque;
} x264_picture_t;
/* x264_picture_init:
* initialize an x264_picture_t. Needs to be done if the calling application
* allocates its own x264_picture_t as opposed to using x264_picture_alloc. */
void x264_picture_init( x264_picture_t *pic );
/* x264_picture_alloc:
* alloc data for a picture. You must call x264_picture_clean on it.
* returns 0 on success, or -1 on malloc failure or invalid colorspace. */
int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height );
/* x264_picture_clean:
* free associated resource for a x264_picture_t allocated with
* x264_picture_alloc ONLY */
void x264_picture_clean( x264_picture_t *pic );
/****************************************************************************
* Encoder functions
****************************************************************************/
/* Force a link error in the case of linking against an incompatible API version.
* Glue #defines exist to force correct macro expansion; the final output of the macro
* is x264_encoder_open_##X264_BUILD (for purposes of dlopen). */
#define x264_encoder_glue1(x,y) x##y
#define x264_encoder_glue2(x,y) x264_encoder_glue1(x,y)
#define x264_encoder_open x264_encoder_glue2(x264_encoder_open_,X264_BUILD)
/* x264_encoder_open:
* create a new encoder handler, all parameters from x264_param_t are copied */
x264_t *x264_encoder_open( x264_param_t * );
/* x264_encoder_reconfig:
* various parameters from x264_param_t are copied.
* this takes effect immediately, on whichever frame is encoded next;
* due to delay, this may not be the next frame passed to encoder_encode.
* if the change should apply to some particular frame, use x264_picture_t->param instead.
* returns 0 on success, negative on parameter validation error.
* not all parameters can be changed; see the actual function for a detailed breakdown.
*
* since not all parameters can be changed, moving from preset to preset may not always
* fully copy all relevant parameters, but should still work usably in practice. however,
* more so than for other presets, many of the speed shortcuts used in ultrafast cannot be
* switched out of; using reconfig to switch between ultrafast and other presets is not
* recommended without a more fine-grained breakdown of parameters to take this into account. */
int x264_encoder_reconfig( x264_t *, x264_param_t * );
/* x264_encoder_parameters:
* copies the current internal set of parameters to the pointer provided
* by the caller. useful when the calling application needs to know
* how x264_encoder_open has changed the parameters, or the current state
* of the encoder after multiple x264_encoder_reconfig calls.
* note that the data accessible through pointers in the returned param struct
* (e.g. filenames) should not be modified by the calling application. */
void x264_encoder_parameters( x264_t *, x264_param_t * );
/* x264_encoder_headers:
* return the SPS and PPS that will be used for the whole stream.
* *pi_nal is the number of NAL units outputted in pp_nal.
* returns the number of bytes in the returned NALs.
* returns negative on error.
* the payloads of all output NALs are guaranteed to be sequential in memory. */
int x264_encoder_headers( x264_t *, x264_nal_t **pp_nal, int *pi_nal );
/* x264_encoder_encode:
* encode one picture.
* *pi_nal is the number of NAL units outputted in pp_nal.
* returns the number of bytes in the returned NALs.
* returns negative on error and zero if no NAL units returned.
* the payloads of all output NALs are guaranteed to be sequential in memory. */
int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out );
/* x264_encoder_close:
* close an encoder handler */
void x264_encoder_close( x264_t * );
/* x264_encoder_delayed_frames:
* return the number of currently delayed (buffered) frames
* this should be used at the end of the stream, to know when you have all the encoded frames. */
int x264_encoder_delayed_frames( x264_t * );
/* x264_encoder_maximum_delayed_frames( x264_t *h ):
* return the maximum number of delayed (buffered) frames that can occur with the current
* parameters. */
int x264_encoder_maximum_delayed_frames( x264_t *h );
/* x264_encoder_intra_refresh:
* If an intra refresh is not in progress, begin one with the next P-frame.
* If an intra refresh is in progress, begin one as soon as the current one finishes.
* Requires that b_intra_refresh be set.
*
* Useful for interactive streaming where the client can tell the server that packet loss has
* occurred. In this case, keyint can be set to an extremely high value so that intra refreshes
* only occur when calling x264_encoder_intra_refresh.
*
* In multi-pass encoding, if x264_encoder_intra_refresh is called differently in each pass,
* behavior is undefined.
*
* Should not be called during an x264_encoder_encode. */
void x264_encoder_intra_refresh( x264_t * );
/* x264_encoder_invalidate_reference:
* An interactive error resilience tool, designed for use in a low-latency one-encoder-few-clients
* system. When the client has packet loss or otherwise incorrectly decodes a frame, the encoder
* can be told with this command to "forget" the frame and all frames that depend on it, referencing
* only frames that occurred before the loss. This will force a keyframe if no frames are left to
* reference after the aforementioned "forgetting".
*
* It is strongly recommended to use a large i_dpb_size in this case, which allows the encoder to
* keep around extra, older frames to fall back on in case more recent frames are all invalidated.
* Unlike increasing i_frame_reference, this does not increase the number of frames used for motion
* estimation and thus has no speed impact. It is also recommended to set a very large keyframe
* interval, so that keyframes are not used except as necessary for error recovery.
*
* x264_encoder_invalidate_reference is not currently compatible with the use of B-frames or intra
* refresh.
*
* In multi-pass encoding, if x264_encoder_invalidate_reference is called differently in each pass,
* behavior is undefined.
*
* Should not be called during an x264_encoder_encode, but multiple calls can be made simultaneously.
*
* Returns 0 on success, negative on failure. */
int x264_encoder_invalidate_reference( x264_t *, int64_t pts );
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,959 @@
// Package x264c implements cgo bindings for [x264](https://www.videolan.org/developers/x264.html) library.
package x264c
/*
#include "stdint.h"
#include "x264.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"
// Constants.
const (
// CPU flags.
CpuMmx = (1 << 0)
// MMX2 aka MMXEXT aka ISSE.
CpuMmx2 = (1 << 1)
CpuMmxext = CpuMmx2
CpuSse = (1 << 2)
CpuSse2 = (1 << 3)
CpuLzcnt = (1 << 4)
CpuSse3 = (1 << 5)
CpuSsse3 = (1 << 6)
// SSE4.1
CpuSse4 = (1 << 7)
// SSE4.2
CpuSse42 = (1 << 8)
// Requires OS support even if YMM registers aren't used.
CpuAvx = (1 << 9)
// AMD XOP.
CpuXop = (1 << 10)
// AMD FMA4.
CpuFma4 = (1 << 11)
CpuFma3 = (1 << 12)
CpuBmi1 = (1 << 13)
CpuBmi2 = (1 << 14)
CpuAvx2 = (1 << 15)
// AVX-512 {F, CD, BW, DQ, VL}, requires OS support.
CpuAvx512 = (1 << 16)
// X86 modifiers.
// Avoid memory loads that span the border between two cachelines.
CpuCacheline32 = (1 << 17)
// 32/64 is the size of a cacheline in bytes.
CpuCacheline64 = (1 << 18)
// Avoid most SSE2 functions on Athlon64.
CpuSse2IsSlow = (1 << 19)
// A few functions are only faster on Core2 and Phenom.
CpuSse2IsFast = (1 << 20)
// The Conroe has a slow shuffle unit (relative to overall SSE performance).
CpuSlowShuffle = (1 << 21)
// If stack is only mod4 and not mod16.
CpuStackMod4 = (1 << 22)
// The Atom is terrible: slow SSE unaligned loads, slow SIMD multiplies, slow SIMD variable shifts, slow pshufb,
// cacheline split penalties -- gather everything here that isn't shared by other CPUs to avoid making half a dozen new SLOW flags.
CpuSlowAtom = (1 << 23)
// Auch as on the Intel Atom.
CpuSlowPshufb = (1 << 24)
// Such as on the AMD Bobcat.
CpuSlowPalignr = (1 << 25)
// PowerPC.
CpuAltivec = 0x0000001
// ARM and AArch64.
CpuArmv6 = 0x0000001
// ARM NEON.
CpuNeon = 0x0000002
// Transfer from NEON to ARM register is fast (Cortex-A9).
CpuFastNeonMrc = 0x0000004
CpuArmv8 = 0x0000008
// MIPS MSA.
CpuMsa = 0x0000001
// Analyse i4x4
AnalyseI4x4 = 0x0001
// Analyse i8x8 (requires 8x8 transform)
AnalyseI8x8 = 0x0002
// Analyse p16x8, p8x16 and p8x8
AnalysePsub16x16 = 0x0010
// Analyse p8x4, p4x8, p4x4
AnalysePsub8x8 = 0x0020
// Analyse b16x8, b8x16 and b8x8
AnalyseBsub16x16 = 0x0100
// Analyse flags.
DirectPredNone = 0
DirectPredSpatial = 1
DirectPredTemporal = 2
DirectPredAuto = 3
MeDia = 0
MeHex = 1
MeUmh = 2
MeEsa = 3
MeTesa = 4
CqmFlat = 0
CqmJvt = 1
CqmCustom = 2
RcCqp = 0
RcCrf = 1
RcAbr = 2
QpAuto = 0
AqNone = 0
AqVariance = 1
AqAutovariance = 2
AqAutovarianceBiased = 3
BAdaptNone = 0
BAdaptFast = 1
BAdaptTrellis = 2
WeightpNone = 0
WeightpSimple = 1
WeightpSmart = 2
BPyramidNone = 0
BPyramidStrict = 1
BPyramidNormal = 2
KeyintMinAuto = 0
KeyintMaxInfinite = (1 << 30)
// Colorspace type.
CspMask = 0x00ff
// Invalid mode.
CspNone = 0x0000
// Yuv 4:2:0 planar.
CspI420 = 0x0001
// Yvu 4:2:0 planar.
CspYv12 = 0x0002
// Yuv 4:2:0, with one y plane and one packed u+v.
CspNv12 = 0x0003
// Yuv 4:2:0, with one y plane and one packed v+u.
CspNv21 = 0x0004
// Yuv 4:2:2 planar.
CspI422 = 0x0005
// Yvu 4:2:2 planar.
CspYv16 = 0x0006
// Yuv 4:2:2, with one y plane and one packed u+v.
CspNv16 = 0x0007
// Yuyv 4:2:2 packed.
CspYuyv = 0x0008
// Uyvy 4:2:2 packed.
CspUyvy = 0x0009
// 10-bit yuv 4:2:2 packed in 32.
CspV210 = 0x000a
// Yuv 4:4:4 planar.
CspI444 = 0x000b
// Yvu 4:4:4 planar.
CspYv24 = 0x000c
// Packed bgr 24bits.
CspBgr = 0x000d
// Packed bgr 32bits.
CspBgra = 0x000e
// Packed rgb 24bits.
CspRgb = 0x000f
// End of list.
CspMax = 0x0010
// The csp is vertically flipped.
CspVflip = 0x1000
// The csp has a depth of 16 bits per pixel component.
CspHighDepth = 0x2000
// Slice type.
// Let x264 choose the right type.
TypeAuto = 0x0000
TypeIdr = 0x0001
TypeI = 0x0002
TypeP = 0x0003
// Non-disposable B-frame
TypeBref = 0x0004
TypeB = 0x0005
// IDR or I depending on BOpenGop option.
TypeKeyframe = 0x0006
// Log level.
LogNone = (-1)
LogError = 0
LogWarning = 1
LogInfo = 2
LogDebug = 3
// Threading.
// Automatically select optimal number of threads.
ThreadsAuto = 0
// Automatically select optimal lookahead thread buffer size
SyncLookaheadAuto = (-1)
// HRD
NalHrdNone = 0
NalHrdVbr = 1
NalHrdCbr = 2
ParamBadName = (-1)
ParamBadValue = (-2)
// MbinfoConstant.
MbinfoConstant = (1 << 0)
)
// NalUnitType enumeration.
const (
NalUnknown = int32(iota)
NalSlice
NalSliceDpa
NalSliceDpb
NalSliceDpc
NalSliceIdr
NalSei
NalSps
NalPps
NalAud
NalFiller
)
// NalPriority enumeration.
const (
NalPriorityDisposable = int32(iota)
NalPriorityLow
NalPriorityHigh
NalPriorityHighest
)
// PicStruct enumeration.
const (
PicStructAuto = int32(iota) // automatically decide (default)
PicStructProgressive // progressive frame
// "TOP" and "BOTTOM" are not supported in x264 (PAFF only)
PicStructTopBottom // top field followed by bottom
PicStructBottomTop // bottom field followed by top
PicStructTopBottomTop // top field, bottom field, top field repeated
PicStructBottomTopBottom // bottom field, top field, bottom field repeated
PicStructDouble // double frame
PicStructTriple // triple frame
)
// T opaque handler for encoder.
type T struct{}
// cptr return C pointer.
func (t *T) cptr() *C.x264_t {
return (*C.x264_t)(unsafe.Pointer(t))
}
// Nal type.
// The data within the payload is already NAL-encapsulated; the ref_idc and type are merely in the struct for easy access by the calling application.
// All data returned in an Nal, including the data in PPayload, is no longer valid after the next call to EncoderEncode.
// Thus it must be used or copied before calling EncoderEncode or EncoderHeaders again.
type Nal struct {
// NalPriority.
IRefIdc int32
// NalUnitType.
IType int32
// Start code.
BLongStartcode int32
// If this NAL is a slice, the index of the first MB in the slice.
IFirstMb int32
// If this NAL is a slice, the index of the last MB in the slice.
ILastMb int32
// Size of payload (including any padding) in bytes.
IPayload int32
// If param.BAnnexb is set, Annex-B bytestream with startcode.
// Otherwise, startcode is replaced with a 4-byte size.
// This size is the size used in mp4/similar muxing; it is equal to IPayload-4.
PPayload unsafe.Pointer
// Size of padding in bytes.
IPadding int32
}
// cptr return C pointer.
func (n *Nal) cptr() *C.x264_nal_t {
return (*C.x264_nal_t)(unsafe.Pointer(n))
}
// Vui type.
type Vui struct {
// They will be reduced to be 0 < x <= 65535 and prime.
ISarHeight int32
ISarWidth int32
// 0=undef, 1=no overscan, 2=overscan.
IOverscan int32
// See h264 annex E for the values of the following.
IVidformat int32
BFullrange int32
IColorprim int32
ITransfer int32
IColmatrix int32
// Both top & bottom.
IChromaLoc int32
}
// Analyse (encoder analyser parameters) type.
type Analyse struct {
// Intra partitions.
Intra uint32
// Inter partitions.
Inter uint32
BTransform8x8 int32
// Weighting for P-frames.
IWeightedPred int32
// Implicit weighting for B-frames.
BWeightedBipred int32
// Spatial vs temporal mv prediction.
IDirectMvPred int32
IChromaQpOffset int32
// Motion estimation algorithm to use (X264_ME_*).
IMeMethod int32
// Integer pixel motion estimation search range (from predicted mv).
IMeRange int32
// Maximum length of a mv (in pixels). -1 = auto, based on level.
IMvRange int32
// Minimum space between threads. -1 = auto, based on number of threads.
IMvRangeThread int32
// Subpixel motion estimation quality.
ISubpelRefine int32
// Chroma ME for subpel and mode decision in P-frames.
BChromaMe int32
// Allow each mb partition to have its own reference number.
BMixedReferences int32
// Trellis RD quantization.
ITrellis int32
// Early SKIP detection on P-frames.
BFastPskip int32
// Transform coefficient thresholding on P-frames.
BDctDecimate int32
// Adaptive pseudo-deadzone.
INoiseReduction int32
// Psy RD strength.
FPsyRd float32
// Psy trellis strength.
FPsyTrellis float32
// Toggle all psy optimizations.
BPsy int32
// Use input MbInfo data in Picture
BMbInfo int32
// Update the values in mb_info according to the results of encoding.
BMbInfoUpdate int32
// The deadzone size that will be used in luma quantization {inter, intra}
ILumaDeadzone [2]int32
// compute and print PSNR stats
BPsnr int32
// compute and print SSIM stats
BSsim int32
}
// Rc (rate control parameters) type.
type Rc struct {
// X264_RC_*
IRcMethod int32
// 0 to (51 + 6*(x264_bit_depth-8)). 0=lossless.
IQpConstant int32
// Min allowed QP value.
IQpMin int32
// Max allowed QP value.
IQpMax int32
// Max QP step between frames.
IQpStep int32
IBitrate int32
// 1pass VBR, nominal QP.
FRfConstant float32
// In CRF mode, maximum CRF as caused by VBV.
FRfConstantMax float32
FRateTolerance float32
IVbvMaxBitrate int32
IVbvBufferSize int32
// <=1: fraction of buffer_size. >1: kbit.
FVbvBufferInit float32
FIpFactor float32
FPbFactor float32
// VBV filler: force CBR VBV and use filler bytes to ensure hard-CBR. Implied by NAL-HRD CBR.
BFiller int32
// Psy adaptive QP. (X264_AQ_*).
IAqMode int32
FAqStrength float32
// Macroblock-tree ratecontrol.
BMbTree int32
ILookahead int32
// 2pass
// Enable stat writing in psz_stat_out.
BStatWrite int32
// Output filename (in UTF-8) of the 2pass stats file.
PszStatOut *int8
// Read stat from psz_stat_in and use it.
BStatRead int32
_ [4]byte
// Input filename (in UTF-8) of the 2pass stats file.
PszStatIn *int8
// 2pass params (same as ffmpeg ones).
// 0.0 => cbr, 1.0 => constant qp.
FQcompress float32
// Temporally blur quants.
FQblur float32
// Temporally blur complexity.
FComplexityBlur float32
_ [4]byte
// Ratecontrol overrides.
Zones *Zone
// Number of Zone's.
IZones int32
_ [4]byte
// Alternate method of specifying zones.
PszZones *int8
}
// CropRect (cropping rectangle parameters) type.
// Added to those implicitly defined by non-mod16 video resolutions.
type CropRect struct {
Left uint32
Top uint32
Right uint32
Bottom uint32
}
// Zone type.
// Zones: override ratecontrol or other options for specific sections of the video.
// See EncoderReconfig() for which options can be changed.
// If zones overlap, whichever comes later in the list takes precedence.
type Zone struct {
// Range of frame numbers.
IStart int32
// Range of frame numbers.
IEnd int32
// Whether to use qp vs bitrate factor.
BForceQp int32
IQp int32
FBitrateFactor float32
_ [4]byte
Param *Param
}
// Level (H.264 level restriction information) type.
type Level struct {
LevelIdc byte
_ [3]byte
// Max macroblock processing rate (macroblocks/sec).
Mbps uint32
// Max frame size (macroblocks).
FrameSize uint32
// Max decoded picture buffer (mbs).
Dpb uint32
// Max bitrate (kbit/sec).
Bitrate uint32
// Max vbv buffer (kbit).
Cpb uint32
// Max vertical mv component range (pixels).
MvRange uint16
// Max mvs per 2 consecutive mbs.
MvsPer2mb byte
SliceRate byte
// Min compression ratio.
Mincr byte
// Limit bipred to >=8x8.
Bipred8x8 byte
// Limit b_direct to >=8x8.
Direct8x8 byte
// Forbid interlacing.
FrameOnly byte
}
// Param type.
type Param struct {
// CPU flags.
Cpu uint32
// Encode multiple frames in parallel.
IThreads int32
// Multiple threads for lookahead analysis.
ILookaheadThreads int32
// Whether to use slice-based threading.
BSlicedThreads int32
// Whether to allow non-deterministic optimizations when threaded.
BDeterministic int32
// Force canonical behavior rather than cpu-dependent optimal algorithms.
BCpuIndependent int32
// Threaded lookahead buffer.
ISyncLookahead int32
// Video Properties.
IWidth int32
IHeight int32
// CSP of encoded bitstream.
ICsp int32
ILevelIdc int32
// Number of frames to encode if known, else 0.
IFrameTotal int32
// NAL HRD.
// Uses Buffering and Picture Timing SEIs to signal HRD. The HRD in H.264 was not designed with VFR in mind.
// It is therefore not recommendeded to use NAL HRD with VFR.
// Furthermore, reconfiguring the VBV (via x264_encoder_reconfig) will currently generate invalid HRD.
INalHrd int32
Vui Vui
// Bitstream parameters.
// Maximum number of reference frames.
IFrameReference int32
// Force a DPB size larger than that implied by B-frames and reference frames.
// Useful in combination with interactive error resilience.
IDpbSize int32
// Force an IDR keyframe at this interval.
IKeyintMax int32
// Scenecuts closer together than this are coded as I, not IDR.
IKeyintMin int32
// How aggressively to insert extra I frames.
IScenecutThreshold int32
// Whether or not to use periodic intra refresh instead of IDR frames.
BIntraRefresh int32
// How many b-frame between 2 references pictures.
IBframe int32
IBframeAdaptive int32
IBframeBias int32
// Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal.
IBframePyramid int32
BOpenGop int32
BBlurayCompat int32
IAvcintraClass int32
BDeblockingFilter int32
// [-6, 6] -6 light filter, 6 strong.
IDeblockingFilterAlphac0 int32
// [-6, 6] idem.
IDeblockingFilterBeta int32
BCabac int32
ICabacInitIdc int32
BInterlaced int32
BConstrainedIntra int32
ICqmPreset int32
_ [4]byte
// Filename (in UTF-8) of CQM file, JM format.
PszCqmFile *int8
// Used only if i_cqm_preset == X264_CQM_CUSTOM.
Cqm4iy [16]byte
Cqm4py [16]byte
Cqm4ic [16]byte
Cqm4pc [16]byte
Cqm8iy [64]byte
Cqm8py [64]byte
Cqm8ic [64]byte
Cqm8pc [64]byte
// Log.
PfLog *[0]byte
PLogPrivate unsafe.Pointer
ILogLevel int32
// Fully reconstruct frames, even when not necessary for encoding. Implied by psz_dump_yuv.
BFullRecon int32
// Filename (in UTF-8) for reconstructed frames.
PszDumpYuv *int8
// Encoder analyser parameters.
Analyse Analyse
_ [4]byte
// Rate control parameters.
Rc Rc
// Cropping Rectangle parameters: added to those implicitly defined by non-mod16 video resolutions.
CropRect CropRect
// Frame packing arrangement flag.
IFramePacking int32
// Muxing parameters.
// Generate access unit delimiters.
BAud int32
// Put SPS/PPS before each keyframe.
BRepeatHeaders int32
// If set, place start codes (4 bytes) before NAL units, otherwise place size (4 bytes) before NAL units.
BAnnexb int32
// SPS and PPS id number.
ISpsId int32
// VFR input. If 1, use timebase and timestamps for ratecontrol purposes. If 0, use fps only.
BVfrInput int32
// Use explicitly set timebase for CFR.
BPulldown int32
IFpsNum uint32
IFpsDen uint32
// Timebase numerator.
ITimebaseNum uint32
// Timebase denominator.
ITimebaseDen uint32
BTff int32
// The correct pic_struct must be passed with each input frame.
// The input timebase should be the timebase corresponding to the output framerate. This should be constant.
// e.g. for 3:2 pulldown timebase should be 1001/30000.
// The PTS passed with each frame must be the PTS of the frame after pulldown is applied.
// Frame doubling and tripling require BVfrInput set to zero (see H.264 Table D-1)
//
// Pulldown changes are not clearly defined in H.264. Therefore, it is the calling app's responsibility to manage this.
BPicStruct int32
// Used only when b_interlaced=0. Setting this flag makes it possible to flag the stream as PAFF interlaced yet
// encode all frames progessively. It is useful for encoding 25p and 30p Blu-Ray streams.
BFakeInterlaced int32
// Don't optimize header parameters based on video content, e.g. ensure that splitting an input video, compressing
// each part, and stitching them back together will result in identical SPS/PPS. This is necessary for stitching
// with container formats that don't allow multiple SPS/PPS.
BStitchable int32
// Use OpenCL when available.
BOpencl int32
// Specify count of GPU devices to skip, for CLI users.
IOpenclDevice int32
_ [4]byte
// Pass explicit cl_device_id as void*, for API users.
OpenclDeviceId unsafe.Pointer
// Filename (in UTF-8) of the compiled OpenCL kernel cache file.
PszClbinFile *int8
// Slicing parameters
// Max size per slice in bytes; includes estimated NAL overhead.
ISliceMaxSize int32
// Max number of MBs per slice; overrides i_slice_count.
ISliceMaxMbs int32
// Min number of MBs per slice.
ISliceMinMbs int32
// Number of slices per frame: forces rectangular slices.
ISliceCount int32
// Absolute cap on slices per frame; stops applying slice-max-size and slice-max-mbs if this is reached.
ISliceCountMax int32
_ [4]byte
ParamFree *[0]byte
NaluProcess *[0]byte
}
// cptr return C pointer.
func (p *Param) cptr() *C.x264_param_t {
return (*C.x264_param_t)(unsafe.Pointer(p))
}
// Hrd type.
type Hrd struct {
CpbInitialArrivalTime float64
CpbFinalArrivalTime float64
CpbRemovalTime float64
DpbOutputTime float64
}
// SeiPayload type.
type SeiPayload struct {
PayloadSize int32
PayloadType int32
Payload *uint8
}
// Sei type.
type Sei struct {
NumPayloads int32
_ [4]byte
Payloads *SeiPayload
SeiFree *[0]byte
}
// Image type.
type Image struct {
// Colorspace.
ICsp int32
// Number of image planes.
IPlane int32
// Strides for each plane.
IStride [4]int32
// Pointers to each plane.
Plane [4]unsafe.Pointer
}
// ImageProperties type.
type ImageProperties struct {
// In: an array of quantizer offsets to be applied to this image during encoding.
QuantOffsets *float32
// In: optional callback to free quant_offsets when used.
// Useful if one wants to use a different quant_offset array for each frame.
QuantOffsetsFree *[0]byte
// In: optional array of flags for each macroblock.
// Out: if b_mb_info_update is set, x264 will update this array as a result of encoding.
MbInfo *uint8
// In: optional callback to free mb_info when used.
MbInfoFree *[0]byte
// Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set).
FSsim float64
// Out: Average PSNR of the frame (if x264_param_t.b_psnr is set).
FPsnrAvg float64
// Out: PSNR of Y, U, and V (if x264_param_t.b_psnr is set).
FPsnr [3]float64
// Out: Average effective CRF of the encoded frame.
FCrfAvg float64
}
// Picture type.
type Picture struct {
// In: force picture type (if not auto).
// Out: type of the picture encoded.
IType int32
// In: force quantizer for != X264_QP_AUTO.
IQpplus1 int32
// In: pic_struct, for pulldown/doubling/etc...used only if b_pic_struct=1.
// Out: pic_struct element associated with frame.
IPicStruct int32
// Out: whether this frame is a keyframe.
// Important when using modes that result in SEI recovery points being used instead of IDR frames.
BKeyframe int32
// In: user pts, Out: pts of encoded picture (user).
IPts int64
// Out: frame dts. When the pts of the first frame is close to zero,
// initial frames may have a negative dts which must be dealt with by any muxer.
IDts int64
// In: custom encoding parameters to be set from this frame forwards (in coded order, not display order).
// If nil, continue using parameters from the previous frame.
Param *Param
// In: raw image data.
// Out: reconstructed image data.
Img Image
// In: optional information to modify encoder decisions for this frame.
// Out: information about the encoded frame.
Prop ImageProperties
// Out: HRD timing information. Output only when i_nal_hrd is set.
Hrdiming Hrd
// In: arbitrary user SEI (e.g subtitles, AFDs).
ExtraSei Sei
// Private user data. copied from input to output frames.
Opaque *byte
}
// cptr return C pointer.
func (p *Picture) cptr() *C.x264_picture_t {
return (*C.x264_picture_t)(unsafe.Pointer(p))
}
// NalEncode - encode Nal.
func NalEncode(h *T, dst []byte, nal *Nal) {
ch := h.cptr()
cdst := (*C.uint8_t)(unsafe.Pointer(&dst[0]))
cnal := nal.cptr()
C.x264_nal_encode(ch, cdst, cnal)
}
// ParamDefault - fill Param with default values and do CPU detection.
func ParamDefault(param *Param) {
C.x264_param_default(param.cptr())
}
// ParamParse - set one parameter by name. Returns 0 on success.
func ParamParse(param *Param, name string, value string) int32 {
cparam := param.cptr()
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cvalue := C.CString(value)
defer C.free(unsafe.Pointer(cvalue))
ret := C.x264_param_parse(cparam, cname, cvalue)
v := (int32)(ret)
return v
}
// ParamDefaultPreset - the same as ParamDefault, but also use the passed preset and tune to modify the default settings
// (either can be nil, which implies no preset or no tune, respectively).
//
// Currently available presets are, ordered from fastest to slowest:
// "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo".
//
// Currently available tunings are:
// "film", "animation", "grain", "stillimage", "psnr", "ssim", "fastdecode", "zerolatency".
//
// Returns 0 on success, negative on failure (e.g. invalid preset/tune name).
func ParamDefaultPreset(param *Param, preset string, tune string) int32 {
cparam := param.cptr()
cpreset := C.CString(preset)
defer C.free(unsafe.Pointer(cpreset))
ctune := C.CString(tune)
defer C.free(unsafe.Pointer(ctune))
ret := C.x264_param_default_preset(cparam, cpreset, ctune)
v := (int32)(ret)
return v
}
// ParamApplyFastfirstpass - if first-pass mode is set (rc.b_stat_read == 0, rc.b_stat_write == 1),
// modify the encoder settings to disable options generally not useful on the first pass.
func ParamApplyFastfirstpass(param *Param) {
cparam := param.cptr()
C.x264_param_apply_fastfirstpass(cparam)
}
// ParamApplyProfile - applies the restrictions of the given profile.
//
// Currently available profiles are, from most to least restrictive:
// "baseline", "main", "high", "high10", "high422", "high444".
// (can be nil, in which case the function will do nothing).
//
// Returns 0 on success, negative on failure (e.g. invalid profile name).
func ParamApplyProfile(param *Param, profile string) int32 {
cparam := param.cptr()
cprofile := C.CString(profile)
defer C.free(unsafe.Pointer(cprofile))
ret := C.x264_param_apply_profile(cparam, cprofile)
v := (int32)(ret)
return v
}
// PictureInit - initialize an Picture. Needs to be done if the calling application
// allocates its own Picture as opposed to using PictureAlloc.
func PictureInit(pic *Picture) {
cpic := pic.cptr()
C.x264_picture_init(cpic)
}
// PictureAlloc - alloc data for a Picture. You must call PictureClean on it.
// Returns 0 on success, or -1 on malloc failure or invalid colorspace.
func PictureAlloc(pic *Picture, iCsp int32, iWidth int32, iHeight int32) int32 {
cpic := pic.cptr()
ciCsp := (C.int)(iCsp)
ciWidth := (C.int)(iWidth)
ciHeight := (C.int)(iHeight)
ret := C.x264_picture_alloc(cpic, ciCsp, ciWidth, ciHeight)
v := (int32)(ret)
return v
}
// PictureClean - free associated resource for a Picture allocated with PictureAlloc ONLY.
func PictureClean(pic *Picture) {
cpic := pic.cptr()
C.x264_picture_clean(cpic)
}
// EncoderOpen - create a new encoder handler, all parameters from Param are copied.
func EncoderOpen(param *Param) *T {
cparam := param.cptr()
ret := C.x264_encoder_open(cparam)
v := *(**T)(unsafe.Pointer(&ret))
return v
}
// EncoderReconfig - various parameters from Param are copied.
// Returns 0 on success, negative on parameter validation error.
func EncoderReconfig(enc *T, param *Param) int32 {
cenc := enc.cptr()
cparam := param.cptr()
ret := C.x264_encoder_reconfig(cenc, cparam)
v := (int32)(ret)
return v
}
// EncoderParameters - copies the current internal set of parameters to the pointer provided.
func EncoderParameters(enc *T, param *Param) {
cenc := enc.cptr()
cparam := param.cptr()
C.x264_encoder_parameters(cenc, cparam)
}
// EncoderHeaders - return the SPS and PPS that will be used for the whole stream.
// Returns the number of bytes in the returned NALs or negative on error.
func EncoderHeaders(enc *T, ppNal []*Nal, piNal *int32) int32 {
cenc := enc.cptr()
cppNal := (**C.x264_nal_t)(unsafe.Pointer(&ppNal[0]))
cpiNal := (*C.int)(unsafe.Pointer(piNal))
ret := C.x264_encoder_headers(cenc, cppNal, cpiNal)
v := (int32)(ret)
return v
}
// EncoderEncode - encode one picture.
// Returns the number of bytes in the returned NALs, negative on error and zero if no NAL units returned.
func EncoderEncode(enc *T, ppNal []*Nal, piNal *int32, picIn *Picture, picOut *Picture) int32 {
cenc := enc.cptr()
cppNal := (**C.x264_nal_t)(unsafe.Pointer(&ppNal[0]))
cpiNal := (*C.int)(unsafe.Pointer(piNal))
cpicIn := picIn.cptr()
cpicOut := picOut.cptr()
ret := C.x264_encoder_encode(cenc, cppNal, cpiNal, cpicIn, cpicOut)
v := (int32)(ret)
return v
}
// EncoderClose - close an encoder handler.
func EncoderClose(enc *T) {
cenc := enc.cptr()
C.x264_encoder_close(cenc)
}
// EncoderDelayedFrames - return the number of currently delayed (buffered) frames.
// This should be used at the end of the stream, to know when you have all the encoded frames.
func EncoderDelayedFrames(enc *T) int32 {
cenc := enc.cptr()
ret := C.x264_encoder_delayed_frames(cenc)
v := (int32)(ret)
return v
}
// EncoderMaximumDelayedFrames - return the maximum number of delayed (buffered) frames that can occur with the current parameters.
func EncoderMaximumDelayedFrames(enc *T) int32 {
cenc := enc.cptr()
ret := C.x264_encoder_maximum_delayed_frames(cenc)
v := (int32)(ret)
return v
}
// EncoderIntraRefresh - If an intra refresh is not in progress, begin one with the next P-frame.
// If an intra refresh is in progress, begin one as soon as the current one finishes.
// Requires that BIntraRefresh be set.
//
// Should not be called during an x264_encoder_encode.
func EncoderIntraRefresh(enc *T) {
cenc := enc.cptr()
C.x264_encoder_intra_refresh(cenc)
}
// EncoderInvalidateReference - An interactive error resilience tool, designed for use in a low-latency one-encoder-few-clients system.
// Should not be called during an EncoderEncode, but multiple calls can be made simultaneously.
//
// Returns 0 on success, negative on failure.
func EncoderInvalidateReference(enc *T, pts int) int32 {
cenc := enc.cptr()
cpts := (C.int64_t)(pts)
ret := C.x264_encoder_invalidate_reference(cenc, cpts)
v := (int32)(ret)
return v
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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