create a libwebputils under src/utils

with bit_reader bit_writer and thread for now.

Change-Id: If961933fcfc43e60220913fe4d527230ba8f46bb
This commit is contained in:
Pascal Massimino
2011-09-07 09:26:35 +00:00
committed by James Zern
parent ee697d9fc9
commit b112e83647
16 changed files with 76 additions and 53 deletions

View File

@@ -1,16 +1,13 @@
AM_CPPFLAGS = -I$(top_srcdir)/src
libwebpdecode_la_SOURCES = bits.h vp8i.h bits.c frame.c \
quant.c tree.c vp8.c webp.c idec.c alpha.c \
layer.c io.c buffer.c thread.c
libwebpdecode_la_SOURCES = vp8i.h webpi.h \
frame.c quant.c tree.c vp8.c webp.c \
idec.c alpha.c layer.c io.c buffer.c
libwebpdecode_la_LDFLAGS = -version-info 0:0:0
libwebpdecode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE)
libwebpdecodeinclude_HEADERS = ../webp/decode.h ../webp/decode_vp8.h ../webp/types.h
libwebpdecodeincludedir = $(includedir)/webp
noinst_HEADERS = bits.h vp8i.h webpi.h thread.h
noinst_HEADERS = vp8i.h webpi.h
noinst_LTLIBRARIES = libwebpdecode.la
# uncomment the following line (and comment the above) if you want
# to install libwebpdecode library.
#lib_LTLIBRARIES = libwebpdecode.la

View File

@@ -1,79 +0,0 @@
// Copyright 2010 Google Inc.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// Boolean decoder
//
// Author: Skal (pascal.massimino@gmail.com)
#include "bits.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// VP8BitReader
void VP8InitBitReader(VP8BitReader* const br,
const uint8_t* const start, const uint8_t* const end) {
assert(br);
assert(start);
assert(start <= end);
br->range_ = 255 - 1;
br->buf_ = start;
br->buf_end_ = end;
br->value_ = 0;
br->missing_ = 8;
br->eof_ = 0;
}
const uint8_t kVP8Log2Range[128] = {
7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0
};
// range = ((range + 1) << kVP8Log2Range[range]) - 1
const uint8_t kVP8NewRange[128] = {
127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239,
127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239,
247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179,
183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239,
243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149,
151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179,
181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209,
211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239,
241, 243, 245, 247, 249, 251, 253, 127
};
//------------------------------------------------------------------------------
// Higher-level calls
uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
uint32_t v = 0;
while (bits-- > 0) {
v |= VP8GetBit(br, 0x80) << bits;
}
return v;
}
int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
const int value = VP8GetValue(br, bits);
return VP8Get(br) ? -value : value;
}
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@@ -1,108 +0,0 @@
// Copyright 2010 Google Inc.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// Boolean decoder
//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DEC_BITS_H_
#define WEBP_DEC_BITS_H_
#include <assert.h>
#include "../webp/decode_vp8.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
//------------------------------------------------------------------------------
// Bitreader and code-tree reader
typedef struct {
const uint8_t* buf_; // next byte to be read
const uint8_t* buf_end_; // end of read buffer
int eof_; // true if input is exhausted
// boolean decoder
uint32_t range_; // current range minus 1. In [127, 254] interval.
uint32_t value_; // current value
int missing_; // number of missing bits in value_ (8bit)
} VP8BitReader;
// Initialize the bit reader and the boolean decoder.
void VP8InitBitReader(VP8BitReader* const br,
const uint8_t* const start, const uint8_t* const end);
// return the next value made of 'num_bits' bits
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
static inline uint32_t VP8Get(VP8BitReader* const br) {
return VP8GetValue(br, 1);
}
// return the next value with sign-extension.
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
// Read a bit with proba 'prob'. Speed-critical function!
extern const uint8_t kVP8Log2Range[128];
extern const uint8_t kVP8NewRange[128];
static inline uint32_t VP8GetByte(VP8BitReader* const br) {
assert(br);
if (br->buf_ < br->buf_end_) {
assert(br->buf_);
return *br->buf_++;
}
br->eof_ = 1;
return 0xff;
}
static inline uint32_t VP8BitUpdate(VP8BitReader* const br, uint32_t split) {
uint32_t bit;
const uint32_t value_split = (split + 1) << 8;
// Make sure we have a least 8 bits in 'value_'
if (br->missing_ > 0) {
br->value_ |= VP8GetByte(br) << br->missing_;
br->missing_ -= 8;
}
bit = (br->value_ >= value_split);
if (bit) {
br->range_ -= split + 1;
br->value_ -= value_split;
} else {
br->range_ = split;
}
return bit;
}
static inline void VP8Shift(VP8BitReader* const br) {
// range_ is in [0..127] interval here.
const int shift = kVP8Log2Range[br->range_];
br->range_ = kVP8NewRange[br->range_];
br->value_ <<= shift;
br->missing_ += shift;
}
static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
const uint32_t split = (br->range_ * prob) >> 8;
const uint32_t bit = VP8BitUpdate(br, split);
if (br->range_ < 0x7f) {
VP8Shift(br);
}
return bit;
}
static inline int VP8GetSigned(VP8BitReader* const br, int v) {
const uint32_t split = br->range_ >> 1;
const uint32_t bit = VP8BitUpdate(br, split);
VP8Shift(br);
return bit ? -v : v;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif // WEBP_DEC_BITS_H_

View File

@@ -1,242 +0,0 @@
// Copyright 2011 Google Inc.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// Multi-threaded worker
//
// Author: skal@google.com (Pascal Massimino)
#include "./vp8i.h"
#include "./thread.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifdef WEBP_USE_THREAD
#if defined(_WIN32)
//------------------------------------------------------------------------------
// simplistic pthread emulation layer
#include <process.h>
// _beginthreadex requires __stdcall
#define THREADFN unsigned int __stdcall
#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
static int pthread_create(pthread_t* const thread, const void* attr,
unsigned int (__stdcall *start)(void*), void* arg) {
(void)attr;
*thread = (pthread_t)_beginthreadex(NULL, /* void *security */
0, /* unsigned stack_size */
start,
arg,
0, /* unsigned initflag */
NULL); /* unsigned *thrdaddr */
if (*thread == NULL) return 1;
SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
return 0;
}
static int pthread_join(pthread_t thread, void** value_ptr) {
(void)value_ptr;
return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
CloseHandle(thread) == 0);
}
// Mutex
static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) {
(void)mutexattr;
InitializeCriticalSection(mutex);
return 0;
}
static int pthread_mutex_lock(pthread_mutex_t* const mutex) {
EnterCriticalSection(mutex);
return 0;
}
static int pthread_mutex_unlock(pthread_mutex_t* const mutex) {
LeaveCriticalSection(mutex);
return 0;
}
static int pthread_mutex_destroy(pthread_mutex_t* const mutex) {
DeleteCriticalSection(mutex);
return 0;
}
// Condition
static int pthread_cond_destroy(pthread_cond_t* const condition) {
int ok = 1;
ok &= (CloseHandle(condition->waiting_sem_) == 0);
ok &= (CloseHandle(condition->received_sem_) == 0);
ok &= (CloseHandle(condition->signal_event_) == 0);
return ok;
}
static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
(void)cond_attr;
condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
if (condition->waiting_sem_ == NULL ||
condition->received_sem_ == NULL ||
condition->signal_event_ == NULL) {
pthread_cond_destroy(condition);
return 1;
}
return 0;
}
static int pthread_cond_signal(pthread_cond_t* const condition) {
int ok = 1;
if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
// a thread is waiting in pthread_cond_wait: allow it to be notified
ok = SetEvent(condition->signal_event_);
// wait until the event is consumed so the signaler cannot consume
// the event via its own pthread_cond_wait.
ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
WAIT_OBJECT_0);
}
return !ok;
}
static int pthread_cond_wait(pthread_cond_t* const condition,
pthread_mutex_t* const mutex) {
int ok;
// note that there is a consumer available so the signal isn't dropped in
// pthread_cond_signal
if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
return 1;
// now unlock the mutex so pthread_cond_signal may be issued
pthread_mutex_unlock(mutex);
ok = (WaitForSingleObject(condition->signal_event_, INFINITE) ==
WAIT_OBJECT_0);
ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
pthread_mutex_lock(mutex);
return !ok;
}
#else // _WIN32
# define THREADFN void*
# define THREAD_RETURN(val) val
#endif
//------------------------------------------------------------------------------
static THREADFN WebPWorkerThreadLoop(void *ptr) { // thread loop
WebPWorker* const worker = (WebPWorker*)ptr;
int done = 0;
while (!done) {
pthread_mutex_lock(&worker->mutex_);
while (worker->status_ == OK) { // wait in idling mode
pthread_cond_wait(&worker->condition_, &worker->mutex_);
}
if (worker->status_ == WORK) {
if (worker->hook) {
worker->had_error |= !worker->hook(worker->data1, worker->data2);
}
worker->status_ = OK;
} else if (worker->status_ == NOT_OK) { // finish the worker
done = 1;
}
// signal to the main thread that we're done (for Sync())
pthread_cond_signal(&worker->condition_);
pthread_mutex_unlock(&worker->mutex_);
}
return THREAD_RETURN(NULL); // Thread is finished
}
// main thread state control
static void WebPWorkerChangeState(WebPWorker* const worker,
WebPWorkerStatus new_status) {
// no-op when attempting to change state on a thread that didn't come up
if (worker->status_ < OK) return;
pthread_mutex_lock(&worker->mutex_);
// wait for the worker to finish
while (worker->status_ != OK) {
pthread_cond_wait(&worker->condition_, &worker->mutex_);
}
// assign new status and release the working thread if needed
if (new_status != OK) {
worker->status_ = new_status;
pthread_cond_signal(&worker->condition_);
}
pthread_mutex_unlock(&worker->mutex_);
}
#endif
//------------------------------------------------------------------------------
void WebPWorkerInit(WebPWorker* const worker) {
memset(worker, 0, sizeof(*worker));
worker->status_ = NOT_OK;
}
int WebPWorkerSync(WebPWorker* const worker) {
#ifdef WEBP_USE_THREAD
WebPWorkerChangeState(worker, OK);
#endif
assert(worker->status_ <= OK);
return !worker->had_error;
}
int WebPWorkerReset(WebPWorker* const worker) {
int ok = 1;
worker->had_error = 0;
if (worker->status_ < OK) {
#ifdef WEBP_USE_THREAD
if (pthread_mutex_init(&worker->mutex_, NULL) ||
pthread_cond_init(&worker->condition_, NULL)) {
return 0;
}
pthread_mutex_lock(&worker->mutex_);
ok = !pthread_create(&worker->thread_, NULL, WebPWorkerThreadLoop, worker);
if (ok) worker->status_ = OK;
pthread_mutex_unlock(&worker->mutex_);
#else
worker->status_ = OK;
#endif
} else if (worker->status_ > OK) {
ok = WebPWorkerSync(worker);
}
assert(!ok || (worker->status_ == OK));
return ok;
}
void WebPWorkerLaunch(WebPWorker* const worker) {
#ifdef WEBP_USE_THREAD
WebPWorkerChangeState(worker, WORK);
#else
if (worker->hook)
worker->had_error |= !worker->hook(worker->data1, worker->data2);
#endif
}
void WebPWorkerEnd(WebPWorker* const worker) {
if (worker->status_ >= OK) {
#ifdef WEBP_USE_THREAD
WebPWorkerChangeState(worker, NOT_OK);
pthread_join(worker->thread_, NULL);
pthread_mutex_destroy(&worker->mutex_);
pthread_cond_destroy(&worker->condition_);
#else
worker->status_ = NOT_OK;
#endif
}
assert(worker->status_ == NOT_OK);
}
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif

View File

@@ -1,86 +0,0 @@
// Copyright 2011 Google Inc.
//
// This code is licensed under the same terms as WebM:
// Software License Agreement: http://www.webmproject.org/license/software/
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// Multi-threaded worker
//
// Author: skal@google.com (Pascal Massimino)
#ifndef WEBP_DEC_THREAD_H
#define WEBP_DEC_THREAD_H
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#if WEBP_USE_THREAD
#if defined(_WIN32)
#include <windows.h>
typedef HANDLE pthread_t;
typedef CRITICAL_SECTION pthread_mutex_t;
typedef struct {
HANDLE waiting_sem_;
HANDLE received_sem_;
HANDLE signal_event_;
} pthread_cond_t;
#else
#include <pthread.h>
#endif // _WIN32
#endif // WEBP_USE_THREAD
// State of the worker thread object
typedef enum {
NOT_OK = 0, // object is unusable
OK, // ready to work
WORK // busy finishing the current task
} WebPWorkerStatus;
// Function to be called by the worker thread. Takes two opaque pointers as
// arguments (data1 and data2), and should return false in case of error.
typedef int (*WebPWorkerHook)(void*, void*);
// Synchronize object used to launch job in the worker thread
typedef struct {
#if WEBP_USE_THREAD
pthread_mutex_t mutex_;
pthread_cond_t condition_;
pthread_t thread_;
#endif
WebPWorkerStatus status_;
WebPWorkerHook hook; // hook to call
void* data1; // first argument passed to 'hook'
void* data2; // second argument passed to 'hook'
int had_error; // return value of the last call to 'hook'
} WebPWorker;
// Must be called first, before any other method.
void WebPWorkerInit(WebPWorker* const worker);
// Must be called initialize the object and spawn the thread. Re-entrant.
// Will potentially launch the thread. Returns false in case of error.
int WebPWorkerReset(WebPWorker* const worker);
// Make sure the previous work is finished. Returns true if worker->had_error
// was not set and not error condition was triggered by the working thread.
int WebPWorkerSync(WebPWorker* const worker);
// Trigger the thread to call hook() with data1 and data2 argument. These
// hook/data1/data2 can be changed at any time before calling this function,
// but not be changed afterward until the next call to WebPWorkerSync().
void WebPWorkerLaunch(WebPWorker* const worker);
// Kill the thread and terminate the object. To use the object again, one
// must call WebPWorkerReset() again.
void WebPWorkerEnd(WebPWorker* const worker);
//------------------------------------------------------------------------------
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif // WEBP_DEC_THREAD_H

View File

@@ -13,8 +13,8 @@
#define WEBP_DEC_VP8I_H_
#include <string.h> // for memcpy()
#include "./bits.h"
#include "./thread.h"
#include "../utils/bit_reader.h"
#include "../utils/thread.h"
#include "../dsp/dsp.h"
#if defined(__cplusplus) || defined(c_plusplus)
@@ -366,4 +366,4 @@ int VP8DecodeLayer(VP8Decoder* const dec);
} // extern "C"
#endif
#endif // WEBP_DEC_VP8I_H_
#endif /* WEBP_DEC_VP8I_H_ */