[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/ThenTech/ImageEncoder/master/VideoBase.cpp [Back]  [Original]

#include "VideoBase.hpp"
#include "utils.hpp"
#include "Logger.hpp"
#include "Huffman.hpp"

dc::VideoBase::VideoBase(const std::string &source_file, const uint16_t &width, const uint16_t &height)
    : ImageBase(source_file, width, height)
    , frame_buffer_size(width * height)
    , frame_garbage_size(width * height / 2)
{
    try {
        this->raw = util::readBinaryFile(source_file);
    } catch (Exceptions::FileReadException const& e) {
        util::Logger::WriteLn(e.getMessage());
        exit(-1);
    }

    this->reader = util::allocVar(this->raw->data(), this->raw->size());
}

/**
 *  @brief  Default dtor
 */
dc::VideoBase::~VideoBase(void) {
    // Empty
}

dc::VideoProcessor::VideoProcessor(const std::string &source_file, const std::string &dest_file,
                                   const uint16_t &width, const uint16_t &height,
                                   const bool &use_rle, MatrixReader &quant_m,
                                   const uint16_t &gop, const uint16_t &merange)
    : VideoBase(source_file, width, height)
    , use_rle(use_rle), quant_m(quant_m)
    , gop(std::max(uint16_t(1), gop)), merange(merange), motioncomp(true)
    , dest_file(dest_file)
    , frames(util::allocVar())
{
    // Encode raw
    this->frame_count = this->reader->get_size()
                      / (this->frame_buffer_size + this->frame_garbage_size);

    dc::Frame::MVEC_BIT_SIZE = util::bits_needed(int16_t(this->merange));
}

dc::VideoProcessor::VideoProcessor(const std::string &source_file, const std::string &dest_file,
                                   const bool &motioncomp)
    : VideoBase(source_file, 0, 0)
    , motioncomp(motioncomp)
    , dest_file(dest_file)
    , frames(util::allocVar())
{
    // Assume input is encoded video and settings should be determined from the bytestream

    // Perform Huffman decompress (if used, first bit is '1' else '0')
    algo::Huffman hm;
    util::BitStreamReader *hm_output = hm.decode(*this->reader);
    util::Logger::WriteLn("", false);

    // Replace reader with result from decompressed Huffman stream
    if (hm_output != nullptr) {
        util::deallocVar(this->reader);
        this->reader = hm_output;
    }

    // Read Matrix
    this->quant_m = dc::MatrixReader::fromBitstream(*this->reader);

    // Read other settings in same order as they were presumably written to the encoded stream
    this->use_rle = this->reader->get(dc::ImageProcessor::RLE_BITS);
    this->width   = uint16_t(this->reader->get(dc::ImageProcessor::DIM_BITS));
    this->height  = uint16_t(this->reader->get(dc::ImageProcessor::DIM_BITS));

    this->frame_count        = this->reader->get(dc::ImageProcessor::DIM_BITS);
    this->frame_buffer_size  = this->width * this->height;  // 1 part Y data
    this->frame_garbage_size = this->frame_buffer_size / 2; // 0.5 parts UV data

    // Decoded frame will be decoded Y data
    //  + this->frame_garbage_size times 0x80 as 'garbage data' for UV components

    this->gop     = uint16_t(this->reader->get(dc::ImageProcessor::DIM_BITS));
    this->merange = uint16_t(this->reader->get(dc::ImageProcessor::DIM_BITS));

    dc::Frame::MVEC_BIT_SIZE = util::bits_needed(int16_t(this->merange));

    // TODO decode
}

/**
 *  @brief  Default dtor
 */
dc::VideoProcessor::~VideoProcessor(void) {
    util::deallocVector(this->frames);
    util::deallocVar(this->writer);
}

bool dc::VideoProcessor::process(uint8_t * const source_frame_buffer) {
    util::Logger::WriteLn("[VideoProcessor] Creating frames...");

    // this->frame_buffer_size;   ///< Total values inside 1 Frame (Y)
    // this->frame_garbage_size;  ///< Total values after frame data (UV)
    // this->frame_count          ///< Total amount of frames

    const size_t total_frame_size = this->frame_buffer_size + this->frame_garbage_size;

    dc::Frame *reference_frame = nullptr;

    for (size_t f_x = 0; f_x < this->frame_count; f_x++) {
        uint8_t * const frame_starts = source_frame_buffer
                                     + f_x * total_frame_size;

        // Every this.gop frame is an I frame
        dc::Frame *current_frame = util::allocVar(frame_starts , reference_frame,
                                                             this->width  , this->height,
                                                             this->use_rle, this->quant_m,
                                                             this->is_i_frame(f_x));

        this->frames->push_back(current_frame);
        reference_frame = current_frame;
    }

    return true;
}

void dc::VideoProcessor::saveResult(bool encoded) const {
    const size_t total_length = this->writer->get_last_byte_position();  // Total final write length in bytes

    #if 1
        // This will only write whole bytes; if pos % 8 != 0, last byte is skipped
        // Edit: Padding is now added after settings, so only whole bytes are in buffer.
        util::writeBinaryFile(this->dest_file,
                              this->writer->get_buffer(),
                              total_length);
    #else
        // Will take last byte into account
        std::ofstream file(this->dest_file, std::ofstream::binary);
        util::write(file, *this->writer);
    #endif

    util::Logger::WriteLn(std::string_format("[VideoProcessor] Original file size: %8d bytes", this->raw->size()));
    util::Logger::WriteLn(std::string_format("[VideoProcessor]       %scoded size: %8d bytes  => Ratio: %.2f%%",
                                             (encoded ? "En" : "De"),
                                             total_length,
                                             (float(total_length) / this->raw->size() * 100)));
    util::Logger::WriteLn("[VideoProcessor] Saved file at: " + this->dest_file);
}

Web Proxy Viewer  |  New URL  |  Original Page