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 +