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