YuvBufferT::YuvBufferT(uint8_t *lumaPointer,
    int32_t lumaWidth, int32_t lumaHeight,
    int32_t lumaElementStrideBytes, int32_t lumaRowStrideBytes,
    uint8_t *chromaUPointer,
    int32_t chromaUWidth, int32_t chromaUHeight,
    int32_t chromaUElementStrideBytes, int32_t chromaURowStrideBytes,
    uint8_t *chromaVPointer,
    int32_t chromaVWidth, int32_t chromaVHeight,
    int32_t chromaVElementStrideBytes, int32_t chromaVRowStrideBytes) {
    assert(lumaPointer != nullptr);
    assert(chromaUPointer != nullptr);
    assert(chromaVPointer != nullptr);

    luma_ = { 0 };
    luma_.host = lumaPointer;
    luma_.host_dirty = true;
    luma_.extent[0] = lumaWidth;
    luma_.extent[1] = lumaHeight;
    luma_.extent[2] = 0;
    luma_.extent[3] = 0;
    // Halide strides are in elements, but element size is 1.
    luma_.stride[0] = lumaElementStrideBytes;
    luma_.stride[1] = lumaRowStrideBytes;
    luma_.min[0] = 0;
    luma_.min[1] = 0;
    luma_.elem_size = 1;

    chromaU_ = { 0 };
    chromaU_.host = chromaUPointer;
    chromaU_.host_dirty = true;
    chromaU_.extent[0] = chromaUWidth;
    chromaU_.extent[1] = chromaUHeight;
    chromaU_.extent[2] = 0;
    chromaU_.extent[3] = 0;
    // Halide strides are in elements, but element size is 1.
    chromaU_.stride[0] = chromaUElementStrideBytes;
    chromaU_.stride[1] = chromaURowStrideBytes;
    chromaU_.min[0] = 0;
    chromaU_.min[1] = 0;
    chromaU_.elem_size = 1;

    chromaV_ = { 0 };
    chromaV_.host = chromaVPointer;
    chromaV_.host_dirty = true;
    chromaV_.extent[0] = chromaVWidth;
    chromaV_.extent[1] = chromaVHeight;
    chromaV_.extent[2] = 0;
    chromaV_.extent[3] = 0;
    // Halide strides are in elements, but element size is 1.
    chromaV_.stride[0] = chromaVElementStrideBytes;
    chromaV_.stride[1] = chromaVRowStrideBytes;
    chromaV_.min[0] = 0;
    chromaV_.min[1] = 0;
    chromaV_.elem_size = 1;

    // See if chroma is stored according to a well known format.
    chromaStorage_ = ChromaStorage::kOther;
    // U and V must have the same extents and strides.
    if (equalExtents(chromaU_, chromaV_) && equalStrides(chromaU_, chromaV_)) {
        // If strides are exactly 2, check if they are interleaved.
        if (chromaU_.stride[0] == 2 && chromaV_.stride[0] == 2) {
            if (chromaU_.host == chromaV_.host - 1) {
                chromaStorage_ = ChromaStorage::kInterleavedUFirst;
            } else if (chromaV_.host == chromaU_.host - 1) {
                chromaStorage_ = ChromaStorage::kInterleavedVFirst;
            }
        } else if (chromaU_.stride[0] == 1 && chromaV_.stride[0] == 1) {
            // If element stride is 1, then they're planar.
            // If there is no space at the end of each row, they might be packed.
            // Check if one directly follows the other.
            if (chromaU_.extent[0] == chromaU_.stride[1] &&
                chromaV_.extent[0] == chromaV_.stride[1]) {
                if (chromaU_.host + chromaU_.stride[1] * chromaU_.extent[1] == chromaV_.host) {
                    chromaStorage_ = ChromaStorage::kPlanarPackedUFirst;
                } else if (chromaV_.host + chromaV_.stride[1] * chromaV_.extent[1] == chromaU_.host) {
                    chromaStorage_ = ChromaStorage::kPlanarPackedVFirst;
                }
            } else {
                chromaStorage_ = ChromaStorage::kPlanarGeneric;
            }
        }
    }

    interleavedChromaView_ = { 0 };
    if (chromaStorage_ == ChromaStorage::kInterleavedUFirst ||
        chromaStorage_ == ChromaStorage::kInterleavedVFirst) {
        const buffer_t &first =
            (chromaStorage_ == ChromaStorage::kInterleavedUFirst) ?
            chromaU_ :
            chromaV_;
        interleavedChromaView_.host = first.host;
        interleavedChromaView_.host_dirty = true;
        interleavedChromaView_.extent[0] = 2 * first.extent[0];
        interleavedChromaView_.extent[1] = first.extent[1];
        // Halide strides are in elements, but element size is 1.
        interleavedChromaView_.stride[0] = 1;
        interleavedChromaView_.stride[1] = first.stride[1];
        interleavedChromaView_.elem_size = 1;
    }

    packedPlanarChromaView_ = { 0 };
    if (chromaStorage_ == ChromaStorage::kPlanarPackedUFirst ||
        chromaStorage_ == ChromaStorage::kPlanarPackedVFirst) {
        const buffer_t &first =
            (chromaStorage_ == ChromaStorage::kPlanarPackedUFirst) ?
            chromaU_ :
            chromaV_;
        packedPlanarChromaView_.host = first.host;
        packedPlanarChromaView_.host_dirty = true;
        packedPlanarChromaView_.extent[0] = first.extent[0];
        packedPlanarChromaView_.extent[1] = 2 * first.extent[1];
        // Halide strides are in elements, but element size is 1.
        packedPlanarChromaView_.stride[0] = first.stride[0];
        packedPlanarChromaView_.stride[1] = first.stride[1];
        packedPlanarChromaView_.elem_size = 1;
    }
}
Exemple #2
0
bool copy2D(const buffer_t &src, const buffer_t &dst) {
    if (!equalExtents(src, dst)) {
        return false;
    }
    if (src.elem_size != dst.elem_size) {
        return false;
    }

    if (src.stride[0] == 1 && src.stride[1] == src.extent[0] &&
        dst.stride[0] == 1 && dst.stride[1] == dst.extent[0]) {
        // Copy all at once.
        memcpy(dst.host, src.host, src.extent[1] * src.stride[1] * src.elem_size);
    } else if (src.stride[0] == 1 && dst.stride[0] == 1) {
        // memcpy row by row.
        int32_t minRowStrideBytes = std::min(src.stride[1], dst.stride[1]) * src.elem_size;
        for (int32_t y = 0; y < src.extent[1]; ++y) {
            const uint8_t *srcRow = src.host + y * src.stride[1] * src.elem_size;
            uint8_t *dstRow = dst.host + y * dst.stride[1] * dst.elem_size;
            memcpy(dstRow, srcRow, minRowStrideBytes);
        }
    } else {
        // Copy element by element.
        int32_t srcElementStrideBytes = src.stride[0] * src.elem_size;
        int32_t dstElementStrideBytes = dst.stride[0] * dst.elem_size;
        int32_t srcRowStrideBytes = src.stride[1] * src.elem_size;
        int32_t dstRowStrideBytes = dst.stride[1] * dst.elem_size;

        // Just do array assignment if elements are small enough.
        // It's slightly ridiculous that we have all these versions, but oh well.
        if (src.elem_size == 1) {
            for (int32_t y = 0; y < src.extent[1]; ++y) {
                const uint8_t *srcRow = src.host + y * srcRowStrideBytes;
                uint8_t *dstRow = dst.host + y * dstRowStrideBytes;
                for (int32_t x = 0; x < src.extent[0]; ++x) {
                    dstRow[x * dstElementStrideBytes] = srcRow[x * srcElementStrideBytes];
                }
            }
        } else if (src.elem_size == 2) {
            for (int32_t y = 0; y < src.extent[1]; ++y) {
                const uint8_t *srcRow = src.host + y * srcRowStrideBytes;
                uint8_t *dstRow = dst.host + y * dstRowStrideBytes;
                for (int32_t x = 0; x < src.extent[0]; ++x) {
                    const uint16_t *srcElement = reinterpret_cast<const uint16_t *>(
                        srcRow + x * srcElementStrideBytes);
                    uint16_t *dstElement = reinterpret_cast<uint16_t *>(
                        dstRow + x * dstElementStrideBytes);
                    *dstElement = *srcElement;
                }
            }
        } else if (src.elem_size == 4) {
            for (int32_t y = 0; y < src.extent[1]; ++y) {
                const uint8_t *srcRow = src.host + y * srcRowStrideBytes;
                uint8_t *dstRow = dst.host + y * dstRowStrideBytes;
                for (int32_t x = 0; x < src.extent[0]; ++x) {
                    const uint32_t *srcElement = reinterpret_cast<const uint32_t *>(
                        srcRow + x * srcElementStrideBytes);
                    uint32_t *dstElement = reinterpret_cast<uint32_t *>(
                        dstRow + x * dstElementStrideBytes);
                    *dstElement = *srcElement;
                }
            }
        } else if (src.elem_size == 8) {
            for (int32_t y = 0; y < src.extent[1]; ++y) {
                const uint8_t *srcRow = src.host + y * srcRowStrideBytes;
                uint8_t *dstRow = dst.host + y * dstRowStrideBytes;
                for (int32_t x = 0; x < src.extent[0]; ++x) {
                    const uint64_t *srcElement = reinterpret_cast<const uint64_t *>(
                        srcRow + x * srcElementStrideBytes);
                    uint64_t *dstElement = reinterpret_cast<uint64_t *>(
                        dstRow + x * dstElementStrideBytes);
                    *dstElement = *srcElement;
                }
            }
        } else {
            // Otherwise, use memcpy.
            for (int32_t y = 0; y < src.extent[1]; ++y) {
                const uint8_t *srcRow = src.host + y * srcRowStrideBytes;
                uint8_t *dstRow = dst.host + y * dstRowStrideBytes;
                for (int32_t x = 0; x < src.extent[0]; ++x) {
                    const uint8_t *srcElementPtr = srcRow + x * srcElementStrideBytes;
                    uint8_t *dstElementPtr = dstRow + x * dstElementStrideBytes;
                    memcpy(dstElementPtr, srcElementPtr, src.elem_size);
                }
            }
        }
    }
    return true;
}