view libavcodec/h264_misc.c @ 2:897f711a7157

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