summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorCYBERDEViL2023-12-25 18:38:09 +0100
committerCYBERDEViL2023-12-25 18:38:09 +0100
commit4b4bd525ed40337fcd05872d641dc3e1c0bf95e2 (patch)
treed235a1b42053a521d0fcf89cef913d2e43f7177c
parent67d230f7ca8022b95126b550e47b2b9ea097ba06 (diff)
downloadaur-4b4bd525ed40337fcd05872d641dc3e1c0bf95e2.tar.gz
New source and patches.
The source of this package (`git.blender.org/blender.git#branch=blender2.7`) does not exist anymore, Blender moved the repo to `https://projects.blender.org/blender/blender.git`. There is no branch `blender2.7` on this new repo, only a `v2.79b` tag which is a different source. As the new source I choose the 2.79b source tarball from Blender. Patches to keep Blender 2.79b up-to-date with modern compiler and libs where mostly derived from Blender upstream commits/code.
-rw-r--r--.SRCINFO67
-rw-r--r--0000_misc.patch394
-rw-r--r--0001_openexr3.patch305
-rw-r--r--0002_opencollada1_6_68.patch91
-rw-r--r--0003_openvdb.patch112
-rw-r--r--0004_openimageio.patch375
-rw-r--r--0005_cycles.patch155
-rw-r--r--0006_python3_7.patch66
-rw-r--r--0007_python3_8.patch608
-rw-r--r--0008_python3_9.patch229
-rw-r--r--0009_python3_10.patch1124
-rw-r--r--0010_python3_11.patch122
-rw-r--r--0011_ffmpeg.patch4805
-rw-r--r--PKGBUILD125
-rw-r--r--SelectCudaComputeArch.patch4
-rw-r--r--cycles.patch22
-rw-r--r--opencolorio1.patch32
-rw-r--r--openexr3.patch57
-rw-r--r--openvdb7.patch29
-rw-r--r--openvdb8.patch16
-rw-r--r--python3.7.patch13
-rw-r--r--python3.8.patch73
-rw-r--r--python3.9.patch141
-rw-r--r--python3.9_2.patch23
-rw-r--r--stl_export_iter.patch13
25 files changed, 8497 insertions, 504 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 3455a320af30..be96c90d1e6d 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,13 +1,13 @@
pkgbase = blender-2.7
- pkgdesc = Maintnance version of Blenders blender2.7 branch
- pkgver = 2.79b.r71421.e045fe53f1b
- pkgrel = 3
+ pkgdesc = Keeping Blender 2.79b up-to-date with modern compiler and libs
+ pkgver = 2.79b
+ pkgrel = 4
url = https://blender.org/
arch = i686
arch = x86_64
license = GPL
makedepends = ninja
- makedepends = git
+ makedepends = cuda
makedepends = cmake
makedepends = boost
makedepends = mesa
@@ -30,39 +30,36 @@ pkgbase = blender-2.7
depends = openshadinglanguage
depends = libtiff
depends = libpng
- optdepends = cuda: CUDA support in Cycles
provides = blender-2.7
- source = git://git.blender.org/blender.git#branch=blender2.7
- source = blender-addons.git::git://git.blender.org/blender-addons.git
- source = blender-addons-contrib.git::git://git.blender.org/blender-addons-contrib.git
- source = blender-translations.git::git://git.blender.org/blender-translations.git
- source = blender-dev-tools.git::git://git.blender.org/blender-dev-tools.git
+ source = https://download.blender.org/source/blender-2.79b.tar.gz
source = SelectCudaComputeArch.patch
- source = stl_export_iter.patch
- source = python3.7.patch
- source = python3.8.patch
- source = python3.9.patch
- source = python3.9_2.patch
- source = openvdb7.patch
- source = openvdb8.patch
- source = cycles.patch
- source = openexr3.patch
source = opencolorio1.patch
- sha256sums = SKIP
- sha256sums = SKIP
- sha256sums = SKIP
- sha256sums = SKIP
- sha256sums = SKIP
- sha256sums = 28e407e3aefdd9bd76805b6033ada0b5b41dd6183bcf4f58a642c109f10c1876
- sha256sums = 649c21a12a1bfc0207078e1e58b4813a3e898c6dbbbb35d21e1de7c9e8f1985a
- sha256sums = 47811284f080e38bcfbfb1f7346279245815a064df092989336b0bf3fe4530e9
- sha256sums = 229853b98bb62e1dec835aea6b2eab4c3dabbc8be591206573a3c1b85f10be59
- sha256sums = d106248d55045f5ef913bf6243ad74a76f6282264d9ee4c9b87ec4a3d2e2064b
- sha256sums = b2a2bc5de8d3b730e49d1f50cb025c1dfdbcb66c58ead573322585b6a887d3a7
- sha256sums = c4079c4c142516d9cd476f5a3cafddf4068f0950c3c11ea4da9cf999c5ccc1f9
- sha256sums = edfd784f8497417660c0b9fdc97893fd0d77764d0bc10f4cb92a9082f41bae75
- sha256sums = d245f02d73bd5b767ffa49d369383d7cd6ae5e57b89c2975a78c1015e1884864
- sha256sums = e7d75a5ef5cb6452b45f6e1e80b6fe69e2630878b1f4f6d53bf0e36ced237712
- sha256sums = b3fa6ef21383287d0f8e7c3b848f3cf02186f9e3a0e8f194f3ca1323935e5e0e
+ source = 0000_misc.patch
+ source = 0001_openexr3.patch
+ source = 0002_opencollada1_6_68.patch
+ source = 0003_openvdb.patch
+ source = 0004_openimageio.patch
+ source = 0005_cycles.patch
+ source = 0006_python3_7.patch
+ source = 0007_python3_8.patch
+ source = 0008_python3_9.patch
+ source = 0009_python3_10.patch
+ source = 0010_python3_11.patch
+ source = 0011_ffmpeg.patch
+ sha512sums = 2db21ace446168dd683cdb5aad9dec001f8888ae4e9603a04ddb44fb78489ded827deb07e83712b0f1118a0e7bf66f2a5d935dc4ebb3a6703d72672ff414367f
+ sha512sums = 15b10bf91c759a8ab6519f3c02f54e7d3ad105eb915663e0de2a65b38d1e42b55cc383bae96a1507f1eb55200eb14ebe904b6a7b772b4073aa6a53ac5d4dd194
+ sha512sums = 4126ddaaab2dc8c45cd850353a2e4a0e6ff2ef4476f9a533916e59fc57e426ca3110f7b3d38685fffd97b969208f941359122b693584c2a70a3f8420a832214b
+ sha512sums = d7b6f1707ad902743a3f08c6423aabd7abd0841eb78404419884d7c0b02affc1b6c3eafea55f9db04bce5e27d22cfd0ec63153c61a5fa2c3227de54a09f0895d
+ sha512sums = 0a8bd2ad7e199f95145bd0a66471686e0c545b071c73e6a659b570c001a860504f0970818fd686f52be9f5c18bd294c0efbede5c058ac96a4682e54b6235aac0
+ sha512sums = 435e33926766a143cb6445a0c3219c9126b5d77e8114601a1f07848120b823ef2d1789bccb10079436b89eb9f894df54571ed50cde0713af857a8148be8f18ae
+ sha512sums = fc86d7a9a46e521ec22b2d87dfb023a71bfde624c4a6ddcf137038c7f46b97d614f8cb99951489a251cb2ea28460690cc0e5eb9ac6f2ccacc27c0052d137dcc9
+ sha512sums = c8bd5ee00f062760ae3a2493750b2eb66d0368955ebb443aad5313f91c1fd0680df239eb1ca957e79cda482c084a023efc60e4341c198d55f897415cf79de35d
+ sha512sums = 3e3bef5e27279fc9c4f66398cd04a51a1ed268b7b99df2cf0151ed63994b742e39917e525ddac666d12a3df02a3ecef7dbe03da52c6be1aa143a3be960acbc5f
+ sha512sums = 7c98cf29fa22e7e816789254e43ed0f5595529f8ed37c88abac8667a80bf2bee9f020fa204a45800586e4d0c2de977df9ceda6d8bc0b77c806743f761b6ffa9f
+ sha512sums = 7effbd675b2167cc4c25a36d58f08824b2770e7b57fee93fd909a715003ee076ffcfc7e91cf965b9836da2fa54246fb68bbe613e44d312702298a5386b124dfa
+ sha512sums = a556445f27eaaba839d0efcfa70c530c269c7189e194c93b929044a54697f3606401dfdf5dbec05b181c26ba82d2b16560f2db7cd579104e0a0a322525cecaff
+ sha512sums = ecae55f642bf7f08edc56f8740a9fec650a3617f0ce7c7ba5b3211994ad8c46dc8fbbe897405699d46cb01c15129c0d4d9184657daeaf41172533195cdbbb104
+ sha512sums = de254cb5e43fe05c3b5e70df881c1ab847b58c383d8df28be6d044c058d4776a5a3d57f710eb3cf0a83b43c95fac29f772c446a23e0f9c2bf73d1dcc8b23b67c
+ sha512sums = a0ff4f4dbc3624692c16d45f632cda1362173a5685c85e62d54af1d63d5a421867a5eb89b5b1c5b72bbceef98664d96b54901790470cbe67f701c582858af0ed
pkgname = blender-2.7
diff --git a/0000_misc.patch b/0000_misc.patch
new file mode 100644
index 000000000000..009368b3fbec
--- /dev/null
+++ b/0000_misc.patch
@@ -0,0 +1,394 @@
+commit 1a734229a8ed6f35f953349bc9bc09cb37d2f5c8
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 18:29:28 2023 +0100
+
+ Fix some compiler warnings (invalid header definitions)
+
+commit 5aa7fe5e858dbd5adfc6bf8fb31549050f9cacc1
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 03:01:40 2023 +0100
+
+ "Cleanup: remove use of deprecated uint32, utin16 types"
+
+ Fully applied Blender upstream ref: e12a8aedce52a05a635a4a70721a33352fe5de58
+
+commit ebed5793e447501c1d6d60b643f6e6cd3a6ca0b0
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 02:57:35 2023 +0100
+
+ misc: "Cleanup: pass arguments as const"
+
+ Partially applied Blender upstream ref: 357acd1d5053b2ff9c8a09b9b6ad2e170c10b875
+
+commit 6d64717fdb0e3d74af99ee824fe364619424cd0b
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 01:03:16 2023 +0100
+
+ "Cleanup: compiler warnings, use const"
+
+ Partially applied Blender upstream ref: e159ec8bc1871da8766b319fcda5c76eff1c0a48
+
+commit e586b0156029339b3d651746ff27f818f4ab22d6
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Fri Dec 15 22:43:37 2023 +0100
+
+ inter: fix missing include (could not find std::cout)
+
+ "error: ‘cout’ is not a member of ‘std’"
+
+commit 06a03f283d71a7eb6a1595476fb186638c6f1141
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Fri Dec 15 22:35:50 2023 +0100
+
+ intern: "Added extra "const" to satisfy the strict clang version in Xcode 9"
+
+ Fully applied Blender upstream ref: ee30a4381f8989ed9f39b4baae9f74e45c9dcdc9
+
+commit a7bfbf39c45757df1fc866418595e48f9d99c242
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Fri Dec 15 22:28:33 2023 +0100
+
+ intern: "Fix for GCC9 new OpenMP data sharing"
+
+ Applied whole Blender upstream ref: d780409156e838e366f4da5126e6aeab44174d62
+
+diff --git a/blender-2.79b/intern/elbeem/intern/solver_main.cpp b/blender-2.79b/intern/elbeem/intern/solver_main.cpp
+index 68f7c04..514087b 100644
+--- a/blender-2.79b/intern/elbeem/intern/solver_main.cpp
++++ b/blender-2.79b/intern/elbeem/intern/solver_main.cpp
+@@ -381,7 +381,7 @@ LbmFsgrSolver::mainLoop(const int lev)
+ GRID_REGION_INIT();
+ #if PARALLEL==1
+ const int gDebugLevel = ::gDebugLevel;
+-#pragma omp parallel default(none) num_threads(mNumOMPThreads) \
++#pragma omp parallel num_threads(mNumOMPThreads) \
+ reduction(+: \
+ calcCurrentMass,calcCurrentVolume, \
+ calcCellsFilled,calcCellsEmptied, \
+@@ -1126,7 +1126,7 @@ LbmFsgrSolver::preinitGrids()
+ GRID_REGION_INIT();
+ #if PARALLEL==1
+ const int gDebugLevel = ::gDebugLevel;
+-#pragma omp parallel default(none) num_threads(mNumOMPThreads) \
++#pragma omp parallel num_threads(mNumOMPThreads) \
+ reduction(+: \
+ calcCurrentMass,calcCurrentVolume, \
+ calcCellsFilled,calcCellsEmptied, \
+@@ -1164,7 +1164,7 @@ LbmFsgrSolver::standingFluidPreinit()
+ GRID_REGION_INIT();
+ #if PARALLEL==1
+ const int gDebugLevel = ::gDebugLevel;
+-#pragma omp parallel default(none) num_threads(mNumOMPThreads) \
++#pragma omp parallel num_threads(mNumOMPThreads) \
+ reduction(+: \
+ calcCurrentMass,calcCurrentVolume, \
+ calcCellsFilled,calcCellsEmptied, \
+diff --git a/blender-2.79b/intern/itasc/kdl/tree.hpp b/blender-2.79b/intern/itasc/kdl/tree.hpp
+index c8a253f..bd35f82 100644
+--- a/blender-2.79b/intern/itasc/kdl/tree.hpp
++++ b/blender-2.79b/intern/itasc/kdl/tree.hpp
+@@ -34,7 +34,7 @@ namespace KDL
+ //Forward declaration
+ class TreeElement;
+ // Eigen allocator is needed for alignment of Eigen data types
+- typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap;
++ typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<const std::string, TreeElement> > > SegmentMap;
+
+ class TreeElement
+ {
+diff --git a/blender-2.79b/intern/locale/boost_locale_wrapper.cpp b/blender-2.79b/intern/locale/boost_locale_wrapper.cpp
+index 0707c0d..580c7a4 100644
+--- a/blender-2.79b/intern/locale/boost_locale_wrapper.cpp
++++ b/blender-2.79b/intern/locale/boost_locale_wrapper.cpp
+@@ -27,6 +27,7 @@
+ */
+
+ #include <stdio.h>
++#include <iostream> // std::cout
+ #include <boost/locale.hpp>
+
+ #include "boost_locale_wrapper.h"
+diff --git a/blender-2.79b/intern/mikktspace/mikktspace.c b/blender-2.79b/intern/mikktspace/mikktspace.c
+index 99e945d..67f0c2b 100644
+--- a/blender-2.79b/intern/mikktspace/mikktspace.c
++++ b/blender-2.79b/intern/mikktspace/mikktspace.c
+@@ -1193,7 +1193,7 @@ static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[],
+
+ static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2);
+ static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed);
+-static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive);
++static STSpace EvalTspace(const int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive);
+
+ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[],
+ const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
+@@ -1364,7 +1364,7 @@ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], con
+ return TTRUE;
+ }
+
+-static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[],
++static STSpace EvalTspace(const int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[],
+ const SMikkTSpaceContext * pContext, const int iVertexRepresentitive)
+ {
+ STSpace res;
+diff --git a/blender-2.79b/source/blender/blenlib/BLI_math_geom.h b/blender-2.79b/source/blender/blenlib/BLI_math_geom.h
+index 0fef849..7e06fff 100644
+--- a/blender-2.79b/source/blender/blenlib/BLI_math_geom.h
++++ b/blender-2.79b/source/blender/blenlib/BLI_math_geom.h
+@@ -429,9 +429,9 @@ MINLINE void add_sh_shsh(float r[9], const float a[9], const float b[9]);
+ MINLINE float dot_shsh(const float a[9], const float b[9]);
+
+ MINLINE float eval_shv3(float r[9], const float v[3]);
+-MINLINE float diffuse_shv3(float r[9], const float v[3]);
++MINLINE float diffuse_shv3(const float r[9], const float v[3]);
+ MINLINE void vec_fac_to_sh(float r[9], const float v[3], const float f);
+-MINLINE void madd_sh_shfl(float r[9], const float sh[3], const float f);
++MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f);
+
+ /********************************* Form Factor *******************************/
+
+diff --git a/blender-2.79b/source/blender/blenlib/BLI_math_vector.h b/blender-2.79b/source/blender/blenlib/BLI_math_vector.h
+index 4fdb339..c5f286f 100644
+--- a/blender-2.79b/source/blender/blenlib/BLI_math_vector.h
++++ b/blender-2.79b/source/blender/blenlib/BLI_math_vector.h
+@@ -120,16 +120,16 @@ MINLINE void mul_v2_v2(float r[2], const float a[2]);
+ MINLINE void mul_v3_v3(float r[3], const float a[3]);
+ MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3]);
+ MINLINE void mul_v4_fl(float r[4], float f);
+-MINLINE void mul_v4_v4fl(float r[3], const float a[3], float f);
++MINLINE void mul_v4_v4fl(float r[4], const float a[3], float f);
+ MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
+ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
+ MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT;
+-MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+-MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+-MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+-MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+-MINLINE float dot_m4_v3_row_y(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+-MINLINE float dot_m4_v3_row_z(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+
+ MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f);
+ MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f);
+@@ -145,7 +145,7 @@ MINLINE void negate_v2_v2(float r[2], const float a[2]);
+ MINLINE void negate_v3(float r[3]);
+ MINLINE void negate_v3_v3(float r[3], const float a[3]);
+ MINLINE void negate_v4(float r[4]);
+-MINLINE void negate_v4_v4(float r[4], const float a[3]);
++MINLINE void negate_v4_v4(float r[4], const float a[4]);
+
+ MINLINE void negate_v3_short(short r[3]);
+ MINLINE void negate_v3_db(double r[3]);
+@@ -171,7 +171,7 @@ MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
+
+ MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]);
+
+-MINLINE void star_m3_v3(float rmat[3][3], float a[3]);
++MINLINE void star_m3_v3(float rmat[3][3], const float a[3]);
+
+ /*********************************** Length **********************************/
+
+@@ -246,7 +246,7 @@ void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
+
+ /********************************* Comparison ********************************/
+
+-MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT;
++MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
+ MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
+ MINLINE bool is_zero_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT;
+
+diff --git a/blender-2.79b/source/blender/blenlib/intern/math_geom_inline.c b/blender-2.79b/source/blender/blenlib/intern/math_geom_inline.c
+index 68a2e68..3b672e2 100644
+--- a/blender-2.79b/source/blender/blenlib/intern/math_geom_inline.c
++++ b/blender-2.79b/source/blender/blenlib/intern/math_geom_inline.c
+@@ -99,7 +99,7 @@ MINLINE float dot_shsh(const float a[9], const float b[9])
+ return r;
+ }
+
+-MINLINE float diffuse_shv3(float sh[9], const float v[3])
++MINLINE float diffuse_shv3(const float sh[9], const float v[3])
+ {
+ /* See formula (13) in:
+ * "An Efficient Representation for Irradiance Environment Maps" */
+diff --git a/blender-2.79b/source/blender/blenlib/intern/math_vector_inline.c b/blender-2.79b/source/blender/blenlib/intern/math_vector_inline.c
+index ee5e865..3f8f2c5 100644
+--- a/blender-2.79b/source/blender/blenlib/intern/math_vector_inline.c
++++ b/blender-2.79b/source/blender/blenlib/intern/math_vector_inline.c
+@@ -501,15 +501,15 @@ MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3])
+ /**
+ * Has the effect of #mul_m3_v3(), on a single axis.
+ */
+-MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3])
++MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3])
+ {
+ return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
+ }
+-MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3])
++MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3])
+ {
+ return M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
+ }
+-MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3])
++MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3])
+ {
+ return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
+ }
+@@ -518,15 +518,15 @@ MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3])
+ * Has the effect of #mul_mat3_m4_v3(), on a single axis.
+ * (no adding translation)
+ */
+-MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3])
++MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3])
+ {
+ return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
+ }
+-MINLINE float dot_m4_v3_row_y(float M[4][4], const float a[3])
++MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3])
+ {
+ return M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
+ }
+-MINLINE float dot_m4_v3_row_z(float M[4][4], const float a[3])
++MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3])
+ {
+ return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
+ }
+@@ -756,7 +756,7 @@ MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const f
+ n[2] += (v_prev[0] - v_curr[0]) * (v_prev[1] + v_curr[1]);
+ }
+
+-MINLINE void star_m3_v3(float rmat[3][3], float a[3])
++MINLINE void star_m3_v3(float rmat[3][3], const float a[3])
+ {
+ rmat[0][0] = rmat[1][1] = rmat[2][2] = 0.0;
+ rmat[0][1] = -a[2];
+diff --git a/blender-2.79b/source/blender/editors/transform/transform.h b/blender-2.79b/source/blender/editors/transform/transform.h
+index d60eb2f..b2a308a 100644
+--- a/blender-2.79b/source/blender/editors/transform/transform.h
++++ b/blender-2.79b/source/blender/editors/transform/transform.h
+@@ -120,12 +120,12 @@ typedef struct TransCon {
+ void (*drawExtra)(struct TransInfo *t);
+ /* For constraints that needs to draw differently from the other
+ * uses this instead of the generic draw function */
+- void (*applyVec)(struct TransInfo *t, struct TransData *td, const float in[3], float out[3], float pvec[3]);
++ void (*applyVec)(struct TransInfo *t, const struct TransData *td, const float in[3], float out[3], float pvec[3]);
+ /* Apply function pointer for linear vectorial transformation */
+ /* The last three parameters are pointers to the in/out/printable vectors */
+- void (*applySize)(struct TransInfo *t, struct TransData *td, float smat[3][3]);
++ void (*applySize)(struct TransInfo *t, const struct TransData *td, float smat[3][3]);
+ /* Apply function pointer for size transformation */
+- void (*applyRot)(struct TransInfo *t, struct TransData *td, float vec[3], float *angle);
++ void (*applyRot)(struct TransInfo *t, const struct TransData *td, float vec[3], float *angle);
+ /* Apply function pointer for rotation transformation */
+ } TransCon;
+
+diff --git a/blender-2.79b/source/blender/editors/transform/transform_constraints.c b/blender-2.79b/source/blender/editors/transform/transform_constraints.c
+index 5621eed..a06e15f 100644
+--- a/blender-2.79b/source/blender/editors/transform/transform_constraints.c
++++ b/blender-2.79b/source/blender/editors/transform/transform_constraints.c
+@@ -331,7 +331,7 @@ static void planeProjection(TransInfo *t, const float in[3], float out[3])
+ *
+ */
+
+-static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3])
++static void applyAxisConstraintVec(TransInfo *t, const TransData *td, const float in[3], float out[3], float pvec[3])
+ {
+ copy_v3_v3(out, in);
+ if (!td && t->con.mode & CON_APPLY) {
+@@ -378,7 +378,7 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3
+ * Further down, that vector is mapped to each data's space.
+ */
+
+-static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3])
++static void applyObjectConstraintVec(TransInfo *t, const TransData *td, const float in[3], float out[3], float pvec[3])
+ {
+ copy_v3_v3(out, in);
+ if (t->con.mode & CON_APPLY) {
+@@ -436,7 +436,7 @@ static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in
+ * Generic callback for constant spatial constraints applied to resize motion
+ */
+
+-static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
++static void applyAxisConstraintSize(TransInfo *t, const TransData *td, float smat[3][3])
+ {
+ if (!td && t->con.mode & CON_APPLY) {
+ float tmat[3][3];
+@@ -460,7 +460,7 @@ static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3
+ * Callback for object based spatial constraints applied to resize motion
+ */
+
+-static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
++static void applyObjectConstraintSize(TransInfo *t, const TransData *td, float smat[3][3])
+ {
+ if (td && t->con.mode & CON_APPLY) {
+ float tmat[3][3];
+@@ -500,7 +500,7 @@ static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3]
+ * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
+ */
+
+-static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
++static void applyAxisConstraintRot(TransInfo *t, const TransData *td, float vec[3], float *angle)
+ {
+ if (!td && t->con.mode & CON_APPLY) {
+ int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
+@@ -542,7 +542,7 @@ static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], fl
+ * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
+ */
+
+-static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
++static void applyObjectConstraintRot(TransInfo *t, const TransData *td, float vec[3], float *angle)
+ {
+ if (t->con.mode & CON_APPLY) {
+ int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
+diff --git a/blender-2.79b/source/blender/imbuf/intern/tiff.c b/blender-2.79b/source/blender/imbuf/intern/tiff.c
+index afd28bb..110cbef 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/tiff.c
++++ b/blender-2.79b/source/blender/imbuf/intern/tiff.c
+@@ -351,7 +351,7 @@ static void scanline_separate_32bit(float *rectf, const float *fbuf, int scanlin
+
+ static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image)
+ {
+- uint16 unit;
++ uint16_t unit;
+ float xres;
+ float yres;
+
+@@ -535,7 +535,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem, size_t size, int flags, char color
+ TIFF *image = NULL;
+ ImBuf *ibuf = NULL, *hbuf;
+ ImbTIFFMemFile memFile;
+- uint32 width, height;
++ uint32_t width, height;
+ char *format = NULL;
+ int level;
+ short spp;
+@@ -656,7 +656,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem, size_t size, int flags, char color
+ void imb_loadtiletiff(ImBuf *ibuf, const unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect)
+ {
+ TIFF *image = NULL;
+- uint32 width, height;
++ uint32_t width, height;
+ ImbTIFFMemFile memFile;
+
+ image = imb_tiff_client_open(&memFile, mem, size);
+@@ -710,7 +710,7 @@ void imb_loadtiletiff(ImBuf *ibuf, const unsigned char *mem, size_t size, int tx
+ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
+ {
+ TIFF *image = NULL;
+- uint16 samplesperpixel, bitspersample;
++ uint16_t samplesperpixel, bitspersample;
+ size_t npixels;
+ unsigned char *pixels = NULL;
+ unsigned char *from = NULL, *to = NULL;
+@@ -723,7 +723,7 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
+ /* check for a valid number of bytes per pixel. Like the PNG writer,
+ * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
+ * to gray, RGB, RGBA respectively. */
+- samplesperpixel = (uint16)((ibuf->planes + 7) >> 3);
++ samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
+ if ((samplesperpixel > 4) || (samplesperpixel == 2)) {
+ fprintf(stderr,
+ "imb_savetiff: unsupported number of bytes per "
diff --git a/0001_openexr3.patch b/0001_openexr3.patch
new file mode 100644
index 000000000000..b8c868720154
--- /dev/null
+++ b/0001_openexr3.patch
@@ -0,0 +1,305 @@
+commit ade5af81ba7b039b42eff6efeb580b78bd54b6b3
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 02:23:16 2023 +0100
+
+ openexr: fix header include
+
+ Thanks to this patch: https://aur.archlinux.org/cgit/aur.git/tree/openexr3.patch?h=blender-2.7
+
+commit e00532824f88fbf8d6215df1509dd13ab33b8628
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Fri Dec 15 23:30:59 2023 +0100
+
+ openexr: "Images: update code to support OpenEXR 3"
+
+ Adjusted Blender ref: cd7550cfe7
+
+commit 7af9405f175999f38df80a421bde7166641183fd
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Fri Dec 15 22:23:21 2023 +0100
+
+ openexr: "Build: update CMake to support OpenEXR 3"
+
+ Applied whole Blender upstream ref: 2c9931699e2080639bb836357e116b8e340335d9
+
+diff --git a/blender-2.79b/build_files/cmake/Modules/FindOpenEXR.cmake b/blender-2.79b/build_files/cmake/Modules/FindOpenEXR.cmake
+index 41e60a7..7e1fdbd 100644
+--- a/blender-2.79b/build_files/cmake/Modules/FindOpenEXR.cmake
++++ b/blender-2.79b/build_files/cmake/Modules/FindOpenEXR.cmake
+@@ -37,14 +37,6 @@ ENDIF()
+ # Old versions (before 2.0?) do not have any version string, just assuming this should be fine though.
+ SET(_openexr_libs_ver_init "2.0")
+
+-SET(_openexr_FIND_COMPONENTS
+- Half
+- Iex
+- IlmImf
+- IlmThread
+- Imath
+-)
+-
+ SET(_openexr_SEARCH_DIRS
+ ${OPENEXR_ROOT_DIR}
+ /usr/local
+@@ -101,6 +93,24 @@ UNSET(_openexr_libs_ver_init)
+
+ STRING(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _openexr_libs_ver ${OPENEXR_VERSION})
+
++# Different library names in 3.0, and Imath and Half moved out.
++IF(OPENEXR_VERSION VERSION_GREATER_EQUAL "3.0.0")
++ SET(_openexr_FIND_COMPONENTS
++ Iex
++ IlmThread
++ OpenEXR
++ OpenEXRCore
++ )
++ELSE()
++ SET(_openexr_FIND_COMPONENTS
++ Half
++ Iex
++ IlmImf
++ IlmThread
++ Imath
++ )
++ENDIF()
++
+ SET(_openexr_LIBRARIES)
+ FOREACH(COMPONENT ${_openexr_FIND_COMPONENTS})
+ STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+@@ -118,6 +128,57 @@ ENDFOREACH()
+
+ UNSET(_openexr_libs_ver)
+
++IF(OPENEXR_VERSION VERSION_GREATER_EQUAL "3.0.0")
++ # For OpenEXR 3.x, we also need to find the now separate Imath library.
++ # For simplicity we add it to the OpenEXR includes and libraries, as we
++ # have no direct dependency on Imath and it's simpler to support both
++ # 2.x and 3.x this way.
++
++ # Find include directory
++ FIND_PATH(IMATH_INCLUDE_DIR
++ NAMES
++ Imath/ImathMath.h
++ HINTS
++ ${_openexr_SEARCH_DIRS}
++ PATH_SUFFIXES
++ include
++ )
++
++ # Find version
++ FIND_FILE(_imath_config
++ NAMES
++ ImathConfig.h
++ PATHS
++ ${IMATH_INCLUDE_DIR}/Imath
++ NO_DEFAULT_PATH
++ )
++
++ # Find line with version, extract string, and format for library suffix.
++ FILE(STRINGS "${_imath_config}" _imath_build_specification
++ REGEX "^[ \t]*#define[ \t]+IMATH_VERSION_STRING[ \t]+\"[.0-9]+\".*$")
++ STRING(REGEX REPLACE ".*#define[ \t]+IMATH_VERSION_STRING[ \t]+\"([.0-9]+)\".*"
++ "\\1" _imath_libs_ver ${_imath_build_specification})
++ STRING(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _imath_libs_ver ${_imath_libs_ver})
++
++ # Find library, with or without version number.
++ FIND_LIBRARY(IMATH_LIBRARY
++ NAMES
++ Imath-${_imath_libs_ver} Imath
++ NAMES_PER_DIR
++ HINTS
++ ${_openexr_SEARCH_DIRS}
++ PATH_SUFFIXES
++ lib64 lib
++ )
++ LIST(APPEND _openexr_LIBRARIES "${IMATH_LIBRARY}")
++
++ # In cmake version 3.21 and up, we can instead use the NO_CACHE option for
++ # FIND_FILE so we don't need to clear it from the cache here.
++ UNSET(_imath_config CACHE)
++ UNSET(_imath_libs_ver)
++ UNSET(_imath_build_specification)
++ENDIF()
++
+ # handle the QUIETLY and REQUIRED arguments and set OPENEXR_FOUND to TRUE if
+ # all listed variables are TRUE
+ INCLUDE(FindPackageHandleStandardArgs)
+@@ -126,13 +187,25 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenEXR DEFAULT_MSG
+
+ IF(OPENEXR_FOUND)
+ SET(OPENEXR_LIBRARIES ${_openexr_LIBRARIES})
+- # Both include paths are needed because of dummy OSL headers mixing #include <OpenEXR/foo.h> and #include <foo.h> :(
+- SET(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR}/OpenEXR)
++ # Both include paths are needed because of dummy OSL headers mixing
++ # #include <OpenEXR/foo.h> and #include <foo.h>, as well as Alembic
++ # include <half.h> directly.
++ SET(OPENEXR_INCLUDE_DIRS
++ ${OPENEXR_INCLUDE_DIR}
++ ${OPENEXR_INCLUDE_DIR}/OpenEXR)
++
++ IF(OPENEXR_VERSION VERSION_GREATER_EQUAL "3.0.0")
++ LIST(APPEND OPENEXR_INCLUDE_DIRS
++ ${IMATH_INCLUDE_DIR}
++ ${IMATH_INCLUDE_DIR}/Imath)
++ ENDIF()
+ ENDIF()
+
+ MARK_AS_ADVANCED(
+ OPENEXR_INCLUDE_DIR
+ OPENEXR_VERSION
++ IMATH_INCLUDE_DIR
++ IMATH_LIBRARY
+ )
+ FOREACH(COMPONENT ${_openexr_FIND_COMPONENTS})
+ STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+diff --git a/blender-2.79b/source/blender/alembic/intern/abc_transform.cc b/blender-2.79b/source/blender/alembic/intern/abc_transform.cc
+index 5392387..9dc3200 100644
+--- a/blender-2.79b/source/blender/alembic/intern/abc_transform.cc
++++ b/blender-2.79b/source/blender/alembic/intern/abc_transform.cc
+@@ -22,7 +22,7 @@
+
+ #include "abc_transform.h"
+
+-#include <OpenEXR/ImathBoxAlgo.h>
++#include <Imath/ImathBoxAlgo.h>
+
+ #include "abc_util.h"
+
+diff --git a/blender-2.79b/source/blender/imbuf/intern/openexr/openexr_api.cpp b/blender-2.79b/source/blender/imbuf/intern/openexr/openexr_api.cpp
+index 5ad42bd..94c2232 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/openexr/openexr_api.cpp
++++ b/blender-2.79b/source/blender/imbuf/intern/openexr/openexr_api.cpp
+@@ -40,30 +40,46 @@
+ #include <algorithm>
+ #include <iostream>
+
+-#include <half.h>
+-#include <Iex.h>
+-#include <ImfVersion.h>
+-#include <ImathBox.h>
+-#include <ImfArray.h>
+-#include <ImfIO.h>
+-#include <ImfChannelList.h>
+-#include <ImfPixelType.h>
+-#include <ImfInputFile.h>
+-#include <ImfOutputFile.h>
+-#include <ImfCompression.h>
+-#include <ImfCompressionAttribute.h>
+-#include <ImfStringAttribute.h>
+-#include <ImfStandardAttributes.h>
++/* The OpenEXR version can reliably be found in this header file from OpenEXR,
++ * for both 2.x and 3.x:
++ */
++#include <OpenEXR/OpenEXRConfig.h>
++#define COMBINED_OPENEXR_VERSION \
++ ((10000 * OPENEXR_VERSION_MAJOR) + (100 * OPENEXR_VERSION_MINOR) + OPENEXR_VERSION_PATCH)
++
++#if COMBINED_OPENEXR_VERSION >= 20599
++/* >=2.5.99 -> OpenEXR >=3.0 */
++# include <Imath/half.h>
++# include <OpenEXR/ImfFrameBuffer.h>
++# define exr_file_offset_t uint64_t
++#else
++/* OpenEXR 2.x, use the old locations. */
++# include <OpenEXR/half.h>
++# define exr_file_offset_t Int64
++#endif
++
++#include <OpenEXR/Iex.h>
++#include <OpenEXR/ImfArray.h>
++#include <OpenEXR/ImfChannelList.h>
++#include <OpenEXR/ImfCompression.h>
++#include <OpenEXR/ImfCompressionAttribute.h>
++#include <OpenEXR/ImfIO.h>
++#include <OpenEXR/ImfInputFile.h>
++#include <OpenEXR/ImfOutputFile.h>
++#include <OpenEXR/ImfPixelType.h>
++#include <OpenEXR/ImfStandardAttributes.h>
++#include <OpenEXR/ImfStringAttribute.h>
++#include <OpenEXR/ImfVersion.h>
+
+ /* multiview/multipart */
+-#include <ImfMultiView.h>
+-#include <ImfMultiPartInputFile.h>
+-#include <ImfInputPart.h>
+-#include <ImfOutputPart.h>
+-#include <ImfMultiPartOutputFile.h>
+-#include <ImfTiledOutputPart.h>
+-#include <ImfPartType.h>
+-#include <ImfPartHelper.h>
++#include <OpenEXR/ImfInputPart.h>
++#include <OpenEXR/ImfMultiPartInputFile.h>
++#include <OpenEXR/ImfMultiPartOutputFile.h>
++#include <OpenEXR/ImfMultiView.h>
++#include <OpenEXR/ImfOutputPart.h>
++#include <OpenEXR/ImfPartHelper.h>
++#include <OpenEXR/ImfPartType.h>
++#include <OpenEXR/ImfTiledOutputPart.h>
+
+ #include "DNA_scene_types.h" /* For OpenEXR compression constants */
+
+@@ -134,15 +150,15 @@ public:
+ }
+
+ virtual bool read(char c[], int n);
+- virtual Int64 tellg();
+- virtual void seekg(Int64 pos);
++ virtual exr_file_offset_t tellg();
++ virtual void seekg(exr_file_offset_t pos);
+ virtual void clear();
+ //virtual ~Mem_IStream() {}; // unused
+
+ private:
+
+- Int64 _exrpos;
+- Int64 _exrsize;
++ exr_file_offset_t _exrpos;
++ exr_file_offset_t _exrsize;
+ unsigned char *_exrbuf;
+ };
+
+@@ -157,12 +173,12 @@ bool Mem_IStream::read(char c[], int n)
+ return false;
+ }
+
+-Int64 Mem_IStream::tellg()
++exr_file_offset_t Mem_IStream::tellg()
+ {
+ return _exrpos;
+ }
+
+-void Mem_IStream::seekg(Int64 pos)
++void Mem_IStream::seekg(exr_file_offset_t pos)
+ {
+ _exrpos = pos;
+ }
+@@ -202,12 +218,12 @@ public:
+ return check_error();
+ }
+
+- virtual Int64 tellg()
++ virtual exr_file_offset_t tellg()
+ {
+ return std::streamoff(ifs.tellg());
+ }
+
+- virtual void seekg(Int64 pos)
++ virtual void seekg(exr_file_offset_t pos)
+ {
+ ifs.seekg(pos);
+ check_error();
+@@ -262,12 +278,12 @@ public:
+ check_error();
+ }
+
+- virtual Int64 tellp()
++ virtual exr_file_offset_t tellp()
+ {
+ return std::streamoff(ofs.tellp());
+ }
+
+- virtual void seekp(Int64 pos)
++ virtual void seekp(exr_file_offset_t pos)
+ {
+ ofs.seekp(pos);
+ check_error();
diff --git a/0002_opencollada1_6_68.patch b/0002_opencollada1_6_68.patch
new file mode 100644
index 000000000000..93bdfbca9219
--- /dev/null
+++ b/0002_opencollada1_6_68.patch
@@ -0,0 +1,91 @@
+commit 7d92888cacde2d345fc2f4f6f69e9c78cb81db65
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 14:54:22 2023 +0100
+
+ opencollada: "Fix (devtalk 4053): Collada build with older cmake ver.."
+
+ Fully applied Blender upstream ref: 3552731551ef1845b493ffebf78be5a42527e9f2
+
+commit bd0befaf99b42881a72eb68257bb7b6632ef0ebe
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 14:50:12 2023 +0100
+
+ opencollada: "fix T58568 build errors when using collada 1.6.68 or n.."
+
+ Fully applied Blender upstream ref: 10c50d7dbf7578b35b3bf19a1948f556f9eb203b
+
+diff --git a/blender-2.79b/source/blender/collada/CMakeLists.txt b/blender-2.79b/source/blender/collada/CMakeLists.txt
+index 293049a..03ccf3b 100644
+--- a/blender-2.79b/source/blender/collada/CMakeLists.txt
++++ b/blender-2.79b/source/blender/collada/CMakeLists.txt
+@@ -25,6 +25,21 @@
+
+ remove_strict_flags()
+
++FIND_FILE(OPENCOLLADA_ANIMATION_CLIP
++ NAMES
++ COLLADAFWAnimationClip.h
++ PATHS
++ ${OPENCOLLADA_INCLUDE_DIRS}
++ NO_DEFAULT_PATH
++ )
++
++IF(OPENCOLLADA_ANIMATION_CLIP)
++ message(STATUS "Found opencollada: ${OPENCOLLADA_ANIMATION_CLIP} ")
++ add_definitions(-DWITH_OPENCOLLADA_ANIMATION_CLIP)
++ELSE()
++ message(STATUS "opencollada: Build without animation clip support")
++ENDIF()
++
+ set(INC
+ .
+ ../blenkernel
+diff --git a/blender-2.79b/source/blender/collada/DocumentImporter.cpp b/blender-2.79b/source/blender/collada/DocumentImporter.cpp
+index 435eaa0..c55305a 100644
+--- a/blender-2.79b/source/blender/collada/DocumentImporter.cpp
++++ b/blender-2.79b/source/blender/collada/DocumentImporter.cpp
+@@ -1340,6 +1340,19 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat
+ return anim_importer.write_animation_list(animationList);
+ }
+
++#if WITH_OPENCOLLADA_ANIMATION_CLIP
++// Since opencollada 1.6.68
++// called on post-process stage after writeVisualScenes
++bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *AnimationClip)
++{
++ if (mImportStage != General)
++ return true;
++
++ return true;
++ //return animation_clip_importer.write_animation_clip(animationClip); // TODO: implement import of AnimationClips
++}
++#endif
++
+ /** When this method is called, the writer must write the skin controller data.
+ * \return The writer should return true, if writing succeeded, false otherwise.*/
+ bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
+diff --git a/blender-2.79b/source/blender/collada/DocumentImporter.h b/blender-2.79b/source/blender/collada/DocumentImporter.h
+index 62f76db..5ad938f 100644
+--- a/blender-2.79b/source/blender/collada/DocumentImporter.h
++++ b/blender-2.79b/source/blender/collada/DocumentImporter.h
+@@ -49,8 +49,6 @@
+ #include "MeshImporter.h"
+ #include "ImportSettings.h"
+
+-
+-
+ struct bContext;
+
+ /** Importer class. */
+@@ -108,6 +106,11 @@ public:
+
+ bool writeAnimationList(const COLLADAFW::AnimationList*);
+
++#if WITH_OPENCOLLADA_ANIMATION_CLIP
++ // Please enable this when building with Collada 1.6.65 or newer (also in DocumentImporter.cpp)
++ bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *AnimationClip);
++#endif
++
+ bool writeGeometry(const COLLADAFW::Geometry*);
+
+ bool writeMaterial(const COLLADAFW::Material*);
diff --git a/0003_openvdb.patch b/0003_openvdb.patch
new file mode 100644
index 000000000000..8dd5b13215d8
--- /dev/null
+++ b/0003_openvdb.patch
@@ -0,0 +1,112 @@
+commit 5fbaf5a402b4e54b4cc9803c1da6ee01ffa939a4
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 15:13:10 2023 +0100
+
+ openvdb: compile with C++17 (openvdb 11)
+
+commit ffa4ddd68e586a7cce81a79e8fc95413268d73a7
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 15:09:21 2023 +0100
+
+ openvdb: "Cleanup: fix compiler warnings"
+
+ Partially applied Blender upstream ref: 37889011070ff2ec52159690f652238d2b325185
+
+commit 73a16ea250d7cd8b46fc16b824a54d238de66f0d
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 15:03:43 2023 +0100
+
+ openvdb: "Build: add WITH_OPENVDB_3_ABI_COMPATIBLE option."
+
+ Fully applied Blender upstream ref: 71d7d6cd8c431b7f4fac8d65a4eaedf3cff6c8f6
+
+diff --git a/blender-2.79b/CMakeLists.txt b/blender-2.79b/CMakeLists.txt
+index bfea2dd..6ad2480 100644
+--- a/blender-2.79b/CMakeLists.txt
++++ b/blender-2.79b/CMakeLists.txt
+@@ -98,6 +98,9 @@ cmake_policy(SET CMP0010 NEW)
+ # Input directories must have CMakeLists.txt
+ cmake_policy(SET CMP0014 NEW)
+
++# Silence draco warning on macOS, new policy works fine.
++cmake_policy(SET CMP0068 NEW)
++
+ #-----------------------------------------------------------------------------
+ # Load some macros.
+ include(build_files/cmake/macros.cmake)
+@@ -251,6 +254,8 @@ option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" _init_OPEN
+
+ option(WITH_OPENVDB "Enable features relying on OpenVDB" OFF)
+ option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" OFF)
++option(WITH_OPENVDB_3_ABI_COMPATIBLE "Assume OpenVDB library has been compiled with version 3 ABI compatibility" OFF)
++mark_as_advanced(WITH_OPENVDB_3_ABI_COMPATIBLE)
+
+ # GHOST Windowing Library Options
+ option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
+diff --git a/blender-2.79b/intern/opensubdiv/CMakeLists.txt b/blender-2.79b/intern/opensubdiv/CMakeLists.txt
+index 876b5c0..bf23acf 100644
+--- a/blender-2.79b/intern/opensubdiv/CMakeLists.txt
++++ b/blender-2.79b/intern/opensubdiv/CMakeLists.txt
+@@ -69,6 +69,7 @@ data_to_c_simple(gpu_shader_opensubdiv_geometry.glsl SRC)
+ data_to_c_simple(gpu_shader_opensubdiv_fragment.glsl SRC)
+
+ add_definitions(-DGLEW_STATIC)
++add_definitions(-DOSD_USES_GLEW)
+
+ if(WIN32)
+ add_definitions(-DNOMINMAX)
+diff --git a/blender-2.79b/intern/openvdb/CMakeLists.txt b/blender-2.79b/intern/openvdb/CMakeLists.txt
+index e0ecdb5..1695dc6 100644
+--- a/blender-2.79b/intern/openvdb/CMakeLists.txt
++++ b/blender-2.79b/intern/openvdb/CMakeLists.txt
+@@ -23,6 +23,8 @@
+ #
+ # ***** END GPL LICENSE BLOCK *****
+
++set(CMAKE_CXX_STANDARD 17)
++
+ set(INC
+ .
+ intern
+@@ -40,6 +42,12 @@ if(WITH_OPENVDB)
+ -DWITH_OPENVDB
+ )
+
++ if(WITH_OPENVDB_3_ABI_COMPATIBLE)
++ add_definitions(
++ -DOPENVDB_3_ABI_COMPATIBLE
++ )
++ endif()
++
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ ${TBB_INCLUDE_DIRS}
+diff --git a/blender-2.79b/intern/openvdb/intern/openvdb_writer.cc b/blender-2.79b/intern/openvdb/intern/openvdb_writer.cc
+index e886c5a..bedcfe6 100644
+--- a/blender-2.79b/intern/openvdb/intern/openvdb_writer.cc
++++ b/blender-2.79b/intern/openvdb/intern/openvdb_writer.cc
+@@ -45,7 +45,7 @@ void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid)
+
+ void OpenVDBWriter::insert(const openvdb::GridBase &grid)
+ {
+-#if (OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER == 3)
++#if (OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER <= 3) || defined(OPENVDB_3_ABI_COMPATIBLE)
+ m_grids->push_back(grid.copyGrid());
+ #else
+ m_grids->push_back(grid.copyGridWithNewTree());
+diff --git a/blender-2.79b/intern/openvdb/openvdb_util.cc b/blender-2.79b/intern/openvdb/openvdb_util.cc
+index d187f55..a09122d 100644
+--- a/blender-2.79b/intern/openvdb/openvdb_util.cc
++++ b/blender-2.79b/intern/openvdb/openvdb_util.cc
+@@ -34,5 +34,10 @@ ScopeTimer::ScopeTimer(const std::string &message)
+
+ ScopeTimer::~ScopeTimer()
+ {
+- std::printf("%s: %fms\n", m_message.c_str(), m_timer.delta());
++#if OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER >= 7
++ double delta = m_timer.milliseconds();
++#else
++ double delta = m_timer.delta(); /* Deprecated in OpenVDB 7. */
++#endif
++ std::printf("%s: %fms\n", m_message.c_str(), delta);
+ }
diff --git a/0004_openimageio.patch b/0004_openimageio.patch
new file mode 100644
index 000000000000..0a03919c2eef
--- /dev/null
+++ b/0004_openimageio.patch
@@ -0,0 +1,375 @@
+commit 6389e1fbc4db6a9d9ee283c93806f8eb5aab26bb
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 16:07:53 2023 +0100
+
+ oiio: Build with C++14
+
+commit 6b0a53306d8b6447288fc703bc6721835bf0a92e
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 15:51:05 2023 +0100
+
+ oiio: "Build: update CMake to support OpenImageIO 2.3.4"
+
+ Fully applied Blender upstream ref: e5100ca3ad17b1b9a40ffd8a8edccb6cb553e558
+
+commit f47f0eb459d739b693043f3980a180b5146fe341
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 15:41:55 2023 +0100
+
+ oiio: update on OIIO 2.0 compatibility
+
+commit 97947d9a336da23a984352cdb85cfea23d9a551a
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 15:39:06 2023 +0100
+
+ oiio: "Update code to be compatible with OIIO 2.0"
+
+ Adjusted Blender upstream ref: 66d8bfb85c61aafe3bad2edf0e7b4d9d694ee2e7
+
+diff --git a/blender-2.79b/build_files/cmake/Modules/FindOpenImageIO.cmake b/blender-2.79b/build_files/cmake/Modules/FindOpenImageIO.cmake
+index e7527f1..39c296e 100644
+--- a/blender-2.79b/build_files/cmake/Modules/FindOpenImageIO.cmake
++++ b/blender-2.79b/build_files/cmake/Modules/FindOpenImageIO.cmake
+@@ -56,6 +56,8 @@ FIND_LIBRARY(OPENIMAGEIO_LIBRARY
+ lib64 lib
+ )
+
++set(_openimageio_LIBRARIES ${OPENIMAGEIO_LIBRARY})
++
+ FIND_FILE(OPENIMAGEIO_IDIFF
+ NAMES
+ idiff
+@@ -65,15 +67,49 @@ FIND_FILE(OPENIMAGEIO_IDIFF
+ bin
+ )
+
++# Additionally find util library if needed. In old versions this library was
++# included in libOpenImageIO and linking to both would duplicate symbols. In
++# new versions we need to link to both.
++FIND_FILE(_openimageio_export
++ NAMES
++ export.h
++ PATHS
++ ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO
++ NO_DEFAULT_PATH
++)
++
++# Use existence of OIIO_UTIL_API to check if it's a separate lib.
++FILE(STRINGS "${_openimageio_export}" _openimageio_util_define
++ REGEX "^[ \t]*#[ \t]*define[ \t]+OIIO_UTIL_API.*$")
++
++IF(_openimageio_util_define)
++ FIND_LIBRARY(OPENIMAGEIO_UTIL_LIBRARY
++ NAMES
++ OpenImageIO_Util
++ HINTS
++ ${_openimageio_SEARCH_DIRS}
++ PATH_SUFFIXES
++ lib64 lib
++ )
++
++ LIST(APPEND _openimageio_LIBRARIES ${OPENIMAGEIO_UTIL_LIBRARY})
++ENDIF()
++
++# In cmake version 3.21 and up, we can instead use the NO_CACHE option for
++# FIND_FILE so we don't need to clear it from the cache here.
++UNSET(_openimageio_export CACHE)
++UNSET(_openimageio_util_define)
++
+ # handle the QUIETLY and REQUIRED arguments and set OPENIMAGEIO_FOUND to TRUE if
+ # all listed variables are TRUE
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenImageIO DEFAULT_MSG
+- OPENIMAGEIO_LIBRARY OPENIMAGEIO_INCLUDE_DIR)
++ _openimageio_LIBRARIES OPENIMAGEIO_INCLUDE_DIR)
+
+ IF(OPENIMAGEIO_FOUND)
+- SET(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY})
++ SET(OPENIMAGEIO_LIBRARIES ${_openimageio_LIBRARIES})
+ SET(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR})
++ SET(CMAKE_CXX_STANDARD 14)
+ IF(EXISTS ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO/pugixml.hpp)
+ SET(OPENIMAGEIO_PUGIXML_FOUND TRUE)
+ ELSE()
+@@ -86,7 +122,9 @@ ENDIF()
+ MARK_AS_ADVANCED(
+ OPENIMAGEIO_INCLUDE_DIR
+ OPENIMAGEIO_LIBRARY
++ OPENIMAGEIO_UTIL_LIBRARY
+ OPENIMAGEIO_IDIFF
+ )
+
+ UNSET(_openimageio_SEARCH_DIRS)
++UNSET(_openimageio_LIBRARIES)
+diff --git a/blender-2.79b/intern/cycles/blender/blender_python.cpp b/blender-2.79b/intern/cycles/blender/blender_python.cpp
+index 54973fd..bee6dd1 100644
+--- a/blender-2.79b/intern/cycles/blender/blender_python.cpp
++++ b/blender-2.79b/intern/cycles/blender/blender_python.cpp
+@@ -493,7 +493,7 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
+ socket_type = "NodeSocketString";
+ data_type = BL::NodeSocket::type_STRING;
+ if(param->validdefault)
+- default_string = param->sdefault[0];
++ default_string = param->sdefault[0].string();
+ }
+ else
+ continue;
+diff --git a/blender-2.79b/intern/cycles/graph/node_xml.cpp b/blender-2.79b/intern/cycles/graph/node_xml.cpp
+index d26b3b2..2a24104 100644
+--- a/blender-2.79b/intern/cycles/graph/node_xml.cpp
++++ b/blender-2.79b/intern/cycles/graph/node_xml.cpp
+@@ -250,7 +250,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
+ }
+ }
+
+- if(node->name)
++ if(!node->name.empty())
+ reader.node_map[node->name] = node;
+ }
+
+diff --git a/blender-2.79b/intern/cycles/render/buffers.cpp b/blender-2.79b/intern/cycles/render/buffers.cpp
+index cf402c3..6df6325 100644
+--- a/blender-2.79b/intern/cycles/render/buffers.cpp
++++ b/blender-2.79b/intern/cycles/render/buffers.cpp
+@@ -27,6 +27,7 @@
+ #include "util/util_opengl.h"
+ #include "util/util_time.h"
+ #include "util/util_types.h"
++#include "util/util_unique_ptr.h"
+
+ CCL_NAMESPACE_BEGIN
+
+@@ -453,7 +454,7 @@ void DisplayBuffer::write(Device *device, const string& filename)
+ device->pixels_copy_from(rgba, 0, w, h);
+
+ /* write image */
+- ImageOutput *out = ImageOutput::create(filename);
++ unique_ptr<ImageOutput> out(ImageOutput::create(filename));
+ ImageSpec spec(w, h, 4, TypeDesc::UINT8);
+ int scanlinesize = w*4*sizeof(uchar);
+
+@@ -467,8 +468,6 @@ void DisplayBuffer::write(Device *device, const string& filename)
+ AutoStride);
+
+ out->close();
+-
+- delete out;
+ }
+
+ device_memory& DisplayBuffer::rgba_data()
+diff --git a/blender-2.79b/intern/cycles/render/image.cpp b/blender-2.79b/intern/cycles/render/image.cpp
+index 595eb46..7829df9 100644
+--- a/blender-2.79b/intern/cycles/render/image.cpp
++++ b/blender-2.79b/intern/cycles/render/image.cpp
+@@ -23,6 +23,7 @@
+ #include "util/util_path.h"
+ #include "util/util_progress.h"
+ #include "util/util_texture.h"
++#include "util/util_unique_ptr.h"
+
+ #ifdef WITH_OSL
+ #include <OSL/oslexec.h>
+@@ -148,7 +149,7 @@ ImageDataType ImageManager::get_image_metadata(const string& filename,
+ return IMAGE_DATA_TYPE_BYTE4;
+ }
+
+- ImageInput *in = ImageInput::create(filename);
++ unique_ptr<ImageInput> in(ImageInput::create(filename));
+
+ if(in) {
+ ImageSpec spec;
+@@ -194,7 +195,6 @@ ImageDataType ImageManager::get_image_metadata(const string& filename,
+ in->close();
+ }
+
+- delete in;
+ }
+
+ if(is_half) {
+@@ -449,7 +449,7 @@ void ImageManager::tag_reload_image(const string& filename,
+ }
+
+ bool ImageManager::file_load_image_generic(Image *img,
+- ImageInput **in,
++ unique_ptr<ImageInput> *in,
+ int &width,
+ int &height,
+ int &depth,
+@@ -465,7 +465,7 @@ bool ImageManager::file_load_image_generic(Image *img,
+ }
+
+ /* load image from file through OIIO */
+- *in = ImageInput::create(img->filename);
++ *in = unique_ptr<ImageInput>(ImageInput::create(img->filename));
+
+ if(!*in)
+ return false;
+@@ -477,8 +477,6 @@ bool ImageManager::file_load_image_generic(Image *img,
+ config.attribute("oiio:UnassociatedAlpha", 1);
+
+ if(!(*in)->open(img->filename, spec, config)) {
+- delete *in;
+- *in = NULL;
+ return false;
+ }
+
+@@ -500,10 +498,7 @@ bool ImageManager::file_load_image_generic(Image *img,
+ if(!(components >= 1 && components <= 4)) {
+ if(*in) {
+ (*in)->close();
+- delete *in;
+- *in = NULL;
+ }
+-
+ return false;
+ }
+
+@@ -519,7 +514,7 @@ bool ImageManager::file_load_image(Image *img,
+ device_vector<DeviceType>& tex_img)
+ {
+ const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1;
+- ImageInput *in = NULL;
++ unique_ptr<ImageInput> in = NULL;
+ int width, height, depth, components;
+ if(!file_load_image_generic(img, &in, width, height, depth, components)) {
+ return false;
+@@ -575,7 +570,6 @@ bool ImageManager::file_load_image(Image *img,
+ }
+ cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
+ in->close();
+- delete in;
+ }
+ else {
+ if(FileFormat == TypeDesc::FLOAT) {
+diff --git a/blender-2.79b/intern/cycles/render/image.h b/blender-2.79b/intern/cycles/render/image.h
+index db7e28a..f4a14f4 100644
+--- a/blender-2.79b/intern/cycles/render/image.h
++++ b/blender-2.79b/intern/cycles/render/image.h
+@@ -23,6 +23,7 @@
+ #include "util/util_image.h"
+ #include "util/util_string.h"
+ #include "util/util_thread.h"
++#include "util/util_unique_ptr.h"
+ #include "util/util_vector.h"
+
+ CCL_NAMESPACE_BEGIN
+@@ -133,7 +134,7 @@ private:
+ bool pack_images;
+
+ bool file_load_image_generic(Image *img,
+- ImageInput **in,
++ unique_ptr<ImageInput> *in,
+ int &width,
+ int &height,
+ int &depth,
+diff --git a/blender-2.79b/intern/cycles/util/util_unique_ptr.h b/blender-2.79b/intern/cycles/util/util_unique_ptr.h
+new file mode 100644
+index 0000000..1ceae73
+--- /dev/null
++++ b/blender-2.79b/intern/cycles/util/util_unique_ptr.h
+@@ -0,0 +1,28 @@
++/*
++ * Copyright 2011-2013 Blender Foundation
++ *
++ * Licensed under the Apache License, Version 2.0 (the "License");
++ * you may not use this file except in compliance with the License.
++ * You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++#ifndef __UTIL_UNIQUE_PTR_H__
++#define __UTIL_UNIQUE_PTR_H__
++
++#include <memory>
++
++CCL_NAMESPACE_BEGIN
++
++using std::unique_ptr;
++
++CCL_NAMESPACE_END
++
++#endif /* __UTIL_UNIQUE_PTR_H__ */
+diff --git a/blender-2.79b/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/blender-2.79b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+index b123d50..c31dc38 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
++++ b/blender-2.79b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+@@ -35,6 +35,11 @@
+ #include "utfconv.h"
+ #endif
+
++// NOTE: Keep first, BLI_path_util conflicts with OIIO's format.
++#include <memory>
++#include <openimageio_api.h>
++#include <OpenImageIO/imageio.h>
++
+ extern "C"
+ {
+ #include "MEM_guardedalloc.h"
+@@ -48,12 +53,11 @@ extern "C"
+ #include "IMB_colormanagement_intern.h"
+ }
+
+-#include <openimageio_api.h>
+-#include <OpenImageIO/imageio.h>
+
+ OIIO_NAMESPACE_USING
+
+ using std::string;
++using std::unique_ptr;
+
+ typedef unsigned char uchar;
+
+@@ -197,7 +201,6 @@ int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags)
+
+ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspace[IM_MAX_SPACE])
+ {
+- ImageInput *in = NULL;
+ struct ImBuf *ibuf = NULL;
+ int width, height, components;
+ bool is_float, is_alpha;
+@@ -210,7 +213,7 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
+
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+
+- in = ImageInput::create(filename);
++ unique_ptr<ImageInput> in(ImageInput::create(filename));
+ if (!in) {
+ std::cerr << __func__ << ": ImageInput::create() failed:" << std::endl
+ << OIIO_NAMESPACE::geterror() << std::endl;
+@@ -223,7 +226,6 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
+ if (!in->open(filename, spec, config)) {
+ std::cerr << __func__ << ": ImageInput::open() failed:" << std::endl
+ << in->geterror() << std::endl;
+- delete in;
+ return NULL;
+ }
+
+@@ -249,19 +251,17 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
+ if (!(components >= 1 && components <= 4)) {
+ if (in) {
+ in->close();
+- delete in;
+ }
+ return NULL;
+ }
+
+ if (is_float)
+- ibuf = imb_oiio_load_image_float(in, width, height, components, flags, is_alpha);
++ ibuf = imb_oiio_load_image_float(in.get(), width, height, components, flags, is_alpha);
+ else
+- ibuf = imb_oiio_load_image(in, width, height, components, flags, is_alpha);
++ ibuf = imb_oiio_load_image(in.get(), width, height, components, flags, is_alpha);
+
+ if (in) {
+ in->close();
+- delete in;
+ }
+
+ if (!ibuf)
diff --git a/0005_cycles.patch b/0005_cycles.patch
new file mode 100644
index 000000000000..483f1c4c42a2
--- /dev/null
+++ b/0005_cycles.patch
@@ -0,0 +1,155 @@
+commit c4818aa2fc716446ff3a109b18e63ff4ef79ff4c
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 17:21:32 2023 +0100
+
+ cycles: "Cycles: Cleanup, silence strict compiler warning"
+
+ Partially applied Blender upstream ref: b763c34e80d3b20f9a7f0a592e479e5fa7ab295f
+
+commit c9f8cf23a076854f5dddae5f72a8182be2468118
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 17:07:44 2023 +0100
+
+ cycles: "Fix Cycles build error with OSL 1.12"
+
+ Fully applied Blender upstream ref: 340529a8453ca9c2715c545245379e442f6006c8
+
+commit e47121b7cbfdbde9c9eb39b5e1bcf1c54a5e3a29
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 17:05:53 2023 +0100
+
+ cycles: "Cycles: Fix bad register cast in sseb"
+
+ Fully applied Blender upstream ref: be587d76efff6610f3b6d65cf42f1ee31ec3bdee
+
+diff --git a/blender-2.79b/intern/cycles/blender/blender_camera.cpp b/blender-2.79b/intern/cycles/blender/blender_camera.cpp
+index b29711d..0c4a48f 100644
+--- a/blender-2.79b/intern/cycles/blender/blender_camera.cpp
++++ b/blender-2.79b/intern/cycles/blender/blender_camera.cpp
+@@ -86,7 +86,7 @@ struct BlenderCamera {
+ static void blender_camera_init(BlenderCamera *bcam,
+ BL::RenderSettings& b_render)
+ {
+- memset(bcam, 0, sizeof(BlenderCamera));
++ memset((void *)bcam, 0, sizeof(BlenderCamera));
+
+ bcam->type = CAMERA_PERSPECTIVE;
+ bcam->zoom = 1.0f;
+diff --git a/blender-2.79b/intern/cycles/blender/blender_util.h b/blender-2.79b/intern/cycles/blender/blender_util.h
+index 363e19f..f697156 100644
+--- a/blender-2.79b/intern/cycles/blender/blender_util.h
++++ b/blender-2.79b/intern/cycles/blender/blender_util.h
+@@ -251,7 +251,7 @@ static inline Transform get_transform(const BL::Array<float, 16>& array)
+
+ /* we assume both types to be just 16 floats, and transpose because blender
+ * use column major matrix order while we use row major */
+- memcpy(&tfm, &array, sizeof(float)*16);
++ memcpy((void *)&tfm, &array, sizeof(float)*16);
+ tfm = transform_transpose(tfm);
+
+ return tfm;
+diff --git a/blender-2.79b/intern/cycles/bvh/bvh_params.h b/blender-2.79b/intern/cycles/bvh/bvh_params.h
+index 7dd699b..75bf5ab 100644
+--- a/blender-2.79b/intern/cycles/bvh/bvh_params.h
++++ b/blender-2.79b/intern/cycles/bvh/bvh_params.h
+@@ -156,7 +156,10 @@ public:
+
+ BVHReference& operator=(const BVHReference &arg) {
+ if(&arg != this) {
+- memcpy(this, &arg, sizeof(BVHReference));
++ /* TODO(sergey): Check if it is still faster to memcpy() with
++ * modern compilers.
++ */
++ memcpy((void *)this, &arg, sizeof(BVHReference));
+ }
+ return *this;
+ }
+diff --git a/blender-2.79b/intern/cycles/kernel/closure/alloc.h b/blender-2.79b/intern/cycles/kernel/closure/alloc.h
+index e799855..ff1de14 100644
+--- a/blender-2.79b/intern/cycles/kernel/closure/alloc.h
++++ b/blender-2.79b/intern/cycles/kernel/closure/alloc.h
+@@ -78,7 +78,7 @@ ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd, int size, float3
+ if(!sc)
+ return NULL;
+
+- memcpy(sc, data, size);
++ memcpy((void *)sc, data, size);
+
+ float sample_weight = fabsf(average(weight));
+ sc->weight = weight;
+diff --git a/blender-2.79b/intern/cycles/kernel/osl/osl_services.h b/blender-2.79b/intern/cycles/kernel/osl/osl_services.h
+index ec34ca7..29055ea 100644
+--- a/blender-2.79b/intern/cycles/kernel/osl/osl_services.h
++++ b/blender-2.79b/intern/cycles/kernel/osl/osl_services.h
+@@ -25,8 +25,9 @@
+ * attributes.
+ */
+
+-#include <OSL/oslexec.h>
+ #include <OSL/oslclosure.h>
++#include <OSL/oslexec.h>
++#include <OSL/rendererservices.h>
+
+ #ifdef WITH_PTEX
+ class PtexCache;
+diff --git a/blender-2.79b/intern/cycles/kernel/osl/osl_shader.cpp b/blender-2.79b/intern/cycles/kernel/osl/osl_shader.cpp
+index 13b19d8..4ad6b74 100644
+--- a/blender-2.79b/intern/cycles/kernel/osl/osl_shader.cpp
++++ b/blender-2.79b/intern/cycles/kernel/osl/osl_shader.cpp
+@@ -53,7 +53,7 @@ void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OS
+ OSL::ShadingSystem *ss = kg->osl->ss;
+ OSLThreadData *tdata = new OSLThreadData();
+
+- memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
++ memset((void *)&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
+ tdata->globals.tracedata = &tdata->tracedata;
+ tdata->globals.flipHandedness = false;
+ tdata->osl_thread_info = ss->create_thread_info();
+diff --git a/blender-2.79b/intern/cycles/render/svm.cpp b/blender-2.79b/intern/cycles/render/svm.cpp
+index 48287d8..0111d75 100644
+--- a/blender-2.79b/intern/cycles/render/svm.cpp
++++ b/blender-2.79b/intern/cycles/render/svm.cpp
+@@ -721,7 +721,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
+ }
+
+ /* clear all compiler state */
+- memset(&active_stack, 0, sizeof(active_stack));
++ memset((void *)&active_stack, 0, sizeof(active_stack));
+ current_svm_nodes.clear();
+
+ foreach(ShaderNode *node_iter, graph->nodes) {
+diff --git a/blender-2.79b/intern/cycles/util/util_sseb.h b/blender-2.79b/intern/cycles/util/util_sseb.h
+index 6e66970..9ffe391 100644
+--- a/blender-2.79b/intern/cycles/util/util_sseb.h
++++ b/blender-2.79b/intern/cycles/util/util_sseb.h
+@@ -116,7 +116,7 @@ __forceinline const sseb unpacklo( const sseb& a, const sseb& b ) { return _mm_u
+ __forceinline const sseb unpackhi( const sseb& a, const sseb& b ) { return _mm_unpackhi_ps(a, b); }
+
+ template<size_t i0, size_t i1, size_t i2, size_t i3> __forceinline const sseb shuffle( const sseb& a ) {
+- return _mm_shuffle_epi32(a, _MM_SHUFFLE(i3, i2, i1, i0));
++ return _mm_castsi128_ps(_mm_shuffle_epi32(a, _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline const sseb shuffle<0, 1, 0, 1>( const sseb& a ) {
+diff --git a/blender-2.79b/intern/cycles/util/util_vector.h b/blender-2.79b/intern/cycles/util/util_vector.h
+index 4add91a..caa6490 100644
+--- a/blender-2.79b/intern/cycles/util/util_vector.h
++++ b/blender-2.79b/intern/cycles/util/util_vector.h
+@@ -131,7 +131,7 @@ public:
+ {
+ if(this != &from) {
+ resize(from.size());
+- memcpy(data_, from.data_, datasize_*sizeof(T));
++ memcpy((void*)data_, from.data_, datasize_*sizeof(T));
+ }
+
+ return *this;
+@@ -191,7 +191,7 @@ public:
+ return NULL;
+ }
+ else if(data_ != NULL) {
+- memcpy(newdata, data_, ((datasize_ < newsize)? datasize_: newsize)*sizeof(T));
++ memcpy((void *)newdata, data_, ((datasize_ < newsize)? datasize_: newsize)*sizeof(T));
+ mem_free(data_, capacity_);
+ }
+ data_ = newdata;
diff --git a/0006_python3_7.patch b/0006_python3_7.patch
new file mode 100644
index 000000000000..f00e0d6611ae
--- /dev/null
+++ b/0006_python3_7.patch
@@ -0,0 +1,66 @@
+commit 00f84e4cb1efc02149d9c04df79048c04351e46a
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 01:13:47 2023 +0100
+
+ python3.7: "Cleanup: remove deprecated PyEval_InitThreads use"
+
+ Fully applied Blender upstream ref: d377b1fe762c24ee74805ea8c1f666f121399698
+
+commit a6323887a2db1acd10bd0fd1539fb8c061efc7f3
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 17:51:18 2023 +0100
+
+ python3.7: "Fix PyRNA class registration w/ Python 3.7"
+
+ Fully applied Blender upstream ref: 1db47a2ccd1e68994bf8140eba6cc2a26a2bc91f
+
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_interface.c b/blender-2.79b/source/blender/python/intern/bpy_interface.c
+index 20cfd36..6077418 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_interface.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_interface.c
+@@ -268,6 +268,7 @@ void BPY_python_start(int argc, const char **argv)
+
+ Py_FrozenFlag = 1;
+
++ /* Initialize Python (also acquires lock). */
+ Py_Initialize();
+
+ // PySys_SetArgv(argc, argv); /* broken in py3, not a huge deal */
+@@ -284,9 +285,7 @@ void BPY_python_start(int argc, const char **argv)
+ PySys_SetObject("argv", py_argv);
+ Py_DECREF(py_argv);
+ }
+-
+- /* Initialize thread support (also acquires lock) */
+- PyEval_InitThreads();
++
+ #else
+ (void)argc;
+ (void)argv;
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_rna.c b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+index 0d3781c..832a872 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_rna.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+@@ -7385,10 +7385,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
+ if (!(flag & PROP_REGISTER))
+ continue;
+
++ /* TODO(campbell): Use Python3.7x _PyObject_LookupAttr(), also in the macro below. */
+ identifier = RNA_property_identifier(prop);
+ item = PyObject_GetAttrString(py_class, identifier);
+
+ if (item == NULL) {
++ PyErr_Clear();
+ /* Sneaky workaround to use the class name as the bl_idname */
+
+ #define BPY_REPLACEMENT_STRING(rna_attr, py_attr) \
+@@ -7404,6 +7406,9 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
+ } \
+ Py_DECREF(item); \
+ } \
++ else { \
++ PyErr_Clear(); \
++ } \
+ } /* intentionally allow else here */
+
+ if (false) {} /* needed for macro */
diff --git a/0007_python3_8.patch b/0007_python3_8.patch
new file mode 100644
index 000000000000..f71dd60f4321
--- /dev/null
+++ b/0007_python3_8.patch
@@ -0,0 +1,608 @@
+commit fce4c8799bcddb8a159d4c3cd1480cf174d02ee4
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 02:43:28 2023 +0100
+
+ python3.8: "Cleanup: define PY_SSIZE_T_CLEAN for Python"
+
+ Fully applied Blender upstream ref: 9dd5e3b6e89ca0be4207e64439f292519eaf7e6e
+
+commit 89c9462c0a921b6af37043ee2ab147c60cd0f422
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 01:49:26 2023 +0100
+
+ python3.8: "PyAPI: use public API's for module & builtin access"
+
+ Partially applied Blender upstream ref: e413b39a936181cc954dfbf054b0a19794d8902c
+
+commit 2b0312742399a9143f33a78a4f5ceedd08d178d6
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 00:53:34 2023 +0100
+
+ python3.8: "Cleanup: warnings building with Python 3.8"
+
+ Adjusted Blender upstream ref: 36b6fb5cd600a7067d24cfe836c0af4d94e083e4
+
+commit 2093b30818fcddf1f0d2d0011bae023d9124b351
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 00:23:26 2023 +0100
+
+ python3.8: "Cleanup: use PyImport_GetModuleDict"
+
+ Adjusted Blender upstream ref: 44f719b63238503ef8f933f55383c6d4798995cc
+
+diff --git a/blender-2.79b/source/blender/python/bmesh/bmesh_py_api.c b/blender-2.79b/source/blender/python/bmesh/bmesh_py_api.c
+index d5973ba..d7324ea 100644
+--- a/blender-2.79b/source/blender/python/bmesh/bmesh_py_api.c
++++ b/blender-2.79b/source/blender/python/bmesh/bmesh_py_api.c
+@@ -196,7 +196,7 @@ PyObject *BPyInit_bmesh(void)
+ {
+ PyObject *mod;
+ PyObject *submodule;
+- PyObject *sys_modules = PyThreadState_GET()->interp->modules;
++ PyObject *sys_modules = PyImport_GetModuleDict();
+
+ BPy_BM_init_types();
+ BPy_BM_init_types_select();
+diff --git a/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c b/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c
+index ee96c85..ea37159 100644
+--- a/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c
++++ b/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c
+@@ -142,7 +142,7 @@ static PyTypeObject bmesh_op_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -260,7 +260,7 @@ static PyTypeObject bmesh_ops_fakemod_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+diff --git a/blender-2.79b/source/blender/python/generic/blf_py_api.c b/blender-2.79b/source/blender/python/generic/blf_py_api.c
+index 69f1e29..bf8259f 100644
+--- a/blender-2.79b/source/blender/python/generic/blf_py_api.c
++++ b/blender-2.79b/source/blender/python/generic/blf_py_api.c
+@@ -26,6 +26,9 @@
+ * This file defines the 'bgl' module, used for drawing text in OpenGL.
+ */
+
++/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
++#define PY_SSIZE_T_CLEAN
++
+ #include <Python.h>
+ #include "blf_py_api.h"
+
+@@ -150,7 +153,7 @@ PyDoc_STRVAR(py_blf_draw_doc,
+ static PyObject *py_blf_draw(PyObject *UNUSED(self), PyObject *args)
+ {
+ const char *text;
+- int text_length;
++ Py_ssize_t text_length;
+ int fontid;
+
+ if (!PyArg_ParseTuple(args, "is#:blf.draw", &fontid, &text, &text_length))
+diff --git a/blender-2.79b/source/blender/python/generic/idprop_py_api.c b/blender-2.79b/source/blender/python/generic/idprop_py_api.c
+index 5d6a7c5..576f114 100644
+--- a/blender-2.79b/source/blender/python/generic/idprop_py_api.c
++++ b/blender-2.79b/source/blender/python/generic/idprop_py_api.c
+@@ -1166,7 +1166,7 @@ PyTypeObject BPy_IDGroup_Type = {
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+@@ -1560,7 +1560,7 @@ PyTypeObject BPy_IDArray_Type = {
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+@@ -1675,7 +1675,7 @@ PyTypeObject BPy_IDGroup_Iter_Type = {
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+@@ -1792,7 +1792,7 @@ PyObject *BPyInit_idprop(void)
+ {
+ PyObject *mod;
+ PyObject *submodule;
+- PyObject *sys_modules = PyThreadState_GET()->interp->modules;
++ PyObject *sys_modules = PyImport_GetModuleDict();
+
+ mod = PyModule_Create(&IDProp_module_def);
+
+diff --git a/blender-2.79b/source/blender/python/generic/py_capi_utils.c b/blender-2.79b/source/blender/python/generic/py_capi_utils.c
+index 861e2db..f4a2595 100644
+--- a/blender-2.79b/source/blender/python/generic/py_capi_utils.c
++++ b/blender-2.79b/source/blender/python/generic/py_capi_utils.c
+@@ -29,6 +29,9 @@
+ * BLI_string_utf8() for unicode conversion.
+ */
+
++/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
++#define PY_SSIZE_T_CLEAN
++
+ #include <Python.h>
+ #include <frameobject.h>
+
+@@ -638,9 +641,10 @@ PyObject *PyC_UnicodeFromByte(const char *str)
+ ****************************************************************************/
+ PyObject *PyC_DefaultNameSpace(const char *filename)
+ {
+- PyInterpreterState *interp = PyThreadState_GET()->interp;
++ PyObject *modules = PyImport_GetModuleDict();
++ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *mod_main = PyModule_New("__main__");
+- PyDict_SetItemString(interp->modules, "__main__", mod_main);
++ PyDict_SetItemString(modules, "__main__", mod_main);
+ Py_DECREF(mod_main); /* sys.modules owns now */
+ PyModule_AddStringConstant(mod_main, "__name__", "__main__");
+ if (filename) {
+@@ -648,23 +652,23 @@ PyObject *PyC_DefaultNameSpace(const char *filename)
+ * note: this wont map to a real file when executing text-blocks and buttons. */
+ PyModule_AddObject(mod_main, "__file__", PyC_UnicodeFromByte(filename));
+ }
+- PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
+- Py_INCREF(interp->builtins); /* AddObject steals a reference */
++ PyModule_AddObject(mod_main, "__builtins__", builtins);
++ Py_INCREF(builtins); /* AddObject steals a reference */
+ return PyModule_GetDict(mod_main);
+ }
+
+ /* restore MUST be called after this */
+ void PyC_MainModule_Backup(PyObject **main_mod)
+ {
+- PyInterpreterState *interp = PyThreadState_GET()->interp;
+- *main_mod = PyDict_GetItemString(interp->modules, "__main__");
++ PyObject *modules = PyImport_GetModuleDict();
++ *main_mod = PyDict_GetItemString(modules, "__main__");
+ Py_XINCREF(*main_mod); /* don't free */
+ }
+
+ void PyC_MainModule_Restore(PyObject *main_mod)
+ {
+- PyInterpreterState *interp = PyThreadState_GET()->interp;
+- PyDict_SetItemString(interp->modules, "__main__", main_mod);
++ PyObject *modules = PyImport_GetModuleDict();
++ PyDict_SetItemString(modules, "__main__", main_mod);
+ Py_XDECREF(main_mod);
+ }
+
+@@ -732,7 +736,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
+
+ va_list vargs;
+
+- int *sizes = PyMem_MALLOC(sizeof(int) * (n / 2));
++ Py_ssize_t *sizes = PyMem_MALLOC(sizeof(*sizes) * (n / 2));
+ int i;
+
+ PyObject *py_dict = PyC_DefaultNameSpace(filepath);
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_app_translations.c b/blender-2.79b/source/blender/python/intern/bpy_app_translations.c
+index 6ba858f..1b853be 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_app_translations.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_app_translations.c
+@@ -714,7 +714,7 @@ static PyTypeObject BlenderAppTranslationsType = {
+ /* methods */
+ /* No destructor, this is a singleton! */
+ NULL, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_interface.c b/blender-2.79b/source/blender/python/intern/bpy_interface.c
+index 6077418..0d36ba1 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_interface.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_interface.c
+@@ -529,7 +529,7 @@ static bool python_script_exec(
+
+ if (py_dict) {
+ #ifdef PYMODULE_CLEAR_WORKAROUND
+- PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItemString(PyThreadState_GET()->interp->modules, "__main__");
++ PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItemString(PyImport_GetModuleDict(), "__main__");
+ PyObject *dict_back = mmod->md_dict;
+ /* freeing the module will clear the namespace,
+ * gives problems running classes defined in this namespace being used later. */
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_library_load.c b/blender-2.79b/source/blender/python/intern/bpy_library_load.c
+index cb6a714..c8fd392 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_library_load.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_library_load.c
+@@ -98,7 +98,7 @@ static PyTypeObject bpy_lib_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)bpy_lib_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_props.c b/blender-2.79b/source/blender/python/intern/bpy_props.c
+index 3a18167..2b8e356 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_props.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_props.c
+@@ -28,6 +28,8 @@
+ * existing blender types.
+ */
+
++/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
++#define PY_SSIZE_T_CLEAN
+
+ #include <Python.h>
+
+@@ -2012,7 +2014,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
+ static const char *kwlist[] = {"attr", "name", "description", "default",
+ "options", "subtype", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ bool def = false;
+ PropertyRNA *prop;
+ PyObject *pyopts = NULL;
+@@ -2094,7 +2096,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
+ static const char *kwlist[] = {"attr", "name", "description", "default",
+ "options", "subtype", "size", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ int def[PYRNA_STACK_ARRAY] = {0};
+ int size = 3;
+ PropertyRNA *prop;
+@@ -2199,7 +2201,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
+ "min", "max", "soft_min", "soft_max",
+ "step", "options", "subtype", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0;
+ PropertyRNA *prop;
+ PyObject *pyopts = NULL;
+@@ -2296,7 +2298,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
+ "min", "max", "soft_min", "soft_max",
+ "step", "options", "subtype", "size", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1;
+ int def[PYRNA_STACK_ARRAY] = {0};
+ int size = 3;
+@@ -2410,7 +2412,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
+ "step", "precision", "options", "subtype",
+ "unit", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3, def = 0.0f;
+ int precision = 2;
+ PropertyRNA *prop;
+@@ -2521,7 +2523,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
+ "step", "precision", "options", "subtype",
+ "unit", "size", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3;
+ float def[PYRNA_STACK_ARRAY] = {0.0f};
+ int precision = 2, size = 3;
+@@ -2628,7 +2630,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
+ static const char *kwlist[] = {"attr", "name", "description", "default",
+ "maxlen", "options", "subtype", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "", *def = "";
+- int id_len;
++ Py_ssize_t id_len;
+ int maxlen = 0;
+ PropertyRNA *prop;
+ PyObject *pyopts = NULL;
+@@ -2738,7 +2740,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
+ "options", "update", "get", "set", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+ PyObject *def = NULL;
+- int id_len;
++ Py_ssize_t id_len;
+ int defvalue = 0;
+ PyObject *items, *items_fast;
+ EnumPropertyItem *eitems;
+@@ -2886,7 +2888,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
+ if (srna) {
+ static const char *kwlist[] = {"attr", "type", "name", "description", "options", "poll", "update", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ PropertyRNA *prop;
+ StructRNA *ptype;
+ PyObject *type = Py_None;
+@@ -2960,7 +2962,7 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
+ if (srna) {
+ static const char *kwlist[] = {"attr", "type", "name", "description", "options", NULL};
+ const char *id = NULL, *name = NULL, *description = "";
+- int id_len;
++ Py_ssize_t id_len;
+ PropertyRNA *prop;
+ StructRNA *ptype;
+ PyObject *type = Py_None;
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_rna.c b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+index 832a872..b473398 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_rna.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+@@ -5647,7 +5647,7 @@ PyTypeObject pyrna_struct_meta_idprop_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* deprecated in python 3.0! */
+@@ -5729,7 +5729,7 @@ PyTypeObject pyrna_struct_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor) pyrna_struct_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -5818,7 +5818,7 @@ PyTypeObject pyrna_prop_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor) pyrna_prop_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -5902,7 +5902,7 @@ PyTypeObject pyrna_prop_array_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)pyrna_prop_array_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -5985,7 +5985,7 @@ PyTypeObject pyrna_prop_collection_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)pyrna_prop_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -6070,7 +6070,7 @@ static PyTypeObject pyrna_prop_collection_idprop_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)pyrna_prop_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -6155,7 +6155,7 @@ PyTypeObject pyrna_func_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+@@ -6251,7 +6251,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)pyrna_prop_collection_iter_dealloc, /* tp_dealloc */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+diff --git a/blender-2.79b/source/blender/python/intern/gpu.c b/blender-2.79b/source/blender/python/intern/gpu.c
+index 48230a7..25016c5 100644
+--- a/blender-2.79b/source/blender/python/intern/gpu.c
++++ b/blender-2.79b/source/blender/python/intern/gpu.c
+@@ -323,7 +323,7 @@ PyObject *GPU_initPython(void)
+ {
+ PyObject *module;
+ PyObject *submodule;
+- PyObject *sys_modules = PyThreadState_GET()->interp->modules;
++ PyObject *sys_modules = PyImport_GetModuleDict();
+
+ module = PyInit_gpu();
+
+@@ -334,7 +334,7 @@ PyObject *GPU_initPython(void)
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
+ Py_INCREF(submodule);
+
+- PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module);
++ PyDict_SetItem(sys_modules, PyModule_GetNameObject(module), module);
+ return module;
+ }
+
+diff --git a/blender-2.79b/source/blender/python/intern/gpu_offscreen.c b/blender-2.79b/source/blender/python/intern/gpu_offscreen.c
+index 7711ce1..d301599 100644
+--- a/blender-2.79b/source/blender/python/intern/gpu_offscreen.c
++++ b/blender-2.79b/source/blender/python/intern/gpu_offscreen.c
+@@ -293,7 +293,7 @@ static PyTypeObject BPy_GPUOffScreen_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)BPy_GPUOffScreen__tp_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils.c b/blender-2.79b/source/blender/python/mathutils/mathutils.c
+index 96ae0a9..21d3624 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils.c
+@@ -622,7 +622,7 @@ PyMODINIT_FUNC PyInit_mathutils(void)
+ {
+ PyObject *mod;
+ PyObject *submodule;
+- PyObject *sys_modules = PyThreadState_GET()->interp->modules;
++ PyObject *sys_modules = PyImport_GetModuleDict();
+
+ if (PyType_Ready(&vector_Type) < 0)
+ return NULL;
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Color.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Color.c
+index 9997cd9..b12982e 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Color.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Color.c
+@@ -846,7 +846,7 @@ PyTypeObject color_Type = {
+ sizeof(ColorObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BaseMathObject_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c
+index 9492b6d..494b5ea 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c
+@@ -700,7 +700,7 @@ PyTypeObject euler_Type = {
+ sizeof(EulerObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BaseMathObject_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
+index e368e88..1b05aae 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
+@@ -2768,7 +2768,7 @@ PyTypeObject matrix_Type = {
+ sizeof(MatrixObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)BaseMathObject_dealloc, /*tp_dealloc*/
+- NULL, /*tp_print*/
++ (printfunc)NULL, /*tp_print*/
+ NULL, /*tp_getattr*/
+ NULL, /*tp_setattr*/
+ NULL, /*tp_compare*/
+@@ -3092,7 +3092,7 @@ PyTypeObject matrix_access_Type = {
+ sizeof(MatrixAccessObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)MatrixAccess_dealloc, /*tp_dealloc*/
+- NULL, /*tp_print*/
++ (printfunc)NULL, /*tp_print*/
+ NULL, /*tp_getattr*/
+ NULL, /*tp_setattr*/
+ NULL, /*tp_compare*/
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c
+index d283c71..02aabd0 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c
+@@ -1275,7 +1275,7 @@ PyTypeObject quaternion_Type = {
+ sizeof(QuaternionObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BaseMathObject_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c
+index afc8a30..af73aa2 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c
+@@ -2887,7 +2887,7 @@ PyTypeObject vector_Type = {
+ /* Methods to implement standard operations */
+
+ (destructor) BaseMathObject_dealloc, /* destructor tp_dealloc; */
+- NULL, /* printfunc tp_print; */
++ (printfunc)NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_bvhtree.c b/blender-2.79b/source/blender/python/mathutils/mathutils_bvhtree.c
+index 30c0cda..c3b28e7 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_bvhtree.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_bvhtree.c
+@@ -1243,7 +1243,7 @@ PyTypeObject PyBVHTree_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)py_bvhtree__tp_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_kdtree.c b/blender-2.79b/source/blender/python/mathutils/mathutils_kdtree.c
+index ca66c19..2e36a08 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_kdtree.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_kdtree.c
+@@ -415,7 +415,7 @@ PyTypeObject PyKDTree_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)PyKDTree__tp_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_noise.c b/blender-2.79b/source/blender/python/mathutils/mathutils_noise.c
+index 143e51e..f9d128f 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_noise.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_noise.c
+@@ -842,16 +842,17 @@ PyMODINIT_FUNC PyInit_mathutils_noise(void)
+ {
+ PyObject *submodule = PyModule_Create(&M_Noise_module_def);
+ PyObject *item_types, *item_metrics;
++ PyObject *sys_modules = PyImport_GetModuleDict();
+
+ /* use current time as seed for random number generator by default */
+ setRndSeed(0);
+
+ PyModule_AddObject(submodule, "types", (item_types = PyInit_mathutils_noise_types()));
+- PyDict_SetItemString(PyThreadState_GET()->interp->modules, "noise.types", item_types);
++ PyDict_SetItemString(sys_modules, "noise.types", item_types);
+ Py_INCREF(item_types);
+
+ PyModule_AddObject(submodule, "distance_metrics", (item_metrics = PyInit_mathutils_noise_metrics()));
+- PyDict_SetItemString(PyThreadState_GET()->interp->modules, "noise.distance_metrics", item_metrics);
++ PyDict_SetItemString(sys_modules, "noise.distance_metrics", item_metrics);
+ Py_INCREF(item_metrics);
+
+ return submodule;
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp
+index 97a7e16..71e610d 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp
+@@ -1569,7 +1569,7 @@ PyTypeObject PyRASOffScreen_Type = {
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)PyRASOffScreen__tp_dealloc, /* tp_dealloc */
+- NULL, /* tp_print */
++ (printfunc)NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+@@ -2239,7 +2239,7 @@ PyMODINIT_FUNC initBGE(void)
+ {
+ PyObject *mod;
+ PyObject *submodule;
+- PyObject *sys_modules = PyThreadState_GET()->interp->modules;
++ PyObject *sys_modules = PyImport_GetModuleDict();
+ const char *mod_full;
+
+ mod = PyModule_Create(&BGE_module_def);
diff --git a/0008_python3_9.patch b/0008_python3_9.patch
new file mode 100644
index 000000000000..46644957a874
--- /dev/null
+++ b/0008_python3_9.patch
@@ -0,0 +1,229 @@
+commit cef9646dbecd745b70f10501477fd7497e874f19
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 01:22:11 2023 +0100
+
+ python3.9: "Fix crash starting Blender with Python 3.9"
+
+ Fully applied Blender upstream ref: 0133bcaf38f6ecb5d6937c9b762026cc452720de
+
+commit 500ea8f791406747ec430e654cabe8a5a90f5dad
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 01:07:33 2023 +0100
+
+ python3.9: "Fix T81688: BPY_thread_save crashes with Python 3.9"
+
+ Fully applied Blender upstream ref: 5edba9b42f684bf8b99894bb6988e7f46180e12c
+
+commit 1a02a89e57a5fcd61da7cf7c2949250ccc88c6bf
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 02:10:10 2023 +0100
+
+ python3.9: "Python: support building again version 3.9 (unreleased)"
+
+ Fully applied Blender upstream ref: 56d0df51a36fdce7ec2d1fbb7b47b1d95b591b5f
+
+diff --git a/blender-2.79b/source/blender/python/generic/bpy_threads.c b/blender-2.79b/source/blender/python/generic/bpy_threads.c
+index fbc1456..628e28f 100644
+--- a/blender-2.79b/source/blender/python/generic/bpy_threads.c
++++ b/blender-2.79b/source/blender/python/generic/bpy_threads.c
+@@ -35,14 +35,11 @@
+ /* analogue of PyEval_SaveThread() */
+ BPy_ThreadStatePtr BPY_thread_save(void)
+ {
+- PyThreadState *tstate = PyThreadState_Swap(NULL);
+- /* note: tstate can be NULL when quitting Blender */
+-
+- if (tstate && PyEval_ThreadsInitialized()) {
+- PyEval_ReleaseLock();
++ /* The thread-state can be NULL when quitting Blender. */
++ if (_PyThreadState_UncheckedGet()) {
++ return (BPy_ThreadStatePtr)PyEval_SaveThread();
+ }
+-
+- return (BPy_ThreadStatePtr)tstate;
++ return NULL;
+ }
+
+ /* analogue of PyEval_RestoreThread() */
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_rna.c b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+index b473398..26a4351 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_rna.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+@@ -7321,13 +7321,15 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
+ PyErr_Clear();
+ }
+ else {
+- Py_DECREF(item); /* no need to keep a ref, the class owns it (technically we should keep a ref but...) */
++ /* Store original so we can decrement it's reference before returning. */
++ PyObject *item_orig = item;
+ if (is_staticmethod) {
+ if (PyMethod_Check(item) == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a static/class method, not a %.200s",
+ class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name);
++ Py_DECREF(item_orig);
+ return -1;
+ }
+ item = ((PyMethodObject *)item)->im_func;
+@@ -7338,6 +7340,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a function, not a %.200s",
+ class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name);
++ Py_DECREF(item_orig);
+ return -1;
+ }
+ }
+@@ -7369,9 +7372,11 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
+ class_type, py_class_name, RNA_function_identifier(func),
+ func_arg_count, arg_count);
+ }
++ Py_DECREF(item_orig);
+ return -1;
+ }
+ }
++ Py_DECREF(item_orig);
+ }
+ }
+
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
+index 1b05aae..0805ab1 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
+@@ -48,7 +48,8 @@ static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix);
+ static PyObject *Matrix_copy(MatrixObject *self);
+ static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args);
+ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
+-static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
++static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
++ MatrixObject *self);
+ static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
+
+ static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
+@@ -385,14 +386,15 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ return NULL;
+ }
+
+-static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
++static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
++ MatrixObject *self)
+ {
+ PyObject *ret = Matrix_copy(self);
+ if (ret) {
+- PyObject *ret_dummy = matrix_func(ret);
++ PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+- return (PyObject *)ret;
++ return ret;
+ }
+ else { /* error */
+ Py_DECREF(ret);
+@@ -1598,7 +1600,7 @@ PyDoc_STRVAR(Matrix_adjugated_doc,
+ );
+ static PyObject *Matrix_adjugated(MatrixObject *self)
+ {
+- return matrix__apply_to_copy((PyNoArgsFunction)Matrix_adjugate, self);
++ return matrix__apply_to_copy(Matrix_adjugate, self);
+ }
+
+ PyDoc_STRVAR(Matrix_rotate_doc,
+@@ -1795,7 +1797,7 @@ PyDoc_STRVAR(Matrix_transposed_doc,
+ );
+ static PyObject *Matrix_transposed(MatrixObject *self)
+ {
+- return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
++ return matrix__apply_to_copy(Matrix_transpose, self);
+ }
+
+ /*---------------------------matrix.normalize() ------------------*/
+@@ -1842,7 +1844,7 @@ PyDoc_STRVAR(Matrix_normalized_doc,
+ );
+ static PyObject *Matrix_normalized(MatrixObject *self)
+ {
+- return matrix__apply_to_copy((PyNoArgsFunction)Matrix_normalize, self);
++ return matrix__apply_to_copy(Matrix_normalize, self);
+ }
+
+ /*---------------------------matrix.zero() -----------------------*/
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c
+index 02aabd0..c8eeaa2 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Quaternion.c
+@@ -40,7 +40,8 @@
+
+ #define QUAT_SIZE 4
+
+-static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self);
++static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
++ QuaternionObject *self);
+ static void quat__axis_angle_sanitize(float axis[3], float *angle);
+ static PyObject *Quaternion_copy(QuaternionObject *self);
+ static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
+@@ -381,7 +382,7 @@ PyDoc_STRVAR(Quaternion_normalized_doc,
+ );
+ static PyObject *Quaternion_normalized(QuaternionObject *self)
+ {
+- return quat__apply_to_copy((PyNoArgsFunction)Quaternion_normalize, self);
++ return quat__apply_to_copy(Quaternion_normalize, self);
+ }
+
+ PyDoc_STRVAR(Quaternion_invert_doc,
+@@ -409,7 +410,7 @@ PyDoc_STRVAR(Quaternion_inverted_doc,
+ );
+ static PyObject *Quaternion_inverted(QuaternionObject *self)
+ {
+- return quat__apply_to_copy((PyNoArgsFunction)Quaternion_invert, self);
++ return quat__apply_to_copy(Quaternion_invert, self);
+ }
+
+ PyDoc_STRVAR(Quaternion_identity_doc,
+@@ -473,7 +474,7 @@ PyDoc_STRVAR(Quaternion_conjugated_doc,
+ );
+ static PyObject *Quaternion_conjugated(QuaternionObject *self)
+ {
+- return quat__apply_to_copy((PyNoArgsFunction)Quaternion_conjugate, self);
++ return quat__apply_to_copy(Quaternion_conjugate, self);
+ }
+
+ PyDoc_STRVAR(Quaternion_copy_doc,
+@@ -1146,10 +1147,11 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
+ return Quaternion_CreatePyObject(quat, type);
+ }
+
+-static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self)
++static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
++ QuaternionObject *self)
+ {
+ PyObject *ret = Quaternion_copy(self);
+- PyObject *ret_dummy = quat_func(ret);
++ PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return ret;
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c
+index af73aa2..18ecf2f 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Vector.c
+@@ -92,10 +92,10 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ return Vector_CreatePyObject_alloc(vec, size, type);
+ }
+
+-static PyObject *vec__apply_to_copy(PyNoArgsFunction vec_func, VectorObject *self)
++static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
+ {
+ PyObject *ret = Vector_copy(self);
+- PyObject *ret_dummy = vec_func(ret);
++ PyObject *ret_dummy = vec_func((VectorObject *)ret);
+ if (ret_dummy) {
+ Py_DECREF(ret_dummy);
+ return (PyObject *)ret;
+@@ -378,7 +378,7 @@ PyDoc_STRVAR(Vector_normalized_doc,
+ );
+ static PyObject *Vector_normalized(VectorObject *self)
+ {
+- return vec__apply_to_copy((PyNoArgsFunction)Vector_normalize, self);
++ return vec__apply_to_copy(Vector_normalize, self);
+ }
+
+ PyDoc_STRVAR(Vector_resize_doc,
diff --git a/0009_python3_10.patch b/0009_python3_10.patch
new file mode 100644
index 000000000000..a5c63da8e58f
--- /dev/null
+++ b/0009_python3_10.patch
@@ -0,0 +1,1124 @@
+commit 5a4f5d69d90dc497e7a0dd8df56e7b3757edf6d4
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 00:33:17 2023 +0100
+
+ python3.10: "Fix T85573: Building with Python 3.10a5 fails"
+
+ Adjusted Blender upstream ref: dae445d94a7a5e1ad38719ea05e5bb0bc76ede84
+
+ Command used:
+
+ grep -rIlZ _PyUnicode_AsString ./blender-2.79b/ | xargs -0 sed -i 's/_PyUnicode_AsString/PyUnicode_AsUTF8/g'
+
+commit 5009c95b82cab0bddefce14d915303634c7369ee
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 00:30:30 2023 +0100
+
+ python3.10: "PyAPI: resolve build error with Python 3.10"
+
+ Fully applied Blender upstream ref: 6fe00939b0a471cc149ea5b3c63ca57b049b4a37
+
+diff --git a/blender-2.79b/intern/cycles/blender/blender_python.cpp b/blender-2.79b/intern/cycles/blender/blender_python.cpp
+index bee6dd1..88fbf8a 100644
+--- a/blender-2.79b/intern/cycles/blender/blender_python.cpp
++++ b/blender-2.79b/intern/cycles/blender/blender_python.cpp
+@@ -141,7 +141,7 @@ void python_thread_state_restore(void **python_thread_state)
+
+ static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
+ {
+- const char *result = _PyUnicode_AsString(py_str);
++ const char *result = PyUnicode_AsUTF8(py_str);
+ if(result) {
+ /* 99% of the time this is enough but we better support non unicode
+ * chars since blender doesnt limit this.
+diff --git a/blender-2.79b/source/blender/freestyle/intern/python/BPy_SShape.cpp b/blender-2.79b/source/blender/freestyle/intern/python/BPy_SShape.cpp
+index 9169adf..eabfc07 100644
+--- a/blender-2.79b/source/blender/freestyle/intern/python/BPy_SShape.cpp
++++ b/blender-2.79b/source/blender/freestyle/intern/python/BPy_SShape.cpp
+@@ -194,7 +194,7 @@ static int SShape_name_set(BPy_SShape *self, PyObject *value, void *UNUSED(closu
+ PyErr_SetString(PyExc_TypeError, "value must be a string");
+ return -1;
+ }
+- const char *name = _PyUnicode_AsString(value);
++ const char *name = PyUnicode_AsUTF8(value);
+ self->ss->setName(name);
+ return 0;
+ }
+diff --git a/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c b/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c
+index ea37159..8543c8f 100644
+--- a/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c
++++ b/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops.c
+@@ -220,7 +220,7 @@ static PyTypeObject bmesh_op_Type = {
+
+ static PyObject *bpy_bmesh_ops_fakemod_getattro(PyObject *UNUSED(self), PyObject *pyname)
+ {
+- const char *opname = _PyUnicode_AsString(pyname);
++ const char *opname = PyUnicode_AsUTF8(pyname);
+
+ if (BMO_opcode_from_opname(opname) != -1) {
+ return bpy_bmesh_op_CreatePyObject(opname);
+diff --git a/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops_call.c b/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops_call.c
+index 8f28791..7f2cab3 100644
+--- a/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops_call.c
++++ b/blender-2.79b/source/blender/python/bmesh/bmesh_py_ops_call.c
+@@ -724,7 +724,7 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(kw, &pos, &key, &value)) {
+- const char *slot_name = _PyUnicode_AsString(key);
++ const char *slot_name = PyUnicode_AsUTF8(key);
+ BMOpSlot *slot;
+
+ if (!BMO_slot_exists(bmop.slots_in, slot_name)) {
+diff --git a/blender-2.79b/source/blender/python/bmesh/bmesh_py_types_customdata.c b/blender-2.79b/source/blender/python/bmesh/bmesh_py_types_customdata.c
+index 908f6b5..9b0d7b9 100644
+--- a/blender-2.79b/source/blender/python/bmesh/bmesh_py_types_customdata.c
++++ b/blender-2.79b/source/blender/python/bmesh/bmesh_py_types_customdata.c
+@@ -658,7 +658,7 @@ static PyObject *bpy_bmlayercollection_subscript(BPy_BMLayerCollection *self, Py
+ {
+ /* don't need error check here */
+ if (PyUnicode_Check(key)) {
+- return bpy_bmlayercollection_subscript_str(self, _PyUnicode_AsString(key));
++ return bpy_bmlayercollection_subscript_str(self, PyUnicode_AsUTF8(key));
+ }
+ else if (PyIndex_Check(key)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
+@@ -712,7 +712,7 @@ static PyObject *bpy_bmlayercollection_subscript(BPy_BMLayerCollection *self, Py
+
+ static int bpy_bmlayercollection_contains(BPy_BMLayerCollection *self, PyObject *value)
+ {
+- const char *keyname = _PyUnicode_AsString(value);
++ const char *keyname = PyUnicode_AsUTF8(value);
+ CustomData *data;
+ int index;
+
+diff --git a/blender-2.79b/source/blender/python/generic/bpy_internal_import.c b/blender-2.79b/source/blender/python/generic/bpy_internal_import.c
+index 7ab6447..78f7b84 100644
+--- a/blender-2.79b/source/blender/python/generic/bpy_internal_import.c
++++ b/blender-2.79b/source/blender/python/generic/bpy_internal_import.c
+@@ -253,7 +253,7 @@ PyObject *bpy_text_reimport(PyObject *module, int *found)
+ if (module_file == NULL) {
+ return NULL;
+ }
+- filepath = (char *)_PyUnicode_AsString(module_file);
++ filepath = (char *)PyUnicode_AsUTF8(module_file);
+ Py_DECREF(module_file);
+ if (filepath == NULL) {
+ return NULL;
+diff --git a/blender-2.79b/source/blender/python/generic/idprop_py_api.c b/blender-2.79b/source/blender/python/generic/idprop_py_api.c
+index 576f114..a8fea1d 100644
+--- a/blender-2.79b/source/blender/python/generic/idprop_py_api.c
++++ b/blender-2.79b/source/blender/python/generic/idprop_py_api.c
+@@ -181,13 +181,13 @@ static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject
+ st = (char *)PyC_UnicodeAsByte(value, &value_coerce);
+ alloc_len = strlen(st) + 1;
+
+- st = _PyUnicode_AsString(value);
++ st = PyUnicode_AsUTF8(value);
+ IDP_ResizeArray(prop, alloc_len);
+ memcpy(IDP_Array(prop), st, alloc_len);
+ Py_XDECREF(value_coerce);
+ }
+ #else
+- st = _PyUnicode_AsString(value);
++ st = PyUnicode_AsUTF8(value);
+ IDP_ResizeArray(prop, strlen(st) + 1);
+ strcpy(IDP_Array(prop), st);
+ #endif
+@@ -248,7 +248,7 @@ static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUS
+ return -1;
+ }
+
+- name = _PyUnicode_AsStringAndSize(value, &name_size);
++ name = PyUnicode_AsUTF8AndSize(value, &name_size);
+
+ if (name_size > MAX_IDPROP_NAME) {
+ PyErr_SetString(PyExc_TypeError, "string length cannot exceed 63 characters!");
+@@ -291,7 +291,7 @@ static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
+ return NULL;
+ }
+
+- name = _PyUnicode_AsString(item);
++ name = PyUnicode_AsUTF8(item);
+
+ if (name == NULL) {
+ PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
+@@ -349,7 +349,7 @@ static const char *idp_try_read_name(PyObject *name_obj)
+ const char *name = NULL;
+ if (name_obj) {
+ Py_ssize_t name_size;
+- name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
++ name = PyUnicode_AsUTF8AndSize(name_obj, &name_size);
+
+ if (name == NULL) {
+ PyErr_Format(PyExc_KeyError,
+@@ -406,7 +406,7 @@ static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob)
+ prop = IDP_New(IDP_STRING, &val, name);
+ Py_XDECREF(value_coerce);
+ #else
+- val.str = _PyUnicode_AsString(ob);
++ val.str = PyUnicode_AsUTF8(ob);
+ prop = IDP_New(IDP_STRING, val, name);
+ #endif
+ return prop;
+@@ -693,7 +693,7 @@ int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
+
+ if (val == NULL) { /* del idprop[key] */
+ IDProperty *pkey;
+- const char *name = _PyUnicode_AsString(key);
++ const char *name = PyUnicode_AsUTF8(key);
+
+ if (name == NULL) {
+ PyErr_Format(PyExc_KeyError,
+@@ -867,7 +867,7 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *value)
+ {
+ IDProperty *idprop;
+ PyObject *pyform;
+- const char *name = _PyUnicode_AsString(value);
++ const char *name = PyUnicode_AsUTF8(value);
+
+ if (!name) {
+ PyErr_Format(PyExc_TypeError,
+@@ -1027,7 +1027,7 @@ static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
+
+ static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
+ {
+- const char *name = _PyUnicode_AsString(value);
++ const char *name = PyUnicode_AsUTF8(value);
+
+ if (!name) {
+ PyErr_Format(PyExc_TypeError,
+@@ -1826,7 +1826,7 @@ void IDP_spit(IDProperty *prop)
+ ret_str = PyObject_Repr(ret_dict);
+ Py_DECREF(ret_dict);
+
+- printf("IDProperty(%p): %s\n", prop, _PyUnicode_AsString(ret_str));
++ printf("IDProperty(%p): %s\n", prop, PyUnicode_AsUTF8(ret_str));
+
+ Py_DECREF(ret_str);
+
+diff --git a/blender-2.79b/source/blender/python/generic/py_capi_utils.c b/blender-2.79b/source/blender/python/generic/py_capi_utils.c
+index f4a2595..17cb657 100644
+--- a/blender-2.79b/source/blender/python/generic/py_capi_utils.c
++++ b/blender-2.79b/source/blender/python/generic/py_capi_utils.c
+@@ -292,7 +292,7 @@ void PyC_FileAndNum(const char **filename, int *lineno)
+
+ /* when executing a script */
+ if (filename) {
+- *filename = _PyUnicode_AsString(frame->f_code->co_filename);
++ *filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
+ }
+
+ /* when executing a module */
+@@ -305,7 +305,7 @@ void PyC_FileAndNum(const char **filename, int *lineno)
+ if (mod) {
+ PyObject *mod_file = PyModule_GetFilenameObject(mod);
+ if (mod_file) {
+- *filename = _PyUnicode_AsString(mod_name);
++ *filename = PyUnicode_AsUTF8(mod_name);
+ Py_DECREF(mod_file);
+ }
+ else {
+@@ -315,7 +315,7 @@ void PyC_FileAndNum(const char **filename, int *lineno)
+
+ /* unlikely, fallback */
+ if (*filename == NULL) {
+- *filename = _PyUnicode_AsString(mod_name);
++ *filename = PyUnicode_AsUTF8(mod_name);
+ }
+ }
+ }
+@@ -554,7 +554,7 @@ const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObjec
+ {
+ const char *result;
+
+- result = _PyUnicode_AsStringAndSize(py_str, size);
++ result = PyUnicode_AsUTF8AndSize(py_str, size);
+
+ if (result) {
+ /* 99% of the time this is enough but we better support non unicode
+@@ -583,7 +583,7 @@ const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
+ {
+ const char *result;
+
+- result = _PyUnicode_AsString(py_str);
++ result = PyUnicode_AsUTF8(py_str);
+
+ if (result) {
+ /* 99% of the time this is enough but we better support non unicode
+@@ -975,7 +975,7 @@ int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, co
+ *r_value = 0;
+
+ while (_PySet_NextEntry(value, &pos, &key, &hash)) {
+- const char *param = _PyUnicode_AsString(key);
++ const char *param = PyUnicode_AsUTF8(key);
+
+ if (param == NULL) {
+ PyErr_Format(PyExc_TypeError,
+@@ -1100,7 +1100,7 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val
+ const char *val;
+ Py_ssize_t val_len;
+
+- val = _PyUnicode_AsStringAndSize(retval, &val_len);
++ val = PyUnicode_AsUTF8AndSize(retval, &val_len);
+ if (val == NULL && PyErr_Occurred()) {
+ ok = false;
+ }
+diff --git a/blender-2.79b/source/blender/python/intern/bpy.c b/blender-2.79b/source/blender/python/intern/bpy.c
+index 5bbfb49..a8e2187 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy.c
++++ b/blender-2.79b/source/blender/python/intern/bpy.c
+@@ -232,7 +232,7 @@ static PyObject *bpy_escape_identifier(PyObject *UNUSED(self), PyObject *value)
+ PyObject *value_escape;
+ size_t size;
+
+- value_str = _PyUnicode_AsStringAndSize(value, &value_str_len);
++ value_str = PyUnicode_AsUTF8AndSize(value, &value_str_len);
+
+ if (value_str == NULL) {
+ PyErr_SetString(PyExc_TypeError, "expected a string");
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_app_translations.c b/blender-2.79b/source/blender/python/intern/bpy_app_translations.c
+index 1b853be..6f1e67b 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_app_translations.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_app_translations.c
+@@ -193,7 +193,7 @@ static void _build_translations_cache(PyObject *py_messages, const char *locale)
+ msgctxt = BLT_I18NCONTEXT_DEFAULT_BPYRNA;
+ }
+ else if (PyUnicode_Check(tmp)) {
+- msgctxt = _PyUnicode_AsString(tmp);
++ msgctxt = PyUnicode_AsUTF8(tmp);
+ }
+ else {
+ invalid_key = true;
+@@ -201,7 +201,7 @@ static void _build_translations_cache(PyObject *py_messages, const char *locale)
+
+ tmp = PyTuple_GET_ITEM(pykey, 1);
+ if (PyUnicode_Check(tmp)) {
+- msgid = _PyUnicode_AsString(tmp);
++ msgid = PyUnicode_AsUTF8(tmp);
+ }
+ else {
+ invalid_key = true;
+@@ -231,7 +231,7 @@ static void _build_translations_cache(PyObject *py_messages, const char *locale)
+ /* Do not overwrite existing keys! */
+ if (BPY_app_translations_py_pgettext(msgctxt, msgid) == msgid) {
+ GHashKey *key = _ghashutil_keyalloc(msgctxt, msgid);
+- BLI_ghash_insert(_translations_cache, key, BLI_strdup(_PyUnicode_AsString(trans)));
++ BLI_ghash_insert(_translations_cache, key, BLI_strdup(PyUnicode_AsUTF8(trans)));
+ }
+ }
+ }
+@@ -313,7 +313,7 @@ static PyObject *app_translations_py_messages_register(BlenderAppTranslations *s
+ if (PyDict_Contains(self->py_messages, module_name)) {
+ PyErr_Format(PyExc_ValueError,
+ "bpy.app.translations.register: translations message cache already contains some data for "
+- "addon '%s'", (const char *)_PyUnicode_AsString(module_name));
++ "addon '%s'", (const char *)PyUnicode_AsUTF8(module_name));
+ return NULL;
+ }
+
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_interface.c b/blender-2.79b/source/blender/python/intern/bpy_interface.c
+index 0d36ba1..5653ba4 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_interface.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_interface.c
+@@ -863,7 +863,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
+ /* updating the module dict below will loose the reference to __file__ */
+ PyObject *filename_obj = PyModule_GetFilenameObject(bpy_proxy);
+
+- const char *filename_rel = _PyUnicode_AsString(filename_obj); /* can be relative */
++ const char *filename_rel = PyUnicode_AsUTF8(filename_obj); /* can be relative */
+ char filename_abs[1024];
+
+ BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs));
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_library_load.c b/blender-2.79b/source/blender/python/intern/bpy_library_load.c
+index c8fd392..6ae5318 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_library_load.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_library_load.c
+@@ -353,7 +353,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
+ for (i = 0; i < size; i++) {
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ PyObject *item_dst; /* must be set below */
+- const char *item_idname = _PyUnicode_AsString(item_src);
++ const char *item_idname = PyUnicode_AsUTF8(item_src);
+
+ // printf(" %s\n", item_idname);
+
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_operator.c b/blender-2.79b/source/blender/python/intern/bpy_operator.c
+index c1fcb07..ad6f6cb 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_operator.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_operator.c
+@@ -398,7 +398,7 @@ static PyObject *pyop_getrna(PyObject *UNUSED(self), PyObject *value)
+ {
+ wmOperatorType *ot;
+ PointerRNA ptr;
+- const char *opname = _PyUnicode_AsString(value);
++ const char *opname = PyUnicode_AsUTF8(value);
+ BPy_StructRNA *pyrna = NULL;
+
+ if (opname == NULL) {
+@@ -431,7 +431,7 @@ static PyObject *pyop_getinstance(PyObject *UNUSED(self), PyObject *value)
+ wmOperatorType *ot;
+ wmOperator *op;
+ PointerRNA ptr;
+- const char *opname = _PyUnicode_AsString(value);
++ const char *opname = PyUnicode_AsUTF8(value);
+ BPy_StructRNA *pyrna = NULL;
+
+ if (opname == NULL) {
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_operator_wrap.c b/blender-2.79b/source/blender/python/intern/bpy_operator_wrap.c
+index 9071990..5d7e56b 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_operator_wrap.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_operator_wrap.c
+@@ -70,7 +70,7 @@ static void operator_properties_init(wmOperatorType *ot)
+ if (bl_property) {
+ if (PyUnicode_Check(bl_property)) {
+ /* since the property is explicitly given, raise an error if its not found */
+- prop_id = _PyUnicode_AsString(bl_property);
++ prop_id = PyUnicode_AsUTF8(bl_property);
+ prop_raise_error = true;
+ }
+ else {
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_props.c b/blender-2.79b/source/blender/python/intern/bpy_props.c
+index 2b8e356..aab4276 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_props.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_props.c
+@@ -192,9 +192,9 @@ static void printf_func_error(PyObject *py_func)
+
+ /* use py style error */
+ fprintf(stderr, "File \"%s\", line %d, in %s\n",
+- _PyUnicode_AsString(f_code->co_filename),
++ PyUnicode_AsUTF8(f_code->co_filename),
+ f_code->co_firstlineno,
+- _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)
++ PyUnicode_AsUTF8(((PyFunctionObject *)py_func)->func_name)
+ );
+ }
+
+@@ -1074,7 +1074,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
+ }
+ else {
+ Py_ssize_t length;
+- const char *buffer = _PyUnicode_AsStringAndSize(ret, &length);
++ const char *buffer = PyUnicode_AsUTF8AndSize(ret, &length);
+ memcpy(value, buffer, length + 1);
+ Py_DECREF(ret);
+ }
+@@ -1134,7 +1134,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
+ }
+ else {
+ Py_ssize_t length_ssize_t = 0;
+- _PyUnicode_AsStringAndSize(ret, &length_ssize_t);
++ PyUnicode_AsUTF8AndSize(ret, &length_ssize_t);
+ length = length_ssize_t;
+ Py_DECREF(ret);
+ }
+@@ -1392,7 +1392,7 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i
+ }
+ else {
+ if (def) {
+- def_cmp = _PyUnicode_AsString(def);
++ def_cmp = PyUnicode_AsUTF8(def);
+ if (def_cmp == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "EnumProperty(...): default option must be a 'str' "
+@@ -1421,13 +1421,13 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i
+ if ((PyTuple_CheckExact(item)) &&
+ (item_size = PyTuple_GET_SIZE(item)) &&
+ (item_size >= 3 && item_size <= 5) &&
+- (tmp.identifier = _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 0), &id_str_size)) &&
+- (tmp.name = _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 1), &name_str_size)) &&
+- (tmp.description = _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 2), &desc_str_size)) &&
++ (tmp.identifier = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(item, 0), &id_str_size)) &&
++ (tmp.name = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(item, 1), &name_str_size)) &&
++ (tmp.description = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(item, 2), &desc_str_size)) &&
+ /* TODO, number isn't ensured to be unique from the script author */
+ (item_size != 4 || py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.value) != -1) &&
+ (item_size != 5 || ((py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.icon) != -1 ||
+- (tmp_icon = _PyUnicode_AsString(PyTuple_GET_ITEM(item, 3)))) &&
++ (tmp_icon = PyUnicode_AsUTF8(PyTuple_GET_ITEM(item, 3)))) &&
+ py_long_as_int(PyTuple_GET_ITEM(item, 4), &tmp.value) != -1)))
+ {
+ if (is_enum_flag) {
+@@ -2845,7 +2845,7 @@ StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
+ if (!srna) {
+ if (PyErr_Occurred()) {
+ PyObject *msg = PyC_ExceptionBuffer();
+- const char *msg_char = _PyUnicode_AsString(msg);
++ const char *msg_char = PyUnicode_AsUTF8(msg);
+ PyErr_Format(PyExc_TypeError,
+ "%.200s expected an RNA type, failed with: %s",
+ error_prefix, msg_char);
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_rna.c b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+index 26a4351..722e23d 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_rna.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+@@ -313,7 +313,7 @@ static bool rna_id_write_error(PointerRNA *ptr, PyObject *key)
+ if (!ELEM(idcode, ID_WM, ID_SCR)) { /* may need more added here */
+ const char *idtype = BKE_idcode_to_name(idcode);
+ const char *pyname;
+- if (key && PyUnicode_Check(key)) pyname = _PyUnicode_AsString(key);
++ if (key && PyUnicode_Check(key)) pyname = PyUnicode_AsUTF8(key);
+ else pyname = "<UNKNOWN>";
+
+ /* make a nice string error */
+@@ -1188,7 +1188,7 @@ static int pyrna_string_to_enum(
+ PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *r_value,
+ const char *error_prefix)
+ {
+- const char *param = _PyUnicode_AsString(item);
++ const char *param = PyUnicode_AsUTF8(item);
+
+ if (param == NULL) {
+ PyErr_Format(PyExc_TypeError,
+@@ -1232,7 +1232,7 @@ BLI_bitmap *pyrna_set_to_enum_bitmap(
+ BLI_bitmap *bitmap = BLI_BITMAP_NEW(bitmap_size, __func__);
+
+ while (_PySet_NextEntry(value, &pos, &key, &hash)) {
+- const char *param = _PyUnicode_AsString(key);
++ const char *param = PyUnicode_AsUTF8(key);
+ if (param == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s expected a string, not %.200s",
+@@ -1289,7 +1289,7 @@ int pyrna_set_to_enum_bitfield(
+ *r_value = 0;
+
+ while (_PySet_NextEntry(value, &pos, &key, &hash)) {
+- const char *param = _PyUnicode_AsString(key);
++ const char *param = PyUnicode_AsUTF8(key);
+
+ if (param == NULL) {
+ PyErr_Format(PyExc_TypeError,
+@@ -1590,7 +1590,7 @@ int pyrna_pydict_to_props(
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(kw, &pos, &key, &value)) {
+- arg_name = _PyUnicode_AsString(key);
++ arg_name = PyUnicode_AsUTF8(key);
+ if (RNA_struct_find_property(ptr, arg_name) == NULL) break;
+ arg_name = NULL;
+ }
+@@ -1761,10 +1761,10 @@ static int pyrna_py_to_prop(
+ param = PyC_UnicodeAsByte(value, &value_coerce);
+ }
+ else {
+- param = _PyUnicode_AsString(value);
++ param = PyUnicode_AsUTF8(value);
+ }
+ #else /* USE_STRING_COERCE */
+- param = _PyUnicode_AsString(value);
++ param = PyUnicode_AsUTF8(value);
+ #endif /* USE_STRING_COERCE */
+
+ if (param == NULL) {
+@@ -2019,7 +2019,7 @@ static int pyrna_py_to_prop(
+ "Converting a python list to an RNA collection") == -1)
+ {
+ PyObject *msg = PyC_ExceptionBuffer();
+- const char *msg_char = _PyUnicode_AsString(msg);
++ const char *msg_char = PyUnicode_AsUTF8(msg);
+
+ PyErr_Format(PyExc_TypeError,
+ "%.200s %.200s.%.200s error converting a member of a collection "
+@@ -2310,7 +2310,7 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(
+ err_prefix, RNA_struct_identifier(self->ptr.type));
+ return -1;
+ }
+- else if ((keyname = _PyUnicode_AsString(PyTuple_GET_ITEM(key, 0))) == NULL) {
++ else if ((keyname = PyUnicode_AsUTF8(PyTuple_GET_ITEM(key, 0))) == NULL) {
+ PyErr_Format(PyExc_KeyError,
+ "%s: id must be a string, not %.200s",
+ err_prefix, Py_TYPE(PyTuple_GET_ITEM(key, 0))->tp_name);
+@@ -2326,7 +2326,7 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(
+ }
+ else if (PyUnicode_Check(keylib)) {
+ Main *bmain = self->ptr.data;
+- const char *keylib_str = _PyUnicode_AsString(keylib);
++ const char *keylib_str = PyUnicode_AsUTF8(keylib);
+ lib = BLI_findstring(&bmain->library, keylib_str, offsetof(Library, name));
+ if (lib == NULL) {
+ if (err_not_found) {
+@@ -2517,7 +2517,7 @@ static PyObject *pyrna_prop_collection_subscript(BPy_PropertyRNA *self, PyObject
+ PYRNA_PROP_CHECK_OBJ(self);
+
+ if (PyUnicode_Check(key)) {
+- return pyrna_prop_collection_subscript_str(self, _PyUnicode_AsString(key));
++ return pyrna_prop_collection_subscript_str(self, PyUnicode_AsUTF8(key));
+ }
+ else if (PyIndex_Check(key)) {
+ Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
+@@ -2640,7 +2640,7 @@ static int pyrna_prop_collection_ass_subscript(BPy_PropertyRNA *self, PyObject *
+
+ #if 0
+ if (PyUnicode_Check(key)) {
+- return pyrna_prop_collection_subscript_str(self, _PyUnicode_AsString(key));
++ return pyrna_prop_collection_subscript_str(self, PyUnicode_AsUTF8(key));
+ }
+ else
+ #endif
+@@ -2704,7 +2704,7 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject
+
+ #if 0
+ if (PyUnicode_Check(key)) {
+- return pyrna_prop_array_subscript_str(self, _PyUnicode_AsString(key));
++ return pyrna_prop_array_subscript_str(self, PyUnicode_AsUTF8(key));
+ }
+ else
+ #endif
+@@ -3141,7 +3141,7 @@ static int pyrna_prop_collection_contains(BPy_PropertyRNA *self, PyObject *key)
+ else {
+
+ /* key in dict style check */
+- const char *keyname = _PyUnicode_AsString(key);
++ const char *keyname = PyUnicode_AsUTF8(key);
+
+ if (keyname == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+@@ -3159,7 +3159,7 @@ static int pyrna_prop_collection_contains(BPy_PropertyRNA *self, PyObject *key)
+ static int pyrna_struct_contains(BPy_StructRNA *self, PyObject *value)
+ {
+ IDProperty *group;
+- const char *name = _PyUnicode_AsString(value);
++ const char *name = PyUnicode_AsUTF8(value);
+
+ PYRNA_STRUCT_CHECK_INT(self);
+
+@@ -3224,7 +3224,7 @@ static PyObject *pyrna_struct_subscript(BPy_StructRNA *self, PyObject *key)
+ {
+ /* mostly copied from BPy_IDGroup_Map_GetItem */
+ IDProperty *group, *idprop;
+- const char *name = _PyUnicode_AsString(key);
++ const char *name = PyUnicode_AsUTF8(key);
+
+ PYRNA_STRUCT_CHECK_OBJ(self);
+
+@@ -3841,7 +3841,7 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self)
+ /* ---------------getattr-------------------------------------------- */
+ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
+ {
+- const char *name = _PyUnicode_AsString(pyname);
++ const char *name = PyUnicode_AsUTF8(pyname);
+ PyObject *ret;
+ PropertyRNA *prop;
+ FunctionRNA *func;
+@@ -3985,7 +3985,7 @@ static PyObject *pyrna_struct_meta_idprop_getattro(PyObject *cls, PyObject *attr
+ if (ret == NULL) { // || pyrna_is_deferred_prop(ret)
+ StructRNA *srna = srna_from_self(cls, "StructRNA.__getattr__");
+ if (srna) {
+- PropertyRNA *prop = RNA_struct_type_find_property(srna, _PyUnicode_AsString(attr));
++ PropertyRNA *prop = RNA_struct_type_find_property(srna, PyUnicode_AsUTF8(attr));
+ if (prop) {
+ PointerRNA tptr;
+ PyErr_Clear(); /* clear error from tp_getattro */
+@@ -4004,7 +4004,7 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb
+ {
+ StructRNA *srna = srna_from_self(cls, "StructRNA.__setattr__");
+ const bool is_deferred_prop = (value && pyrna_is_deferred_prop(value));
+- const char *attr_str = _PyUnicode_AsString(attr);
++ const char *attr_str = PyUnicode_AsUTF8(attr);
+
+ if (srna && !pyrna_write_check() && (is_deferred_prop || RNA_struct_type_find_property(srna, attr_str))) {
+ PyErr_Format(PyExc_AttributeError,
+@@ -4064,7 +4064,7 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb
+
+ static int pyrna_struct_setattro(BPy_StructRNA *self, PyObject *pyname, PyObject *value)
+ {
+- const char *name = _PyUnicode_AsString(pyname);
++ const char *name = PyUnicode_AsUTF8(pyname);
+ PropertyRNA *prop = NULL;
+
+ PYRNA_STRUCT_CHECK_INT(self);
+@@ -4159,7 +4159,7 @@ static PyObject *pyrna_prop_array_getattro(BPy_PropertyRNA *self, PyObject *pyna
+
+ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject *pyname)
+ {
+- const char *name = _PyUnicode_AsString(pyname);
++ const char *name = PyUnicode_AsUTF8(pyname);
+
+ if (name == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "bpy_prop_collection: __getattr__ must be a string");
+@@ -4227,7 +4227,7 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject
+ /* --------------- setattr------------------------------------------- */
+ static int pyrna_prop_collection_setattro(BPy_PropertyRNA *self, PyObject *pyname, PyObject *value)
+ {
+- const char *name = _PyUnicode_AsString(pyname);
++ const char *name = PyUnicode_AsUTF8(pyname);
+ PropertyRNA *prop;
+ PointerRNA r_ptr;
+
+@@ -4573,7 +4573,7 @@ static PyObject *pyrna_prop_collection_get(BPy_PropertyRNA *self, PyObject *args
+ return NULL;
+
+ if (PyUnicode_Check(key_ob)) {
+- const char *key = _PyUnicode_AsString(key_ob);
++ const char *key = PyUnicode_AsUTF8(key_ob);
+
+ if (RNA_property_collection_lookup_string(&self->ptr, self->prop, key, &newptr))
+ return pyrna_struct_CreatePyObject(&newptr);
+@@ -4608,7 +4608,7 @@ PyDoc_STRVAR(pyrna_prop_collection_find_doc,
+ static PyObject *pyrna_prop_collection_find(BPy_PropertyRNA *self, PyObject *key_ob)
+ {
+ Py_ssize_t key_len_ssize_t;
+- const char *key = _PyUnicode_AsStringAndSize(key_ob, &key_len_ssize_t);
++ const char *key = PyUnicode_AsUTF8AndSize(key_ob, &key_len_ssize_t);
+ const int key_len = (int)key_len_ssize_t; /* comare with same type */
+
+ char name[256], *nameptr;
+@@ -5308,7 +5308,7 @@ static PyObject *small_dict_get_item_string(PyObject *dict, const char *key_look
+
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ if (PyUnicode_Check(key)) {
+- if (STREQ(key_lookup, _PyUnicode_AsString(key))) {
++ if (STREQ(key_lookup, PyUnicode_AsUTF8(key))) {
+ return value;
+ }
+ }
+@@ -5444,7 +5444,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
+ #ifdef DEBUG_STRING_FREE
+ if (item) {
+ if (PyUnicode_Check(item)) {
+- PyList_APPEND(string_free_ls, PyUnicode_FromString(_PyUnicode_AsString(item)));
++ PyList_APPEND(string_free_ls, PyUnicode_FromString(PyUnicode_AsUTF8(item)));
+ }
+ }
+ #endif
+@@ -5495,7 +5495,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
+
+ while (PyDict_Next(kw, &pos, &key, &value)) {
+
+- arg_name = _PyUnicode_AsString(key);
++ arg_name = PyUnicode_AsUTF8(key);
+ found = false;
+
+ if (arg_name == NULL) { /* unlikely the argname is not a string but ignore if it is*/
+@@ -6862,7 +6862,7 @@ static PyObject *pyrna_basetype_getattro(BPy_BaseTypeRNA *self, PyObject *pyname
+ {
+ PointerRNA newptr;
+ PyObject *ret;
+- const char *name = _PyUnicode_AsString(pyname);
++ const char *name = PyUnicode_AsUTF8(pyname);
+
+ if (name == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "bpy.types: __getattr__ must be a string");
+@@ -6873,14 +6873,14 @@ static PyObject *pyrna_basetype_getattro(BPy_BaseTypeRNA *self, PyObject *pyname
+ if (ret == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "bpy.types.%.200s subtype could not be generated, this is a bug!",
+- _PyUnicode_AsString(pyname));
++ PyUnicode_AsUTF8(pyname));
+ }
+ }
+ else {
+ #if 0
+ PyErr_Format(PyExc_AttributeError,
+ "bpy.types.%.200s RNA_Struct does not exist",
+- _PyUnicode_AsString(pyname));
++ PyUnicode_AsUTF8(pyname));
+ return NULL;
+ #endif
+ /* The error raised here will be displayed */
+@@ -7090,11 +7090,11 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
+ if (PyArg_ParseTuple(item, "OO!", &py_func, &PyDict_Type, &py_kw)) {
+ PyObject *args_fake;
+
+- if (*_PyUnicode_AsString(key) == '_') {
++ if (*PyUnicode_AsUTF8(key) == '_') {
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" registration error: "
+ "%.200s could not register because the property starts with an '_'\n",
+- RNA_struct_identifier(srna), _PyUnicode_AsString(key));
++ RNA_struct_identifier(srna), PyUnicode_AsUTF8(key));
+ return -1;
+ }
+ py_srna_cobject = PyCapsule_New(srna, NULL, NULL);
+@@ -7137,7 +7137,7 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" registration error: "
+ "%.200s could not register\n",
+- RNA_struct_identifier(srna), _PyUnicode_AsString(key));
++ RNA_struct_identifier(srna), PyUnicode_AsUTF8(key));
+ return -1;
+ }
+ }
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_traceback.c b/blender-2.79b/source/blender/python/intern/bpy_traceback.c
+index bff778b..fedf889 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_traceback.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_traceback.c
+@@ -143,7 +143,7 @@ void python_script_error_jump(const char *filepath, int *lineno, int *offset)
+ PyObject *filename_py, *text_py;
+
+ if (parse_syntax_error(value, &message, &filename_py, lineno, offset, &text_py)) {
+- const char *filename = _PyUnicode_AsString(filename_py);
++ const char *filename = PyUnicode_AsUTF8(filename_py);
+ /* python adds a '/', prefix, so check for both */
+ if ((BLI_path_cmp(filename, filepath) == 0) ||
+ ((filename[0] == '\\' || filename[0] == '/') && BLI_path_cmp(filename + 1, filepath) == 0))
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_util.c b/blender-2.79b/source/blender/python/intern/bpy_util.c
+index 2b8ad6c..a292147 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_util.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_util.c
+@@ -121,13 +121,13 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo
+ }
+
+ #if 0 /* ARG!. workaround for a bug in blenders use of vsnprintf */
+- BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", _PyUnicode_AsString(pystring), filename, lineno);
++ BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", PyUnicode_AsUTF8(pystring), filename, lineno);
+ #else
+ pystring_format = PyUnicode_FromFormat(
+ TIP_("%s\nlocation: %s:%d\n"),
+- _PyUnicode_AsString(pystring), filename, lineno);
++ PyUnicode_AsUTF8(pystring), filename, lineno);
+
+- cstring = _PyUnicode_AsString(pystring_format);
++ cstring = PyUnicode_AsUTF8(pystring_format);
+ BKE_report(reports, RPT_ERROR, cstring);
+
+ /* not exactly needed. just for testing */
+@@ -137,7 +137,7 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo
+ #endif
+ }
+ else {
+- BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(pystring));
++ BKE_report(reports, RPT_ERROR, PyUnicode_AsUTF8(pystring));
+ }
+
+
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils.c b/blender-2.79b/source/blender/python/mathutils/mathutils.c
+index 21d3624..8b0959e 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils.c
+@@ -110,7 +110,11 @@ Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
+ x = 0x345678UL;
+ i = 0;
+ while (--len >= 0) {
++#if PY_VERSION_HEX >= 0x30a0000 /* Version: 3.10. */
++ y = _Py_HashDouble(NULL, (double)(array[i++]));
++#else
+ y = _Py_HashDouble((double)(array[i++]));
++#endif
+ if (y == -1)
+ return -1;
+ x = (x ^ y) * mult;
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c
+index 494b5ea..d4200fb 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Euler.c
+@@ -639,7 +639,7 @@ static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(clos
+ if (BaseMath_Prepare_ForWrite(self) == -1)
+ return -1;
+
+- if (((order_str = _PyUnicode_AsString(value)) == NULL) ||
++ if (((order_str = PyUnicode_AsUTF8(value)) == NULL) ||
+ ((order = euler_order_from_string(order_str, "euler.order")) == -1))
+ {
+ return -1;
+diff --git a/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c b/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
+index 0805ab1..d535e17 100644
+--- a/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
++++ b/blender-2.79b/source/blender/python/mathutils/mathutils_Matrix.c
+@@ -482,7 +482,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
+ }
+
+ if (vec && PyUnicode_Check(vec)) {
+- axis = _PyUnicode_AsString((PyObject *)vec);
++ axis = PyUnicode_AsUTF8((PyObject *)vec);
+ if (axis == NULL || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') {
+ PyErr_SetString(PyExc_ValueError,
+ "Matrix.Rotation(): "
+@@ -695,7 +695,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
+
+ if (PyUnicode_Check(axis)) { /* ortho projection onto cardinal plane */
+ Py_ssize_t plane_len;
+- const char *plane = _PyUnicode_AsStringAndSize(axis, &plane_len);
++ const char *plane = PyUnicode_AsUTF8AndSize(axis, &plane_len);
+ if (matSize == 2) {
+ if (plane_len == 1 && plane[0] == 'X') {
+ mat[0] = 1.0f;
+diff --git a/blender-2.79b/source/gameengine/Converter/BL_ActionActuator.cpp b/blender-2.79b/source/gameengine/Converter/BL_ActionActuator.cpp
+index d28cdb8..abbcd38 100644
+--- a/blender-2.79b/source/gameengine/Converter/BL_ActionActuator.cpp
++++ b/blender-2.79b/source/gameengine/Converter/BL_ActionActuator.cpp
+@@ -358,7 +358,7 @@ PyObject *BL_ActionActuator::PyGetChannel(PyObject *value)
+ PyErr_SetString(PyExc_NotImplementedError, "BL_ActionActuator.getChannel() no longer works, please use BL_ArmatureObject.channels instead");
+ return NULL;
+ #if 0 // XXX To be removed in a later version (first removed in 2.64)
+- const char *string= _PyUnicode_AsString(value);
++ const char *string= PyUnicode_AsUTF8(value);
+
+ if (GetParent()->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE)
+ {
+@@ -580,7 +580,7 @@ int BL_ActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF
+ }
+
+ bAction *action= NULL;
+- STR_String val = _PyUnicode_AsString(value);
++ STR_String val = PyUnicode_AsUTF8(value);
+
+ if (val != "")
+ {
+diff --git a/blender-2.79b/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/blender-2.79b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
+index f21db41..dcb6433 100644
+--- a/blender-2.79b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
++++ b/blender-2.79b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
+@@ -543,7 +543,7 @@ int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE
+ }
+
+ bAction *action= NULL;
+- STR_String val = _PyUnicode_AsString(value);
++ STR_String val = PyUnicode_AsUTF8(value);
+
+ if (val != "")
+ {
+diff --git a/blender-2.79b/source/gameengine/Expressions/intern/ListValue.cpp b/blender-2.79b/source/gameengine/Expressions/intern/ListValue.cpp
+index 557ce7b..7111fc8 100644
+--- a/blender-2.79b/source/gameengine/Expressions/intern/ListValue.cpp
++++ b/blender-2.79b/source/gameengine/Expressions/intern/ListValue.cpp
+@@ -362,7 +362,7 @@ static PyObject *listvalue_mapping_subscript(PyObject *self, PyObject *key)
+ }
+
+ if (PyUnicode_Check(key)) {
+- CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(key));
++ CValue *item = ((CListValue*) list)->FindValue(PyUnicode_AsUTF8(key));
+ if (item) {
+ PyObject *pyobj = item->ConvertValueToPython();
+ if (pyobj)
+@@ -483,7 +483,7 @@ static int listvalue_buffer_contains(PyObject *self_v, PyObject *value)
+ }
+
+ if (PyUnicode_Check(value)) {
+- if (self->FindValue((const char *)_PyUnicode_AsString(value))) {
++ if (self->FindValue((const char *)PyUnicode_AsUTF8(value))) {
+ return 1;
+ }
+ }
+diff --git a/blender-2.79b/source/gameengine/Expressions/intern/ListWrapper.cpp b/blender-2.79b/source/gameengine/Expressions/intern/ListWrapper.cpp
+index db1518a..92737cf 100644
+--- a/blender-2.79b/source/gameengine/Expressions/intern/ListWrapper.cpp
++++ b/blender-2.79b/source/gameengine/Expressions/intern/ListWrapper.cpp
+@@ -240,7 +240,7 @@ PyObject *CListWrapper::py_mapping_subscript(PyObject *self, PyObject *key)
+ return NULL;
+ }
+
+- const char *name = _PyUnicode_AsString(key);
++ const char *name = PyUnicode_AsUTF8(key);
+ int size = list->GetSize();
+
+ for (unsigned int i = 0; i < size; ++i) {
+@@ -281,7 +281,7 @@ int CListWrapper::py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObje
+ return -1;
+ }
+
+- const char *name = _PyUnicode_AsString(key);
++ const char *name = PyUnicode_AsUTF8(key);
+ int size = list->GetSize();
+
+ for (unsigned int i = 0; i < size; ++i) {
+@@ -320,7 +320,7 @@ int CListWrapper::py_contains(PyObject *self, PyObject *key)
+ return -1;
+ }
+
+- const char *name = _PyUnicode_AsString(key);
++ const char *name = PyUnicode_AsUTF8(key);
+ int size = list->GetSize();
+
+ for (unsigned int i = 0; i < size; ++i) {
+diff --git a/blender-2.79b/source/gameengine/Expressions/intern/PyObjectPlus.cpp b/blender-2.79b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
+index 1e4a59a..8c0f056 100644
+--- a/blender-2.79b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
++++ b/blender-2.79b/source/gameengine/Expressions/intern/PyObjectPlus.cpp
+@@ -1021,7 +1021,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
+ if (PyUnicode_Check(value))
+ {
+ Py_ssize_t val_size;
+- const char *val = _PyUnicode_AsStringAndSize(value, &val_size);
++ const char *val = PyUnicode_AsUTF8AndSize(value, &val_size);
+ strncpy(ptr, val, attrdef->m_size);
+ ptr[attrdef->m_size-1] = 0;
+ }
+@@ -1038,7 +1038,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
+ if (PyUnicode_Check(value))
+ {
+ Py_ssize_t val_len;
+- const char *val = _PyUnicode_AsStringAndSize(value, &val_len); /* XXX, should be 'const' but we do a silly trick to have a shorter string */
++ const char *val = PyUnicode_AsUTF8AndSize(value, &val_len); /* XXX, should be 'const' but we do a silly trick to have a shorter string */
+ if (attrdef->m_clamp)
+ {
+ if (val_len < attrdef->m_imin)
+diff --git a/blender-2.79b/source/gameengine/Expressions/intern/Value.cpp b/blender-2.79b/source/gameengine/Expressions/intern/Value.cpp
+index f8796a7..ecc5142 100644
+--- a/blender-2.79b/source/gameengine/Expressions/intern/Value.cpp
++++ b/blender-2.79b/source/gameengine/Expressions/intern/Value.cpp
+@@ -612,7 +612,7 @@ CValue *CValue::ConvertPythonToValue(PyObject *pyobj, const bool do_type_excepti
+ } else
+ if (PyUnicode_Check(pyobj))
+ {
+- vallie = new CStringValue(_PyUnicode_AsString(pyobj),"");
++ vallie = new CStringValue(PyUnicode_AsUTF8(pyobj),"");
+ } else
+ if (PyObject_TypeCheck(pyobj, &CValue::Type)) /* Note, don't let these get assigned to GameObject props, must check elsewhere */
+ {
+diff --git a/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp b/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp
+index fd2e723..6aaf6f0 100644
+--- a/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp
++++ b/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp
+@@ -204,7 +204,7 @@ SCA_IActuator* SCA_PythonController::LinkedActuatorFromPy(PyObject *value)
+
+ if (PyUnicode_Check(value)) {
+ /* get the actuator from the name */
+- const char *name= _PyUnicode_AsString(value);
++ const char *name= PyUnicode_AsUTF8(value);
+ for (it = lacts.begin(); it!= lacts.end(); ++it) {
+ if ( name == (*it)->GetName() ) {
+ return *it;
+@@ -513,7 +513,7 @@ int SCA_PythonController::pyattr_set_script(void *self_v, const KX_PYATTRIBUTE_D
+ {
+ SCA_PythonController* self = static_cast<SCA_PythonController*>(self_v);
+
+- const char *scriptArg = _PyUnicode_AsString(value);
++ const char *scriptArg = PyUnicode_AsUTF8(value);
+
+ if (scriptArg==NULL) {
+ PyErr_SetString(PyExc_TypeError, "controller.script = string: Python Controller, expected a string script text");
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_Camera.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_Camera.cpp
+index 89aea80..51b2272 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_Camera.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_Camera.cpp
+@@ -987,7 +987,7 @@ bool ConvertPythonToCamera(PyObject *value, KX_Camera **object, bool py_none_ok,
+ }
+
+ if (PyUnicode_Check(value)) {
+- STR_String value_str = _PyUnicode_AsString(value);
++ STR_String value_str = PyUnicode_AsUTF8(value);
+ *object = KX_GetActiveScene()->FindCamera(value_str);
+
+ if (*object) {
+@@ -995,7 +995,7 @@ bool ConvertPythonToCamera(PyObject *value, KX_Camera **object, bool py_none_ok,
+ } else {
+ PyErr_Format(PyExc_ValueError,
+ "%s, requested name \"%s\" did not match any KX_Camera in this scene",
+- error_prefix, _PyUnicode_AsString(value));
++ error_prefix, PyUnicode_AsUTF8(value));
+ return false;
+ }
+ }
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_FontObject.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_FontObject.cpp
+index 91e8e4f..62ad415 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_FontObject.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_FontObject.cpp
+@@ -281,7 +281,7 @@ int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrd
+ KX_FontObject* self = static_cast<KX_FontObject*>(self_v);
+ if (!PyUnicode_Check(value))
+ return PY_SET_ATTR_FAIL;
+- const char *chars = _PyUnicode_AsString(value);
++ const char *chars = PyUnicode_AsUTF8(value);
+
+ /* Allow for some logic brick control */
+ CValue* tprop = self->GetProperty("Text");
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_GameObject.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_GameObject.cpp
+index 3244400..e6f8e00 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_GameObject.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_GameObject.cpp
+@@ -2087,7 +2087,7 @@ PyObject *KX_GameObject::PyReinstancePhysicsMesh(PyObject *args)
+ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item)
+ {
+ KX_GameObject* self = static_cast<KX_GameObject*>BGE_PROXY_REF(self_v);
+- const char *attr_str= _PyUnicode_AsString(item);
++ const char *attr_str= PyUnicode_AsUTF8(item);
+ CValue* resultattr;
+ PyObject *pyconvert;
+
+@@ -2121,7 +2121,7 @@ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item)
+ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
+ {
+ KX_GameObject* self = static_cast<KX_GameObject*>BGE_PROXY_REF(self_v);
+- const char *attr_str= _PyUnicode_AsString(key);
++ const char *attr_str= PyUnicode_AsUTF8(key);
+ if (attr_str==NULL)
+ PyErr_Clear();
+
+@@ -2214,7 +2214,7 @@ static int Seq_Contains(PyObject *self_v, PyObject *value)
+ return -1;
+ }
+
+- if (PyUnicode_Check(value) && self->GetProperty(_PyUnicode_AsString(value)))
++ if (PyUnicode_Check(value) && self->GetProperty(PyUnicode_AsUTF8(value)))
+ return 1;
+
+ if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value))
+@@ -4124,7 +4124,7 @@ PyObject *KX_GameObject::Pyget(PyObject *args)
+
+
+ if (PyUnicode_Check(key)) {
+- CValue *item = GetProperty(_PyUnicode_AsString(key));
++ CValue *item = GetProperty(PyUnicode_AsUTF8(key));
+ if (item) {
+ ret = item->ConvertValueToPython();
+ if (ret)
+@@ -4163,12 +4163,12 @@ bool ConvertPythonToGameObject(SCA_LogicManager *manager, PyObject *value, KX_Ga
+ }
+
+ if (PyUnicode_Check(value)) {
+- *object = (KX_GameObject*)manager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) ));
++ *object = (KX_GameObject*)manager->GetGameObjectByName(STR_String( PyUnicode_AsUTF8(value) ));
+
+ if (*object) {
+ return true;
+ } else {
+- PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_GameObject in this scene", error_prefix, _PyUnicode_AsString(value));
++ PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_GameObject in this scene", error_prefix, PyUnicode_AsUTF8(value));
+ return false;
+ }
+ }
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_MeshProxy.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_MeshProxy.cpp
+index 8da3542..0da22dc 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_MeshProxy.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_MeshProxy.cpp
+@@ -427,12 +427,12 @@ bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, RAS_MeshOb
+ }
+
+ if (PyUnicode_Check(value)) {
+- *object = (RAS_MeshObject*)logicmgr->GetMeshByName(STR_String( _PyUnicode_AsString(value) ));
++ *object = (RAS_MeshObject*)logicmgr->GetMeshByName(STR_String( PyUnicode_AsUTF8(value) ));
+
+ if (*object) {
+ return true;
+ } else {
+- PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_MeshProxy in this scene", error_prefix, _PyUnicode_AsString(value));
++ PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_MeshProxy in this scene", error_prefix, PyUnicode_AsUTF8(value));
+ return false;
+ }
+ }
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp
+index 71e610d..a112a63 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_PythonInit.cpp
+@@ -825,7 +825,7 @@ static PyObject *gLibNew(PyObject *, PyObject *args)
+ PyObject *ret= PyList_New(0);
+ PyObject *item;
+ for (Py_ssize_t i= 0; i < PyList_GET_SIZE(names); i++) {
+- name= _PyUnicode_AsString(PyList_GET_ITEM(names, i));
++ name= PyUnicode_AsUTF8(PyList_GET_ITEM(names, i));
+ if (name) {
+ RAS_MeshObject *meshobj= kx_scene->GetSceneConverter()->ConvertMeshSpecial(kx_scene, maggie, name);
+ if (meshobj) {
+diff --git a/blender-2.79b/source/gameengine/Ketsji/KX_Scene.cpp b/blender-2.79b/source/gameengine/Ketsji/KX_Scene.cpp
+index b306108..86e51f5 100644
+--- a/blender-2.79b/source/gameengine/Ketsji/KX_Scene.cpp
++++ b/blender-2.79b/source/gameengine/Ketsji/KX_Scene.cpp
+@@ -2218,7 +2218,7 @@ PyMethodDef KX_Scene::Methods[] = {
+ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item)
+ {
+ KX_Scene* self = static_cast<KX_Scene*>BGE_PROXY_REF(self_v);
+- const char *attr_str= _PyUnicode_AsString(item);
++ const char *attr_str= PyUnicode_AsUTF8(item);
+ PyObject *pyconvert;
+
+ if (self == NULL) {
+@@ -2247,7 +2247,7 @@ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item)
+ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
+ {
+ KX_Scene* self = static_cast<KX_Scene*>BGE_PROXY_REF(self_v);
+- const char *attr_str= _PyUnicode_AsString(key);
++ const char *attr_str= PyUnicode_AsUTF8(key);
+ if (attr_str==NULL)
+ PyErr_Clear();
+
diff --git a/0010_python3_11.patch b/0010_python3_11.patch
new file mode 100644
index 000000000000..3babb1047744
--- /dev/null
+++ b/0010_python3_11.patch
@@ -0,0 +1,122 @@
+commit 3e7abb113568b07627e00a7a4e5df5e3cfefccfe
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 17 14:37:36 2023 +0100
+
+ python3.11: eval.h has been removed from Python 3.11
+
+ And compile.h is included with Python.h
+
+commit 5b4980bb042bf23779de97f38d6678f483a6f23e
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 02:31:55 2023 +0100
+
+ python3.11: Remove invalid use of Py_TPFLAGS_HAVE_GC flag
+
+ Error otherwise thrown:
+
+ SystemError: type bpy_struct has the Py_TPFLAGS_HAVE_GC flag but has
+ no traverse function
+
+ This is for Python 3.11, see https://docs.python.org/3/whatsnew/3.11.html
+ """
+ The PyType_Ready() function now raises an error if a type is defined
+ with the Py_TPFLAGS_HAVE_GC flag set but has no traverse function
+ (PyTypeObject.tp_traverse). (Contributed by Victor Stinner in
+ bpo-44263.)
+ """
+
+commit 54c261ddfcb7221b1e6828c0a6a29a8b07f57043
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sat Dec 16 01:12:28 2023 +0100
+
+ python3.11: "Python: support v3.11 (beta) with changes to PyFrameObj.."
+
+ Partially applied Blender upstream ref: 780c0ea097444c3be60314dffd203c099720badb
+
+diff --git a/blender-2.79b/source/blender/python/generic/py_capi_utils.c b/blender-2.79b/source/blender/python/generic/py_capi_utils.c
+index 17cb657..10a38da 100644
+--- a/blender-2.79b/source/blender/python/generic/py_capi_utils.c
++++ b/blender-2.79b/source/blender/python/generic/py_capi_utils.c
+@@ -282,17 +282,21 @@ void PyC_StackSpit(void)
+ void PyC_FileAndNum(const char **filename, int *lineno)
+ {
+ PyFrameObject *frame;
+-
++ PyCodeObject *code;
++
+ if (filename) *filename = NULL;
+ if (lineno) *lineno = -1;
+
+- if (!(frame = PyThreadState_GET()->frame)) {
++ if (!(frame = PyEval_GetFrame())) {
++ return;
++ }
++ if (!(code = PyFrame_GetCode(frame))) {
+ return;
+ }
+
+ /* when executing a script */
+ if (filename) {
+- *filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
++ *filename = PyUnicode_AsUTF8(code->co_filename);
+ }
+
+ /* when executing a module */
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_app_handlers.c b/blender-2.79b/source/blender/python/intern/bpy_app_handlers.c
+index 90aa22d..bcabd09 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_app_handlers.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_app_handlers.c
+@@ -155,8 +155,7 @@ static PyTypeObject BPyPersistent_Type = {
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+- Py_TPFLAGS_BASETYPE, /* tp_flags */
++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_rna.c b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+index 722e23d..f2f0ed7 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_rna.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_rna.c
+@@ -5753,7 +5753,7 @@ PyTypeObject pyrna_struct_Type = {
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+diff --git a/blender-2.79b/source/blender/python/intern/bpy_traceback.c b/blender-2.79b/source/blender/python/intern/bpy_traceback.c
+index fedf889..462438f 100644
+--- a/blender-2.79b/source/blender/python/intern/bpy_traceback.c
++++ b/blender-2.79b/source/blender/python/intern/bpy_traceback.c
+@@ -39,7 +39,9 @@
+
+ static const char *traceback_filepath(PyTracebackObject *tb, PyObject **coerce)
+ {
+- return PyBytes_AS_STRING((*coerce = PyUnicode_EncodeFSDefault(tb->tb_frame->f_code->co_filename)));
++ PyCodeObject *code = PyFrame_GetCode(tb->tb_frame);
++ *coerce = PyUnicode_EncodeFSDefault(code->co_filename);
++ return PyBytes_AS_STRING(*coerce);
+ }
+
+ /* copied from pythonrun.c, 3.4.0 */
+diff --git a/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp b/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp
+index 6aaf6f0..f8a9cc4 100644
+--- a/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp
++++ b/blender-2.79b/source/gameengine/GameLogic/SCA_PythonController.cpp
+@@ -41,11 +41,6 @@
+ #include "SCA_IActuator.h"
+ #include "EXP_PyObjectPlus.h"
+
+-#ifdef WITH_PYTHON
+-#include "compile.h"
+-#include "eval.h"
+-#endif // WITH_PYTHON
+-
+ #include <algorithm>
+
+
diff --git a/0011_ffmpeg.patch b/0011_ffmpeg.patch
new file mode 100644
index 000000000000..340dc66d1c80
--- /dev/null
+++ b/0011_ffmpeg.patch
@@ -0,0 +1,4805 @@
+commit cc06806e12600076b1f7b1de4adcf41f0d7e9a6f
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Sun Dec 24 22:59:30 2023 +0100
+
+ ffmpeg: fix building BGE with latest FFMpeg
+
+commit 5e5a2a1eaf4205f10ac25c61358c613b240cc7cc
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Tue Dec 19 21:46:52 2023 +0100
+
+ ffmpeg: support for FFmpeg 5
+
+ Used Blender upstream refs:
+
+ - 8d6264ea12 "Cleanup: Remove deprecated variables and functions calls from our ffmpeg code"
+ - dd2e187344 "Audaspace: add support for latest ffmpeg."
+ - af6a1b08e3 "VSE: Refactor our code to be compatible with ffmpeg 5.0"
+ - 08a6321501 "FFmpeg pixel format conversion improvements"
+ - fba35aa8c5 "Use FFmpeg's own `av_guess_frame_rate()` function instead of guessing ourselves"
+
+ Updated the FFmpeg related code as much as possible to above refs
+
+commit abec792ffaf1f70ce68c18ff06065ae4224de1b1
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Tue Dec 19 18:09:24 2023 +0100
+
+ ffmpeg: replace deprecated av_free_packet() with av_packet_unref()
+
+commit 528f895ac4a3cd9b992c2e0b4e8c742e22b68e28
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Tue Dec 19 18:07:17 2023 +0100
+
+ ffmpeg: remove use of deprecated av_register_all()
+
+commit b234ee57030f620b7b5cee5f655cfcac27a5cb91
+Author: CYBERDEViL <cyberdevil@notabug.org>
+Date: Mon Dec 18 22:36:24 2023 +0100
+
+ ffmpeg: "Fix building with latest versions of ffmpeg."
+
+ Fully applied Blender upstream ref: 4e4a93bc454d93ec8523f44b73a42977e2868ecc
+
+diff --git a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
+index e9eea19..f28fb80 100644
+--- a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
++++ b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
+@@ -38,37 +38,36 @@ extern "C" {
+ #include <libavcodec/avcodec.h>
+ #include <libavformat/avformat.h>
+ #include <libavformat/avio.h>
++#include <libavutil/avutil.h>
+ #include "ffmpeg_compat.h"
+ }
+
++#if LIBAVCODEC_VERSION_MAJOR < 58
++#define FFMPEG_OLD_CODE
++#endif
++
+ int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer)
+ {
+-#ifdef FFMPEG_HAVE_DECODE_AUDIO4
+- AVFrame* frame = NULL;
++ int buf_size = buffer.getSize();
++ int buf_pos = 0;
++
++#ifdef FFMPEG_OLD_CODE
+ int got_frame;
+ int read_length;
+ uint8_t* orig_data = packet.data;
+ int orig_size = packet.size;
+
+- int buf_size = buffer.getSize();
+- int buf_pos = 0;
+-
+ while(packet.size > 0)
+ {
+ got_frame = 0;
+
+- if(!frame)
+- frame = av_frame_alloc();
+- else
+- av_frame_unref(frame);
+-
+- read_length = avcodec_decode_audio4(m_codecCtx, frame, &got_frame, &packet);
++ read_length = avcodec_decode_audio4(m_codecCtx, m_frame, &got_frame, &packet);
+ if(read_length < 0)
+ break;
+
+ if(got_frame)
+ {
+- int data_size = av_samples_get_buffer_size(NULL, m_codecCtx->channels, frame->nb_samples, m_codecCtx->sample_fmt, 1);
++ int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1);
+
+ if(buf_size - buf_pos < data_size)
+ {
+@@ -78,18 +77,18 @@ int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer)
+
+ if(m_tointerleave)
+ {
+- int single_size = data_size / m_codecCtx->channels / frame->nb_samples;
++ int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples;
+ for(int channel = 0; channel < m_codecCtx->channels; channel++)
+ {
+- for(int i = 0; i < frame->nb_samples; i++)
++ for(int i = 0; i < m_frame->nb_samples; i++)
+ {
+ memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
+- frame->data[channel] + i * single_size, single_size);
++ m_frame->data[channel] + i * single_size, single_size);
+ }
+ }
+ }
+ else
+- memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size);
++ memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size);
+
+ buf_pos += data_size;
+ }
+@@ -99,57 +98,44 @@ int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer)
+
+ packet.data = orig_data;
+ packet.size = orig_size;
+- av_free(frame);
+-
+- return buf_pos;
+ #else
+- // save packet parameters
+- uint8_t *audio_pkg_data = packet.data;
+- int audio_pkg_size = packet.size;
+-
+- int buf_size = buffer.getSize();
+- int buf_pos = 0;
++ avcodec_send_packet(m_codecCtx, &packet);
+
+- int read_length, data_size;
++ while(true)
++ {
++ auto ret = avcodec_receive_frame(m_codecCtx, m_frame);
+
+- AVPacket tmp_pkt;
++ if(ret != 0)
++ break;
+
+- av_init_packet(&tmp_pkt);
++ int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1);
+
+- // as long as there is still data in the package
+- while(audio_pkg_size > 0)
+- {
+- // resize buffer if needed
+- if(buf_size - buf_pos < AVCODEC_MAX_AUDIO_FRAME_SIZE)
++ if(buf_size - buf_pos < data_size)
+ {
+- buffer.resize(buf_size + AVCODEC_MAX_AUDIO_FRAME_SIZE, true);
+- buf_size += AVCODEC_MAX_AUDIO_FRAME_SIZE;
++ buffer.resize(buf_size + data_size, true);
++ buf_size += data_size;
+ }
+
+- // read samples from the packet
+- data_size = buf_size - buf_pos;
+-
+- tmp_pkt.data = audio_pkg_data;
+- tmp_pkt.size = audio_pkg_size;
+-
+- read_length = avcodec_decode_audio3(
+- m_codecCtx,
+- (int16_t*)(((data_t*)buffer.getBuffer()) + buf_pos),
+- &data_size, &tmp_pkt);
+-
+- // read error, next packet!
+- if(read_length < 0)
+- break;
++ if(m_tointerleave)
++ {
++ int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples;
++ for(int channel = 0; channel < m_codecCtx->channels; channel++)
++ {
++ for(int i = 0; i < m_frame->nb_samples; i++)
++ {
++ std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
++ m_frame->data[channel] + i * single_size, single_size);
++ }
++ }
++ }
++ else
++ std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size);
+
+ buf_pos += data_size;
+-
+- // move packet parameters
+- audio_pkg_data += read_length;
+- audio_pkg_size -= read_length;
+ }
++#endif
+
+ return buf_pos;
+-#endif
+ }
+
+ static const char* streaminfo_error = "AUD_FFMPEGReader: Stream info couldn't "
+@@ -176,7 +162,11 @@ void AUD_FFMPEGReader::init()
+
+ for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
+ {
++#ifdef FFMPEG_OLD_CODE
+ if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
++#else
++ if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
++#endif
+ && (m_stream < 0))
+ {
+ m_stream=i;
+@@ -187,12 +177,35 @@ void AUD_FFMPEGReader::init()
+ if(m_stream == -1)
+ AUD_THROW(AUD_ERROR_FFMPEG, noaudio_error);
+
+- m_codecCtx = m_formatCtx->streams[m_stream]->codec;
+-
+ // get a decoder and open it
+- AVCodec *aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
+- if(!aCodec)
++#ifndef FFMPEG_OLD_CODE
++ const AVCodec* aCodec = avcodec_find_decoder(m_formatCtx->streams[m_stream]->codecpar->codec_id);
++
++ if(!aCodec) {
+ AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error);
++ }
++#endif
++
++ m_frame = av_frame_alloc();
++
++ if(!m_frame)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be read, ffmpeg frame couldn't be allocated.");
++
++#ifdef FFMPEG_OLD_CODE
++ m_codecCtx = m_formatCtx->streams[m_stream]->codec;
++
++ AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
++#else
++ m_codecCtx = avcodec_alloc_context3(aCodec);
++#endif
++
++ if(!m_codecCtx)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be read, ffmpeg context couldn't be allocated.");
++
++#ifndef FFMPEG_OLD_CODE
++ if(avcodec_parameters_to_context(m_codecCtx, m_formatCtx->streams[m_stream]->codecpar) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be read, ffmpeg decoder parameters couldn't be copied to decoder context.");
++#endif
+
+ if(avcodec_open2(m_codecCtx, aCodec, NULL) < 0)
+ AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error);
+@@ -236,8 +249,10 @@ static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be "
+ "opened.";
+
+ AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) :
+- m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
++ m_pkgbuf(),
+ m_formatCtx(NULL),
++ m_codecCtx(nullptr),
++ m_frame(nullptr),
+ m_aviocontext(NULL),
+ m_membuf(NULL)
+ {
+@@ -260,13 +275,15 @@ static const char* streamopen_error = "AUD_FFMPEGReader: Stream couldn't be "
+ "opened.";
+
+ AUD_FFMPEGReader::AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer) :
+- m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
++ m_pkgbuf(),
++ m_codecCtx(nullptr),
++ m_frame(nullptr),
+ m_membuffer(buffer),
+ m_membufferpos(0)
+ {
+- m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE));
++ m_membuf = reinterpret_cast<data_t*>(av_malloc(AV_INPUT_BUFFER_MIN_SIZE + AV_INPUT_BUFFER_PADDING_SIZE));
+
+- m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this,
++ m_aviocontext = avio_alloc_context(m_membuf, AV_INPUT_BUFFER_MIN_SIZE, 0, this,
+ read_packet, NULL, seek_packet);
+
+ if(!m_aviocontext)
+@@ -297,7 +314,14 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer) :
+
+ AUD_FFMPEGReader::~AUD_FFMPEGReader()
+ {
++ if(m_frame)
++ av_frame_free(&m_frame);
++#ifdef FFMPEG_OLD_CODE
+ avcodec_close(m_codecCtx);
++#else
++ if(m_codecCtx)
++ avcodec_free_context(&m_codecCtx);
++#endif
+ avformat_close_input(&m_formatCtx);
+ }
+
+@@ -398,7 +422,7 @@ void AUD_FFMPEGReader::seek(int position)
+ }
+ }
+ }
+- av_free_packet(&packet);
++ av_packet_unref(&packet);
+ }
+ }
+ else
+@@ -429,7 +453,7 @@ AUD_Specs AUD_FFMPEGReader::getSpecs() const
+ void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
+ {
+ // read packages and decode them
+- AVPacket packet;
++ AVPacket packet = {};
+ int data_size = 0;
+ int pkgbuf_pos;
+ int left = length;
+@@ -446,7 +470,7 @@ void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
+ m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(),
+ data_size / AUD_FORMAT_SIZE(m_specs.format));
+ buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
+- left -= data_size/sample_size;
++ left -= data_size / sample_size;
+ }
+
+ // for each frame read as long as there isn't enough data already
+@@ -463,9 +487,9 @@ void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
+ m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(),
+ data_size / AUD_FORMAT_SIZE(m_specs.format));
+ buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
+- left -= data_size/sample_size;
++ left -= data_size / sample_size;
+ }
+- av_free_packet(&packet);
++ av_packet_unref(&packet);
+ }
+ // read more data than necessary?
+ if(pkgbuf_pos > data_size)
+diff --git a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
+index 377086e..a86be99 100644
+--- a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
++++ b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
+@@ -81,6 +81,11 @@ private:
+ */
+ AVCodecContext* m_codecCtx;
+
++ /**
++ * The AVFrame structure for using ffmpeg.
++ */
++ AVFrame* m_frame;
++
+ /**
+ * The AVIOContext to read the data from.
+ */
+@@ -129,9 +134,9 @@ private:
+ */
+ void init();
+
+- // hide copy constructor and operator=
+- AUD_FFMPEGReader(const AUD_FFMPEGReader&);
+- AUD_FFMPEGReader& operator=(const AUD_FFMPEGReader&);
++ // delete copy constructor and operator=
++ AUD_FFMPEGReader(const AUD_FFMPEGReader&) = delete;
++ AUD_FFMPEGReader& operator=(const AUD_FFMPEGReader&) = delete;
+
+ public:
+ /**
+diff --git a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
+index 3f95ac7..bde90a6 100644
+--- a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
++++ b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
+@@ -36,11 +36,15 @@
+
+ extern "C" {
+ #include <libavcodec/avcodec.h>
+-#include <libavformat/avformat.h>
+ #include <libavformat/avio.h>
++#include <libavutil/channel_layout.h>
+ #include "ffmpeg_compat.h"
+ }
+
++#if LIBAVCODEC_VERSION_MAJOR < 58
++#define FFMPEG_OLD_CODE
++#endif
++
+ static const char* context_error = "AUD_FFMPEGWriter: Couldn't allocate context.";
+ static const char* codec_error = "AUD_FFMPEGWriter: Invalid codec or codec not found.";
+ static const char* stream_error = "AUD_FFMPEGWriter: Couldn't allocate stream.";
+@@ -51,88 +55,135 @@ static const char* write_error = "AUD_FFMPEGWriter: Error writing packet.";
+ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate) :
+ m_position(0),
+ m_specs(specs),
++ m_formatCtx(nullptr),
++ m_codecCtx(nullptr),
++ m_stream(nullptr),
++ m_packet(nullptr),
++ m_frame(nullptr),
++ m_deinterleave(false),
+ m_input_samples(0)
+ {
+- static const char* formats[] = { NULL, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };
++ static const char* formats[] = { nullptr, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };
+
+- m_formatCtx = avformat_alloc_context();
+- if (!m_formatCtx) AUD_THROW(AUD_ERROR_FFMPEG, context_error);
++ if(avformat_alloc_output_context2(&m_formatCtx, nullptr, formats[format], filename.c_str()) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, format couldn't be found with ffmpeg.");
+
+- strcpy(m_formatCtx->filename, filename.c_str());
+- m_outputFmt = m_formatCtx->oformat = av_guess_format(formats[format], filename.c_str(), NULL);
+- if (!m_outputFmt) {
++ const AVOutputFormat* outputFmt = m_formatCtx->oformat;
++
++ if(!outputFmt) {
+ avformat_free_context(m_formatCtx);
+- AUD_THROW(AUD_ERROR_FFMPEG, context_error);
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, output format couldn't be found with ffmpeg.");
+ }
+
++ AVCodecID audio_codec = AV_CODEC_ID_NONE;
++
+ switch(codec)
+ {
+ case AUD_CODEC_AAC:
+- m_outputFmt->audio_codec = AV_CODEC_ID_AAC;
++ audio_codec = AV_CODEC_ID_AAC;
+ break;
+ case AUD_CODEC_AC3:
+- m_outputFmt->audio_codec = AV_CODEC_ID_AC3;
++ audio_codec = AV_CODEC_ID_AC3;
+ break;
+ case AUD_CODEC_FLAC:
+- m_outputFmt->audio_codec = AV_CODEC_ID_FLAC;
++ audio_codec = AV_CODEC_ID_FLAC;
+ break;
+ case AUD_CODEC_MP2:
+- m_outputFmt->audio_codec = AV_CODEC_ID_MP2;
++ audio_codec = AV_CODEC_ID_MP2;
+ break;
+ case AUD_CODEC_MP3:
+- m_outputFmt->audio_codec = AV_CODEC_ID_MP3;
++ audio_codec = AV_CODEC_ID_MP3;
++ break;
++ case AUD_CODEC_OPUS:
++ audio_codec = AV_CODEC_ID_OPUS;
+ break;
+ case AUD_CODEC_PCM:
+ switch(specs.format)
+ {
+ case AUD_FORMAT_U8:
+- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_U8;
++ audio_codec = AV_CODEC_ID_PCM_U8;
+ break;
+ case AUD_FORMAT_S16:
+- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
++ audio_codec = AV_CODEC_ID_PCM_S16LE;
+ break;
+ case AUD_FORMAT_S24:
+- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE;
++ audio_codec = AV_CODEC_ID_PCM_S24LE;
+ break;
+ case AUD_FORMAT_S32:
+- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE;
++ audio_codec = AV_CODEC_ID_PCM_S32LE;
+ break;
+ case AUD_FORMAT_FLOAT32:
+- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE;
++ audio_codec = AV_CODEC_ID_PCM_F32LE;
+ break;
+ case AUD_FORMAT_FLOAT64:
+- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE;
++ audio_codec = AV_CODEC_ID_PCM_F64LE;
+ break;
+ default:
+- m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
++ audio_codec = AV_CODEC_ID_NONE;
+ break;
+ }
+ break;
+ case AUD_CODEC_VORBIS:
+- m_outputFmt->audio_codec = AV_CODEC_ID_VORBIS;
++ audio_codec = AV_CODEC_ID_VORBIS;
+ break;
+ default:
+- m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
++ audio_codec = AV_CODEC_ID_NONE;
++ break;
++ }
++
++ uint64_t channel_layout = 0;
++
++ switch(m_specs.channels)
++ {
++ case AUD_CHANNELS_MONO:
++ channel_layout = AV_CH_LAYOUT_MONO;
++ break;
++ case AUD_CHANNELS_STEREO:
++ channel_layout = AV_CH_LAYOUT_STEREO;
++ break;
++ case AUD_CHANNELS_STEREO_LFE:
++ channel_layout = AV_CH_LAYOUT_2POINT1;
++ break;
++ case AUD_CHANNELS_SURROUND4:
++ channel_layout = AV_CH_LAYOUT_QUAD;
++ break;
++ case AUD_CHANNELS_SURROUND5:
++ channel_layout = AV_CH_LAYOUT_5POINT0_BACK;
++ break;
++ case AUD_CHANNELS_SURROUND51:
++ channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
++ break;
++ case AUD_CHANNELS_SURROUND61:
++ channel_layout = AV_CH_LAYOUT_6POINT1_BACK;
++ break;
++ case AUD_CHANNELS_SURROUND71:
++ channel_layout = AV_CH_LAYOUT_7POINT1;
+ break;
+ }
+
+ try
+ {
+- if(m_outputFmt->audio_codec == AV_CODEC_ID_NONE)
+- AUD_THROW(AUD_ERROR_SPECS, codec_error);
++ if(audio_codec == AV_CODEC_ID_NONE)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, audio codec not found with ffmpeg.");
++
++ const AVCodec* codec = avcodec_find_encoder(audio_codec);
++ if(!codec)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, audio encoder couldn't be found with ffmpeg.");
+
+- m_stream = avformat_new_stream(m_formatCtx, NULL);
++ m_stream = avformat_new_stream(m_formatCtx, codec);
+ if(!m_stream)
+- AUD_THROW(AUD_ERROR_FFMPEG, stream_error);
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, stream creation failed with ffmpeg.");
+
++ m_stream->id = m_formatCtx->nb_streams - 1;
++
++#ifdef FFMPEG_OLD_CODE
+ m_codecCtx = m_stream->codec;
+- m_codecCtx->codec_id = m_outputFmt->audio_codec;
+- m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
+- m_codecCtx->bit_rate = bitrate;
+- m_codecCtx->sample_rate = int(m_specs.rate);
+- m_codecCtx->channels = m_specs.channels;
+- m_codecCtx->time_base.num = 1;
+- m_codecCtx->time_base.den = m_codecCtx->sample_rate;
++#else
++ m_codecCtx = avcodec_alloc_context3(codec);
++#endif
++
++ if(!m_codecCtx)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, context creation failed with ffmpeg.");
+
+ switch(m_specs.format)
+ {
+@@ -148,133 +199,182 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
+ m_convert = AUD_convert_float_s32;
+ m_codecCtx->sample_fmt = AV_SAMPLE_FMT_S32;
+ break;
+- case AUD_FORMAT_FLOAT32:
+- m_convert = AUD_convert_copy<float>;
+- m_codecCtx->sample_fmt = AV_SAMPLE_FMT_FLT;
+- break;
+ case AUD_FORMAT_FLOAT64:
+ m_convert = AUD_convert_float_double;
+ m_codecCtx->sample_fmt = AV_SAMPLE_FMT_DBL;
+ break;
+ default:
+- AUD_THROW(AUD_ERROR_FFMPEG, format_error);
++ m_convert = AUD_convert_copy<sample_t>;
++ m_codecCtx->sample_fmt = AV_SAMPLE_FMT_FLT;
++ break;
+ }
+
+- try
+- {
+- if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
+- m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+-
+- AVCodec* codec = avcodec_find_encoder(m_codecCtx->codec_id);
+- if(!codec)
+- AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
+-
+- if(codec->sample_fmts) {
+- // Check if the preferred sample format for this codec is supported.
+- const enum AVSampleFormat *p = codec->sample_fmts;
+- for(; *p != -1; p++) {
+- if(*p == m_stream->codec->sample_fmt)
+- break;
+- }
+- if(*p == -1) {
+- // Sample format incompatible with codec. Defaulting to a format known to work.
+- m_stream->codec->sample_fmt = codec->sample_fmts[0];
+- }
+- }
+-
+- if(avcodec_open2(m_codecCtx, codec, NULL))
+- AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
++ if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
++ m_codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+- m_output_buffer.resize(FF_MIN_BUFFER_SIZE);
+- int samplesize = AUD_MAX(AUD_SAMPLE_SIZE(m_specs), AUD_DEVICE_SAMPLE_SIZE(m_specs));
++ bool format_supported = false;
+
+- if(m_codecCtx->frame_size <= 1) {
+- m_input_size = FF_MIN_BUFFER_SIZE * 8 / m_codecCtx->bits_per_coded_sample / m_codecCtx->channels;
+- m_input_buffer.resize(m_input_size * samplesize);
+- }
+- else
++ for(int i = 0; codec->sample_fmts[i] != -1; i++)
++ {
++ if(av_get_alt_sample_fmt(codec->sample_fmts[i], false) == m_codecCtx->sample_fmt)
+ {
+- m_input_buffer.resize(m_codecCtx->frame_size * samplesize);
+- m_input_size = m_codecCtx->frame_size;
++ m_deinterleave = av_sample_fmt_is_planar(codec->sample_fmts[i]);
++ m_codecCtx->sample_fmt = codec->sample_fmts[i];
++ format_supported = true;
+ }
++ }
+
+-#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
+- m_frame = av_frame_alloc();
+- if (!m_frame)
+- AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
+- av_frame_unref(m_frame);
+- m_frame->linesize[0] = m_input_size * samplesize;
+- m_frame->format = m_codecCtx->sample_fmt;
+- m_frame->nb_samples = m_input_size;
+-# ifdef FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
+- m_frame->sample_rate = m_codecCtx->sample_rate;
+-# endif
+-# ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
+- m_frame->channel_layout = m_codecCtx->channel_layout;
+-# endif
+- m_sample_size = av_get_bytes_per_sample(m_codecCtx->sample_fmt);
+- m_frame_pts = 0;
+- m_deinterleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt);
+- if(m_deinterleave)
+- m_deinterleave_buffer.resize(m_input_size * m_codecCtx->channels * m_sample_size);
+-#endif
+-
+- try
++ if(!format_supported)
++ {
++ int chosen_index = 0;
++ auto chosen = av_get_alt_sample_fmt(codec->sample_fmts[chosen_index], false);
++ for(int i = 1; codec->sample_fmts[i] != -1; i++)
+ {
+- if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
+- AUD_THROW(AUD_ERROR_FILE, file_error);
+-
+- if(avformat_write_header(m_formatCtx, NULL) < 0) {
+- throw;
++ auto fmt = av_get_alt_sample_fmt(codec->sample_fmts[i], false);
++ if((fmt > chosen && chosen < m_codecCtx->sample_fmt) || (fmt > m_codecCtx->sample_fmt && fmt < chosen))
++ {
++ chosen = fmt;
++ chosen_index = i;
+ }
+ }
+- catch(AUD_Exception&)
++
++ m_codecCtx->sample_fmt = codec->sample_fmts[chosen_index];
++ m_deinterleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt);
++ switch(av_get_alt_sample_fmt(m_codecCtx->sample_fmt, false))
+ {
+- avcodec_close(m_codecCtx);
+- av_freep(&m_formatCtx->streams[0]->codec);
+- throw;
++ case AV_SAMPLE_FMT_U8:
++ specs.format = AUD_FORMAT_U8;
++ m_convert = AUD_convert_float_u8;
++ break;
++ case AV_SAMPLE_FMT_S16:
++ specs.format = AUD_FORMAT_S16;
++ m_convert = AUD_convert_float_s16;
++ break;
++ case AV_SAMPLE_FMT_S32:
++ specs.format = AUD_FORMAT_S32;
++ m_convert = AUD_convert_float_s32;
++ break;
++ case AV_SAMPLE_FMT_FLT:
++ specs.format = AUD_FORMAT_FLOAT32;
++ m_convert = AUD_convert_copy<sample_t>;
++ break;
++ case AV_SAMPLE_FMT_DBL:
++ specs.format = AUD_FORMAT_FLOAT64;
++ m_convert = AUD_convert_float_double;
++ break;
++ default:
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, sample format not supported with ffmpeg.");
+ }
+ }
+- catch(AUD_Exception&)
++
++ m_codecCtx->sample_rate = 0;
++
++ if(codec->supported_samplerates)
+ {
+- av_freep(&m_formatCtx->streams[0]);
+- throw;
++ for(int i = 0; codec->supported_samplerates[i]; i++)
++ {
++ if(codec->supported_samplerates[i] == m_specs.rate)
++ {
++ m_codecCtx->sample_rate = codec->supported_samplerates[i];
++ break;
++ }
++ else if((codec->supported_samplerates[i] > m_codecCtx->sample_rate && m_specs.rate > m_codecCtx->sample_rate) ||
++ (codec->supported_samplerates[i] < m_codecCtx->sample_rate && m_specs.rate < codec->supported_samplerates[i]))
++ {
++ m_codecCtx->sample_rate = codec->supported_samplerates[i];
++ }
++ }
+ }
++
++ if(m_codecCtx->sample_rate == 0)
++ m_codecCtx->sample_rate = m_specs.rate;
++
++ m_specs.rate = m_codecCtx->sample_rate;
++
++#ifdef FFMPEG_OLD_CODE
++ m_codecCtx->codec_id = audio_codec;
++#endif
++
++ m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
++ m_codecCtx->bit_rate = bitrate;
++ m_codecCtx->channel_layout = channel_layout;
++ m_codecCtx->channels = m_specs.channels;
++ m_stream->time_base.num = m_codecCtx->time_base.num = 1;
++ m_stream->time_base.den = m_codecCtx->time_base.den = m_codecCtx->sample_rate;
++
++ if(avcodec_open2(m_codecCtx, codec, nullptr) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, encoder couldn't be opened with ffmpeg.");
++
++#ifndef FFMPEG_OLD_CODE
++ if(avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, codec parameters couldn't be copied to the context.");
++#endif
++
++ int samplesize = std::max(int(AUD_SAMPLE_SIZE(m_specs)), AUD_DEVICE_SAMPLE_SIZE(m_specs));
++
++ if((m_input_size = m_codecCtx->frame_size))
++ m_input_buffer.resize(m_input_size * samplesize);
++
++ if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, file opening failed with ffmpeg.");
++
++ if(avformat_write_header(m_formatCtx, nullptr) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, writing the header failed.");
+ }
+ catch(AUD_Exception&)
+ {
+- av_free(m_formatCtx);
++#ifndef FFMPEG_OLD_CODE
++ if(m_codecCtx)
++ avcodec_free_context(&m_codecCtx);
++#endif
++ avformat_free_context(m_formatCtx);
+ throw;
+ }
++
++#ifdef FFMPEG_OLD_CODE
++ m_packet = new AVPacket({});
++#else
++ m_packet = av_packet_alloc();
++#endif
++
++ m_frame = av_frame_alloc();
+ }
+
+ AUD_FFMPEGWriter::~AUD_FFMPEGWriter()
+ {
+ // writte missing data
+ if(m_input_samples)
+- {
+- sample_t* buf = m_input_buffer.getBuffer();
+- memset(buf + m_specs.channels * m_input_samples, 0,
+- (m_input_size - m_input_samples) * AUD_DEVICE_SAMPLE_SIZE(m_specs));
++ encode();
+
+- encode(buf);
+- }
++ close();
+
+ av_write_trailer(m_formatCtx);
+
+- avcodec_close(m_codecCtx);
++ if(m_frame)
++ av_frame_free(&m_frame);
+
+- av_freep(&m_formatCtx->streams[0]->codec);
+- av_freep(&m_formatCtx->streams[0]);
++ if(m_packet)
++ {
++#ifdef FFMPEG_OLD_CODE
++ delete m_packet;
++#else
++ av_packet_free(&m_packet);
++#endif
++ }
+
+-#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
+- av_frame_free(&m_frame);
++#ifdef FFMPEG_OLD_CODE
++ avcodec_close(m_codecCtx);
++#else
++ if(m_codecCtx)
++ avcodec_free_context(&m_codecCtx);
+ #endif
+
+- avio_close(m_formatCtx->pb);
+- av_free(m_formatCtx);
++ avio_closep(&m_formatCtx->pb);
++ avformat_free_context(m_formatCtx);
+ }
+
++
++
+ int AUD_FFMPEGWriter::getPosition() const
+ {
+ return m_position;
+@@ -285,72 +385,130 @@ AUD_DeviceSpecs AUD_FFMPEGWriter::getSpecs() const
+ return m_specs;
+ }
+
+-void AUD_FFMPEGWriter::encode(sample_t* data)
++void AUD_FFMPEGWriter::encode()
+ {
+- // convert first
+- if(m_input_size)
+- m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_size * m_specs.channels);
++ sample_t* data = m_input_buffer.getBuffer();
+
+- AVPacket packet = { 0 };
+- av_init_packet(&packet);
+-
+-#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
+- int got_output, ret;
+- m_frame->pts = m_frame_pts / av_q2d(m_codecCtx->time_base);
+- m_frame_pts++;
+-#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
+- m_frame->channel_layout = m_codecCtx->channel_layout;
+-#endif
++ if(m_deinterleave)
++ {
++ m_deinterleave_buffer.assureSize(m_input_buffer.getSize());
+
+- if(m_deinterleave) {
+- for(int channel = 0; channel < m_codecCtx->channels; channel++) {
+- for(int i = 0; i < m_frame->nb_samples; i++) {
+- memcpy(reinterpret_cast<uint8_t*>(m_deinterleave_buffer.getBuffer()) + (i + channel * m_frame->nb_samples) * m_sample_size,
+- reinterpret_cast<uint8_t*>(data) + (m_codecCtx->channels * i + channel) * m_sample_size, m_sample_size);
++ sample_t* dbuf = m_deinterleave_buffer.getBuffer();
++ // deinterleave
++ int single_size = sizeof(sample_t);
++ for(int channel = 0; channel < m_specs.channels; channel++)
++ {
++ for(int i = 0; i < m_input_buffer.getSize() / AUD_SAMPLE_SIZE(m_specs); i++)
++ {
++ std::memcpy(((data_t*)dbuf) + (m_input_samples * channel + i) * single_size,
++ ((data_t*)data) + ((m_specs.channels * i) + channel) * single_size, single_size);
+ }
+ }
+
+- data = m_deinterleave_buffer.getBuffer();
++ // convert first
++ if(m_input_size)
++ m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(dbuf), m_input_samples * m_specs.channels);
++ else
++ std::memcpy(data, dbuf, m_input_buffer.getSize());
+ }
++ else
++ // convert first
++ if(m_input_size)
++ m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_samples * m_specs.channels);
+
+- avcodec_fill_audio_frame(m_frame, m_codecCtx->channels, m_codecCtx->sample_fmt, reinterpret_cast<uint8_t*>(data),
+- m_frame->nb_samples * av_get_bytes_per_sample(m_codecCtx->sample_fmt) * m_codecCtx->channels, 1);
++#ifdef FFMPEG_OLD_CODE
++ m_packet->data = nullptr;
++ m_packet->size = 0;
+
+- ret = avcodec_encode_audio2(m_codecCtx, &packet, m_frame, &got_output);
+- if(ret < 0)
+- AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
++ av_init_packet(m_packet);
+
+- if(!got_output)
+- return;
++ av_frame_unref(m_frame);
++ int got_packet;
++#endif
++
++ m_frame->nb_samples = m_input_samples;
++ m_frame->format = m_codecCtx->sample_fmt;
++ m_frame->channel_layout = m_codecCtx->channel_layout;
++
++ if(avcodec_fill_audio_frame(m_frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, filling the audio frame failed with ffmpeg.");
++
++ AVRational sample_time = { 1, static_cast<int>(m_specs.rate) };
++ m_frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time);
++
++#ifdef FFMPEG_OLD_CODE
++ if(avcodec_encode_audio2(m_codecCtx, m_packet, m_frame, &got_packet))
++ {
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, audio encoding failed with ffmpeg.");
++ }
++
++ if(got_packet)
++ {
++ m_packet->flags |= AV_PKT_FLAG_KEY;
++ m_packet->stream_index = m_stream->index;
++ if(av_write_frame(m_formatCtx, m_packet) < 0)
++ {
++ av_free_packet(m_packet);
++ AUD_THROW(AUD_ERROR_FILE, "Frame couldn't be writen to the file with ffmpeg.");
++ }
++ av_free_packet(m_packet);
++ }
+ #else
+- sample_t* outbuf = m_output_buffer.getBuffer();
++ if(avcodec_send_frame(m_codecCtx, m_frame) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, audio encoding failed with ffmpeg.");
+
+- packet.size = avcodec_encode_audio(m_codecCtx, reinterpret_cast<uint8_t*>(outbuf), m_output_buffer.getSize(), reinterpret_cast<short*>(data));
+- if(m_codecCtx->coded_frame && m_codecCtx->coded_frame->pts != AV_NOPTS_VALUE)
+- packet.pts = av_rescale_q(m_codecCtx->coded_frame->pts, m_codecCtx->time_base, m_stream->time_base);
+- packet.flags |= AV_PKT_FLAG_KEY;
+- packet.data = reinterpret_cast<uint8_t*>(outbuf);
++ while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
++ {
++ m_packet->stream_index = m_stream->index;
++
++ if(av_write_frame(m_formatCtx, m_packet) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "Frame couldn't be writen to the file with ffmpeg.");
++ }
+ #endif
++}
++
++void AUD_FFMPEGWriter::close()
++{
++#ifdef FFMPEG_OLD_CODE
++ int got_packet = true;
+
+- if(packet.pts != AV_NOPTS_VALUE)
+- packet.pts = av_rescale_q(packet.pts, m_codecCtx->time_base, m_stream->time_base);
+- if(packet.dts != AV_NOPTS_VALUE)
+- packet.dts = av_rescale_q(packet.dts, m_codecCtx->time_base, m_stream->time_base);
+- if(packet.duration > 0)
+- packet.duration = av_rescale_q(packet.duration, m_codecCtx->time_base, m_stream->time_base);
++ while(got_packet)
++ {
++ m_packet->data = nullptr;
++ m_packet->size = 0;
+
+- packet.stream_index = m_stream->index;
++ av_init_packet(m_packet);
+
+- packet.flags |= AV_PKT_FLAG_KEY;
++ if(avcodec_encode_audio2(m_codecCtx, m_packet, nullptr, &got_packet))
++ AUD_THROW(AUD_ERROR_FILE, "File end couldn't be written, audio encoding failed with ffmpeg.");
+
+- if(av_interleaved_write_frame(m_formatCtx, &packet)) {
+- av_free_packet(&packet);
+- AUD_THROW(AUD_ERROR_FFMPEG, write_error);
++ if(got_packet)
++ {
++ m_packet->flags |= AV_PKT_FLAG_KEY;
++ m_packet->stream_index = m_stream->index;
++ if(av_write_frame(m_formatCtx, m_packet))
++ {
++ av_free_packet(m_packet);
++ AUD_THROW(AUD_ERROR_FILE, "Final frames couldn't be writen to the file with ffmpeg.");
++ }
++ av_free_packet(m_packet);
++ }
+ }
++#else
++ if(avcodec_send_frame(m_codecCtx, nullptr) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "File couldn't be written, audio encoding failed with ffmpeg.");
++
++ while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
++ {
++ m_packet->stream_index = m_stream->index;
+
+- av_free_packet(&packet);
++ if(av_write_frame(m_formatCtx, m_packet) < 0)
++ AUD_THROW(AUD_ERROR_FILE, "Frame couldn't be writen to the file with ffmpeg.");
++ }
++#endif
+ }
+
++
+ void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer)
+ {
+ unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
+@@ -361,9 +519,9 @@ void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer)
+
+ while(length)
+ {
+- unsigned int len = AUD_MIN(m_input_size - m_input_samples, length);
++ unsigned int len = std::min(m_input_size - m_input_samples, length);
+
+- memcpy(inbuf + m_input_samples * m_specs.channels, buffer, len * samplesize);
++ std::memcpy(inbuf + m_input_samples * m_specs.channels, buffer, len * samplesize);
+
+ buffer += len * m_specs.channels;
+ m_input_samples += len;
+@@ -372,7 +530,7 @@ void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer)
+
+ if(m_input_samples == m_input_size)
+ {
+- encode(inbuf);
++ encode();
+
+ m_input_samples = 0;
+ }
+@@ -381,15 +539,15 @@ void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer)
+ else // PCM data, can write directly!
+ {
+ int samplesize = AUD_SAMPLE_SIZE(m_specs);
+- if(m_output_buffer.getSize() != length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8)
+- m_output_buffer.resize(length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8);
+- m_input_buffer.assureSize(length * AUD_MAX(AUD_DEVICE_SAMPLE_SIZE(m_specs), samplesize));
++ m_input_buffer.assureSize(length * std::max(AUD_DEVICE_SAMPLE_SIZE(m_specs), samplesize));
+
+ sample_t* buf = m_input_buffer.getBuffer();
+ m_convert(reinterpret_cast<data_t*>(buf), reinterpret_cast<data_t*>(buffer), length * m_specs.channels);
+
+- encode(buf);
++ m_input_samples = length;
+
+ m_position += length;
++
++ encode();
+ }
+ }
+diff --git a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
+index 492aa35..a77d250 100644
+--- a/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
++++ b/blender-2.79b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
+@@ -68,19 +68,19 @@ private:
+ AVCodecContext* m_codecCtx;
+
+ /**
+- * The AVOutputFormat structure for using ffmpeg.
++ * The AVStream structure for using ffmpeg.
+ */
+- AVOutputFormat* m_outputFmt;
++ AVStream* m_stream;
+
+ /**
+- * The AVStream structure for using ffmpeg.
++ * The AVPacket structure for using ffmpeg.
+ */
+- AVStream* m_stream;
++ AVPacket* m_packet;
+
+ /**
+- * Frame sent to the encoder.
++ * The AVFrame structure for using ffmpeg.
+ */
+- AVFrame *m_frame;
++ AVFrame* m_frame;
+
+ /**
+ * PTS of next frame to write.
+@@ -132,7 +132,13 @@ private:
+ * Encodes to the output buffer.
+ * \param data Pointer to the data to encode.
+ */
+- void encode(sample_t* data);
++ void encode();
++
++ /**
++ * Finishes writing to the file.
++ */
++ void close();
++
+
+ public:
+ /**
+diff --git a/blender-2.79b/intern/audaspace/intern/AUD_C-API.cpp b/blender-2.79b/intern/audaspace/intern/AUD_C-API.cpp
+index 52cf256..ea2faae 100644
+--- a/blender-2.79b/intern/audaspace/intern/AUD_C-API.cpp
++++ b/blender-2.79b/intern/audaspace/intern/AUD_C-API.cpp
+@@ -113,9 +113,6 @@ static AUD_I3DDevice *AUD_3ddevice;
+
+ void AUD_initOnce()
+ {
+-#ifdef WITH_FFMPEG
+- av_register_all();
+-#endif
+ #ifdef WITH_JACK
+ AUD_jack_init();
+ #endif
+diff --git a/blender-2.79b/intern/audaspace/intern/AUD_Space.h b/blender-2.79b/intern/audaspace/intern/AUD_Space.h
+index 26bbdc5..bda500b 100644
+--- a/blender-2.79b/intern/audaspace/intern/AUD_Space.h
++++ b/blender-2.79b/intern/audaspace/intern/AUD_Space.h
+@@ -195,7 +195,8 @@ typedef enum
+ AUD_CODEC_MP2,
+ AUD_CODEC_MP3,
+ AUD_CODEC_PCM,
+- AUD_CODEC_VORBIS
++ AUD_CODEC_VORBIS,
++ AUD_CODEC_OPUS
+ } AUD_Codec;
+
+ /// Sample type.(float samples)
+diff --git a/blender-2.79b/intern/ffmpeg/ffmpeg_compat.h b/blender-2.79b/intern/ffmpeg/ffmpeg_compat.h
+index 9c06c8a..0e4bcbb 100644
+--- a/blender-2.79b/intern/ffmpeg/ffmpeg_compat.h
++++ b/blender-2.79b/intern/ffmpeg/ffmpeg_compat.h
+@@ -23,9 +23,17 @@
+
+ #include <libavformat/avformat.h>
+
+-/* check our ffmpeg is new enough, avoids user complaints */
+-#if (LIBAVFORMAT_VERSION_MAJOR < 52) || ((LIBAVFORMAT_VERSION_MAJOR == 52) && (LIBAVFORMAT_VERSION_MINOR <= 64))
+-# error "FFmpeg 0.7 or newer is needed, Upgrade your FFmpeg or disable it"
++/* Check if our ffmpeg is new enough, avoids user complaints.
++ * Minimum supported version is currently 3.2.0 which mean the following library versions:
++ * libavutil > 55.30
++ * libavcodec > 57.60
++ * libavformat > 57.50
++ *
++ * We only check for one of these as they are usually updated in tandem.
++ */
++#if (LIBAVFORMAT_VERSION_MAJOR < 57) || \
++ ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR <= 50))
++# error "FFmpeg 3.2.0 or newer is needed, Upgrade your FFmpeg or disable it"
+ #endif
+ /* end sanity check */
+
+@@ -36,214 +44,7 @@
+ # define FFMPEG_INLINE static inline
+ #endif
+
+-#include <libavcodec/avcodec.h>
+-#include <libavutil/rational.h>
+-#include <libavutil/opt.h>
+-#include <libavutil/mathematics.h>
+-
+-#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
+-# define FFMPEG_HAVE_PARSE_UTILS 1
+-# include <libavutil/parseutils.h>
+-#endif
+-
+-#include <libswscale/swscale.h>
+-
+-#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
+-# define FFMPEG_HAVE_AVIO 1
+-#endif
+-
+-#if (LIBAVCODEC_VERSION_MAJOR > 53) || ((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR > 1)) || ((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR == 1) && (LIBAVCODEC_VERSION_MICRO >= 1)) || ((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR >= 121))
+-# define FFMPEG_HAVE_DEFAULT_VAL_UNION 1
+-#endif
+-
+-#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
+-# define FFMPEG_HAVE_AV_DUMP_FORMAT 1
+-#endif
+-
+-#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 45))
+-# define FFMPEG_HAVE_AV_GUESS_FORMAT 1
+-#endif
+-
+-#if (LIBAVCODEC_VERSION_MAJOR > 52) || ((LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 23))
+-# define FFMPEG_HAVE_DECODE_AUDIO3 1
+-# define FFMPEG_HAVE_DECODE_VIDEO2 1
+-#endif
+-
+-#if (LIBAVCODEC_VERSION_MAJOR > 52) || ((LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 64))
+-# define FFMPEG_HAVE_AVMEDIA_TYPES 1
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 52) || (LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 29)) && \
+- ((LIBSWSCALE_VERSION_MAJOR > 0) || (LIBSWSCALE_VERSION_MAJOR >= 0) && (LIBSWSCALE_VERSION_MINOR >= 10))
+-# define FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 54) || (LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR > 14))
+-# define FFMPEG_HAVE_CANON_H264_RESOLUTION_FIX
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 53) || (LIBAVCODEC_VERSION_MAJOR >= 53) && (LIBAVCODEC_VERSION_MINOR >= 60))
+-# define FFMPEG_HAVE_ENCODE_AUDIO2
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 53) || (LIBAVCODEC_VERSION_MAJOR >= 53) && (LIBAVCODEC_VERSION_MINOR >= 42))
+-# define FFMPEG_HAVE_DECODE_AUDIO4
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 54) || (LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR >= 13))
+-# define FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
+-#endif
+-
+-#if ((LIBAVUTIL_VERSION_MAJOR > 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR >= 21))
+-# define FFMPEG_FFV1_ALPHA_SUPPORTED
+-# define FFMPEG_SAMPLE_FMT_S16P_SUPPORTED
+-#else
+-
+-FFMPEG_INLINE
+-int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt)
+-{
+- /* no planar formats in FFmpeg < 0.9 */
+- (void) sample_fmt;
+- return 0;
+-}
+-
+-#endif
+-
+-/* FFmpeg upstream 1.0 is the first who added AV_ prefix. */
+-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
+-# define AV_CODEC_ID_NONE CODEC_ID_NONE
+-# define AV_CODEC_ID_MPEG4 CODEC_ID_MPEG4
+-# define AV_CODEC_ID_MJPEG CODEC_ID_MJPEG
+-# define AV_CODEC_ID_DNXHD CODEC_ID_DNXHD
+-# define AV_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO
+-# define AV_CODEC_ID_MPEG1VIDEO CODEC_ID_MPEG1VIDEO
+-# define AV_CODEC_ID_DVVIDEO CODEC_ID_DVVIDEO
+-# define AV_CODEC_ID_THEORA CODEC_ID_THEORA
+-# define AV_CODEC_ID_PNG CODEC_ID_PNG
+-# define AV_CODEC_ID_QTRLE CODEC_ID_QTRLE
+-# define AV_CODEC_ID_FFV1 CODEC_ID_FFV1
+-# define AV_CODEC_ID_HUFFYUV CODEC_ID_HUFFYUV
+-# define AV_CODEC_ID_H264 CODEC_ID_H264
+-# define AV_CODEC_ID_FLV1 CODEC_ID_FLV1
+-
+-# define AV_CODEC_ID_AAC CODEC_ID_AAC
+-# define AV_CODEC_ID_AC3 CODEC_ID_AC3
+-# define AV_CODEC_ID_MP3 CODEC_ID_MP3
+-# define AV_CODEC_ID_MP2 CODEC_ID_MP2
+-# define AV_CODEC_ID_FLAC CODEC_ID_FLAC
+-# define AV_CODEC_ID_PCM_U8 CODEC_ID_PCM_U8
+-# define AV_CODEC_ID_PCM_S16LE CODEC_ID_PCM_S16LE
+-# define AV_CODEC_ID_PCM_S24LE CODEC_ID_PCM_S24LE
+-# define AV_CODEC_ID_PCM_S32LE CODEC_ID_PCM_S32LE
+-# define AV_CODEC_ID_PCM_F32LE CODEC_ID_PCM_F32LE
+-# define AV_CODEC_ID_PCM_F64LE CODEC_ID_PCM_F64LE
+-# define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS
+-#endif
+-
+-FFMPEG_INLINE
+-int av_get_cropped_height_from_codec(AVCodecContext *pCodecCtx)
+-{
+- int y = pCodecCtx->height;
+-
+-#ifndef FFMPEG_HAVE_CANON_H264_RESOLUTION_FIX
+-/* really bad hack to remove this dreadfull black bar at the bottom
+- with Canon footage and old ffmpeg versions.
+- (to fix this properly in older ffmpeg versions one has to write a new
+- demuxer...)
+-
+- see the actual fix here for reference:
+-
+- http://git.libav.org/?p=libav.git;a=commit;h=30f515091c323da59c0f1b533703dedca2f4b95d
+-
+- We do our best to apply this only to matching footage.
+-*/
+- if (pCodecCtx->width == 1920 &&
+- pCodecCtx->height == 1088 &&
+- pCodecCtx->pix_fmt == PIX_FMT_YUVJ420P &&
+- pCodecCtx->codec_id == AV_CODEC_ID_H264 ) {
+- y = 1080;
+- }
+-#endif
+-
+- return y;
+-}
+-
+-#if ((LIBAVUTIL_VERSION_MAJOR < 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 22))
+-FFMPEG_INLINE
+-int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
+-{
+- const AVOption *rv = NULL;
+- (void) search_flags;
+- av_set_string3(obj, name, val, 1, &rv);
+- return rv != NULL;
+-}
+-
+-FFMPEG_INLINE
+-int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
+-{
+- const AVOption *rv = NULL;
+- (void) search_flags;
+- rv = av_set_int(obj, name, val);
+- return rv != NULL;
+-}
+-
+-FFMPEG_INLINE
+-int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
+-{
+- const AVOption *rv = NULL;
+- (void) search_flags;
+- rv = av_set_double(obj, name, val);
+- return rv != NULL;
+-}
+-
+-# define AV_OPT_TYPE_INT FF_OPT_TYPE_INT
+-# define AV_OPT_TYPE_INT64 FF_OPT_TYPE_INT64
+-# define AV_OPT_TYPE_STRING FF_OPT_TYPE_STRING
+-# define AV_OPT_TYPE_CONST FF_OPT_TYPE_CONST
+-# define AV_OPT_TYPE_DOUBLE FF_OPT_TYPE_DOUBLE
+-# define AV_OPT_TYPE_FLOAT FF_OPT_TYPE_FLOAT
+-#endif
+-
+-#if ((LIBAVUTIL_VERSION_MAJOR < 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 54))
+-FFMPEG_INLINE
+-enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt)
+-{
+- if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
+- return AV_SAMPLE_FMT_NONE;
+- return sample_fmt;
+-}
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR < 53) || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR < 35))
+-FFMPEG_INLINE
+-int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary **options)
+-{
+- /* TODO: no options are taking into account */
+- (void) options;
+- return avcodec_open(avctx, codec);
+-}
+-#endif
+-
+-#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR < 21))
+-FFMPEG_INLINE
+-AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
+-{
+- /* TODO: no codec is taking into account */
+- (void) c;
+- return av_new_stream(s, 0);
+-}
+-
+-FFMPEG_INLINE
+-int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
+-{
+- /* TODO: no options are taking into account */
+- (void) options;
+- return av_find_stream_info(ic);
+-}
+-#endif
+-
+-#if ((LIBAVFORMAT_VERSION_MAJOR > 53) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR > 32)) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR == 24) && (LIBAVFORMAT_VERSION_MICRO >= 100)))
+-FFMPEG_INLINE
++/*FFMPEG_INLINE
+ void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
+ {
+ int i;
+@@ -251,9 +52,9 @@ void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+
+- st->cur_dts = av_rescale(timestamp,
+- st->time_base.den * (int64_t)ref_st->time_base.num,
+- st->time_base.num * (int64_t)ref_st->time_base.den);
++ st->internal->cur_dts = av_rescale(timestamp,
++ st->time_base.den * (int64_t)ref_st->time_base.num,
++ st->time_base.num * (int64_t)ref_st->time_base.den);
+ }
+ }
+
+@@ -261,101 +62,13 @@ FFMPEG_INLINE
+ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
+ {
+ my_update_cur_dts(s, ref_st, timestamp);
+-}
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR < 54) || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR < 28))
+-FFMPEG_INLINE
+-void avcodec_free_frame(AVFrame **frame)
+-{
+- /* don't need to do anything with old AVFrame
+- * since it does not have malloced members */
+- (void)frame;
+-}
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 54) || (LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR >= 13))
+-# define FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
+-#endif
+-
+-#if ((LIBAVCODEC_VERSION_MAJOR > 54) || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 13))
+-# define FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
+-#endif
+-
+-#ifndef FFMPEG_HAVE_AVIO
+-# define AVIO_FLAG_WRITE URL_WRONLY
+-# define avio_open url_fopen
+-# define avio_tell url_ftell
+-# define avio_close url_fclose
+-# define avio_size url_fsize
+-#endif
+-
+-/* there are some version inbetween, which have avio_... functions but no
+- * AVIO_FLAG_... */
+-#ifndef AVIO_FLAG_WRITE
+-# define AVIO_FLAG_WRITE URL_WRONLY
+-#endif
+-
+-#ifndef AV_PKT_FLAG_KEY
+-# define AV_PKT_FLAG_KEY PKT_FLAG_KEY
+-#endif
+-
+-#ifndef FFMPEG_HAVE_AV_DUMP_FORMAT
+-# define av_dump_format dump_format
+-#endif
+-
+-#ifndef FFMPEG_HAVE_AV_GUESS_FORMAT
+-# define av_guess_format guess_format
+-#endif
+-
+-#ifndef FFMPEG_HAVE_PARSE_UTILS
+-# define av_parse_video_rate av_parse_video_frame_rate
+-#endif
+-
+-#ifdef FFMPEG_HAVE_DEFAULT_VAL_UNION
+-# define FFMPEG_DEF_OPT_VAL_INT(OPT) OPT->default_val.i64
+-# define FFMPEG_DEF_OPT_VAL_DOUBLE(OPT) OPT->default_val.dbl
+-#else
+-# define FFMPEG_DEF_OPT_VAL_INT(OPT) OPT->default_val
+-# define FFMPEG_DEF_OPT_VAL_DOUBLE(OPT) OPT->default_val
+-#endif
+-
+-#ifndef FFMPEG_HAVE_AVMEDIA_TYPES
+-# define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
+-# define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
+-#endif
+-
+-#ifndef FFMPEG_HAVE_DECODE_AUDIO3
+-FFMPEG_INLINE
+-int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
+- int *frame_size_ptr, AVPacket *avpkt)
+-{
+- return avcodec_decode_audio2(avctx, samples,
+- frame_size_ptr, avpkt->data,
+- avpkt->size);
+-}
+-#endif
+-
+-#ifndef FFMPEG_HAVE_DECODE_VIDEO2
+-FFMPEG_INLINE
+-int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
+- int *got_picture_ptr,
+- AVPacket *avpkt)
+-{
+- return avcodec_decode_video(avctx, picture, got_picture_ptr,
+- avpkt->data, avpkt->size);
+-}
+-#endif
++}*/
+
+ FFMPEG_INLINE
+ int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame * picture)
+ {
+ int64_t pts;
+-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 34, 100)
+ pts = picture->pts;
+-#else
+- pts = picture->pkt_pts;
+-#endif
+
+ if (pts == AV_NOPTS_VALUE) {
+ pts = picture->pkt_dts;
+@@ -368,101 +81,7 @@ int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame * picture)
+ return pts;
+ }
+
+-/* obsolete constant formerly defined in FFMpeg libavcodec/avcodec.h */
+-#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
+-# define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
+-#endif
+-
+-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 1, 0)
+-FFMPEG_INLINE
+-int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *pkt,
+- const AVFrame *frame, int *got_output)
+-{
+- int outsize, ret;
+-
+- ret = av_new_packet(pkt, avctx->width * avctx->height * 7 + 10000);
+- if (ret < 0)
+- return ret;
+-
+- outsize = avcodec_encode_video(avctx, pkt->data, pkt->size, frame);
+- if (outsize <= 0) {
+- *got_output = 0;
+- av_free_packet(pkt);
+- }
+- else {
+- *got_output = 1;
+- av_shrink_packet(pkt, outsize);
+- if (avctx->coded_frame) {
+- pkt->pts = avctx->coded_frame->pts;
+- if (avctx->coded_frame->key_frame)
+- pkt->flags |= AV_PKT_FLAG_KEY;
+- }
+- }
+-
+- return outsize >= 0 ? 0 : outsize;
+-}
+-
+-#endif
+-
+-#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 17, 0)
+-FFMPEG_INLINE
+-void avformat_close_input(AVFormatContext **ctx)
+-{
+- av_close_input_file(*ctx);
+- *ctx = NULL;
+-}
+-#endif
+-
+-#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0)
+-FFMPEG_INLINE
+-AVFrame *av_frame_alloc(void)
+-{
+- return avcodec_alloc_frame();
+-}
+-
+-FFMPEG_INLINE
+-void av_frame_free(AVFrame **frame)
+-{
+- av_freep(frame);
+-}
+-#endif
+-
+-FFMPEG_INLINE
+-AVRational av_get_r_frame_rate_compat(const AVStream *stream)
+-{
+-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
+- /* For until r_frame_rate was deprecated use it. */
+- return stream->r_frame_rate;
+-#else
+- return stream->avg_frame_rate;
+-#endif
+-}
+-
+-#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
+-# define AV_OPT_SEARCH_FAKE_OBJ 0
+-#endif
+-
+-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
+-# define FFMPEG_HAVE_DEPRECATED_FLAGS2
+-#endif
+-
+-/* Since FFmpeg-1.1 this constant have AV_ prefix. */
+-#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 3, 100)
+-# define AV_PIX_FMT_BGR32 PIX_FMT_BGR32
+-# define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
+-# define AV_PIX_FMT_BGRA PIX_FMT_BGRA
+-# define AV_PIX_FMT_ARGB PIX_FMT_ARGB
+-# define AV_PIX_FMT_RGBA PIX_FMT_RGBA
+-#endif
+-
+-/* New API from FFmpeg-2.0 which soon became recommended one. */
+-#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 38, 100)
+-# define av_frame_alloc avcodec_alloc_frame
+-# define av_frame_free avcodec_free_frame
+-# define av_frame_unref avcodec_get_frame_defaults
+-#endif
+-
+-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 102)
++/* --- Deinterlace code block begin --- */
+
+ /* NOTE: The code in this block are from FFmpeg 2.6.4, which is licensed by LGPL. */
+
+@@ -586,8 +205,9 @@ int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
+ uint8_t *src_m1, *src_0, *src_p1, *src_p2;
+ int y;
+ uint8_t *buf = (uint8_t *)av_malloc(width);
+- if (!buf)
++ if (!buf) {
+ return AVERROR(ENOMEM);
++ }
+
+ src_m1 = src1;
+ memcpy(buf,src_m1,width);
+@@ -607,14 +227,9 @@ int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
+ return 0;
+ }
+
+-#ifdef __GNUC__
+-# pragma GCC diagnostic push
+-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+-#endif
+-
+ FFMPEG_INLINE
+-int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
+- enum AVPixelFormat pix_fmt, int width, int height)
++int av_image_deinterlace(
++ AVFrame *dst, const AVFrame *src, enum AVPixelFormat pix_fmt, int width, int height)
+ {
+ int i, ret;
+
+@@ -624,10 +239,12 @@ int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
+ pix_fmt != AV_PIX_FMT_YUVJ422P &&
+ pix_fmt != AV_PIX_FMT_YUV444P &&
+ pix_fmt != AV_PIX_FMT_YUV411P &&
+- pix_fmt != AV_PIX_FMT_GRAY8)
++ pix_fmt != AV_PIX_FMT_GRAY8) {
+ return -1;
+- if ((width & 3) != 0 || (height & 3) != 0)
++ }
++ if ((width & 3) != 0 || (height & 3) != 0) {
+ return -1;
++ }
+
+ for(i=0;i<3;i++) {
+ if (i == 1) {
+@@ -655,8 +272,9 @@ int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
+ ret = deinterlace_bottom_field_inplace(dst->data[i],
+ dst->linesize[i],
+ width, height);
+- if (ret < 0)
++ if (ret < 0) {
+ return ret;
++ }
+ } else {
+ deinterlace_bottom_field(dst->data[i],dst->linesize[i],
+ src->data[i], src->linesize[i],
+@@ -666,10 +284,6 @@ int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
+ return 0;
+ }
+
+-#ifdef __GNUC__
+-# pragma GCC diagnostic pop
+-#endif
+-
+-#endif
++/* --- Deinterlace code block end --- */
+
+ #endif
+diff --git a/blender-2.79b/source/blender/blenkernel/BKE_writeffmpeg.h b/blender-2.79b/source/blender/blenkernel/BKE_writeffmpeg.h
+index a40c310..9a0d9ef 100644
+--- a/blender-2.79b/source/blender/blenkernel/BKE_writeffmpeg.h
++++ b/blender-2.79b/source/blender/blenkernel/BKE_writeffmpeg.h
+@@ -76,12 +76,8 @@ void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview,
+
+ void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset);
+ void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf);
+-void BKE_ffmpeg_codec_settings_verify(struct RenderData *rd);
+ bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd);
+
+-int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
+-void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);
+-
+ void *BKE_ffmpeg_context_create(void);
+ void BKE_ffmpeg_context_free(void *context_v);
+
+diff --git a/blender-2.79b/source/blender/blenkernel/intern/scene.c b/blender-2.79b/source/blender/blenkernel/intern/scene.c
+index 6fd53bb..bd428b2 100644
+--- a/blender-2.79b/source/blender/blenkernel/intern/scene.c
++++ b/blender-2.79b/source/blender/blenkernel/intern/scene.c
+@@ -325,10 +325,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
+ scen->r.qtcodecdata = MEM_dupallocN(sce->r.qtcodecdata);
+ scen->r.qtcodecdata->cdParms = MEM_dupallocN(scen->r.qtcodecdata->cdParms);
+ }
+-
+- if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */
+- scen->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
+- }
+
+ /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
+ * are done outside of blenkernel with ED_objects_single_users! */
+@@ -424,11 +420,6 @@ void BKE_scene_free(Scene *sce)
+ MEM_freeN(sce->r.qtcodecdata);
+ sce->r.qtcodecdata = NULL;
+ }
+- if (sce->r.ffcodecdata.properties) {
+- IDP_FreeProperty(sce->r.ffcodecdata.properties);
+- MEM_freeN(sce->r.ffcodecdata.properties);
+- sce->r.ffcodecdata.properties = NULL;
+- }
+
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ if (srl->prop != NULL) {
+diff --git a/blender-2.79b/source/blender/blenkernel/intern/writeffmpeg.c b/blender-2.79b/source/blender/blenkernel/intern/writeffmpeg.c
+index a19e414..a32278d 100644
+--- a/blender-2.79b/source/blender/blenkernel/intern/writeffmpeg.c
++++ b/blender-2.79b/source/blender/blenkernel/intern/writeffmpeg.c
+@@ -34,6 +34,9 @@
+
+ #include <libavformat/avformat.h>
+ #include <libavcodec/avcodec.h>
++#include <libavutil/channel_layout.h>
++#include <libavutil/imgutils.h>
++#include <libavutil/opt.h>
+ #include <libavutil/rational.h>
+ #include <libavutil/samplefmt.h>
+ #include <libswscale/swscale.h>
+@@ -50,6 +53,7 @@
+ #endif
+
+ #include "BLI_utildefines.h"
++#include "BLI_threads.h"
+
+ #include "BKE_global.h"
+ #include "BKE_idprop.h"
+@@ -78,18 +82,19 @@ typedef struct FFMpegContext {
+ int ffmpeg_preset; /* see FFMpegPreset */
+
+ AVFormatContext *outfile;
++ AVCodecContext *video_codec;
++ AVCodecContext *audio_codec;
+ AVStream *video_stream;
+ AVStream *audio_stream;
+- AVFrame *current_frame;
++ AVFrame *current_frame; /* Image frame in output pixel format. */
++
++ /* Image frame in Blender's own pixel format, may need conversion to the output pixel format. */
++ AVFrame *img_convert_frame;
+ struct SwsContext *img_convert_ctx;
+
+ uint8_t *audio_input_buffer;
+ uint8_t *audio_deinterleave_buffer;
+ int audio_input_samples;
+-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+- uint8_t *audio_output_buffer;
+- int audio_outbuf_size;
+-#endif
+ double audio_time;
+ bool audio_deinterleave;
+ int audio_sample_size;
+@@ -104,8 +109,6 @@ typedef struct FFMpegContext {
+ #define PRINT if (G.debug & G_DEBUG_FFMPEG) printf
+
+ static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
+-static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
+-static void ffmpeg_set_expert_options(RenderData *rd);
+ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
+
+ /* Delete a picture buffer */
+@@ -125,31 +128,20 @@ static int request_float_audio_buffer(int codec_id)
+ }
+
+ #ifdef WITH_AUDASPACE
++
+ static int write_audio_frame(FFMpegContext *context)
+ {
+- AVCodecContext *c = NULL;
+- AVPacket pkt;
+ AVFrame *frame = NULL;
+- int got_output = 0;
+-
+- c = context->audio_stream->codec;
+-
+- av_init_packet(&pkt);
+- pkt.size = 0;
+- pkt.data = NULL;
++ AVCodecContext *c = context->audio_codec;
+
+ AUD_Device_read(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
+ context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
+
+-#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
+ frame = av_frame_alloc();
+- av_frame_unref(frame);
+ frame->pts = context->audio_time / av_q2d(c->time_base);
+ frame->nb_samples = context->audio_input_samples;
+ frame->format = c->sample_fmt;
+-#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
+ frame->channel_layout = c->channel_layout;
+-#endif
+
+ if (context->audio_deinterleave) {
+ int channel, i;
+@@ -170,53 +162,49 @@ static int write_audio_frame(FFMpegContext *context)
+ avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer,
+ context->audio_input_samples * c->channels * context->audio_sample_size, 1);
+
+- if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
+- // XXX error("Error writing audio packet");
+- return -1;
+- }
++ int success = 0;
+
+- if (!got_output) {
+- av_frame_free(&frame);
+- return 0;
++ int ret = avcodec_send_frame(c, frame);
++ if (ret < 0) {
++ /* Can't send frame to encoder. This shouldn't happen. */
++ fprintf(stderr, "Can't send audio frame: %s\n", av_err2str(ret));
++ success = -1;
+ }
+-#else
+- pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer);
+
+- if (pkt.size < 0) {
+- // XXX error("Error writing audio packet");
+- return -1;
+- }
++ AVPacket *pkt = av_packet_alloc();
+
+- pkt.data = context->audio_output_buffer;
+- got_output = 1;
+-#endif
++ while (ret >= 0) {
+
+- if (got_output) {
+- if (pkt.pts != AV_NOPTS_VALUE)
+- pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
+- if (pkt.dts != AV_NOPTS_VALUE)
+- pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
+- if (pkt.duration > 0)
+- pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
++ ret = avcodec_receive_packet(c, pkt);
++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
++ break;
++ }
++ if (ret < 0) {
++ fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
++ success = -1;
++ }
+
+- pkt.stream_index = context->audio_stream->index;
++ av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base);
++ if (pkt->duration > 0) {
++ pkt->duration = av_rescale_q(pkt->duration, c->time_base, context->audio_stream->time_base);
++ }
+
+- pkt.flags |= AV_PKT_FLAG_KEY;
++ pkt->stream_index = context->audio_stream->index;
+
+- if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
+- fprintf(stderr, "Error writing audio packet!\n");
+- if (frame)
+- av_frame_free(&frame);
+- return -1;
+- }
++ pkt->flags |= AV_PKT_FLAG_KEY;
+
+- av_free_packet(&pkt);
++ int write_ret = av_interleaved_write_frame(context->outfile, pkt);
++ if (write_ret != 0) {
++ fprintf(stderr, "Error writing audio packet: %s\n", av_err2str(write_ret));
++ success = -1;
++ break;
++ }
+ }
+
+- if (frame)
+- av_frame_free(&frame);
++ av_packet_free(&pkt);
++ av_frame_free(&frame);
+
+- return 0;
++ return success;
+ }
+ #endif // #ifdef WITH_AUDASPACE
+
+@@ -229,15 +217,22 @@ static AVFrame *alloc_picture(int pix_fmt, int width, int height)
+
+ /* allocate space for the struct */
+ f = av_frame_alloc();
+- if (!f) return NULL;
+- size = avpicture_get_size(pix_fmt, width, height);
++ if (!f) {
++ return NULL;
++ }
++ size = av_image_get_buffer_size(pix_fmt, width, height, 1);
+ /* allocate the actual picture buffer */
+ buf = MEM_mallocN(size, "AVFrame buffer");
+ if (!buf) {
+ free(f);
+ return NULL;
+ }
+- avpicture_fill((AVPicture *)f, buf, pix_fmt, width, height);
++
++ av_image_fill_arrays(f->data, f->linesize, buf, pix_fmt, width, height, 1);
++ f->format = pix_fmt;
++ f->width = width;
++ f->height = height;
++
+ return f;
+ }
+
+@@ -310,225 +305,114 @@ static const char **get_file_extensions(int format)
+ }
+
+ /* Write a frame to the output file */
+-static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
++static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, ReportList *reports)
+ {
+- int got_output;
+ int ret, success = 1;
+- AVCodecContext *c = context->video_stream->codec;
+- AVPacket packet = { 0 };
++ AVPacket *packet = av_packet_alloc();
+
+- av_init_packet(&packet);
++ AVCodecContext *c = context->video_codec;
+
+ frame->pts = cfra;
+
+- if (rd->mode & R_FIELDS) {
+- frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0);
++ ret = avcodec_send_frame(c, frame);
++ if (ret < 0) {
++ /* Can't send frame to encoder. This shouldn't happen. */
++ fprintf(stderr, "Can't send video frame: %s\n", av_err2str(ret));
++ success = -1;
+ }
+
+- ret = avcodec_encode_video2(c, &packet, frame, &got_output);
++ while (ret >= 0) {
++ ret = avcodec_receive_packet(c, packet);
+
+- if (ret >= 0 && got_output) {
+- if (packet.pts != AV_NOPTS_VALUE) {
+- packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
+- PRINT("Video Frame PTS: %d\n", (int)packet.pts);
+- }
+- else {
+- PRINT("Video Frame PTS: not set\n");
+- }
+- if (packet.dts != AV_NOPTS_VALUE) {
+- packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
+- PRINT("Video Frame DTS: %d\n", (int)packet.dts);
++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
++ /* No more packets available. */
++ break;
+ }
+- else {
+- PRINT("Video Frame DTS: not set\n");
++ if (ret < 0) {
++ fprintf(stderr, "Error encoding frame: %s\n", av_err2str(ret));
++ break;
+ }
+
+- packet.stream_index = context->video_stream->index;
+- ret = av_interleaved_write_frame(context->outfile, &packet);
+- success = (ret == 0);
++ packet->stream_index = context->video_stream->index;
++ av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base);
++ if (av_interleaved_write_frame(context->outfile, packet) != 0) {
++ success = -1;
++ break;
++ }
+ }
+- else if (ret < 0) {
+- success = 0;
++
++ if (!success) {
++ PRINT("Error writing frame: %s\n", av_err2str(ret));
+ }
+
+- if (!success)
+- BKE_report(reports, RPT_ERROR, "Error writing frame");
++ av_packet_free(&packet);
+
+ return success;
+ }
+
+ /* read and encode a frame of audio from the buffer */
+-static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports)
++static AVFrame *generate_video_frame(FFMpegContext *context, const uint8_t *pixels)
+ {
+- uint8_t *rendered_frame;
+-
+- AVCodecContext *c = context->video_stream->codec;
+- int width = c->width;
+- int height = c->height;
++ AVCodecParameters *codec = context->video_stream->codecpar;
++ int height = codec->height;
+ AVFrame *rgb_frame;
+
+- if (c->pix_fmt != AV_PIX_FMT_BGR32) {
+- rgb_frame = alloc_picture(AV_PIX_FMT_BGR32, width, height);
+- if (!rgb_frame) {
+- BKE_report(reports, RPT_ERROR, "Could not allocate temporary frame");
+- return NULL;
+- }
++ if (context->img_convert_frame != NULL) {
++ /* Pixel format conversion is needed. */
++ rgb_frame = context->img_convert_frame;
+ }
+ else {
++ /* The output pixel format is Blender's internal pixel format. */
+ rgb_frame = context->current_frame;
+ }
+
+- rendered_frame = pixels;
++ /* Copy the Blender pixels into the FFmpeg datastructure, taking care of endianness and flipping
++ * the image vertically. */
++ int linesize = rgb_frame->linesize[0];
++ for (int y = 0; y < height; y++) {
++ uint8_t *target = rgb_frame->data[0] + linesize * (height - y - 1);
++ const uint8_t *src = pixels + linesize * y;
+
+- /* Do RGBA-conversion and flipping in one step depending
+- * on CPU-Endianess */
++# if ENDIAN_ORDER == L_ENDIAN
++ memcpy(target, src, linesize);
+
+- if (ENDIAN_ORDER == L_ENDIAN) {
+- int y;
+- for (y = 0; y < height; y++) {
+- uint8_t *target = rgb_frame->data[0] + width * 4 * (height - y - 1);
+- uint8_t *src = rendered_frame + width * 4 * y;
+- uint8_t *end = src + width * 4;
+- while (src != end) {
+- target[3] = src[3];
+- target[2] = src[2];
+- target[1] = src[1];
+- target[0] = src[0];
++# elif ENDIAN_ORDER == B_ENDIAN
++ const uint8_t *end = src + linesize;
++ while (src != end) {
++ target[3] = src[0];
++ target[2] = src[1];
++ target[1] = src[2];
++ target[0] = src[3];
+
+- target += 4;
+- src += 4;
+- }
+- }
+- }
+- else {
+- int y;
+- for (y = 0; y < height; y++) {
+- uint8_t *target = rgb_frame->data[0] + width * 4 * (height - y - 1);
+- uint8_t *src = rendered_frame + width * 4 * y;
+- uint8_t *end = src + width * 4;
+- while (src != end) {
+- target[3] = src[0];
+- target[2] = src[1];
+- target[1] = src[2];
+- target[0] = src[3];
+-
+- target += 4;
+- src += 4;
+- }
++ target += 4;
++ src += 4;
+ }
++# else
++# error ENDIAN_ORDER should either be L_ENDIAN or B_ENDIAN.
++# endif
+ }
+
+- if (c->pix_fmt != AV_PIX_FMT_BGR32) {
+- sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
+- rgb_frame->linesize, 0, c->height,
+- context->current_frame->data, context->current_frame->linesize);
+- delete_picture(rgb_frame);
++ /* Convert to the output pixel format, if it's different that Blender's internal one. */
++ if (context->img_convert_frame != NULL) {
++ BLI_assert(context->img_convert_ctx != NULL);
++ sws_scale(context->img_convert_ctx,
++ (const uint8_t *const *)rgb_frame->data,
++ rgb_frame->linesize,
++ 0,
++ codec->height,
++ context->current_frame->data,
++ context->current_frame->linesize);
+ }
+
+- context->current_frame->format = AV_PIX_FMT_BGR32;
+- context->current_frame->width = width;
+- context->current_frame->height = height;
+-
+ return context->current_frame;
+ }
+
+-static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
+-{
+- char name[128];
+- char *param;
+-
+- PRINT("FFMPEG expert option: %s: ", prop->name);
+-
+- BLI_strncpy(name, prop->name, sizeof(name));
+-
+- param = strchr(name, ':');
+-
+- if (param) {
+- *param++ = '\0';
+- }
+-
+- switch (prop->type) {
+- case IDP_STRING:
+- PRINT("%s.\n", IDP_String(prop));
+- av_dict_set(dictionary, name, IDP_String(prop), 0);
+- break;
+- case IDP_FLOAT:
+- PRINT("%g.\n", IDP_Float(prop));
+- ffmpeg_dict_set_float(dictionary, prop->name, IDP_Float(prop));
+- break;
+- case IDP_INT:
+- PRINT("%d.\n", IDP_Int(prop));
+-
+- if (param) {
+- if (IDP_Int(prop)) {
+- av_dict_set(dictionary, name, param, 0);
+- }
+- else {
+- return;
+- }
+- }
+- else {
+- ffmpeg_dict_set_int(dictionary, prop->name, IDP_Int(prop));
+- }
+- break;
+- }
+-}
+-
+-static int ffmpeg_proprty_valid(AVCodecContext *c, const char *prop_name, IDProperty *curr)
+-{
+- int valid = 1;
+-
+- if (STREQ(prop_name, "video")) {
+- if (STREQ(curr->name, "bf")) {
+- /* flash codec doesn't support b frames */
+- valid &= c->codec_id != AV_CODEC_ID_FLV1;
+- }
+- }
+-
+- return valid;
+-}
+-
+-static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char *prop_name,
+- AVDictionary **dictionary)
+-{
+- IDProperty *prop;
+- IDProperty *curr;
+-
+- /* TODO(sergey): This is actually rather stupid, because changing
+- * codec settings in render panel would also set expert options.
+- *
+- * But we need ti here in order to get rid of deprecated settings
+- * when opening old files in new blender.
+- *
+- * For as long we don't allow editing properties in the interface
+- * it's all good. bug if we allow editing them, we'll need to
+- * replace it with some smarter code which would port settings
+- * from deprecated to new one.
+- */
+- ffmpeg_set_expert_options(rd);
+-
+- if (!rd->ffcodecdata.properties) {
+- return;
+- }
+-
+- prop = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, prop_name);
+- if (!prop) {
+- return;
+- }
+-
+- for (curr = prop->data.group.first; curr; curr = curr->next) {
+- if (ffmpeg_proprty_valid(c, prop_name, curr))
+- set_ffmpeg_property_option(c, curr, dictionary);
+- }
+-}
+-
+ /* prepare a video stream for the output file */
+
+ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of,
+ int rectx, int recty, char *error, int error_size)
+ {
+ AVStream *st;
+- AVCodecContext *c;
+ AVCodec *codec;
+ AVDictionary *opts = NULL;
+
+@@ -539,13 +423,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
+ st->id = 0;
+
+ /* Set up the codec context */
+-
+- c = st->codec;
++
++ context->video_codec = avcodec_alloc_context3(NULL);
++ AVCodecContext *c = context->video_codec;
+ c->codec_id = codec_id;
+ c->codec_type = AVMEDIA_TYPE_VIDEO;
+
+ /* Get some values from the current render settings */
+-
++
+ c->width = rectx;
+ c->height = recty;
+
+@@ -605,12 +490,12 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
+ c->rc_buffer_aggressivity = 1.0;
+ #endif
+
+- c->me_method = ME_EPZS;
+-
+ codec = avcodec_find_encoder(c->codec_id);
+- if (!codec)
++ if (!codec) {
++ avcodec_free_context(&c);
+ return NULL;
+-
++ }
++
+ /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
+
+ if (codec->pix_fmts) {
+@@ -643,6 +528,13 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
+ }
+ }
+
++ if (codec_id == AV_CODEC_ID_DNXHD) {
++ if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT) {
++ /* Set the block decision algorithm to be of the highest quality ("rd" == 2). */
++ c->mb_decision = 2;
++ }
++ }
++
+ if (codec_id == AV_CODEC_ID_FFV1) {
+ c->pix_fmt = AV_PIX_FMT_RGB32;
+ }
+@@ -668,14 +560,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
+ )
+ {
+ PRINT("Using global header\n");
+- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
++ c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+ /* Determine whether we are encoding interlaced material or not */
+ if (rd->mode & R_FIELDS) {
+ PRINT("Encoding interlaced video\n");
+- c->flags |= CODEC_FLAG_INTERLACED_DCT;
+- c->flags |= CODEC_FLAG_INTERLACED_ME;
++ c->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
++ c->flags |= AV_CODEC_FLAG_INTERLACED_ME;
+ }
+
+ /* xasp & yasp got float lately... */
+@@ -683,28 +575,46 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
+ st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
+ st->avg_frame_rate = av_inv_q(c->time_base);
+
+- set_ffmpeg_properties(rd, c, "video", &opts);
+-
+ if (avcodec_open2(c, codec, &opts) < 0) {
+ BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
+ av_dict_free(&opts);
++ avcodec_free_context(&c);
+ return NULL;
+ }
+ av_dict_free(&opts);
+
++ /* FFmpeg expects its data in the output pixel format. */
+ context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
+
+- context->img_convert_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
+- NULL, NULL, NULL);
++ if (c->pix_fmt == AV_PIX_FMT_RGBA) {
++ /* Output pixel format is the same we use internally, no conversion necessary. */
++ context->img_convert_frame = NULL;
++ context->img_convert_ctx = NULL;
++ }
++ else {
++ /* Output pixel format is different, allocate frame for conversion. */
++ context->img_convert_frame = alloc_picture(AV_PIX_FMT_RGBA, c->width, c->height);
++ context->img_convert_ctx = sws_getContext(c->width,
++ c->height,
++ AV_PIX_FMT_RGBA,
++ c->width,
++ c->height,
++ c->pix_fmt,
++ SWS_BICUBIC,
++ NULL,
++ NULL,
++ NULL);
++ }
++
++ avcodec_parameters_from_context(st->codecpar, c);
++
+ return st;
+ }
+
+ static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
+ {
+ AVStream *st;
+- AVCodecContext *c;
+- AVCodec *codec;
+- AVDictionary *opts = NULL;
++ const AVCodec *codec;
+
+ error[0] = '\0';
+
+@@ -712,27 +622,47 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int
+ if (!st) return NULL;
+ st->id = 1;
+
+- c = st->codec;
+- c->codec_id = codec_id;
+- c->codec_type = AVMEDIA_TYPE_AUDIO;
++ codec = avcodec_find_encoder(codec_id);
++ if (!codec) {
++ fprintf(stderr, "Couldn't find valid audio codec\n");
++ context->audio_codec = NULL;
++ return NULL;
++ }
++
++ context->audio_codec = avcodec_alloc_context3(codec);
++ AVCodecContext *c = context->audio_codec;
++ c->thread_count = BLI_system_thread_count();
++ c->thread_type = FF_THREAD_SLICE;
+
+ c->sample_rate = rd->ffcodecdata.audio_mixrate;
+ c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
+ c->sample_fmt = AV_SAMPLE_FMT_S16;
+ c->channels = rd->ffcodecdata.audio_channels;
+
++ switch (rd->ffcodecdata.audio_channels) {
++ case AUD_CHANNELS_MONO:
++ c->channel_layout = AV_CH_LAYOUT_MONO;
++ break;
++ case AUD_CHANNELS_STEREO:
++ c->channel_layout = AV_CH_LAYOUT_STEREO;
++ break;
++ case AUD_CHANNELS_SURROUND4:
++ c->channel_layout = AV_CH_LAYOUT_QUAD;
++ break;
++ case AUD_CHANNELS_SURROUND51:
++ c->channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
++ break;
++ case AUD_CHANNELS_SURROUND71:
++ c->channel_layout = AV_CH_LAYOUT_7POINT1;
++ break;
++ }
++
+ if (request_float_audio_buffer(codec_id)) {
+ /* mainly for AAC codec which is experimental */
+ c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+ c->sample_fmt = AV_SAMPLE_FMT_FLT;
+ }
+
+- codec = avcodec_find_encoder(c->codec_id);
+- if (!codec) {
+- //XXX error("Couldn't find a valid audio codec");
+- return NULL;
+- }
+-
+ if (codec->sample_fmts) {
+ /* check if the preferred sample format for this codec is supported.
+ * this is because, depending on the version of libav, and with the whole ffmpeg/libav fork situation,
+@@ -740,12 +670,13 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int
+ */
+ const enum AVSampleFormat *p = codec->sample_fmts;
+ for (; *p != -1; p++) {
+- if (*p == st->codec->sample_fmt)
++ if (*p == c->sample_fmt) {
+ break;
++ }
+ }
+ if (*p == -1) {
+ /* sample format incompatible with codec. Defaulting to a format known to work */
+- st->codec->sample_fmt = codec->sample_fmts[0];
++ c->sample_fmt = codec->sample_fmts[0];
+ }
+ }
+
+@@ -754,50 +685,40 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int
+ int best = 0;
+ int best_dist = INT_MAX;
+ for (; *p; p++) {
+- int dist = abs(st->codec->sample_rate - *p);
++ int dist = abs(c->sample_rate - *p);
+ if (dist < best_dist) {
+ best_dist = dist;
+ best = *p;
+ }
+ }
+ /* best is the closest supported sample rate (same as selected if best_dist == 0) */
+- st->codec->sample_rate = best;
++ c->sample_rate = best;
+ }
+
+ if (of->oformat->flags & AVFMT_GLOBALHEADER) {
+- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
++ c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+- set_ffmpeg_properties(rd, c, "audio", &opts);
+-
+- if (avcodec_open2(c, codec, &opts) < 0) {
++ if (avcodec_open2(c, codec, NULL) < 0) {
+ //XXX error("Couldn't initialize audio codec");
+ BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
+- av_dict_free(&opts);
++ avcodec_free_context(&c);
++ context->audio_codec = NULL;
+ return NULL;
+ }
+- av_dict_free(&opts);
+
+ /* need to prevent floating point exception when using vorbis audio codec,
+ * initialize this value in the same way as it's done in FFmpeg itself (sergey) */
+- st->codec->time_base.num = 1;
+- st->codec->time_base.den = st->codec->sample_rate;
+-
+-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+- context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
+-#endif
++ c->time_base.num = 1;
++ c->time_base.den = c->sample_rate;
+
+ if (c->frame_size == 0)
+ // used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
+ // not sure if that is needed anymore, so let's try out if there are any
+ // complaints regarding some ffmpeg versions users might have
+- context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
++ context->audio_input_samples = AV_INPUT_BUFFER_MIN_SIZE * 8 / c->bits_per_coded_sample / c->channels;
+ else {
+ context->audio_input_samples = c->frame_size;
+-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+- if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
+- context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
+-#endif
+ }
+
+ context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
+@@ -805,15 +726,14 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int
+ context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
+
+ context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
+-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+- context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size);
+-#endif
+
+ if (context->audio_deinterleave)
+ context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
+
+ context->audio_time = 0.0f;
+
++ avcodec_parameters_from_context(st->codecpar, c);
++
+ return st;
+ }
+ /* essential functions -- start, append, end */
+@@ -827,21 +747,11 @@ static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value)
+ av_dict_set(dict, key, buffer, 0);
+ }
+
+-static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value)
+-{
+- char buffer[32];
+-
+- BLI_snprintf(buffer, sizeof(buffer), "%.8f", value);
+-
+- av_dict_set(dict, key, buffer, 0);
+-}
+-
+ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
+ {
+ /* Handle to the output file */
+ AVFormatContext *of;
+- AVOutputFormat *fmt;
+- AVDictionary *opts = NULL;
++ const AVOutputFormat *fmt;
+ char name[FILE_MAX], error[1024];
+ const char **exts;
+
+@@ -869,12 +779,14 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
+ name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec,
+ context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate,
+ context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty);
+-
++
++ /* Sanity checks for the output file extensions. */
+ exts = get_file_extensions(context->ffmpeg_type);
+ if (!exts) {
+ BKE_report(reports, RPT_ERROR, "No valid formats found");
+ return 0;
+ }
++
+ fmt = av_guess_format(NULL, exts[0], NULL);
+ if (!fmt) {
+ BKE_report(reports, RPT_ERROR, "No valid formats found");
+@@ -883,67 +795,50 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
+
+ of = avformat_alloc_context();
+ if (!of) {
+- BKE_report(reports, RPT_ERROR, "Error opening output file");
++ BKE_report(reports, RPT_ERROR, "Can't allocate ffmpeg format context");
+ return 0;
+ }
+
++ enum AVCodecID audio_codec = context->ffmpeg_audio_codec;
++ enum AVCodecID video_codec = context->ffmpeg_codec;
+
+- /* Returns after this must 'goto fail;' */
+-
+- of->oformat = fmt;
+-
+- /* Only bother with setting packet size & mux rate when CRF is not used. */
+- if (context->ffmpeg_crf == 0) {
+- of->packet_size = rd->ffcodecdata.mux_packet_size;
+- if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+- ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
+- }
+- else {
+- av_dict_set(&opts, "muxrate", "0", 0);
+- }
+- }
+-
+- ffmpeg_dict_set_int(&opts, "preload", (int)(0.5 * AV_TIME_BASE));
+-
+- of->max_delay = (int)(0.7 * AV_TIME_BASE);
+-
+- fmt->audio_codec = context->ffmpeg_audio_codec;
+-
+- BLI_strncpy(of->filename, name, sizeof(of->filename));
+- /* set the codec to the user's selection */
++ of->url = av_strdup(name);
++ /* Check if we need to force change the codec because of file type codec restrictions */
+ switch (context->ffmpeg_type) {
+- case FFMPEG_AVI:
+- case FFMPEG_MOV:
+- case FFMPEG_MKV:
+- fmt->video_codec = context->ffmpeg_codec;
+- break;
+ case FFMPEG_OGG:
+- fmt->video_codec = AV_CODEC_ID_THEORA;
++ video_codec = AV_CODEC_ID_THEORA;
+ break;
+ case FFMPEG_DV:
+- fmt->video_codec = AV_CODEC_ID_DVVIDEO;
++ video_codec = AV_CODEC_ID_DVVIDEO;
+ break;
+ case FFMPEG_MPEG1:
+- fmt->video_codec = AV_CODEC_ID_MPEG1VIDEO;
++ video_codec = AV_CODEC_ID_MPEG1VIDEO;
+ break;
+ case FFMPEG_MPEG2:
+- fmt->video_codec = AV_CODEC_ID_MPEG2VIDEO;
++ video_codec = AV_CODEC_ID_MPEG2VIDEO;
+ break;
+ case FFMPEG_H264:
+- fmt->video_codec = AV_CODEC_ID_H264;
++ video_codec = AV_CODEC_ID_H264;
+ break;
+ case FFMPEG_XVID:
+- fmt->video_codec = AV_CODEC_ID_MPEG4;
++ video_codec = AV_CODEC_ID_MPEG4;
+ break;
+ case FFMPEG_FLV:
+- fmt->video_codec = AV_CODEC_ID_FLV1;
++ video_codec = AV_CODEC_ID_FLV1;
+ break;
+- case FFMPEG_MPEG4:
+ default:
+- fmt->video_codec = context->ffmpeg_codec;
++ /* These containers are not restricted to any specific codec types.
++ * Currently we expect these to be .avi, .mov, .mkv, and .mp4.
++ */
++ video_codec = context->ffmpeg_codec;
+ break;
+ }
+- if (fmt->video_codec == AV_CODEC_ID_DVVIDEO) {
++
++ /* Returns after this must 'goto fail;' */
++
++ of->oformat = fmt;
++
++ if (video_codec == AV_CODEC_ID_DVVIDEO) {
+ if (rectx != 720) {
+ BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!");
+ goto fail;
+@@ -957,51 +852,62 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
+ goto fail;
+ }
+ }
+-
++
+ if (context->ffmpeg_type == FFMPEG_DV) {
+- fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
++ audio_codec = AV_CODEC_ID_PCM_S16LE;
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
+ BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
+ goto fail;
+ }
+ }
+
+- if (fmt->video_codec != AV_CODEC_ID_NONE) {
+- context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
++ if (video_codec != AV_CODEC_ID_NONE) {
++ context->video_stream = alloc_video_stream(context, rd, video_codec, of, rectx, recty, error, sizeof(error));
+ PRINT("alloc video stream %p\n", context->video_stream);
+ if (!context->video_stream) {
+- if (error[0])
++ if (error[0]) {
+ BKE_report(reports, RPT_ERROR, error);
+- else
++ PRINT("Video stream error: %s\n", error);
++ }
++ else {
+ BKE_report(reports, RPT_ERROR, "Error initializing video stream");
++ PRINT("Error initializing video stream");
++ }
+ goto fail;
+ }
+ }
+
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+- context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error));
++ context->audio_stream = alloc_audio_stream(context, rd, audio_codec, of, error, sizeof(error));
+ if (!context->audio_stream) {
+- if (error[0])
++ if (error[0]) {
+ BKE_report(reports, RPT_ERROR, error);
+- else
++ PRINT("Audio stream error: %s\n", error);
++ }
++ else {
+ BKE_report(reports, RPT_ERROR, "Error initializing audio stream");
++ PRINT("Error initializing audio stream");
++ }
+ goto fail;
+ }
+ }
+ if (!(fmt->flags & AVFMT_NOFILE)) {
+ if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
+ BKE_report(reports, RPT_ERROR, "Could not open file for writing");
++ PRINT("Could not open file for writing\n");
+ goto fail;
+ }
+ }
+- if (avformat_write_header(of, NULL) < 0) {
++
++ int ret = avformat_write_header(of, NULL);
++ if (ret < 0) {
+ BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination");
++ PRINT("Could not write media header: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ context->outfile = of;
+ av_dump_format(of, 0, name, 1);
+- av_dict_free(&opts);
+
+ return 1;
+
+@@ -1011,17 +917,14 @@ fail:
+ avio_close(of->pb);
+ }
+
+- if (context->video_stream && context->video_stream->codec) {
+- avcodec_close(context->video_stream->codec);
++ if (context->video_stream) {
+ context->video_stream = NULL;
+ }
+
+- if (context->audio_stream && context->audio_stream->codec) {
+- avcodec_close(context->audio_stream->codec);
++ if (context->audio_stream) {
+ context->audio_stream = NULL;
+ }
+
+- av_dict_free(&opts);
+ avformat_free_context(of);
+ return 0;
+ }
+@@ -1045,46 +948,35 @@ fail:
+ */
+ static void flush_ffmpeg(FFMpegContext *context)
+ {
+- int ret = 0;
+-
+- AVCodecContext *c = context->video_stream->codec;
+- /* get the delayed frames */
+- while (1) {
+- int got_output;
+- AVPacket packet = { 0 };
+- av_init_packet(&packet);
+-
+- ret = avcodec_encode_video2(c, &packet, NULL, &got_output);
+- if (ret < 0) {
+- fprintf(stderr, "Error encoding delayed frame %d\n", ret);
++ AVCodecContext *c = context->video_codec;
++ AVPacket *packet = av_packet_alloc();
++
++ avcodec_send_frame(c, NULL);
++ /* Get the packets frames. */
++ int ret = 1;
++ while (ret >= 0) {
++ ret = avcodec_receive_packet(c, packet);
++
++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
++ /* No more packets to flush. */
+ break;
+ }
+- if (!got_output) {
++ if (ret < 0) {
++ fprintf(stderr, "Error encoding delayed frame: %s\n", av_err2str(ret));
+ break;
+ }
+- if (packet.pts != AV_NOPTS_VALUE) {
+- packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
+- PRINT("Video Frame PTS: %d\n", (int) packet.pts);
+- }
+- else {
+- PRINT("Video Frame PTS: not set\n");
+- }
+- if (packet.dts != AV_NOPTS_VALUE) {
+- packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
+- PRINT("Video Frame DTS: %d\n", (int) packet.dts);
+- }
+- else {
+- PRINT("Video Frame DTS: not set\n");
+- }
+
+- packet.stream_index = context->video_stream->index;
+- ret = av_interleaved_write_frame(context->outfile, &packet);
+- if (ret != 0) {
+- fprintf(stderr, "Error writing delayed frame %d\n", ret);
++ packet->stream_index = context->video_stream->index;
++ av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base);
++
++ int write_ret = av_interleaved_write_frame(context->outfile, packet);
++ if (write_ret != 0) {
++ fprintf(stderr, "Error writing delayed frame: %s\n", av_err2str(write_ret));
+ break;
+ }
+ }
+- avcodec_flush_buffers(context->video_stream->codec);
++
++ av_packet_free(&packet);
+ }
+
+ /* **********************************************************************
+@@ -1172,7 +1064,8 @@ int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int r
+ success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
+ #ifdef WITH_AUDASPACE
+ if (context->audio_stream) {
+- AVCodecContext *c = context->audio_stream->codec;
++ AVCodecContext *c = context->audio_codec;
++
+ AUD_DeviceSpecs specs;
+ specs.channels = c->channels;
+
+@@ -1198,10 +1091,6 @@ int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int r
+
+ specs.rate = rd->ffcodecdata.audio_mixrate;
+ context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
+-#ifdef FFMPEG_CODEC_TIME_BASE
+- c->time_base.den = specs.rate;
+- c->time_base.num = 1;
+-#endif
+ }
+ #endif
+ return success;
+@@ -1237,8 +1126,8 @@ int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int fram
+ // write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
+
+ if (context->video_stream) {
+- avframe = generate_video_frame(context, (unsigned char *) pixels, reports);
+- success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
++ avframe = generate_video_frame(context, (unsigned char *)pixels);
++ success = (avframe && write_video_frame(context, frame - start_frame, avframe, reports));
+
+ if (context->ffmpeg_autosplit) {
+ if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+@@ -1274,7 +1163,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
+ }
+ #endif
+
+- if (context->video_stream && context->video_stream->codec) {
++ if (context->video_stream) {
+ PRINT("Flushing delayed frames...\n");
+ flush_ffmpeg(context);
+ }
+@@ -1285,14 +1174,12 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
+
+ /* Close the video codec */
+
+- if (context->video_stream != NULL && context->video_stream->codec != NULL) {
+- avcodec_close(context->video_stream->codec);
++ if (context->video_stream != NULL) {
+ PRINT("zero video stream %p\n", context->video_stream);
+ context->video_stream = NULL;
+ }
+
+- if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
+- avcodec_close(context->audio_stream->codec);
++ if (context->audio_stream != NULL) {
+ context->audio_stream = NULL;
+ }
+
+@@ -1306,20 +1193,30 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
+ avio_close(context->outfile->pb);
+ }
+ }
++
++ if (context->video_codec != NULL) {
++ avcodec_free_context(&context->video_codec);
++ context->video_codec = NULL;
++ }
++ if (context->audio_codec != NULL) {
++ avcodec_free_context(&context->audio_codec);
++ context->audio_codec = NULL;
++ }
++
++ if (context->img_convert_frame != NULL) {
++ delete_picture(context->img_convert_frame);
++ context->img_convert_frame = NULL;
++ }
++
+ if (context->outfile != NULL) {
+ avformat_free_context(context->outfile);
+ context->outfile = NULL;
+ }
++
+ if (context->audio_input_buffer != NULL) {
+ av_free(context->audio_input_buffer);
+ context->audio_input_buffer = NULL;
+ }
+-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+- if (context->audio_output_buffer != NULL) {
+- av_free(context->audio_output_buffer);
+- context->audio_output_buffer = NULL;
+- }
+-#endif
+
+ if (context->audio_deinterleave_buffer != NULL) {
+ av_free(context->audio_deinterleave_buffer);
+@@ -1338,235 +1235,17 @@ void BKE_ffmpeg_end(void *context_v)
+ end_ffmpeg_impl(context, false);
+ }
+
+-/* properties */
+-
+-void BKE_ffmpeg_property_del(RenderData *rd, void *type, void *prop_)
+-{
+- struct IDProperty *prop = (struct IDProperty *) prop_;
+- IDProperty *group;
+-
+- if (!rd->ffcodecdata.properties) {
+- return;
+- }
+-
+- group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
+- if (group && prop) {
+- IDP_FreeFromGroup(group, prop);
+- }
+-}
+-
+-static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, const AVOption *o, const AVOption *parent)
+-{
+- AVCodecContext c;
+- IDProperty *group;
+- IDProperty *prop;
+- IDPropertyTemplate val;
+- int idp_type;
+- char name[256];
+-
+- val.i = 0;
+-
+- avcodec_get_context_defaults3(&c, NULL);
+-
+- if (!rd->ffcodecdata.properties) {
+- rd->ffcodecdata.properties = IDP_New(IDP_GROUP, &val, "ffmpeg");
+- }
+-
+- group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
+-
+- if (!group) {
+- group = IDP_New(IDP_GROUP, &val, type);
+- IDP_AddToGroup(rd->ffcodecdata.properties, group);
+- }
+-
+- if (parent) {
+- BLI_snprintf(name, sizeof(name), "%s:%s", parent->name, o->name);
+- }
+- else {
+- BLI_strncpy(name, o->name, sizeof(name));
+- }
+-
+- PRINT("ffmpeg_property_add: %s %s\n", type, name);
+-
+- prop = IDP_GetPropertyFromGroup(group, name);
+- if (prop) {
+- return prop;
+- }
+-
+- switch (o->type) {
+- case AV_OPT_TYPE_INT:
+- case AV_OPT_TYPE_INT64:
+- val.i = FFMPEG_DEF_OPT_VAL_INT(o);
+- idp_type = IDP_INT;
+- break;
+- case AV_OPT_TYPE_DOUBLE:
+- case AV_OPT_TYPE_FLOAT:
+- val.f = FFMPEG_DEF_OPT_VAL_DOUBLE(o);
+- idp_type = IDP_FLOAT;
+- break;
+- case AV_OPT_TYPE_STRING:
+- val.string.str = (char *)" ";
+- val.string.len = 80;
+-/* val.str = (char *)" ";*/
+- idp_type = IDP_STRING;
+- break;
+- case AV_OPT_TYPE_CONST:
+- val.i = 1;
+- idp_type = IDP_INT;
+- break;
+- default:
+- return NULL;
+- }
+- prop = IDP_New(idp_type, &val, name);
+- IDP_AddToGroup(group, prop);
+- return prop;
+-}
+-
+-/* not all versions of ffmpeg include that, so here we go ... */
+-
+-int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str)
+-{
+- AVCodecContext c;
+- const AVOption *o = NULL;
+- const AVOption *p = NULL;
+- char name_[128];
+- char *name;
+- char *param;
+- IDProperty *prop = NULL;
+-
+- avcodec_get_context_defaults3(&c, NULL);
+-
+- BLI_strncpy(name_, str, sizeof(name_));
+-
+- name = name_;
+- while (*name == ' ') name++;
+-
+- param = strchr(name, ':');
+-
+- if (!param) {
+- param = strchr(name, ' ');
+- }
+- if (param) {
+- *param++ = '\0';
+- while (*param == ' ') param++;
+- }
+-
+- o = av_opt_find(&c, name, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+- if (!o) {
+- PRINT("Ignoring unknown expert option %s\n", str);
+- return 0;
+- }
+- if (param && o->type == AV_OPT_TYPE_CONST) {
+- return 0;
+- }
+- if (param && o->type != AV_OPT_TYPE_CONST && o->unit) {
+- p = av_opt_find(&c, param, o->unit, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+- if (p) {
+- prop = BKE_ffmpeg_property_add(rd, (char *) type, p, o);
+- }
+- else {
+- PRINT("Ignoring unknown expert option %s\n", str);
+- }
+- }
+- else {
+- prop = BKE_ffmpeg_property_add(rd, (char *) type, o, NULL);
+- }
+-
+-
+- if (!prop) {
+- return 0;
+- }
+-
+- if (param && !p) {
+- switch (prop->type) {
+- case IDP_INT:
+- IDP_Int(prop) = atoi(param);
+- break;
+- case IDP_FLOAT:
+- IDP_Float(prop) = atof(param);
+- break;
+- case IDP_STRING:
+- strncpy(IDP_String(prop), param, prop->len);
+- break;
+- }
+- }
+- return 1;
+-}
+-
+-static void ffmpeg_set_expert_options(RenderData *rd)
+-{
+- int codec_id = rd->ffcodecdata.codec;
+-
+- if (rd->ffcodecdata.properties)
+- IDP_FreeProperty(rd->ffcodecdata.properties);
+-
+- if (codec_id == AV_CODEC_ID_H264) {
+- /*
+- * All options here are for x264, but must be set via ffmpeg.
+- * The names are therefore different - Search for "x264 to FFmpeg option mapping"
+- * to get a list.
+- */
+-
+- /*
+- * Use CABAC coder. Using "coder:1", which should be equivalent,
+- * crashes Blender for some reason. Either way - this is no big deal.
+- */
+- BKE_ffmpeg_property_add_string(rd, "video", "coder:vlc");
+-
+- /*
+- * The other options were taken from the libx264-default.preset
+- * included in the ffmpeg distribution.
+- */
+-// ffmpeg_property_add_string(rd, "video", "flags:loop"); // this breaks compatibility for QT
+- BKE_ffmpeg_property_add_string(rd, "video", "cmp:chroma");
+- BKE_ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); // Deprecated.
+- BKE_ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); // Deprecated.
+- BKE_ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); // Deprecated.
+- BKE_ffmpeg_property_add_string(rd, "video", "me:hex");
+- BKE_ffmpeg_property_add_string(rd, "video", "subq:6");
+- BKE_ffmpeg_property_add_string(rd, "video", "me_range:16");
+- BKE_ffmpeg_property_add_string(rd, "video", "qdiff:4");
+- BKE_ffmpeg_property_add_string(rd, "video", "keyint_min:25");
+- BKE_ffmpeg_property_add_string(rd, "video", "sc_threshold:40");
+- BKE_ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71");
+- BKE_ffmpeg_property_add_string(rd, "video", "b_strategy:1");
+- BKE_ffmpeg_property_add_string(rd, "video", "bf:3");
+- BKE_ffmpeg_property_add_string(rd, "video", "refs:2");
+- BKE_ffmpeg_property_add_string(rd, "video", "qcomp:0.6");
+-
+- BKE_ffmpeg_property_add_string(rd, "video", "trellis:0");
+- BKE_ffmpeg_property_add_string(rd, "video", "weightb:1");
+-#ifdef FFMPEG_HAVE_DEPRECATED_FLAGS2
+- BKE_ffmpeg_property_add_string(rd, "video", "flags2:dct8x8");
+- BKE_ffmpeg_property_add_string(rd, "video", "directpred:3");
+- BKE_ffmpeg_property_add_string(rd, "video", "flags2:fastpskip");
+- BKE_ffmpeg_property_add_string(rd, "video", "flags2:wpred");
+-#else
+- BKE_ffmpeg_property_add_string(rd, "video", "8x8dct:1");
+- BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
+- BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
+-#endif
+- }
+- else if (codec_id == AV_CODEC_ID_DNXHD) {
+- if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
+- BKE_ffmpeg_property_add_string(rd, "video", "mbd:rd");
+- }
+-}
+-
+ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
+ {
+- int isntsc = (rd->frs_sec != 25);
+-
+- if (rd->ffcodecdata.properties)
+- IDP_FreeProperty(rd->ffcodecdata.properties);
++ bool is_ntsc = (rd->frs_sec != 25);
+
+ switch (preset) {
+ case FFMPEG_PRESET_VCD:
+ rd->ffcodecdata.type = FFMPEG_MPEG1;
+ rd->ffcodecdata.video_bitrate = 1150;
+ rd->xsch = 352;
+- rd->ysch = isntsc ? 240 : 288;
+- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
++ rd->ysch = is_ntsc ? 240 : 288;
++ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 1150;
+ rd->ffcodecdata.rc_min_rate = 1150;
+ rd->ffcodecdata.rc_buffer_size = 40 * 8;
+@@ -1578,8 +1257,8 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
+ rd->ffcodecdata.type = FFMPEG_MPEG2;
+ rd->ffcodecdata.video_bitrate = 2040;
+ rd->xsch = 480;
+- rd->ysch = isntsc ? 480 : 576;
+- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
++ rd->ysch = is_ntsc ? 480 : 576;
++ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 2516;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+@@ -1593,9 +1272,9 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
+
+ /* Don't set resolution, see [#21351]
+ * rd->xsch = 720;
+- * rd->ysch = isntsc ? 480 : 576; */
++ * rd->ysch = is_ntsc ? 480 : 576; */
+
+- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
++ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+@@ -1606,14 +1285,14 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
+ case FFMPEG_PRESET_DV:
+ rd->ffcodecdata.type = FFMPEG_DV;
+ rd->xsch = 720;
+- rd->ysch = isntsc ? 480 : 576;
++ rd->ysch = is_ntsc ? 480 : 576;
+ break;
+
+ case FFMPEG_PRESET_H264:
+ rd->ffcodecdata.type = FFMPEG_AVI;
+ rd->ffcodecdata.codec = AV_CODEC_ID_H264;
+ rd->ffcodecdata.video_bitrate = 6000;
+- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
++ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+@@ -1634,17 +1313,14 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
+ }
+
+ rd->ffcodecdata.video_bitrate = 6000;
+- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
++ rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+ break;
+-
+ }
+-
+- ffmpeg_set_expert_options(rd);
+ }
+
+ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
+@@ -1693,30 +1369,17 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
+ }
+ }
+
+-void BKE_ffmpeg_codec_settings_verify(RenderData *rd)
+-{
+- ffmpeg_set_expert_options(rd);
+-}
+-
+ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
+ {
+ int codec = rd->ffcodecdata.codec;
+
+- if (codec == AV_CODEC_ID_QTRLE)
+- return true;
+-
+- if (codec == AV_CODEC_ID_PNG)
+- return true;
+-
+- if (codec == AV_CODEC_ID_HUFFYUV)
+- return true;
+-
+-#ifdef FFMPEG_FFV1_ALPHA_SUPPORTED
+- if (codec == AV_CODEC_ID_FFV1)
+- return true;
+-#endif
++ return ELEM(codec,
++ AV_CODEC_ID_FFV1,
++ AV_CODEC_ID_QTRLE,
++ AV_CODEC_ID_PNG,
++ AV_CODEC_ID_VP9,
++ AV_CODEC_ID_HUFFYUV);
+
+- return false;
+ }
+
+ void *BKE_ffmpeg_context_create(void)
+diff --git a/blender-2.79b/source/blender/blenlib/BLI_math_base.h b/blender-2.79b/source/blender/blenlib/BLI_math_base.h
+index e7e89a6..0872000 100644
+--- a/blender-2.79b/source/blender/blenlib/BLI_math_base.h
++++ b/blender-2.79b/source/blender/blenlib/BLI_math_base.h
+@@ -153,6 +153,8 @@ MINLINE int iroundf(float a);
+ MINLINE int divide_round_i(int a, int b);
+ MINLINE int mod_i(int i, int n);
+
++MINLINE int round_fl_to_int(float a);
++
+ MINLINE signed char round_fl_to_char_clamp(float a);
+ MINLINE unsigned char round_fl_to_uchar_clamp(float a);
+ MINLINE short round_fl_to_short_clamp(float a);
+diff --git a/blender-2.79b/source/blender/blenlib/intern/math_base_inline.c b/blender-2.79b/source/blender/blenlib/intern/math_base_inline.c
+index 37efe95..95ff62b 100644
+--- a/blender-2.79b/source/blender/blenlib/intern/math_base_inline.c
++++ b/blender-2.79b/source/blender/blenlib/intern/math_base_inline.c
+@@ -189,6 +189,15 @@ MINLINE int iroundf(float a)
+ return (int)floorf(a + 0.5f);
+ }
+
++#define _round_fl_impl(arg, ty) \
++ { \
++ return (ty)floorf(arg + 0.5f); \
++ }
++
++MINLINE int round_fl_to_int(float a){_round_fl_impl(a, int)}
++
++#undef _round_fl_impl
++
+ #define _round_clamp_fl_impl(arg, ty, min, max) { \
+ float r = floorf(arg + 0.5f); \
+ if (UNLIKELY(r <= (float)min)) return (ty)min; \
+diff --git a/blender-2.79b/source/blender/blenloader/intern/readfile.c b/blender-2.79b/source/blender/blenloader/intern/readfile.c
+index f440cca..bd6168c 100644
+--- a/blender-2.79b/source/blender/blenloader/intern/readfile.c
++++ b/blender-2.79b/source/blender/blenloader/intern/readfile.c
+@@ -6169,7 +6169,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
+ }
+ }
+ }
+-
++
+ sce->r.avicodecdata = newdataadr(fd, sce->r.avicodecdata);
+ if (sce->r.avicodecdata) {
+ sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat);
+@@ -6180,11 +6180,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
+ if (sce->r.qtcodecdata) {
+ sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms);
+ }
+- if (sce->r.ffcodecdata.properties) {
+- sce->r.ffcodecdata.properties = newdataadr(fd, sce->r.ffcodecdata.properties);
+- IDP_DirectLinkGroup_OrFree(&sce->r.ffcodecdata.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+- }
+-
++
+ link_list(fd, &(sce->markers));
+ link_list(fd, &(sce->transform_spaces));
+ link_list(fd, &(sce->r.layers));
+@@ -6209,7 +6205,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
+ }
+
+ direct_link_view_settings(fd, &sce->view_settings);
+-
++
+ sce->rigidbody_world = newdataadr(fd, sce->rigidbody_world);
+ rbw = sce->rigidbody_world;
+ if (rbw) {
+diff --git a/blender-2.79b/source/blender/blenloader/intern/writefile.c b/blender-2.79b/source/blender/blenloader/intern/writefile.c
+index a50afc4..0c54b11 100644
+--- a/blender-2.79b/source/blender/blenloader/intern/writefile.c
++++ b/blender-2.79b/source/blender/blenloader/intern/writefile.c
+@@ -2697,9 +2697,6 @@ static void write_scene(WriteData *wd, Scene *sce)
+ writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ }
+ }
+- if (sce->r.ffcodecdata.properties) {
+- IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
+- }
+
+ /* writing dynamic list of TimeMarkers to the blend file */
+ for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+diff --git a/blender-2.79b/source/blender/imbuf/intern/IMB_anim.h b/blender-2.79b/source/blender/imbuf/intern/IMB_anim.h
+index 5f47769..8d380fb 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/IMB_anim.h
++++ b/blender-2.79b/source/blender/imbuf/intern/IMB_anim.h
+@@ -145,7 +145,7 @@ struct anim {
+ #ifdef WITH_FFMPEG
+ AVFormatContext *pFormatCtx;
+ AVCodecContext *pCodecCtx;
+- AVCodec *pCodec;
++ const AVCodec *pCodec;
+ AVFrame *pFrame;
+ int pFrameComplete;
+ AVFrame *pFrameRGB;
+@@ -156,7 +156,7 @@ struct anim {
+ struct ImBuf *last_frame;
+ int64_t last_pts;
+ int64_t next_pts;
+- AVPacket next_packet;
++ AVPacket *next_packet;
+ #endif
+
+ char index_dir[768];
+diff --git a/blender-2.79b/source/blender/imbuf/intern/anim_movie.c b/blender-2.79b/source/blender/imbuf/intern/anim_movie.c
+index 8bd808f..9eb40d3 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/anim_movie.c
++++ b/blender-2.79b/source/blender/imbuf/intern/anim_movie.c
+@@ -92,6 +92,7 @@
+ #ifdef WITH_FFMPEG
+ # include <libavformat/avformat.h>
+ # include <libavcodec/avcodec.h>
++# include <libavutil/imgutils.h>
+ # include <libavutil/rational.h>
+ # include <libswscale/swscale.h>
+
+@@ -448,24 +449,25 @@ BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
+
+ static int startffmpeg(struct anim *anim)
+ {
+- int i, videoStream;
++ int i, video_stream_index;
+
+- AVCodec *pCodec;
++ const AVCodec *pCodec;
+ AVFormatContext *pFormatCtx = NULL;
+ AVCodecContext *pCodecCtx;
+ AVRational frame_rate;
++ AVStream *video_stream;
+ int frs_num;
+ double frs_den;
+ int streamcount;
+
+-#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
+ /* The following for color space determination */
+ int srcRange, dstRange, brightness, contrast, saturation;
+ int *table;
+ const int *inv_table;
+-#endif
+
+- if (anim == NULL) return(-1);
++ if (anim == NULL) {
++ return(-1);
++ }
+
+ streamcount = anim->streamindex;
+
+@@ -482,47 +484,50 @@ static int startffmpeg(struct anim *anim)
+
+
+ /* Find the video stream */
+- videoStream = -1;
++ video_stream_index = -1;
+
+- for (i = 0; i < pFormatCtx->nb_streams; i++)
+- if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
++ for (i = 0; i < pFormatCtx->nb_streams; i++) {
++ if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+ }
+- videoStream = i;
++ video_stream_index = i;
+ break;
+ }
++ }
+
+- if (videoStream == -1) {
++ if (video_stream_index == -1) {
+ avformat_close_input(&pFormatCtx);
+ return -1;
+ }
+
+- pCodecCtx = pFormatCtx->streams[videoStream]->codec;
++ video_stream = pFormatCtx->streams[video_stream_index];
+
+ /* Find the decoder for the video stream */
+- pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
++ pCodec = avcodec_find_decoder(video_stream->codecpar->codec_id);
+ if (pCodec == NULL) {
+ avformat_close_input(&pFormatCtx);
+ return -1;
+ }
+
+- pCodecCtx->workaround_bugs = 1;
++ pCodecCtx = avcodec_alloc_context3(NULL);
++ avcodec_parameters_to_context(pCodecCtx, video_stream->codecpar);
++ pCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
+
+ if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
+ avformat_close_input(&pFormatCtx);
+ return -1;
+ }
+ if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) {
+- avcodec_close(anim->pCodecCtx);
++ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&pFormatCtx);
+ return -1;
+ }
+
+- frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
+- if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
+- anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
++ frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL);
++ if (video_stream->nb_frames != 0) {
++ anim->duration = video_stream->nb_frames;
+ }
+ else {
+ anim->duration = (int)(pFormatCtx->duration *
+@@ -546,12 +551,12 @@ static int startffmpeg(struct anim *anim)
+ anim->params = 0;
+
+ anim->x = pCodecCtx->width;
+- anim->y = av_get_cropped_height_from_codec(pCodecCtx);
++ anim->y = pCodecCtx->height;
+
+ anim->pFormatCtx = pFormatCtx;
+ anim->pCodecCtx = pCodecCtx;
+ anim->pCodec = pCodec;
+- anim->videoStream = videoStream;
++ anim->videoStream = video_stream_index;
+
+ anim->interlacing = 0;
+ anim->orientation = 0;
+@@ -561,7 +566,8 @@ static int startffmpeg(struct anim *anim)
+ anim->last_frame = 0;
+ anim->last_pts = -1;
+ anim->next_pts = -1;
+- anim->next_packet.stream_index = -1;
++ anim->next_packet = av_packet_alloc();
++ anim->next_packet->stream_index = -1;
+
+ anim->pFrame = av_frame_alloc();
+ anim->pFrameComplete = false;
+@@ -575,8 +581,9 @@ static int startffmpeg(struct anim *anim)
+
+ if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+- avcodec_close(anim->pCodecCtx);
++ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
++ av_packet_free(&anim->next_packet);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+@@ -585,13 +592,13 @@ static int startffmpeg(struct anim *anim)
+ }
+ }
+
+- if (avpicture_get_size(AV_PIX_FMT_RGBA, anim->x, anim->y) !=
+- anim->x * anim->y * 4)
++ if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->x, anim->y, 1) != anim->x * anim->y * 4)
+ {
+ fprintf(stderr,
+ "ffmpeg has changed alloc scheme ... ARGHHH!\n");
+- avcodec_close(anim->pCodecCtx);
++ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
++ av_packet_free(&anim->next_packet);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+@@ -600,15 +607,17 @@ static int startffmpeg(struct anim *anim)
+ }
+
+ if (anim->ib_flags & IB_animdeinterlace) {
+- avpicture_fill((AVPicture *) anim->pFrameDeinterlaced,
+- MEM_callocN(avpicture_get_size(
+- anim->pCodecCtx->pix_fmt,
+- anim->pCodecCtx->width,
+- anim->pCodecCtx->height),
+- "ffmpeg deinterlace"),
+- anim->pCodecCtx->pix_fmt,
+- anim->pCodecCtx->width,
+- anim->pCodecCtx->height);
++ av_image_fill_arrays(anim->pFrameDeinterlaced->data,
++ anim->pFrameDeinterlaced->linesize,
++ MEM_callocN(av_image_get_buffer_size(anim->pCodecCtx->pix_fmt,
++ anim->pCodecCtx->width,
++ anim->pCodecCtx->height,
++ 1),
++ "ffmpeg deinterlace"),
++ anim->pCodecCtx->pix_fmt,
++ anim->pCodecCtx->width,
++ anim->pCodecCtx->height,
++ 1);
+ }
+
+ if (pCodecCtx->has_b_frames) {
+@@ -617,7 +626,7 @@ static int startffmpeg(struct anim *anim)
+ else {
+ anim->preseek = 0;
+ }
+-
++
+ anim->img_convert_ctx = sws_getContext(
+ anim->x,
+ anim->y,
+@@ -627,12 +636,13 @@ static int startffmpeg(struct anim *anim)
+ AV_PIX_FMT_RGBA,
+ SWS_FAST_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
+ NULL, NULL, NULL);
+-
++
+ if (!anim->img_convert_ctx) {
+ fprintf(stderr,
+ "Can't transform color space??? Bailing out...\n");
+- avcodec_close(anim->pCodecCtx);
++ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
++ av_packet_free(&anim->next_packet);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+@@ -640,7 +650,6 @@ static int startffmpeg(struct anim *anim)
+ return -1;
+ }
+
+-#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
+ /* Try do detect if input has 0-255 YCbCR range (JFIF Jpeg MotionJpeg) */
+ if (!sws_getColorspaceDetails(anim->img_convert_ctx, (int **)&inv_table, &srcRange,
+ &table, &dstRange, &brightness, &contrast, &saturation))
+@@ -657,8 +666,7 @@ static int startffmpeg(struct anim *anim)
+ else {
+ fprintf(stderr, "Warning: Could not set libswscale colorspace details.\n");
+ }
+-#endif
+-
++
+ return (0);
+ }
+
+@@ -695,14 +703,11 @@ static void ffmpeg_postprocess(struct anim *anim)
+
+
+ if (anim->ib_flags & IB_animdeinterlace) {
+- if (avpicture_deinterlace(
+- (AVPicture *)
+- anim->pFrameDeinterlaced,
+- (const AVPicture *)
+- anim->pFrame,
+- anim->pCodecCtx->pix_fmt,
+- anim->pCodecCtx->width,
+- anim->pCodecCtx->height) < 0)
++ if (av_image_deinterlace(anim->pFrameDeinterlaced,
++ anim->pFrame,
++ anim->pCodecCtx->pix_fmt,
++ anim->pCodecCtx->width,
++ anim->pCodecCtx->height) < 0)
+ {
+ filter_y = true;
+ }
+@@ -712,9 +717,13 @@ static void ffmpeg_postprocess(struct anim *anim)
+ }
+
+ if (!need_aligned_ffmpeg_buffer(anim)) {
+- avpicture_fill((AVPicture *) anim->pFrameRGB,
+- (unsigned char *) ibuf->rect,
+- AV_PIX_FMT_RGBA, anim->x, anim->y);
++ av_image_fill_arrays(anim->pFrameRGB->data,
++ anim->pFrameRGB->linesize,
++ (unsigned char *)ibuf->rect,
++ AV_PIX_FMT_RGBA,
++ anim->x,
++ anim->y,
++ 1);
+ }
+
+ if (ENDIAN_ORDER == B_ENDIAN) {
+@@ -803,33 +812,27 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
+
+- if (anim->next_packet.stream_index == anim->videoStream) {
+- av_free_packet(&anim->next_packet);
+- anim->next_packet.stream_index = -1;
++ if (anim->next_packet->stream_index == anim->videoStream) {
++ av_packet_unref(anim->next_packet);
++ anim->next_packet->stream_index = -1;
+ }
+-
+- while ((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) {
++
++ while ((rval = av_read_frame(anim->pFormatCtx, anim->next_packet)) >= 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ "%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld "
+ "%s\n",
+- (anim->next_packet.stream_index == anim->videoStream)
+- ? "->" : " ",
+- anim->next_packet.stream_index,
++ (anim->next_packet->stream_index == anim->videoStream) ? "->" : " ",
++ anim->next_packet->stream_index,
+ anim->videoStream,
+- (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1 :
+- (long long int)anim->next_packet.dts,
+- (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1 :
+- (long long int)anim->next_packet.pts,
+- (anim->next_packet.flags & AV_PKT_FLAG_KEY) ?
+- " KEY" : "");
+- if (anim->next_packet.stream_index == anim->videoStream) {
++ (anim->next_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet->dts,
++ (anim->next_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet->pts,
++ (anim->next_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : "");
++ if (anim->next_packet->stream_index == anim->videoStream) {
+ anim->pFrameComplete = 0;
+
+- avcodec_decode_video2(
+- anim->pCodecCtx,
+- anim->pFrame, &anim->pFrameComplete,
+- &anim->next_packet);
++ avcodec_send_packet(anim->pCodecCtx, anim->next_packet);
++ anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+
+ if (anim->pFrameComplete) {
+ anim->next_pts = av_get_pts_from_frame(
+@@ -837,38 +840,23 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+- " FRAME DONE: next_pts=%lld "
+- "pkt_pts=%lld, guessed_pts=%lld\n",
++ " FRAME DONE: next_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+- -1 : (long long int)anim->pFrame->pts,
+- (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
+- -1 : (long long int)anim->pFrame->pkt_pts,
+- (long long int)anim->next_pts);
++ -1 : (int64_t)anim->pFrame->pts,
++ (int64_t)anim->next_pts);
+ break;
+ }
+ }
+- av_free_packet(&anim->next_packet);
+- anim->next_packet.stream_index = -1;
++ av_packet_unref(anim->next_packet);
++ anim->next_packet->stream_index = -1;
+ }
+
+ if (rval == AVERROR_EOF) {
+- /* this sets size and data fields to zero,
+- * which is necessary to decode the remaining data
+- * in the decoder engine after EOF. It also prevents a memory
+- * leak, since av_read_frame spills out a full size packet even
+- * on EOF... (and: it's safe to call on NULL packets) */
+-
+- av_free_packet(&anim->next_packet);
+-
+- anim->next_packet.size = 0;
+- anim->next_packet.data = 0;
+-
++ /* Flush any remaining frames out of the decoder. */
+ anim->pFrameComplete = 0;
+
+- avcodec_decode_video2(
+- anim->pCodecCtx,
+- anim->pFrame, &anim->pFrameComplete,
+- &anim->next_packet);
++ avcodec_send_packet(anim->pCodecCtx, NULL);
++ anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+
+ if (anim->pFrameComplete) {
+ anim->next_pts = av_get_pts_from_frame(
+@@ -876,23 +864,21 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+- " FRAME DONE (after EOF): next_pts=%lld "
+- "pkt_pts=%lld, guessed_pts=%lld\n",
++ " FRAME DONE (after EOF): next_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+ -1 : (long long int)anim->pFrame->pts,
+- (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
+- -1 : (long long int)anim->pFrame->pkt_pts,
+ (long long int)anim->next_pts);
+ rval = 0;
+ }
+ }
+
+ if (rval < 0) {
+- anim->next_packet.stream_index = -1;
++ av_packet_unref(anim->next_packet);
++ anim->next_packet->stream_index = -1;
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR, " DECODE READ FAILED: av_read_frame() "
+- "returned error: %d\n", rval);
++ "returned error: %s\n", av_err2str(rval));
+ }
+
+ return (rval >= 0);
+@@ -998,7 +984,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
+
+ v_st = anim->pFormatCtx->streams[anim->videoStream];
+
+- frame_rate = av_q2d(av_get_r_frame_rate_compat(v_st));
++ frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
+
+ st_time = anim->pFormatCtx->start_time;
+ pts_time_base = av_q2d(v_st->time_base);
+@@ -1082,7 +1068,6 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
+ ret = av_seek_frame(anim->pFormatCtx,
+ -1,
+ pos, AVSEEK_FLAG_BYTE);
+- av_update_cur_dts(anim->pFormatCtx, v_st, dts);
+ }
+ else {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+@@ -1127,9 +1112,9 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
+
+ anim->next_pts = -1;
+
+- if (anim->next_packet.stream_index == anim->videoStream) {
+- av_free_packet(&anim->next_packet);
+- anim->next_packet.stream_index = -1;
++ if (anim->next_packet->stream_index == anim->videoStream) {
++ av_packet_unref(&anim->next_packet);
++ anim->next_packet->stream_index = -1;
+ }
+
+ /* memset(anim->pFrame, ...) ?? */
+@@ -1154,11 +1139,11 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
+ ffmpeg_postprocess(anim);
+
+ anim->last_pts = anim->next_pts;
+-
++
+ ffmpeg_decode_video_frame(anim);
+-
++
+ anim->curposition = position;
+-
++
+ IMB_refImBuf(anim->last_frame);
+
+ return anim->last_frame;
+@@ -1169,35 +1154,30 @@ static void free_anim_ffmpeg(struct anim *anim)
+ if (anim == NULL) return;
+
+ if (anim->pCodecCtx) {
+- avcodec_close(anim->pCodecCtx);
++ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
++ av_packet_free(&anim->next_packet);
+
+- /* Special case here: pFrame could share pointers with codec,
+- * so in order to avoid double-free we don't use av_frame_free()
+- * to free the frame.
+- *
+- * Could it be a bug in FFmpeg?
+- */
+- av_free(anim->pFrame);
++ av_frame_free(&anim->pFrame);
+
+ if (!need_aligned_ffmpeg_buffer(anim)) {
+ /* If there's no need for own aligned buffer it means that FFmpeg's
+ * frame shares the same buffer as temporary ImBuf. In this case we
+ * should not free the buffer when freeing the FFmpeg buffer.
+ */
+- avpicture_fill((AVPicture *)anim->pFrameRGB,
+- NULL,
+- AV_PIX_FMT_RGBA,
+- anim->x, anim->y);
++ av_image_fill_arrays(anim->pFrameRGB->data,
++ anim->pFrameRGB->linesize,
++ NULL,
++ AV_PIX_FMT_RGBA,
++ anim->x,
++ anim->y,
++ 1);
+ }
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+
+ sws_freeContext(anim->img_convert_ctx);
+ IMB_freeImBuf(anim->last_frame);
+- if (anim->next_packet.stream_index != -1) {
+- av_free_packet(&anim->next_packet);
+- }
+ }
+ anim->duration = 0;
+ }
+diff --git a/blender-2.79b/source/blender/imbuf/intern/indexer.c b/blender-2.79b/source/blender/imbuf/intern/indexer.c
+index e1b3abc..df8d5c4 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/indexer.c
++++ b/blender-2.79b/source/blender/imbuf/intern/indexer.c
+@@ -32,6 +32,7 @@
+
+ #include "BLI_utildefines.h"
+ #include "BLI_endian_switch.h"
++#include "BLI_math_base.h"
+ #include "BLI_path_util.h"
+ #include "BLI_string.h"
+ #include "BLI_fileops.h"
+@@ -49,6 +50,7 @@
+
+ #ifdef WITH_FFMPEG
+ # include "ffmpeg_compat.h"
++# include <libavutil/imgutils.h>
+ #endif
+
+
+@@ -452,7 +454,7 @@ struct proxy_output_ctx {
+ AVFormatContext *of;
+ AVStream *st;
+ AVCodecContext *c;
+- AVCodec *codec;
++ const AVCodec *codec;
+ struct SwsContext *sws_ctx;
+ AVFrame *frame;
+ int cfra;
+@@ -477,7 +479,6 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
+ sizeof(struct proxy_output_ctx), "alloc_proxy_output");
+
+ char fname[FILE_MAX];
+- int ffmpeg_quality;
+
+ /* JPEG requires this */
+ width = round_up(width, 8);
+@@ -491,30 +492,30 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
+
+ rv->of = avformat_alloc_context();
+ rv->of->oformat = av_guess_format("avi", NULL, NULL);
+-
+- BLI_strncpy(rv->of->filename, fname, sizeof(rv->of->filename));
+
+- fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename);
++ rv->of->url = av_strdup(fname);
++
++ fprintf(stderr, "Starting work on proxy: %s\n", rv->of->url);
+
+ rv->st = avformat_new_stream(rv->of, NULL);
+ rv->st->id = 0;
+
+- rv->c = rv->st->codec;
+- rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
+- rv->c->codec_id = AV_CODEC_ID_MJPEG;
+- rv->c->width = width;
+- rv->c->height = height;
++ rv->codec = avcodec_find_encoder(AV_CODEC_ID_H264);
+
+- rv->of->oformat->video_codec = rv->c->codec_id;
+- rv->codec = avcodec_find_encoder(rv->c->codec_id);
++ rv->c = avcodec_alloc_context3(rv->codec);
+
+ if (!rv->codec) {
+ fprintf(stderr, "No ffmpeg MJPEG encoder available? "
+ "Proxy not built!\n");
+- av_free(rv->of);
++ avcodec_free_context(&rv->c);
++ avformat_free_context(rv->of);
++ MEM_freeN(rv);
+ return NULL;
+ }
+
++ rv->c->width = width;
++ rv->c->height = height;
++
+ if (rv->codec->pix_fmts) {
+ rv->c->pix_fmt = rv->codec->pix_fmts[0];
+ }
+@@ -522,76 +523,105 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
+ rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P;
+ }
+
+- rv->c->sample_aspect_ratio =
+- rv->st->sample_aspect_ratio =
+- st->codec->sample_aspect_ratio;
++ rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->sample_aspect_ratio;
+
+ rv->c->time_base.den = 25;
+ rv->c->time_base.num = 1;
+ rv->st->time_base = rv->c->time_base;
+
+- /* there's no way to set JPEG quality in the same way as in AVI JPEG and image sequence,
+- * but this seems to be giving expected quality result */
+- ffmpeg_quality = (int)(1.0f + 30.0f * (1.0f - (float)quality / 100.0f) + 0.5f);
+- av_opt_set_int(rv->c, "qmin", ffmpeg_quality, 0);
+- av_opt_set_int(rv->c, "qmax", ffmpeg_quality, 0);
++ /* This range matches #eFFMpegCrf. `crf_range_min` corresponds to lowest quality,
++ * `crf_range_max` to highest quality. */
++ const int crf_range_min = 32;
++ const int crf_range_max = 17;
++ int crf = round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min);
++
++ AVDictionary *codec_opts = NULL;
++ /* High quality preset value. */
++ av_dict_set_int(&codec_opts, "crf", crf, 0);
++ /* Prefer smaller file-size. Presets from `veryslow` to `veryfast` produce output with very
++ * similar file-size, but there is big difference in performance.
++ * In some cases `veryfast` preset will produce smallest file-size. */
++ av_dict_set(&codec_opts, "preset", "veryfast", 0);
++ av_dict_set(&codec_opts, "tune", "fastdecode", 0);
+
+ if (rv->of->flags & AVFMT_GLOBALHEADER) {
+- rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
++ rv->c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+- if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) {
+- fprintf(stderr, "Couldn't open outputfile! "
+- "Proxy not built!\n");
+- av_free(rv->of);
+- return 0;
++ avcodec_parameters_from_context(rv->st->codecpar, rv->c);
++
++ int ret = avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE);
++
++ if (ret < 0) {
++ fprintf(stderr, "Couldn't open IO: %s\n"
++ "Proxy not built!\n",
++ av_err2str(ret));
++ avcodec_free_context(&rv->c);
++ avformat_free_context(rv->of);
++ MEM_freeN(rv);
++ return NULL;
+ }
+
+- avcodec_open2(rv->c, rv->codec, NULL);
++ ret = avcodec_open2(rv->c, rv->codec, &codec_opts);
++ if (ret < 0) {
++ fprintf(stderr,
++ "Couldn't open codec: %s\n"
++ "Proxy not built!\n",
++ av_err2str(ret));
++ avcodec_free_context(&rv->c);
++ avformat_free_context(rv->of);
++ MEM_freeN(rv);
++ return NULL;
++ }
+
+- rv->orig_height = av_get_cropped_height_from_codec(st->codec);
++ rv->orig_height = st->codecpar->height;
+
+- if (st->codec->width != width || st->codec->height != height ||
+- st->codec->pix_fmt != rv->c->pix_fmt)
++ if (st->codecpar->width != width || st->codecpar->height != height ||
++ st->codecpar->format != rv->c->pix_fmt)
+ {
+ rv->frame = av_frame_alloc();
+- avpicture_fill((AVPicture *) rv->frame,
+- MEM_mallocN(avpicture_get_size(
+- rv->c->pix_fmt,
+- round_up(width, 16), height),
+- "alloc proxy output frame"),
+- rv->c->pix_fmt, round_up(width, 16), height);
++ av_image_fill_arrays(rv->frame->data,
++ rv->frame->linesize,
++ MEM_mallocN(av_image_get_buffer_size(rv->c->pix_fmt, round_up(width, 16), height, 1), "alloc proxy output frame"),
++ rv->c->pix_fmt,
++ round_up(width, 16),
++ height,
++ 1);
+
+ rv->sws_ctx = sws_getContext(
+- st->codec->width,
++ st->codecpar->width,
+ rv->orig_height,
+- st->codec->pix_fmt,
++ st->codecpar->format,
+ width, height,
+ rv->c->pix_fmt,
+ SWS_FAST_BILINEAR | SWS_PRINT_INFO,
+ NULL, NULL, NULL);
+ }
+
+- if (avformat_write_header(rv->of, NULL) < 0) {
+- fprintf(stderr, "Couldn't set output parameters? "
+- "Proxy not built!\n");
+- av_free(rv->of);
+- return 0;
++ ret = avformat_write_header(rv->of, NULL);
++ if (ret < 0) {
++ fprintf(stderr, "Couldn't write header: %s\n"
++ "Proxy not built!\n",
++ av_err2str(ret));
++
++ if (rv->frame) {
++ av_frame_free(&rv->frame);
++ }
++
++ avcodec_free_context(&rv->c);
++ avformat_free_context(rv->of);
++ MEM_freeN(rv);
++ return NULL;
+ }
+
+ return rv;
+ }
+
+-static int add_to_proxy_output_ffmpeg(
++static void add_to_proxy_output_ffmpeg(
+ struct proxy_output_ctx *ctx, AVFrame *frame)
+ {
+- AVPacket packet = { 0 };
+- int ret, got_output;
+-
+- av_init_packet(&packet);
+-
+ if (!ctx) {
+- return 0;
++ return;
+ }
+
+ if (ctx->sws_ctx && frame &&
+@@ -609,39 +639,42 @@ static int add_to_proxy_output_ffmpeg(
+ frame->pts = ctx->cfra++;
+ }
+
+- ret = avcodec_encode_video2(ctx->c, &packet, frame, &got_output);
++ int ret = avcodec_send_frame(ctx->c, frame);
+ if (ret < 0) {
+- fprintf(stderr, "Error encoding proxy frame %d for '%s'\n",
+- ctx->cfra - 1, ctx->of->filename);
+- return 0;
++ /* Can't send frame to encoder. This shouldn't happen. */
++ fprintf(stderr, "Can't send video frame: %s\n", av_err2str(ret));
++ return;
+ }
++ AVPacket *packet = av_packet_alloc();
++
++ while (ret >= 0) {
++ ret = avcodec_receive_packet(ctx->c, packet);
+
+- if (got_output) {
+- if (packet.pts != AV_NOPTS_VALUE) {
+- packet.pts = av_rescale_q(packet.pts,
+- ctx->c->time_base,
+- ctx->st->time_base);
++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
++ /* No more packets to flush. */
++ break;
+ }
+- if (packet.dts != AV_NOPTS_VALUE) {
+- packet.dts = av_rescale_q(packet.dts,
+- ctx->c->time_base,
+- ctx->st->time_base);
++ if (ret < 0) {
++ fprintf(stderr,
++ "Error encoding proxy frame %d for '%s': %s\n",
++ ctx->cfra - 1,
++ ctx->of->url,
++ av_err2str(ret));
++ break;
+ }
+
+- packet.stream_index = ctx->st->index;
++ packet->stream_index = ctx->st->index;
++ av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base);
+
+- if (av_interleaved_write_frame(ctx->of, &packet) != 0) {
++ int write_ret = av_interleaved_write_frame(ctx->of, packet);
++ if (write_ret != 0) {
+ fprintf(stderr, "Error writing proxy frame %d "
+- "into '%s'\n", ctx->cfra - 1,
+- ctx->of->filename);
+- return 0;
++ "into '%s': %s\n", ctx->cfra - 1,
++ ctx->of->url, av_err2str(write_ret));
++ break;
+ }
+-
+- return 1;
+- }
+- else {
+- return 0;
+ }
++ av_packet_free(&packet);
+ }
+
+ static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx,
+@@ -655,15 +688,16 @@ static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx,
+ }
+
+ if (!rollback) {
+- while (add_to_proxy_output_ffmpeg(ctx, NULL)) {}
++ /* Flush the remaining packets. */
++ add_to_proxy_output_ffmpeg(ctx, NULL);
+ }
+
+ avcodec_flush_buffers(ctx->c);
+
+ av_write_trailer(ctx->of);
+-
+- avcodec_close(ctx->c);
+-
++
++ avcodec_free_context(&ctx->c);
++
+ if (ctx->of->oformat) {
+ if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
+ avio_close(ctx->of->pb);
+@@ -699,7 +733,7 @@ typedef struct FFmpegIndexBuilderContext {
+
+ AVFormatContext *iFormatCtx;
+ AVCodecContext *iCodecCtx;
+- AVCodec *iCodec;
++ const AVCodec *iCodec;
+ AVStream *iStream;
+ int videoStream;
+
+@@ -756,7 +790,7 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Tim
+ /* Find the video stream */
+ context->videoStream = -1;
+ for (i = 0; i < context->iFormatCtx->nb_streams; i++)
+- if (context->iFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
++ if (context->iFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+@@ -772,9 +806,8 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Tim
+ }
+
+ context->iStream = context->iFormatCtx->streams[context->videoStream];
+- context->iCodecCtx = context->iStream->codec;
+
+- context->iCodec = avcodec_find_decoder(context->iCodecCtx->codec_id);
++ context->iCodec = avcodec_find_decoder(context->iStream->codecpar->codec_id);
+
+ if (context->iCodec == NULL) {
+ avformat_close_input(&context->iFormatCtx);
+@@ -782,22 +815,25 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Tim
+ return NULL;
+ }
+
+- context->iCodecCtx->workaround_bugs = 1;
++ context->iCodecCtx = avcodec_alloc_context3(NULL);
++ avcodec_parameters_to_context(context->iCodecCtx, context->iStream->codecpar);
++ context->iCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
+
+ if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) {
+ avformat_close_input(&context->iFormatCtx);
++ avcodec_free_context(&context->iCodecCtx);
+ MEM_freeN(context);
+ return NULL;
+ }
+
+ for (i = 0; i < num_proxy_sizes; i++) {
+ if (proxy_sizes_in_use & proxy_sizes[i]) {
+- context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(
+- anim, context->iStream, proxy_sizes[i],
+- context->iCodecCtx->width * proxy_fac[i],
+- av_get_cropped_height_from_codec(
+- context->iCodecCtx) * proxy_fac[i],
+- quality);
++ context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(anim,
++ context->iStream,
++ proxy_sizes[i],
++ context->iCodecCtx->width * proxy_fac[i],
++ context->iCodecCtx->height * proxy_fac[i],
++ quality);
+ if (!context->proxy_ctx[i]) {
+ proxy_sizes_in_use &= ~proxy_sizes[i];
+ }
+@@ -836,7 +872,7 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int
+ }
+ }
+
+- avcodec_close(context->iCodecCtx);
++ avcodec_free_context(&context->iCodecCtx);
+ avformat_close_input(&context->iFormatCtx);
+
+ MEM_freeN(context);
+@@ -899,23 +935,18 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(
+ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
+ short *stop, short *do_update, float *progress)
+ {
+- AVFrame *in_frame = 0;
+- AVPacket next_packet;
++ AVFrame *in_frame = av_frame_alloc();
++ AVPacket *next_packet = av_packet_alloc();
+ uint64_t stream_size;
+
+- memset(&next_packet, 0, sizeof(AVPacket));
+-
+- in_frame = av_frame_alloc();
+-
+ stream_size = avio_size(context->iFormatCtx->pb);
+
+- context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iStream));
++ context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL));
+ context->pts_time_base = av_q2d(context->iStream->time_base);
+
+- while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
++ while (av_read_frame(context->iFormatCtx, next_packet) >= 0) {
+ int frame_finished = 0;
+- float next_progress = (float)((int)floor(((double) next_packet.pos) * 100 /
+- ((double) stream_size) + 0.5)) / 100;
++ float next_progress = (float)((int)floor(((double)next_packet->pos) * 100 / ((double)stream_size) + 0.5)) / 100;
+
+ if (*progress != next_progress) {
+ *progress = next_progress;
+@@ -923,56 +954,59 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
+ }
+
+ if (*stop) {
+- av_free_packet(&next_packet);
+ break;
+ }
+
+- if (next_packet.stream_index == context->videoStream) {
+- if (next_packet.flags & AV_PKT_FLAG_KEY) {
++ if (next_packet->stream_index == context->videoStream) {
++ if (next_packet->flags & AV_PKT_FLAG_KEY) {
+ context->last_seek_pos = context->seek_pos;
+ context->last_seek_pos_dts = context->seek_pos_dts;
+- context->seek_pos = next_packet.pos;
+- context->seek_pos_dts = next_packet.dts;
+- context->seek_pos_pts = next_packet.pts;
++ context->seek_pos = next_packet->pos;
++ context->seek_pos_dts = next_packet->dts;
++ context->seek_pos_pts = next_packet->pts;
+ }
+
+- avcodec_decode_video2(
+- context->iCodecCtx, in_frame, &frame_finished,
+- &next_packet);
+- }
+-
+- if (frame_finished) {
+- index_rebuild_ffmpeg_proc_decoded_frame(
+- context, &next_packet, in_frame);
++ int ret = avcodec_send_packet(context->iCodecCtx, next_packet);
++ while (ret >= 0) {
++ ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
++ /* No more frames to flush. */
++ break;
++ }
++ if (ret < 0) {
++ fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret));
++ break;
++ }
++ index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame);
++ }
+ }
+- av_free_packet(&next_packet);
+ }
+
+ /* process pictures still stuck in decoder engine after EOF
+- * according to ffmpeg docs using 0-size packets.
++ * according to ffmpeg docs using NULL packets.
+ *
+ * At least, if we haven't already stopped... */
+
+- /* this creates the 0-size packet and prevents a memory leak. */
+- av_free_packet(&next_packet);
+-
+ if (!*stop) {
+- int frame_finished;
++ int ret = avcodec_send_packet(context->iCodecCtx, NULL);
+
+- do {
+- frame_finished = 0;
++ while (ret >= 0) {
++ ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
+
+- avcodec_decode_video2(
+- context->iCodecCtx, in_frame, &frame_finished,
+- &next_packet);
++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
++ /* No more frames to flush. */
++ break;
++ }
+
+- if (frame_finished) {
+- index_rebuild_ffmpeg_proc_decoded_frame(
+- context, &next_packet, in_frame);
++ if (ret < 0) {
++ fprintf(stderr, "Error flushing proxy frame: %s\n", av_err2str(ret));
++ break;
+ }
+- } while (frame_finished);
++ index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame);
++ }
+ }
+
++ av_packet_free(&next_packet);
+ av_free(in_frame);
+
+ return 1;
+diff --git a/blender-2.79b/source/blender/imbuf/intern/util.c b/blender-2.79b/source/blender/imbuf/intern/util.c
+index ba8480b..24e360c 100644
+--- a/blender-2.79b/source/blender/imbuf/intern/util.c
++++ b/blender-2.79b/source/blender/imbuf/intern/util.c
+@@ -290,7 +290,6 @@ static void ffmpeg_log_callback(void *ptr, int level, const char *format, va_lis
+
+ void IMB_ffmpeg_init(void)
+ {
+- av_register_all();
+ avdevice_register_all();
+
+ ffmpeg_last_error[0] = '\0';
+@@ -312,8 +311,7 @@ static int isffmpeg(const char *filename)
+ AVFormatContext *pFormatCtx = NULL;
+ unsigned int i;
+ int videoStream;
+- AVCodec *pCodec;
+- AVCodecContext *pCodecCtx;
++ const AVCodec *pCodec;
+
+ if (BLI_testextensie_n(
+ filename,
+@@ -339,9 +337,8 @@ static int isffmpeg(const char *filename)
+ /* Find the first video stream */
+ videoStream = -1;
+ for (i = 0; i < pFormatCtx->nb_streams; i++)
+- if (pFormatCtx->streams[i] &&
+- pFormatCtx->streams[i]->codec &&
+- (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))
++ if (pFormatCtx->streams[i] && pFormatCtx->streams[i]->codecpar &&
++ (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO))
+ {
+ videoStream = i;
+ break;
+@@ -352,21 +349,15 @@ static int isffmpeg(const char *filename)
+ return 0;
+ }
+
+- pCodecCtx = pFormatCtx->streams[videoStream]->codec;
++ AVCodecParameters *codec_par = pFormatCtx->streams[videoStream]->codecpar;
+
+ /* Find the decoder for the video stream */
+- pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
++ pCodec = avcodec_find_decoder(codec_par->codec_id);
+ if (pCodec == NULL) {
+ avformat_close_input(&pFormatCtx);
+ return 0;
+ }
+
+- if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
+- avformat_close_input(&pFormatCtx);
+- return 0;
+- }
+-
+- avcodec_close(pCodecCtx);
+ avformat_close_input(&pFormatCtx);
+
+ return 1;
+diff --git a/blender-2.79b/source/blender/makesdna/DNA_scene_types.h b/blender-2.79b/source/blender/makesdna/DNA_scene_types.h
+index 79ee91b..d7e377a 100644
+--- a/blender-2.79b/source/blender/makesdna/DNA_scene_types.h
++++ b/blender-2.79b/source/blender/makesdna/DNA_scene_types.h
+@@ -174,7 +174,6 @@ typedef struct FFMpegCodecData {
+ int audio_bitrate;
+ int audio_mixrate;
+ int audio_channels;
+- int audio_pad;
+ float audio_volume;
+ int gop_size;
+ int max_b_frames; /* only used if FFMPEG_USE_MAX_B_FRAMES flag is set. */
+@@ -187,9 +186,7 @@ typedef struct FFMpegCodecData {
+ int rc_buffer_size;
+ int mux_packet_size;
+ int mux_rate;
+- int pad1;
+-
+- IDProperty *properties;
++ void *_pad1;
+ } FFMpegCodecData;
+
+ /* ************************************************************* */
+diff --git a/blender-2.79b/source/blender/makesrna/intern/rna_scene.c b/blender-2.79b/source/blender/makesrna/intern/rna_scene.c
+index db3ff9b..fa02539 100644
+--- a/blender-2.79b/source/blender/makesrna/intern/rna_scene.c
++++ b/blender-2.79b/source/blender/makesrna/intern/rna_scene.c
+@@ -1406,20 +1406,12 @@ static void rna_FFmpegSettings_lossless_output_set(PointerRNA *ptr, int value)
+ Scene *scene = (Scene *) ptr->id.data;
+ RenderData *rd = &scene->r;
+
+- if (value)
++ if (value) {
+ rd->ffcodecdata.flags |= FFMPEG_LOSSLESS_OUTPUT;
+- else
++ }
++ else {
+ rd->ffcodecdata.flags &= ~FFMPEG_LOSSLESS_OUTPUT;
+-
+- BKE_ffmpeg_codec_settings_verify(rd);
+-}
+-
+-static void rna_FFmpegSettings_codec_settings_update(Main *UNUSED(bmain), Scene *UNUSED(scene_unused), PointerRNA *ptr)
+-{
+- Scene *scene = (Scene *) ptr->id.data;
+- RenderData *rd = &scene->r;
+-
+- BKE_ffmpeg_codec_settings_verify(rd);
++ }
+ }
+ #endif
+
+@@ -5594,7 +5586,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
+ RNA_def_property_enum_items(prop, ffmpeg_format_items);
+ RNA_def_property_enum_default(prop, FFMPEG_MKV);
+ RNA_def_property_ui_text(prop, "Container", "Output file container");
+- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
+
+ prop = RNA_def_property(srna, "codec", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "codec");
+@@ -5602,7 +5593,6 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
+ RNA_def_property_enum_items(prop, ffmpeg_codec_items);
+ RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
+ RNA_def_property_ui_text(prop, "Codec", "FFmpeg codec to use");
+- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_settings_update");
+
+ prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "video_bitrate");
+diff --git a/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+index 083e9e2..7246278 100644
+--- a/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
++++ b/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+@@ -36,6 +36,10 @@
+ #define __STDC_CONSTANT_MACROS
+ #ifdef __STDC_CONSTANT_MACROS /* quiet warning */
+ #endif
++extern "C" {
++#include <libavutil/imgutils.h>
++#include <libswscale/swscale.h>
++}
+ #endif
+
+ #include <stdint.h>
+@@ -63,7 +67,7 @@ const double defFrameRate = 25.0;
+ VideoFFmpeg::VideoFFmpeg (HRESULT * hRslt) : VideoBase(),
+ m_codec(NULL), m_formatCtx(NULL), m_codecCtx(NULL),
+ m_frame(NULL), m_frameDeinterlaced(NULL), m_frameRGB(NULL), m_imgConvertCtx(NULL),
+-m_deinterlace(false), m_preseek(0), m_videoStream(-1), m_baseFrameRate(25.0),
++m_deinterlace(false), m_preseek(0), m_videoStreamIndex(-1), m_baseFrameRate(25.0),
+ m_lastFrame(-1), m_eof(false), m_externTime(false), m_curPosition(-1), m_startTime(0),
+ m_captWidth(0), m_captHeight(0), m_captRate(0.f), m_isImage(false),
+ m_isThreaded(false), m_isStreaming(false), m_stopThread(false), m_cacheStarted(false)
+@@ -144,20 +148,22 @@ AVFrame *VideoFFmpeg::allocFrameRGB()
+ frame = av_frame_alloc();
+ if (m_format == RGBA32)
+ {
+- avpicture_fill((AVPicture*)frame,
+- (uint8_t*)MEM_callocN(avpicture_get_size(
+- AV_PIX_FMT_RGBA,
+- m_codecCtx->width, m_codecCtx->height),
+- "ffmpeg rgba"),
+- AV_PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height);
++ av_image_fill_arrays(frame->data,
++ frame->linesize,
++ (uint8_t*)MEM_mallocN(av_image_get_buffer_size(AV_PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height, 1), "ffmpeg rgba"),
++ AV_PIX_FMT_RGBA,
++ m_codecCtx->width,
++ m_codecCtx->height,
++ 1);
+ } else
+ {
+- avpicture_fill((AVPicture*)frame,
+- (uint8_t*)MEM_callocN(avpicture_get_size(
+- AV_PIX_FMT_RGB24,
+- m_codecCtx->width, m_codecCtx->height),
+- "ffmpeg rgb"),
+- AV_PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height);
++ av_image_fill_arrays(frame->data,
++ frame->linesize,
++ (uint8_t*)MEM_mallocN(av_image_get_buffer_size(AV_PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height, 1), "ffmpeg rgba"),
++ AV_PIX_FMT_RGBA,
++ m_codecCtx->width,
++ m_codecCtx->height,
++ 1);
+ }
+ return frame;
+ }
+@@ -172,12 +178,13 @@ void VideoFFmpeg::initParams (short width, short height, float rate, bool image)
+ }
+
+
+-int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVDictionary **formatParams)
++int VideoFFmpeg::openStream(const char *filename, const AVInputFormat *inputFormat, AVDictionary **formatParams)
+ {
+ AVFormatContext *formatCtx = NULL;
+- int i, videoStream;
+- AVCodec *codec;
++ int i, video_stream_index;
++ const AVCodec *codec;
+ AVCodecContext *codecCtx;
++ AVStream *video_stream;
+
+ if (avformat_open_input(&formatCtx, filename, inputFormat, formatParams)!=0)
+ return -1;
+@@ -188,65 +195,63 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
+ return -1;
+ }
+
+- /* Find the first video stream */
+- videoStream=-1;
+- for (i=0; i<formatCtx->nb_streams; i++)
+- {
++ /* Find the video stream */
++ video_stream_index = -1;
++
++ for (i = 0; i < formatCtx->nb_streams; i++) {
+ if (formatCtx->streams[i] &&
+- get_codec_from_stream(formatCtx->streams[i]) &&
+- (get_codec_from_stream(formatCtx->streams[i])->codec_type==AVMEDIA_TYPE_VIDEO))
++ formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
+ {
+- videoStream=i;
++ video_stream_index = i;
+ break;
+ }
+ }
+
+- if (videoStream==-1)
++ if (video_stream_index == -1)
+ {
+ avformat_close_input(&formatCtx);
+ return -1;
+ }
+
+- codecCtx = get_codec_from_stream(formatCtx->streams[videoStream]);
++ video_stream = formatCtx->streams[video_stream_index];
+
+ /* Find the decoder for the video stream */
+- codec=avcodec_find_decoder(codecCtx->codec_id);
+- if (codec==NULL)
+- {
++ codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
++ if (codec == nullptr) {
+ avformat_close_input(&formatCtx);
+ return -1;
+ }
+- codecCtx->workaround_bugs = 1;
+- if (avcodec_open2(codecCtx, codec, NULL) < 0)
++
++ codecCtx = avcodec_alloc_context3(NULL);
++ avcodec_parameters_to_context(codecCtx, video_stream->codecpar);
++ codecCtx->workaround_bugs = FF_BUG_AUTODETECT;
++
++ if (avcodec_open2(codecCtx, codec, nullptr) < 0)
+ {
+ avformat_close_input(&formatCtx);
+ return -1;
+ }
+
+-#ifdef FFMPEG_OLD_FRAME_RATE
+- if (codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
+- codecCtx->frame_rate_base=1000;
+- m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
+-#else
+- m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx->streams[videoStream]));
+-#endif
+- if (m_baseFrameRate <= 0.0)
++ m_baseFrameRate = av_q2d(av_guess_frame_rate(formatCtx, video_stream, nullptr));
++ if (m_baseFrameRate <= 0.0) {
+ m_baseFrameRate = defFrameRate;
++ }
+
+ m_codec = codec;
+ m_codecCtx = codecCtx;
+ m_formatCtx = formatCtx;
+- m_videoStream = videoStream;
++ m_videoStreamIndex = video_stream_index;
+ m_frame = av_frame_alloc();
+ m_frameDeinterlaced = av_frame_alloc();
+
+ // allocate buffer if deinterlacing is required
+- avpicture_fill((AVPicture*)m_frameDeinterlaced,
+- (uint8_t*)MEM_callocN(avpicture_get_size(
+- m_codecCtx->pix_fmt,
+- m_codecCtx->width, m_codecCtx->height),
+- "ffmpeg deinterlace"),
+- m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height);
++ av_image_fill_arrays(m_frameDeinterlaced->data,
++ m_frameDeinterlaced->linesize,
++ (uint8_t*)MEM_mallocN(av_image_get_buffer_size(m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height, 1), "ffmpeg deinterlace"),
++ m_codecCtx->pix_fmt,
++ m_codecCtx->width,
++ m_codecCtx->height,
++ 1);
+
+ // check if the pixel format supports Alpha
+ if (m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32 ||
+@@ -321,8 +326,8 @@ void *VideoFFmpeg::cacheThread(void *data)
+ CachePacket *cachePacket;
+ bool endOfFile = false;
+ int frameFinished = 0;
+- double timeBase = av_q2d(video->m_formatCtx->streams[video->m_videoStream]->time_base);
+- int64_t startTs = video->m_formatCtx->streams[video->m_videoStream]->start_time;
++ double timeBase = av_q2d(video->m_formatCtx->streams[video->m_videoStreamIndex]->time_base);
++ int64_t startTs = video->m_formatCtx->streams[video->m_videoStreamIndex]->start_time;
+
+ if (startTs == AV_NOPTS_VALUE)
+ startTs = 0;
+@@ -340,17 +345,17 @@ void *VideoFFmpeg::cacheThread(void *data)
+ // free packet => packet cache is not full yet, just read more
+ if (av_read_frame(video->m_formatCtx, &cachePacket->packet)>=0)
+ {
+- if (cachePacket->packet.stream_index == video->m_videoStream)
++ if (cachePacket->packet.stream_index == video->m_videoStreamIndex)
+ {
+ // make sure fresh memory is allocated for the packet and move it to queue
+- av_dup_packet(&cachePacket->packet);
++ av_packet_ref(&cachePacket->packet, nullptr);
+ BLI_remlink(&video->m_packetCacheFree, cachePacket);
+ BLI_addtail(&video->m_packetCacheBase, cachePacket);
+ break;
+ } else {
+ // this is not a good packet for us, just leave it on free queue
+ // Note: here we could handle sound packet
+- av_free_packet(&cachePacket->packet);
++ av_packet_unref(&cachePacket->packet);
+ frameFinished++;
+ }
+
+@@ -380,9 +385,8 @@ void *VideoFFmpeg::cacheThread(void *data)
+ BLI_remlink(&video->m_packetCacheBase, cachePacket);
+ // use m_frame because when caching, it is not used in main thread
+ // we can't use currentFrame directly because we need to convert to RGB first
+- avcodec_decode_video2(video->m_codecCtx,
+- video->m_frame, &frameFinished,
+- &cachePacket->packet);
++ avcodec_send_packet(video->m_codecCtx, &cachePacket->packet);
++ frameFinished = avcodec_receive_frame(video->m_codecCtx, video->m_frame) == 0;
+ if (frameFinished)
+ {
+ AVFrame * input = video->m_frame;
+@@ -393,9 +397,9 @@ void *VideoFFmpeg::cacheThread(void *data)
+ {
+ if (video->m_deinterlace)
+ {
+- if (avpicture_deinterlace(
+- (AVPicture*) video->m_frameDeinterlaced,
+- (const AVPicture*) video->m_frame,
++ if (av_image_deinterlace(
++ video->m_frameDeinterlaced,
++ video->m_frame,
+ video->m_codecCtx->pix_fmt,
+ video->m_codecCtx->width,
+ video->m_codecCtx->height) >= 0)
+@@ -420,7 +424,7 @@ void *VideoFFmpeg::cacheThread(void *data)
+ currentFrame = NULL;
+ }
+ }
+- av_free_packet(&cachePacket->packet);
++ av_packet_unref(&cachePacket->packet);
+ BLI_addtail(&video->m_packetCacheFree, cachePacket);
+ }
+ if (currentFrame && endOfFile)
+@@ -500,7 +504,7 @@ void VideoFFmpeg::stopCache()
+ while ((packet = (CachePacket *)m_packetCacheBase.first) != NULL)
+ {
+ BLI_remlink(&m_packetCacheBase, packet);
+- av_free_packet(&packet->packet);
++ av_packet_unref(&packet->packet);
+ delete packet;
+ }
+ while ((packet = (CachePacket *)m_packetCacheFree.first) != NULL)
+@@ -590,7 +594,7 @@ void VideoFFmpeg::openFile (char *filename)
+ void VideoFFmpeg::openCam (char *file, short camIdx)
+ {
+ // open camera source
+- AVInputFormat *inputFormat;
++ const AVInputFormat *inputFormat;
+ AVDictionary *formatParams = NULL;
+ char filename[28], rateStr[20];
+
+@@ -930,8 +934,8 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ pthread_mutex_unlock(&m_cacheMutex);
+ } while (true);
+ }
+- double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base);
+- int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time;
++ double timeBase = av_q2d(m_formatCtx->streams[m_videoStreamIndex]->time_base);
++ int64_t startTs = m_formatCtx->streams[m_videoStreamIndex]->start_time;
+ if (startTs == AV_NOPTS_VALUE)
+ startTs = 0;
+
+@@ -947,18 +951,16 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ {
+ while (av_read_frame(m_formatCtx, &packet)>=0)
+ {
+- if (packet.stream_index == m_videoStream)
++ if (packet.stream_index == m_videoStreamIndex)
+ {
+- avcodec_decode_video2(
+- m_codecCtx,
+- m_frame, &frameFinished,
+- &packet);
++ avcodec_send_packet(m_codecCtx, &packet);
++ frameFinished = avcodec_receive_frame(m_codecCtx, m_frame) == 0;
+ if (frameFinished)
+ {
+ m_curPosition = (long)((packet.dts-startTs) * (m_baseFrameRate*timeBase) + 0.5);
+ }
+ }
+- av_free_packet(&packet);
++ av_packet_unref(&packet);
+ if (position == m_curPosition+1)
+ break;
+ }
+@@ -983,10 +985,10 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ if (position <= m_preseek)
+ {
+ // we can safely go the beginning of the file
+- if (av_seek_frame(m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_BYTE) >= 0)
++ if (av_seek_frame(m_formatCtx, m_videoStreamIndex, 0, AVSEEK_FLAG_BYTE) >= 0)
+ {
+ // binary seek does not reset the timestamp, must do it now
+- av_update_cur_dts(m_formatCtx, m_formatCtx->streams[m_videoStream], startTs);
++ av_update_cur_dts(m_formatCtx, m_formatCtx->streams[m_videoStreamIndex], startTs);
+ m_curPosition = 0;
+ }
+ }
+@@ -994,7 +996,7 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ #endif
+ {
+ // current position is now lost, guess a value.
+- if (av_seek_frame(m_formatCtx, m_videoStream, pos, AVSEEK_FLAG_BACKWARD) >= 0)
++ if (av_seek_frame(m_formatCtx, m_videoStreamIndex, pos, AVSEEK_FLAG_BACKWARD) >= 0)
+ {
+ // current position is now lost, guess a value.
+ // It's not important because it will be set at this end of this function
+@@ -1022,14 +1024,15 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ // return the next frame. This is not quite correct, may need more work
+ while (av_read_frame(m_formatCtx, &packet) >= 0)
+ {
+- if (packet.stream_index == m_videoStream)
++ if (packet.stream_index == m_videoStreamIndex)
+ {
+ AVFrame *input = m_frame;
+ short counter = 0;
+
+ /* If m_isImage, while the data is not read properly (png, tiffs, etc formats may need several pass), else don't need while loop*/
+ do {
+- avcodec_decode_video2(m_codecCtx, m_frame, &frameFinished, &packet);
++ avcodec_send_packet(m_codecCtx, &packet);
++ frameFinished = avcodec_receive_frame(m_codecCtx, m_frame) == 0;
+ counter++;
+ } while ((input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) && counter < 10 && m_isImage);
+
+@@ -1052,15 +1055,15 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ if ( input->data[0]==0 && input->data[1]==0
+ && input->data[2]==0 && input->data[3]==0)
+ {
+- av_free_packet(&packet);
++ av_packet_unref(&packet);
+ break;
+ }
+
+ if (m_deinterlace)
+ {
+- if (avpicture_deinterlace(
+- (AVPicture*) m_frameDeinterlaced,
+- (const AVPicture*) m_frame,
++ if (av_image_deinterlace(
++ m_frameDeinterlaced,
++ m_frame,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height) >= 0)
+@@ -1076,12 +1079,12 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
+ m_codecCtx->height,
+ m_frameRGB->data,
+ m_frameRGB->linesize);
+- av_free_packet(&packet);
++ av_packet_unref(&packet);
+ frameLoaded = true;
+ break;
+ }
+ }
+- av_free_packet(&packet);
++ av_packet_unref(&packet);
+ }
+ m_eof = m_isFile && !frameLoaded;
+ if (frameLoaded)
+diff --git a/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.h b/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.h
+index 0a49a0b..b25d569 100644
+--- a/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.h
++++ b/blender-2.79b/source/gameengine/VideoTexture/VideoFFmpeg.h
+@@ -36,32 +36,17 @@
+ #if defined(__FreeBSD__)
+ # include <inttypes.h>
+ #endif
++
++struct AVCodecContext;
+ extern "C" {
+ #include <pthread.h>
+ #include "ffmpeg_compat.h"
+ #include "DNA_listBase.h"
+ #include "BLI_threads.h"
+ #include "BLI_blenlib.h"
++#include <libavcodec/avcodec.h>
+ }
+
+-#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+-# define FFMPEG_OLD_FRAME_RATE 1
+-#else
+-# define FFMPEG_CODEC_IS_POINTER 1
+-#endif
+-
+-#ifdef FFMPEG_CODEC_IS_POINTER
+-static inline AVCodecContext *get_codec_from_stream(AVStream* stream)
+-{
+- return stream->codec;
+-}
+-#else
+-static inline AVCodecContext *get_codec_from_stream(AVStream* stream)
+-{
+- return &stream->codec;
+-}
+-#endif
+-
+ #include "VideoBase.h"
+
+ #define CACHE_FRAME_SIZE 10
+@@ -106,7 +91,7 @@ public:
+
+ protected:
+ // format and codec information
+- AVCodec *m_codec;
++ const AVCodec *m_codec;
+ AVFormatContext *m_formatCtx;
+ AVCodecContext *m_codecCtx;
+ // raw frame extracted from video file
+@@ -122,7 +107,7 @@ protected:
+ // number of frame of preseek
+ int m_preseek;
+ // order number of stream holding the video in format context
+- int m_videoStream;
++ int m_videoStreamIndex;
+
+ // the actual frame rate
+ double m_baseFrameRate;
+@@ -173,7 +158,7 @@ protected:
+ double actFrameRate (void) { return m_frameRate * m_baseFrameRate; }
+
+ /// common function to video file and capture
+- int openStream(const char *filename, AVInputFormat *inputFormat, AVDictionary **formatParams);
++ int openStream(const char *filename, const AVInputFormat *inputFormat, AVDictionary **formatParams);
+
+ /// check if a frame is available and load it in pFrame, return true if a frame could be retrieved
+ AVFrame* grabFrame(long frame);
diff --git a/PKGBUILD b/PKGBUILD
index 71189ed79b60..7408c7995ae3 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -4,10 +4,7 @@
# shellcheck disable=SC2191 # preserve current _CMAKE_FLAGS initialization.
# Configuration.
-_branch="blender2.7"
-_fragment=${FRAGMENT:-#branch=${_branch}}
[[ -v CUDA_ARCH ]] && _cuda_capability=${CUDA_ARCH}
-_commit_url="https://git.blender.org/gitweb/gitweb.cgi/blender.git/patch"
#some extra, unofficially supported stuff goes here:
((TRAVIS)) && _cuda_capability+=(sm_50 sm_52 sm_60 sm_61 sm_70 sm_75) # Travis memory limit is not enough to build for arch 3.x.
@@ -16,69 +13,71 @@ _commit_url="https://git.blender.org/gitweb/gitweb.cgi/blender.git/patch"
((DISABLE_CUDA)) && optdepends+=('cuda: CUDA support in Cycles') || makedepends+=('cuda')
pkgname=blender-2.7
-pkgver=2.79b.r71421.e045fe53f1b
-pkgrel=3
-pkgdesc="Maintnance version of Blenders ${_branch} branch"
+pkgver=2.79b
+pkgrel=4
+pkgdesc="Keeping Blender 2.79b up-to-date with modern compiler and libs"
arch=('i686' 'x86_64')
url="https://blender.org/"
-depends+=('alembic' 'libgl' 'python' 'python-numpy' 'openjpeg2'
- 'ffmpeg' 'fftw' 'openal' 'freetype2' 'libxi' 'openimageio' 'opencolorio1'
- 'openvdb' 'opencollada' 'opensubdiv' 'openshadinglanguage' 'libtiff' 'libpng')
-makedepends+=('git' 'cmake' 'boost' 'mesa' 'llvm')
+depends+=('alembic' 'libgl' 'python' 'python-numpy' 'openjpeg2' 'ffmpeg'
+ 'fftw' 'openal' 'freetype2' 'libxi' 'openimageio' 'opencolorio1'
+ 'openvdb' 'opencollada' 'opensubdiv' 'openshadinglanguage' 'libtiff'
+ 'libpng')
+makedepends+=('cmake' 'boost' 'mesa' 'llvm')
provides=('blender-2.7')
license=('GPL')
-# NOTE: the source array has to be kept in sync with .gitmodules
-# the submodules has to be stored in path ending with git to match
-# the path in .gitmodules.
-# More info:
-# http://wiki.blender.org/index.php/Dev:Doc/Tools/Git
-source=("git://git.blender.org/blender.git${_fragment}"
- 'blender-addons.git::git://git.blender.org/blender-addons.git'
- 'blender-addons-contrib.git::git://git.blender.org/blender-addons-contrib.git'
- 'blender-translations.git::git://git.blender.org/blender-translations.git'
- 'blender-dev-tools.git::git://git.blender.org/blender-dev-tools.git'
+source=('https://download.blender.org/source/blender-2.79b.tar.gz'
SelectCudaComputeArch.patch
- stl_export_iter.patch
- python3.7.patch
- python3.8.patch
- 'python3.9.patch' # ::https://git.blender.org/gitweb/gitweb.cgi/blender.git/patch/56d0df51a36fdce7ec2d1fbb7b47b1d95b591b5f
- 'python3.9_2.patch' # ::https://git.blender.org/gitweb/gitweb.cgi/blender.git/patch/5edba9b42f684bf8b99894bb6988e7f46180e12c
- openvdb7.patch
- openvdb8.patch # ::${_commit_url}/37889011070ff2ec52159690f652238d2b325185
- cycles.patch
- openexr3.patch
opencolorio1.patch
- )
-sha256sums=('SKIP'
- 'SKIP'
- 'SKIP'
- 'SKIP'
- 'SKIP'
- '28e407e3aefdd9bd76805b6033ada0b5b41dd6183bcf4f58a642c109f10c1876'
- '649c21a12a1bfc0207078e1e58b4813a3e898c6dbbbb35d21e1de7c9e8f1985a'
- '47811284f080e38bcfbfb1f7346279245815a064df092989336b0bf3fe4530e9'
- '229853b98bb62e1dec835aea6b2eab4c3dabbc8be591206573a3c1b85f10be59'
- 'd106248d55045f5ef913bf6243ad74a76f6282264d9ee4c9b87ec4a3d2e2064b'
- 'b2a2bc5de8d3b730e49d1f50cb025c1dfdbcb66c58ead573322585b6a887d3a7'
- 'c4079c4c142516d9cd476f5a3cafddf4068f0950c3c11ea4da9cf999c5ccc1f9'
- 'edfd784f8497417660c0b9fdc97893fd0d77764d0bc10f4cb92a9082f41bae75'
- 'd245f02d73bd5b767ffa49d369383d7cd6ae5e57b89c2975a78c1015e1884864'
- 'e7d75a5ef5cb6452b45f6e1e80b6fe69e2630878b1f4f6d53bf0e36ced237712'
- 'b3fa6ef21383287d0f8e7c3b848f3cf02186f9e3a0e8f194f3ca1323935e5e0e')
-
-pkgver() {
-# shellcheck disable=SC2164
- cd "$srcdir/blender"
- printf "2.79b.r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
-}
+ 0000_misc.patch
+ 0001_openexr3.patch
+ 0002_opencollada1_6_68.patch
+ 0003_openvdb.patch
+ 0004_openimageio.patch
+ 0005_cycles.patch
+ 0006_python3_7.patch
+ 0007_python3_8.patch
+ 0008_python3_9.patch
+ 0009_python3_10.patch
+ 0010_python3_11.patch
+ 0011_ffmpeg.patch)
+sha512sums=('2db21ace446168dd683cdb5aad9dec001f8888ae4e9603a04ddb44fb78489ded827deb07e83712b0f1118a0e7bf66f2a5d935dc4ebb3a6703d72672ff414367f'
+ '15b10bf91c759a8ab6519f3c02f54e7d3ad105eb915663e0de2a65b38d1e42b55cc383bae96a1507f1eb55200eb14ebe904b6a7b772b4073aa6a53ac5d4dd194'
+ '4126ddaaab2dc8c45cd850353a2e4a0e6ff2ef4476f9a533916e59fc57e426ca3110f7b3d38685fffd97b969208f941359122b693584c2a70a3f8420a832214b'
+ 'd7b6f1707ad902743a3f08c6423aabd7abd0841eb78404419884d7c0b02affc1b6c3eafea55f9db04bce5e27d22cfd0ec63153c61a5fa2c3227de54a09f0895d'
+ '0a8bd2ad7e199f95145bd0a66471686e0c545b071c73e6a659b570c001a860504f0970818fd686f52be9f5c18bd294c0efbede5c058ac96a4682e54b6235aac0'
+ '435e33926766a143cb6445a0c3219c9126b5d77e8114601a1f07848120b823ef2d1789bccb10079436b89eb9f894df54571ed50cde0713af857a8148be8f18ae'
+ 'fc86d7a9a46e521ec22b2d87dfb023a71bfde624c4a6ddcf137038c7f46b97d614f8cb99951489a251cb2ea28460690cc0e5eb9ac6f2ccacc27c0052d137dcc9'
+ 'c8bd5ee00f062760ae3a2493750b2eb66d0368955ebb443aad5313f91c1fd0680df239eb1ca957e79cda482c084a023efc60e4341c198d55f897415cf79de35d'
+ '3e3bef5e27279fc9c4f66398cd04a51a1ed268b7b99df2cf0151ed63994b742e39917e525ddac666d12a3df02a3ecef7dbe03da52c6be1aa143a3be960acbc5f'
+ '7c98cf29fa22e7e816789254e43ed0f5595529f8ed37c88abac8667a80bf2bee9f020fa204a45800586e4d0c2de977df9ceda6d8bc0b77c806743f761b6ffa9f'
+ '7effbd675b2167cc4c25a36d58f08824b2770e7b57fee93fd909a715003ee076ffcfc7e91cf965b9836da2fa54246fb68bbe613e44d312702298a5386b124dfa'
+ 'a556445f27eaaba839d0efcfa70c530c269c7189e194c93b929044a54697f3606401dfdf5dbec05b181c26ba82d2b16560f2db7cd579104e0a0a322525cecaff'
+ 'ecae55f642bf7f08edc56f8740a9fec650a3617f0ce7c7ba5b3211994ad8c46dc8fbbe897405699d46cb01c15129c0d4d9184657daeaf41172533195cdbbb104'
+ 'de254cb5e43fe05c3b5e70df881c1ab847b58c383d8df28be6d044c058d4776a5a3d57f710eb3cf0a83b43c95fac29f772c446a23e0f9c2bf73d1dcc8b23b67c'
+ 'a0ff4f4dbc3624692c16d45f632cda1362173a5685c85e62d54af1d63d5a421867a5eb89b5b1c5b72bbceef98664d96b54901790470cbe67f701c582858af0ed')
prepare() {
- # update the submodules
- git -C "$srcdir/blender" -c protocol.file.allow=always submodule update --init --recursive --remote
+ # Apply CUDA patch
if [ ! -v _cuda_capability ] && grep -q nvidia <(lsmod); then
- git -C "$srcdir/blender" apply -v "${srcdir}"/SelectCudaComputeArch.patch
+ patch -p1 < SelectCudaComputeArch.patch
fi
- git -C "$srcdir/blender" apply -v "${srcdir}"/{python3.7,stl_export_iter,python3.{8,9,9_2},openvdb{7,8},cycles,open{exr3,colorio1}}.patch
+
+ # Build with OpenColorIO 1 for now
+ patch -p1 < opencolorio1.patch
+
+ # Apply patches to build with modern libs and compiler
+ patch -p1 < 0000_misc.patch
+ patch -p1 < 0001_openexr3.patch
+ patch -p1 < 0002_opencollada1_6_68.patch
+ patch -p1 < 0003_openvdb.patch
+ patch -p1 < 0004_openimageio.patch
+ patch -p1 < 0005_cycles.patch
+ patch -p1 < 0006_python3_7.patch
+ patch -p1 < 0007_python3_8.patch
+ patch -p1 < 0008_python3_9.patch
+ patch -p1 < 0009_python3_10.patch
+ patch -p1 < 0010_python3_11.patch
+ patch -p1 < 0011_ffmpeg.patch
}
build() {
@@ -100,8 +99,8 @@ build() {
fi
((DISABLE_NINJA)) && generator="Unix Makefiles" || generator="Ninja"
- cmake -G "$generator" -S "$srcdir/blender" -B "$srcdir/build" \
- -C "${srcdir}/blender/build_files/cmake/config/blender_release.cmake" \
+ cmake -G "$generator" -S "$srcdir/blender-2.79b" -B "$srcdir/build" \
+ -C "${srcdir}/blender-2.79b/build_files/cmake/config/blender_release.cmake" \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_INSTALL_PORTABLE=OFF \
@@ -111,6 +110,16 @@ build() {
-DWITH_PYTHON_INSTALL=OFF \
-DPYTHON_VERSION="${_pyver}" \
-DWITH_LLVM=ON \
+ -DWITH_CODEC_FFMPEG=ON \
+ -DWITH_CYCLES=ON \
+ -DWITH_OPENCOLLADA=ON \
+ -DWITH_OPENCOLORIO=ON \
+ -DWITH_OPENVDB=ON \
+ -DWITH_OPENIMAGEIO=ON \
+ -DWITH_GAMEENGINE=ON \
+ -DWITH_PLAYER=ON \
+ -DWITH_PYTHON_MODULE=OFF \
+ -DWITH_CYCLES_OSL=NO
"${_CMAKE_FLAGS[@]}"
export NINJA_STATUS="[%p | %f<%r<%u | %cbps ] "
# shellcheck disable=SC2086 # allow MAKEFLAGS to split when multiple flags provided.
diff --git a/SelectCudaComputeArch.patch b/SelectCudaComputeArch.patch
index ab63fd128490..385f532ac91c 100644
--- a/SelectCudaComputeArch.patch
+++ b/SelectCudaComputeArch.patch
@@ -1,7 +1,7 @@
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index d0f473a2939..90fcb40107a 100644
---- a/intern/cycles/cmake/external_libs.cmake
-+++ b/intern/cycles/cmake/external_libs.cmake
+--- a/blender-2.79b/intern/cycles/cmake/external_libs.cmake
++++ b/blender-2.79b/intern/cycles/cmake/external_libs.cmake
@@ -41,6 +41,11 @@ if(WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD)
find_package(CUDA) # Try to auto locate CUDA toolkit
if(CUDA_FOUND)
diff --git a/cycles.patch b/cycles.patch
deleted file mode 100644
index 9d949f95058b..000000000000
--- a/cycles.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
-index 3990a22aefd..8b2faf3afe4 100644
---- a/intern/cycles/kernel/osl/osl_services.h
-+++ b/intern/cycles/kernel/osl/osl_services.h
-@@ -92,7 +92,7 @@ public:
- bool getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
- TypeDesc type, void *val, bool derivatives) override;
-
-- TextureSystem::TextureHandle *get_texture_handle(ustring filename) override;
-+ TextureSystem::TextureHandle *get_texture_handle(ustring filename);
-
- bool good(TextureSystem::TextureHandle *texture_handle) override;
-
-@@ -145,7 +145,7 @@ public:
- int subimage,
- ustring dataname,
- TypeDesc datatype,
-- void *data) override;
-+ void *data);
-
- static bool get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
- TypeDesc type, bool derivatives, void *val);
diff --git a/opencolorio1.patch b/opencolorio1.patch
index 89fbbd65455d..7e52cd057d3b 100644
--- a/opencolorio1.patch
+++ b/opencolorio1.patch
@@ -1,7 +1,7 @@
diff --git a/build_files/cmake/Modules/FindOpenColorIO.cmake b/build_files/cmake/Modules/FindOpenColorIO.cmake
index 090032e06ec..f5db181d73d 100644
---- a/build_files/cmake/Modules/FindOpenColorIO.cmake
-+++ b/build_files/cmake/Modules/FindOpenColorIO.cmake
+--- a/blender-2.79b/build_files/cmake/Modules/FindOpenColorIO.cmake
++++ b/blender-2.79b/build_files/cmake/Modules/FindOpenColorIO.cmake
@@ -28,7 +28,7 @@ IF(NOT OPENCOLORIO_ROOT_DIR AND NOT $ENV{OPENCOLORIO_ROOT_DIR} STREQUAL "")
ENDIF()
@@ -11,7 +11,7 @@ index 090032e06ec..f5db181d73d 100644
yaml-cpp
tinyxml
)
-@@ -40,7 +40,7 @@ SET(_opencolorio_SEARCH_DIRS
+@@ -44,7 +44,7 @@ SET(_opencolorio_SEARCH_DIRS
FIND_PATH(OPENCOLORIO_INCLUDE_DIR
NAMES
@@ -22,9 +22,9 @@ index 090032e06ec..f5db181d73d 100644
PATH_SUFFIXES
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index 0e25c89f5d7..f1f99de4bd8 100644
---- a/intern/opencolorio/ocio_impl.cc
-+++ b/intern/opencolorio/ocio_impl.cc
-@@ -26,7 +26,7 @@
+--- a/blender-2.79b/intern/opencolorio/ocio_impl.cc
++++ b/blender-2.79b/intern/opencolorio/ocio_impl.cc
+@@ -33,7 +33,7 @@
# pragma warning(push)
# pragma warning(disable : 4251 4275)
#endif
@@ -35,9 +35,9 @@ index 0e25c89f5d7..f1f99de4bd8 100644
#endif
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index df6adc8f34b..24d1ec8a871 100644
---- a/intern/opencolorio/ocio_impl_glsl.cc
-+++ b/intern/opencolorio/ocio_impl_glsl.cc
-@@ -40,7 +40,7 @@
+--- a/blender-2.79b/intern/opencolorio/ocio_impl_glsl.cc
++++ b/blender-2.79b/intern/opencolorio/ocio_impl_glsl.cc
+@@ -43,7 +43,7 @@
# pragma warning(push)
# pragma warning(disable : 4251 4275)
#endif
@@ -46,16 +46,4 @@ index df6adc8f34b..24d1ec8a871 100644
#ifdef _MSC_VER
# pragma warning(pop)
#endif
-diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
-index 8403a636e1c..54abe4cfa3c 100644
---- a/intern/cycles/render/shader.cpp
-+++ b/intern/cycles/render/shader.cpp
-@@ -35,7 +35,7 @@
- #include "util/util_murmurhash.h"
-
- #ifdef WITH_OCIO
--# include <OpenColorIO/OpenColorIO.h>
-+# include <OpenColorIO1/OpenColorIO.h>
- namespace OCIO = OCIO_NAMESPACE;
- #endif
-
+
diff --git a/openexr3.patch b/openexr3.patch
deleted file mode 100644
index a60f5f99bab6..000000000000
--- a/openexr3.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-diff --git a/build_files/cmake/Modules/FindOpenEXR.cmake b/build_files/cmake/Modules/FindOpenEXR.cmake
-index 090f80b8df7..a2f7b4c622b 100644
---- a/build_files/cmake/Modules/FindOpenEXR.cmake
-+++ b/build_files/cmake/Modules/FindOpenEXR.cmake
-@@ -34,11 +34,10 @@ ENDIF()
- SET(_openexr_libs_ver_init "2.0")
-
- SET(_openexr_FIND_COMPONENTS
-- Half
- Iex
-- IlmImf
-- IlmThread
- Imath
-+ OpenEXR
-+ IlmThread
- )
-
- SET(_openexr_SEARCH_DIRS
-@@ -120,7 +119,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenEXR DEFAULT_MSG
- IF(OPENEXR_FOUND)
- SET(OPENEXR_LIBRARIES ${_openexr_LIBRARIES})
- # Both include paths are needed because of dummy OSL headers mixing #include <OpenEXR/foo.h> and #include <foo.h> :(
-- SET(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR}/OpenEXR)
-+ SET(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR}/OpenEXR ${OPENEXR_INCLUDE_DIR}/Imath)
- ENDIF()
-
- MARK_AS_ADVANCED(
-diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
-index a254111e489..50aa6d784f6 100644
---- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
-+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
-@@ -37,10 +37,12 @@
- #include <ImfVersion.h>
- #include <ImathBox.h>
- #include <ImfArray.h>
-+#include <ImfFrameBuffer.h>
- #include <ImfIO.h>
- #include <ImfChannelList.h>
- #include <ImfPixelType.h>
- #include <ImfInputFile.h>
-+#include <ImfInt64.h>
- #include <ImfOutputFile.h>
- #include <ImfCompression.h>
- #include <ImfCompressionAttribute.h>
-diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
-index 68eb1652210..679f3deaf8c 100644
---- a/source/blender/alembic/intern/abc_transform.cc
-+++ b/source/blender/alembic/intern/abc_transform.cc
-@@ -16,7 +16,7 @@
-
- #include "abc_transform.h"
-
--#include <OpenEXR/ImathBoxAlgo.h>
-+#include <Imath/ImathBoxAlgo.h>
-
- #include "abc_util.h"
-
diff --git a/openvdb7.patch b/openvdb7.patch
deleted file mode 100644
index 630605a6c353..000000000000
--- a/openvdb7.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-diff --git a/intern/openvdb/CMakeLists.txt b/intern/openvdb/CMakeLists.txt
-index 9ac0817903b..e60d45b7f64 100644
---- a/intern/openvdb/CMakeLists.txt
-+++ b/intern/openvdb/CMakeLists.txt
-@@ -23,6 +23,8 @@
- #
- # ***** END GPL LICENSE BLOCK *****
-
-+set (CMAKE_CXX_STANDARD 14)
-+
- set(INC
- .
- intern
-diff --git a/intern/openvdb/intern/openvdb_writer.cc b/intern/openvdb/intern/openvdb_writer.cc
-index 900c5371682..f209ec758b6 100644
---- a/intern/openvdb/intern/openvdb_writer.cc
-+++ b/intern/openvdb/intern/openvdb_writer.cc
-@@ -39,11 +39,7 @@ void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid)
-
- void OpenVDBWriter::insert(const openvdb::GridBase &grid)
- {
--#if (OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER <= 3) || defined(OPENVDB_3_ABI_COMPATIBLE)
-- m_grids->push_back(grid.copyGrid());
--#else
- m_grids->push_back(grid.copyGridWithNewTree());
--#endif
- }
-
- void OpenVDBWriter::insertFloatMeta(const openvdb::Name &name, const float value)
diff --git a/openvdb8.patch b/openvdb8.patch
deleted file mode 100644
index bb44c7946cdf..000000000000
--- a/openvdb8.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/intern/openvdb/openvdb_util.cc b/intern/openvdb/openvdb_util.cc
-index a221a537851..899b41ff09b 100644
---- a/intern/openvdb/openvdb_util.cc
-+++ b/intern/openvdb/openvdb_util.cc
-@@ -27,5 +27,10 @@ ScopeTimer::ScopeTimer(const std::string &message) : m_message(message), m_timer
-
- ScopeTimer::~ScopeTimer()
- {
-- std::printf("%s: %fms\n", m_message.c_str(), m_timer.delta());
-+#if OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER >= 7
-+ double delta = m_timer.milliseconds();
-+#else
-+ double delta = m_timer.delta(); /* Deprecated in OpenVDB 7. */
-+#endif
-+ std::printf("%s: %fms\n", m_message.c_str(), delta);
- }
diff --git a/python3.7.patch b/python3.7.patch
deleted file mode 100644
index 1b93964aecaf..000000000000
--- a/python3.7.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/object_facemap_auto/auto_fmap_widgets.py b/object_facemap_auto/auto_fmap_widgets.py
-index 5b26f75..646e844 100644
---- a/release/scripts/addons_contrib/object_facemap_auto/auto_fmap_widgets.py
-+++ b/release/scripts/addons_contrib/object_facemap_auto/auto_fmap_widgets.py
-@@ -324,7 +324,7 @@ class AutoFaceMapWidgetGroup(ManipulatorGroup):
-
- # foo;bar=baz;bonzo=bingo --> {"bar": baz", "bonzo": bingo}
- mpr.fmap_target_rules = dict(
-- item.partition("=")[::2] for item in fmap_rules,
-+ item.partition("=")[::2] for item in fmap_rules
- )
-
- # XXX, we might want to have some way to extract a 'center' from a face-map
diff --git a/python3.8.patch b/python3.8.patch
deleted file mode 100644
index ffaa3e2a914b..000000000000
--- a/python3.8.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-From 4b663ecf264020b1d7003a137ce84b06d7ec4ce6 Mon Sep 17 00:00:00 2001
-From: bartus <szczepaniak.bartek+github@gmail.com>
-Date: Sat, 16 Nov 2019 20:29:30 +0100
-Subject: [PATCH] Add python 3.8 support.
-
----
- source/blender/python/generic/py_capi_utils.c | 27 +++++++++++++++----
- 1 file changed, 22 insertions(+), 5 deletions(-)
-
-diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
-index 545e0506f84..a7eab70600b 100644
---- a/source/blender/python/generic/py_capi_utils.c
-+++ b/source/blender/python/generic/py_capi_utils.c
-@@ -696,9 +696,16 @@ PyObject *PyC_UnicodeFromByte(const char *str)
- ****************************************************************************/
- PyObject *PyC_DefaultNameSpace(const char *filename)
- {
-+ #if PY_VERSION_HEX >= 0x03080000
-+ PyObject *modules = PyImport_GetModuleDict();
-+ PyObject *builtins = PyEval_GetBuiltins();
-+ #else
- PyInterpreterState *interp = PyThreadState_GET()->interp;
-+ PyObject *modules = interp->modules;
-+ PyObject *builtins = interp->builtins;
-+ #endif
- PyObject *mod_main = PyModule_New("__main__");
-- PyDict_SetItemString(interp->modules, "__main__", mod_main);
-+ PyDict_SetItemString(modules, "__main__", mod_main);
- Py_DECREF(mod_main); /* sys.modules owns now */
- PyModule_AddStringConstant(mod_main, "__name__", "__main__");
- if (filename) {
-@@ -706,8 +713,8 @@ PyObject *PyC_DefaultNameSpace(const char *filename)
- * note: this wont map to a real file when executing text-blocks and buttons. */
- PyModule_AddObject(mod_main, "__file__", PyC_UnicodeFromByte(filename));
- }
-- PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
-- Py_INCREF(interp->builtins); /* AddObject steals a reference */
-+ PyModule_AddObject(mod_main, "__builtins__", builtins);
-+ Py_INCREF(builtins); /* AddObject steals a reference */
- return PyModule_GetDict(mod_main);
- }
-
-@@ -734,15 +741,25 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[])
- /* restore MUST be called after this */
- void PyC_MainModule_Backup(PyObject **main_mod)
- {
-+ #if PY_VERSION_HEX >= 0x03080000
-+ PyObject *modules = PyImport_GetModuleDict();
-+ #else
- PyInterpreterState *interp = PyThreadState_GET()->interp;
-- *main_mod = PyDict_GetItemString(interp->modules, "__main__");
-+ PyObject *modules = interp->modules;
-+ #endif
-+ *main_mod = PyDict_GetItemString(modules, "__main__");
- Py_XINCREF(*main_mod); /* don't free */
- }
-
- void PyC_MainModule_Restore(PyObject *main_mod)
- {
-+ #if PY_VERSION_HEX >= 0x03080000
-+ PyObject *modules = PyImport_GetModuleDict();
-+ #else
- PyInterpreterState *interp = PyThreadState_GET()->interp;
-- PyDict_SetItemString(interp->modules, "__main__", main_mod);
-+ PyObject *modules = interp->modules;
-+ #endif
-+ PyDict_SetItemString(modules, "__main__", main_mod);
- Py_XDECREF(main_mod);
- }
-
---
-2.24.0
-
diff --git a/python3.9.patch b/python3.9.patch
deleted file mode 100644
index f4d7869d09f3..000000000000
--- a/python3.9.patch
+++ /dev/null
@@ -1,141 +0,0 @@
-diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
-index 19fc05e66ea..5e10baa43ac 100644
---- a/source/blender/python/mathutils/mathutils_Matrix.c
-+++ b/source/blender/python/mathutils/mathutils_Matrix.c
-@@ -43,7 +43,8 @@ static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix);
- static PyObject *Matrix_copy(MatrixObject *self);
- static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args);
- static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
--static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
-+static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
-+ MatrixObject *self);
- static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
-
- static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
-@@ -380,14 +381,15 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- return NULL;
- }
-
--static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
-+static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
-+ MatrixObject *self)
- {
- PyObject *ret = Matrix_copy(self);
- if (ret) {
-- PyObject *ret_dummy = matrix_func(ret);
-+ PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
-- return (PyObject *)ret;
-+ return ret;
- }
- else { /* error */
- Py_DECREF(ret);
-@@ -1593,7 +1595,7 @@ PyDoc_STRVAR(Matrix_adjugated_doc,
- );
- static PyObject *Matrix_adjugated(MatrixObject *self)
- {
-- return matrix__apply_to_copy((PyNoArgsFunction)Matrix_adjugate, self);
-+ return matrix__apply_to_copy(Matrix_adjugate, self);
- }
-
- PyDoc_STRVAR(Matrix_rotate_doc,
-@@ -1799,7 +1801,7 @@ PyDoc_STRVAR(Matrix_transposed_doc,
- );
- static PyObject *Matrix_transposed(MatrixObject *self)
- {
-- return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
-+ return matrix__apply_to_copy(Matrix_transpose, self);
- }
-
- /*---------------------------matrix.normalize() ------------------*/
-@@ -1846,7 +1848,7 @@ PyDoc_STRVAR(Matrix_normalized_doc,
- );
- static PyObject *Matrix_normalized(MatrixObject *self)
- {
-- return matrix__apply_to_copy((PyNoArgsFunction)Matrix_normalize, self);
-+ return matrix__apply_to_copy(Matrix_normalize, self);
- }
-
- /*---------------------------matrix.zero() -----------------------*/
-diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
-index 7255c0028d7..89c448d6413 100644
---- a/source/blender/python/mathutils/mathutils_Quaternion.c
-+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
-@@ -35,7 +35,8 @@
-
- #define QUAT_SIZE 4
-
--static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self);
-+static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
-+ QuaternionObject *self);
- static void quat__axis_angle_sanitize(float axis[3], float *angle);
- static PyObject *Quaternion_copy(QuaternionObject *self);
- static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
-@@ -376,7 +377,7 @@ PyDoc_STRVAR(Quaternion_normalized_doc,
- );
- static PyObject *Quaternion_normalized(QuaternionObject *self)
- {
-- return quat__apply_to_copy((PyNoArgsFunction)Quaternion_normalize, self);
-+ return quat__apply_to_copy(Quaternion_normalize, self);
- }
-
- PyDoc_STRVAR(Quaternion_invert_doc,
-@@ -404,7 +405,7 @@ PyDoc_STRVAR(Quaternion_inverted_doc,
- );
- static PyObject *Quaternion_inverted(QuaternionObject *self)
- {
-- return quat__apply_to_copy((PyNoArgsFunction)Quaternion_invert, self);
-+ return quat__apply_to_copy(Quaternion_invert, self);
- }
-
- PyDoc_STRVAR(Quaternion_identity_doc,
-@@ -468,7 +469,7 @@ PyDoc_STRVAR(Quaternion_conjugated_doc,
- );
- static PyObject *Quaternion_conjugated(QuaternionObject *self)
- {
-- return quat__apply_to_copy((PyNoArgsFunction)Quaternion_conjugate, self);
-+ return quat__apply_to_copy(Quaternion_conjugate, self);
- }
-
- PyDoc_STRVAR(Quaternion_copy_doc,
-@@ -1143,10 +1144,11 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
- return Quaternion_CreatePyObject(quat, type);
- }
-
--static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self)
-+static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
-+ QuaternionObject *self)
- {
- PyObject *ret = Quaternion_copy(self);
-- PyObject *ret_dummy = quat_func(ret);
-+ PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return ret;
-diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
-index b3bba79280d..626eaa6505f 100644
---- a/source/blender/python/mathutils/mathutils_Vector.c
-+++ b/source/blender/python/mathutils/mathutils_Vector.c
-@@ -94,10 +94,10 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- return Vector_CreatePyObject_alloc(vec, size, type);
- }
-
--static PyObject *vec__apply_to_copy(PyNoArgsFunction vec_func, VectorObject *self)
-+static PyObject *vec__apply_to_copy(PyObject *(*vec_func)(VectorObject *), VectorObject *self)
- {
- PyObject *ret = Vector_copy(self);
-- PyObject *ret_dummy = vec_func(ret);
-+ PyObject *ret_dummy = vec_func((VectorObject *)ret);
- if (ret_dummy) {
- Py_DECREF(ret_dummy);
- return (PyObject *)ret;
-@@ -380,7 +380,7 @@ PyDoc_STRVAR(Vector_normalized_doc,
- );
- static PyObject *Vector_normalized(VectorObject *self)
- {
-- return vec__apply_to_copy((PyNoArgsFunction)Vector_normalize, self);
-+ return vec__apply_to_copy(Vector_normalize, self);
- }
-
- PyDoc_STRVAR(Vector_resize_doc,
diff --git a/python3.9_2.patch b/python3.9_2.patch
deleted file mode 100644
index a1de7b401485..000000000000
--- a/python3.9_2.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-diff --git a/source/blender/python/generic/bpy_threads.c b/source/blender/python/generic/bpy_threads.c
-index 5507aa73183..4807c1f5071 100644
---- a/source/blender/python/generic/bpy_threads.c
-+++ b/source/blender/python/generic/bpy_threads.c
-@@ -29,14 +29,11 @@
- /* analogue of PyEval_SaveThread() */
- BPy_ThreadStatePtr BPY_thread_save(void)
- {
-- PyThreadState *tstate = PyThreadState_Swap(NULL);
-- /* note: tstate can be NULL when quitting Blender */
--
-- if (tstate && PyEval_ThreadsInitialized()) {
-- PyEval_ReleaseLock();
-+ /* The thread-state can be NULL when quitting Blender. */
-+ if (_PyThreadState_UncheckedGet()) {
-+ return (BPy_ThreadStatePtr)PyEval_SaveThread();
- }
--
-- return (BPy_ThreadStatePtr)tstate;
-+ return NULL;
- }
-
- /* analogue of PyEval_RestoreThread() */
diff --git a/stl_export_iter.patch b/stl_export_iter.patch
deleted file mode 100644
index edf985e88ca1..000000000000
--- a/stl_export_iter.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/release/scripts/addons/io_mesh_stl/blender_utils.py b/release/scripts/addons/io_mesh_stl/blender_utils.py
-index 864335ab..c74853db 100644
---- a/release/scripts/addons/io_mesh_stl/blender_utils.py
-+++ b/release/scripts/addons/io_mesh_stl/blender_utils.py
-@@ -86,7 +86,7 @@ def faces_from_mesh(ob, global_matrix, use_mesh_modifiers=False, triangulate=Tru
- try:
- mesh = ob.to_mesh(bpy.context.scene, use_mesh_modifiers, "PREVIEW")
- except RuntimeError:
-- raise StopIteration
-+ return
-
- mat = global_matrix * ob.matrix_world
- mesh.transform(mat)