pylibvpx 1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pylibvpx-1.0/.cmake-format.yaml +10 -0
- pylibvpx-1.0/CMakeLists.txt +70 -0
- pylibvpx-1.0/LICENSE +21 -0
- pylibvpx-1.0/PKG-INFO +12 -0
- pylibvpx-1.0/README.md +2 -0
- pylibvpx-1.0/pylibvpx.cpp +97 -0
- pylibvpx-1.0/pylibvpx.egg-info/PKG-INFO +12 -0
- pylibvpx-1.0/pylibvpx.egg-info/SOURCES.txt +17 -0
- pylibvpx-1.0/pylibvpx.egg-info/dependency_links.txt +1 -0
- pylibvpx-1.0/pylibvpx.egg-info/top_level.txt +1 -0
- pylibvpx-1.0/pyproject.toml +3 -0
- pylibvpx-1.0/setup.cfg +4 -0
- pylibvpx-1.0/setup.py +24 -0
- pylibvpx-1.0/vpxcommon.hpp +18 -0
- pylibvpx-1.0/vpxcommon_impl.hpp +57 -0
- pylibvpx-1.0/vpxdecoder.cpp +75 -0
- pylibvpx-1.0/vpxdecoder.hpp +25 -0
- pylibvpx-1.0/vpxencoder.cpp +116 -0
- pylibvpx-1.0/vpxencoder.hpp +39 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.16)
|
|
2
|
+
project(pylibvpx LANGUAGES CXX VERSION "1.0")
|
|
3
|
+
|
|
4
|
+
# Default to Release build type
|
|
5
|
+
if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
|
|
6
|
+
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
|
|
7
|
+
endif()
|
|
8
|
+
|
|
9
|
+
# Fetch conan.cmake
|
|
10
|
+
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
|
|
11
|
+
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
|
|
12
|
+
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
|
|
13
|
+
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
|
|
14
|
+
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/0.18.1/conan.cmake"
|
|
15
|
+
"${CMAKE_BINARY_DIR}/conan.cmake" TLS_VERIFY ON)
|
|
16
|
+
endif()
|
|
17
|
+
include(${CMAKE_BINARY_DIR}/conan.cmake)
|
|
18
|
+
|
|
19
|
+
# Get pybind11 and libvpx from conan
|
|
20
|
+
conan_cmake_configure(
|
|
21
|
+
REQUIRES pybind11/2.10.4 libvpx/1.11.0
|
|
22
|
+
GENERATORS cmake_find_package
|
|
23
|
+
)
|
|
24
|
+
conan_cmake_autodetect(settings)
|
|
25
|
+
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
26
|
+
# MSVC 2022 can't build libvpx -> donwload binary for MSVC 2019
|
|
27
|
+
list(APPEND settings "libvpx:compiler.version=16")
|
|
28
|
+
endif()
|
|
29
|
+
conan_cmake_install(
|
|
30
|
+
PATH_OR_REFERENCE .
|
|
31
|
+
BUILD missing
|
|
32
|
+
REMOTE conancenter
|
|
33
|
+
SETTINGS ${settings}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Create libvpx python library
|
|
37
|
+
find_package(pybind11 REQUIRED)
|
|
38
|
+
find_package(libvpx REQUIRED)
|
|
39
|
+
pybind11_add_module(${PROJECT_NAME} "pylibvpx.cpp" "vpxcommon.hpp" "vpxcommon_impl.hpp")
|
|
40
|
+
set_target_properties(${PROJECT_NAME} PROPERTIES
|
|
41
|
+
CXX_STANDARD 20
|
|
42
|
+
CXX_STANDARD_REQUIRED ON
|
|
43
|
+
)
|
|
44
|
+
target_link_libraries(${PROJECT_NAME} PRIVATE libvpx::libvpx)
|
|
45
|
+
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
|
46
|
+
MODULE_NAME=${PROJECT_NAME}
|
|
47
|
+
MODULE_VERSION=${PROJECT_VERSION}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
option(WITH_VPX_ENCODER "With vpx encoder" ON)
|
|
51
|
+
if(WITH_VPX_ENCODER)
|
|
52
|
+
message(STATUS "With VPX encoder")
|
|
53
|
+
target_sources(${PROJECT_NAME} PRIVATE "vpxencoder.hpp" "vpxencoder.cpp")
|
|
54
|
+
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_VPX_ENCODER=1)
|
|
55
|
+
endif()
|
|
56
|
+
|
|
57
|
+
option(WITH_VPX_DECODER "With vpx decoder" ON)
|
|
58
|
+
if(WITH_VPX_DECODER)
|
|
59
|
+
message(STATUS "With VPX decoder")
|
|
60
|
+
target_sources(${PROJECT_NAME} PRIVATE "vpxdecoder.hpp" "vpxdecoder.cpp")
|
|
61
|
+
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_VPX_DECODER=1)
|
|
62
|
+
endif()
|
|
63
|
+
|
|
64
|
+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|
65
|
+
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic)
|
|
66
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
67
|
+
target_compile_options(${PROJECT_NAME} PUBLIC "/Zc:__cplusplus")
|
|
68
|
+
endif()
|
|
69
|
+
|
|
70
|
+
install(TARGETS ${PROJECT_NAME} DESTINATION ".")
|
pylibvpx-1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Peter Würtz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pylibvpx-1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pylibvpx
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Python bindings for libvpx
|
|
5
|
+
Home-page: https://github.com/pwuertz/libvpx-bindings
|
|
6
|
+
Author: Peter Würtz
|
|
7
|
+
Author-email: pwuertz@gmail.com
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
|
|
11
|
+
# Python `libvpx` bindings
|
|
12
|
+
Python bindings for VPX encoding/decoding library
|
pylibvpx-1.0/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#include <Python.h>
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
#include <pybind11/pytypes.h>
|
|
4
|
+
#include <pybind11/numpy.h>
|
|
5
|
+
#include "vpxcommon.hpp"
|
|
6
|
+
#ifdef WITH_VPX_ENCODER
|
|
7
|
+
#include "vpxencoder.hpp"
|
|
8
|
+
#endif
|
|
9
|
+
#ifdef WITH_VPX_DECODER
|
|
10
|
+
#include "vpxdecoder.hpp"
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
#include <string_view>
|
|
14
|
+
#include <iostream>
|
|
15
|
+
|
|
16
|
+
namespace py = pybind11;
|
|
17
|
+
|
|
18
|
+
constexpr std::string_view VERSION_STR = PYBIND11_TOSTRING(MODULE_VERSION);
|
|
19
|
+
|
|
20
|
+
#ifdef WITH_VPX_ENCODER
|
|
21
|
+
void py_vpxe_encode(Vpx::Encoder& encoder, const py::object& fn)
|
|
22
|
+
{
|
|
23
|
+
const auto packetHandler = [&](const uint8_t* packet, const size_t size) {
|
|
24
|
+
fn(py::memoryview::from_memory(packet, size));
|
|
25
|
+
};
|
|
26
|
+
encoder.encode(packetHandler);
|
|
27
|
+
}
|
|
28
|
+
py::array_t<uint8_t, py::array::c_style> py_vpxe_yplane(Vpx::Encoder& encoder)
|
|
29
|
+
{
|
|
30
|
+
const Vpx::Plane plane = encoder.yPlane();
|
|
31
|
+
return py::array_t<uint8_t, py::array::c_style>(
|
|
32
|
+
std::vector<Py_ssize_t>{plane.height, plane.width},
|
|
33
|
+
std::vector<Py_ssize_t>{plane.stride, 1},
|
|
34
|
+
plane.data
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
void py_vpxe_copygray(Vpx::Encoder& encoder, const py::array& image)
|
|
38
|
+
{
|
|
39
|
+
const auto* imageData = static_cast<const uint8_t*>(image.data());
|
|
40
|
+
encoder.copyFromGray(imageData);
|
|
41
|
+
}
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
#ifdef WITH_VPX_DECODER
|
|
45
|
+
void py_vpxd_decode(Vpx::Decoder& decoder, const py::bytes& packet, const py::object& fn)
|
|
46
|
+
{
|
|
47
|
+
uint8_t* data; Py_ssize_t size;
|
|
48
|
+
PyBytes_AsStringAndSize(packet.ptr(), reinterpret_cast<char**>(&data), &size);
|
|
49
|
+
const auto frameHandler = [&](const Vpx::Plane& plane) {
|
|
50
|
+
py::array_t<uint8_t, py::array::c_style> img(
|
|
51
|
+
std::vector<Py_ssize_t>{plane.height, plane.width},
|
|
52
|
+
std::vector<Py_ssize_t>{plane.stride, 1},
|
|
53
|
+
plane.data
|
|
54
|
+
);
|
|
55
|
+
fn(img);
|
|
56
|
+
};
|
|
57
|
+
decoder.decode(data, static_cast<size_t>(size), frameHandler);
|
|
58
|
+
}
|
|
59
|
+
#endif
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
PYBIND11_MODULE(MODULE_NAME, m) {
|
|
63
|
+
m.attr("__version__") = py::str(VERSION_STR.data(), VERSION_STR.size());
|
|
64
|
+
|
|
65
|
+
py::enum_<Vpx::Gen>(m, "VpxGen")
|
|
66
|
+
.value("Vp8", Vpx::Gen::Vp8)
|
|
67
|
+
.value("Vp9", Vpx::Gen::Vp9);
|
|
68
|
+
|
|
69
|
+
#ifdef WITH_VPX_ENCODER
|
|
70
|
+
py::class_<Vpx::Encoder> vpxencCls(m, "VpxEncoder");
|
|
71
|
+
vpxencCls.def(py::init<const Vpx::Encoder::Config&>())
|
|
72
|
+
.def(py::init([](const unsigned int width, const unsigned int height) {
|
|
73
|
+
return new Vpx::Encoder({.width = width, .height = height});
|
|
74
|
+
}))
|
|
75
|
+
.def("encode", py_vpxe_encode)
|
|
76
|
+
.def("yPlane", py_vpxe_yplane)
|
|
77
|
+
.def("copyGray", py_vpxe_copygray);
|
|
78
|
+
|
|
79
|
+
py::class_<Vpx::Encoder::Config>(vpxencCls, "Config")
|
|
80
|
+
.def(py::init([](const unsigned int width, const unsigned int height) {
|
|
81
|
+
return new Vpx::Encoder::Config { .width=width, .height=height };
|
|
82
|
+
}))
|
|
83
|
+
.def_readwrite("width", &Vpx::Encoder::Config::width)
|
|
84
|
+
.def_readwrite("height", &Vpx::Encoder::Config::height)
|
|
85
|
+
.def_readwrite("fps", &Vpx::Encoder::Config::fps)
|
|
86
|
+
.def_readwrite("bitrate", &Vpx::Encoder::Config::bitrate)
|
|
87
|
+
.def_readwrite("threads", &Vpx::Encoder::Config::threads)
|
|
88
|
+
.def_readwrite("cpu_used", &Vpx::Encoder::Config::cpu_used)
|
|
89
|
+
.def_readwrite("gen", &Vpx::Encoder::Config::gen);
|
|
90
|
+
#endif
|
|
91
|
+
|
|
92
|
+
#ifdef WITH_VPX_DECODER
|
|
93
|
+
py::class_<Vpx::Decoder> vpxdecCls(m, "VpxDecoder");
|
|
94
|
+
vpxdecCls.def(py::init<Vpx::Gen>())
|
|
95
|
+
.def("decode", py_vpxd_decode);
|
|
96
|
+
#endif
|
|
97
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pylibvpx
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Python bindings for libvpx
|
|
5
|
+
Home-page: https://github.com/pwuertz/libvpx-bindings
|
|
6
|
+
Author: Peter Würtz
|
|
7
|
+
Author-email: pwuertz@gmail.com
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
|
|
11
|
+
# Python `libvpx` bindings
|
|
12
|
+
Python bindings for VPX encoding/decoding library
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.cmake-format.yaml
|
|
2
|
+
CMakeLists.txt
|
|
3
|
+
LICENSE
|
|
4
|
+
README.md
|
|
5
|
+
pylibvpx.cpp
|
|
6
|
+
pyproject.toml
|
|
7
|
+
setup.py
|
|
8
|
+
vpxcommon.hpp
|
|
9
|
+
vpxcommon_impl.hpp
|
|
10
|
+
vpxdecoder.cpp
|
|
11
|
+
vpxdecoder.hpp
|
|
12
|
+
vpxencoder.cpp
|
|
13
|
+
vpxencoder.hpp
|
|
14
|
+
pylibvpx.egg-info/PKG-INFO
|
|
15
|
+
pylibvpx.egg-info/SOURCES.txt
|
|
16
|
+
pylibvpx.egg-info/dependency_links.txt
|
|
17
|
+
pylibvpx.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pylibvpx
|
pylibvpx-1.0/setup.cfg
ADDED
pylibvpx-1.0/setup.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
from setuptools import setup
|
|
3
|
+
from cmake_build_extension import BuildExtension, CMakeExtension
|
|
4
|
+
|
|
5
|
+
this_directory = pathlib.Path(__file__).parent
|
|
6
|
+
long_description = (this_directory / "README.md").read_text()
|
|
7
|
+
long_description_content_type="text/markdown"
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name="pylibvpx",
|
|
11
|
+
version="1.0",
|
|
12
|
+
author="Peter Würtz",
|
|
13
|
+
author_email="pwuertz@gmail.com",
|
|
14
|
+
url="https://github.com/pwuertz/libvpx-bindings",
|
|
15
|
+
description="Python bindings for libvpx",
|
|
16
|
+
long_description=long_description,
|
|
17
|
+
long_description_content_type=long_description_content_type,
|
|
18
|
+
ext_modules=[CMakeExtension(
|
|
19
|
+
name="pylibvpx",
|
|
20
|
+
source_dir=".",
|
|
21
|
+
install_prefix=".",
|
|
22
|
+
)],
|
|
23
|
+
cmdclass=dict(build_ext=BuildExtension),
|
|
24
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <algorithm>
|
|
3
|
+
#include <stdexcept>
|
|
4
|
+
#include <vpx/vpx_image.h>
|
|
5
|
+
#include "vpxcommon.hpp"
|
|
6
|
+
|
|
7
|
+
namespace Vpx {
|
|
8
|
+
|
|
9
|
+
struct Image
|
|
10
|
+
{
|
|
11
|
+
Image(const unsigned int width, const unsigned int height)
|
|
12
|
+
{
|
|
13
|
+
if (vpx_img_alloc(&m_img, VPX_IMG_FMT_I420, width, height, 1) == nullptr) {
|
|
14
|
+
throw std::runtime_error("Failed to allocate image");
|
|
15
|
+
}
|
|
16
|
+
fillBlack();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Image(const Image&) = delete;
|
|
20
|
+
void operator=(const Image&) = delete;
|
|
21
|
+
|
|
22
|
+
~Image() noexcept { vpx_img_free(&m_img); }
|
|
23
|
+
|
|
24
|
+
constexpr operator vpx_image_t*() noexcept { return &m_img; }
|
|
25
|
+
constexpr operator const vpx_image_t*() const noexcept { return &m_img; }
|
|
26
|
+
|
|
27
|
+
void fillBlack() noexcept
|
|
28
|
+
{
|
|
29
|
+
std::fill_n(m_img.planes[VPX_PLANE_Y], m_img.w * m_img.h, 0);
|
|
30
|
+
std::fill_n(m_img.planes[VPX_PLANE_U], m_img.w * m_img.h / 4, 128);
|
|
31
|
+
std::fill_n(m_img.planes[VPX_PLANE_V], m_img.w * m_img.h / 4, 128);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
constexpr Plane yPlane() const noexcept
|
|
35
|
+
{
|
|
36
|
+
return {
|
|
37
|
+
.data = m_img.planes[VPX_PLANE_Y],
|
|
38
|
+
.height = m_img.d_h, .width = m_img.d_w,
|
|
39
|
+
.stride = m_img.stride[0]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void copyFromGrayscale(const uint8_t* src)
|
|
44
|
+
{
|
|
45
|
+
const auto yPlane = this->yPlane();
|
|
46
|
+
for (unsigned int row = 0; row < yPlane.height; ++row) {
|
|
47
|
+
const auto* srcRow = src + row * yPlane.width;
|
|
48
|
+
auto* dstRow = yPlane.data + row * yPlane.stride;
|
|
49
|
+
std::copy_n(srcRow, yPlane.width, dstRow);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
vpx_image_t m_img;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
} // namespace Vpx
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#include "vpxdecoder.hpp"
|
|
2
|
+
#include "vpxcommon_impl.hpp"
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <stdexcept>
|
|
5
|
+
#include <vpx/vpx_decoder.h>
|
|
6
|
+
#include <vpx/vp8dx.h>
|
|
7
|
+
|
|
8
|
+
using namespace Vpx;
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
constexpr vpx_codec_iface_t* decoder_vp8 = &vpx_codec_vp8_dx_algo;
|
|
13
|
+
constexpr vpx_codec_iface_t* decoder_vp9 = &vpx_codec_vp9_dx_algo;
|
|
14
|
+
|
|
15
|
+
struct DecCtx
|
|
16
|
+
{
|
|
17
|
+
DecCtx(const Gen gen)
|
|
18
|
+
{
|
|
19
|
+
// Create decoder context
|
|
20
|
+
const auto* decoder_iface = (gen == Gen::Vp8) ? decoder_vp8 : decoder_vp9;
|
|
21
|
+
if (vpx_codec_dec_init(&m_ctx, decoder_iface, nullptr, 0) != VPX_CODEC_OK) {
|
|
22
|
+
throw std::runtime_error("Failed to create decoding context");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
DecCtx(const DecCtx&) = delete;
|
|
27
|
+
void operator=(const DecCtx&) = delete;
|
|
28
|
+
|
|
29
|
+
~DecCtx() noexcept { vpx_codec_destroy(&m_ctx); }
|
|
30
|
+
|
|
31
|
+
constexpr operator vpx_codec_ctx_t*() noexcept { return &m_ctx; }
|
|
32
|
+
constexpr operator const vpx_codec_ctx_t*() const noexcept { return &m_ctx; }
|
|
33
|
+
|
|
34
|
+
private:
|
|
35
|
+
vpx_codec_ctx_t m_ctx;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
} // private namespace
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
struct Decoder::Ctx {
|
|
42
|
+
Ctx(const Gen gen) : m_ctx(gen) { }
|
|
43
|
+
|
|
44
|
+
template<typename Fn> void decode(const uint8_t* data, const size_t size, Fn&& fn)
|
|
45
|
+
{
|
|
46
|
+
constexpr auto VPX_DL_REALTIME = 1;
|
|
47
|
+
if (vpx_codec_decode(m_ctx, data, size, nullptr, VPX_DL_REALTIME) != VPX_CODEC_OK) {
|
|
48
|
+
throw std::runtime_error("Failed to decode packet");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
vpx_codec_iter_t iter = nullptr;
|
|
52
|
+
vpx_image* img = nullptr;
|
|
53
|
+
while ((img = vpx_codec_get_frame(m_ctx, &iter)) != nullptr) {
|
|
54
|
+
fn(Plane {
|
|
55
|
+
.data = img->planes[VPX_PLANE_Y],
|
|
56
|
+
.height = img->d_h, .width = img->d_w,
|
|
57
|
+
.stride = img->stride[0]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private:
|
|
63
|
+
DecCtx m_ctx;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
Decoder::Decoder(const Gen gen)
|
|
67
|
+
: ctx(std::make_unique<Ctx>(gen))
|
|
68
|
+
{ }
|
|
69
|
+
|
|
70
|
+
Decoder::~Decoder() = default;
|
|
71
|
+
|
|
72
|
+
void Decoder::decode(const uint8_t* packet, size_t size, const frame_handler_t& fn)
|
|
73
|
+
{
|
|
74
|
+
ctx->decode(packet, size, fn);
|
|
75
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <memory>
|
|
3
|
+
#include <cstdint>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include "vpxcommon.hpp"
|
|
6
|
+
|
|
7
|
+
namespace Vpx {
|
|
8
|
+
|
|
9
|
+
struct Decoder
|
|
10
|
+
{
|
|
11
|
+
private:
|
|
12
|
+
struct Ctx;
|
|
13
|
+
|
|
14
|
+
public:
|
|
15
|
+
Decoder(Gen gen = Gen::Vp8);
|
|
16
|
+
~Decoder();
|
|
17
|
+
|
|
18
|
+
using frame_handler_t = std::function<void(const Plane&)>;
|
|
19
|
+
void decode(const uint8_t* packet, size_t size, const frame_handler_t& fn);
|
|
20
|
+
|
|
21
|
+
private:
|
|
22
|
+
std::unique_ptr<Ctx> ctx;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
} // namespace Vpx
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#include "vpxencoder.hpp"
|
|
2
|
+
#include "vpxcommon_impl.hpp"
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <vpx/vpx_encoder.h>
|
|
5
|
+
#include <vpx/vp8cx.h>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
|
|
8
|
+
using namespace Vpx;
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
constexpr vpx_codec_iface_t* encoder_vp8 = &vpx_codec_vp8_cx_algo;
|
|
13
|
+
constexpr vpx_codec_iface_t* encoder_vp9 = &vpx_codec_vp9_cx_algo;
|
|
14
|
+
|
|
15
|
+
struct EncCtx
|
|
16
|
+
{
|
|
17
|
+
EncCtx(const Encoder::Config& config)
|
|
18
|
+
{
|
|
19
|
+
// Encoder config from defaults + provided settings
|
|
20
|
+
vpx_codec_enc_cfg_t cfg;
|
|
21
|
+
const auto* encoder_iface = (config.gen == Gen::Vp8) ? encoder_vp8 : encoder_vp9;
|
|
22
|
+
if (vpx_codec_enc_config_default(encoder_iface, &cfg, 0) != VPX_CODEC_OK) {
|
|
23
|
+
throw std::runtime_error("Failed to get default codec config");
|
|
24
|
+
}
|
|
25
|
+
cfg.g_w = config.width;
|
|
26
|
+
cfg.g_h = config.height;
|
|
27
|
+
cfg.g_timebase.num = 1;
|
|
28
|
+
cfg.g_timebase.den = config.fps;
|
|
29
|
+
cfg.rc_target_bitrate = config.bitrate;
|
|
30
|
+
cfg.g_error_resilient = 0;
|
|
31
|
+
cfg.g_threads = config.threads;
|
|
32
|
+
// Create encoder context
|
|
33
|
+
constexpr auto use_flags = 0;
|
|
34
|
+
if (vpx_codec_enc_init(&m_ctx, encoder_iface, &cfg, use_flags) != VPX_CODEC_OK) {
|
|
35
|
+
throw std::runtime_error("Failed to create encoding context");
|
|
36
|
+
}
|
|
37
|
+
// Set codec parameters (destroy ctx on fail)
|
|
38
|
+
try {
|
|
39
|
+
if (vpx_codec_control(&m_ctx, VP8E_SET_CPUUSED, config.cpu_used) != VPX_CODEC_OK) {
|
|
40
|
+
throw std::runtime_error("Failed to set CPUUSED parameter");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch(...) {
|
|
44
|
+
vpx_codec_destroy(&m_ctx);
|
|
45
|
+
throw;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
EncCtx(const EncCtx&) = delete;
|
|
50
|
+
void operator=(const EncCtx&) = delete;
|
|
51
|
+
|
|
52
|
+
~EncCtx() noexcept { vpx_codec_destroy(&m_ctx); }
|
|
53
|
+
|
|
54
|
+
constexpr operator vpx_codec_ctx_t*() noexcept { return &m_ctx; }
|
|
55
|
+
constexpr operator const vpx_codec_ctx_t*() const noexcept { return &m_ctx; }
|
|
56
|
+
|
|
57
|
+
private:
|
|
58
|
+
vpx_codec_ctx_t m_ctx;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
} // private namespace
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
struct Encoder::Ctx {
|
|
65
|
+
Ctx(const Encoder::Config& config)
|
|
66
|
+
: m_img(config.width, config.height)
|
|
67
|
+
, m_ctx(config)
|
|
68
|
+
{ }
|
|
69
|
+
|
|
70
|
+
constexpr Vpx::Image& frame() noexcept { return m_img; }
|
|
71
|
+
constexpr const Vpx::Image& frame() const noexcept { return m_img; }
|
|
72
|
+
|
|
73
|
+
constexpr const auto frameIdx() const noexcept { return m_frameIdx; }
|
|
74
|
+
|
|
75
|
+
template<typename Fn> void encode(Fn&& fn)
|
|
76
|
+
{
|
|
77
|
+
constexpr vpx_enc_frame_flags_t flags = 0;
|
|
78
|
+
if (vpx_codec_encode(m_ctx, m_img, ++m_frameIdx, 1, flags, VPX_DL_REALTIME) != VPX_CODEC_OK) {
|
|
79
|
+
throw std::runtime_error("Failed to encode frame");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
vpx_codec_iter_t iter = nullptr;
|
|
83
|
+
const vpx_codec_cx_pkt_t *pkt = nullptr;
|
|
84
|
+
while ((pkt = vpx_codec_get_cx_data(m_ctx, &iter)) != nullptr) {
|
|
85
|
+
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
|
86
|
+
fn(static_cast<const uint8_t*>(pkt->data.raw.buf), pkt->data.raw.sz);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private:
|
|
92
|
+
unsigned int m_frameIdx = 0;
|
|
93
|
+
Vpx::Image m_img;
|
|
94
|
+
EncCtx m_ctx;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
Encoder::Encoder(const Config& config)
|
|
98
|
+
: ctx(std::make_unique<Ctx>(config))
|
|
99
|
+
{ }
|
|
100
|
+
|
|
101
|
+
Encoder::~Encoder() = default;
|
|
102
|
+
|
|
103
|
+
void Encoder::encode(const packet_handler_t& fn)
|
|
104
|
+
{
|
|
105
|
+
ctx->encode(fn);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Plane Encoder::yPlane() const noexcept
|
|
109
|
+
{
|
|
110
|
+
return ctx->frame().yPlane();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void Encoder::copyFromGray(const uint8_t* data)
|
|
114
|
+
{
|
|
115
|
+
ctx->frame().copyFromGrayscale(data);
|
|
116
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <memory>
|
|
3
|
+
#include <cstdint>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include "vpxcommon.hpp"
|
|
6
|
+
|
|
7
|
+
namespace Vpx {
|
|
8
|
+
|
|
9
|
+
struct Encoder
|
|
10
|
+
{
|
|
11
|
+
private:
|
|
12
|
+
struct Ctx;
|
|
13
|
+
|
|
14
|
+
public:
|
|
15
|
+
struct Config {
|
|
16
|
+
unsigned int width;
|
|
17
|
+
unsigned int height;
|
|
18
|
+
unsigned int fps = 30;
|
|
19
|
+
unsigned int bitrate = 3000;
|
|
20
|
+
unsigned int threads = 0;
|
|
21
|
+
int cpu_used = 16;
|
|
22
|
+
Gen gen = Gen::Vp8;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
Encoder(const Config& config);
|
|
26
|
+
~Encoder();
|
|
27
|
+
|
|
28
|
+
Plane yPlane() const noexcept;
|
|
29
|
+
|
|
30
|
+
void copyFromGray(const uint8_t* data);
|
|
31
|
+
|
|
32
|
+
using packet_handler_t = std::function<void(const uint8_t*, size_t)>;
|
|
33
|
+
void encode(const packet_handler_t& fn);
|
|
34
|
+
|
|
35
|
+
private:
|
|
36
|
+
std::unique_ptr<Ctx> ctx;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
} // namespace Vpx
|