| OLD | NEW |
| 1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // This code is licensed under the same terms as WebM: | 3 // Use of this source code is governed by a BSD-style license |
| 4 // Software License Agreement: http://www.webmproject.org/license/software/ | 4 // that can be found in the COPYING file in the root of the source |
| 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. |
| 6 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 7 // | 9 // |
| 8 // Incremental decoding | 10 // Incremental decoding |
| 9 // | 11 // |
| 10 // Author: somnath@google.com (Somnath Banerjee) | 12 // Author: somnath@google.com (Somnath Banerjee) |
| 11 | 13 |
| 12 #include <assert.h> | 14 #include <assert.h> |
| 13 #include <string.h> | 15 #include <string.h> |
| 14 #include <stdlib.h> | 16 #include <stdlib.h> |
| 15 | 17 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 if (br->buf_ != NULL) { | 92 if (br->buf_ != NULL) { |
| 91 br->buf_ += offset; | 93 br->buf_ += offset; |
| 92 br->buf_end_ += offset; | 94 br->buf_end_ += offset; |
| 93 } | 95 } |
| 94 } | 96 } |
| 95 | 97 |
| 96 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { | 98 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { |
| 97 return (mem->end_ - mem->start_); | 99 return (mem->end_ - mem->start_); |
| 98 } | 100 } |
| 99 | 101 |
| 102 // Check if we need to preserve the compressed alpha data, as it may not have |
| 103 // been decoded yet. |
| 104 static int NeedCompressedAlpha(const WebPIDecoder* const idec) { |
| 105 if (idec->state_ == STATE_PRE_VP8) { |
| 106 // We haven't parsed the headers yet, so we don't know whether the image is |
| 107 // lossy or lossless. This also means that we haven't parsed the ALPH chunk. |
| 108 return 0; |
| 109 } |
| 110 if (idec->is_lossless_) { |
| 111 return 0; // ALPH chunk is not present for lossless images. |
| 112 } else { |
| 113 const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 114 assert(dec != NULL); // Must be true as idec->state_ != STATE_PRE_VP8. |
| 115 return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_; |
| 116 } |
| 117 } |
| 118 |
| 100 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { | 119 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { |
| 101 MemBuffer* const mem = &idec->mem_; | 120 MemBuffer* const mem = &idec->mem_; |
| 102 const uint8_t* const new_base = mem->buf_ + mem->start_; | 121 const uint8_t* const new_base = mem->buf_ + mem->start_; |
| 103 // note: for VP8, setting up idec->io_ is only really needed at the beginning | 122 // note: for VP8, setting up idec->io_ is only really needed at the beginning |
| 104 // of the decoding, till partition #0 is complete. | 123 // of the decoding, till partition #0 is complete. |
| 105 idec->io_.data = new_base; | 124 idec->io_.data = new_base; |
| 106 idec->io_.data_size = MemDataSize(mem); | 125 idec->io_.data_size = MemDataSize(mem); |
| 107 | 126 |
| 108 if (idec->dec_ != NULL) { | 127 if (idec->dec_ != NULL) { |
| 109 if (!idec->is_lossless_) { | 128 if (!idec->is_lossless_) { |
| 110 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; | 129 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 111 const int last_part = dec->num_parts_ - 1; | 130 const int last_part = dec->num_parts_ - 1; |
| 112 if (offset != 0) { | 131 if (offset != 0) { |
| 113 int p; | 132 int p; |
| 114 for (p = 0; p <= last_part; ++p) { | 133 for (p = 0; p <= last_part; ++p) { |
| 115 RemapBitReader(dec->parts_ + p, offset); | 134 RemapBitReader(dec->parts_ + p, offset); |
| 116 } | 135 } |
| 117 // Remap partition #0 data pointer to new offset, but only in MAP | 136 // Remap partition #0 data pointer to new offset, but only in MAP |
| 118 // mode (in APPEND mode, partition #0 is copied into a fixed memory). | 137 // mode (in APPEND mode, partition #0 is copied into a fixed memory). |
| 119 if (mem->mode_ == MEM_MODE_MAP) { | 138 if (mem->mode_ == MEM_MODE_MAP) { |
| 120 RemapBitReader(&dec->br_, offset); | 139 RemapBitReader(&dec->br_, offset); |
| 121 } | 140 } |
| 122 } | 141 } |
| 123 assert(last_part >= 0); | 142 assert(last_part >= 0); |
| 124 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_; | 143 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_; |
| 144 if (NeedCompressedAlpha(idec)) dec->alpha_data_ += offset; |
| 125 } else { // Resize lossless bitreader | 145 } else { // Resize lossless bitreader |
| 126 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; | 146 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; |
| 127 VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); | 147 VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); |
| 128 } | 148 } |
| 129 } | 149 } |
| 130 } | 150 } |
| 131 | 151 |
| 132 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory | 152 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory |
| 133 // size if required and also updates VP8BitReader's if new memory is allocated. | 153 // size if required and also updates VP8BitReader's if new memory is allocated. |
| 134 static int AppendToMemBuffer(WebPIDecoder* const idec, | 154 static int AppendToMemBuffer(WebPIDecoder* const idec, |
| 135 const uint8_t* const data, size_t data_size) { | 155 const uint8_t* const data, size_t data_size) { |
| 156 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 136 MemBuffer* const mem = &idec->mem_; | 157 MemBuffer* const mem = &idec->mem_; |
| 137 const uint8_t* const old_base = mem->buf_ + mem->start_; | 158 const int need_compressed_alpha = NeedCompressedAlpha(idec); |
| 159 const uint8_t* const old_start = mem->buf_ + mem->start_; |
| 160 const uint8_t* const old_base = |
| 161 need_compressed_alpha ? dec->alpha_data_ : old_start; |
| 138 assert(mem->mode_ == MEM_MODE_APPEND); | 162 assert(mem->mode_ == MEM_MODE_APPEND); |
| 139 if (data_size > MAX_CHUNK_PAYLOAD) { | 163 if (data_size > MAX_CHUNK_PAYLOAD) { |
| 140 // security safeguard: trying to allocate more than what the format | 164 // security safeguard: trying to allocate more than what the format |
| 141 // allows for a chunk should be considered a smoke smell. | 165 // allows for a chunk should be considered a smoke smell. |
| 142 return 0; | 166 return 0; |
| 143 } | 167 } |
| 144 | 168 |
| 145 if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory | 169 if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory |
| 146 const size_t current_size = MemDataSize(mem); | 170 const size_t new_mem_start = old_start - old_base; |
| 171 const size_t current_size = MemDataSize(mem) + new_mem_start; |
| 147 const uint64_t new_size = (uint64_t)current_size + data_size; | 172 const uint64_t new_size = (uint64_t)current_size + data_size; |
| 148 const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1); | 173 const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1); |
| 149 uint8_t* const new_buf = | 174 uint8_t* const new_buf = |
| 150 (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); | 175 (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); |
| 151 if (new_buf == NULL) return 0; | 176 if (new_buf == NULL) return 0; |
| 152 memcpy(new_buf, old_base, current_size); | 177 memcpy(new_buf, old_base, current_size); |
| 153 free(mem->buf_); | 178 free(mem->buf_); |
| 154 mem->buf_ = new_buf; | 179 mem->buf_ = new_buf; |
| 155 mem->buf_size_ = (size_t)extra_size; | 180 mem->buf_size_ = (size_t)extra_size; |
| 156 mem->start_ = 0; | 181 mem->start_ = new_mem_start; |
| 157 mem->end_ = current_size; | 182 mem->end_ = current_size; |
| 158 } | 183 } |
| 159 | 184 |
| 160 memcpy(mem->buf_ + mem->end_, data, data_size); | 185 memcpy(mem->buf_ + mem->end_, data, data_size); |
| 161 mem->end_ += data_size; | 186 mem->end_ += data_size; |
| 162 assert(mem->end_ <= mem->buf_size_); | 187 assert(mem->end_ <= mem->buf_size_); |
| 163 | 188 |
| 164 DoRemap(idec, mem->buf_ + mem->start_ - old_base); | 189 DoRemap(idec, mem->buf_ + mem->start_ - old_start); |
| 165 return 1; | 190 return 1; |
| 166 } | 191 } |
| 167 | 192 |
| 168 static int RemapMemBuffer(WebPIDecoder* const idec, | 193 static int RemapMemBuffer(WebPIDecoder* const idec, |
| 169 const uint8_t* const data, size_t data_size) { | 194 const uint8_t* const data, size_t data_size) { |
| 170 MemBuffer* const mem = &idec->mem_; | 195 MemBuffer* const mem = &idec->mem_; |
| 171 const uint8_t* const old_base = mem->buf_ + mem->start_; | 196 const uint8_t* const old_buf = mem->buf_; |
| 197 const uint8_t* const old_start = old_buf + mem->start_; |
| 172 assert(mem->mode_ == MEM_MODE_MAP); | 198 assert(mem->mode_ == MEM_MODE_MAP); |
| 173 | 199 |
| 174 if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! | 200 if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! |
| 175 | 201 |
| 176 mem->buf_ = (uint8_t*)data; | 202 mem->buf_ = (uint8_t*)data; |
| 177 mem->end_ = mem->buf_size_ = data_size; | 203 mem->end_ = mem->buf_size_ = data_size; |
| 178 | 204 |
| 179 DoRemap(idec, mem->buf_ + mem->start_ - old_base); | 205 DoRemap(idec, mem->buf_ + mem->start_ - old_start); |
| 180 return 1; | 206 return 1; |
| 181 } | 207 } |
| 182 | 208 |
| 183 static void InitMemBuffer(MemBuffer* const mem) { | 209 static void InitMemBuffer(MemBuffer* const mem) { |
| 184 mem->mode_ = MEM_MODE_NONE; | 210 mem->mode_ = MEM_MODE_NONE; |
| 185 mem->buf_ = NULL; | 211 mem->buf_ = NULL; |
| 186 mem->buf_size_ = 0; | 212 mem->buf_size_ = 0; |
| 187 mem->part0_buf_ = NULL; | 213 mem->part0_buf_ = NULL; |
| 188 mem->part0_size_ = 0; | 214 mem->part0_size_ = 0; |
| 189 } | 215 } |
| (...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 idec->io_.setup = setup; | 831 idec->io_.setup = setup; |
| 806 idec->io_.teardown = teardown; | 832 idec->io_.teardown = teardown; |
| 807 idec->io_.opaque = user_data; | 833 idec->io_.opaque = user_data; |
| 808 | 834 |
| 809 return 1; | 835 return 1; |
| 810 } | 836 } |
| 811 | 837 |
| 812 #if defined(__cplusplus) || defined(c_plusplus) | 838 #if defined(__cplusplus) || defined(c_plusplus) |
| 813 } // extern "C" | 839 } // extern "C" |
| 814 #endif | 840 #endif |
| OLD | NEW |