From 5ebd3a2c75366ca50a026c61526a069df09e0f3f Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 9 Jun 2025 00:03:01 +0800 Subject: [PATCH] avrecorder ndk demo Signed-off-by: Steven --- code/DocsSample/Media/AVRecorder/.gitignore | 12 + .../Media/AVRecorder/AppScope/app.json5 | 24 + .../resources/base/element/string.json | 8 + .../resources/base/media/app_icon.png | Bin 0 -> 6790 bytes code/DocsSample/Media/AVRecorder/README_zh.md | 68 ++ .../Media/AVRecorder/build-profile.json5 | 53 + .../Media/AVRecorder/entry/.gitignore | 6 + .../AVRecorder/entry/build-profile.json5 | 54 + .../Media/AVRecorder/entry/hvigorfile.ts | 21 + .../Media/AVRecorder/entry/oh-package.json5 | 26 + .../entry/src/main/cpp/CMakeLists.txt | 18 + .../entry/src/main/cpp/camera_manager.cpp | 1044 +++++++++++++++++ .../entry/src/main/cpp/camera_manager.h | 162 +++ .../entry/src/main/cpp/log_common.h | 31 + .../AVRecorder/entry/src/main/cpp/main.cpp | 550 +++++++++ .../AVRecorder/entry/src/main/cpp/main.h | 49 + .../AVRecorder/entry/src/main/cpp/muxer.cpp | 91 ++ .../AVRecorder/entry/src/main/cpp/muxer.h | 46 + .../entry/src/main/cpp/sample_info.h | 142 +++ .../src/main/cpp/types/libentry/index.d.ts | 38 + .../main/cpp/types/libentry/oh-package.json5 | 20 + .../src/main/cpp/video_encoder_sample.cpp | 73 ++ .../entry/src/main/cpp/video_encoder_sample.h | 36 + .../main/ets/entryability/EntryAbility.ets | 65 + .../entrybackupability/EntryBackupAbility.ets | 28 + .../entry/src/main/ets/pages/Index.ets | 163 +++ .../AVRecorder/entry/src/main/module.json5 | 137 +++ .../main/resources/base/element/color.json | 8 + .../main/resources/base/element/string.json | 56 + .../src/main/resources/base/media/icon.png | Bin 0 -> 6790 bytes .../resources/base/media/layered_image.json | 7 + .../main/resources/base/media/startIcon.png | Bin 0 -> 6790 bytes .../resources/base/profile/main_pages.json | 5 + .../main/resources/en_US/element/string.json | 16 + .../main/resources/zh_CN/element/string.json | 16 + .../AVRecorder/hvigor/hvigor-config.json5 | 47 + .../DocsSample/Media/AVRecorder/hvigorfile.ts | 22 + code/DocsSample/Media/AVRecorder/hvigorw | 60 + code/DocsSample/Media/AVRecorder/hvigorw.bat | 63 + .../Media/AVRecorder/oh-package.json5 | 29 + code/DocsSample/Media/AVRecorder/ohosTest.md | 10 + 41 files changed, 3304 insertions(+) create mode 100644 code/DocsSample/Media/AVRecorder/.gitignore create mode 100644 code/DocsSample/Media/AVRecorder/AppScope/app.json5 create mode 100644 code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json create mode 100644 code/DocsSample/Media/AVRecorder/AppScope/resources/base/media/app_icon.png create mode 100644 code/DocsSample/Media/AVRecorder/README_zh.md create mode 100644 code/DocsSample/Media/AVRecorder/build-profile.json5 create mode 100644 code/DocsSample/Media/AVRecorder/entry/.gitignore create mode 100644 code/DocsSample/Media/AVRecorder/entry/build-profile.json5 create mode 100644 code/DocsSample/Media/AVRecorder/entry/hvigorfile.ts create mode 100644 code/DocsSample/Media/AVRecorder/entry/oh-package.json5 create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/CMakeLists.txt create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.cpp create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/icon.png create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/layered_image.json create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/startIcon.png create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/profile/main_pages.json create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/en_US/element/string.json create mode 100644 code/DocsSample/Media/AVRecorder/entry/src/main/resources/zh_CN/element/string.json create mode 100644 code/DocsSample/Media/AVRecorder/hvigor/hvigor-config.json5 create mode 100644 code/DocsSample/Media/AVRecorder/hvigorfile.ts create mode 100644 code/DocsSample/Media/AVRecorder/hvigorw create mode 100644 code/DocsSample/Media/AVRecorder/hvigorw.bat create mode 100644 code/DocsSample/Media/AVRecorder/oh-package.json5 create mode 100644 code/DocsSample/Media/AVRecorder/ohosTest.md diff --git a/code/DocsSample/Media/AVRecorder/.gitignore b/code/DocsSample/Media/AVRecorder/.gitignore new file mode 100644 index 0000000000..d2ff20141c --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/AppScope/app.json5 b/code/DocsSample/Media/AVRecorder/AppScope/app.json5 new file mode 100644 index 0000000000..7e5ebd28f9 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "bundleName": "com.samples.avrecorder", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000..c341df60c8 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "AVRecorderSample" + } + ] +} diff --git a/code/DocsSample/Media/AVRecorder/AppScope/resources/base/media/app_icon.png b/code/DocsSample/Media/AVRecorder/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 zcmX|G1ymHk)?T_}Vd;>R?p|tHQo6fg38|$UVM!6BLrPFWk?s;$LOP{GmJpBl$qoSA!PUg~PA65-S00{{S`XKG6NkG0RgjEntPrmV+?0|00mu7;+5 zrdpa{2QLqPJ4Y{j7=Mrl{BaxrkdY69+c~(w{Fv-v&aR%aEI&JYSeRTLWm!zbv;?)_ ziZB;fwGbbeL5Q}YLx`J$lp~A09KK8t_z}PZ=4ZzgdeKtgoc+o5EvN9A1K1_<>M?MBqb#!ASf&# zEX?<)!RH(7>1P+j=jqG(58}TVN-$psA6K}atCuI!KTJD&FMmH-78ZejBm)0qc{ESp z|LuG1{QnBUJRg_E=h1#XMWt2%fcoN@l7eAS!Es?Q+;XsRNPhiiE=@AqlLkJzF`O18 zbsbSmKN=aaq8k3NFYZfDWpKmM!coBU0(XnL8R{4=i|wi{!uWYM2je{U{B*K2PVdu&=E zTq*-XsEsJ$u5H4g6DIm2Y!DN`>^v|AqlwuCD;w45K0@eqauiqWf7l&o)+YLHm~|L~ z7$0v5mkobriU!H<@mVJHLlmQqzQ3d6Rh_-|%Yy2li*tHO>_vcnuZ7OR_xkAIuIU&x z-|8Y0wj|6|a6_I(v91y%k_kNw6pnkNdxjqG8!%Vz_d%c_!X+6-;1`GC9_FpjoHev5fEV7RhJ>r=mh-jp$fqbqRJ=obwdgLDVP5+s zy1=_DWG0Y-Jb3t^WXmkr(d9~08k-|#Ly zaNOmT(^9tIb&eb4%CzIT zAm3CUtWSr1t4?h1kk#NBi{U|pJslvME{q|_eS^3En>SOqSxyuN1x;Is@8~m?*>}** znrRFArP!K_52RpX*&JHMR<^lVdm8ypJ}0R(SD(51j;6@ni$6bQ+2XL+R^|NnSp5}(kzvMZ^(@4fD_{QVu$(&K6H|C37TG1Am9Re{<<3gd zh@`>;BqkXMW&p0T6rt|iB$)~CvFe(XC)F9WgAZn*0@t$oZo;!*}r@_`h?KKH&6A@3= zISXoQB+~`op>NP-buiA*^0n{@i{_?MRG)&k)c)k_F+-2Lud!S9pc+i`s74NpBCaGF zXN+pHkubw*msGBTY27BKHv)RRh3;nMg4&$fD_6X9Vt~;_4D+5XPH~#Kn-yjcy!$}1 zigv#FNY>TqMhtIBb@UoF!cE~Q8~;!Pek>SQQwHnHuWKoVBosAiOr}q>!>aE*Krc)V zBUMEcJ5NU0g8}-h6i1zpMY9>m4ne?=U2~`w7K7Q0gB_=p@$5K7p6}thw z-~3dMj?YNX2X$lZ+7ngQ$=s}3mizNN@kE%OtB)?c&i~2L55z8^=yz;xMHLmlY>&Q# zJj?!)M#q_SyfkQh)k?j8IfLtB)ZCp|*vf4_B zos?73yd^h-Ac+;?E4*bpf=o*^3x3-`TVjbY4n6!EN10K6o@fxdyps05Vo3PU)otB} z`3kR+2w7_C#8Z!q`J)p{Vh!+m9-UP!$STp+Hb}}#@#_u^SsUQg<}59< zTvH3%XS4G+6FF^(m6bVF&nSUIXcl;nw{=H$%fgeJ>CgDYiLdpDXr{;-AnG z8dvcrHYVMI&`R6;GWekI@Ir3!uo)oz4^{6q0m^}@f2tM9&=YHNi6-?rh0-{+k@cQm zdp`g#YdQn%MDVg2GR>wZ`n2<0l4)9nx1Wfr&!Dvz=bPwU!h2S?ez6MVc5APE4-xLB zi&W9Q8k2@0w!C53g?iAIQ}~p*3O(@zja6KQ=M3zfW*_6o5SwR-)6VBh~m7{^-=MC-owYH5-u40a}a0liho3QZZ5L{bS_xM1)4}19)zTU$$MY zq3eZML1WC{K%YFd`Be0M-rkO^l?h{kM{$2oK1*A@HVJ57*yhDkUF!2WZ&oA4Y-sK( zCY69%#`mBCi6>6uw(x4gbFaP0+FD*JKJ-q!F1E?vLJ+d35!I5d7@^eU?(CS|C^tmI5?lv@s{{*|1F zFg|OzNpZ0hxljdjaW%45O0MOttRrd(Z?h{HYbB-KFUx&9GfFL3b8NwZ$zNu)WbBD` zYkj$^UB5%3Pj1MDr>S2Ejr9pUcgA!;ZG!@{uAy12)vG=*^9-|dNQBc8&`oxBlU~#y zs!anJX&T?57Jdr^sb>e+V`MVfY>Y0ESg7MG<7W0g&bR-ZYzzZ%2H&Etcp zcd6QeXO1D!5A#zM0lx*GH}`M)2~ZFLE;sP^RSB5wVMNfiZXPd(cmO>j=OSA3`o5r& zna(|^jGXbdN7PK)U8b7^zYtYkkeb%<%F~=OqB~kXMQkq}ii|skh@WSRt>5za;cjP0 zZ~nD%6)wzedqE}BMLt~qKwlvTr33))#uP~xyw#*Eaa|DbMQ_%mG0U8numf8)0DX`r zRoG2bM;#g|p-8gWnwRV5SCW0tLjLO&9Z?K>FImeIxlGUgo0Zk`9Qzhj1eco~7XZy+hXc@YF&ZQ=? zn*^1O56yK^x{y}q`j7}blGCx%dydV!c7)g~tJzmHhV=W~jbWRRR{1<^oDK+1clprm zz$eCy7y9+?{E|YgkW~}}iB#I4XoJ*xr8R?i_Hv$=Cof5bo-Nj~f`-DLebH}&0% zfQj9@WGd4;N~Y?mzQsHJTJq6!Qzl^-vwol(+fMt#Pl=Wh#lI5Vmu@QM0=_r+1wHt` z+8WZ~c2}KQQ+q)~2Ki77QvV&`xb|xVcTms99&cD$Zz4+-^R4kvUBxG8gDk7Y`K*)JZ^2rL(+ZWV~%W(@6 z)0bPArG#BROa_PHs~&WplQ_UIrpd)1N1QGPfv!J(Z9jNT#i%H?CE6|pPZb9hJ1JW4 z^q;ft#!HRNV0YgPojzIYT`8LuET2rUe-J|c!9l4`^*;4WtY@Ew@pL>wkjmMgGfN7 ze}}GtmU0@<_#08~I-Suk=^*9GLW=H4xhsml;vAV{%hy5Eegl@!6qKqbG024%n2HHw zCc@ivW_$@5ZoHP70(7D+(`PvgjW1Pd`wsiuv-aCukMrafwDm)B!xXVy*j2opohhoU zcJz%ADmj>i3`-3-$7nQKBQQuGY;2Qt&+(L~C>vSGFj5{Mlv?T_^dql;{zkpe4R1}R z%XfZyQ}wr*sr>jrKgm*PWLjuVc%6&&`Kbf1SuFpHPN&>W)$GmqC;pIoBC`=4-hPY8 zT*>%I2fP}vGW;R=^!1be?ta2UQd2>alOFFbVl;(SQJ4Jk#)4Z0^wpWEVvY4=vyDk@ zqlModi@iVPMC+{?rm=4(n+<;|lmUO@UKYA>EPTS~AndtK^Wy^%#3<;(dQdk3WaUkRtzSMC9}7x2||CNpF#(3T4C)@ z$~RWs`BNABKX|{cmBt>Q=&gkXl&x!!NK_%5hW0LS)Z4PB>%sV?F-{Wyj#s7W%$F{D zXdK^Fp3wvy+48+GP6F_|^PCRx=ddcTO3sG;B23A49~Qaw31SZ0Rc~`r4qqt%#OGW{ zCA_(LG5^N>yzUn&kAgVmxb=EA8s&tBXC}S1CZ(KoW)(%^JjLTPo^fs`Va;`=YlVPgmB$!yB}<(4ym6OeZ3xAJJ#;)2+B%p3P1Wt+d$eo`vz`T zXfUP2))kBDPoscH;Jc7I3NU<({|@wM$&GaDt`n7WLgIY3IA7A6-_R?z8N3mz|}*i z(zl5ot--Oq@f2-nv{X(ujT2T(k1vY_qh93pK@>H-qc%2Xta)IP0Q%zt%bqYgI`o!wv!0QerB`nCN^1n|@$sVOQ!V0teVG!I z_fD%JvfDeT1cK#-{o6Gv7}& zY0#NWin~kVaf$aufV&;63Hbs|`QVZWpDX6IMk1Hj2G}fiH9e-^6u2zf^FIr^BwD<6zjw63+{yUe8PUFvk8v{sJ=R{d#`O!sz`Q13~< zPT$JS(w=yQfU2`zPCNfSw=&zup@DXc(98afjhv@1w_f!m2Z>rMJ19AB&dB%P#Ls3b z=lK7OILM+SQ&VEd=1GN6o&>YVVtIzoZ%=Z_SdqJN2}E43{bE`>w+A;=y->@^k{oCC z$F*WTY&?34;kfyFV?b*Xb1Pq`Z=%OgwEg)Rz)tx=`f%5#w_INP=x&z5!jI;#;N$ma zhO)+MDm;SxOEVL15; zGq(v2pL3&P1Sl)8P*;G-fd{l1QJsv@e@d8)1PK4w2m*M%V3j-V~L^$i|&C@b?D?9tfwE{B^}Z$k8e5FmQ>v7Xz)sG32g9t}YBt zyR$+*_00RmPx+0mW+vVG4mxd(n$(eQf3-w>JPl2UJpafrPaL5@2j}%{VE-) zBI%6Qpj*dsdH<;g!S!avA~bv^0E+ zfyJbSjPb+j;J52U)<|cIcntQBI2T#>2;tOxu{%D?kML476AErF(qN9hPva5Nkc@BF zC-tLF@3ZFb%Kpj)M<{)x*l|*Ia@ECeXo2E4h2f!aV=cHAhi_E_mfUth(sM4^hJq7B zQsGWqdZUm9S%F`$nQ*_#NcuD`&)Ek%_s{&^78{9Hm ztri&rYLOxgFdG>O@+XHy z9#;|&vBCPXH5Mon^I`jSuR$&~ZWtyB67ujzFSj!51>#C}C17~TffQ{c-!QFQkTQ%! zIR^b1`zHx|*1GU?tbBx23weFLz5H?y_Q%N&t$}k?w+``2A=aotj0;2v$~AL z{scF-cL{wsdrmPvf#a9OHyYLcwQD4Kcm)`LLwMh4WT~p29f7M!iafJSU`IV}QY5Wa z(n44-9oA}?J{a+ah*@31WTs#&J#o1`H98#6IQf;Wv0N_!);f&9g7o-k(lW5rWnDUR zQBFIRG+X=6NnsI@mxnwm;tf5;_Uxg?jZ8m-m0}&6+DA!qam(p$mN5R})yA_7m$q@| zFEd|dpS595rxQr-n#GjI5i-AhnUE>Cr;jpCqSrD~EwK_DqI^7%3#p5)%T_od!t3SOmH9MyXeeGO2(UQL;ax|x?Ncixmeo1=$ z{-);Au{*tfzOG?KQ~K|ak8-HQ?`Pekhe2WM(8s{xv-p>Zmu_6{G!-oE$7$mY`MOJorI=+mMx?H;`pr!;fVYz?5~yXBACruWB`Ph zZM}90_<^OBxIhyZ9BW$`>6JvO;%VFpqVr8|7t3~AmxYak6?`Pp#c;**_SYmi`&z23 z`p6_~ePvH)C6x-G9$hgL=eVALq`-AiamN>!3~Lxw&{H(b{B(7xSRm6<3<{%{yXiH# zos5Rv1L+8fUKJLo%P>4I&$}y g_int32ToCameraSceneMode = { + {1, Camera_SceneMode::NORMAL_PHOTO}, + {2, Camera_SceneMode::NORMAL_VIDEO}, + {12, Camera_SceneMode::SECURE_PHOTO} +}; + +NDKCamera::NDKCamera(uint32_t focusMode, uint32_t cameraDeviceIndex, uint32_t sceneMode, + char *previewId, char *photoId, char *videoId) + : focusMode_(focusMode), cameraDeviceIndex_(cameraDeviceIndex), + previewSurfaceId_(previewId), photoSurfaceId_(photoId), videoSurfaceId_(videoId), + cameras_(nullptr), profile_(nullptr), cameraOutputCapability_(nullptr), captureSession_(nullptr), + cameraInput_(nullptr), previewOutput_(nullptr), photoOutput_(nullptr), videoOutput_(nullptr), + isCameraMuted_(nullptr), metaDataObjectType_(nullptr), metadataOutput_(nullptr), + isExposureModeSupported_(false), isFocusModeSupported_(false), isSuccess_(false), + sceneMode_(NORMAL_VIDEO), exposureMode_(EXPOSURE_MODE_LOCKED), ret_(CAMERA_OK), + size_(0), minExposureBias_(0), maxExposureBias_(0), step_(0) +{ + // release camera + ReleaseCamera(); + + // create camera manager + Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager_); + if (cameraManager_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Get CameraManager failed."); + } + + // create capture session + ret = OH_CameraManager_CreateCaptureSession(cameraManager_, &captureSession_); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Create captureSession failed."); + } + + // look up sceneMode + auto itr1 = g_int32ToCameraSceneMode.find(sceneMode); + if (itr1 != g_int32ToCameraSceneMode.end()) { + sceneMode_ = itr1->second; + } + + // set session mode + ret = OH_CaptureSession_SetSessionMode(captureSession_, NORMAL_VIDEO); + + // get capture session profile + GetSupportedCameras(); + GetSupportedOutputCapability(); + + // create preview output + CreatePreviewOutput(); + + // create camera input and register camera input callback + CreateCameraInput(); + CameraInputOpen(); // 设备打开 + + // config and start session + SessionFlowFn(); +} + +NDKCamera::~NDKCamera() +{ + OH_LOG_INFO(LOG_APP, "~NDKCamera"); + Camera_ErrorCode ret = CAMERA_OK; + + if (cameraManager_) { + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameraOutputCapability. enter"); + ret = OH_CameraManager_DeleteSupportedCameraOutputCapability(cameraManager_, cameraOutputCapability_); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Delete CameraOutputCapability failed."); + } else { + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameraOutputCapability. ok"); + } + + OH_LOG_ERROR(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameras. enter"); + ret = OH_CameraManager_DeleteSupportedCameras(cameraManager_, cameras_, size_); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); + } else { + OH_LOG_INFO(LOG_APP, "Release OH_CameraManager_DeleteSupportedCameras. ok"); + } + + ret = OH_Camera_DeleteCameraManager(cameraManager_); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Delete CameraManager failed."); + } else { + OH_LOG_INFO(LOG_APP, "Release OH_Camera_DeleteCameraMananger. ok"); + } + cameraManager_ = nullptr; + } + OH_LOG_INFO(LOG_APP, "~NDKCamera exit"); +} + +Camera_ErrorCode NDKCamera::ReleaseCamera(void) +{ + OH_LOG_INFO(LOG_APP, " enter ReleaseCamera"); + if (previewOutput_ && captureSession_) { + PreviewOutputStop(); + OH_CaptureSession_RemovePreviewOutput(captureSession_, previewOutput_); + PreviewOutputRelease(); + } + if (photoOutput_) { + PhotoOutputRelease(); + } + if (videoOutput_) { + VideoOutputRelease(); + } + if (captureSession_) { + SessionRealese(); + } + if (cameraInput_) { + CameraInputClose(); + } + OH_LOG_INFO(LOG_APP, " exit ReleaseCamera"); + return ret_; +} + +Camera_ErrorCode NDKCamera::ReleaseSession(void) +{ + OH_LOG_INFO(LOG_APP, " enter ReleaseSession"); + PreviewOutputStop(); + PhotoOutputRelease(); + VideoOutputRelease(); + SessionRealese(); + OH_LOG_INFO(LOG_APP, " exit ReleaseSession"); + return ret_; +} + +Camera_ErrorCode NDKCamera::SessionRealese(void) +{ + OH_LOG_INFO(LOG_APP, " enter SessionRealese"); + Camera_ErrorCode ret = OH_CaptureSession_Release(captureSession_); + captureSession_ = nullptr; + OH_LOG_INFO(LOG_APP, " exit SessionRealese"); + return ret; +} + +Camera_ErrorCode NDKCamera::HasFlashFn(uint32_t mode) +{ + Camera_FlashMode flashMode = static_cast(mode); + // Check for flashing lights + bool hasFlash = false; + Camera_ErrorCode ret = OH_CaptureSession_HasFlash(captureSession_, &hasFlash); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed."); + } + if (hasFlash) { + OH_LOG_INFO(LOG_APP, "hasFlash success-----"); + } else { + OH_LOG_ERROR(LOG_APP, "hasFlash fail-----"); + } + + // Check if the flash mode is supported + bool isSupported = false; + ret = OH_CaptureSession_IsFlashModeSupported(captureSession_, flashMode, &isSupported); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed."); + } + if (isSupported) { + OH_LOG_INFO(LOG_APP, "isFlashModeSupported success-----"); + } else { + OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail-----"); + } + + // Set flash mode + ret = OH_CaptureSession_SetFlashMode(captureSession_, flashMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret); + } + + // Obtain the flash mode of the current device + ret = OH_CaptureSession_GetFlashMode(captureSession_, &flashMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode: %{public}d ", flashMode); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::IsVideoStabilizationModeSupportedFn(uint32_t mode) +{ + Camera_VideoStabilizationMode videoMode = static_cast(mode); + // Check if the specified video anti shake mode is supported + bool isSupported = false; + Camera_ErrorCode ret = + OH_CaptureSession_IsVideoStabilizationModeSupported(captureSession_, videoMode, &isSupported); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsVideoStabilizationModeSupported failed."); + } + if (isSupported) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_IsVideoStabilizationModeSupported success-----"); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsVideoStabilizationModeSupported fail-----"); + } + + // Set video stabilization + ret = OH_CaptureSession_SetVideoStabilizationMode(captureSession_, videoMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetVideoStabilizationMode success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetVideoStabilizationMode failed. %{public}d ", ret); + } + + ret = OH_CaptureSession_GetVideoStabilizationMode(captureSession_, &videoMode); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetVideoStabilizationMode success. videoMode: %{public}f ", + videoMode); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetVideoStabilizationMode failed. %{public}d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::setZoomRatioFn(uint32_t zoomRatio) +{ + float zoom = float(zoomRatio); + // Obtain supported zoom range + float minZoom; + float maxZoom; + Camera_ErrorCode ret = OH_CaptureSession_GetZoomRatioRange(captureSession_, &minZoom, &maxZoom); + if (captureSession_ == nullptr || ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed."); + } else { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f", + minZoom, maxZoom); + } + + // Set Zoom + ret = OH_CaptureSession_SetZoomRatio(captureSession_, zoom); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret); + } + + // Obtain the zoom value of the current device + ret = OH_CaptureSession_GetZoomRatio(captureSession_, &zoom); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom: %{public}f ", zoom); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionBegin(void) +{ + Camera_ErrorCode ret = OH_CaptureSession_BeginConfig(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_BeginConfig success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionCommitConfig(void) +{ + Camera_ErrorCode ret = OH_CaptureSession_CommitConfig(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_CommitConfig success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionStart(void) +{ + bool isSupport = false; + OH_CaptureSession_IsVideoStabilizationModeSupported(captureSession_, + Camera_VideoStabilizationMode::STABILIZATION_MODE_AUTO, &isSupport); + if (isSupport) { + OH_CaptureSession_SetVideoStabilizationMode(captureSession_, + Camera_VideoStabilizationMode::STABILIZATION_MODE_AUTO); + } + + // Start focusing + OH_LOG_INFO(LOG_APP, "IsFocusMode start"); + OH_CaptureSession_SetFocusMode(captureSession_, Camera_FocusMode::FOCUS_MODE_AUTO); + OH_LOG_INFO(LOG_APP, "IsFocusMode success"); + + Camera_ErrorCode ret = OH_CaptureSession_Start(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Start success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionStop(void) +{ + Camera_ErrorCode ret = OH_CaptureSession_Stop(captureSession_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Stop success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Stop failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::SessionFlowFn(void) +{ + OH_LOG_INFO(LOG_APP, "Start SessionFlowFn IN."); + + // start configuring session + OH_LOG_INFO(LOG_APP, "session beginConfig."); + Camera_ErrorCode ret = OH_CaptureSession_BeginConfig(captureSession_); + + // add cameraInput to the session + OH_LOG_INFO(LOG_APP, "session add Input."); + ret = OH_CaptureSession_AddInput(captureSession_, cameraInput_); + + // add previewOutput to the session + OH_LOG_INFO(LOG_APP, "session add Preview Output."); + ret = OH_CaptureSession_AddPreviewOutput(captureSession_, previewOutput_); + + if (sceneMode_ == Camera_SceneMode::NORMAL_VIDEO) { + // create video output and register video output callback + CreateVideoOutput(videoSurfaceId_); + + // add videoOutput to the Session + AddVideoOutput(); + } + + // Submit configuration information + OH_LOG_INFO(LOG_APP, "session commitConfig"); + ret = OH_CaptureSession_CommitConfig(captureSession_); + + // Start Session Work + OH_LOG_INFO(LOG_APP, "session start"); + SessionStart(); + OH_LOG_INFO(LOG_APP, "session success"); + OH_VideoOutput_Start(videoOutput_); + + return ret; +} + +Camera_ErrorCode NDKCamera::CreateCameraInput(void) +{ + OH_LOG_ERROR(LOG_APP, "enter CreateCameraInput."); + ret_ = OH_CameraManager_CreateCameraInput(cameraManager_, &cameras_[cameraDeviceIndex_], &cameraInput_); + if (cameraInput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreateCameraInput failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_ERROR(LOG_APP, "exit CreateCameraInput."); + + // register camera input callback + CameraInputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputOpen(void) +{ + OH_LOG_ERROR(LOG_APP, "enter CameraInputOpen."); + ret_ = OH_CameraInput_Open(cameraInput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CameraInput_Open failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_ERROR(LOG_APP, "exit CameraInputOpen."); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputClose(void) +{ + OH_LOG_ERROR(LOG_APP, "enter CameraInput_Close."); + ret_ = OH_CameraInput_Close(cameraInput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CameraInput_Close failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_ERROR(LOG_APP, "exit CameraInput_Close."); + return ret_; +} + +Camera_ErrorCode NDKCamera::CameraInputRelease(void) +{ + OH_LOG_ERROR(LOG_APP, "enter CameraInputRelease."); + ret_ = OH_CameraInput_Release(cameraInput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CameraInput_Release failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_ERROR(LOG_APP, "exit CameraInputRelease."); + return ret_; +} + +Camera_ErrorCode NDKCamera::GetSupportedCameras(void) +{ + ret_ = OH_CameraManager_GetSupportedCameras(cameraManager_, &cameras_, &size_); + if (cameras_ == nullptr || &size_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "Get supported cameras failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::GetSupportedOutputCapability(void) +{ + ret_ = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager_, &cameras_[cameraDeviceIndex_], + &cameraOutputCapability_); + if (cameraOutputCapability_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetSupportedCameraOutputCapability failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::CreatePreviewOutput(void) +{ + DRAWING_LOGD("NDKCamera::CreatePreviewOutput start!"); + profile_ = cameraOutputCapability_->previewProfiles[0]; + + if (profile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get previewProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + profile_->size.width = videoFrameWidth; + profile_->size.height = videoFrameHeight; + ret_ = OH_CameraManager_CreatePreviewOutput(cameraManager_, profile_, previewSurfaceId_, &previewOutput_); + + if (previewSurfaceId_ == nullptr || previewOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreatePreviewOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + // register preview output callback + PreviewOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CreatePhotoOutput(char *photoSurfaceId) +{ + DRAWING_LOGD("NDKCamera::CreatePhotoOutput start!"); + profile_ = cameraOutputCapability_->photoProfiles[0]; + + if (profile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get photoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + profile_->size.width = videoFrameWidth; + profile_->size.height = videoFrameHeight ; + ret_ = OH_CameraManager_CreatePhotoOutput(cameraManager_, profile_, photoSurfaceId, &photoOutput_); + + if (photoSurfaceId == nullptr || photoOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreatePhotoOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + // register photo output callback + PhotoOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::CreateVideoOutput(char *videoId) +{ + DRAWING_LOGD("NDKCamera::CreateVideoOutput start!"); + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput width:%{public}d", videoProfile_->size.width); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput height:%{public}d", videoProfile_->size.height); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput format:%{public}d", videoProfile_->format); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput range.min:%{public}d", videoProfile_->range.min); + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput range.max:%{public}d", videoProfile_->range.max); + + videoProfile_->size.width = videoFrameWidth; + videoProfile_->size.height = videoFrameHeight; + ret_ = OH_CameraManager_CreateVideoOutput(cameraManager_, videoProfile_, videoId, &videoOutput_); + + if (videoId == nullptr || videoOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreateVideoOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + // register video output callback + VideoOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::AddVideoOutput(void) +{ + Camera_ErrorCode ret = OH_CaptureSession_AddVideoOutput(captureSession_, videoOutput_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_AddVideoOutput success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddVideoOutput failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::AddPhotoOutput() +{ + Camera_ErrorCode ret = OH_CaptureSession_AddPhotoOutput(captureSession_, photoOutput_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_CaptureSession_AddPhotoOutput success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPhotoOutput failed. %d ", ret); + } + return ret; +} + +Camera_ErrorCode NDKCamera::CreateMetadataOutput(void) +{ + metaDataObjectType_ = cameraOutputCapability_->supportedMetadataObjectTypes[0]; + if (metaDataObjectType_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get metaDataObjectType failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CameraManager_CreateMetadataOutput(cameraManager_, metaDataObjectType_, &metadataOutput_); + if (metadataOutput_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "CreateMetadataOutput failed."); + return CAMERA_INVALID_ARGUMENT; + } + + // register metadata output callback + MetadataOutputRegisterCallback(); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsCameraMuted(void) +{ + ret_ = OH_CameraManager_IsCameraMuted(cameraManager_, isCameraMuted_); + if (isCameraMuted_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsCameraMuted failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::PreviewOutputStop(void) +{ + OH_LOG_ERROR(LOG_APP, "enter PreviewOutputStop."); + ret_ = OH_PreviewOutput_Stop(previewOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PreviewOutputStop failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::PreviewOutputRelease(void) +{ + OH_LOG_ERROR(LOG_APP, "enter PreviewOutputRelease."); + if (previewOutput_ != nullptr) { + ret_ = OH_PreviewOutput_Release(previewOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PreviewOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + previewOutput_ = nullptr; + } + return CAMERA_OK; +} + +Camera_ErrorCode NDKCamera::PhotoOutputRelease(void) +{ + OH_LOG_ERROR(LOG_APP, "enter PhotoOutputRelease."); + ret_ = OH_PhotoOutput_Release(photoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "PhotoOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + photoOutput_ = nullptr; + return ret_; +} + +Camera_ErrorCode NDKCamera::VideoOutputStart(void) +{ + OH_LOG_INFO(LOG_APP, "VideoOutputStart begin."); + Camera_ErrorCode ret = OH_VideoOutput_Start(videoOutput_); + if (ret == CAMERA_OK) { + OH_LOG_INFO(LOG_APP, "OH_VideoOutput_Start success."); + } else { + OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_Start failed. %d ", ret); + } + return ret; +} + +// exposure mode +Camera_ErrorCode NDKCamera::IsExposureModeSupportedFn(uint32_t mode) +{ + OH_LOG_INFO(LOG_APP, "IsExposureModeSupportedFn start."); + exposureMode_ = static_cast(mode); + ret_ = OH_CaptureSession_IsExposureModeSupported(captureSession_, exposureMode_, &isExposureModeSupported_); + if (&isExposureModeSupported_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsExposureModeSupported failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetExposureMode(captureSession_, exposureMode_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetExposureMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetExposureMode(captureSession_, &exposureMode_); + if (&exposureMode_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsExposureModeSupportedFn end."); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsMeteringPoint(int x, int y) +{ + OH_LOG_INFO(LOG_APP, "IsMeteringPoint start."); + ret_ = OH_CaptureSession_GetExposureMode(captureSession_, &exposureMode_); + if (&exposureMode_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + Camera_Point exposurePoint; + exposurePoint.x = x; + exposurePoint.y = y; + ret_ = OH_CaptureSession_SetMeteringPoint(captureSession_, exposurePoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetMeteringPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetMeteringPoint(captureSession_, &exposurePoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetMeteringPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsMeteringPoint end."); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsExposureBiasRange(int exposureBias) +{ + OH_LOG_INFO(LOG_APP, "IsExposureBiasRange end."); + float exposureBiasValue = (float)exposureBias; + ret_ = OH_CaptureSession_GetExposureBiasRange(captureSession_, &minExposureBias_, &maxExposureBias_, &step_); + if (&minExposureBias_ == nullptr || &maxExposureBias_ == nullptr || &step_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureBiasRange failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetExposureBias(captureSession_, exposureBiasValue); + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetExposureBias end."); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetExposureBias failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetExposureBias(captureSession_, &exposureBiasValue); + if (&exposureBiasValue == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetExposureBias failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsExposureBiasRange end."); + return ret_; +} + +// focus mode +Camera_ErrorCode NDKCamera::IsFocusModeSupported(uint32_t mode) +{ + Camera_FocusMode focusMode = static_cast(mode); + ret_ = OH_CaptureSession_IsFocusModeSupported(captureSession_, focusMode, &isFocusModeSupported_); + if (&isFocusModeSupported_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsFocusModeSupported failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::IsFocusMode(uint32_t mode) +{ + OH_LOG_INFO(LOG_APP, "IsFocusMode start."); + Camera_FocusMode focusMode = static_cast(mode); + ret_ = OH_CaptureSession_IsFocusModeSupported(captureSession_, focusMode, &isFocusModeSupported_); + if (&isFocusModeSupported_ == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "IsFocusModeSupported failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_SetFocusMode(captureSession_, focusMode); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetFocusMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetFocusMode(captureSession_, &focusMode); + if (&focusMode == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetFocusMode failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsFocusMode end."); + return ret_; +} + +Camera_ErrorCode NDKCamera::IsFocusPoint(float x, float y) +{ + OH_LOG_INFO(LOG_APP, "IsFocusPoint start."); + Camera_Point focusPoint; + focusPoint.x = x; + focusPoint.y = y; + ret_ = OH_CaptureSession_SetFocusPoint(captureSession_, focusPoint); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "SetFocusPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + ret_ = OH_CaptureSession_GetFocusPoint(captureSession_, &focusPoint); + if (&focusPoint == nullptr || ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "GetFocusPoint failed."); + return CAMERA_INVALID_ARGUMENT; + } + OH_LOG_INFO(LOG_APP, "IsFocusPoint end."); + return ret_; +} + +int32_t NDKCamera::GetVideoFrameWidth(void) +{ + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + return videoProfile_->size.width; +} + +int32_t NDKCamera::GetVideoFrameHeight(void) +{ + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + return videoProfile_->size.height; +} + +int32_t NDKCamera::GetVideoFrameRate(void) +{ + videoProfile_ = cameraOutputCapability_->videoProfiles[0]; + if (videoProfile_ == nullptr) { + OH_LOG_ERROR(LOG_APP, "Get videoProfiles failed."); + return CAMERA_INVALID_ARGUMENT; + } + return videoProfile_->range.min; +} + +Camera_ErrorCode NDKCamera::VideoOutputStop(void) +{ + OH_LOG_ERROR(LOG_APP, "enter VideoOutputStop."); + ret_ = OH_VideoOutput_Stop(videoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "VideoOutputStop failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret_; +} + +Camera_ErrorCode NDKCamera::VideoOutputRelease(void) +{ + OH_LOG_ERROR(LOG_APP, "enter VideoOutputRelease."); + if (videoOutput_ == nullptr) { + OH_LOG_DEBUG(LOG_APP, "VideoOutputRelease videoOutput_ is already null."); + return CAMERA_OK; + } + ret_ = OH_VideoOutput_Release(videoOutput_); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "VideoOutputRelease failed."); + return CAMERA_INVALID_ARGUMENT; + } + videoOutput_ = nullptr; + return ret_; +} + +Camera_ErrorCode NDKCamera::TakePicture(void) +{ + Camera_ErrorCode ret = CAMERA_OK; + ret = OH_PhotoOutput_Capture(photoOutput_); + OH_LOG_ERROR(LOG_APP, "takePicture OH_PhotoOutput_Capture ret = %{public}d.", ret); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "startPhoto failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret; +} + +Camera_ErrorCode NDKCamera::TakePictureWithPhotoSettings(Camera_PhotoCaptureSetting photoSetting) +{ + Camera_ErrorCode ret = CAMERA_OK; + ret = OH_PhotoOutput_Capture_WithCaptureSetting(photoOutput_, photoSetting); + + OH_LOG_INFO(LOG_APP, + "TakePictureWithPhotoSettings get quality %{public}d, rotation %{public}d, mirror %{public}d, " + "latitude, %{public}d, longitude %{public}d, altitude %{public}d", + photoSetting.quality, photoSetting.rotation, photoSetting.mirror, photoSetting.location->latitude, + photoSetting.location->longitude, photoSetting.location->altitude); + + OH_LOG_ERROR(LOG_APP, "takePicture TakePictureWithPhotoSettings ret = %{public}d.", ret); + if (ret != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "startPhoto failed."); + return CAMERA_INVALID_ARGUMENT; + } + return ret; +} + +// CameraManager Callback +void CameraManagerStatusCallback(Camera_Manager *cameraManager, Camera_StatusInfo *status) +{ + OH_LOG_INFO(LOG_APP, "CameraManagerStatusCallback"); +} + +CameraManager_Callbacks *NDKCamera::GetCameraManagerListener(void) +{ + static CameraManager_Callbacks cameraManagerListener = {.onCameraStatus = CameraManagerStatusCallback}; + return &cameraManagerListener; +} + +Camera_ErrorCode NDKCamera::CameraManagerRegisterCallback(void) +{ + ret_ = OH_CameraManager_RegisterCallback(cameraManager_, GetCameraManagerListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CameraManager_RegisterCallback failed."); + } + return ret_; +} + +// CameraInput Callback +void OnCameraInputError(const Camera_Input *cameraInput, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "OnCameraInput errorCode = %{public}d", errorCode); +} + +CameraInput_Callbacks *NDKCamera::GetCameraInputListener(void) +{ + static CameraInput_Callbacks cameraInputCallbacks = {.onError = OnCameraInputError}; + return &cameraInputCallbacks; +} + +Camera_ErrorCode NDKCamera::CameraInputRegisterCallback(void) +{ + ret_ = OH_CameraInput_RegisterCallback(cameraInput_, GetCameraInputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed."); + } + return ret_; +} + +// PreviewOutput Callback +void PreviewOutputOnFrameStart(Camera_PreviewOutput *previewOutput) +{ + OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameStart"); +} + +void PreviewOutputOnFrameEnd(Camera_PreviewOutput *previewOutput, int32_t frameCount) +{ + OH_LOG_INFO(LOG_APP, "PreviewOutput frameCount = %{public}d", frameCount); +} + +void PreviewOutputOnError(Camera_PreviewOutput *previewOutput, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "PreviewOutput errorCode = %{public}d", errorCode); +} + +PreviewOutput_Callbacks *NDKCamera::GetPreviewOutputListener(void) +{ + static PreviewOutput_Callbacks previewOutputListener = { + .onFrameStart = PreviewOutputOnFrameStart, + .onFrameEnd = PreviewOutputOnFrameEnd, + .onError = PreviewOutputOnError + }; + return &previewOutputListener; +} + +Camera_ErrorCode NDKCamera::PreviewOutputRegisterCallback(void) +{ + ret_ = OH_PreviewOutput_RegisterCallback(previewOutput_, GetPreviewOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed."); + } + return ret_; +} + +// PhotoOutput Callback +void PhotoOutputOnFrameStart(Camera_PhotoOutput *photoOutput) +{ + DRAWING_LOGD("PhotoOutputOnFrameStart start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart"); +} + +void PhotoOutputOnFrameShutter(Camera_PhotoOutput *photoOutput, Camera_FrameShutterInfo *info) +{ + DRAWING_LOGD("PhotoOutputOnFrameShutter start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter"); +} + +void PhotoOutputOnFrameEnd(Camera_PhotoOutput *photoOutput, int32_t frameCount) +{ + DRAWING_LOGD("PhotoOutputOnFrameEnd start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount); +} + +void PhotoOutputOnError(Camera_PhotoOutput *photoOutput, Camera_ErrorCode errorCode) +{ + DRAWING_LOGD("PhotoOutputOnError start!"); + OH_LOG_INFO(LOG_APP, "PhotoOutput errorCode = %{public}d", errorCode); +} + +PhotoOutput_Callbacks *NDKCamera::GetPhotoOutputListener(void) +{ + static PhotoOutput_Callbacks photoOutputListener = { + .onFrameStart = PhotoOutputOnFrameStart, + .onFrameShutter = PhotoOutputOnFrameShutter, + .onFrameEnd = PhotoOutputOnFrameEnd, + .onError = PhotoOutputOnError + }; + return &photoOutputListener; +} + +Camera_ErrorCode NDKCamera::PhotoOutputRegisterCallback(void) +{ + ret_ = OH_PhotoOutput_RegisterCallback(photoOutput_, GetPhotoOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterCallback failed."); + } + return ret_; +} + +// VideoOutput Callback +void VideoOutputOnFrameStart(Camera_VideoOutput *videoOutput) +{ + OH_LOG_INFO(LOG_APP, "VideoOutputOnFrameStart"); +} + +void VideoOutputOnFrameEnd(Camera_VideoOutput *videoOutput, int32_t frameCount) +{ + OH_LOG_INFO(LOG_APP, "VideoOutput frameCount = %{public}d", frameCount); +} + +void VideoOutputOnError(Camera_VideoOutput *videoOutput, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "VideoOutput errorCode = %{public}d", errorCode); +} + +VideoOutput_Callbacks *NDKCamera::GetVideoOutputListener(void) +{ + static VideoOutput_Callbacks videoOutputListener = { + .onFrameStart = VideoOutputOnFrameStart, + .onFrameEnd = VideoOutputOnFrameEnd, + .onError = VideoOutputOnError + }; + return &videoOutputListener; +} + +Camera_ErrorCode NDKCamera::VideoOutputRegisterCallback(void) +{ + ret_ = OH_VideoOutput_RegisterCallback(videoOutput_, GetVideoOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_RegisterCallback failed."); + } + return ret_; +} + +// Metadata Callback +void OnMetadataObjectAvailable(Camera_MetadataOutput *metadataOutput, Camera_MetadataObject *metadataObject, + uint32_t size) +{ + OH_LOG_INFO(LOG_APP, "size = %{public}d", size); +} + +void OnMetadataOutputError(Camera_MetadataOutput *metadataOutput, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "OnMetadataOutput errorCode = %{public}d", errorCode); +} + +MetadataOutput_Callbacks *NDKCamera::GetMetadataOutputListener(void) +{ + static MetadataOutput_Callbacks metadataOutputListener = { + .onMetadataObjectAvailable = OnMetadataObjectAvailable, + .onError = OnMetadataOutputError + }; + return &metadataOutputListener; +} + +Camera_ErrorCode NDKCamera::MetadataOutputRegisterCallback(void) +{ + ret_ = OH_MetadataOutput_RegisterCallback(metadataOutput_, GetMetadataOutputListener()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_MetadataOutput_RegisterCallback failed."); + } + return ret_; +} + +// Session Callback +void CaptureSessionOnFocusStateChange(Camera_CaptureSession *session, Camera_FocusState focusState) +{ + OH_LOG_INFO(LOG_APP, "CaptureSession_Callbacks CaptureSessionOnFocusStateChange"); + OH_LOG_INFO(LOG_APP, "CaptureSessionOnFocusStateChange"); +} + +void CaptureSessionOnError(Camera_CaptureSession *session, Camera_ErrorCode errorCode) +{ + OH_LOG_INFO(LOG_APP, "CaptureSession_Callbacks CaptureSessionOnError"); + OH_LOG_INFO(LOG_APP, "CaptureSession errorCode = %{public}d", errorCode); +} + +CaptureSession_Callbacks *NDKCamera::GetCaptureSessionRegister(void) +{ + static CaptureSession_Callbacks captureSessionCallbacks = { + .onFocusStateChange = CaptureSessionOnFocusStateChange, + .onError = CaptureSessionOnError + }; + return &captureSessionCallbacks; +} + +Camera_ErrorCode NDKCamera::CaptureSessionRegisterCallback(void) +{ + ret_ = OH_CaptureSession_RegisterCallback(captureSession_, GetCaptureSessionRegister()); + if (ret_ != CAMERA_OK) { + OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed."); + } + return ret_; +} +} // namespace OHOS_CAMERA_SAMPLE \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h new file mode 100644 index 0000000000..a4a00267b9 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/camera_manager.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVRECORDER_CAMERA_MANAGER_H +#define AVRECORDER_CAMERA_MANAGER_H + +#include "napi/native_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iostream" +#include "mutex" + +#include "hilog/log.h" +#include "ohcamera/camera.h" +#include "ohcamera/camera_input.h" +#include "ohcamera/capture_session.h" +#include "ohcamera/photo_output.h" +#include "ohcamera/preview_output.h" +#include "ohcamera/video_output.h" +#include "napi/native_api.h" +#include "ohcamera/camera_manager.h" +#include "log_common.h" +#include "main.h" + +namespace OHOS_CAMERA_SAMPLE { +class NDKCamera { + public: + ~NDKCamera(); + NDKCamera(uint32_t focusMode, uint32_t cameraDeviceIndex, uint32_t sceneMode, + char *previewId, char *photoId, char *videoId); + + static void Destroy() + { + if (ndkCamera_ != nullptr) { + delete ndkCamera_; + ndkCamera_ = nullptr; + } + } + + Camera_ErrorCode CreateCameraInput(void); + Camera_ErrorCode CameraInputOpen(void); + Camera_ErrorCode CameraInputClose(void); + Camera_ErrorCode CameraInputRelease(void); + Camera_ErrorCode GetSupportedCameras(void); + Camera_ErrorCode GetSupportedOutputCapability(void); + Camera_ErrorCode CreatePreviewOutput(void); + Camera_ErrorCode CreatePhotoOutput(char *photoId); + Camera_ErrorCode CreateVideoOutput(char *videoId); + Camera_ErrorCode CreateMetadataOutput(void); + Camera_ErrorCode IsCameraMuted(void); + Camera_ErrorCode PreviewOutputStop(void); + Camera_ErrorCode PreviewOutputRelease(void); + Camera_ErrorCode PhotoOutputRelease(void); + Camera_ErrorCode HasFlashFn(uint32_t mode); + Camera_ErrorCode IsVideoStabilizationModeSupportedFn(uint32_t mode); + Camera_ErrorCode setZoomRatioFn(uint32_t zoomRatio); + Camera_ErrorCode SessionFlowFn(void); + Camera_ErrorCode SessionBegin(void); + Camera_ErrorCode SessionCommitConfig(void); + Camera_ErrorCode SessionStart(void); + Camera_ErrorCode SessionStop(void); + Camera_ErrorCode StartVideo(char *videoId, char *photoId); + Camera_ErrorCode AddVideoOutput(void); + Camera_ErrorCode AddPhotoOutput(); + Camera_ErrorCode VideoOutputStart(void); + Camera_ErrorCode StartPhoto(char *mSurfaceId); + Camera_ErrorCode IsExposureModeSupportedFn(uint32_t mode); + Camera_ErrorCode IsMeteringPoint(int x, int y); + Camera_ErrorCode IsExposureBiasRange(int exposureBias); + Camera_ErrorCode IsFocusMode(uint32_t mode); + Camera_ErrorCode IsFocusPoint(float x, float y); + Camera_ErrorCode IsFocusModeSupported(uint32_t mode); + Camera_ErrorCode ReleaseCamera(void); + Camera_ErrorCode SessionRealese(void); + Camera_ErrorCode ReleaseSession(void); + int32_t GetVideoFrameWidth(void); + int32_t GetVideoFrameHeight(void); + int32_t GetVideoFrameRate(void); + Camera_ErrorCode VideoOutputStop(void); + Camera_ErrorCode VideoOutputRelease(void); + Camera_ErrorCode TakePicture(void); + Camera_ErrorCode TakePictureWithPhotoSettings(Camera_PhotoCaptureSetting photoSetting); + + // callback + Camera_ErrorCode CameraManagerRegisterCallback(void); + Camera_ErrorCode CameraInputRegisterCallback(void); + Camera_ErrorCode PreviewOutputRegisterCallback(void); + Camera_ErrorCode PhotoOutputRegisterCallback(void); + Camera_ErrorCode VideoOutputRegisterCallback(void); + Camera_ErrorCode MetadataOutputRegisterCallback(void); + Camera_ErrorCode CaptureSessionRegisterCallback(void); + + // Get callback + CameraManager_Callbacks *GetCameraManagerListener(void); + CameraInput_Callbacks *GetCameraInputListener(void); + PreviewOutput_Callbacks *GetPreviewOutputListener(void); + PhotoOutput_Callbacks *GetPhotoOutputListener(void); + VideoOutput_Callbacks *GetVideoOutputListener(void); + MetadataOutput_Callbacks *GetMetadataOutputListener(void); + CaptureSession_Callbacks *GetCaptureSessionRegister(void); + + private: + NDKCamera(const NDKCamera &) = delete; + NDKCamera &operator=(const NDKCamera &) = delete; + uint32_t cameraDeviceIndex_; + Camera_Manager *cameraManager_; + Camera_CaptureSession *captureSession_ = nullptr; + Camera_Device *cameras_; + uint32_t size_; + Camera_OutputCapability *cameraOutputCapability_; + Camera_Profile *profile_; + Camera_VideoProfile *videoProfile_; + Camera_PreviewOutput *previewOutput_ = nullptr; + Camera_PhotoOutput *photoOutput_ = nullptr; + Camera_VideoOutput *videoOutput_ = nullptr; + const Camera_MetadataObjectType *metaDataObjectType_; + Camera_MetadataOutput *metadataOutput_; + Camera_Input *cameraInput_; + bool *isCameraMuted_; + Camera_Position position_; + Camera_Type type_; + char *previewSurfaceId_; + Camera_ErrorCode ret_; + uint32_t takePictureTimes = 0; + Camera_ExposureMode exposureMode_; + bool isExposureModeSupported_; + bool isFocusModeSupported_; + float minExposureBias_; + float maxExposureBias_; + float step_; + uint32_t focusMode_; + + static NDKCamera *ndkCamera_; + static std::mutex mtx_; + volatile bool valid_; + + Camera_SceneMode sceneMode_; + char *photoSurfaceId_; + char *videoSurfaceId_; + bool isSuccess_; +}; +} // namespace OHOS_CAMERA_SAMPLE +#endif //AVRECORDER_CAMERA_MANAGER_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h new file mode 100644 index 0000000000..1440bd5059 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/log_common.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVRECORDER_LOG_COMMON_H +#define AVRECORDER_LOG_COMMON_H + +#ifndef LOG_COMMON_H +#define LOG_COMMON_H +#include +#define LOG_PRINT_DOMAIN 0xFF00 +#define APP_LOG_DOMAIN 0x0001 +constexpr const char *APP_LOG_TAG = "AVRecorderSample"; +#define DRAWING_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define DRAWING_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define DRAWING_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define DRAWING_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) + +#endif // LOG_COMMON_H +#endif //AVRECORDER_LOG_COMMON_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp new file mode 100644 index 0000000000..93b79dbddb --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.cpp @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "main.h" +#include "napi/native_api.h" +#include "camera_manager.h" + +#define LOG_DOMAIN 0x3200 +#define LOG_TAG "MY_NDKDEMO" +#include + +using namespace std; +using namespace OHOS_CAMERA_SAMPLE; +static NDKCamera* ndkCamera_ = nullptr; + +// 设置视频分辨率 +int videoFrameWidth = 1280; +int videoFrameHeight = 720; + +// 配置参数,可选三种录制模式 +// Type 1: 音视频录制 +void SetConfig(OH_AVRecorder_Config &config) +{ + config.audioSourceType = AVRECORDER_MIC; + config.videoSourceType = AVRECORDER_SURFACE_YUV; + + config.profile.audioBitrate = 96000; + config.profile.audioChannels = 2; + config.profile.audioCodec = AVRECORDER_AUDIO_AAC; + config.profile.audioSampleRate = 48000; + + config.profile.videoBitrate = 2000000; + config.profile.videoFrameWidth = videoFrameWidth; + config.profile.videoFrameHeight = videoFrameHeight; + config.profile.videoFrameRate = 30; + config.profile.videoCodec = AVRECORDER_VIDEO_AVC; + config.profile.isHdr = false; + config.profile.enableTemporalScale = false; + + config.profile.fileFormat = AVRECORDER_CFT_MPEG_4; + config.fileGenerationMode = AVRECORDER_AUTO_CREATE_CAMERA_SCENE; + + config.metadata.videoOrientation = (char*)malloc(2); + if (config.metadata.videoOrientation != nullptr) { + strcpy(config.metadata.videoOrientation, "90"); + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== videoOrientation: %{public}s", config.metadata.videoOrientation); + + config.metadata.location.latitude = 31.791863; + config.metadata.location.longitude = 64.574687; +} + +// Type 2: 只录音频 +void SetConfigAudio(OH_AVRecorder_Config &config) +{ + config.audioSourceType = AVRECORDER_MIC; + + config.profile.audioBitrate = 32000; + config.profile.audioChannels = 2; + config.profile.audioCodec = AVRECORDER_AUDIO_AAC; + config.profile.audioSampleRate = 8000; + + config.profile.fileFormat = AVRECORDER_CFT_AAC; + config.fileGenerationMode = AVRECORDER_APP_CREATE; + + config.metadata.location.latitude = 31.791863; + config.metadata.location.longitude = 64.574687; +} + +// Type 3: 只录视频 +void SetConfigVideo(OH_AVRecorder_Config &config) +{ + config.videoSourceType = AVRECORDER_SURFACE_YUV; + + config.profile.videoBitrate = 2000000; + config.profile.videoFrameWidth = videoFrameWidth; + config.profile.videoFrameHeight = videoFrameHeight; + config.profile.videoFrameRate = 30; + config.profile.videoCodec = AVRECORDER_VIDEO_AVC; + config.profile.isHdr = false; + config.profile.enableTemporalScale = false; + + config.profile.fileFormat = AVRECORDER_CFT_MPEG_4; + config.fileGenerationMode = AVRECORDER_APP_CREATE; + + config.metadata.videoOrientation = (char*)malloc(2); + if (config.metadata.videoOrientation != nullptr) { + strcpy(config.metadata.videoOrientation, "90"); + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== videoOrientation: %{public}s", config.metadata.videoOrientation); + + config.metadata.location.latitude = 31.791863; + config.metadata.location.longitude = 64.574687; +} + +// 设置状态回调 +void OnStateChange(OH_AVRecorder *recorder, OH_AVRecorder_State state, + OH_AVRecorder_StateChangeReason reason, void *userData) { + (void)recorder; + (void)userData; + + // 将 reason 转换为字符串表示 + const char *reasonStr = (reason == AVRECORDER_USER) ? "USER" : (reason == AVRECORDER_BACKGROUND) ? "BACKGROUND" : "UNKNOWN"; + + if (state == AVRECORDER_IDLE) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange IDLE, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_PREPARED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange PREPARED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_STARTED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange STARTED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_PAUSED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange PAUSED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_STOPPED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange STOPPED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_RELEASED) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange RELEASED, reason: %{public}s", reasonStr); + // 处理状态变更 + } + if (state == AVRECORDER_ERROR) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnStateChange ERROR, reason: %{public}s", reasonStr); + // 处理状态变更 + } +} + +// 设置错误回调 +void OnError(OH_AVRecorder *recorder, int32_t errorCode, const char *errorMsg, void *userData) { + (void)recorder; + (void)userData; + OH_LOG_INFO(LOG_APP, "==NDKDemo== Recorder OnError errorCode: %{public}d, error message: %{public}s", + errorCode, errorMsg); +} + +// 设置生成媒体文件回调 +void OnUri(OH_AVRecorder *recorder, OH_MediaAsset *asset, void *userData) { + (void)recorder; + (void)userData; + OH_LOG_INFO(LOG_APP, "==NDKDemo== OnUri in!"); + if (asset != nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_MediaAsset: %p", asset); + auto changeRequest = OH_MediaAssetChangeRequest_Create(asset); + OH_LOG_INFO(LOG_APP, "==NDKDemo== changeRequest: %p", changeRequest); + if (changeRequest == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== changeRequest is null!"); + return; + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== changeRequest is not null!"); + MediaLibrary_ImageFileType imageFileType = MEDIA_LIBRARY_FILE_VIDEO; + + uint32_t result = OH_MediaAssetChangeRequest_SaveCameraPhoto(changeRequest, imageFileType); + OH_LOG_INFO(LOG_APP, "result of OH_MediaAssetChangeRequest_SaveCameraPhoto: %d", result); + uint32_t resultChange = OH_MediaAccessHelper_ApplyChanges(changeRequest); + OH_LOG_INFO(LOG_APP, "result of OH_MediaAccessHelper_ApplyChanges: %d", resultChange); + OH_MediaAsset_Release(asset); + OH_MediaAssetChangeRequest_Release(changeRequest); + } else { + OH_LOG_ERROR(LOG_APP, "Received null media asset!"); + } + OH_LOG_INFO(LOG_APP, "==NDKDemo== OnUri out!"); +} + +// 1.准备录制 +static napi_value PrepareAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + OH_LOG_INFO(LOG_APP, "==NDKDemo== PrepareAVRecorder in!"); + g_avRecorder = OH_AVRecorder_Create(); + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder Create OK! g_avRecorder: %{public}p", g_avRecorder); + if (g_avRecorder == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Create failed!"); + } + OH_AVRecorder_Config *config = new OH_AVRecorder_Config(); + + SetConfig(*config); + + // 1.1 设置URL + const std::string AVREORDER_ROOT = "/data/storage/el2/base/files/"; + int32_t outputFd = open((AVREORDER_ROOT + "avrecorder01.mp4").c_str(), O_RDWR | O_CREAT, 0777); // 设置文件名 + std::string fileUrl = "fd://" + std::to_string(outputFd); + config->url = const_cast(fileUrl.c_str()); + OH_LOG_INFO(LOG_APP, "config.url is: %s", const_cast(fileUrl.c_str())); + std::cout<< "config.url is:" << config->url << std::endl; + + // 1.2 回调 + // 状态回调 + OH_AVRecorder_SetStateCallback(g_avRecorder, OnStateChange, nullptr); + // 错误回调 + OH_AVRecorder_SetErrorCallback(g_avRecorder, OnError, nullptr); + // 生成媒体文件回调 + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_SetUriCallback in!"); + OH_AVErrCode ret = OH_AVRecorder_SetUriCallback(g_avRecorder, OnUri, nullptr); + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_SetUriCallback out!"); + if (ret == AV_ERR_OK) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_SetUriCallback succeed!"); + } else { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== Failed to set URI callback, error code: %d", ret); + } + + // 1.3 prepare接口 + int result = OH_AVRecorder_Prepare(g_avRecorder, config); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Prepare failed %{public}d", result); + } + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder enableTemporalScale:%{public}d", static_cast(config->profile.enableTemporalScale)); + + // 1.4 更新视频旋转角度 OH_AVRecorder_UpdateRotation + char *videoOrientation = config->metadata.videoOrientation; + if (videoOrientation == nullptr || videoOrientation[0] == '\0') { + OH_LOG_INFO(LOG_APP, "==NDKDemo== videoOrientation is null or empty!"); + napi_value res; + napi_create_int32(env, -1, &res); + return res; + } + // 使用 strtol 进行字符串到整数的转换,并进行错误检查 + char *end; + int32_t rotation= static_cast(strtol(videoOrientation, &end, 10)); // 基数 10 表示十进制 + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder rotation: %{public}d", rotation); + + // 检查转换是否成功 + if (end == videoOrientation || *end != '\0') { + // 转换失败,videoOrientation 包含无效的整数 + OH_LOG_INFO(LOG_APP, "Invalid rotation value: %s", videoOrientation); + } + // 选择是否更新旋转角度 + int32_t rotation = 90; + result = OH_AVRecorder_UpdateRotation(g_avRecorder, rotation); + if (result != AV_ERR_OK) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder UpdateRotation failed! ret=%{public}d", result); + } else { + OH_LOG_INFO(LOG_APP, "==NDKDemo== OH_AVRecorder_UpdateRotation: %{public}d", rotation); + } + + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 获取实时配置参数 +static napi_value GetAVRecorderConfig(napi_env env, napi_callback_info info) +{ + (void)info; + +// OH_AVRecorder_Config *config = new OH_AVRecorder_Config(); +// SetConfig(*config); + + OH_AVRecorder_Config *config = nullptr; + + int result = OH_AVRecorder_GetAVRecorderConfig(g_avRecorder, &config); + if (result != AV_ERR_OK || config == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== Get AVRecorder Config failed %{public}d", result); + napi_value res; + napi_create_int32(env, result, &res); + return res; + } + + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoOrientation: %{public}s", config->metadata.videoOrientation); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioSourceType: %{public}d", config->audioSourceType); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoSourceType: %{public}d", config->videoSourceType); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioBitrate: %{public}d", config->profile.audioBitrate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioChannels: %{public}d", config->profile.audioChannels); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioCodec: %{public}d", config->profile.audioCodec); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig audioSampleRate: %{public}d", config->profile.audioSampleRate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig fileFormat: %{public}d", config->profile.fileFormat); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoBitrate: %{public}d", config->profile.videoBitrate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoCodec: %{public}d", config->profile.videoCodec); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoFrameWidth: %{public}d", config->profile.videoFrameWidth); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoFrameHeight: %{public}d", config->profile.videoFrameHeight); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig videoFrameRate: %{public}d", config->profile.videoFrameRate); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig latitude: %{public}.6f", config->metadata.location.latitude); + OH_LOG_INFO(LOG_APP, "==NDKDemo== GetAVRecorderConfig longitude: %{public}.6f", config->metadata.location.longitude); + + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 获取录制支持的编码信息 +static napi_value GetAvailableEncoder(napi_env env, napi_callback_info info) +{ + (void)info; + + OH_AVRecorder_EncoderInfo *encoderInfo = nullptr; + int32_t lengthValue = 0; // 定义一个实际的 int32_t 变量 + int32_t *length = &lengthValue; + + int result = OH_AVRecorder_GetAvailableEncoder(g_avRecorder, &encoderInfo, length); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== GetAvailableEncoder failed %{public}d", result); + } else { + // 打印 encoderInfo 的内容 + if (encoderInfo != nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== Encoder Info in!"); + + // 打印 mimeType (假设是一个枚举类型或可转为字符串的类型) + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder MIME Type: %{public}d", encoderInfo->mimeType); + + // 打印 type + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Type: %{public}s", encoderInfo->type); + + // 打印 bitRate 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder BitRate Min: %{public}d, Max: %{public}d", encoderInfo->bitRate.min, encoderInfo->bitRate.max); + + // 打印 frameRate 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder FrameRate Min: %{public}d, Max: %{public}d", encoderInfo->frameRate.min, encoderInfo->frameRate.max); + + // 打印 width 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Width Min: %{public}d, Max: %{public}d", encoderInfo->width.min, encoderInfo->width.max); + + // 打印 height 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Height Min: %{public}d, Max: %{public}d", encoderInfo->height.min, encoderInfo->height.max); + + // 打印 channels 范围 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder Channels Min: %{public}d, Max: %{public}d", encoderInfo->channels.min, encoderInfo->channels.max); + + // 打印 sampleRate 列表和长度 + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder SampleRate Length: %{public}d", encoderInfo->sampleRateLen); + if (encoderInfo->sampleRate != nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== SampleRates: "); + for (int i = 0; i < encoderInfo->sampleRateLen; i++) { + OH_LOG_INFO(LOG_APP, " ==NDKDemo== GetAvailableEncoder SampleRate: %{public}d", i, encoderInfo->sampleRate[i]); + } + } + } else { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== EncoderInfo is null"); + } + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 2. 启动相机 +static napi_value PrepareCamera(napi_env env, napi_callback_info info) +{ + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder PrepareCamera"); + (void)info; + + // 2.1 相机初始化(init) + + size_t argc = 6; + napi_value args[6] = {nullptr}; + size_t typeLen = 0; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + int32_t focusMode; + napi_get_value_int32(env, args[0], &focusMode); + + uint32_t cameraDeviceIndex; + napi_get_value_uint32(env, args[1], &cameraDeviceIndex); + + uint32_t sceneMode; + napi_get_value_uint32(env, args[2], &sceneMode); + + char* previewId = nullptr; + napi_get_value_string_utf8(env, args[3], nullptr, 0, &typeLen); + previewId = new char[typeLen + 1]; + napi_get_value_string_utf8(env, args[3], previewId, typeLen + 1, &typeLen); + + char* photoId = nullptr; + napi_get_value_string_utf8(env, args[4], nullptr, 0, &typeLen); + photoId = new char[typeLen + 1]; + napi_get_value_string_utf8(env, args[4], photoId, typeLen + 1, &typeLen); + + // 获取surfaceID + OHNativeWindow *window = nullptr; + + int resultCode = OH_AVRecorder_GetInputSurface(g_avRecorder, &window); + if (resultCode != AV_ERR_OK || window == nullptr) { + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder GetInputSurface failed! resultCode=%{public}d, window=%{public}p", resultCode, window); + napi_value errorResult; + napi_create_int32(env, -1, &errorResult); // -1 表示错误 + return errorResult; + } else { + // 打印 window 地址以确认是否分配成功 + OH_LOG_INFO(LOG_APP, "==NDKDemo== AVRecorder GetInputSurface succeeded! window address: %{public}p", window); + } + + uint64_t surfaceId; + OH_NativeWindow_GetSurfaceId(window, &surfaceId); + char videoId[30]; + OH_LOG_ERROR(LOG_APP, "InitCamera focusMode : %{public}d", focusMode); + OH_LOG_ERROR(LOG_APP, "InitCamera cameraDeviceIndex : %{public}d", cameraDeviceIndex); + OH_LOG_ERROR(LOG_APP, "InitCamera sceneMode : %{public}d", sceneMode); + OH_LOG_ERROR(LOG_APP, "InitCamera previewId : %{public}s", previewId); + OH_LOG_ERROR(LOG_APP, "InitCamera photoId : %{public}s", photoId); + OH_LOG_ERROR(LOG_APP, "InitCamera videoId : %{public}s", videoId); + + ndkCamera_ = new NDKCamera(focusMode, cameraDeviceIndex, sceneMode, previewId, photoId, videoId); + OH_LOG_INFO(LOG_APP, "InitCamera End"); + + int result = 0; + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 3. 开始录制 +static napi_value StartAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + OH_LOG_INFO(LOG_APP, "==NDKDemo== g_avRecorder start: %{public}p", g_avRecorder); + int result = OH_AVRecorder_Start(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Start failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 4. 暂停录制 +static napi_value PauseAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + int result = OH_AVRecorder_Pause(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Pause failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 5. 恢复录制 +static napi_value ResumeAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + int result = OH_AVRecorder_Resume(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Resume failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 6. 停止录制 +static napi_value StopAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + OH_LOG_INFO(LOG_APP, "==NDKDemo== g_avRecorder stop: %{public}p", g_avRecorder); + int result = OH_AVRecorder_Stop(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Stop failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 7. 重置录制 +static napi_value ResetAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + // 检查 g_avRecorder 是否有效 + if (g_avRecorder == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== g_avRecorder is nullptr!"); + napi_value res; + napi_create_int32(env, AV_ERR_INVALID_VAL, &res); + return res; + } + + int result = OH_AVRecorder_Reset(g_avRecorder); + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Reset failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +// 8. 释放录制资源 +static napi_value ReleaseAVRecorder(napi_env env, napi_callback_info info) +{ + (void)info; + // 检查 g_avRecorder 是否有效 + if (g_avRecorder == nullptr) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== g_avRecorder is nullptr!"); + napi_value res; + napi_create_int32(env, AV_ERR_INVALID_VAL, &res); + return res; + } + + int result = OH_AVRecorder_Release(g_avRecorder); + g_avRecorder = nullptr; // 释放录制资源后,需要显式地将g_avRecorder指针置空 + + if (result != AV_ERR_OK) { + OH_LOG_ERROR(LOG_APP, "==NDKDemo== AVRecorder Release failed %{public}d", result); + } + napi_value res; + napi_create_int32(env, result, &res); + return res; +} + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + {"prepareAVRecorder", nullptr, PrepareAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getAVRecorderConfig", nullptr, GetAVRecorderConfig, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getAvailableEncoder", nullptr, GetAvailableEncoder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"prepareCamera", nullptr, PrepareCamera, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"startAVRecorder", nullptr, StartAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"pauseAVRecorder", nullptr, PauseAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"resumeAVRecorder", nullptr, ResumeAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"stopAVRecorder", nullptr, StopAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"resetAVRecorder", nullptr, ResetAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"releaseAVRecorder", nullptr, ReleaseAVRecorder, nullptr, nullptr, nullptr, napi_default, nullptr}, + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&demoModule); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h new file mode 100644 index 0000000000..8a4605c259 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/main.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVRECORDER_MAIN_H +#define AVRECORDER_MAIN_H + +#include "napi/native_api.h" +#include "hilog/log.h" +#include "mutex" +#include "muxer.h" +#include "ohcamera/camera.h" +#include "ohcamera/camera_input.h" +#include "ohcamera/capture_session.h" +#include "ohcamera/photo_output.h" +#include "ohcamera/preview_output.h" +#include "ohcamera/video_output.h" +#include "ohcamera/camera_manager.h" +#include "native_window/external_window.h" +#include "video_encoder_sample.h" +#include +#include +#include +#include +#include +#include "multimedia/player_framework/native_avcodec_videoencoder.h" +#include "multimedia/media_library/media_asset_change_request_capi.h" +#include "multimedia/media_library/media_access_helper_capi.h" +#include "multimedia/media_library/media_asset_capi.h" + +static struct OH_AVRecorder *g_avRecorder = {}; +OH_AVRecorder* InitRecorder(); +void StartRecording(OH_AVRecorder *recorder); + +extern int videoFrameWidth; +extern int videoFrameHeight; + +#endif //AVRECORDER_MAIN_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp new file mode 100644 index 0000000000..7aebe1b616 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer.h" +#include "hilog/log.h" + +#undef LOG_TAG +#define LOG_TAG "Muxer" + +namespace { +constexpr int32_t VERTICAL_ANGLE = 90; +constexpr int32_t HORIZONTAL_ANGLE = 0; +} + +Muxer::~Muxer() +{ + Release(); +} + +int32_t Muxer::Create(int32_t fd) +{ + muxer_ = OH_AVMuxer_Create(fd, AV_OUTPUT_FORMAT_MPEG_4); + return 0; +} + +int32_t Muxer::Config(SampleInfo &sampleInfo) +{ + OH_LOG_INFO(LOG_APP, "==DEMO== Config"); + OH_AVFormat *formatVideo = OH_AVFormat_CreateVideoFormat(sampleInfo.codecMime.data(), + sampleInfo.videoWidth, sampleInfo.videoHeight); + + OH_AVFormat_SetDoubleValue(formatVideo, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate); + OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_WIDTH, sampleInfo.videoWidth); + OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight); + OH_AVFormat_SetStringValue(formatVideo, OH_MD_KEY_CODEC_MIME, sampleInfo.codecMime.data()); + + int32_t ret = OH_AVMuxer_AddTrack(muxer_, &videoTrackId_, formatVideo); // ! + OH_AVFormat_Destroy(formatVideo); + + OH_LOG_INFO(LOG_APP, "==DEMO== Config End"); + return 0; +} + +int32_t Muxer::Start() +{ + int ret = OH_AVMuxer_Start(muxer_); + return 0; +} + +int32_t Muxer::WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +{ + OH_LOG_INFO(LOG_APP, "==DEMO== WriteSample"); + int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &attr); + ret = OH_AVMuxer_WriteSampleBuffer(muxer_, videoTrackId_, buffer); + return 0; +} + +int32_t Muxer::WriteAudioData(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) +{ + OH_LOG_INFO(LOG_APP, "==DEMO== WriteAudioSample"); + int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &attr); + ret = OH_AVMuxer_WriteSampleBuffer(muxer_, audioTrackId_, buffer); + return 0; +} + +int32_t Muxer::Stop() +{ + int32_t ret = OH_AVMuxer_Stop(muxer_); + return 0; +} + +int32_t Muxer::Release() +{ + if (muxer_ != nullptr) { + OH_AVMuxer_Destroy(muxer_); + muxer_ = nullptr; + } + return 0; +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h new file mode 100644 index 0000000000..603cc602a3 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/muxer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MUXER_H +#define MUXER_H + +#define LOG_DOMAIN 0x3200 +#define LOG_TAG "MY_NDKDEMO" +#include +#include "sample_info.h" +#include "multimedia/player_framework/native_avmuxer.h" + +class Muxer { +public: + Muxer() = default; + ~Muxer(); + + int32_t Create(int32_t fd); + int32_t Config(SampleInfo &sampleInfo); + int32_t Start(); + int32_t WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + int32_t WriteAudioData(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + + int32_t Stop(); + int32_t Release(); + +private: + OH_AVMuxer *muxer_ = nullptr; + int32_t videoTrackId_ = -1; + int32_t audioTrackId_ = -1; + int32_t coverTrackId_ = -1; +}; + +#endif // MUXER_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h new file mode 100644 index 0000000000..d9a20dadaf --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/sample_info.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVCODEC_SAMPLE_INFO_H +#define AVCODEC_SAMPLE_INFO_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANNEXB_INPUT_ONLY 1 + +const std::string_view MIME_VIDEO_AVC = "video/avc"; +const std::string_view MIME_VIDEO_HEVC = "video/hevc"; + +constexpr int32_t BITRATE_10M = 10 * 1024 * 1024; // 10Mbps +constexpr int32_t BITRATE_20M = 20 * 1024 * 1024; // 20Mbps +constexpr int32_t BITRATE_30M = 30 * 1024 * 1024; // 30Mbps + +struct SampleInfo { + int32_t sampleId = 0; + + int32_t inputFd = -1; + int32_t outFd = -1; + int64_t inputFileOffset = 0; + int64_t inputFileSize = 0; + std::string inputFilePath; + std::string outputFilePath; + std::string videoCodecMime = ""; + std::string audioCodecMime = ""; + std::string codecMime = MIME_VIDEO_AVC.data(); + int32_t videoWidth = 0; + int32_t videoHeight = 0; + double frameRate = 0.0; + int64_t bitrate = 10 * 1024 * 1024; // 10Mbps; + int64_t frameInterval = 0; + int32_t perfmode = 0; + int64_t durationTime = 0; + uint32_t maxFrames = UINT32_MAX; + int32_t isHDRVivid = 0; + uint32_t repeatTimes = 1; + OH_AVPixelFormat pixelFormat = AV_PIXEL_FORMAT_NV12; + bool needDumpOutput = false; + uint32_t bitrateMode = CBR; + int32_t hevcProfile = HEVC_PROFILE_MAIN; + int32_t rotation = 0; + OHNativeWindow *window = nullptr; + + + int32_t sampleRate = 44100; + int32_t channelCount = 2; + + uint32_t bufferSize = 0; + double readTime = 0; + double memcpyTime = 0; + double writeTime = 0; + void (*PlayDoneCallback)(void *context) = nullptr; + void *playDoneCallbackData = nullptr; +}; + +struct CodecBufferInfo { + uint32_t bufferIndex = 0; + uintptr_t *buffer = nullptr; + uint8_t *bufferAddr = nullptr; + OH_AVCodecBufferAttr attr = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE}; + + CodecBufferInfo(uint8_t *addr) : bufferAddr(addr){}; + CodecBufferInfo(uint8_t *addr, int32_t bufferSize) + : bufferAddr(addr), attr({0, bufferSize, 0, AVCODEC_BUFFER_FLAGS_NONE}){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVMemory *argBuffer, OH_AVCodecBufferAttr argAttr) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)), attr(argAttr){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVMemory *argBuffer) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)){}; + CodecBufferInfo(uint32_t argBufferIndex, OH_AVBuffer *argBuffer) + : bufferIndex(argBufferIndex), buffer(reinterpret_cast(argBuffer)) { + OH_AVBuffer_GetBufferAttr(argBuffer, &attr); + }; +}; + +class AEncBufferSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::mutex startMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::condition_variable startCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; + OH_AVCodecBufferAttr audioInfo = {0, 0, 0, AVCODEC_BUFFER_FLAGS_NONE}; +}; + +class CodecUserData { +public: + SampleInfo *sampleInfo = nullptr; + + uint32_t inputFrameCount_ = 0; + std::mutex inputMutex_; + std::condition_variable inputCond_; + std::queue inputBufferInfoQueue_; + + uint32_t outputFrameCount_ = 0; + std::mutex outputMutex_; + std::condition_variable outputCond_; + std::queue outputBufferInfoQueue_; + AEncBufferSignal *signal_; + + void ClearQueue() { + { + std::unique_lock lock(inputMutex_); + auto emptyQueue = std::queue(); + inputBufferInfoQueue_.swap(emptyQueue); + } + { + std::unique_lock lock(outputMutex_); + auto emptyQueue = std::queue(); + outputBufferInfoQueue_.swap(emptyQueue); + } + } +}; + +#endif // AVCODEC_SAMPLE_INFO_H \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts new file mode 100644 index 0000000000..58387bb645 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const prepareAVRecorder: () => number; + +export const getAVRecorderConfig: () => number; + +export const getAvailableEncoder: () => number; + +export const prepareCamera: (focusMode: number, cameraDeviceIndex: number, sceneMode: number, + previewId: string, photoId: string, videoId: string) => number; + +export const startAVRecorder: () => number; + +export const pauseAVRecorder: () => number; + +export const resumeAVRecorder: () => number; + +export const stopAVRecorder: () => number; + +export const resetAVRecorder: () => number; + +export const releaseAVRecorder: () => number; + + + diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000..ce82a4c96b --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "libavrecorderndk.so", + "types": "./index.d.ts", + "version": "", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp new file mode 100644 index 0000000000..aca43bbabb --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "video_encoder_sample.h" +#include "hilog/log.h" + +namespace { +constexpr int LIMIT_LOGD_FREQUENCY = 50; +} + +// 设置 OnError 回调函数 +void SampleCallback::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) { + // 回调的错误码由用户判断处理 + (void)codec; + (void)errorCode; + (void)userData; + OH_LOG_ERROR(LOG_APP, "On error, error code: %{public}d", errorCode); +} + +// 设置 OnStreamChanged 回调函数 +void SampleCallback::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) { +// surface模式下,该回调函数无作用 + (void)codec; + (void)format; + (void)userData; +} + +// 设置 OH_AVCodecOnNeedInputBuffer 回调函数,编码输入帧送入数据队列 +void SampleCallback::OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { +// surface模式下,该回调函数无作用,用户通过获取的surface输入数据 + OH_LOG_INFO(LOG_APP, "==DEMO== Video OnNeedInputBuffer"); + + (void)userData; + (void)index; + (void)buffer; + if (userData == nullptr) { + return; + } + (void)codec; + CodecUserData *codecUserData = static_cast(userData); + std::unique_lock lock(codecUserData->inputMutex_); + codecUserData->inputBufferInfoQueue_.emplace(index, buffer); + codecUserData->inputCond_.notify_all(); +} + +// 设置 OH_AVCodecOnNewOutputBuffer 回调函数,编码完成帧送入输出队列 +void SampleCallback::OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) { + // 完成帧buffer对应的index,送入outIndexQueue队列 + // 完成帧的数据buffer送入outBufferQueue队列 + // 数据处理,请参考: + // - 释放编码帧 + OH_LOG_INFO(LOG_APP, "==DEMO== Video OnNewOutputBuffer"); + if (userData == nullptr) { + return; + } + (void)codec; + CodecUserData *codecUserData = static_cast(userData); + std::unique_lock lock(codecUserData->outputMutex_); + codecUserData->outputBufferInfoQueue_.emplace(index, buffer); + codecUserData->outputCond_.notify_all(); +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h new file mode 100644 index 0000000000..0324949f8b --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/cpp/video_encoder_sample.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVCODEC_SAMPLE_CALLBACK_H +#define AVCODEC_SAMPLE_CALLBACK_H +#define LOG_DOMAIN 0x3200 +#define LOG_TAG "MY_NDKDEMO" + +#include "sample_info.h" +#include +class SampleCallback { +public: + SampleCallback() {} + SampleCallback(SampleCallback *p1) {} + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData); + static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData); + static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData); + + OH_AVMuxer *muxer_ = nullptr; + int32_t g_videoTrackId = -1; +}; + +#endif //AVCODEC_SAMPLE_CALLBACK_H diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000..6ff5e236f7 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + let permissionNames: Array = ['ohos.permission.MEDIA_LOCATION', 'ohos.permission.READ_MEDIA', + 'ohos.permission.WRITE_MEDIA', 'ohos.permission.CAMERA', 'ohos.permission.MICROPHONE']; + globalThis.abilityWant = this.launchWant; + globalThis.abilityContext = this.context; + let atManager = abilityAccessCtrl.createAtManager(); + atManager.requestPermissionsFromUser(globalThis.abilityContext, permissionNames).then((data) => { + hilog.info(0x0000, 'testTag', '%{public}s', 'requestPermissionsFromUser called'); + }); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +}; diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000..20b967c87b --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,28 @@ + +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000..a561b00e06 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import testNapi from 'libentry.so'; +import camera from '@ohos.multimedia.camera'; +import image from '@ohos.multimedia.image'; +import media from '@ohos.multimedia.media'; +import { BusinessError } from'@kit.BasicServicesKit'; +import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; +const permissions: Array = ['ohos.permission.CAMERA']; + +const componentType_Jpeg = image.ComponentType.JPEG + +@Entry +@Component +export struct Index { + @State message: string = 'Hello World'; + // XComponentController + private mXComponentController: XComponentController = new XComponentController(); + public videoRecorder?: media.AVRecorder; + // surfaceID value + @State focusMode: number = 2; + @State cameraDeviceIndex: number = 0; + @State sceneMode: number = 2; + @State previewId: string = ''; + @State photoId: string = ''; + @State videoId: string = ''; + @State xComponentWidth: number = 384; + @State xComponentHeight: number = 450; + + build() { + Column() { + XComponent({ + id: 'componentId', + type: XComponentType.SURFACE, + controller: this.mXComponentController + }) + .onLoad(async () => { + this.previewId = this.mXComponentController.getXComponentSurfaceId(); + hilog.info(0x0000, 'testTag', 'previewId: %{public}s', this.previewId); + + hilog.info(0x0000, 'testTag', 'Prepare AVRecorder %{public}d', testNapi.prepareAVRecorder()); + + hilog.info(0x0000, 'testTag', 'prepare Camera %{public}d', testNapi.prepareCamera(this.focusMode, this.cameraDeviceIndex, + this.sceneMode, this.previewId, this.photoId, this.videoId)); + }) + .onDestroy(() => { + // 组件销毁时释放录制资源 + hilog.info(0x0000, 'testTag', 'Application is closing, perform cleanup.'); + testNapi.releaseAVRecorder(); + }) + .backgroundColor(Color.Black) + .width('100%') + .height('70%') + Flex({ direction: FlexDirection.Row, wrap:FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly, + alignItems: ItemAlign.Center, alignContent:FlexAlign.Center }) { + + // ** 可选: 获取实时录制参数 ** + Button($r('app.string.GetConfig'), { type: ButtonType.Circle, stateEffect: true }) + .id("GetConfig") + .backgroundColor(0xF55A42) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Get AVRecorder Config %{public}d', testNapi.getAVRecorderConfig()); + }) + + // ** 可选: 获取编码信息 ** + Button($r('app.string.GetInfo'), { type: ButtonType.Circle, stateEffect: true }) + .id("GetInfo") + .backgroundColor(0xF55A42) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Get AVRecorder EncoderInfo %{public}d', testNapi.getAvailableEncoder()); + }) + } + Flex({ direction: FlexDirection.Row, wrap:FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly, + alignItems: ItemAlign.Center, alignContent:FlexAlign.Center }){ + Button($r('app.string.Prepare'), { type: ButtonType.Circle, stateEffect: true }) + .id("Prepare") + .backgroundColor(Color.Black) + .width(65) + .height(65) + .onClick(() => { + this.previewId = this.mXComponentController.getXComponentSurfaceId(); + hilog.info(0x0000, 'testTag', 'dztdztdzt previewId: %{public}s', this.previewId); + hilog.info(0x0000, 'testTag', 'Prepare AVRecorder %{public}d', testNapi.prepareAVRecorder()); + hilog.info(0x0000, 'testTag', 'prepare Camera %{public}d', testNapi.prepareCamera(this.focusMode, this.cameraDeviceIndex, + this.sceneMode, this.previewId, this.photoId, this.videoId)); + hilog.info(0x0000, 'testTag', 'Start AVRecorder %{public}d', testNapi.startAVRecorder()); + }) + Button($r('app.string.Start'), { type: ButtonType.Circle, stateEffect: true }) + .id("Start") + .backgroundColor(0xF55A42) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'After prepare surfaceId: %{public}s', this.videoId); + hilog.info(0x0000, 'testTag', 'Start AVRecorder %{public}d', testNapi.startAVRecorder()); + }) + Button($r('app.string.Pause'), { type: ButtonType.Normal, stateEffect: true }) + .id("Pause") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Pause AVRecorder %{public}d', testNapi.pauseAVRecorder()); + }) + Button($r('app.string.Resume'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Resume") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Pause AVRecorder %{public}d', testNapi.resumeAVRecorder()); + }) + } + Flex({ direction: FlexDirection.Row, wrap:FlexWrap.Wrap, justifyContent: FlexAlign.SpaceEvenly, + alignItems: ItemAlign.Center, alignContent:FlexAlign.Center }){ + Button($r('app.string.Stop'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Stop") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Stop AVRecorder %{public}d', testNapi.stopAVRecorder()); + }) + Button($r('app.string.Reset'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Reset") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Reset AVRecorder %{public}d', testNapi.resetAVRecorder()); + }) + Button($r('app.string.Release'), { type: ButtonType.Capsule, stateEffect: true }) + .id("Release") + .backgroundColor(0x4287F5) + .width(65) + .height(65) + .onClick(() => { + hilog.info(0x0000, 'testTag', 'Release AVRecorder %{public}d', testNapi.releaseAVRecorder()); + }) + } + } + .width('100%') + .height('100%') + } +} diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 b/code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 new file mode 100644 index 0000000000..c1964ea1db --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/module.json5 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.INTERNET", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.CAMERA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.MEDIA_LOCATION", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.KEEP_BACKGROUND_RUNNING", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + } + ] + } +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000..3c712962da --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000..4d2dc3eec6 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/element/string.json @@ -0,0 +1,56 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "AVRecorderSample" + }, + { + "name": "sample_label", + "value": "AVRecorderSample" + }, + { + "name": "GetConfig", + "value": "GetConfig" + }, + { + "name": "GetInfo", + "value": "GetInfo" + }, + { + "name": "Prepare", + "value": "Prepare" + }, + { + "name": "Start", + "value": "Start" + }, + { + "name": "Pause", + "value": "Pause" + }, + { + "name": "Resume", + "value": "Resume" + }, + { + "name": "Stop", + "value": "Stop" + }, + { + "name": "Reset", + "value": "Reset" + }, + { + "name": "Release", + "value": "Release" + } + ] +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/icon.png b/code/DocsSample/Media/AVRecorder/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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 /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path" +fi + +# Check hvigor wrapper script +if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then + fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}" +fi + +# start hvigor-wrapper script +exec "${EXECUTABLE_NODE}" \ + "${HVIGOR_WRAPPER_SCRIPT}" "$@" diff --git a/code/DocsSample/Media/AVRecorder/hvigorw.bat b/code/DocsSample/Media/AVRecorder/hvigorw.bat new file mode 100644 index 0000000000..d77138670c --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/hvigorw.bat @@ -0,0 +1,63 @@ +@rem Copyright (C) 2025 Huawei Device Co., Ltd. +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@echo off +@rem +@rem ------------------------------------------------------------------- +@rem Hvigor startup script for Windows, version 1.0.0 +@rem +@rem Required ENV vars: +@rem ------------------ +@rem NODE_HOME - location of a Node home dir +@rem or +@rem Add %NODE_HOME%/bin to the PATH environment variable +@rem ------------------------------------------------------------------- +@rem + +set DIRNAME=%~dp0 +set APP_BASE_NAME=%~n0 +set NODE_EXE_PATH="" +set APP_HOME=. +set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js +set NODE_EXE=node.exe +@rem set NODE_OPTS="--max-old-space-size=4096" + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +if not defined NODE_OPTS set NODE_OPTS="--" + +@rem Find node.exe +if defined NODE_HOME ( + set NODE_HOME=%NODE_HOME:"=% + set "PATH=%PATH%;%NODE_HOME%" + set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE% +) + +%NODE_EXE% --version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" ( + "%NODE_EXE%" "%NODE_OPTS%" "%WRAPPER_MODULE_PATH%" %* +) else if exist "%NODE_EXE_PATH%" ( + "%NODE_EXE_PATH%" "%NODE_OPTS%" "%WRAPPER_MODULE_PATH%" %* +) else ( + echo. + echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH. + echo. + echo Please set the NODE_HOME variable in your environment to match the + echo location of your NodeJs installation. +) + +if "%ERRORLEVEL%" == "0"( + if "%OS%" == "Windows_NT" endlocal +) else ( + exit /b %ERRORLEVEL% +) diff --git a/code/DocsSample/Media/AVRecorder/oh-package.json5 b/code/DocsSample/Media/AVRecorder/oh-package.json5 new file mode 100644 index 0000000000..bf39c8a7ea --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/oh-package.json5 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "license": "", + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + }, + "author": "", + "name": "AVRecorderSample", + "description": "Please describe the basic information.", + "main": "", + "version": "1.0.0", + "dependencies": {} +} \ No newline at end of file diff --git a/code/DocsSample/Media/AVRecorder/ohosTest.md b/code/DocsSample/Media/AVRecorder/ohosTest.md new file mode 100644 index 0000000000..b419a7aba4 --- /dev/null +++ b/code/DocsSample/Media/AVRecorder/ohosTest.md @@ -0,0 +1,10 @@ +# AVRecorderSample测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|----------------|-----------|---------------------------------------------------------|---------------------------|------|------| +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 音视频录制功能 | 进入示例应用 | 1. 点击Prepare
2. 点击Start
3. 一段时间后点击Stop | 生成录制文件到沙箱 | 是 | Pass | +| 音频录制功能 | 进入示例应用 | 1. Demo中选择音频录制模式
2. 点击Prepare
3. 点击Start
4. 一段时间后点击Stop | 生成录制文件到沙箱 | 是 | Pass | +| 录制文件保存图库功能 | 进入示例应用 | 1. Demo中fileGenerationMode选择AUTO_CREATE模式
2. 点击Prepare
3. 点击Start
4. 一段时间后点击Stop | 视频文件保存至图库 | 是 | Pass | \ No newline at end of file -- Gitee