diff --git a/YUViewLib/externalLibs/LibFFmpeg++/Decoder.cpp b/YUViewLib/externalLibs/LibFFmpeg++/Decoder.cpp new file mode 100644 index 000000000..c7c413688 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/Decoder.cpp @@ -0,0 +1,43 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Decoder.h" + +namespace LibFFmpeg +{ + +Decoder::Decoder(std::shared_ptr libraries) +{ + this->libraries = libraries; +} + +} // namespace LibFFmpeg \ No newline at end of file diff --git a/YUViewLib/externalLibs/LibFFmpeg++/Decoder.h b/YUViewLib/externalLibs/LibFFmpeg++/Decoder.h new file mode 100644 index 000000000..bd3e16f72 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/Decoder.h @@ -0,0 +1,49 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +namespace LibFFmpeg +{ + +class Decoder +{ +public: + Decoder(std::shared_ptr libraries); + +private: + std::shared_ptr libraries; +}; + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/Demuxer.cpp b/YUViewLib/externalLibs/LibFFmpeg++/Demuxer.cpp new file mode 100644 index 000000000..ed9fbf158 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/Demuxer.cpp @@ -0,0 +1,43 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Demuxer.h" + +namespace LibFFmpeg +{ + +Demuxer::Demuxer(std::shared_ptr libraries) +{ + this->libraries = libraries; +} + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/Demuxer.h b/YUViewLib/externalLibs/LibFFmpeg++/Demuxer.h new file mode 100644 index 000000000..eb0f62e3f --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/Demuxer.h @@ -0,0 +1,49 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +namespace LibFFmpeg +{ + +class Demuxer +{ +public: + Demuxer(std::shared_ptr libraries); + +private: + std::shared_ptr libraries; +}; + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/LibFFmpeg.h b/YUViewLib/externalLibs/LibFFmpeg++/LibFFmpeg.h new file mode 100644 index 000000000..c204321c8 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/LibFFmpeg.h @@ -0,0 +1,44 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace LibFFmpeg +{ + +// Demuxer openFileForParsing(); + +// Decoder createPacketDecoder(); + +// Check if a path contains usable ffmpeg libraries + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/common/Expected.h b/YUViewLib/externalLibs/LibFFmpeg++/common/Expected.h new file mode 100644 index 000000000..afee404d4 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/common/Expected.h @@ -0,0 +1,2444 @@ +/// +// expected - An implementation of std::expected with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at http://tl.tartanllama.xyz/ +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// . +/// + +#ifndef TL_EXPECTED_HPP +#define TL_EXPECTED_HPP + +#define TL_EXPECTED_VERSION_MAJOR 1 +#define TL_EXPECTED_VERSION_MINOR 1 +#define TL_EXPECTED_VERSION_PATCH 0 + +#include +#include +#include +#include + +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define TL_EXPECTED_EXCEPTIONS_ENABLED +#endif + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_EXPECTED_MSVC2015 +#define TL_EXPECTED_MSVC2015_CONSTEXPR +#else +#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC55 +#endif + +#if !defined(TL_ASSERT) +//can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug +#if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49) +#include +#define TL_ASSERT(x) assert(x) +#else +#define TL_ASSERT(x) +#endif +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions + +#define TL_EXPECTED_NO_CONSTRR +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::has_trivial_copy_assign + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks +// std::vector for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { +namespace detail { +template +struct is_trivially_copy_constructible + : std::is_trivially_copy_constructible {}; +#ifdef _GLIBCXX_VECTOR +template +struct is_trivially_copy_constructible> : std::false_type {}; +#endif +} // namespace detail +} // namespace tl +#endif + +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#else +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#endif + +#if __cplusplus > 201103L +#define TL_EXPECTED_CXX14 +#endif + +#ifdef TL_EXPECTED_GCC49 +#define TL_EXPECTED_GCC49_CONSTEXPR +#else +#define TL_EXPECTED_GCC49_CONSTEXPR constexpr +#endif + +#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \ + defined(TL_EXPECTED_GCC49)) +#define TL_EXPECTED_11_CONSTEXPR +#else +#define TL_EXPECTED_11_CONSTEXPR constexpr +#endif + +namespace tl { +template class expected; + +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +class monostate {}; + +struct in_place_t { + explicit in_place_t() = default; +}; +static constexpr in_place_t in_place{}; +#endif + +template class unexpected { +public: + static_assert(!std::is_same::value, "E must not be void"); + + unexpected() = delete; + constexpr explicit unexpected(const E &e) : m_val(e) {} + + constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} + + template ::value>::type * = nullptr> + constexpr explicit unexpected(Args &&...args) + : m_val(std::forward(args)...) {} + template < + class U, class... Args, + typename std::enable_if &, Args &&...>::value>::type * = nullptr> + constexpr explicit unexpected(std::initializer_list l, Args &&...args) + : m_val(l, std::forward(args)...) {} + + constexpr const E &value() const & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); } + constexpr const E &&value() const && { return std::move(m_val); } + +private: + E m_val; +}; + +#ifdef __cpp_deduction_guides +template unexpected(E) -> unexpected; +#endif + +template +constexpr bool operator==(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() == rhs.value(); +} +template +constexpr bool operator!=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() != rhs.value(); +} +template +constexpr bool operator<(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() < rhs.value(); +} +template +constexpr bool operator<=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() <= rhs.value(); +} +template +constexpr bool operator>(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() > rhs.value(); +} +template +constexpr bool operator>=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() >= rhs.value(); +} + +template +unexpected::type> make_unexpected(E &&e) { + return unexpected::type>(std::forward(e)); +} + +struct unexpect_t { + unexpect_t() = default; +}; +static constexpr unexpect_t unexpect{}; + +namespace detail { +template +[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) { +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + throw std::forward(e); +#else + (void)e; +#ifdef _MSC_VER + __assume(0); +#else + __builtin_unreachable(); +#endif +#endif +} + +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX +// C++14-style aliases for brevity +template using remove_const_t = typename std::remove_const::type; +template +using remove_reference_t = typename std::remove_reference::type; +template using decay_t = typename std::decay::type; +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; + +// std::conjunction from C++17 +template struct conjunction : std::true_type {}; +template struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template +struct is_pointer_to_non_const_member_func : std::false_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; + +template struct is_const_or_const_ref : std::false_type {}; +template struct is_const_or_const_ref : std::true_type {}; +template struct is_const_or_const_ref : std::true_type {}; +#endif + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template < + typename Fn, typename... Args, +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t::value && + is_const_or_const_ref::value)>, +#endif + typename = enable_if_t>::value>, int = 0> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} + +template >::value>> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} + +// std::invoke_result from C++17 +template struct invoke_result_impl; + +template +struct invoke_result_impl< + F, + decltype(detail::invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = + decltype(detail::invoke(std::declval(), std::declval()...)); +}; + +template +using invoke_result = invoke_result_impl; + +template +using invoke_result_t = typename invoke_result::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template struct is_swappable : std::true_type {}; + +template struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template tag swap(T &, T &); +template tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); + +template std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); + +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; + +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; + +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std( + 0))::value || + is_swappable::value)> {}; + +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> {}; +#endif +#endif + +// Trait for checking if a type is a tl::expected +template struct is_expected_impl : std::false_type {}; +template +struct is_expected_impl> : std::true_type {}; +template using is_expected = is_expected_impl>; + +template +using expected_enable_forward_value = detail::enable_if_t< + std::is_constructible::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value && + !std::is_same, detail::decay_t>::value>; + +template +using expected_enable_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; + +template +using is_void_or = conditional_t::value, std::true_type, U>; + +template +using is_copy_constructible_or_void = + is_void_or>; + +template +using is_move_constructible_or_void = + is_void_or>; + +template +using is_copy_assignable_or_void = is_void_or>; + +template +using is_move_assignable_or_void = is_void_or>; + +} // namespace detail + +namespace detail { +struct no_init_t {}; +static constexpr no_init_t no_init{}; + +// Implements the storage of the values, and ensures that the destructor is +// trivial if it can be. +// +// This specialization is for where neither `T` or `E` is trivially +// destructible, so the destructors must be called on destruction of the +// `expected` +template ::value, + bool = std::is_trivially_destructible::value> +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } else { + m_unexpect.~unexpected(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// This specialization is for when both `T` and `E` are trivially-destructible, +// so the destructor of the `expected` can be trivial. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() = default; + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// T is trivial, E is not. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) + : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// E is trivial, T is not. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is trivially-destructible +template struct expected_storage_base { + #if __GNUC__ <= 5 + //no constexpr for GCC 4/5 bug + #else + TL_EXPECTED_MSVC2015_CONSTEXPR + #endif + expected_storage_base() : m_has_val(true) {} + + constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_has_val(true) {} + + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() = default; + struct dummy {}; + union { + unexpected m_unexpect; + dummy m_val; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is not trivially-destructible +template struct expected_storage_base { + constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} + + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + unexpected m_unexpect; + char m_dummy; + }; + bool m_has_val; +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template void construct(Args &&...args) noexcept { + new (std::addressof(this->m_val)) T(std::forward(args)...); + this->m_has_val = true; + } + + template void construct_with(Rhs &&rhs) noexcept { + new (std::addressof(this->m_val)) T(std::forward(rhs).get()); + this->m_has_val = true; + } + + template void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + + // These assign overloads ensure that the most efficient assignment + // implementation is used while maintaining the strong exception guarantee. + // The problematic case is where rhs has a value, but *this does not. + // + // This overload handles the case where we can just copy-construct `T` + // directly into place without throwing. + template ::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + // This overload handles the case where we can attempt to create a copy of + // `T`, then no-throw move it into place if the copy was successful. + template ::value && + std::is_nothrow_move_constructible::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + T tmp = rhs.get(); + geterr().~unexpected(); + construct(std::move(tmp)); + } else { + assign_common(rhs); + } + } + + // This overload is the worst-case, where we have to move-construct the + // unexpected value into temporary storage, then try to copy the T into place. + // If the construction succeeds, then everything is fine, but if it throws, + // then we move the old unexpected value back into place before rethrowing the + // exception. + template ::value && + !std::is_nothrow_move_constructible::value> + * = nullptr> + void assign(const expected_operations_base &rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(rhs.get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(rhs.get()); +#endif + } else { + assign_common(rhs); + } + } + + // These overloads do the same as above, but for rvalues + template ::value> + * = nullptr> + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + + template ::value> + * = nullptr> + void assign(expected_operations_base &&rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(std::move(rhs).get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(std::move(rhs).get()); +#endif + } else { + assign_common(std::move(rhs)); + } + } + +#else + + // If exceptions are disabled then we can just copy-construct + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + +#endif + + // The common part of move/copy assigning + template void assign_common(Rhs &&rhs) { + if (this->m_has_val) { + if (rhs.m_has_val) { + get() = std::forward(rhs).get(); + } else { + destroy_val(); + construct_error(std::forward(rhs).geterr()); + } + } else { + if (!rhs.m_has_val) { + geterr() = std::forward(rhs).geterr(); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; } + constexpr const T &get() const & { return this->m_val; } + TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const T &&get() const && { return std::move(this->m_val); } +#endif + + TL_EXPECTED_11_CONSTEXPR unexpected &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); } +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template void construct() noexcept { this->m_has_val = true; } + + // This function doesn't use its argument, but needs it so that code in + // levels above this can work independently of whether T is void + template void construct_with(Rhs &&) noexcept { + this->m_has_val = true; + } + + template void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + + template void assign(Rhs &&rhs) noexcept { + if (!this->m_has_val) { + if (rhs.m_has_val) { + geterr().~unexpected(); + construct(); + } else { + geterr() = std::forward(rhs).geterr(); + } + } else { + if (!rhs.m_has_val) { + construct_error(std::forward(rhs).geterr()); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR unexpected &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { + // no-op + } +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T and E are trivially copy constructible +template :: + value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value> +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; +}; + +// This specialization is for when T or E are not trivially copy constructible +template +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; + + expected_copy_base() = default; + expected_copy_base(const expected_copy_base &rhs) + : expected_operations_base(no_init) { + if (rhs.has_value()) { + this->construct_with(rhs); + } else { + this->construct_error(rhs.geterr()); + } + } + + expected_copy_base(expected_copy_base &&rhs) = default; + expected_copy_base &operator=(const expected_copy_base &rhs) = default; + expected_copy_base &operator=(expected_copy_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef TL_EXPECTED_GCC49 +template >::value + &&std::is_trivially_move_constructible::value> +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; +}; +#else +template struct expected_move_base; +#endif +template +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; + + expected_move_base() = default; + expected_move_base(const expected_move_base &rhs) = default; + + expected_move_base(expected_move_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value) + : expected_copy_base(no_init) { + if (rhs.has_value()) { + this->construct_with(std::move(rhs)); + } else { + this->construct_error(std::move(rhs.geterr())); + } + } + expected_move_base &operator=(const expected_move_base &rhs) = default; + expected_move_base &operator=(expected_move_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial copy assignment operator +template >::value + &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value + &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value + &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value> +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; +}; + +template +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; + + expected_copy_assign_base() = default; + expected_copy_assign_base(const expected_copy_assign_base &rhs) = default; + + expected_copy_assign_base(expected_copy_assign_base &&rhs) = default; + expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { + this->assign(rhs); + return *this; + } + expected_copy_assign_base & + operator=(expected_copy_assign_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef TL_EXPECTED_GCC49 +template , + std::is_trivially_move_constructible, + std::is_trivially_move_assignable>>:: + value &&std::is_trivially_destructible::value + &&std::is_trivially_move_constructible::value + &&std::is_trivially_move_assignable::value> +struct expected_move_assign_base : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; +}; +#else +template struct expected_move_assign_base; +#endif + +template +struct expected_move_assign_base + : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; + + expected_move_assign_base() = default; + expected_move_assign_base(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base(expected_move_assign_base &&rhs) = default; + + expected_move_assign_base & + operator=(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base & + operator=(expected_move_assign_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value + &&std::is_nothrow_move_assignable::value) { + this->assign(std::move(rhs)); + return *this; + } +}; + +// expected_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template ::value && + std::is_copy_constructible::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value)> +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +// expected_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T and E are copy/move constructible + +// assignable +template ::value && + std::is_copy_constructible::value && + is_copy_assignable_or_void::value && + std::is_copy_assignable::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value && + is_move_assignable_or_void::value && + std::is_move_assignable::value)> +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +// This is needed to be able to construct the expected_default_ctor_base which +// follows, while still conditionally deleting the default constructor. +struct default_constructor_tag { + explicit constexpr default_constructor_tag() = default; +}; + +// expected_default_ctor_base will ensure that expected has a deleted default +// consturctor if T is not default constructible. +// This specialization is for when T is default constructible +template ::value || std::is_void::value> +struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = default; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; + +// This specialization is for when T is not default constructible +template struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = delete; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; +} // namespace detail + +template class bad_expected_access : public std::exception { +public: + explicit bad_expected_access(E e) : m_val(std::move(e)) {} + + virtual const char *what() const noexcept override { + return "Bad expected access"; + } + + const E &error() const & { return m_val; } + E &error() & { return m_val; } + const E &&error() const && { return std::move(m_val); } + E &&error() && { return std::move(m_val); } + +private: + E m_val; +}; + +/// An `expected` object is an object that contains the storage for +/// another object and manages the lifetime of this contained object `T`. +/// Alternatively it could contain the storage for another unexpected object +/// `E`. The contained object may not be initialized after the expected object +/// has been initialized, and may not be destroyed before the expected object +/// has been destroyed. The initialization state of the contained object is +/// tracked by the expected object. +template +class expected : private detail::expected_move_assign_base, + private detail::expected_delete_ctor_base, + private detail::expected_delete_assign_base, + private detail::expected_default_ctor_base { + static_assert(!std::is_reference::value, "T must not be a reference"); + static_assert(!std::is_same::type>::value, + "T must not be in_place_t"); + static_assert(!std::is_same::type>::value, + "T must not be unexpect_t"); + static_assert( + !std::is_same>::type>::value, + "T must not be unexpected"); + static_assert(!std::is_reference::value, "E must not be a reference"); + + T *valptr() { return std::addressof(this->m_val); } + const T *valptr() const { return std::addressof(this->m_val); } + unexpected *errptr() { return std::addressof(this->m_unexpect); } + const unexpected *errptr() const { + return std::addressof(this->m_unexpect); + } + + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &val() { + return this->m_val; + } + TL_EXPECTED_11_CONSTEXPR unexpected &err() { return this->m_unexpect; } + + template ::value> * = nullptr> + constexpr const U &val() const { + return this->m_val; + } + constexpr const unexpected &err() const { return this->m_unexpect; } + + using impl_base = detail::expected_move_assign_base; + using ctor_base = detail::expected_default_ctor_base; + +public: + typedef T value_type; + typedef E error_type; + typedef unexpected unexpected_type; + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { + return and_then_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { + return and_then_impl(std::move(*this), std::forward(f)); + } + template constexpr auto and_then(F &&f) const & { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template constexpr auto and_then(F &&f) const && { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif + +#else + template + TL_EXPECTED_11_CONSTEXPR auto + and_then(F &&f) & -> decltype(and_then_impl(std::declval(), + std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto + and_then(F &&f) && -> decltype(and_then_impl(std::declval(), + std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto and_then(F &&f) const & -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr auto and_then(F &&f) const && -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template constexpr auto map(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + template constexpr auto map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) + map(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template constexpr auto transform(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + template constexpr auto transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) + transform(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template constexpr auto map_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + template constexpr auto map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template constexpr auto transform_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + template constexpr auto transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { + return or_else_impl(*this, std::forward(f)); + } + + template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && { + return or_else_impl(std::move(*this), std::forward(f)); + } + + template expected constexpr or_else(F &&f) const & { + return or_else_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template expected constexpr or_else(F &&f) const && { + return or_else_impl(std::move(*this), std::forward(f)); + } +#endif + constexpr expected() = default; + constexpr expected(const expected &rhs) = default; + constexpr expected(expected &&rhs) = default; + expected &operator=(const expected &rhs) = default; + expected &operator=(expected &&rhs) = default; + + template ::value> * = + nullptr> + constexpr expected(in_place_t, Args &&...args) + : impl_base(in_place, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected(in_place_t, std::initializer_list il, Args &&...args) + : impl_base(in_place, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value> * = + nullptr, + detail::enable_if_t::value> * = + nullptr> + explicit constexpr expected(const unexpected &e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr> + constexpr expected(unexpected const &e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + explicit constexpr expected(unexpected &&e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + constexpr expected(unexpected &&e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value> * = + nullptr> + constexpr explicit expected(unexpect_t, Args &&...args) + : impl_base(unexpect, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected(unexpect_t, std::initializer_list il, + Args &&...args) + : impl_base(unexpect, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value && + std::is_convertible::value)> * = + nullptr, + detail::expected_enable_from_other + * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template ::value && + std::is_convertible::value)> * = + nullptr, + detail::expected_enable_from_other + * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template < + class U, class G, + detail::enable_if_t::value && + std::is_convertible::value)> * = nullptr, + detail::expected_enable_from_other * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U, class G, + detail::enable_if_t<(std::is_convertible::value && + std::is_convertible::value)> * = nullptr, + detail::expected_enable_from_other * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::expected_enable_forward_value * = nullptr> + explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::expected_enable_forward_value * = nullptr> + TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, class G = T, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)> * = nullptr> + expected &operator=(U &&v) { + if (has_value()) { + val() = std::forward(v); + } else { + err().~unexpected(); + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } + + return *this; + } + + template < + class U = T, class G = T, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)> * = nullptr> + expected &operator=(U &&v) { + if (has_value()) { + val() = std::forward(v); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; +#endif + } + + return *this; + } + + template ::value && + std::is_assignable::value> * = nullptr> + expected &operator=(const unexpected &rhs) { + if (!has_value()) { + err() = rhs; + } else { + this->destroy_val(); + ::new (errptr()) unexpected(rhs); + this->m_has_val = false; + } + + return *this; + } + + template ::value && + std::is_move_assignable::value> * = nullptr> + expected &operator=(unexpected &&rhs) noexcept { + if (!has_value()) { + err() = std::move(rhs); + } else { + this->destroy_val(); + ::new (errptr()) unexpected(std::move(rhs)); + this->m_has_val = false; + } + + return *this; + } + + template ::value> * = nullptr> + void emplace(Args &&...args) { + if (has_value()) { + val().~T(); + } else { + err().~unexpected(); + this->m_has_val = true; + } + ::new (valptr()) T(std::forward(args)...); + } + + template ::value> * = nullptr> + void emplace(Args &&...args) { + if (has_value()) { + val().~T(); + ::new (valptr()) T(std::forward(args)...); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; +#endif + } + } + + template &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list il, Args &&...args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + err().~unexpected(); + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } + } + + template &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list il, Args &&...args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; +#endif + } + } + +private: + using t_is_void = std::true_type; + using t_is_not_void = std::false_type; + using t_is_nothrow_move_constructible = std::true_type; + using move_constructing_t_can_throw = std::false_type; + using e_is_nothrow_move_constructible = std::true_type; + using move_constructing_e_can_throw = std::false_type; + + void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept { + // swapping void is a no-op + } + + void swap_where_both_have_value(expected &rhs, t_is_not_void) { + using std::swap; + swap(val(), rhs.val()); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept( + std::is_nothrow_move_constructible::value) { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_not_void) { + swap_where_only_one_has_value_and_t_is_not_void( + rhs, typename std::is_nothrow_move_constructible::type{}, + typename std::is_nothrow_move_constructible::type{}); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + e_is_nothrow_move_constructible) noexcept { + auto temp = std::move(val()); + val().~T(); + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + move_constructing_e_can_throw) { + auto temp = std::move(val()); + val().~T(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + val() = std::move(temp); + throw; + } +#else + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, move_constructing_t_can_throw, + e_is_nothrow_move_constructible) { + auto temp = std::move(rhs.err()); + rhs.err().~unexpected_type(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + rhs.err() = std::move(temp); + throw; + } +#else + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + +public: + template + detail::enable_if_t::value && + detail::is_swappable::value && + (std::is_nothrow_move_constructible::value || + std::is_nothrow_move_constructible::value)> + swap(expected &rhs) noexcept( + std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value + &&std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value) { + if (has_value() && rhs.has_value()) { + swap_where_both_have_value(rhs, typename std::is_void::type{}); + } else if (!has_value() && rhs.has_value()) { + rhs.swap(*this); + } else if (has_value()) { + swap_where_only_one_has_value(rhs, typename std::is_void::type{}); + } else { + using std::swap; + swap(err(), rhs.err()); + } + } + + constexpr const T *operator->() const { + TL_ASSERT(has_value()); + return valptr(); + } + TL_EXPECTED_11_CONSTEXPR T *operator->() { + TL_ASSERT(has_value()); + return valptr(); + } + + template ::value> * = nullptr> + constexpr const U &operator*() const & { + TL_ASSERT(has_value()); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &operator*() & { + TL_ASSERT(has_value()); + return val(); + } + template ::value> * = nullptr> + constexpr const U &&operator*() const && { + TL_ASSERT(has_value()); + return std::move(val()); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&operator*() && { + TL_ASSERT(has_value()); + return std::move(val()); + } + + constexpr bool has_value() const noexcept { return this->m_has_val; } + constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &value() const & { + if (!has_value()) + detail::throw_exception(bad_expected_access(err().value())); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &value() & { + if (!has_value()) + detail::throw_exception(bad_expected_access(err().value())); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &&value() const && { + if (!has_value()) + detail::throw_exception(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&value() && { + if (!has_value()) + detail::throw_exception(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + + constexpr const E &error() const & { + TL_ASSERT(!has_value()); + return err().value(); + } + TL_EXPECTED_11_CONSTEXPR E &error() & { + TL_ASSERT(!has_value()); + return err().value(); + } + constexpr const E &&error() const && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + TL_EXPECTED_11_CONSTEXPR E &&error() && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + + template constexpr T value_or(U &&v) const & { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy-constructible and convertible to from U&&"); + return bool(*this) ? **this : static_cast(std::forward(v)); + } + template TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move-constructible and convertible to from U&&"); + return bool(*this) ? std::move(**this) : static_cast(std::forward(v)); + } +}; + +namespace detail { +template using exp_t = typename detail::decay_t::value_type; +template using err_t = typename detail::decay_t::error_type; +template using ret_t = expected>; + +#ifdef TL_EXPECTED_CXX14 +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#else +template struct TC; +template (), + *std::declval())), + detail::enable_if_t>::value> * = nullptr> +auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template ())), + detail::enable_if_t>::value> * = nullptr> +constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} +#else +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#else +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto or_else_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +detail::decay_t or_else_impl(Exp &&exp, F &&f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#else +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto or_else_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +detail::decay_t or_else_impl(Exp &&exp, F &&f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#endif +} // namespace detail + +template +constexpr bool operator==(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs); +} +template +constexpr bool operator!=(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs); +} +template +constexpr bool operator==(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : true); +} +template +constexpr bool operator!=(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() == rhs.error() : false); +} + +template +constexpr bool operator==(const expected &x, const U &v) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator==(const U &v, const expected &x) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator!=(const expected &x, const U &v) { + return x.has_value() ? *x != v : true; +} +template +constexpr bool operator!=(const U &v, const expected &x) { + return x.has_value() ? *x != v : true; +} + +template +constexpr bool operator==(const expected &x, const unexpected &e) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator==(const unexpected &e, const expected &x) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator!=(const expected &x, const unexpected &e) { + return x.has_value() ? true : x.error() != e.value(); +} +template +constexpr bool operator!=(const unexpected &e, const expected &x) { + return x.has_value() ? true : x.error() != e.value(); +} + +template ::value || + std::is_move_constructible::value) && + detail::is_swappable::value && + std::is_move_constructible::value && + detail::is_swappable::value> * = nullptr> +void swap(expected &lhs, + expected &rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} +} // namespace tl + +#endif diff --git a/YUViewLib/src/ffmpeg/FFMpegLibrariesTypes.cpp b/YUViewLib/externalLibs/LibFFmpeg++/common/FFMpegLibrariesTypes.cpp similarity index 76% rename from YUViewLib/src/ffmpeg/FFMpegLibrariesTypes.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/common/FFMpegLibrariesTypes.cpp index b6d46af7b..6a2f093c7 100644 --- a/YUViewLib/src/ffmpeg/FFMpegLibrariesTypes.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/common/FFMpegLibrariesTypes.cpp @@ -32,7 +32,7 @@ #include "FFMpegLibrariesTypes.h" -namespace FFmpeg +namespace LibFFmpeg { QString timestampToString(int64_t timestamp, AVRational timebase) @@ -53,4 +53,32 @@ QString timestampToString(int64_t timestamp, AVRational timebase) .arg(milliseconds, 3, 10, QChar('0')); } -} // namespace FFmpeg +Version Version::fromFFmpegVersion(const unsigned ffmpegVersion) +{ + Version v; + v.major = AV_VERSION_MAJOR(ffmpegVersion); + v.minor = AV_VERSION_MINOR(ffmpegVersion); + v.micro = AV_VERSION_MICRO(ffmpegVersion); + return v; +} + +std::string to_string(const Version &version) +{ + std::ostringstream stream; + stream << "v" << version.major; + if (version.minor) + { + stream << "." << version.minor.value(); + if (version.micro) + stream << "." << version.micro.value(); + } + return stream.str(); +} + +std::ostream &operator<<(std::ostream &stream, const Version &version) +{ + stream << to_string(version); + return stream; +} + +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/FFMpegLibrariesTypes.h b/YUViewLib/externalLibs/LibFFmpeg++/common/FFMpegLibrariesTypes.h similarity index 94% rename from YUViewLib/src/ffmpeg/FFMpegLibrariesTypes.h rename to YUViewLib/externalLibs/LibFFmpeg++/common/FFMpegLibrariesTypes.h index c4941cd89..450a0c319 100644 --- a/YUViewLib/src/ffmpeg/FFMpegLibrariesTypes.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/common/FFMpegLibrariesTypes.h @@ -35,6 +35,7 @@ #include #include #include +#include #include /* This file defines all FFmpeg specific defines like structs, enums and some common things like @@ -43,9 +44,24 @@ * from the FFmpeg public API headers. Please see (www.ffmpeg.org). */ -namespace FFmpeg +namespace LibFFmpeg { +struct Size +{ + int width{}; + int height{}; +}; + +struct Ratio +{ + int num{}; + int den{}; +}; + +using ByteVector = std::vector; +using Log = std::vector; + // Some structs/enums which actual definition does not interest us. struct AVFormatContext; struct AVClass; @@ -380,30 +396,39 @@ enum AVSampleFormat struct Version { - unsigned major{}; - std::optional minor{}; - std::optional micro{}; -}; + Version() = default; + Version(const int major) { this->major = major; } -struct LibraryVersion -{ - LibraryVersion() = default; - LibraryVersion(unsigned avutilMajor, - unsigned avcodecMajor, - unsigned avformatMajor, - unsigned swresampleMajor) + constexpr bool operator!=(const Version &other) const { - this->avutil.major = avutilMajor; - this->avcodec.major = avcodecMajor; - this->avformat.major = avformatMajor; - this->swresample.major = swresampleMajor; + if (this->major != other.major) + return true; + if (this->minor && other.minor && this->minor.value() != other.minor.value()) + return true; + if (this->micro && other.micro && this->micro.value() != other.micro.value()) + return true; + + return false; } - Version avutil{}; - Version avcodec{}; + + static Version fromFFmpegVersion(const unsigned ffmpegVersion); + + int major{}; + std::optional minor{}; + std::optional micro{}; +}; + +std::string to_string(const Version &version); +std::ostream &operator<<(std::ostream &stream, const Version &version); + +struct LibraryVersions +{ Version avformat{}; + Version avcodec{}; + Version avutil{}; Version swresample{}; }; QString timestampToString(int64_t timestamp, AVRational timebase); -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/common/MotionVector.cpp b/YUViewLib/externalLibs/LibFFmpeg++/common/MotionVector.cpp new file mode 100644 index 000000000..20b260f83 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/common/MotionVector.cpp @@ -0,0 +1,122 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "MotionVector.h" +#include + +namespace LibFFmpeg +{ + +namespace +{ + +typedef struct AVMotionVector_54 +{ + int32_t source; + uint8_t w, h; + int16_t src_x, src_y; + int16_t dst_x, dst_y; + uint64_t flags; +} AVMotionVector_54; + +typedef struct AVMotionVector_55_56_57 +{ + int32_t source; + uint8_t w, h; + int16_t src_x, src_y; + int16_t dst_x, dst_y; + uint64_t flags; + int32_t motion_x, motion_y; + uint16_t motion_scale; +} AVMotionVector_55_56_57; + +} // namespace + +std::vector +parseMotionData(const LibraryVersions &libraryVersions, const uint8_t *data, const size_t dataSize) +{ + std::vector motionVectors; + if (libraryVersions.avutil.major == 54) + { + const auto nrMotionVectors = dataSize / sizeof(AVMotionVector_54); + for (size_t index = 0; index < nrMotionVectors; ++index) + { + const auto byteOffset = sizeof(AVMotionVector_54) * index; + const auto p = reinterpret_cast(data + byteOffset); + + MotionVector motionVector; + motionVector.source = p->source; + motionVector.w = p->w; + motionVector.h = p->h; + motionVector.src_x = p->src_x; + motionVector.src_y = p->src_y; + motionVector.dst_x = p->dst_x; + motionVector.dst_y = p->dst_y; + motionVector.flags = p->flags; + motionVector.motion_x = -1; + motionVector.motion_y = -1; + motionVector.motion_scale = -1; + motionVectors.push_back(motionVector); + } + return motionVectors; + } + else if (libraryVersions.avutil.major == 55 || // + libraryVersions.avutil.major == 56 || // + libraryVersions.avutil.major == 57) + { + const auto nrMotionVectors = dataSize / sizeof(AVMotionVector_55_56_57); + for (size_t index = 0; index < nrMotionVectors; ++index) + { + const auto byteOffset = sizeof(AVMotionVector_55_56_57) * index; + const auto p = reinterpret_cast(data + byteOffset); + + MotionVector motionVector; + motionVector.source = p->source; + motionVector.w = p->w; + motionVector.h = p->h; + motionVector.src_x = p->src_x; + motionVector.src_y = p->src_y; + motionVector.dst_x = p->dst_x; + motionVector.dst_y = p->dst_y; + motionVector.flags = p->flags; + motionVector.motion_x = p->motion_x; + motionVector.motion_y = p->motion_y; + motionVector.motion_scale = p->motion_scale; + motionVectors.push_back(motionVector); + } + return motionVectors; + } + else + throw std::runtime_error("Invalid library version"); +} + +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVMotionVectorWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/common/MotionVector.h similarity index 83% rename from YUViewLib/src/ffmpeg/AVMotionVectorWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/common/MotionVector.h index 553a733d6..bc8d7a221 100644 --- a/YUViewLib/src/ffmpeg/AVMotionVectorWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/common/MotionVector.h @@ -34,19 +34,11 @@ #include "FFMpegLibrariesTypes.h" -namespace FFmpeg +namespace LibFFmpeg { -class AVMotionVectorWrapper +struct MotionVector { -public: - AVMotionVectorWrapper() = delete; - AVMotionVectorWrapper(LibraryVersion &libVer, uint8_t *data, unsigned idx); - - static size_t getNumberOfMotionVectors(LibraryVersion &libVer, size_t dataSize); - - // For performance reasons, these are public here. Since update is called at construction, these - // should be valid. int32_t source{}; uint8_t w{}; uint8_t h{}; @@ -61,4 +53,7 @@ class AVMotionVectorWrapper uint16_t motion_scale{}; }; -} // namespace FFmpeg +std::vector +parseMotionData(const LibraryVersions &libraryVersions, const uint8_t *data, const size_t dataSize); + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libFFmpeg++.pro b/YUViewLib/externalLibs/LibFFmpeg++/libFFmpeg++.pro new file mode 100644 index 000000000..2f01bd634 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libFFmpeg++.pro @@ -0,0 +1,9 @@ +TEMPLATE = lib +CONFIG += staticlib +CONFIG += c++1z +CONFIG -= debug_and_release + +SOURCES += $$files(*.cpp, true) +HEADERS += $$files(*.h, true) + +warning("Sources list " + $${SOURCES}) diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterface.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterface.cpp new file mode 100644 index 000000000..ccbc8f1fd --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterface.cpp @@ -0,0 +1,293 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "FFmpegLibrariesInterface.h" + +namespace LibFFmpeg +{ + +namespace +{ + +using LoadingResult = tl::expected; +using LoadingResultAndLog = std::pair; + +std::vector getPossibleLibraryNames(std::string libraryName, int version) +{ + // The ffmpeg libraries are named using a major version number. E.g: avutil-55.dll on windows. + // On linux, the libraries may be named differently. On Ubuntu they are named + // libavutil-ffmpeg.so.55. On arch linux the name is libavutil.so.55. We will try to look for both + // namings. On MAC os (installed with homebrew), there is a link to the lib named + // libavutil.54.dylib. + +#if defined(_WIN32) + return {{libraryName + "-" + std::to_string(version)}}; +#elif defined(__APPLE__) + return {{"lib" + libraryName + "." + std::to_string(version) + ".dylib"}}; +#else + return {{"lib" + libraryName + "-ffmpeg.so." + std::to_string(version)}, + {"lib" + libraryName + ".so." + std::to_string(version)}}; +#endif + + return {}; +} + +bool tryLoadLibraryInPath(SharedLibraryLoader & lib, + const std::filesystem::path &absoluteDirectoryPath, + std::string libName, + const Version & version, + Log & log) +{ + log.push_back("Trying to load library " + libName + " in path " + absoluteDirectoryPath.string()); + + for (const auto &possibleLibName : getPossibleLibraryNames(libName, version.major)) + { + const auto filePath = absoluteDirectoryPath / possibleLibName; + const auto fileStatus = std::filesystem::status(filePath); + + if (fileStatus.type() == std::filesystem::file_type::not_found) + { + log.push_back("Loading using lib name " + possibleLibName + " failed. Can not find file " + + filePath.string()); + continue; + } + + const auto success = lib.load(filePath); + log.push_back("Loading library " + filePath.string() + (success ? " succeded" : " failed")); + if (success) + return true; + } + return false; +}; + +bool checkLibraryVersion(const std::string &libName, + unsigned ffmpegVersionOfLoadedLibrary, + const Version & expectedVersion, + Log & log) +{ + const auto loadedVersion = Version::fromFFmpegVersion(ffmpegVersionOfLoadedLibrary); + if (loadedVersion != expectedVersion) + { + log.push_back("Version of loaded " + libName + " library (" + to_string(loadedVersion) + + ") is not the one we are trying to load (" + to_string(expectedVersion) + ")"); + return false; + } + + log.push_back("Version check for library " + libName + " successfull. Version " + + to_string(loadedVersion) + "."); + return true; +} + +// These FFmpeg versions are supported. The numbers indicate the major version of +// the following libraries in this order: Util, codec, format, swresample +// The versions are sorted from newest to oldest, so that we try to open the newest ones first. +auto SupportedMajorLibraryVersionCombinations = { + LibraryVersions({Version(58), Version(60), Version(60), Version(4)}), + LibraryVersions({Version(57), Version(59), Version(59), Version(4)}), + LibraryVersions({Version(56), Version(58), Version(58), Version(3)}), + LibraryVersions({Version(55), Version(57), Version(57), Version(2)}), + LibraryVersions({Version(54), Version(56), Version(56), Version(1)}), +}; + +} // namespace + +FFmpegLibrariesInterface::LoadingResultAndLog +FFmpegLibrariesInterface::tryLoadFFmpegLibrariesInPath(const std::filesystem::path &path) +{ + Log log; + + std::filesystem::path absoluteDirectoryPath; + if (!path.empty()) + { + if (!std::filesystem::exists(path)) + { + log.push_back("The given path (" + path.string() + ") could not be found"); + return {false, log}; + } + + absoluteDirectoryPath = std::filesystem::absolute(path); + log.push_back("Using absolute path " + absoluteDirectoryPath.string()); + } + + for (const auto &libraryVersions : SupportedMajorLibraryVersionCombinations) + { + this->unloadAllLibraries(); + log.push_back("Unload libraries"); + + if (this->tryLoadLibrariesBindFunctionsAndCheckVersions(path, libraryVersions, log)) + { + log.push_back( + "Loading of ffmpeg libraries successfully finished. FFmpeg is ready to be used."); + return {false, log}; + } + } + + this->unloadAllLibraries(); + log.push_back("Unload libraries"); + log.push_back( + "We tried all supported versions in given path. Loading of ffmpeg libraries in path failed."); + + return {true, log}; +} + +bool FFmpegLibrariesInterface::tryLoadLibrariesBindFunctionsAndCheckVersions( + const std::filesystem::path &absoluteDirectoryPath, + const LibraryVersions & libraryVersions, + Log & log) +{ + // AVUtil + + if (!tryLoadLibraryInPath( + this->libAvutil, absoluteDirectoryPath, "avutil", libraryVersions.avutil, log)) + return false; + + if (const auto functions = functions::tryBindAVUtilFunctionsFromLibrary(this->libAvutil, log)) + this->avutil = functions.value(); + else + return false; + + if (!checkLibraryVersion("avUtil", this->avutil.avutil_version(), libraryVersions.avutil, log)) + return false; + + // SWResample + + if (!tryLoadLibraryInPath(this->libSwresample, + absoluteDirectoryPath, + "swresample", + libraryVersions.swresample, + log)) + return false; + + if (const auto functions = + functions::tryBindSwResampleFunctionsFromLibrary(this->libSwresample, log)) + this->swresample = functions.value(); + else + return false; + + if (!checkLibraryVersion( + "swresample", this->swresample.swresample_version(), libraryVersions.swresample, log)) + return false; + + // AVCodec + + if (!tryLoadLibraryInPath( + this->libAvcodec, absoluteDirectoryPath, "avcodec", libraryVersions.avcodec, log)) + return false; + + if (const auto functions = functions::tryBindAVCodecFunctionsFromLibrary(this->libAvcodec, log)) + this->avcodec = functions.value(); + else + return false; + + if (!checkLibraryVersion( + "avcodec", this->avcodec.avcodec_version(), libraryVersions.avcodec, log)) + return false; + + // AVFormat + + if (!tryLoadLibraryInPath( + this->libAvformat, absoluteDirectoryPath, "avformat", libraryVersions.avformat, log)) + return false; + + if (const auto functions = functions::tryBindAVFormatFunctionsFromLibrary(this->libAvformat, log)) + this->avformat = functions.value(); + else + return false; + + if (!checkLibraryVersion( + "avformat", this->avformat.avformat_version(), libraryVersions.avformat, log)) + return false; + + // Success + + this->libraryVersions.avutil = Version::fromFFmpegVersion(this->avutil.avutil_version()); + this->libraryVersions.avcodec = Version::fromFFmpegVersion(this->avcodec.avcodec_version()); + this->libraryVersions.avformat = Version::fromFFmpegVersion(this->avformat.avformat_version()); + this->libraryVersions.swresample = + Version::fromFFmpegVersion(this->swresample.swresample_version()); + + this->avutil.av_log_set_callback(&FFmpegLibrariesInterface::avLogCallback); + + if (this->libraryVersions.avformat.major < 59) + this->avformat.av_register_all(); + + return true; +} + +void FFmpegLibrariesInterface::unloadAllLibraries() +{ + this->libAvutil.unload(); + this->libSwresample.unload(); + this->libAvcodec.unload(); + this->libAvformat.unload(); +} + +std::vector FFmpegLibrariesInterface::getLibrariesInfo() const +{ + if (!this->libAvutil || !this->libSwresample || !this->libAvcodec || !this->libAvformat) + return {}; + + std::vector infoPerLIbrary; + + auto addLibraryInfo = [&infoPerLIbrary](const char * name, + const std::filesystem::path &path, + const unsigned ffmpegVersion) { + const auto libraryVersion = Version::fromFFmpegVersion(ffmpegVersion); + const auto version = to_string(libraryVersion); + + infoPerLIbrary.push_back(LibraryInfo({name, path, version})); + }; + + addLibraryInfo("AVFormat", this->libAvformat.getLibraryPath(), this->avformat.avformat_version()); + addLibraryInfo("AVCodec", this->libAvcodec.getLibraryPath(), this->avcodec.avcodec_version()); + addLibraryInfo("AVUtil", this->libAvutil.getLibraryPath(), this->avutil.avutil_version()); + addLibraryInfo( + "SwResample", this->libSwresample.getLibraryPath(), this->swresample.swresample_version()); + + return infoPerLIbrary; +} + +std::string FFmpegLibrariesInterface::logListFFmpeg; + +void FFmpegLibrariesInterface::avLogCallback(void *, int level, const char *fmt, va_list vargs) +{ + std::string message; + va_list vargs_copy; + va_copy(vargs_copy, vargs); + size_t len = vsnprintf(0, 0, fmt, vargs_copy); + message.resize(len); + vsnprintf(&message[0], len + 1, fmt, vargs); + + FFmpegLibrariesInterface::logListFFmpeg.append("Level " + std::to_string(level) + message); +} + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterface.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterface.h new file mode 100644 index 000000000..b89ca80e3 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterface.h @@ -0,0 +1,92 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace LibFFmpeg +{ + +struct LibraryInfo +{ + std::string name; + std::filesystem::path path; + std::string version; +}; + +class FFmpegLibrariesInterface +{ +public: + FFmpegLibrariesInterface() = default; + ~FFmpegLibrariesInterface() = default; + + using LoadingResultAndLog = std::pair; + LoadingResultAndLog tryLoadFFmpegLibrariesInPath(const std::filesystem::path &path); + + std::vector getLibrariesInfo() const; + + functions::AvFormatFunctions avformat{}; + functions::AvCodecFunctions avcodec{}; + functions::AvUtilFunctions avutil{}; + functions::SwResampleFunctions swresample{}; + +private: + bool + tryLoadLibrariesBindFunctionsAndCheckVersions(const std::filesystem::path &absoluteDirectoryPath, + const LibraryVersions & libraryVersions, + Log & log); + + void unloadAllLibraries(); + + SharedLibraryLoader libAvutil; + SharedLibraryLoader libSwresample; + SharedLibraryLoader libAvcodec; + SharedLibraryLoader libAvformat; + + LibraryVersions libraryVersions{}; + + static std::string logListFFmpeg; + static void avLogCallback(void *ptr, int level, const char *fmt, va_list vargs); + + friend class FFmpegLibrariesInterfaceBuilder; +}; + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterfaceBuilder.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterfaceBuilder.cpp new file mode 100644 index 000000000..0718243a5 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterfaceBuilder.cpp @@ -0,0 +1,93 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "FFmpegLibrariesInterfaceBuilder.h" + +namespace LibFFmpeg +{ + +LibrariesLoadingResult FFmpegLibrariesInterfaceBuilder::tryLoadingOfLibraries() +{ + LibrariesLoadingResult result; + + if (this->forceReload) + result.loadingLog.push_back("Library reload forced. Will skip cache check."); + else + { + if (auto cachedLibrariesInterface = this->lastLoadedLibraries.lock()) + { + result.loadingLog.push_back("Cached libraries still loaded. Returning cached libraries."); + result.librariesInterface = cachedLibrariesInterface; + return result; + } + } + + if (this->searchPaths.empty()) + { + result.loadingLog.push_back( + "No search paths specified. We will only try the default empty path."); + this->searchPaths.push_back(""); + } + + auto libraryInterface = std::make_shared(); + + for (const auto &path : this->searchPaths) + { + result.loadingLog.push_back("Trying to load the libraries in the path " + path.string()); + + const auto [success, log] = libraryInterface->tryLoadFFmpegLibrariesInPath(path); + result.loadingLog.insert(result.loadingLog.begin(), log.begin(), log.end()); + + if (success) + { + result.librariesInterface = libraryInterface; + return result; + } + } + + return result; +} + +FFmpegLibrariesInterfaceBuilder &FFmpegLibrariesInterfaceBuilder::withAdditionalSearchPaths( + const std::vector &additionalPath) +{ + this->searchPaths.insert(this->searchPaths.begin(), additionalPath.begin(), additionalPath.end()); + return *this; +} + +FFmpegLibrariesInterfaceBuilder &FFmpegLibrariesInterfaceBuilder::withForcedReload() +{ + this->forceReload = true; + return *this; +} + +} // namespace LibFFmpeg \ No newline at end of file diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterfaceBuilder.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterfaceBuilder.h new file mode 100644 index 000000000..40a1c045b --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegLibrariesInterfaceBuilder.h @@ -0,0 +1,68 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include + +namespace LibFFmpeg +{ + +struct LibrariesLoadingResult +{ + std::shared_ptr librariesInterface{}; + std::string errorMessage{}; + std::vector loadingLog{}; + + explicit operator bool() const { return this->librariesInterface.get() != nullptr; }; +}; + +class FFmpegLibrariesInterfaceBuilder +{ +public: + FFmpegLibrariesInterfaceBuilder() = default; + + LibrariesLoadingResult tryLoadingOfLibraries(); + + FFmpegLibrariesInterfaceBuilder & + withAdditionalSearchPaths(const std::vector &additionalPath); + FFmpegLibrariesInterfaceBuilder &withForcedReload(); + +private: + std::vector searchPaths{}; + bool forceReload{false}; + std::weak_ptr lastLoadedLibraries{}; +}; + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegVersionHandler.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegVersionHandler.cpp new file mode 100644 index 000000000..40e6be3ca --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegVersionHandler.cpp @@ -0,0 +1,426 @@ +// /* This file is part of YUView - The YUV player with advanced analytics toolset +// * +// * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY +// * +// * This program is free software; you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation; either version 3 of the License, or +// * (at your option) any later version. +// * +// * In addition, as a special exception, the copyright holders give +// * permission to link the code of portions of this program with the +// * OpenSSL library under certain conditions as described in each +// * individual source file, and distribute linked combinations including +// * the two. +// * +// * You must obey the GNU General Public License in all respects for all +// * of the code used other than OpenSSL. If you modify file(s) with this +// * exception, you may extend this exception to your version of the +// * file(s), but you are not obligated to do so. If you do not wish to do +// * so, delete this exception statement from your version. If you delete +// * this exception statement from all source files in the program, then +// * also delete it here. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see . +// */ + +// #include "FFmpegVersionHandler.h" +// #include +// #include +// #include + +// namespace LibFFmpeg +// { + +// namespace +// { + +// LibraryVersions getLibraryVersionsFromLoadedLibraries(const FFmpegLibraryFunctions &libraries) +// { +// const auto avFormatVersion = Version::fromFFmpegVersion(libraries.avformat.avformat_version()); +// const auto avCodecVersion = Version::fromFFmpegVersion(libraries.avcodec.avcodec_version()); +// const auto avUtilVersion = Version::fromFFmpegVersion(libraries.avutil.avutil_version()); +// const auto swresampleVersion = +// Version::fromFFmpegVersion(libraries.swresample.swresample_version()); + +// return {avFormatVersion, avCodecVersion, avUtilVersion, swresampleVersion}; +// } + +// tl::expected +// checkMajorVersionWithLibraries(const LibraryVersions &librariesInfo, +// const LibraryVersions &expectedMajorVersion) +// { +// auto createErrorString = [](std::string_view libname, +// const Version & realVersion, +// const Version & expectedVersion) -> std::string { +// std::ostringstream stream; +// stream << "The openend " << libname << " returned a different version (" << realVersion +// << ") than we are looking for (" << expectedVersion << ")."; +// return stream.str(); +// }; + +// if (expectedMajorVersion.avcodec != librariesInfo.avcodec) +// return tl::unexpected( +// createErrorString("avcodec", librariesInfo.avcodec, expectedMajorVersion.avcodec)); + +// if (expectedMajorVersion.avformat != librariesInfo.avformat) +// return tl::unexpected( +// createErrorString("avformat", librariesInfo.avformat, expectedMajorVersion.avformat)); + +// if (expectedMajorVersion.avutil != librariesInfo.avutil) +// return tl::unexpected( +// createErrorString("avutil", librariesInfo.avutil, expectedMajorVersion.avutil)); + +// if (expectedMajorVersion.swresample != librariesInfo.swresample) +// return tl::unexpected( +// createErrorString("swresample", librariesInfo.swresample, expectedMajorVersion.swresample)); + +// return {}; +// } + +// } // namespace + +// AVCodecIDWrapper FFmpegVersionHandler::getCodecIDWrapper(AVCodecID id) +// { +// const auto codecName = std::string(lib.avcodec.avcodec_get_name(id)); +// return AVCodecIDWrapper(id, codecName); +// } + +// AVCodecID FFmpegVersionHandler::getCodecIDFromWrapper(AVCodecIDWrapper &wrapper) +// { +// if (wrapper.getCodecID() != AV_CODEC_ID_NONE) +// return wrapper.getCodecID(); + +// int codecID = 1; +// std::string codecName; +// do +// { +// codecName = std::string(this->lib.avcodec.avcodec_get_name(AVCodecID(codecID))); +// if (codecName == wrapper.getCodecName()) +// { +// wrapper.setCodecID(AVCodecID(codecID)); +// return wrapper.getCodecID(); +// } +// codecID++; +// } while (codecName != "unknown_codec"); + +// return AV_CODEC_ID_NONE; +// } + +// bool FFmpegVersionHandler::configureDecoder(AVCodecContextWrapper & decCtx, +// AVCodecParametersWrapper &codecpar) +// { +// if (this->lib.avcodec.newParametersAPIAvailable) +// { +// // Use the new avcodec_parameters_to_context function. +// auto origin_par = codecpar.getCodecParameters(); +// if (!origin_par) +// return false; +// auto ret = this->lib.avcodec.avcodec_parameters_to_context(decCtx.getCodec(), origin_par); +// if (ret < 0) +// return false; +// } +// else +// { +// // TODO: Is this even necessary / what is really happening here? + +// // The new parameters API is not available. Perform what the function would do. +// // This is equal to the implementation of avcodec_parameters_to_context. +// // AVCodecContext *ctxSrc = videoStream.getCodec().getCodec(); +// // int ret = lib.AVCodecContextCopyParameters(ctxSrc, decCtx.getCodec()); +// // return setOpeningError(QStringLiteral("Could not copy decoder parameters from stream +// // decoder.")); +// } +// return true; +// } + +// int FFmpegVersionHandler::pushPacketToDecoder(AVCodecContextWrapper &decCtx, AVPacketWrapper &pkt) +// { +// if (!pkt) +// return this->lib.avcodec.avcodec_send_packet(decCtx.getCodec(), nullptr); +// else +// return this->lib.avcodec.avcodec_send_packet(decCtx.getCodec(), pkt.getPacket()); +// } + +// int FFmpegVersionHandler::getFrameFromDecoder(AVCodecContextWrapper &decCtx, AVFrameWrapper &frame) +// { +// return this->lib.avcodec.avcodec_receive_frame(decCtx.getCodec(), frame.getFrame()); +// } + +// void FFmpegVersionHandler::flush_buffers(AVCodecContextWrapper &decCtx) +// { +// lib.avcodec.avcodec_flush_buffers(decCtx.getCodec()); +// } + + + +// FFmpegVersionHandler::FFmpegVersionHandler() +// { +// this->librariesLoaded = false; +// } + +// FFmpegVersionHandler::~FFmpegVersionHandler() +// { +// } + + + +// LibraryLoadingResult +// FFmpegVersionHandler::loadFFmpegLibraries(std::vector searchPaths) +// { +// LibraryLoadingResult result; + +// if (this->librariesLoaded) +// { +// result.addLogLine("Libraries already loaded"); +// return result; +// } + +// for (const auto &path : searchPaths) +// { +// result.addLogLine("Trying to load the libraries in the path " + path.string()); + +// auto resultForPath = this->loadFFmpegLibraryInPath(path); +// result.loadingLog.append(resultForPath.loadingLog); +// this->librariesLoaded = resultForPath.success; +// if (resultForPath.success) +// { +// result.success = true; +// break; +// } +// } + +// if (this->librariesLoaded) +// this->lib.avutil.av_log_set_callback(&FFmpegVersionHandler::avLogCallback); + +// return result; +// } + +// bool FFmpegVersionHandler::openInput(AVFormatContextWrapper &fmt, QString url) +// { +// AVFormatContext *f_ctx = nullptr; +// int ret = +// this->lib.avformat.avformat_open_input(&f_ctx, url.toStdString().c_str(), nullptr, nullptr); +// if (ret < 0) +// return false; +// if (f_ctx == nullptr) +// return false; + +// // The wrapper will take ownership of this pointer +// fmt = AVFormatContextWrapper(f_ctx, this->libraryVersions); + +// ret = lib.avformat.avformat_find_stream_info(fmt.getFormatCtx(), nullptr); +// if (ret < 0) +// return false; + +// return true; +// } + +// AVCodecParametersWrapper FFmpegVersionHandler::allocCodecParameters() +// { +// return AVCodecParametersWrapper(this->lib.avcodec.avcodec_parameters_alloc(), +// this->libraryVersions); +// } + +// AVCodecWrapper FFmpegVersionHandler::findDecoder(AVCodecIDWrapper codecId) +// { +// AVCodecID avCodecID = getCodecIDFromWrapper(codecId); +// AVCodec * c = this->lib.avcodec.avcodec_find_decoder(avCodecID); +// if (c == nullptr) +// return {}; +// return AVCodecWrapper(c, this->libraryVersions); +// } + +// AVCodecContextWrapper FFmpegVersionHandler::allocDecoder(AVCodecWrapper &codec) +// { +// return AVCodecContextWrapper(this->lib.avcodec.avcodec_alloc_context3(codec.getAVCodec()), +// this->libraryVersions); +// } + +// int FFmpegVersionHandler::dictSet(AVDictionaryWrapper &dict, +// const char * key, +// const char * value, +// int flags) +// { +// AVDictionary *d = dict.getDictionary(); +// int ret = this->lib.avutil.av_dict_set(&d, key, value, flags); +// dict.setDictionary(d); +// return ret; +// } + +// StringPairVec +// FFmpegVersionHandler::getDictionaryEntries(AVDictionaryWrapper d, QString key, int flags) +// { +// StringPairVec ret; +// AVDictionaryEntry *tag = NULL; +// while ((tag = this->lib.avutil.av_dict_get(d.getDictionary(), key.toLatin1().data(), tag, flags))) +// { +// StringPair pair; +// pair.first = std::string(tag->key); +// pair.second = std::string(tag->value); +// ret.push_back(pair); +// } +// return ret; +// } +// int FFmpegVersionHandler::avcodecOpen2(AVCodecContextWrapper &decCtx, +// AVCodecWrapper & codec, +// AVDictionaryWrapper & dict) +// { +// auto d = dict.getDictionary(); +// int ret = this->lib.avcodec.avcodec_open2(decCtx.getCodec(), codec.getAVCodec(), &d); +// dict.setDictionary(d); +// return ret; +// } + +// AVFrameSideDataWrapper FFmpegVersionHandler::getSideData(AVFrameWrapper & frame, +// AVFrameSideDataType type) +// { +// auto sd = this->lib.avutil.av_frame_get_side_data(frame.getFrame(), type); +// return AVFrameSideDataWrapper(sd, this->libraryVersions); +// } + +// AVDictionaryWrapper FFmpegVersionHandler::getMetadata(AVFrameWrapper &frame) +// { +// AVDictionary *dict; +// if (this->libraryVersions.avutil.major < 57) +// dict = this->lib.avutil.av_frame_get_metadata(frame.getFrame()); +// else +// dict = frame.getMetadata(); +// return AVDictionaryWrapper(dict); +// } + +// int FFmpegVersionHandler::seekFrame(AVFormatContextWrapper &fmt, int stream_idx, int64_t dts) +// { +// int ret = +// this->lib.avformat.av_seek_frame(fmt.getFormatCtx(), stream_idx, dts, AVSEEK_FLAG_BACKWARD); +// return ret; +// } + +// int FFmpegVersionHandler::seekBeginning(AVFormatContextWrapper &fmt) +// { +// // This is "borrowed" from the ffmpeg sources +// // (https://ffmpeg.org/doxygen/4.0/ffmpeg_8c_source.html seek_to_start) +// return lib.avformat.av_seek_frame(fmt.getFormatCtx(), -1, fmt.getStartTime(), 0); +// } + +// LibraryLoadingResult FFmpegVersionHandler::loadFFmpegLibraryInPath(const std::filesystem::path path) +// { +// LibraryLoadingResult result; +// for (auto version : SupportedMajorLibraryVersionCombinations) +// { +// if (auto loadResult = this->lib.loadFFmpegLibraryInPath(path, version)) +// { +// result.loadingLog.append(loadResult.loadingLog); + +// result.addLogLine("Checking versions avutil " + to_string(version.avutil) + ", swresample " + +// to_string(version.swresample) + ", avcodec " + to_string(version.avcodec) + +// ", avformat " + to_string(version.avformat)); + +// const auto libraryVersions = getLibraryVersionsFromLoadedLibraries(this->lib); + +// const auto checkVersionResult = checkMajorVersionWithLibraries(libraryVersions, version); +// if (checkVersionResult.has_value()) +// { +// this->libraryVersions = libraryVersions; + +// if (this->libraryVersions.avformat.major < 59) +// this->lib.avformat.av_register_all(); + +// result.success = true; +// result.addLogLine("Library version check passed."); +// return result; +// } +// else +// { +// result.addLogLine(checkVersionResult.error()); +// } +// } +// } + +// result.errorMessage = "No supported ffmpeg library files found in path " + path.string(); +// return result; +// } + +// LibraryLoadingResult +// FFmpegVersionHandler::checkPathForUsableFFmpeg(const std::filesystem::path &path) +// { +// FFmpegVersionHandler handler; +// return handler.loadFFmpegLibraryInPath(path); +// } + +// void FFmpegVersionHandler::enableLoggingWarning() +// { +// lib.avutil.av_log_set_level(AV_LOG_WARNING); +// } + +// AVPixFmtDescriptorWrapper +// FFmpegVersionHandler::getAvPixFmtDescriptionFromAvPixelFormat(AVPixelFormat pixFmt) +// { +// if (pixFmt == AV_PIX_FMT_NONE) +// return {}; +// return AVPixFmtDescriptorWrapper(lib.avutil.av_pix_fmt_desc_get(pixFmt), this->libraryVersions); +// } + +// AVPixelFormat +// FFmpegVersionHandler::getAVPixelFormatFromPixelFormatYUV(video::yuv::PixelFormatYUV pixFmt) +// { +// AVPixFmtDescriptorWrapper wrapper; +// wrapper.setValuesFromPixelFormatYUV(pixFmt); + +// // We will have to search through all pixel formats which the library knows and compare them to +// // the one we are looking for. Unfortunately there is no other more direct search function in +// // libavutil. +// auto desc = this->lib.avutil.av_pix_fmt_desc_next(nullptr); +// while (desc != nullptr) +// { +// AVPixFmtDescriptorWrapper descWrapper(desc, this->libraryVersions); + +// if (descWrapper == wrapper) +// return this->lib.avutil.av_pix_fmt_desc_get_id(desc); + +// // Get the next descriptor +// desc = this->lib.avutil.av_pix_fmt_desc_next(desc); +// } + +// return AV_PIX_FMT_NONE; +// } + +// AVFrameWrapper FFmpegVersionHandler::allocateFrame() +// { +// auto framePtr = this->lib.avutil.av_frame_alloc(); +// return AVFrameWrapper(framePtr, this->libraryVersions); +// } + +// void FFmpegVersionHandler::freeFrame(AVFrameWrapper &frame) +// { +// auto framePtr = frame.getFrame(); +// this->lib.avutil.av_frame_free(&framePtr); +// frame.clear(); +// } + +// AVPacketWrapper FFmpegVersionHandler::allocatePacket() +// { +// auto rawPacket = this->lib.avcodec.av_packet_alloc(); +// this->lib.avcodec.av_init_packet(rawPacket); +// return AVPacketWrapper(rawPacket, this->libraryVersions); +// } + +// void FFmpegVersionHandler::unrefPacket(AVPacketWrapper &packet) +// { +// this->lib.avcodec.av_packet_unref(packet.getPacket()); +// } + +// void FFmpegVersionHandler::freePacket(AVPacketWrapper &packet) +// { +// auto packetPtr = packet.getPacket(); +// this->lib.avcodec.av_packet_free(&packetPtr); +// packet.clear(); +// } + +// } // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegVersionHandler.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegVersionHandler.h new file mode 100644 index 000000000..94c1eb218 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/FFmpegVersionHandler.h @@ -0,0 +1,132 @@ +// /* This file is part of YUView - The YUV player with advanced analytics toolset +// * +// * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY +// * +// * This program is free software; you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation; either version 3 of the License, or +// * (at your option) any later version. +// * +// * In addition, as a special exception, the copyright holders give +// * permission to link the code of portions of this program with the +// * OpenSSL library under certain conditions as described in each +// * individual source file, and distribute linked combinations including +// * the two. +// * +// * You must obey the GNU General Public License in all respects for all +// * of the code used other than OpenSSL. If you modify file(s) with this +// * exception, you may extend this exception to your version of the +// * file(s), but you are not obligated to do so. If you do not wish to do +// * so, delete this exception statement from your version. If you delete +// * this exception statement from all source files in the program, then +// * also delete it here. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see . +// */ + +// #pragma once + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// namespace LibFFmpeg +// { + +// class FFmpegVersionHandler +// { +// public: +// FFmpegVersionHandler(); +// ~FFmpegVersionHandler(); + +// // Try to load the ffmpeg libraries and get all the function pointers. +// LibraryLoadingResult loadFFmpegLibraries(std::vector searchPaths); + +// std::vector getLibrariesInfo() const { return this->lib.getLibrariesInfo(); } + +// // Only these functions can be used to get valid versions of these wrappers (they have to use +// // ffmpeg functions to retrieve the needed information) +// AVCodecIDWrapper getCodecIDWrapper(AVCodecID id); +// AVCodecID getCodecIDFromWrapper(AVCodecIDWrapper &wrapper); +// AVPixFmtDescriptorWrapper getAvPixFmtDescriptionFromAvPixelFormat(AVPixelFormat pixFmt); +// AVPixelFormat getAVPixelFormatFromPixelFormatYUV(video::yuv::PixelFormatYUV pixFmt); + +// AVFrameWrapper allocateFrame(); +// void freeFrame(AVFrameWrapper &frame); +// AVPacketWrapper allocatePacket(); +// void unrefPacket(AVPacketWrapper &packet); +// void freePacket(AVPacketWrapper &packet); + +// bool configureDecoder(AVCodecContextWrapper &decCtx, AVCodecParametersWrapper &codecpar); + +// // Push a packet to the given decoder using avcodec_send_packet +// int pushPacketToDecoder(AVCodecContextWrapper &decCtx, AVPacketWrapper &pkt); +// // Retrive a frame using avcodec_receive_frame +// int getFrameFromDecoder(AVCodecContextWrapper &decCtx, AVFrameWrapper &frame); + +// void flush_buffers(AVCodecContextWrapper &decCtx); + +// LibraryVersions libVersions; + +// // Open the input file. This will call avformat_open_input and avformat_find_stream_info. +// bool openInput(AVFormatContextWrapper &fmt, QString url); +// // Try to find a decoder for the given codecID +// AVCodecWrapper findDecoder(AVCodecIDWrapper codecID); +// // Allocate the decoder (avcodec_alloc_context3) +// AVCodecContextWrapper allocDecoder(AVCodecWrapper &codec); +// // Set info in the dictionary +// int dictSet(AVDictionaryWrapper &dict, const char *key, const char *value, int flags); +// // Get all entries with the given key (leave empty for all) +// StringPairVec getDictionaryEntries(AVDictionaryWrapper d, QString key, int flags); +// // Allocate a new set of codec parameters +// AVCodecParametersWrapper allocCodecParameters(); + +// // Open the codec +// int avcodecOpen2(AVCodecContextWrapper &decCtx, AVCodecWrapper &codec, AVDictionaryWrapper &dict); +// // Get side/meta data +// AVFrameSideDataWrapper getSideData(AVFrameWrapper &frame, AVFrameSideDataType type); +// AVDictionaryWrapper getMetadata(AVFrameWrapper &frame); + +// // Seek to a specific frame +// int seekFrame(AVFormatContextWrapper &fmt, int stream_idx, int64_t dts); +// int seekBeginning(AVFormatContextWrapper &fmt); + +// // All the function pointers of the ffmpeg library +// FFmpegLibraryFunctions lib; + +// static AVPixelFormat convertYUVAVPixelFormat(video::yuv::PixelFormatYUV fmt); + +// static LibraryLoadingResult checkPathForUsableFFmpeg(const std::filesystem::path &path); + +// // Logging. By default we set the logging level of ffmpeg to AV_LOG_ERROR (Log errors and +// // everything worse) +// static QStringList getFFmpegLog() { return logListFFmpeg; } +// void enableLoggingWarning(); + +// private: +// LibraryLoadingResult loadFFmpegLibraryInPath(const std::filesystem::path); + +// bool librariesLoaded{}; +// LibraryVersions libraryVersions{}; + +// // FFmpeg has a callback where it loggs stuff. This log goes here. +// static QStringList logListFFmpeg; +// static void avLogCallback(void *ptr, int level, const char *fmt, va_list vargs); +// }; + +// } // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/SharedLibraryLoader.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/SharedLibraryLoader.cpp new file mode 100644 index 000000000..8a8741001 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/SharedLibraryLoader.cpp @@ -0,0 +1,60 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "SharedLibraryLoader.h" + +namespace LibFFmpeg +{ + +void SharedLibraryLoader::unload() +{ + this->library.unload(); + this->libraryPath.clear(); +}; + +bool SharedLibraryLoader::load(std::filesystem::path pathToLib) +{ + const auto filePathQString = QString::fromStdString(pathToLib.string()); + this->library.setFileName(filePathQString); + const auto success = this->library.load(); + if (success) + this->libraryPath = pathToLib; + return success; +}; + +FunctionPointer SharedLibraryLoader::resolve(std::string functionName) +{ + auto functionPointer = this->library.resolve(functionName.c_str()); + return functionPointer; +}; + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/SharedLibraryLoader.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/SharedLibraryLoader.h new file mode 100644 index 000000000..085646653 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/SharedLibraryLoader.h @@ -0,0 +1,70 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +typedef void (*FunctionPointer)(); + +namespace LibFFmpeg +{ + +class SharedLibraryLoader +{ +public: + SharedLibraryLoader() = default; + + void unload(); + bool load(std::filesystem::path pathToLib); + FunctionPointer resolve(std::string functionName); + + auto getLibraryPath() const { return this->libraryPath; } + + operator bool() const { return this->library.isLoaded(); } + + template + void tryResolveFunction(std::function &function, const char *symbolName) const + { + if (auto ptr = this->library.resolve(symbolName)) + function = reinterpret_cast(ptr); + } + +private: + // Todo: Replace this with alternative + QLibrary library; + + std::filesystem::path libraryPath; +}; + +} // namespace LibFFmpeg diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AVFormatFunctions.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AVFormatFunctions.cpp new file mode 100644 index 000000000..301b280f7 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AVFormatFunctions.cpp @@ -0,0 +1,97 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "AVFormatFunctions.h" + +#include "Functions.h" + +namespace LibFFmpeg::functions +{ + +std::optional tryBindFunctionsFromLibrary(SharedLibraryLoader &lib, Log &log) +{ + if (!lib) + { + log.push_back("Binding of avFormat functions failed. Library is not loaded."); + return {}; + } + + AvFormatFunctions functions; + + lib.tryResolveFunction(functions.avformat_version, "avformat_version"); + lib.tryResolveFunction(functions.av_register_all, "av_register_all"); + lib.tryResolveFunction(functions.avformat_open_input, "avformat_open_input"); + lib.tryResolveFunction(functions.avformat_close_input, "avformat_close_input"); + lib.tryResolveFunction(functions.avformat_find_stream_info, "avformat_find_stream_info"); + lib.tryResolveFunction(functions.av_read_frame, "av_read_frame"); + lib.tryResolveFunction(functions.av_seek_frame, "av_seek_frame"); + + std::vector missingFunctions; + + checkForMissingFunctionAndLog( + functions.avformat_version, "avformat_version", missingFunctions, log); + + if (!functions.avformat_version) + { + log.push_back("Binding avFormat functions failed. Missing function avformat_version"); + return {}; + } + + const auto version = Version::fromFFmpegVersion(functions.avformat_version()); + + if (version.major < 59) + checkForMissingFunctionAndLog( + functions.av_register_all, "av_register_all", missingFunctions, log); + + checkForMissingFunctionAndLog( + functions.avformat_open_input, "avformat_open_input", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avformat_close_input, "avformat_close_input", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avformat_find_stream_info, "avformat_find_stream_info", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_read_frame, "av_read_frame", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_seek_frame, "av_seek_frame", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avformat_version, "avformat_version", missingFunctions, log); + + if (!missingFunctions.empty()) + { + log.push_back("Binding avFormat functions failed. Missing functions: " + + to_string(missingFunctions)); + return {}; + } + + log.push_back("Binding of avFormat functions successful."); + return functions; +} + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AVFormatFunctions.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AVFormatFunctions.h new file mode 100644 index 000000000..bc9f74518 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AVFormatFunctions.h @@ -0,0 +1,59 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace LibFFmpeg::functions +{ + +struct AvFormatFunctions +{ + std::function av_register_all; + std::function + avformat_open_input; + std::function avformat_close_input; + std::function avformat_find_stream_info; + std::function av_read_frame; + std::function + av_seek_frame; + std::function avformat_version; +}; + +std::optional tryBindAVFormatFunctionsFromLibrary(SharedLibraryLoader &lib, + Log & log); + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvCodecFunctions.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvCodecFunctions.cpp new file mode 100644 index 000000000..20cbdf8af --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvCodecFunctions.cpp @@ -0,0 +1,127 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "AvCodecFunctions.h" + +#include "Functions.h" + +namespace LibFFmpeg::functions +{ + +std::optional tryBindAVCodecFunctionsFromLibrary(SharedLibraryLoader &lib, + Log & log) +{ + if (!lib) + { + log.push_back("Binding of avCodec functions failed. Library is not loaded."); + return {}; + } + + AvCodecFunctions functions; + + lib.tryResolveFunction(functions.avcodec_find_decoder, "avcodec_find_decoder"); + lib.tryResolveFunction(functions.avcodec_alloc_context3, "avcodec_alloc_context3"); + lib.tryResolveFunction(functions.avcodec_open2, "avcodec_open2"); + lib.tryResolveFunction(functions.avcodec_free_context, "avcodec_free_context"); + lib.tryResolveFunction(functions.av_packet_alloc, "av_packet_alloc"); + lib.tryResolveFunction(functions.av_packet_free, "av_packet_free"); + lib.tryResolveFunction(functions.av_init_packet, "av_init_packet"); + lib.tryResolveFunction(functions.av_packet_unref, "av_packet_unref"); + lib.tryResolveFunction(functions.avcodec_flush_buffers, "avcodec_flush_buffers"); + lib.tryResolveFunction(functions.avcodec_version, "avcodec_version"); + lib.tryResolveFunction(functions.avcodec_get_name, "avcodec_get_name"); + lib.tryResolveFunction(functions.avcodec_parameters_alloc, "avcodec_parameters_alloc"); + lib.tryResolveFunction(functions.avcodec_send_packet, "avcodec_send_packet"); + lib.tryResolveFunction(functions.avcodec_receive_frame, "avcodec_receive_frame"); + lib.tryResolveFunction(functions.avcodec_parameters_to_context, "avcodec_parameters_to_context"); + lib.tryResolveFunction(functions.avcodec_decode_video2, "avcodec_decode_video2"); + + std::vector missingFunctions; + + checkForMissingFunctionAndLog( + functions.avcodec_find_decoder, "avcodec_find_decoder", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avcodec_alloc_context3, "avcodec_alloc_context3", missingFunctions, log); + checkForMissingFunctionAndLog(functions.avcodec_open2, "avcodec_open2", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avcodec_free_context, "avcodec_free_context", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_packet_alloc, "av_packet_alloc", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_packet_free, "av_packet_free", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_init_packet, "av_init_packet", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_packet_unref, "av_packet_unref", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avcodec_flush_buffers, "avcodec_flush_buffers", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avcodec_version, "avcodec_version", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avcodec_get_name, "avcodec_get_name", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.avcodec_parameters_alloc, "avcodec_parameters_alloc", missingFunctions, log); + + std::vector missingFunctionsNewApi; + + checkForMissingFunctionAndLog( + functions.avcodec_send_packet, "avcodec_send_packet", missingFunctionsNewApi, log); + checkForMissingFunctionAndLog( + functions.avcodec_receive_frame, "avcodec_receive_frame", missingFunctionsNewApi, log); + checkForMissingFunctionAndLog(functions.avcodec_parameters_to_context, + "avcodec_parameters_to_context", + missingFunctionsNewApi, + log); + + if (missingFunctionsNewApi.empty()) + { + log.push_back("New Decoding API found. Skipping check for old API function."); + functions.newParametersAPIAvailable = true; + } + else + { + log.push_back("New Decoding API not found. Missing functions " + + to_string(missingFunctionsNewApi) + ". Checking old decoding API."); + checkForMissingFunctionAndLog( + functions.avcodec_decode_video2, "avcodec_decode_video2", missingFunctions, log); + } + + if (!missingFunctions.empty()) + { + log.push_back("Binding avCodec functions failed. Missing functions: " + + to_string(missingFunctions)); + return {}; + } + + log.push_back("Binding of avCodec functions successful."); + return functions; +} + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvCodecFunctions.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvCodecFunctions.h new file mode 100644 index 000000000..e6c5b123b --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvCodecFunctions.h @@ -0,0 +1,71 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace LibFFmpeg::functions +{ + +struct AvCodecFunctions +{ + std::function avcodec_find_decoder; + std::function avcodec_alloc_context3; + std::function + avcodec_open2; + std::function avcodec_free_context; + std::function av_packet_alloc; + std::function av_packet_free; + std::function av_init_packet; + std::function av_packet_unref; + std::function avcodec_flush_buffers; + std::function avcodec_version; + std::function avcodec_get_name; + std::function avcodec_parameters_alloc; + // The following functions are part of the new API. + // We will check if it is available. If not, we will use the old decoding API. + bool newParametersAPIAvailable{}; + std::function avcodec_send_packet; + std::function avcodec_receive_frame; + std::function + avcodec_parameters_to_context; + // This is the old API + std::function avcodec_decode_video2; +}; + +std::optional tryBindAVCodecFunctionsFromLibrary(SharedLibraryLoader &lib, + Log & log); + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvUtilFunctions.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvUtilFunctions.cpp new file mode 100644 index 000000000..e121b7c0d --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvUtilFunctions.cpp @@ -0,0 +1,110 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "AvUtilFunctions.h" + +#include "Functions.h" + +namespace LibFFmpeg::functions +{ + +std::optional tryBindAVUtilFunctionsFromLibrary(SharedLibraryLoader &lib, Log &log) +{ + if (!lib) + { + log.push_back("Binding of avUtil functions failed. Library is not loaded."); + return {}; + } + + AvUtilFunctions functions; + + lib.tryResolveFunction(functions.avutil_version, "avutil_version"); + lib.tryResolveFunction(functions.av_frame_alloc, "av_frame_alloc"); + lib.tryResolveFunction(functions.av_frame_free, "av_frame_free"); + lib.tryResolveFunction(functions.av_mallocz, "av_mallocz"); + lib.tryResolveFunction(functions.av_dict_set, "av_dict_set"); + lib.tryResolveFunction(functions.av_dict_get, "av_dict_get"); + lib.tryResolveFunction(functions.av_frame_get_side_data, "av_frame_get_side_data"); + lib.tryResolveFunction(functions.av_frame_get_metadata, "av_frame_get_metadata"); + lib.tryResolveFunction(functions.av_log_set_callback, "av_log_set_callback"); + lib.tryResolveFunction(functions.av_log_set_level, "av_log_set_level"); + lib.tryResolveFunction(functions.av_pix_fmt_desc_get, "av_pix_fmt_desc_get"); + lib.tryResolveFunction(functions.av_pix_fmt_desc_next, "av_pix_fmt_desc_next"); + lib.tryResolveFunction(functions.av_pix_fmt_desc_get_id, "av_pix_fmt_desc_get_id"); + + std::vector missingFunctions; + + checkForMissingFunctionAndLog(functions.avutil_version, "avutil_version", missingFunctions, log); + if (!functions.avutil_version) + { + log.push_back("Binding avutil functions failed.Missing function avutil_version"); + return {}; + } + + const auto version = Version::fromFFmpegVersion(functions.avutil_version()); + + checkForMissingFunctionAndLog(functions.av_frame_alloc, "av_frame_alloc", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_frame_free, "av_frame_free", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_frame_free, "av_frame_free", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_mallocz, "av_mallocz", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_dict_set, "av_dict_set", missingFunctions, log); + checkForMissingFunctionAndLog(functions.av_dict_get, "av_dict_get", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_frame_get_side_data, "av_frame_get_side_data", missingFunctions, log); + + if (version.major < 57) + checkForMissingFunctionAndLog( + functions.av_frame_get_metadata, "av_frame_get_metadata", missingFunctions, log); + + checkForMissingFunctionAndLog( + functions.av_log_set_callback, "av_log_set_callback", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_log_set_level, "av_log_set_level", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_pix_fmt_desc_get, "av_pix_fmt_desc_get", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_pix_fmt_desc_next, "av_pix_fmt_desc_next", missingFunctions, log); + checkForMissingFunctionAndLog( + functions.av_pix_fmt_desc_get_id, "av_pix_fmt_desc_get_id", missingFunctions, log); + + if (!missingFunctions.empty()) + { + log.push_back("Binding avUtil functions failed. Missing functions: " + + to_string(missingFunctions)); + return {}; + } + + log.push_back("Binding of avUtil functions successful."); + return functions; +} + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvUtilFunctions.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvUtilFunctions.h new file mode 100644 index 000000000..0827157ab --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/AvUtilFunctions.h @@ -0,0 +1,65 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace LibFFmpeg::functions +{ + +struct AvUtilFunctions +{ + std::function avutil_version; + std::function av_frame_alloc; + std::function av_frame_free; + std::function av_mallocz; + std::function av_dict_set; + std::function + av_dict_get; + std::function + av_frame_get_side_data; + std::function av_frame_get_metadata; + std::function av_log_set_callback; + std::function av_log_set_level; + std::function av_pix_fmt_desc_get; + std::function av_pix_fmt_desc_next; + std::function av_pix_fmt_desc_get_id; +}; + +std::optional tryBindAVUtilFunctionsFromLibrary(SharedLibraryLoader &lib, + Log & log); + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/Functions.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/Functions.cpp new file mode 100644 index 000000000..2bf0d52ac --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/Functions.cpp @@ -0,0 +1,62 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Functions.h" + +namespace LibFFmpeg::functions +{ + +std::string to_string(std::vector strings) +{ + std::ostringstream stream; + for (auto it = strings.begin(); it != strings.end(); it++) + { + if (it != strings.begin()) + stream << ", "; + stream << (*it); + } + return stream.str(); +} + +std::string logMissingFunctionsAndGetErrorMessage(const std::vector &missingFunctions, + const std::string libraryName, + Log & log) +{ + assert(!missingFunctions.empty()); + + const auto errorMessage = "Binding " + libraryName + + " functions failed. Missing functions: " + to_string(missingFunctions); + log.push_back(errorMessage); + return errorMessage; +} + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/Functions.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/Functions.h new file mode 100644 index 000000000..1f3adfed0 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/Functions.h @@ -0,0 +1,69 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace LibFFmpeg::functions +{ + +using LoadingResult = tl::expected; +using LoadingResultAndLog = std::pair; + +template +void checkForMissingFunctionAndLog(std::function & function, + std::string name, + std::vector &missingFunctions, + Log & log) +{ + if (function) + log.push_back("Successfully resolved function " + name); + else + { + log.push_back("Failed to resolved function " + name); + missingFunctions.push_back(name); + } +} + +std::string to_string(std::vector strings); + +std::string logMissingFunctionsAndGetErrorMessage(const std::vector &missingFunctions, + const std::string libraryName, + Log & log); + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/SwResampleFunctions.cpp b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/SwResampleFunctions.cpp new file mode 100644 index 000000000..0f240b4cc --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/SwResampleFunctions.cpp @@ -0,0 +1,69 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "SwResampleFunctions.h" + +#include "Functions.h" + +namespace LibFFmpeg::functions +{ + +std::optional tryBindSwResampleFunctionsFromLibrary(SharedLibraryLoader &lib, + Log & log) +{ + if (!lib) + { + log.push_back("Binding of swResample functions failed. Library is not loaded."); + return {}; + } + + SwResampleFunctions functions; + + lib.tryResolveFunction(functions.swresample_version, "swresample_version"); + + std::vector missingFunctions; + + checkForMissingFunctionAndLog( + functions.swresample_version, "swresample_version", missingFunctions, log); + + if (!missingFunctions.empty()) + { + log.push_back("Binding swResample functions failed. Missing functions: " + + to_string(missingFunctions)); + return {}; + } + + log.push_back("Binding of swPresample functions successful."); + return functions; +} + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/SwResampleFunctions.h b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/SwResampleFunctions.h new file mode 100644 index 000000000..41f1c8a58 --- /dev/null +++ b/YUViewLib/externalLibs/LibFFmpeg++/libHandling/libraryFunctions/SwResampleFunctions.h @@ -0,0 +1,50 @@ +/* This file is part of YUView - The YUV player with advanced analytics toolset + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace LibFFmpeg::functions +{ + +struct SwResampleFunctions +{ + std::function swresample_version; +}; + +std::optional tryBindSwResampleFunctionsFromLibrary(SharedLibraryLoader &lib, + Log & log); + +} // namespace LibFFmpeg::functions diff --git a/YUViewLib/src/ffmpeg/AVCodecContextWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecContextWrapper.cpp similarity index 96% rename from YUViewLib/src/ffmpeg/AVCodecContextWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecContextWrapper.cpp index dea86930a..36325f677 100644 --- a/YUViewLib/src/ffmpeg/AVCodecContextWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecContextWrapper.cpp @@ -31,9 +31,10 @@ */ #include "AVCodecContextWrapper.h" -#include -namespace FFmpeg +#include "Functions.h" + +namespace LibFFmpeg { namespace @@ -419,10 +420,11 @@ AVCodecContextWrapper::AVCodecContextWrapper() this->codec = nullptr; } -AVCodecContextWrapper::AVCodecContextWrapper(AVCodecContext *c, LibraryVersion v) +AVCodecContextWrapper::AVCodecContextWrapper(AVCodecContext * c, + const LibraryVersions &libraryVersions) { - this->codec = c; - this->libVer = v; + this->codec = c; + this->libraryVersions = libraryVersions; this->update(); } @@ -467,7 +469,7 @@ AVRational AVCodecContextWrapper::getTimeBase() return this->time_base; } -QByteArray AVCodecContextWrapper::getExtradata() +ByteVector AVCodecContextWrapper::getExtradata() { this->update(); return this->extradata; @@ -478,11 +480,11 @@ void AVCodecContextWrapper::update() if (this->codec == nullptr) return; - if (this->libVer.avcodec.major == 56) + if (this->libraryVersions.avcodec.major == 56) { auto p = reinterpret_cast(this->codec); this->codec_type = p->codec_type; - this->codec_name = QString(p->codec_name); + this->codec_name = std::string(p->codec_name); this->codec_id = p->codec_id; this->codec_tag = p->codec_tag; this->stream_codec_tag = p->stream_codec_tag; @@ -492,7 +494,7 @@ void AVCodecContextWrapper::update() this->compression_level = p->compression_level; this->flags = p->flags; this->flags2 = p->flags2; - this->extradata = QByteArray((const char *)p->extradata, p->extradata_size); + this->extradata = copyDataFromRawArray(p->extradata, p->extradata_size); this->time_base = p->time_base; this->ticks_per_frame = p->ticks_per_frame; this->delay = p->delay; @@ -562,11 +564,11 @@ void AVCodecContextWrapper::update() this->color_range = p->color_range; this->chroma_sample_location = p->chroma_sample_location; } - else if (libVer.avcodec.major == 57) + else if (this->libraryVersions.avcodec.major == 57) { auto p = reinterpret_cast(this->codec); this->codec_type = p->codec_type; - this->codec_name = QString(p->codec_name); + this->codec_name = std::string(p->codec_name); this->codec_id = p->codec_id; this->codec_tag = p->codec_tag; this->stream_codec_tag = p->stream_codec_tag; @@ -576,7 +578,7 @@ void AVCodecContextWrapper::update() this->compression_level = p->compression_level; this->flags = p->flags; this->flags2 = p->flags2; - this->extradata = QByteArray((const char *)p->extradata, p->extradata_size); + this->extradata = copyDataFromRawArray(p->extradata, p->extradata_size); this->time_base = p->time_base; this->ticks_per_frame = p->ticks_per_frame; this->delay = p->delay; @@ -646,11 +648,11 @@ void AVCodecContextWrapper::update() this->color_range = p->color_range; this->chroma_sample_location = p->chroma_sample_location; } - else if (libVer.avcodec.major == 58) + else if (this->libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(this->codec); this->codec_type = p->codec_type; - this->codec_name = QString("Not supported in AVCodec >= 58"); + this->codec_name = std::string("Not supported in AVCodec >= 58"); this->codec_id = p->codec_id; this->codec_tag = p->codec_tag; this->stream_codec_tag = -1; @@ -660,7 +662,7 @@ void AVCodecContextWrapper::update() this->compression_level = p->compression_level; this->flags = p->flags; this->flags2 = p->flags2; - this->extradata = QByteArray((const char *)p->extradata, p->extradata_size); + this->extradata = copyDataFromRawArray(p->extradata, p->extradata_size); this->time_base = p->time_base; this->ticks_per_frame = p->ticks_per_frame; this->delay = p->delay; @@ -730,11 +732,12 @@ void AVCodecContextWrapper::update() this->color_range = p->color_range; this->chroma_sample_location = p->chroma_sample_location; } - else if (libVer.avcodec.major == 59 || libVer.avcodec.major == 60) + else if (this->libraryVersions.avcodec.major == 59 || // + this->libraryVersions.avcodec.major == 60) { auto p = reinterpret_cast(this->codec); this->codec_type = p->codec_type; - this->codec_name = QString("Not supported in AVCodec >= 58"); + this->codec_name = std::string("Not supported in AVCodec >= 58"); this->codec_id = p->codec_id; this->codec_tag = p->codec_tag; this->stream_codec_tag = -1; @@ -744,7 +747,7 @@ void AVCodecContextWrapper::update() this->compression_level = p->compression_level; this->flags = p->flags; this->flags2 = p->flags2; - this->extradata = QByteArray((const char *)p->extradata, p->extradata_size); + this->extradata = copyDataFromRawArray(p->extradata, p->extradata_size); this->time_base = p->time_base; this->ticks_per_frame = p->ticks_per_frame; this->delay = p->delay; @@ -818,4 +821,4 @@ void AVCodecContextWrapper::update() throw std::runtime_error("Invalid library version"); } -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVCodecContextWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecContextWrapper.h similarity index 94% rename from YUViewLib/src/ffmpeg/AVCodecContextWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecContextWrapper.h index 760f6a171..ef16f9aaa 100644 --- a/YUViewLib/src/ffmpeg/AVCodecContextWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecContextWrapper.h @@ -32,17 +32,16 @@ #pragma once -#include "FFMpegLibrariesTypes.h" -#include +#include -namespace FFmpeg +namespace LibFFmpeg { class AVCodecContextWrapper { public: AVCodecContextWrapper(); - AVCodecContextWrapper(AVCodecContext *c, LibraryVersion v); + AVCodecContextWrapper(AVCodecContext *c, const LibraryVersions &libraryVersions); explicit operator bool() const { return this->codec != nullptr; }; @@ -53,14 +52,14 @@ class AVCodecContextWrapper Size getSize(); AVColorSpace getColorspace(); AVRational getTimeBase(); - QByteArray getExtradata(); + ByteVector getExtradata(); private: void update(); // These are private. Use "update" to update them from the AVCodecContext AVMediaType codec_type{}; - QString codec_name{}; + std::string codec_name{}; AVCodecID codec_id{}; unsigned int codec_tag{}; unsigned int stream_codec_tag{}; @@ -70,7 +69,7 @@ class AVCodecContextWrapper int compression_level{}; int flags{}; int flags2{}; - QByteArray extradata{}; + ByteVector extradata{}; AVRational time_base{}; int ticks_per_frame{}; int delay{}; @@ -142,7 +141,7 @@ class AVCodecContextWrapper AVChromaLocation chroma_sample_location{}; AVCodecContext *codec{}; - LibraryVersion libVer{}; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVCodecIDWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecIDWrapper.h similarity index 83% rename from YUViewLib/src/ffmpeg/AVCodecIDWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecIDWrapper.h index 4502c73e8..8fadd22b6 100644 --- a/YUViewLib/src/ffmpeg/AVCodecIDWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecIDWrapper.h @@ -32,19 +32,22 @@ #pragma once -#include "FFMpegLibrariesTypes.h" +#include -namespace FFmpeg +namespace LibFFmpeg { class AVCodecIDWrapper { public: AVCodecIDWrapper() {} - AVCodecIDWrapper(AVCodecID codecID, QString codecName) : codecID(codecID), codecName(codecName) {} + AVCodecIDWrapper(AVCodecID codecID, std::string codecName) + : codecID(codecID), codecName(codecName) + { + } - QString getCodecName() const { return this->codecName; } - AVCodecID getCodecID() const { return this->codecID; } + std::string getCodecName() const { return this->codecName; } + AVCodecID getCodecID() const { return this->codecID; } void setCodecID(AVCodecID id) { this->codecID = id; } @@ -58,15 +61,15 @@ class AVCodecIDWrapper bool isNone() const { - return this->codecName.isEmpty() || this->codecName == "unknown_codec" || + return this->codecName.empty() || this->codecName == "unknown_codec" || this->codecName == "none"; } bool operator==(const AVCodecIDWrapper &a) const { return codecID == a.codecID; } private: - AVCodecID codecID{AV_CODEC_ID_NONE}; - QString codecName; + AVCodecID codecID{AV_CODEC_ID_NONE}; + std::string codecName; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVCodecParametersWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecParametersWrapper.cpp similarity index 51% rename from YUViewLib/src/ffmpeg/AVCodecParametersWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecParametersWrapper.cpp index 56d0c943e..0693d8325 100644 --- a/YUViewLib/src/ffmpeg/AVCodecParametersWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecParametersWrapper.cpp @@ -32,8 +32,8 @@ #include "AVCodecParametersWrapper.h" -#include -namespace FFmpeg +#include "Functions.h" +namespace LibFFmpeg { namespace @@ -69,10 +69,11 @@ typedef struct AVCodecParameters_57_58_59_60 } // namespace -AVCodecParametersWrapper::AVCodecParametersWrapper(AVCodecParameters *p, LibraryVersion v) +AVCodecParametersWrapper::AVCodecParametersWrapper(AVCodecParameters * p, + const LibraryVersions &libraryVersions) { - this->param = p; - this->libVer = v; + this->param = p; + this->libraryVersions = libraryVersions; this->update(); } @@ -88,7 +89,7 @@ AVCodecID AVCodecParametersWrapper::getCodecID() return this->codec_id; } -QByteArray AVCodecParametersWrapper::getExtradata() +ByteVector AVCodecParametersWrapper::getExtradata() { this->update(); return this->extradata; @@ -97,7 +98,7 @@ QByteArray AVCodecParametersWrapper::getExtradata() Size AVCodecParametersWrapper::getSize() { this->update(); - return Size(this->width, this->height); + return Size({this->width, this->height}); } AVColorSpace AVCodecParametersWrapper::getColorspace() @@ -118,119 +119,12 @@ Ratio AVCodecParametersWrapper::getSampleAspectRatio() return {this->sample_aspect_ratio.num, this->sample_aspect_ratio.den}; } -QStringPairList AVCodecParametersWrapper::getInfoText() -{ - QStringPairList info; - - if (this->param == nullptr) - { - info.append(QStringPair("Codec parameters are nullptr", "")); - return info; - } - this->update(); - - info.append({"Codec Tag", QString::number(this->codec_tag)}); - info.append({"Format", QString::number(this->format)}); - info.append({"Bitrate", QString::number(this->bit_rate)}); - info.append({"Bits per coded sample", QString::number(this->bits_per_coded_sample)}); - info.append({"Bits per Raw sample", QString::number(this->bits_per_raw_sample)}); - info.append({"Profile", QString::number(this->profile)}); - info.append({"Level", QString::number(this->level)}); - info.append({"Width/Height", QString("%1/%2").arg(this->width).arg(this->height)}); - info.append( - {"Sample aspect ratio", - QString("%1:%2").arg(this->sample_aspect_ratio.num).arg(this->sample_aspect_ratio.den)}); - auto fieldOrders = QStringList() << "Unknown" - << "Progressive" - << "Top coded_first, top displayed first" - << "Bottom coded first, bottom displayed first" - << "Top coded first, bottom displayed first" - << "Bottom coded first, top displayed first"; - info.append( - {"Field Order", - fieldOrders.at(functions::clip(int(this->codec_type), 0, int(fieldOrders.count())))}); - auto colorRanges = QStringList() << "Unspecified" - << "The normal 219*2^(n-8) MPEG YUV ranges" - << "The normal 2^n-1 JPEG YUV ranges" - << "Not part of ABI"; - info.append( - {"Color Range", - colorRanges.at(functions::clip(int(this->color_range), 0, int(colorRanges.count())))}); - auto colorPrimaries = - QStringList() - << "Reserved" - << "BT709 / ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B" - << "Unspecified" - << "Reserved" - << "BT470M / FCC Title 47 Code of Federal Regulations 73.682 (a)(20)" - << "BT470BG / ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM" - << "SMPTE170M / also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC" - << "SMPTE240M" - << "FILM - colour filters using Illuminant C" - << "ITU-R BT2020" - << "SMPTE ST 428-1 (CIE 1931 XYZ)" - << "SMPTE ST 431-2 (2011)" - << "SMPTE ST 432-1 D65 (2010)" - << "Not part of ABI"; - info.append(QStringPair("Color Primaries", colorPrimaries.at((int)this->color_primaries))); - auto colorTransfers = - QStringList() - << "Reserved" - << "BT709 / ITU-R BT1361" - << "Unspecified" - << "Reserved" - << "Gamma22 / ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM" - << "Gamma28 / ITU-R BT470BG" - << "SMPTE170M / ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC" - << "SMPTE240M" - << "Linear transfer characteristics" - << "Logarithmic transfer characteristic (100:1 range)" - << "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" - << "IEC 61966-2-4" - << "ITU-R BT1361 Extended Colour Gamut" - << "IEC 61966-2-1 (sRGB or sYCC)" - << "ITU-R BT2020 for 10-bit system" - << "ITU-R BT2020 for 12-bit system" - << "SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems" - << "SMPTE ST 428-1" - << "ARIB STD-B67, known as Hybrid log-gamma" - << "Not part of ABI"; - info.append({"Color Transfer", colorTransfers.at((int)this->color_trc)}); - auto colorSpaces = QStringList() - << "RGB - order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB)" - << "BT709 / ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B" - << "Unspecified" - << "Reserved" - << "FCC Title 47 Code of Federal Regulations 73.682 (a)(20)" - << "BT470BG / ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & " - "SECAM / IEC 61966-2-4 xvYCC601" - << "SMPTE170M / ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC" - << "SMPTE240M" - << "YCOCG - Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16" - << "ITU-R BT2020 non-constant luminance system" - << "ITU-R BT2020 constant luminance system" - << "SMPTE 2085, Y'D'zD'x" - << "Not part of ABI"; - info.append({"Color Space", colorSpaces.at((int)this->color_space)}); - auto chromaLocations = QStringList() - << "Unspecified" - << "Left / MPEG-2/4 4:2:0, H.264 default for 4:2:0" - << "Center / MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0" - << "Top Left / ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2" - << "Top" - << "Bottom Left" - << "Bottom" - << "Not part of ABI"; - info.append({"Chroma Location", chromaLocations.at((int)this->chroma_location)}); - info.append({"Video Delay", QString::number(this->video_delay)}); - - return info; -} - void AVCodecParametersWrapper::setClearValues() { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); p->codec_type = AVMEDIA_TYPE_UNKNOWN; @@ -265,8 +159,10 @@ void AVCodecParametersWrapper::setClearValues() void AVCodecParametersWrapper::setAVMediaType(AVMediaType type) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); p->codec_type = type; @@ -276,8 +172,10 @@ void AVCodecParametersWrapper::setAVMediaType(AVMediaType type) void AVCodecParametersWrapper::setAVCodecID(AVCodecID id) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); p->codec_id = id; @@ -285,22 +183,26 @@ void AVCodecParametersWrapper::setAVCodecID(AVCodecID id) } } -void AVCodecParametersWrapper::setExtradata(QByteArray data) +void AVCodecParametersWrapper::setExtradata(const ByteVector &data) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { this->extradata = data; auto p = reinterpret_cast(this->param); p->extradata = reinterpret_cast(this->extradata.data()); - p->extradata_size = this->extradata.length(); + p->extradata_size = static_cast(this->extradata.size()); } } void AVCodecParametersWrapper::setSize(Size size) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); p->width = size.width; @@ -312,8 +214,10 @@ void AVCodecParametersWrapper::setSize(Size size) void AVCodecParametersWrapper::setAVPixelFormat(AVPixelFormat format) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); p->format = format; @@ -323,8 +227,10 @@ void AVCodecParametersWrapper::setAVPixelFormat(AVPixelFormat format) void AVCodecParametersWrapper::setProfileLevel(int profile, int level) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); p->profile = profile; @@ -336,8 +242,10 @@ void AVCodecParametersWrapper::setProfileLevel(int profile, int level) void AVCodecParametersWrapper::setSampleAspectRatio(int num, int den) { - if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(param); AVRational ratio; @@ -353,20 +261,22 @@ void AVCodecParametersWrapper::update() if (this->param == nullptr) return; - if (this->libVer.avformat.major == 56) + if (this->libraryVersions.avformat.major == 56) { // This data structure does not exist in avformat major version 56. this->param = nullptr; } - else if (this->libVer.avformat.major == 57 || this->libVer.avformat.major == 58 || - this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + else if (this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->param); this->codec_type = p->codec_type; this->codec_id = p->codec_id; this->codec_tag = p->codec_tag; - this->extradata = QByteArray((const char *)p->extradata, p->extradata_size); + this->extradata = copyDataFromRawArray(p->extradata, p->extradata_size); this->format = p->format; this->bit_rate = p->bit_rate; this->bits_per_coded_sample = p->bits_per_coded_sample; @@ -388,4 +298,4 @@ void AVCodecParametersWrapper::update() throw std::runtime_error("Invalid library version"); } -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVCodecParametersWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecParametersWrapper.h similarity index 88% rename from YUViewLib/src/ffmpeg/AVCodecParametersWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecParametersWrapper.h index 3542e11bb..2aab2e70a 100644 --- a/YUViewLib/src/ffmpeg/AVCodecParametersWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecParametersWrapper.h @@ -32,22 +32,20 @@ #pragma once -#include "FFMpegLibrariesTypes.h" -#include +#include -namespace FFmpeg +namespace LibFFmpeg { class AVCodecParametersWrapper { public: AVCodecParametersWrapper() = default; - AVCodecParametersWrapper(AVCodecParameters *p, LibraryVersion v); - explicit operator bool() const { return this->param != nullptr; } - QStringPairList getInfoText(); + AVCodecParametersWrapper(AVCodecParameters *p, const LibraryVersions &libraryVersions); + explicit operator bool() const { return this->param != nullptr; } AVMediaType getCodecType(); AVCodecID getCodecID(); - QByteArray getExtradata(); + ByteVector getExtradata(); Size getSize(); AVColorSpace getColorspace(); AVPixelFormat getPixelFormat(); @@ -58,7 +56,7 @@ class AVCodecParametersWrapper void setAVMediaType(AVMediaType type); void setAVCodecID(AVCodecID id); - void setExtradata(QByteArray extradata); + void setExtradata(const ByteVector &extradata); void setSize(Size size); void setAVPixelFormat(AVPixelFormat f); void setProfileLevel(int profile, int level); @@ -74,7 +72,7 @@ class AVCodecParametersWrapper AVMediaType codec_type{}; AVCodecID codec_id{}; uint32_t codec_tag{}; - QByteArray extradata{}; + ByteVector extradata{}; int format{}; int64_t bit_rate{}; int bits_per_coded_sample{}; @@ -93,7 +91,7 @@ class AVCodecParametersWrapper int video_delay{}; AVCodecParameters *param{}; - LibraryVersion libVer{}; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVCodecWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecWrapper.cpp similarity index 84% rename from YUViewLib/src/ffmpeg/AVCodecWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecWrapper.cpp index 2d826e43c..d65519a3f 100644 --- a/YUViewLib/src/ffmpeg/AVCodecWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecWrapper.cpp @@ -33,7 +33,7 @@ #include "AVCodecWrapper.h" #include -namespace FFmpeg +namespace LibFFmpeg { namespace @@ -90,16 +90,40 @@ template std::vector convertRawListToVec(const T *rawValues, T t } // namespace +AVCodecWrapper::AVCodecWrapper(AVCodec *codec, const LibraryVersions &libraryVersions) + : codec(codec), libraryVersions(libraryVersions) +{ +} + +AVCodecID AVCodecWrapper::getCodecID() +{ + this->update(); + return this->id; +} + +std::string AVCodecWrapper::getName() +{ + this->update(); + return this->name; +} +std::string AVCodecWrapper::getLongName() +{ + this->update(); + return this->long_name; +} + void AVCodecWrapper::update() { if (codec == nullptr) return; - if (libVer.avcodec.major == 56 || libVer.avcodec.major == 57 || libVer.avcodec.major == 58) + if (libraryVersions.avcodec.major == 56 || // + libraryVersions.avcodec.major == 57 || // + libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(codec); - this->name = QString(p->name); - this->long_name = QString(p->long_name); + this->name = std::string(p->name); + this->long_name = std::string(p->long_name); this->type = p->type; this->id = p->id; this->capabilities = p->capabilities; @@ -110,11 +134,11 @@ void AVCodecWrapper::update() this->channel_layouts = convertRawListToVec(p->channel_layouts, uint64_t(0)); this->max_lowres = p->max_lowres; } - else if (libVer.avcodec.major == 59) + else if (libraryVersions.avcodec.major == 59) { auto p = reinterpret_cast(codec); - this->name = QString(p->name); - this->long_name = QString(p->long_name); + this->name = std::string(p->name); + this->long_name = std::string(p->long_name); this->type = p->type; this->id = p->id; this->capabilities = p->capabilities; @@ -129,4 +153,4 @@ void AVCodecWrapper::update() throw std::runtime_error("Invalid library version"); } -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg \ No newline at end of file diff --git a/YUViewLib/src/ffmpeg/AVCodecWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecWrapper.h similarity index 76% rename from YUViewLib/src/ffmpeg/AVCodecWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecWrapper.h index 9ce2bee89..ef1cbe408 100644 --- a/YUViewLib/src/ffmpeg/AVCodecWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVCodecWrapper.h @@ -32,41 +32,31 @@ #pragma once -#include "FFMpegLibrariesTypes.h" +#include #include -namespace FFmpeg +namespace LibFFmpeg { class AVCodecWrapper { public: - AVCodecWrapper() {} - AVCodecWrapper(AVCodec *codec, LibraryVersion libVer) : codec(codec), libVer(libVer) {} - explicit operator bool() const { return this->codec != nullptr; } - AVCodec * getAVCodec() { return this->codec; } - AVCodecID getCodecID() - { - update(); - return this->id; - } - QString getName() - { - update(); - return this->name; - } - QString getLongName() - { - update(); - return this->long_name; - } + AVCodecWrapper() = default; + AVCodecWrapper(AVCodec *codec, const LibraryVersions &libraryVersions); + + explicit operator bool() const { return this->codec != nullptr; } + AVCodec *getAVCodec() { return this->codec; } + + AVCodecID getCodecID(); + std::string getName(); + std::string getLongName(); private: void update(); - QString name{}; - QString long_name{}; + std::string name{}; + std::string long_name{}; AVMediaType type; AVCodecID id{AV_CODEC_ID_NONE}; int capabilities{0}; @@ -77,8 +67,8 @@ class AVCodecWrapper std::vector channel_layouts; uint8_t max_lowres{0}; - AVCodec * codec{nullptr}; - LibraryVersion libVer; + AVCodec * codec{nullptr}; + LibraryVersions libraryVersions; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVDictionaryWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVDictionaryWrapper.h similarity index 95% rename from YUViewLib/src/ffmpeg/AVDictionaryWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVDictionaryWrapper.h index 7818a31d8..728963d2a 100644 --- a/YUViewLib/src/ffmpeg/AVDictionaryWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVDictionaryWrapper.h @@ -32,9 +32,9 @@ #pragma once -#include "FFMpegLibrariesTypes.h" +#include -namespace FFmpeg +namespace LibFFmpeg { class AVDictionaryWrapper @@ -51,4 +51,4 @@ class AVDictionaryWrapper AVDictionary *dict{}; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVFormatContextWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFormatContextWrapper.cpp similarity index 80% rename from YUViewLib/src/ffmpeg/AVFormatContextWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFormatContextWrapper.cpp index 4bcc37278..4c6a3923c 100644 --- a/YUViewLib/src/ffmpeg/AVFormatContextWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFormatContextWrapper.cpp @@ -33,7 +33,7 @@ #include "AVFormatContextWrapper.h" #include "AVStreamWrapper.h" -namespace FFmpeg +namespace LibFFmpeg { namespace @@ -184,10 +184,11 @@ typedef struct AVFormatContext_59_60 } // namespace -AVFormatContextWrapper::AVFormatContextWrapper(AVFormatContext *c, LibraryVersion v) +AVFormatContextWrapper::AVFormatContextWrapper(AVFormatContext * c, + const LibraryVersions &libraryVersions) { - this->ctx = c; - this->libVer = v; + this->ctx = c; + this->libraryVersions = libraryVersions; this->update(); } @@ -252,14 +253,14 @@ void AVFormatContextWrapper::update() this->streams.clear(); // Copy values from the source pointer - if (this->libVer.avformat.major == 56) + if (this->libraryVersions.avformat.major == 56) { auto p = reinterpret_cast(this->ctx); this->ctx_flags = p->ctx_flags; this->nb_streams = p->nb_streams; for (unsigned i = 0; i < this->nb_streams; i++) - this->streams.append(AVStreamWrapper(p->streams[i], this->libVer)); - this->filename = QString(p->filename); + this->streams.push_back(AVStreamWrapper(p->streams[i], this->libraryVersions)); + this->filename = std::string(p->filename); this->start_time = p->start_time; this->duration = p->duration; this->bit_rate = p->bit_rate; @@ -268,7 +269,7 @@ void AVFormatContextWrapper::update() this->flags = p->flags; this->probesize = p->probesize; this->max_analyze_duration = p->max_analyze_duration; - this->key = QString::fromLatin1((const char *)p->key, p->keylen); + this->key = std::string((const char *)p->key, p->keylen); this->nb_programs = p->nb_programs; this->video_codec_id = p->video_codec_id; this->audio_codec_id = p->audio_codec_id; @@ -278,16 +279,16 @@ void AVFormatContextWrapper::update() this->nb_chapters = p->nb_chapters; this->metadata = AVDictionaryWrapper(p->metadata); - this->iformat = AVInputFormatWrapper(p->iformat, libVer); + this->iformat = AVInputFormatWrapper(p->iformat, this->libraryVersions); } - else if (this->libVer.avformat.major == 57) + else if (this->libraryVersions.avformat.major == 57) { auto p = reinterpret_cast(this->ctx); this->ctx_flags = p->ctx_flags; this->nb_streams = p->nb_streams; for (unsigned i = 0; i < nb_streams; i++) - this->streams.append(AVStreamWrapper(p->streams[i], this->libVer)); - this->filename = QString(p->filename); + this->streams.push_back(AVStreamWrapper(p->streams[i], this->libraryVersions)); + this->filename = std::string(p->filename); this->start_time = p->start_time; this->duration = p->duration; this->bit_rate = p->bit_rate; @@ -296,7 +297,7 @@ void AVFormatContextWrapper::update() this->flags = p->flags; this->probesize = p->probesize; this->max_analyze_duration = p->max_analyze_duration; - this->key = QString::fromLatin1((const char *)p->key, p->keylen); + this->key = std::string((const char *)p->key, p->keylen); this->nb_programs = p->nb_programs; this->video_codec_id = p->video_codec_id; this->audio_codec_id = p->audio_codec_id; @@ -306,16 +307,16 @@ void AVFormatContextWrapper::update() this->nb_chapters = p->nb_chapters; this->metadata = AVDictionaryWrapper(p->metadata); - this->iformat = AVInputFormatWrapper(p->iformat, libVer); + this->iformat = AVInputFormatWrapper(p->iformat, this->libraryVersions); } - else if (this->libVer.avformat.major == 58) + else if (this->libraryVersions.avformat.major == 58) { auto p = reinterpret_cast(this->ctx); this->ctx_flags = p->ctx_flags; this->nb_streams = p->nb_streams; for (unsigned i = 0; i < nb_streams; i++) - this->streams.append(AVStreamWrapper(p->streams[i], this->libVer)); - this->filename = QString(p->filename); + this->streams.push_back(AVStreamWrapper(p->streams[i], this->libraryVersions)); + this->filename = std::string(p->filename); this->start_time = p->start_time; this->duration = p->duration; this->bit_rate = p->bit_rate; @@ -324,7 +325,7 @@ void AVFormatContextWrapper::update() this->flags = p->flags; this->probesize = p->probesize; this->max_analyze_duration = p->max_analyze_duration; - this->key = QString::fromLatin1((const char *)p->key, p->keylen); + this->key = std::string((const char *)p->key, p->keylen); this->nb_programs = p->nb_programs; this->video_codec_id = p->video_codec_id; this->audio_codec_id = p->audio_codec_id; @@ -334,16 +335,17 @@ void AVFormatContextWrapper::update() this->nb_chapters = p->nb_chapters; this->metadata = AVDictionaryWrapper(p->metadata); - this->iformat = AVInputFormatWrapper(p->iformat, this->libVer); + this->iformat = AVInputFormatWrapper(p->iformat, this->libraryVersions); } - else if (this->libVer.avformat.major == 59 || this->libVer.avformat.major == 60) + else if (this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { auto p = reinterpret_cast(this->ctx); this->ctx_flags = p->ctx_flags; this->nb_streams = p->nb_streams; for (unsigned i = 0; i < nb_streams; i++) - this->streams.append(AVStreamWrapper(p->streams[i], this->libVer)); - this->filename = QString(p->url); + this->streams.push_back(AVStreamWrapper(p->streams[i], this->libraryVersions)); + this->filename = std::string(p->url); this->start_time = p->start_time; this->duration = p->duration; this->bit_rate = p->bit_rate; @@ -352,7 +354,7 @@ void AVFormatContextWrapper::update() this->flags = p->flags; this->probesize = p->probesize; this->max_analyze_duration = p->max_analyze_duration; - this->key = QString::fromLatin1((const char *)p->key, p->keylen); + this->key = std::string((const char *)p->key, p->keylen); this->nb_programs = p->nb_programs; this->video_codec_id = p->video_codec_id; this->audio_codec_id = p->audio_codec_id; @@ -362,51 +364,10 @@ void AVFormatContextWrapper::update() this->nb_chapters = p->nb_chapters; this->metadata = AVDictionaryWrapper(p->metadata); - this->iformat = AVInputFormatWrapper(p->iformat, this->libVer); + this->iformat = AVInputFormatWrapper(p->iformat, this->libraryVersions); } else throw std::runtime_error("Invalid library version"); } -QStringPairList AVFormatContextWrapper::getInfoText() -{ - if (this->ctx == nullptr) - return {QStringPair("Format context not initialized", "")}; - - this->update(); - - QStringPairList info; - if (this->ctx_flags != 0) - { - QString flags; - if (this->ctx_flags & 1) - flags += QString("No-Header"); - if (this->ctx_flags & 2) - flags += QString("Un-seekable"); - info.append(QStringPair("Flags", flags)); - } - - AVRational time_base; - time_base.num = 1; - time_base.den = AV_TIME_BASE; - - info.append(QStringPair("Number streams", QString::number(this->nb_streams))); - info.append(QStringPair("File name", this->filename)); - info.append(QStringPair("Start time", - QString("%1 (%2)") - .arg(this->start_time) - .arg(timestampToString(this->start_time, time_base)))); - info.append(QStringPair( - "Duration", - QString("%1 (%2)").arg(this->duration).arg(timestampToString(duration, time_base)))); - if (bit_rate > 0) - info.append(QStringPair("Bitrate", QString::number(this->bit_rate))); - info.append(QStringPair("Packet size", QString::number(this->packet_size))); - info.append(QStringPair("Max delay", QString::number(this->max_delay))); - info.append(QStringPair("Number programs", QString::number(this->nb_programs))); - info.append(QStringPair("Number chapters", QString::number(this->nb_chapters))); - - return info; -} - -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVFormatContextWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFormatContextWrapper.h similarity index 78% rename from YUViewLib/src/ffmpeg/AVFormatContextWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFormatContextWrapper.h index 8059c51f2..d7d926484 100644 --- a/YUViewLib/src/ffmpeg/AVFormatContextWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFormatContextWrapper.h @@ -36,21 +36,20 @@ #include "AVInputFormatWrapper.h" #include "AVPacketWrapper.h" #include "AVStreamWrapper.h" -#include "FFMpegLibrariesTypes.h" -#include -namespace FFmpeg +#include + +namespace LibFFmpeg { class AVFormatContextWrapper { public: AVFormatContextWrapper() = default; - AVFormatContextWrapper(AVFormatContext *c, LibraryVersion v); + AVFormatContextWrapper(AVFormatContext *c, const LibraryVersions &libraryVersions); - void updateFrom(AVFormatContext *c); - explicit operator bool() const; - QStringPairList getInfoText(); + void updateFrom(AVFormatContext *c); + explicit operator bool() const; unsigned int getNbStreams(); AVStreamWrapper getStream(int idx); @@ -67,20 +66,20 @@ class AVFormatContextWrapper AVInputFormatWrapper iformat{}; // These are private. Use "update" to update them from the AVFormatContext - int ctx_flags{0}; - unsigned int nb_streams{0}; - QList streams; - QString filename{}; - int64_t start_time{-1}; - int64_t duration{-1}; - int bit_rate{0}; - unsigned int packet_size{0}; - int max_delay{0}; - int flags{0}; + int ctx_flags{0}; + unsigned int nb_streams{0}; + std::vector streams; + std::string filename{}; + int64_t start_time{-1}; + int64_t duration{-1}; + int bit_rate{0}; + unsigned int packet_size{0}; + int max_delay{0}; + int flags{0}; unsigned int probesize{0}; int max_analyze_duration{0}; - QString key{}; + std::string key{}; unsigned int nb_programs{0}; AVCodecID video_codec_id{AV_CODEC_ID_NONE}; AVCodecID audio_codec_id{AV_CODEC_ID_NONE}; @@ -91,7 +90,7 @@ class AVFormatContextWrapper AVDictionaryWrapper metadata; AVFormatContext *ctx{nullptr}; - LibraryVersion libVer{}; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVFrameSideDataWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameSideDataWrapper.cpp similarity index 65% rename from YUViewLib/src/ffmpeg/AVFrameSideDataWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameSideDataWrapper.cpp index 2e905b1d4..281f9661b 100644 --- a/YUViewLib/src/ffmpeg/AVFrameSideDataWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameSideDataWrapper.cpp @@ -33,7 +33,7 @@ #include "AVFrameSideDataWrapper.h" #include -namespace FFmpeg +namespace LibFFmpeg { namespace @@ -59,56 +59,40 @@ typedef struct AVFrameSideData_57_58 } // namespace -AVFrameSideDataWrapper::AVFrameSideDataWrapper(AVFrameSideData *sideData, LibraryVersion libVer) - : sideData(sideData), libVer(libVer) +AVFrameSideDataWrapper::AVFrameSideDataWrapper(AVFrameSideData * sideData, + const LibraryVersions &libraryVersions) + : sideData(sideData), libraryVersions(libraryVersions) { - this->update(); } -size_t AVFrameSideDataWrapper::getNumberMotionVectors() -{ - this->update(); - - if (this->type != AV_FRAME_DATA_MOTION_VECTORS) - return 0; - - return AVMotionVectorWrapper::getNumberOfMotionVectors(this->libVer, this->size); -} - -AVMotionVectorWrapper AVFrameSideDataWrapper::getMotionVector(unsigned idx) -{ - this->update(); - return AVMotionVectorWrapper(this->libVer, this->data, idx); -} - -void AVFrameSideDataWrapper::update() +std::vector AVFrameSideDataWrapper::getMotionVectors() const { if (this->sideData == nullptr) - return; + return {}; - if (this->libVer.avutil.major == 54 || // - this->libVer.avutil.major == 55 || // - this->libVer.avutil.major == 56) + if (this->libraryVersions.avutil.major == 54 || // + this->libraryVersions.avutil.major == 55 || // + this->libraryVersions.avutil.major == 56) { - auto p = reinterpret_cast(sideData); - this->type = p->type; - this->data = p->data; - if (p->size > 0) - this->size = size_t(p->size); - this->metadata = p->metadata; - this->buf = p->buf; + auto p = reinterpret_cast(sideData); + + if (p->type != AV_FRAME_DATA_MOTION_VECTORS) + return {}; + + return parseMotionData(this->libraryVersions, p->data, p->size); } - else if (this->libVer.avutil.major == 57 || this->libVer.avutil.major == 58) + else if (this->libraryVersions.avutil.major == 57 || // + this->libraryVersions.avutil.major == 58) { - auto p = reinterpret_cast(sideData); - this->type = p->type; - this->data = p->data; - this->size = p->size; - this->metadata = p->metadata; - this->buf = p->buf; + auto p = reinterpret_cast(sideData); + + if (p->type != AV_FRAME_DATA_MOTION_VECTORS) + return {}; + + return parseMotionData(this->libraryVersions, p->data, p->size); } else throw std::runtime_error("Invalid library version"); } -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVFrameSideDataWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameSideDataWrapper.h similarity index 78% rename from YUViewLib/src/ffmpeg/AVFrameSideDataWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameSideDataWrapper.h index a3169e9c0..007f1266f 100644 --- a/YUViewLib/src/ffmpeg/AVFrameSideDataWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameSideDataWrapper.h @@ -32,34 +32,25 @@ #pragma once -#include "AVMotionVectorWrapper.h" -#include "FFMpegLibrariesTypes.h" +#include +#include -namespace FFmpeg +namespace LibFFmpeg { class AVFrameSideDataWrapper { public: AVFrameSideDataWrapper() = default; - AVFrameSideDataWrapper(AVFrameSideData *sideData, LibraryVersion libVer); + AVFrameSideDataWrapper(AVFrameSideData *sideData, const LibraryVersions &libraryVersions); - size_t getNumberMotionVectors(); - AVMotionVectorWrapper getMotionVector(unsigned idx); + std::vector getMotionVectors() const; explicit operator bool() const { return sideData != nullptr; } private: - void update(); - - AVFrameSideDataType type{}; - uint8_t * data{nullptr}; - size_t size{}; - AVDictionary * metadata{}; - AVBufferRef * buf{}; - AVFrameSideData *sideData{}; - LibraryVersion libVer; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVFrameWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameWrapper.cpp similarity index 91% rename from YUViewLib/src/ffmpeg/AVFrameWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameWrapper.cpp index de10570c9..55bdb21df 100644 --- a/YUViewLib/src/ffmpeg/AVFrameWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameWrapper.cpp @@ -33,7 +33,7 @@ #include "AVFrameWrapper.h" #include -namespace FFmpeg +namespace LibFFmpeg { namespace @@ -127,16 +127,16 @@ typedef struct AVFrame_57_58 } // namespace -AVFrameWrapper::AVFrameWrapper(LibraryVersion libVersion, AVFrame *frame) +AVFrameWrapper::AVFrameWrapper(AVFrame *frame, const LibraryVersions &libraryVersions) { - this->libVer = libVersion; - this->frame = frame; + this->frame = frame; + this->libraryVersions = libraryVersions; } void AVFrameWrapper::clear() { - this->frame = nullptr; - this->libVer = {}; + this->frame = nullptr; + this->libraryVersions = {}; } uint8_t *AVFrameWrapper::getData(int component) @@ -171,7 +171,7 @@ int AVFrameWrapper::getHeight() Size AVFrameWrapper::getSize() { this->update(); - return Size(width, height); + return Size({width, height}); } int AVFrameWrapper::getPTS() @@ -194,7 +194,7 @@ int AVFrameWrapper::getKeyFrame() AVDictionary *AVFrameWrapper::getMetadata() { - assert(this->libVer.avutil.major >= 57); + assert(this->libraryVersions.avutil.major >= 57); this->update(); return this->metadata; } @@ -204,10 +204,10 @@ void AVFrameWrapper::update() if (this->frame == nullptr) return; - if (this->libVer.avutil.major == 54) + if (this->libraryVersions.avutil.major == 54) { auto p = reinterpret_cast(this->frame); - for (unsigned i = 0; i < AV_NUM_DATA_POINTERS; i++) + for (auto i = 0; i < AV_NUM_DATA_POINTERS; ++i) { this->data[i] = p->data[i]; this->linesize[i] = p->linesize[i]; @@ -226,11 +226,11 @@ void AVFrameWrapper::update() this->display_picture_number = p->display_picture_number; this->quality = p->quality; } - else if (this->libVer.avutil.major == 55 || // - this->libVer.avutil.major == 56) + else if (this->libraryVersions.avutil.major == 55 || // + this->libraryVersions.avutil.major == 56) { auto p = reinterpret_cast(this->frame); - for (unsigned i = 0; i < AV_NUM_DATA_POINTERS; i++) + for (auto i = 0; i < AV_NUM_DATA_POINTERS; ++i) { this->data[i] = p->data[i]; this->linesize[i] = p->linesize[i]; @@ -249,11 +249,11 @@ void AVFrameWrapper::update() this->display_picture_number = p->display_picture_number; this->quality = p->quality; } - else if (this->libVer.avutil.major == 57 || // - this->libVer.avutil.major == 58) + else if (this->libraryVersions.avutil.major == 57 || // + this->libraryVersions.avutil.major == 58) { auto p = reinterpret_cast(this->frame); - for (unsigned i = 0; i < AV_NUM_DATA_POINTERS; i++) + for (auto i = 0; i < AV_NUM_DATA_POINTERS; ++i) { this->data[i] = p->data[i]; this->linesize[i] = p->linesize[i]; @@ -277,4 +277,4 @@ void AVFrameWrapper::update() throw std::runtime_error("Invalid library version"); } -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVFrameWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameWrapper.h similarity index 91% rename from YUViewLib/src/ffmpeg/AVFrameWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameWrapper.h index 72b3998fc..4dd65ef52 100644 --- a/YUViewLib/src/ffmpeg/AVFrameWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVFrameWrapper.h @@ -32,18 +32,16 @@ #pragma once -#include "FFMpegLibrariesTypes.h" -#include +#include -namespace FFmpeg +namespace LibFFmpeg { class AVFrameWrapper { public: AVFrameWrapper() = default; - AVFrameWrapper(LibraryVersion libVersion, AVFrame *frame); - ~AVFrameWrapper() = default; + AVFrameWrapper(AVFrame *frame, const LibraryVersions &libraryVersions); void clear(); @@ -81,8 +79,8 @@ class AVFrameWrapper int quality{}; AVDictionary *metadata{}; - AVFrame * frame{}; - LibraryVersion libVer{}; + AVFrame * frame{}; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVInputFormatWrapper.cpp similarity index 73% rename from YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVInputFormatWrapper.cpp index 7362e3372..561f0aebe 100644 --- a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVInputFormatWrapper.cpp @@ -32,7 +32,7 @@ #include "AVInputFormatWrapper.h" -namespace FFmpeg +namespace LibFFmpeg { namespace @@ -53,36 +53,32 @@ typedef struct AVInputFormat_56_57_58_59_60 } // namespace -AVInputFormatWrapper::AVInputFormatWrapper() +AVInputFormatWrapper::AVInputFormatWrapper(AVInputFormat * avInputFormat, + const LibraryVersions &libraryVersions) { - this->fmt = nullptr; -} - -AVInputFormatWrapper::AVInputFormatWrapper(AVInputFormat *f, LibraryVersion v) -{ - this->fmt = f; - this->libVer = v; + this->avInputFormat = avInputFormat; + this->libraryVersions = libraryVersions; this->update(); } void AVInputFormatWrapper::update() { - if (this->fmt == nullptr) + if (this->avInputFormat == nullptr) return; - if (this->libVer.avformat.major == 56 || // - this->libVer.avformat.major == 57 || // - this->libVer.avformat.major == 58 || // - this->libVer.avformat.major == 59 || // - this->libVer.avformat.major == 60) + if (this->libraryVersions.avformat.major == 56 || // + this->libraryVersions.avformat.major == 57 || // + this->libraryVersions.avformat.major == 58 || // + this->libraryVersions.avformat.major == 59 || // + this->libraryVersions.avformat.major == 60) { - auto p = reinterpret_cast(this->fmt); - this->name = QString(p->name); - this->long_name = QString(p->long_name); + auto p = reinterpret_cast(this->avInputFormat); + this->name = std::string(p->name); + this->long_name = std::string(p->long_name); this->flags = p->flags; - this->extensions = QString(p->extensions); - this->mime_type = QString(p->mime_type); + this->extensions = std::string(p->extensions); + this->mime_type = std::string(p->mime_type); } } -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVInputFormatWrapper.h similarity index 78% rename from YUViewLib/src/ffmpeg/AVInputFormatWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVInputFormatWrapper.h index ec1ebdf2c..30f646f2f 100644 --- a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVInputFormatWrapper.h @@ -32,34 +32,32 @@ #pragma once -#include "FFMpegLibrariesTypes.h" +#include -namespace FFmpeg +namespace LibFFmpeg { class AVInputFormatWrapper { public: - AVInputFormatWrapper(); - AVInputFormatWrapper(AVInputFormat *f, LibraryVersion v); + AVInputFormatWrapper() = default; + AVInputFormatWrapper(AVInputFormat *avInputFormat, const LibraryVersions &libraryVersions); - explicit operator bool() const { return fmt != nullptr; }; + explicit operator bool() const { return this->avInputFormat != nullptr; }; private: // Update all private values from the AVCodecContext void update(); // These are here for debugging purposes. - QString name{}; - QString long_name{}; - int flags{}; - QString extensions{}; - // const struct AVCodecTag * const *codec_tag; - // const AVClass *priv_class; - QString mime_type{}; - - AVInputFormat *fmt{}; - LibraryVersion libVer{}; + std::string name{}; + std::string long_name{}; + int flags{}; + std::string extensions{}; + std::string mime_type{}; + + AVInputFormat * avInputFormat{}; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVPacketWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPacketWrapper.cpp similarity index 53% rename from YUViewLib/src/ffmpeg/AVPacketWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPacketWrapper.cpp index 1d144ca97..13a8396f0 100644 --- a/YUViewLib/src/ffmpeg/AVPacketWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPacketWrapper.cpp @@ -31,125 +31,32 @@ */ #include "AVPacketWrapper.h" -#include -#include -namespace FFmpeg +namespace LibFFmpeg { -namespace -{ - -bool checkForRawNALFormat(QByteArray &data, bool threeByteStartCode) -{ - if (threeByteStartCode && data.length() > 3 && data.at(0) == (char)0 && data.at(1) == (char)0 && - data.at(2) == (char)1) - return true; - if (!threeByteStartCode && data.length() > 4 && data.at(0) == (char)0 && data.at(1) == (char)0 && - data.at(2) == (char)0 && data.at(3) == (char)1) - return true; - return false; -} - -bool checkForMp4Format(QByteArray &data) -{ - // Check the ISO mp4 format: Parse the whole data and check if the size bytes per Unit are - // correct. - uint64_t posInData = 0; - while (posInData + 4 <= uint64_t(data.length())) - { - auto firstBytes = data.mid(posInData, 4); - - unsigned size = (unsigned char)firstBytes.at(3); - size += (unsigned char)firstBytes.at(2) << 8; - size += (unsigned char)firstBytes.at(1) << 16; - size += (unsigned char)firstBytes.at(0) << 24; - posInData += 4; - - if (size > 1'000'000'000) - // A Nal with more then 1GB? This is probably an error. - return false; - if (posInData + size > uint64_t(data.length())) - // Not enough data in the input array to read NAL unit. - return false; - posInData += size; - } - return true; -} - -bool checkForObuFormat(QByteArray &data) -{ - // TODO: We already have an implementation of this in the parser - // That should also be used here so we only have one place where we parse OBUs. - try - { - size_t posInData = 0; - while (posInData + 2 <= size_t(data.length())) - { - parser::reader::SubByteReaderLogging reader( - parser::reader::SubByteReaderLogging::convertToByteVector(data), nullptr, "", posInData); - - QString bitsRead; - auto forbiddenBit = reader.readFlag("obu_forbidden_bit"); - if (forbiddenBit) - return false; - auto obu_type = reader.readBits("obu_type", 4); - if (obu_type == 0 || (obu_type >= 9 && obu_type <= 14)) - // RESERVED obu types should not occur (highly unlikely) - return false; - auto obu_extension_flag = reader.readFlag("obu_extension_flag"); - auto obu_has_size_field = reader.readFlag("obu_has_size_field"); - reader.readFlag("obu_reserved_1bit", parser::reader::Options().withCheckEqualTo(1)); - - if (obu_extension_flag) - { - reader.readBits("temporal_id", 3); - reader.readBits("spatial_id", 2); - reader.readBits( - "extension_header_reserved_3bits", 3, parser::reader::Options().withCheckEqualTo(0)); - } - size_t obu_size; - if (obu_has_size_field) - { - obu_size = reader.readLEB128("obu_size"); - } - else - { - obu_size = (size_t(data.size()) - posInData) - 1 - (obu_extension_flag ? 1 : 0); - } - posInData += obu_size + reader.nrBytesRead(); - } - } - catch (...) - { - return false; - } - return true; -} - -} // namespace - -AVPacketWrapper::AVPacketWrapper(LibraryVersion libVersion, AVPacket *packet) +AVPacketWrapper::AVPacketWrapper(AVPacket *packet, const LibraryVersions &libraryVersions) { assert(packet != nullptr); - this->libVer = libVersion; + this->libraryVersions = libraryVersions; - if (this->libVer.avcodec.major == 56) + if (this->libraryVersions.avcodec.major == 56) { auto p = reinterpret_cast(packet); p->data = nullptr; p->size = 0; this->pkt = reinterpret_cast(p); } - else if (this->libVer.avcodec.major == 57 || this->libVer.avcodec.major == 58) + else if (this->libraryVersions.avcodec.major == 57 || // + this->libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(packet); p->data = nullptr; p->size = 0; this->pkt = reinterpret_cast(p); } - else if (this->libVer.avcodec.major == 59 || // - this->libVer.avcodec.major == 60) + else if (this->libraryVersions.avcodec.major == 59 || // + this->libraryVersions.avcodec.major == 60) { auto p = reinterpret_cast(packet); p->data = nullptr; @@ -162,13 +69,13 @@ AVPacketWrapper::AVPacketWrapper(LibraryVersion libVersion, AVPacket *packet) void AVPacketWrapper::clear() { - this->pkt = nullptr; - this->libVer = {}; + this->pkt = nullptr; + this->libraryVersions = {}; } void AVPacketWrapper::setData(QByteArray &set_data) { - if (this->libVer.avcodec.major == 56) + if (this->libraryVersions.avcodec.major == 56) { auto p = reinterpret_cast(this->pkt); p->data = (uint8_t *)set_data.data(); @@ -176,7 +83,8 @@ void AVPacketWrapper::setData(QByteArray &set_data) data = p->data; size = p->size; } - else if (this->libVer.avcodec.major == 57 || this->libVer.avcodec.major == 58) + else if (this->libraryVersions.avcodec.major == 57 || // + this->libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(this->pkt); p->data = (uint8_t *)set_data.data(); @@ -184,8 +92,8 @@ void AVPacketWrapper::setData(QByteArray &set_data) data = p->data; size = p->size; } - else if (this->libVer.avcodec.major == 59 || // - this->libVer.avcodec.major == 60) + else if (this->libraryVersions.avcodec.major == 59 || // + this->libraryVersions.avcodec.major == 60) { auto p = reinterpret_cast(this->pkt); p->data = (uint8_t *)set_data.data(); @@ -199,20 +107,21 @@ void AVPacketWrapper::setData(QByteArray &set_data) void AVPacketWrapper::setPTS(int64_t pts) { - if (this->libVer.avcodec.major == 56) + if (this->libraryVersions.avcodec.major == 56) { auto p = reinterpret_cast(this->pkt); p->pts = pts; this->pts = pts; } - else if (this->libVer.avcodec.major == 57 || this->libVer.avcodec.major == 58) + else if (this->libraryVersions.avcodec.major == 57 || // + this->libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(this->pkt); p->pts = pts; this->pts = pts; } - else if (this->libVer.avcodec.major == 59 || // - this->libVer.avcodec.major == 60) + else if (this->libraryVersions.avcodec.major == 59 || // + this->libraryVersions.avcodec.major == 60) { auto p = reinterpret_cast(this->pkt); p->pts = pts; @@ -224,20 +133,21 @@ void AVPacketWrapper::setPTS(int64_t pts) void AVPacketWrapper::setDTS(int64_t dts) { - if (this->libVer.avcodec.major == 56) + if (this->libraryVersions.avcodec.major == 56) { auto p = reinterpret_cast(this->pkt); p->dts = dts; this->dts = dts; } - else if (this->libVer.avcodec.major == 57 || this->libVer.avcodec.major == 58) + else if (this->libraryVersions.avcodec.major == 57 || // + this->libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(this->pkt); p->dts = dts; this->dts = dts; } - else if (this->libVer.avcodec.major == 59 || // - this->libVer.avcodec.major == 60) + else if (this->libraryVersions.avcodec.major == 59 || // + this->libraryVersions.avcodec.major == 60) { auto p = reinterpret_cast(this->pkt); p->dts = dts; @@ -313,52 +223,12 @@ int AVPacketWrapper::getDataSize() return this->size; } -PacketType AVPacketWrapper::getPacketType() const -{ - return this->packetType; -} - -void AVPacketWrapper::setPacketType(PacketType packetType) -{ - this->packetType = packetType; -} - -PacketDataFormat AVPacketWrapper::guessDataFormatFromData() -{ - if (this->packetFormat != PacketDataFormat::Unknown) - return this->packetFormat; - - auto avpacketData = QByteArray::fromRawData((const char *)(getData()), getDataSize()); - if (avpacketData.length() < 4) - { - this->packetFormat = PacketDataFormat::Unknown; - return this->packetFormat; - } - - // AVPacket data can be in one of two formats: - // 1: The raw annexB format with start codes (0x00000001 or 0x000001) - // 2: ISO/IEC 14496-15 mp4 format: The first 4 bytes determine the size of the NAL unit followed - // by the payload We will try to guess the format of the data from the data in this AVPacket. This - // should always work unless a format is used which we did not encounter so far (which is not - // listed above) Also I think this should be identical for all packets in a bitstream. - if (checkForRawNALFormat(avpacketData, false)) - this->packetFormat = PacketDataFormat::RawNAL; - else if (checkForMp4Format(avpacketData)) - this->packetFormat = PacketDataFormat::MP4; - else if (checkForObuFormat(avpacketData)) - this->packetFormat = PacketDataFormat::OBU; - else if (checkForRawNALFormat(avpacketData, true)) - this->packetFormat = PacketDataFormat::RawNAL; - - return this->packetFormat; -} - void AVPacketWrapper::update() { if (this->pkt == nullptr) return; - if (this->libVer.avcodec.major == 56) + if (this->libraryVersions.avcodec.major == 56) { auto p = reinterpret_cast(this->pkt); @@ -374,8 +244,8 @@ void AVPacketWrapper::update() this->duration = p->duration; this->pos = p->pos; } - else if (this->libVer.avcodec.major == 57 || // - this->libVer.avcodec.major == 58) + else if (this->libraryVersions.avcodec.major == 57 || // + this->libraryVersions.avcodec.major == 58) { auto p = reinterpret_cast(this->pkt); @@ -391,8 +261,8 @@ void AVPacketWrapper::update() this->duration = p->duration; this->pos = p->pos; } - else if (this->libVer.avcodec.major == 59 || // - this->libVer.avcodec.major == 60) + else if (this->libraryVersions.avcodec.major == 59 || // + this->libraryVersions.avcodec.major == 60) { auto p = reinterpret_cast(this->pkt); @@ -412,4 +282,4 @@ void AVPacketWrapper::update() throw std::runtime_error("Invalid library version"); } -} // namespace FFmpeg +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVPacketWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPacketWrapper.h similarity index 81% rename from YUViewLib/src/ffmpeg/AVPacketWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPacketWrapper.h index 7d727c0e7..904dbe7c1 100644 --- a/YUViewLib/src/ffmpeg/AVPacketWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPacketWrapper.h @@ -32,32 +32,11 @@ #pragma once -#include "FFMpegLibrariesTypes.h" +#include -namespace FFmpeg +namespace LibFFmpeg { -// AVPacket data can be in one of two formats: -// 1: The raw annexB format with start codes (0x00000001 or 0x000001) -// 2: ISO/IEC 14496-15 mp4 format: The first 4 bytes determine the size of the NAL unit followed by -// the payload -enum class PacketDataFormat -{ - Unknown, - RawNAL, - MP4, - OBU -}; - -enum class PacketType -{ - VIDEO, - AUDIO, - SUBTITLE_DVB, - SUBTITLE_608, - OTHER -}; - // AVPacket is part of avcodec. The definition is different for different major versions of avcodec. // These are the version independent functions to retrive data from AVPacket. // The size of this struct is part of the public API and must be correct @@ -119,7 +98,7 @@ class AVPacketWrapper { public: AVPacketWrapper() = default; - AVPacketWrapper(LibraryVersion libVersion, AVPacket *packet); + AVPacketWrapper(AVPacket *packet, const LibraryVersions &libraryVersions); void clear(); @@ -139,13 +118,6 @@ class AVPacketWrapper uint8_t * getData(); int getDataSize(); - // This info is set externally (in FileSourceFFmpegFile) based on the stream info - PacketType getPacketType() const; - void setPacketType(PacketType packetType); - - // Guess the format. The actual guessing is only performed if the packetFormat is not set yet. - PacketDataFormat guessDataFormatFromData(); - explicit operator bool() const { return this->pkt != nullptr; }; private: @@ -164,11 +136,8 @@ class AVPacketWrapper int64_t duration{}; int64_t pos{}; - PacketType packetType{}; - - AVPacket * pkt{}; - LibraryVersion libVer{}; - PacketDataFormat packetFormat{PacketDataFormat::Unknown}; + AVPacket * pkt{}; + LibraryVersions libraryVersions{}; }; -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg diff --git a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPixFmtDescriptorWrapper.cpp similarity index 55% rename from YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPixFmtDescriptorWrapper.cpp index 91c1c6768..ed6de2be3 100644 --- a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPixFmtDescriptorWrapper.cpp @@ -32,28 +32,24 @@ #include "AVPixFmtDescriptorWrapper.h" -using Subsampling = video::yuv::Subsampling; -using PlaneOrder = video::yuv::PlaneOrder; -using PixelFormatYUV = video::yuv::PixelFormatYUV; - using namespace std::rel_ops; -namespace FFmpeg +namespace LibFFmpeg { namespace { -typedef struct AVComponentDescriptor_54 +struct AVComponentDescriptor_54 { uint16_t plane : 2; uint16_t step_minus1 : 3; uint16_t offset_plus1 : 3; uint16_t shift : 3; uint16_t depth_minus1 : 4; -} AVComponentDescriptor_54; +}; -typedef struct AVPixFmtDescriptor_54 +struct AVPixFmtDescriptor_54 { const char * name; uint8_t nb_components; @@ -62,9 +58,9 @@ typedef struct AVPixFmtDescriptor_54 uint8_t flags; AVComponentDescriptor_54 comp[4]; const char * alias; -} AVPixFmtDescriptor_54; +}; -typedef struct AVComponentDescriptor_55_56 +struct AVComponentDescriptor_55_56 { int plane; int step; @@ -76,9 +72,9 @@ typedef struct AVComponentDescriptor_55_56 int step_minus1; int depth_minus1; int offset_plus1; -} AVComponentDescriptor_55_56; +}; -typedef struct AVPixFmtDescriptor_55 +struct AVPixFmtDescriptor_55 { const char * name; uint8_t nb_components; @@ -87,9 +83,9 @@ typedef struct AVPixFmtDescriptor_55 uint64_t flags; AVComponentDescriptor_55_56 comp[4]; const char * alias; -} AVPixFmtDescriptor_55; +}; -typedef struct AVPixFmtDescriptor_56 +struct AVPixFmtDescriptor_56 { const char * name; uint8_t nb_components; @@ -98,18 +94,18 @@ typedef struct AVPixFmtDescriptor_56 uint64_t flags; AVComponentDescriptor_55_56 comp[4]; const char * alias; -} AVPixFmtDescriptor_56; +}; -typedef struct AVComponentDescriptor_57 +struct AVComponentDescriptor_57 { int plane; int step; int offset; int shift; int depth; -} AVComponentDescriptor_57; +}; -typedef struct AVPixFmtDescriptor_57_58 +struct AVPixFmtDescriptor_57_58 { const char * name; uint8_t nb_components; @@ -118,9 +114,9 @@ typedef struct AVPixFmtDescriptor_57_58 uint64_t flags; AVComponentDescriptor_57 comp[4]; const char * alias; -} AVPixFmtDescriptor_57_58; +}; -AVPixFmtDescriptorWrapper::Flags parseFlags(uint8_t flagsValue) +AVPixFmtDescriptorWrapper::Flags parseFlags(const uint8_t flagsValue) { AVPixFmtDescriptorWrapper::Flags flags; flags.bigEndian = flagsValue & (1 << 0); @@ -131,36 +127,34 @@ AVPixFmtDescriptorWrapper::Flags parseFlags(uint8_t flagsValue) flags.rgb = flagsValue & (1 << 5); flags.pseudoPallette = flagsValue & (1 << 6); flags.hasAlphaPlane = flagsValue & (1 << 7); - flags.bayerPattern = flagsValue & (1 << 8); - flags.floatValues = flagsValue & (1 << 9); return flags; } -bool flagsSupported(const AVPixFmtDescriptorWrapper::Flags &flags) +AVPixFmtDescriptorWrapper::Flags parseFlags(const uint64_t flagsValue) { - // We don't support any of these - if (flags.pallette) - return false; - if (flags.hwAccelerated) - return false; - if (flags.pseudoPallette) - return false; - if (flags.bayerPattern) - return false; - if (flags.floatValues) - return false; - return true; + AVPixFmtDescriptorWrapper::Flags flags; + flags.bigEndian = flagsValue & (1 << 0); + flags.pallette = flagsValue & (1 << 1); + flags.bitwisePacked = flagsValue & (1 << 2); + flags.hwAccelerated = flagsValue & (1 << 3); + flags.planar = flagsValue & (1 << 4); + flags.rgb = flagsValue & (1 << 5); + flags.pseudoPallette = flagsValue & (1 << 6); + flags.hasAlphaPlane = flagsValue & (1 << 7); + flags.bayerPattern = flagsValue & (1 << 8); + flags.floatValues = flagsValue & (1 << 9); + return flags; } } // namespace -AVPixFmtDescriptorWrapper::AVPixFmtDescriptorWrapper(AVPixFmtDescriptor *descriptor, - LibraryVersion libVer) +AVPixFmtDescriptorWrapper::AVPixFmtDescriptorWrapper(AVPixFmtDescriptor * descriptor, + const LibraryVersions &libraryVersions) { - if (libVer.avutil.major == 54) + if (libraryVersions.avutil.major == 54) { auto p = reinterpret_cast(descriptor); - this->name = QString(p->name); + this->name = std::string(p->name); this->nb_components = p->nb_components; this->log2_chroma_w = p->log2_chroma_w; this->log2_chroma_h = p->log2_chroma_h; @@ -175,12 +169,12 @@ AVPixFmtDescriptorWrapper::AVPixFmtDescriptorWrapper(AVPixFmtDescriptor *descrip this->comp[i].depth = p->comp[i].depth_minus1 + 1; } - aliases = QString(p->alias); + aliases = std::string(p->alias); } - else if (libVer.avutil.major == 55) + else if (libraryVersions.avutil.major == 55) { auto p = reinterpret_cast(descriptor); - this->name = QString(p->name); + this->name = std::string(p->name); this->nb_components = p->nb_components; this->log2_chroma_w = p->log2_chroma_w; this->log2_chroma_h = p->log2_chroma_h; @@ -195,12 +189,12 @@ AVPixFmtDescriptorWrapper::AVPixFmtDescriptorWrapper(AVPixFmtDescriptor *descrip this->comp[i].depth = p->comp[i].depth; } - aliases = QString(p->alias); + aliases = std::string(p->alias); } - else if (libVer.avutil.major == 56) + else if (libraryVersions.avutil.major == 56) { auto p = reinterpret_cast(descriptor); - this->name = QString(p->name); + this->name = std::string(p->name); this->nb_components = p->nb_components; this->log2_chroma_w = p->log2_chroma_w; this->log2_chroma_h = p->log2_chroma_h; @@ -215,13 +209,13 @@ AVPixFmtDescriptorWrapper::AVPixFmtDescriptorWrapper(AVPixFmtDescriptor *descrip this->comp[i].depth = p->comp[i].depth; } - aliases = QString(p->alias); + aliases = std::string(p->alias); } - else if (libVer.avutil.major == 57 || // - libVer.avutil.major == 58) + else if (libraryVersions.avutil.major == 57 || // + libraryVersions.avutil.major == 58) { auto p = reinterpret_cast(descriptor); - this->name = QString(p->name); + this->name = std::string(p->name); this->nb_components = p->nb_components; this->log2_chroma_w = p->log2_chroma_w; this->log2_chroma_h = p->log2_chroma_h; @@ -236,138 +230,10 @@ AVPixFmtDescriptorWrapper::AVPixFmtDescriptorWrapper(AVPixFmtDescriptor *descrip this->comp[i].depth = p->comp[i].depth; } - aliases = QString(p->alias); + aliases = std::string(p->alias); } } -video::RawFormat AVPixFmtDescriptorWrapper::getRawFormat() const -{ - return this->flags.rgb ? video::RawFormat::RGB : video::RawFormat::YUV; -} - -PixelFormatYUV AVPixFmtDescriptorWrapper::getPixelFormatYUV() const -{ - if (this->getRawFormat() == video::RawFormat::RGB || !flagsSupported(this->flags)) - return {}; - - Subsampling subsampling; - if (this->nb_components == 1) - subsampling = Subsampling::YUV_400; - else if (this->log2_chroma_w == 0 && this->log2_chroma_h == 0) - subsampling = Subsampling::YUV_444; - else if (this->log2_chroma_w == 1 && this->log2_chroma_h == 0) - subsampling = Subsampling::YUV_422; - else if (this->log2_chroma_w == 1 && this->log2_chroma_h == 1) - subsampling = Subsampling::YUV_420; - else if (this->log2_chroma_w == 0 && this->log2_chroma_h == 1) - subsampling = Subsampling::YUV_440; - else if (this->log2_chroma_w == 2 && this->log2_chroma_h == 2) - subsampling = Subsampling::YUV_410; - else if (this->log2_chroma_w == 0 && this->log2_chroma_h == 2) - subsampling = Subsampling::YUV_411; - else - return {}; - - PlaneOrder planeOrder; - if (this->nb_components == 1) - planeOrder = PlaneOrder::YUV; - else if (this->nb_components == 3 && !this->flags.hasAlphaPlane) - planeOrder = PlaneOrder::YUV; - else if (this->nb_components == 4 && this->flags.hasAlphaPlane) - planeOrder = PlaneOrder::YUVA; - else - return {}; - - int bitsPerSample = comp[0].depth; - for (int i = 1; i < this->nb_components; i++) - if (comp[i].depth != bitsPerSample) - // Varying bit depths for components is not supported - return {}; - - if (this->flags.bitwisePacked || !this->flags.planar) - // Maybe this could be supported but I don't think that any decoder actually uses this. - // If you encounter a format that does not work because of this check please let us know. - return {}; - - return PixelFormatYUV(subsampling, bitsPerSample, planeOrder, this->flags.bigEndian); -} - -video::rgb::PixelFormatRGB AVPixFmtDescriptorWrapper::getRGBPixelFormat() const -{ - if (this->getRawFormat() == video::RawFormat::YUV || !flagsSupported(this->flags)) - return {}; - - auto bitsPerSample = comp[0].depth; - for (int i = 1; i < nb_components; i++) - if (comp[i].depth != bitsPerSample) - // Varying bit depths for components is not supported - return {}; - - if (this->flags.bitwisePacked) - // Maybe this could be supported but I don't think that any decoder actually uses this. - // If you encounter a format that does not work because of this check please let us know. - return {}; - - // The only possible order of planes seems to be RGB(A) - auto dataLayout = this->flags.planar ? video::DataLayout::Planar : video::DataLayout::Packed; - auto alphaMode = - this->flags.hasAlphaPlane ? video::rgb::AlphaMode::Last : video::rgb::AlphaMode::None; - auto endianness = this->flags.bigEndian ? video::Endianness::Big : video::Endianness::Little; - - return video::rgb::PixelFormatRGB( - bitsPerSample, dataLayout, video::rgb::ChannelOrder::RGB, alphaMode, endianness); -} - -bool AVPixFmtDescriptorWrapper::setValuesFromPixelFormatYUV(PixelFormatYUV fmt) -{ - const auto planeOrder = fmt.getPlaneOrder(); - if (planeOrder == PlaneOrder::YVU || planeOrder == PlaneOrder::YVUA) - return false; - - const auto subsampling = fmt.getSubsampling(); - switch (subsampling) - { - case Subsampling::YUV_422: - this->log2_chroma_w = 1; - this->log2_chroma_h = 0; - break; - case Subsampling::YUV_420: - this->log2_chroma_w = 1; - this->log2_chroma_h = 1; - break; - case Subsampling::YUV_440: - this->log2_chroma_w = 0; - this->log2_chroma_h = 1; - break; - case Subsampling::YUV_410: - this->log2_chroma_w = 2; - this->log2_chroma_h = 2; - break; - case Subsampling::YUV_411: - this->log2_chroma_w = 0; - this->log2_chroma_h = 2; - break; - default: - break; - } - - this->nb_components = (subsampling == Subsampling::YUV_400 ? 1 : 3); - - this->flags.bigEndian = fmt.isBigEndian(); - this->flags.planar = fmt.isPlanar(); - this->flags.hasAlphaPlane = (planeOrder == PlaneOrder::YUVA); - - for (int i = 0; i < this->nb_components; i++) - { - this->comp[i].plane = i; - this->comp[i].step = (fmt.getBitsPerSample() > 8) ? 2 : 1; - this->comp[i].offset = 0; - this->comp[i].shift = 0; - this->comp[i].depth = fmt.getBitsPerSample(); - } - return true; -} - bool AVPixFmtDescriptorWrapper::Flags::operator==( const AVPixFmtDescriptorWrapper::Flags &other) const { @@ -406,4 +272,4 @@ bool AVPixFmtDescriptorWrapper::operator==(const AVPixFmtDescriptorWrapper &othe return true; } -} // namespace FFmpeg \ No newline at end of file +} // namespace LibFFmpeg \ No newline at end of file diff --git a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPixFmtDescriptorWrapper.h similarity index 84% rename from YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h rename to YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPixFmtDescriptorWrapper.h index d8642a3a3..1846a1cf1 100644 --- a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h +++ b/YUViewLib/externalLibs/LibFFmpeg++/wrappers/AVPixFmtDescriptorWrapper.h @@ -32,29 +32,21 @@ #pragma once -#include "FFMpegLibrariesTypes.h" +#include -#include