Mercurial > cgi-bin > hgwebdir.cgi > PR > Applications > VSs > VSs__H264__App
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libavcodec/h264_misc.c Tue Sep 25 15:55:33 2012 +0200 1.3 @@ -0,0 +1,944 @@ 1.4 +#include "config.h" 1.5 + 1.6 +#include "h264_types.h" 1.7 + 1.8 +#include <unistd.h> 1.9 +#include <sys/resource.h> 1.10 +#include <sys/time.h> 1.11 +#include <time.h> 1.12 +#include <pthread.h> 1.13 +#undef NDEBUG 1.14 +#include <assert.h> 1.15 + 1.16 +#if HAVE_LIBSDL2 1.17 +#include <SDL2/SDL.h> 1.18 +#if HAVE_LIBSDL_TTF 1.19 +#include <SDL/SDL_ttf.h> 1.20 +#endif 1.21 +#endif 1.22 + 1.23 +void start_timer(H264Context *h, int stage){ 1.24 + clock_gettime(CLOCK_REALTIME, &h->start_time[stage]); 1.25 +} 1.26 + 1.27 +void stop_timer(H264Context *h, int stage){ 1.28 + clock_gettime(CLOCK_REALTIME, &h->end_time[stage]); 1.29 + 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); 1.30 + h->last_time [stage] = time; 1.31 + h->total_time[stage] += time; 1.32 +} 1.33 + 1.34 +void init_sb_entry(H264Context *h, SliceBufferEntry *sbe){ 1.35 + sbe->mbs = av_malloc(h->mb_width*h->mb_height* sizeof(H264Mb)); 1.36 + sbe->initialized = 1; 1.37 +} 1.38 + 1.39 +void free_sb_entry(SliceBufferEntry *sbe){ 1.40 + av_free(sbe->mbs); 1.41 + av_freep(&sbe->gb.raw); 1.42 + if (sbe->gb.rbsp) 1.43 + av_freep(&sbe->gb.rbsp); 1.44 + sbe->initialized = 0; 1.45 +} 1.46 + 1.47 +SliceBufferEntry *get_sb_entry(H264Context *h){ 1.48 + SliceBufferEntry *sb = NULL; 1.49 + 1.50 + pthread_mutex_lock(&h->lock[PARSE]); 1.51 + while (h->free_sb_cnt<=0) 1.52 + pthread_cond_wait(&h->cond[PARSE], &h->lock[PARSE]); 1.53 + /* use first free picture */ 1.54 + for(int i=0; i<h->sb_size; i++){ 1.55 + if(h->sb[i].state==0){ 1.56 + sb= &h->sb[i]; 1.57 + sb->state=1; 1.58 + sb->lines_taken=0; 1.59 + sb->lines_total=h->mb_height; 1.60 + break; 1.61 + } 1.62 + } 1.63 + h->free_sb_cnt--; 1.64 + 1.65 + pthread_mutex_unlock(&h->lock[PARSE]); 1.66 + 1.67 + memset (&sb->slice, 0, sizeof(H264Slice)); 1.68 + 1.69 + return sb; 1.70 +} 1.71 + 1.72 +void release_sb_entry(H264Context *h, SliceBufferEntry *sb){ 1.73 + pthread_mutex_lock(&h->lock[PARSE]); 1.74 + 1.75 + sb->state = 0; 1.76 + h->free_sb_cnt++; 1.77 + pthread_cond_signal(&h->cond[PARSE]); 1.78 + 1.79 + pthread_mutex_unlock(&h->lock[PARSE]); 1.80 +} 1.81 + 1.82 +int init_dpb_entry(H264Context *h, DecodedPicture *pic, H264Slice *s, int width, int height){ 1.83 + int i; 1.84 + 1.85 + s->curr_pic=pic; 1.86 + pic->poc = s->poc; 1.87 + pic->key_frame = s->key_frame; 1.88 + pic->mmco_reset = s->mmco_reset; 1.89 + pic->reference = s->nal_ref_idc? 3:1; 1.90 + pic->cpn = s->coded_pic_num; 1.91 + 1.92 + if(pic->data[0]==NULL) { 1.93 + int size[3] = {0}; 1.94 + 1.95 + width+= EDGE_WIDTH*2; 1.96 + height+= EDGE_WIDTH*2; 1.97 + 1.98 + pic->linesize[0]= width; 1.99 + pic->linesize[1]= pic->linesize[2] = width>>1; 1.100 + 1.101 + size[0] = width*height; 1.102 + size[1] = size[2] = width*height>>2; 1.103 + 1.104 + for(i=0; i<3; i++){ 1.105 + pic->base[i]= av_malloc(size[i]); 1.106 + } 1.107 + 1.108 + pic->data[0] = pic->base[0] + (pic->linesize[0]*EDGE_WIDTH) + EDGE_WIDTH; 1.109 + pic->data[1] = pic->base[1] + (pic->linesize[1]*EDGE_WIDTH>>1) + (EDGE_WIDTH>>1); 1.110 + pic->data[2] = pic->base[2] + (pic->linesize[2]*EDGE_WIDTH>>1) + (EDGE_WIDTH>>1); 1.111 + } 1.112 + 1.113 + const int big_mb_num= h->mb_stride*(h->mb_height+1) + 1; //the +1 is needed so memset(,,stride*height) does not sig11 1.114 + const int mb_array_size= h->mb_stride*h->mb_height; 1.115 + const int b4_array_size= h->b4_stride*h->mb_height*4; 1.116 + 1.117 + if(pic->mb_type_base==NULL){ 1.118 + FF_ALLOCZ_OR_GOTO(pic->mb_type_base , big_mb_num * sizeof(uint32_t), fail) 1.119 + pic->mb_type= pic->mb_type_base + h->mb_stride+1; 1.120 + 1.121 + for(int i=0; i<2; i++){ 1.122 + FF_ALLOCZ_OR_GOTO(pic->motion_val_base[i], 2 * (b4_array_size+4) * sizeof(int16_t), fail) 1.123 + pic->motion_val[i]= pic->motion_val_base[i]+4; 1.124 + FF_ALLOCZ_OR_GOTO(pic->ref_index[i], 4*mb_array_size * sizeof(uint8_t), fail) 1.125 + } 1.126 + FF_ALLOCZ_OR_GOTO(pic->intra4x4_pred_mode, h->mb_width*h->mb_height * 4* sizeof(int8_t), fail) 1.127 + } 1.128 + 1.129 + return 0; 1.130 + fail: 1.131 + return -1; 1.132 +} 1.133 + 1.134 +void free_dp(DecodedPicture *pic){ 1.135 + if(pic->base[0]){ 1.136 + for (int i=0; i<3; i++){ 1.137 + av_free(pic->base[i]); 1.138 + pic->data[i]= NULL; 1.139 + } 1.140 + } 1.141 + if (pic->mb_type_base){ 1.142 + av_free(pic->mb_type_base); 1.143 + pic->mb_type= NULL; 1.144 + for(int i=0; i<2; i++){ 1.145 + av_free(pic->motion_val_base[i]); 1.146 + av_free(pic->ref_index[i]); 1.147 + } 1.148 + av_free(pic->intra4x4_pred_mode); 1.149 + } 1.150 +} 1.151 + 1.152 +DecodedPicture *get_dpb_entry(H264Context *h, H264Slice *s){ 1.153 + DecodedPicture *dp = NULL; 1.154 + 1.155 + pthread_mutex_lock(&h->lock[REORDER2]); 1.156 + while (h->free_dpb_cnt<=0){ 1.157 + #if OMPSS 1.158 + assert(0); 1.159 + #endif 1.160 + pthread_cond_wait(&h->cond[REORDER2], &h->lock[REORDER2]); 1.161 + } 1.162 + /* use first free picture */ 1.163 + for(int i=0; i<h->max_dpb_cnt; i++){ 1.164 + if(h->dpb[i].reference==0){ 1.165 + dp= &h->dpb[i]; 1.166 + break; 1.167 + } 1.168 + } 1.169 + assert(dp); 1.170 + init_dpb_entry(h, dp, s, h->width, h->height); 1.171 + h->free_dpb_cnt--; 1.172 + h->acdpb_cnt++; //debug 1.173 + pthread_mutex_unlock(&h->lock[REORDER2]); 1.174 + 1.175 + return dp; 1.176 +} 1.177 + 1.178 +void release_dpb_entry(H264Context *h, DecodedPicture *pic, int mode){ 1.179 + pthread_mutex_lock(&h->lock[REORDER2]); 1.180 + pic->reference &= ~mode; 1.181 + if (pic->reference == 0){ 1.182 + h->free_dpb_cnt++; 1.183 + h->reldpb_cnt++; //debug 1.184 + pthread_cond_signal(&h->cond[REORDER2]); 1.185 + } 1.186 + pthread_mutex_unlock(&h->lock[REORDER2]); 1.187 +} 1.188 + 1.189 + 1.190 +/** 1.191 +* Extends the edges of a macroblock line. 1.192 +*/ 1.193 +void draw_edges(MBRecContext *d, H264Slice *s, int line){ 1.194 + int i; 1.195 + int mb_width=d->mb_width; 1.196 + int mb_height=d->mb_height; 1.197 + int last = (line+1 == mb_height); 1.198 + int lines = last?16:12; 1.199 + int linesize = d->linesize; 1.200 + int uvlinesize = d->uvlinesize; 1.201 + uint8_t *y = s->curr_pic->data[0] + 16*line*linesize; 1.202 + uint8_t *cb = s->curr_pic->data[1] + 8*line*uvlinesize; 1.203 + uint8_t *cr = s->curr_pic->data[2] + 8*line*uvlinesize; 1.204 + 1.205 + for (i=-4; i<lines; i++){ 1.206 + memset(y + i*linesize - EDGE_WIDTH, y[i*linesize], EDGE_WIDTH); 1.207 + memset(y + i*linesize + mb_width*16, y[i*linesize +mb_width*16 -1], EDGE_WIDTH); 1.208 + } 1.209 + for (i=-2; i<lines/2; i++){ 1.210 + memset(cb + i*uvlinesize - EDGE_WIDTH/2, cb[i*uvlinesize], EDGE_WIDTH/2); 1.211 + memset(cb + i*uvlinesize + mb_width*8, cb[i*uvlinesize +mb_width*8 -1], EDGE_WIDTH/2); 1.212 + memset(cr + i*uvlinesize - EDGE_WIDTH/2, cr[i*uvlinesize], EDGE_WIDTH/2); 1.213 + memset(cr + i*uvlinesize + mb_width*8, cr[i*uvlinesize +mb_width*8 -1], EDGE_WIDTH/2); 1.214 + } 1.215 + 1.216 + if (line==0){ 1.217 + y -= EDGE_WIDTH; 1.218 + cb -= EDGE_WIDTH/2; 1.219 + cr -= EDGE_WIDTH/2; 1.220 + for (i=1; i<=21; i++){ 1.221 + memcpy(y -i*linesize, y, linesize); 1.222 + } 1.223 + for (i=1; i<=9; i++){ 1.224 + memcpy(cb -i*uvlinesize, cb, uvlinesize); 1.225 + memcpy(cr -i*uvlinesize, cr, uvlinesize); 1.226 + } 1.227 + }else if (last){ 1.228 + y += -EDGE_WIDTH + 15*linesize; 1.229 + cb += -EDGE_WIDTH/2 + 7*uvlinesize; 1.230 + cr += -EDGE_WIDTH/2 + 7*uvlinesize; 1.231 + for (i=1; i<=21; i++){ 1.232 + memcpy(y +i*linesize, y, linesize); 1.233 + } 1.234 + for (i=1; i<=9; i++){ 1.235 + memcpy(cb +i*uvlinesize, cb, uvlinesize); 1.236 + memcpy(cr +i*uvlinesize, cr, uvlinesize); 1.237 + } 1.238 + } 1.239 +} 1.240 + 1.241 +static int64_t timer_start; 1.242 +int64_t av_gettime(void) { 1.243 + struct timeval tv; 1.244 + gettimeofday(&tv,NULL); 1.245 + return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; 1.246 +} 1.247 + 1.248 +void av_start_timer(){ 1.249 + timer_start = av_gettime(); 1.250 +} 1.251 + 1.252 +void print_report(int frame_number, uint64_t video_size, int is_last_report, int verbose) { 1.253 + static int64_t last_time = -1; 1.254 + static int64_t last_frame_number = 0; 1.255 + float t=0, t2=0; 1.256 + int64_t cur_time=0; 1.257 + 1.258 + if (!is_last_report) { 1.259 + /* display the report every 0.5 seconds */ 1.260 + cur_time = av_gettime(); 1.261 + if (last_time == -1) { 1.262 + last_time = cur_time; 1.263 + return; 1.264 + } 1.265 + if ((cur_time - last_time) < 500000) 1.266 + return; 1.267 + t = (cur_time-timer_start) / 1000000.0; 1.268 + t2 = (cur_time-last_time) / 1000000.0; 1.269 + } 1.270 + 1.271 + if (verbose){ 1.272 + 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) ); 1.273 + fflush(stderr); 1.274 + } 1.275 + last_frame_number = frame_number; 1.276 + last_time = cur_time; 1.277 + 1.278 + if (is_last_report){ 1.279 + t = (av_gettime()-timer_start) / 1000000.0; 1.280 + fprintf(stderr, "%c[2Kframe=%5d avgfps=%3d\r", 27, frame_number, (int)(frame_number/t+0.5)); 1.281 + fprintf(stderr, "\n"); 1.282 + fprintf(stderr, "video:%1.0fkB\n", video_size/1024.0); 1.283 + fflush(stderr); 1.284 + } 1.285 +} 1.286 + 1.287 +/* Sort B-frames into display order */ 1.288 +static DecodedPicture *get_reordered_picture(OutputContext *w, int flush){ 1.289 + int i; 1.290 + int out_idx = 0; 1.291 + DecodedPicture *out = w->delayed_pic[0]; 1.292 + 1.293 + if (!out) 1.294 + return NULL; 1.295 + 1.296 + for(i=1; w->delayed_pic[i] && !w->delayed_pic[i]->key_frame && !w->delayed_pic[i]->mmco_reset; i++){ 1.297 + if(w->delayed_pic[i]->poc < out->poc){ 1.298 + out = w->delayed_pic[i]; 1.299 + out_idx = i; 1.300 + } 1.301 + } 1.302 + 1.303 + if(w->dp_cnt > MAX_DELAYED_PIC_COUNT || flush) { 1.304 + for(i=out_idx; w->delayed_pic[i]; i++) 1.305 + w->delayed_pic[i] = w->delayed_pic[i+1]; 1.306 + w->dp_cnt--; 1.307 + return out; 1.308 + } 1.309 + return NULL; 1.310 +} 1.311 + 1.312 +/** 1.313 +* Remove the extra borders, and places the three parts of the image after each other. 1.314 +*/ 1.315 +static int raw_encode(const DecodedPicture* src, int width, int height, unsigned char *dest) { 1.316 + int i, j; 1.317 +/** To write entire image including extra borders*/ 1.318 +// int w = src->linesize[0]; 1.319 +// int h = height+64; 1.320 +// int w2 = w>>1; 1.321 +// int h2 = h>>1; 1.322 +// int data_planes=3; 1.323 +// int size = w * h + 2 *w2*h2; 1.324 +// const unsigned char* s; 1.325 +// for (i=0; i<data_planes; i++) { 1.326 +// if (i == 1) { 1.327 +// w = w2; 1.328 +// h = h2; 1.329 +// } 1.330 +// s = src->base[i]; 1.331 +// for(j=0; j<h; j++) { 1.332 +// memcpy(dest, s, src->linesize[i]); 1.333 +// dest += w; 1.334 +// s += src->linesize[i]; 1.335 +// } 1.336 +// } 1.337 + 1.338 + int w = (width*8 + 7)/8; 1.339 + int h = height; 1.340 + int w2 =((width >>1) * 8 + 7) / 8; 1.341 + int h2 = ((height+1) >>1); //not sure about +1 1.342 + int data_planes=3; 1.343 + int size = w * h + 2 *w2*h2; 1.344 + const unsigned char* s; 1.345 + 1.346 + 1.347 + for (i=0; i<data_planes; i++) { 1.348 + if (i == 1) { 1.349 + w = w2; 1.350 + h = h2; 1.351 + } 1.352 + s = src->data[i]; 1.353 + for(j=0; j<h; j++) { 1.354 + memcpy(dest, s, w); 1.355 + dest += w; 1.356 + s += src->linesize[i]; 1.357 + } 1.358 + } 1.359 + return size; 1.360 +} 1.361 + 1.362 +#ifdef HAVE_LIBSDL2 1.363 +static SDL_Texture *get_next_texture(H264Context *h, int side){ 1.364 + SDLTextureQueue *sdlq = &h->sdlq; 1.365 + SDL_Texture *texture; 1.366 + pthread_mutex_lock (&sdlq->sdl_lock); 1.367 + if (side ){ //send 1.368 + while (sdlq->ready >= sdlq->size) 1.369 + pthread_cond_wait(&sdlq->sdl_cond, &sdlq->sdl_lock); 1.370 + texture = sdlq->queue[sdlq->fi]; 1.371 + sdlq->fi++; sdlq->fi %= sdlq->size; 1.372 + } else { //recv 1.373 + while (sdlq->ready <= 0 && !sdlq->exit) 1.374 + pthread_cond_wait(&sdlq->sdl_cond, &sdlq->sdl_lock); 1.375 + 1.376 + if (sdlq->ready == 0 && sdlq->exit){ 1.377 + texture = NULL; 1.378 + }else{ 1.379 + texture = sdlq->queue[sdlq->fo]; 1.380 + sdlq->fo++; sdlq->fo %= sdlq->size; 1.381 + } 1.382 + } 1.383 + pthread_mutex_unlock(&sdlq->sdl_lock); 1.384 + 1.385 + return texture; 1.386 +} 1.387 + 1.388 +static void signal_texture(H264Context *h, int side){ 1.389 + SDLTextureQueue *sdlq = &h->sdlq; 1.390 + pthread_mutex_lock (&sdlq->sdl_lock); 1.391 + if (side) 1.392 + sdlq->ready++; 1.393 + else 1.394 + sdlq->ready--; 1.395 + pthread_cond_signal(&sdlq->sdl_cond); 1.396 + pthread_mutex_unlock(&sdlq->sdl_lock); 1.397 +} 1.398 + 1.399 +void signal_sdl_exit(H264Context *h){ 1.400 + SDLTextureQueue *sdlq = &h->sdlq; 1.401 + pthread_mutex_lock (&sdlq->sdl_lock); 1.402 + sdlq->exit=1; 1.403 + pthread_cond_signal(&sdlq->sdl_cond); 1.404 + pthread_mutex_unlock(&sdlq->sdl_lock); 1.405 +} 1.406 + 1.407 +static void display_frame(H264Context *h, OutputContext *w, int fd, DecodedPicture *in_picture, int frame_width, int frame_height, int dropable){ 1.408 + static int64_t last_time = -1; 1.409 + int64_t cur_time; 1.410 +// SDLContext *sdlc = h->sdlc; 1.411 + uint8_t *iyuv_pixels; 1.412 + int pitch; 1.413 + 1.414 + 1.415 + if (last_time == -1){ 1.416 + last_time = av_gettime(); 1.417 + } 1.418 + 1.419 + 1.420 + /* do not display frames that are less than 8.125 ms apart (120fps)*/ 1.421 + if (dropable){ 1.422 + cur_time = av_gettime(); 1.423 + 1.424 + if ((cur_time - last_time) < 8125) 1.425 + return; 1.426 + 1.427 + last_time =cur_time; 1.428 + } 1.429 + 1.430 + if(in_picture){ 1.431 + 1.432 + SDL_Texture *texture= get_next_texture(h, 1); 1.433 + 1.434 + SDL_LockTexture( texture, NULL, (void **)&iyuv_pixels, &pitch ); 1.435 + 1.436 + raw_encode(in_picture, frame_width, frame_height, iyuv_pixels); 1.437 + 1.438 + signal_texture(h, 1); 1.439 + } 1.440 +} 1.441 +#endif 1.442 + 1.443 +// TODO: Parallelize the raw_encode (either split frame or over frames) 1.444 +static void do_video_out(OutputContext *w, int fd, DecodedPicture *in_picture, int frame_width, int frame_height) { 1.445 + int size=0; 1.446 + //remove extra borders 1.447 + 1.448 + if(in_picture) 1.449 + size= raw_encode(in_picture, frame_width, frame_height, w->bit_buffer); 1.450 + 1.451 + if (size < 0) { 1.452 + fprintf(stderr, "Video encoding failed\n"); 1.453 + }else { 1.454 + if (write(fd, w->bit_buffer, size)<0) 1.455 + fprintf(stderr, "Write frame failed\n"); 1.456 + } 1.457 + 1.458 + w->video_size += size; 1.459 +} 1.460 + 1.461 +DecodedPicture *output_frame(H264Context *h, OutputContext *oc, DecodedPicture *pic, int fd, int frame_width, int frame_height) { 1.462 + DecodedPicture *out; 1.463 + 1.464 + if (pic){ 1.465 + oc->delayed_pic[oc->dp_cnt++]=pic; 1.466 + out = get_reordered_picture(oc, 0); 1.467 + }else{ 1.468 + out = get_reordered_picture(oc, 1); 1.469 + } 1.470 + 1.471 + if (out){ 1.472 + if (fd){ 1.473 + do_video_out(oc, fd, out, frame_width, frame_height); 1.474 + }else{ 1.475 +#ifdef HAVE_LIBSDL2 1.476 + if (h->display){ 1.477 + display_frame(h, oc, fd, out, frame_width, frame_height, !(pic==NULL)); 1.478 + } 1.479 +#endif 1.480 + } 1.481 + oc->frame_number++; 1.482 + } 1.483 + 1.484 + return out; 1.485 +} 1.486 + 1.487 +OutputContext *get_output_context(H264Context *h){ 1.488 + const int frame_width=h->frame_width; 1.489 + const int frame_height=h->frame_height; 1.490 + const int frame_size = frame_width*frame_height; 1.491 + 1.492 + OutputContext *oc = av_mallocz(sizeof(OutputContext)); 1.493 + oc->bit_buffer_size= FFMAX(1024*256, frame_size*2); // oversize a little bit to allow extra border write 1.494 + oc->bit_buffer= av_mallocz(oc->bit_buffer_size); 1.495 + 1.496 + return oc; 1.497 +} 1.498 + 1.499 +void free_output_context(OutputContext *oc){ 1.500 + 1.501 + av_free(oc->bit_buffer); 1.502 + av_free(oc); 1.503 +} 1.504 + 1.505 +SuperMBContext *getSuperMBContext(H264Context *h, int smb_width, int smb_height){ 1.506 + SuperMBContext *smbc = av_mallocz(sizeof(SuperMBContext)); 1.507 + 1.508 + smbc->smb_width = smb_width; 1.509 + smbc->smb_height = smb_height; 1.510 + 1.511 + 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 1.512 + smbc->nsmb_width = h->mb_width / smbc->smb_width; 1.513 + while ( (smbc->nsmb_width * smbc->smb_width)-(smbc->smb_height-1) < h->mb_width ) 1.514 + smbc->nsmb_width++; 1.515 + 1.516 + smbc->nsmb_3dheight= smbc->nsmb_height - ((h->mb_height/2)/smbc->smb_height +1); //assuming max motion vector of half the height 1.517 + 1.518 + smbc->smbs[0] = av_malloc (smbc->nsmb_width * smbc->nsmb_height * sizeof(SuperMBTask)); 1.519 + smbc->smbs[1] = av_malloc (smbc->nsmb_width * smbc->nsmb_height * sizeof(SuperMBTask)); 1.520 + for (int y=0, i=0; i<smbc->nsmb_height; i++, y+=smbc->smb_height){ 1.521 + for (int x=0, j=0; j<smbc->nsmb_width; j++, x+=smbc->smb_width){ 1.522 + smbc->smbs[0][i*smbc->nsmb_width +j].smb_y = y; 1.523 + smbc->smbs[0][i*smbc->nsmb_width +j].smb_x = x; 1.524 + smbc->smbs[1][i*smbc->nsmb_width +j].smb_y = y; 1.525 + smbc->smbs[1][i*smbc->nsmb_width +j].smb_x = x; 1.526 + } 1.527 + } 1.528 + 1.529 + smbc->refcount = 1; 1.530 + 1.531 + return smbc; 1.532 +} 1.533 + 1.534 +void freeSuperMBContext(SuperMBContext *smbc){ 1.535 + av_free(smbc->smbs[0]); 1.536 + av_free(smbc->smbs[1]); 1.537 + av_free(smbc); 1.538 +} 1.539 + 1.540 +SuperMBContext * acquire_smbc(H264Context *h ){ 1.541 + SuperMBContext *smbc; 1.542 + 1.543 + pthread_mutex_lock (&h->smb_lock); 1.544 + smbc = h->smbc; 1.545 + smbc->refcount++; 1.546 + pthread_mutex_unlock(&h->smb_lock); 1.547 + return smbc; 1.548 +} 1.549 + 1.550 +void release_smbc(H264Context *h, SuperMBContext *smbc){ 1.551 + pthread_mutex_lock (&h->smb_lock); 1.552 + smbc->refcount--; 1.553 + if (smbc->refcount==0){ 1.554 + freeSuperMBContext(smbc); 1.555 + } 1.556 + pthread_mutex_unlock(&h->smb_lock); 1.557 + 1.558 +} 1.559 + 1.560 + 1.561 +#ifdef HAVE_LIBSDL2 1.562 + 1.563 +// #if OMPSS 1.564 +static void draw_sb_border(H264Context *h, uint32_t *rgba_pixels, int smb_x, int smb_y){ 1.565 + int mb_width = h->mb_width; 1.566 + int mb_height = h->mb_height; 1.567 + int width = h->frame_width; 1.568 + int height = h->frame_height; 1.569 + 1.570 + int mb_x = smb_x * h->smb_width; 1.571 + int mb_y = smb_y * h->smb_height; 1.572 + 1.573 + uint32_t pix= 0x0000FFC0; 1.574 + 1.575 + for (int k=0, i=mb_y; i< mb_y + h->smb_height; i++, k++){ 1.576 + for (int l=0, j=mb_x -k ; j< mb_x - k + h->smb_width; j++, l++){ 1.577 + //outside frame 1.578 + if (i<0 || i>=mb_height || j<0 || j>=mb_width) { 1.579 + continue; 1.580 + } 1.581 + 1.582 + //draw top 1.583 + if (i==0 || k==0 || l==0){ 1.584 + int mx = j*16; 1.585 + int my = i*16; 1.586 + uint32_t *top = rgba_pixels + my*width + mx; 1.587 + int endx = mx+16 < width? 16: width-mx; 1.588 + 1.589 + for (int x = 0; x<endx; x++){ 1.590 + top[x] = pix; 1.591 + } 1.592 + } 1.593 + 1.594 + //draw bottom 1.595 + if (i==mb_height-1 || k==h->smb_height-1 || l==h->smb_width-1){ 1.596 + int mx = j*16; 1.597 + int my = i*16 + 15; my = my < height ? my: height-1; 1.598 + uint32_t *bottom = rgba_pixels + my*width + mx; 1.599 + int endx = mx+16 < width? 16: width-mx; 1.600 + 1.601 + for (int x = 0; x<endx; x++){ 1.602 + bottom[x] = pix; 1.603 + } 1.604 + } 1.605 + 1.606 + //draw left 1.607 + if (j==0 || l==0 ){ 1.608 + int mx = j*16; 1.609 + int my = i*16; 1.610 + uint32_t *left = rgba_pixels + my*width + mx; 1.611 + int endy = my +16 < height ? 16: height - my; 1.612 + 1.613 + for (int y = 0; y<endy; y++){ 1.614 + left[y*width] = pix; 1.615 + } 1.616 + } 1.617 + 1.618 + //draw right 1.619 + if (j==mb_width -1 || l==h->smb_width-1 ){ 1.620 + int mx = j*16 + 15; mx = mx < width ? mx: width-1; 1.621 + int my = i*16; 1.622 + uint32_t *right = rgba_pixels + my*width + mx; 1.623 + int endy = my +16 < height ? 16: height - my; 1.624 + 1.625 + for (int y = 0; y<endy; y++){ 1.626 + right[y*width] = pix; 1.627 + } 1.628 + } 1.629 + } 1.630 + } 1.631 +} 1.632 + 1.633 +static void draw_sbmap (H264Context *h, SuperMBContext *smbc, SDLContext *sdlc){ 1.634 + int pitch; 1.635 + uint32_t *rgba_pixels; 1.636 + SDL_Texture *sbmap= sdlc->sbmap_texture; 1.637 + 1.638 + SDL_LockTexture( sbmap, NULL, (void **)&rgba_pixels, &pitch ); 1.639 + 1.640 + memset (rgba_pixels, 0, pitch * h->height); 1.641 + for (int i=0; i< smbc->nsmb_height; i++){ 1.642 + for (int j=0; j< smbc->nsmb_width; j++){ 1.643 + draw_sb_border(h, rgba_pixels, j, i); 1.644 + } 1.645 + } 1.646 + 1.647 + SDL_UnlockTexture( sbmap ); 1.648 +} 1.649 +// #endif 1.650 + 1.651 +// static void calc_sb_sizes (H264Context *h, SuperMBContext *smbc){ 1.652 +// smbc->smb_height = h->smb_height; 1.653 +// smbc->smb_width = h->smb_width; 1.654 +// 1.655 +// 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 1.656 +// smbc->nsmb_width = h->mb_width / smbc->smb_width; 1.657 +// while ( (smbc->nsmb_width * smbc->smb_width)-(smbc->smb_height-1) < h->mb_width ) 1.658 +// smbc->nsmb_width++; 1.659 +// } 1.660 + 1.661 + 1.662 +static void handle_key_event(H264Context *h, SDLContext *sdlc, SDL_Keysym keysym){ 1.663 + int arrow=0; 1.664 + 1.665 + switch (keysym.sym){ 1.666 + case SDLK_ESCAPE: 1.667 + if (sdlc->fullscreen){ 1.668 + SDL_SetWindowFullscreen(sdlc->window, SDL_FALSE); 1.669 + sdlc->fullscreen = 0; 1.670 + } 1.671 + break; 1.672 + case SDLK_SPACE: 1.673 + pthread_mutex_lock(&h->sdl_lock); 1.674 + sdlc->pause = !sdlc->pause; 1.675 + pthread_cond_signal(&h->sdl_cond); 1.676 + pthread_mutex_unlock(&h->sdl_lock); 1.677 + break; 1.678 + case SDLK_f: 1.679 + if (!sdlc->fullscreen){ 1.680 + if (keysym.mod == KMOD_LCTRL){ 1.681 +// SDL_SetWindowDisplayMode (sdlc->window, &sdlc->full); 1.682 + SDL_SetWindowFullscreen(sdlc->window, SDL_TRUE); 1.683 + 1.684 + sdlc->fullscreen = 1; 1.685 + } 1.686 + } 1.687 + break; 1.688 + case SDLK_m: 1.689 + sdlc->showmap = !sdlc->showmap; 1.690 + break; 1.691 + case SDLK_UP: 1.692 + if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_height < h->mb_height && h->smb_height < h->smb_width){ 1.693 + h->smb_height++; 1.694 + arrow =1; 1.695 + } 1.696 + break; 1.697 + case SDLK_DOWN: 1.698 + if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_height > 1 ){ 1.699 + h->smb_height--; 1.700 + arrow =1; 1.701 + } 1.702 + break; 1.703 + case SDLK_LEFT: 1.704 + if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_width > 1 && h->smb_width > h->smb_height){ 1.705 + h->smb_width--; 1.706 + arrow =1; 1.707 + } 1.708 + break; 1.709 + case SDLK_RIGHT: 1.710 + if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_width < h->mb_width){ 1.711 + h->smb_width++; 1.712 + arrow =1; 1.713 + } 1.714 + break; 1.715 + } 1.716 + 1.717 + if (arrow){ 1.718 + SuperMBContext *smbc = getSuperMBContext(h, h->smb_width, h->smb_height); 1.719 + pthread_mutex_lock(&h->smb_lock); 1.720 + h->smbc->refcount--; 1.721 + if (h->smbc->refcount == 0) 1.722 + freeSuperMBContext(h->smbc); 1.723 + h->smbc = smbc; 1.724 + sdlc->updatemap =1; 1.725 + pthread_mutex_unlock(&h->smb_lock); 1.726 + } 1.727 +} 1.728 + 1.729 +void handle_window_event(H264Context *h, SDLContext *sdlc, SDL_WindowEvent winevent){ 1.730 + SDL_Rect nrect; 1.731 + switch (winevent.event){ 1.732 + case SDL_WINDOWEVENT_RESIZED: 1.733 + 1.734 + sdlc->win_w = winevent.data1; 1.735 + sdlc->win_h = winevent.data2; 1.736 + 1.737 + double aspect = (double) sdlc->win_w/ sdlc->win_h; 1.738 + if ( aspect < sdlc->aspect){ 1.739 + double r = (double) sdlc->win_w / sdlc->rect.w; 1.740 + double h = (double) sdlc->rect.h * r; 1.741 + 1.742 + nrect.y = lrint(( (double) sdlc->win_h - h)/2); 1.743 + nrect.h = lrint(h); 1.744 + 1.745 + nrect.x=0; 1.746 + nrect.w= sdlc->win_w; 1.747 + 1.748 + }else { 1.749 + double r = (double) sdlc->win_h / sdlc->rect.h; 1.750 + double w = (double) sdlc->rect.w * r; 1.751 + 1.752 + nrect.x = lrint(( (double) sdlc->win_w - w)/2); 1.753 + nrect.w = lrint(w); 1.754 + 1.755 + nrect.y=0; 1.756 + nrect.h= sdlc->win_h; 1.757 + } 1.758 + //prob better to lock 1.759 + sdlc->win_rect = nrect; 1.760 + sdlc->resized=1; 1.761 + break; 1.762 + } 1.763 +} 1.764 + 1.765 +void *sdl_event_listen_thread(void *arg){ 1.766 + H264Context *h = (H264Context *) arg; 1.767 + SDLContext *sdlc = h->sdlc; 1.768 + SDL_Event event; 1.769 + 1.770 + while ( SDL_WaitEvent(&event) ) { 1.771 + switch (event.type) { 1.772 + case SDL_KEYDOWN: 1.773 + handle_key_event(h, sdlc, event.key.keysym); 1.774 + break; 1.775 + case SDL_WINDOWEVENT: 1.776 + handle_window_event(h, sdlc, event.window); 1.777 + break; 1.778 + case SDL_QUIT: 1.779 + h->quit=1; 1.780 + goto finish; 1.781 + } 1.782 + } 1.783 +finish: 1.784 + pthread_exit(NULL); 1.785 + return NULL; 1.786 +} 1.787 + 1.788 +//XInitThreads not called in SDL2 library, causes crash 1.789 +//remove in future when fixed ... 1.790 +#include <X11/Xlib.h> 1.791 + 1.792 +SDLContext *get_SDL_context(H264Context *h){ 1.793 + const int frame_width=h->frame_width; 1.794 + const int frame_height=h->frame_height; 1.795 + 1.796 + SDLContext *sdlc = av_mallocz(sizeof(SDLContext)); 1.797 + sdlc->display = h->display; 1.798 + sdlc->fullscreen = h->fullscreen; 1.799 + 1.800 + sdlc->aspect = (double) frame_width / (double) frame_height; 1.801 + sdlc->rect.x =0; 1.802 + sdlc->rect.y =0; 1.803 + sdlc->rect.w =frame_width; 1.804 + sdlc->rect.h =frame_height; 1.805 + 1.806 + XInitThreads(); //workaround 1.807 + 1.808 + // Initializes the video subsystem 1.809 + if (SDL_Init(SDL_INIT_VIDEO) < 0) { 1.810 + fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); 1.811 + #undef exit 1.812 + exit(-1); 1.813 + } 1.814 + SDL_SetHint("SDL_HINT_RENDER_SCALE_QUALITY", "best"); 1.815 + SDL_SetHint("SDL_HINT_RENDER_OPENGL_SHADERS", "1"); 1.816 + 1.817 + SDL_GetDesktopDisplayMode(0, &sdlc->full); 1.818 + sdlc->full.format = SDL_PIXELFORMAT_IYUV; 1.819 + 1.820 + sdlc->wind = sdlc->full; 1.821 + if (sdlc->wind.w > frame_width) sdlc->wind.w = frame_width; 1.822 + if (sdlc->wind.h > frame_height) sdlc->wind.h = frame_height; 1.823 + 1.824 + sdlc->win_rect.x =0; 1.825 + sdlc->win_rect.y =0; 1.826 + sdlc->win_rect.w =sdlc->wind.w; 1.827 + sdlc->win_rect.h =sdlc->wind.h; 1.828 + 1.829 + if (sdlc->fullscreen){ 1.830 + 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); 1.831 + SDL_SetWindowDisplayMode (sdlc->window, &sdlc->full); 1.832 + } else { 1.833 + 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); 1.834 + SDL_SetWindowDisplayMode (sdlc->window, &sdlc->wind); 1.835 + } 1.836 + 1.837 + sdlc->renderer = SDL_CreateRenderer(sdlc->window, -1, SDL_RENDERER_ACCELERATED); 1.838 +// sdlc->renderer = SDL_CreateRenderer(sdlc->window, -1, SDL_RENDERER_SOFTWARE); 1.839 + 1.840 + h->sdlq.queue[0] = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height); 1.841 + h->sdlq.queue[1] = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height); 1.842 + 1.843 + sdlc->sbmap_texture = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height); 1.844 + SDL_SetTextureBlendMode(sdlc->sbmap_texture, SDL_BLENDMODE_BLEND); 1.845 + sdlc->updatemap = 1; 1.846 + 1.847 +#if HAVE_LIBSDL_TTF 1.848 + //not working with SDL 2.0, try again in future when supported 1.849 + if(TTF_Init()==-1) { 1.850 + printf("TTF_Init: %s\n", TTF_GetError()); 1.851 + exit(2); 1.852 + } 1.853 + 1.854 + // Load a font 1.855 + TTF_Font *font; 1.856 + font = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 24); 1.857 + if (font == NULL) 1.858 + { 1.859 + printf("TTF_OpenFont() Failed: %s\n", TTF_GetError()); 1.860 + TTF_Quit(); 1.861 + exit(1); 1.862 + } 1.863 +#endif 1.864 + 1.865 + pthread_create(&sdlc->listen_thread, NULL, sdl_event_listen_thread, h); 1.866 + 1.867 + return sdlc; 1.868 + 1.869 +} 1.870 + 1.871 +void free_SDL_context(H264Context *h){ 1.872 + SDLContext *sdlc = h->sdlc; 1.873 + pthread_join(sdlc->listen_thread, NULL); 1.874 + 1.875 +#if HAVE_LIBSDL_TTF 1.876 + TTF_Quit(); 1.877 +#endif 1.878 + SDL_DestroyTexture(h->sdlq.queue[0]); 1.879 + SDL_DestroyTexture(h->sdlq.queue[1]); 1.880 + SDL_DestroyTexture(sdlc->sbmap_texture); 1.881 + SDL_DestroyRenderer(sdlc->renderer); 1.882 + SDL_DestroyWindow(sdlc->window); 1.883 + SDL_Quit(); 1.884 + 1.885 +} 1.886 + 1.887 +void *sdl_thread(void *arg){ 1.888 + H264Context *h = (H264Context *) arg; 1.889 + 1.890 + SDLContext *sdlc = get_SDL_context(h); 1.891 + h->sdlc = sdlc; 1.892 + 1.893 + signal_texture(h, 0); 1.894 + signal_texture(h, 0); 1.895 + 1.896 + SDL_Texture *texture; 1.897 + for (;;){ 1.898 + pthread_mutex_lock(&h->sdl_lock); 1.899 + while (sdlc->pause){ 1.900 + pthread_cond_wait(&h->sdl_cond, &h->sdl_lock); 1.901 + } 1.902 + pthread_mutex_unlock(&h->sdl_lock); 1.903 + 1.904 + texture = get_next_texture(h, 0); 1.905 + if (texture == NULL) 1.906 + break; 1.907 + 1.908 + SDL_UnlockTexture(texture); 1.909 + 1.910 + //clear if resized 1.911 + if (sdlc->resized){ 1.912 + // KDE bug prob, reset viewport change after resize from max 1.913 + SDL_RenderSetViewport(sdlc->renderer, NULL); 1.914 + SDL_SetRenderDrawColor(sdlc->renderer, 0, 0, 0, 255); 1.915 + SDL_RenderClear(sdlc->renderer); 1.916 + sdlc->resized = 0; 1.917 + } 1.918 + 1.919 + SDL_RenderCopy(sdlc->renderer, texture, &sdlc->rect, &sdlc->win_rect); 1.920 + 1.921 + if (sdlc->showmap){ 1.922 + if (sdlc->updatemap){ 1.923 + SuperMBContext *smbc; 1.924 + pthread_mutex_lock (&h->smb_lock); 1.925 + smbc = h->smbc; 1.926 + smbc->refcount++; 1.927 + sdlc->updatemap=0; 1.928 + pthread_mutex_unlock(&h->smb_lock); 1.929 + 1.930 + draw_sbmap(h, smbc, sdlc); 1.931 + 1.932 + release_smbc(h, smbc); 1.933 + } 1.934 + SDL_RenderCopy(sdlc->renderer, sdlc->sbmap_texture, &sdlc->rect, &sdlc->win_rect); 1.935 + } 1.936 + 1.937 + SDL_RenderPresent(sdlc->renderer); 1.938 + signal_texture(h, 0); 1.939 + } 1.940 + 1.941 + free_SDL_context(h); 1.942 + 1.943 + pthread_exit(NULL); 1.944 + return NULL; 1.945 +} 1.946 +#endif 1.947 +
