| rev |
line source |
|
nengel@2
|
1 #include "config.h"
|
|
nengel@2
|
2
|
|
nengel@2
|
3 #include "h264_types.h"
|
|
nengel@2
|
4
|
|
nengel@2
|
5 #include <unistd.h>
|
|
nengel@2
|
6 #include <sys/resource.h>
|
|
nengel@2
|
7 #include <sys/time.h>
|
|
nengel@2
|
8 #include <time.h>
|
|
nengel@2
|
9 #include <pthread.h>
|
|
nengel@2
|
10 #undef NDEBUG
|
|
nengel@2
|
11 #include <assert.h>
|
|
nengel@2
|
12
|
|
nengel@2
|
13 #if HAVE_LIBSDL2
|
|
nengel@2
|
14 #include <SDL2/SDL.h>
|
|
nengel@2
|
15 #if HAVE_LIBSDL_TTF
|
|
nengel@2
|
16 #include <SDL/SDL_ttf.h>
|
|
nengel@2
|
17 #endif
|
|
nengel@2
|
18 #endif
|
|
nengel@2
|
19
|
|
nengel@2
|
20 void start_timer(H264Context *h, int stage){
|
|
nengel@2
|
21 clock_gettime(CLOCK_REALTIME, &h->start_time[stage]);
|
|
nengel@2
|
22 }
|
|
nengel@2
|
23
|
|
nengel@2
|
24 void stop_timer(H264Context *h, int stage){
|
|
nengel@2
|
25 clock_gettime(CLOCK_REALTIME, &h->end_time[stage]);
|
|
nengel@2
|
26 double time = (double) 1.e3*(h->end_time[stage].tv_sec - h->start_time[stage].tv_sec) + 1.e-6*(h->end_time[stage].tv_nsec - h->start_time[stage].tv_nsec);
|
|
nengel@2
|
27 h->last_time [stage] = time;
|
|
nengel@2
|
28 h->total_time[stage] += time;
|
|
nengel@2
|
29 }
|
|
nengel@2
|
30
|
|
nengel@2
|
31 void init_sb_entry(H264Context *h, SliceBufferEntry *sbe){
|
|
nengel@2
|
32 sbe->mbs = av_malloc(h->mb_width*h->mb_height* sizeof(H264Mb));
|
|
nengel@2
|
33 sbe->initialized = 1;
|
|
nengel@2
|
34 }
|
|
nengel@2
|
35
|
|
nengel@2
|
36 void free_sb_entry(SliceBufferEntry *sbe){
|
|
nengel@2
|
37 av_free(sbe->mbs);
|
|
nengel@2
|
38 av_freep(&sbe->gb.raw);
|
|
nengel@2
|
39 if (sbe->gb.rbsp)
|
|
nengel@2
|
40 av_freep(&sbe->gb.rbsp);
|
|
nengel@2
|
41 sbe->initialized = 0;
|
|
nengel@2
|
42 }
|
|
nengel@2
|
43
|
|
nengel@2
|
44 SliceBufferEntry *get_sb_entry(H264Context *h){
|
|
nengel@2
|
45 SliceBufferEntry *sb = NULL;
|
|
nengel@2
|
46
|
|
nengel@2
|
47 pthread_mutex_lock(&h->lock[PARSE]);
|
|
nengel@2
|
48 while (h->free_sb_cnt<=0)
|
|
nengel@2
|
49 pthread_cond_wait(&h->cond[PARSE], &h->lock[PARSE]);
|
|
nengel@2
|
50 /* use first free picture */
|
|
nengel@2
|
51 for(int i=0; i<h->sb_size; i++){
|
|
nengel@2
|
52 if(h->sb[i].state==0){
|
|
nengel@2
|
53 sb= &h->sb[i];
|
|
nengel@2
|
54 sb->state=1;
|
|
nengel@2
|
55 sb->lines_taken=0;
|
|
nengel@2
|
56 sb->lines_total=h->mb_height;
|
|
nengel@2
|
57 break;
|
|
nengel@2
|
58 }
|
|
nengel@2
|
59 }
|
|
nengel@2
|
60 h->free_sb_cnt--;
|
|
nengel@2
|
61
|
|
nengel@2
|
62 pthread_mutex_unlock(&h->lock[PARSE]);
|
|
nengel@2
|
63
|
|
nengel@2
|
64 memset (&sb->slice, 0, sizeof(H264Slice));
|
|
nengel@2
|
65
|
|
nengel@2
|
66 return sb;
|
|
nengel@2
|
67 }
|
|
nengel@2
|
68
|
|
nengel@2
|
69 void release_sb_entry(H264Context *h, SliceBufferEntry *sb){
|
|
nengel@2
|
70 pthread_mutex_lock(&h->lock[PARSE]);
|
|
nengel@2
|
71
|
|
nengel@2
|
72 sb->state = 0;
|
|
nengel@2
|
73 h->free_sb_cnt++;
|
|
nengel@2
|
74 pthread_cond_signal(&h->cond[PARSE]);
|
|
nengel@2
|
75
|
|
nengel@2
|
76 pthread_mutex_unlock(&h->lock[PARSE]);
|
|
nengel@2
|
77 }
|
|
nengel@2
|
78
|
|
nengel@2
|
79 int init_dpb_entry(H264Context *h, DecodedPicture *pic, H264Slice *s, int width, int height){
|
|
nengel@2
|
80 int i;
|
|
nengel@2
|
81
|
|
nengel@2
|
82 s->curr_pic=pic;
|
|
nengel@2
|
83 pic->poc = s->poc;
|
|
nengel@2
|
84 pic->key_frame = s->key_frame;
|
|
nengel@2
|
85 pic->mmco_reset = s->mmco_reset;
|
|
nengel@2
|
86 pic->reference = s->nal_ref_idc? 3:1;
|
|
nengel@2
|
87 pic->cpn = s->coded_pic_num;
|
|
nengel@2
|
88
|
|
nengel@2
|
89 if(pic->data[0]==NULL) {
|
|
nengel@2
|
90 int size[3] = {0};
|
|
nengel@2
|
91
|
|
nengel@2
|
92 width+= EDGE_WIDTH*2;
|
|
nengel@2
|
93 height+= EDGE_WIDTH*2;
|
|
nengel@2
|
94
|
|
nengel@2
|
95 pic->linesize[0]= width;
|
|
nengel@2
|
96 pic->linesize[1]= pic->linesize[2] = width>>1;
|
|
nengel@2
|
97
|
|
nengel@2
|
98 size[0] = width*height;
|
|
nengel@2
|
99 size[1] = size[2] = width*height>>2;
|
|
nengel@2
|
100
|
|
nengel@2
|
101 for(i=0; i<3; i++){
|
|
nengel@2
|
102 pic->base[i]= av_malloc(size[i]);
|
|
nengel@2
|
103 }
|
|
nengel@2
|
104
|
|
nengel@2
|
105 pic->data[0] = pic->base[0] + (pic->linesize[0]*EDGE_WIDTH) + EDGE_WIDTH;
|
|
nengel@2
|
106 pic->data[1] = pic->base[1] + (pic->linesize[1]*EDGE_WIDTH>>1) + (EDGE_WIDTH>>1);
|
|
nengel@2
|
107 pic->data[2] = pic->base[2] + (pic->linesize[2]*EDGE_WIDTH>>1) + (EDGE_WIDTH>>1);
|
|
nengel@2
|
108 }
|
|
nengel@2
|
109
|
|
nengel@2
|
110 const int big_mb_num= h->mb_stride*(h->mb_height+1) + 1; //the +1 is needed so memset(,,stride*height) does not sig11
|
|
nengel@2
|
111 const int mb_array_size= h->mb_stride*h->mb_height;
|
|
nengel@2
|
112 const int b4_array_size= h->b4_stride*h->mb_height*4;
|
|
nengel@2
|
113
|
|
nengel@2
|
114 if(pic->mb_type_base==NULL){
|
|
nengel@2
|
115 FF_ALLOCZ_OR_GOTO(pic->mb_type_base , big_mb_num * sizeof(uint32_t), fail)
|
|
nengel@2
|
116 pic->mb_type= pic->mb_type_base + h->mb_stride+1;
|
|
nengel@2
|
117
|
|
nengel@2
|
118 for(int i=0; i<2; i++){
|
|
nengel@2
|
119 FF_ALLOCZ_OR_GOTO(pic->motion_val_base[i], 2 * (b4_array_size+4) * sizeof(int16_t), fail)
|
|
nengel@2
|
120 pic->motion_val[i]= pic->motion_val_base[i]+4;
|
|
nengel@2
|
121 FF_ALLOCZ_OR_GOTO(pic->ref_index[i], 4*mb_array_size * sizeof(uint8_t), fail)
|
|
nengel@2
|
122 }
|
|
nengel@2
|
123 FF_ALLOCZ_OR_GOTO(pic->intra4x4_pred_mode, h->mb_width*h->mb_height * 4* sizeof(int8_t), fail)
|
|
nengel@2
|
124 }
|
|
nengel@2
|
125
|
|
nengel@2
|
126 return 0;
|
|
nengel@2
|
127 fail:
|
|
nengel@2
|
128 return -1;
|
|
nengel@2
|
129 }
|
|
nengel@2
|
130
|
|
nengel@2
|
131 void free_dp(DecodedPicture *pic){
|
|
nengel@2
|
132 if(pic->base[0]){
|
|
nengel@2
|
133 for (int i=0; i<3; i++){
|
|
nengel@2
|
134 av_free(pic->base[i]);
|
|
nengel@2
|
135 pic->data[i]= NULL;
|
|
nengel@2
|
136 }
|
|
nengel@2
|
137 }
|
|
nengel@2
|
138 if (pic->mb_type_base){
|
|
nengel@2
|
139 av_free(pic->mb_type_base);
|
|
nengel@2
|
140 pic->mb_type= NULL;
|
|
nengel@2
|
141 for(int i=0; i<2; i++){
|
|
nengel@2
|
142 av_free(pic->motion_val_base[i]);
|
|
nengel@2
|
143 av_free(pic->ref_index[i]);
|
|
nengel@2
|
144 }
|
|
nengel@2
|
145 av_free(pic->intra4x4_pred_mode);
|
|
nengel@2
|
146 }
|
|
nengel@2
|
147 }
|
|
nengel@2
|
148
|
|
nengel@2
|
149 DecodedPicture *get_dpb_entry(H264Context *h, H264Slice *s){
|
|
nengel@2
|
150 DecodedPicture *dp = NULL;
|
|
nengel@2
|
151
|
|
nengel@2
|
152 pthread_mutex_lock(&h->lock[REORDER2]);
|
|
nengel@2
|
153 while (h->free_dpb_cnt<=0){
|
|
nengel@2
|
154 #if OMPSS
|
|
nengel@2
|
155 assert(0);
|
|
nengel@2
|
156 #endif
|
|
nengel@2
|
157 pthread_cond_wait(&h->cond[REORDER2], &h->lock[REORDER2]);
|
|
nengel@2
|
158 }
|
|
nengel@2
|
159 /* use first free picture */
|
|
nengel@2
|
160 for(int i=0; i<h->max_dpb_cnt; i++){
|
|
nengel@2
|
161 if(h->dpb[i].reference==0){
|
|
nengel@2
|
162 dp= &h->dpb[i];
|
|
nengel@2
|
163 break;
|
|
nengel@2
|
164 }
|
|
nengel@2
|
165 }
|
|
nengel@2
|
166 assert(dp);
|
|
nengel@2
|
167 init_dpb_entry(h, dp, s, h->width, h->height);
|
|
nengel@2
|
168 h->free_dpb_cnt--;
|
|
nengel@2
|
169 h->acdpb_cnt++; //debug
|
|
nengel@2
|
170 pthread_mutex_unlock(&h->lock[REORDER2]);
|
|
nengel@2
|
171
|
|
nengel@2
|
172 return dp;
|
|
nengel@2
|
173 }
|
|
nengel@2
|
174
|
|
nengel@2
|
175 void release_dpb_entry(H264Context *h, DecodedPicture *pic, int mode){
|
|
nengel@2
|
176 pthread_mutex_lock(&h->lock[REORDER2]);
|
|
nengel@2
|
177 pic->reference &= ~mode;
|
|
nengel@2
|
178 if (pic->reference == 0){
|
|
nengel@2
|
179 h->free_dpb_cnt++;
|
|
nengel@2
|
180 h->reldpb_cnt++; //debug
|
|
nengel@2
|
181 pthread_cond_signal(&h->cond[REORDER2]);
|
|
nengel@2
|
182 }
|
|
nengel@2
|
183 pthread_mutex_unlock(&h->lock[REORDER2]);
|
|
nengel@2
|
184 }
|
|
nengel@2
|
185
|
|
nengel@2
|
186
|
|
nengel@2
|
187 /**
|
|
nengel@2
|
188 * Extends the edges of a macroblock line.
|
|
nengel@2
|
189 */
|
|
nengel@2
|
190 void draw_edges(MBRecContext *d, H264Slice *s, int line){
|
|
nengel@2
|
191 int i;
|
|
nengel@2
|
192 int mb_width=d->mb_width;
|
|
nengel@2
|
193 int mb_height=d->mb_height;
|
|
nengel@2
|
194 int last = (line+1 == mb_height);
|
|
nengel@2
|
195 int lines = last?16:12;
|
|
nengel@2
|
196 int linesize = d->linesize;
|
|
nengel@2
|
197 int uvlinesize = d->uvlinesize;
|
|
nengel@2
|
198 uint8_t *y = s->curr_pic->data[0] + 16*line*linesize;
|
|
nengel@2
|
199 uint8_t *cb = s->curr_pic->data[1] + 8*line*uvlinesize;
|
|
nengel@2
|
200 uint8_t *cr = s->curr_pic->data[2] + 8*line*uvlinesize;
|
|
nengel@2
|
201
|
|
nengel@2
|
202 for (i=-4; i<lines; i++){
|
|
nengel@2
|
203 memset(y + i*linesize - EDGE_WIDTH, y[i*linesize], EDGE_WIDTH);
|
|
nengel@2
|
204 memset(y + i*linesize + mb_width*16, y[i*linesize +mb_width*16 -1], EDGE_WIDTH);
|
|
nengel@2
|
205 }
|
|
nengel@2
|
206 for (i=-2; i<lines/2; i++){
|
|
nengel@2
|
207 memset(cb + i*uvlinesize - EDGE_WIDTH/2, cb[i*uvlinesize], EDGE_WIDTH/2);
|
|
nengel@2
|
208 memset(cb + i*uvlinesize + mb_width*8, cb[i*uvlinesize +mb_width*8 -1], EDGE_WIDTH/2);
|
|
nengel@2
|
209 memset(cr + i*uvlinesize - EDGE_WIDTH/2, cr[i*uvlinesize], EDGE_WIDTH/2);
|
|
nengel@2
|
210 memset(cr + i*uvlinesize + mb_width*8, cr[i*uvlinesize +mb_width*8 -1], EDGE_WIDTH/2);
|
|
nengel@2
|
211 }
|
|
nengel@2
|
212
|
|
nengel@2
|
213 if (line==0){
|
|
nengel@2
|
214 y -= EDGE_WIDTH;
|
|
nengel@2
|
215 cb -= EDGE_WIDTH/2;
|
|
nengel@2
|
216 cr -= EDGE_WIDTH/2;
|
|
nengel@2
|
217 for (i=1; i<=21; i++){
|
|
nengel@2
|
218 memcpy(y -i*linesize, y, linesize);
|
|
nengel@2
|
219 }
|
|
nengel@2
|
220 for (i=1; i<=9; i++){
|
|
nengel@2
|
221 memcpy(cb -i*uvlinesize, cb, uvlinesize);
|
|
nengel@2
|
222 memcpy(cr -i*uvlinesize, cr, uvlinesize);
|
|
nengel@2
|
223 }
|
|
nengel@2
|
224 }else if (last){
|
|
nengel@2
|
225 y += -EDGE_WIDTH + 15*linesize;
|
|
nengel@2
|
226 cb += -EDGE_WIDTH/2 + 7*uvlinesize;
|
|
nengel@2
|
227 cr += -EDGE_WIDTH/2 + 7*uvlinesize;
|
|
nengel@2
|
228 for (i=1; i<=21; i++){
|
|
nengel@2
|
229 memcpy(y +i*linesize, y, linesize);
|
|
nengel@2
|
230 }
|
|
nengel@2
|
231 for (i=1; i<=9; i++){
|
|
nengel@2
|
232 memcpy(cb +i*uvlinesize, cb, uvlinesize);
|
|
nengel@2
|
233 memcpy(cr +i*uvlinesize, cr, uvlinesize);
|
|
nengel@2
|
234 }
|
|
nengel@2
|
235 }
|
|
nengel@2
|
236 }
|
|
nengel@2
|
237
|
|
nengel@2
|
238 static int64_t timer_start;
|
|
nengel@2
|
239 int64_t av_gettime(void) {
|
|
nengel@2
|
240 struct timeval tv;
|
|
nengel@2
|
241 gettimeofday(&tv,NULL);
|
|
nengel@2
|
242 return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
|
|
nengel@2
|
243 }
|
|
nengel@2
|
244
|
|
nengel@2
|
245 void av_start_timer(){
|
|
nengel@2
|
246 timer_start = av_gettime();
|
|
nengel@2
|
247 }
|
|
nengel@2
|
248
|
|
nengel@2
|
249 void print_report(int frame_number, uint64_t video_size, int is_last_report, int verbose) {
|
|
nengel@2
|
250 static int64_t last_time = -1;
|
|
nengel@2
|
251 static int64_t last_frame_number = 0;
|
|
nengel@2
|
252 float t=0, t2=0;
|
|
nengel@2
|
253 int64_t cur_time=0;
|
|
nengel@2
|
254
|
|
nengel@2
|
255 if (!is_last_report) {
|
|
nengel@2
|
256 /* display the report every 0.5 seconds */
|
|
nengel@2
|
257 cur_time = av_gettime();
|
|
nengel@2
|
258 if (last_time == -1) {
|
|
nengel@2
|
259 last_time = cur_time;
|
|
nengel@2
|
260 return;
|
|
nengel@2
|
261 }
|
|
nengel@2
|
262 if ((cur_time - last_time) < 500000)
|
|
nengel@2
|
263 return;
|
|
nengel@2
|
264 t = (cur_time-timer_start) / 1000000.0;
|
|
nengel@2
|
265 t2 = (cur_time-last_time) / 1000000.0;
|
|
nengel@2
|
266 }
|
|
nengel@2
|
267
|
|
nengel@2
|
268 if (verbose){
|
|
nengel@6
|
269 fprintf(stderr, "frame=%5d avgfps=%3d curfps=%3d\r", frame_number, (int)(frame_number/t+0.5), (int)((frame_number - last_frame_number)/t2+0.5) );
|
|
nengel@6
|
270 fflush(stderr);
|
|
nengel@2
|
271 }
|
|
nengel@2
|
272 last_frame_number = frame_number;
|
|
nengel@2
|
273 last_time = cur_time;
|
|
nengel@2
|
274
|
|
nengel@2
|
275 if (is_last_report){
|
|
nengel@2
|
276 t = (av_gettime()-timer_start) / 1000000.0;
|
|
nengel@6
|
277 fprintf(stderr, "%c[2Kframe=%5d avgfps=%3d\r", 27, frame_number, (int)(frame_number/t+0.5));
|
|
nengel@6
|
278 fprintf(stderr, "\n");
|
|
nengel@6
|
279 fprintf(stderr, "video:%1.0fkB\n", video_size/1024.0);
|
|
nengel@6
|
280 fflush(stderr);
|
|
nengel@2
|
281 }
|
|
nengel@2
|
282 }
|
|
nengel@2
|
283
|
|
nengel@2
|
284 /* Sort B-frames into display order */
|
|
nengel@2
|
285 static DecodedPicture *get_reordered_picture(OutputContext *w, int flush){
|
|
nengel@2
|
286 int i;
|
|
nengel@2
|
287 int out_idx = 0;
|
|
nengel@2
|
288 DecodedPicture *out = w->delayed_pic[0];
|
|
nengel@2
|
289
|
|
nengel@2
|
290 if (!out)
|
|
nengel@2
|
291 return NULL;
|
|
nengel@2
|
292
|
|
nengel@2
|
293 for(i=1; w->delayed_pic[i] && !w->delayed_pic[i]->key_frame && !w->delayed_pic[i]->mmco_reset; i++){
|
|
nengel@2
|
294 if(w->delayed_pic[i]->poc < out->poc){
|
|
nengel@2
|
295 out = w->delayed_pic[i];
|
|
nengel@2
|
296 out_idx = i;
|
|
nengel@2
|
297 }
|
|
nengel@2
|
298 }
|
|
nengel@2
|
299
|
|
nengel@2
|
300 if(w->dp_cnt > MAX_DELAYED_PIC_COUNT || flush) {
|
|
nengel@2
|
301 for(i=out_idx; w->delayed_pic[i]; i++)
|
|
nengel@2
|
302 w->delayed_pic[i] = w->delayed_pic[i+1];
|
|
nengel@2
|
303 w->dp_cnt--;
|
|
nengel@2
|
304 return out;
|
|
nengel@2
|
305 }
|
|
nengel@2
|
306 return NULL;
|
|
nengel@2
|
307 }
|
|
nengel@2
|
308
|
|
nengel@2
|
309 /**
|
|
nengel@2
|
310 * Remove the extra borders, and places the three parts of the image after each other.
|
|
nengel@2
|
311 */
|
|
nengel@2
|
312 static int raw_encode(const DecodedPicture* src, int width, int height, unsigned char *dest) {
|
|
nengel@2
|
313 int i, j;
|
|
nengel@2
|
314 /** To write entire image including extra borders*/
|
|
nengel@2
|
315 // int w = src->linesize[0];
|
|
nengel@2
|
316 // int h = height+64;
|
|
nengel@2
|
317 // int w2 = w>>1;
|
|
nengel@2
|
318 // int h2 = h>>1;
|
|
nengel@2
|
319 // int data_planes=3;
|
|
nengel@2
|
320 // int size = w * h + 2 *w2*h2;
|
|
nengel@2
|
321 // const unsigned char* s;
|
|
nengel@2
|
322 // for (i=0; i<data_planes; i++) {
|
|
nengel@2
|
323 // if (i == 1) {
|
|
nengel@2
|
324 // w = w2;
|
|
nengel@2
|
325 // h = h2;
|
|
nengel@2
|
326 // }
|
|
nengel@2
|
327 // s = src->base[i];
|
|
nengel@2
|
328 // for(j=0; j<h; j++) {
|
|
nengel@2
|
329 // memcpy(dest, s, src->linesize[i]);
|
|
nengel@2
|
330 // dest += w;
|
|
nengel@2
|
331 // s += src->linesize[i];
|
|
nengel@2
|
332 // }
|
|
nengel@2
|
333 // }
|
|
nengel@2
|
334
|
|
nengel@2
|
335 int w = (width*8 + 7)/8;
|
|
nengel@2
|
336 int h = height;
|
|
nengel@2
|
337 int w2 =((width >>1) * 8 + 7) / 8;
|
|
nengel@2
|
338 int h2 = ((height+1) >>1); //not sure about +1
|
|
nengel@2
|
339 int data_planes=3;
|
|
nengel@2
|
340 int size = w * h + 2 *w2*h2;
|
|
nengel@2
|
341 const unsigned char* s;
|
|
nengel@2
|
342
|
|
nengel@2
|
343
|
|
nengel@2
|
344 for (i=0; i<data_planes; i++) {
|
|
nengel@2
|
345 if (i == 1) {
|
|
nengel@2
|
346 w = w2;
|
|
nengel@2
|
347 h = h2;
|
|
nengel@2
|
348 }
|
|
nengel@2
|
349 s = src->data[i];
|
|
nengel@2
|
350 for(j=0; j<h; j++) {
|
|
nengel@2
|
351 memcpy(dest, s, w);
|
|
nengel@2
|
352 dest += w;
|
|
nengel@2
|
353 s += src->linesize[i];
|
|
nengel@2
|
354 }
|
|
nengel@2
|
355 }
|
|
nengel@2
|
356 return size;
|
|
nengel@2
|
357 }
|
|
nengel@2
|
358
|
|
nengel@2
|
359 #ifdef HAVE_LIBSDL2
|
|
nengel@2
|
360 static SDL_Texture *get_next_texture(H264Context *h, int side){
|
|
nengel@2
|
361 SDLTextureQueue *sdlq = &h->sdlq;
|
|
nengel@2
|
362 SDL_Texture *texture;
|
|
nengel@2
|
363 pthread_mutex_lock (&sdlq->sdl_lock);
|
|
nengel@2
|
364 if (side ){ //send
|
|
nengel@2
|
365 while (sdlq->ready >= sdlq->size)
|
|
nengel@2
|
366 pthread_cond_wait(&sdlq->sdl_cond, &sdlq->sdl_lock);
|
|
nengel@2
|
367 texture = sdlq->queue[sdlq->fi];
|
|
nengel@2
|
368 sdlq->fi++; sdlq->fi %= sdlq->size;
|
|
nengel@2
|
369 } else { //recv
|
|
nengel@2
|
370 while (sdlq->ready <= 0 && !sdlq->exit)
|
|
nengel@2
|
371 pthread_cond_wait(&sdlq->sdl_cond, &sdlq->sdl_lock);
|
|
nengel@2
|
372
|
|
nengel@2
|
373 if (sdlq->ready == 0 && sdlq->exit){
|
|
nengel@2
|
374 texture = NULL;
|
|
nengel@2
|
375 }else{
|
|
nengel@2
|
376 texture = sdlq->queue[sdlq->fo];
|
|
nengel@2
|
377 sdlq->fo++; sdlq->fo %= sdlq->size;
|
|
nengel@2
|
378 }
|
|
nengel@2
|
379 }
|
|
nengel@2
|
380 pthread_mutex_unlock(&sdlq->sdl_lock);
|
|
nengel@2
|
381
|
|
nengel@2
|
382 return texture;
|
|
nengel@2
|
383 }
|
|
nengel@2
|
384
|
|
nengel@2
|
385 static void signal_texture(H264Context *h, int side){
|
|
nengel@2
|
386 SDLTextureQueue *sdlq = &h->sdlq;
|
|
nengel@2
|
387 pthread_mutex_lock (&sdlq->sdl_lock);
|
|
nengel@2
|
388 if (side)
|
|
nengel@2
|
389 sdlq->ready++;
|
|
nengel@2
|
390 else
|
|
nengel@2
|
391 sdlq->ready--;
|
|
nengel@2
|
392 pthread_cond_signal(&sdlq->sdl_cond);
|
|
nengel@2
|
393 pthread_mutex_unlock(&sdlq->sdl_lock);
|
|
nengel@2
|
394 }
|
|
nengel@2
|
395
|
|
nengel@2
|
396 void signal_sdl_exit(H264Context *h){
|
|
nengel@2
|
397 SDLTextureQueue *sdlq = &h->sdlq;
|
|
nengel@2
|
398 pthread_mutex_lock (&sdlq->sdl_lock);
|
|
nengel@2
|
399 sdlq->exit=1;
|
|
nengel@2
|
400 pthread_cond_signal(&sdlq->sdl_cond);
|
|
nengel@2
|
401 pthread_mutex_unlock(&sdlq->sdl_lock);
|
|
nengel@2
|
402 }
|
|
nengel@2
|
403
|
|
nengel@2
|
404 static void display_frame(H264Context *h, OutputContext *w, int fd, DecodedPicture *in_picture, int frame_width, int frame_height, int dropable){
|
|
nengel@2
|
405 static int64_t last_time = -1;
|
|
nengel@2
|
406 int64_t cur_time;
|
|
nengel@2
|
407 // SDLContext *sdlc = h->sdlc;
|
|
nengel@2
|
408 uint8_t *iyuv_pixels;
|
|
nengel@2
|
409 int pitch;
|
|
nengel@2
|
410
|
|
nengel@2
|
411
|
|
nengel@2
|
412 if (last_time == -1){
|
|
nengel@2
|
413 last_time = av_gettime();
|
|
nengel@2
|
414 }
|
|
nengel@2
|
415
|
|
nengel@2
|
416
|
|
nengel@2
|
417 /* do not display frames that are less than 8.125 ms apart (120fps)*/
|
|
nengel@2
|
418 if (dropable){
|
|
nengel@2
|
419 cur_time = av_gettime();
|
|
nengel@2
|
420
|
|
nengel@2
|
421 if ((cur_time - last_time) < 8125)
|
|
nengel@2
|
422 return;
|
|
nengel@2
|
423
|
|
nengel@2
|
424 last_time =cur_time;
|
|
nengel@2
|
425 }
|
|
nengel@2
|
426
|
|
nengel@2
|
427 if(in_picture){
|
|
nengel@2
|
428
|
|
nengel@2
|
429 SDL_Texture *texture= get_next_texture(h, 1);
|
|
nengel@2
|
430
|
|
nengel@2
|
431 SDL_LockTexture( texture, NULL, (void **)&iyuv_pixels, &pitch );
|
|
nengel@2
|
432
|
|
nengel@2
|
433 raw_encode(in_picture, frame_width, frame_height, iyuv_pixels);
|
|
nengel@2
|
434
|
|
nengel@2
|
435 signal_texture(h, 1);
|
|
nengel@2
|
436 }
|
|
nengel@2
|
437 }
|
|
nengel@2
|
438 #endif
|
|
nengel@2
|
439
|
|
nengel@2
|
440 // TODO: Parallelize the raw_encode (either split frame or over frames)
|
|
nengel@2
|
441 static void do_video_out(OutputContext *w, int fd, DecodedPicture *in_picture, int frame_width, int frame_height) {
|
|
nengel@2
|
442 int size=0;
|
|
nengel@2
|
443 //remove extra borders
|
|
nengel@2
|
444
|
|
nengel@2
|
445 if(in_picture)
|
|
nengel@2
|
446 size= raw_encode(in_picture, frame_width, frame_height, w->bit_buffer);
|
|
nengel@2
|
447
|
|
nengel@2
|
448 if (size < 0) {
|
|
nengel@2
|
449 fprintf(stderr, "Video encoding failed\n");
|
|
nengel@2
|
450 }else {
|
|
nengel@2
|
451 if (write(fd, w->bit_buffer, size)<0)
|
|
nengel@2
|
452 fprintf(stderr, "Write frame failed\n");
|
|
nengel@2
|
453 }
|
|
nengel@2
|
454
|
|
nengel@2
|
455 w->video_size += size;
|
|
nengel@2
|
456 }
|
|
nengel@2
|
457
|
|
nengel@2
|
458 DecodedPicture *output_frame(H264Context *h, OutputContext *oc, DecodedPicture *pic, int fd, int frame_width, int frame_height) {
|
|
nengel@2
|
459 DecodedPicture *out;
|
|
nengel@2
|
460
|
|
nengel@2
|
461 if (pic){
|
|
nengel@2
|
462 oc->delayed_pic[oc->dp_cnt++]=pic;
|
|
nengel@2
|
463 out = get_reordered_picture(oc, 0);
|
|
nengel@2
|
464 }else{
|
|
nengel@2
|
465 out = get_reordered_picture(oc, 1);
|
|
nengel@2
|
466 }
|
|
nengel@2
|
467
|
|
nengel@2
|
468 if (out){
|
|
nengel@2
|
469 if (fd){
|
|
nengel@2
|
470 do_video_out(oc, fd, out, frame_width, frame_height);
|
|
nengel@2
|
471 }else{
|
|
nengel@2
|
472 #ifdef HAVE_LIBSDL2
|
|
nengel@2
|
473 if (h->display){
|
|
nengel@2
|
474 display_frame(h, oc, fd, out, frame_width, frame_height, !(pic==NULL));
|
|
nengel@2
|
475 }
|
|
nengel@2
|
476 #endif
|
|
nengel@2
|
477 }
|
|
nengel@2
|
478 oc->frame_number++;
|
|
nengel@2
|
479 }
|
|
nengel@2
|
480
|
|
nengel@2
|
481 return out;
|
|
nengel@2
|
482 }
|
|
nengel@2
|
483
|
|
nengel@2
|
484 OutputContext *get_output_context(H264Context *h){
|
|
nengel@2
|
485 const int frame_width=h->frame_width;
|
|
nengel@2
|
486 const int frame_height=h->frame_height;
|
|
nengel@2
|
487 const int frame_size = frame_width*frame_height;
|
|
nengel@2
|
488
|
|
nengel@2
|
489 OutputContext *oc = av_mallocz(sizeof(OutputContext));
|
|
nengel@2
|
490 oc->bit_buffer_size= FFMAX(1024*256, frame_size*2); // oversize a little bit to allow extra border write
|
|
nengel@2
|
491 oc->bit_buffer= av_mallocz(oc->bit_buffer_size);
|
|
nengel@2
|
492
|
|
nengel@2
|
493 return oc;
|
|
nengel@2
|
494 }
|
|
nengel@2
|
495
|
|
nengel@2
|
496 void free_output_context(OutputContext *oc){
|
|
nengel@2
|
497
|
|
nengel@2
|
498 av_free(oc->bit_buffer);
|
|
nengel@2
|
499 av_free(oc);
|
|
nengel@2
|
500 }
|
|
nengel@2
|
501
|
|
nengel@2
|
502 SuperMBContext *getSuperMBContext(H264Context *h, int smb_width, int smb_height){
|
|
nengel@2
|
503 SuperMBContext *smbc = av_mallocz(sizeof(SuperMBContext));
|
|
nengel@2
|
504
|
|
nengel@2
|
505 smbc->smb_width = smb_width;
|
|
nengel@2
|
506 smbc->smb_height = smb_height;
|
|
nengel@2
|
507
|
|
nengel@2
|
508 smbc->nsmb_height = h->mb_height / smbc->smb_height + (h->mb_height%smbc->smb_height ? 1:0); //only need one extra if mb_height was not dividable
|
|
nengel@2
|
509 smbc->nsmb_width = h->mb_width / smbc->smb_width;
|
|
nengel@2
|
510 while ( (smbc->nsmb_width * smbc->smb_width)-(smbc->smb_height-1) < h->mb_width )
|
|
nengel@2
|
511 smbc->nsmb_width++;
|
|
nengel@2
|
512
|
|
nengel@2
|
513 smbc->nsmb_3dheight= smbc->nsmb_height - ((h->mb_height/2)/smbc->smb_height +1); //assuming max motion vector of half the height
|
|
nengel@2
|
514
|
|
nengel@2
|
515 smbc->smbs[0] = av_malloc (smbc->nsmb_width * smbc->nsmb_height * sizeof(SuperMBTask));
|
|
nengel@2
|
516 smbc->smbs[1] = av_malloc (smbc->nsmb_width * smbc->nsmb_height * sizeof(SuperMBTask));
|
|
nengel@2
|
517 for (int y=0, i=0; i<smbc->nsmb_height; i++, y+=smbc->smb_height){
|
|
nengel@2
|
518 for (int x=0, j=0; j<smbc->nsmb_width; j++, x+=smbc->smb_width){
|
|
nengel@2
|
519 smbc->smbs[0][i*smbc->nsmb_width +j].smb_y = y;
|
|
nengel@2
|
520 smbc->smbs[0][i*smbc->nsmb_width +j].smb_x = x;
|
|
nengel@2
|
521 smbc->smbs[1][i*smbc->nsmb_width +j].smb_y = y;
|
|
nengel@2
|
522 smbc->smbs[1][i*smbc->nsmb_width +j].smb_x = x;
|
|
nengel@2
|
523 }
|
|
nengel@2
|
524 }
|
|
nengel@2
|
525
|
|
nengel@2
|
526 smbc->refcount = 1;
|
|
nengel@2
|
527
|
|
nengel@2
|
528 return smbc;
|
|
nengel@2
|
529 }
|
|
nengel@2
|
530
|
|
nengel@2
|
531 void freeSuperMBContext(SuperMBContext *smbc){
|
|
nengel@2
|
532 av_free(smbc->smbs[0]);
|
|
nengel@2
|
533 av_free(smbc->smbs[1]);
|
|
nengel@2
|
534 av_free(smbc);
|
|
nengel@2
|
535 }
|
|
nengel@2
|
536
|
|
nengel@2
|
537 SuperMBContext * acquire_smbc(H264Context *h ){
|
|
nengel@2
|
538 SuperMBContext *smbc;
|
|
nengel@2
|
539
|
|
nengel@2
|
540 pthread_mutex_lock (&h->smb_lock);
|
|
nengel@2
|
541 smbc = h->smbc;
|
|
nengel@2
|
542 smbc->refcount++;
|
|
nengel@2
|
543 pthread_mutex_unlock(&h->smb_lock);
|
|
nengel@2
|
544 return smbc;
|
|
nengel@2
|
545 }
|
|
nengel@2
|
546
|
|
nengel@2
|
547 void release_smbc(H264Context *h, SuperMBContext *smbc){
|
|
nengel@2
|
548 pthread_mutex_lock (&h->smb_lock);
|
|
nengel@2
|
549 smbc->refcount--;
|
|
nengel@2
|
550 if (smbc->refcount==0){
|
|
nengel@2
|
551 freeSuperMBContext(smbc);
|
|
nengel@2
|
552 }
|
|
nengel@2
|
553 pthread_mutex_unlock(&h->smb_lock);
|
|
nengel@2
|
554
|
|
nengel@2
|
555 }
|
|
nengel@2
|
556
|
|
nengel@2
|
557
|
|
nengel@2
|
558 #ifdef HAVE_LIBSDL2
|
|
nengel@2
|
559
|
|
nengel@2
|
560 // #if OMPSS
|
|
nengel@2
|
561 static void draw_sb_border(H264Context *h, uint32_t *rgba_pixels, int smb_x, int smb_y){
|
|
nengel@2
|
562 int mb_width = h->mb_width;
|
|
nengel@2
|
563 int mb_height = h->mb_height;
|
|
nengel@2
|
564 int width = h->frame_width;
|
|
nengel@2
|
565 int height = h->frame_height;
|
|
nengel@2
|
566
|
|
nengel@2
|
567 int mb_x = smb_x * h->smb_width;
|
|
nengel@2
|
568 int mb_y = smb_y * h->smb_height;
|
|
nengel@2
|
569
|
|
nengel@2
|
570 uint32_t pix= 0x0000FFC0;
|
|
nengel@2
|
571
|
|
nengel@2
|
572 for (int k=0, i=mb_y; i< mb_y + h->smb_height; i++, k++){
|
|
nengel@2
|
573 for (int l=0, j=mb_x -k ; j< mb_x - k + h->smb_width; j++, l++){
|
|
nengel@2
|
574 //outside frame
|
|
nengel@2
|
575 if (i<0 || i>=mb_height || j<0 || j>=mb_width) {
|
|
nengel@2
|
576 continue;
|
|
nengel@2
|
577 }
|
|
nengel@2
|
578
|
|
nengel@2
|
579 //draw top
|
|
nengel@2
|
580 if (i==0 || k==0 || l==0){
|
|
nengel@2
|
581 int mx = j*16;
|
|
nengel@2
|
582 int my = i*16;
|
|
nengel@2
|
583 uint32_t *top = rgba_pixels + my*width + mx;
|
|
nengel@2
|
584 int endx = mx+16 < width? 16: width-mx;
|
|
nengel@2
|
585
|
|
nengel@2
|
586 for (int x = 0; x<endx; x++){
|
|
nengel@2
|
587 top[x] = pix;
|
|
nengel@2
|
588 }
|
|
nengel@2
|
589 }
|
|
nengel@2
|
590
|
|
nengel@2
|
591 //draw bottom
|
|
nengel@2
|
592 if (i==mb_height-1 || k==h->smb_height-1 || l==h->smb_width-1){
|
|
nengel@2
|
593 int mx = j*16;
|
|
nengel@2
|
594 int my = i*16 + 15; my = my < height ? my: height-1;
|
|
nengel@2
|
595 uint32_t *bottom = rgba_pixels + my*width + mx;
|
|
nengel@2
|
596 int endx = mx+16 < width? 16: width-mx;
|
|
nengel@2
|
597
|
|
nengel@2
|
598 for (int x = 0; x<endx; x++){
|
|
nengel@2
|
599 bottom[x] = pix;
|
|
nengel@2
|
600 }
|
|
nengel@2
|
601 }
|
|
nengel@2
|
602
|
|
nengel@2
|
603 //draw left
|
|
nengel@2
|
604 if (j==0 || l==0 ){
|
|
nengel@2
|
605 int mx = j*16;
|
|
nengel@2
|
606 int my = i*16;
|
|
nengel@2
|
607 uint32_t *left = rgba_pixels + my*width + mx;
|
|
nengel@2
|
608 int endy = my +16 < height ? 16: height - my;
|
|
nengel@2
|
609
|
|
nengel@2
|
610 for (int y = 0; y<endy; y++){
|
|
nengel@2
|
611 left[y*width] = pix;
|
|
nengel@2
|
612 }
|
|
nengel@2
|
613 }
|
|
nengel@2
|
614
|
|
nengel@2
|
615 //draw right
|
|
nengel@2
|
616 if (j==mb_width -1 || l==h->smb_width-1 ){
|
|
nengel@2
|
617 int mx = j*16 + 15; mx = mx < width ? mx: width-1;
|
|
nengel@2
|
618 int my = i*16;
|
|
nengel@2
|
619 uint32_t *right = rgba_pixels + my*width + mx;
|
|
nengel@2
|
620 int endy = my +16 < height ? 16: height - my;
|
|
nengel@2
|
621
|
|
nengel@2
|
622 for (int y = 0; y<endy; y++){
|
|
nengel@2
|
623 right[y*width] = pix;
|
|
nengel@2
|
624 }
|
|
nengel@2
|
625 }
|
|
nengel@2
|
626 }
|
|
nengel@2
|
627 }
|
|
nengel@2
|
628 }
|
|
nengel@2
|
629
|
|
nengel@2
|
630 static void draw_sbmap (H264Context *h, SuperMBContext *smbc, SDLContext *sdlc){
|
|
nengel@2
|
631 int pitch;
|
|
nengel@2
|
632 uint32_t *rgba_pixels;
|
|
nengel@2
|
633 SDL_Texture *sbmap= sdlc->sbmap_texture;
|
|
nengel@2
|
634
|
|
nengel@2
|
635 SDL_LockTexture( sbmap, NULL, (void **)&rgba_pixels, &pitch );
|
|
nengel@2
|
636
|
|
nengel@2
|
637 memset (rgba_pixels, 0, pitch * h->height);
|
|
nengel@2
|
638 for (int i=0; i< smbc->nsmb_height; i++){
|
|
nengel@2
|
639 for (int j=0; j< smbc->nsmb_width; j++){
|
|
nengel@2
|
640 draw_sb_border(h, rgba_pixels, j, i);
|
|
nengel@2
|
641 }
|
|
nengel@2
|
642 }
|
|
nengel@2
|
643
|
|
nengel@2
|
644 SDL_UnlockTexture( sbmap );
|
|
nengel@2
|
645 }
|
|
nengel@2
|
646 // #endif
|
|
nengel@2
|
647
|
|
nengel@2
|
648 // static void calc_sb_sizes (H264Context *h, SuperMBContext *smbc){
|
|
nengel@2
|
649 // smbc->smb_height = h->smb_height;
|
|
nengel@2
|
650 // smbc->smb_width = h->smb_width;
|
|
nengel@2
|
651 //
|
|
nengel@2
|
652 // smbc->nsmb_height = h->mb_height / smbc->smb_height + (h->mb_height%smbc->smb_height ? 1:0); //only need one extra if mb_height was not dividable
|
|
nengel@2
|
653 // smbc->nsmb_width = h->mb_width / smbc->smb_width;
|
|
nengel@2
|
654 // while ( (smbc->nsmb_width * smbc->smb_width)-(smbc->smb_height-1) < h->mb_width )
|
|
nengel@2
|
655 // smbc->nsmb_width++;
|
|
nengel@2
|
656 // }
|
|
nengel@2
|
657
|
|
nengel@2
|
658
|
|
nengel@2
|
659 static void handle_key_event(H264Context *h, SDLContext *sdlc, SDL_Keysym keysym){
|
|
nengel@2
|
660 int arrow=0;
|
|
nengel@2
|
661
|
|
nengel@2
|
662 switch (keysym.sym){
|
|
nengel@2
|
663 case SDLK_ESCAPE:
|
|
nengel@2
|
664 if (sdlc->fullscreen){
|
|
nengel@2
|
665 SDL_SetWindowFullscreen(sdlc->window, SDL_FALSE);
|
|
nengel@2
|
666 sdlc->fullscreen = 0;
|
|
nengel@2
|
667 }
|
|
nengel@2
|
668 break;
|
|
nengel@2
|
669 case SDLK_SPACE:
|
|
nengel@2
|
670 pthread_mutex_lock(&h->sdl_lock);
|
|
nengel@2
|
671 sdlc->pause = !sdlc->pause;
|
|
nengel@2
|
672 pthread_cond_signal(&h->sdl_cond);
|
|
nengel@2
|
673 pthread_mutex_unlock(&h->sdl_lock);
|
|
nengel@2
|
674 break;
|
|
nengel@2
|
675 case SDLK_f:
|
|
nengel@2
|
676 if (!sdlc->fullscreen){
|
|
nengel@2
|
677 if (keysym.mod == KMOD_LCTRL){
|
|
nengel@2
|
678 // SDL_SetWindowDisplayMode (sdlc->window, &sdlc->full);
|
|
nengel@2
|
679 SDL_SetWindowFullscreen(sdlc->window, SDL_TRUE);
|
|
nengel@2
|
680
|
|
nengel@2
|
681 sdlc->fullscreen = 1;
|
|
nengel@2
|
682 }
|
|
nengel@2
|
683 }
|
|
nengel@2
|
684 break;
|
|
nengel@2
|
685 case SDLK_m:
|
|
nengel@2
|
686 sdlc->showmap = !sdlc->showmap;
|
|
nengel@2
|
687 break;
|
|
nengel@2
|
688 case SDLK_UP:
|
|
nengel@2
|
689 if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_height < h->mb_height && h->smb_height < h->smb_width){
|
|
nengel@2
|
690 h->smb_height++;
|
|
nengel@2
|
691 arrow =1;
|
|
nengel@2
|
692 }
|
|
nengel@2
|
693 break;
|
|
nengel@2
|
694 case SDLK_DOWN:
|
|
nengel@2
|
695 if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_height > 1 ){
|
|
nengel@2
|
696 h->smb_height--;
|
|
nengel@2
|
697 arrow =1;
|
|
nengel@2
|
698 }
|
|
nengel@2
|
699 break;
|
|
nengel@2
|
700 case SDLK_LEFT:
|
|
nengel@2
|
701 if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_width > 1 && h->smb_width > h->smb_height){
|
|
nengel@2
|
702 h->smb_width--;
|
|
nengel@2
|
703 arrow =1;
|
|
nengel@2
|
704 }
|
|
nengel@2
|
705 break;
|
|
nengel@2
|
706 case SDLK_RIGHT:
|
|
nengel@2
|
707 if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_width < h->mb_width){
|
|
nengel@2
|
708 h->smb_width++;
|
|
nengel@2
|
709 arrow =1;
|
|
nengel@2
|
710 }
|
|
nengel@2
|
711 break;
|
|
nengel@2
|
712 }
|
|
nengel@2
|
713
|
|
nengel@2
|
714 if (arrow){
|
|
nengel@2
|
715 SuperMBContext *smbc = getSuperMBContext(h, h->smb_width, h->smb_height);
|
|
nengel@2
|
716 pthread_mutex_lock(&h->smb_lock);
|
|
nengel@2
|
717 h->smbc->refcount--;
|
|
nengel@2
|
718 if (h->smbc->refcount == 0)
|
|
nengel@2
|
719 freeSuperMBContext(h->smbc);
|
|
nengel@2
|
720 h->smbc = smbc;
|
|
nengel@2
|
721 sdlc->updatemap =1;
|
|
nengel@2
|
722 pthread_mutex_unlock(&h->smb_lock);
|
|
nengel@2
|
723 }
|
|
nengel@2
|
724 }
|
|
nengel@2
|
725
|
|
nengel@2
|
726 void handle_window_event(H264Context *h, SDLContext *sdlc, SDL_WindowEvent winevent){
|
|
nengel@2
|
727 SDL_Rect nrect;
|
|
nengel@2
|
728 switch (winevent.event){
|
|
nengel@2
|
729 case SDL_WINDOWEVENT_RESIZED:
|
|
nengel@2
|
730
|
|
nengel@2
|
731 sdlc->win_w = winevent.data1;
|
|
nengel@2
|
732 sdlc->win_h = winevent.data2;
|
|
nengel@2
|
733
|
|
nengel@2
|
734 double aspect = (double) sdlc->win_w/ sdlc->win_h;
|
|
nengel@2
|
735 if ( aspect < sdlc->aspect){
|
|
nengel@2
|
736 double r = (double) sdlc->win_w / sdlc->rect.w;
|
|
nengel@2
|
737 double h = (double) sdlc->rect.h * r;
|
|
nengel@2
|
738
|
|
nengel@2
|
739 nrect.y = lrint(( (double) sdlc->win_h - h)/2);
|
|
nengel@2
|
740 nrect.h = lrint(h);
|
|
nengel@2
|
741
|
|
nengel@2
|
742 nrect.x=0;
|
|
nengel@2
|
743 nrect.w= sdlc->win_w;
|
|
nengel@2
|
744
|
|
nengel@2
|
745 }else {
|
|
nengel@2
|
746 double r = (double) sdlc->win_h / sdlc->rect.h;
|
|
nengel@2
|
747 double w = (double) sdlc->rect.w * r;
|
|
nengel@2
|
748
|
|
nengel@2
|
749 nrect.x = lrint(( (double) sdlc->win_w - w)/2);
|
|
nengel@2
|
750 nrect.w = lrint(w);
|
|
nengel@2
|
751
|
|
nengel@2
|
752 nrect.y=0;
|
|
nengel@2
|
753 nrect.h= sdlc->win_h;
|
|
nengel@2
|
754 }
|
|
nengel@2
|
755 //prob better to lock
|
|
nengel@2
|
756 sdlc->win_rect = nrect;
|
|
nengel@2
|
757 sdlc->resized=1;
|
|
nengel@2
|
758 break;
|
|
nengel@2
|
759 }
|
|
nengel@2
|
760 }
|
|
nengel@2
|
761
|
|
nengel@2
|
762 void *sdl_event_listen_thread(void *arg){
|
|
nengel@2
|
763 H264Context *h = (H264Context *) arg;
|
|
nengel@2
|
764 SDLContext *sdlc = h->sdlc;
|
|
nengel@2
|
765 SDL_Event event;
|
|
nengel@2
|
766
|
|
nengel@2
|
767 while ( SDL_WaitEvent(&event) ) {
|
|
nengel@2
|
768 switch (event.type) {
|
|
nengel@2
|
769 case SDL_KEYDOWN:
|
|
nengel@2
|
770 handle_key_event(h, sdlc, event.key.keysym);
|
|
nengel@2
|
771 break;
|
|
nengel@2
|
772 case SDL_WINDOWEVENT:
|
|
nengel@2
|
773 handle_window_event(h, sdlc, event.window);
|
|
nengel@2
|
774 break;
|
|
nengel@2
|
775 case SDL_QUIT:
|
|
nengel@2
|
776 h->quit=1;
|
|
nengel@2
|
777 goto finish;
|
|
nengel@2
|
778 }
|
|
nengel@2
|
779 }
|
|
nengel@2
|
780 finish:
|
|
nengel@2
|
781 pthread_exit(NULL);
|
|
nengel@2
|
782 return NULL;
|
|
nengel@2
|
783 }
|
|
nengel@2
|
784
|
|
nengel@2
|
785 //XInitThreads not called in SDL2 library, causes crash
|
|
nengel@2
|
786 //remove in future when fixed ...
|
|
nengel@2
|
787 #include <X11/Xlib.h>
|
|
nengel@2
|
788
|
|
nengel@2
|
789 SDLContext *get_SDL_context(H264Context *h){
|
|
nengel@2
|
790 const int frame_width=h->frame_width;
|
|
nengel@2
|
791 const int frame_height=h->frame_height;
|
|
nengel@2
|
792
|
|
nengel@2
|
793 SDLContext *sdlc = av_mallocz(sizeof(SDLContext));
|
|
nengel@2
|
794 sdlc->display = h->display;
|
|
nengel@2
|
795 sdlc->fullscreen = h->fullscreen;
|
|
nengel@2
|
796
|
|
nengel@2
|
797 sdlc->aspect = (double) frame_width / (double) frame_height;
|
|
nengel@2
|
798 sdlc->rect.x =0;
|
|
nengel@2
|
799 sdlc->rect.y =0;
|
|
nengel@2
|
800 sdlc->rect.w =frame_width;
|
|
nengel@2
|
801 sdlc->rect.h =frame_height;
|
|
nengel@2
|
802
|
|
nengel@2
|
803 XInitThreads(); //workaround
|
|
nengel@2
|
804
|
|
nengel@2
|
805 // Initializes the video subsystem
|
|
nengel@2
|
806 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
nengel@2
|
807 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
|
|
nengel@2
|
808 #undef exit
|
|
nengel@2
|
809 exit(-1);
|
|
nengel@2
|
810 }
|
|
nengel@2
|
811 SDL_SetHint("SDL_HINT_RENDER_SCALE_QUALITY", "best");
|
|
nengel@2
|
812 SDL_SetHint("SDL_HINT_RENDER_OPENGL_SHADERS", "1");
|
|
nengel@2
|
813
|
|
nengel@2
|
814 SDL_GetDesktopDisplayMode(0, &sdlc->full);
|
|
nengel@2
|
815 sdlc->full.format = SDL_PIXELFORMAT_IYUV;
|
|
nengel@2
|
816
|
|
nengel@2
|
817 sdlc->wind = sdlc->full;
|
|
nengel@2
|
818 if (sdlc->wind.w > frame_width) sdlc->wind.w = frame_width;
|
|
nengel@2
|
819 if (sdlc->wind.h > frame_height) sdlc->wind.h = frame_height;
|
|
nengel@2
|
820
|
|
nengel@2
|
821 sdlc->win_rect.x =0;
|
|
nengel@2
|
822 sdlc->win_rect.y =0;
|
|
nengel@2
|
823 sdlc->win_rect.w =sdlc->wind.w;
|
|
nengel@2
|
824 sdlc->win_rect.h =sdlc->wind.h;
|
|
nengel@2
|
825
|
|
nengel@2
|
826 if (sdlc->fullscreen){
|
|
nengel@2
|
827 sdlc->window = SDL_CreateWindow( h->file_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sdlc->full.w, sdlc->full.h, SDL_WINDOW_FULLSCREEN|SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
|
|
nengel@2
|
828 SDL_SetWindowDisplayMode (sdlc->window, &sdlc->full);
|
|
nengel@2
|
829 } else {
|
|
nengel@2
|
830 sdlc->window = SDL_CreateWindow( h->file_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sdlc->wind.w, sdlc->wind.h, SDL_WINDOW_RESIZABLE|SDL_WINDOW_SHOWN);
|
|
nengel@2
|
831 SDL_SetWindowDisplayMode (sdlc->window, &sdlc->wind);
|
|
nengel@2
|
832 }
|
|
nengel@2
|
833
|
|
nengel@2
|
834 sdlc->renderer = SDL_CreateRenderer(sdlc->window, -1, SDL_RENDERER_ACCELERATED);
|
|
nengel@2
|
835 // sdlc->renderer = SDL_CreateRenderer(sdlc->window, -1, SDL_RENDERER_SOFTWARE);
|
|
nengel@2
|
836
|
|
nengel@2
|
837 h->sdlq.queue[0] = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height);
|
|
nengel@2
|
838 h->sdlq.queue[1] = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height);
|
|
nengel@2
|
839
|
|
nengel@2
|
840 sdlc->sbmap_texture = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height);
|
|
nengel@2
|
841 SDL_SetTextureBlendMode(sdlc->sbmap_texture, SDL_BLENDMODE_BLEND);
|
|
nengel@2
|
842 sdlc->updatemap = 1;
|
|
nengel@2
|
843
|
|
nengel@2
|
844 #if HAVE_LIBSDL_TTF
|
|
nengel@2
|
845 //not working with SDL 2.0, try again in future when supported
|
|
nengel@2
|
846 if(TTF_Init()==-1) {
|
|
nengel@2
|
847 printf("TTF_Init: %s\n", TTF_GetError());
|
|
nengel@2
|
848 exit(2);
|
|
nengel@2
|
849 }
|
|
nengel@2
|
850
|
|
nengel@2
|
851 // Load a font
|
|
nengel@2
|
852 TTF_Font *font;
|
|
nengel@2
|
853 font = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 24);
|
|
nengel@2
|
854 if (font == NULL)
|
|
nengel@2
|
855 {
|
|
nengel@2
|
856 printf("TTF_OpenFont() Failed: %s\n", TTF_GetError());
|
|
nengel@2
|
857 TTF_Quit();
|
|
nengel@2
|
858 exit(1);
|
|
nengel@2
|
859 }
|
|
nengel@2
|
860 #endif
|
|
nengel@2
|
861
|
|
nengel@2
|
862 pthread_create(&sdlc->listen_thread, NULL, sdl_event_listen_thread, h);
|
|
nengel@2
|
863
|
|
nengel@2
|
864 return sdlc;
|
|
nengel@2
|
865
|
|
nengel@2
|
866 }
|
|
nengel@2
|
867
|
|
nengel@2
|
868 void free_SDL_context(H264Context *h){
|
|
nengel@2
|
869 SDLContext *sdlc = h->sdlc;
|
|
nengel@2
|
870 pthread_join(sdlc->listen_thread, NULL);
|
|
nengel@2
|
871
|
|
nengel@2
|
872 #if HAVE_LIBSDL_TTF
|
|
nengel@2
|
873 TTF_Quit();
|
|
nengel@2
|
874 #endif
|
|
nengel@2
|
875 SDL_DestroyTexture(h->sdlq.queue[0]);
|
|
nengel@2
|
876 SDL_DestroyTexture(h->sdlq.queue[1]);
|
|
nengel@2
|
877 SDL_DestroyTexture(sdlc->sbmap_texture);
|
|
nengel@2
|
878 SDL_DestroyRenderer(sdlc->renderer);
|
|
nengel@2
|
879 SDL_DestroyWindow(sdlc->window);
|
|
nengel@2
|
880 SDL_Quit();
|
|
nengel@2
|
881
|
|
nengel@2
|
882 }
|
|
nengel@2
|
883
|
|
nengel@2
|
884 void *sdl_thread(void *arg){
|
|
nengel@2
|
885 H264Context *h = (H264Context *) arg;
|
|
nengel@2
|
886
|
|
nengel@2
|
887 SDLContext *sdlc = get_SDL_context(h);
|
|
nengel@2
|
888 h->sdlc = sdlc;
|
|
nengel@2
|
889
|
|
nengel@2
|
890 signal_texture(h, 0);
|
|
nengel@2
|
891 signal_texture(h, 0);
|
|
nengel@2
|
892
|
|
nengel@2
|
893 SDL_Texture *texture;
|
|
nengel@2
|
894 for (;;){
|
|
nengel@2
|
895 pthread_mutex_lock(&h->sdl_lock);
|
|
nengel@2
|
896 while (sdlc->pause){
|
|
nengel@2
|
897 pthread_cond_wait(&h->sdl_cond, &h->sdl_lock);
|
|
nengel@2
|
898 }
|
|
nengel@2
|
899 pthread_mutex_unlock(&h->sdl_lock);
|
|
nengel@2
|
900
|
|
nengel@2
|
901 texture = get_next_texture(h, 0);
|
|
nengel@2
|
902 if (texture == NULL)
|
|
nengel@2
|
903 break;
|
|
nengel@2
|
904
|
|
nengel@2
|
905 SDL_UnlockTexture(texture);
|
|
nengel@2
|
906
|
|
nengel@2
|
907 //clear if resized
|
|
nengel@2
|
908 if (sdlc->resized){
|
|
nengel@2
|
909 // KDE bug prob, reset viewport change after resize from max
|
|
nengel@2
|
910 SDL_RenderSetViewport(sdlc->renderer, NULL);
|
|
nengel@2
|
911 SDL_SetRenderDrawColor(sdlc->renderer, 0, 0, 0, 255);
|
|
nengel@2
|
912 SDL_RenderClear(sdlc->renderer);
|
|
nengel@2
|
913 sdlc->resized = 0;
|
|
nengel@2
|
914 }
|
|
nengel@2
|
915
|
|
nengel@2
|
916 SDL_RenderCopy(sdlc->renderer, texture, &sdlc->rect, &sdlc->win_rect);
|
|
nengel@2
|
917
|
|
nengel@2
|
918 if (sdlc->showmap){
|
|
nengel@2
|
919 if (sdlc->updatemap){
|
|
nengel@2
|
920 SuperMBContext *smbc;
|
|
nengel@2
|
921 pthread_mutex_lock (&h->smb_lock);
|
|
nengel@2
|
922 smbc = h->smbc;
|
|
nengel@2
|
923 smbc->refcount++;
|
|
nengel@2
|
924 sdlc->updatemap=0;
|
|
nengel@2
|
925 pthread_mutex_unlock(&h->smb_lock);
|
|
nengel@2
|
926
|
|
nengel@2
|
927 draw_sbmap(h, smbc, sdlc);
|
|
nengel@2
|
928
|
|
nengel@2
|
929 release_smbc(h, smbc);
|
|
nengel@2
|
930 }
|
|
nengel@2
|
931 SDL_RenderCopy(sdlc->renderer, sdlc->sbmap_texture, &sdlc->rect, &sdlc->win_rect);
|
|
nengel@2
|
932 }
|
|
nengel@2
|
933
|
|
nengel@2
|
934 SDL_RenderPresent(sdlc->renderer);
|
|
nengel@2
|
935 signal_texture(h, 0);
|
|
nengel@2
|
936 }
|
|
nengel@2
|
937
|
|
nengel@2
|
938 free_SDL_context(h);
|
|
nengel@2
|
939
|
|
nengel@2
|
940 pthread_exit(NULL);
|
|
nengel@2
|
941 return NULL;
|
|
nengel@2
|
942 }
|
|
nengel@2
|
943 #endif
|
|
nengel@2
|
944
|