nengel@2: #include "config.h" nengel@2: nengel@2: #include "h264_types.h" nengel@2: nengel@2: #include nengel@2: #include nengel@2: #include nengel@2: #include nengel@2: #include nengel@2: #undef NDEBUG nengel@2: #include nengel@2: nengel@2: #if HAVE_LIBSDL2 nengel@2: #include nengel@2: #if HAVE_LIBSDL_TTF nengel@2: #include nengel@2: #endif nengel@2: #endif nengel@2: nengel@2: void start_timer(H264Context *h, int stage){ nengel@2: clock_gettime(CLOCK_REALTIME, &h->start_time[stage]); nengel@2: } nengel@2: nengel@2: void stop_timer(H264Context *h, int stage){ nengel@2: clock_gettime(CLOCK_REALTIME, &h->end_time[stage]); nengel@2: 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: h->last_time [stage] = time; nengel@2: h->total_time[stage] += time; nengel@2: } nengel@2: nengel@2: void init_sb_entry(H264Context *h, SliceBufferEntry *sbe){ nengel@2: sbe->mbs = av_malloc(h->mb_width*h->mb_height* sizeof(H264Mb)); nengel@2: sbe->initialized = 1; nengel@2: } nengel@2: nengel@2: void free_sb_entry(SliceBufferEntry *sbe){ nengel@2: av_free(sbe->mbs); nengel@2: av_freep(&sbe->gb.raw); nengel@2: if (sbe->gb.rbsp) nengel@2: av_freep(&sbe->gb.rbsp); nengel@2: sbe->initialized = 0; nengel@2: } nengel@2: nengel@2: SliceBufferEntry *get_sb_entry(H264Context *h){ nengel@2: SliceBufferEntry *sb = NULL; nengel@2: nengel@2: pthread_mutex_lock(&h->lock[PARSE]); nengel@2: while (h->free_sb_cnt<=0) nengel@2: pthread_cond_wait(&h->cond[PARSE], &h->lock[PARSE]); nengel@2: /* use first free picture */ nengel@2: for(int i=0; isb_size; i++){ nengel@2: if(h->sb[i].state==0){ nengel@2: sb= &h->sb[i]; nengel@2: sb->state=1; nengel@2: sb->lines_taken=0; nengel@2: sb->lines_total=h->mb_height; nengel@2: break; nengel@2: } nengel@2: } nengel@2: h->free_sb_cnt--; nengel@2: nengel@2: pthread_mutex_unlock(&h->lock[PARSE]); nengel@2: nengel@2: memset (&sb->slice, 0, sizeof(H264Slice)); nengel@2: nengel@2: return sb; nengel@2: } nengel@2: nengel@2: void release_sb_entry(H264Context *h, SliceBufferEntry *sb){ nengel@2: pthread_mutex_lock(&h->lock[PARSE]); nengel@2: nengel@2: sb->state = 0; nengel@2: h->free_sb_cnt++; nengel@2: pthread_cond_signal(&h->cond[PARSE]); nengel@2: nengel@2: pthread_mutex_unlock(&h->lock[PARSE]); nengel@2: } nengel@2: nengel@2: int init_dpb_entry(H264Context *h, DecodedPicture *pic, H264Slice *s, int width, int height){ nengel@2: int i; nengel@2: nengel@2: s->curr_pic=pic; nengel@2: pic->poc = s->poc; nengel@2: pic->key_frame = s->key_frame; nengel@2: pic->mmco_reset = s->mmco_reset; nengel@2: pic->reference = s->nal_ref_idc? 3:1; nengel@2: pic->cpn = s->coded_pic_num; nengel@2: nengel@2: if(pic->data[0]==NULL) { nengel@2: int size[3] = {0}; nengel@2: nengel@2: width+= EDGE_WIDTH*2; nengel@2: height+= EDGE_WIDTH*2; nengel@2: nengel@2: pic->linesize[0]= width; nengel@2: pic->linesize[1]= pic->linesize[2] = width>>1; nengel@2: nengel@2: size[0] = width*height; nengel@2: size[1] = size[2] = width*height>>2; nengel@2: nengel@2: for(i=0; i<3; i++){ nengel@2: pic->base[i]= av_malloc(size[i]); nengel@2: } nengel@2: nengel@2: pic->data[0] = pic->base[0] + (pic->linesize[0]*EDGE_WIDTH) + EDGE_WIDTH; nengel@2: pic->data[1] = pic->base[1] + (pic->linesize[1]*EDGE_WIDTH>>1) + (EDGE_WIDTH>>1); nengel@2: pic->data[2] = pic->base[2] + (pic->linesize[2]*EDGE_WIDTH>>1) + (EDGE_WIDTH>>1); nengel@2: } nengel@2: nengel@2: 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: const int mb_array_size= h->mb_stride*h->mb_height; nengel@2: const int b4_array_size= h->b4_stride*h->mb_height*4; nengel@2: nengel@2: if(pic->mb_type_base==NULL){ nengel@2: FF_ALLOCZ_OR_GOTO(pic->mb_type_base , big_mb_num * sizeof(uint32_t), fail) nengel@2: pic->mb_type= pic->mb_type_base + h->mb_stride+1; nengel@2: nengel@2: for(int i=0; i<2; i++){ nengel@2: FF_ALLOCZ_OR_GOTO(pic->motion_val_base[i], 2 * (b4_array_size+4) * sizeof(int16_t), fail) nengel@2: pic->motion_val[i]= pic->motion_val_base[i]+4; nengel@2: FF_ALLOCZ_OR_GOTO(pic->ref_index[i], 4*mb_array_size * sizeof(uint8_t), fail) nengel@2: } nengel@2: FF_ALLOCZ_OR_GOTO(pic->intra4x4_pred_mode, h->mb_width*h->mb_height * 4* sizeof(int8_t), fail) nengel@2: } nengel@2: nengel@2: return 0; nengel@2: fail: nengel@2: return -1; nengel@2: } nengel@2: nengel@2: void free_dp(DecodedPicture *pic){ nengel@2: if(pic->base[0]){ nengel@2: for (int i=0; i<3; i++){ nengel@2: av_free(pic->base[i]); nengel@2: pic->data[i]= NULL; nengel@2: } nengel@2: } nengel@2: if (pic->mb_type_base){ nengel@2: av_free(pic->mb_type_base); nengel@2: pic->mb_type= NULL; nengel@2: for(int i=0; i<2; i++){ nengel@2: av_free(pic->motion_val_base[i]); nengel@2: av_free(pic->ref_index[i]); nengel@2: } nengel@2: av_free(pic->intra4x4_pred_mode); nengel@2: } nengel@2: } nengel@2: nengel@2: DecodedPicture *get_dpb_entry(H264Context *h, H264Slice *s){ nengel@2: DecodedPicture *dp = NULL; nengel@2: nengel@2: pthread_mutex_lock(&h->lock[REORDER2]); nengel@2: while (h->free_dpb_cnt<=0){ nengel@2: #if OMPSS nengel@2: assert(0); nengel@2: #endif nengel@2: pthread_cond_wait(&h->cond[REORDER2], &h->lock[REORDER2]); nengel@2: } nengel@2: /* use first free picture */ nengel@2: for(int i=0; imax_dpb_cnt; i++){ nengel@2: if(h->dpb[i].reference==0){ nengel@2: dp= &h->dpb[i]; nengel@2: break; nengel@2: } nengel@2: } nengel@2: assert(dp); nengel@2: init_dpb_entry(h, dp, s, h->width, h->height); nengel@2: h->free_dpb_cnt--; nengel@2: h->acdpb_cnt++; //debug nengel@2: pthread_mutex_unlock(&h->lock[REORDER2]); nengel@2: nengel@2: return dp; nengel@2: } nengel@2: nengel@2: void release_dpb_entry(H264Context *h, DecodedPicture *pic, int mode){ nengel@2: pthread_mutex_lock(&h->lock[REORDER2]); nengel@2: pic->reference &= ~mode; nengel@2: if (pic->reference == 0){ nengel@2: h->free_dpb_cnt++; nengel@2: h->reldpb_cnt++; //debug nengel@2: pthread_cond_signal(&h->cond[REORDER2]); nengel@2: } nengel@2: pthread_mutex_unlock(&h->lock[REORDER2]); nengel@2: } nengel@2: nengel@2: nengel@2: /** nengel@2: * Extends the edges of a macroblock line. nengel@2: */ nengel@2: void draw_edges(MBRecContext *d, H264Slice *s, int line){ nengel@2: int i; nengel@2: int mb_width=d->mb_width; nengel@2: int mb_height=d->mb_height; nengel@2: int last = (line+1 == mb_height); nengel@2: int lines = last?16:12; nengel@2: int linesize = d->linesize; nengel@2: int uvlinesize = d->uvlinesize; nengel@2: uint8_t *y = s->curr_pic->data[0] + 16*line*linesize; nengel@2: uint8_t *cb = s->curr_pic->data[1] + 8*line*uvlinesize; nengel@2: uint8_t *cr = s->curr_pic->data[2] + 8*line*uvlinesize; nengel@2: nengel@2: for (i=-4; idelayed_pic[0]; nengel@2: nengel@2: if (!out) nengel@2: return NULL; nengel@2: nengel@2: for(i=1; w->delayed_pic[i] && !w->delayed_pic[i]->key_frame && !w->delayed_pic[i]->mmco_reset; i++){ nengel@2: if(w->delayed_pic[i]->poc < out->poc){ nengel@2: out = w->delayed_pic[i]; nengel@2: out_idx = i; nengel@2: } nengel@2: } nengel@2: nengel@2: if(w->dp_cnt > MAX_DELAYED_PIC_COUNT || flush) { nengel@2: for(i=out_idx; w->delayed_pic[i]; i++) nengel@2: w->delayed_pic[i] = w->delayed_pic[i+1]; nengel@2: w->dp_cnt--; nengel@2: return out; nengel@2: } nengel@2: return NULL; nengel@2: } nengel@2: nengel@2: /** nengel@2: * Remove the extra borders, and places the three parts of the image after each other. nengel@2: */ nengel@2: static int raw_encode(const DecodedPicture* src, int width, int height, unsigned char *dest) { nengel@2: int i, j; nengel@2: /** To write entire image including extra borders*/ nengel@2: // int w = src->linesize[0]; nengel@2: // int h = height+64; nengel@2: // int w2 = w>>1; nengel@2: // int h2 = h>>1; nengel@2: // int data_planes=3; nengel@2: // int size = w * h + 2 *w2*h2; nengel@2: // const unsigned char* s; nengel@2: // for (i=0; ibase[i]; nengel@2: // for(j=0; jlinesize[i]); nengel@2: // dest += w; nengel@2: // s += src->linesize[i]; nengel@2: // } nengel@2: // } nengel@2: nengel@2: int w = (width*8 + 7)/8; nengel@2: int h = height; nengel@2: int w2 =((width >>1) * 8 + 7) / 8; nengel@2: int h2 = ((height+1) >>1); //not sure about +1 nengel@2: int data_planes=3; nengel@2: int size = w * h + 2 *w2*h2; nengel@2: const unsigned char* s; nengel@2: nengel@2: nengel@2: for (i=0; idata[i]; nengel@2: for(j=0; jlinesize[i]; nengel@2: } nengel@2: } nengel@2: return size; nengel@2: } nengel@2: nengel@2: #ifdef HAVE_LIBSDL2 nengel@2: static SDL_Texture *get_next_texture(H264Context *h, int side){ nengel@2: SDLTextureQueue *sdlq = &h->sdlq; nengel@2: SDL_Texture *texture; nengel@2: pthread_mutex_lock (&sdlq->sdl_lock); nengel@2: if (side ){ //send nengel@2: while (sdlq->ready >= sdlq->size) nengel@2: pthread_cond_wait(&sdlq->sdl_cond, &sdlq->sdl_lock); nengel@2: texture = sdlq->queue[sdlq->fi]; nengel@2: sdlq->fi++; sdlq->fi %= sdlq->size; nengel@2: } else { //recv nengel@2: while (sdlq->ready <= 0 && !sdlq->exit) nengel@2: pthread_cond_wait(&sdlq->sdl_cond, &sdlq->sdl_lock); nengel@2: nengel@2: if (sdlq->ready == 0 && sdlq->exit){ nengel@2: texture = NULL; nengel@2: }else{ nengel@2: texture = sdlq->queue[sdlq->fo]; nengel@2: sdlq->fo++; sdlq->fo %= sdlq->size; nengel@2: } nengel@2: } nengel@2: pthread_mutex_unlock(&sdlq->sdl_lock); nengel@2: nengel@2: return texture; nengel@2: } nengel@2: nengel@2: static void signal_texture(H264Context *h, int side){ nengel@2: SDLTextureQueue *sdlq = &h->sdlq; nengel@2: pthread_mutex_lock (&sdlq->sdl_lock); nengel@2: if (side) nengel@2: sdlq->ready++; nengel@2: else nengel@2: sdlq->ready--; nengel@2: pthread_cond_signal(&sdlq->sdl_cond); nengel@2: pthread_mutex_unlock(&sdlq->sdl_lock); nengel@2: } nengel@2: nengel@2: void signal_sdl_exit(H264Context *h){ nengel@2: SDLTextureQueue *sdlq = &h->sdlq; nengel@2: pthread_mutex_lock (&sdlq->sdl_lock); nengel@2: sdlq->exit=1; nengel@2: pthread_cond_signal(&sdlq->sdl_cond); nengel@2: pthread_mutex_unlock(&sdlq->sdl_lock); nengel@2: } nengel@2: nengel@2: static void display_frame(H264Context *h, OutputContext *w, int fd, DecodedPicture *in_picture, int frame_width, int frame_height, int dropable){ nengel@2: static int64_t last_time = -1; nengel@2: int64_t cur_time; nengel@2: // SDLContext *sdlc = h->sdlc; nengel@2: uint8_t *iyuv_pixels; nengel@2: int pitch; nengel@2: nengel@2: nengel@2: if (last_time == -1){ nengel@2: last_time = av_gettime(); nengel@2: } nengel@2: nengel@2: nengel@2: /* do not display frames that are less than 8.125 ms apart (120fps)*/ nengel@2: if (dropable){ nengel@2: cur_time = av_gettime(); nengel@2: nengel@2: if ((cur_time - last_time) < 8125) nengel@2: return; nengel@2: nengel@2: last_time =cur_time; nengel@2: } nengel@2: nengel@2: if(in_picture){ nengel@2: nengel@2: SDL_Texture *texture= get_next_texture(h, 1); nengel@2: nengel@2: SDL_LockTexture( texture, NULL, (void **)&iyuv_pixels, &pitch ); nengel@2: nengel@2: raw_encode(in_picture, frame_width, frame_height, iyuv_pixels); nengel@2: nengel@2: signal_texture(h, 1); nengel@2: } nengel@2: } nengel@2: #endif nengel@2: nengel@2: // TODO: Parallelize the raw_encode (either split frame or over frames) nengel@2: static void do_video_out(OutputContext *w, int fd, DecodedPicture *in_picture, int frame_width, int frame_height) { nengel@2: int size=0; nengel@2: //remove extra borders nengel@2: nengel@2: if(in_picture) nengel@2: size= raw_encode(in_picture, frame_width, frame_height, w->bit_buffer); nengel@2: nengel@2: if (size < 0) { nengel@2: fprintf(stderr, "Video encoding failed\n"); nengel@2: }else { nengel@2: if (write(fd, w->bit_buffer, size)<0) nengel@2: fprintf(stderr, "Write frame failed\n"); nengel@2: } nengel@2: nengel@2: w->video_size += size; nengel@2: } nengel@2: nengel@2: DecodedPicture *output_frame(H264Context *h, OutputContext *oc, DecodedPicture *pic, int fd, int frame_width, int frame_height) { nengel@2: DecodedPicture *out; nengel@2: nengel@2: if (pic){ nengel@2: oc->delayed_pic[oc->dp_cnt++]=pic; nengel@2: out = get_reordered_picture(oc, 0); nengel@2: }else{ nengel@2: out = get_reordered_picture(oc, 1); nengel@2: } nengel@2: nengel@2: if (out){ nengel@2: if (fd){ nengel@2: do_video_out(oc, fd, out, frame_width, frame_height); nengel@2: }else{ nengel@2: #ifdef HAVE_LIBSDL2 nengel@2: if (h->display){ nengel@2: display_frame(h, oc, fd, out, frame_width, frame_height, !(pic==NULL)); nengel@2: } nengel@2: #endif nengel@2: } nengel@2: oc->frame_number++; nengel@2: } nengel@2: nengel@2: return out; nengel@2: } nengel@2: nengel@2: OutputContext *get_output_context(H264Context *h){ nengel@2: const int frame_width=h->frame_width; nengel@2: const int frame_height=h->frame_height; nengel@2: const int frame_size = frame_width*frame_height; nengel@2: nengel@2: OutputContext *oc = av_mallocz(sizeof(OutputContext)); nengel@2: oc->bit_buffer_size= FFMAX(1024*256, frame_size*2); // oversize a little bit to allow extra border write nengel@2: oc->bit_buffer= av_mallocz(oc->bit_buffer_size); nengel@2: nengel@2: return oc; nengel@2: } nengel@2: nengel@2: void free_output_context(OutputContext *oc){ nengel@2: nengel@2: av_free(oc->bit_buffer); nengel@2: av_free(oc); nengel@2: } nengel@2: nengel@2: SuperMBContext *getSuperMBContext(H264Context *h, int smb_width, int smb_height){ nengel@2: SuperMBContext *smbc = av_mallocz(sizeof(SuperMBContext)); nengel@2: nengel@2: smbc->smb_width = smb_width; nengel@2: smbc->smb_height = smb_height; nengel@2: nengel@2: 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: smbc->nsmb_width = h->mb_width / smbc->smb_width; nengel@2: while ( (smbc->nsmb_width * smbc->smb_width)-(smbc->smb_height-1) < h->mb_width ) nengel@2: smbc->nsmb_width++; nengel@2: nengel@2: smbc->nsmb_3dheight= smbc->nsmb_height - ((h->mb_height/2)/smbc->smb_height +1); //assuming max motion vector of half the height nengel@2: nengel@2: smbc->smbs[0] = av_malloc (smbc->nsmb_width * smbc->nsmb_height * sizeof(SuperMBTask)); nengel@2: smbc->smbs[1] = av_malloc (smbc->nsmb_width * smbc->nsmb_height * sizeof(SuperMBTask)); nengel@2: for (int y=0, i=0; insmb_height; i++, y+=smbc->smb_height){ nengel@2: for (int x=0, j=0; jnsmb_width; j++, x+=smbc->smb_width){ nengel@2: smbc->smbs[0][i*smbc->nsmb_width +j].smb_y = y; nengel@2: smbc->smbs[0][i*smbc->nsmb_width +j].smb_x = x; nengel@2: smbc->smbs[1][i*smbc->nsmb_width +j].smb_y = y; nengel@2: smbc->smbs[1][i*smbc->nsmb_width +j].smb_x = x; nengel@2: } nengel@2: } nengel@2: nengel@2: smbc->refcount = 1; nengel@2: nengel@2: return smbc; nengel@2: } nengel@2: nengel@2: void freeSuperMBContext(SuperMBContext *smbc){ nengel@2: av_free(smbc->smbs[0]); nengel@2: av_free(smbc->smbs[1]); nengel@2: av_free(smbc); nengel@2: } nengel@2: nengel@2: SuperMBContext * acquire_smbc(H264Context *h ){ nengel@2: SuperMBContext *smbc; nengel@2: nengel@2: pthread_mutex_lock (&h->smb_lock); nengel@2: smbc = h->smbc; nengel@2: smbc->refcount++; nengel@2: pthread_mutex_unlock(&h->smb_lock); nengel@2: return smbc; nengel@2: } nengel@2: nengel@2: void release_smbc(H264Context *h, SuperMBContext *smbc){ nengel@2: pthread_mutex_lock (&h->smb_lock); nengel@2: smbc->refcount--; nengel@2: if (smbc->refcount==0){ nengel@2: freeSuperMBContext(smbc); nengel@2: } nengel@2: pthread_mutex_unlock(&h->smb_lock); nengel@2: nengel@2: } nengel@2: nengel@2: nengel@2: #ifdef HAVE_LIBSDL2 nengel@2: nengel@2: // #if OMPSS nengel@2: static void draw_sb_border(H264Context *h, uint32_t *rgba_pixels, int smb_x, int smb_y){ nengel@2: int mb_width = h->mb_width; nengel@2: int mb_height = h->mb_height; nengel@2: int width = h->frame_width; nengel@2: int height = h->frame_height; nengel@2: nengel@2: int mb_x = smb_x * h->smb_width; nengel@2: int mb_y = smb_y * h->smb_height; nengel@2: nengel@2: uint32_t pix= 0x0000FFC0; nengel@2: nengel@2: for (int k=0, i=mb_y; i< mb_y + h->smb_height; i++, k++){ nengel@2: for (int l=0, j=mb_x -k ; j< mb_x - k + h->smb_width; j++, l++){ nengel@2: //outside frame nengel@2: if (i<0 || i>=mb_height || j<0 || j>=mb_width) { nengel@2: continue; nengel@2: } nengel@2: nengel@2: //draw top nengel@2: if (i==0 || k==0 || l==0){ nengel@2: int mx = j*16; nengel@2: int my = i*16; nengel@2: uint32_t *top = rgba_pixels + my*width + mx; nengel@2: int endx = mx+16 < width? 16: width-mx; nengel@2: nengel@2: for (int x = 0; xsmb_height-1 || l==h->smb_width-1){ nengel@2: int mx = j*16; nengel@2: int my = i*16 + 15; my = my < height ? my: height-1; nengel@2: uint32_t *bottom = rgba_pixels + my*width + mx; nengel@2: int endx = mx+16 < width? 16: width-mx; nengel@2: nengel@2: for (int x = 0; xsmb_width-1 ){ nengel@2: int mx = j*16 + 15; mx = mx < width ? mx: width-1; nengel@2: int my = i*16; nengel@2: uint32_t *right = rgba_pixels + my*width + mx; nengel@2: int endy = my +16 < height ? 16: height - my; nengel@2: nengel@2: for (int y = 0; ysbmap_texture; nengel@2: nengel@2: SDL_LockTexture( sbmap, NULL, (void **)&rgba_pixels, &pitch ); nengel@2: nengel@2: memset (rgba_pixels, 0, pitch * h->height); nengel@2: for (int i=0; i< smbc->nsmb_height; i++){ nengel@2: for (int j=0; j< smbc->nsmb_width; j++){ nengel@2: draw_sb_border(h, rgba_pixels, j, i); nengel@2: } nengel@2: } nengel@2: nengel@2: SDL_UnlockTexture( sbmap ); nengel@2: } nengel@2: // #endif nengel@2: nengel@2: // static void calc_sb_sizes (H264Context *h, SuperMBContext *smbc){ nengel@2: // smbc->smb_height = h->smb_height; nengel@2: // smbc->smb_width = h->smb_width; nengel@2: // nengel@2: // 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: // smbc->nsmb_width = h->mb_width / smbc->smb_width; nengel@2: // while ( (smbc->nsmb_width * smbc->smb_width)-(smbc->smb_height-1) < h->mb_width ) nengel@2: // smbc->nsmb_width++; nengel@2: // } nengel@2: nengel@2: nengel@2: static void handle_key_event(H264Context *h, SDLContext *sdlc, SDL_Keysym keysym){ nengel@2: int arrow=0; nengel@2: nengel@2: switch (keysym.sym){ nengel@2: case SDLK_ESCAPE: nengel@2: if (sdlc->fullscreen){ nengel@2: SDL_SetWindowFullscreen(sdlc->window, SDL_FALSE); nengel@2: sdlc->fullscreen = 0; nengel@2: } nengel@2: break; nengel@2: case SDLK_SPACE: nengel@2: pthread_mutex_lock(&h->sdl_lock); nengel@2: sdlc->pause = !sdlc->pause; nengel@2: pthread_cond_signal(&h->sdl_cond); nengel@2: pthread_mutex_unlock(&h->sdl_lock); nengel@2: break; nengel@2: case SDLK_f: nengel@2: if (!sdlc->fullscreen){ nengel@2: if (keysym.mod == KMOD_LCTRL){ nengel@2: // SDL_SetWindowDisplayMode (sdlc->window, &sdlc->full); nengel@2: SDL_SetWindowFullscreen(sdlc->window, SDL_TRUE); nengel@2: nengel@2: sdlc->fullscreen = 1; nengel@2: } nengel@2: } nengel@2: break; nengel@2: case SDLK_m: nengel@2: sdlc->showmap = !sdlc->showmap; nengel@2: break; nengel@2: case SDLK_UP: nengel@2: if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_height < h->mb_height && h->smb_height < h->smb_width){ nengel@2: h->smb_height++; nengel@2: arrow =1; nengel@2: } nengel@2: break; nengel@2: case SDLK_DOWN: nengel@2: if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_height > 1 ){ nengel@2: h->smb_height--; nengel@2: arrow =1; nengel@2: } nengel@2: break; nengel@2: case SDLK_LEFT: nengel@2: if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_width > 1 && h->smb_width > h->smb_height){ nengel@2: h->smb_width--; nengel@2: arrow =1; nengel@2: } nengel@2: break; nengel@2: case SDLK_RIGHT: nengel@2: if (keysym.mod == KMOD_NONE && sdlc->showmap && h->smb_width < h->mb_width){ nengel@2: h->smb_width++; nengel@2: arrow =1; nengel@2: } nengel@2: break; nengel@2: } nengel@2: nengel@2: if (arrow){ nengel@2: SuperMBContext *smbc = getSuperMBContext(h, h->smb_width, h->smb_height); nengel@2: pthread_mutex_lock(&h->smb_lock); nengel@2: h->smbc->refcount--; nengel@2: if (h->smbc->refcount == 0) nengel@2: freeSuperMBContext(h->smbc); nengel@2: h->smbc = smbc; nengel@2: sdlc->updatemap =1; nengel@2: pthread_mutex_unlock(&h->smb_lock); nengel@2: } nengel@2: } nengel@2: nengel@2: void handle_window_event(H264Context *h, SDLContext *sdlc, SDL_WindowEvent winevent){ nengel@2: SDL_Rect nrect; nengel@2: switch (winevent.event){ nengel@2: case SDL_WINDOWEVENT_RESIZED: nengel@2: nengel@2: sdlc->win_w = winevent.data1; nengel@2: sdlc->win_h = winevent.data2; nengel@2: nengel@2: double aspect = (double) sdlc->win_w/ sdlc->win_h; nengel@2: if ( aspect < sdlc->aspect){ nengel@2: double r = (double) sdlc->win_w / sdlc->rect.w; nengel@2: double h = (double) sdlc->rect.h * r; nengel@2: nengel@2: nrect.y = lrint(( (double) sdlc->win_h - h)/2); nengel@2: nrect.h = lrint(h); nengel@2: nengel@2: nrect.x=0; nengel@2: nrect.w= sdlc->win_w; nengel@2: nengel@2: }else { nengel@2: double r = (double) sdlc->win_h / sdlc->rect.h; nengel@2: double w = (double) sdlc->rect.w * r; nengel@2: nengel@2: nrect.x = lrint(( (double) sdlc->win_w - w)/2); nengel@2: nrect.w = lrint(w); nengel@2: nengel@2: nrect.y=0; nengel@2: nrect.h= sdlc->win_h; nengel@2: } nengel@2: //prob better to lock nengel@2: sdlc->win_rect = nrect; nengel@2: sdlc->resized=1; nengel@2: break; nengel@2: } nengel@2: } nengel@2: nengel@2: void *sdl_event_listen_thread(void *arg){ nengel@2: H264Context *h = (H264Context *) arg; nengel@2: SDLContext *sdlc = h->sdlc; nengel@2: SDL_Event event; nengel@2: nengel@2: while ( SDL_WaitEvent(&event) ) { nengel@2: switch (event.type) { nengel@2: case SDL_KEYDOWN: nengel@2: handle_key_event(h, sdlc, event.key.keysym); nengel@2: break; nengel@2: case SDL_WINDOWEVENT: nengel@2: handle_window_event(h, sdlc, event.window); nengel@2: break; nengel@2: case SDL_QUIT: nengel@2: h->quit=1; nengel@2: goto finish; nengel@2: } nengel@2: } nengel@2: finish: nengel@2: pthread_exit(NULL); nengel@2: return NULL; nengel@2: } nengel@2: nengel@2: //XInitThreads not called in SDL2 library, causes crash nengel@2: //remove in future when fixed ... nengel@2: #include nengel@2: nengel@2: SDLContext *get_SDL_context(H264Context *h){ nengel@2: const int frame_width=h->frame_width; nengel@2: const int frame_height=h->frame_height; nengel@2: nengel@2: SDLContext *sdlc = av_mallocz(sizeof(SDLContext)); nengel@2: sdlc->display = h->display; nengel@2: sdlc->fullscreen = h->fullscreen; nengel@2: nengel@2: sdlc->aspect = (double) frame_width / (double) frame_height; nengel@2: sdlc->rect.x =0; nengel@2: sdlc->rect.y =0; nengel@2: sdlc->rect.w =frame_width; nengel@2: sdlc->rect.h =frame_height; nengel@2: nengel@2: XInitThreads(); //workaround nengel@2: nengel@2: // Initializes the video subsystem nengel@2: if (SDL_Init(SDL_INIT_VIDEO) < 0) { nengel@2: fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); nengel@2: #undef exit nengel@2: exit(-1); nengel@2: } nengel@2: SDL_SetHint("SDL_HINT_RENDER_SCALE_QUALITY", "best"); nengel@2: SDL_SetHint("SDL_HINT_RENDER_OPENGL_SHADERS", "1"); nengel@2: nengel@2: SDL_GetDesktopDisplayMode(0, &sdlc->full); nengel@2: sdlc->full.format = SDL_PIXELFORMAT_IYUV; nengel@2: nengel@2: sdlc->wind = sdlc->full; nengel@2: if (sdlc->wind.w > frame_width) sdlc->wind.w = frame_width; nengel@2: if (sdlc->wind.h > frame_height) sdlc->wind.h = frame_height; nengel@2: nengel@2: sdlc->win_rect.x =0; nengel@2: sdlc->win_rect.y =0; nengel@2: sdlc->win_rect.w =sdlc->wind.w; nengel@2: sdlc->win_rect.h =sdlc->wind.h; nengel@2: nengel@2: if (sdlc->fullscreen){ nengel@2: 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: SDL_SetWindowDisplayMode (sdlc->window, &sdlc->full); nengel@2: } else { nengel@2: 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: SDL_SetWindowDisplayMode (sdlc->window, &sdlc->wind); nengel@2: } nengel@2: nengel@2: sdlc->renderer = SDL_CreateRenderer(sdlc->window, -1, SDL_RENDERER_ACCELERATED); nengel@2: // sdlc->renderer = SDL_CreateRenderer(sdlc->window, -1, SDL_RENDERER_SOFTWARE); nengel@2: nengel@2: h->sdlq.queue[0] = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height); nengel@2: h->sdlq.queue[1] = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height); nengel@2: nengel@2: sdlc->sbmap_texture = SDL_CreateTexture (sdlc->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, frame_width, frame_height); nengel@2: SDL_SetTextureBlendMode(sdlc->sbmap_texture, SDL_BLENDMODE_BLEND); nengel@2: sdlc->updatemap = 1; nengel@2: nengel@2: #if HAVE_LIBSDL_TTF nengel@2: //not working with SDL 2.0, try again in future when supported nengel@2: if(TTF_Init()==-1) { nengel@2: printf("TTF_Init: %s\n", TTF_GetError()); nengel@2: exit(2); nengel@2: } nengel@2: nengel@2: // Load a font nengel@2: TTF_Font *font; nengel@2: font = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 24); nengel@2: if (font == NULL) nengel@2: { nengel@2: printf("TTF_OpenFont() Failed: %s\n", TTF_GetError()); nengel@2: TTF_Quit(); nengel@2: exit(1); nengel@2: } nengel@2: #endif nengel@2: nengel@2: pthread_create(&sdlc->listen_thread, NULL, sdl_event_listen_thread, h); nengel@2: nengel@2: return sdlc; nengel@2: nengel@2: } nengel@2: nengel@2: void free_SDL_context(H264Context *h){ nengel@2: SDLContext *sdlc = h->sdlc; nengel@2: pthread_join(sdlc->listen_thread, NULL); nengel@2: nengel@2: #if HAVE_LIBSDL_TTF nengel@2: TTF_Quit(); nengel@2: #endif nengel@2: SDL_DestroyTexture(h->sdlq.queue[0]); nengel@2: SDL_DestroyTexture(h->sdlq.queue[1]); nengel@2: SDL_DestroyTexture(sdlc->sbmap_texture); nengel@2: SDL_DestroyRenderer(sdlc->renderer); nengel@2: SDL_DestroyWindow(sdlc->window); nengel@2: SDL_Quit(); nengel@2: nengel@2: } nengel@2: nengel@2: void *sdl_thread(void *arg){ nengel@2: H264Context *h = (H264Context *) arg; nengel@2: nengel@2: SDLContext *sdlc = get_SDL_context(h); nengel@2: h->sdlc = sdlc; nengel@2: nengel@2: signal_texture(h, 0); nengel@2: signal_texture(h, 0); nengel@2: nengel@2: SDL_Texture *texture; nengel@2: for (;;){ nengel@2: pthread_mutex_lock(&h->sdl_lock); nengel@2: while (sdlc->pause){ nengel@2: pthread_cond_wait(&h->sdl_cond, &h->sdl_lock); nengel@2: } nengel@2: pthread_mutex_unlock(&h->sdl_lock); nengel@2: nengel@2: texture = get_next_texture(h, 0); nengel@2: if (texture == NULL) nengel@2: break; nengel@2: nengel@2: SDL_UnlockTexture(texture); nengel@2: nengel@2: //clear if resized nengel@2: if (sdlc->resized){ nengel@2: // KDE bug prob, reset viewport change after resize from max nengel@2: SDL_RenderSetViewport(sdlc->renderer, NULL); nengel@2: SDL_SetRenderDrawColor(sdlc->renderer, 0, 0, 0, 255); nengel@2: SDL_RenderClear(sdlc->renderer); nengel@2: sdlc->resized = 0; nengel@2: } nengel@2: nengel@2: SDL_RenderCopy(sdlc->renderer, texture, &sdlc->rect, &sdlc->win_rect); nengel@2: nengel@2: if (sdlc->showmap){ nengel@2: if (sdlc->updatemap){ nengel@2: SuperMBContext *smbc; nengel@2: pthread_mutex_lock (&h->smb_lock); nengel@2: smbc = h->smbc; nengel@2: smbc->refcount++; nengel@2: sdlc->updatemap=0; nengel@2: pthread_mutex_unlock(&h->smb_lock); nengel@2: nengel@2: draw_sbmap(h, smbc, sdlc); nengel@2: nengel@2: release_smbc(h, smbc); nengel@2: } nengel@2: SDL_RenderCopy(sdlc->renderer, sdlc->sbmap_texture, &sdlc->rect, &sdlc->win_rect); nengel@2: } nengel@2: nengel@2: SDL_RenderPresent(sdlc->renderer); nengel@2: signal_texture(h, 0); nengel@2: } nengel@2: nengel@2: free_SDL_context(h); nengel@2: nengel@2: pthread_exit(NULL); nengel@2: return NULL; nengel@2: } nengel@2: #endif nengel@2: