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.
Unified · Split
| @@ -2632,80 +2632,100 @@ static void encode_mb(MPVEncContext *const s, int motion_x, int motion_y) · 2631 unmodified lines | |||
| 2632 | encode_mb_internal(s, motion_x, motion_y, 16, 16, 12, 0, 0, CHROMA_444); | 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, | 2635 | typedef struct MBBackup { |
| 2636 | const MPVEncContext *const s) | 2636 | struct { |
| 2637 | { | 2637 | int mv[2][4][2]; |
| 2638 | int i; | 2638 | int last_mv[2][2][2]; |
| 2639 | 2639 | int mv_type, mv_dir; | |
| 2640 | memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster than a loop? | 2640 | int last_dc[3]; |
| 2641 | 2641 | int mb_intra, mb_skipped, mb_skip_run; | |
| 2642 | /* MPEG-1 */ | 2642 | int qscale; |
| 2643 | d->c.mb_skip_run = s->c.mb_skip_run; | 2643 | int block_last_index[8]; |
| 2644 | for(i=0; i<3; i++) | 2644 | int interlaced_dct; |
| 2645 | d->c.last_dc[i] = s->c.last_dc[i]; | 2645 | int16_t (*block)[64]; |
| 2646 | 2646 | } c; | |
| 2647 | /* statistics */ | 2647 | int mv_bits, i_tex_bits, p_tex_bits, i_count, misc_bits, last_bits; |
| 2648 | d->mv_bits= s->mv_bits; | 2648 | int dquant; |
| 2649 | d->i_tex_bits= s->i_tex_bits; | 2649 | int esc3_level_length; |
| 2650 | d->p_tex_bits= s->p_tex_bits; | 2650 | PutBitContext pb, pb2, tex_pb; |
| 2651 | d->i_count= s->i_count; | 2651 | } MBBackup; |
| 2652 | d->misc_bits= s->misc_bits; | 2652 | |
| 2653 | d->last_bits= 0; | 2653 | #define COPY_CONTEXT(BEFORE, AFTER, DST_TYPE, SRC_TYPE) \ |
| 2654 | 2654 | static inline void BEFORE ##_context_before_encode(DST_TYPE *const d, \ | |
| 2655 | d->c.mb_skipped = 0; | 2655 | const SRC_TYPE *const s) \ |
| 2656 | d->c.qscale = s->c.qscale; | 2656 | { \ |
| 2657 | d->dquant= s->dquant; | 2657 | /* FIXME is memcpy faster than a loop? */ \ |
| 2658 | 2658 | memcpy(d->c.last_mv, s->c.last_mv, 2*2*2*sizeof(int)); \ | |
| 2659 | d->esc3_level_length= s->esc3_level_length; | 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, | 2718 | COPY_CONTEXT(backup, save, MBBackup, MPVEncContext) |
| 2663 | const MPVEncContext *const s, | 2719 | COPY_CONTEXT(reset, store, MPVEncContext, MBBackup) |
| 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 | } | ||
| 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 | PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], | 2722 | PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], |
| 2703 | int *dmin, int *next_block, int motion_x, int motion_y) | 2723 | int *dmin, int *next_block, int motion_x, int motion_y) |
| 2704 | { | 2724 | { |
| 2705 | int score; | 2725 | int score; |
| 2706 | uint8_t *dest_backup[3]; | 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 | s->c.block = s->c.blocks[*next_block]; | 2730 | s->c.block = s->c.blocks[*next_block]; |
| 2711 | s->pb = pb[*next_block]; | 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 | *dmin= score; | 2765 | *dmin= score; |
| 2746 | *next_block^=1; | 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 | MPVEncContext *const s = *(void**)arg; | 2983 | MPVEncContext *const s = *(void**)arg; |
| 2964 | int chr_h = 16 >> s->c.chroma_y_shift; | 2984 | int chr_h = 16 >> s->c.chroma_y_shift; |
| 2965 | int i; | 2985 | int i; |
| 2966 | MPVEncContext best_s = { 0 }, backup_s; | 2986 | MBBackup best_s = { 0 }, backup_s; |
| 2967 | uint8_t bit_buf[2][MAX_MB_BYTES]; | 2987 | uint8_t bit_buf[2][MAX_MB_BYTES]; |
| 2968 | uint8_t bit_buf2[2][MAX_MB_BYTES]; | 2988 | uint8_t bit_buf2[2][MAX_MB_BYTES]; |
| 2969 | uint8_t bit_buf_tex[2][MAX_MB_BYTES]; | 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 | int next_block=0; | 3184 | int next_block=0; |
| 3165 | int pb_bits_count, pb2_bits_count, tex_pb_bits_count; | 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 | backup_s.pb= s->pb; | 3188 | backup_s.pb= s->pb; |
| 3169 | if (s->c.data_partitioning) { | 3189 | if (s->c.data_partitioning) { |
| 3170 | backup_s.pb2= s->pb2; | 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 | pb_bits_count= put_bits_count(&s->pb); | 3414 | pb_bits_count= put_bits_count(&s->pb); |
| 3395 | flush_put_bits(&s->pb); | 3415 | flush_put_bits(&s->pb); |