Libav
|
00001 /* 00002 * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> 00003 * 00004 * This file is part of FFmpeg. 00005 * 00006 * FFmpeg is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * FFmpeg is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with FFmpeg; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 //#define DEBUG 00021 00022 #include "avcodec.h" 00023 00024 #define WIN32_LEAN_AND_MEAN 00025 #include <windows.h> 00026 #include <process.h> 00027 00028 typedef struct ThreadContext{ 00029 AVCodecContext *avctx; 00030 HANDLE thread; 00031 HANDLE work_sem; 00032 HANDLE job_sem; 00033 HANDLE done_sem; 00034 int (*func)(AVCodecContext *c, void *arg); 00035 int (*func2)(AVCodecContext *c, void *arg, int, int); 00036 void *arg; 00037 int argsize; 00038 int *jobnr; 00039 int *ret; 00040 int threadnr; 00041 }ThreadContext; 00042 00043 00044 static unsigned WINAPI attribute_align_arg thread_func(void *v){ 00045 ThreadContext *c= v; 00046 00047 for(;;){ 00048 int ret, jobnr; 00049 //printf("thread_func %X enter wait\n", (int)v); fflush(stdout); 00050 WaitForSingleObject(c->work_sem, INFINITE); 00051 // avoid trying to access jobnr if we should quit 00052 if (!c->func && !c->func2) 00053 break; 00054 WaitForSingleObject(c->job_sem, INFINITE); 00055 jobnr = (*c->jobnr)++; 00056 ReleaseSemaphore(c->job_sem, 1, 0); 00057 //printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout); 00058 if(c->func) 00059 ret= c->func(c->avctx, (uint8_t *)c->arg + jobnr*c->argsize); 00060 else 00061 ret= c->func2(c->avctx, c->arg, jobnr, c->threadnr); 00062 if (c->ret) 00063 c->ret[jobnr] = ret; 00064 //printf("thread_func %X signal complete\n", (int)v); fflush(stdout); 00065 ReleaseSemaphore(c->done_sem, 1, 0); 00066 } 00067 00068 return 0; 00069 } 00070 00075 void avcodec_thread_free(AVCodecContext *s){ 00076 ThreadContext *c= s->thread_opaque; 00077 int i; 00078 00079 for(i=0; i<s->thread_count; i++){ 00080 00081 c[i].func= NULL; 00082 c[i].func2= NULL; 00083 } 00084 ReleaseSemaphore(c[0].work_sem, s->thread_count, 0); 00085 for(i=0; i<s->thread_count; i++){ 00086 WaitForSingleObject(c[i].thread, INFINITE); 00087 if(c[i].thread) CloseHandle(c[i].thread); 00088 } 00089 if(c[0].work_sem) CloseHandle(c[0].work_sem); 00090 if(c[0].job_sem) CloseHandle(c[0].job_sem); 00091 if(c[0].done_sem) CloseHandle(c[0].done_sem); 00092 00093 av_freep(&s->thread_opaque); 00094 } 00095 00096 static int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size){ 00097 ThreadContext *c= s->thread_opaque; 00098 int i; 00099 int jobnr = 0; 00100 00101 assert(s == c->avctx); 00102 00103 /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */ 00104 00105 for(i=0; i<s->thread_count; i++){ 00106 c[i].arg= arg; 00107 c[i].argsize= size; 00108 c[i].func= func; 00109 c[i].ret= ret; 00110 c[i].jobnr = &jobnr; 00111 } 00112 ReleaseSemaphore(c[0].work_sem, count, 0); 00113 for(i=0; i<count; i++) 00114 WaitForSingleObject(c[0].done_sem, INFINITE); 00115 00116 return 0; 00117 } 00118 00119 static int avcodec_thread_execute2(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count){ 00120 ThreadContext *c= s->thread_opaque; 00121 int i; 00122 for(i=0; i<s->thread_count; i++) 00123 c[i].func2 = func; 00124 avcodec_thread_execute(s, NULL, arg, ret, count, 0); 00125 } 00126 00127 int avcodec_thread_init(AVCodecContext *s, int thread_count){ 00128 int i; 00129 ThreadContext *c; 00130 uint32_t threadid; 00131 00132 s->thread_count= thread_count; 00133 00134 if (thread_count <= 1) 00135 return 0; 00136 00137 assert(!s->thread_opaque); 00138 c= av_mallocz(sizeof(ThreadContext)*thread_count); 00139 s->thread_opaque= c; 00140 if(!(c[0].work_sem = CreateSemaphore(NULL, 0, INT_MAX, NULL))) 00141 goto fail; 00142 if(!(c[0].job_sem = CreateSemaphore(NULL, 1, 1, NULL))) 00143 goto fail; 00144 if(!(c[0].done_sem = CreateSemaphore(NULL, 0, INT_MAX, NULL))) 00145 goto fail; 00146 00147 for(i=0; i<thread_count; i++){ 00148 //printf("init semaphors %d\n", i); fflush(stdout); 00149 c[i].avctx= s; 00150 c[i].work_sem = c[0].work_sem; 00151 c[i].job_sem = c[0].job_sem; 00152 c[i].done_sem = c[0].done_sem; 00153 c[i].threadnr = i; 00154 00155 //printf("create thread %d\n", i); fflush(stdout); 00156 c[i].thread = (HANDLE)_beginthreadex(NULL, 0, thread_func, &c[i], 0, &threadid ); 00157 if( !c[i].thread ) goto fail; 00158 } 00159 //printf("init done\n"); fflush(stdout); 00160 00161 s->execute= avcodec_thread_execute; 00162 s->execute2= avcodec_thread_execute2; 00163 00164 return 0; 00165 fail: 00166 avcodec_thread_free(s); 00167 return -1; 00168 }