You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
7.9 KiB
313 lines
7.9 KiB
2 years ago
|
/*
|
||
|
* H.265 video codec.
|
||
|
* Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
|
||
|
*
|
||
|
* This file is part of libde265.
|
||
|
*
|
||
|
* libde265 is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Lesser General Public License as
|
||
|
* published by the Free Software Foundation, either version 3 of
|
||
|
* the License, or (at your option) any later version.
|
||
|
*
|
||
|
* libde265 is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public License
|
||
|
* along with libde265. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "threads.h"
|
||
|
#include <assert.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||
|
# include <malloc.h>
|
||
|
#elif defined(HAVE_ALLOCA_H)
|
||
|
# include <alloca.h>
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifndef _WIN32
|
||
|
// #include <intrin.h>
|
||
|
|
||
|
#define THREAD_RESULT void*
|
||
|
#define THREAD_PARAM void*
|
||
|
|
||
|
#include <stdio.h>
|
||
|
|
||
|
int de265_thread_create(de265_thread* t, void *(*start_routine) (void *), void *arg) { return pthread_create(t,NULL,start_routine,arg); }
|
||
|
void de265_thread_join(de265_thread t) { pthread_join(t,NULL); }
|
||
|
void de265_thread_destroy(de265_thread* t) { }
|
||
|
void de265_mutex_init(de265_mutex* m) { pthread_mutex_init(m,NULL); }
|
||
|
void de265_mutex_destroy(de265_mutex* m) { pthread_mutex_destroy(m); }
|
||
|
void de265_mutex_lock(de265_mutex* m) { pthread_mutex_lock(m); }
|
||
|
void de265_mutex_unlock(de265_mutex* m) { pthread_mutex_unlock(m); }
|
||
|
void de265_cond_init(de265_cond* c) { pthread_cond_init(c,NULL); }
|
||
|
void de265_cond_destroy(de265_cond* c) { pthread_cond_destroy(c); }
|
||
|
void de265_cond_broadcast(de265_cond* c,de265_mutex* m) { pthread_cond_broadcast(c); }
|
||
|
void de265_cond_wait(de265_cond* c,de265_mutex* m) { pthread_cond_wait(c,m); }
|
||
|
void de265_cond_signal(de265_cond* c) { pthread_cond_signal(c); }
|
||
|
#else // _WIN32
|
||
|
|
||
|
#define THREAD_RESULT DWORD WINAPI
|
||
|
#define THREAD_PARAM LPVOID
|
||
|
|
||
|
int de265_thread_create(de265_thread* t, LPTHREAD_START_ROUTINE start_routine, void *arg) {
|
||
|
HANDLE handle = CreateThread(NULL, 0, start_routine, arg, 0, NULL);
|
||
|
if (handle == NULL) {
|
||
|
return -1;
|
||
|
}
|
||
|
*t = handle;
|
||
|
return 0;
|
||
|
}
|
||
|
void de265_thread_join(de265_thread t) { WaitForSingleObject(t, INFINITE); }
|
||
|
void de265_thread_destroy(de265_thread* t) { CloseHandle(*t); *t = NULL; }
|
||
|
void de265_mutex_init(de265_mutex* m) { *m = CreateMutex(NULL, FALSE, NULL); }
|
||
|
void de265_mutex_destroy(de265_mutex* m) { CloseHandle(*m); }
|
||
|
void de265_mutex_lock(de265_mutex* m) { WaitForSingleObject(*m, INFINITE); }
|
||
|
void de265_mutex_unlock(de265_mutex* m) { ReleaseMutex(*m); }
|
||
|
void de265_cond_init(de265_cond* c) { win32_cond_init(c); }
|
||
|
void de265_cond_destroy(de265_cond* c) { win32_cond_destroy(c); }
|
||
|
void de265_cond_broadcast(de265_cond* c,de265_mutex* m)
|
||
|
{
|
||
|
de265_mutex_lock(m);
|
||
|
win32_cond_broadcast(c);
|
||
|
de265_mutex_unlock(m);
|
||
|
}
|
||
|
void de265_cond_wait(de265_cond* c,de265_mutex* m) { win32_cond_wait(c,m); }
|
||
|
void de265_cond_signal(de265_cond* c) { win32_cond_signal(c); }
|
||
|
#endif // _WIN32
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
de265_progress_lock::de265_progress_lock()
|
||
|
{
|
||
|
mProgress = 0;
|
||
|
|
||
|
de265_mutex_init(&mutex);
|
||
|
de265_cond_init(&cond);
|
||
|
}
|
||
|
|
||
|
de265_progress_lock::~de265_progress_lock()
|
||
|
{
|
||
|
de265_mutex_destroy(&mutex);
|
||
|
de265_cond_destroy(&cond);
|
||
|
}
|
||
|
|
||
|
void de265_progress_lock::wait_for_progress(int progress)
|
||
|
{
|
||
|
if (mProgress >= progress) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
de265_mutex_lock(&mutex);
|
||
|
while (mProgress < progress) {
|
||
|
de265_cond_wait(&cond, &mutex);
|
||
|
}
|
||
|
de265_mutex_unlock(&mutex);
|
||
|
}
|
||
|
|
||
|
void de265_progress_lock::set_progress(int progress)
|
||
|
{
|
||
|
de265_mutex_lock(&mutex);
|
||
|
|
||
|
if (progress>mProgress) {
|
||
|
mProgress = progress;
|
||
|
|
||
|
de265_cond_broadcast(&cond, &mutex);
|
||
|
}
|
||
|
|
||
|
de265_mutex_unlock(&mutex);
|
||
|
}
|
||
|
|
||
|
void de265_progress_lock::increase_progress(int progress)
|
||
|
{
|
||
|
de265_mutex_lock(&mutex);
|
||
|
|
||
|
mProgress += progress;
|
||
|
de265_cond_broadcast(&cond, &mutex);
|
||
|
|
||
|
de265_mutex_unlock(&mutex);
|
||
|
}
|
||
|
|
||
|
int de265_progress_lock::get_progress() const
|
||
|
{
|
||
|
return mProgress;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#include "libde265/decctx.h"
|
||
|
|
||
|
#if 0
|
||
|
const char* line="--------------------------------------------------";
|
||
|
void printblks(const thread_pool* pool)
|
||
|
{
|
||
|
int w = pool->tasks[0].data.task_ctb.ctx->current_sps->PicWidthInCtbsY;
|
||
|
int h = pool->tasks[0].data.task_ctb.ctx->current_sps->PicHeightInCtbsY;
|
||
|
|
||
|
printf("active threads: %d queue len: %d\n",pool->num_threads_working,pool->num_tasks);
|
||
|
|
||
|
char *const p = (char *)alloca(w * h * sizeof(char));
|
||
|
assert(p != NULL);
|
||
|
memset(p,' ',w*h);
|
||
|
|
||
|
for (int i=0;i<pool->num_tasks;i++) {
|
||
|
int b = 0; //pool->tasks[i].num_blockers;
|
||
|
int x = pool->tasks[i].data.task_ctb.ctb_x;
|
||
|
int y = pool->tasks[i].data.task_ctb.ctb_y;
|
||
|
p[y*w+x] = b+'0';
|
||
|
}
|
||
|
|
||
|
for (int i=0;i<pool->num_threads_working;i++) {
|
||
|
int x = pool->ctbx[i];
|
||
|
int y = pool->ctby[i];
|
||
|
p[y*w+x] = '*';
|
||
|
}
|
||
|
|
||
|
printf("+%s+\n",line+50-w);
|
||
|
for (int y=0;y<h;y++)
|
||
|
{
|
||
|
printf("|");
|
||
|
for (int x=0;x<w;x++)
|
||
|
{
|
||
|
printf("%c",p[x+y*w]);
|
||
|
}
|
||
|
printf("|\n");
|
||
|
}
|
||
|
printf("+%s+\n",line+50-w);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static THREAD_RESULT worker_thread(THREAD_PARAM pool_ptr)
|
||
|
{
|
||
|
thread_pool* pool = (thread_pool*)pool_ptr;
|
||
|
|
||
|
|
||
|
de265_mutex_lock(&pool->mutex);
|
||
|
|
||
|
while(true) {
|
||
|
|
||
|
// wait until we can pick a task or until the pool has been stopped
|
||
|
|
||
|
for (;;) {
|
||
|
// end waiting if thread-pool has been stopped or we have a task to execute
|
||
|
|
||
|
if (pool->stopped || pool->tasks.size()>0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//printf("going idle\n");
|
||
|
de265_cond_wait(&pool->cond_var, &pool->mutex);
|
||
|
}
|
||
|
|
||
|
// if the pool was shut down, end the execution
|
||
|
|
||
|
if (pool->stopped) {
|
||
|
de265_mutex_unlock(&pool->mutex);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// get a task
|
||
|
|
||
|
thread_task* task = pool->tasks.front();
|
||
|
pool->tasks.pop_front();
|
||
|
|
||
|
pool->num_threads_working++;
|
||
|
|
||
|
//printblks(pool);
|
||
|
|
||
|
de265_mutex_unlock(&pool->mutex);
|
||
|
|
||
|
|
||
|
// execute the task
|
||
|
|
||
|
task->work();
|
||
|
|
||
|
// end processing and check if this was the last task to be processed
|
||
|
|
||
|
de265_mutex_lock(&pool->mutex);
|
||
|
|
||
|
pool->num_threads_working--;
|
||
|
}
|
||
|
de265_mutex_unlock(&pool->mutex);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
de265_error start_thread_pool(thread_pool* pool, int num_threads)
|
||
|
{
|
||
|
de265_error err = DE265_OK;
|
||
|
|
||
|
// limit number of threads to maximum
|
||
|
|
||
|
if (num_threads > MAX_THREADS) {
|
||
|
num_threads = MAX_THREADS;
|
||
|
err = DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM;
|
||
|
}
|
||
|
|
||
|
pool->num_threads = 0; // will be increased below
|
||
|
|
||
|
de265_mutex_init(&pool->mutex);
|
||
|
de265_cond_init(&pool->cond_var);
|
||
|
|
||
|
de265_mutex_lock(&pool->mutex);
|
||
|
pool->num_threads_working = 0;
|
||
|
pool->stopped = false;
|
||
|
de265_mutex_unlock(&pool->mutex);
|
||
|
|
||
|
// start worker threads
|
||
|
|
||
|
for (int i=0; i<num_threads; i++) {
|
||
|
int ret = de265_thread_create(&pool->thread[i], worker_thread, pool);
|
||
|
if (ret != 0) {
|
||
|
// cerr << "pthread_create() failed: " << ret << endl;
|
||
|
return DE265_ERROR_CANNOT_START_THREADPOOL;
|
||
|
}
|
||
|
|
||
|
pool->num_threads++;
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
|
||
|
void stop_thread_pool(thread_pool* pool)
|
||
|
{
|
||
|
de265_mutex_lock(&pool->mutex);
|
||
|
pool->stopped = true;
|
||
|
de265_mutex_unlock(&pool->mutex);
|
||
|
|
||
|
de265_cond_broadcast(&pool->cond_var, &pool->mutex);
|
||
|
|
||
|
for (int i=0;i<pool->num_threads;i++) {
|
||
|
de265_thread_join(pool->thread[i]);
|
||
|
de265_thread_destroy(&pool->thread[i]);
|
||
|
}
|
||
|
|
||
|
de265_mutex_destroy(&pool->mutex);
|
||
|
de265_cond_destroy(&pool->cond_var);
|
||
|
}
|
||
|
|
||
|
|
||
|
void add_task(thread_pool* pool, thread_task* task)
|
||
|
{
|
||
|
de265_mutex_lock(&pool->mutex);
|
||
|
if (!pool->stopped) {
|
||
|
|
||
|
pool->tasks.push_back(task);
|
||
|
|
||
|
// wake up one thread
|
||
|
|
||
|
de265_cond_signal(&pool->cond_var);
|
||
|
}
|
||
|
de265_mutex_unlock(&pool->mutex);
|
||
|
}
|