3#include <Tempest/Painter>
4#include <Tempest/TextCodec>
6#include <Tempest/Application>
7#include <Tempest/Platform>
8#include <Tempest/Fence>
17using namespace Tempest;
22 void read(
void *dest,
size_t count)
override {
23 if(
fin.read(dest,count)!=count)
24 throw std::runtime_error(
"i/o error");
27 void skip(
size_t count)
override {
28 fin.seek(ptrdiff_t(count), zenkit::Whence::CUR);
31 void seek(
size_t pos)
override {
32 fin.seek(ptrdiff_t(pos), zenkit::Whence::BEG);
42 :Tempest::SoundProducer(sampleRate, isMono ? 1 : 2),
ctx(c),
channels(isMono ? 1 : 2) {
73 std::memcpy(
samples.data()+sz, s.data(), s.size()*
sizeof(s[0]));
77 Tempest::SoundEffect
snd;
93 for(
size_t i=0; i<n; ++i) {
95 out[i] = (v < -1.00004566f ? int16_t(-32768) : (v > 1.00001514f ? int16_t(32767) : int16_t(v * 32767.5f)));
104 for(
size_t i=0; i<
sndCtx.size(); ++i) {
110 sndDev.setGlobalVolume(volume);
126 void advance(Tempest::Device& device, uint8_t fId) {
130 sndCtx[i]->pushSamples(f.audio(uint8_t(i)).samples);
133 const uint64_t tickVis = Application::tickCount() -
frameTime;
135 const uint64_t
tick = std::min(tickVis, tickSnd);
137 if(destTick >
tick) {
138 Application::sleep(uint32_t(destTick-
tick));
144 uint64_t tickSnd = uint64_t(-1);
148 tickSnd = std::min(tickSnd,
sndCtx[i]->tickCount());
160 auto alignBuf = [](
size_t size,
size_t align) {
return (size+align-1) & ~(align-1); };
162 auto& planeY = f.
plane(0);
163 auto& planeU = f.
plane(1);
164 auto& planeV = f.
plane(2);
166 auto align = std::max<size_t>(device.properties().ssbo.offsetAlign, 4);
167 auto sizeY = alignBuf(f.
height()*planeY.stride(), align);
168 auto sizeU = alignBuf((f.
height()/2)*planeU.stride(), align);
169 auto sizeV = alignBuf((f.
height()/2)*planeV.stride(), align);
170 auto size = sizeY + sizeU + sizeV;
173 if(stage.byteSize()!=size) {
175 stage = device.ssbo(BufferHeap::Upload, Uninitialized, size);
177 stage.update(planeY.data(), 0, (f.
height()) *planeY.stride());
178 stage.update(planeU.data(), sizeY, (f.
height()/2)*planeU.stride());
179 stage.update(planeV.data(), sizeY+sizeU, (f.
height()/2)*planeV.stride());
182 auto cmd = this->
cmd[fId].startEncoding(device);
183 cmd.setFramebuffer({{
frameImg, Vec4(0), Tempest::Preserve}});
185 struct Push { uint32_t strideY; uint32_t strideU; uint32_t strideV; } push = {};
186 push.strideY = planeY.stride();
187 push.strideU = planeU.stride();
188 push.strideV = planeV.stride();
190 cmd.setDebugMarker(
"Bink");
191 cmd.setPushData(push);
192 cmd.setBinding(0, stage, 0);
193 cmd.setBinding(1, stage, sizeY);
194 cmd.setBinding(2, stage, sizeY + sizeU);
196 cmd.draw(
nullptr, 0, 3);
198 sync[fId] = device.submit(this->
cmd[fId]);
204 pm = Pixmap(f.
width(),f.
height(),TextureFormat::RGBA8);
205 auto& planeY = f.
plane(0);
206 auto& planeU = f.
plane(1);
207 auto& planeV = f.
plane(2);
208 auto dst =
reinterpret_cast<uint8_t*
>(pm.data());
210 const uint32_t w = pm.w();
211 for(uint32_t y=0; y<pm.h(); ++y)
212 for(uint32_t x=0; x<w; ++x) {
213 uint8_t* rgb = &dst[(x+y*w)*4];
214 float Y = planeY.at(x, y );
215 float U = planeU.at(x/2,y/2);
216 float V = planeV.at(x/2,y/2);
218 float r = 1.164f * (Y - 16.f) + 1.596f * (V - 128.f);
219 float g = 1.164f * (Y - 16.f) - 0.813f * (V - 128.f) - 0.391f * (U - 128.f);
220 float b = 1.164f * (Y - 16.f) + 2.018f * (U - 128.f);
222 r = std::max(0.f,std::min(r,255.f));
223 g = std::max(0.f,std::min(g,255.f));
224 b = std::max(0.f,std::min(b,255.f));
237 std::unique_ptr<zenkit::Read>
fin;
248 std::vector<std::unique_ptr<SoundContext>>
sndCtx;
252 setCursorShape(CursorShape::Hidden);
262 std::lock_guard<std::mutex> guard(syncVideo);
263 pendingVideo.emplace(filename);
264 hasPendingVideo.store(
true);
268 return ctx!=
nullptr || hasPendingVideo.load();
272 if(ctx!=
nullptr && ctx->isEof()) {
282 std::string filename;
284 std::lock_guard<std::mutex> guard(syncVideo);
285 if(pendingVideo.empty())
287 filename = std::move(pendingVideo.front());
289 if(pendingVideo.size()==0)
290 hasPendingVideo.store(
false);
293 std::unique_ptr<zenkit::Read> read;
295 read = entry->open_read();
299 read = entry->open_read();
302 Log::e(
"unable to locate video file: \"",filename,
"\"");
308 ctx.reset(
new Context(std::move(read)));
316 Log::e(
"unable to play video: \"",filename,
"\"");
322 if(event.key==Event::K_ESCAPE) {
335#if defined(__MOBILE_PLATFORM__)
340void VideoWidget::stopVideo() {
342 if(!hasPendingVideo) {
354 ctx->advance(device, fId);
355 frame = &textureCast<Texture2d&>(ctx->frameImg);
359 Log::e(
"video decoding error. frame: ",ctx->vid.currentFrame(),
", what: \"", e.what(),
"\"");
362 Log::e(
"video decoding error. frame: ",ctx->vid.currentFrame());
368 if(ctx==
nullptr || frame==
nullptr)
370 float k = float(w())/float(frame->w());
371 int vh = int(k*
float(frame->h()));
374 p.setBrush(Color(0,0,0,1));
375 p.drawRect(0,0,w(),h());
377 p.setBrush(Brush(*frame,Painter::NoBlend,ClampMode::ClampToEdge));
378 p.drawRect(0,(h()-vh)/2,w(),vh,
379 0,0,p.brush().w(),p.brush().h());
const Plane & plane(uint8_t id) const
size_t currentFrame() const
const Frame & nextFrame()
const FrameRate & fps() const
size_t frameCount() const
size_t audioCount() const
const Audio & audio(uint8_t i) const
static GameMusic & inst()
static int settingsGetI(std::string_view sec, std::string_view name)
static float settingsGetF(std::string_view sec, std::string_view name)
static Tempest::Device & device()
static const zenkit::Vfs & vdfsIndex()
static void recycle(Tempest::DescriptorArray &&arr)
Tempest::RenderPipeline bink
uint64_t tickSound() const
Tempest::Attachment frameImg
Tempest::CommandBuffer cmd[Resources::MaxFramesInFlight]
std::unique_ptr< zenkit::Read > fin
Tempest::StorageBuffer staging[Resources::MaxFramesInFlight]
std::vector< std::unique_ptr< SoundContext > > sndCtx
Context(std::unique_ptr< zenkit::Read > &&f)
void advance(Tempest::Device &device, uint8_t fId)
void yuvToRgba(const Bink::Frame &f, Pixmap &pm)
void yuvToRgba(const Bink::Frame &f, Tempest::Device &device, uint8_t fId)
Tempest::SoundDevice sndDev
Tempest::Fence sync[Resources::MaxFramesInFlight]
uint64_t processedSamples
void pushSamples(const std::vector< float > &s)
uint64_t tickCount() const
SoundContext(Context &ctx, SoundDevice &dev, uint16_t sampleRate, bool isMono)
std::vector< float > samples