It is more efficient and easier to manage.
Unified · Split
| @@ -2598,7 +2598,7 @@ static int hls_slice_data(HEVCContext *s) · 2597 unmodified lines | ||
| 2598 | 2598 | static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *hevc_lclist, |
| 2599 | 2599 | int job, int self_id) |
| 2600 | 2600 | { |
| 2601 | − HEVCLocalContext *lc = ((HEVCLocalContext**)hevc_lclist)[self_id]; | |
| 2601 | + HEVCLocalContext *lc = &((HEVCLocalContext*)hevc_lclist)[self_id]; | |
| 2602 | 2602 | const HEVCContext *const s = lc->parent; |
| 2603 | 2603 | int ctb_size = 1 << s->ps.sps->log2_ctb_size; |
| 2604 | 2604 | int more_data = 1; |
| @@ -2682,7 +2682,7 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) · 77 unmodified lines | ||
| 2682 | 2682 | { |
| 2683 | 2683 | const uint8_t *data = nal->data; |
| 2684 | 2684 | int length = nal->size; |
| 2685 | − HEVCLocalContext *lc = s->HEVClc; | |
| 2685 | + HEVCLocalContext *lc; | |
| 2686 | 2686 | int *ret; |
| 2687 | 2687 | int64_t offset; |
| 2688 | 2688 | int64_t startheader, cmpt = 0; |
| @@ -2696,19 +2696,31 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) · 7 unmodified lines | ||
| 2696 | 2696 | return AVERROR_INVALIDDATA; |
| 2697 | 2697 | } |
| 2698 | 2698 | |
| 2699 | − for (i = 1; i < s->threads_number; i++) { | |
| 2700 | − if (i < s->nb_local_ctx) | |
| 2701 | − continue; | |
| 2702 | − s->local_ctx[i] = av_mallocz(sizeof(HEVCLocalContext)); | |
| 2703 | − if (!s->local_ctx[i]) | |
| 2699 | + if (s->threads_number > s->nb_local_ctx) { | |
| 2700 | + HEVCLocalContext *tmp = av_malloc_array(s->threads_number, sizeof(*s->local_ctx)); | |
| 2701 | + | |
| 2702 | + if (!tmp) | |
| 2704 | 2703 | return AVERROR(ENOMEM); |
| 2705 | − s->nb_local_ctx++; | |
| 2706 | 2704 | |
| 2707 | − s->local_ctx[i]->logctx = s->avctx; | |
| 2708 | − s->local_ctx[i]->parent = s; | |
| 2709 | − s->local_ctx[i]->common_cabac_state = &s->cabac; | |
| 2705 | + memcpy(tmp, s->local_ctx, sizeof(*s->local_ctx) * s->nb_local_ctx); | |
| 2706 | + av_free(s->local_ctx); | |
| 2707 | + s->local_ctx = tmp; | |
| 2708 | + s->HEVClc = &s->local_ctx[0]; | |
| 2709 | + | |
| 2710 | + for (unsigned i = s->nb_local_ctx; i < s->threads_number; i++) { | |
| 2711 | + tmp = &s->local_ctx[i]; | |
| 2712 | + | |
| 2713 | + memset(tmp, 0, sizeof(*tmp)); | |
| 2714 | + | |
| 2715 | + tmp->logctx = s->avctx; | |
| 2716 | + tmp->parent = s; | |
| 2717 | + tmp->common_cabac_state = &s->cabac; | |
| 2718 | + } | |
| 2719 | + | |
| 2720 | + s->nb_local_ctx = s->threads_number; | |
| 2710 | 2721 | } |
| 2711 | 2722 | |
| 2723 | + lc = &s->local_ctx[0]; | |
| 2712 | 2724 | offset = (lc->gb.index >> 3); |
| 2713 | 2725 | |
| 2714 | 2726 | for (j = 0, cmpt = 0, startheader = offset + s->sh.entry_point_offset[0]; j < nal->skipped_bytes; j++) { |
| @@ -2744,8 +2756,8 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) · 29 unmodified lines | ||
| 2744 | 2756 | s->data = data; |
| 2745 | 2757 | |
| 2746 | 2758 | for (i = 1; i < s->threads_number; i++) { |
| 2747 | − s->local_ctx[i]->first_qp_group = 1; | |
| 2748 | − s->local_ctx[i]->qp_y = s->HEVClc->qp_y; | |
| 2759 | + s->local_ctx[i].first_qp_group = 1; | |
| 2760 | + s->local_ctx[i].qp_y = s->HEVClc->qp_y; | |
| 2749 | 2761 | } |
| 2750 | 2762 | |
| 2751 | 2763 | atomic_store(&s->wpp_err, 0); |
| @@ -3474,12 +3486,6 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) · 722 unmodified lines | ||
| 3474 | 3486 | av_freep(&s->sh.offset); |
| 3475 | 3487 | av_freep(&s->sh.size); |
| 3476 | 3488 | |
| 3477 | − if (s->local_ctx) { | |
| 3478 | − for (i = 1; i < s->nb_local_ctx; i++) { | |
| 3479 | − av_freep(&s->local_ctx[i]); | |
| 3480 | − } | |
| 3481 | − } | |
| 3482 | − av_freep(&s->HEVClc); | |
| 3483 | 3489 | av_freep(&s->local_ctx); |
| 3484 | 3490 | |
| 3485 | 3491 | ff_h2645_packet_uninit(&s->pkt); |
| @@ -3496,15 +3502,16 @@ static av_cold int hevc_init_context(AVCodecContext *avctx) · 10 unmodified lines | ||
| 3496 | 3502 | |
| 3497 | 3503 | s->avctx = avctx; |
| 3498 | 3504 | |
| 3499 | − s->HEVClc = av_mallocz(sizeof(HEVCLocalContext)); | |
| 3500 | − s->local_ctx = av_mallocz(sizeof(HEVCLocalContext*) * s->threads_number); | |
| 3501 | − if (!s->HEVClc || !s->local_ctx) | |
| 3505 | + s->local_ctx = av_mallocz(sizeof(*s->local_ctx)); | |
| 3506 | + if (!s->local_ctx) | |
| 3502 | 3507 | return AVERROR(ENOMEM); |
| 3508 | + s->nb_local_ctx = 1; | |
| 3509 | + | |
| 3510 | + s->HEVClc = &s->local_ctx[0]; | |
| 3511 | + | |
| 3503 | 3512 | s->HEVClc->parent = s; |
| 3504 | 3513 | s->HEVClc->logctx = avctx; |
| 3505 | 3514 | s->HEVClc->common_cabac_state = &s->cabac; |
| 3506 | − s->local_ctx[0] = s->HEVClc; | |
| 3507 | − s->nb_local_ctx = 1; | |
| 3508 | 3515 | |
| 3509 | 3516 | s->output_frame = av_frame_alloc(); |
| 3510 | 3517 | if (!s->output_frame) |
| @@ -439,13 +439,17 @@ typedef struct HEVCLocalContext { · 438 unmodified lines | ||
| 439 | 439 | /* properties of the boundary of the current CTB for the purposes |
| 440 | 440 | * of the deblocking filter */ |
| 441 | 441 | int boundary_flags; |
| 442 | + | |
| 443 | + // an array of these structs is used for per-thread state - pad its size | |
| 444 | + // to avoid false sharing | |
| 445 | + char padding[128]; | |
| 442 | 446 | } HEVCLocalContext; |
| 443 | 447 | |
| 444 | 448 | typedef struct HEVCContext { |
| 445 | 449 | const AVClass *c; // needed by private avoptions |
| 446 | 450 | AVCodecContext *avctx; |
| 447 | 451 | |
| 448 | − HEVCLocalContext **local_ctx; | |
| 452 | + HEVCLocalContext *local_ctx; | |
| 449 | 453 | unsigned nb_local_ctx; |
| 450 | 454 | |
| 451 | 455 | HEVCLocalContext *HEVClc; |