OLD | NEW |
1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // Incremental decoding | 10 // Incremental decoding |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 } MemBuffer; | 63 } MemBuffer; |
64 | 64 |
65 struct WebPIDecoder { | 65 struct WebPIDecoder { |
66 DecState state_; // current decoding state | 66 DecState state_; // current decoding state |
67 WebPDecParams params_; // Params to store output info | 67 WebPDecParams params_; // Params to store output info |
68 int is_lossless_; // for down-casting 'dec_'. | 68 int is_lossless_; // for down-casting 'dec_'. |
69 void* dec_; // either a VP8Decoder or a VP8LDecoder instance | 69 void* dec_; // either a VP8Decoder or a VP8LDecoder instance |
70 VP8Io io_; | 70 VP8Io io_; |
71 | 71 |
72 MemBuffer mem_; // input memory buffer. | 72 MemBuffer mem_; // input memory buffer. |
73 WebPDecBuffer output_; // output buffer (when no external one is supplied) | 73 WebPDecBuffer output_; // output buffer (when no external one is supplied, |
| 74 // or if the external one has slow-memory) |
| 75 WebPDecBuffer* final_output_; // Slow-memory output to copy to eventually. |
74 size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. | 76 size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. |
75 | 77 |
76 int last_mb_y_; // last row reached for intra-mode decoding | 78 int last_mb_y_; // last row reached for intra-mode decoding |
77 }; | 79 }; |
78 | 80 |
79 // MB context to restore in case VP8DecodeMB() fails | 81 // MB context to restore in case VP8DecodeMB() fails |
80 typedef struct { | 82 typedef struct { |
81 VP8MB left_; | 83 VP8MB left_; |
82 VP8MB info_; | 84 VP8MB info_; |
83 VP8BitReader token_br_; | 85 VP8BitReader token_br_; |
(...skipping 27 matching lines...) Expand all Loading... |
111 MemBuffer* const mem = &idec->mem_; | 113 MemBuffer* const mem = &idec->mem_; |
112 const uint8_t* const new_base = mem->buf_ + mem->start_; | 114 const uint8_t* const new_base = mem->buf_ + mem->start_; |
113 // note: for VP8, setting up idec->io_ is only really needed at the beginning | 115 // note: for VP8, setting up idec->io_ is only really needed at the beginning |
114 // of the decoding, till partition #0 is complete. | 116 // of the decoding, till partition #0 is complete. |
115 idec->io_.data = new_base; | 117 idec->io_.data = new_base; |
116 idec->io_.data_size = MemDataSize(mem); | 118 idec->io_.data_size = MemDataSize(mem); |
117 | 119 |
118 if (idec->dec_ != NULL) { | 120 if (idec->dec_ != NULL) { |
119 if (!idec->is_lossless_) { | 121 if (!idec->is_lossless_) { |
120 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; | 122 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
121 const int last_part = dec->num_parts_ - 1; | 123 const uint32_t last_part = dec->num_parts_minus_one_; |
122 if (offset != 0) { | 124 if (offset != 0) { |
123 int p; | 125 uint32_t p; |
124 for (p = 0; p <= last_part; ++p) { | 126 for (p = 0; p <= last_part; ++p) { |
125 VP8RemapBitReader(dec->parts_ + p, offset); | 127 VP8RemapBitReader(dec->parts_ + p, offset); |
126 } | 128 } |
127 // Remap partition #0 data pointer to new offset, but only in MAP | 129 // Remap partition #0 data pointer to new offset, but only in MAP |
128 // mode (in APPEND mode, partition #0 is copied into a fixed memory). | 130 // mode (in APPEND mode, partition #0 is copied into a fixed memory). |
129 if (mem->mode_ == MEM_MODE_MAP) { | 131 if (mem->mode_ == MEM_MODE_MAP) { |
130 VP8RemapBitReader(&dec->br_, offset); | 132 VP8RemapBitReader(&dec->br_, offset); |
131 } | 133 } |
132 } | 134 } |
133 { | 135 { |
134 const uint8_t* const last_start = dec->parts_[last_part].buf_; | 136 const uint8_t* const last_start = dec->parts_[last_part].buf_; |
135 assert(last_part >= 0); | |
136 VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start, | 137 VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start, |
137 mem->buf_ + mem->end_ - last_start); | 138 mem->buf_ + mem->end_ - last_start); |
138 } | 139 } |
139 if (NeedCompressedAlpha(idec)) { | 140 if (NeedCompressedAlpha(idec)) { |
140 ALPHDecoder* const alph_dec = dec->alph_dec_; | 141 ALPHDecoder* const alph_dec = dec->alph_dec_; |
141 dec->alpha_data_ += offset; | 142 dec->alpha_data_ += offset; |
142 if (alph_dec != NULL) { | 143 if (alph_dec != NULL) { |
143 if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { | 144 if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { |
144 VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; | 145 VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; |
145 assert(alph_vp8l_dec != NULL); | 146 assert(alph_vp8l_dec != NULL); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 return 1; | 243 return 1; |
243 } | 244 } |
244 | 245 |
245 // To be called last. | 246 // To be called last. |
246 static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { | 247 static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { |
247 const WebPDecoderOptions* const options = idec->params_.options; | 248 const WebPDecoderOptions* const options = idec->params_.options; |
248 WebPDecBuffer* const output = idec->params_.output; | 249 WebPDecBuffer* const output = idec->params_.output; |
249 | 250 |
250 idec->state_ = STATE_DONE; | 251 idec->state_ = STATE_DONE; |
251 if (options != NULL && options->flip) { | 252 if (options != NULL && options->flip) { |
252 return WebPFlipBuffer(output); | 253 const VP8StatusCode status = WebPFlipBuffer(output); |
253 } else { | 254 if (status != VP8_STATUS_OK) return status; |
254 return VP8_STATUS_OK; | |
255 } | 255 } |
| 256 if (idec->final_output_ != NULL) { |
| 257 WebPCopyDecBufferPixels(output, idec->final_output_); // do the slow-copy |
| 258 WebPFreeDecBuffer(&idec->output_); |
| 259 *output = *idec->final_output_; |
| 260 idec->final_output_ = NULL; |
| 261 } |
| 262 return VP8_STATUS_OK; |
256 } | 263 } |
257 | 264 |
258 //------------------------------------------------------------------------------ | 265 //------------------------------------------------------------------------------ |
259 // Macroblock-decoding contexts | 266 // Macroblock-decoding contexts |
260 | 267 |
261 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, | 268 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, |
262 MBContext* const context) { | 269 MBContext* const context) { |
263 context->left_ = dec->mb_info_[-1]; | 270 context->left_ = dec->mb_info_[-1]; |
264 context->info_ = dec->mb_info_[dec->mb_x_]; | 271 context->info_ = dec->mb_info_[dec->mb_x_]; |
265 context->token_br_ = *token_br; | 272 context->token_br_ = *token_br; |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 if (!VP8ParseIntraModeRow(&dec->br_, dec)) { | 457 if (!VP8ParseIntraModeRow(&dec->br_, dec)) { |
451 // note: normally, error shouldn't occur since we already have the whole | 458 // note: normally, error shouldn't occur since we already have the whole |
452 // partition0 available here in DecodeRemaining(). Reaching EOF while | 459 // partition0 available here in DecodeRemaining(). Reaching EOF while |
453 // reading intra modes really means a BITSTREAM_ERROR. | 460 // reading intra modes really means a BITSTREAM_ERROR. |
454 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); | 461 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); |
455 } | 462 } |
456 idec->last_mb_y_ = dec->mb_y_; | 463 idec->last_mb_y_ = dec->mb_y_; |
457 } | 464 } |
458 for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { | 465 for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { |
459 VP8BitReader* const token_br = | 466 VP8BitReader* const token_br = |
460 &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; | 467 &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; |
461 MBContext context; | 468 MBContext context; |
462 SaveContext(dec, token_br, &context); | 469 SaveContext(dec, token_br, &context); |
463 if (!VP8DecodeMB(dec, token_br)) { | 470 if (!VP8DecodeMB(dec, token_br)) { |
464 // We shouldn't fail when MAX_MB data was available | 471 // We shouldn't fail when MAX_MB data was available |
465 if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) { | 472 if (dec->num_parts_minus_one_ == 0 && |
| 473 MemDataSize(&idec->mem_) > MAX_MB_SIZE) { |
466 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); | 474 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); |
467 } | 475 } |
468 RestoreContext(&context, dec, token_br); | 476 RestoreContext(&context, dec, token_br); |
469 return VP8_STATUS_SUSPENDED; | 477 return VP8_STATUS_SUSPENDED; |
470 } | 478 } |
471 // Release buffer only if there is only one partition | 479 // Release buffer only if there is only one partition |
472 if (dec->num_parts_ == 1) { | 480 if (dec->num_parts_minus_one_ == 0) { |
473 idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; | 481 idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; |
474 assert(idec->mem_.start_ <= idec->mem_.end_); | 482 assert(idec->mem_.start_ <= idec->mem_.end_); |
475 } | 483 } |
476 } | 484 } |
477 VP8InitScanline(dec); // Prepare for next scanline | 485 VP8InitScanline(dec); // Prepare for next scanline |
478 | 486 |
479 // Reconstruct, filter and emit the row. | 487 // Reconstruct, filter and emit the row. |
480 if (!VP8ProcessRow(dec, io)) { | 488 if (!VP8ProcessRow(dec, io)) { |
481 return IDecError(idec, VP8_STATUS_USER_ABORT); | 489 return IDecError(idec, VP8_STATUS_USER_ABORT); |
482 } | 490 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 if (idec->state_ == STATE_VP8L_HEADER) { | 576 if (idec->state_ == STATE_VP8L_HEADER) { |
569 status = DecodeVP8LHeader(idec); | 577 status = DecodeVP8LHeader(idec); |
570 } | 578 } |
571 if (idec->state_ == STATE_VP8L_DATA) { | 579 if (idec->state_ == STATE_VP8L_DATA) { |
572 status = DecodeVP8LData(idec); | 580 status = DecodeVP8LData(idec); |
573 } | 581 } |
574 return status; | 582 return status; |
575 } | 583 } |
576 | 584 |
577 //------------------------------------------------------------------------------ | 585 //------------------------------------------------------------------------------ |
578 // Public functions | 586 // Internal constructor |
579 | 587 |
580 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { | 588 static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer, |
| 589 const WebPBitstreamFeatures* const features) { |
581 WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec)); | 590 WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec)); |
582 if (idec == NULL) { | 591 if (idec == NULL) { |
583 return NULL; | 592 return NULL; |
584 } | 593 } |
585 | 594 |
586 idec->state_ = STATE_WEBP_HEADER; | 595 idec->state_ = STATE_WEBP_HEADER; |
587 idec->chunk_size_ = 0; | 596 idec->chunk_size_ = 0; |
588 | 597 |
589 idec->last_mb_y_ = -1; | 598 idec->last_mb_y_ = -1; |
590 | 599 |
591 InitMemBuffer(&idec->mem_); | 600 InitMemBuffer(&idec->mem_); |
592 WebPInitDecBuffer(&idec->output_); | 601 WebPInitDecBuffer(&idec->output_); |
593 VP8InitIo(&idec->io_); | 602 VP8InitIo(&idec->io_); |
594 | 603 |
595 WebPResetDecParams(&idec->params_); | 604 WebPResetDecParams(&idec->params_); |
596 idec->params_.output = (output_buffer != NULL) ? output_buffer | 605 if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) { |
597 : &idec->output_; | 606 idec->params_.output = &idec->output_; |
| 607 idec->final_output_ = output_buffer; |
| 608 if (output_buffer != NULL) { |
| 609 idec->params_.output->colorspace = output_buffer->colorspace; |
| 610 } |
| 611 } else { |
| 612 idec->params_.output = output_buffer; |
| 613 idec->final_output_ = NULL; |
| 614 } |
598 WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. | 615 WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. |
599 | 616 |
600 return idec; | 617 return idec; |
601 } | 618 } |
602 | 619 |
| 620 //------------------------------------------------------------------------------ |
| 621 // Public functions |
| 622 |
| 623 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { |
| 624 return NewDecoder(output_buffer, NULL); |
| 625 } |
| 626 |
603 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, | 627 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, |
604 WebPDecoderConfig* config) { | 628 WebPDecoderConfig* config) { |
605 WebPIDecoder* idec; | 629 WebPIDecoder* idec; |
| 630 WebPBitstreamFeatures tmp_features; |
| 631 WebPBitstreamFeatures* const features = |
| 632 (config == NULL) ? &tmp_features : &config->input; |
| 633 memset(&tmp_features, 0, sizeof(tmp_features)); |
606 | 634 |
607 // Parse the bitstream's features, if requested: | 635 // Parse the bitstream's features, if requested: |
608 if (data != NULL && data_size > 0 && config != NULL) { | 636 if (data != NULL && data_size > 0) { |
609 if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) { | 637 if (WebPGetFeatures(data, data_size, features) != VP8_STATUS_OK) { |
610 return NULL; | 638 return NULL; |
611 } | 639 } |
612 } | 640 } |
| 641 |
613 // Create an instance of the incremental decoder | 642 // Create an instance of the incremental decoder |
614 idec = WebPINewDecoder(config ? &config->output : NULL); | 643 idec = (config != NULL) ? NewDecoder(&config->output, features) |
| 644 : NewDecoder(NULL, features); |
615 if (idec == NULL) { | 645 if (idec == NULL) { |
616 return NULL; | 646 return NULL; |
617 } | 647 } |
618 // Finish initialization | 648 // Finish initialization |
619 if (config != NULL) { | 649 if (config != NULL) { |
620 idec->params_.options = &config->options; | 650 idec->params_.options = &config->options; |
621 } | 651 } |
622 return idec; | 652 return idec; |
623 } | 653 } |
624 | 654 |
(...skipping 13 matching lines...) Expand all Loading... |
638 ClearMemBuffer(&idec->mem_); | 668 ClearMemBuffer(&idec->mem_); |
639 WebPFreeDecBuffer(&idec->output_); | 669 WebPFreeDecBuffer(&idec->output_); |
640 WebPSafeFree(idec); | 670 WebPSafeFree(idec); |
641 } | 671 } |
642 | 672 |
643 //------------------------------------------------------------------------------ | 673 //------------------------------------------------------------------------------ |
644 // Wrapper toward WebPINewDecoder | 674 // Wrapper toward WebPINewDecoder |
645 | 675 |
646 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer, | 676 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer, |
647 size_t output_buffer_size, int output_stride) { | 677 size_t output_buffer_size, int output_stride) { |
648 const int is_external_memory = (output_buffer != NULL); | 678 const int is_external_memory = (output_buffer != NULL) ? 1 : 0; |
649 WebPIDecoder* idec; | 679 WebPIDecoder* idec; |
650 | 680 |
651 if (mode >= MODE_YUV) return NULL; | 681 if (mode >= MODE_YUV) return NULL; |
652 if (!is_external_memory) { // Overwrite parameters to sane values. | 682 if (is_external_memory == 0) { // Overwrite parameters to sane values. |
653 output_buffer_size = 0; | 683 output_buffer_size = 0; |
654 output_stride = 0; | 684 output_stride = 0; |
655 } else { // A buffer was passed. Validate the other params. | 685 } else { // A buffer was passed. Validate the other params. |
656 if (output_stride == 0 || output_buffer_size == 0) { | 686 if (output_stride == 0 || output_buffer_size == 0) { |
657 return NULL; // invalid parameter. | 687 return NULL; // invalid parameter. |
658 } | 688 } |
659 } | 689 } |
660 idec = WebPINewDecoder(NULL); | 690 idec = WebPINewDecoder(NULL); |
661 if (idec == NULL) return NULL; | 691 if (idec == NULL) return NULL; |
662 idec->output_.colorspace = mode; | 692 idec->output_.colorspace = mode; |
663 idec->output_.is_external_memory = is_external_memory; | 693 idec->output_.is_external_memory = is_external_memory; |
664 idec->output_.u.RGBA.rgba = output_buffer; | 694 idec->output_.u.RGBA.rgba = output_buffer; |
665 idec->output_.u.RGBA.stride = output_stride; | 695 idec->output_.u.RGBA.stride = output_stride; |
666 idec->output_.u.RGBA.size = output_buffer_size; | 696 idec->output_.u.RGBA.size = output_buffer_size; |
667 return idec; | 697 return idec; |
668 } | 698 } |
669 | 699 |
670 WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, | 700 WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, |
671 uint8_t* u, size_t u_size, int u_stride, | 701 uint8_t* u, size_t u_size, int u_stride, |
672 uint8_t* v, size_t v_size, int v_stride, | 702 uint8_t* v, size_t v_size, int v_stride, |
673 uint8_t* a, size_t a_size, int a_stride) { | 703 uint8_t* a, size_t a_size, int a_stride) { |
674 const int is_external_memory = (luma != NULL); | 704 const int is_external_memory = (luma != NULL) ? 1 : 0; |
675 WebPIDecoder* idec; | 705 WebPIDecoder* idec; |
676 WEBP_CSP_MODE colorspace; | 706 WEBP_CSP_MODE colorspace; |
677 | 707 |
678 if (!is_external_memory) { // Overwrite parameters to sane values. | 708 if (is_external_memory == 0) { // Overwrite parameters to sane values. |
679 luma_size = u_size = v_size = a_size = 0; | 709 luma_size = u_size = v_size = a_size = 0; |
680 luma_stride = u_stride = v_stride = a_stride = 0; | 710 luma_stride = u_stride = v_stride = a_stride = 0; |
681 u = v = a = NULL; | 711 u = v = a = NULL; |
682 colorspace = MODE_YUVA; | 712 colorspace = MODE_YUVA; |
683 } else { // A luma buffer was passed. Validate the other parameters. | 713 } else { // A luma buffer was passed. Validate the other parameters. |
684 if (u == NULL || v == NULL) return NULL; | 714 if (u == NULL || v == NULL) return NULL; |
685 if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL; | 715 if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL; |
686 if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL; | 716 if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL; |
687 if (a != NULL) { | 717 if (a != NULL) { |
688 if (a_size == 0 || a_stride == 0) return NULL; | 718 if (a_size == 0 || a_stride == 0) return NULL; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 | 806 |
777 //------------------------------------------------------------------------------ | 807 //------------------------------------------------------------------------------ |
778 | 808 |
779 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { | 809 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { |
780 if (idec == NULL || idec->dec_ == NULL) { | 810 if (idec == NULL || idec->dec_ == NULL) { |
781 return NULL; | 811 return NULL; |
782 } | 812 } |
783 if (idec->state_ <= STATE_VP8_PARTS0) { | 813 if (idec->state_ <= STATE_VP8_PARTS0) { |
784 return NULL; | 814 return NULL; |
785 } | 815 } |
| 816 if (idec->final_output_ != NULL) { |
| 817 return NULL; // not yet slow-copied |
| 818 } |
786 return idec->params_.output; | 819 return idec->params_.output; |
787 } | 820 } |
788 | 821 |
789 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, | 822 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, |
790 int* left, int* top, | 823 int* left, int* top, |
791 int* width, int* height) { | 824 int* width, int* height) { |
792 const WebPDecBuffer* const src = GetOutputBuffer(idec); | 825 const WebPDecBuffer* const src = GetOutputBuffer(idec); |
793 if (left != NULL) *left = 0; | 826 if (left != NULL) *left = 0; |
794 if (top != NULL) *top = 0; | 827 if (top != NULL) *top = 0; |
795 if (src) { | 828 if (src != NULL) { |
796 if (width != NULL) *width = src->width; | 829 if (width != NULL) *width = src->width; |
797 if (height != NULL) *height = idec->params_.last_y; | 830 if (height != NULL) *height = idec->params_.last_y; |
798 } else { | 831 } else { |
799 if (width != NULL) *width = 0; | 832 if (width != NULL) *width = 0; |
800 if (height != NULL) *height = 0; | 833 if (height != NULL) *height = 0; |
801 } | 834 } |
802 return src; | 835 return src; |
803 } | 836 } |
804 | 837 |
805 uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y, | 838 uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 return 0; | 883 return 0; |
851 } | 884 } |
852 | 885 |
853 idec->io_.put = put; | 886 idec->io_.put = put; |
854 idec->io_.setup = setup; | 887 idec->io_.setup = setup; |
855 idec->io_.teardown = teardown; | 888 idec->io_.teardown = teardown; |
856 idec->io_.opaque = user_data; | 889 idec->io_.opaque = user_data; |
857 | 890 |
858 return 1; | 891 return 1; |
859 } | 892 } |
OLD | NEW |