1/* 2 * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20//#define DEBUG 21 22#include "avcodec.h" 23 24#define WIN32_LEAN_AND_MEAN 25#include <windows.h> 26#include <process.h> 27 28typedef struct ThreadContext{ 29 AVCodecContext *avctx; 30 HANDLE thread; 31 HANDLE work_sem; 32 HANDLE job_sem; 33 HANDLE done_sem; 34 int (*func)(AVCodecContext *c, void *arg); 35 int (*func2)(AVCodecContext *c, void *arg, int, int); 36 void *arg; 37 int argsize; 38 int *jobnr; 39 int *ret; 40 int threadnr; 41}ThreadContext; 42 43 44static unsigned WINAPI attribute_align_arg thread_func(void *v){ 45 ThreadContext *c= v; 46 47 for(;;){ 48 int ret, jobnr; 49//printf("thread_func %X enter wait\n", (int)v); fflush(stdout); 50 WaitForSingleObject(c->work_sem, INFINITE); 51 // avoid trying to access jobnr if we should quit 52 if (!c->func && !c->func2) 53 break; 54 WaitForSingleObject(c->job_sem, INFINITE); 55 jobnr = (*c->jobnr)++; 56 ReleaseSemaphore(c->job_sem, 1, 0); 57//printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout); 58 if(c->func) 59 ret= c->func(c->avctx, (uint8_t *)c->arg + jobnr*c->argsize); 60 else 61 ret= c->func2(c->avctx, c->arg, jobnr, c->threadnr); 62 if (c->ret) 63 c->ret[jobnr] = ret; 64//printf("thread_func %X signal complete\n", (int)v); fflush(stdout); 65 ReleaseSemaphore(c->done_sem, 1, 0); 66 } 67 68 return 0; 69} 70 71/** 72 * Free what has been allocated by avcodec_thread_init(). 73 * Must be called after decoding has finished, especially do not call while avcodec_thread_execute() is running. 74 */ 75void avcodec_thread_free(AVCodecContext *s){ 76 ThreadContext *c= s->thread_opaque; 77 int i; 78 79 for(i=0; i<s->thread_count; i++){ 80 81 c[i].func= NULL; 82 c[i].func2= NULL; 83 } 84 ReleaseSemaphore(c[0].work_sem, s->thread_count, 0); 85 for(i=0; i<s->thread_count; i++){ 86 WaitForSingleObject(c[i].thread, INFINITE); 87 if(c[i].thread) CloseHandle(c[i].thread); 88 } 89 if(c[0].work_sem) CloseHandle(c[0].work_sem); 90 if(c[0].job_sem) CloseHandle(c[0].job_sem); 91 if(c[0].done_sem) CloseHandle(c[0].done_sem); 92 93 av_freep(&s->thread_opaque); 94} 95 96static int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size){ 97 ThreadContext *c= s->thread_opaque; 98 int i; 99 int jobnr = 0; 100 101 assert(s == c->avctx); 102 103 /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */ 104 105 for(i=0; i<s->thread_count; i++){ 106 c[i].arg= arg; 107 c[i].argsize= size; 108 c[i].func= func; 109 c[i].ret= ret; 110 c[i].jobnr = &jobnr; 111 } 112 ReleaseSemaphore(c[0].work_sem, count, 0); 113 for(i=0; i<count; i++) 114 WaitForSingleObject(c[0].done_sem, INFINITE); 115 116 return 0; 117} 118 119static int avcodec_thread_execute2(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count){ 120 ThreadContext *c= s->thread_opaque; 121 int i; 122 for(i=0; i<s->thread_count; i++) 123 c[i].func2 = func; 124 avcodec_thread_execute(s, NULL, arg, ret, count, 0); 125} 126 127int avcodec_thread_init(AVCodecContext *s, int thread_count){ 128 int i; 129 ThreadContext *c; 130 uint32_t threadid; 131 132 s->thread_count= thread_count; 133 134 if (thread_count <= 1) 135 return 0; 136 137 assert(!s->thread_opaque); 138 c= av_mallocz(sizeof(ThreadContext)*thread_count); 139 s->thread_opaque= c; 140 if(!(c[0].work_sem = CreateSemaphore(NULL, 0, INT_MAX, NULL))) 141 goto fail; 142 if(!(c[0].job_sem = CreateSemaphore(NULL, 1, 1, NULL))) 143 goto fail; 144 if(!(c[0].done_sem = CreateSemaphore(NULL, 0, INT_MAX, NULL))) 145 goto fail; 146 147 for(i=0; i<thread_count; i++){ 148//printf("init semaphors %d\n", i); fflush(stdout); 149 c[i].avctx= s; 150 c[i].work_sem = c[0].work_sem; 151 c[i].job_sem = c[0].job_sem; 152 c[i].done_sem = c[0].done_sem; 153 c[i].threadnr = i; 154 155//printf("create thread %d\n", i); fflush(stdout); 156 c[i].thread = (HANDLE)_beginthreadex(NULL, 0, thread_func, &c[i], 0, &threadid ); 157 if( !c[i].thread ) goto fail; 158 } 159//printf("init done\n"); fflush(stdout); 160 161 s->execute= avcodec_thread_execute; 162 s->execute2= avcodec_thread_execute2; 163 164 return 0; 165fail: 166 avcodec_thread_free(s); 167 return -1; 168} 169