1 #ifdef __cplusplus
2 extern "C" {
3 #endif
4 #include <libavformat/avformat.h>
5 #ifdef __cplusplus
6 }
7 #endif
8
9 #include <rthreads/rthreads.h>
10
11 #include "video_buffer.h"
12
13 enum kbStatus
14 {
15 KB_OPEN = 0,
16 KB_IN_PROGRESS,
17 KB_FINISHED
18 };
19
20 struct video_buffer
21 {
22 int64_t head;
23 int64_t tail;
24 video_decoder_context_t *buffer;
25 enum kbStatus *status;
26 slock_t *lock;
27 scond_t *open_cond;
28 scond_t *finished_cond;
29 size_t capacity;
30 };
31
video_buffer_create(size_t capacity,int frame_size,int width,int height)32 video_buffer_t *video_buffer_create(
33 size_t capacity, int frame_size, int width, int height)
34 {
35 unsigned i;
36 video_buffer_t *b = (video_buffer_t*)malloc(sizeof(video_buffer_t));
37 if (!b)
38 return NULL;
39
40 b->buffer = NULL;
41 b->capacity = capacity;
42 b->lock = NULL;
43 b->open_cond = NULL;
44 b->finished_cond = NULL;
45 b->head = 0;
46 b->tail = 0;
47 b->status = (enum kbStatus*)malloc(sizeof(enum kbStatus) * capacity);
48
49 if (!b->status)
50 goto fail;
51
52 for (i = 0; i < capacity; i++)
53 b->status[i] = KB_OPEN;
54
55 b->lock = slock_new();
56 b->open_cond = scond_new();
57 b->finished_cond = scond_new();
58 if (!b->lock || !b->open_cond || !b->finished_cond)
59 goto fail;
60
61 b->buffer = (video_decoder_context_t*)
62 malloc(sizeof(video_decoder_context_t) * capacity);
63 if (!b->buffer)
64 goto fail;
65
66 for (i = 0; i < (unsigned)capacity; i++)
67 {
68 b->buffer[i].index = i;
69 b->buffer[i].pts = 0;
70 b->buffer[i].sws = sws_alloc_context();
71 b->buffer[i].source = av_frame_alloc();
72 #if LIBAVUTIL_VERSION_MAJOR > 55
73 b->buffer[i].hw_source = av_frame_alloc();
74 #endif
75 b->buffer[i].target = av_frame_alloc();
76
77 avpicture_alloc((AVPicture*)b->buffer[i].target,
78 PIX_FMT_RGB32, width, height);
79
80 if (!b->buffer[i].sws ||
81 !b->buffer[i].source ||
82 #if LIBAVUTIL_VERSION_MAJOR > 55
83 !b->buffer[i].hw_source ||
84 #endif
85 !b->buffer[i].target)
86 goto fail;
87 }
88 return b;
89
90 fail:
91 video_buffer_destroy(b);
92 return NULL;
93 }
94
video_buffer_destroy(video_buffer_t * video_buffer)95 void video_buffer_destroy(video_buffer_t *video_buffer)
96 {
97 unsigned i;
98 if (!video_buffer)
99 return;
100
101 slock_free(video_buffer->lock);
102 scond_free(video_buffer->open_cond);
103 scond_free(video_buffer->finished_cond);
104 free(video_buffer->status);
105 if (video_buffer->buffer)
106 {
107 for (i = 0; i < video_buffer->capacity; i++)
108 {
109 #if LIBAVUTIL_VERSION_MAJOR > 55
110 av_frame_free(&video_buffer->buffer[i].hw_source);
111 #endif
112 av_frame_free(&video_buffer->buffer[i].source);
113 avpicture_free((AVPicture*)video_buffer->buffer[i].target);
114 av_frame_free(&video_buffer->buffer[i].target);
115 sws_freeContext(video_buffer->buffer[i].sws);
116 }
117 }
118 free(video_buffer->buffer);
119 free(video_buffer);
120 }
121
video_buffer_clear(video_buffer_t * video_buffer)122 void video_buffer_clear(video_buffer_t *video_buffer)
123 {
124 unsigned i;
125 if (!video_buffer)
126 return;
127
128 slock_lock(video_buffer->lock);
129
130 scond_signal(video_buffer->open_cond);
131 scond_signal(video_buffer->finished_cond);
132
133 video_buffer->head = 0;
134 video_buffer->tail = 0;
135 for (i = 0; i < video_buffer->capacity; i++)
136 video_buffer->status[i] = KB_OPEN;
137
138 slock_unlock(video_buffer->lock);
139 }
140
video_buffer_get_open_slot(video_buffer_t * video_buffer,video_decoder_context_t ** context)141 void video_buffer_get_open_slot(
142 video_buffer_t *video_buffer, video_decoder_context_t **context)
143 {
144 slock_lock(video_buffer->lock);
145
146 if (video_buffer->status[video_buffer->head] == KB_OPEN)
147 {
148 *context = &video_buffer->buffer[video_buffer->head];
149 video_buffer->status[video_buffer->head] = KB_IN_PROGRESS;
150 video_buffer->head++;
151 video_buffer->head %= video_buffer->capacity;
152 }
153
154 slock_unlock(video_buffer->lock);
155 }
156
video_buffer_return_open_slot(video_buffer_t * video_buffer,video_decoder_context_t * context)157 void video_buffer_return_open_slot(
158 video_buffer_t *video_buffer, video_decoder_context_t *context)
159 {
160 slock_lock(video_buffer->lock);
161
162 if (video_buffer->status[context->index] == KB_IN_PROGRESS)
163 {
164 video_buffer->status[context->index] = KB_OPEN;
165 video_buffer->head--;
166 video_buffer->head %= video_buffer->capacity;
167 }
168
169 slock_unlock(video_buffer->lock);
170 }
171
video_buffer_open_slot(video_buffer_t * video_buffer,video_decoder_context_t * context)172 void video_buffer_open_slot(
173 video_buffer_t *video_buffer,
174 video_decoder_context_t *context)
175 {
176 slock_lock(video_buffer->lock);
177
178 if (video_buffer->status[context->index] == KB_FINISHED)
179 {
180 video_buffer->status[context->index] = KB_OPEN;
181 video_buffer->tail++;
182 video_buffer->tail %= (video_buffer->capacity);
183 scond_signal(video_buffer->open_cond);
184 }
185
186 slock_unlock(video_buffer->lock);
187 }
188
video_buffer_get_finished_slot(video_buffer_t * video_buffer,video_decoder_context_t ** context)189 void video_buffer_get_finished_slot(
190 video_buffer_t *video_buffer,
191 video_decoder_context_t **context)
192 {
193 slock_lock(video_buffer->lock);
194
195 if (video_buffer->status[video_buffer->tail] == KB_FINISHED)
196 *context = &video_buffer->buffer[video_buffer->tail];
197
198 slock_unlock(video_buffer->lock);
199 }
200
video_buffer_finish_slot(video_buffer_t * video_buffer,video_decoder_context_t * context)201 void video_buffer_finish_slot(
202 video_buffer_t *video_buffer,
203 video_decoder_context_t *context)
204 {
205 slock_lock(video_buffer->lock);
206
207 if (video_buffer->status[context->index] == KB_IN_PROGRESS)
208 {
209 video_buffer->status[context->index] = KB_FINISHED;
210 scond_signal(video_buffer->finished_cond);
211 }
212
213 slock_unlock(video_buffer->lock);
214 }
215
video_buffer_wait_for_open_slot(video_buffer_t * video_buffer)216 bool video_buffer_wait_for_open_slot(video_buffer_t *video_buffer)
217 {
218 slock_lock(video_buffer->lock);
219
220 while (video_buffer->status[video_buffer->head] != KB_OPEN)
221 scond_wait(video_buffer->open_cond, video_buffer->lock);
222
223 slock_unlock(video_buffer->lock);
224
225 return true;
226 }
227
video_buffer_wait_for_finished_slot(video_buffer_t * video_buffer)228 bool video_buffer_wait_for_finished_slot(video_buffer_t *video_buffer)
229 {
230 slock_lock(video_buffer->lock);
231
232 while (video_buffer->status[video_buffer->tail] != KB_FINISHED)
233 scond_wait(video_buffer->finished_cond, video_buffer->lock);
234
235 slock_unlock(video_buffer->lock);
236
237 return true;
238 }
239
video_buffer_has_open_slot(video_buffer_t * video_buffer)240 bool video_buffer_has_open_slot(video_buffer_t *video_buffer)
241 {
242 bool ret = false;
243
244 slock_lock(video_buffer->lock);
245
246 if (video_buffer->status[video_buffer->head] == KB_OPEN)
247 ret = true;
248
249 slock_unlock(video_buffer->lock);
250
251 return ret;
252 }
253
video_buffer_has_finished_slot(video_buffer_t * video_buffer)254 bool video_buffer_has_finished_slot(video_buffer_t *video_buffer)
255 {
256 bool ret = false;
257
258 slock_lock(video_buffer->lock);
259
260 if (video_buffer->status[video_buffer->tail] == KB_FINISHED)
261 ret = true;
262
263 slock_unlock(video_buffer->lock);
264
265 return ret;
266 }
267