uniapp中實(shí)現(xiàn)H5錄音和上傳脑漫、實(shí)時(shí)語音識(shí)別(兼容App小程序)和波形可視化

在uniapp中使用Recorder-UniCore插件可以實(shí)現(xiàn)跨平臺(tái)錄音功能髓抑,uniapp自帶的recorderManager接口不支持H5、錄音格式和實(shí)時(shí)回調(diào)onFrameRecorded兼容性不好优幸,用Recorder插件可避免這些問題吨拍。

DCloud插件市場(chǎng)下載插件(有demo項(xiàng)目源碼):https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore

Recorder-UniCore插件特性

  • 支持vue2、vue3网杆、nvue
  • 支持編譯成:H5羹饰、Android App、iOS App碳却、微信小程序
  • 支持已有的大部分錄音格式:mp3队秩、wav、pcm昼浦、amr刹碾、ogg、g711a座柱、g711u等
  • 支持實(shí)時(shí)處理,包括變速變調(diào)物舒、實(shí)時(shí)上傳色洞、ASR語音轉(zhuǎn)文字
  • 支持可視化波形顯示

[圖片上傳失敗 真6]

集成到項(xiàng)目中

1、通過npm安裝recorder-core

//在uniapp項(xiàng)目跟目錄進(jìn)行npm安裝
npm install recorder-core

2冠胯、下載導(dǎo)入Recorder-UniCore插件

// 到插件市場(chǎng) https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore 下載插件
然后添加到你的項(xiàng)目中 /uni_modules/Recorder-UniCore

3火诸、在vue頁面文件內(nèi)引入js

<script> /**這里是邏輯層**/
//必須引入的Recorder核心(文件路徑是 /src/recorder-core.js 下同)
import Recorder from 'recorder-core' //使用import、require都行

//必須引入的RecordApp核心文件(文件路徑是 /src/app-support/app.js)
import RecordApp from 'recorder-core/src/app-support/app'

//所有平臺(tái)必須引入的uni-app支持文件(如果編譯出現(xiàn)路徑錯(cuò)誤荠察,請(qǐng)把@換成 ../../ 這種)
import '@/uni_modules/Recorder-UniCore/app-uni-support.js'

/** 需要編譯成微信小程序時(shí)置蜀,引入微信小程序支持文件 **/
// #ifdef MP-WEIXIN
    import 'recorder-core/src/app-support/app-miniProgram-wx-support.js'
// #endif


/** H5、小程序環(huán)境中:引入需要的格式編碼器悉盆、可視化插件盯荤,App環(huán)境中在renderjs中引入 **/
// #ifdef H5 || MP-WEIXIN
    //按需引入你需要的錄音格式支持文件,如果需要多個(gè)格式支持焕盟,把這些格式的編碼引擎js文件統(tǒng)統(tǒng)引入進(jìn)來即可
    import 'recorder-core/src/engine/mp3'
    import 'recorder-core/src/engine/mp3-engine' //如果此格式有額外的編碼引擎(*-engine.js)的話秋秤,必須要加上
    
    //可選的插件支持項(xiàng)
    import 'recorder-core/src/extensions/waveview'
// #endif
</script>
<!-- #ifdef APP -->
<script module="yourModuleName" lang="renderjs">
/**需要編譯成App時(shí),你需要添加一個(gè)renderjs模塊脚翘,然后一模一樣的import上面那些js(微信的js除外)
    灼卢,因?yàn)锳pp中默認(rèn)是在renderjs(WebView)中進(jìn)行錄音和音頻編碼**/
import 'recorder-core'
import RecordApp from 'recorder-core/src/app-support/app'
import '../../uni_modules/Recorder-UniCore/app-uni-support.js' //renderjs中似乎不支持"@/"打頭的路徑,如果編譯路徑錯(cuò)誤請(qǐng)改正路徑即可

//按需引入你需要的錄音格式支持文件来农,和插件
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine' 

import 'recorder-core/src/extensions/waveview'

export default {
    mounted(){
        //App的renderjs必須調(diào)用的函數(shù)鞋真,傳入當(dāng)前模塊this
        RecordApp.UniRenderjsRegister(this);
    },
    methods: {
        //這里定義的方法,在邏輯層中可通過 RecordApp.UniWebViewVueCall(this,'this.xxxFunc()') 直接調(diào)用
        //調(diào)用邏輯層的方法沃于,請(qǐng)直接用 this.$ownerInstance.callMethod("xxxFunc",{args}) 調(diào)用涩咖,二進(jìn)制數(shù)據(jù)需轉(zhuǎn)成base64來傳遞
    }
}
</script>
<!-- #endif -->

調(diào)用錄音

/**在邏輯層中編寫**/
//import ... 上面那些import代碼

export default {
data() { return {} }

,mounted() {
    this.isMounted=true;
    //頁面onShow時(shí)【必須調(diào)用】的函數(shù)海诲,傳入當(dāng)前組件this
    RecordApp.UniPageOnShow(this);
}
,onShow(){ //onShow可能比mounted先執(zhí)行,頁面可能還未準(zhǔn)備好
    if(this.isMounted) RecordApp.UniPageOnShow(this);
}

,methods:{
    //請(qǐng)求錄音權(quán)限
    recReq(){
        //編譯成App時(shí)提供的授權(quán)許可(編譯成H5抠藕、小程序?yàn)槊赓M(fèi)授權(quán)可不填寫)饿肺;如果未填寫授權(quán)許可,將會(huì)在App打開后第一次調(diào)用請(qǐng)求錄音權(quán)限時(shí)盾似,彈出“未獲得商用授權(quán)時(shí)敬辣,App上僅供測(cè)試”提示框
        //RecordApp.UniAppUseLicense='我已獲得UniAppID=*****的商用授權(quán)';
        
        RecordApp.UniWebViewActivate(this); //App環(huán)境下必須先切換成當(dāng)前頁面WebView
        RecordApp.RequestPermission(()=>{
            console.log("已獲得錄音權(quán)限,可以開始錄音了");
        },(msg,isUserNotAllow)=>{
            if(isUserNotAllow){//用戶拒絕了錄音權(quán)限
                //這里你應(yīng)當(dāng)編寫代碼進(jìn)行引導(dǎo)用戶給錄音權(quán)限零院,不同平臺(tái)分別進(jìn)行編寫
            }
            console.error("請(qǐng)求錄音權(quán)限失敻仍尽:"+msg);
        });
    }
    
    //開始錄音
    ,recStart(){
        //錄音配置信息
        var set={
            type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采樣率hz告抄、比特率kbps撰茎,其他參數(shù)使用默認(rèn)配置;注意:是數(shù)字的參數(shù)必須提供數(shù)字打洼,不要用字符串龄糊;需要使用的type類型,需提前把格式支持文件加載進(jìn)來募疮,比如使用wav格式需要提前加載wav.js編碼引擎
            ,onProcess:(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd)=>{
                //全平臺(tái)通用:可實(shí)時(shí)上傳(發(fā)送)數(shù)據(jù)炫惩,配合Recorder.SampleData方法,將buffers中的新數(shù)據(jù)連續(xù)的轉(zhuǎn)換成pcm上傳阿浓,或使用mock方法將新數(shù)據(jù)連續(xù)的轉(zhuǎn)碼成其他格式上傳他嚷,可以參考Recorder文檔里面的:Demo片段列表 -> 實(shí)時(shí)轉(zhuǎn)碼并上傳-通用版;基于本功能可以做到:實(shí)時(shí)轉(zhuǎn)發(fā)數(shù)據(jù)芭毙、實(shí)時(shí)保存數(shù)據(jù)筋蓖、實(shí)時(shí)語音識(shí)別(ASR)等
                
                //注意:App里面是在renderjs中進(jìn)行實(shí)際的音頻格式編碼操作,此處的buffers數(shù)據(jù)是renderjs實(shí)時(shí)轉(zhuǎn)發(fā)過來的退敦,修改此處的buffers數(shù)據(jù)不會(huì)改變r(jià)enderjs中buffers粘咖,所以不會(huì)改變生成的音頻文件,可在onProcess_renderjs中進(jìn)行修改操作就沒有此問題了苛聘;如需清理buffers內(nèi)存涂炎,此處和onProcess_renderjs中均需要進(jìn)行清理,H5设哗、小程序中無此限制
                //注意:如果你要用只支持在瀏覽器中使用的Recorder擴(kuò)展插件唱捣,App里面請(qǐng)?jiān)趓enderjs中引入此擴(kuò)展插件,然后在onProcess_renderjs中調(diào)用這個(gè)插件网梢;H5可直接在這里進(jìn)行調(diào)用震缭,小程序不支持這類插件;如果調(diào)用插件的邏輯比較復(fù)雜战虏,建議封裝成js文件拣宰,這樣邏輯層党涕、renderjs中直接import,不需要重復(fù)編寫
                
                //H5巡社、小程序等可視化圖形繪制膛堤,直接運(yùn)行在邏輯層;App里面需要在onProcess_renderjs中進(jìn)行這些操作
                // #ifdef H5 || MP-WEIXIN
                if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
                // #endif
            }
            ,onProcess_renderjs:`function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
                //App中在這里修改buffers才會(huì)改變生成的音頻文件
                //App中是在renderjs中進(jìn)行的可視化圖形繪制晌该,因此需要寫在這里肥荔,this是renderjs模塊的this(也可以用This變量);如果代碼比較復(fù)雜朝群,請(qǐng)直接在renderjs的methods里面放個(gè)方法xxxFunc燕耿,這里直接使用this.xxxFunc(args)進(jìn)行調(diào)用
                if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
            }`
            
            ,takeoffEncodeChunk:true?null:(chunkBytes)=>{
                //全平臺(tái)通用:實(shí)時(shí)接收到編碼器編碼出來的音頻片段數(shù)據(jù),chunkBytes是Uint8Array二進(jìn)制數(shù)據(jù)姜胖,可以實(shí)時(shí)上傳(發(fā)送)出去
                //App中如果未配置RecordApp.UniWithoutAppRenderjs時(shí)誉帅,建議提供此回調(diào),因?yàn)殇浺艚Y(jié)束后會(huì)將整個(gè)錄音文件從renderjs傳回邏輯層右莱,由于uni-app的邏輯層和renderjs層數(shù)據(jù)交互性能實(shí)在太拉跨了蚜锨,大點(diǎn)的文件傳輸會(huì)比較慢,提供此回調(diào)后可避免Stop時(shí)產(chǎn)生超大數(shù)據(jù)回傳
            }
            ,takeoffEncodeChunk_renderjs:true?null:`function(chunkBytes){
                //App中這里可以做一些僅在renderjs中才生效的事情慢蜓,不提供也行踏志,this是renderjs模塊的this(也可以用This變量)
            }`
            
            ,start_renderjs:`function(){
                //App中可以放一個(gè)函數(shù),在Start成功時(shí)renderjs中會(huì)先調(diào)用這里的代碼胀瞪,this是renderjs模塊的this(也可以用This變量)
                //放一些僅在renderjs中才生效的事情,比如初始化饲鄙,不提供也行
            }`
            ,stop_renderjs:`function(arrayBuffer,duration,mime){
                //App中可以放一個(gè)函數(shù)凄诞,在Stop成功時(shí)renderjs中會(huì)先調(diào)用這里的代碼,this是renderjs模塊的this(也可以用This變量)
                //放一些僅在renderjs中才生效的事情忍级,不提供也行
            }`
        };
        
        RecordApp.UniWebViewActivate(this); //App環(huán)境下必須先切換成當(dāng)前頁面WebView
        RecordApp.Start(set,()=>{
            console.log("已開始錄音");
            
            //創(chuàng)建音頻可視化圖形繪制帆谍,App環(huán)境下是在renderjs中繪制,H5轴咱、小程序等是在邏輯層中繪制汛蝙,因此需要提供兩段相同的代碼
            //view里面放一個(gè)canvas,canvas需要指定寬高(下面style里指定了300*100)
            //<canvas type="2d" class="recwave-WaveView" style="width:300px;height:100px"></canvas>
            RecordApp.UniFindCanvas(this,[".recwave-WaveView"],`
                this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
            `,(canvas1)=>{
                this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
            });
        },(msg)=>{
            console.error("開始錄音失斊臃巍:"+msg);
        });
    }
    
    //暫停錄音
    ,recPause(){
        if(RecordApp.GetCurrentRecOrNull()){
            RecordApp.Pause();
            console.log("已暫停");
        }
    }
    //繼續(xù)錄音
    ,recResume(){
        if(RecordApp.GetCurrentRecOrNull()){
            RecordApp.Resume();
            console.log("繼續(xù)錄音中...");
        }
    }
    
    //停止錄音
    ,recStop(){
        RecordApp.Stop((arrayBuffer,duration,mime)=>{
            //全平臺(tái)通用:arrayBuffer是音頻文件二進(jìn)制數(shù)據(jù)窖剑,可以保存成文件或者發(fā)送給服務(wù)器
            //App中如果在Start參數(shù)中提供了stop_renderjs,renderjs中的函數(shù)會(huì)比這個(gè)函數(shù)先執(zhí)行
            
            //注意:當(dāng)Start時(shí)提供了takeoffEncodeChunk后戈稿,你需要自行實(shí)時(shí)保存錄音文件數(shù)據(jù)西土,因此Stop時(shí)返回的arrayBuffer的長度將為0字節(jié)
            
            //如果當(dāng)前環(huán)境支持Blob,也可以直接構(gòu)造成Blob文件對(duì)象鞍盗,和Recorder使用一致
            if(typeof(Blob)!="undefined" && typeof(window)=="object"){
                var blob=new Blob([arrayBuffer],{type:mime});
                console.log(blob, (window.URL||webkitURL).createObjectURL(blob));
            }
        },(msg)=>{
            console.error("結(jié)束錄音失斝枇恕:"+msg);
        });
    }
    
}
}

上面代碼中包含了開始錄音跳昼、結(jié)束錄音、暫停肋乍、繼續(xù)的功能方法代碼鹅颊,在view中放幾個(gè)按鈕進(jìn)行點(diǎn)擊調(diào)用即可;在onProcess回調(diào)中可以做到錄音數(shù)據(jù)實(shí)時(shí)處理墓造,可視化圖形的繪制操作也是在onProcess中進(jìn)行的(Recorder提供了多中可視化波形顯示)堪伍,H5、App滔岳、小程序均可使用杠娱。

要編譯成App時(shí),記得先在 manifest.json 中配置好Android和iOS的錄音權(quán)限聲明:

//Android需要勾選的權(quán)限谱煤,第二個(gè)必須勾選摊求,不然使用H5錄音時(shí)將沒法打開麥克風(fēng)
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

//iOS需要聲明的權(quán)限
NSMicrophoneUsageDescription

上傳錄音

在上面錄音recStop代碼中,結(jié)束錄音后會(huì)得到ArrayBuffer二進(jìn)制數(shù)據(jù)刘离,將ArrayBuffer上傳到服務(wù)器即可室叉;實(shí)時(shí)處理中也支持上傳,實(shí)時(shí)得到音頻數(shù)據(jù)的ArrayBuffer后按下面的上傳方法上傳即可硫惕。

上傳方式一(簡單):轉(zhuǎn)成Base64文本上傳

//由于是base64文本茧痕,因此直接使用普通的接口請(qǐng)求就可以了,代碼簡單,H5恼除、App踪旷、小程序通用

uni.request({
    url: "上傳接口地址"
    ,method: "POST"
    ,header: { "content-type":"application/x-www-form-urlencoded" }
    ,data: {
        audio: uni.arrayBufferToBase64(arrayBuffer)
        ,... 其他表單參數(shù) ...
    }
    ,success: (res) => { }
    ,fail: (err)=>{ }
});

上傳方式二(復(fù)雜):使用上傳表單上傳 multipart/form-data

//使用multipart/form-data表單上傳文件,在uniapp中支持不是很好豁辉,每個(gè)平臺(tái)單獨(dú)處理

// #ifdef H5
    //H5中直接使用瀏覽器提供的File接口構(gòu)造一個(gè)文件
    uni.uploadFile({
        url: "上傳接口地址"
        ,file: new File([arrayBuffer], "recorder.mp3")
        ,name: "audio"
        ,formData: {
            ... 其他表單參數(shù) ...
        }
        ,success: (res) => { }
        ,fail: (err)=>{ }
    });
// #endif

// #ifdef APP
    //App中直接將二進(jìn)制數(shù)據(jù)保存到本地文件令野,然后再上傳
    RecordApp.UniSaveLocalFile("recorder.mp3",arrayBuffer,(savePath)=>{
        uni.uploadFile({
            url: "上傳接口地址"
            ,filePath: savePath
            ,name: "audio"
            ,formData: {
                ... 其他表單參數(shù) ...
            }
            ,success: (res) => { }
            ,fail: (err)=>{ }
        });
    },(err)=>{});
// #endif

// #ifdef MP-WEIXIN
    //小程序中需要將二進(jìn)制數(shù)據(jù)保存到本地文件,然后再上傳
    var savePath=wx.env.USER_DATA_PATH+"/recorder.mp3";
    wx.getFileSystemManager().writeFile({
        filePath:savePath
        ,data:arrayBuffer
        ,encoding:"binary"
        ,success:()=>{
            wx.uploadFile({
                url: "上傳接口地址"
                ,filePath: savePath
                ,name: "audio"
                ,formData: {
                    ... 其他表單參數(shù) ...
                }
                ,success: (res) => { }
                ,fail: (err)=>{ }
            });
        }
        ,fail:(e)=>{  }
    });
// #endif

ASR語音識(shí)別

假如你的服務(wù)器提供了識(shí)別接口徽级,可以參考上面的文件上傳气破,將文件上傳給你的服務(wù)器后,服務(wù)器將識(shí)別結(jié)果返回給前端餐抢,此方式可以適配:騰訊云现使、阿里云、訊飛等的一句話語音識(shí)別旷痕,或自己搭建的語音識(shí)別碳锈,比較簡單。

實(shí)時(shí)的語音識(shí)別可以參考Recorder-UniCore插件的demo項(xiàng)目欺抗,demo源碼里面有個(gè)page_asr.vue示例頁面殴胧,可以做到邊錄音邊返回識(shí)別結(jié)果;此demo使用的是阿里云接口,其他語音識(shí)別接口同樣的可以在onProcess中進(jìn)行實(shí)時(shí)處理即可完成對(duì)接团滥,可以參考Recorder H5錄音開源庫 https://github.com/xiangyuecn/Recorder 中的實(shí)時(shí)上傳處理demo代碼竿屹,不難做到邊錄音邊上傳到語音識(shí)別,H5灸姊、App拱燃、小程序中也是通用的。

【完】

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末力惯,一起剝皮案震驚了整個(gè)濱河市碗誉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌父晶,老刑警劉巖哮缺,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異甲喝,居然都是意外死亡尝苇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門埠胖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糠溜,“玉大人,你說我怎么就攤上這事直撤》歉停” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵谋竖,是天一觀的道長红柱。 經(jīng)常有香客問我,道長蓖乘,這世上最難降的妖魔是什么豹芯? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮驱敲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宽闲。我一直安慰自己众眨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布容诬。 她就那樣靜靜地躺著娩梨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪览徒。 梳的紋絲不亂的頭發(fā)上狈定,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼纽什。 笑死措嵌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芦缰。 我是一名探鬼主播企巢,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼让蕾!你這毒婦竟也來了浪规?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤探孝,失蹤者是張志新(化名)和其女友劉穎笋婿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顿颅,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缸濒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了元镀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绍填。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖栖疑,靈堂內(nèi)的尸體忽然破棺而出讨永,到底是詐尸還是另有隱情,我是刑警寧澤遇革,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布卿闹,位于F島的核電站,受9級(jí)特大地震影響萝快,放射性物質(zhì)發(fā)生泄漏锻霎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一揪漩、第九天 我趴在偏房一處隱蔽的房頂上張望旋恼。 院中可真熱鬧,春花似錦奄容、人聲如沸冰更。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜀细。三九已至,卻和暖如春戈盈,著一層夾襖步出監(jiān)牢的瞬間奠衔,已是汗流浹背谆刨。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留归斤,地道東北人痊夭。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像官册,于是被迫代替她去往敵國和親生兆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容