diff --git a/vrs/utils/PixelFrame.cpp b/vrs/utils/PixelFrame.cpp index 0e9966a3..b20e2239 100644 --- a/vrs/utils/PixelFrame.cpp +++ b/vrs/utils/PixelFrame.cpp @@ -25,6 +25,7 @@ #include #include +#include #include using namespace std; @@ -179,9 +180,17 @@ PixelFrame::PixelFrame(const ImageContentBlockSpec& spec) } } +PixelFrame::PixelFrame(const ImageContentBlockSpec& spec, vector&& frameBytes) + : imageSpec_{spec}, frameBytes_{std::move(frameBytes)} {} + void PixelFrame::init(const ImageContentBlockSpec& spec) { - if (!hasSamePixels(spec)) { - imageSpec_ = spec; + if (imageSpec_.getImageFormat() != ImageFormat::RAW || !hasSamePixels(spec)) { + imageSpec_ = { + spec.getPixelFormat(), + spec.getWidth(), + spec.getHeight(), + spec.getRawStride(), + spec.getRawStride2()}; size_t size = imageSpec_.getRawImageSize(); if (XR_VERIFY(size != ContentBlock::kSizeUnknown)) { frameBytes_.resize(size); @@ -189,6 +198,11 @@ void PixelFrame::init(const ImageContentBlockSpec& spec) { } } +void PixelFrame::init(const ImageContentBlockSpec& spec, vector&& frameBytes) { + imageSpec_ = spec; + frameBytes_ = std::move(frameBytes); +} + void PixelFrame::init(shared_ptr& inOutFrame, const ImageContentBlockSpec& spec) { if (!inOutFrame) { inOutFrame = make_shared(spec); @@ -260,6 +274,60 @@ bool PixelFrame::readFrame(RecordReader* reader, const ContentBlock& cb) { return false; } +bool PixelFrame::readDiskImageData( + shared_ptr& frame, + RecordReader* reader, + const ContentBlock& cb) { + if (!frame) { + frame = make_shared(); + } + return frame->readDiskImageData(reader, cb); +} + +bool PixelFrame::readDiskImageData(RecordReader* reader, const ContentBlock& cb) { + size_t blockSize = cb.getBlockSize(); + if (cb.getContentType() != ContentType::IMAGE || blockSize == ContentBlock::kSizeUnknown) { + return false; + } + const auto& spec = cb.image(); + if (spec.getImageFormat() == ImageFormat::RAW) { + return readRawFrame(reader, spec); + } + imageSpec_ = spec; + frameBytes_.resize(blockSize); + return VERIFY_SUCCESS(reader->read(frameBytes_.data(), blockSize)); +} + +bool PixelFrame::decompressImage(VideoFrameHandler* videoFrameHandler) { + switch (imageSpec_.getImageFormat()) { + case ImageFormat::RAW: + return true; + case ImageFormat::VIDEO: + if (videoFrameHandler != nullptr) { + vector compressedData(std::move(frameBytes_)); + BufferReader reader; + return videoFrameHandler->tryToDecodeFrame( + *this, reader.init(compressedData), {imageSpec_, compressedData.size()}) == 0; + } + break; + case ImageFormat::PNG: { + vector compressedData(std::move(frameBytes_)); + return readPngFrame(compressedData); + } + case ImageFormat::JPG: { + vector compressedData(std::move(frameBytes_)); + return readJpegFrame(compressedData); + } + case ImageFormat::JXL: { + vector compressedData(std::move(frameBytes_)); + return readJxlFrame(compressedData); + } + default: + return false; + } + return false; +} + bool PixelFrame::readRawFrame(RecordReader* reader, const ImageContentBlockSpec& inputImageSpec) { // Read multiplane images as is if (inputImageSpec.getPlaneCount() != 1) { diff --git a/vrs/utils/PixelFrame.h b/vrs/utils/PixelFrame.h index f5dc0d39..0fc91f3a 100644 --- a/vrs/utils/PixelFrame.h +++ b/vrs/utils/PixelFrame.h @@ -50,6 +50,7 @@ class PixelFrame { public: PixelFrame() = default; PixelFrame(const ImageContentBlockSpec& spec); + PixelFrame(const ImageContentBlockSpec& spec, vector&& frameBytes); PixelFrame(PixelFormat pf, uint32_t w, uint32_t h, uint32_t stride = 0) : PixelFrame(ImageContentBlockSpec(pf, w, h, stride)) {} @@ -57,6 +58,7 @@ class PixelFrame { inline void init(PixelFormat pf, uint32_t w, uint32_t h, uint32_t stride = 0) { init(ImageContentBlockSpec(pf, w, h, stride)); } + void init(const ImageContentBlockSpec& spec, vector&& frameBytes); static void init(shared_ptr& inOutFrame, const ImageContentBlockSpec& spec); static inline void init( @@ -118,11 +120,22 @@ class PixelFrame { readFrame(shared_ptr& frame, RecordReader* reader, const ContentBlock& cb); bool readFrame(RecordReader* reader, const ContentBlock& cb); + /// Read a record's image data, merely reading the disk data without any decompression. + /// The resulting PixelFrame will have an unmodified ImageFormat (raw, jpg, png, jxl, video). + static bool + readDiskImageData(shared_ptr& frame, RecordReader* reader, const ContentBlock& cb); + bool readDiskImageData(RecordReader* reader, const ContentBlock& cb); + + /// From any ImageFormat, decompress the image to ImageFormat::RAW if necessary. + /// To decompress ImageFormat::VIDEO data, you must provide a valid VideoFrameHandler object, the + /// same one for all the frames of a particular stream. + bool decompressImage(VideoFrameHandler* videoFrameHandler = nullptr); + /// Read a RAW frame into the internal buffer. /// @return True if the frame type is supported & the frame was read. bool readRawFrame(RecordReader* reader, const ImageContentBlockSpec& inputImageSpec); - /// Read a compressed image, except for video codec compression. + /// Decode compressed image data, except for video codec compression. bool readCompressedFrame(const vector& pixels, ImageFormat imageFormat); static bool readRawFrame(