view libavcodec/h264_pthread.c @ 9:ea1ba68cf0ed

update to match api changes + add sscc produced source
author Nina Engelhardt <nengel@mailbox.tu-berlin.de>
date Wed, 05 Jun 2013 14:43:26 +0200
parents
children
line source
1 #include "config.h"
3 #include "h264_types.h"
4 #include "h264_parser.h"
5 #include "h264_nal.h"
6 #include "h264_entropy.h"
7 #include "h264_rec.h"
8 #include "h264_misc.h"
9 // #undef NDEBUG
10 #include <assert.h>
11 #include <pthread.h>
13 #define XOANON 1
15 #ifdef XOANON
16 static int ed_rec_affinity[40] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36,
17 1, 5, 9, 13, 17, 21, 25, 29, 33, 37,
18 2, 6, 10, 14, 18, 22, 26, 30, 34, 38,
19 3, 7, 11, 15, 19, 23, 27, 31, 35, 39 };
20 static int ed_rec_smt_aff[80] = { 0, 40, 4, 44, 8, 48, 12, 52, 16, 56, 20, 60, 24, 64, 28, 68, 32, 72, 36, 76,
21 1, 41, 5, 45, 9, 49, 13, 53, 17, 57, 21, 61, 25, 65, 29, 69, 33, 73, 37, 77,
22 2, 42, 6, 46, 10, 50, 14, 54, 18, 58, 22, 62, 26, 66, 30, 70, 34, 74, 38, 78,
23 3, 43, 7, 47, 11, 51, 15, 55, 19, 59, 23, 63, 27, 67, 31, 71, 35, 75, 39, 79 };
24 #else
25 static int ed_rec_affinity[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
26 static int ed_rec_smt_aff[20] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };
27 #endif
29 static int frames=0;
31 static void notify_one_worker(H264Context *h){
32 pthread_mutex_lock(&h->task_lock);
33 pthread_cond_signal(&h->task_cond);
34 pthread_mutex_unlock(&h->task_lock);
35 }
37 static void notify_all_workers(H264Context *h){
38 pthread_mutex_lock(&h->task_lock);
39 pthread_cond_broadcast(&h->task_cond);
40 pthread_mutex_unlock(&h->task_lock);
41 }
43 static void push_sbe (SliceBufferQueue *sbq, SliceBufferEntry *sbe, int notify ){
44 pthread_mutex_lock(&sbq->lock);
45 while (sbq->cnt >= sbq->size)
46 pthread_cond_wait(&sbq->cond, &sbq->lock);
47 sbq->queue[sbq->fi] = sbe;
48 sbq->cnt++;
49 sbq->fi++; sbq->fi %= sbq->size;
50 if (notify)
51 pthread_cond_signal(&sbq->cond);
52 pthread_mutex_unlock(&sbq->lock);
53 }
55 static SliceBufferEntry* pop_sbe (SliceBufferQueue *sbq, int block){
56 SliceBufferEntry *sbe=NULL;
58 pthread_mutex_lock(&sbq->lock);
59 if (block){
60 while (sbq->cnt <= 0)
61 pthread_cond_wait(&sbq->cond, &sbq->lock);
62 }else {
63 if (sbq->cnt <= 0)
64 goto nonblock;
65 }
66 sbe = sbq->queue[sbq->fo];
67 sbq->cnt--;
68 sbq->fo++; sbq->fo %= sbq->size;
69 pthread_cond_signal(&sbq->cond);
70 nonblock:
71 pthread_mutex_unlock(&sbq->lock);
73 return sbe;
74 }
76 // static void push_rle (RingLineQueue *rlq, SliceBufferEntry *sbe, int line, int notify){
77 //
78 // //check for free slots
79 // pthread_mutex_lock(&rlq->wslock);
80 // while (rlq->free <= 0){
81 // pthread_cond_wait(&rlq->wscond, &rlq->wslock);
82 // }
83 // //free slot is available, decrement one in this lock
84 // rlq->free--;
85 // pthread_mutex_unlock(&rlq->wslock);
86 //
87 // pthread_mutex_lock(&rlq->swlock);
88 // rlq->queue[rlq->fi]->sbe=sbe;
89 // rlq->queue[rlq->fi]->line=line;
90 // rlq->queue[rlq->fi]->mb_cnt=0;
91 // rlq->fi++; rlq->fi %= rlq->size;
92 // rlq->ready++;
93 // if(notify)
94 // pthread_cond_signal(&rlq->swcond);
95 // pthread_mutex_unlock(&rlq->swlock);
96 // }
98 // static RingLineEntry* pop_rle (RingLineQueue *rlq, int block){
99 // RingLineEntry *rle=NULL;
100 //
101 // pthread_mutex_lock(&rlq->swlock);
102 // if (block){
103 // while (rlq->ready <= 0)
104 // pthread_cond_wait(&rlq->swcond, &rlq->swlock);
105 // }else {
106 // if (rlq->ready <= 0)
107 // goto nonblock;
108 // }
109 // rle = rlq->queue[rlq->fo];
110 // rlq->fo++; rlq->fo %= rlq->size;
111 // rlq->ready--;
112 // nonblock:
113 // pthread_mutex_unlock(&rlq->swlock);
114 //
115 // return rle;
116 // }
117 //
118 // static void rel_rle (RingLineQueue *rlq){
119 // pthread_mutex_lock(&rlq->wslock);
120 // rlq->free++;
121 // pthread_cond_signal(&rlq->wscond);
122 // pthread_mutex_unlock(&rlq->wslock);
123 // }
125 static RingLineEntry* pop_rle (SliceBufferQueue *sbq, RingLineQueue *rlq, int *has_token){
126 RingLineEntry *rle=NULL;
127 SliceBufferEntry *sbe=NULL;
128 int line=-1;
130 pthread_mutex_lock(&sbq->lock);
131 if (sbq->cnt <= 0)
132 goto unlock;
133 sbe = sbq->queue[sbq->fo];
134 line = sbe->lines_taken;
137 pthread_mutex_lock(&rlq->swlock);
138 if (!*has_token){
139 if (rlq->free <= 0)
140 goto unlock2;
141 rlq->free--;
142 *has_token=1;
143 }
144 rle = rlq->queue[rlq->fo];
145 rlq->fo++; rlq->fo %= rlq->size;
146 rle->sbe=sbe;
147 rle->line = line;
148 rle->mb_cnt =0;
149 if (++sbe->lines_taken >= sbe->lines_total){
150 sbq->cnt--;
151 sbq->fo++; sbq->fo %= sbq->size;
152 pthread_cond_signal(&sbq->cond);
153 }
154 unlock2:
155 pthread_mutex_unlock(&rlq->swlock);
156 unlock:
157 pthread_mutex_unlock(&sbq->lock);
160 return rle;
161 }
163 static void rel_rle (RingLineQueue *rlq, int *rec_token){
164 pthread_mutex_lock(&rlq->swlock);
165 rlq->free++;
166 *rec_token=0;
167 // pthread_cond_signal(&rlq->swcond);
168 pthread_mutex_unlock(&rlq->swlock);
170 }
172 //get either a entropy or a line reconstruct task
173 static void pop_next_task(H264Context *h, SliceBufferEntry **psbe, RingLineEntry **prle, int *rec_token){
175 pthread_mutex_lock(&h->task_lock);
177 for(;;){
178 if ( (*psbe = pop_sbe(&h->sb_q[ENTROPY], 0)) ){
179 if (*rec_token){
180 rel_rle(&h->rl_q, rec_token);
181 pthread_cond_signal(&h->task_cond);
182 }
183 break;
184 }
185 else if ( (*prle = pop_rle(&h->sb_q[MBDEC], &h->rl_q, rec_token)) )
186 break;
187 pthread_cond_wait(&h->task_cond, &h->task_lock);
188 }
190 pthread_mutex_unlock(&h->task_lock);
191 }
193 void *parse_thread(void *arg){
194 H264Context *h = (H264Context *) arg;
195 ParserContext *pc = get_parse_context(h->ifile);
196 NalContext *nc = get_nal_context(h->width, h->height);
197 H264Slice *s;
198 SliceBufferEntry *sbe = NULL;
200 while(!pc->final_frame && frames++ <h->num_frames && !h->quit){
201 sbe = get_sb_entry(h);
203 av_read_frame_internal(pc, &sbe->gb);
204 s = &sbe->slice;
206 decode_nal_units(nc, s, &sbe->gb);
208 push_sbe(&h->sb_q[ENTROPY], sbe, 0);
209 notify_one_worker(h);
210 }
212 if (!h->no_mbd){
213 sbe = get_sb_entry(h);
214 sbe->state=-1;
215 sbe->slice.coded_pic_num=nc->coded_pic_num;
216 sbe->lines_total=h->threads;
218 push_sbe(&h->sb_q[REORDER], sbe, 1);
219 }else{
220 for (int i=0; i<h->threads; i++){
221 sbe = get_sb_entry(h);
222 sbe->state=-1;
223 push_sbe(&h->sb_q[ENTROPY], sbe, 1);
224 notify_one_worker(h);
225 }
226 }
227 free_nal_context(nc);
228 free_parse_context(pc);
230 pthread_exit(NULL);
231 return NULL;
232 }
234 int decode_slice_entropy(EntropyContext *ec, SliceBufferEntry *sbe){
235 int i,j;
236 H264Slice *s = &sbe->slice;
237 GetBitContext *gb = &sbe->gb;
238 CABACContext *c = &ec->c;
239 H264Mb *mbs = sbe->mbs;
241 if( !s->pps.cabac ){
242 av_log(AV_LOG_ERROR, "Only cabac encoded streams are supported\n");
243 return -1;
244 }
246 init_dequant_tables(s, ec);
247 ec->curr_qscale = s->qscale;
248 ec->last_qscale_diff = 0;
249 ec->chroma_qp[0] = get_chroma_qp( s, 0, s->qscale);
250 ec->chroma_qp[1] = get_chroma_qp( s, 1, s->qscale);
252 /* realign */
253 align_get_bits( gb );
254 /* init cabac */
255 ff_init_cabac_decoder( c, gb->buffer + get_bits_count(gb)/8, (get_bits_left(gb) + 7)/8);
257 ff_h264_init_cabac_states(ec, s, c);
259 for(j=0; j<ec->mb_height; j++){
260 init_entropy_buf(ec, s, j);
261 for(i=0; i<ec->mb_width; i++){
262 int eos,ret;
263 H264Mb *m = &mbs[i + j*ec->mb_width];
264 //memset(m, 0, sizeof(H264Mb));
265 m->mb_x=i;
266 m->mb_y=j;
267 ec->m = m;
269 ret = ff_h264_decode_mb_cabac(ec, s, c);
270 eos = get_cabac_terminate( c); (void) eos;
272 if( ret < 0 || c->bytestream > c->bytestream_end + 2) {
273 av_log(AV_LOG_ERROR, "error while decoding MB %d %d, bytestream (%td)\n", m->mb_x, m->mb_y, c->bytestream_end - c->bytestream);
274 return -1;
275 }
276 }
277 }
279 return 0;
280 }
282 static int decode_slice_mb(MBRecContext *d, RingLineEntry *rle, int frames){
283 SliceBufferEntry *sbe= rle->sbe;
284 H264Slice *s = &sbe->slice;
285 H264Mb *mbs = sbe->mbs;
287 int mb_width= d->mb_width;
288 int i;
289 const int line = rle->line;
291 init_mbrec_context(d, d->mrs, s, line);
293 H264Mb *m = &mbs[line*mb_width];
294 d->top=rle->prev_line->top;
295 d->top_next=rle->top;
297 // assert(rle->mb_cnt ==0);
298 for(i=0; i< mb_width; i++){
299 if (frames || line>0){
300 while (rle->mb_cnt >= rle->prev_line->mb_cnt -1);
301 }
302 h264_decode_mb_internal( d, d->mrs, s, &m[i]);
303 rle->mb_cnt++;
304 }
305 draw_edges(d, s, line);
307 return 0;
308 }
310 // static int decode_slice_mb_static(MBRecContext *d, H264Slice *s, RLThreadContext *r, RLThreadContext *rp, int frames){
311 // int mb_height= d->mb_height;
312 // int mb_width= d->mb_width;
313 // int thread_num = r->thread_num;
314 // int thread_total = r->thread_total;
315 // int i;
316 // int j = thread_num;
317 //
318 // r->mb_cnt=frames* mb_height*mb_width;
319 // for(; j<mb_height; j+=thread_total){
320 // H264Mb *m = &s->mbs[j*mb_width];
321 // for(i=0; i< mb_width; i++){
322 // if (j>0){
323 // while (r->mb_cnt- (thread_num? 0:mb_width) >= rp->mb_cnt-1);
324 // }
325 // h264_decode_mb_internal(d, s, m++);
326 // r->mb_cnt++;
327 // }
328 // draw_edges(d, s, j);
329 // }
330 // return 0;
331 // }
333 static void *ed_rec_thread(void *arg){
334 H264Context *h = (H264Context*) arg;
335 EntropyContext *ec=NULL;
336 MBRecContext *mrc=NULL;
338 RingLineEntry *rle=NULL;
339 SliceBufferEntry *sbe=NULL;
340 H264Slice *s;
341 int rec_token=0;
343 if (!h->no_mbd){
344 mrc = get_mbrec_context(h);
345 }
346 ec = get_entropy_context(h);
348 for(;;){
349 pop_next_task(h, &sbe, &rle, &rec_token);
350 if (sbe){
351 if (h->no_mbd && sbe->state<0){
352 break;
353 }
354 if (!sbe->initialized){
355 init_sb_entry(h, sbe);
356 }
357 decode_slice_entropy(ec, sbe);
359 if (h->no_mbd){
360 release_sb_entry(h, sbe);
361 sbe=NULL;
362 } else {
363 push_sbe(&h->sb_q[REORDER], sbe, 1);
364 }
365 } else if (rle){
366 if (rle->sbe->state<0)
367 break;
368 s = &rle->sbe->slice;
370 decode_slice_mb(mrc, rle, s->coded_pic_num);
372 if (rle->line == h->mb_height-1){
373 push_sbe(&h->sb_q[OUTPUT], rle->sbe, 1);
374 }
375 rle->mb_cnt++;
376 }
377 }
379 //make sure threads quit in order of rle assignment
380 if (!h->no_mbd){
381 while (rle->prev_line->mb_cnt <= h->mb_width);
382 rel_rle(&h->rl_q, &rec_token);
383 notify_one_worker(h);
384 rle->mb_cnt = h->mb_width +1;
385 if (rle->line == h->threads-1){
386 push_sbe(&h->sb_q[OUTPUT], rle->sbe, 1);
387 }
389 free_mbrec_context(mrc);
390 }
392 free_entropy_context(ec);
394 pthread_exit(NULL);
395 return NULL;
396 }
398 static void *reorder_thread(void *arg){
399 H264Context *h = (H264Context *) arg;
400 int i;
401 SliceBufferEntry *reorder[h->sb_size];
402 SliceBufferEntry *sbe, *next_sbe;
403 H264Slice *s;
404 int reorder_cnt=0;
405 unsigned next_pic_num=0;
407 for(;;){
409 sbe = pop_sbe(&h->sb_q[REORDER], 1);
411 s = &sbe->slice;
412 for(i=reorder_cnt; i>0; i--){
413 if (s->coded_pic_num < reorder[i-1]->slice.coded_pic_num)
414 break;
415 reorder[i]=reorder[i-1];
416 }
417 reorder[i]=sbe;
419 while(reorder_cnt>=0){
420 if (next_pic_num!=reorder[reorder_cnt]->slice.coded_pic_num){
421 break;
422 }
423 next_sbe = reorder[reorder_cnt];
424 H264Slice *es = &next_sbe->slice;
426 if (next_sbe->state<0)
427 goto end;
429 for (int i=0; i<2; i++){
430 for(int j=0; j< es->ref_count[i]; j++){
431 if (es->ref_list_cpn[i][j] ==-1)
432 continue;
433 int k;
434 for (k=0; k<h->max_dpb_cnt; k++){
435 if(h->dpb[k].reference >= 2 && h->dpb[k].cpn == es->ref_list_cpn[i][j]){
436 es->dp_ref_list[i][j] = &h->dpb[k];
437 break;
438 }
439 }
440 }
441 }
442 next_sbe->dp = get_dpb_entry(h, es);
444 push_sbe(&h->sb_q[MBDEC], next_sbe, 0);
445 notify_all_workers(h);
447 // for (int i=0; i< h->mb_height; i++){
448 // push_rle(&h->rl_q, next_sbe, i, 0);
449 // notify_one_worker(h);
450 // }
453 next_pic_num++;
454 reorder_cnt--;
455 }
456 reorder_cnt++;
457 }
459 end:
460 {
461 push_sbe(&h->sb_q[MBDEC], next_sbe, 0);
462 notify_all_workers(h);
463 if (h->no_mbd){
464 push_sbe(&h->sb_q[OUTPUT], next_sbe, 1);
465 }
466 // for (int i=0; i< h->threads; i++){
467 // push_rle(&h->rl_q, next_sbe, i, 0);
468 // notify_one_worker(h);
469 // }
470 }
472 pthread_exit(NULL);
473 return NULL;
474 }
476 void create_ed_rec_threads(H264Context *h){
477 cpu_set_t cpuset;
478 int* aff;
480 if (h->setaff){
481 aff = h->smt ? ed_rec_smt_aff : ed_rec_affinity ;
482 for (int i=0; i<h->threads; i++){
483 pthread_attr_init(&h->ed_rec_attr[i]);
484 CPU_ZERO(&cpuset);
485 CPU_SET(aff[i], &cpuset);
486 pthread_attr_setaffinity_np(&h->ed_rec_attr[i], sizeof(cpu_set_t), &cpuset);
487 pthread_create(&h->ed_rec_thr[i], &h->ed_rec_attr[i], ed_rec_thread, h);
488 }
489 } else {
490 for (int i=0; i<h->threads; i++){
491 pthread_create(&h->ed_rec_thr[i], NULL, ed_rec_thread, h);
492 }
493 }
494 }
496 void join_ed_rec_threads(H264Context *h){
497 for (int i=0; i< h->threads; i++){
498 pthread_join(h->ed_rec_thr[i], NULL);
499 }
500 }
502 void *output_thread(void *arg){
503 H264Context *h = (H264Context *) arg;
505 OutputContext *oc = get_output_context( h );
507 SliceBufferEntry *sbe = NULL;
508 H264Slice *s=NULL;
509 for(;;) {
510 DecodedPicture *out, *dp;
511 sbe = pop_sbe(&h->sb_q[OUTPUT], 1);
513 if (sbe->state <0)
514 break;
516 s = &sbe->slice;
517 for (int i=0; i<s->release_cnt; i++){
518 for(int j=0; j<h->max_dpb_cnt; j++){
519 if(h->dpb[j].cpn== s->release_ref_cpn[i]){
520 release_dpb_entry(h, &h->dpb[j], 2);
521 break;
522 }
523 }
524 }
526 dp=sbe->dp;
527 release_sb_entry(h, sbe);
529 out =output_frame(h, oc, dp, h->ofile, h->frame_width, h->frame_height);
530 if (out){
531 release_dpb_entry(h, out, 1);
532 }
534 print_report(oc->frame_number, oc->video_size, 0, h->verbose);
536 }
537 /* at the end of stream, we must flush the decoder buffers */
538 while (output_frame(h, oc, NULL, h->ofile, h->frame_width, h->frame_height));
539 print_report(oc->frame_number, oc->video_size, 1, h->verbose);
541 free_output_context(oc);
543 pthread_exit(NULL);
544 return NULL;
545 }
547 /*
548 * The following code is the main loop of the file converter
549 */
550 int h264_decode_pthread(H264Context *h) {
551 pthread_t parse_thr, reorder_thr, output_thr;
553 av_start_timer();
555 pthread_create(&parse_thr, NULL, parse_thread, h);
556 if (!h->no_mbd){
557 pthread_create(&reorder_thr, NULL, reorder_thread, h);
558 pthread_create(&output_thr, NULL, output_thread, h);
559 }
560 #if HAVE_LIBSDL2
561 pthread_t sdl_thr;
562 if (h->display){
563 pthread_create(&sdl_thr, NULL, sdl_thread, h);
564 }
565 #endif
566 create_ed_rec_threads(h);
569 if (h->rl_side_touch){
570 pthread_mutex_lock(&h->ilock);
571 while (h->init_threads< h->threads)
572 pthread_cond_wait(&h->icond, &h->ilock);
573 pthread_mutex_unlock(&h->ilock);
575 pthread_mutex_lock(&h->tlock);
576 h->touch_start =1;
577 pthread_cond_broadcast(&h->tcond);
578 pthread_mutex_unlock(&h->tlock);
580 pthread_mutex_lock(&h->tdlock);
581 while (h->touch_done < h->threads)
582 pthread_cond_wait(&h->tdcond, &h->tdlock);
583 pthread_mutex_unlock(&h->tdlock);
585 pthread_mutex_lock(&h->slock);
586 h->start =1;
587 pthread_cond_broadcast(&h->scond);
588 pthread_mutex_unlock(&h->slock);
589 }
590 join_ed_rec_threads(h);
591 pthread_join(parse_thr, NULL);
592 if (!h->no_mbd){
593 pthread_join(reorder_thr, NULL);
594 pthread_join(output_thr, NULL);
595 }
596 #if HAVE_LIBSDL2
597 if (h->display)
598 signal_sdl_exit(h);
599 pthread_join(sdl_thr, NULL);
600 #endif
603 return 0;
604 }