encode_thread() puts two MPVEncContexts (2*6516B here) on the stack and zeroes one of them in order to temporarily store the variables that get changed during encoding a macroblock (when there is more than one candidate type for a macroblock). This is wasteful and therefore this commit adds a small (328B here) structure to store exactly the fields that actually need to be backed up. Then one can extend MPVEncContext without fearing too use up to much stack.
Showing the changes to libavcodec (1 of 1 file). Show all
Unified · Split
| @@ -2632,80 +2632,100 @@ static void encode_mb(MPVEncContext *const s, int motion_x, int motion_y) · 2631 unmodified lines | ||
| 2632 | 2632 | encode_mb_internal(s, motion_x, motion_y, 16, 16, 12, 0, 0, CHROMA_444); |
| 2633 | 2633 | } |
| 2634 | 2634 | |
| 2635 | −static inline void copy_context_before_encode(MPVEncContext *const d, | |
| 2636 | − const MPVEncContext *const s) | |
| 2637 | −{ | |
| 2638 | − int i; | |
| 2639 | − | |
| 2640 | − memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? | |
| 2641 | − | |
| 2642 | − /* MPEG-1 */ | |
| 2643 | − d->c.mb_skip_run = s->c.mb_skip_run; | |
| 2644 | − for(i=0; i<3; i++) | |
| 2645 | − d->c.last_dc[i] = s->c.last_dc[i]; | |
| 2646 | − | |
| 2647 | − /* statistics */ | |
| 2648 | − d->mv_bits= s->mv_bits; | |
| 2649 | − d->i_tex_bits= s->i_tex_bits; | |
| 2650 | − d->p_tex_bits= s->p_tex_bits; | |
| 2651 | − d->i_count= s->i_count; | |
| 2652 | − d->misc_bits= s->misc_bits; | |
| 2653 | − d->last_bits= 0; | |
| 2654 | − | |
| 2655 | − d->c.mb_skipped = 0; | |
| 2656 | − d->c.qscale = s->c.qscale; | |
| 2657 | − d->dquant= s->dquant; | |
| 2658 | − | |
| 2659 | − d->esc3_level_length= s->esc3_level_length; | |
| 2635 | +typedef struct MBBackup { | |
| 2636 | + struct { | |
| 2637 | + int mv[2][4][2]; | |
| 2638 | + int last_mv[2][2][2]; | |
| 2639 | + int mv_type, mv_dir; | |
| 2640 | + int last_dc[3]; | |
| 2641 | + int mb_intra, mb_skipped, mb_skip_run; | |
| 2642 | + int qscale; | |
| 2643 | + int block_last_index[8]; | |
| 2644 | + int interlaced_dct; | |
| 2645 | + int16_t (*block)[64]; | |
| 2646 | + } c; | |
| 2647 | + int mv_bits, i_tex_bits, p_tex_bits, i_count, misc_bits, last_bits; | |
| 2648 | + int dquant; | |
| 2649 | + int esc3_level_length; | |
| 2650 | + PutBitContext pb, pb2, tex_pb; | |
| 2651 | +} MBBackup; | |
| 2652 | + | |
| 2653 | +#define COPY_CONTEXT(BEFORE, AFTER, DST_TYPE, SRC_TYPE) \ | |
| 2654 | +static inline void BEFORE ##_context_before_encode(DST_TYPE *const d, \ | |
| 2655 | + const SRC_TYPE *const s) \ | |
| 2656 | +{ \ | |
| 2657 | + /* FIXME is memcpy faster than a loop? */ \ | |
| 2658 | + memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ | |
| 2659 | + \ | |
| 2660 | + /* MPEG-1 */ \ | |
| 2661 | + d->c.mb_skip_run = s->c.mb_skip_run; \ | |
| 2662 | + for (int i = 0; i < 3; i++) \ | |
| 2663 | + d->c.last_dc[i] = s->c.last_dc[i]; \ | |
| 2664 | + \ | |
| 2665 | + /* statistics */ \ | |
| 2666 | + d->mv_bits = s->mv_bits; \ | |
| 2667 | + d->i_tex_bits = s->i_tex_bits; \ | |
| 2668 | + d->p_tex_bits = s->p_tex_bits; \ | |
| 2669 | + d->i_count = s->i_count; \ | |
| 2670 | + d->misc_bits = s->misc_bits; \ | |
| 2671 | + d->last_bits = 0; \ | |
| 2672 | + \ | |
| 2673 | + d->c.mb_skipped = 0; \ | |
| 2674 | + d->c.qscale = s->c.qscale; \ | |
| 2675 | + d->dquant = s->dquant; \ | |
| 2676 | + \ | |
| 2677 | + d->esc3_level_length = s->esc3_level_length; \ | |
| 2678 | +} \ | |
| 2679 | + \ | |
| 2680 | +static inline void AFTER ## _context_after_encode(DST_TYPE *const d, \ | |
| 2681 | + const SRC_TYPE *const s, \ | |
| 2682 | + int data_partitioning) \ | |
| 2683 | +{ \ | |
| 2684 | + /* FIXME is memcpy faster than a loop? */ \ | |
| 2685 | + memcpy(d->c.mv, s->c.mv, 2*4*2*sizeof(int)); \ | |
| 2686 | + memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ | |
| 2687 | + \ | |
| 2688 | + /* MPEG-1 */ \ | |
| 2689 | + d->c.mb_skip_run = s->c.mb_skip_run; \ | |
| 2690 | + for (int i = 0; i < 3; i++) \ | |
| 2691 | + d->c.last_dc[i] = s->c.last_dc[i]; \ | |
| 2692 | + \ | |
| 2693 | + /* statistics */ \ | |
| 2694 | + d->mv_bits = s->mv_bits; \ | |
| 2695 | + d->i_tex_bits = s->i_tex_bits; \ | |
| 2696 | + d->p_tex_bits = s->p_tex_bits; \ | |
| 2697 | + d->i_count = s->i_count; \ | |
| 2698 | + d->misc_bits = s->misc_bits; \ | |
| 2699 | + \ | |
| 2700 | + d->c.mb_intra = s->c.mb_intra; \ | |
| 2701 | + d->c.mb_skipped = s->c.mb_skipped; \ | |
| 2702 | + d->c.mv_type = s->c.mv_type; \ | |
| 2703 | + d->c.mv_dir = s->c.mv_dir; \ | |
| 2704 | + d->pb = s->pb; \ | |
| 2705 | + if (data_partitioning) { \ | |
| 2706 | + d->pb2 = s->pb2; \ | |
| 2707 | + d->tex_pb = s->tex_pb; \ | |
| 2708 | + } \ | |
| 2709 | + d->c.block = s->c.block; \ | |
| 2710 | + for (int i = 0; i < 8; i++) \ | |
| 2711 | + d->c.block_last_index[i] = s->c.block_last_index[i]; \ | |
| 2712 | + d->c.interlaced_dct = s->c.interlaced_dct; \ | |
| 2713 | + d->c.qscale = s->c.qscale; \ | |
| 2714 | + \ | |
| 2715 | + d->esc3_level_length = s->esc3_level_length; \ | |
| 2660 | 2716 | } |
| 2661 | 2717 | |
| 2662 | −static inline void copy_context_after_encode(MPVEncContext *const d, | |
| 2663 | − const MPVEncContext *const s, | |
| 2664 | − int data_partitioning) | |
| 2665 | −{ | |
| 2666 | − int i; | |
| 2667 | − | |
| 2668 | − memcpy(d->c.mv, s->c.mv, 2*4*2*sizeof(int)); | |
| 2669 | − memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? | |
| 2670 | − | |
| 2671 | − /* MPEG-1 */ | |
| 2672 | − d->c.mb_skip_run = s->c.mb_skip_run; | |
| 2673 | − for(i=0; i<3; i++) | |
| 2674 | − d->c.last_dc[i] = s->c.last_dc[i]; | |
| 2675 | − | |
| 2676 | − /* statistics */ | |
| 2677 | − d->mv_bits= s->mv_bits; | |
| 2678 | − d->i_tex_bits= s->i_tex_bits; | |
| 2679 | − d->p_tex_bits= s->p_tex_bits; | |
| 2680 | − d->i_count= s->i_count; | |
| 2681 | − d->misc_bits= s->misc_bits; | |
| 2682 | − | |
| 2683 | − d->c.mb_intra = s->c.mb_intra; | |
| 2684 | − d->c.mb_skipped = s->c.mb_skipped; | |
| 2685 | − d->c.mv_type = s->c.mv_type; | |
| 2686 | − d->c.mv_dir = s->c.mv_dir; | |
| 2687 | − d->pb= s->pb; | |
| 2688 | − if (data_partitioning) { | |
| 2689 | − d->pb2= s->pb2; | |
| 2690 | − d->tex_pb= s->tex_pb; | |
| 2691 | − } | |
| 2692 | − d->c.block = s->c.block; | |
| 2693 | − for(i=0; i<8; i++) | |
| 2694 | − d->c.block_last_index[i] = s->c.block_last_index[i]; | |
| 2695 | − d->c.interlaced_dct = s->c.interlaced_dct; | |
| 2696 | − d->c.qscale = s->c.qscale; | |
| 2697 | − | |
| 2698 | − d->esc3_level_length= s->esc3_level_length; | |
| 2699 | −} | |
| 2718 | +COPY_CONTEXT(backup, save, MBBackup, MPVEncContext) | |
| 2719 | +COPY_CONTEXT(reset, store, MPVEncContext, MBBackup) | |
| 2700 | 2720 | |
| 2701 | −static void encode_mb_hq(MPVEncContext *const s, MPVEncContext *const backup, MPVEncContext *const best, | |
| 2721 | +static void encode_mb_hq(MPVEncContext *const s, MBBackup *const backup, MBBackup *const best, | |
| 2702 | 2722 | PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], |
| 2703 | 2723 | int *dmin, int *next_block, int motion_x, int motion_y) |
| 2704 | 2724 | { |
| 2705 | 2725 | int score; |
| 2706 | 2726 | uint8_t *dest_backup[3]; |
| 2707 | 2727 | |
| 2708 | − copy_context_before_encode(s, backup); | |
| 2728 | + reset_context_before_encode(s, backup); | |
| 2709 | 2729 | |
| 2710 | 2730 | s->c.block = s->c.blocks[*next_block]; |
| 2711 | 2731 | s->pb = pb[*next_block]; |
| @@ -2745,7 +2765,7 @@ static void encode_mb_hq(MPVEncContext *const s, MPVEncContext *const backup, MP · 33 unmodified lines | ||
| 2745 | 2765 | *dmin= score; |
| 2746 | 2766 | *next_block^=1; |
| 2747 | 2767 | |
| 2748 | − copy_context_after_encode(best, s, s->c.data_partitioning); | |
| 2768 | + save_context_after_encode(best, s, s->c.data_partitioning); | |
| 2749 | 2769 | } |
| 2750 | 2770 | } |
| 2751 | 2771 | |
| @@ -2963,7 +2983,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ · 211 unmodified lines | ||
| 2963 | 2983 | MPVEncContext *const s = *(void**)arg; |
| 2964 | 2984 | int chr_h = 16 >> s->c.chroma_y_shift; |
| 2965 | 2985 | int i; |
| 2966 | − MPVEncContext best_s = { 0 }, backup_s; | |
| 2986 | + MBBackup best_s = { 0 }, backup_s; | |
| 2967 | 2987 | uint8_t bit_buf[2][MAX_MB_BYTES]; |
| 2968 | 2988 | uint8_t bit_buf2[2][MAX_MB_BYTES]; |
| 2969 | 2989 | uint8_t bit_buf_tex[2][MAX_MB_BYTES]; |
| @@ -3164,7 +3184,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ · 194 unmodified lines | ||
| 3164 | 3184 | int next_block=0; |
| 3165 | 3185 | int pb_bits_count, pb2_bits_count, tex_pb_bits_count; |
| 3166 | 3186 | |
| 3167 | − copy_context_before_encode(&backup_s, s); | |
| 3187 | + backup_context_before_encode(&backup_s, s); | |
| 3168 | 3188 | backup_s.pb= s->pb; |
| 3169 | 3189 | if (s->c.data_partitioning) { |
| 3170 | 3190 | backup_s.pb2= s->pb2; |
| @@ -3389,7 +3409,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ · 218 unmodified lines | ||
| 3389 | 3409 | } |
| 3390 | 3410 | } |
| 3391 | 3411 | |
| 3392 | − copy_context_after_encode(s, &best_s, s->c.data_partitioning); | |
| 3412 | + store_context_after_encode(s, &best_s, s->c.data_partitioning); | |
| 3393 | 3413 | |
| 3394 | 3414 | pb_bits_count= put_bits_count(&s->pb); |
| 3395 | 3415 | flush_put_bits(&s->pb); |