1a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Copyright 2011 Google Inc. All Rights Reserved.
27c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license
40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source
50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found
60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may
70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree.
87c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// -----------------------------------------------------------------------------
97c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
107c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// WebP encoder: main entry point
117c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
127c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Author: Skal (pascal.massimino@gmail.com)
137c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
14466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#include <assert.h>
157c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <stdlib.h>
167c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <string.h>
177c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <math.h>
187c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
19a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "./vp8enci.h"
20a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "./vp8li.h"
21a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../utils/utils.h"
227c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
237c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// #define PRINT_MEMORY_INFO
247c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
257c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#if defined(__cplusplus) || defined(c_plusplus)
267c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Aroraextern "C" {
277c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#endif
287c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
297c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#ifdef PRINT_MEMORY_INFO
307c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#include <stdio.h>
317c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#endif
327c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
33a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
347c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
357c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Aroraint WebPGetEncoderVersion(void) {
367c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION;
377c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
387c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
39a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
407c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// WebPPicture
41a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
427c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
437c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic int DummyWriter(const uint8_t* data, size_t data_size,
447c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                       const WebPPicture* const picture) {
457c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // The following are to prevent 'unused variable' error message.
467c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  (void)data;
477c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  (void)data_size;
487c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  (void)picture;
497c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return 1;
507c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
517c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
52a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPPictureInitInternal(WebPPicture* picture, int version) {
53a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
547c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    return 0;   // caller/system version mismatch!
557c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
56a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (picture != NULL) {
577c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    memset(picture, 0, sizeof(*picture));
587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    picture->writer = DummyWriter;
59466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    WebPEncodingSetError(picture, VP8_ENC_OK);
607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
617c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return 1;
627c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
637c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
64a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
657c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// VP8Encoder
66a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
687c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void ResetSegmentHeader(VP8Encoder* const enc) {
697c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8SegmentHeader* const hdr = &enc->segment_hdr_;
707c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->num_segments_ = enc->config_->segments;
717c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->update_map_  = (hdr->num_segments_ > 1);
727c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->size_ = 0;
737c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
747c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
757c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void ResetFilterHeader(VP8Encoder* const enc) {
767c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8FilterHeader* const hdr = &enc->filter_hdr_;
777c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->simple_ = 1;
787c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->level_ = 0;
797c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->sharpness_ = 0;
807c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  hdr->i4x4_lf_delta_ = 0;
817c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
827c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
837c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void ResetBoundaryPredictions(VP8Encoder* const enc) {
847c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // init boundary values once for all
857c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // Note: actually, initializing the preds_[] is only needed for intra4.
867c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  int i;
877c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  uint8_t* const top = enc->preds_ - enc->preds_w_;
887c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  uint8_t* const left = enc->preds_ - 1;
897c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (i = -1; i < 4 * enc->mb_w_; ++i) {
907c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    top[i] = B_DC_PRED;
917c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
927c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  for (i = 0; i < 4 * enc->mb_h_; ++i) {
937c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    left[i * enc->preds_w_] = B_DC_PRED;
947c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
957c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->nz_[-1] = 0;   // constant
967c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
977c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
981e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Mapping from config->method_ to coding tools used.
991e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1001e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   Method          | 0 | 1 | 2 | 3 |(4)| 5 | 6 |
1011e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1021e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// fast probe        | x |   |   | x |   |   |   |
1031e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1041e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// dynamic proba     | ~ | x | x | x | x | x | x |
1051e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1061e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// fast mode analysis|   |   |   |   | x | x | x |
1071e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1081e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// basic rd-opt      |   |   |   | x | x | x | x |
1091e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1101e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// disto-score i4/16 |   |   | x |   |   |   |   |
1111e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1121e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// rd-opt i4/16      |   |   | ~ | x | x | x | x |
1131e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1141e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// token buffer (opt)|   |   |   | x | x | x | x |
1151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Trellis           |   |   |   |   |   | x |Ful|
1171e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1181e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// full-SNS          |   |   |   |   | x | x | x |
1191e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//-------------------+---+---+---+---+---+---+---+
1207c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1217c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void MapConfigToTools(VP8Encoder* const enc) {
1221e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const WebPConfig* const config = enc->config_;
1231e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int method = config->method;
1241e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int limit = 100 - config->partition_limit;
1257c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->method_ = method;
1261e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL
1271e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                     : (method >= 5) ? RD_OPT_TRELLIS
1281e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                     : (method >= 3) ? RD_OPT_BASIC
1291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora                     : RD_OPT_NONE;
130a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  enc->max_i4_header_bits_ =
131a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      256 * 16 * 16 *                 // upper bound: up to 16bit per 4x4 block
132a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      (limit * limit) / (100 * 100);  // ... modulated with a quadratic curve.
1331e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1341e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  enc->thread_level_ = config->thread_level;
1351e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
1361e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0);
1371e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  if (!config->low_memory) {
1381e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#if !defined(DISABLE_TOKEN_BUFFER)
1391e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    enc->use_tokens_ = (method >= 3) && !enc->do_search_;
1401e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#endif
1411e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    if (enc->use_tokens_) {
1421e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora      enc->num_parts_ = 1;   // doesn't work with multi-partition
1431e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    }
1441e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  }
1457c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
1467c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1477c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Memory scaling with dimensions:
1487c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//  memory (bytes) ~= 2.25 * w + 0.0625 * w * h
1497c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//
1507c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Typical memory footprint (768x510 picture)
1517c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Memory used:
1527c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//              encoder: 33919
1537c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//          block cache: 2880
1547c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//                 info: 3072
1557c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//                preds: 24897
1567c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//          top samples: 1623
1577c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//             non-zero: 196
1587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//             lf-stats: 2048
1597c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//                total: 68635
1607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Transcient object sizes:
1617c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//       VP8EncIterator: 352
1627c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//         VP8ModeScore: 912
1637c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//       VP8SegmentInfo: 532
1647c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//             VP8Proba: 31032
1657c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora//              LFStats: 2048
1667c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora// Picture size (yuv): 589824
1677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
168a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
169a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                  WebPPicture* const picture) {
1707c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int use_filter =
1717c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      (config->filter_strength > 0) || (config->autofilter > 0);
1727c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int mb_w = (picture->width + 15) >> 4;
1737c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int mb_h = (picture->height + 15) >> 4;
1747c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int preds_w = 4 * mb_w + 1;
1757c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int preds_h = 4 * mb_h + 1;
1767c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const size_t preds_size = preds_w * preds_h * sizeof(uint8_t);
1777c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const int top_stride = mb_w * 16;
1787c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const size_t nz_size = (mb_w + 1) * sizeof(uint32_t);
1797c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const size_t cache_size = (3 * YUV_SIZE + PRED_SIZE) * sizeof(uint8_t);
1807c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const size_t info_size = mb_w * mb_h * sizeof(VP8MBInfo);
1817c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const size_t samples_size = (2 * top_stride +         // top-luma/u/v
1827c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                               16 + 16 + 16 + 8 + 1 +   // left y/u/v
1837c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                               2 * ALIGN_CST)           // align all
1847c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora                               * sizeof(uint8_t);
185466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  const size_t lf_stats_size =
186466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora      config->autofilter ? sizeof(LFStats) + ALIGN_CST : 0;
1877c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8Encoder* enc;
1887c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  uint8_t* mem;
189a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const uint64_t size = (uint64_t)sizeof(VP8Encoder)   // main struct
190a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + ALIGN_CST                      // cache alignment
191a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + cache_size                     // working caches
192a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + info_size                      // modes info
193a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + preds_size                     // prediction modes
194a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + samples_size                   // top/left samples
195a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + nz_size                        // coeff context bits
196a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                      + lf_stats_size;                 // autofilter stats
1977c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
1987c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#ifdef PRINT_MEMORY_INFO
1997c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  printf("===================================\n");
2007c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  printf("Memory used:\n"
2017c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "             encoder: %ld\n"
2027c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "         block cache: %ld\n"
2037c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "                info: %ld\n"
2047c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "               preds: %ld\n"
2057c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "         top samples: %ld\n"
2067c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "            non-zero: %ld\n"
2077c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "            lf-stats: %ld\n"
2087c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "               total: %ld\n",
2097c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         sizeof(VP8Encoder) + ALIGN_CST, cache_size, info_size,
2107c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         preds_size, samples_size, nz_size, lf_stats_size, size);
2117c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  printf("Transcient object sizes:\n"
2127c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "      VP8EncIterator: %ld\n"
2137c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "        VP8ModeScore: %ld\n"
2147c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "      VP8SegmentInfo: %ld\n"
2157c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "            VP8Proba: %ld\n"
2167c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         "             LFStats: %ld\n",
2177c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         sizeof(VP8EncIterator), sizeof(VP8ModeScore),
2187c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         sizeof(VP8SegmentInfo), sizeof(VP8Proba),
2197c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         sizeof(LFStats));
2207c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  printf("Picture size (yuv): %ld\n",
2217c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora         mb_w * mb_h * 384 * sizeof(uint8_t));
2227c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  printf("===================================\n");
2237c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#endif
224a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem));
225466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (mem == NULL) {
226466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
227466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return NULL;
228466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
2297c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc = (VP8Encoder*)mem;
2307c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc));
2317c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  memset(enc, 0, sizeof(*enc));
2327c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->num_parts_ = 1 << config->partitions;
2337c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->mb_w_ = mb_w;
2347c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->mb_h_ = mb_h;
2357c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->preds_w_ = preds_w;
2367c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->yuv_in_ = (uint8_t*)mem;
2377c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += YUV_SIZE;
2387c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->yuv_out_ = (uint8_t*)mem;
2397c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += YUV_SIZE;
2407c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->yuv_out2_ = (uint8_t*)mem;
2417c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += YUV_SIZE;
2427c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->yuv_p_ = (uint8_t*)mem;
2437c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += PRED_SIZE;
2447c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->mb_info_ = (VP8MBInfo*)mem;
2457c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += info_size;
2467c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->preds_ = ((uint8_t*)mem) + 1 + enc->preds_w_;
2477c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += preds_w * preds_h * sizeof(uint8_t);
2487c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->nz_ = 1 + (uint32_t*)mem;
2497c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += nz_size;
250466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  enc->lf_stats_ = lf_stats_size ? (LFStats*)DO_ALIGN(mem) : NULL;
2517c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += lf_stats_size;
2527c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2537c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  // top samples (all 16-aligned)
2547c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem = (uint8_t*)DO_ALIGN(mem);
2557c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->y_top_ = (uint8_t*)mem;
2567c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->uv_top_ = enc->y_top_ + top_stride;
2577c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += 2 * top_stride;
2587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem = (uint8_t*)DO_ALIGN(mem + 1);
2597c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->y_left_ = (uint8_t*)mem;
2607c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += 16 + 16;
2617c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->u_left_ = (uint8_t*)mem;
2627c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += 16;
2637c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->v_left_ = (uint8_t*)mem;
2647c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  mem += 8;
2657c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2667c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->config_ = config;
2677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2;
2687c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  enc->pic_ = picture;
269a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  enc->percent_ = 0;
2707c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2717c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  MapConfigToTools(enc);
2727c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8EncDspInit();
2737c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  VP8DefaultProbas(enc);
2747c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  ResetSegmentHeader(enc);
2757c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  ResetFilterHeader(enc);
2767c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  ResetBoundaryPredictions(enc);
2777c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
278466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  VP8EncInitAlpha(enc);
279a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#ifdef WEBP_EXPERIMENTAL_FEATURES
280466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  VP8EncInitLayer(enc);
281466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
282466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
2831e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  VP8TBufferInit(&enc->tokens_);
2847c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return enc;
2857c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
2867c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
2871e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic int DeleteVP8Encoder(VP8Encoder* enc) {
2881e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int ok = 1;
289a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (enc != NULL) {
2901e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok = VP8EncDeleteAlpha(enc);
291a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#ifdef WEBP_EXPERIMENTAL_FEATURES
292466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    VP8EncDeleteLayer(enc);
293466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
2941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    VP8TBufferClear(&enc->tokens_);
295466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    free(enc);
296466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  }
2971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  return ok;
2987c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
2997c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
300a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
3017c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3027c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic double GetPSNR(uint64_t err, uint64_t size) {
3037c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return err ? 10. * log10(255. * 255. * size / err) : 99.;
3047c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
3057c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3067c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void FinalizePSNR(const VP8Encoder* const enc) {
3077c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  WebPAuxStats* stats = enc->pic_->stats;
3087c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const uint64_t size = enc->sse_count_;
3097c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  const uint64_t* const sse = enc->sse_;
3107c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  stats->PSNR[0] = (float)GetPSNR(sse[0], size);
3117c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4);
3127c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4);
3137c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2);
314a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  stats->PSNR[4] = (float)GetPSNR(sse[3], size);
3157c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
3167c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
3177c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arorastatic void StoreStats(VP8Encoder* const enc) {
3187c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  WebPAuxStats* const stats = enc->pic_->stats;
319a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (stats != NULL) {
3207c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    int i, s;
3217c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
3227c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      stats->segment_level[i] = enc->dqm_[i].fstrength_;
3237c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      stats->segment_quant[i] = enc->dqm_[i].quant_;
3247c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      for (s = 0; s <= 2; ++s) {
3257c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora        stats->residual_bytes[s][i] = enc->residual_bytes_[s][i];
3267c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      }
3277c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
3287c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    FinalizePSNR(enc);
3297c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    stats->coded_size = enc->coded_size_;
3307c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    for (i = 0; i < 3; ++i) {
3317c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora      stats->block_count[i] = enc->block_count_[i];
3327c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora    }
3337c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  }
334a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  WebPReportProgress(enc->pic_, 100, &enc->percent_);  // done!
3357c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
3367c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
337a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPEncodingSetError(const WebPPicture* const pic,
338a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                         WebPEncodingError error) {
339a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  assert((int)error < VP8_ENC_ERROR_LAST);
340466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  assert((int)error >= VP8_ENC_OK);
341a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  ((WebPPicture*)pic)->error_code = error;
342466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  return 0;
343466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
344466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
345a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPReportProgress(const WebPPicture* const pic,
346a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                       int percent, int* const percent_store) {
347a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (percent_store != NULL && percent != *percent_store) {
348a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    *percent_store = percent;
349a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (pic->progress_hook && !pic->progress_hook(percent, pic)) {
350a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      // user abort requested
351a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT);
352a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      return 0;
353a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
354a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
355a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  return 1;  // ok
356a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
357a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
3587c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
359a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroraint WebPEncode(const WebPConfig* config, WebPPicture* pic) {
3601e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  int ok = 0;
3617c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
362466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (pic == NULL)
363466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return 0;
364466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  WebPEncodingSetError(pic, VP8_ENC_OK);  // all ok so far
365466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  if (config == NULL)  // bad params
366466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
3677c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  if (!WebPValidateConfig(config))
368466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
3697c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  if (pic->width <= 0 || pic->height <= 0)
370466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
371a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION)
372466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora    return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
3737c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
374a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats));
375a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
376a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  if (!config->lossless) {
377a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    VP8Encoder* enc = NULL;
378a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (pic->y == NULL || pic->u == NULL || pic->v == NULL) {
3790406ce1417f76f2034833414dcecc9f56253640cVikas Arora      // Make sure we have YUVA samples.
3800406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0;
381a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
382a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
383a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    enc = InitVP8Encoder(config, pic);
384a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (enc == NULL) return 0;  // pic->error is already set.
385a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    // Note: each of the tasks below account for 20% in the progress report.
3861e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok = VP8EncAnalyze(enc);
3871e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
3881e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    // Analysis is done, proceed to actual coding.
3891e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok = ok && VP8EncStartAlpha(enc);   // possibly done in parallel
3901e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    if (!enc->use_tokens_) {
3910406ce1417f76f2034833414dcecc9f56253640cVikas Arora      ok = ok && VP8EncLoop(enc);
3921e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    } else {
3930406ce1417f76f2034833414dcecc9f56253640cVikas Arora      ok = ok && VP8EncTokenLoop(enc);
3941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    }
3951e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok = ok && VP8EncFinishAlpha(enc);
396466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#ifdef WEBP_EXPERIMENTAL_FEATURES
3971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok = ok && VP8EncFinishLayer(enc);
398466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora#endif
3991e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
4001e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok = ok && VP8EncWrite(enc);
401a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    StoreStats(enc);
402a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    if (!ok) {
403a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora      VP8EncFreeBitWriters(enc);
404a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    }
4051e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora    ok &= DeleteVP8Encoder(enc);  // must always be called, even if !ok
406a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  } else {
4070406ce1417f76f2034833414dcecc9f56253640cVikas Arora    // Make sure we have ARGB samples.
4080406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) {
4090406ce1417f76f2034833414dcecc9f56253640cVikas Arora      return 0;
4100406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
411a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
412a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora    ok = VP8LEncodeImage(config, pic);  // Sets pic->error in case of problem.
413a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  }
414466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
4157c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora  return ok;
4167c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}
4177c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora
4187c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#if defined(__cplusplus) || defined(c_plusplus)
4197c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora}    // extern "C"
4207c970a0a679089e416c5887cf7fcece15a70bfa4Vikas Arora#endif
421