From c42d40b8f609c35c687efc180a7143cf30601cf0 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 21 Nov 2013 09:55:57 -0500 Subject: [PATCH] Remove an extra frame copy that wasn't needed. Only update the stored frame if the previous frame had been displayed. Don't render the same frame again if there's no new frame to update. --- jni/nv_avc_dec/nv_avc_dec.c | 59 ++++++++++-------------------- libs/armeabi-v7a/libnv_avc_dec.so | Bin 17700 -> 17700 bytes libs/x86/libnv_avc_dec.so | Bin 9580 -> 9576 bytes 3 files changed, 20 insertions(+), 39 deletions(-) diff --git a/jni/nv_avc_dec/nv_avc_dec.c b/jni/nv_avc_dec/nv_avc_dec.c index 8758318e..525f3567 100644 --- a/jni/nv_avc_dec/nv_avc_dec.c +++ b/jni/nv_avc_dec/nv_avc_dec.c @@ -12,12 +12,10 @@ AVCodec* decoder; AVCodecContext* decoder_ctx; AVFrame* yuv_frame; AVFrame* rgb_frame; -AVFrame* rnd_frame; AVFrame* dec_frame; pthread_mutex_t mutex; char* rgb_frame_buf; struct SwsContext* scaler_ctx; -int picture_new; #define RENDER_PIX_FMT AV_PIX_FMT_RGBA #define BYTES_PER_PIXEL 4 @@ -161,43 +159,31 @@ void nv_avc_destroy(void) { av_free(rgb_frame_buf); rgb_frame_buf = NULL; } - if (rnd_frame) { - av_frame_free(&rnd_frame); - rnd_frame = NULL; - } pthread_mutex_destroy(&mutex); } void nv_avc_redraw(JNIEnv *env, jobject surface) { ANativeWindow* window; ANativeWindow_Buffer buffer; + AVFrame *our_yuv_frame; int err; - // Free the old decoded frame - if (rnd_frame) { - av_frame_free(&rnd_frame); - } - pthread_mutex_lock(&mutex); // Check if there's a new frame - if (picture_new) { - // Clone the decoder's last frame - rnd_frame = av_frame_clone(yuv_frame); + if (yuv_frame) { + // We now own the decoder's frame and are + // responsible for freeing it when we're done + our_yuv_frame = yuv_frame; + yuv_frame = NULL; // The remaining processing can be done without the mutex pthread_mutex_unlock(&mutex); - if (rnd_frame == NULL) { - __android_log_write(ANDROID_LOG_ERROR, "NVAVCDEC", - "Cloning failed"); - return; - } - // Convert the YUV image to RGB err = sws_scale(scaler_ctx, - rnd_frame->data, - rnd_frame->linesize, + our_yuv_frame->data, + our_yuv_frame->linesize, 0, decoder_ctx->height, rgb_frame->data, @@ -205,14 +191,14 @@ void nv_avc_redraw(JNIEnv *env, jobject surface) { if (err != decoder_ctx->height) { __android_log_write(ANDROID_LOG_ERROR, "NVAVCDEC", "Scaling failed"); - return; + goto free_frame_and_return; } window = ANativeWindow_fromSurface(env, surface); if (window == NULL) { __android_log_write(ANDROID_LOG_ERROR, "NVAVCDEC", "Failed to get window from surface"); - return; + goto free_frame_and_return; } // Lock down a render buffer @@ -236,10 +222,12 @@ void nv_avc_redraw(JNIEnv *env, jobject surface) { } ANativeWindow_release(window); + + free_frame_and_return: + av_frame_free(&our_yuv_frame); } else { pthread_mutex_unlock(&mutex); - rnd_frame = NULL; } } @@ -272,24 +260,17 @@ int nv_avc_decode(unsigned char* indata, int inlen) { } if (got_pic) { - // Update the frame if it's not being read - if (pthread_mutex_trylock(&mutex) == 0) { - // Free the old frame - if (yuv_frame) { - av_frame_free(&yuv_frame); - } + pthread_mutex_lock(&mutex); + // Only clone this frame if the last frame was taken. + // This saves on extra copies for frames that don't get + // rendered. + if (yuv_frame == NULL) { // Clone a new frame yuv_frame = av_frame_clone(dec_frame); - if (yuv_frame) { - picture_new = 1; - } - else { - picture_new = 0; - } - - pthread_mutex_unlock(&mutex); } + + pthread_mutex_unlock(&mutex); } pkt.size -= err; diff --git a/libs/armeabi-v7a/libnv_avc_dec.so b/libs/armeabi-v7a/libnv_avc_dec.so index 2d1c289d1afab7eaef53641c405239895c88efa5..ad485f7c990cde52cc2cf7229c9447db6b13c568 100644 GIT binary patch delta 4429 zcmZ3|#ki!4aYBmidLsq~5N2gyU|h=&>vvXFsc z4Vr>OObiT+(hLkYzz*PIxPT^q4~_p6jsKfz@-=3;dP!ymhMUq13|vrS{FoUS9!o<) z5ELS9%nS_Ar6F+z;_qcA7|zDPz@rI?;(Cxk1{(u|fF?pg0~-T_fhGgP0jL4f*-(RcH5&uN z6D|zd_#5yh5(2HFy8}>AIr|b zP=X|1h{kVbXJBa2XJBxEI&d001H%!01_m7{e=R!$!v}p(BKC&F=~;FL1`Pv55Ittc@! zH9k2fKQDFjOs-~D&Ljqqy$lS2lLZ-tBPAIa7$O-M7(mgj$iTp0$H2hg!@$503b6}J zMu15M1}i8HqCjPXFNgufwhRmm5)6=3oyfqzAUAoUfV?ayg3K5g7=#%Z7(m${lvkA* z7#MgN7#P$iD+&r*Izsh>s3-;ohG-B2ibWY17=joW7{Z`@8z`;Ez`$TSd7+?qt{Vdb zgDV3ALkI%{g9ihokN_$2VqjnhXJBA3VPIe|Vqjo!0tqreQfM#(1A{yR1A{aJ14A4G z149f01A`O;1A`h=O#+k#QQ`~?42BF0415d>44RWS8v9RvBWN?(KuBhCfRMsu1xA+1 zbA)(gH5ecf2hstGVObCZiWMf$6_OS-hVnq^!IFW2!5$p;{0xv{4=TxE&cMK6z`(%Z z&%nR{ifbOIgg2B1QK}3K47v;q4Ei7r0|SFI0|SE}0|P@W0|SFL0|SFK0|SHmWK&^B zP{e}kD+UHosDmm&5Y5cMGF4$9T2U-!0-S>YceoA0nu9Z3=A(o3~dI6Hy~Pvf#Cy)He_J<0-~)L7=D0g zTLy+dAlihe4NXUAel8))_-Hb#q_XI>cMKZrZtS;IJ=MUf*cASM z-!j=&Qkn6<kTp-WJ&~>&*l9fV($wJ2gVPUyBYS2nL#`R zaumoD5B~rE5Awi`|Ns9V`CtG4zwXNqj_ht0J`*-rcz3wfxIBw6aQpw=>z%3h;|Qq? z2Ce7|45|ihvI#7c{(pCSXXtI{b^phS2hSoFM1=g{b1=?enR(?0!vn^T3QYHY)I4CE ztYFMES=;UG4~7Q}8UMcQ1CX=dycO86_r-@shW&Y_kcfr(7vz6X#F~gRFuV|FV2~4MV0b9b!05K2Y*f z@?ILjxax6)W`;xt)9U}(*}8MIH`VOqiV>RH+U z@B7{wxQRi18Dzr1kRisvkSGpGq97j{i7_y^iX(h4;3nzDFzf&Ki+lfn-?&fE?f>_G zlkdyOGgeLhFO$f)esiL1J0la1@#a@@LX3=mCjXTWXM8p}RH2&j+UAQ2{7j6YlOHN2 zGulsfRbI{{`gij?C7&5=;!~}91glK5B&W9y2AZ{8^eM5 zPx(LeJaBk6*~-vPlHvLP`VDK@8uq;SU%!%LV?)Tx|MeTz@HeDvo@ls~akHy&KG)_0 z#{7()C7?I|IW!1_&+80ihikAvCC21?mB-LdDIXv?r7fhSG^p zIuA;hLFqaU259pyPe@d3i^lTSLzbAn<6gheKQbd=`=1quisnJnof z&jt#bDZ-QOoRru=p|U}Ea+;G8Cn&Z-xMA`{CwWd#S^!~*$vd6oIbq)2G5MjBJXeA^ z0|N-ZkeJNnEXU?yz`)>PFj>!8i48JXF*(dxi4zo(AgnyO(OI4oJmg`^z`!xt&{=r$ u9%mlb6TS=#CnleDR%QhccTE23tjww7&%mH#&%khHvZ9MWqr&7um(2hs3xCM~ delta 4788 zcmZ3|#ki!4aYBmiCSwK$5N2gyU| zS%*=ENm6367vn!yi2#TuK?Y%ldPW8Y86fKX#7?thI*KKu!b3E3Ra@=kD~E!GchoTAUXIs69dCtX$FQ5U9@PW$r zure?Rz#Lf5z{RixqyZ+tz{RkOm4QJ4iGQ1wfguNp|CyD6;Rq6+n~i~CjRqo-OR+I9 zY|&s~SOWEs85;vbgeC)n43rX-6pf0}2&cN`*0FjD+vNJHq7$SmLfP;ZS1&OcD!N9;007+B=3?KjNq4BLa7#MVr zPvU4&q7v-f)w&&E~ODu~|D@x2wjZe))2L=WP2?hoR zcLoNA6b1$cd9Wyi;0D>0tH!{K`28MVB1_mhx1_lkNnq(*q zqQn^(7)%%#82A_%7<48(3U*Hp5agJAMo?z50wc@h7lI0katx5v2~rKhpzH{$WI$|v z1_lP%$&5ncx}Y)#Bm%;q3eyb4U|?WyW?*2jVPIfzg7QI>-sD^%aZf7-1_omW28JL8 z28Lh;1_mCG6axc;ACv}B>I@7F1`G@gMj#FY1A`j_14AGK149A>1A`(11A`p{1B2J( zvqFyYAUi=Z0x5$*@dB#285uwcY8<43j4d*Ghq^ageVS{23TPv;TaU3=Dffv?2q;0T8Xkz;FaaD>E>h0MRN8 z3}-;JDg(m>5Us|*a0NuGGceo$(Haa4cR;i@1H%Ilt;4|Z1VroBGcddWG4vQ1-hgO* z28ItH+Ju4O3y8L5VE6%|9T*t?fM`bs29^i9Pgx$!f6Diu{{hE`eNRb2zV}d%%sr&p#T5>SAWbwwd4G!3=I7b`u_ia z^~RimLHFec=LWZMpY{#m-kokWE)0sIZVw{7w5|NFYhDUv?K$Aha>~TDMcqfWc>eL z^NvATJ3-F-X?=u7h6Gp`Bp~hmG(tN=d83Bg|L+xGB@##?d0-I{B#|_*h@dyfaF8iM zU_Kv`iV&~}m-mB+y)P^r7(XQJt}}&r5ah@c|Lgz%zw!V7e~^zrKDqP%|9?mB-oxxvBh|97Kz*50opF8^Sdu=67Wf8qs8 z@7EC$86Y(V2_SjBcZL~?J54-I!6C2pz{K0c>;8``58g$rh+zDvz!ds}uRg#yB*)b2{y6*|M$MP3U2?u{{WM}-m*LZx%|@GV?P)s2yWQ>;zKjT{zE1V46u-S@E;Ol zbHo`K0wf@50Th&=G!rGxz#uEZz~Cazz#t~Uz`!BS!0<;LoI@O^ZD4m}TEXk~|NFVO zx;`~73>s{1?6-94J=qj=z%Kd!-RrIA1CAM%Zdz{tzaM&Q{XpGI-Fs;SXJ!AtPk3wKCI$+LMuz=G#taM%Vhju&;*cBx^0k*314E8DBo~3w5-5ZO+$7x? zX8r%ZaPR-`jr#=M{(rwQ`L(n>W8P$LnMB6vn{#E_8JR?kHh+^9Vq|)d3iktU3{agA?C&Z`js3T8#rEq_yP?+ zo97xVW#n_t$gBqYQ22igS)R6^=BVz+G1_lbSKP8&6=-vF!ei0*M zz~qIF@|>WU0O8G(PddtTN(eA8fUv^kkB;)3pa25lQ*M#3C};&Pj<46haCj zlhd4(I6*NF!V@M>bdu);r3(;Nn7q?To)hNfBaVkbn$1@m|Ws diff --git a/libs/x86/libnv_avc_dec.so b/libs/x86/libnv_avc_dec.so index 44b86be8267e1210f70e6e84684a64013820d746..8c52cb7f5e84caa28580ba396c6dd800611fcce4 100644 GIT binary patch delta 4260 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 SE^$JEf#Du3h9D^%%mV;^n7f() delta 4520 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