From fb8b6fd7f58cd571211dfa4f8b7c22d6140ee9ba Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 24 Nov 2013 21:46:47 -0500 Subject: [PATCH] Add configurable ffmpeg performance options --- jni/nv_avc_dec/nv_avc_dec.c | 52 ++++++++++++------ jni/nv_avc_dec/nv_avc_dec.h | 2 +- jni/nv_avc_dec/nv_avc_dec_jni.c | 4 +- libs/armeabi-v7a/libnv_avc_dec.so | Bin 17700 -> 17700 bytes libs/x86/libnv_avc_dec.so | Bin 9576 -> 9576 bytes .../nvstream/av/video/AvcDecoder.java | 15 ++++- .../nvstream/av/video/CpuDecoderRenderer.java | 20 ++++++- 7 files changed, 72 insertions(+), 21 deletions(-) diff --git a/jni/nv_avc_dec/nv_avc_dec.c b/jni/nv_avc_dec/nv_avc_dec.c index 525f3567..4366ce11 100644 --- a/jni/nv_avc_dec/nv_avc_dec.c +++ b/jni/nv_avc_dec/nv_avc_dec.c @@ -20,15 +20,24 @@ struct SwsContext* scaler_ctx; #define RENDER_PIX_FMT AV_PIX_FMT_RGBA #define BYTES_PER_PIXEL 4 -#define VERY_LOW_PERF 0 -#define LOW_PERF 1 -#define MED_PERF 2 -#define HIGH_PERF 3 +// Disables the deblocking filter at the cost of image quality +#define DISABLE_LOOP_FILTER 0x1 +// Uses the low latency decode flag (disables multithreading) +#define LOW_LATENCY_DECODE 0x2 +// Threads process each slice, rather than each frame +#define SLICE_THREADING 0x4 +// Uses nonstandard speedup tricks +#define FAST_DECODE 0x8 +// Uses bilinear filtering instead of bicubic +#define BILINEAR_FILTERING 0x10 +// Uses a faster bilinear filtering with lower image quality +#define FAST_BILINEAR_FILTERING 0x20 // This function must be called before // any other decoding functions -int nv_avc_init(int width, int height, int perf_lvl) { +int nv_avc_init(int width, int height, int perf_lvl, int thread_count) { int err; + int filtering; pthread_mutex_init(&mutex, NULL); @@ -53,24 +62,25 @@ int nv_avc_init(int width, int height, int perf_lvl) { // Show frames even before a reference frame decoder_ctx->flags2 |= CODEC_FLAG2_SHOW_ALL; - if (perf_lvl <= LOW_PERF) { + if (perf_lvl & DISABLE_LOOP_FILTER) { // Skip the loop filter for performance reasons decoder_ctx->skip_loop_filter = AVDISCARD_ALL; } - if (perf_lvl <= MED_PERF) { - // Run 2 threads for decoding - decoder_ctx->thread_count = 2; - decoder_ctx->thread_type = FF_THREAD_FRAME; - - // Use some tricks to make things faster - decoder_ctx->flags2 |= CODEC_FLAG2_FAST; - } - else { + if (perf_lvl & LOW_LATENCY_DECODE) { // Use low delay single threaded encoding decoder_ctx->flags |= CODEC_FLAG_LOW_DELAY; } + if (perf_lvl & SLICE_THREADING) { + decoder_ctx->thread_type = FF_THREAD_SLICE; + } + else { + decoder_ctx->thread_type = FF_THREAD_FRAME; + } + + decoder_ctx->thread_count = thread_count; + decoder_ctx->width = width; decoder_ctx->height = height; decoder_ctx->pix_fmt = PIX_FMT_YUV420P; @@ -114,13 +124,23 @@ int nv_avc_init(int width, int height, int perf_lvl) { return err; } + if (perf_lvl & FAST_BILINEAR_FILTERING) { + filtering = SWS_FAST_BILINEAR; + } + else if (perf_lvl & BILINEAR_FILTERING) { + filtering = SWS_BILINEAR; + } + else { + filtering = SWS_BICUBIC; + } + scaler_ctx = sws_getContext(decoder_ctx->width, decoder_ctx->height, decoder_ctx->pix_fmt, decoder_ctx->width, decoder_ctx->height, RENDER_PIX_FMT, - SWS_BICUBIC, + filtering, NULL, NULL, NULL); if (scaler_ctx == NULL) { __android_log_write(ANDROID_LOG_ERROR, "NVAVCDEC", diff --git a/jni/nv_avc_dec/nv_avc_dec.h b/jni/nv_avc_dec/nv_avc_dec.h index d53d5425..bc47b021 100644 --- a/jni/nv_avc_dec/nv_avc_dec.h +++ b/jni/nv_avc_dec/nv_avc_dec.h @@ -1,6 +1,6 @@ #include -int nv_avc_init(int width, int height, int perf_lvl); +int nv_avc_init(int width, int height, int perf_lvl, int thread_count); void nv_avc_destroy(void); void nv_avc_redraw(JNIEnv *env, jobject surface); int nv_avc_decode(unsigned char* indata, int inlen); diff --git a/jni/nv_avc_dec/nv_avc_dec_jni.c b/jni/nv_avc_dec/nv_avc_dec_jni.c index e438c703..70f165b7 100644 --- a/jni/nv_avc_dec/nv_avc_dec_jni.c +++ b/jni/nv_avc_dec/nv_avc_dec_jni.c @@ -7,9 +7,9 @@ // any other decoding functions JNIEXPORT jint JNICALL Java_com_limelight_nvstream_av_video_AvcDecoder_init(JNIEnv *env, jobject this, jint width, - jint height, jint perflvl) + jint height, jint perflvl, jint threadcount) { - return nv_avc_init(width, height, perflvl); + return nv_avc_init(width, height, perflvl, threadcount); } // This function must be called after diff --git a/libs/armeabi-v7a/libnv_avc_dec.so b/libs/armeabi-v7a/libnv_avc_dec.so index ad485f7c990cde52cc2cf7229c9447db6b13c568..f9e6b5bc1e60743afe815631a4a4a7f4fe077417 100644 GIT binary patch delta 1962 zcmZ9Ne{54#6vyxFUfXRHw-LG@ZMSu8fx<@U7>qJhh8vHTPGriD{zDiMLXBXjF=i;x zA_>1T$=Gv%qLDuk28eW2A`2O7fCLnOAfkbS@(i#aj&?OcUlH;7eUGO;_~X2DKj)l# z?z!jQyt{83-M5XlE!SR{Ovr^DF9oyqx(JbF$1g9_>(OUvIn4_@2+1Ubj3U|OC?#YW zw^b9=P!sp3W;-q7wq`7y{F|8&gAy_?gOCScM&V6hY9U0Ya1U5-;Y>_Ps71+aLuNbT zn^jx`c1^$>W!gfpRmHD>YgOD1p0DB~;43OV4>o{DEBWFK;XY^b@)#>2^@=Tpm}c%O zGf88p;Ig$Pp)C$V8c?sa^(HMLZdJk-uv5j`!5$SK1;4A}bKpBFz5%{G?*G;%!Pmk2 zlwz`VBt*haLeM+800%nw0eF?dZgA#!bVcFCU?&)xkmCd33Y9+$ZUDy=|1Pk)BZtAH zoDl3;o_|&sdem?Y0S;BboyYh-*rW0n=pW@u@G6zx^B6Ayx2gQEE_lqa5xjR2&RwZ+ zCzuCUD0~ELzzudQ{57~9{O|3(1#XDm({0ZU&3TVq(y%GA#204Q*5|OK%*gV7Q7{b$ zQ+gr_mSIt_4qL3E;22)$yXk+QEo`!Ozu;XkcTN49^;x_qlng)b>+`#sJl&1nM%k*f zK9>@wi$ebJ7XHlYL4DobaK@Pxnjc*DSbBcdA$=_Ed?8Bp5D5<#2!zR zTo_guQ%sJbm)bRUVvD6Ks$%I@ES^ph=LVLE*LY{hOH^awyUFP&NGiweb<5V%{h~0C ztoAKPXS98h#)asf;+-mcj`!>DX9_2XDEyqP#4IXr!{v2_WcU95sz5wQ+AX%Ln6@V< z3YX*s_3`oE337xEMMRQiJhdIxF_(?0TolRJG`6aMWz6p2)gbL4V>In#$3ZrugXz$A ze2=m-SW);aX;z9fc};Sr=6(;Wi}VbnHeZ@XNa(C6isvD>iU=8ke1-8h&?(3&NGIeX zY>S}xLoQ?dBy=m}3dSYSn;?G`60#opI&8-jcxgkaZ*Bc;zcb+K5{1{3&VVSq zktFu=CX-LH7A}>|lA!>G@_@a|iK<_dLq@AC0ojtPvNXw-kq^@#OM}eWKHlFm;I5^q z87E2a-&46Si>A=0IkCt{YdE8+a@yFWJ#a0!`x)lq81GoQAz8eeorOiMNj>ZCws~#; zHT-mzIAQj<53 z-bLJZrh;+q0{nF#Hpp#AUq1fy&=Ut!vvx-Gtfq4$X7zD7=7N=h#7sVO_jFcTIi9HG zZF6nDkNxz}P5<~nVL)?O6n;#g5_Uwq7_}5DwaiOcuz68vPndbSXJc2PbPvO|$nka} z-`DS-5ioa4{Xdm(H%Zp@+&gCT>|+TRo3B(_GX-akx>ler>CC0OP!0BirF+6da@ivG z!vOOm(n%d2#bjl&SCM;&gg2(W~xa|j{Z?RiqhY?tkT8w2DhyA zE&6Trr_vk^oyR50UZifW(RP475xr+yOsOH-=-9>3*65(KPG5BLo;Z|QJ8`fZx@As` zC9#ig=cHPB2RGX_v+`D-7>azV4WAegLkBav!t)2gpX7v_ewDN_>>3h7cp`}tIueP5 ztE0zV!-i<=sWzI|S^4m7mEKe7En|UBZ!xVAZbtT&6_)jh8Cf3=t^83pz#7LUa K8C_R*fc^t@D_#%) delta 2025 zcmZ9NeN0nV6u|F&{U#Ve1^Ts8TbSi5wotWh*)b85R` z<}ic+FMdpt?H?C#&H?K-B@=DbL}T2db1{l$t6vn*_u4IHuj;b9^PW$A`p47VZ$~zLXz}ddl#RKt;A(Gx2*^vJwj*>%0j~!p#a-O zg{f&1d!OpTnC()nsl04K;C#4cl?tI7z-pO415N^KWgZ9SEUZ~=i@YhH?0{e=>~B)= z3&8VAAw~{c4Xjr12H+wE_XB$sd=U7Ef=>gdOW;iTya_d852)Bv-l9RssyMI%I9tIzz~u@a2JTSsDd2Mo{uB7{f+wxzf#bmY z75=(s_$}a#3jg~}&loy^w=G1d zM$T{-@JZlunGXV|fqgRn0_=i`el)!|f!(ot+Mb+(Zy#w6cF~(_(fm9*5h8*$ z6;A6A5o{?UI8s(S5sFd`!DPtSVjo)-Xjt)4?WS5of(Z81%HU+k-BLGJAE=kCT6;s9 zEFpq1wKZ{~9as48MpY-)s;;^n@l2yro1iLe$2!~ncagJmt?oSKh{Q84CkAJ^bFTly zT2#E0iDx>Z@yzDlQaYaLZY08eerTDFR!=MnES9eD!o~ma-r$Xp5z?s&R7uw3Ng~Yf z9yv*Oz#~}?B@GYsnTDCqp_uD@1;k)lj4BJ1Oa8$~vWl4qqkgNy#|(staFItY9j%)v z4m>Yy&_eA$@TNo+V|6T~_k=HpalhK3+KKw8e)Uex&I_4tyNV`4oVUmcnFD4ia#PYr z>qf?>(w)C8fp3QpavJ2U384!hXJP#l=*T7bXaea4IS0m?a4v{?Hh9h9FLp(D>px(*gK)aG!O)8>%sbS38jx(Ax8)SR#DS`5G7|O0&bw3D zY-6r97JsQ1=XQG@KF#8DEIyn~vDWHA6*XmKv-~zq9sJGJu@!!&MtZ*4)vyvHx?@}X GgZO`y#DhBk diff --git a/libs/x86/libnv_avc_dec.so b/libs/x86/libnv_avc_dec.so index 8c52cb7f5e84caa28580ba396c6dd800611fcce4..affff12fc086536ab6452e9d7e5dcf231dec19cb 100644 GIT binary patch delta 1548 zcmZ`(ZD?Cn7(VAV?P6Dxv`yNiUun%j=5(^MGP>Cx>x@uKXCqB(HC?MvN(B|&!l)9K zX19UeT`#7dqKIQ`phMVTKLWFeXl%B|=>(nr80?2p#(HCi1eCU`bJyqG8)^|3xHUoj+X`r>*=-nZNzC zhmgI5kQ!1+dddjN12>lNG%%?nWP1sJ3cNGzvsG^`i?Lz8!})kTebX?EWJalQ&bTB( z6dTiz{%siQIo+~9MVvER;7Ih05VDV~<|wqHmAUDl(8Bv_4qoC+hTu@vbJK4FiJ$zd zOY8sbWjd6Bfc30@`2T5F7%wS&bk8uf=)*)_a>)kuW#qgh zXQVC1@V|hdkg@4E{xXchAs|h@ z3dizKn!Fo3mal4ZQQ%9OJR$Js+C_vTLj(FjbUu+i(1PIO?6%sF7H31PNM@p5(YX&H zsG2=I!_Qay8s7)biByT27UNPK$tzKZ(!q3%=c|43!<+nKa;B2$e}0ok%&X)<4FA6# zIS-GB`vh!A$Q>EYnuU+EIb{TAEXrQgWppNyJ=`pEF!?byuDrq~k%gq!^0#W*DCH+> zdOE&dN0_=j`(x2=O+NO2oim%(2AURRts?Fq_ttKsG2UIXkY|BQ0~WK^>4%_AZTctk!p7)wVT($&OS?YJRPVytZqis_-tX_P` z^H@8vUdOtIkLE7cVPJdO)3D2yo@}{kqx<-QfWJJ0TRFqu2n5RYdR$}tgFv9dy6n>n HfwS}MAaF0+MPbnMRUHW>VKS zcTG6CUNStyATe>qgg;_16v1SR4vH2Qei-$K(LW@Do-%&SsH8IC`kZ^~oQX8Keed&r zJc9Xn}MY^z97A}&<4Z%j84 zavve2fz*&l1tIgmEoGbrz65-C8J`BO%LSbEYbwTAOx)|)kea=0nr3#MS9zwEC?VX* z(Lq9xfd<6s$5@n)CV6zC zkbVoa>Q@M}YGw7cJjR@g;vP`&f}vea{S0=~v%eD^WS1fq*KFc)TUoE1vr8)~Ri@|o z7>k~{;^6Cpp!T$)8|#`qLAjtW^Sn5WvICsaGihKmKK{y5RNf|3E2o z>Cp*2V%6}NI8xV~LXF>v5Uf|#>eh15p_+RcdOM{+4_%a2m_J3g|lUSRZIP4O~!4iJnvA)7{w%<8Ho* z$&cS|2&BZSuo|S*$O^x)DxyYMj-c^F|3lCs~4zu~CR{$X;=zp_6usxrWFlc>^@QEsrF}`weY3mi_-5-H$XQ%sLeB z>!Po*o4zMrXl$hiM5=L1DuHNrexgquz)`#_`x435w&!p@OB#;+9zNt-U(D5 z*g;X%5p+=bd`awUYD!Tw!c`FDj^Yp&{gPEbBq!m{Kc4^RlbBnlBn`<2t@;gieMx>~ABgI>t#3%SS#fu>sPXky{RByw{I|KV?;NEi zafiR1PKdkke^_kuw+H5~n`W(Qi(d@SG@g_2?GYJ&Ffc=F+}=msb@_gG?N|No>O#NU z`Q_tl95Hdq|BYK+xCCC!G3f5tCEf{4b{@w0_2Vo49<~p*1Y5%06#T<9hk?6u_c!-C t#dLE=ZnW*PlXi$FL+zC_K0;>1-cYFW{8~cJi+4jImwoBy&W4WCzX8VovDyFt diff --git a/src/com/limelight/nvstream/av/video/AvcDecoder.java b/src/com/limelight/nvstream/av/video/AvcDecoder.java index a886bb0f..c4299080 100644 --- a/src/com/limelight/nvstream/av/video/AvcDecoder.java +++ b/src/com/limelight/nvstream/av/video/AvcDecoder.java @@ -15,7 +15,20 @@ public class AvcDecoder { System.loadLibrary("nv_avc_dec"); } - public static native int init(int width, int height, int perflvl); + /** Disables the deblocking filter at the cost of image quality */ + public static final int DISABLE_LOOP_FILTER = 0x1; + /** Uses the low latency decode flag (disables multithreading) */ + public static final int LOW_LATENCY_DECODE = 0x2; + /** Threads process each slice, rather than each frame */ + public static final int SLICE_THREADING = 0x4; + /** Uses nonstandard speedup tricks */ + public static final int FAST_DECODE = 0x8; + /** Uses bilinear filtering instead of bicubic */ + public static final int BILINEAR_FILTERING = 0x10; + /** Uses a faster bilinear filtering with lower image quality */ + public static final int FAST_BILINEAR_FILTERING = 0x20; + + public static native int init(int width, int height, int perflvl, int threadcount); public static native void destroy(); public static native void redraw(Surface surface); public static native int decode(byte[] indata, int inoff, int inlen); diff --git a/src/com/limelight/nvstream/av/video/CpuDecoderRenderer.java b/src/com/limelight/nvstream/av/video/CpuDecoderRenderer.java index 9b724fc2..ca3ad89d 100644 --- a/src/com/limelight/nvstream/av/video/CpuDecoderRenderer.java +++ b/src/com/limelight/nvstream/av/video/CpuDecoderRenderer.java @@ -73,7 +73,25 @@ public class CpuDecoderRenderer implements DecoderRenderer { this.renderTarget = renderTarget; this.perfLevel = findOptimalPerformanceLevel(); - int err = AvcDecoder.init(width, height, perfLevel); + int flags = 0; + switch (perfLevel) { + case LOW_PERF: + flags = AvcDecoder.DISABLE_LOOP_FILTER | + AvcDecoder.FAST_BILINEAR_FILTERING | + AvcDecoder.FAST_DECODE | + AvcDecoder.LOW_LATENCY_DECODE; + break; + case MED_PERF: + flags = AvcDecoder.LOW_LATENCY_DECODE | + AvcDecoder.FAST_DECODE | + AvcDecoder.BILINEAR_FILTERING; + break; + case HIGH_PERF: + flags = AvcDecoder.LOW_LATENCY_DECODE; + break; + } + + int err = AvcDecoder.init(width, height, flags, 2); if (err != 0) { throw new IllegalStateException("AVC decoder initialization failure: "+err); }