1b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi/* 2b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * Copyright (C) 2013 The Android Open Source Project 3b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * 4b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * Licensed under the Apache License, Version 2.0 (the "License"); 5b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * you may not use this file except in compliance with the License. 6b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * You may obtain a copy of the License at 7b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * 8b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * http://www.apache.org/licenses/LICENSE-2.0 9b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * 10b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * Unless required by applicable law or agreed to in writing, software 11b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * distributed under the License is distributed on an "AS IS" BASIS, 12b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * See the License for the specific language governing permissions and 14b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi * limitations under the License. 15b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi */ 16b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 17b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include <string.h> 18b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include "JNIHelpers.h" 19b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include "utils/log.h" 20b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include "utils/math.h" 21b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include "webp/format_constants.h" 22b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 23b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include "FrameSequence_webp.h" 24b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 25b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#define WEBP_DEBUG 0 26b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 27b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 28b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Frame sequence 29b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 30b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 31b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic uint32_t GetLE32(const uint8_t* const data) { 32b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return MKFOURCC(data[0], data[1], data[2], data[3]); 33b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 34b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 35b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Returns true if the frame covers full canvas. 36b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic bool isFullFrame(const WebPIterator& frame, int canvasWidth, int canvasHeight) { 37b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return (frame.width == canvasWidth && frame.height == canvasHeight); 38b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 39b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 409b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi// Returns true if the rectangle defined by 'frame' contains pixel (x, y). 419b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshistatic bool FrameContainsPixel(const WebPIterator& frame, int x, int y) { 429b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi const int left = frame.x_offset; 439b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi const int right = left + frame.width; 449b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi const int top = frame.y_offset; 459b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi const int bottom = top + frame.height; 469b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi return x >= left && x < right && y >= top && y < bottom; 479b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi} 489b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi 49b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Construct mIsKeyFrame array. 50b34f1da83570613bb349f8026d4325552ac495edUrvang Joshivoid FrameSequence_webp::constructDependencyChain() { 51b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const size_t frameCount = getFrameCount(); 52b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mIsKeyFrame = new bool[frameCount]; 53b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasWidth = getWidth(); 54b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasHeight = getHeight(); 55b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 56b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPIterator prev; 57b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPIterator curr; 58b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 59b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Note: WebPDemuxGetFrame() uses base-1 counting. 60b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int ok = WebPDemuxGetFrame(mDemux, 1, &curr); 61b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOG_ASSERT(ok, "Could not retrieve frame# 0"); 62b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mIsKeyFrame[0] = true; // 0th frame is always a key frame. 63b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (size_t i = 1; i < frameCount; i++) { 64b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi prev = curr; 65b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ok = WebPDemuxGetFrame(mDemux, i + 1, &curr); // Get ith frame. 66b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOG_ASSERT(ok, "Could not retrieve frame# %d", i); 67b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 68b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if ((!curr.has_alpha || curr.blend_method == WEBP_MUX_NO_BLEND) && 69b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi isFullFrame(curr, canvasWidth, canvasHeight)) { 70b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mIsKeyFrame[i] = true; 71b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } else { 72b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mIsKeyFrame[i] = (prev.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) && 73b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi (isFullFrame(prev, canvasWidth, canvasHeight) || mIsKeyFrame[i - 1]); 74b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 75b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 76b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPDemuxReleaseIterator(&prev); 77b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPDemuxReleaseIterator(&curr); 78b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 79b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#if WEBP_DEBUG 80b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGD("Dependency chain:"); 81b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (size_t i = 0; i < frameCount; i++) { 82b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGD("Frame# %zu: %s", i, mIsKeyFrame[i] ? "Key frame" : "NOT a key frame"); 83b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 84b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#endif 85b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 86b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 87c6eca849a1d737fe7c0d397fb8265584d1e34226Chris CraikFrameSequence_webp::FrameSequence_webp(Stream* stream) 88c6eca849a1d737fe7c0d397fb8265584d1e34226Chris Craik : mDemux(NULL) 89fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik , mIsKeyFrame(NULL) 90fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik , mRawByteBuffer(NULL) { 916a61141137c7a46d747aa611c9caf62436bc119fChris Craik if (stream->getRawBuffer() != NULL) { 926a61141137c7a46d747aa611c9caf62436bc119fChris Craik mData.size = stream->getRawBufferSize(); 936a61141137c7a46d747aa611c9caf62436bc119fChris Craik mData.bytes = stream->getRawBufferAddr(); 946a61141137c7a46d747aa611c9caf62436bc119fChris Craik mRawByteBuffer = stream->getRawBuffer(); 956a61141137c7a46d747aa611c9caf62436bc119fChris Craik } else { 966a61141137c7a46d747aa611c9caf62436bc119fChris Craik // Read RIFF header to get file size. 976a61141137c7a46d747aa611c9caf62436bc119fChris Craik uint8_t riff_header[RIFF_HEADER_SIZE]; 986a61141137c7a46d747aa611c9caf62436bc119fChris Craik if (stream->read(riff_header, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE) { 996a61141137c7a46d747aa611c9caf62436bc119fChris Craik ALOGE("WebP header load failed"); 1006a61141137c7a46d747aa611c9caf62436bc119fChris Craik return; 1016a61141137c7a46d747aa611c9caf62436bc119fChris Craik } 102fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik uint32_t readSize = GetLE32(riff_header + TAG_SIZE); 103fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik if (readSize > MAX_CHUNK_PAYLOAD) { 104fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik ALOGE("WebP got header size too large"); 105fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik return; 106fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik } 107fffaa9f25edddc6fa10512c1cc19f625c2abee8cChris Craik mData.size = CHUNK_HEADER_SIZE + readSize; 108d2fd12358d35eb999ef8b92b1dcce07f7be15fc3Chris Craik if(mData.size < RIFF_HEADER_SIZE) { 109d2fd12358d35eb999ef8b92b1dcce07f7be15fc3Chris Craik ALOGE("WebP file malformed"); 110d2fd12358d35eb999ef8b92b1dcce07f7be15fc3Chris Craik return; 111d2fd12358d35eb999ef8b92b1dcce07f7be15fc3Chris Craik } 1126a61141137c7a46d747aa611c9caf62436bc119fChris Craik mData.bytes = new uint8_t[mData.size]; 1136a61141137c7a46d747aa611c9caf62436bc119fChris Craik memcpy((void*)mData.bytes, riff_header, RIFF_HEADER_SIZE); 1146a61141137c7a46d747aa611c9caf62436bc119fChris Craik 1156a61141137c7a46d747aa611c9caf62436bc119fChris Craik // Read rest of the bytes. 1166a61141137c7a46d747aa611c9caf62436bc119fChris Craik void* remaining_bytes = (void*)(mData.bytes + RIFF_HEADER_SIZE); 1176a61141137c7a46d747aa611c9caf62436bc119fChris Craik size_t remaining_size = mData.size - RIFF_HEADER_SIZE; 1186a61141137c7a46d747aa611c9caf62436bc119fChris Craik if (stream->read(remaining_bytes, remaining_size) != remaining_size) { 1196a61141137c7a46d747aa611c9caf62436bc119fChris Craik ALOGE("WebP full load failed"); 1206a61141137c7a46d747aa611c9caf62436bc119fChris Craik return; 1216a61141137c7a46d747aa611c9caf62436bc119fChris Craik } 122b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 123b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 124b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Construct demux. 125b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mDemux = WebPDemux(&mData); 126b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (!mDemux) { 127b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGE("Parsing of WebP container file failed"); 128b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return; 129b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 130b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mLoopCount = WebPDemuxGetI(mDemux, WEBP_FF_LOOP_COUNT); 131b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mFormatFlags = WebPDemuxGetI(mDemux, WEBP_FF_FORMAT_FLAGS); 132b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#if WEBP_DEBUG 133b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGD("FrameSequence_webp created with size = %d x %d, number of frames = %d, flags = 0x%X", 134b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi getWidth(), getHeight(), getFrameCount(), mFormatFlags); 135b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#endif 136b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi constructDependencyChain(); 137b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 138b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 139b34f1da83570613bb349f8026d4325552ac495edUrvang JoshiFrameSequence_webp::~FrameSequence_webp() { 140b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPDemuxDelete(mDemux); 141b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi delete[] mIsKeyFrame; 1426a61141137c7a46d747aa611c9caf62436bc119fChris Craik if (mRawByteBuffer == NULL) { 1436a61141137c7a46d747aa611c9caf62436bc119fChris Craik delete[] mData.bytes; 1446a61141137c7a46d747aa611c9caf62436bc119fChris Craik } 145b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 146b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 147b34f1da83570613bb349f8026d4325552ac495edUrvang JoshiFrameSequenceState* FrameSequence_webp::createState() const { 148b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return new FrameSequenceState_webp(*this); 149b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 150b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 151b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 152b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// draw helpers 153b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 154b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 155b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic bool willBeCleared(const WebPIterator& iter) { 156b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND; 157b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 158b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 159b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// return true if area of 'target' completely covers area of 'covered' 160b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic bool checkIfCover(const WebPIterator& target, const WebPIterator& covered) { 161b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int covered_x_max = covered.x_offset + covered.width; 162b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int target_x_max = target.x_offset + target.width; 163b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int covered_y_max = covered.y_offset + covered.height; 164b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int target_y_max = target.y_offset + target.height; 165b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return target.x_offset <= covered.x_offset 166b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi && covered_x_max <= target_x_max 167b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi && target.y_offset <= covered.y_offset 168b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi && covered_y_max <= target_y_max; 169b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 170b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 171b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Clear all pixels in a line to transparent. 172b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic void clearLine(Color8888* dst, int width) { 173b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi memset(dst, 0, width * sizeof(*dst)); // Note: Assumes TRANSPARENT == 0x0. 174b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 175b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 176b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Copy all pixels from 'src' to 'dst'. 177b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic void copyFrame(const Color8888* src, int srcStride, Color8888* dst, int dstStride, 178b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int width, int height) { 179b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int y = 0; y < height; y++) { 180b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi memcpy(dst, src, width * sizeof(*dst)); 181b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi src += srcStride; 182b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi dst += dstStride; 183b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 184b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 185b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 186b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 187b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Frame sequence state 188b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 189b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 190b34f1da83570613bb349f8026d4325552ac495edUrvang JoshiFrameSequenceState_webp::FrameSequenceState_webp(const FrameSequence_webp& frameSequence) : 191b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mFrameSequence(frameSequence) { 192b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPInitDecoderConfig(&mDecoderConfig); 193b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mDecoderConfig.output.is_external_memory = 1; 194b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mDecoderConfig.output.colorspace = MODE_rgbA; // Pre-multiplied alpha mode. 195b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasWidth = mFrameSequence.getWidth(); 196b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasHeight = mFrameSequence.getHeight(); 197b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mPreservedBuffer = new Color8888[canvasWidth * canvasHeight]; 198b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 199b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 200b34f1da83570613bb349f8026d4325552ac495edUrvang JoshiFrameSequenceState_webp::~FrameSequenceState_webp() { 201b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi delete[] mPreservedBuffer; 202b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 203b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 204b34f1da83570613bb349f8026d4325552ac495edUrvang Joshivoid FrameSequenceState_webp::initializeFrame(const WebPIterator& currIter, Color8888* currBuffer, 205b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int currStride, const WebPIterator& prevIter, const Color8888* prevBuffer, int prevStride) { 206b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasWidth = mFrameSequence.getWidth(); 207b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasHeight = mFrameSequence.getHeight(); 208b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const bool currFrameIsKeyFrame = mFrameSequence.isKeyFrame(currIter.frame_num - 1); 209b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 210b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (currFrameIsKeyFrame) { // Clear canvas. 211b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int y = 0; y < canvasHeight; y++) { 212b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* dst = currBuffer + y * currStride; 213b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi clearLine(dst, canvasWidth); 214b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 215b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } else { 216b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Preserve previous frame as starting state of current frame. 217b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi copyFrame(prevBuffer, prevStride, currBuffer, currStride, canvasWidth, canvasHeight); 218b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 219b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Dispose previous frame rectangle to Background if needed. 220b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi bool prevFrameCompletelyCovered = 221b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi (!currIter.has_alpha || currIter.blend_method == WEBP_MUX_NO_BLEND) && 222b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi checkIfCover(currIter, prevIter); 223b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if ((prevIter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) && 224b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi !prevFrameCompletelyCovered) { 225b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* dst = currBuffer + prevIter.x_offset + prevIter.y_offset * currStride; 226b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int j = 0; j < prevIter.height; j++) { 227b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi clearLine(dst, prevIter.width); 228b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi dst += currStride; 229b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 230b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 231b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 232b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 233b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 234b34f1da83570613bb349f8026d4325552ac495edUrvang Joshibool FrameSequenceState_webp::decodeFrame(const WebPIterator& currIter, Color8888* currBuffer, 235b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int currStride, const WebPIterator& prevIter, const Color8888* prevBuffer, int prevStride) { 236b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* dst = currBuffer + currIter.x_offset + currIter.y_offset * currStride; 237b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mDecoderConfig.output.u.RGBA.rgba = (uint8_t*)dst; 238b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mDecoderConfig.output.u.RGBA.stride = currStride * 4; 239b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi mDecoderConfig.output.u.RGBA.size = mDecoderConfig.output.u.RGBA.stride * currIter.height; 240b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 241b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const WebPData& currFrame = currIter.fragment; 242b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (WebPDecode(currFrame.bytes, currFrame.size, &mDecoderConfig) != VP8_STATUS_OK) { 243b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return false; 244b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 245b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 246b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasWidth = mFrameSequence.getWidth(); 247b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasHeight = mFrameSequence.getHeight(); 248b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const bool currFrameIsKeyFrame = mFrameSequence.isKeyFrame(currIter.frame_num - 1); 249b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // During the decoding of current frame, we may have set some pixels to be transparent 250b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // (i.e. alpha < 255). However, the value of each of these pixels should have been determined 251b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // by blending it against the value of that pixel in the previous frame if WEBP_MUX_BLEND was 252b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // specified. So, we correct these pixels based on disposal method of the previous frame and 253b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // the previous frame buffer. 254b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (currIter.blend_method == WEBP_MUX_BLEND && !currFrameIsKeyFrame) { 255b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (prevIter.dispose_method == WEBP_MUX_DISPOSE_NONE) { 256b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int y = 0; y < currIter.height; y++) { 257b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasY = currIter.y_offset + y; 258b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int x = 0; x < currIter.width; x++) { 259b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasX = currIter.x_offset + x; 260b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888& currPixel = currBuffer[canvasY * currStride + canvasX]; 261b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // FIXME: Use alpha-blending when alpha is between 0 and 255. 262b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (!(currPixel & COLOR_8888_ALPHA_MASK)) { 263b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const Color8888 prevPixel = prevBuffer[canvasY * prevStride + canvasX]; 264b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi currPixel = prevPixel; 265b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 266b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 267b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 268b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } else { // prevIter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND 269b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Need to restore transparent pixels to as they were just after frame initialization. 270b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // That is: 271b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // * Transparent if it belongs to previous frame rectangle <-- This is a no-op. 272b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // * Pixel in the previous canvas otherwise <-- Need to restore. 273b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int y = 0; y < currIter.height; y++) { 274b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasY = currIter.y_offset + y; 275b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int x = 0; x < currIter.width; x++) { 276b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasX = currIter.x_offset + x; 277b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888& currPixel = currBuffer[canvasY * currStride + canvasX]; 278b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // FIXME: Use alpha-blending when alpha is between 0 and 255. 2799b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi if (!(currPixel & COLOR_8888_ALPHA_MASK) 2809b38510c08561d2c71cc2aa2ea5432e46d27e82fUrvang Joshi && !FrameContainsPixel(prevIter, canvasX, canvasY)) { 281b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const Color8888 prevPixel = prevBuffer[canvasY * prevStride + canvasX]; 282b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi currPixel = prevPixel; 283b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 284b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 285b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 286b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 287b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 288b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return true; 289b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 290b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 291b34f1da83570613bb349f8026d4325552ac495edUrvang Joshilong FrameSequenceState_webp::drawFrame(int frameNr, 292b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* outputPtr, int outputPixelStride, int previousFrameNr) { 293b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPDemuxer* demux = mFrameSequence.getDemuxer(); 294b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOG_ASSERT(demux, "Cannot drawFrame, mDemux is NULL"); 295b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 296b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#if WEBP_DEBUG 297b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGD(" drawFrame called for frame# %d, previous frame# %d", frameNr, previousFrameNr); 298b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#endif 299b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 300b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasWidth = mFrameSequence.getWidth(); 301b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int canvasHeight = mFrameSequence.getHeight(); 302b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 303b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Find the first frame to be decoded. 304b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int start = max(previousFrameNr + 1, 0); 305b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int earliestRequired = frameNr; 306b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi while (earliestRequired > start) { 307b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (mFrameSequence.isKeyFrame(earliestRequired)) { 308b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi start = earliestRequired; 309b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi break; 310b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 311b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi earliestRequired--; 312b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 313b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 314b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPIterator currIter; 315b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPIterator prevIter; 316b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int ok = WebPDemuxGetFrame(demux, start, &currIter); // Get frame number 'start - 1'. 317b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOG_ASSERT(ok, "Could not retrieve frame# %d", start - 1); 318b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 319b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Use preserve buffer only if needed. 320b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* prevBuffer = (frameNr == 0) ? outputPtr : mPreservedBuffer; 321b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int prevStride = (frameNr == 0) ? outputPixelStride : canvasWidth; 322b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* currBuffer = outputPtr; 323b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int currStride = outputPixelStride; 324b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 325b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi for (int i = start; i <= frameNr; i++) { 326b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi prevIter = currIter; 327b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ok = WebPDemuxGetFrame(demux, i + 1, &currIter); // Get ith frame. 328b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOG_ASSERT(ok, "Could not retrieve frame# %d", i); 329b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#if WEBP_DEBUG 330b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGD(" producing frame %d (has_alpha = %d, dispose = %s, blend = %s, duration = %d)", 331b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi i, currIter.has_alpha, 332b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi (currIter.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none" : "background", 333b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi (currIter.blend_method == WEBP_MUX_BLEND) ? "yes" : "no", currIter.duration); 334b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#endif 335b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // We swap the prev/curr buffers as we go. 336b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi Color8888* tmpBuffer = prevBuffer; 337b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi prevBuffer = currBuffer; 338b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi currBuffer = tmpBuffer; 339b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 340b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi int tmpStride = prevStride; 341b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi prevStride = currStride; 342b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi currStride = tmpStride; 343b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 344b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#if WEBP_DEBUG 345b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGD(" prev = %p, curr = %p, out = %p, tmp = %p", 346b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi prevBuffer, currBuffer, outputPtr, mPreservedBuffer); 347b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#endif 348b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Process this frame. 349b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi initializeFrame(currIter, currBuffer, currStride, prevIter, prevBuffer, prevStride); 350b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 351b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (i == frameNr || !willBeCleared(currIter)) { 352b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (!decodeFrame(currIter, currBuffer, currStride, prevIter, prevBuffer, prevStride)) { 353b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOGE("Error decoding frame# %d", i); 354b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return -1; 355b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 356b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 357b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 358b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 359b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi if (outputPtr != currBuffer) { 360b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi copyFrame(currBuffer, currStride, outputPtr, outputPixelStride, canvasWidth, canvasHeight); 361b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi } 362b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 363b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi // Return last frame's delay. 364b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int frameCount = mFrameSequence.getFrameCount(); 365b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int lastFrame = (frameNr + frameCount - 1) % frameCount; 366b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ok = WebPDemuxGetFrame(demux, lastFrame, &currIter); 367b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi ALOG_ASSERT(ok, "Could not retrieve frame# %d", lastFrame - 1); 368b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const int lastFrameDelay = currIter.duration; 369b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 370b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPDemuxReleaseIterator(&currIter); 371b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi WebPDemuxReleaseIterator(&prevIter); 372b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 373b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return lastFrameDelay; 374b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 375b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 376b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 377b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi// Registry 378b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi//////////////////////////////////////////////////////////////////////////////// 379b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 380b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi#include "Registry.h" 381b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 382b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic bool isWebP(void* header, int header_size) { 383b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi const uint8_t* const header_str = (const uint8_t*)header; 384b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return (header_size >= RIFF_HEADER_SIZE) && 385b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi !memcmp("RIFF", header_str, 4) && 386b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi !memcmp("WEBP", header_str + 8, 4); 387b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 388b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 3896a61141137c7a46d747aa611c9caf62436bc119fChris Craikstatic bool acceptsWebPBuffer() { 3906a61141137c7a46d747aa611c9caf62436bc119fChris Craik return true; 3916a61141137c7a46d747aa611c9caf62436bc119fChris Craik} 3926a61141137c7a46d747aa611c9caf62436bc119fChris Craik 393b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic FrameSequence* createFramesequence(Stream* stream) { 394b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi return new FrameSequence_webp(stream); 395b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi} 396b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 397b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic RegistryEntry gEntry = { 398b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi RIFF_HEADER_SIZE, 399b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi isWebP, 400b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi createFramesequence, 401b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi NULL, 4026a61141137c7a46d747aa611c9caf62436bc119fChris Craik acceptsWebPBuffer, 403b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi}; 404b34f1da83570613bb349f8026d4325552ac495edUrvang Joshistatic Registry gRegister(gEntry); 405b34f1da83570613bb349f8026d4325552ac495edUrvang Joshi 406