diff options
Diffstat (limited to 'gpr/source/lib/vc5_common')
28 files changed, 4538 insertions, 0 deletions
diff --git a/gpr/source/lib/vc5_common/CMakeLists.txt b/gpr/source/lib/vc5_common/CMakeLists.txt new file mode 100644 index 0000000..090b212 --- /dev/null +++ b/gpr/source/lib/vc5_common/CMakeLists.txt @@ -0,0 +1,20 @@ +# library +set( LIB_NAME vc5_common ) + +# get source files +file( GLOB SRC_FILES "*.c" ) + +# get include files +file( GLOB INC_FILES "*.h" ) + +# add include files from other folders +include_directories( "../common/private" ) +include_directories( "../common/public" ) + +# library +add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} ) + +target_link_libraries( ${LIB_NAME} ) + +# set the folder where to place the projects +set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib ) diff --git a/gpr/source/lib/vc5_common/bitstream.c b/gpr/source/lib/vc5_common/bitstream.c new file mode 100755 index 0000000..cef4312 --- /dev/null +++ b/gpr/source/lib/vc5_common/bitstream.c @@ -0,0 +1,445 @@ +/*! @file bitstream.c + * + * @brief Implementation of a bitstream for reading bits from a byte stream. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +/*! + @brief Return a mask with the specified number of bits set to one + */ +BITWORD BitMask(int n) +{ + if (n < bit_word_count) + { + BITWORD mask = 0; + if (n > 0) { + mask = ((1 << n) - 1); + } + return mask; + } + return BIT_WORD_MAX; +} + +/*! + @brief Initialize a bitstream data structure + + This routine is the constructor for the bitstream data type. + + The sample offset stack is used to mark the offset to a position + in the bitstream for computing the size field of sample chunks. + */ +CODEC_ERROR InitBitstream(BITSTREAM *bitstream) +{ + if (bitstream != NULL) + { + bitstream->error = BITSTREAM_ERROR_OKAY; + bitstream->stream = NULL; + bitstream->buffer = 0; + bitstream->count = 0; + +#if VC5_ENABLED_PART(VC5_PART_SECTIONS) + // Initialize the stack of sample offsets + memset(bitstream->sample_offset_stack, 0, sizeof(bitstream->sample_offset_stack)); + bitstream->sample_offset_count = 0; +#endif + + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_NULLPTR; +} + +/*! + @brief Attach a bitstream to a byte stream. + + It is permitted for the byte stream to be NULL, in which case the + bitstream will not be able to replenish its internal buffer, but + the consequences are undefined. + */ +CODEC_ERROR AttachBitstream(struct _bitstream *bitstream, struct _stream *stream) +{ + assert(bitstream != NULL); + bitstream->stream = stream; + return CODEC_ERROR_OKAY; +} + +/*! + @brief Detach a bitstream from a byte stream. + + Any resources allocated by the bitstream are released without deallocating + the bitstream data structure itself. The byte stream associated with the + bitstream is not closed by this routine. The byte stream must be closed, + if and when appropriate, by the caller. + */ +CODEC_ERROR ReleaseBitstream(BITSTREAM *bitstream) +{ + //TODO: What cleanup needs to be performed? + (void) bitstream; + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return the specified number of bits from the bitstream + */ +BITWORD GetBits(BITSTREAM *stream, BITCOUNT count) +{ + // Return zero if the request cannot be satisfied + BITWORD bits = 0; + + // Check that the number of requested bits is valid + //assert(0 <= count && count <= bit_word_count); + assert(count <= bit_word_count); + + // Check that the unused portion of the bit buffer is empty + assert((stream->buffer & BitMask(bit_word_count - stream->count)) == 0); + + if (count == 0) goto finish; + + // Are there enough bits in the buffer to satisfy the request? + if (count <= stream->count) + { + // Right align the requested number of bits in the bit buffer + bits = (stream->buffer >> (bit_word_count - count)); + + // Reduce the number of bits in the bit buffer + stream->buffer <<= count; + stream->count = (stream->count - count); + } + else + { + BITCOUNT low_bit_count; + + // Use the remaining bits in the bit buffer + assert(stream->count > 0 || stream->buffer == 0); + bits = (stream->buffer >> (bit_word_count - count)); + + // Compute the number of bits to be used from the next word + low_bit_count = count - stream->count; + stream->count = 0; + assert(low_bit_count > 0); + + // Fill the bit buffer + assert(stream->count == 0); + GetBuffer(stream); + assert(stream->count >= low_bit_count); + + // Use the new bits in the bit buffer + bits |= (stream->buffer >> (bit_word_count - low_bit_count)); + + // Reduce the number of bits in the bit buffer + if (low_bit_count < bit_word_count) { + stream->buffer <<= low_bit_count; + } + else { + stream->buffer = 0; + } + assert(low_bit_count <= stream->count); + stream->count = (stream->count - low_bit_count); + } + +finish: + // The bit count should never be negative or larger than the size of the bit buffer + //assert(0 <= stream->count && stream->count <= bit_word_count); + assert(stream->count <= bit_word_count); + + // The unused bits in the bit buffer should all be zero + assert((stream->buffer & BitMask(bit_word_count - stream->count)) == 0); + + // The unused bits in the result should all be zero + assert((bits & ~BitMask(count)) == 0); + + return bits; +} + +/*! + @brief Read more bits and append to an existing word of bits + + Read the specified number of bits from the bitstream and append + the new bits to the right end of the word supplied as an argument. + This is a convenience routine that is used to accumulate bits that + may match a codeword. + */ +BITWORD AddBits(BITSTREAM *bitstream, BITWORD bits, BITCOUNT count) +{ + BITWORD new_bits = GetBits(bitstream, count); + assert((new_bits & ~BitMask(count)) == 0); + + bits = (bits << count) | new_bits; + + return bits; +} + +/*! + @brief Write a longword (32 bits) to the stream + */ +CODEC_ERROR PutLong(BITSTREAM *stream, BITWORD longword) +{ + return PutBits(stream, longword, bit_word_count); +} + +/*! + @brief Write the specified number of bits to the bitstream + */ +CODEC_ERROR PutBits(BITSTREAM *stream, BITWORD bits, BITCOUNT count) +{ + BITCOUNT unused_bit_count; + + if (count == 0) { + return CODEC_ERROR_OKAY; + } + + // Check that the unused portion of the input bits is empty + assert((bits & (BitMask(bit_word_count - count) << count)) == 0); + + // Check that the number of input bits is valid + //assert(0 <= count && count <= bit_word_count); + assert(count <= bit_word_count); + + // Check that the unused portion of the bit buffer is empty + unused_bit_count = bit_word_count - stream->count; + assert((stream->buffer & BitMask(unused_bit_count)) == 0); + + // Is there room in the bit buffer for the new bits? + if (count <= unused_bit_count) + { + // Fill the remaining space in the bit buffer + stream->buffer |= (bits << (unused_bit_count - count)); + + // Reduce the number of unused bits in the bit buffer + stream->count += count; + } + else + { + // Any room in the bit buffer? + if (unused_bit_count > 0) + { + // Use the number of input bits that will fit in the bit buffer + stream->buffer |= (bits >> (count - unused_bit_count)); + + // Reduce the number of input bits by the amount used + count -= unused_bit_count; + //assert(count >= 0); + } + + // Write the bit buffer to the byte stream + PutWord(stream->stream, stream->buffer ); + + // Insert the remaining input bits into the bit buffer + stream->buffer = (bits << (bit_word_count - count)); + + // Increment the number of bits in the bit buffer + stream->count = count; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Fill the internal bitstream buffer by reading a byte stream + + @todo Need to modify this routine to return an error code if it cannot + read from the byte stream associated with the bitstream. + */ +CODEC_ERROR GetBuffer(BITSTREAM *bitstream) +{ + // Need to signal an underflow error? + if (! (bitstream != NULL && bitstream->stream != NULL)) { + assert(0); + + if( bitstream->error == BITSTREAM_ERROR_UNDERFLOW ) + return CODEC_ERROR_OUTOFMEMORY; + } + + // The bit buffer should be empty + assert(bitstream->count == 0); + + // Fill the bit buffer with a word from the byte stream + bitstream->buffer = Swap32(GetWord(bitstream->stream)); + bitstream->count = bit_word_count; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write the internal bitstream buffer to a byte stream + + @todo Need to modify this routine to return an error code if it cannot + write to the byte stream associated with the bitstream. + */ +CODEC_ERROR PutBuffer(BITSTREAM *bitstream) +{ + //TODO: Need to signal an overflow error + assert(bitstream != NULL && bitstream->stream != NULL); + + // The bit buffer should be full + assert(bitstream->count == bit_word_count); + + // Write the bit buffer to the byte stream + PutWord(bitstream->stream, bitstream->buffer ); + + // Empty the bit buffer + bitstream->buffer = 0; + bitstream->count = 0; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Convert a bitstream error code to a codec error codec + + The bitstream and byte stream modules use a separate enumeration + for error codes since these modules are used in other applications. + The bistream error code is embedded in a range of codec error codes + that are reserved for bitstream errors. + */ +CODEC_ERROR CodecErrorBitstream(BITSTREAM_ERROR error) +{ + uint32_t codec_error = CODEC_ERROR_BITSTREAM; + codec_error |= (uint32_t)error; + return (CODEC_ERROR)codec_error; +} + +/*! + @brief Convert a bitstream error code into a codec error code + + The bitstream and byte stream modules might be used in other + applications and have their own errors codes. This routine + embeds a bitstream error code into a codec error code. The + bitstream error code is carried in the low bits of the codec + error code. + + @todo Eliminate separate error codes for bitstreams? + */ +CODEC_ERROR BitstreamCodecError(BITSTREAM *bitstream) +{ + assert(bitstream != NULL); + if (! (bitstream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + return CodecErrorBitstream(bitstream->error); +} + +/*! + @brief Read a block of bytes from the bitstream + */ +CODEC_ERROR GetByteArray(BITSTREAM *bitstream, uint8_t *array, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + { + array[i] = GetBits(bitstream, 8); + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write a block of bytes into the bitstream + */ +CODEC_ERROR PutByteArray(BITSTREAM *bitstream, const uint8_t *array, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + { + PutBits(bitstream, array[i], 8); + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write any bits in the buffer to the byte stream + */ +CODEC_ERROR FlushBitstream(BITSTREAM *bitstream) +{ + // Any bits remaining in the bit buffer? + if (bitstream->count > 0) + { + // Write the bit buffer to the output stream + PutBuffer(bitstream); + } + + // Indicate that the bitstream buffer is empty + bitstream->count = 0; + bitstream->buffer = 0; + + // Flush the output stream + FlushStream(bitstream->stream); + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Get the current position in the byte stream + + The current position in the byte stream associated with the + bitstream is returned. The intent is to allow the bitstream + (and the associated byte stream) to be restored to the saved + position. + + @todo Need to record the state of the bitstream buffer and + bit count so that the entire bitstream state can be restored. + */ +size_t GetBitstreamPosition(BITSTREAM *bitstream) +{ + if (bitstream->count == bit_word_count) { + PutBuffer(bitstream); + } + + // The bit buffer must be empty + assert(bitstream->count == 0); + + // The bit buffer must be empty + return (bitstream->stream->byte_count); +} + +/*! + @brief Rewind the bitstream + + This routine rewinds the bitstream to the beginning of the byte stream + that has been attached to the bitstream. The byte stream is also reset. + + If the byte stream could not be reset, then the internal bitstream state + is not reset. + */ +CODEC_ERROR RewindBitstream(BITSTREAM *bitstream) +{ + assert(bitstream != NULL); + if (! (bitstream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + if (bitstream->stream != NULL) { + CODEC_ERROR error = RewindStream(bitstream->stream); + if (error != CODEC_ERROR_OKAY) { + return error; + } + } + + // Reset the bitstream internal state + bitstream->buffer = 0; + bitstream->count = 0; + bitstream->error = BITSTREAM_ERROR_OKAY; + + return CODEC_ERROR_OKAY; +} + diff --git a/gpr/source/lib/vc5_common/bitstream.h b/gpr/source/lib/vc5_common/bitstream.h new file mode 100755 index 0000000..85c2a25 --- /dev/null +++ b/gpr/source/lib/vc5_common/bitstream.h @@ -0,0 +1,135 @@ +/*! @file bitstream.h + * + * @brief Declaration of the bitstream data structure. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +/*! + @brief Bitstream error codes + + The bitstream contains its own enumeration of error codes since this + module may be used in other applications. + */ +typedef enum _bitstream_error +{ + BITSTREAM_ERROR_OKAY = 0, //!< No error + BITSTREAM_ERROR_UNDERFLOW, //!< No unread bits remaining in the bitstream + BITSTREAM_ERROR_OVERFLOW, //!< No more bits can be written to the bitstream + BITSTREAM_ERROR_BADTAG, //!< Unexpected tag found in the bitstream + + //TODO: Add more bitstream errors + +} BITSTREAM_ERROR; + +typedef uint32_t BITWORD; //!< Data type of the internal bitstream buffer + +typedef uint_fast8_t BITCOUNT; //!< Number of bits in the bitsteam buffer + +//! Maximum number of bits in a bit word +static const BITCOUNT bit_word_count = 32; + +//! Maximum value of a bit word +#define BIT_WORD_MAX 0xFFFFFFFF + +//! Sample offset stack depth +#define MAX_SAMPLE_OFFSET_COUNT 8 + +/*! + @brief Declaration of the bitstream data structure + + The bitstream uses a byte stream to read bytes from a file or a buffer + in memory. This isolates that bitstream module from the type of byte + stream. + */ +typedef struct _bitstream +{ + BITSTREAM_ERROR error; //!< Error while processing the bitstream + struct _stream *stream; //!< Stream for reading bytes into the buffer + BITWORD buffer; //!< Internal buffer holds remaining bits + BITCOUNT count; //!< Number of bits remaining in the buffer + +#if VC5_ENABLED_PART(VC5_PART_SECTIONS) + /*! + The sample offset stack is used to record offsets to the start of nested + syntax structures. For example, a sample size segment is written into the + bitstream with a size of zero, since the size of the syntax element is not + known in advance. The offset to the sample size segment is pushed onto the + sample offset stack so that the location of the sample size segment can be + updated with the actual size of a syntax element after the complete element + is written into the bitstream. + + This data structure is called the ChunkSizeOffset in the current codec + implementation. + */ + uint32_t sample_offset_stack[MAX_SAMPLE_OFFSET_COUNT]; + + //! Number of entries in the sample offset stack + uint_fast8_t sample_offset_count; +#endif + +} BITSTREAM; + +#ifdef __cplusplus +extern "C" { +#endif + + BITWORD BitMask(int n); + + CODEC_ERROR CodecErrorBitstream(BITSTREAM_ERROR error); + + // Initialize a bitstream data structure + CODEC_ERROR InitBitstream(BITSTREAM *bitstream); + + // Bind the bitstream to a byte stream + CODEC_ERROR AttachBitstream(struct _bitstream *bitstream, struct _stream *stream); + + CODEC_ERROR ReleaseBitstream(BITSTREAM *stream); + + BITWORD GetBits(BITSTREAM *stream, BITCOUNT count); + + CODEC_ERROR PutBits(BITSTREAM *stream, BITWORD bits, BITCOUNT count); + + BITWORD AddBits(BITSTREAM *stream, BITWORD bits, BITCOUNT count); + + CODEC_ERROR GetBuffer(BITSTREAM *stream); + + CODEC_ERROR PutBuffer(BITSTREAM *stream); + + CODEC_ERROR PutLong(BITSTREAM *stream, BITWORD longword); + + // Rewind the bitstream and the associated byte stream + CODEC_ERROR RewindBitstream(BITSTREAM *bitstream); + + CODEC_ERROR BitstreamCodecError(BITSTREAM *bitstream); + + // Return the current position of the bitstream pointer in the sample + size_t GetBitstreamPosition(BITSTREAM *stream); + + CODEC_ERROR FlushBitstream(BITSTREAM *bitstream); + + CODEC_ERROR GetByteArray(BITSTREAM *bitstream, uint8_t *array, size_t size); + + CODEC_ERROR PutByteArray(BITSTREAM *bitstream, const uint8_t *block, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // BITSTREAM_H diff --git a/gpr/source/lib/vc5_common/codec.c b/gpr/source/lib/vc5_common/codec.c new file mode 100755 index 0000000..2308f75 --- /dev/null +++ b/gpr/source/lib/vc5_common/codec.c @@ -0,0 +1,201 @@ +/*! @file codec.c + * + * @brief Implementation of functions that are common to the + * reference decoder and encoder + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +/*! + @brief Initialize the codec state to before encoding or decoding the bitstream + + Most of the codec state can be deduced from the decoding parameters. + For example, the dimensions of the first wavelet band in the bitstream + can be deduced from the encoded frame dimensions and the structure of + the wavelet tree. + + The encoder will not insert parameters into the bitstream if the values + of the parameters are the same as in the codec state. This routine + should initialize the codec state with correct values if those values + can be inferred by the decoder, otherwise the use incorrect or default + values. + + Note that the default encoded format is YUV 4:2:2, but this format is not + supported by the baseline profile encoder so the encoded format must be + explicitly written into the bitstream. + + @todo Add more default values required to properly initialize the codec state. +*/ +CODEC_ERROR PrepareCodecState(CODEC_STATE *codec) +{ + // Initialize the channel to channel number zero + codec->channel_number = 0; + + // Initialize the subband number to subband zero (the lowpass band) + codec->subband_number = 0; + + // The number of subbands per channel is a constant + codec->subband_count = 10; + + // The default precision of pixels in the input frame is ten bits + codec->bits_per_component = 12; + + // Force the encoder to insert the encoded dimensions into the bitstream + //codec->encoded.width = 0; + //codec->encoded.height = 0; + + /* + TODO: Do not have to encode the display dimensions into the bitstream if the decoder + can infer the display dimensions from the encoded dimensions and format, but must + encode the display dimensions if the encoded dimensions include padding. + + TODO: Check that this matches the current decoder implementation. + */ + + // Set the default precision for encoding lowpass band coefficients + codec->lowpass_precision = 16; + + //TODO: Set more default values in the codec state + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Reformat a segment value into the encoder version + + The version of the encoder that created the clip may be encoded into every sample. + + @todo Document the encoder version number format +*/ +uint32_t EncoderVersion(uint32_t value) +{ + return (((value >> 12) & 0x0F) << 16) | + (((value >> 8) & 0x0F) << 8) | + ((value) & 0xFF); +} + +/*! + @brief Unpack the version tag value into its components +*/ +void SetCodecVersion(uint8_t version[3], uint16_t value) +{ + version[0] = (uint8_t)((value >> 12) & 0x0F); // Major version + version[1] = (uint8_t)((value >> 8) & 0x0F); // Minor version + version[2] = (uint8_t)(value & 0xFF); // Revision +} + +#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS) +/*! + @brief Return true if the image format is valid +*/ +bool ValidImageFormat(IMAGE_FORMAT image_format) +{ + if (0 < image_format && image_format < IMAGE_FORMAT_COUNT) { + return true; + } + return false; +} +#endif + +/*! + @brief Unpack the tag value into the prescale table + + The prescale table contains the prescale value for each wavelet in the + transform. The prescale value is a right shift that is applied to the + input data before the wavelet is computed. + + The prescale table is used for all transforms and does not depend on the + channel number. +*/ +CODEC_ERROR UpdatePrescaleTable(CODEC_STATE *codec, TAGWORD value) +{ + int wavelet_index; + + for (wavelet_index = 0; wavelet_index < MAX_WAVELET_COUNT; wavelet_index++) + { + // Unpack the prescale value + int prescale_value = (value >> (14 - wavelet_index * 2)) & 0x03; + assert(0 <= prescale_value && prescale_value < UINT8_MAX); + + // Store the prescale value in the codec state + codec->prescale_table[wavelet_index] = (uint_fast8_t)prescale_value; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Update the flags that describe the frame structure + + The frame structure includes characteristics such as interlaced versus + progressive and top or bottom field first. +*/ +CODEC_ERROR UpdateFrameStructureFlags(CODEC_STATE *codec, TAGWORD value) +{ + codec->progressive = !(value & IMAGE_STRUCTURE_INTERLACED); + codec->top_field_first = !(value & IMAGE_STRUCTURE_BOTTOM_FIELD_FIRST); + codec->frame_inverted = (value & IMAGE_STRUCTURE_BOTTOM_ROW_FIRST); + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Initialize the codec state using the default constructor + + This routine is like a default constructor in C++ as it guarantees that + the codec state is initialized to a know starting state with all pointers + set to NULL and all counters set to zero. + + The routine @ref PrepareCodecState is used to set default values for the + codec state prior to decoding a sample. +*/ +CODEC_ERROR InitCodecState(CODEC_STATE *state) +{ + // Clear the codec state + memset(state, 0, sizeof(CODEC_STATE)); + return CODEC_ERROR_OKAY; +} + +/*! + @brief Set the flags that determine the band coding + + There can be up to 15 different codebooks as specified by the lower + four bigs in the band coding flags. Use the default codebook if the + active codebook is zero. + + The baseline profile does not allow difference coding or alternative + codebooks. +*/ +CODEC_ERROR SetBandCoding(CODEC_STATE *codec, TAGWORD value) +{ + (void) codec; + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return true if the specified part is enabled at runtime + + This predicate is used to test whether a specific part in the VC-5 standard is + enabled at runtime by this codec implementation. + +*/ +bool IsPartEnabled(ENABLED_PARTS enabled_parts, int part_number) +{ + return ((enabled_parts & VC5_PART_MASK(part_number)) != 0); +} + diff --git a/gpr/source/lib/vc5_common/codec.h b/gpr/source/lib/vc5_common/codec.h new file mode 100755 index 0000000..6763091 --- /dev/null +++ b/gpr/source/lib/vc5_common/codec.h @@ -0,0 +1,315 @@ +/*! @file codec.h + * + * @brief State of the decoder while decoding a sample. The codec state + * contains information about the current state of the decoding process. + * The codec state is updated as the bitstream is decoded. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef CODEC_H +#define CODEC_H + +#include "syntax.h" + +static const SEGMENT StartMarkerSegment = ((0x56 << 24) | (0x43 << 16) | (0x2D << 8) | 0x35); + +/*! + @brief Tags that define elements in the bitstream + + All syntax elements in the encoded bitstream begin with a 16-bit tag that + specifies the type of element. The 16-bit tag is followed by a 16-bit value, + forming a tag-value pair. + + If the tag is a negative number, then the actual tag is the negation of the + tag value and the negative sign indicates that the tag and its value are an + optional tag value pair. If the tag is a positive value, then the segment + is required. A decoder must be able to decode all required tag-value pairs, + but can skip tag-value pairs that are optional. + + In a VC-5 Part 1 bitstream, the image width and height are an upper bound on the + dimensions of each channel represented in the bitstream. In a VC-5 Part 3 bitstream, + the image width and height are the actual dimensions of the image represented in the + bitstream. The width and height of the image and each pattern element is sufficient + to determine the width and height of each component array. + + A range of tags is reserved for chunks and the value is the size of the chunk. +*/ +typedef enum _codec_tag +{ + CODEC_TAG_ImageWidth = 20, //!< Upper bound on the width of the image + CODEC_TAG_ImageHeight = 21, //!< Upper bound on the height of the image + CODEC_TAG_BitsPerComponent = 101, //!< Number of bits in the source image + CODEC_TAG_ChannelCount = 12, //!< Number of channels in the transform + CODEC_TAG_SubbandCount = 14, //!< Number of encoded subbands + CODEC_TAG_ChannelNumber = 62, //!< Channel number + CODEC_TAG_SubbandNumber = 48, //!< Subband number of this wavelet band + CODEC_TAG_LowpassPrecision = 35, //!< Number of bits per lowpass coefficient + CODEC_TAG_Quantization = 53, //!< Quantization applied to band + CODEC_TAG_PrescaleShift = 109, //!< Packed prescale shift for each wavelet level + CODEC_TAG_ChannelWidth = 104, //!< Width of the next channel in the bitstream + CODEC_TAG_ChannelHeight = 105, //!< Height of the next channel in the bitstream + + CODEC_TAG_LargeCodeblock = 0x6000, //!< Large chunk that contains a codeblock + + CODEC_TAG_SMALL_CHUNK = 0x4000, //!< Small chunk with a 16-bit payload size (in segments) + CODEC_TAG_LARGE_CHUNK = 0x2000, //!< Large chunk with a 24-bit payload size (in segments) + + //! Mask for detecting the tag for a small or large chunk (including codeblocks) + CODEC_TAG_CHUNK_MASK = (CODEC_TAG_SMALL_CHUNK | CODEC_TAG_LARGE_CHUNK), + +#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS) + // Codec tags used by VC-5 Part 3 bitstreams + CODEC_TAG_PatternWidth = 106, //!< Number of samples per row in each pattern element + CODEC_TAG_PatternHeight = 107, //!< Number of rows of samples in each pattern element + CODEC_TAG_ComponentsPerSample = 108, //!< Number of components in each sample in the pattern element + CODEC_TAG_ImageFormat = 84, //!< Format of the image represented by the bitstream + CODEC_TAG_MaxBitsPerComponent = 102, //!< Upper bound on the number of bits per component + + // Small chunk elements defined by VC-5 Part 3 + CODEC_TAG_VendorSpecificData = 0x4000, //!< Small chunk containing vendor-specific data + CODEC_TAG_InversePermutation = 0x4001, //!< Small chunk containing the inverse component permutation + CODEC_TAG_InverseTransform = 0x4002, //!< Small chunk containing the inverse component transform (8 bit representation) + CODEC_TAG_InverseTransform16 = 0x4003, //!< Small chunk containing the inverse component transform (16 bit representation) + CODEC_TAG_UniqueImageIdentifier = 0x4004, //!< Small chunk containing the identifier and sequence number for the image +#endif + +#if VC5_ENABLED_PART(VC5_PART_LAYERS) + CODEC_TAG_LayerCount = 120, //!< Number of layers in the bitstream + CODEC_TAG_LayerNumber = 121, //!< Number of the next layer in the bitstream + CODEC_TAG_LayerPattern = 122, //!< Mask indicating the use cases in the bitstream +#endif + +#if VC5_ENABLED_PART(VC5_PART_SECTIONS) + CODEC_TAG_ImageCount = 130, //!< Number of image bitstream sections in the bitstream + CODEC_TAG_ImageNumber = 131, //!< Unique number assigned to an image bitstream section + + // Predefined codec tags for structures in the VC-5 bitstream + CODEC_TAG_ImageSectionTag = 0x2700, //!< Section that contains a single image + CODEC_TAG_HeaderSectionTag = 0x2500, //!< Section that contains the bitstream header + CODEC_TAG_LayerSectionTag = 0x2600, //!< Section that contains a single layer + CODEC_TAG_ChannelSectionTag = 0x2400, //!< Section that contains a single channel + CODEC_TAG_WaveletSectionTag = 0x2100, //!< Section that contains all subbands for one wavelet + CODEC_TAG_SubbandSectionTag = 0x2000, //!< Section that contains a single subband +#endif + +#if VC5_ENABLED_PART(VC5_PART_METADATA) + // Small and large chunks of metadata + CODEC_TAG_SmallMetadata = 0x4010, //!< Small chunk containing metadata tuples (VC-5 Part 7) + CODEC_TAG_LargeMetadata = 0x6100, //!< Large chunk containing metadata tuples (VC-5 Part 7) +#endif + +} CODEC_TAG; + +#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS) +/*! + @brief Format of the encoded sample + + The VC-5 Part 3 can support four bitstream representations of the encoded image. + + The image format must be specified for any VC-5 Part 3 bitstream. +*/ +typedef enum _image_format +{ + IMAGE_FORMAT_UNKNOWN = 0, //!< The image format has not been specified + IMAGE_FORMAT_RAW = 4, //!< RAW image format (special case of CFA) + + /***** Add new encoded formats above this line *****/ + + IMAGE_FORMAT_COUNT, //!< Number of image formats that have been defined + +} IMAGE_FORMAT; + +#endif + + +/*! + @brief Band encoding method + + Several different schemes have been tried for entropy coding the highpass bands. + The baseline profile only supports the run lengths encoding method. + + The run lengths encoding method using a Huffman code to encode runs of zeros and + highpass coefficient magnitudes (unsigned). Runs of zeros can extend across row + boundaries, so large sections of a highpass band that are mostly zeros can be + encoded very efficiently. + + @todo Need to cull this list as many band encoding methods are no longer supported. +*/ +enum band_encoding { + BAND_ENCODING_ZEROTREE = 1, + BAND_ENCODING_CODEBOOK, + BAND_ENCODING_RUNLENGTHS, + BAND_ENCODING_16BIT, + BAND_ENCODING_LOSSLESS +}; + +/*! + The codec state contains information about the decoding process obtained + as a sample is decoded. The information is transient and is only used + while decoding a sample. The decoder data structure contains information + that should persist from onen sample to the next. + + The codec state is initialized using information in the decoder data structure + at the start of decoding a sample. + + The intent is that the encoder can operate the same state machine during encoding + and any information available in the state machine does not have to be encoded into + the sample as it is assumed that the decoder can and will derive the same information. + For example, the dimensions of the first subband can be computed from the encoded + dimensions and the number of wavelet levels, so it is not necessary to encode this + information. Likewise, after the last band in a wavelet is decoded the dimensions + of the bands in the wavelet at the next level can be deduced and it is not necessary + to encode this information into the sample. +*/ +typedef struct _codec_state +{ + uint16_t channel_number; //!< Index of current channel being decoded + DIMENSION channel_width; //!< Width of the next channel in the bitstream + DIMENSION channel_height; //!< Height of the next channel in the bitstream + PRECISION bits_per_component; //!< Precision of the component array (in bits) + + uint16_t subband_number; //!< Index of current subband being decoded + +#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS) + IMAGE_FORMAT image_format; //!< Format of the image represented by the bitstream + DIMENSION pattern_width; //!< Width of the pattern elements (in samples) + DIMENSION pattern_height; //!< Height of the pattern elements (in rows) + DIMENSION components_per_sample; //!< Number of components in each sample in the pattern element + PRECISION max_bits_per_component; //!< Maximum number of bits for each value in the component arrays +#endif + +#if VC5_ENABLED_PART(VC5_PART_LAYERS) + uint_least8_t layer_count; +#endif + + uint_least8_t channel_count; //!< Number of channels in the current layer + uint_least8_t wavelet_count; //!< Number of wavelets in the current layer + uint_least8_t subband_count; //!< Number of suibbands in the current layer + + //! The channel position is used for skipping subbands and jumping to particular channels + size_t channel_position; + + uint32_t encoded_format; //!< Internal encoded representation + uint32_t encoded_quality; //!< Quality setting of the encoded video + + uint32_t decoded_subband_mask; //!< Indicates which subbands have been decoded + + bool progressive; //!< True if the encoded frame is progressive + + bool top_field_first; //!< True if the top field is encoded first + + bool frame_inverted; //!< True if the frame is encoded upside down + + uint_least8_t group_length; //!< Number of frames in a group of pictures (GOP) + + //! Indicates that enough of the sample has been read to allow decoding the sample + bool end_of_sample; + + //! Indicates that the layer has been decoded + bool end_of_layer; + + //! Most recent tag-value pair was a header parameter + bool header; + + //! Most recent syntax element was a codeblock (large chunk element) + bool codeblock; + + //! Parameters of the most recently decoded subband + struct + { + //DIMENSION width; //!< Width of the decoded band + //DIMENSION height; //!< Height of the decoded band + uint_least8_t subband; //!< Subband index + //uint_least8_t encoding; //!< Band encoding method + uint16_t quantization; //!< Quantization parameter + + } band; //!< Information about the current highpass band + + DIMENSION image_width; //!< Upper bound on the channel width + DIMENSION image_height; //!< Upper bound on the channel height + + PRECISION lowpass_precision; //!< Number of bits per lowpass coefficient + + /*! + @brief Table of prescale shifts applied before computing each wavelet transform + + The prescale shift was applied by the encoder to each input to the forward + wavelet transform. The table of prescale values is indexed by the same + index used for the wavelets in the transform. + */ + //uint_fast8_t prescale_table[MAX_WAVELET_COUNT]; + PRESCALE prescale_table[MAX_WAVELET_COUNT]; + + //! Picture aspect ratio read from the encoded sample + struct _picture_aspect_ratio + { + uint_least16_t x; //!< Relative width of the picture + uint_least16_t y; //!< Relative height of the picture + + } picture_aspect_ratio; //!< Picture aspect ratio read from the sample + +#if VC5_ENABLED_PART(VC5_PART_LAYERS) + uint32_t interlaced_flags; + uint32_t protection_flags; + + //!< Parameters of the current layer + struct + { + int width; //!< Width of the current layer + int height; //!< Height of the current layer + + } layer; //!< Information about the encoded layer from the sample + +#endif + +#if VC5_ENABLED_PART(VC5_PART_SECTIONS) + int section_number; //!< Number of the most recent section encountered in the bitstream + int section_length; //!< Length of the most recent section element payload (in segments) +#endif + +} CODEC_STATE; + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the codec state + CODEC_ERROR PrepareCodecState(CODEC_STATE *codec); + + uint32_t EncoderVersion(uint32_t value); + + uint32_t RepackedEncoderVersion(uint32_t value); + + void SetCodecVersion(uint8_t version[3], uint16_t value); + + CODEC_ERROR UpdatePrescaleTable(CODEC_STATE *codec, TAGWORD value); + + CODEC_ERROR UpdateSampleFlags(CODEC_STATE *codec, TAGWORD value); + + CODEC_ERROR UpdateCodecFlags(CODEC_STATE *codec, TAGWORD value); + + CODEC_ERROR UpdateFrameStructureFlags(CODEC_STATE *codec, TAGWORD value); + + CODEC_ERROR SetBandCoding(CODEC_STATE *codec, TAGWORD value); + + bool IsPartEnabled(ENABLED_PARTS enabled_parts, int part_number); + +#ifdef __cplusplus +} +#endif + +#endif // CODEC_H diff --git a/gpr/source/lib/vc5_common/codeset.h b/gpr/source/lib/vc5_common/codeset.h new file mode 100755 index 0000000..e220239 --- /dev/null +++ b/gpr/source/lib/vc5_common/codeset.h @@ -0,0 +1,44 @@ +/*! @file codeset.h + * + * @brief The codeset data structure includes the codebook and flags that + * indicate how to use the codebook. The codeset may also include tables + * that are derived from the codebook to facilite encoding and decoding. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef CODESET_H +#define CODESET_H + +/*! + @brief Codeset flags that determine how the codebook is used for encoding + + The codeset flags determine how the codebook in the codeset is used to + compute the tables for encoding coefficient magnitudes and runs of zeros. + + The companding curve is applied to the quantized coefficients before the + values are entropy coded to fit the coefficient magnitudes into the range + of magnitudes provided by the codebook. The companding curve is applied + when the encoding table for coefficient magnitudes is computed. +*/ +typedef enum _codeset_flags +{ + CODESET_FLAGS_COMPANDING_NONE = 0x0002, //!< Do not apply a companding curve + CODESET_FLAGS_COMPANDING_CUBIC = 0x0004, //!< Apply a cubic companding curve + +} CODESET_FLAGS; + +#endif // CODESET_H diff --git a/gpr/source/lib/vc5_common/common.h b/gpr/source/lib/vc5_common/common.h new file mode 100755 index 0000000..c0ff501 --- /dev/null +++ b/gpr/source/lib/vc5_common/common.h @@ -0,0 +1,53 @@ +/*! @file common.h + * + * @brief This file includes all of the header files that are used by + * the encoder and decoder. Including a single header file in all + * reference encoder and decoder source files ensures that all + * modules see the same header files in the same order. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "gpr_platform.h" +#include "gpr_allocator.h" +#include "gpr_buffer.h" +#include "gpr_rgb_buffer.h" + +#include "stdc_includes.h" + +#include "log.h" +#include "types.h" +#include "timer.h" +#include "config.h" +#include "macros.h" +#include "error.h" +#include "pixel.h" +#include "image.h" +#include "logcurve.h" +#include "wavelet.h" +#include "bitstream.h" +#include "stream.h" +#include "companding.h" +#include "syntax.h" +#include "codec.h" +#include "codeset.h" +#include "utilities.h" +#include "unique.h" + +#endif // COMMON_H diff --git a/gpr/source/lib/vc5_common/companding.c b/gpr/source/lib/vc5_common/companding.c new file mode 100755 index 0000000..00b0fb5 --- /dev/null +++ b/gpr/source/lib/vc5_common/companding.c @@ -0,0 +1,259 @@ +/*! @file companding.c + * + * @brief Implementation of the routines for computing the companding curves + * that is applied to the quantized coefficient magnitudes. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +//TODO: Change the companding parameter into a global constant + +#ifndef COMPANDING +#define COMPANDING 1 +#define COMPANDING_MORE (54) // Zero means no companding (54 is a good value) +#endif + + +/*! + @brief Maximum coefficient magnitude in the codebook + + @todo Need to calculate the maximum value from the codebook +*/ +const int maximum_codebook_value = 255; + + +/*! + @brief Apply the default companding curve to the specified value + + Note that this companding curve has been superceeded by the cubic curve. +*/ +int32_t CompandedValue(int32_t value) +{ + const int midpoint_rounding = 2; + + int32_t magnitude = absolute(value); + +#if COMPANDING + if (magnitude >= 40) + { + magnitude -= 40; + magnitude += midpoint_rounding; + magnitude >>= 2; + magnitude += 40; + + #if COMPANDING_MORE + if (magnitude >= COMPANDING_MORE) + { + magnitude -= COMPANDING_MORE; + magnitude += midpoint_rounding; + magnitude >>= 2; + magnitude += COMPANDING_MORE; + } +#endif + } +#endif + + // Restore the sign to the companded value + return ((value >= 0) ? magnitude : neg(magnitude)); +} + +/*! + @brief Return the parameter that controls the companding curve + + This parameter does not apply if the cubic companding curve is used. +*/ +uint32_t CompandingParameter() +{ + return COMPANDING_MORE; +} + +/*! + @brief Compute a table of values for the cubic companding curve + + The companding curve is f(x) = x + (x ^ 3 / (255 ^ 3)) * 768 + so the range of coefficient magnitudes from 0 to 255 becomess 0 to 1023. +*/ +CODEC_ERROR ComputeCubicTable(int16_t cubic_table[], int cubic_table_length, int16_t maximum_value) +{ + size_t cubic_table_size = cubic_table_length * sizeof(cubic_table[0]); + int last_cubic_table_index = cubic_table_length - 2; + int16_t last_magnitude; + int16_t index; + + // Clear the cubic table + memset(cubic_table, 0, cubic_table_size); + + for (index = 1; index <= maximum_value; index++) + { + double cubic = index; + + int magnitude = index; + + cubic *= index; + cubic *= index; + cubic *= 768; + //cubic /= 256*256*256; + cubic /= 255*255*255; + + magnitude += (int)cubic; + + //if (mag > 1023) mag = 1023; + if (magnitude > last_cubic_table_index) { + magnitude = last_cubic_table_index; + } + + cubic_table[magnitude] = index; + } + + // Fill unused entries in the cubic table + last_magnitude = 0; + for (index = 0; index < cubic_table_length; index++) + { + if (cubic_table[index]) + { + last_magnitude = cubic_table[index]; + } + else + { + cubic_table[index] = last_magnitude; + } + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Invert the companding curve applied during encoding +*/ +int32_t UncompandedValue(int32_t value) +{ +#if 1 //CUBIC_COMPANDING + double cubic; + int32_t magnitude = absolute(value); + + cubic = magnitude; + cubic *= magnitude; + cubic *= magnitude; + cubic *= 768; + //cubic /= 256*256*256; + cubic /= 255*255*255; + + magnitude += (int32_t)cubic; + + // Restore the sign + value = ((value < 0) ? neg(magnitude) : magnitude); +#else + if (40 <= value && value < 264) + { +#if COMPANDING_MORE + if (value >= COMPANDING_MORE) + { + value -= COMPANDING_MORE; + value <<= 2; + value += COMPANDING_MORE; + } +#endif + value -= 40; + value <<= 2; + value += 40; + } + else if (value <= -40) + { + // Apply the inverse companding formula to the absolute value + value = -value; + +#if COMPANDING_MORE + if (value >= COMPANDING_MORE) + { + value -= COMPANDING_MORE; + value <<= 2; + value += COMPANDING_MORE; + } +#endif + value -= 40; + value <<= 2; + value += 40; + + // Restore the sign + value = -value; + } +#endif + + return value; +} + +/*! + @brief Invert the companding curve applied to a pixel +*/ +PIXEL UncompandedPixel(PIXEL value) +{ +#if 1 //CUBIC_COMPANDING + double cubic; + int32_t magnitude = absolute(value); + + cubic = magnitude; + cubic *= magnitude; + cubic *= magnitude; + cubic *= 768; + //cubic /= 256*256*256; + cubic /= 255*255*255; + + magnitude += (int32_t)cubic; + + // Restore the sign + value = ClampPixel((value < 0) ? neg(magnitude) : magnitude); +#else + if (40 <= value && value < 264) + { +#if COMPANDING_MORE + if (value >= COMPANDING_MORE) + { + value -= COMPANDING_MORE; + value <<= 2; + value += COMPANDING_MORE; + } +#endif + value -= 40; + value <<= 2; + value += 40; + } + else if (value <= -40) + { + // Apply the inverse companding formula to the absolute value + value = neg(value); + +#if COMPANDING_MORE + if (value >= COMPANDING_MORE) + { + value -= COMPANDING_MORE; + value <<= 2; + value += COMPANDING_MORE; + } +#endif + value -= 40; + value <<= 2; + value += 40; + + // Restore the sign + value = neg(value); + } +#endif + + return value; +} + diff --git a/gpr/source/lib/vc5_common/companding.h b/gpr/source/lib/vc5_common/companding.h new file mode 100755 index 0000000..5931e73 --- /dev/null +++ b/gpr/source/lib/vc5_common/companding.h @@ -0,0 +1,46 @@ +/*! @file companding.h + * + * @brief Declaration of the routines for computing the companding curves + * that is applied to the quantized coefficient magnitudes. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef COMPANDING_H +#define COMPANDING_H + +#ifdef __cplusplus +extern "C" { +#endif + + int32_t CompandedValue(int32_t value); + + uint32_t CompandingParameter(void); + + CODEC_ERROR ComputeCubicTable(int16_t cubic_table[], int cubic_table_length, int16_t maximum_value); + + // Invert the companding curve applied to a quantized coefficient magnitude (for debugging) + int32_t UncompandedValue(int32_t value); + + PIXEL UncompandedPixel(PIXEL value); + + CODEC_ERROR InvertCompanding(PIXEL *image, DIMENSION width, DIMENSION height, DIMENSION pitch); + +#ifdef __cplusplus +} +#endif + +#endif // COMPANDING_H diff --git a/gpr/source/lib/vc5_common/config.h b/gpr/source/lib/vc5_common/config.h new file mode 100755 index 0000000..5169510 --- /dev/null +++ b/gpr/source/lib/vc5_common/config.h @@ -0,0 +1,87 @@ +/*! @file config.h + * + * @brief Parameters that control the configuration of the codec. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +// Maximum number of layers +#define MAX_LAYER_COUNT 10 + +// Maximum number of color channels +#define MAX_CHANNEL_COUNT 4 +//const int MAX_CHANNEL_COUNT = 4; + +// Maximum number of wavelets per channel +#define MAX_WAVELET_COUNT 3 +//const int MAX_WAVELET_COUNT = 3; + +// Maximum number of bands per wavelet +#define MAX_BAND_COUNT 4 +//const int MAX_BAND_COUNT = 4; + +// Maximum number of subbands in all wavelets (including the lowpass band in the first wavelet) +#define MAX_SUBBAND_COUNT 10 + +// The number of prescale values that are encoded into the bitstream +#define MAX_PRESCALE_COUNT 8 + +//TODO: The maximum number of channels and wavelets depends on the profile + +//! Internal precision of the intermediate results after unpacking +static const int default_internal_precision = 12; + +//TODO: Change the global variable from internal_precision to encoded_precision? + +// Definitions of VC-5 parts +#define VC5_PART_ELEMENTARY 1 +#define VC5_PART_CONFORMANCE 2 // Conformance does not affect what capabilities are included +#define VC5_PART_IMAGE_FORMATS 3 +#define VC5_PART_COLOR_SAMPLING 4 +#define VC5_PART_LAYERS 5 +#define VC5_PART_SECTIONS 6 +#define VC5_PART_METADATA 7 + +// Convert a part number into a part mask +#define VC5_PART_MASK(n) (1 << ((n)-1)) + +// Define the parts supported by this codec implementation +#define VC5_ENABLED_PARTS (VC5_PART_MASK(VC5_PART_ELEMENTARY) | \ + VC5_PART_MASK(VC5_PART_IMAGE_FORMATS) | \ + VC5_PART_MASK(VC5_PART_COLOR_SAMPLING) | \ + VC5_PART_MASK(VC5_PART_SECTIONS)) + +// Compile code if any of the parts in the specified mask are supported +#define VC5_ENABLED_MASK(m) ((VC5_ENABLED_PARTS & (m)) != 0) + +// Macro for testing support for a specific part of the VC-5 standard +#define VC5_ENABLED_PART(n) (VC5_ENABLED_MASK(VC5_PART_MASK(n))) + + +#if VC5_ENABLED_PART(VC5_PART_LAYERS) + +// Maximum number of layers supported by the reference codec +#define MAX_LAYER_COUNT 10 + +#endif + +//! Number of rows of intermediate horizontal transform results +#define ROW_BUFFER_COUNT 6 + +#endif // CONFIG_H diff --git a/gpr/source/lib/vc5_common/error.h b/gpr/source/lib/vc5_common/error.h new file mode 100755 index 0000000..fbb1573 --- /dev/null +++ b/gpr/source/lib/vc5_common/error.h @@ -0,0 +1,88 @@ +/*! @file config.h + * + * @brief Definitions of the error codes reported by this codec implementation + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef ERROR_H +#define ERROR_H + +/*! + @brief Codec error codes +*/ +typedef enum _codec_error +{ + CODEC_ERROR_OKAY = 0, //!< No error + CODEC_ERROR_UNEXPECTED, //!< Encountered an unexpected condition + CODEC_ERROR_OUTOFMEMORY, //!< Memory allocation failed + CODEC_ERROR_UNIMPLEMENTED, //!< Function has not been implemented + CODEC_ERROR_NULLPTR, //!< Data structure or argument pointer was null + CODEC_ERROR_BITSTREAM_SYNTAX, //!< Error in the sequence of tag value pairs + CODEC_ERROR_IMAGE_DIMENSIONS, //!< Wrong or unknown image dimensions + CODEC_ERROR_INVALID_TAG, //!< Found a tag that should not be present + CODEC_ERROR_INVALID_BAND, //!< Wavelet band index is out of range + CODEC_ERROR_DECODING_SUBBAND, //!< Error decoding a wavetet subband + CODEC_ERROR_NOTFOUND, //!< Did not find a value codeword + CODEC_ERROR_BAND_END_MARKER, //!< Could not find special codeword after end of band + CODEC_ERROR_BAND_END_TRAILER, //!< Could not find start of highpass band trailer + CODEC_ERROR_PIXEL_FORMAT, //!< Unsupported pixel format + CODEC_ERROR_INVALID_MARKER, //!< Bitstream marker was not found in the codebook + CODEC_ERROR_FILE_GET_POSITION, //!< Could not get position of the file stream + CODEC_ERROR_FILE_SEEK, //!< Could not seek to a position in a file stream + CODEC_ERROR_FILE_READ, //!< Read from a file stream failed + CODEC_ERROR_FILE_WRITE, //!< Write to a file stream failed + CODEC_ERROR_CHANNEL_SIZE_TABLE, //!< Could not write the channel size table + CODEC_ERROR_UNSUPPORTED_FORMAT, //!< Pixel or encoded format is not supported + CODEC_ERROR_MISSING_START_MARKER, //!< Bitstream does not begin with the start marker + CODEC_ERROR_DUPLICATE_HEADER_PARAMETER, //!< Header parameter occurs more than once + CODEC_ERROR_REQUIRED_PARAMETER, //!< Optional tag-value pair for a required parameter + CODEC_ERROR_LOWPASS_PRECISION, //!< Number of bits per lowpass coefficient out of range + CODEC_ERROR_LOWPASS_VALUE, //!< Lowpass coefficient value is out of range + CODEC_ERROR_IMAGE_TYPE, //!< Could not determine the characteristics of the input image + CODEC_ERROR_BAD_IMAGE_FORMAT, //!< Bad image format (VC-5 Part 3 only) + CODEC_ERROR_PATTERN_DIMENSIONS, //!< Bad pattern dimensions (VC-5 Part 3 only) + CODEC_ERROR_ENABLED_PARTS, //!< Incorrect enabled parts of the VC-5 standard + CODEC_ERROR_SYNTAX_ERROR, //!< Unspecified error in the bitstream syntax + CODEC_ERROR_UMID_LABEL, //!< Incorrect UMID label + CODEC_ERROR_BAD_SECTION_TAG, //!< The specified tag does not correspond to a section header + + + /***** Reserve a block of error codes for the bitstream *****/ + + CODEC_ERROR_BITSTREAM = (1 << 10), //!< Block of bitstream error codes + + + /***** Reserve a block of error codes for the calling application *****/ + + CODEC_ERROR_APPLICATION = (16 << 10), //!< Block of error codes for the application + CODEC_ERROR_MISSING_ARGUMENT, //!< Program did not have enough arguments + CODEC_ERROR_BAD_ARGUMENT, //!< Invalid value for one of the arguments + CODEC_ERROR_OPEN_FILE_FAILED, //!< Could not open the file for reading + CODEC_ERROR_CREATE_FILE_FAILED, //!< Could not open the file for writing + CODEC_ERROR_UNSUPPORTED_FILE_TYPE, //!< The output file type is not supported + CODEC_ERROR_FILE_SIZE_FAILED, //!< Could not determine the size of the file + CODEC_ERROR_READ_FILE_FAILED, //!< Could not read a file + CODEC_ERROR_FILE_WRITE_FAILED, //!< Could not write to the file + CODEC_ERROR_FILE_FLUSH_FAILED, //!< Could not flush the file buffer + CODEC_ERROR_PARSE_ARGUMENTS, //!< Error while parsing the command-line arguments + CODEC_ERROR_USAGE_INFO, //!< User asked for help with program usage + CODEC_ERROR_BANDFILE_FAILED, //!< Could not write the bandfile + CODEC_ERROR_BAD_PARAMETER, //!< Missing or inconsistent parameters + +} CODEC_ERROR; + +#endif // ERROR_H diff --git a/gpr/source/lib/vc5_common/image.c b/gpr/source/lib/vc5_common/image.c new file mode 100755 index 0000000..0af14fe --- /dev/null +++ b/gpr/source/lib/vc5_common/image.c @@ -0,0 +1,321 @@ +/*! @file image.c + * + * @brief Implementation of the data structure for the image that is + * input to the image unpacking process. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +/*! + @brief Initialize the fields in an image data structure + This routine is the constructor for the image data type that + initializes an image instance to default values. + */ +CODEC_ERROR InitImage(IMAGE *image) +{ + if (image != NULL) + { + image->width = 0; + image->height = 0; + image->pitch = 0; + image->offset = 0; + image->format = PIXEL_FORMAT_UNKNOWN; + image->buffer = NULL; + image->size = 0; + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_NULLPTR; +} + +CODEC_ERROR InitRGBImage(RGB_IMAGE *image) +{ + if (image != NULL) + { + image->width = 0; + image->height = 0; + image->pitch = 0; + image->buffer = NULL; + image->size = 0; + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_NULLPTR; +} +/*! + @brief Allocate the buffer for a image with the sepcified dimensions and format. + This routine calculates the image pitch from the width and format, rounding up + the pitch to satisfy memory alignment requirements in the codec. + This routine will cause a memory leak if it is called with a image that has + already been allocated. + */ +CODEC_ERROR AllocImage(gpr_allocator *allocator, IMAGE *image, DIMENSION width, DIMENSION height, PIXEL_FORMAT format) +{ + size_t size = 0; + DIMENSION pitch = 0; + + assert(image != NULL); + + // Compute the pitch from the width and format + pitch = ImagePitch(width, format); + assert(pitch > 0); + +#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING) + size = height * pitch; +#else + size = height * pitch; +#endif + assert(size > 0); + + // Allocate the image buffer + image->buffer = allocator->Alloc(size); + if (image->buffer != NULL) + { + image->width = width; + image->height = height; + image->pitch = pitch; + image->format = format; + image->offset = 0; + image->size = size; + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_OUTOFMEMORY; +} + +/*! + @brief Deallocate the buffer in a image data structure + This routine does not deallocate the image data structure itself. + In the typical use case, the image data structure is allocated on + the stack and teh decoder allocates the buffer for the output image + after determining the size of the image. The image data structure + is deallocated automatically by a calling routine. + */ +CODEC_ERROR ReleaseImage(gpr_allocator *allocator, IMAGE *image) +{ + allocator->Free(image->buffer); + return CODEC_ERROR_OKAY; +} + +/*! + @brief Compute the image pitch for the specified width and pixel format + The pitch of the image (in bytes) is computed for a image with the width + and pixel format that is specified. The pitch is rounted up to satisfy + memory alignment constraints required by the codec. + The return value is zero if the pitch could not be computed for the + specified width and format. + */ +DIMENSION ImagePitch(DIMENSION width, PIXEL_FORMAT format) +{ + DIMENSION pitch = 0; + + switch (format) + { + case PIXEL_FORMAT_RAW_RGGB_14: + case PIXEL_FORMAT_RAW_GBRG_12: + case PIXEL_FORMAT_RAW_GBRG_12P: + case PIXEL_FORMAT_RAW_RGGB_16: + // Half the width of the image times 2 samples times 2 bytes per sample + pitch = width * sizeof(uint16_t); + break; + + default: + assert(0); + } + + return pitch; +} + +/*! + @brief Set the dimensions and pixel format of a image + This routine is used to set the dimensions and format of a image + that was allocated with unknown parameters. + */ +CODEC_ERROR SetImageFormat(IMAGE *image, + DIMENSION width, + DIMENSION height, + DIMENSION pitch, + PIXEL_FORMAT format, + size_t offset) +{ + assert(image != NULL); + + image->width = width; + image->height = height; + image->pitch = pitch; + image->format = format; + image->offset = offset; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return the address of the image in the buffer + This routine should be used to obtain the starting address of + a image in a image buffer since the image may be offset from the + beginning of the buffer. + */ +void *ImageData(IMAGE *image) +{ + uint8_t *buffer = image->buffer; + buffer += image->offset; + return buffer; +} + +/*! + @brief Return the address of the specified row in the image + The routine returns NULL if the image argument is null or the + specified row is out of bounds. + */ +void *RowAddress(IMAGE *image, DIMENSION row) +{ + size_t pitch = image->pitch; + + if (image != NULL && image->pitch != 0) + { + //if (0 <= row && row < image->height) + if (row < image->height) + { + void *address = (void *)((uintptr_t)ImageData(image) + row * pitch); + return address; + } + } + + // Could not compute the address of a valid row + return NULL; +} + +CODEC_ERROR ReleaseComponentArrays(gpr_allocator *allocator, + UNPACKED_IMAGE *image, + int channel_count ) +{ + int channel; + + for (channel = 0; channel < channel_count; channel++) + { + allocator->Free( image->component_array_list[channel].data ); + } + + allocator->Free( image->component_array_list ); + + return CODEC_ERROR_OKAY; +} + +CODEC_ERROR AllocateComponentArrays(gpr_allocator *allocator, + UNPACKED_IMAGE *image, + int channel_count, + DIMENSION max_channel_width, + DIMENSION max_channel_height, + PIXEL_FORMAT format, + int bits_per_component) +{ + int channel; + + // Allocate the vector of component arrays + size_t size = channel_count * sizeof(COMPONENT_ARRAY); + image->component_array_list = allocator->Alloc(size); + if (image->component_array_list == NULL) { + return CODEC_ERROR_OUTOFMEMORY; + } + + // Clear the component array information so that the state is consistent + image->component_count = 0; + memset(image->component_array_list, 0, size); + + // Initialize each component array + for (channel = 0; channel < channel_count; channel++) + { + DIMENSION channel_width = max_channel_width; + DIMENSION channel_height = max_channel_height; + + // Allocate space for the data in the component array + CODEC_ERROR error = AllocateComponentArray( allocator, &image->component_array_list[channel], channel_width, channel_height, (uint_least8_t)bits_per_component ); + + if( error != CODEC_ERROR_OKAY ) { + return error; + } + } + + // Set the number of component arrays + image->component_count = channel_count; + + return CODEC_ERROR_OKAY; +} + +CODEC_ERROR AllocateComponentArray(gpr_allocator *allocator, + COMPONENT_ARRAY *component_array, + DIMENSION width, + DIMENSION height, + PRECISION bits_per_component) +{ + //COMPONENT_ARRAY *component_array = Alloc(allocator, sizeof(COMPONENT_ARRAY)); + + // Allocate space for the data in the component array + size_t pitch = width * sizeof(COMPONENT_VALUE); + size_t size = height * pitch; + void *buffer = allocator->Alloc(size); + assert(buffer != NULL); + if (! (buffer != NULL)) { + return CODEC_ERROR_OUTOFMEMORY; + } + + component_array->width = width; + component_array->height = height; + component_array->pitch = pitch; + component_array->data = buffer; + component_array->bits_per_component = bits_per_component; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Initialize the data structure for the unpacked image + Note that the component arrays will be allocated after the bitstream + has been decoded and the dimensions of the component arrys are known. + */ +CODEC_ERROR InitUnpackedImage(UNPACKED_IMAGE *unpacked_image) +{ + if (unpacked_image == NULL) { + return CODEC_ERROR_UNEXPECTED; + } + + // Clear the fields in the unpacked iamge + memset(unpacked_image, 0, sizeof(UNPACKED_IMAGE)); + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return the maximum number of bits per component across all channels in the unpacked image + */ +PRECISION MaxBitsPerComponent(const UNPACKED_IMAGE *image) +{ + PRECISION max_bits_per_component = 0; + int channel; + + for (channel = 0; channel < image->component_count; channel++) + { + COMPONENT_ARRAY *component_array = &image->component_array_list[channel]; + + if (max_bits_per_component < component_array->bits_per_component) { + max_bits_per_component = component_array->bits_per_component; + } + } + + return max_bits_per_component; +} diff --git a/gpr/source/lib/vc5_common/image.h b/gpr/source/lib/vc5_common/image.h new file mode 100755 index 0000000..4739727 --- /dev/null +++ b/gpr/source/lib/vc5_common/image.h @@ -0,0 +1,165 @@ +/*! @file image.h + * + * @brief Declaration of structures and functions for images + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef IMAGE_H +#define IMAGE_H + +//! Data type for the values in a component array +typedef uint16_t COMPONENT_VALUE; + +/*! + @brief Data structure for an image input to the unpacking process + + This data structure is used to represent the image that is the input to the + image unpacking process that unpacks an image into component arrays for encoding. + Unlike the wavelet data structures, an image contains multiple color components, + usually in a packed pixel format. +*/ +typedef struct _packed_image +{ + DIMENSION width; //!< Width of the frame (in pixels) + DIMENSION height; //!< Height of the frame + size_t pitch; //!< Distance between rows (in bytes) + PIXEL_FORMAT format; //!< Format of the pixels + void *buffer; //!< Address of the buffer for the frame + size_t size; //!< Allocated size of the buffer (in bytes) + size_t offset; //!< Offset to the start of the frame +} PACKED_IMAGE; + +/*! + @brief Data structure for an image input to the unpacking process + + This data structure is used to represent the image that is the input to the + image unpacking process that unpacks an image into component arrays for encoding. + Unlike the wavelet data structures, an image contains multiple color components, + usually in a packed pixel format. + */ +typedef struct _rgb_image +{ + DIMENSION width; //!< Width of the frame (in pixels) + DIMENSION height; //!< Height of the frame + size_t pitch; //!< Distance between rows (in bytes) + void *buffer; //!< Address of the buffer for the frame + size_t size; //!< Allocated size of the buffer (in bytes) +} RGB_IMAGE; + +//! Short name for the packed image data type +typedef PACKED_IMAGE IMAGE; + +/*! + @brief Data structure for an array that contains a single type of component + + This data structure is used to represent the component array output by the image + unpacking process. The image unpacking process unpacks an image into component + arrays for encoding. +*/ +typedef struct _component_array +{ + DIMENSION width; //!< Width of the frame (in pixels) + DIMENSION height; //!< Height of the frame + size_t pitch; //!< Distance between rows (in bytes) + COMPONENT_VALUE *data; //!< Buffer for the array of component values + + //! Number of bits per in each component value + PRECISION bits_per_component; + +} COMPONENT_ARRAY; + +/*! + @brief Image represented as an ordered set of component arrays + + The decoder outputs a set of component arrays that represent an image. + + The image repacking process can pack the component arrays output by the + decoder into a packed image. +*/ +typedef struct _unpacked_image +{ + //! Number of component arrays in the unpacked image + int component_count; + + //! Vector of component arrays + COMPONENT_ARRAY *component_array_list; + +} UNPACKED_IMAGE; + +/*! + @brief Flags that describe the image structure +*/ +typedef enum +{ + IMAGE_STRUCTURE_INTERLACED = 0x0001, //!< Set the first bit if the image is interlaced + IMAGE_STRUCTURE_BOTTOM_FIELD_FIRST = 0x0002, //!< The bottom field is encoded before the top field + IMAGE_STRUCTURE_BOTTOM_ROW_FIRST = 0x0010, //!< The encoded image is upside down +} IMAGE_STRUCTURE; + + +#ifdef __cplusplus +extern "C" { +#endif + + CODEC_ERROR InitImage(IMAGE *image); + + CODEC_ERROR InitRGBImage(RGB_IMAGE *image); + + CODEC_ERROR AllocImage(gpr_allocator *allocator, IMAGE *image, DIMENSION width, DIMENSION height, PIXEL_FORMAT format); + + CODEC_ERROR ReleaseImage(gpr_allocator *allocator, IMAGE *image); + + DIMENSION ImagePitch(DIMENSION width, PIXEL_FORMAT format); + + CODEC_ERROR SetImageFormat(IMAGE *image, + DIMENSION width, + DIMENSION height, + DIMENSION pitch, + PIXEL_FORMAT format, + size_t offset); + + void *ImageData(IMAGE *image); + + void *RowAddress(IMAGE *image, DIMENSION row); + + CODEC_ERROR ReleaseComponentArrays(gpr_allocator *allocator, + UNPACKED_IMAGE *image, + int channel_count ); + + CODEC_ERROR AllocateComponentArrays(gpr_allocator *allocator, + UNPACKED_IMAGE *image, + int channel_count, + DIMENSION max_channel_width, + DIMENSION max_channel_height, + PIXEL_FORMAT format, + int bits_per_component); + + CODEC_ERROR AllocateComponentArray(gpr_allocator *allocator, + COMPONENT_ARRAY *component_array, + DIMENSION width, + DIMENSION height, + PRECISION bits_per_component); + + CODEC_ERROR InitUnpackedImage(UNPACKED_IMAGE *image); + + PRECISION MaxBitsPerComponent(const UNPACKED_IMAGE *image); + +#ifdef __cplusplus +} +#endif + +#endif // IMAGE_H diff --git a/gpr/source/lib/vc5_common/logcurve.c b/gpr/source/lib/vc5_common/logcurve.c new file mode 100755 index 0000000..45aecbf --- /dev/null +++ b/gpr/source/lib/vc5_common/logcurve.c @@ -0,0 +1,58 @@ +/*! @file logcurve.c + * + * @brief Implementation of functions used to do log conversion. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +uint16_t EncoderLogCurve[LOG_CURVE_TABLE_LENGTH]; + +uint16_t DecoderLogCurve[LOG_CURVE_TABLE_LENGTH]; + +void SetupDecoderLogCurve(void) +{ + int i; + const int log_table_size = sizeof(DecoderLogCurve) / sizeof(DecoderLogCurve[0]); + + const int max_16_bit = (1 << 16) - 1; + + for( i = 0; i < log_table_size; i++ ) + { + //input 12-bit, output 16-bit + float input = i; + float output = max_16_bit * (pow(113.0, input/4095.0) - 1.0)/112.0; + + DecoderLogCurve[i] = minimum( (int)output, max_16_bit ); + } +} + +void SetupEncoderLogCurve(void) +{ + int i; + const int max_input_val = LOG_CURVE_TABLE_LENGTH - 1; + + for( i = 0; i < LOG_CURVE_TABLE_LENGTH; i++ ) + { + //input 16-bit, output 12-bit + float input = maximum( 0, i ); + float output = 4095.0 * (log10(input/max_input_val * 112.0 + 1.0)/log10(113)); + + EncoderLogCurve[i] = ( (uint16_t)output ); + } +} + diff --git a/gpr/source/lib/vc5_common/logcurve.h b/gpr/source/lib/vc5_common/logcurve.h new file mode 100755 index 0000000..3e6a269 --- /dev/null +++ b/gpr/source/lib/vc5_common/logcurve.h @@ -0,0 +1,42 @@ +/*! @file logcurve.h + * + * @brief Declaration of the data structures and constants used to do log conversion. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef LOGCURVE_H +#define LOGCURVE_H + +#define LOG_CURVE_TABLE_LENGTH (1 << 12) + +#ifdef __cplusplus +extern "C" { +#endif + + extern uint16_t EncoderLogCurve[]; + + extern uint16_t DecoderLogCurve[]; + + void SetupDecoderLogCurve(void); + + void SetupEncoderLogCurve(void); + +#ifdef __cplusplus +} +#endif + +#endif // LOGCURVE_H diff --git a/gpr/source/lib/vc5_common/pixel.h b/gpr/source/lib/vc5_common/pixel.h new file mode 100755 index 0000000..7c3b9e0 --- /dev/null +++ b/gpr/source/lib/vc5_common/pixel.h @@ -0,0 +1,100 @@ +/*! @file pixel.h + * + * @brief The pixel format enumerations define the pixel packing formats that are + * supported by the codec for input to the image unpacking process and for + * output from the image repacking process. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef PIXEL_H +#define PIXEL_H + +//! Data type for pixels +typedef int16_t PIXEL; + +//! Minimum and maximum pixel values +enum { + PIXEL_MIN = INT16_MIN, + PIXEL_MAX = INT16_MAX, +}; + +//! Alternative definition for wavelet coefficients +typedef int16_t COEFFICIENT; + +//! Minimum and maximum coefficient values +enum +{ + COEFFICIENT_MIN = INT16_MIN, + COEFFICIENT_MAX = INT16_MAX, +}; + +/*! + @brief Pixels formats supported by the codec + + The pixel format is only the packing arrangement for color components and + does not specify whether the image is interlaced or the bottom row is first. + + @todo Need to add support for more pixel formats to the reference decoder +*/ +typedef enum +{ + PIXEL_FORMAT_UNKNOWN = 0, + + PIXEL_FORMAT_RAW_RGGB_16 = 104, + + PIXEL_FORMAT_RAW_RGGB_12 = 106, + PIXEL_FORMAT_RAW_RGGB_12P = 107, + PIXEL_FORMAT_RAW_RGGB_14 = 108, + + PIXEL_FORMAT_RAW_GBRG_12 = 109, + PIXEL_FORMAT_RAW_GBRG_12P = 110, + PIXEL_FORMAT_RAW_GBRG_14 = 111, + + PIXEL_FORMAT_RAW_DEFAULT = PIXEL_FORMAT_RAW_RGGB_14, + + //! Input pixel formats above this value must be encoded into the sample + PIXEL_FORMAT_TAG_REQUIRED = 100, + +} PIXEL_FORMAT; + + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +@brief Force a pixel value to be in range +*/ +STATIC_INLINE PIXEL ClampPixel(int32_t value) +{ + // Check for values that are outside the range (for debugging) + assert(PIXEL_MIN <= value && value <= PIXEL_MAX); + + if (value < PIXEL_MIN) + value = PIXEL_MIN; + else + if (value > PIXEL_MAX) + value = PIXEL_MAX; + + return (PIXEL)value; +} + +#ifdef __cplusplus +} +#endif + +#endif // PIXEL_H diff --git a/gpr/source/lib/vc5_common/stream.c b/gpr/source/lib/vc5_common/stream.c new file mode 100755 index 0000000..59ecc7d --- /dev/null +++ b/gpr/source/lib/vc5_common/stream.c @@ -0,0 +1,524 @@ +/*! @file stream.h + * + * @brief This module implements a byte stream abstraction that hides the details + * of how a stream of bytes is read or written on demand by the bitstream. + * The byte stream can be bound to a binary file opened for reading (writing), + * to a buffer in memory, or to a module that reads (writes) a video track + * in a media container. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +// Local functions +CODEC_ERROR GetBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset); +CODEC_ERROR PutBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset); +CODEC_ERROR GetBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset); +CODEC_ERROR PutBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset); + +/*! + @brief Open a stream for reading bytes from the specified file + +*/ +CODEC_ERROR OpenStream(STREAM *stream, const char *pathname) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + // Clear all members of the stream data structure + memset(stream, 0, sizeof(STREAM)); + + // Open the file and bind it to the stream + stream->location.file.iobuf = fopen(pathname, "rb"); + assert(stream->location.file.iobuf != NULL); + if (! (stream->location.file.iobuf != NULL)) { + return CODEC_ERROR_OPEN_FILE_FAILED; + } + + // Set the stream type and access + stream->type = STREAM_TYPE_FILE; + stream->access = STREAM_ACCESS_READ; + + // Clear the number of bytes read from the stream + stream->byte_count = 0; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Create a stream for writing bytes to a specified file + +*/ +CODEC_ERROR CreateStream(STREAM *stream, const char *pathname) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + // Clear all members of the stream data structure + memset(stream, 0, sizeof(STREAM)); + + // Open the file and bind it to the stream + stream->location.file.iobuf = fopen(pathname, "wb+"); + assert(stream->location.file.iobuf != NULL); + if (! (stream->location.file.iobuf != NULL)) { + return CODEC_ERROR_CREATE_FILE_FAILED; + } + + // Set the stream type and access + stream->type = STREAM_TYPE_FILE; + stream->access = STREAM_ACCESS_WRITE; + + // Clear the number of bytes written to the stream + stream->byte_count = 0; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Read a word from a byte stream + + This routine is used by the bitstream to read a word from a byte stream. + A word is the number of bytes that can be stored in the internal buffer + used by the bitstream. + + @todo Need to modify the routine to return an indication of end of file + or an error reading from the byte stream. +*/ +BITWORD GetWord(STREAM *stream) +{ + BITWORD buffer = 0; + size_t bytes_read = sizeof(buffer); + + assert(stream != NULL); + + switch (stream->type) + { + case STREAM_TYPE_FILE: + bytes_read = fread(&buffer, 1, sizeof(buffer), stream->location.file.iobuf); + assert(bytes_read == sizeof(buffer)); + break; + + case STREAM_TYPE_MEMORY: + memcpy(&buffer, (uint8_t *)stream->location.memory.buffer + stream->byte_count, sizeof(buffer)); + break; + + default: + assert(0); + break; + } + + if (bytes_read > 0) + stream->byte_count += sizeof(buffer); + + return buffer; +} + +/*! + @brief Read a byte from a byte stream +*/ +uint8_t GetByte(STREAM *stream) +{ + assert(stream != NULL); + int byte = 0; + + switch (stream->type) + { + case STREAM_TYPE_FILE: + byte = fgetc(stream->location.file.iobuf); + break; + + case STREAM_TYPE_MEMORY: + byte = ((uint8_t *)stream->location.memory.buffer)[stream->byte_count]; + break; + + default: + assert(0); + break; + } + + stream->byte_count++; + assert(byte >= 0 && (byte & ~0xFF) == 0); + + return (uint8_t)byte; +} + +/*! + @brief Write a word to a byte stream + + This routine is used by the bitstream to write a word to a byte stream. + A word is the number of bytes that can be stored in the internal buffer + used by the bitstream. + + @todo Need to modify the routine to return an indication of an error + writing to the byte stream. +*/ +CODEC_ERROR PutWord(STREAM *stream, BITWORD word) +{ + size_t written; + + word = Swap32(word); + + assert(stream != NULL); + + switch (stream->type) + { + case STREAM_TYPE_FILE: + written = fwrite(&word, sizeof(word), 1, stream->location.file.iobuf); + if (written == 0) + return CODEC_ERROR_FILE_WRITE_FAILED; + break; + + case STREAM_TYPE_MEMORY: + { + uint8_t* buffer = (uint8_t *)stream->location.memory.buffer + stream->byte_count; + + memcpy(buffer, &word, sizeof(word)); + } + break; + + default: + assert(0); + break; + } + + stream->byte_count += sizeof(word); + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write a byte to a byte stream +*/ +CODEC_ERROR PutByte(STREAM *stream, uint8_t byte) +{ + assert(stream != NULL); + + //assert(byte >= 0 && (byte & ~0xFF) == 0); + + switch (stream->type) + { + case STREAM_TYPE_FILE: + if (fputc(byte, stream->location.file.iobuf) == EOF) + return CODEC_ERROR_FILE_WRITE_FAILED; + break; + + case STREAM_TYPE_MEMORY: + ((uint8_t *)stream->location.memory.buffer)[stream->byte_count] = byte; + break; + + default: + assert(0); + break; + } + + stream->byte_count++; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Rewind the stream to the beginning of the buffer or file +*/ +CODEC_ERROR RewindStream(STREAM *stream) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + if( stream->type == STREAM_TYPE_FILE ) + { + if (stream->location.file.iobuf != NULL) { + assert(fseek(stream->location.file.iobuf, 0, SEEK_SET) == 0); + return CODEC_ERROR_BITSTREAM; + } + } + + stream->byte_count = 0; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Skip the specified number of bytes in the stream +*/ +CODEC_ERROR SkipBytes(STREAM *stream, size_t size) +{ + for (; size > 0; size--) + { + (void)GetByte(stream); + } + return CODEC_ERROR_OKAY; +} + +/*! + @brief Pad the specified number of bytes in the stream +*/ +CODEC_ERROR PadBytes(STREAM *stream, size_t size) +{ + const uint8_t byte = 0; + for (; size > 0; size--) + { + PutByte(stream, byte); + } + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write the stream buffer to the file +*/ +CODEC_ERROR FlushStream(STREAM *stream) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + if (stream->type == STREAM_TYPE_FILE) + { + int result = fflush(stream->location.file.iobuf); + if (result != 0) { + return CODEC_ERROR_FILE_FLUSH_FAILED; + } + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Create a byte stream for reading from a memory location + */ +CODEC_ERROR OpenStreamBuffer(STREAM *stream, void *buffer, size_t size) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + // Clear all members of the stream data structure + memset(stream, 0, sizeof(STREAM)); + + // Bind the stream to the buffer + stream->location.memory.buffer = buffer; + stream->location.memory.size = size; + + // Set the stream type and access + stream->type = STREAM_TYPE_MEMORY; + stream->access = STREAM_ACCESS_READ; + + // Clear the number of bytes written to the stream + stream->byte_count = 0; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Create a byte stream for writing to a memory location +*/ +CODEC_ERROR CreateStreamBuffer(STREAM *stream, void *buffer, size_t size) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + // Clear all members of the stream data structure + memset(stream, 0, sizeof(STREAM)); + + // Bind the stream to the buffer + stream->location.memory.buffer = buffer; + stream->location.memory.size = size; + + // Set the stream type and access + stream->type = STREAM_TYPE_MEMORY; + stream->access = STREAM_ACCESS_WRITE; + + // Clear the number of bytes written to the stream + stream->byte_count = 0; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return the starting address and number of bytes in a buffer + + This routine is used to get the address and count of the bytes written + to a memory stream (buffer). +*/ +CODEC_ERROR GetStreamBuffer(STREAM *stream, void **buffer_out, size_t *size_out) +{ + assert(stream != NULL); + if (! (stream != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + assert(stream->type == STREAM_TYPE_MEMORY); + + if (buffer_out != NULL) { + *buffer_out = stream->location.memory.buffer; + } + + if (size_out != NULL) { + *size_out = stream->byte_count; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Read a block of data at the specified offset in the byte stream +*/ +CODEC_ERROR GetBlock(STREAM *stream, void *buffer, size_t size, size_t offset) +{ + switch (stream->type) + { + case STREAM_TYPE_FILE: + return GetBlockFile(stream, buffer, size, offset); + break; + + case STREAM_TYPE_MEMORY: + return GetBlockMemory(stream, buffer, size, offset); + break; + + case STREAM_TYPE_UNKNOWN: + assert(0); + break; + } + + return CODEC_ERROR_UNEXPECTED; +} + +/*! + @brief Read a block of data from a file stream +*/ +CODEC_ERROR GetBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset) +{ + FILE *file = stream->location.file.iobuf; + fpos_t position; + + (void)file; + (void)position; + + // Save the current position in the file + if (fgetpos(file, &position) != 0) { + return CODEC_ERROR_FILE_GET_POSITION; + } + + // Seek to the specified offset + assert(offset <= LONG_MAX); + if (fseek(file, (long)offset, SEEK_SET) != 0) { + return CODEC_ERROR_FILE_SEEK; + } + + // Read data from the file + if (fread(buffer, size, 1, file) != 1) { + return CODEC_ERROR_FILE_READ; + } + + // Return to the previous position in the file + // if (fseek(file, (long)position, SEEK_SET) != 0) { + if (fsetpos(file, &position) != 0) { + return CODEC_ERROR_FILE_SEEK; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Read a block of data from a memory stream (buffer) +*/ +CODEC_ERROR GetBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset) +{ + uint8_t *block = (uint8_t *)stream->location.memory.buffer + offset; + memcpy(buffer, block, size); + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write a block of data at the specified offset in the byte stream +*/ +CODEC_ERROR PutBlock(STREAM *stream, void *buffer, size_t size, size_t offset) +{ + switch (stream->type) + { + case STREAM_TYPE_FILE: + return PutBlockFile(stream, buffer, size, offset); + break; + + case STREAM_TYPE_MEMORY: + return PutBlockMemory(stream, buffer, size, offset); + break; + + case STREAM_TYPE_UNKNOWN: + assert(0); + break; + } + + return CODEC_ERROR_UNEXPECTED; +} + +/*! + @brief Write a block of data at the specified offset in a file stream +*/ +CODEC_ERROR PutBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset) +{ + FILE *file = stream->location.file.iobuf; + fpos_t position; + + (void)file; + (void)position; + + // Save the current position in the file + if (fgetpos(file, &position) != 0) { + return CODEC_ERROR_FILE_GET_POSITION; + } + + // Seek to the specified offset and write to the file + assert(offset <= LONG_MAX); + if (fseek(file, (long)offset, SEEK_SET) != 0) { + return CODEC_ERROR_FILE_SEEK; + } + + // Write data to the file + if (fwrite(buffer, size, 1, file) != 1) { + return CODEC_ERROR_FILE_WRITE; + } + + // Return to the previous position in the file + // if (fseek(file, (long)position, SEEK_SET) != 0) { + if (fsetpos(file, &position) != 0) { + return CODEC_ERROR_FILE_SEEK; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Write a block of data at the specified offset in a memory stream +*/ +CODEC_ERROR PutBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset) +{ + uint8_t *block = (uint8_t *)stream->location.memory.buffer + offset; + memcpy(block, buffer, size); + return CODEC_ERROR_OKAY; +} + + diff --git a/gpr/source/lib/vc5_common/stream.h b/gpr/source/lib/vc5_common/stream.h new file mode 100755 index 0000000..df70a4f --- /dev/null +++ b/gpr/source/lib/vc5_common/stream.h @@ -0,0 +1,133 @@ +/*! @file stream.h + * + * @brief The stream abstracts the methods used by bitstreams to output bytes + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef STREAM_H +#define STREAM_H + +//! Type of stream (binary file or memory buffer) +typedef enum _stream_type +{ + STREAM_TYPE_UNKNOWN = 0, //!< Unknown type of stream + STREAM_TYPE_FILE, //!< Simple binary file + STREAM_TYPE_MEMORY, //!< Buffer in memory + +} STREAM_TYPE; + +/*! + @brief Stream access (read or write) + + The stream provided with the reference decoder only supports + read access. +*/ +typedef enum _stream_access +{ + STREAM_ACCESS_UNKNOWN = 0, + STREAM_ACCESS_READ, + STREAM_ACCESS_WRITE, + +} STREAM_ACCESS; + + +/*! + @brief Declaration of the data structure for a byte stream + + The byte stream encapsulates the location of encoded images and the + means for reading (writing) encoded images samples. The byte stream + could be a binary file that has been opened for reading (writing) or + a buffer in memory. The reference codec uses a binary file as the byte + stream so the functionality for streams attached to memory buffers has + not been tested. + + It is intended that the byte stream can be enhanced to read (write) + encoded images from (into) a track in a media container. +*/ +#define STREAM_CACHE_SIZE 16 +typedef struct _stream +{ + STREAM_TYPE type; //!< Type of stream (file or memory buffer) + STREAM_ACCESS access; //!< Type of access (read or write) + + //! Union of parameters for different types of streams + union _location + { + //! Parameters for a binary file stream + struct _file + { + FILE *iobuf; //!< Binary file that contains the stream + BITWORD cache[STREAM_CACHE_SIZE]; + int cache_index; + + } file; //!< Parameters for a stream in a binary file + + //! Parameters for a stream bound to a memory buffer + struct _memory + { + void *buffer; //!< Memory buffer that contains the stream + size_t size; //!< Length of the stream (in bytes) + + } memory; //!< Parameters for a stream in a memory buffer + + //TODO: Add other stream types for media containers + + } location; //!< Location of the byte stream (file or memory buffer) + + size_t byte_count; //!< Number of bytes read or written to the stream + +} STREAM; + +#ifdef __cplusplus +extern "C" { +#endif + + CODEC_ERROR OpenStream(STREAM *stream, const char *pathname); + + CODEC_ERROR CreateStream(STREAM *stream, const char *pathname); + + CODEC_ERROR RewindStream(STREAM *stream); + + BITWORD GetWord(STREAM *stream); + + uint8_t GetByte(STREAM *stream); + + CODEC_ERROR SkipBytes(STREAM *stream, size_t size); + + CODEC_ERROR PutWord(STREAM *stream, BITWORD word); + + CODEC_ERROR PutByte(STREAM *stream, uint8_t byte); + + CODEC_ERROR PadBytes(STREAM *stream, size_t size); + + CODEC_ERROR FlushStream(STREAM *stream); + + CODEC_ERROR OpenStreamBuffer(STREAM *stream, void *buffer, size_t size); + + CODEC_ERROR CreateStreamBuffer(STREAM *stream, void *buffer, size_t size); + + CODEC_ERROR GetStreamBuffer(STREAM *stream, void **buffer_out, size_t *size_out); + + CODEC_ERROR GetBlock(STREAM *stream, void *buffer, size_t size, size_t offset); + + CODEC_ERROR PutBlock(STREAM *stream, void *buffer, size_t size, size_t offset); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gpr/source/lib/vc5_common/syntax.c b/gpr/source/lib/vc5_common/syntax.c new file mode 100755 index 0000000..bf64afe --- /dev/null +++ b/gpr/source/lib/vc5_common/syntax.c @@ -0,0 +1,150 @@ +/*! @file syntax.c + * + * @brief Implementation of functions for parsing the bitstream syntax of encoded samples. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +//TODO: Simplify the definition of the marker bits +#define CODEC_LOWPASS_START_CODE 0x1A4A +#define CODEC_LOWPASS_START_SIZE 16 +#define CODEC_LOWPASS_END_CODE 0x1B4B +#define CODEC_LOWPASS_END_SIZE 16 + +#define CODEC_HIGHPASS_START_CODE 0x0D0D +#define CODEC_HIGHPASS_START_SIZE 16 +#define CODEC_HIGHPASS_END_CODE 0x0C0C +#define CODEC_HIGHPASS_END_SIZE 16 + +#define CODEC_BAND_START_CODE 0x0E0E +#define CODEC_BAND_START_SIZE 16 +//#define CODEC_BAND_END_CODE 0x038F0B3E //Codeset dependent cs9 +//#define CODEC_BAND_END_SIZE 26 //Codeset dependent cs9 +#define CODEC_BAND_END_CODE 0x0000E33F //Codeset dependent cs15 +#define CODEC_BAND_END_SIZE 16 //Codeset dependent cs15 + +#define CODEC_SAMPLE_STOP_CODE 0x1E1E +#define CODEC_SAMPLE_STOP_SIZE 16 + +#define CODEC_COEFFICIENT_START_CODE 0x0F0F +#define CODEC_COEFFICIENT_START_SIZE 16 + +//! Size of a tag or value (in bits) +#define BITSTREAM_TAG_SIZE 16 + + +// Bits in the interlace structure flags + +#define CODEC_FLAGS_INTERLACED 0x01 //!< Interlaced flags +#define CODEC_FLAGS_FIELD1_FIRST 0x02 //!< NTSC has this bit cleared +#define CODEC_FLAGS_FIELD1_ONLY 0x04 //!< Indicates missing fields +#define CODEC_FLAGS_FIELD2_ONLY 0x08 +#define CODEC_FLAGS_DOMINANCE 0x10 + +#define CODEC_FLAGS_INTERLACED_MASK 0x1F //!< Unused bits must be zero + +// Useful macros for testing the interlaced flags + +#define INTERLACED(flags) (((flags) & CODEC_FLAGS_INTERLACED) != 0) +#define PROGRESSIVE(flags) (((flags) & CODEC_FLAGS_INTERLACED) == 0) +#define FIELD_ORDER_NTSC(flags) (((flags) & CODEC_FLAGS_FIELD1_FIRST) == 0) +#define FIELD_ORDER_PAL(flags) (((flags) & CODEC_FLAGS_FIELD1_FIRST) != 0) +#define FIELD_ONE_ONLY(flags) (((flags) & CODEC_FLAGS_FIELD1_ONLY) != 0) +#define FIELD_TWO_ONLY(flags) (((flags) & CODEC_FLAGS_FIELD2_ONLY) != 0) +#define FIELD_ONE_PRESENT(flags) (((flags) & CODEC_FLAGS_FIELD2_ONLY) == 0) +#define FIELD_TWO_PRESENT(flags) (((flags) & CODEC_FLAGS_FIELD1_ONLY) == 0) +#define FIELD_BOTH_PRESENT(flags) (((flags) & (CODEC_FLAGS_FIELD1_ONLY | CODEC_FLAGS_FIELD1_ONLY)) == 0) + +// Bits in the copy protection flags + +#define CODEC_FLAGS_PROTECTED 0x01 //!< Copy protection flags +#define CODEC_FLAGS_PROTECTION_MASK 0x01 //!< Unused bits must be zero + +/*! + @brief Check that the bitstream is aligned to a segment boundary + + This function definition duplicates the same function in common/src/syntax.c, + but that file includes definitions intended only for the encoder. + + @todo Remove duplicate function definitions. + */ +bool IsAlignedSegment(BITSTREAM *stream) +{ + return (stream->count == 0 || stream->count == bit_word_count); +} + +/*! + @brief Convert the tag to an optional tag + + An optional tag has a negative value. +*/ +TAGWORD OptionalTag(TAGWORD tag) +{ + return ((tag < 0) ? tag : neg(tag)); +} + +/*! + @brief Convert the tag to a required tag + + An optional tag has a negative value. +*/ +TAGWORD RequiredTag(TAGWORD tag) +{ + return ((tag >= 0) ? tag : neg(tag)); +} + + +/*! + @brief Check that the bitstream is aligned to a tag word boundary + + @todo Check the places in the code where this function is used to + determine whether the bitstream should actually be aligned to a + segment boundary. +*/ +bool IsAlignedTag(BITSTREAM *stream) +{ + return ((stream->count % BITSTREAM_TAG_SIZE) == 0); +} + +/*! + @brief Pack the vector of prescale values into a single word + + The wavelet transform uses a vector of prescale values indexed by the + wavelet level with the input image at level zero to specify the amount + of prescaling that should be performed on the input the wavelet transform. + + This routine packs the prescale values into a segment value that can be + written into the bitstream. +*/ +TAGWORD PackTransformPrescale(TRANSFORM *transform) +{ + TAGWORD packed_prescale = 0; + int i; + + // Encode the prescale values that are actually used + for (i = 0; i < MAX_WAVELET_COUNT; i++) + { + assert((transform->prescale[i] & ~0x03) == 0); + packed_prescale += transform->prescale[i] << (14 - i * 2); + } + + // The remaining prescale values with filled with zeros + + return packed_prescale; +} + diff --git a/gpr/source/lib/vc5_common/syntax.h b/gpr/source/lib/vc5_common/syntax.h new file mode 100755 index 0000000..699c72e --- /dev/null +++ b/gpr/source/lib/vc5_common/syntax.h @@ -0,0 +1,129 @@ +/*! @file syntax.h + * + * @brief Declaration of bitstream elements and functions that define the syntax + * of an encoded sample. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef SYNTAX_H +#define SYNTAX_H + +#define CODEC_TAG_SIZE 16 //!< Size of a codec tag (in bits) +#define CODEC_TAG_MASK 0xFFFF //!< Mask for usable part of tag or value + +typedef uint32_t SEGMENT; //!< The bitstream is a sequence of segments + +typedef int16_t TAGWORD; //!< Bitstream tag or value + +//! Number of bits in a tag or value +static const BITCOUNT tagword_count = 16; + +//! Number of bits in a segment (tag value pair) +static const BITCOUNT segment_count = 32; + +typedef union tagvalue //!< Bitstream tag and value pair +{ + struct { // Fields are in the order for byte swapping + TAGWORD value; + TAGWORD tag; + } tuple; //!< Tag value pair as separate members + + uint32_t longword; //!< Tag value pair as a int32_t word + +} TAGVALUE; + +/*! + @brief Values corresponding to the special codewords + + Special codewords are inserted into an entropy coded band to + mark certain locations in the bitstream. For example, the end + of an encoded band is marked by the band end codeword. Special + codewords are recorded in the codebook as entries that have a + run length of zero. The value indicates the syntax element that + is represented by the codeword. +*/ +typedef enum _special_marker +{ + SPECIAL_MARKER_BAND_END = 1, + +} SPECIAL_MARKER; + + +// The encoded quality is inserted into the bitstream using two tag value pairs +#define ENCODED_QUALITY_LOW_SHIFT 0 //!< Shift for the low part of the quality +#define ENCODED_QUALITY_LOW_MASK 0xFFFF //!< Mask for the low part of the quality +#define ENCODED_QUALITY_HIGH_SHIFT 16 //!< Shift for the high part of the quality +#define ENCODED_QUALITY_HIGH_MASK 0xFFFF //!< Mask for the high part of the quality + +#ifdef __cplusplus +extern "C" { +#endif + +TAGWORD RequiredTag(TAGWORD tag); + +//TAGVALUE GetSegment(BITSTREAM *stream); + +//TAGWORD GetValue(BITSTREAM *stream, int tag); + +// Output a tagged value with double word alignment +CODEC_ERROR PutTagPair(BITSTREAM *stream, int tag, int value); + +// Output an optional tagged value +CODEC_ERROR PutTagPairOptional(BITSTREAM *stream, int tag, int value); + +// Output a tag that marks a place in the bitstream for debugging +CODEC_ERROR PutTagMarker(BITSTREAM *stream, uint32_t marker, int size); + +TAGWORD OptionalTag(TAGWORD tag); + +//bool IsTagOptional(TAGWORD tag); + +//bool IsTagRequired(TAGWORD tag); + +//bool IsValidSegment(BITSTREAM *stream, TAGVALUE segment, TAGWORD tag); + +//CODEC_ERROR AlignBitsTag(BITSTREAM *stream); + +bool IsLowPassHeaderMarker(int marker); +bool IsLowPassBandMarker(int marker); +bool IsHighPassBandMarker(int marker); + +bool IsAlignedTag(BITSTREAM *stream); + +bool IsAlignedSegment(BITSTREAM *stream); + +// Write an index block for the sample bands +CODEC_ERROR PutGroupIndex(BITSTREAM *stream, + void *index_table[], + int index_table_length, + size_t *channel_size_table_offset); + +TAGWORD PackTransformPrescale(TRANSFORM *transform); + +//TODO: Move other declarations for routines that write syntax elements here +struct _encoder ; + +CODEC_ERROR PutFrameStructureFlags(struct _encoder *encoder, BITSTREAM *stream); + +// Output a tag and marker before the lowpass coefficients for debugging +CODEC_ERROR PutVideoLowpassMarker(BITSTREAM *stream); + +#ifdef __cplusplus +} +#endif + +#endif // SYNTAX_H diff --git a/gpr/source/lib/vc5_common/table17.inc b/gpr/source/lib/vc5_common/table17.inc new file mode 100755 index 0000000..973f297 --- /dev/null +++ b/gpr/source/lib/vc5_common/table17.inc @@ -0,0 +1,290 @@ +/*! @file bitstream.h + * + * @brief Declaration of the bitstream data structure. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +RLVTABLE(264) table17 = +{ + 264, + { + {1, 0x00000000, 1, 0}, // m0 + {2, 0x00000002, 1, 1}, // m1 + {3, 0x00000007, 1, 2}, // m2 + {5, 0x00000019, 1, 3}, // m3 + {6, 0x00000030, 1, 4}, // m4 + {6, 0x00000036, 1, 5}, // m5 + {7, 0x0000006F, 1, 8}, // m8 + {7, 0x00000063, 1, 6}, // m6 + {7, 0x00000069, 12, 0}, // z12 + {7, 0x0000006B, 1, 7}, // m7 + {8, 0x000000D1, 20, 0}, // z20 + {8, 0x000000D4, 1, 9}, // m9 + {8, 0x000000DC, 1, 10}, // m10 + {9, 0x00000189, 1, 11}, // m11 + {9, 0x0000018A, 32, 0}, // z32 + {9, 0x000001A0, 1, 12}, // m12 + {9, 0x000001AB, 1, 13}, // m13 + {10, 0x00000377, 1, 18}, // m18 + {10, 0x00000310, 1, 14}, // m14 + {10, 0x00000316, 1, 15}, // m15 + {10, 0x00000343, 60, 0}, // z60 + {10, 0x00000354, 1, 16}, // m16 + {10, 0x00000375, 1, 17}, // m17 + {11, 0x00000623, 1, 19}, // m19 + {11, 0x00000684, 1, 20}, // m20 + {11, 0x00000685, 100, 0}, // z100 + {11, 0x000006AB, 1, 21}, // m21 + {11, 0x000006EC, 1, 22}, // m22 + {12, 0x00000DDB, 1, 29}, // m29 + {12, 0x00000C5C, 1, 24}, // m24 + {12, 0x00000C5E, 1, 25}, // m25 + {12, 0x00000C44, 1, 23}, // m23 + {12, 0x00000D55, 1, 26}, // m26 + {12, 0x00000DD1, 1, 27}, // m27 + {12, 0x00000DD3, 1, 28}, // m28 + {13, 0x00001BB5, 1, 35}, // m35 + {13, 0x0000188B, 1, 30}, // m30 + {13, 0x000018BB, 1, 31}, // m31 + {13, 0x000018BF, 180, 0}, // z180 + {13, 0x00001AA8, 1, 32}, // m32 + {13, 0x00001BA0, 1, 33}, // m33 + {13, 0x00001BA5, 320, 0}, // z320 + {13, 0x00001BA4, 1, 34}, // m34 + {14, 0x00003115, 1, 36}, // m36 + {14, 0x00003175, 1, 37}, // m37 + {14, 0x0000317D, 1, 38}, // m38 + {14, 0x00003553, 1, 39}, // m39 + {14, 0x00003768, 1, 40}, // m40 + {15, 0x00006E87, 1, 46}, // m46 + {15, 0x00006ED3, 1, 47}, // m47 + {15, 0x000062E8, 1, 42}, // m42 + {15, 0x000062F8, 1, 43}, // m43 + {15, 0x00006228, 1, 41}, // m41 + {15, 0x00006AA4, 1, 44}, // m44 + {15, 0x00006E85, 1, 45}, // m45 + {16, 0x0000C453, 1, 48}, // m48 + {16, 0x0000C5D3, 1, 49}, // m49 + {16, 0x0000C5F3, 1, 50}, // m50 + {16, 0x0000DDA4, 1, 53}, // m53 + {16, 0x0000DD08, 1, 51}, // m51 + {16, 0x0000DD0C, 1, 52}, // m52 + {17, 0x0001BB4B, 1, 61}, // m61 + {17, 0x0001BB4A, 1, 60}, // m60 + {17, 0x00018BA5, 1, 55}, // m55 + {17, 0x00018BE5, 1, 56}, // m56 + {17, 0x0001AA95, 1, 57}, // m57 + {17, 0x0001AA97, 1, 58}, // m58 + {17, 0x000188A4, 1, 54}, // m54 + {17, 0x0001BA13, 1, 59}, // m59 + {18, 0x00031748, 1, 62}, // m62 + {18, 0x000317C8, 1, 63}, // m63 + {18, 0x00035528, 1, 64}, // m64 + {18, 0x0003552C, 1, 65}, // m65 + {18, 0x00037424, 1, 66}, // m66 + {18, 0x00037434, 1, 67}, // m67 + {18, 0x00037436, 1, 68}, // m68 + {19, 0x00062294, 1, 69}, // m69 + {19, 0x00062E92, 1, 70}, // m70 + {19, 0x00062F92, 1, 71}, // m71 + {19, 0x0006AA52, 1, 72}, // m72 + {19, 0x0006AA5A, 1, 73}, // m73 + {19, 0x0006E86A, 1, 75}, // m75 + {19, 0x0006E86E, 1, 76}, // m76 + {19, 0x0006E84A, 1, 74}, // m74 + {20, 0x000C452A, 1, 77}, // m77 + {20, 0x000C5D27, 1, 78}, // m78 + {20, 0x000C5F26, 1, 79}, // m79 + {20, 0x000D54A6, 1, 80}, // m80 + {20, 0x000D54B6, 1, 81}, // m81 + {20, 0x000DD096, 1, 82}, // m82 + {20, 0x000DD0D6, 1, 83}, // m83 + {20, 0x000DD0DE, 1, 84}, // m84 + {21, 0x00188A56, 1, 85}, // m85 + {21, 0x0018BA4D, 1, 86}, // m86 + {21, 0x0018BE4E, 1, 87}, // m87 + {21, 0x0018BE4F, 1, 88}, // m88 + {21, 0x001AA96E, 1, 89}, // m89 + {21, 0x001BA12E, 1, 90}, // m90 + {21, 0x001BA12F, 1, 91}, // m91 + {21, 0x001BA1AF, 1, 92}, // m92 + {21, 0x001BA1BF, 1, 93}, // m93 + {22, 0x0037435D, 1, 99}, // m99 + {22, 0x0037437D, 1, 100}, // m100 + {22, 0x00317498, 1, 94}, // m94 + {22, 0x0035529C, 1, 95}, // m95 + {22, 0x0035529D, 1, 96}, // m96 + {22, 0x003552DE, 1, 97}, // m97 + {22, 0x003552DF, 1, 98}, // m98 + {23, 0x0062E933, 1, 102}, // m102 + {23, 0x0062295D, 1, 101}, // m101 + {23, 0x006AA53D, 1, 103}, // m103 + {23, 0x006AA53F, 1, 105}, // m105 + {23, 0x006AA53E, 1, 104}, // m104 + {23, 0x006E86B9, 1, 106}, // m106 + {23, 0x006E86F8, 1, 107}, // m107 + {24, 0x00D54A79, 1, 111}, // m111 + {24, 0x00C5D265, 1, 109}, // m109 + {24, 0x00C452B8, 1, 108}, // m108 + {24, 0x00DD0D71, 1, 113}, // m113 + {24, 0x00D54A78, 1, 110}, // m110 + {24, 0x00DD0D70, 1, 112}, // m112 + {24, 0x00DD0DF2, 1, 114}, // m114 + {24, 0x00DD0DF3, 1, 115}, // m115 + {25, 0x0188A5F6, 1, 225}, // m225 + {25, 0x0188A5F5, 1, 189}, // m189 + {25, 0x0188A5F4, 1, 188}, // m188 + {25, 0x0188A5F3, 1, 203}, // m203 + {25, 0x0188A5F2, 1, 202}, // m202 + {25, 0x0188A5F1, 1, 197}, // m197 + {25, 0x0188A5F0, 1, 207}, // m207 + {25, 0x0188A5EF, 1, 169}, // m169 + {25, 0x0188A5EE, 1, 223}, // m223 + {25, 0x0188A5ED, 1, 159}, // m159 + {25, 0x0188A5AA, 1, 235}, // m235 + {25, 0x0188A5E3, 1, 152}, // m152 + {25, 0x0188A5DF, 1, 192}, // m192 + {25, 0x0188A589, 1, 179}, // m179 + {25, 0x0188A5DD, 1, 201}, // m201 + {25, 0x0188A578, 1, 172}, // m172 + {25, 0x0188A5E0, 1, 149}, // m149 + {25, 0x0188A588, 1, 178}, // m178 + {25, 0x0188A5D6, 1, 120}, // m120 + {25, 0x0188A5DB, 1, 219}, // m219 + {25, 0x0188A5E1, 1, 150}, // m150 + {25, 0x0188A587, 1, 127}, // m127 + {25, 0x0188A59A, 1, 211}, // m211 + {25, 0x0188A5C4, 1, 125}, // m125 + {25, 0x0188A5EC, 1, 158}, // m158 + {25, 0x0188A586, 1, 247}, // m247 + {25, 0x0188A573, 1, 238}, // m238 + {25, 0x0188A59C, 1, 163}, // m163 + {25, 0x0188A5C8, 1, 228}, // m228 + {25, 0x0188A5FB, 1, 183}, // m183 + {25, 0x0188A5A1, 1, 217}, // m217 + {25, 0x0188A5EB, 1, 168}, // m168 + {25, 0x0188A5A8, 1, 122}, // m122 + {25, 0x0188A584, 1, 128}, // m128 + {25, 0x0188A5D2, 1, 249}, // m249 + {25, 0x0188A599, 1, 187}, // m187 + {25, 0x0188A598, 1, 186}, // m186 + {25, 0x0188A583, 1, 136}, // m136 + {25, 0x018BA4C9, 1, 181}, // m181 + {25, 0x0188A5D0, 1, 255}, // m255 + {25, 0x0188A594, 1, 230}, // m230 + {25, 0x0188A582, 1, 135}, // m135 + {25, 0x0188A5CB, 1, 233}, // m233 + {25, 0x0188A5D8, 1, 222}, // m222 + {25, 0x0188A5E7, 1, 145}, // m145 + {25, 0x0188A581, 1, 134}, // m134 + {25, 0x0188A5EA, 1, 167}, // m167 + {25, 0x0188A5A9, 1, 248}, // m248 + {25, 0x0188A5A6, 1, 209}, // m209 + {25, 0x0188A580, 1, 243}, // m243 + {25, 0x0188A5A0, 1, 216}, // m216 + {25, 0x0188A59D, 1, 164}, // m164 + {25, 0x0188A5C3, 1, 140}, // m140 + {25, 0x0188A57F, 1, 157}, // m157 + {25, 0x0188A5C0, 1, 239}, // m239 + {25, 0x0188A5DE, 1, 191}, // m191 + {25, 0x0188A5D4, 1, 251}, // m251 + {25, 0x0188A57E, 1, 156}, // m156 + {25, 0x0188A5C2, 1, 139}, // m139 + {25, 0x0188A592, 1, 242}, // m242 + {25, 0x0188A5CD, 1, 133}, // m133 + {25, 0x0188A57D, 1, 162}, // m162 + {25, 0x0188A5A3, 1, 213}, // m213 + {25, 0x0188A5E8, 1, 165}, // m165 + {25, 0x0188A5A2, 1, 212}, // m212 + {25, 0x0188A57C, 1, 227}, // m227 + {25, 0x0188A58E, 1, 198}, // m198 + {25, 0x0188A5B3, 1, 236}, // m236 + {25, 0x0188A5B2, 1, 234}, // m234 + {25, 0x0188A5B1, 1, 117}, // m117 + {25, 0x0188A5B0, 1, 215}, // m215 + {25, 0x0188A5AF, 1, 124}, // m124 + {25, 0x0188A5AE, 1, 123}, // m123 + {25, 0x0188A5AD, 1, 254}, // m254 + {25, 0x0188A5AC, 1, 253}, // m253 + {25, 0x0188A5AB, 1, 148}, // m148 + {25, 0x0188A5DA, 1, 218}, // m218 + {25, 0x0188A5E4, 1, 146}, // m146 + {25, 0x0188A5E5, 1, 147}, // m147 + {25, 0x0188A5D9, 1, 224}, // m224 + {25, 0x0188A5B5, 1, 143}, // m143 + {25, 0x0188A5BC, 1, 184}, // m184 + {25, 0x0188A5BD, 1, 185}, // m185 + {25, 0x0188A5E9, 1, 166}, // m166 + {25, 0x0188A5CC, 1, 132}, // m132 + {25, 0x0188A585, 1, 129}, // m129 + {25, 0x0188A5D3, 1, 250}, // m250 + {25, 0x0188A5E2, 1, 151}, // m151 + {25, 0x0188A595, 1, 119}, // m119 + {25, 0x0188A596, 1, 193}, // m193 + {25, 0x0188A5B8, 1, 176}, // m176 + {25, 0x0188A590, 1, 245}, // m245 + {25, 0x0188A5C9, 1, 229}, // m229 + {25, 0x0188A5A4, 1, 206}, // m206 + {25, 0x0188A5E6, 1, 144}, // m144 + {25, 0x0188A5A5, 1, 208}, // m208 + {25, 0x0188A5CE, 1, 137}, // m137 + {25, 0x0188A5BF, 1, 241}, // m241 + {25, 0x0188A572, 1, 237}, // m237 + {25, 0x0188A59B, 1, 190}, // m190 + {25, 0x0188A5BE, 1, 240}, // m240 + {25, 0x0188A5C7, 1, 131}, // m131 + {25, 0x0188A5CA, 1, 232}, // m232 + {25, 0x0188A5D5, 1, 252}, // m252 + {25, 0x0188A57B, 1, 171}, // m171 + {25, 0x0188A58D, 1, 205}, // m205 + {25, 0x0188A58C, 1, 204}, // m204 + {25, 0x0188A58B, 1, 118}, // m118 + {25, 0x0188A58A, 1, 214}, // m214 + {25, 0x018BA4C8, 1, 180}, // m180 + {25, 0x0188A5C5, 1, 126}, // m126 + {25, 0x0188A5FA, 1, 182}, // m182 + {25, 0x0188A5BB, 1, 175}, // m175 + {25, 0x0188A5C1, 1, 141}, // m141 + {25, 0x0188A5CF, 1, 138}, // m138 + {25, 0x0188A5B9, 1, 177}, // m177 + {25, 0x0188A5B6, 1, 153}, // m153 + {25, 0x0188A597, 1, 194}, // m194 + {25, 0x0188A5FE, 1, 160}, // m160 + {25, 0x0188A5D7, 1, 121}, // m121 + {25, 0x0188A5BA, 1, 174}, // m174 + {25, 0x0188A591, 1, 246}, // m246 + {25, 0x0188A5C6, 1, 130}, // m130 + {25, 0x0188A5DC, 1, 200}, // m200 + {25, 0x0188A57A, 1, 170}, // m170 + {25, 0x0188A59F, 1, 221}, // m221 + {25, 0x0188A5F9, 1, 196}, // m196 + {25, 0x0188A5B4, 1, 142}, // m142 + {25, 0x0188A5A7, 1, 210}, // m210 + {25, 0x0188A58F, 1, 199}, // m199 + {25, 0x0188A5FD, 1, 155}, // m155 + {25, 0x0188A5B7, 1, 154}, // m154 + {25, 0x0188A593, 1, 244}, // m244 + {25, 0x0188A59E, 1, 220}, // m220 + {25, 0x0188A5F8, 1, 195}, // m195 + {25, 0x0188A5FF, 1, 161}, // m161 + {25, 0x0188A5FC, 1, 231}, // m231 + {25, 0x0188A579, 1, 173}, // m173 + {25, 0x0188A5F7, 1, 226}, // m226 + {26, 0x03114BA2, 1, 116}, // m116 + {26, 0x03114BA3, 0, 1}, // c256 + } +}; diff --git a/gpr/source/lib/vc5_common/types.h b/gpr/source/lib/vc5_common/types.h new file mode 100755 index 0000000..2e5f5b9 --- /dev/null +++ b/gpr/source/lib/vc5_common/types.h @@ -0,0 +1,94 @@ +/*! @file types.h + * + * @brief Definition of some common data types used by the codec. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef TYPES_H +#define TYPES_H + +//! Data type for Boolean variables +typedef uint_fast8_t BOOLEAN; + +//! Data type for image and frame dimensions +typedef uint_least16_t DIMENSION; + +//! Data type for an unsigned number (count) that can be the value in a tag-value pair +typedef uint_least16_t COUNT; + +/*! + @brief Define a data type large enough to hold a quantization value + + Define a data type that is large enough to hold any quantization value. + Older code assumed that the quantization data type was an int, but newer + could should use the QUANT data type. After all quantization values are + stored in a QUANT data type, the data type can be redefined as a byte. +*/ +typedef int QUANT; + +/*! + @brief Integer value for the amount of prescale shift + + @todo Redefine this data type to be uint_fast8_t? +*/ +typedef uint16_t PRESCALE; + + +/*! + @brief Number of bits in a component value +*/ +typedef uint_least8_t PRECISION; + +enum +{ + PRECISION_MIN = 8, + PRECISION_MAX = 32, +}; + +/*! + @brief Data type for the channel number +*/ +typedef uint_least8_t CHANNEL; + +/*! + @brief Data type for the bit mask that represents enabled parts + + The bit mask indicates which parts of the VC-5 standard are enabled + at runtime. +*/ +typedef uint32_t ENABLED_PARTS; + +/*! + @brief Codec version number (major, minor, revision, build) + + The major and minor product numbers identify versions that are released. + Revision numbers are used to identify interim releases for bug fixes. + The build number is incremented for every build, independent of product + numbering, to uniquely identify every build that is a release candidate. +*/ +typedef struct _version +{ + uint8_t major; //!< Major product number + uint8_t minor; //!< Minor product number + uint8_t revision; //!< Product revision + uint8_t padding; //!< Padding to a multiple of 4 bytes + uint32_t build; //!< Unique number for each codec build +} VERSION; + +#define VERSION_INITIALIZER(major, minor, revision, build) {major, minor, revision, 0, build} + +#endif // TYPES_H diff --git a/gpr/source/lib/vc5_common/unique.h b/gpr/source/lib/vc5_common/unique.h new file mode 100755 index 0000000..b90942e --- /dev/null +++ b/gpr/source/lib/vc5_common/unique.h @@ -0,0 +1,42 @@ +/*! @file unique.h + * + * @brief Declaration of data structures for the unique image identifier. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef UNIQUE_H +#define UNIQUE_H + +// Basic UMID label using the UUID method + +static const uint8_t UMID_label[] = { + 0x06, 0x0A, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, 0x01, 0x20, +}; + +// Length of the UMID (in bytes) +#define UMID_size 32 + +// Length of the unique identifier chunk payload (in segments) +#define UMID_length (UMID_size/sizeof(SEGMENT)) + +// Length of the image sequence number (in bytes) +#define sequence_number_size sizeof(uint32_t) + +// Length of the image sequence number (in segments) +#define sequence_number_length (sequence_number_size/sizeof(SEGMENT)) + +#endif // UNIQUE_H diff --git a/gpr/source/lib/vc5_common/utilities.c b/gpr/source/lib/vc5_common/utilities.c new file mode 100755 index 0000000..adc8678 --- /dev/null +++ b/gpr/source/lib/vc5_common/utilities.c @@ -0,0 +1,82 @@ +/*! @file utilities.c + * + * @brief The utilities in this file are included to allow the codec to be tested. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +/*! + @brief Check that the enabled parts are correct +*/ +CODEC_ERROR CheckEnabledParts(ENABLED_PARTS *enabled_parts_ref) +{ + ENABLED_PARTS enabled_parts = (*enabled_parts_ref); + + // The elementary bitstream is always enabled + if ((enabled_parts & VC5_PART_MASK(VC5_PART_ELEMENTARY)) == 0) { + enabled_parts |= VC5_PART_MASK(VC5_PART_ELEMENTARY); + } + + // The conformance specification is never enabled + enabled_parts &= ~((uint32_t)VC5_PART_MASK(VC5_PART_CONFORMANCE)); + + // Image formats must be enabled if subsampled color differences are enabled + if ((enabled_parts & VC5_PART_MASK(VC5_PART_COLOR_SAMPLING)) != 0) { + enabled_parts |= VC5_PART_MASK(VC5_PART_IMAGE_FORMATS); + } + + // Check that the enabled parts were built at compile-time + //assert((enabled_parts & VC5_ENABLED_PARTS) == enabled_parts); + if (! ((enabled_parts & VC5_ENABLED_PARTS) == enabled_parts)) { + return CODEC_ERROR_ENABLED_PARTS; + } + + // Return the correct enabled parts mask + *enabled_parts_ref = enabled_parts; + return CODEC_ERROR_OKAY; +} + +/*! + @brief Verify that the enabled parts are correct +*/ +CODEC_ERROR VerifyEnabledParts(ENABLED_PARTS enabled_parts) +{ + // The elementary bitstream must always be enabled + if ((enabled_parts & VC5_PART_MASK(VC5_PART_ELEMENTARY)) == 0) { + return CODEC_ERROR_ENABLED_PARTS; + } + + // The conformance specification must not be enabled + if ((enabled_parts & VC5_PART_MASK(VC5_PART_CONFORMANCE)) != 0) { + return CODEC_ERROR_ENABLED_PARTS; + } + + // Image formats must be enabled if subsampled color differences are enabled + if ((enabled_parts & VC5_PART_MASK(VC5_PART_COLOR_SAMPLING)) != 0 && + (enabled_parts & VC5_PART_MASK(VC5_PART_IMAGE_FORMATS)) == 0) { + return CODEC_ERROR_ENABLED_PARTS; + } + + // All enabled parts must be compiled into this codec implementation + if ((enabled_parts & VC5_ENABLED_PARTS) != enabled_parts) { + return CODEC_ERROR_ENABLED_PARTS; + } + + // This codec implementation supports the enabled parts of the VC-5 standard + return CODEC_ERROR_OKAY; +} diff --git a/gpr/source/lib/vc5_common/utilities.h b/gpr/source/lib/vc5_common/utilities.h new file mode 100755 index 0000000..851515b --- /dev/null +++ b/gpr/source/lib/vc5_common/utilities.h @@ -0,0 +1,36 @@ +/*! @file utilities.c + * + * @brief Utility routines used by the code for testing the codec. + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef UTILITIES_H +#define UTILITIES_H + +#ifdef __cplusplus +extern "C" { +#endif + + CODEC_ERROR CheckEnabledParts(ENABLED_PARTS *enabled_parts_ref); + + CODEC_ERROR VerifyEnabledParts(ENABLED_PARTS enabled_parts); + +#ifdef __cplusplus +} +#endif + +#endif // UTILITIES_H diff --git a/gpr/source/lib/vc5_common/vc5_common.h b/gpr/source/lib/vc5_common/vc5_common.h new file mode 100644 index 0000000..a83dc41 --- /dev/null +++ b/gpr/source/lib/vc5_common/vc5_common.h @@ -0,0 +1,34 @@ +/*! @file vc5_common.h + * + * @brief Declaration of items that are used by encoder and decoder API + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef VC5_COMMON_H +#define VC5_COMMON_H + +#include "config.h" + +// ================================================================================================= +// VC5 version numbering +// ================================================================================================= + +#define VC5_VERSION_MAJOR 1 +#define VC5_VERSION_MINOR 0 +#define VC5_VERSION_REVISION 0 + +#endif // VC5_COMMON_H diff --git a/gpr/source/lib/vc5_common/wavelet.c b/gpr/source/lib/vc5_common/wavelet.c new file mode 100755 index 0000000..ec7e31a --- /dev/null +++ b/gpr/source/lib/vc5_common/wavelet.c @@ -0,0 +1,519 @@ +/*! @file wavelet.c + * + * @brief Implementation of the module for wavelet data structures and transforms + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#include "common.h" + +/*! + @brief Table of prescale values for the spatial wavelet transform + + Each prescale value is indexed by the wavelet level. Index level zero + corresponds to the input frame, the other prescale values correspond to + wavelets in the transform: frame, spatial, spatial, ... + + Note that the prescale values depend on the encoded precision. The default + precale values are for 10-bit precision and the actual will depend on the + encoded precision. +*/ +const int spatial_prescale[] = {0, 2, 0, 0, 0, 0, 0, 0}; + +/*! + @brief Initialize a wavelet data structure with the specified dimensions +*/ +CODEC_ERROR InitWavelet(WAVELET *wavelet, DIMENSION width, DIMENSION height) +{ + assert(wavelet != NULL); + if (! (wavelet != NULL)) { + return CODEC_ERROR_NULLPTR; + } + + memset(wavelet, 0, sizeof(WAVELET)); + + wavelet->width = width; + wavelet->height = height; + wavelet->band_count = 4; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Allocate a wavelet data structure with the specified dimensions +*/ +CODEC_ERROR AllocWavelet(gpr_allocator *allocator, WAVELET *wavelet, DIMENSION width, DIMENSION height) +{ + // Initialize the fields in the wavelet data structure + InitWavelet(wavelet, width, height); + + if (width > 0 && height > 0) + { + int band; + + //TODO: Align the pitch? + DIMENSION pitch = width * sizeof(PIXEL); + + size_t band_data_size = height * pitch; + + PIXEL* data_all_bands = (PIXEL *)allocator->Alloc(band_data_size * MAX_BAND_COUNT); + + if ( data_all_bands == NULL ) + { + ReleaseWavelet(allocator, wavelet); + return CODEC_ERROR_OUTOFMEMORY; + } + + // Allocate the wavelet bands + for (band = 0; band < MAX_BAND_COUNT; band++) + { + wavelet->data[band] = data_all_bands + band * height * width; + } + + wavelet->pitch = pitch; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Release all resources allocated to the wavelet + + The wavelet data structure itself is not reallocated. +*/ +CODEC_ERROR ReleaseWavelet(gpr_allocator *allocator, WAVELET *wavelet) +{ + int band; + + PIXEL* data_all_bands = wavelet->data[0]; + + allocator->Free(data_all_bands); + + for (band = 0; band < MAX_BAND_COUNT; band++) { + wavelet->data[band] = NULL; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Create and allocate a wavelet data structure +*/ +WAVELET *CreateWavelet(gpr_allocator *allocator, DIMENSION width, DIMENSION height) +{ + CODEC_ERROR error = CODEC_ERROR_OKAY; + + if (width > 0 && height > 0) + { + // Allocate the image data structure for the wavelet + WAVELET *wavelet = (WAVELET *)allocator->Alloc(sizeof(WAVELET)); + assert(wavelet != NULL); + if (! (wavelet != NULL)) { + return NULL; + } + + // Allocate space for the wavelet bands + error = AllocWavelet(allocator, wavelet, width, height); + if (error == CODEC_ERROR_OKAY) { + return wavelet; + } + + // Avoid a memory leak + DeleteWavelet(allocator, wavelet); + } + + return NULL; +} + +/*! + @brief Release all resources the free the wavelet data structure +*/ +CODEC_ERROR DeleteWavelet(gpr_allocator *allocator, WAVELET *wavelet) +{ + ReleaseWavelet(allocator, wavelet); + allocator->Free(wavelet); + return CODEC_ERROR_OKAY; +} + +/*! + @brief Compute the amount of scaling for each band in the wavelet tree + + The forward wavelet transforms increase the number of bits required to + represent the coefficients. This routine computes the amount by which + the input pixels are scaled as each band is computed. The horizontal or + vertical transform scales the lowpass values by one bit, but the hgihpass + values are not scaled. The lowpass wavelet band will be scaled by two + bits, the first and second highpass bands will be scaled by one bit, and + the third highpass band will not be scaled. +*/ +CODEC_ERROR SetTransformScale(TRANSFORM *transform) +{ + //int num_wavelets = 3; + int num_spatial = 2; + + int num_lowpass_spatial; // Number of spatial transforms for lowpass temporal band + //int num_highpass_spatial; // Number of spatial transforms for highpass temporal band + int num_frame_wavelets; // Number of frame wavelets at the base of the pyramid + + // Area of the temporal lowpass filter + int temporal_lowpass_area = 2; + + // Area of the each wavelet filter + int horizontal_lowpass_area = 2; + int vertical_lowpass_area = 2; + + // Combination of the horizontal and vertical wavelet transforms + int spatial_lowpass_area = (horizontal_lowpass_area * vertical_lowpass_area); + + int temporal_lowpass_scale; + int temporal_highpass_scale; + + WAVELET *wavelet = NULL; + //WAVELET *temporal; + + int k; + int i; + + // Coefficients in each band are scaled by the forward wavelet filters + int scale[4] = {1, 1, 1, 1}; + + // Compute the number of frame and spatial wavelets + num_frame_wavelets = 1; + num_lowpass_spatial = num_spatial; + + // Compute the change in scale due to the filters used in the frame transform + temporal_lowpass_scale = temporal_lowpass_area * scale[0]; + temporal_highpass_scale = scale[0]; + + // Compute the scale factors for the first wavelet + scale[0] = horizontal_lowpass_area * temporal_lowpass_scale; + scale[1] = temporal_lowpass_scale; + scale[2] = horizontal_lowpass_area * temporal_highpass_scale; + scale[3] = temporal_highpass_scale; + + for (k = 0; k < num_frame_wavelets; k++) + { + wavelet = transform->wavelet[k]; + assert(wavelet != NULL); + if (! (wavelet != NULL)) { + return CODEC_ERROR_UNEXPECTED; + } + + wavelet->scale[0] = scale[0]; + wavelet->scale[1] = scale[1]; + wavelet->scale[2] = scale[2]; + wavelet->scale[3] = scale[3]; + } + + // Compute the scale factors for the spatial wavelets + for (i = 0; i < num_lowpass_spatial; i++) + { + WAVELET *spatial = transform->wavelet[k++]; + //int k; + + assert(spatial != NULL); + if (! (spatial != NULL)) { + return CODEC_ERROR_UNEXPECTED; + } + + assert(wavelet != NULL); + if (! (wavelet != NULL)) { + return CODEC_ERROR_UNEXPECTED; + } + + // The lowpass band is the input to the spatial transform + temporal_lowpass_scale = wavelet->scale[0]; + + spatial->scale[0] = (spatial_lowpass_area * temporal_lowpass_scale);// >> _LOWPASS_PRESCALE; + spatial->scale[1] = (vertical_lowpass_area * temporal_lowpass_scale);// >> _LOWPASS_PRESCALE; + spatial->scale[2] = (horizontal_lowpass_area * temporal_lowpass_scale);// >> _LOWPASS_PRESCALE; + spatial->scale[3] = (temporal_lowpass_scale);// >> _LOWPASS_PRESCALE; + + // The spatial wavelet is the input for the next level + wavelet = spatial; + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Calculate the amount of prescaling required to prevent overflow + + This routine calculates the arithmetic right shift that is applied to each + lowpass band prior to computation of the wavelet transform. Prescaling is + required to prevent overflow in the wavelet transforms. +*/ +CODEC_ERROR SetTransformPrescale(TRANSFORM *transform, int precision) +{ + if (precision == 8) + { + memset(transform->prescale, 0, sizeof(transform->prescale)); + return CODEC_ERROR_OKAY; + } + else if (precision == 10) + { + PRESCALE spatial_prescale[] = {0, 2, 2, 0, 0, 0, 0, 0}; + memcpy(transform->prescale, spatial_prescale, sizeof(transform->prescale)); + } + else if (precision == 12) + { + // frame, spatial, spatial, ... + PRESCALE spatial_prescale[] = {0, 2, 2, 0, 0, 0, 0, 0}; + memcpy(transform->prescale, spatial_prescale, sizeof(transform->prescale)); + } + else + { + //TODO: Need to handle other precisions + assert(0); + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return a mask for the specified wavelet band + + The wavelet data structure contains a mask that indicates which + bands have been decoded. +*/ +bool BandValidMask(int band) +{ + return (1 << band); +} + +/*! + @brief Check that all bands are valid + + The wavelet valid band mask is checked to determine whether + all of the bands in the wavelet have been decoded. +*/ +bool BandsAllValid(WAVELET *wavelet) +{ + uint32_t all_bands_valid_mask = ((1 << wavelet->band_count) - 1); + return (wavelet->valid_band_mask == all_bands_valid_mask); +} + +/*! + @brief Set the bit for the specified band in the valid band mask +*/ +CODEC_ERROR UpdateWaveletValidBandMask(WAVELET *wavelet, int band) +{ + if (0 <= band && band < MAX_BAND_COUNT) + { + // Update the valid wavelet band flags + wavelet->valid_band_mask |= (1 << band); + return CODEC_ERROR_OKAY; + } + return CODEC_ERROR_INVALID_BAND; +} + +/*! + @brief Compute the wavelet index from the subband index + + All subbands that are encoded into the bitstream, including the + lowpass band at the highest wavelet level, are numbered in decode + order starting with zero for the lowpass band. + + This routine maps the subband index to the index of the wavelet + that contains the specified subband. + + Note the sifference between a wavelet band and a subband: The bands in + each wavelet are numbered starting at zero, while the subband index + applies to all wavelet bands in the encoded sample and does not include + the lowpass bands that are reconstructed during decoding from the bands + that were encoded into the bitstream. +*/ +int SubbandWaveletIndex(int subband) +{ + //TODO: Adjust for other transform types and decoded resolutions + static int subband_wavelet_index[] = {2, 2, 2, 2, 1, 1, 1, 0, 0, 0}; + + assert(0 <= subband && subband < MAX_SUBBAND_COUNT); + + // Return the index of the wavelet corresponding to this subband + return subband_wavelet_index[subband]; +} + +/*! + @brief Compute the index for the band in a wavelet from the subband index + + See the explanation of wavelet bands and subbands in the documentation for + @ref SubbandWaveletIndex. +*/ +int SubbandBandIndex(int subband) +{ + //TODO: Adjust for other transform types and decoded resolutions + static int subband_band_index[] = {0, 1, 2, 3, 1, 2, 3, 1, 2, 3}; + + assert(0 <= subband && subband < MAX_SUBBAND_COUNT); + + // Return the index to the band within the wavelet + return subband_band_index[subband]; +} + +/*! + @brief Free the wavelets allocated for this transform +*/ +CODEC_ERROR ReleaseTransform(gpr_allocator *allocator, TRANSFORM *transform) +{ + int wavelet_index; + + for (wavelet_index = 0; wavelet_index < MAX_WAVELET_COUNT; wavelet_index++) + { + WAVELET *wavelet = transform->wavelet[wavelet_index]; + if (wavelet != NULL) { + DeleteWavelet(allocator, wavelet); + transform->wavelet[wavelet_index] = NULL; + } + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return true if the prescale table is the same as the default table + + This routine compares the prescale values used by the transform with the default + table of prescale values. If the actual prescale values are the same as the + default values, then the table of prescale values do not have to be encoded + into the bitstream. +*/ +bool IsTransformPrescaleDefault(TRANSFORM *transform, int precision) +{ + int prescale_count = sizeof(transform->prescale) / sizeof(transform->prescale[0]); + int total = 0; + int i; + + if (precision == 8) + { + for (i = 0; i < prescale_count; i++) { + total += transform->prescale[i]; + } + return (total == 0); + } + + for (i = 0; i < prescale_count; i++) { + total += absolute(transform->prescale[i] - spatial_prescale[i]); + } + for(; i < MAX_PRESCALE_COUNT; i++) { + total += spatial_prescale[i]; + } + return (total == 0); +} + +PIXEL *WaveletRowAddress(WAVELET *wavelet, int band, int row) +{ + assert(wavelet != NULL); + if (! (wavelet != NULL)) { + return NULL; + } + + assert(0 <= row && row < wavelet->height); + if (! (0 <= row && row < wavelet->height)) + { + return NULL; + } + else + { + uint8_t *address = (uint8_t *)wavelet->data[band]; + address += row * wavelet->pitch; + return (PIXEL *)address; + } +} + +void WaveletToRGB( gpr_allocator allocator, PIXEL* GS_src, PIXEL* RG_src, PIXEL* BG_src, DIMENSION src_width, DIMENSION src_height, DIMENSION src_pitch, RGB_IMAGE *dst_image, + int input_precision_bits, int output_precision_bits, gpr_rgb_gain* rgb_gain ) +{ + TIMESTAMP("[BEG]", 2) + + assert( dst_image ); + assert( dst_image->buffer == NULL ); + + size_t size; + if( output_precision_bits == 8 ) + { + size = src_width * src_height * 3; + } + else + { + size = src_width * src_height * 6; + } + + dst_image->width = src_width; + dst_image->height = src_height; + dst_image->pitch = src_width * 3; + dst_image->size = size; + dst_image->buffer = allocator.Alloc( size ); + + const int32_t midpoint = (1 << (input_precision_bits - 1)); + const int32_t shift = input_precision_bits - 12; + + unsigned char* RGB_dst_8bits = dst_image->buffer; + unsigned short* RGB_dst_16bits = dst_image->buffer; + + DIMENSION x, y; + + for ( y = 0; y < src_height; y++) + { + for ( x = 0; x < src_width; x++) + { + int32_t G = GS_src[ (src_width - x - 1) + y * src_pitch]; + int32_t R = 2 * ( RG_src[(src_width - x - 1) + y * src_pitch] - midpoint) + G; + int32_t B = 2 * ( BG_src[(src_width - x - 1) + y * src_pitch] - midpoint) + G; + + // R,G,B are in 16-bit range since DecoderLogCurve outputs in 16 bits (although it's input is 12 bits) + R = DecoderLogCurve[ clamp_uint( (R >> shift), 12) ]; + G = DecoderLogCurve[ clamp_uint( (G >> shift), 12) ]; + B = DecoderLogCurve[ clamp_uint( (B >> shift), 12) ]; + + if( output_precision_bits == 8 ) + { + R *= rgb_gain->r_gain_num; + R >>= rgb_gain->r_gain_pow2_den; + + G *= rgb_gain->g_gain_num; + G >>= rgb_gain->g_gain_pow2_den; + + B *= rgb_gain->b_gain_num; + B >>= rgb_gain->b_gain_pow2_den; + + R = sqrtf((float)R); + G = sqrtf((float)G); + B = sqrtf((float)B); + + R = clamp_uint8( R ); + G = clamp_uint8( G ); + B = clamp_uint8( B ); + + RGB_dst_8bits[3 * (x) + 0 + y * dst_image->pitch] = R; + RGB_dst_8bits[3 * (x) + 1 + y * dst_image->pitch] = G; + RGB_dst_8bits[3 * (x) + 2 + y * dst_image->pitch] = B; + } + else + { + R = clamp_uint16( R ); + G = clamp_uint16( G ); + B = clamp_uint16( B ); + + RGB_dst_16bits[3 * (x) + 0 + y * dst_image->pitch] = ( (R & 0x00FF) << 8 ) | ( (R & 0xFF00) >> 8 ); + RGB_dst_16bits[3 * (x) + 1 + y * dst_image->pitch] = ( (G & 0x00FF) << 8 ) | ( (G & 0xFF00) >> 8 ); + RGB_dst_16bits[3 * (x) + 2 + y * dst_image->pitch] = ( (B & 0x00FF) << 8 ) | ( (B & 0xFF00) >> 8 ); + } + } + } + + TIMESTAMP("[BEG]", 2) +} diff --git a/gpr/source/lib/vc5_common/wavelet.h b/gpr/source/lib/vc5_common/wavelet.h new file mode 100755 index 0000000..cc5e2b6 --- /dev/null +++ b/gpr/source/lib/vc5_common/wavelet.h @@ -0,0 +1,126 @@ +/*! @file vlc.h + * + * @brief This file defines the data structures for the wavelet tree + * + * @version 1.0.0 + * + * (C) Copyright 2018 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * 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. + */ + +#ifndef WAVELET_H +#define WAVELET_H + +#include "common.h" + +/*! + @brief Data structure used for wavelets + + This data structure is used for wavelets and can be used for images since + an image with multiple planar channels and a wavelet with multiple bands + are similar data structures. + + The pitch is the distance between rows in bytes and must always be + an integer multiple of the pixel size in bytes. + + The wavelet data structure contains an array of the scale factor for + each band that is the cummulative result of the application of the + wavelet transforms that created the wavelet. +*/ +typedef struct _wavelet +{ + DIMENSION width; //!< Width of the image in pixels + DIMENSION height; //!< Height of the image in lines + DIMENSION pitch; //!< Distance between rows (in bytes) + uint16_t band_count; //!< Number of bands in a wavelet + uint32_t valid_band_mask; //!< Mask indicating which bands have been decoded + uint16_t scale[MAX_BAND_COUNT]; //!< Cumulative scaling by the wavelet transforms + QUANT quant[MAX_BAND_COUNT]; //!< Quantization value for each band + PIXEL *data[MAX_BAND_COUNT]; //!< Data buffer for each band + +} WAVELET; + +//! Indices for the wavelet bands in the image data structure +typedef enum +{ + LL_BAND = 0, //!< Lowpass transform of lowpass intermediate result + LH_BAND, //!< Lowpass transform of highpass intermediate result + HL_BAND, //!< Highpass transform of lowpass intermediate result + HH_BAND //!< Highpass transform of highpass intermediate result +} WAVELET_BAND; + +//! Types of wavelet tranforms +enum +{ + WAVELET_TYPE_HORIZONTAL = 1, + WAVELET_TYPE_VERTICAL = 2, + WAVELET_TYPE_TEMPORAL = 4, + + //! The baseline profile only supports spatial wavelets + WAVELET_TYPE_SPATIAL = (WAVELET_TYPE_HORIZONTAL | WAVELET_TYPE_VERTICAL), + +}; + +//! Data structure for the wavelet tree (one channel) +typedef struct _transform +{ + //! Prescale the input by the specified shift before the transform + PRESCALE prescale[MAX_WAVELET_COUNT]; + + //! List of the wavelets in the transform for one channel + WAVELET *wavelet[MAX_WAVELET_COUNT]; + +} TRANSFORM; + + +#ifdef __cplusplus +extern "C" { +#endif + + CODEC_ERROR AllocWavelet(gpr_allocator *allocator, WAVELET *wavelet, DIMENSION width, DIMENSION height); + CODEC_ERROR ReleaseWavelet(gpr_allocator *allocator, WAVELET *wavelet); + + WAVELET *CreateWavelet(gpr_allocator *allocator, DIMENSION width, DIMENSION height); + CODEC_ERROR DeleteWavelet(gpr_allocator *allocator, WAVELET *wavelet); + + CODEC_ERROR SetTransformScale(TRANSFORM *transform); + + CODEC_ERROR SetTransformPrescale(TRANSFORM *transform, int precision); + + bool BandValidMask(int band); + + bool BandsAllValid(WAVELET *wavelet); + #define AllBandsValid BandsAllValid + + CODEC_ERROR UpdateWaveletValidBandMask(WAVELET *wavelet, int band); + + int SubbandWaveletIndex(int subband); + + int SubbandBandIndex(int subband); + + CODEC_ERROR ResetTransformFlags(TRANSFORM transform[], int transform_count); + + CODEC_ERROR ReleaseTransform(gpr_allocator *allocator, TRANSFORM *transform); + + bool IsTransformPrescaleDefault(TRANSFORM *transform, int precision); + + PIXEL *WaveletRowAddress(WAVELET *wavelet, int band, int row); + + void WaveletToRGB( gpr_allocator allocator, PIXEL* GS_src, PIXEL* RG_src, PIXEL* BG_src, DIMENSION src_width, DIMENSION src_height, DIMENSION src_pitch, RGB_IMAGE *dst_image, + int input_precision_bits, int output_precision_bits, gpr_rgb_gain* rgb_gain ); + +#ifdef __cplusplus +} +#endif + +#endif // WAVELET_H |