blob: 13cafff79a8a847dac405651b0272069bcb51c9f [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
//
// WP2 decode into RGB 12 bits to keep as much precision as possible.
#include "extras/ccsp_imageio.h"
#include "extras/extras.h"
#include "src/utils/data_source.h"
#include "src/utils/utils.h"
#include "src/wp2/decode.h"
namespace WP2 {
//------------------------------------------------------------------------------
// Identity matrix but keep 12 bits of precision (unsigned) compared to 8.
constexpr CSPMtx kRGBToRGB12({16, 0, 0, 0, 16, 0, 0, 0, 16}, 0);
class ImageReaderWP212b : public ImageReader::Impl {
public:
ImageReaderWP212b(const uint8_t* data, size_t data_size,
YUVPlane* const ccsp_buffer, CSPMtx* const ccsp_to_rgb,
Metadata* const metadata, LogLevel log_level,
size_t max_num_pixels)
: ImageReader::Impl(nullptr, data, data_size, log_level, max_num_pixels),
ccsp_buffer_(ccsp_buffer),
ccsp_to_rgb_(ccsp_to_rgb),
metadata_(metadata) {}
WP2Status ReadFrame(bool* const is_last,
uint32_t* const duration_ms) override {
// Check width/height before allocating anything.
BitstreamFeatures features;
WP2_CHECK_STATUS(features.Read(data_, data_size_));
// TODO(yguyon): Is it better to output only the first frame or an error?
WP2_CHECK_OK(!features.is_animation, WP2_STATUS_UNSUPPORTED_FEATURE);
*is_last = true;
*duration_ms = ImageReader::kInfiniteDuration;
WP2_CHECK_STATUS(CheckDimensions(features.width, features.height));
loop_count_ = ImageReader::kInfiniteLoopCount;
// Allocate a padded buffer to avoid doing it internally.
// TODO(yguyon): Check if 'has_alpha' is needed beforehand (decode GParams).
WP2_CHECK_STATUS(ccsp_buffer_->Resize(features.width, features.height,
/*pad=*/kPredWidth,
/*has_alpha=*/true));
// Decode.
WP2_CHECK_STATUS(Decode(data_, data_size_,
kRGBToRGB12.mtx(), kRGBToRGB12.shift,
ccsp_buffer_->Y.Row(0), ccsp_buffer_->Y.Step(), ccsp_buffer_->Y.Size(),
ccsp_buffer_->U.Row(0), ccsp_buffer_->U.Step(), ccsp_buffer_->U.Size(),
ccsp_buffer_->V.Row(0), ccsp_buffer_->V.Step(), ccsp_buffer_->V.Size(),
ccsp_buffer_->HasAlpha() ? ccsp_buffer_->A.Row(0) : nullptr,
ccsp_buffer_->A.Step(), ccsp_buffer_->A.Size(), metadata_));
bool is_opaque = true;
for (uint32_t y = 0; y < ccsp_buffer_->A.h_ && is_opaque; ++y) {
for (uint32_t x = 0; x < ccsp_buffer_->A.w_ && is_opaque; ++x) {
if (ccsp_buffer_->A.At(x, y) != kAlphaMax) is_opaque = false;
}
}
if (is_opaque) ccsp_buffer_->A.Clear();
// Remove padding without deallocating.
WP2_CHECK_STATUS(ccsp_buffer_->SetView(
*ccsp_buffer_, {0, 0, features.width, features.height}));
*ccsp_to_rgb_ = CSPMtx({1, 0, 0, 0, 1, 0, 0, 0, 1}, 4); // Go back to 8b.
return WP2_STATUS_OK;
}
protected:
// Pointers to user structs.
YUVPlane* const ccsp_buffer_;
CSPMtx* const ccsp_to_rgb_;
Metadata* const metadata_;
};
void CCSPImageReader::SetImplWP2(YUVPlane* const buffer,
CSPMtx* const ccsp_to_rgb,
Metadata* const metadata, LogLevel log_level,
size_t max_num_pixels) {
impl_.reset(new (WP2Allocable::nothrow) ImageReaderWP212b(
data_.bytes, data_.size, buffer, ccsp_to_rgb, metadata, log_level,
max_num_pixels));
if (impl_ == nullptr) status_ = WP2_STATUS_OUT_OF_MEMORY;
}
//------------------------------------------------------------------------------
} // namespace WP2