ffmpeg / libavcodec / beosthread.c @ 5509bffa
History | View | Annotate | Download (4.69 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2004 François Revol <revol@free.fr>
|
3 |
*
|
4 |
* This library is free software; you can redistribute it and/or
|
5 |
* modify it under the terms of the GNU Lesser General Public
|
6 |
* License as published by the Free Software Foundation; either
|
7 |
* version 2 of the License, or (at your option) any later version.
|
8 |
*
|
9 |
* This library is distributed in the hope that it will be useful,
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12 |
* Lesser General Public License for more details.
|
13 |
*
|
14 |
* You should have received a copy of the GNU Lesser General Public
|
15 |
* License along with this library; if not, write to the Free Software
|
16 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17 |
*
|
18 |
*/
|
19 |
//#define DEBUG
|
20 |
|
21 |
#include "avcodec.h" |
22 |
#include "common.h" |
23 |
|
24 |
#include <OS.h> |
25 |
|
26 |
typedef struct ThreadContext{ |
27 |
AVCodecContext *avctx; |
28 |
thread_id thread; |
29 |
sem_id work_sem; |
30 |
sem_id done_sem; |
31 |
int (*func)(AVCodecContext *c, void *arg); |
32 |
void *arg;
|
33 |
int ret;
|
34 |
}ThreadContext; |
35 |
|
36 |
// it's odd Be never patented that :D
|
37 |
struct benaphore {
|
38 |
vint32 atom; |
39 |
sem_id sem; |
40 |
}; |
41 |
static inline int lock_ben(struct benaphore *ben) |
42 |
{ |
43 |
if (atomic_add(&ben->atom, 1) > 0) |
44 |
return acquire_sem(ben->sem);
|
45 |
return B_OK;
|
46 |
} |
47 |
static inline int unlock_ben(struct benaphore *ben) |
48 |
{ |
49 |
if (atomic_add(&ben->atom, -1) > 1) |
50 |
return release_sem(ben->sem);
|
51 |
return B_OK;
|
52 |
} |
53 |
|
54 |
static struct benaphore av_thread_lib_ben; |
55 |
|
56 |
static int32 ff_thread_func(void *v){ |
57 |
ThreadContext *c= v; |
58 |
|
59 |
for(;;){
|
60 |
//printf("thread_func %X enter wait\n", (int)v); fflush(stdout);
|
61 |
acquire_sem(c->work_sem); |
62 |
//printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout);
|
63 |
if(c->func)
|
64 |
c->ret= c->func(c->avctx, c->arg); |
65 |
else
|
66 |
return 0; |
67 |
//printf("thread_func %X signal complete\n", (int)v); fflush(stdout);
|
68 |
release_sem(c->done_sem); |
69 |
} |
70 |
|
71 |
return B_OK;
|
72 |
} |
73 |
|
74 |
/**
|
75 |
* free what has been allocated by avcodec_thread_init().
|
76 |
* must be called after decoding has finished, especially dont call while avcodec_thread_execute() is running
|
77 |
*/
|
78 |
void avcodec_thread_free(AVCodecContext *s){
|
79 |
ThreadContext *c= s->thread_opaque; |
80 |
int i;
|
81 |
int32 ret; |
82 |
|
83 |
for(i=0; i<s->thread_count; i++){ |
84 |
|
85 |
c[i].func= NULL;
|
86 |
release_sem(c[i].work_sem); |
87 |
wait_for_thread(c[i].thread, &ret); |
88 |
if(c[i].work_sem > B_OK) delete_sem(c[i].work_sem);
|
89 |
if(c[i].done_sem > B_OK) delete_sem(c[i].done_sem);
|
90 |
} |
91 |
|
92 |
av_freep(&s->thread_opaque); |
93 |
} |
94 |
|
95 |
int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count){ |
96 |
ThreadContext *c= s->thread_opaque; |
97 |
int i;
|
98 |
|
99 |
assert(s == c->avctx); |
100 |
assert(count <= s->thread_count); |
101 |
|
102 |
/* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */
|
103 |
|
104 |
for(i=0; i<count; i++){ |
105 |
c[i].arg= arg[i]; |
106 |
c[i].func= func; |
107 |
c[i].ret= 12345;
|
108 |
|
109 |
release_sem(c[i].work_sem); |
110 |
} |
111 |
for(i=0; i<count; i++){ |
112 |
acquire_sem(c[i].done_sem); |
113 |
|
114 |
c[i].func= NULL;
|
115 |
if(ret) ret[i]= c[i].ret;
|
116 |
} |
117 |
return 0; |
118 |
} |
119 |
|
120 |
int avcodec_thread_init(AVCodecContext *s, int thread_count){ |
121 |
int i;
|
122 |
ThreadContext *c; |
123 |
|
124 |
s->thread_count= thread_count; |
125 |
|
126 |
assert(!s->thread_opaque); |
127 |
c= av_mallocz(sizeof(ThreadContext)*thread_count);
|
128 |
s->thread_opaque= c; |
129 |
|
130 |
for(i=0; i<thread_count; i++){ |
131 |
//printf("init semaphors %d\n", i); fflush(stdout);
|
132 |
c[i].avctx= s; |
133 |
|
134 |
if((c[i].work_sem = create_sem(0, "ff work sem")) < B_OK) |
135 |
goto fail;
|
136 |
if((c[i].done_sem = create_sem(0, "ff done sem")) < B_OK) |
137 |
goto fail;
|
138 |
|
139 |
//printf("create thread %d\n", i); fflush(stdout);
|
140 |
c[i].thread = spawn_thread(ff_thread_func, "libavcodec thread", B_LOW_PRIORITY, &c[i] );
|
141 |
if( c[i].thread < B_OK ) goto fail; |
142 |
resume_thread(c[i].thread ); |
143 |
} |
144 |
//printf("init done\n"); fflush(stdout);
|
145 |
|
146 |
s->execute= avcodec_thread_execute; |
147 |
|
148 |
return 0; |
149 |
fail:
|
150 |
avcodec_thread_free(s); |
151 |
return -1; |
152 |
} |
153 |
|
154 |
/* provide a mean to serialize calls to avcodec_*() for thread safety. */
|
155 |
|
156 |
int avcodec_thread_lock_lib(void) |
157 |
{ |
158 |
return lock_ben(&av_thread_lib_ben);
|
159 |
} |
160 |
|
161 |
int avcodec_thread_unlock_lib(void) |
162 |
{ |
163 |
return unlock_ben(&av_thread_lib_ben);
|
164 |
} |
165 |
|
166 |
/* our versions of _init and _fini (which are called by those actually from crt.o) */
|
167 |
|
168 |
void initialize_after(void) |
169 |
{ |
170 |
av_thread_lib_ben.atom = 0;
|
171 |
av_thread_lib_ben.sem = create_sem(0, "libavcodec benaphore"); |
172 |
} |
173 |
|
174 |
void uninitialize_before(void) |
175 |
{ |
176 |
delete_sem(av_thread_lib_ben.sem); |
177 |
} |
178 |
|
179 |
|
180 |
|