1f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Copyright 2013 Google Inc. All Rights Reserved.
2f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//
3f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Use of this source code is governed by a BSD-style license
4f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// that can be found in the COPYING file in the root of the source
5f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// tree. An additional intellectual property rights grant can be found
6f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// in the file PATENTS. All contributing project authors may
7f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// be found in the AUTHORS file in the root of the source tree.
8f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// -----------------------------------------------------------------------------
9f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//
10f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Multi-threaded worker
11f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//
12f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Original source:
13f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//  http://git.chromium.org/webm/libwebp.git
14f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//  100644 blob 13a61a4c84194c3374080cbf03d881d3cd6af40d  src/utils/thread.h
15f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
16f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
17f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#ifndef VP9_DECODER_VP9_THREAD_H_
18f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#define VP9_DECODER_VP9_THREAD_H_
19f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include "./vpx_config.h"
21f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
22b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#ifdef __cplusplus
23f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangextern "C" {
24f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#endif
25f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
26f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#if CONFIG_MULTITHREAD
27f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
28f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#if defined(_WIN32)
29b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#include <errno.h>  // NOLINT
30b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#include <process.h>  // NOLINT
315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <windows.h>  // NOLINT
32f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef HANDLE pthread_t;
33f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef CRITICAL_SECTION pthread_mutex_t;
34f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef struct {
35f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  HANDLE waiting_sem_;
36f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  HANDLE received_sem_;
37f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  HANDLE signal_event_;
38f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} pthread_cond_t;
39f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
40b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian//------------------------------------------------------------------------------
41b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian// simplistic pthread emulation layer
42b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
43b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian// _beginthreadex requires __stdcall
44b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#define THREADFN unsigned int __stdcall
45b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
46b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
47b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_create(pthread_t* const thread, const void* attr,
48b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                 unsigned int (__stdcall *start)(void*),
49b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                 void* arg) {
50b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  (void)attr;
51b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  *thread = (pthread_t)_beginthreadex(NULL,   /* void *security */
52b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                      0,      /* unsigned stack_size */
53b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                      start,
54b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                      arg,
55b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                      0,      /* unsigned initflag */
56b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                      NULL);  /* unsigned *thrdaddr */
57b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  if (*thread == NULL) return 1;
58b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
59b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return 0;
60b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
61b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
62b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_join(pthread_t thread, void** value_ptr) {
63b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  (void)value_ptr;
64b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
65b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian          CloseHandle(thread) == 0);
66b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
67b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
68b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian// Mutex
69b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_init(pthread_mutex_t *const mutex,
70b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                     void* mutexattr) {
71b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  (void)mutexattr;
72b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  InitializeCriticalSection(mutex);
73b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return 0;
74b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
75b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
76b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_trylock(pthread_mutex_t *const mutex) {
77b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return TryEnterCriticalSection(mutex) ? 0 : EBUSY;
78b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
79b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
80b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_lock(pthread_mutex_t *const mutex) {
81b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  EnterCriticalSection(mutex);
82b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return 0;
83b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
84b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
85b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_unlock(pthread_mutex_t *const mutex) {
86b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  LeaveCriticalSection(mutex);
87b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return 0;
88b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
89b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
90b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) {
91b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  DeleteCriticalSection(mutex);
92b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return 0;
93b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
94b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
95b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian// Condition
96b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_cond_destroy(pthread_cond_t *const condition) {
97b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  int ok = 1;
98b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  ok &= (CloseHandle(condition->waiting_sem_) != 0);
99b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  ok &= (CloseHandle(condition->received_sem_) != 0);
100b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  ok &= (CloseHandle(condition->signal_event_) != 0);
101b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return !ok;
102b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
103b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
104b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_cond_init(pthread_cond_t *const condition,
105b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                    void* cond_attr) {
106b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  (void)cond_attr;
107b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
108b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
109b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
110b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  if (condition->waiting_sem_ == NULL ||
111b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      condition->received_sem_ == NULL ||
112b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      condition->signal_event_ == NULL) {
113b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    pthread_cond_destroy(condition);
114b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    return 1;
115b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  }
116b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return 0;
117b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
118b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
119b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_cond_signal(pthread_cond_t *const condition) {
120b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  int ok = 1;
121b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
122b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // a thread is waiting in pthread_cond_wait: allow it to be notified
123b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    ok = SetEvent(condition->signal_event_);
124b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // wait until the event is consumed so the signaler cannot consume
125b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // the event via its own pthread_cond_wait.
126b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
127b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian           WAIT_OBJECT_0);
128b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  }
129b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return !ok;
130b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
131b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
132b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic INLINE int pthread_cond_wait(pthread_cond_t *const condition,
133b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                    pthread_mutex_t *const mutex) {
134b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  int ok;
135b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // note that there is a consumer available so the signal isn't dropped in
136b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // pthread_cond_signal
137b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
138b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    return 1;
139b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // now unlock the mutex so pthread_cond_signal may be issued
140b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  pthread_mutex_unlock(mutex);
141b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  ok = (WaitForSingleObject(condition->signal_event_, INFINITE) ==
142b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian        WAIT_OBJECT_0);
143b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
144b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  pthread_mutex_lock(mutex);
145b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  return !ok;
146b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian}
147b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#else  // _WIN32
1485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <pthread.h> // NOLINT
149b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian# define THREADFN void*
150b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian# define THREAD_RETURN(val) val
151b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#endif
152f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
153b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#endif  // CONFIG_MULTITHREAD
154f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
155f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// State of the worker thread object
156f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef enum {
157f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  NOT_OK = 0,   // object is unusable
158f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  OK,           // ready to work
159f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  WORK          // busy finishing the current task
160f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} VP9WorkerStatus;
161f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
162f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Function to be called by the worker thread. Takes two opaque pointers as
163f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// arguments (data1 and data2), and should return false in case of error.
164f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef int (*VP9WorkerHook)(void*, void*);
165f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
166f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Synchronize object used to launch job in the worker thread
167f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef struct {
168f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#if CONFIG_MULTITHREAD
169f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  pthread_mutex_t mutex_;
170f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  pthread_cond_t  condition_;
171f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  pthread_t       thread_;
172f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#endif
173f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  VP9WorkerStatus status_;
174f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  VP9WorkerHook hook;     // hook to call
175f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  void* data1;            // first argument passed to 'hook'
176f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  void* data2;            // second argument passed to 'hook'
177f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  int had_error;          // return value of the last call to 'hook'
178f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} VP9Worker;
179f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
180f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Must be called first, before any other method.
181f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangvoid vp9_worker_init(VP9Worker* const worker);
182f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Must be called to initialize the object and spawn the thread. Re-entrant.
183f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Will potentially launch the thread. Returns false in case of error.
184f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangint vp9_worker_reset(VP9Worker* const worker);
185f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Makes sure the previous work is finished. Returns true if worker->had_error
186f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// was not set and no error condition was triggered by the working thread.
187f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangint vp9_worker_sync(VP9Worker* const worker);
188f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Triggers the thread to call hook() with data1 and data2 argument. These
189f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// hook/data1/data2 can be changed at any time before calling this function,
190f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// but not be changed afterward until the next call to vp9_worker_sync().
191f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangvoid vp9_worker_launch(VP9Worker* const worker);
1925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// This function is similar to vp9_worker_launch() except that it calls the
1935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// hook directly instead of using a thread. Convenient to bypass the thread
1945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// mechanism while still using the VP9Worker structs. vp9_worker_sync() must
1955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// still be called afterward (for error reporting).
1965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvoid vp9_worker_execute(VP9Worker* const worker);
197f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Kill the thread and terminate the object. To use the object again, one
198f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// must call vp9_worker_reset() again.
199f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangvoid vp9_worker_end(VP9Worker* const worker);
200f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
201f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//------------------------------------------------------------------------------
202f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
203b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#ifdef __cplusplus
204f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang}    // extern "C"
205f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#endif
206f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
2075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#endif  // VP9_DECODER_VP9_THREAD_H_
208