#include "fx/video/pixel_stream.h" #include "fl/dbg.h" #include "fl/namespace.h" #ifndef INT32_MAX #define INT32_MAX 0x7fffffff #endif #define DBG FASTLED_DBG using fl::ByteStreamPtr; using fl::FileHandlePtr; namespace fl { PixelStream::PixelStream(int bytes_per_frame) : mbytesPerFrame(bytes_per_frame), mUsingByteStream(false) {} PixelStream::~PixelStream() { close(); } bool PixelStream::begin(FileHandlePtr h) { close(); mFileHandle = h; mUsingByteStream = false; return mFileHandle->available(); } bool PixelStream::beginStream(ByteStreamPtr s) { close(); mByteStream = s; mUsingByteStream = true; return mByteStream->available(mbytesPerFrame); } void PixelStream::close() { if (!mUsingByteStream && mFileHandle) { mFileHandle.reset(); } mByteStream.reset(); mFileHandle.reset(); } int32_t PixelStream::bytesPerFrame() { return mbytesPerFrame; } bool PixelStream::readPixel(CRGB *dst) { if (mUsingByteStream) { return mByteStream->read(&dst->r, 1) && mByteStream->read(&dst->g, 1) && mByteStream->read(&dst->b, 1); } else { return mFileHandle->read(&dst->r, 1) && mFileHandle->read(&dst->g, 1) && mFileHandle->read(&dst->b, 1); } } bool PixelStream::available() const { if (mUsingByteStream) { return mByteStream->available(mbytesPerFrame); } else { return mFileHandle->available(); } } bool PixelStream::atEnd() const { if (mUsingByteStream) { return false; } else { return !mFileHandle->available(); } } bool PixelStream::readFrame(Frame *frame) { if (!frame) { return false; } if (!mUsingByteStream) { if (!framesRemaining()) { return false; } size_t n = mFileHandle->readCRGB(frame->rgb(), mbytesPerFrame / 3); DBG("pos: " << mFileHandle->pos()); return n * 3 == size_t(mbytesPerFrame); } size_t n = mByteStream->readCRGB(frame->rgb(), mbytesPerFrame / 3); return n * 3 == size_t(mbytesPerFrame); } bool PixelStream::hasFrame(fl::u32 frameNumber) { if (mUsingByteStream) { // ByteStream doesn't support seeking DBG("Not implemented and therefore always returns true"); return true; } else { size_t total_bytes = mFileHandle->size(); return frameNumber * mbytesPerFrame < total_bytes; } } bool PixelStream::readFrameAt(fl::u32 frameNumber, Frame *frame) { // DBG("read frame at " << frameNumber); if (mUsingByteStream) { // ByteStream doesn't support seeking FASTLED_DBG("ByteStream doesn't support seeking"); return false; } else { // DBG("mbytesPerFrame: " << mbytesPerFrame); mFileHandle->seek(frameNumber * mbytesPerFrame); if (mFileHandle->bytesLeft() == 0) { return false; } size_t read = mFileHandle->readCRGB(frame->rgb(), mbytesPerFrame / 3) * 3; // DBG("read: " << read); // DBG("pos: " << mFileHandle->Position()); bool ok = int(read) == mbytesPerFrame; if (!ok) { DBG("readFrameAt failed - read: " << read << ", mbytesPerFrame: " << mbytesPerFrame << ", frame:" << frameNumber << ", left: " << mFileHandle->bytesLeft()); } return ok; } } int32_t PixelStream::framesRemaining() const { if (mbytesPerFrame == 0) return 0; int32_t bytes_left = bytesRemaining(); if (bytes_left <= 0) { return 0; } return bytes_left / mbytesPerFrame; } int32_t PixelStream::framesDisplayed() const { if (mUsingByteStream) { // ByteStream doesn't have a concept of total size, so we can't // calculate this return -1; } else { int32_t bytes_played = mFileHandle->pos(); return bytes_played / mbytesPerFrame; } } int32_t PixelStream::bytesRemaining() const { if (mUsingByteStream) { return INT32_MAX; } else { return mFileHandle->bytesLeft(); } } int32_t PixelStream::bytesRemainingInFrame() const { return bytesRemaining() % mbytesPerFrame; } bool PixelStream::rewind() { if (mUsingByteStream) { // ByteStream doesn't support rewinding return false; } else { mFileHandle->seek(0); return true; } } PixelStream::Type PixelStream::getType() const { return mUsingByteStream ? Type::kStreaming : Type::kFile; } size_t PixelStream::readBytes(uint8_t *dst, size_t len) { uint16_t bytesRead = 0; if (mUsingByteStream) { while (bytesRead < len && mByteStream->available(len)) { // use pop_front() if (mByteStream->read(dst + bytesRead, 1)) { bytesRead++; } else { break; } } } else { while (bytesRead < len && mFileHandle->available()) { if (mFileHandle->read(dst + bytesRead, 1)) { bytesRead++; } else { break; } } } return bytesRead; } } // namespace fl