Skip to content
Snippets Groups Projects
pthread.c 5.24 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * Copyright (c) 2004 Roman Shaposhnik
    
     * Many thanks to Steven M. Schultz for providing clever ideas and
     * to Michael Niedermayer <michaelni@gmx.at> for writing initial
     * implementation.
    
     * This file is part of FFmpeg.
     *
     * FFmpeg 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 2.1 of the License, or (at your option) any later version.
    
     * FFmpeg 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 FFmpeg; if not, write to the Free Software
    
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    
     */
    #include <pthread.h>
    
    #include "avcodec.h"
    
    
    typedef int (action_func)(AVCodecContext *c, void *arg);
    
    typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr);
    
    typedef struct ThreadContext {
        pthread_t *workers;
    
        action_func *func;
    
        int job_count;
    
        pthread_cond_t last_job_cond;
        pthread_cond_t current_job_cond;
        pthread_mutex_t current_job_lock;
        int current_job;
        int done;
    } ThreadContext;
    
    
    static void* attribute_align_arg worker(void *v)
    
    {
        AVCodecContext *avctx = v;
        ThreadContext *c = avctx->thread_opaque;
        int our_job = c->job_count;
        int thread_count = avctx->thread_count;
        int self_id;
    
        pthread_mutex_lock(&c->current_job_lock);
        self_id = c->current_job++;
    
            while (our_job >= c->job_count) {
                if (c->current_job == thread_count + c->job_count)
                    pthread_cond_signal(&c->last_job_cond);
    
                pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
    
                if (c->done) {
                    pthread_mutex_unlock(&c->current_job_lock);
                    return NULL;
                }
            }
            pthread_mutex_unlock(&c->current_job_lock);
    
            c->rets[our_job%c->rets_count] = c->func ? c->func(avctx, (char*)c->args + our_job*c->job_size):
                                                       c->func2(avctx, c->args, our_job, self_id);
    
            pthread_mutex_lock(&c->current_job_lock);
            our_job = c->current_job++;
    
    static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count)
    
    {
        pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
        pthread_mutex_unlock(&c->current_job_lock);
    
    void avcodec_thread_free(AVCodecContext *avctx)
    
    {
        ThreadContext *c = avctx->thread_opaque;
        int i;
    
        pthread_mutex_lock(&c->current_job_lock);
        c->done = 1;
    
        pthread_cond_broadcast(&c->current_job_cond);
    
        pthread_mutex_unlock(&c->current_job_lock);
    
        for (i=0; i<avctx->thread_count; i++)
             pthread_join(c->workers[i], NULL);
    
        pthread_mutex_destroy(&c->current_job_lock);
        pthread_cond_destroy(&c->current_job_cond);
        pthread_cond_destroy(&c->last_job_cond);
        av_free(c->workers);
    
        av_freep(&avctx->thread_opaque);
    
    int avcodec_thread_execute(AVCodecContext *avctx, action_func* func, void *arg, int *ret, int job_count, int job_size)
    
    {
        ThreadContext *c= avctx->thread_opaque;
        int dummy_ret;
    
        pthread_mutex_lock(&c->current_job_lock);
    
        c->current_job = avctx->thread_count;
        c->job_count = job_count;
    
        c->args = arg;
        c->func = func;
        if (ret) {
            c->rets = ret;
    
            c->rets_count = job_count;
    
            c->rets_count = 1;
    
        pthread_cond_broadcast(&c->current_job_cond);
    
        avcodec_thread_park_workers(c, avctx->thread_count);
    
    int avcodec_thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count)
    {
        ThreadContext *c= avctx->thread_opaque;
        c->func2 = func2;
        return avcodec_thread_execute(avctx, NULL, arg, ret, job_count, 0);
    }
    
    
    int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
    
        int i;
        ThreadContext *c;
    
    
        c = av_mallocz(sizeof(ThreadContext));
        if (!c)
            return -1;
    
        c->workers = av_mallocz(sizeof(pthread_t)*thread_count);
        if (!c->workers) {
            av_free(c);
            return -1;
        }
    
        avctx->thread_opaque = c;
        avctx->thread_count = thread_count;
        c->current_job = 0;
        c->job_count = 0;
    
        pthread_cond_init(&c->current_job_cond, NULL);
    
        pthread_cond_init(&c->last_job_cond, NULL);
        pthread_mutex_init(&c->current_job_lock, NULL);
        pthread_mutex_lock(&c->current_job_lock);
    
        for (i=0; i<thread_count; i++) {
    
            if(pthread_create(&c->workers[i], NULL, worker, avctx)) {
    
               avctx->thread_count = i;
               pthread_mutex_unlock(&c->current_job_lock);
    
               avcodec_thread_free(avctx);
               return -1;
            }
    
        avcodec_thread_park_workers(c, thread_count);
    
        avctx->execute = avcodec_thread_execute;
    
        avctx->execute2 = avcodec_thread_execute2;