forked from mia/Aegisub
Add bestsource video provider
Co-authored-by: Asada shinon <joshwoo71@gmail.com>
This commit is contained in:
parent
1772dd17ae
commit
33b9a6e395
|
@ -18,6 +18,7 @@ tools/repack-thes-dict.dSYM
|
||||||
|
|
||||||
# Meson
|
# Meson
|
||||||
build*/
|
build*/
|
||||||
|
subprojects/bestsource/
|
||||||
subprojects/boost*/
|
subprojects/boost*/
|
||||||
subprojects/cairo*
|
subprojects/cairo*
|
||||||
subprojects/ffmpeg
|
subprojects/ffmpeg
|
||||||
|
|
17
meson.build
17
meson.build
|
@ -220,6 +220,23 @@ foreach dep: [
|
||||||
endif
|
endif
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
|
needs_ffmpeg = false
|
||||||
|
|
||||||
|
if get_option('bestsource').enabled()
|
||||||
|
conf.set('WITH_BESTSOURCE', 1)
|
||||||
|
bs = subproject('bestsource')
|
||||||
|
deps += bs.get_variable('bestsource_dep')
|
||||||
|
needs_ffmpeg = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
if needs_ffmpeg
|
||||||
|
conf.set('WITH_FFMPEG', 1)
|
||||||
|
deps += [
|
||||||
|
dependency('libavutil', default_options: ['tests=disabled']),
|
||||||
|
dependency('libswscale', default_options: ['tests=disabled']),
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
if host_machine.system() == 'windows' and get_option('avisynth').enabled()
|
if host_machine.system() == 'windows' and get_option('avisynth').enabled()
|
||||||
conf.set('WITH_AVISYNTH', 1) # bundled separately with installer
|
conf.set('WITH_AVISYNTH', 1) # bundled separately with installer
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -7,6 +7,7 @@ option('default_audio_output', type: 'combo', choices: ['auto', 'ALSA', 'OpenAL'
|
||||||
|
|
||||||
option('ffms2', type: 'feature', description: 'FFMS2 video source')
|
option('ffms2', type: 'feature', description: 'FFMS2 video source')
|
||||||
option('avisynth', type: 'feature', description: 'AviSynth video source')
|
option('avisynth', type: 'feature', description: 'AviSynth video source')
|
||||||
|
option('bestsource', type: 'feature', description: 'BestSource video source')
|
||||||
|
|
||||||
option('fftw3', type: 'feature', description: 'FFTW3 support')
|
option('fftw3', type: 'feature', description: 'FFTW3 support')
|
||||||
option('hunspell', type: 'feature', description: 'Hunspell spell checker')
|
option('hunspell', type: 'feature', description: 'Hunspell spell checker')
|
||||||
|
|
|
@ -224,6 +224,10 @@ if conf.has('WITH_CSRI')
|
||||||
aegisub_src += files('subtitles_provider_csri.cpp')
|
aegisub_src += files('subtitles_provider_csri.cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if conf.has('WITH_BESTSOURCE')
|
||||||
|
aegisub_src += files('video_provider_bestsource.cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
opt_src = [
|
opt_src = [
|
||||||
['ALSA', 'audio_player_alsa.cpp'],
|
['ALSA', 'audio_player_alsa.cpp'],
|
||||||
['PortAudio', 'audio_player_portaudio.cpp'],
|
['PortAudio', 'audio_player_portaudio.cpp'],
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class wxImage;
|
class wxImage;
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
// Copyright (c) 2022, arch1t3cht <arch1t3cht@gmail.com>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
//
|
||||||
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
|
/// @file video_provider_bestsource.cpp
|
||||||
|
/// @brief BestSource-based video provider
|
||||||
|
/// @ingroup video_input bestsource
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifdef WITH_BESTSOURCE
|
||||||
|
#include "include/aegisub/video_provider.h"
|
||||||
|
|
||||||
|
#include "videosource.h"
|
||||||
|
#include "BSRational.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavutil/frame.h>
|
||||||
|
#include <libavutil/pixfmt.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #include "utils.h" */
|
||||||
|
#include "options.h"
|
||||||
|
#include "compat.h"
|
||||||
|
#include "video_frame.h"
|
||||||
|
namespace agi { class BackgroundRunner; }
|
||||||
|
|
||||||
|
#include <libaegisub/fs.h>
|
||||||
|
#include <libaegisub/path.h>
|
||||||
|
#include <libaegisub/make_unique.h>
|
||||||
|
#include <libaegisub/background_runner.h>
|
||||||
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include <boost/crc.hpp>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// @class BSVideoProvider
|
||||||
|
/// @brief Implements video loading through BestSource.
|
||||||
|
class BSVideoProvider final : public VideoProvider {
|
||||||
|
std::map<std::string, std::string> bsopts;
|
||||||
|
BestVideoSource bs;
|
||||||
|
VideoProperties properties;
|
||||||
|
|
||||||
|
std::vector<int> Keyframes;
|
||||||
|
agi::vfr::Framerate Timecodes;
|
||||||
|
|
||||||
|
std::string GetCacheFile(agi::fs::path const& filename);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BSVideoProvider(agi::fs::path const& filename, std::string const& colormatrix, agi::BackgroundRunner *br);
|
||||||
|
|
||||||
|
void GetFrame(int n, VideoFrame &out) override;
|
||||||
|
|
||||||
|
void SetColorSpace(std::string const& matrix) override { }
|
||||||
|
|
||||||
|
int GetFrameCount() const override { return properties.NumFrames; };
|
||||||
|
|
||||||
|
int GetWidth() const override { return properties.Width; };
|
||||||
|
int GetHeight() const override { return properties.Height; };
|
||||||
|
double GetDAR() const override { return ((double) properties.Width * properties.SAR.Num) / (properties.Height * properties.SAR.Den); };
|
||||||
|
|
||||||
|
agi::vfr::Framerate GetFPS() const override { return Timecodes; };
|
||||||
|
std::string GetColorSpace() const override { return "TV.709"; }; // TODO
|
||||||
|
std::string GetRealColorSpace() const override { return "TV.709"; };
|
||||||
|
std::vector<int> GetKeyFrames() const override { return Keyframes; };
|
||||||
|
std::string GetDecoderName() const override { return "BestSource"; };
|
||||||
|
bool WantsCaching() const override { return false; };
|
||||||
|
bool HasAudio() const override { return false; };
|
||||||
|
};
|
||||||
|
|
||||||
|
BSVideoProvider::BSVideoProvider(agi::fs::path const& filename, std::string const& colormatrix, agi::BackgroundRunner *br) try
|
||||||
|
: bsopts()
|
||||||
|
, bs(filename.string(), "", -1, false, 0, GetCacheFile(filename), &bsopts)
|
||||||
|
{
|
||||||
|
|
||||||
|
properties = bs.GetVideoProperties();
|
||||||
|
|
||||||
|
if (properties.NumFrames == -1) {
|
||||||
|
LOG_D("bs") << "File not cached or varying samples, creating cache.";
|
||||||
|
br->Run([&](agi::ProgressSink *ps) {
|
||||||
|
ps->SetTitle(from_wx(_("Exacting")));
|
||||||
|
ps->SetMessage(from_wx(_("Creating cache... This can take a while!")));
|
||||||
|
ps->SetIndeterminate();
|
||||||
|
if (bs.GetExactDuration()) {
|
||||||
|
LOG_D("bs") << "File cached and has exact samples.";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
properties = bs.GetVideoProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
br->Run([&](agi::ProgressSink *ps) {
|
||||||
|
ps->SetTitle(from_wx(_("Scanning")));
|
||||||
|
ps->SetMessage(from_wx(_("Finding Keyframes and Timecodes...")));
|
||||||
|
|
||||||
|
std::vector<int> TimecodesVector;
|
||||||
|
for (int n = 0; n < properties.NumFrames; n++) {
|
||||||
|
if (ps->IsCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::unique_ptr<BestVideoFrame> frame(bs.GetFrame(n));
|
||||||
|
if (frame == nullptr) {
|
||||||
|
throw VideoOpenError("Couldn't read frame!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->GetAVFrame()->key_frame) {
|
||||||
|
Keyframes.push_back(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimecodesVector.push_back((int) frame->GetAVFrame()->pts);
|
||||||
|
ps->SetProgress(n, properties.NumFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TimecodesVector.size() < 2 || TimecodesVector.front() == TimecodesVector.back()) {
|
||||||
|
Timecodes = (double) properties.FPS.Num / properties.FPS.Den;
|
||||||
|
} else {
|
||||||
|
Timecodes = agi::vfr::Framerate(TimecodesVector);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (VideoException const& err) {
|
||||||
|
throw VideoOpenError("Failed to create BestVideoSource");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BSVideoProvider::GetCacheFile(agi::fs::path const& filename) {
|
||||||
|
// BS can store all its index data in a single file, but we make a separate index file
|
||||||
|
// for each video file to ensure that the old index is invalidated if the file is modified.
|
||||||
|
// While BS does check the filesize of the files, it doesn't check the modification time.
|
||||||
|
uintmax_t len = agi::fs::Size(filename);
|
||||||
|
boost::crc_32_type hash;
|
||||||
|
hash.process_bytes(filename.string().c_str(), filename.string().size());
|
||||||
|
|
||||||
|
auto result = config::path->Decode("?local/bsindex/" + filename.filename().string() + "_" + std::to_string(hash.checksum()) + "_" + std::to_string(len) + "_" + std::to_string(agi::fs::ModifiedTime(filename)) + ".json");
|
||||||
|
agi::fs::CreateDirectory(result.parent_path());
|
||||||
|
|
||||||
|
return result.string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSVideoProvider::GetFrame(int n, VideoFrame &out) {
|
||||||
|
std::unique_ptr<BestVideoFrame> bsframe(bs.GetFrame(n));
|
||||||
|
if (bsframe == nullptr) {
|
||||||
|
throw VideoDecodeError("Couldn't read frame!");
|
||||||
|
}
|
||||||
|
const AVFrame *frame = bsframe->GetAVFrame();
|
||||||
|
AVFrame *newframe = av_frame_alloc();
|
||||||
|
|
||||||
|
SwsContext *context = sws_getContext(
|
||||||
|
frame->width, frame->height, (AVPixelFormat) frame->format, // TODO figure out aegi's color space forcing.
|
||||||
|
frame->width, frame->height, AV_PIX_FMT_BGR0,
|
||||||
|
SWS_BICUBIC, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (context == nullptr) {
|
||||||
|
throw VideoDecodeError("Couldn't convert frame!");
|
||||||
|
}
|
||||||
|
|
||||||
|
sws_scale_frame(context, newframe, frame);
|
||||||
|
|
||||||
|
out.width = newframe->width;
|
||||||
|
out.height = newframe->height;
|
||||||
|
out.pitch = newframe->width * 4;
|
||||||
|
out.flipped = false; // TODO figure out flipped
|
||||||
|
|
||||||
|
out.data.assign(newframe->data[0], newframe->data[0] + newframe->linesize[0] * newframe->height);
|
||||||
|
|
||||||
|
sws_freeContext(context);
|
||||||
|
av_frame_free(&newframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VideoProvider> CreateBSVideoProvider(agi::fs::path const& path, std::string const& colormatrix, agi::BackgroundRunner *br) {
|
||||||
|
return agi::make_unique<BSVideoProvider>(path, colormatrix, br);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WITH_BESTSOURCE */
|
|
@ -29,6 +29,7 @@ std::unique_ptr<VideoProvider> CreateDummyVideoProvider(agi::fs::path const&, st
|
||||||
std::unique_ptr<VideoProvider> CreateYUV4MPEGVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
std::unique_ptr<VideoProvider> CreateYUV4MPEGVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||||
std::unique_ptr<VideoProvider> CreateFFmpegSourceVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
std::unique_ptr<VideoProvider> CreateFFmpegSourceVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||||
std::unique_ptr<VideoProvider> CreateAvisynthVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
std::unique_ptr<VideoProvider> CreateAvisynthVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||||
|
std::unique_ptr<VideoProvider> CreateBSVideoProvider(agi::fs::path const&, std::string const&, agi::BackgroundRunner *);
|
||||||
|
|
||||||
std::unique_ptr<VideoProvider> CreateCacheVideoProvider(std::unique_ptr<VideoProvider>);
|
std::unique_ptr<VideoProvider> CreateCacheVideoProvider(std::unique_ptr<VideoProvider>);
|
||||||
|
|
||||||
|
@ -47,6 +48,9 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_AVISYNTH
|
#ifdef WITH_AVISYNTH
|
||||||
{"Avisynth", CreateAvisynthVideoProvider, false},
|
{"Avisynth", CreateAvisynthVideoProvider, false},
|
||||||
|
#endif
|
||||||
|
#ifdef WITH_BESTSOURCE
|
||||||
|
{"BestSource", CreateBSVideoProvider, false},
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[wrap-git]
|
||||||
|
url = https://github.com/vapoursynth/bestsource
|
||||||
|
revision = head
|
||||||
|
patch_directory = bestsource
|
||||||
|
|
||||||
|
[provide]
|
||||||
|
bestsource = bestsource_dep
|
|
@ -0,0 +1,156 @@
|
||||||
|
// Since we don't use ExportAsPlanar, we don't actually need libp2p.
|
||||||
|
// So instead of adding another wrap and meson build file, and *also*
|
||||||
|
// patching the include statement in videosource.cpp, we throw a dummy
|
||||||
|
// header file in the folder that should contain the checkout of libp2p.
|
||||||
|
|
||||||
|
#ifndef P2P_API_H_
|
||||||
|
#define P2P_API_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notation: [Xa-Ya-Za]
|
||||||
|
*
|
||||||
|
* [] denotes a machine word of the specified endianness. Xa-Ya-Za denote
|
||||||
|
* component X, Y, and Z packed in the word, with bit depths a, b, c, in order
|
||||||
|
* from MSB to LSB. Padding bits are represented by the component '!'.
|
||||||
|
*/
|
||||||
|
enum p2p_packing {
|
||||||
|
/** [R8-G8-B8] */
|
||||||
|
p2p_rgb24_be, /* RGB */
|
||||||
|
p2p_rgb24_le, /* BGR */
|
||||||
|
p2p_rgb24,
|
||||||
|
/** [A8-R8-G8-B8] */
|
||||||
|
p2p_argb32_be, /* ARGB */
|
||||||
|
p2p_argb32_le, /* BGRA */
|
||||||
|
p2p_argb32,
|
||||||
|
/** [A8-Y8-U8-V8] */
|
||||||
|
p2p_ayuv_be, /* AYUV */
|
||||||
|
p2p_ayuv_le, /* VUYA */
|
||||||
|
p2p_ayuv,
|
||||||
|
/** [R16-G16-B16] */
|
||||||
|
p2p_rgb48_be, /* RGB, big-endian components */
|
||||||
|
p2p_rgb48_le, /* BGR, little-endian components */
|
||||||
|
p2p_rgb48,
|
||||||
|
/** [A16-R16-G16-B16] */
|
||||||
|
p2p_argb64_be, /* ARGB big-endian components */
|
||||||
|
p2p_argb64_le, /* BGRA little-endian components */
|
||||||
|
p2p_argb64,
|
||||||
|
/** [A2-R10-G10-B10] */
|
||||||
|
p2p_rgb30_be, /* ARGB packed in big-endian DWORD */
|
||||||
|
p2p_rgb30_le, /* ARGB packed in little-endian DWORD */
|
||||||
|
p2p_rgb30,
|
||||||
|
/** [A2-V10-Y10-U10] */
|
||||||
|
p2p_y410_be, /* AVYU packed in big-endian DWORD */
|
||||||
|
p2p_y410_le, /* AVYU packed in little-endian DWORD */
|
||||||
|
p2p_y410,
|
||||||
|
/** [A16-V16-Y16-U16] */
|
||||||
|
p2p_y416_be, /* AVYU, big-endian components */
|
||||||
|
p2p_y416_le, /* UYVA, little-endian components */
|
||||||
|
p2p_y416,
|
||||||
|
/** [Y8] [U8] [Y8] [V8] */
|
||||||
|
p2p_yuy2,
|
||||||
|
/** [U8] [Y8] [V8] [Y8] */
|
||||||
|
p2p_uyvy,
|
||||||
|
/** [Y10-!6] [U10-!6] [Y10-!6] [V10-!6] */
|
||||||
|
p2p_y210_be, /* YUYV, big-endian components, lower 6 bits zero */
|
||||||
|
p2p_y210_le, /* YUYV, little-endian components, lower 6 bits zero. Microsoft Y210. */
|
||||||
|
p2p_y210,
|
||||||
|
/** [Y16] [U16] [Y16] [V16] */
|
||||||
|
p2p_y216_be, /* YUYV, big-endian components */
|
||||||
|
p2p_y216_le, /* YUYV, little-endian components. Microsoft Y216. */
|
||||||
|
p2p_y216,
|
||||||
|
/** [!2-V10-Y10-U10] [!2-Y10-U10-Y10] [!2-U10-Y10-V10] [!2-Y10-V10-Y10] */
|
||||||
|
p2p_v210_be, /* v210 with big-endian DWORDs */
|
||||||
|
p2p_v210_le, /* Apple/QuickTime v210 */
|
||||||
|
p2p_v210,
|
||||||
|
/** [U16] [Y16] [V16] [Y16] */
|
||||||
|
p2p_v216_be, /* UYVY, big-endian components */
|
||||||
|
p2p_v216_le, /* UYVY, little-endian components. Apple/QuickTime v216. */
|
||||||
|
p2p_v216,
|
||||||
|
/** [U8-V8] */
|
||||||
|
p2p_nv12_be, /* aka NV21, V first */
|
||||||
|
p2p_nv12_le, /* NV12 */
|
||||||
|
p2p_nv12,
|
||||||
|
/** [U10-!6-V10-!6] */
|
||||||
|
p2p_p010_be, /* NV21, big-endian components, lower 6 bits zero */
|
||||||
|
p2p_p010_le, /* NV12, little-endian components, lower 6 bits zero. Microsoft P010. */
|
||||||
|
p2p_p010,
|
||||||
|
/** [U16-V16] */
|
||||||
|
p2p_p016_be, /* NV21, big-endian components */
|
||||||
|
p2p_p016_le, /* NV12, little-endian components. Microsoft P016. */
|
||||||
|
p2p_p016,
|
||||||
|
/** [U10-!6-V10-!6] */
|
||||||
|
p2p_p210_be, /* NV21, big-endian components, lower 6 bits zero */
|
||||||
|
p2p_p210_le, /* NV12, little-endian components, lower 6 bits zero. Microsoft P210. */
|
||||||
|
p2p_p210,
|
||||||
|
/** [U16-V16] */
|
||||||
|
p2p_p216_be, /* NV21, big-endian components */
|
||||||
|
p2p_p216_le, /* NV12, little-endian components. Microsoft P216. */
|
||||||
|
p2p_p216,
|
||||||
|
/** [R8-G8-B8-A8] */
|
||||||
|
p2p_rgba32_be, /* RGBA */
|
||||||
|
p2p_rgba32_le, /* ABGR */
|
||||||
|
p2p_rgba32,
|
||||||
|
/** [R16-G16-B16-A16] */
|
||||||
|
p2p_rgba64_be, /* RGBA, big-endian components */
|
||||||
|
p2p_rgba64_le, /* ABGR, little-endian components */
|
||||||
|
p2p_rgba64,
|
||||||
|
/** [A16-B16-G16-R16] */
|
||||||
|
p2p_abgr64_be, /* ABGR, big-endian components */
|
||||||
|
p2p_abgr64_le, /* RGBA, little-endian components */
|
||||||
|
p2p_abgr64,
|
||||||
|
/** [B16-G16-R16] */
|
||||||
|
p2p_bgr48_be, /* BGR, big-endian components */
|
||||||
|
p2p_bgr48_le, /* RGB, little-endian components */
|
||||||
|
p2p_bgr48,
|
||||||
|
/** [B16-G16-R16-A16] */
|
||||||
|
p2p_bgra64_be, /* BGRA, big-endian components */
|
||||||
|
p2p_bgra64_le, /* ARGB, little-endian components */
|
||||||
|
p2p_bgra64,
|
||||||
|
|
||||||
|
p2p_packing_max,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct p2p_buffer_param {
|
||||||
|
/**
|
||||||
|
* Planar order: R-G-B-A or Y-U-V-A. Alpha is optional.
|
||||||
|
* Packed order: Y-UV if NV12/21, else single plane. Y optional for NV12/21.
|
||||||
|
*/
|
||||||
|
const void *src[4];
|
||||||
|
void *dst[4];
|
||||||
|
ptrdiff_t src_stride[4];
|
||||||
|
ptrdiff_t dst_stride[4];
|
||||||
|
unsigned width;
|
||||||
|
unsigned height;
|
||||||
|
enum p2p_packing packing;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Pack/unpack a range of pixels from a scanline. */
|
||||||
|
typedef void (*p2p_unpack_func)(const void *src, void * const dst[4], unsigned left, unsigned right);
|
||||||
|
typedef void (*p2p_pack_func)(const void * const src[4], void *dst, unsigned left, unsigned right);
|
||||||
|
|
||||||
|
/** Select a line pack/unpack function. */
|
||||||
|
p2p_unpack_func p2p_select_unpack_func(enum p2p_packing packing);
|
||||||
|
p2p_pack_func p2p_select_pack_func(enum p2p_packing packing);
|
||||||
|
p2p_pack_func p2p_select_pack_func_ex(enum p2p_packing packing, int alpha_one_fill);
|
||||||
|
|
||||||
|
|
||||||
|
/** When processing formats like NV12, ignore the unpacked plane. */
|
||||||
|
#define P2P_SKIP_UNPACKED_PLANES (1UL << 0)
|
||||||
|
/** When packing, store a bit pattern of all ones in the alpha channel instead of all zeros. */
|
||||||
|
#define P2P_ALPHA_SET_ONE (1UL << 1)
|
||||||
|
|
||||||
|
/** Helper function to pack/unpack between memory locations. */
|
||||||
|
void p2p_unpack_frame(const struct p2p_buffer_param *param, unsigned long flags) {};
|
||||||
|
void p2p_pack_frame(const struct p2p_buffer_param *param, unsigned long flags) {};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* P2P_API_H_ */
|
|
@ -0,0 +1,28 @@
|
||||||
|
project('BestSource', 'cpp',
|
||||||
|
default_options: ['buildtype=release', 'b_ndebug=if-release', 'cpp_std=c++14'],
|
||||||
|
meson_version: '>=0.48.0'
|
||||||
|
)
|
||||||
|
|
||||||
|
libs = []
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'src/audiosource.cpp',
|
||||||
|
'src/videosource.cpp',
|
||||||
|
'src/SrcAttribCache.cpp',
|
||||||
|
'src/BSRational.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
deps = [
|
||||||
|
dependency('jansson', version: '>= 2.7', required: true),
|
||||||
|
dependency('libavcodec'),
|
||||||
|
dependency('libavformat'),
|
||||||
|
dependency('libavutil'),
|
||||||
|
]
|
||||||
|
|
||||||
|
bs_lib = static_library('bestsource', sources,
|
||||||
|
dependencies: deps,
|
||||||
|
gnu_symbol_visibility: 'hidden'
|
||||||
|
)
|
||||||
|
|
||||||
|
bestsource_dep = declare_dependency(link_with: bs_lib, include_directories: include_directories('src'))
|
||||||
|
|
Loading…
Reference in New Issue