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